diff --git a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx index c5b9f2ffe8..6ab3470e9b 100644 --- a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx +++ b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx @@ -27,7 +27,7 @@ void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegP SelectBasics_PickResult& thePickResult) const { gp_XYZ anU = theSegPnt2.XYZ() - theSegPnt1.XYZ(); - gp_XYZ aV = myViewRayDir.XYZ(); + gp_XYZ aV = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ(); // use unnormalized vector instead of myViewRayDir to clip solutions behind Far plane gp_XYZ aW = theSegPnt1.XYZ() - myNearPickedPnt.XYZ(); Standard_Real anA = anU.Dot (anU); @@ -70,7 +70,7 @@ void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegP } aTc = (Abs (aTd) < gp::Resolution() ? 0.0 : aTn / aTd); - const gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTc; + const gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + aV * aTc; thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale); const gp_Vec aPickedVec = aClosestPnt.XYZ() - theSegPnt1.XYZ(); @@ -97,7 +97,7 @@ bool SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePl const gp_Pnt& thePntOnPlane, SelectBasics_PickResult& thePickResult) const { - gp_XYZ anU = myViewRayDir.XYZ(); + gp_XYZ anU = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ(); // use unnormalized vector instead of myViewRayDir to clip solutions behind Far plane by > 1.0 check gp_XYZ aW = myNearPickedPnt.XYZ() - thePntOnPlane.XYZ(); Standard_Real aD = thePlane.Dot (anU); Standard_Real aN = -thePlane.Dot (aW); @@ -117,7 +117,7 @@ bool SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePl } Standard_Real aParam = aN / aD; - if (aParam < 0.0 || aParam > 1.0) + if (aParam < 0.0 || aParam > 1.0) // > 1.0 check could be removed for an infinite ray and anU=myViewRayDir { thePickResult.Invalidate(); return false; @@ -429,7 +429,7 @@ Handle(SelectMgr_BaseFrustum) SelectMgr_RectangularFrustum::ScaleAndTransform (c theTrsf.Transforms (aPoint.ChangeCoord()); aRes->myFarPickedPnt = aPoint; - aRes->myViewRayDir = aRes->myFarPickedPnt.XYZ() - aRes->myNearPickedPnt.XYZ(); + aRes->myViewRayDir = aRes->myFarPickedPnt.XYZ() - aRes->myNearPickedPnt.XYZ(); for (Standard_Integer anIt = 0; anIt < 8; anIt++) { @@ -533,10 +533,9 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt, return Standard_False; gp_XYZ aV = thePnt.XYZ() - myNearPickedPnt.XYZ(); - gp_Pnt aDetectedPnt = - myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * (aV.Dot (myViewRayDir.XYZ()) / myViewRayDir.Dot (myViewRayDir)); + const Standard_Real aDepth = aV.Dot (myViewRayDir.XYZ()); - thePickResult.SetDepth (aDetectedPnt.Distance (myNearPickedPnt) * myScale); + thePickResult.SetDepth (Abs (aDepth) * myScale); thePickResult.SetPickedPoint (thePnt); return !theClipRange.IsClipped (thePickResult.Depth()); @@ -648,39 +647,47 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1, { gp_Vec aTriangleNormal (gp_XYZ (RealLast(), RealLast(), RealLast())); if (!hasOverlap (thePnt1, thePnt2, thePnt3, aTriangleNormal)) + { return Standard_False; + } - // check if intersection point belongs to triangle's interior part - gp_XYZ aTrEdges[3] = { thePnt2.XYZ() - thePnt1.XYZ(), - thePnt3.XYZ() - thePnt2.XYZ(), - thePnt1.XYZ() - thePnt3.XYZ() }; + const gp_XYZ aTrEdges[3] = { thePnt2.XYZ() - thePnt1.XYZ(), + thePnt3.XYZ() - thePnt2.XYZ(), + thePnt1.XYZ() - thePnt3.XYZ() }; + if (aTriangleNormal.SquareMagnitude() < gp::Resolution()) + { + // consider degenerated triangle as point or segment + return aTrEdges[0].SquareModulus() > gp::Resolution() + ? Overlaps (thePnt1, thePnt2, theClipRange, thePickResult) + : (aTrEdges[1].SquareModulus() > gp::Resolution() + ? Overlaps (thePnt2, thePnt3, theClipRange, thePickResult) + : Overlaps (thePnt1, theClipRange, thePickResult)); + } - Standard_Real anAlpha = aTriangleNormal.Dot (myViewRayDir); + const gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3}; + const Standard_Real anAlpha = aTriangleNormal.XYZ().Dot (myViewRayDir.XYZ()); if (Abs (anAlpha) < gp::Resolution()) { - // handle degenerated triangles: in this case, there is no possible way to detect overlap correctly. - if (aTriangleNormal.SquareMagnitude() < gp::Resolution()) + // handle the case when triangle normal and selecting frustum direction are orthogonal + SelectBasics_PickResult aPickResult; + thePickResult.Invalidate(); + for (Standard_Integer anEdgeIter = 0; anEdgeIter < 3; ++anEdgeIter) { - return Standard_False; + const gp_Pnt& aStartPnt = aPnts[anEdgeIter]; + const gp_Pnt& anEndPnt = aPnts[anEdgeIter < 2 ? anEdgeIter + 1 : 0]; + segmentSegmentDistance (aStartPnt, anEndPnt, aPickResult); + thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult); } - - // handle the case when triangle normal and selecting frustum direction are orthogonal: for this case, overlap - // is detected correctly, and distance to triangle's plane can be measured as distance to its arbitrary vertex. - const gp_XYZ aDiff = myNearPickedPnt.XYZ() - thePnt1.XYZ(); - thePickResult.SetDepth (aTriangleNormal.Dot (aDiff) * myScale); - thePickResult.SetPickedPoint (thePnt1); - thePickResult.SetSurfaceNormal (aTriangleNormal); return !theClipRange.IsClipped (thePickResult.Depth()); } - gp_XYZ anEdge = (thePnt1.XYZ() - myNearPickedPnt.XYZ()) * (1.0 / anAlpha); + // check if intersection point belongs to triangle's interior part + const gp_XYZ anEdge = (thePnt1.XYZ() - myNearPickedPnt.XYZ()) * (1.0 / anAlpha); - Standard_Real aTime = aTriangleNormal.Dot (anEdge); - - gp_XYZ aVec = myViewRayDir.XYZ().Crossed (anEdge); - - Standard_Real anU = aVec.Dot (aTrEdges[2]); - Standard_Real aV = aVec.Dot (aTrEdges[0]); + const Standard_Real aTime = aTriangleNormal.Dot (anEdge); + const gp_XYZ aVec = myViewRayDir.XYZ().Crossed (anEdge); + const Standard_Real anU = aVec.Dot (aTrEdges[2]); + const Standard_Real aV = aVec.Dot (aTrEdges[0]); const Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0); const gp_Pnt aPtOnPlane = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTime; @@ -692,21 +699,25 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1, return !theClipRange.IsClipped (thePickResult.Depth()); } - gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3}; Standard_Real aMinDist = RealLast(); - Standard_Integer aNearestEdgeIdx = -1; + Standard_Integer aNearestEdgeIdx1 = -1; for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx) { gp_XYZ aW = aPtOnPlane.XYZ() - aPnts[anEdgeIdx].XYZ(); Standard_Real aCoef = aTrEdges[anEdgeIdx].Dot (aW) / aTrEdges[anEdgeIdx].Dot (aTrEdges[anEdgeIdx]); Standard_Real aDist = aPtOnPlane.Distance (aPnts[anEdgeIdx].XYZ() + aCoef * aTrEdges[anEdgeIdx]); - if (aMinDist > aDist) + if (aDist < aMinDist) { aMinDist = aDist; - aNearestEdgeIdx = anEdgeIdx; + aNearestEdgeIdx1 = anEdgeIdx; } } - segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], thePickResult); + Standard_Integer aNearestEdgeIdx2 = (aNearestEdgeIdx1 + 1) % 3; + if (myViewRayDir.IsParallel (gp_Vec (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2]), Precision::Angular())) + { + aNearestEdgeIdx2 = aNearestEdgeIdx1 == 0 ? 2 : aNearestEdgeIdx1 - 1; + } + segmentSegmentDistance (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2], thePickResult); } return !theClipRange.IsClipped (thePickResult.Depth()); @@ -729,7 +740,7 @@ Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& // ======================================================================= gp_Pnt SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const { - return myNearPickedPnt.XYZ() + myViewRayDir.Normalized().XYZ() * theDepth / myScale; + return myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * theDepth / myScale; } // ======================================================================= diff --git a/src/SelectMgr/SelectMgr_RectangularFrustum.hxx b/src/SelectMgr/SelectMgr_RectangularFrustum.hxx index 81411401e6..e5170fcccd 100644 --- a/src/SelectMgr/SelectMgr_RectangularFrustum.hxx +++ b/src/SelectMgr/SelectMgr_RectangularFrustum.hxx @@ -120,7 +120,7 @@ public: inline const gp_Pnt& GetFarPnt() const { return myFarPickedPnt; } //! Return view ray direction. - const gp_Vec& GetViewRayDirection() const { return myViewRayDir; } + const gp_Dir& GetViewRayDirection() const { return myViewRayDir; } //! Return mouse coordinates. const gp_Pnt2d& GetMousePosition() const { return myMousePos; } @@ -153,7 +153,7 @@ private: gp_Pnt myNearPickedPnt; //!< 3d projection of user-picked selection point onto near view plane gp_Pnt myFarPickedPnt; //!< 3d projection of user-picked selection point onto far view plane - gp_Vec myViewRayDir; + gp_Dir myViewRayDir; gp_Pnt2d myMousePos; //!< Mouse coordinates Standard_Real myScale; //!< Scale factor of applied transformation, if there was any diff --git a/src/ViewerTest/ViewerTest_ObjectCommands.cxx b/src/ViewerTest/ViewerTest_ObjectCommands.cxx index 40bd1232c3..d2c3aa1939 100644 --- a/src/ViewerTest/ViewerTest_ObjectCommands.cxx +++ b/src/ViewerTest/ViewerTest_ObjectCommands.cxx @@ -1062,8 +1062,7 @@ static int VAxisBuilder(Draw_Interpretor& di, Standard_Integer argc, const char* //============================================================================== //function : VPointBuilder -//purpose : Build an AIS_Point from coordinates or with a selected vertex or edge -//Draw arg : vpoint PoinName [Xa] [Ya] [Za] +//purpose : //============================================================================== #include #include @@ -1071,70 +1070,105 @@ static int VAxisBuilder(Draw_Interpretor& di, Standard_Integer argc, const char* #include #include -static int VPointBuilder(Draw_Interpretor& di, Standard_Integer argc, const char** argv) +static int VPointBuilder(Draw_Interpretor& , + Standard_Integer theArgNb, + const char** theArgVec) { - // Declarations - Standard_Boolean HasArg; - TCollection_AsciiString name; - - // Verification - if (argc<2 || argc>5 ) {di<<" Syntaxe error\n";return 1;} - if (argc==5) HasArg=Standard_True; - else HasArg=Standard_False; - - name=argv[1]; - - // Il y a des arguments: teste l'unique constructeur AIS_Pnt::AIS_Pnt(Point from Geom) - if (HasArg) { - Standard_Real thecoord[3]; - for(Standard_Integer i=0;i<=2;i++) - thecoord[i]=Draw::Atof(argv[2+i]); - Handle(Geom_CartesianPoint ) myGeomPoint= new Geom_CartesianPoint (thecoord[0],thecoord[1],thecoord[2]); - Handle(AIS_Point) myAISPoint=new AIS_Point(myGeomPoint ); - GetMapOfAIS().Bind (myAISPoint,name); - TheAISContext()->Display (myAISPoint, Standard_True); - } - - // Il n'a pas d'arguments - else + TCollection_AsciiString aName; + gp_Pnt aPnt (RealLast(), 0.0, 0.0); + bool is2d = false, isNoSel = false; + for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter) { - TopTools_ListOfShape aShapes; - ViewerTest::GetSelectedShapes (aShapes); - - if (aShapes.Extent() != 1) + TCollection_AsciiString anArg (theArgVec[anArgIter]); + anArg.LowerCase(); + if (anArg == "-2d") { - Message::SendFail() << "Error: Wrong number of selected shapes.\n" - << "\tYou should select one edge or vertex."; - return 1; + is2d = true; } - - const TopoDS_Shape& aShapeA = aShapes.First(); - - if (aShapeA.ShapeType()==TopAbs_VERTEX ) + else if (anArg == "-nosel" + || anArg == "-noselection") { - gp_Pnt A=BRep_Tool::Pnt(TopoDS::Vertex(aShapeA ) ); - Handle(Geom_CartesianPoint) myGeomPoint= new Geom_CartesianPoint (A ); - Handle(AIS_Point) myAISPoint = new AIS_Point (myGeomPoint ); - GetMapOfAIS().Bind(myAISPoint,name); - TheAISContext()->Display (myAISPoint, Standard_True); + isNoSel = true; + } + else if (aName.IsEmpty()) + { + aName = theArgVec[anArgIter]; + } + else if (aPnt.X() == RealLast() + && anArgIter + 1 < theArgNb + && Draw::ParseReal (theArgVec[anArgIter + 0], aPnt.ChangeCoord().ChangeCoord (1)) + && Draw::ParseReal (theArgVec[anArgIter + 1], aPnt.ChangeCoord().ChangeCoord (2))) + { + if (anArgIter + 2 < theArgNb + && TCollection_AsciiString (theArgVec[anArgIter + 2]) != "-2d" + && Draw::ParseReal (theArgVec[anArgIter + 2], aPnt.ChangeCoord().ChangeCoord (3))) + { + anArgIter += 2; + } + else + { + anArgIter += 1; + } } else { - TopoDS_Edge myEdge=TopoDS::Edge(aShapeA); - TopoDS_Vertex myVertexA,myVertexB; - TopExp::Vertices (myEdge ,myVertexA ,myVertexB ); - gp_Pnt A=BRep_Tool::Pnt(myVertexA ); - gp_Pnt B=BRep_Tool::Pnt(myVertexB ); - // M est le milieu de [AB] - Handle(Geom_CartesianPoint) myGeomPointM= new Geom_CartesianPoint ( (A.X()+B.X())/2 , (A.Y()+B.Y())/2 , (A.Z()+B.Z())/2 ); - Handle(AIS_Point) myAISPointM = new AIS_Point (myGeomPointM ); - GetMapOfAIS().Bind(myAISPointM,name); - TheAISContext()->Display (myAISPointM, Standard_True); + Message::SendFail() << "Syntax error at argument '" << anArg << "'\n"; + return 1; } + } + if (aPnt.X() == RealLast()) + { + TopTools_ListOfShape aShapes; + ViewerTest::GetSelectedShapes (aShapes); + TopoDS_Shape aShapeA; + if (aShapes.Extent() == 1) + { + aShapeA = aShapes.First(); + } + switch (!aShapeA.IsNull() ? aShapeA.ShapeType() : TopAbs_SHAPE) + { + case TopAbs_VERTEX: + { + aPnt = BRep_Tool::Pnt (TopoDS::Vertex (aShapeA)); + break; + } + case TopAbs_EDGE: // edge middle point + { + const TopoDS_Edge& anEdge = TopoDS::Edge (aShapeA); + TopoDS_Vertex aVertPair[2]; + TopExp::Vertices (anEdge, aVertPair[0], aVertPair[1]); + const gp_Pnt A = BRep_Tool::Pnt (aVertPair[0]); + const gp_Pnt B = BRep_Tool::Pnt (aVertPair[1]); + aPnt = (A.XYZ() + B.XYZ()) / 2; + break; + } + default: + { + Message::SendFail() << "Error: Wrong number of selected shapes.\n" + << "\tYou should select one edge or vertex."; + return 1; + } + } + } + + if (is2d) + { + aPnt.SetY (-aPnt.Y()); + } + Handle(Geom_CartesianPoint ) aGeomPoint = new Geom_CartesianPoint (aPnt); + Handle(AIS_Point) aPointPrs = new AIS_Point (aGeomPoint); + if (is2d) + { + aPointPrs->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER)); + aPointPrs->SetZLayer (Graphic3d_ZLayerId_TopOSD); + } + ViewerTest::Display (aName, aPointPrs); + if (isNoSel) + { + ViewerTest::GetAISContext()->Deactivate (aPointPrs); } return 0; - } //============================================================================== @@ -6448,9 +6482,11 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands) __FILE__,VAxisBuilder,group); theCommands.Add("vpoint", - "vpoint PointName [Xa] [Ya] [Za] " - "\n\t\t: Creates a point from coordinates. If the values are not defined," - "\n\t\t: a point is created by interactive selection of a vertice or an edge (in the center of the edge).", + "vpoint name [X Y [Z]] [-2d] [-nosel]" + "\n\t\t: Creates a point from coordinates." + "\n\t\t: If the values are not defined, a point is created from selected vertex or edge (center)." + "\n\t\t: -2d defines on-screen 2D point from top-left window corner" + "\n\t\t: -nosel creates non-selectable presentation", __FILE__,VPointBuilder,group); theCommands.Add("vplane", diff --git a/tests/bugs/vis/bug31412 b/tests/bugs/vis/bug31412 new file mode 100644 index 0000000000..f581d900bd --- /dev/null +++ b/tests/bugs/vis/bug31412 @@ -0,0 +1,35 @@ +puts "=============" +puts "0031412: Visualization - entity behind is returned as topmost at the edges" +puts "=============" + +pload VISUALIZATION +box b1 250 250 900 1000 1000 200 +box b2 1000 1000 1000 +vdisplay -dispMode 1 b1 b2 +vaspects b1 -setWidth 3 -setColor ORANGE +vaspects b2 -setWidth 3 -setColor MATRABLUE +vrenderparams -shadingModel UNLIT + +vviewparams -proj 0 0 1 +vfit +vmoveto 325 100 +if { [vreadpixel 325 400 rgb name] == "CYAN" } { puts "ERROR: back box is misdetected" } +vpoint p1 -2d -nosel 325 100 +vdump $imagedir/${casename}_proj_Z.png +vremove p1 + +vviewparams -proj 0 1 0 +vfit +vmoveto 200 58 +if { [vreadpixel 400 58 rgb name] == "CYAN" } { puts "ERROR: back box is misdetected" } +vpoint p2 -2d -nosel 200 58 +vdump $imagedir/${casename}_proj_Y.png +vremove p2 + +vviewparams -proj 1 0 0 +vfit +vmoveto 200 58 +if { [vreadpixel 50 58 rgb name] == "CYAN" } { puts "ERROR: back box is misdetected" } +vpoint p3 -2d -nosel 200 58 +vdump $imagedir/${casename}_proj_X.png +vremove p3 diff --git a/tests/v3d/manipulator/zoom_persistence b/tests/v3d/manipulator/zoom_persistence index 22f53c0bf0..4cbd69d5cd 100644 --- a/tests/v3d/manipulator/zoom_persistence +++ b/tests/v3d/manipulator/zoom_persistence @@ -28,7 +28,7 @@ vfit vmanipulator m1 -attach b1 -adjustPosition 1 -adjustSize 1 -enableModes 1 -zoomable 1 -set mouse_pick_1 {84 135} +set mouse_pick_1 {84 133} set mouse_pick_2 {29 103} set mouse_pick_3 {29 103} set mouse_drag_3 {121 126} @@ -60,9 +60,9 @@ vfit vmanipulator m2 -attach b2 -adjustPosition 1 -adjustSize 0 -enableModes 1 -zoomable 0 -size 40 -set mouse_pick_1 {341 283} -set mouse_pick_2 {277 246} -set mouse_pick_3 {277 246} +set mouse_pick_1 {341 282} +set mouse_pick_2 {277 245} +set mouse_pick_3 {277 245} set mouse_drag_3 {210 210} # pick at default zoom