diff --git a/src/AIS/AIS_AngleDimension.cxx b/src/AIS/AIS_AngleDimension.cxx index c07d6121d5..216c932f5d 100644 --- a/src/AIS/AIS_AngleDimension.cxx +++ b/src/AIS/AIS_AngleDimension.cxx @@ -152,7 +152,7 @@ void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge, if (myIsGeometryValid && !myIsPlaneCustom) { - ComputePlane(); + myPlane = aComputedPlane; } SetToUpdate(); @@ -318,6 +318,21 @@ gp_Pnt AIS_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach, return ElCLib::Value ((aParamBeg + aParamEnd) * 0.5, aCircle); } +//======================================================================= +//function : GetNormalForMinAngle +//purpose : +//======================================================================= +gp_Dir AIS_AngleDimension::GetNormalForMinAngle() const +{ + const gp_Dir& aNormal = myPlane.Axis().Direction(); + gp_Dir aFirst (gp_Vec (myCenterPoint, myFirstPoint) ); + gp_Dir aSecond (gp_Vec (myCenterPoint, mySecondPoint) ); + + return aFirst.AngleWithRef (aSecond, aNormal) < 0.0 + ? aNormal.Reversed() + : aNormal; +} + //======================================================================= //function : DrawArc //purpose : draws the arc between two attach points @@ -329,14 +344,7 @@ void AIS_AngleDimension::DrawArc (const Handle(Prs3d_Presentation)& thePresentat const Standard_Real theRadius, const Standard_Integer theMode) { - // construct plane where the circle and the arc are located - gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter); - if (!aConstructPlane.IsDone()) - { - return; - } - - gp_Pln aPlane = aConstructPlane.Value(); + gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle()); // construct circle forming the arc gce_MakeCirc aConstructCircle (theCenter, aPlane, theRadius); @@ -413,15 +421,8 @@ void AIS_AngleDimension::DrawArcWithText (const Handle(Prs3d_Presentation)& theP const Standard_Integer theMode, const Standard_Integer theLabelPosition) { - // construct plane where the circle and the arc are located - gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter); - if (!aConstructPlane.IsDone()) - { - return; - } - - gp_Pln aPlane = aConstructPlane.Value(); - + gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle()); + Standard_Real aRadius = theFirstAttach.Distance (myCenterPoint); // construct circle forming the arc @@ -468,14 +469,21 @@ void AIS_AngleDimension::DrawArcWithText (const Handle(Prs3d_Presentation)& theP if (isLineBreak) { // compute gap for label as parameteric size of sector on circle segment - Standard_Real aSectorOnCircle = theTextWidth / aRadius; - - gp_Pnt aTextPntBeg = ElCLib::Value (aParamMid - aSectorOnCircle * 0.5, aCircle); - gp_Pnt aTextPntEnd = ElCLib::Value (aParamMid + aSectorOnCircle * 0.5, aCircle); + Standard_Real aSectorOfText = theTextWidth / aRadius; + Standard_Real aTextBegin = aParamMid - aSectorOfText * 0.5; + Standard_Real aTextEnd = aParamMid + aSectorOfText * 0.5; + gp_Pnt aTextPntBeg = ElCLib::Value (aTextBegin, aCircle); + gp_Pnt aTextPntEnd = ElCLib::Value (aTextEnd, aCircle); // Drawing arcs - DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode); - DrawArc (thePresentation, theSecondAttach, aTextPntEnd, theCenter, aRadius, theMode); + if (aTextBegin > aParamBeg) + { + DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode); + } + if (aTextEnd < aParamEnd) + { + DrawArc (thePresentation, aTextPntEnd, theSecondAttach, theCenter, aRadius, theMode); + } } else { @@ -510,11 +518,13 @@ void AIS_AngleDimension::ComputePlane() return; } - gp_Vec aFirstVec = gp_Vec (myCenterPoint, myFirstPoint).Normalized(); - gp_Vec aSecondVec = gp_Vec (myCenterPoint, mySecondPoint).Normalized(); - gp_Vec aDirectionN = aSecondVec.Crossed (aFirstVec).Normalized(); - gp_Vec aDirectionY = (aFirstVec + aSecondVec).Normalized(); - gp_Vec aDirectionX = aDirectionY.Crossed (aDirectionN).Normalized(); + // Compute working plane so that Y axis is codirectional + // with Y axis of text coordinate system (necessary for text alignment) + gp_Vec aFirstVec = gp_Vec (myCenterPoint, myFirstPoint); + gp_Vec aSecondVec = gp_Vec (myCenterPoint, mySecondPoint); + gp_Vec aDirectionN = aSecondVec ^ aFirstVec; + gp_Vec aDirectionY = aFirstVec + aSecondVec; + gp_Vec aDirectionX = aDirectionY ^ aDirectionN; myPlane = gp_Pln (gp_Ax3 (myCenterPoint, gp_Dir (aDirectionN), gp_Dir (aDirectionX))); } @@ -569,7 +579,7 @@ Standard_Real AIS_AngleDimension::ComputeValue() const gp_Vec aVec1 (myCenterPoint, myFirstPoint); gp_Vec aVec2 (myCenterPoint, mySecondPoint); - Standard_Real anAngle = aVec2.AngleWithRef (aVec1, GetPlane().Axis().Direction()); + Standard_Real anAngle = aVec1.AngleWithRef (aVec2, GetNormalForMinAngle()); return anAngle > 0.0 ? anAngle : (2.0 * M_PI + anAngle); } @@ -626,25 +636,25 @@ void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /* gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout()); //Arrows positions and directions - gp_Vec aWPDir = gp_Vec (GetPlane().Axis().Direction()); + gp_Vec aWorkingPlaneDir (GetNormalForMinAngle()); - gp_Dir aFirstExtensionDir = aWPDir ^ gp_Vec (myCenterPoint, aFirstAttach); - gp_Dir aSecondExtensionDir = aWPDir.Reversed() ^ gp_Vec (myCenterPoint, aSecondAttach); + gp_Dir aFirstExtensionDir = aWorkingPlaneDir.Reversed() ^ gp_Vec (myCenterPoint, aFirstAttach); + gp_Dir aSecondExtensionDir = aWorkingPlaneDir ^ gp_Vec (myCenterPoint, aSecondAttach); gp_Vec aFirstArrowVec = gp_Vec (aFirstExtensionDir) * anArrowLength; gp_Vec aSecondArrowVec = gp_Vec (aSecondExtensionDir) * anArrowLength; - gp_Pnt aFirstArrowBegin (0.0, 0.0, 0.0); - gp_Pnt aFirstArrowEnd (0.0, 0.0, 0.0); - gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0); - gp_Pnt aSecondArrowEnd (0.0, 0.0, 0.0); - if (isArrowsExternal) { aFirstArrowVec.Reverse(); aSecondArrowVec.Reverse(); } + gp_Pnt aFirstArrowBegin (0.0, 0.0, 0.0); + gp_Pnt aFirstArrowEnd (0.0, 0.0, 0.0); + gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0); + gp_Pnt aSecondArrowEnd (0.0, 0.0, 0.0); + aFirstArrowBegin = aFirstAttach; aSecondArrowBegin = aSecondAttach; aFirstArrowEnd = aFirstAttach.Translated (-aFirstArrowVec); @@ -840,16 +850,12 @@ Standard_Boolean AIS_AngleDimension::InitTwoEdgesAngle (gp_Pln& theComputedPlane gp_Lin aFirstLin = aFirstLine->Lin(); gp_Lin aSecondLin = aSecondLine->Lin(); - Standard_Boolean isParallelLines = Abs (aFirstLin.Angle (aSecondLin) - M_PI) <= Precision::Angular(); + Standard_Boolean isParallelLines = aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular()); - gp_Pnt aPoint = aFirstLine->Value (0.0); - gp_Dir aNormal = isParallelLines - ? gp_Vec (aSecondLin.Normal (aPoint).Direction()) ^ gp_Vec (aSecondLin.Direction()) - : gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction()); + theComputedPlane = isParallelLines ? gp_Pln(gp::XOY()) + : gp_Pln (aSecondLin.Location(), gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction())); - theComputedPlane = gp_Pln (aPoint, aNormal); - - // Compute geometry for this plane and edges + // Compute geometry for this plane and edges Standard_Boolean isInfinite1,isInfinite2; gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2; @@ -862,17 +868,32 @@ Standard_Boolean AIS_AngleDimension::InitTwoEdgesAngle (gp_Pln& theComputedPlane return Standard_False; } - if (aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular())) - { - myFirstPoint = aFirstLin.Location(); - mySecondPoint = ElCLib::Value (ElCLib::Parameter (aFirstLin, myFirstPoint), aSecondLin); + Standard_Boolean isSameLines = aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular()) + && aFirstLin.Location().IsEqual (aSecondLin.Location(),Precision::Confusion()); - if (mySecondPoint.Distance (myFirstPoint) <= Precision::Confusion()) + // It can be the same gp_Lin geometry but the different begin and end parameters + Standard_Boolean isSameEdges = + (aFirstPoint1.IsEqual (aFirstPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aLastPoint2, Precision::Confusion())) + || (aFirstPoint1.IsEqual (aLastPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aFirstPoint2, Precision::Confusion())); + + if (isParallelLines) + { + // Zero angle, it could not handle this geometry + if (isSameLines && isSameEdges) { - mySecondPoint.Translate (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout())); + return Standard_False; } - myCenterPoint.SetXYZ ((myFirstPoint.XYZ() + mySecondPoint.XYZ()) / 2.0); + // Handle the case of Pi angle + const Standard_Real aParam11 = ElCLib::Parameter (aFirstLin, aFirstPoint1); + const Standard_Real aParam12 = ElCLib::Parameter (aFirstLin, aLastPoint1); + const Standard_Real aParam21 = ElCLib::Parameter (aFirstLin, aFirstPoint2); + const Standard_Real aParam22 = ElCLib::Parameter (aFirstLin, aLastPoint2); + myCenterPoint = ElCLib::Value ( (Min (aParam11, aParam12) + Max (aParam21, aParam22)) * 0.5, aFirstLin); + myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout())); + mySecondPoint = myCenterPoint.XYZ() + (aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular()) + ? aFirstLin.Direction().Reversed().XYZ() * Abs (GetFlyout()) + : aSecondLin.Direction().XYZ() * Abs (GetFlyout())); } else { diff --git a/src/AIS/AIS_AngleDimension.hxx b/src/AIS/AIS_AngleDimension.hxx index b53e6e03f6..071a485dc7 100755 --- a/src/AIS/AIS_AngleDimension.hxx +++ b/src/AIS/AIS_AngleDimension.hxx @@ -217,6 +217,11 @@ protected: //! Initialization of fields that is common to all constructors. Standard_EXPORT void Init(); + //! Gets plane normal for minimal angle. + //! Dimension computation is based on three attach points and plane normal. + //! Based on this normal angle arc, arrows and extensions are constructed. + gp_Dir GetNormalForMinAngle() const; + //! @param theFirstAttach [in] the first attachment point. //! @param theSecondAttach [in] the second attachment point. //! @param theCenter [in] the center point (center point of the angle). diff --git a/tests/bugs/vis/bug25549_1 b/tests/bugs/vis/bug25549_1 new file mode 100644 index 0000000000..a4cbbc1a67 --- /dev/null +++ b/tests/bugs/vis/bug25549_1 @@ -0,0 +1,22 @@ +puts "============" +puts "CR25549" +puts "Visualization - do not crash on attempt to display the Angle dimension between two parallel lines" +puts "============" +puts "" +puts "Tests case of two edges with the same line but different end points parameters" +pload MODELING VISUALIZATION +line l 0 0 0 1 0 0 +mkedge e1 l 50 100 +mkedge e2 l 50 0 + +vinit View1 +vclear +vaxo +vdisplay e1 e2 +vdimension ad -angle -shapes e1 e2 +vfit + +set only_screen 1 + + + diff --git a/tests/bugs/vis/bug25549_2 b/tests/bugs/vis/bug25549_2 new file mode 100644 index 0000000000..ea1fa9937f --- /dev/null +++ b/tests/bugs/vis/bug25549_2 @@ -0,0 +1,21 @@ +puts "============" +puts "CR25549" +puts "Visualization - do not crash on attempt to display the Angle dimension between two parallel lines" +puts "============" +puts "" +puts "Tests case of two edges with opposite lines directions" + +pload MODELING VISUALIZATION +line Line1 0 0 0 1 0 0 +copy Line1 Line2 +reverse Line1 +mkedge e1 Line1 0 50 +mkedge e2 Line2 0 50 + +vinit View1 +vclear +vaxo +vdisplay e1 e2 +vdimension ad -angle -shapes e1 e2 +vfit +set only_screen 1