0025549: Visualization - do not crash on attempt to display the Angle dimension betwe...
authoraba <aba@opencascade.com>
Tue, 10 Nov 2015 06:49:39 +0000 (09:49 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 26 Nov 2015 08:59:30 +0000 (11:59 +0300)
- Handle cases of 0 and Pi angle depending on lines in edges and end points

Draw arcs in accordance with input normal for minimum angle, check correctness of input circle parameters

src/AIS/AIS_AngleDimension.cxx
src/AIS/AIS_AngleDimension.hxx
tests/bugs/vis/bug25549_1 [new file with mode: 0644]
tests/bugs/vis/bug25549_2 [new file with mode: 0644]

index c07d612..216c932 100644 (file)
@@ -152,7 +152,7 @@ void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge,
 
   if (myIsGeometryValid && !myIsPlaneCustom)
   {
-    ComputePlane();
+    myPlane = aComputedPlane;
   }
 
   SetToUpdate();
@@ -319,6 +319,21 @@ gp_Pnt AIS_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach,
 }
 
 //=======================================================================
+//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());
+
+  // 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 (mySecondPoint.Distance (myFirstPoint) <= 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
   {
index b53e6e0..071a485 100755 (executable)
@@ -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 (file)
index 0000000..a4cbbc1
--- /dev/null
@@ -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 (file)
index 0000000..ea1fa99
--- /dev/null
@@ -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