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 <PrsDim_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_ShadingAspect.hxx>
45 #include <PrsMgr_PresentationManager.hxx>
46 #include <Select3D_SensitiveGroup.hxx>
47 #include <Select3D_SensitiveSegment.hxx>
48 #include <SelectMgr_Selection.hxx>
49 #include <Standard_ProgramError.hxx>
50 #include <UnitsAPI.hxx>
51 #include <Geom_Line.hxx>
52 #include <Geom_Plane.hxx>
54 IMPLEMENT_STANDARD_RTTIEXT(PrsDim_AngleDimension, PrsDim_Dimension)
58 static const TCollection_ExtendedString THE_EMPTY_LABEL_STRING;
59 static const Standard_Real THE_EMPTY_LABEL_WIDTH = 0.0;
60 static const Standard_ExtCharacter THE_DEGREE_SYMBOL (0x00B0);
61 static const Standard_Real THE_3D_TEXT_MARGIN = 0.1;
63 //! Returns true if the given points lie on a same line.
64 static Standard_Boolean isSameLine (const gp_Pnt& theFirstPoint,
65 const gp_Pnt& theCenterPoint,
66 const gp_Pnt& theSecondPoint)
68 gp_Vec aVec1 (theFirstPoint, theCenterPoint);
69 gp_Vec aVec2 (theCenterPoint, theSecondPoint);
71 return aVec1.IsParallel (aVec2, Precision::Angular());
75 //=======================================================================
76 //function : Constructor
78 //=======================================================================
79 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Edge& theFirstEdge,
80 const TopoDS_Edge& theSecondEdge)
81 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
84 SetMeasuredGeometry (theFirstEdge, theSecondEdge);
87 //=======================================================================
88 //function : Constructor
90 //=======================================================================
91 PrsDim_AngleDimension::PrsDim_AngleDimension (const gp_Pnt& theFirstPoint,
92 const gp_Pnt& theSecondPoint,
93 const gp_Pnt& theThirdPoint)
94 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
97 SetMeasuredGeometry (theFirstPoint, theSecondPoint, theThirdPoint);
100 //=======================================================================
101 //function : Constructor
103 //=======================================================================
104 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Vertex& theFirstVertex,
105 const TopoDS_Vertex& theSecondVertex,
106 const TopoDS_Vertex& theThirdVertex)
107 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
110 SetMeasuredGeometry (theFirstVertex, theSecondVertex, theThirdVertex);
113 //=======================================================================
114 //function : Constructor
116 //=======================================================================
117 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Face& theCone)
118 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
121 SetMeasuredGeometry (theCone);
124 //=======================================================================
125 //function : Constructor
127 //=======================================================================
128 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Face& theFirstFace,
129 const TopoDS_Face& theSecondFace)
130 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
133 SetMeasuredGeometry (theFirstFace, theSecondFace);
136 //=======================================================================
137 //function : Constructor
139 //=======================================================================
140 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Face& theFirstFace,
141 const TopoDS_Face& theSecondFace,
142 const gp_Pnt& thePoint)
143 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
146 SetMeasuredGeometry (theFirstFace, theSecondFace, thePoint);
149 //=======================================================================
150 //function : SetMeasuredGeometry
152 //=======================================================================
153 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge,
154 const TopoDS_Edge& theSecondEdge)
156 gp_Pln aComputedPlane;
158 myFirstShape = theFirstEdge;
159 mySecondShape = theSecondEdge;
160 myThirdShape = TopoDS_Shape();
161 myGeometryType = GeometryType_Edges;
162 myIsGeometryValid = InitTwoEdgesAngle (aComputedPlane);
164 if (myIsGeometryValid && !myIsPlaneCustom)
166 myPlane = aComputedPlane;
172 //=======================================================================
173 //function : SetMeasuredGeometry
175 //=======================================================================
176 void PrsDim_AngleDimension::SetMeasuredGeometry (const gp_Pnt& theFirstPoint,
177 const gp_Pnt& theSecondPoint,
178 const gp_Pnt& theThirdPoint)
180 myFirstPoint = theFirstPoint;
181 myCenterPoint = theSecondPoint;
182 mySecondPoint = theThirdPoint;
183 myFirstShape = BRepLib_MakeVertex (myFirstPoint);
184 mySecondShape = BRepLib_MakeVertex (myCenterPoint);
185 myThirdShape = BRepLib_MakeVertex (mySecondPoint);
186 myGeometryType = GeometryType_Points;
187 myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
189 Standard_Boolean anIsSameLine = isSameLine (myFirstPoint, myCenterPoint, mySecondPoint);
190 if (myIsGeometryValid && !myIsPlaneCustom && !anIsSameLine)
198 //=======================================================================
199 //function : SetMeasuredGeometry
201 //=======================================================================
202 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Vertex& theFirstVertex,
203 const TopoDS_Vertex& theSecondVertex,
204 const TopoDS_Vertex& theThirdVertex)
206 myFirstShape = theFirstVertex;
207 mySecondShape = theSecondVertex;
208 myThirdShape = theThirdVertex;
209 myFirstPoint = BRep_Tool::Pnt (theFirstVertex);
210 myCenterPoint = BRep_Tool::Pnt (theSecondVertex);
211 mySecondPoint = BRep_Tool::Pnt (theThirdVertex);
212 myGeometryType = GeometryType_Points;
213 myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
215 Standard_Boolean anIsSameLine = isSameLine (myFirstPoint, myCenterPoint, mySecondPoint);
216 if (myIsGeometryValid && !myIsPlaneCustom && !anIsSameLine)
224 //=======================================================================
225 //function : SetMeasuredGeometry
227 //=======================================================================
228 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theCone)
230 myFirstShape = theCone;
231 mySecondShape = TopoDS_Shape();
232 myThirdShape = TopoDS_Shape();
233 myGeometryType = GeometryType_Face;
234 myIsGeometryValid = InitConeAngle();
236 if (myIsGeometryValid && !myIsPlaneCustom)
244 //=======================================================================
245 //function : SetMeasuredGeometry
247 //=======================================================================
248 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
249 const TopoDS_Face& theSecondFace)
251 myFirstShape = theFirstFace;
252 mySecondShape = theSecondFace;
253 myThirdShape = TopoDS_Shape();
254 myGeometryType = GeometryType_Faces;
255 myIsGeometryValid = InitTwoFacesAngle();
257 if (myIsGeometryValid && !myIsPlaneCustom)
265 //=======================================================================
266 //function : SetMeasuredGeometry
268 //=======================================================================
269 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
270 const TopoDS_Face& theSecondFace,
271 const gp_Pnt& thePoint)
273 myFirstShape = theFirstFace;
274 mySecondShape = theSecondFace;
275 myThirdShape = TopoDS_Shape();
276 myGeometryType = GeometryType_Faces;
277 myIsGeometryValid = InitTwoFacesAngle (thePoint);
279 if (myIsGeometryValid && !myIsPlaneCustom)
287 //=======================================================================
290 //=======================================================================
291 void PrsDim_AngleDimension::Init()
293 SetType (PrsDim_TypeOfAngle_Interior);
294 SetArrowsVisibility (PrsDim_TypeOfAngleArrowVisibility_Both);
295 SetSpecialSymbol (THE_DEGREE_SYMBOL);
296 SetDisplaySpecialSymbol (PrsDim_DisplaySpecialSymbol_After);
300 //=======================================================================
301 //function: GetCenterOnArc
303 //=======================================================================
304 gp_Pnt PrsDim_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach,
305 const gp_Pnt& theSecondAttach,
306 const gp_Pnt& theCenter) const
308 // construct plane where the circle and the arc are located
309 gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
310 if (!aConstructPlane.IsDone())
315 gp_Pln aPlane = aConstructPlane.Value();
316 // to have an exterior angle presentation, a plane for further constructed circle should be reversed
317 if (myType == PrsDim_TypeOfAngle_Exterior)
319 gp_Ax1 anAxis = aPlane.Axis();
320 gp_Dir aDir = anAxis.Direction();
322 aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
325 Standard_Real aRadius = theFirstAttach.Distance (theCenter);
327 // construct circle forming the arc
328 gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
329 if (!aConstructCircle.IsDone())
334 gp_Circ aCircle = aConstructCircle.Value();
336 // compute angle parameters of arc end-points on circle
337 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
338 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
339 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
341 return ElCLib::Value ((aParamBeg + aParamEnd) * 0.5, aCircle);
344 //=======================================================================
345 //function : GetNormalForMinAngle
347 //=======================================================================
348 gp_Dir PrsDim_AngleDimension::GetNormalForMinAngle() const
350 const gp_Dir& aNormal = myPlane.Axis().Direction();
351 gp_Dir aFirst (gp_Vec (myCenterPoint, myFirstPoint) );
352 gp_Dir aSecond (gp_Vec (myCenterPoint, mySecondPoint) );
354 return aFirst.AngleWithRef (aSecond, aNormal) < 0.0
359 //=======================================================================
361 //purpose : draws the arc between two attach points
362 //=======================================================================
363 void PrsDim_AngleDimension::DrawArc (const Handle(Prs3d_Presentation)& thePresentation,
364 const gp_Pnt& theFirstAttach,
365 const gp_Pnt& theSecondAttach,
366 const gp_Pnt& theCenter,
367 const Standard_Real theRadius,
368 const Standard_Integer theMode)
370 gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle());
372 // to have an exterior angle presentation, a plane for further constructed circle should be reversed
373 if (myType == PrsDim_TypeOfAngle_Exterior)
375 gp_Ax1 anAxis = aPlane.Axis();
376 gp_Dir aDir = anAxis.Direction();
378 aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
381 // construct circle forming the arc
382 gce_MakeCirc aConstructCircle (theCenter, aPlane, theRadius);
383 if (!aConstructCircle.IsDone())
388 gp_Circ aCircle = aConstructCircle.Value();
391 GC_MakeArcOfCircle aConstructArc (aCircle, theFirstAttach, theSecondAttach, Standard_True);
392 if (!aConstructArc.IsDone())
397 // generate points with specified deflection
398 const Handle(Geom_TrimmedCurve)& anArcCurve = aConstructArc.Value();
400 GeomAdaptor_Curve anArcAdaptor (anArcCurve, anArcCurve->FirstParameter(), anArcCurve->LastParameter());
402 // compute number of discretization elements in old-fanshioned way
403 gp_Vec aCenterToFirstVec (theCenter, theFirstAttach);
404 gp_Vec aCenterToSecondVec (theCenter, theSecondAttach);
405 Standard_Real anAngle = aCenterToFirstVec.Angle (aCenterToSecondVec);
406 if (myType == PrsDim_TypeOfAngle_Exterior)
407 anAngle = 2.0 * M_PI - anAngle;
408 // it sets 50 points on PI, and a part of points if angle is less
409 const Standard_Integer aNbPoints = Max (4, Standard_Integer (50.0 * anAngle / M_PI));
411 GCPnts_UniformAbscissa aMakePnts (anArcAdaptor, aNbPoints);
412 if (!aMakePnts.IsDone())
417 // init data arrays for graphical and selection primitives
418 Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aNbPoints);
420 SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
422 // load data into arrays
423 for (Standard_Integer aPntIt = 1; aPntIt <= aMakePnts.NbPoints(); ++aPntIt)
425 gp_Pnt aPnt = anArcAdaptor.Value (aMakePnts.Parameter (aPntIt));
427 aPrimSegments->AddVertex (aPnt);
429 aSensitiveCurve.Append (aPnt);
432 // add display presentation
433 if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
435 thePresentation->CurrentGroup()->SetStencilTestOptions (Standard_True);
437 Handle(Graphic3d_AspectLine3d) aDimensionLineStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
438 thePresentation->CurrentGroup()->SetPrimitivesAspect (aDimensionLineStyle);
439 thePresentation->CurrentGroup()->AddPrimitiveArray (aPrimSegments);
440 if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
442 thePresentation->CurrentGroup()->SetStencilTestOptions (Standard_False);
446 //=======================================================================
447 //function: DrawArcWithText
449 //=======================================================================
450 void PrsDim_AngleDimension::DrawArcWithText (const Handle(Prs3d_Presentation)& thePresentation,
451 const gp_Pnt& theFirstAttach,
452 const gp_Pnt& theSecondAttach,
453 const gp_Pnt& theCenter,
454 const TCollection_ExtendedString& theText,
455 const Standard_Real theTextWidth,
456 const Standard_Integer theMode,
457 const Standard_Integer theLabelPosition)
459 gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle());
461 Standard_Real aRadius = theFirstAttach.Distance (myCenterPoint);
463 // construct circle forming the arc
464 gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
465 if (!aConstructCircle.IsDone())
470 gp_Circ aCircle = aConstructCircle.Value();
472 // compute angle parameters of arc end-points on circle
473 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
474 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
475 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
477 // middle point of arc parameter on circle
478 Standard_Real aParamMid = (aParamBeg + aParamEnd) * 0.5;
480 // add text graphical primitives
481 if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
483 gp_Pnt aTextPos = ElCLib::Value (aParamMid, aCircle);
484 gp_Dir aTextDir = gce_MakeDir (theFirstAttach, theSecondAttach);
487 drawText (thePresentation,
494 if (theMode != ComputeMode_All && theMode != ComputeMode_Line)
499 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
501 Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
502 && aDimensionAspect->IsText3d();
506 // compute gap for label as parameteric size of sector on circle segment
507 Standard_Real aSectorOfText = theTextWidth / aRadius;
508 Standard_Real aTextBegin = aParamMid - aSectorOfText * 0.5;
509 Standard_Real aTextEnd = aParamMid + aSectorOfText * 0.5;
510 gp_Pnt aTextPntBeg = ElCLib::Value (aTextBegin, aCircle);
511 gp_Pnt aTextPntEnd = ElCLib::Value (aTextEnd, aCircle);
514 if (aTextBegin > aParamBeg)
516 DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode);
518 if (aTextEnd < aParamEnd)
520 DrawArc (thePresentation, aTextPntEnd, theSecondAttach, theCenter, aRadius, theMode);
525 DrawArc (thePresentation, theFirstAttach, theSecondAttach, theCenter, aRadius, theMode);
529 //=======================================================================
530 //function : CheckPlane
532 //=======================================================================
533 Standard_Boolean PrsDim_AngleDimension::CheckPlane (const gp_Pln& thePlane)const
535 if (!thePlane.Contains (myFirstPoint, Precision::Confusion()) &&
536 !thePlane.Contains (mySecondPoint, Precision::Confusion()) &&
537 !thePlane.Contains (myCenterPoint, Precision::Confusion()))
539 return Standard_False;
542 return Standard_True;
545 //=======================================================================
546 //function : ComputePlane
548 //=======================================================================
549 void PrsDim_AngleDimension::ComputePlane()
551 if (!myIsGeometryValid)
556 // Compute working plane so that Y axis is codirectional
557 // with Y axis of text coordinate system (necessary for text alignment)
558 gp_Vec aFirstVec = gp_Vec (myCenterPoint, myFirstPoint);
559 gp_Vec aSecondVec = gp_Vec (myCenterPoint, mySecondPoint);
560 gp_Vec aDirectionN = aSecondVec ^ aFirstVec;
561 gp_Vec aDirectionY = aFirstVec + aSecondVec;
562 gp_Vec aDirectionX = aDirectionY ^ aDirectionN;
564 myPlane = gp_Pln (gp_Ax3 (myCenterPoint, gp_Dir (aDirectionN), gp_Dir (aDirectionX)));
567 //=======================================================================
568 //function : GetModelUnits
570 //=======================================================================
571 const TCollection_AsciiString& PrsDim_AngleDimension::GetModelUnits() const
573 return myDrawer->DimAngleModelUnits();
576 //=======================================================================
577 //function : GetDisplayUnits
579 //=======================================================================
580 const TCollection_AsciiString& PrsDim_AngleDimension::GetDisplayUnits() const
582 return myDrawer->DimAngleDisplayUnits();
585 //=======================================================================
586 //function : SetModelUnits
588 //=======================================================================
589 void PrsDim_AngleDimension::SetModelUnits (const TCollection_AsciiString& theUnits)
591 myDrawer->SetDimAngleModelUnits (theUnits);
594 //=======================================================================
595 //function : SetDisplayUnits
597 //=======================================================================
598 void PrsDim_AngleDimension::SetDisplayUnits (const TCollection_AsciiString& theUnits)
600 myDrawer->SetDimAngleDisplayUnits (theUnits);
603 //=======================================================================
604 //function : ComputeValue
606 //=======================================================================
607 Standard_Real PrsDim_AngleDimension::ComputeValue() const
614 gp_Vec aVec1 (myCenterPoint, myFirstPoint);
615 gp_Vec aVec2 (myCenterPoint, mySecondPoint);
617 Standard_Real anAngle = aVec1.AngleWithRef (aVec2, GetNormalForMinAngle());
619 return anAngle > 0.0 ? anAngle : (2.0 * M_PI + anAngle);
622 //=======================================================================
624 //purpose : Having three gp_Pnt points compute presentation
625 //=======================================================================
626 void PrsDim_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager)& ,
627 const Handle(Prs3d_Presentation)& thePresentation,
628 const Standard_Integer theMode)
630 mySelectionGeom.Clear (theMode);
637 // Parameters for presentation
638 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
640 thePresentation->CurrentGroup()->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
642 Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
644 // prepare label string and compute its geometrical width
645 Standard_Real aLabelWidth;
646 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
648 // add margins to label width
649 if (aDimensionAspect->IsText3d())
651 aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
654 // Get parameters from aspect or adjust it according with custom text position
655 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
656 Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition();
658 if (IsTextPositionCustom())
660 AdjustParameters (myFixedTextPosition,anExtensionSize, aHorisontalTextPos, myFlyout);
663 // Handle user-defined and automatic arrow placement
664 Standard_Boolean isArrowsExternal = Standard_False;
665 Standard_Integer aLabelPosition = LabelPosition_None;
667 FitTextAlignment (aHorisontalTextPos, aLabelPosition, isArrowsExternal);
669 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
670 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
672 //Arrows positions and directions
673 gp_Vec aWorkingPlaneDir (GetNormalForMinAngle());
675 gp_Dir aFirstExtensionDir = aWorkingPlaneDir.Reversed() ^ gp_Vec (myCenterPoint, aFirstAttach);
676 gp_Dir aSecondExtensionDir = aWorkingPlaneDir ^ gp_Vec (myCenterPoint, aSecondAttach);
678 gp_Vec aFirstArrowVec = gp_Vec (aFirstExtensionDir) * anArrowLength;
679 gp_Vec aSecondArrowVec = gp_Vec (aSecondExtensionDir) * anArrowLength;
681 if (isArrowsExternal)
683 aFirstArrowVec.Reverse();
684 aSecondArrowVec.Reverse();
687 gp_Pnt aFirstArrowBegin (0.0, 0.0, 0.0);
688 gp_Pnt aFirstArrowEnd (0.0, 0.0, 0.0);
689 gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0);
690 gp_Pnt aSecondArrowEnd (0.0, 0.0, 0.0);
692 aFirstArrowBegin = aFirstAttach;
693 aSecondArrowBegin = aSecondAttach;
694 aFirstArrowEnd = aFirstAttach.Translated (-aFirstArrowVec);
695 aSecondArrowEnd = aSecondAttach.Translated (-aSecondArrowVec);
697 // Group1: stenciling text and the angle dimension arc
698 thePresentation->NewGroup();
700 Standard_Integer aHPosition = aLabelPosition & LabelPosition_HMask;
705 case LabelPosition_HCenter :
707 Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
708 && aDimensionAspect->IsText3d();
712 DrawArcWithText (thePresentation,
723 // compute text primitives
724 if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
726 gp_Vec aDimensionDir (aFirstAttach, aSecondAttach);
727 gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition
728 : GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
729 gp_Dir aTextDir = aDimensionDir;
731 drawText (thePresentation,
738 if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
740 DrawArc (thePresentation,
741 (isArrowsExternal || !isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First)) ? aFirstAttach : aFirstArrowEnd,
742 (isArrowsExternal || !isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second)) ? aSecondAttach : aSecondArrowEnd,
750 case LabelPosition_Left :
752 DrawExtension (thePresentation,
754 (isArrowsExternal && isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First)) ? aFirstArrowEnd : aFirstAttach,
763 case LabelPosition_Right :
765 DrawExtension (thePresentation,
767 (isArrowsExternal && isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second)) ? aSecondArrowEnd : aSecondAttach,
777 // dimension arc without text
778 if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && aHPosition != LabelPosition_HCenter)
780 thePresentation->NewGroup();
782 DrawArc (thePresentation,
783 (isArrowsExternal || !isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First)) ? aFirstAttach : aFirstArrowEnd,
784 (isArrowsExternal || !isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second)) ? aSecondAttach : aSecondArrowEnd,
790 // arrows and arrow extensions
791 if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
793 thePresentation->NewGroup();
795 if (isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First))
796 DrawArrow (thePresentation, aFirstArrowBegin, gp_Dir (aFirstArrowVec));
797 if (isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second))
798 DrawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec));
801 if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && isArrowsExternal)
803 thePresentation->NewGroup();
805 if (aHPosition != LabelPosition_Left && isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First))
807 DrawExtension (thePresentation,
808 aDimensionAspect->ArrowTailSize(),
811 THE_EMPTY_LABEL_STRING,
812 THE_EMPTY_LABEL_WIDTH,
817 if (aHPosition != LabelPosition_Right && isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second))
819 DrawExtension (thePresentation,
820 aDimensionAspect->ArrowTailSize(),
823 THE_EMPTY_LABEL_STRING,
824 THE_EMPTY_LABEL_WIDTH,
831 if (theMode == ComputeMode_All)
833 thePresentation->NewGroup();
835 Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (4);
836 aPrimSegments->AddVertex (myCenterPoint);
837 aPrimSegments->AddVertex (aFirstAttach);
838 aPrimSegments->AddVertex (myCenterPoint);
839 aPrimSegments->AddVertex (aSecondAttach);
841 Handle(Graphic3d_AspectLine3d) aFlyoutStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
842 thePresentation->CurrentGroup()->SetPrimitivesAspect (aFlyoutStyle);
843 thePresentation->CurrentGroup()->AddPrimitiveArray (aPrimSegments);
846 mySelectionGeom.IsComputed = Standard_True;
849 //=======================================================================
850 //function : ComputeFlyoutSelection
851 //purpose : computes selection for flyouts
852 //=======================================================================
853 void PrsDim_AngleDimension::ComputeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection,
854 const Handle(SelectMgr_EntityOwner)& theOwner)
856 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
857 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
859 Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner);
860 aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aFirstAttach));
861 aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aSecondAttach));
863 theSelection->Add (aSensitiveEntity);
866 //=======================================================================
867 //function : InitTwoEdgesAngle
869 //=======================================================================
870 Standard_Boolean PrsDim_AngleDimension::InitTwoEdgesAngle (gp_Pln& theComputedPlane)
872 TopoDS_Edge aFirstEdge = TopoDS::Edge (myFirstShape);
873 TopoDS_Edge aSecondEdge = TopoDS::Edge (mySecondShape);
875 BRepAdaptor_Curve aMakeFirstLine (aFirstEdge);
876 BRepAdaptor_Curve aMakeSecondLine (aSecondEdge);
878 if (aMakeFirstLine.GetType() != GeomAbs_Line || aMakeSecondLine.GetType() != GeomAbs_Line)
880 return Standard_False;
883 Handle(Geom_Line) aFirstLine = new Geom_Line (aMakeFirstLine.Line());
884 Handle(Geom_Line) aSecondLine = new Geom_Line (aMakeSecondLine.Line());
886 gp_Lin aFirstLin = aFirstLine->Lin();
887 gp_Lin aSecondLin = aSecondLine->Lin();
889 Standard_Boolean isParallelLines = aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular());
891 theComputedPlane = isParallelLines ? gp_Pln(gp::XOY())
892 : gp_Pln (aSecondLin.Location(), gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction()));
894 // Compute geometry for this plane and edges
895 Standard_Boolean isInfinite1,isInfinite2;
896 gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2;
897 Handle(Geom_Curve) aFirstCurve = aFirstLine, aSecondCurve = aSecondLine;
898 if (!PrsDim::ComputeGeometry (aFirstEdge, aSecondEdge,
899 aFirstCurve, aSecondCurve,
900 aFirstPoint1, aLastPoint1,
901 aFirstPoint2, aLastPoint2,
902 isInfinite1, isInfinite2))
904 return Standard_False;
907 Standard_Boolean isSameLines = aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular())
908 && aFirstLin.Location().IsEqual (aSecondLin.Location(),Precision::Confusion());
910 // It can be the same gp_Lin geometry but the different begin and end parameters
911 Standard_Boolean isSameEdges =
912 (aFirstPoint1.IsEqual (aFirstPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aLastPoint2, Precision::Confusion()))
913 || (aFirstPoint1.IsEqual (aLastPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aFirstPoint2, Precision::Confusion()));
917 // Zero angle, it could not handle this geometry
918 if (isSameLines && isSameEdges)
920 return Standard_False;
923 // Handle the case of Pi angle
924 const Standard_Real aParam11 = ElCLib::Parameter (aFirstLin, aFirstPoint1);
925 const Standard_Real aParam12 = ElCLib::Parameter (aFirstLin, aLastPoint1);
926 const Standard_Real aParam21 = ElCLib::Parameter (aFirstLin, aFirstPoint2);
927 const Standard_Real aParam22 = ElCLib::Parameter (aFirstLin, aLastPoint2);
928 myCenterPoint = ElCLib::Value ( (Min (aParam11, aParam12) + Max (aParam21, aParam22)) * 0.5, aFirstLin);
929 myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
930 mySecondPoint = myCenterPoint.XYZ() + (aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular())
931 ? aFirstLin.Direction().Reversed().XYZ() * Abs (GetFlyout())
932 : aSecondLin.Direction().XYZ() * Abs (GetFlyout()));
937 gp_Lin2d aFirstLin2d = ProjLib::Project (theComputedPlane, aFirstLin);
938 gp_Lin2d aSecondLin2d = ProjLib::Project (theComputedPlane, aSecondLin);
940 IntAna2d_AnaIntersection anInt2d (aFirstLin2d, aSecondLin2d);
941 gp_Pnt2d anIntersectPoint;
942 if (!anInt2d.IsDone() || anInt2d.IsEmpty())
944 return Standard_False;
947 anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value());
948 myCenterPoint = ElCLib::To3d (theComputedPlane.Position().Ax2(), anIntersectPoint);
950 if (isInfinite1 || isInfinite2)
952 myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
953 mySecondPoint = myCenterPoint.Translated (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout()));
955 return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
959 // | <- dimension should be here
961 myFirstPoint = myCenterPoint.Distance (aFirstPoint1) > myCenterPoint.Distance (aLastPoint1)
965 mySecondPoint = myCenterPoint.Distance (aFirstPoint2) > myCenterPoint.Distance (aLastPoint2)
970 return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
973 //=======================================================================
974 //function : InitTwoFacesAngle
975 //purpose : initialization of angle dimension between two faces
976 //=======================================================================
977 Standard_Boolean PrsDim_AngleDimension::InitTwoFacesAngle()
979 TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
980 TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
982 gp_Dir aFirstDir, aSecondDir;
983 gp_Pln aFirstPln, aSecondPln;
984 Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
985 PrsDim_KindOfSurface aFirstSurfType, aSecondSurfType;
986 Standard_Real aFirstOffset, aSecondOffset;
988 PrsDim::GetPlaneFromFace (aFirstFace, aFirstPln,
989 aFirstBasisSurf,aFirstSurfType,aFirstOffset);
991 PrsDim::GetPlaneFromFace (aSecondFace, aSecondPln,
992 aSecondBasisSurf, aSecondSurfType, aSecondOffset);
994 if (aFirstSurfType == PrsDim_KOS_Plane && aSecondSurfType == PrsDim_KOS_Plane)
997 Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
998 Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
999 return PrsDim::InitAngleBetweenPlanarFaces (aFirstFace, aSecondFace,
1000 myCenterPoint, myFirstPoint, mySecondPoint)
1001 && IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
1005 // Curvilinear faces angle
1006 return PrsDim::InitAngleBetweenCurvilinearFaces (aFirstFace, aSecondFace,
1007 aFirstSurfType, aSecondSurfType,
1008 myCenterPoint, myFirstPoint, mySecondPoint)
1009 && IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
1013 //=======================================================================
1014 //function : InitTwoFacesAngle
1015 //purpose : initialization of angle dimension between two faces
1016 //=======================================================================
1017 Standard_Boolean PrsDim_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 PrsDim_KindOfSurface aFirstSurfType, aSecondSurfType;
1026 Standard_Real aFirstOffset, aSecondOffset;
1028 PrsDim::GetPlaneFromFace (aFirstFace, aFirstPln,
1029 aFirstBasisSurf,aFirstSurfType,aFirstOffset);
1031 PrsDim::GetPlaneFromFace (aSecondFace, aSecondPln,
1032 aSecondBasisSurf, aSecondSurfType, aSecondOffset);
1034 myFirstPoint = thePointOnFirstFace;
1035 if (aFirstSurfType == PrsDim_KOS_Plane && aSecondSurfType == PrsDim_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 PrsDim::InitAngleBetweenPlanarFaces (aFirstFace, aSecondFace,
1041 myCenterPoint, myFirstPoint, mySecondPoint,
1043 && IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
1047 // Curvilinear faces angle
1048 return PrsDim::InitAngleBetweenCurvilinearFaces (aFirstFace, aSecondFace,
1049 aFirstSurfType, aSecondSurfType,
1050 myCenterPoint, myFirstPoint, mySecondPoint,
1052 && IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
1056 //=======================================================================
1057 //function : InitConeAngle
1058 //purpose : initialization of the cone angle
1059 //=======================================================================
1060 Standard_Boolean PrsDim_AngleDimension::InitConeAngle()
1062 if (myFirstShape.IsNull())
1064 return Standard_False;
1067 TopoDS_Face aConeShape = TopoDS::Face (myFirstShape);
1071 // A surface from the Face
1072 Handle(Geom_Surface) aSurf;
1073 Handle(Geom_OffsetSurface) aOffsetSurf;
1074 Handle(Geom_ConicalSurface) aConicalSurf;
1075 Handle(Geom_SurfaceOfRevolution) aRevSurf;
1076 Handle(Geom_Line) aLine;
1077 BRepAdaptor_Surface aConeAdaptor (aConeShape);
1079 PrsDim_KindOfSurface aSurfType;
1080 Standard_Real anOffset = 0.;
1081 Handle(Standard_Type) aType;
1083 const Standard_Real aMaxV = aConeAdaptor.FirstVParameter();
1084 const Standard_Real aMinV = aConeAdaptor.LastVParameter();
1085 PrsDim::GetPlaneFromFace (aConeShape, aPln, aSurf, aSurfType, anOffset);
1086 if (aSurfType == PrsDim_KOS_Revolution)
1088 // Surface of revolution
1089 aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aSurf);
1090 gp_Lin aLin (aRevSurf->Axis());
1091 Handle(Geom_Curve) aBasisCurve = aRevSurf->BasisCurve();
1092 //Must be a part of line (basis curve should be linear)
1093 if (aBasisCurve ->DynamicType() != STANDARD_TYPE(Geom_Line))
1094 return Standard_False;
1096 gp_Pnt aFirst1 = aConeAdaptor.Value (0., aMinV);
1097 gp_Pnt aLast1 = aConeAdaptor.Value (0., aMaxV);
1098 gp_Vec aVec1 (aFirst1, aLast1);
1100 //Projection <aFirst> on <aLin>
1101 gp_Pnt aFirst2 = ElCLib::Value (ElCLib::Parameter (aLin, aFirst1), aLin);
1102 // Projection <aLast> on <aLin>
1103 gp_Pnt aLast2 = ElCLib::Value (ElCLib::Parameter (aLin, aLast1), aLin);
1105 gp_Vec aVec2 (aFirst2, aLast2);
1107 // Check if two parts of revolution are parallel (it's a cylinder) or normal (it's a circle).
1108 if (aVec1.IsParallel (aVec2, Precision::Angular())
1109 || aVec1.IsNormal (aVec2,Precision::Angular()))
1110 return Standard_False;
1112 gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1);
1113 aCone = aMkCone.Value();
1114 myCenterPoint = aCone.Apex();
1118 aType = aSurf->DynamicType();
1119 if (aType == STANDARD_TYPE(Geom_OffsetSurface) || anOffset > 0.01)
1122 aOffsetSurf = new Geom_OffsetSurface (aSurf, anOffset);
1123 aSurf = aOffsetSurf->Surface();
1124 BRepBuilderAPI_MakeFace aMkFace(aSurf, Precision::Confusion());
1126 if (!aMkFace.IsDone())
1127 return Standard_False;
1128 aConeAdaptor.Initialize (aMkFace.Face());
1130 aCone = aConeAdaptor.Cone();
1131 aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf);
1132 myCenterPoint = aConicalSurf->Apex();
1135 // A circle where the angle is drawn
1136 Handle(Geom_Curve) aCurve;
1137 Standard_Real aMidV = ( aMinV + aMaxV ) / 2.5;
1138 aCurve = aSurf->VIso (aMidV);
1139 aCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
1141 aCurve = aSurf->VIso(aMaxV);
1142 gp_Circ aCircVmax = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1143 aCurve = aSurf->VIso(aMinV);
1144 gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1146 if (aCircVmax.Radius() < aCircVmin.Radius())
1148 gp_Circ aTmpCirc = aCircVmax;
1149 aCircVmax = aCircVmin;
1150 aCircVmin = aTmpCirc;
1153 myFirstPoint = ElCLib::Value (0, aCircle);
1154 mySecondPoint = ElCLib::Value (M_PI, aCircle);
1155 return Standard_True;
1158 //=======================================================================
1159 //function : IsValidPoints
1161 //=======================================================================
1162 Standard_Boolean PrsDim_AngleDimension::IsValidPoints (const gp_Pnt& theFirstPoint,
1163 const gp_Pnt& theCenterPoint,
1164 const gp_Pnt& theSecondPoint) const
1166 return theFirstPoint.Distance (theCenterPoint) > Precision::Confusion()
1167 && theSecondPoint.Distance (theCenterPoint) > Precision::Confusion()
1168 && gp_Vec (theCenterPoint, theFirstPoint).Angle (
1169 gp_Vec (theCenterPoint, theSecondPoint)) > Precision::Angular();
1172 //=======================================================================
1173 //function : isArrowVisible
1174 //purpose : compares given and internal arrows types, returns true if the the type should be shown
1175 //=======================================================================
1176 Standard_Boolean PrsDim_AngleDimension::isArrowVisible(const PrsDim_TypeOfAngleArrowVisibility theArrowType) const
1178 switch (theArrowType)
1180 case PrsDim_TypeOfAngleArrowVisibility_Both:
1181 return myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_Both;
1182 case PrsDim_TypeOfAngleArrowVisibility_First:
1183 return myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_Both || myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_First;
1184 case PrsDim_TypeOfAngleArrowVisibility_Second:
1185 return myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_Both || myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_Second;
1186 case PrsDim_TypeOfAngleArrowVisibility_None:
1192 //=======================================================================
1193 //function : GetTextPosition
1195 //=======================================================================
1196 gp_Pnt PrsDim_AngleDimension::GetTextPosition() const
1200 return gp::Origin();
1203 if (IsTextPositionCustom())
1205 return myFixedTextPosition;
1208 // Counts text position according to the dimension parameters
1209 gp_Pnt aTextPosition (gp::Origin());
1211 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1213 // Prepare label string and compute its geometrical width
1214 Standard_Real aLabelWidth;
1215 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1217 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1218 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1220 // Handle user-defined and automatic arrow placement
1221 Standard_Boolean isArrowsExternal = Standard_False;
1222 Standard_Integer aLabelPosition = LabelPosition_None;
1223 FitTextAlignment (aDimensionAspect->TextHorizontalPosition(),
1224 aLabelPosition, isArrowsExternal);
1226 // Get text position
1227 switch (aLabelPosition & LabelPosition_HMask)
1229 case LabelPosition_HCenter:
1231 aTextPosition = GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
1234 case LabelPosition_Left:
1236 gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1237 gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aFirstAttach);
1238 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1239 Standard_Real anOffset = isArrowsExternal
1240 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1242 gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * -anOffset;
1243 aTextPosition = aFirstAttach.Translated (anExtensionVec);
1246 case LabelPosition_Right:
1248 gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1249 gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aSecondAttach);
1250 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1251 Standard_Real anOffset = isArrowsExternal
1252 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1254 gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * anOffset;
1255 aTextPosition = aSecondAttach.Translated (anExtensionVec);
1260 return aTextPosition;
1263 //=======================================================================
1264 //function : SetTextPosition
1266 //=======================================================================
1267 void PrsDim_AngleDimension::SetTextPosition (const gp_Pnt& theTextPos)
1274 // The text position point for angle dimension should belong to the working plane.
1275 if (!GetPlane().Contains (theTextPos, Precision::Confusion()))
1277 throw Standard_ProgramError("The text position point for angle dimension doesn't belong to the working plane.");
1280 myIsTextPositionFixed = Standard_True;
1281 myFixedTextPosition = theTextPos;
1284 //=======================================================================
1285 //function : AdjustParameters
1287 //=======================================================================
1288 void PrsDim_AngleDimension::AdjustParameters (const gp_Pnt& theTextPos,
1289 Standard_Real& theExtensionSize,
1290 Prs3d_DimensionTextHorizontalPosition& theAlignment,
1291 Standard_Real& theFlyout) const
1293 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1294 Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1296 // Build circle with radius that is equal to distance from text position to the center point.
1297 Standard_Real aRadius = gp_Vec (myCenterPoint, theTextPos).Magnitude();
1299 // Set attach points in positive direction of the flyout.
1300 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * aRadius);
1301 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * aRadius);
1303 gce_MakeCirc aConstructCircle (myCenterPoint, GetPlane(), aRadius);
1304 if (!aConstructCircle.IsDone())
1308 gp_Circ aCircle = aConstructCircle.Value();
1311 theExtensionSize = aDimensionAspect->ArrowAspect()->Length();
1312 theAlignment = Prs3d_DTHP_Center;
1314 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, aFirstAttach);
1315 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, aSecondAttach);
1316 if (aParamEnd < aParamBeg)
1318 Standard_Real aParam = aParamEnd;
1319 aParamEnd = aParamBeg;
1323 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1324 Standard_Real aTextPar = ElCLib::Parameter (aCircle , theTextPos);
1326 // Horizontal center
1327 if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1329 theFlyout = aRadius;
1335 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1337 if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1339 theFlyout = -aRadius;
1343 // Text on the extensions
1344 gp_Lin aFirstLine = gce_MakeLin (myCenterPoint, myFirstPoint);
1345 gp_Lin aSecondLine = gce_MakeLin (myCenterPoint, mySecondPoint);
1346 gp_Pnt aFirstTextProj = PrsDim::Nearest (aFirstLine, theTextPos);
1347 gp_Pnt aSecondTextProj = PrsDim::Nearest (aSecondLine, theTextPos);
1348 Standard_Real aFirstDist = aFirstTextProj.Distance (theTextPos);
1349 Standard_Real aSecondDist = aSecondTextProj.Distance (theTextPos);
1351 if (aFirstDist <= aSecondDist)
1353 aRadius = myCenterPoint.Distance (aFirstTextProj);
1354 Standard_Real aNewExtensionSize = aFirstDist - anArrowLength;
1355 theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1357 theAlignment = Prs3d_DTHP_Left;
1359 gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, myFirstPoint).Normalized().Scaled (aRadius);
1361 theFlyout = aFirstTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1362 ? -aRadius : aRadius;
1366 aRadius = myCenterPoint.Distance (aSecondTextProj);
1368 Standard_Real aNewExtensionSize = aSecondDist - anArrowLength;
1370 theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1372 theAlignment = Prs3d_DTHP_Right;
1374 gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, mySecondPoint).Normalized().Scaled (aRadius);
1376 theFlyout = aSecondTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1377 ? -aRadius : aRadius;
1381 //=======================================================================
1382 //function : FitTextAlignment
1384 //=======================================================================
1385 void PrsDim_AngleDimension::FitTextAlignment (const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos,
1386 Standard_Integer& theLabelPosition,
1387 Standard_Boolean& theIsArrowsExternal) const
1389 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1391 Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1393 // Prepare label string and compute its geometrical width
1394 Standard_Real aLabelWidth;
1395 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1397 // add margins to label width
1398 if (aDimensionAspect->IsText3d())
1400 aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
1403 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1404 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1406 // Handle user-defined and automatic arrow placement
1407 switch (aDimensionAspect->ArrowOrientation())
1409 case Prs3d_DAO_External: theIsArrowsExternal = true; break;
1410 case Prs3d_DAO_Internal: theIsArrowsExternal = false; break;
1413 gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1414 Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1416 // Add margin to ensure a small tail between text and arrow
1417 Standard_Real anArrowMargin = aDimensionAspect->IsText3d()
1418 ? aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN
1421 Standard_Real anArrowsWidth = (anArrowLength + anArrowMargin) * 2.0;
1423 theIsArrowsExternal = aDimensionWidth < aLabelWidth + anArrowsWidth;
1428 // Handle user-defined and automatic text placement
1429 switch (theHorizontalTextPos)
1431 case Prs3d_DTHP_Left : theLabelPosition |= LabelPosition_Left; break;
1432 case Prs3d_DTHP_Right : theLabelPosition |= LabelPosition_Right; break;
1433 case Prs3d_DTHP_Center: theLabelPosition |= LabelPosition_HCenter; break;
1434 case Prs3d_DTHP_Fit:
1436 gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1437 Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1438 Standard_Real anArrowsWidth = anArrowLength * 2.0;
1439 Standard_Real aContentWidth = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth;
1441 theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter;
1446 switch (aDimensionAspect->TextVerticalPosition())
1448 case Prs3d_DTVP_Above : theLabelPosition |= LabelPosition_Above; break;
1449 case Prs3d_DTVP_Below : theLabelPosition |= LabelPosition_Below; break;
1450 case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;