1 // Created on: 1996-12-05
2 // Created by: Arnaud BOUZY/Odile Olivier
3 // Copyright (c) 1996-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <AIS_AngleDimension.hxx>
20 #include <BRepBuilderAPI_MakeFace.hxx>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRepAdaptor_Surface.hxx>
23 #include <BRepLib_MakeVertex.hxx>
24 #include <BRep_Tool.hxx>
26 #include <GCPnts_UniformAbscissa.hxx>
27 #include <GC_MakeArcOfCircle.hxx>
28 #include <gce_MakeLin2d.hxx>
29 #include <gce_MakeLin.hxx>
30 #include <gce_MakeCirc.hxx>
31 #include <gce_MakeCone.hxx>
32 #include <gce_MakePln.hxx>
33 #include <gce_MakeDir.hxx>
34 #include <Geom_Circle.hxx>
35 #include <Geom_TrimmedCurve.hxx>
36 #include <Geom_ConicalSurface.hxx>
37 #include <Geom_SurfaceOfRevolution.hxx>
38 #include <Geom_OffsetSurface.hxx>
39 #include <Graphic3d_ArrayOfSegments.hxx>
40 #include <Graphic3d_Group.hxx>
41 #include <Graphic3d_ArrayOfPolylines.hxx>
42 #include <IntAna2d_AnaIntersection.hxx>
43 #include <ProjLib.hxx>
44 #include <Prs3d_Root.hxx>
45 #include <Prs3d_ShadingAspect.hxx>
46 #include <PrsMgr_PresentationManager3d.hxx>
47 #include <Select3D_SensitiveGroup.hxx>
48 #include <Select3D_SensitiveSegment.hxx>
49 #include <SelectMgr_Selection.hxx>
50 #include <Standard_ProgramError.hxx>
51 #include <UnitsAPI.hxx>
52 #include <Geom_Line.hxx>
53 #include <Geom_Plane.hxx>
56 IMPLEMENT_STANDARD_RTTIEXT(AIS_AngleDimension,AIS_Dimension)
60 static const TCollection_ExtendedString THE_EMPTY_LABEL_STRING;
61 static const Standard_Real THE_EMPTY_LABEL_WIDTH = 0.0;
62 static const Standard_ExtCharacter THE_DEGREE_SYMBOL (0x00B0);
63 static const Standard_Real THE_3D_TEXT_MARGIN = 0.1;
66 //=======================================================================
67 //function : Constructor
69 //=======================================================================
70 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
71 const TopoDS_Edge& theSecondEdge)
72 : AIS_Dimension (AIS_KOD_PLANEANGLE)
75 SetMeasuredGeometry (theFirstEdge, theSecondEdge);
78 //=======================================================================
79 //function : Constructor
81 //=======================================================================
82 AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint,
83 const gp_Pnt& theSecondPoint,
84 const gp_Pnt& theThirdPoint)
85 : AIS_Dimension (AIS_KOD_PLANEANGLE)
88 SetMeasuredGeometry (theFirstPoint, theSecondPoint, theThirdPoint);
91 //=======================================================================
92 //function : Constructor
94 //=======================================================================
95 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Vertex& theFirstVertex,
96 const TopoDS_Vertex& theSecondVertex,
97 const TopoDS_Vertex& theThirdVertex)
98 : AIS_Dimension (AIS_KOD_PLANEANGLE)
101 SetMeasuredGeometry (theFirstVertex, theSecondVertex, theThirdVertex);
104 //=======================================================================
105 //function : Constructor
107 //=======================================================================
108 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theCone)
109 : AIS_Dimension (AIS_KOD_PLANEANGLE)
112 SetMeasuredGeometry (theCone);
115 //=======================================================================
116 //function : Constructor
118 //=======================================================================
119 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
120 const TopoDS_Face& theSecondFace)
121 : AIS_Dimension (AIS_KOD_PLANEANGLE)
124 SetMeasuredGeometry (theFirstFace, theSecondFace);
127 //=======================================================================
128 //function : Constructor
130 //=======================================================================
131 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
132 const TopoDS_Face& theSecondFace,
133 const gp_Pnt& thePoint)
134 : AIS_Dimension (AIS_KOD_PLANEANGLE)
137 SetMeasuredGeometry (theFirstFace, theSecondFace, thePoint);
140 //=======================================================================
141 //function : SetMeasuredGeometry
143 //=======================================================================
144 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge,
145 const TopoDS_Edge& theSecondEdge)
147 gp_Pln aComputedPlane;
149 myFirstShape = theFirstEdge;
150 mySecondShape = theSecondEdge;
151 myThirdShape = TopoDS_Shape();
152 myGeometryType = GeometryType_Edges;
153 myIsGeometryValid = InitTwoEdgesAngle (aComputedPlane);
155 if (myIsGeometryValid && !myIsPlaneCustom)
157 myPlane = aComputedPlane;
163 //=======================================================================
164 //function : SetMeasuredGeometry
166 //=======================================================================
167 void AIS_AngleDimension::SetMeasuredGeometry (const gp_Pnt& theFirstPoint,
168 const gp_Pnt& theSecondPoint,
169 const gp_Pnt& theThirdPoint)
171 myFirstPoint = theFirstPoint;
172 myCenterPoint = theSecondPoint;
173 mySecondPoint = theThirdPoint;
174 myFirstShape = BRepLib_MakeVertex (myFirstPoint);
175 mySecondShape = BRepLib_MakeVertex (myCenterPoint);
176 myThirdShape = BRepLib_MakeVertex (mySecondPoint);
177 myGeometryType = GeometryType_Points;
178 myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
180 if (myIsGeometryValid && !myIsPlaneCustom)
188 //=======================================================================
189 //function : SetMeasuredGeometry
191 //=======================================================================
192 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Vertex& theFirstVertex,
193 const TopoDS_Vertex& theSecondVertex,
194 const TopoDS_Vertex& theThirdVertex)
196 myFirstShape = theFirstVertex;
197 mySecondShape = theSecondVertex;
198 myThirdShape = theThirdVertex;
199 myFirstPoint = BRep_Tool::Pnt (theFirstVertex);
200 myCenterPoint = BRep_Tool::Pnt (theSecondVertex);
201 mySecondPoint = BRep_Tool::Pnt (theThirdVertex);
202 myGeometryType = GeometryType_Points;
203 myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
205 if (myIsGeometryValid && !myIsPlaneCustom)
213 //=======================================================================
214 //function : SetMeasuredGeometry
216 //=======================================================================
217 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theCone)
219 myFirstShape = theCone;
220 mySecondShape = TopoDS_Shape();
221 myThirdShape = TopoDS_Shape();
222 myGeometryType = GeometryType_Face;
223 myIsGeometryValid = InitConeAngle();
225 if (myIsGeometryValid && !myIsPlaneCustom)
233 //=======================================================================
234 //function : SetMeasuredGeometry
236 //=======================================================================
237 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
238 const TopoDS_Face& theSecondFace)
240 myFirstShape = theFirstFace;
241 mySecondShape = theSecondFace;
242 myThirdShape = TopoDS_Shape();
243 myGeometryType = GeometryType_Faces;
244 myIsGeometryValid = InitTwoFacesAngle();
246 if (myIsGeometryValid && !myIsPlaneCustom)
254 //=======================================================================
255 //function : SetMeasuredGeometry
257 //=======================================================================
258 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
259 const TopoDS_Face& theSecondFace,
260 const gp_Pnt& thePoint)
262 myFirstShape = theFirstFace;
263 mySecondShape = theSecondFace;
264 myThirdShape = TopoDS_Shape();
265 myGeometryType = GeometryType_Faces;
266 myIsGeometryValid = InitTwoFacesAngle (thePoint);
268 if (myIsGeometryValid && !myIsPlaneCustom)
276 //=======================================================================
279 //=======================================================================
280 void AIS_AngleDimension::Init()
282 SetType (AIS_TOA_Interior);
283 SetArrowsVisibility (AIS_TOAV_Both);
284 SetSpecialSymbol (THE_DEGREE_SYMBOL);
285 SetDisplaySpecialSymbol (AIS_DSS_After);
289 //=======================================================================
290 //function: GetCenterOnArc
292 //=======================================================================
293 gp_Pnt AIS_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach,
294 const gp_Pnt& theSecondAttach,
295 const gp_Pnt& theCenter) const
297 // construct plane where the circle and the arc are located
298 gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
299 if (!aConstructPlane.IsDone())
304 gp_Pln aPlane = aConstructPlane.Value();
305 // to have an exterior angle presentation, a plane for further constructed circle should be reversed
306 if (myType == AIS_TOA_Exterior)
308 gp_Ax1 anAxis = aPlane.Axis();
309 gp_Dir aDir = anAxis.Direction();
311 aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
314 Standard_Real aRadius = theFirstAttach.Distance (theCenter);
316 // construct circle forming the arc
317 gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
318 if (!aConstructCircle.IsDone())
323 gp_Circ aCircle = aConstructCircle.Value();
325 // compute angle parameters of arc end-points on circle
326 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
327 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
328 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
330 return ElCLib::Value ((aParamBeg + aParamEnd) * 0.5, aCircle);
333 //=======================================================================
334 //function : GetNormalForMinAngle
336 //=======================================================================
337 gp_Dir AIS_AngleDimension::GetNormalForMinAngle() const
339 const gp_Dir& aNormal = myPlane.Axis().Direction();
340 gp_Dir aFirst (gp_Vec (myCenterPoint, myFirstPoint) );
341 gp_Dir aSecond (gp_Vec (myCenterPoint, mySecondPoint) );
343 return aFirst.AngleWithRef (aSecond, aNormal) < 0.0
348 //=======================================================================
350 //purpose : draws the arc between two attach points
351 //=======================================================================
352 void AIS_AngleDimension::DrawArc (const Handle(Prs3d_Presentation)& thePresentation,
353 const gp_Pnt& theFirstAttach,
354 const gp_Pnt& theSecondAttach,
355 const gp_Pnt& theCenter,
356 const Standard_Real theRadius,
357 const Standard_Integer theMode)
359 gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle());
361 // to have an exterior angle presentation, a plane for further constructed circle should be reversed
362 if (myType == AIS_TOA_Exterior)
364 gp_Ax1 anAxis = aPlane.Axis();
365 gp_Dir aDir = anAxis.Direction();
367 aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
370 // construct circle forming the arc
371 gce_MakeCirc aConstructCircle (theCenter, aPlane, theRadius);
372 if (!aConstructCircle.IsDone())
377 gp_Circ aCircle = aConstructCircle.Value();
380 GC_MakeArcOfCircle aConstructArc (aCircle, theFirstAttach, theSecondAttach, Standard_True);
381 if (!aConstructArc.IsDone())
386 // generate points with specified deflection
387 const Handle(Geom_TrimmedCurve)& anArcCurve = aConstructArc.Value();
389 GeomAdaptor_Curve anArcAdaptor (anArcCurve, anArcCurve->FirstParameter(), anArcCurve->LastParameter());
391 // compute number of discretization elements in old-fanshioned way
392 gp_Vec aCenterToFirstVec (theCenter, theFirstAttach);
393 gp_Vec aCenterToSecondVec (theCenter, theSecondAttach);
394 Standard_Real anAngle = aCenterToFirstVec.Angle (aCenterToSecondVec);
395 if (myType == AIS_TOA_Exterior)
396 anAngle = 2.0 * M_PI - anAngle;
397 // it sets 50 points on PI, and a part of points if angle is less
398 const Standard_Integer aNbPoints = Max (4, Standard_Integer (50.0 * anAngle / M_PI));
400 GCPnts_UniformAbscissa aMakePnts (anArcAdaptor, aNbPoints);
401 if (!aMakePnts.IsDone())
406 // init data arrays for graphical and selection primitives
407 Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aNbPoints);
409 SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
411 // load data into arrays
412 for (Standard_Integer aPntIt = 1; aPntIt <= aMakePnts.NbPoints(); ++aPntIt)
414 gp_Pnt aPnt = anArcAdaptor.Value (aMakePnts.Parameter (aPntIt));
416 aPrimSegments->AddVertex (aPnt);
418 aSensitiveCurve.Append (aPnt);
421 // add display presentation
422 if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
424 Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True);
426 Handle(Graphic3d_AspectLine3d) aDimensionLineStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
427 Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionLineStyle);
428 Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
429 if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
431 Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False);
435 //=======================================================================
436 //function: DrawArcWithText
438 //=======================================================================
439 void AIS_AngleDimension::DrawArcWithText (const Handle(Prs3d_Presentation)& thePresentation,
440 const gp_Pnt& theFirstAttach,
441 const gp_Pnt& theSecondAttach,
442 const gp_Pnt& theCenter,
443 const TCollection_ExtendedString& theText,
444 const Standard_Real theTextWidth,
445 const Standard_Integer theMode,
446 const Standard_Integer theLabelPosition)
448 gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle());
450 Standard_Real aRadius = theFirstAttach.Distance (myCenterPoint);
452 // construct circle forming the arc
453 gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
454 if (!aConstructCircle.IsDone())
459 gp_Circ aCircle = aConstructCircle.Value();
461 // compute angle parameters of arc end-points on circle
462 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
463 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
464 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
466 // middle point of arc parameter on circle
467 Standard_Real aParamMid = (aParamBeg + aParamEnd) * 0.5;
469 // add text graphical primitives
470 if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
472 gp_Pnt aTextPos = ElCLib::Value (aParamMid, aCircle);
473 gp_Dir aTextDir = gce_MakeDir (theFirstAttach, theSecondAttach);
476 drawText (thePresentation,
483 if (theMode != ComputeMode_All && theMode != ComputeMode_Line)
488 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
490 Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
491 && aDimensionAspect->IsText3d();
495 // compute gap for label as parameteric size of sector on circle segment
496 Standard_Real aSectorOfText = theTextWidth / aRadius;
497 Standard_Real aTextBegin = aParamMid - aSectorOfText * 0.5;
498 Standard_Real aTextEnd = aParamMid + aSectorOfText * 0.5;
499 gp_Pnt aTextPntBeg = ElCLib::Value (aTextBegin, aCircle);
500 gp_Pnt aTextPntEnd = ElCLib::Value (aTextEnd, aCircle);
503 if (aTextBegin > aParamBeg)
505 DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode);
507 if (aTextEnd < aParamEnd)
509 DrawArc (thePresentation, aTextPntEnd, theSecondAttach, theCenter, aRadius, theMode);
514 DrawArc (thePresentation, theFirstAttach, theSecondAttach, theCenter, aRadius, theMode);
518 //=======================================================================
519 //function : CheckPlane
521 //=======================================================================
522 Standard_Boolean AIS_AngleDimension::CheckPlane (const gp_Pln& thePlane)const
524 if (!thePlane.Contains (myFirstPoint, Precision::Confusion()) &&
525 !thePlane.Contains (mySecondPoint, Precision::Confusion()) &&
526 !thePlane.Contains (myCenterPoint, Precision::Confusion()))
528 return Standard_False;
531 return Standard_True;
534 //=======================================================================
535 //function : ComputePlane
537 //=======================================================================
538 void AIS_AngleDimension::ComputePlane()
540 if (!myIsGeometryValid)
545 // Compute working plane so that Y axis is codirectional
546 // with Y axis of text coordinate system (necessary for text alignment)
547 gp_Vec aFirstVec = gp_Vec (myCenterPoint, myFirstPoint);
548 gp_Vec aSecondVec = gp_Vec (myCenterPoint, mySecondPoint);
549 gp_Vec aDirectionN = aSecondVec ^ aFirstVec;
550 gp_Vec aDirectionY = aFirstVec + aSecondVec;
551 gp_Vec aDirectionX = aDirectionY ^ aDirectionN;
553 myPlane = gp_Pln (gp_Ax3 (myCenterPoint, gp_Dir (aDirectionN), gp_Dir (aDirectionX)));
556 //=======================================================================
557 //function : GetModelUnits
559 //=======================================================================
560 const TCollection_AsciiString& AIS_AngleDimension::GetModelUnits() const
562 return myDrawer->DimAngleModelUnits();
565 //=======================================================================
566 //function : GetDisplayUnits
568 //=======================================================================
569 const TCollection_AsciiString& AIS_AngleDimension::GetDisplayUnits() const
571 return myDrawer->DimAngleDisplayUnits();
574 //=======================================================================
575 //function : SetModelUnits
577 //=======================================================================
578 void AIS_AngleDimension::SetModelUnits (const TCollection_AsciiString& theUnits)
580 myDrawer->SetDimAngleModelUnits (theUnits);
583 //=======================================================================
584 //function : SetDisplayUnits
586 //=======================================================================
587 void AIS_AngleDimension::SetDisplayUnits (const TCollection_AsciiString& theUnits)
589 myDrawer->SetDimAngleDisplayUnits (theUnits);
592 //=======================================================================
593 //function : ComputeValue
595 //=======================================================================
596 Standard_Real AIS_AngleDimension::ComputeValue() const
603 gp_Vec aVec1 (myCenterPoint, myFirstPoint);
604 gp_Vec aVec2 (myCenterPoint, mySecondPoint);
606 Standard_Real anAngle = aVec1.AngleWithRef (aVec2, GetNormalForMinAngle());
608 return anAngle > 0.0 ? anAngle : (2.0 * M_PI + anAngle);
611 //=======================================================================
613 //purpose : Having three gp_Pnt points compute presentation
614 //=======================================================================
615 void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePM*/,
616 const Handle(Prs3d_Presentation)& thePresentation,
617 const Standard_Integer theMode)
619 mySelectionGeom.Clear (theMode);
626 // Parameters for presentation
627 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
629 Prs3d_Root::CurrentGroup(thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
631 Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
633 // prepare label string and compute its geometrical width
634 Standard_Real aLabelWidth;
635 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
637 // add margins to label width
638 if (aDimensionAspect->IsText3d())
640 aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
643 // Get parameters from aspect or adjust it according with custom text position
644 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
645 Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition();
647 if (IsTextPositionCustom())
649 AdjustParameters (myFixedTextPosition,anExtensionSize, aHorisontalTextPos, myFlyout);
652 // Handle user-defined and automatic arrow placement
653 Standard_Boolean isArrowsExternal = Standard_False;
654 Standard_Integer aLabelPosition = LabelPosition_None;
656 FitTextAlignment (aHorisontalTextPos, aLabelPosition, isArrowsExternal);
658 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
659 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
661 //Arrows positions and directions
662 gp_Vec aWorkingPlaneDir (GetNormalForMinAngle());
664 gp_Dir aFirstExtensionDir = aWorkingPlaneDir.Reversed() ^ gp_Vec (myCenterPoint, aFirstAttach);
665 gp_Dir aSecondExtensionDir = aWorkingPlaneDir ^ gp_Vec (myCenterPoint, aSecondAttach);
667 gp_Vec aFirstArrowVec = gp_Vec (aFirstExtensionDir) * anArrowLength;
668 gp_Vec aSecondArrowVec = gp_Vec (aSecondExtensionDir) * anArrowLength;
670 if (isArrowsExternal)
672 aFirstArrowVec.Reverse();
673 aSecondArrowVec.Reverse();
676 gp_Pnt aFirstArrowBegin (0.0, 0.0, 0.0);
677 gp_Pnt aFirstArrowEnd (0.0, 0.0, 0.0);
678 gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0);
679 gp_Pnt aSecondArrowEnd (0.0, 0.0, 0.0);
681 aFirstArrowBegin = aFirstAttach;
682 aSecondArrowBegin = aSecondAttach;
683 aFirstArrowEnd = aFirstAttach.Translated (-aFirstArrowVec);
684 aSecondArrowEnd = aSecondAttach.Translated (-aSecondArrowVec);
686 // Group1: stenciling text and the angle dimension arc
687 Prs3d_Root::NewGroup (thePresentation);
689 Standard_Integer aHPosition = aLabelPosition & LabelPosition_HMask;
694 case LabelPosition_HCenter :
696 Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
697 && aDimensionAspect->IsText3d();
701 DrawArcWithText (thePresentation,
712 // compute text primitives
713 if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
715 gp_Vec aDimensionDir (aFirstAttach, aSecondAttach);
716 gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition
717 : GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
718 gp_Dir aTextDir = aDimensionDir;
720 drawText (thePresentation,
727 if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
729 DrawArc (thePresentation,
730 (isArrowsExternal || !isArrowVisible(AIS_TOAV_First)) ? aFirstAttach : aFirstArrowEnd,
731 (isArrowsExternal || !isArrowVisible(AIS_TOAV_Second)) ? aSecondAttach : aSecondArrowEnd,
739 case LabelPosition_Left :
741 DrawExtension (thePresentation,
743 (isArrowsExternal && isArrowVisible(AIS_TOAV_First)) ? aFirstArrowEnd : aFirstAttach,
752 case LabelPosition_Right :
754 DrawExtension (thePresentation,
756 (isArrowsExternal && isArrowVisible(AIS_TOAV_Second)) ? aSecondArrowEnd : aSecondAttach,
766 // dimension arc without text
767 if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && aHPosition != LabelPosition_HCenter)
769 Prs3d_Root::NewGroup (thePresentation);
771 DrawArc (thePresentation,
772 (isArrowsExternal || !isArrowVisible(AIS_TOAV_First)) ? aFirstAttach : aFirstArrowEnd,
773 (isArrowsExternal || !isArrowVisible(AIS_TOAV_Second)) ? aSecondAttach : aSecondArrowEnd,
779 // arrows and arrow extensions
780 if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
782 Prs3d_Root::NewGroup (thePresentation);
784 if (isArrowVisible(AIS_TOAV_First))
785 DrawArrow (thePresentation, aFirstArrowBegin, gp_Dir (aFirstArrowVec));
786 if (isArrowVisible(AIS_TOAV_Second))
787 DrawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec));
790 if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && isArrowsExternal)
792 Prs3d_Root::NewGroup (thePresentation);
794 if (aHPosition != LabelPosition_Left && isArrowVisible(AIS_TOAV_First))
796 DrawExtension (thePresentation,
797 aDimensionAspect->ArrowTailSize(),
800 THE_EMPTY_LABEL_STRING,
801 THE_EMPTY_LABEL_WIDTH,
806 if (aHPosition != LabelPosition_Right && isArrowVisible(AIS_TOAV_Second))
808 DrawExtension (thePresentation,
809 aDimensionAspect->ArrowTailSize(),
812 THE_EMPTY_LABEL_STRING,
813 THE_EMPTY_LABEL_WIDTH,
820 if (theMode == ComputeMode_All)
822 Prs3d_Root::NewGroup (thePresentation);
824 Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (4);
825 aPrimSegments->AddVertex (myCenterPoint);
826 aPrimSegments->AddVertex (aFirstAttach);
827 aPrimSegments->AddVertex (myCenterPoint);
828 aPrimSegments->AddVertex (aSecondAttach);
830 Handle(Graphic3d_AspectLine3d) aFlyoutStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
831 Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aFlyoutStyle);
832 Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
835 mySelectionGeom.IsComputed = Standard_True;
838 //=======================================================================
839 //function : ComputeFlyoutSelection
840 //purpose : computes selection for flyouts
841 //=======================================================================
842 void AIS_AngleDimension::ComputeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection,
843 const Handle(SelectMgr_EntityOwner)& theOwner)
845 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
846 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
848 Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner);
849 aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aFirstAttach));
850 aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aSecondAttach));
852 theSelection->Add (aSensitiveEntity);
855 //=======================================================================
856 //function : InitTwoEdgesAngle
858 //=======================================================================
859 Standard_Boolean AIS_AngleDimension::InitTwoEdgesAngle (gp_Pln& theComputedPlane)
861 TopoDS_Edge aFirstEdge = TopoDS::Edge (myFirstShape);
862 TopoDS_Edge aSecondEdge = TopoDS::Edge (mySecondShape);
864 BRepAdaptor_Curve aMakeFirstLine (aFirstEdge);
865 BRepAdaptor_Curve aMakeSecondLine (aSecondEdge);
867 if (aMakeFirstLine.GetType() != GeomAbs_Line || aMakeSecondLine.GetType() != GeomAbs_Line)
869 return Standard_False;
872 Handle(Geom_Line) aFirstLine = new Geom_Line (aMakeFirstLine.Line());
873 Handle(Geom_Line) aSecondLine = new Geom_Line (aMakeSecondLine.Line());
875 gp_Lin aFirstLin = aFirstLine->Lin();
876 gp_Lin aSecondLin = aSecondLine->Lin();
878 Standard_Boolean isParallelLines = aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular());
880 theComputedPlane = isParallelLines ? gp_Pln(gp::XOY())
881 : gp_Pln (aSecondLin.Location(), gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction()));
883 // Compute geometry for this plane and edges
884 Standard_Boolean isInfinite1,isInfinite2;
885 gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2;
886 Handle(Geom_Curve) aFirstCurve = aFirstLine, aSecondCurve = aSecondLine;
887 if (!AIS::ComputeGeometry (aFirstEdge, aSecondEdge,
888 aFirstCurve, aSecondCurve,
889 aFirstPoint1, aLastPoint1,
890 aFirstPoint2, aLastPoint2,
891 isInfinite1, isInfinite2))
893 return Standard_False;
896 Standard_Boolean isSameLines = aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular())
897 && aFirstLin.Location().IsEqual (aSecondLin.Location(),Precision::Confusion());
899 // It can be the same gp_Lin geometry but the different begin and end parameters
900 Standard_Boolean isSameEdges =
901 (aFirstPoint1.IsEqual (aFirstPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aLastPoint2, Precision::Confusion()))
902 || (aFirstPoint1.IsEqual (aLastPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aFirstPoint2, Precision::Confusion()));
906 // Zero angle, it could not handle this geometry
907 if (isSameLines && isSameEdges)
909 return Standard_False;
912 // Handle the case of Pi angle
913 const Standard_Real aParam11 = ElCLib::Parameter (aFirstLin, aFirstPoint1);
914 const Standard_Real aParam12 = ElCLib::Parameter (aFirstLin, aLastPoint1);
915 const Standard_Real aParam21 = ElCLib::Parameter (aFirstLin, aFirstPoint2);
916 const Standard_Real aParam22 = ElCLib::Parameter (aFirstLin, aLastPoint2);
917 myCenterPoint = ElCLib::Value ( (Min (aParam11, aParam12) + Max (aParam21, aParam22)) * 0.5, aFirstLin);
918 myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
919 mySecondPoint = myCenterPoint.XYZ() + (aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular())
920 ? aFirstLin.Direction().Reversed().XYZ() * Abs (GetFlyout())
921 : aSecondLin.Direction().XYZ() * Abs (GetFlyout()));
926 gp_Lin2d aFirstLin2d = ProjLib::Project (theComputedPlane, aFirstLin);
927 gp_Lin2d aSecondLin2d = ProjLib::Project (theComputedPlane, aSecondLin);
929 IntAna2d_AnaIntersection anInt2d (aFirstLin2d, aSecondLin2d);
930 gp_Pnt2d anIntersectPoint;
931 if (!anInt2d.IsDone() || anInt2d.IsEmpty())
933 return Standard_False;
936 anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value());
937 myCenterPoint = ElCLib::To3d (theComputedPlane.Position().Ax2(), anIntersectPoint);
939 if (isInfinite1 || isInfinite2)
941 myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
942 mySecondPoint = myCenterPoint.Translated (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout()));
944 return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
948 // | <- dimension should be here
950 myFirstPoint = myCenterPoint.Distance (aFirstPoint1) > myCenterPoint.Distance (aLastPoint1)
954 mySecondPoint = myCenterPoint.Distance (aFirstPoint2) > myCenterPoint.Distance (aLastPoint2)
959 return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
962 //=======================================================================
963 //function : InitTwoFacesAngle
964 //purpose : initialization of angle dimension between two faces
965 //=======================================================================
966 Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle()
968 TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
969 TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
971 gp_Dir aFirstDir, aSecondDir;
972 gp_Pln aFirstPln, aSecondPln;
973 Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
974 AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
975 Standard_Real aFirstOffset, aSecondOffset;
977 AIS::GetPlaneFromFace (aFirstFace, aFirstPln,
978 aFirstBasisSurf,aFirstSurfType,aFirstOffset);
980 AIS::GetPlaneFromFace (aSecondFace, aSecondPln,
981 aSecondBasisSurf, aSecondSurfType, aSecondOffset);
983 if (aFirstSurfType == AIS_KOS_Plane && aSecondSurfType == AIS_KOS_Plane)
986 Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
987 Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
988 return AIS::InitAngleBetweenPlanarFaces (aFirstFace,
993 && IsValidPoints (myFirstPoint,
999 // Curvilinear faces angle
1000 return AIS::InitAngleBetweenCurvilinearFaces (aFirstFace,
1007 && IsValidPoints (myFirstPoint,
1013 //=======================================================================
1014 //function : InitTwoFacesAngle
1015 //purpose : initialization of angle dimension between two faces
1016 //=======================================================================
1017 Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle (const gp_Pnt thePointOnFirstFace)
1019 TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
1020 TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
1022 gp_Dir aFirstDir, aSecondDir;
1023 gp_Pln aFirstPln, aSecondPln;
1024 Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
1025 AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
1026 Standard_Real aFirstOffset, aSecondOffset;
1028 AIS::GetPlaneFromFace (aFirstFace, aFirstPln,
1029 aFirstBasisSurf,aFirstSurfType,aFirstOffset);
1031 AIS::GetPlaneFromFace (aSecondFace, aSecondPln,
1032 aSecondBasisSurf, aSecondSurfType, aSecondOffset);
1034 myFirstPoint = thePointOnFirstFace;
1035 if (aFirstSurfType == AIS_KOS_Plane && aSecondSurfType == AIS_KOS_Plane)
1037 //Planar faces angle
1038 Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
1039 Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
1040 return AIS::InitAngleBetweenPlanarFaces (aFirstFace,
1046 && IsValidPoints (myFirstPoint,
1052 // Curvilinear faces angle
1053 return AIS::InitAngleBetweenCurvilinearFaces (aFirstFace,
1061 && IsValidPoints (myFirstPoint,
1067 //=======================================================================
1068 //function : InitConeAngle
1069 //purpose : initialization of the cone angle
1070 //=======================================================================
1071 Standard_Boolean AIS_AngleDimension::InitConeAngle()
1073 if (myFirstShape.IsNull())
1075 return Standard_False;
1078 TopoDS_Face aConeShape = TopoDS::Face (myFirstShape);
1082 // A surface from the Face
1083 Handle(Geom_Surface) aSurf;
1084 Handle(Geom_OffsetSurface) aOffsetSurf;
1085 Handle(Geom_ConicalSurface) aConicalSurf;
1086 Handle(Geom_SurfaceOfRevolution) aRevSurf;
1087 Handle(Geom_Line) aLine;
1088 BRepAdaptor_Surface aConeAdaptor (aConeShape);
1090 AIS_KindOfSurface aSurfType;
1091 Standard_Real anOffset = 0.;
1092 Handle(Standard_Type) aType;
1094 Standard_Real aMaxV = aConeAdaptor.FirstVParameter();
1095 Standard_Real aMinV = aConeAdaptor.LastVParameter();
1097 AIS::GetPlaneFromFace (aConeShape, aPln, aSurf, aSurfType, anOffset);
1099 if (aSurfType == AIS_KOS_Revolution)
1101 // Surface of revolution
1102 aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aSurf);
1103 gp_Lin aLin (aRevSurf->Axis());
1104 Handle(Geom_Curve) aBasisCurve = aRevSurf->BasisCurve();
1105 //Must be a part of line (basis curve should be linear)
1106 if (aBasisCurve ->DynamicType() != STANDARD_TYPE(Geom_Line))
1107 return Standard_False;
1109 gp_Pnt aFirst1 = aConeAdaptor.Value (0., aMinV);
1110 gp_Pnt aLast1 = aConeAdaptor.Value (0., aMaxV);
1111 gp_Vec aVec1 (aFirst1, aLast1);
1113 //Projection <aFirst> on <aLin>
1114 gp_Pnt aFirst2 = ElCLib::Value (ElCLib::Parameter (aLin, aFirst1), aLin);
1115 // Projection <aLast> on <aLin>
1116 gp_Pnt aLast2 = ElCLib::Value (ElCLib::Parameter (aLin, aLast1), aLin);
1118 gp_Vec aVec2 (aFirst2, aLast2);
1120 // Check if two parts of revolution are parallel (it's a cylinder) or normal (it's a circle).
1121 if (aVec1.IsParallel (aVec2, Precision::Angular())
1122 || aVec1.IsNormal (aVec2,Precision::Angular()))
1123 return Standard_False;
1125 gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1);
1126 aCone = aMkCone.Value();
1127 myCenterPoint = aCone.Apex();
1131 aType = aSurf->DynamicType();
1132 if (aType == STANDARD_TYPE(Geom_OffsetSurface) || anOffset > 0.01)
1135 aOffsetSurf = new Geom_OffsetSurface (aSurf, anOffset);
1136 aSurf = aOffsetSurf->Surface();
1137 BRepBuilderAPI_MakeFace aMkFace(aSurf, Precision::Confusion());
1139 if (!aMkFace.IsDone())
1140 return Standard_False;
1141 aConeAdaptor.Initialize (aMkFace.Face());
1143 aCone = aConeAdaptor.Cone();
1144 aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf);
1145 myCenterPoint = aConicalSurf->Apex();
1148 // A circle where the angle is drawn
1149 Handle(Geom_Curve) aCurve;
1150 Standard_Real aMidV = ( aMinV + aMaxV ) / 2.5;
1151 aCurve = aSurf->VIso (aMidV);
1152 aCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
1154 aCurve = aSurf->VIso(aMaxV);
1155 gp_Circ aCircVmax = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1156 aCurve = aSurf->VIso(aMinV);
1157 gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1159 if (aCircVmax.Radius() < aCircVmin.Radius())
1161 gp_Circ aTmpCirc = aCircVmax;
1162 aCircVmax = aCircVmin;
1163 aCircVmin = aTmpCirc;
1166 myFirstPoint = ElCLib::Value (0, aCircle);
1167 mySecondPoint = ElCLib::Value (M_PI, aCircle);
1168 return Standard_True;
1171 //=======================================================================
1172 //function : IsValidPoints
1174 //=======================================================================
1175 Standard_Boolean AIS_AngleDimension::IsValidPoints (const gp_Pnt& theFirstPoint,
1176 const gp_Pnt& theCenterPoint,
1177 const gp_Pnt& theSecondPoint) const
1179 return theFirstPoint.Distance (theCenterPoint) > Precision::Confusion()
1180 && theSecondPoint.Distance (theCenterPoint) > Precision::Confusion()
1181 && gp_Vec (theCenterPoint, theFirstPoint).Angle (
1182 gp_Vec (theCenterPoint, theSecondPoint)) > Precision::Angular();
1185 //=======================================================================
1186 //function : isArrowVisible
1187 //purpose : compares given and internal arrows types, returns true if the the type should be shown
1188 //=======================================================================
1189 Standard_Boolean AIS_AngleDimension::isArrowVisible(const AIS_TypeOfAngleArrowVisibility& theArrowType) const
1191 switch (theArrowType)
1194 return myArrowsVisibility == AIS_TOAV_Both;
1195 case AIS_TOAV_First:
1196 return myArrowsVisibility == AIS_TOAV_Both || myArrowsVisibility == AIS_TOAV_First;
1197 case AIS_TOAV_Second:
1198 return myArrowsVisibility == AIS_TOAV_Both || myArrowsVisibility == AIS_TOAV_Second;
1205 //=======================================================================
1206 //function : GetTextPosition
1208 //=======================================================================
1209 const gp_Pnt AIS_AngleDimension::GetTextPosition() const
1213 return gp::Origin();
1216 if (IsTextPositionCustom())
1218 return myFixedTextPosition;
1221 // Counts text position according to the dimension parameters
1222 gp_Pnt aTextPosition (gp::Origin());
1224 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1226 // Prepare label string and compute its geometrical width
1227 Standard_Real aLabelWidth;
1228 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1230 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1231 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1233 // Handle user-defined and automatic arrow placement
1234 Standard_Boolean isArrowsExternal = Standard_False;
1235 Standard_Integer aLabelPosition = LabelPosition_None;
1236 FitTextAlignment (aDimensionAspect->TextHorizontalPosition(),
1237 aLabelPosition, isArrowsExternal);
1239 // Get text position
1240 switch (aLabelPosition & LabelPosition_HMask)
1242 case LabelPosition_HCenter:
1244 aTextPosition = GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
1247 case LabelPosition_Left:
1249 gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1250 gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aFirstAttach);
1251 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1252 Standard_Real anOffset = isArrowsExternal
1253 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1255 gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * -anOffset;
1256 aTextPosition = aFirstAttach.Translated (anExtensionVec);
1259 case LabelPosition_Right:
1261 gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1262 gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aSecondAttach);
1263 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1264 Standard_Real anOffset = isArrowsExternal
1265 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1267 gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * anOffset;
1268 aTextPosition = aSecondAttach.Translated (anExtensionVec);
1273 return aTextPosition;
1276 //=======================================================================
1277 //function : SetTextPosition
1279 //=======================================================================
1280 void AIS_AngleDimension::SetTextPosition (const gp_Pnt& theTextPos)
1287 // The text position point for angle dimension should belong to the working plane.
1288 if (!GetPlane().Contains (theTextPos, Precision::Confusion()))
1290 Standard_ProgramError::Raise ("The text position point for angle dimension doesn't belong to the working plane.");
1293 myIsTextPositionFixed = Standard_True;
1294 myFixedTextPosition = theTextPos;
1297 //=======================================================================
1298 //function : AdjustParameters
1300 //=======================================================================
1301 void AIS_AngleDimension::AdjustParameters (const gp_Pnt& theTextPos,
1302 Standard_Real& theExtensionSize,
1303 Prs3d_DimensionTextHorizontalPosition& theAlignment,
1304 Standard_Real& theFlyout) const
1306 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1307 Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1309 // Build circle with radius that is equal to distance from text position to the center point.
1310 Standard_Real aRadius = gp_Vec (myCenterPoint, theTextPos).Magnitude();
1312 // Set attach points in positive direction of the flyout.
1313 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * aRadius);
1314 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * aRadius);
1316 gce_MakeCirc aConstructCircle (myCenterPoint, GetPlane(), aRadius);
1317 if (!aConstructCircle.IsDone())
1321 gp_Circ aCircle = aConstructCircle.Value();
1324 theExtensionSize = aDimensionAspect->ArrowAspect()->Length();
1325 theAlignment = Prs3d_DTHP_Center;
1327 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, aFirstAttach);
1328 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, aSecondAttach);
1329 if (aParamEnd < aParamBeg)
1331 Standard_Real aParam = aParamEnd;
1332 aParamEnd = aParamBeg;
1336 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1337 Standard_Real aTextPar = ElCLib::Parameter (aCircle , theTextPos);
1339 // Horizontal center
1340 if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1342 theFlyout = aRadius;
1348 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1350 if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1352 theFlyout = -aRadius;
1356 // Text on the extensions
1357 gp_Lin aFirstLine = gce_MakeLin (myCenterPoint, myFirstPoint);
1358 gp_Lin aSecondLine = gce_MakeLin (myCenterPoint, mySecondPoint);
1359 gp_Pnt aFirstTextProj = AIS::Nearest (aFirstLine, theTextPos);
1360 gp_Pnt aSecondTextProj = AIS::Nearest (aSecondLine, theTextPos);
1361 Standard_Real aFirstDist = aFirstTextProj.Distance (theTextPos);
1362 Standard_Real aSecondDist = aSecondTextProj.Distance (theTextPos);
1364 if (aFirstDist <= aSecondDist)
1366 aRadius = myCenterPoint.Distance (aFirstTextProj);
1367 Standard_Real aNewExtensionSize = aFirstDist - anArrowLength;
1368 theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1370 theAlignment = Prs3d_DTHP_Left;
1372 gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, myFirstPoint).Normalized().Scaled (aRadius);
1374 theFlyout = aFirstTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1375 ? -aRadius : aRadius;
1379 aRadius = myCenterPoint.Distance (aSecondTextProj);
1381 Standard_Real aNewExtensionSize = aSecondDist - anArrowLength;
1383 theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1385 theAlignment = Prs3d_DTHP_Right;
1387 gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, mySecondPoint).Normalized().Scaled (aRadius);
1389 theFlyout = aSecondTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1390 ? -aRadius : aRadius;
1394 //=======================================================================
1395 //function : FitTextAlignment
1397 //=======================================================================
1398 void AIS_AngleDimension::FitTextAlignment (const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos,
1399 Standard_Integer& theLabelPosition,
1400 Standard_Boolean& theIsArrowsExternal) const
1402 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1404 Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1406 // Prepare label string and compute its geometrical width
1407 Standard_Real aLabelWidth;
1408 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1410 // add margins to label width
1411 if (aDimensionAspect->IsText3d())
1413 aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
1416 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1417 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1419 // Handle user-defined and automatic arrow placement
1420 switch (aDimensionAspect->ArrowOrientation())
1422 case Prs3d_DAO_External: theIsArrowsExternal = true; break;
1423 case Prs3d_DAO_Internal: theIsArrowsExternal = false; break;
1426 gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1427 Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1429 // Add margin to ensure a small tail between text and arrow
1430 Standard_Real anArrowMargin = aDimensionAspect->IsText3d()
1431 ? aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN
1434 Standard_Real anArrowsWidth = (anArrowLength + anArrowMargin) * 2.0;
1436 theIsArrowsExternal = aDimensionWidth < aLabelWidth + anArrowsWidth;
1441 // Handle user-defined and automatic text placement
1442 switch (theHorizontalTextPos)
1444 case Prs3d_DTHP_Left : theLabelPosition |= LabelPosition_Left; break;
1445 case Prs3d_DTHP_Right : theLabelPosition |= LabelPosition_Right; break;
1446 case Prs3d_DTHP_Center: theLabelPosition |= LabelPosition_HCenter; break;
1447 case Prs3d_DTHP_Fit:
1449 gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1450 Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1451 Standard_Real anArrowsWidth = anArrowLength * 2.0;
1452 Standard_Real aContentWidth = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth;
1454 theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter;
1459 switch (aDimensionAspect->TextVerticalPosition())
1461 case Prs3d_DTVP_Above : theLabelPosition |= LabelPosition_Above; break;
1462 case Prs3d_DTVP_Below : theLabelPosition |= LabelPosition_Below; break;
1463 case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;