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 <Geom_Line.hxx>
51 #include <Geom_Plane.hxx>
53 IMPLEMENT_STANDARD_RTTIEXT(PrsDim_AngleDimension, PrsDim_Dimension)
57 static const TCollection_ExtendedString THE_EMPTY_LABEL_STRING;
58 static const Standard_Real THE_EMPTY_LABEL_WIDTH = 0.0;
59 static const Standard_ExtCharacter THE_DEGREE_SYMBOL (0x00B0);
60 static const Standard_Real THE_3D_TEXT_MARGIN = 0.1;
62 //! Returns true if the given points lie on a same line.
63 static Standard_Boolean isSameLine (const gp_Pnt& theFirstPoint,
64 const gp_Pnt& theCenterPoint,
65 const gp_Pnt& theSecondPoint)
67 gp_Vec aVec1 (theFirstPoint, theCenterPoint);
68 gp_Vec aVec2 (theCenterPoint, theSecondPoint);
70 return aVec1.IsParallel (aVec2, Precision::Angular());
74 //=======================================================================
75 //function : Constructor
77 //=======================================================================
78 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Edge& theFirstEdge,
79 const TopoDS_Edge& theSecondEdge)
80 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
83 SetMeasuredGeometry (theFirstEdge, theSecondEdge);
86 //=======================================================================
87 //function : Constructor
89 //=======================================================================
90 PrsDim_AngleDimension::PrsDim_AngleDimension (const gp_Pnt& theFirstPoint,
91 const gp_Pnt& theSecondPoint,
92 const gp_Pnt& theThirdPoint)
93 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
96 SetMeasuredGeometry (theFirstPoint, theSecondPoint, theThirdPoint);
99 //=======================================================================
100 //function : Constructor
102 //=======================================================================
103 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Vertex& theFirstVertex,
104 const TopoDS_Vertex& theSecondVertex,
105 const TopoDS_Vertex& theThirdVertex)
106 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
109 SetMeasuredGeometry (theFirstVertex, theSecondVertex, theThirdVertex);
112 //=======================================================================
113 //function : Constructor
115 //=======================================================================
116 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Face& theCone)
117 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
120 SetMeasuredGeometry (theCone);
123 //=======================================================================
124 //function : Constructor
126 //=======================================================================
127 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Face& theFirstFace,
128 const TopoDS_Face& theSecondFace)
129 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
132 SetMeasuredGeometry (theFirstFace, theSecondFace);
135 //=======================================================================
136 //function : Constructor
138 //=======================================================================
139 PrsDim_AngleDimension::PrsDim_AngleDimension (const TopoDS_Face& theFirstFace,
140 const TopoDS_Face& theSecondFace,
141 const gp_Pnt& thePoint)
142 : PrsDim_Dimension (PrsDim_KOD_PLANEANGLE)
145 SetMeasuredGeometry (theFirstFace, theSecondFace, thePoint);
148 //=======================================================================
149 //function : SetMeasuredGeometry
151 //=======================================================================
152 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge,
153 const TopoDS_Edge& theSecondEdge)
155 gp_Pln aComputedPlane;
157 myFirstShape = theFirstEdge;
158 mySecondShape = theSecondEdge;
159 myThirdShape = TopoDS_Shape();
160 myGeometryType = GeometryType_Edges;
161 myIsGeometryValid = InitTwoEdgesAngle (aComputedPlane);
163 if (myIsGeometryValid && !myIsPlaneCustom)
165 myPlane = aComputedPlane;
171 //=======================================================================
172 //function : SetMeasuredGeometry
174 //=======================================================================
175 void PrsDim_AngleDimension::SetMeasuredGeometry (const gp_Pnt& theFirstPoint,
176 const gp_Pnt& theSecondPoint,
177 const gp_Pnt& theThirdPoint)
179 myFirstPoint = theFirstPoint;
180 myCenterPoint = theSecondPoint;
181 mySecondPoint = theThirdPoint;
182 myFirstShape = BRepLib_MakeVertex (myFirstPoint);
183 mySecondShape = BRepLib_MakeVertex (myCenterPoint);
184 myThirdShape = BRepLib_MakeVertex (mySecondPoint);
185 myGeometryType = GeometryType_Points;
186 myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
188 Standard_Boolean anIsSameLine = isSameLine (myFirstPoint, myCenterPoint, mySecondPoint);
189 if (myIsGeometryValid && !myIsPlaneCustom && !anIsSameLine)
197 //=======================================================================
198 //function : SetMeasuredGeometry
200 //=======================================================================
201 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Vertex& theFirstVertex,
202 const TopoDS_Vertex& theSecondVertex,
203 const TopoDS_Vertex& theThirdVertex)
205 myFirstShape = theFirstVertex;
206 mySecondShape = theSecondVertex;
207 myThirdShape = theThirdVertex;
208 myFirstPoint = BRep_Tool::Pnt (theFirstVertex);
209 myCenterPoint = BRep_Tool::Pnt (theSecondVertex);
210 mySecondPoint = BRep_Tool::Pnt (theThirdVertex);
211 myGeometryType = GeometryType_Points;
212 myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
214 Standard_Boolean anIsSameLine = isSameLine (myFirstPoint, myCenterPoint, mySecondPoint);
215 if (myIsGeometryValid && !myIsPlaneCustom && !anIsSameLine)
223 //=======================================================================
224 //function : SetMeasuredGeometry
226 //=======================================================================
227 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theCone)
229 myFirstShape = theCone;
230 mySecondShape = TopoDS_Shape();
231 myThirdShape = TopoDS_Shape();
232 myGeometryType = GeometryType_Face;
233 myIsGeometryValid = InitConeAngle();
235 if (myIsGeometryValid && !myIsPlaneCustom)
243 //=======================================================================
244 //function : SetMeasuredGeometry
246 //=======================================================================
247 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
248 const TopoDS_Face& theSecondFace)
250 myFirstShape = theFirstFace;
251 mySecondShape = theSecondFace;
252 myThirdShape = TopoDS_Shape();
253 myGeometryType = GeometryType_Faces;
254 myIsGeometryValid = InitTwoFacesAngle();
256 if (myIsGeometryValid && !myIsPlaneCustom)
264 //=======================================================================
265 //function : SetMeasuredGeometry
267 //=======================================================================
268 void PrsDim_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
269 const TopoDS_Face& theSecondFace,
270 const gp_Pnt& thePoint)
272 myFirstShape = theFirstFace;
273 mySecondShape = theSecondFace;
274 myThirdShape = TopoDS_Shape();
275 myGeometryType = GeometryType_Faces;
276 myIsGeometryValid = InitTwoFacesAngle (thePoint);
278 if (myIsGeometryValid && !myIsPlaneCustom)
286 //=======================================================================
289 //=======================================================================
290 void PrsDim_AngleDimension::Init()
292 SetType (PrsDim_TypeOfAngle_Interior);
293 SetArrowsVisibility (PrsDim_TypeOfAngleArrowVisibility_Both);
294 SetSpecialSymbol (THE_DEGREE_SYMBOL);
295 SetDisplaySpecialSymbol (PrsDim_DisplaySpecialSymbol_After);
299 //=======================================================================
300 //function: GetCenterOnArc
302 //=======================================================================
303 gp_Pnt PrsDim_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach,
304 const gp_Pnt& theSecondAttach,
305 const gp_Pnt& theCenter) const
307 // construct plane where the circle and the arc are located
308 gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
309 if (!aConstructPlane.IsDone())
314 gp_Pln aPlane = aConstructPlane.Value();
315 // to have an exterior angle presentation, a plane for further constructed circle should be reversed
316 if (myType == PrsDim_TypeOfAngle_Exterior)
318 gp_Ax1 anAxis = aPlane.Axis();
319 gp_Dir aDir = anAxis.Direction();
321 aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
324 Standard_Real aRadius = theFirstAttach.Distance (theCenter);
326 // construct circle forming the arc
327 gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
328 if (!aConstructCircle.IsDone())
333 gp_Circ aCircle = aConstructCircle.Value();
335 // compute angle parameters of arc end-points on circle
336 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
337 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
338 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
340 return ElCLib::Value ((aParamBeg + aParamEnd) * 0.5, aCircle);
343 //=======================================================================
344 //function : GetNormalForMinAngle
346 //=======================================================================
347 gp_Dir PrsDim_AngleDimension::GetNormalForMinAngle() const
349 const gp_Dir& aNormal = myPlane.Axis().Direction();
350 gp_Dir aFirst (gp_Vec (myCenterPoint, myFirstPoint) );
351 gp_Dir aSecond (gp_Vec (myCenterPoint, mySecondPoint) );
353 return aFirst.AngleWithRef (aSecond, aNormal) < 0.0
358 //=======================================================================
360 //purpose : draws the arc between two attach points
361 //=======================================================================
362 void PrsDim_AngleDimension::DrawArc (const Handle(Prs3d_Presentation)& thePresentation,
363 const gp_Pnt& theFirstAttach,
364 const gp_Pnt& theSecondAttach,
365 const gp_Pnt& theCenter,
366 const Standard_Real theRadius,
367 const Standard_Integer theMode)
369 gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle());
371 // to have an exterior angle presentation, a plane for further constructed circle should be reversed
372 if (myType == PrsDim_TypeOfAngle_Exterior)
374 gp_Ax1 anAxis = aPlane.Axis();
375 gp_Dir aDir = anAxis.Direction();
377 aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
380 // construct circle forming the arc
381 gce_MakeCirc aConstructCircle (theCenter, aPlane, theRadius);
382 if (!aConstructCircle.IsDone())
387 gp_Circ aCircle = aConstructCircle.Value();
390 GC_MakeArcOfCircle aConstructArc (aCircle, theFirstAttach, theSecondAttach, Standard_True);
391 if (!aConstructArc.IsDone())
396 // generate points with specified deflection
397 const Handle(Geom_TrimmedCurve)& anArcCurve = aConstructArc.Value();
399 GeomAdaptor_Curve anArcAdaptor (anArcCurve, anArcCurve->FirstParameter(), anArcCurve->LastParameter());
401 // compute number of discretization elements in old-fanshioned way
402 gp_Vec aCenterToFirstVec (theCenter, theFirstAttach);
403 gp_Vec aCenterToSecondVec (theCenter, theSecondAttach);
404 Standard_Real anAngle = aCenterToFirstVec.Angle (aCenterToSecondVec);
405 if (myType == PrsDim_TypeOfAngle_Exterior)
406 anAngle = 2.0 * M_PI - anAngle;
407 // it sets 50 points on PI, and a part of points if angle is less
408 const Standard_Integer aNbPoints = Max (4, Standard_Integer (50.0 * anAngle / M_PI));
410 GCPnts_UniformAbscissa aMakePnts (anArcAdaptor, aNbPoints);
411 if (!aMakePnts.IsDone())
416 // init data arrays for graphical and selection primitives
417 Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aNbPoints);
419 SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
421 // load data into arrays
422 for (Standard_Integer aPntIt = 1; aPntIt <= aMakePnts.NbPoints(); ++aPntIt)
424 gp_Pnt aPnt = anArcAdaptor.Value (aMakePnts.Parameter (aPntIt));
426 aPrimSegments->AddVertex (aPnt);
428 aSensitiveCurve.Append (aPnt);
431 // add display presentation
432 if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
434 thePresentation->CurrentGroup()->SetStencilTestOptions (Standard_True);
436 Handle(Graphic3d_AspectLine3d) aDimensionLineStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
437 thePresentation->CurrentGroup()->SetPrimitivesAspect (aDimensionLineStyle);
438 thePresentation->CurrentGroup()->AddPrimitiveArray (aPrimSegments);
439 if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
441 thePresentation->CurrentGroup()->SetStencilTestOptions (Standard_False);
445 //=======================================================================
446 //function: DrawArcWithText
448 //=======================================================================
449 void PrsDim_AngleDimension::DrawArcWithText (const Handle(Prs3d_Presentation)& thePresentation,
450 const gp_Pnt& theFirstAttach,
451 const gp_Pnt& theSecondAttach,
452 const gp_Pnt& theCenter,
453 const TCollection_ExtendedString& theText,
454 const Standard_Real theTextWidth,
455 const Standard_Integer theMode,
456 const Standard_Integer theLabelPosition)
458 gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle());
460 Standard_Real aRadius = theFirstAttach.Distance (myCenterPoint);
462 // construct circle forming the arc
463 gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
464 if (!aConstructCircle.IsDone())
469 gp_Circ aCircle = aConstructCircle.Value();
471 // compute angle parameters of arc end-points on circle
472 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
473 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
474 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
476 // middle point of arc parameter on circle
477 Standard_Real aParamMid = (aParamBeg + aParamEnd) * 0.5;
479 // add text graphical primitives
480 if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
482 gp_Pnt aTextPos = ElCLib::Value (aParamMid, aCircle);
483 gp_Dir aTextDir = gce_MakeDir (theFirstAttach, theSecondAttach);
486 drawText (thePresentation,
493 if (theMode != ComputeMode_All && theMode != ComputeMode_Line)
498 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
500 Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
501 && aDimensionAspect->IsText3d();
505 // compute gap for label as parameteric size of sector on circle segment
506 Standard_Real aSectorOfText = theTextWidth / aRadius;
507 Standard_Real aTextBegin = aParamMid - aSectorOfText * 0.5;
508 Standard_Real aTextEnd = aParamMid + aSectorOfText * 0.5;
509 gp_Pnt aTextPntBeg = ElCLib::Value (aTextBegin, aCircle);
510 gp_Pnt aTextPntEnd = ElCLib::Value (aTextEnd, aCircle);
513 if (aTextBegin > aParamBeg)
515 DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode);
517 if (aTextEnd < aParamEnd)
519 DrawArc (thePresentation, aTextPntEnd, theSecondAttach, theCenter, aRadius, theMode);
524 DrawArc (thePresentation, theFirstAttach, theSecondAttach, theCenter, aRadius, theMode);
528 //=======================================================================
529 //function : CheckPlane
531 //=======================================================================
532 Standard_Boolean PrsDim_AngleDimension::CheckPlane (const gp_Pln& thePlane)const
534 if (!thePlane.Contains (myFirstPoint, Precision::Confusion()) &&
535 !thePlane.Contains (mySecondPoint, Precision::Confusion()) &&
536 !thePlane.Contains (myCenterPoint, Precision::Confusion()))
538 return Standard_False;
541 return Standard_True;
544 //=======================================================================
545 //function : ComputePlane
547 //=======================================================================
548 void PrsDim_AngleDimension::ComputePlane()
550 if (!myIsGeometryValid)
555 // Compute working plane so that Y axis is codirectional
556 // with Y axis of text coordinate system (necessary for text alignment)
557 gp_Vec aFirstVec = gp_Vec (myCenterPoint, myFirstPoint);
558 gp_Vec aSecondVec = gp_Vec (myCenterPoint, mySecondPoint);
559 gp_Vec aDirectionN = aSecondVec ^ aFirstVec;
560 gp_Vec aDirectionY = aFirstVec + aSecondVec;
561 gp_Vec aDirectionX = aDirectionY ^ aDirectionN;
563 myPlane = gp_Pln (gp_Ax3 (myCenterPoint, gp_Dir (aDirectionN), gp_Dir (aDirectionX)));
566 //=======================================================================
567 //function : GetModelUnits
569 //=======================================================================
570 const TCollection_AsciiString& PrsDim_AngleDimension::GetModelUnits() const
572 return myDrawer->DimAngleModelUnits();
575 //=======================================================================
576 //function : GetDisplayUnits
578 //=======================================================================
579 const TCollection_AsciiString& PrsDim_AngleDimension::GetDisplayUnits() const
581 return myDrawer->DimAngleDisplayUnits();
584 //=======================================================================
585 //function : SetModelUnits
587 //=======================================================================
588 void PrsDim_AngleDimension::SetModelUnits (const TCollection_AsciiString& theUnits)
590 myDrawer->SetDimAngleModelUnits (theUnits);
593 //=======================================================================
594 //function : SetDisplayUnits
596 //=======================================================================
597 void PrsDim_AngleDimension::SetDisplayUnits (const TCollection_AsciiString& theUnits)
599 myDrawer->SetDimAngleDisplayUnits (theUnits);
602 //=======================================================================
603 //function : ComputeValue
605 //=======================================================================
606 Standard_Real PrsDim_AngleDimension::ComputeValue() const
613 gp_Vec aVec1 (myCenterPoint, myFirstPoint);
614 gp_Vec aVec2 (myCenterPoint, mySecondPoint);
616 Standard_Real anAngle = aVec1.AngleWithRef (aVec2, GetNormalForMinAngle());
618 return anAngle > 0.0 ? anAngle : (2.0 * M_PI + anAngle);
621 //=======================================================================
623 //purpose : Having three gp_Pnt points compute presentation
624 //=======================================================================
625 void PrsDim_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager)& ,
626 const Handle(Prs3d_Presentation)& thePresentation,
627 const Standard_Integer theMode)
629 mySelectionGeom.Clear (theMode);
636 // Parameters for presentation
637 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
639 thePresentation->CurrentGroup()->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
641 Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
643 // prepare label string and compute its geometrical width
644 Standard_Real aLabelWidth;
645 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
647 // add margins to label width
648 if (aDimensionAspect->IsText3d())
650 aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
653 // Get parameters from aspect or adjust it according with custom text position
654 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
655 Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition();
657 if (IsTextPositionCustom())
659 AdjustParameters (myFixedTextPosition,anExtensionSize, aHorisontalTextPos, myFlyout);
662 // Handle user-defined and automatic arrow placement
663 Standard_Boolean isArrowsExternal = Standard_False;
664 Standard_Integer aLabelPosition = LabelPosition_None;
666 FitTextAlignment (aHorisontalTextPos, aLabelPosition, isArrowsExternal);
668 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
669 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
671 //Arrows positions and directions
672 gp_Vec aWorkingPlaneDir (GetNormalForMinAngle());
674 gp_Dir aFirstExtensionDir = aWorkingPlaneDir.Reversed() ^ gp_Vec (myCenterPoint, aFirstAttach);
675 gp_Dir aSecondExtensionDir = aWorkingPlaneDir ^ gp_Vec (myCenterPoint, aSecondAttach);
677 gp_Vec aFirstArrowVec = gp_Vec (aFirstExtensionDir) * anArrowLength;
678 gp_Vec aSecondArrowVec = gp_Vec (aSecondExtensionDir) * anArrowLength;
680 if (isArrowsExternal)
682 aFirstArrowVec.Reverse();
683 aSecondArrowVec.Reverse();
686 gp_Pnt aFirstArrowBegin (0.0, 0.0, 0.0);
687 gp_Pnt aFirstArrowEnd (0.0, 0.0, 0.0);
688 gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0);
689 gp_Pnt aSecondArrowEnd (0.0, 0.0, 0.0);
691 aFirstArrowBegin = aFirstAttach;
692 aSecondArrowBegin = aSecondAttach;
693 aFirstArrowEnd = aFirstAttach;
694 aSecondArrowEnd = aSecondAttach;
696 if (aDimensionAspect->ArrowAspect()->IsZoomable())
698 aFirstArrowEnd.Translate (-aFirstArrowVec);
699 aSecondArrowEnd.Translate (-aSecondArrowVec);
702 // Group1: stenciling text and the angle dimension arc
703 thePresentation->NewGroup();
705 Standard_Integer aHPosition = aLabelPosition & LabelPosition_HMask;
710 case LabelPosition_HCenter :
712 Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
713 && aDimensionAspect->IsText3d();
717 DrawArcWithText (thePresentation,
728 // compute text primitives
729 if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
731 gp_Vec aDimensionDir (aFirstAttach, aSecondAttach);
732 gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition
733 : GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
734 gp_Dir aTextDir = aDimensionDir;
736 drawText (thePresentation,
743 if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
745 DrawArc (thePresentation,
746 (isArrowsExternal || !isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First)) ? aFirstAttach : aFirstArrowEnd,
747 (isArrowsExternal || !isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second)) ? aSecondAttach : aSecondArrowEnd,
755 case LabelPosition_Left :
757 DrawExtension (thePresentation,
759 (isArrowsExternal && isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First)) ? aFirstArrowEnd : aFirstAttach,
768 case LabelPosition_Right :
770 DrawExtension (thePresentation,
772 (isArrowsExternal && isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second)) ? aSecondArrowEnd : aSecondAttach,
782 // dimension arc without text
783 if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && aHPosition != LabelPosition_HCenter)
785 thePresentation->NewGroup();
787 DrawArc (thePresentation,
788 (isArrowsExternal || !isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First)) ? aFirstAttach : aFirstArrowEnd,
789 (isArrowsExternal || !isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second)) ? aSecondAttach : aSecondArrowEnd,
795 // arrows and arrow extensions
796 if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
798 thePresentation->NewGroup();
800 if (isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First))
801 DrawArrow (thePresentation, aFirstArrowBegin, gp_Dir (aFirstArrowVec));
802 if (isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second))
803 DrawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec));
806 if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && isArrowsExternal)
808 thePresentation->NewGroup();
810 if (aHPosition != LabelPosition_Left && isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_First))
812 DrawExtension (thePresentation,
813 aDimensionAspect->ArrowTailSize(),
816 THE_EMPTY_LABEL_STRING,
817 THE_EMPTY_LABEL_WIDTH,
822 if (aHPosition != LabelPosition_Right && isArrowVisible(PrsDim_TypeOfAngleArrowVisibility_Second))
824 DrawExtension (thePresentation,
825 aDimensionAspect->ArrowTailSize(),
828 THE_EMPTY_LABEL_STRING,
829 THE_EMPTY_LABEL_WIDTH,
836 if (theMode == ComputeMode_All)
838 thePresentation->NewGroup();
840 Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (4);
841 aPrimSegments->AddVertex (myCenterPoint);
842 aPrimSegments->AddVertex (aFirstAttach);
843 aPrimSegments->AddVertex (myCenterPoint);
844 aPrimSegments->AddVertex (aSecondAttach);
846 Handle(Graphic3d_AspectLine3d) aFlyoutStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
847 thePresentation->CurrentGroup()->SetPrimitivesAspect (aFlyoutStyle);
848 thePresentation->CurrentGroup()->AddPrimitiveArray (aPrimSegments);
851 mySelectionGeom.IsComputed = Standard_True;
854 //=======================================================================
855 //function : ComputeFlyoutSelection
856 //purpose : computes selection for flyouts
857 //=======================================================================
858 void PrsDim_AngleDimension::ComputeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection,
859 const Handle(SelectMgr_EntityOwner)& theOwner)
861 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
862 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
864 Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner);
865 aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aFirstAttach));
866 aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aSecondAttach));
868 theSelection->Add (aSensitiveEntity);
871 //=======================================================================
872 //function : InitTwoEdgesAngle
874 //=======================================================================
875 Standard_Boolean PrsDim_AngleDimension::InitTwoEdgesAngle (gp_Pln& theComputedPlane)
877 TopoDS_Edge aFirstEdge = TopoDS::Edge (myFirstShape);
878 TopoDS_Edge aSecondEdge = TopoDS::Edge (mySecondShape);
880 BRepAdaptor_Curve aMakeFirstLine (aFirstEdge);
881 BRepAdaptor_Curve aMakeSecondLine (aSecondEdge);
883 if (aMakeFirstLine.GetType() != GeomAbs_Line || aMakeSecondLine.GetType() != GeomAbs_Line)
885 return Standard_False;
888 Handle(Geom_Line) aFirstLine = new Geom_Line (aMakeFirstLine.Line());
889 Handle(Geom_Line) aSecondLine = new Geom_Line (aMakeSecondLine.Line());
891 gp_Lin aFirstLin = aFirstLine->Lin();
892 gp_Lin aSecondLin = aSecondLine->Lin();
894 Standard_Boolean isParallelLines = aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular());
896 theComputedPlane = isParallelLines ? gp_Pln(gp::XOY())
897 : gp_Pln (aSecondLin.Location(), gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction()));
899 // Compute geometry for this plane and edges
900 Standard_Boolean isInfinite1,isInfinite2;
901 gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2;
902 Handle(Geom_Curve) aFirstCurve = aFirstLine, aSecondCurve = aSecondLine;
903 if (!PrsDim::ComputeGeometry (aFirstEdge, aSecondEdge,
904 aFirstCurve, aSecondCurve,
905 aFirstPoint1, aLastPoint1,
906 aFirstPoint2, aLastPoint2,
907 isInfinite1, isInfinite2))
909 return Standard_False;
912 Standard_Boolean isSameLines = aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular())
913 && aFirstLin.Location().IsEqual (aSecondLin.Location(),Precision::Confusion());
915 // It can be the same gp_Lin geometry but the different begin and end parameters
916 Standard_Boolean isSameEdges =
917 (aFirstPoint1.IsEqual (aFirstPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aLastPoint2, Precision::Confusion()))
918 || (aFirstPoint1.IsEqual (aLastPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aFirstPoint2, Precision::Confusion()));
922 // Zero angle, it could not handle this geometry
923 if (isSameLines && isSameEdges)
925 return Standard_False;
928 // Handle the case of Pi angle
929 const Standard_Real aParam11 = ElCLib::Parameter (aFirstLin, aFirstPoint1);
930 const Standard_Real aParam12 = ElCLib::Parameter (aFirstLin, aLastPoint1);
931 const Standard_Real aParam21 = ElCLib::Parameter (aFirstLin, aFirstPoint2);
932 const Standard_Real aParam22 = ElCLib::Parameter (aFirstLin, aLastPoint2);
933 myCenterPoint = ElCLib::Value ( (Min (aParam11, aParam12) + Max (aParam21, aParam22)) * 0.5, aFirstLin);
934 myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
935 mySecondPoint = myCenterPoint.XYZ() + (aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular())
936 ? aFirstLin.Direction().Reversed().XYZ() * Abs (GetFlyout())
937 : aSecondLin.Direction().XYZ() * Abs (GetFlyout()));
942 gp_Lin2d aFirstLin2d = ProjLib::Project (theComputedPlane, aFirstLin);
943 gp_Lin2d aSecondLin2d = ProjLib::Project (theComputedPlane, aSecondLin);
945 IntAna2d_AnaIntersection anInt2d (aFirstLin2d, aSecondLin2d);
946 gp_Pnt2d anIntersectPoint;
947 if (!anInt2d.IsDone() || anInt2d.IsEmpty())
949 return Standard_False;
952 anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value());
953 myCenterPoint = ElCLib::To3d (theComputedPlane.Position().Ax2(), anIntersectPoint);
955 if (isInfinite1 || isInfinite2)
957 myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
958 mySecondPoint = myCenterPoint.Translated (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout()));
960 return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
964 // | <- dimension should be here
966 myFirstPoint = myCenterPoint.Distance (aFirstPoint1) > myCenterPoint.Distance (aLastPoint1)
970 mySecondPoint = myCenterPoint.Distance (aFirstPoint2) > myCenterPoint.Distance (aLastPoint2)
975 return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
978 //=======================================================================
979 //function : InitTwoFacesAngle
980 //purpose : initialization of angle dimension between two faces
981 //=======================================================================
982 Standard_Boolean PrsDim_AngleDimension::InitTwoFacesAngle()
984 TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
985 TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
987 gp_Dir aFirstDir, aSecondDir;
988 gp_Pln aFirstPln, aSecondPln;
989 Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
990 PrsDim_KindOfSurface aFirstSurfType, aSecondSurfType;
991 Standard_Real aFirstOffset, aSecondOffset;
993 PrsDim::GetPlaneFromFace (aFirstFace, aFirstPln,
994 aFirstBasisSurf,aFirstSurfType,aFirstOffset);
996 PrsDim::GetPlaneFromFace (aSecondFace, aSecondPln,
997 aSecondBasisSurf, aSecondSurfType, aSecondOffset);
999 if (aFirstSurfType == PrsDim_KOS_Plane && aSecondSurfType == PrsDim_KOS_Plane)
1001 //Planar faces angle
1002 Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
1003 Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
1004 return PrsDim::InitAngleBetweenPlanarFaces (aFirstFace, aSecondFace,
1005 myCenterPoint, myFirstPoint, mySecondPoint)
1006 && IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
1010 // Curvilinear faces angle
1011 return PrsDim::InitAngleBetweenCurvilinearFaces (aFirstFace, aSecondFace,
1012 aFirstSurfType, aSecondSurfType,
1013 myCenterPoint, myFirstPoint, mySecondPoint)
1014 && IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
1018 //=======================================================================
1019 //function : InitTwoFacesAngle
1020 //purpose : initialization of angle dimension between two faces
1021 //=======================================================================
1022 Standard_Boolean PrsDim_AngleDimension::InitTwoFacesAngle (const gp_Pnt& thePointOnFirstFace)
1024 TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
1025 TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
1027 gp_Dir aFirstDir, aSecondDir;
1028 gp_Pln aFirstPln, aSecondPln;
1029 Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
1030 PrsDim_KindOfSurface aFirstSurfType, aSecondSurfType;
1031 Standard_Real aFirstOffset, aSecondOffset;
1033 PrsDim::GetPlaneFromFace (aFirstFace, aFirstPln,
1034 aFirstBasisSurf,aFirstSurfType,aFirstOffset);
1036 PrsDim::GetPlaneFromFace (aSecondFace, aSecondPln,
1037 aSecondBasisSurf, aSecondSurfType, aSecondOffset);
1039 myFirstPoint = thePointOnFirstFace;
1040 if (aFirstSurfType == PrsDim_KOS_Plane && aSecondSurfType == PrsDim_KOS_Plane)
1042 //Planar faces angle
1043 Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
1044 Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
1045 return PrsDim::InitAngleBetweenPlanarFaces (aFirstFace, aSecondFace,
1046 myCenterPoint, myFirstPoint, mySecondPoint,
1048 && IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
1052 // Curvilinear faces angle
1053 return PrsDim::InitAngleBetweenCurvilinearFaces (aFirstFace, aSecondFace,
1054 aFirstSurfType, aSecondSurfType,
1055 myCenterPoint, myFirstPoint, mySecondPoint,
1057 && IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
1061 //=======================================================================
1062 //function : InitConeAngle
1063 //purpose : initialization of the cone angle
1064 //=======================================================================
1065 Standard_Boolean PrsDim_AngleDimension::InitConeAngle()
1067 if (myFirstShape.IsNull())
1069 return Standard_False;
1072 TopoDS_Face aConeShape = TopoDS::Face (myFirstShape);
1076 // A surface from the Face
1077 Handle(Geom_Surface) aSurf;
1078 Handle(Geom_OffsetSurface) aOffsetSurf;
1079 Handle(Geom_ConicalSurface) aConicalSurf;
1080 Handle(Geom_SurfaceOfRevolution) aRevSurf;
1081 Handle(Geom_Line) aLine;
1082 BRepAdaptor_Surface aConeAdaptor (aConeShape);
1084 PrsDim_KindOfSurface aSurfType;
1085 Standard_Real anOffset = 0.;
1086 Handle(Standard_Type) aType;
1088 const Standard_Real aMaxV = aConeAdaptor.FirstVParameter();
1089 const Standard_Real aMinV = aConeAdaptor.LastVParameter();
1090 PrsDim::GetPlaneFromFace (aConeShape, aPln, aSurf, aSurfType, anOffset);
1091 if (aSurfType == PrsDim_KOS_Revolution)
1093 // Surface of revolution
1094 aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aSurf);
1095 gp_Lin aLin (aRevSurf->Axis());
1096 Handle(Geom_Curve) aBasisCurve = aRevSurf->BasisCurve();
1097 //Must be a part of line (basis curve should be linear)
1098 if (aBasisCurve ->DynamicType() != STANDARD_TYPE(Geom_Line))
1099 return Standard_False;
1101 gp_Pnt aFirst1 = aConeAdaptor.Value (0., aMinV);
1102 gp_Pnt aLast1 = aConeAdaptor.Value (0., aMaxV);
1103 gp_Vec aVec1 (aFirst1, aLast1);
1105 //Projection <aFirst> on <aLin>
1106 gp_Pnt aFirst2 = ElCLib::Value (ElCLib::Parameter (aLin, aFirst1), aLin);
1107 // Projection <aLast> on <aLin>
1108 gp_Pnt aLast2 = ElCLib::Value (ElCLib::Parameter (aLin, aLast1), aLin);
1110 gp_Vec aVec2 (aFirst2, aLast2);
1112 // Check if two parts of revolution are parallel (it's a cylinder) or normal (it's a circle).
1113 if (aVec1.IsParallel (aVec2, Precision::Angular())
1114 || aVec1.IsNormal (aVec2,Precision::Angular()))
1115 return Standard_False;
1117 gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1);
1118 aCone = aMkCone.Value();
1119 myCenterPoint = aCone.Apex();
1123 aType = aSurf->DynamicType();
1124 if (aType == STANDARD_TYPE(Geom_OffsetSurface) || anOffset > 0.01)
1127 aOffsetSurf = new Geom_OffsetSurface (aSurf, anOffset);
1128 aSurf = aOffsetSurf->Surface();
1129 BRepBuilderAPI_MakeFace aMkFace(aSurf, Precision::Confusion());
1131 if (!aMkFace.IsDone())
1132 return Standard_False;
1133 aConeAdaptor.Initialize (aMkFace.Face());
1135 aCone = aConeAdaptor.Cone();
1136 aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf);
1137 myCenterPoint = aConicalSurf->Apex();
1140 // A circle where the angle is drawn
1141 Handle(Geom_Curve) aCurve;
1142 Standard_Real aMidV = ( aMinV + aMaxV ) / 2.5;
1143 aCurve = aSurf->VIso (aMidV);
1144 aCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
1146 aCurve = aSurf->VIso(aMaxV);
1147 gp_Circ aCircVmax = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1148 aCurve = aSurf->VIso(aMinV);
1149 gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1151 if (aCircVmax.Radius() < aCircVmin.Radius())
1153 gp_Circ aTmpCirc = aCircVmax;
1154 aCircVmax = aCircVmin;
1155 aCircVmin = aTmpCirc;
1158 myFirstPoint = ElCLib::Value (0, aCircle);
1159 mySecondPoint = ElCLib::Value (M_PI, aCircle);
1160 return Standard_True;
1163 //=======================================================================
1164 //function : IsValidPoints
1166 //=======================================================================
1167 Standard_Boolean PrsDim_AngleDimension::IsValidPoints (const gp_Pnt& theFirstPoint,
1168 const gp_Pnt& theCenterPoint,
1169 const gp_Pnt& theSecondPoint) const
1171 return theFirstPoint.Distance (theCenterPoint) > Precision::Confusion()
1172 && theSecondPoint.Distance (theCenterPoint) > Precision::Confusion()
1173 && gp_Vec (theCenterPoint, theFirstPoint).Angle (
1174 gp_Vec (theCenterPoint, theSecondPoint)) > Precision::Angular();
1177 //=======================================================================
1178 //function : isArrowVisible
1179 //purpose : compares given and internal arrows types, returns true if the type should be shown
1180 //=======================================================================
1181 Standard_Boolean PrsDim_AngleDimension::isArrowVisible(const PrsDim_TypeOfAngleArrowVisibility theArrowType) const
1183 switch (theArrowType)
1185 case PrsDim_TypeOfAngleArrowVisibility_Both:
1186 return myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_Both;
1187 case PrsDim_TypeOfAngleArrowVisibility_First:
1188 return myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_Both || myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_First;
1189 case PrsDim_TypeOfAngleArrowVisibility_Second:
1190 return myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_Both || myArrowsVisibility == PrsDim_TypeOfAngleArrowVisibility_Second;
1191 case PrsDim_TypeOfAngleArrowVisibility_None:
1197 //=======================================================================
1198 //function : GetTextPosition
1200 //=======================================================================
1201 gp_Pnt PrsDim_AngleDimension::GetTextPosition() const
1205 return gp::Origin();
1208 if (IsTextPositionCustom())
1210 return myFixedTextPosition;
1213 // Counts text position according to the dimension parameters
1214 gp_Pnt aTextPosition (gp::Origin());
1216 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1218 // Prepare label string and compute its geometrical width
1219 Standard_Real aLabelWidth;
1220 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1222 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1223 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1225 // Handle user-defined and automatic arrow placement
1226 Standard_Boolean isArrowsExternal = Standard_False;
1227 Standard_Integer aLabelPosition = LabelPosition_None;
1228 FitTextAlignment (aDimensionAspect->TextHorizontalPosition(),
1229 aLabelPosition, isArrowsExternal);
1231 // Get text position
1232 switch (aLabelPosition & LabelPosition_HMask)
1234 case LabelPosition_HCenter:
1236 aTextPosition = GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
1239 case LabelPosition_Left:
1241 gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1242 gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aFirstAttach);
1243 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1244 Standard_Real anOffset = isArrowsExternal
1245 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1247 gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * -anOffset;
1248 aTextPosition = aFirstAttach.Translated (anExtensionVec);
1251 case LabelPosition_Right:
1253 gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1254 gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aSecondAttach);
1255 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1256 Standard_Real anOffset = isArrowsExternal
1257 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1259 gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * anOffset;
1260 aTextPosition = aSecondAttach.Translated (anExtensionVec);
1265 return aTextPosition;
1268 //=======================================================================
1269 //function : SetTextPosition
1271 //=======================================================================
1272 void PrsDim_AngleDimension::SetTextPosition (const gp_Pnt& theTextPos)
1279 // The text position point for angle dimension should belong to the working plane.
1280 if (!GetPlane().Contains (theTextPos, Precision::Confusion()))
1282 throw Standard_ProgramError("The text position point for angle dimension doesn't belong to the working plane.");
1285 myIsTextPositionFixed = Standard_True;
1286 myFixedTextPosition = theTextPos;
1289 //=======================================================================
1290 //function : AdjustParameters
1292 //=======================================================================
1293 void PrsDim_AngleDimension::AdjustParameters (const gp_Pnt& theTextPos,
1294 Standard_Real& theExtensionSize,
1295 Prs3d_DimensionTextHorizontalPosition& theAlignment,
1296 Standard_Real& theFlyout) const
1298 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1299 Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1301 // Build circle with radius that is equal to distance from text position to the center point.
1302 Standard_Real aRadius = gp_Vec (myCenterPoint, theTextPos).Magnitude();
1304 // Set attach points in positive direction of the flyout.
1305 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * aRadius);
1306 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * aRadius);
1308 gce_MakeCirc aConstructCircle (myCenterPoint, GetPlane(), aRadius);
1309 if (!aConstructCircle.IsDone())
1313 gp_Circ aCircle = aConstructCircle.Value();
1316 theExtensionSize = aDimensionAspect->ArrowAspect()->Length();
1317 theAlignment = Prs3d_DTHP_Center;
1319 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, aFirstAttach);
1320 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, aSecondAttach);
1321 if (aParamEnd < aParamBeg)
1323 Standard_Real aParam = aParamEnd;
1324 aParamEnd = aParamBeg;
1328 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1329 Standard_Real aTextPar = ElCLib::Parameter (aCircle , theTextPos);
1331 // Horizontal center
1332 if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1334 theFlyout = aRadius;
1340 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1342 if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1344 theFlyout = -aRadius;
1348 // Text on the extensions
1349 gp_Lin aFirstLine = gce_MakeLin (myCenterPoint, myFirstPoint);
1350 gp_Lin aSecondLine = gce_MakeLin (myCenterPoint, mySecondPoint);
1351 gp_Pnt aFirstTextProj = PrsDim::Nearest (aFirstLine, theTextPos);
1352 gp_Pnt aSecondTextProj = PrsDim::Nearest (aSecondLine, theTextPos);
1353 Standard_Real aFirstDist = aFirstTextProj.Distance (theTextPos);
1354 Standard_Real aSecondDist = aSecondTextProj.Distance (theTextPos);
1356 if (aFirstDist <= aSecondDist)
1358 aRadius = myCenterPoint.Distance (aFirstTextProj);
1359 Standard_Real aNewExtensionSize = aFirstDist - anArrowLength;
1360 theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1362 theAlignment = Prs3d_DTHP_Left;
1364 gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, myFirstPoint).Normalized().Scaled (aRadius);
1366 theFlyout = aFirstTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1367 ? -aRadius : aRadius;
1371 aRadius = myCenterPoint.Distance (aSecondTextProj);
1373 Standard_Real aNewExtensionSize = aSecondDist - anArrowLength;
1375 theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1377 theAlignment = Prs3d_DTHP_Right;
1379 gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, mySecondPoint).Normalized().Scaled (aRadius);
1381 theFlyout = aSecondTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1382 ? -aRadius : aRadius;
1386 //=======================================================================
1387 //function : FitTextAlignment
1389 //=======================================================================
1390 void PrsDim_AngleDimension::FitTextAlignment (const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos,
1391 Standard_Integer& theLabelPosition,
1392 Standard_Boolean& theIsArrowsExternal) const
1394 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1396 Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1398 // Prepare label string and compute its geometrical width
1399 Standard_Real aLabelWidth;
1400 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1402 // add margins to label width
1403 if (aDimensionAspect->IsText3d())
1405 aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
1408 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1409 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1411 // Handle user-defined and automatic arrow placement
1412 switch (aDimensionAspect->ArrowOrientation())
1414 case Prs3d_DAO_External: theIsArrowsExternal = true; break;
1415 case Prs3d_DAO_Internal: theIsArrowsExternal = false; break;
1418 gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1419 Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1421 // Add margin to ensure a small tail between text and arrow
1422 Standard_Real anArrowMargin = aDimensionAspect->IsText3d()
1423 ? aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN
1426 Standard_Real anArrowsWidth = (anArrowLength + anArrowMargin) * 2.0;
1428 theIsArrowsExternal = aDimensionWidth < aLabelWidth + anArrowsWidth;
1433 // Handle user-defined and automatic text placement
1434 switch (theHorizontalTextPos)
1436 case Prs3d_DTHP_Left : theLabelPosition |= LabelPosition_Left; break;
1437 case Prs3d_DTHP_Right : theLabelPosition |= LabelPosition_Right; break;
1438 case Prs3d_DTHP_Center: theLabelPosition |= LabelPosition_HCenter; break;
1439 case Prs3d_DTHP_Fit:
1441 gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1442 Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1443 Standard_Real anArrowsWidth = anArrowLength * 2.0;
1444 Standard_Real aContentWidth = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth;
1446 theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter;
1451 switch (aDimensionAspect->TextVerticalPosition())
1453 case Prs3d_DTVP_Above : theLabelPosition |= LabelPosition_Above; break;
1454 case Prs3d_DTVP_Below : theLabelPosition |= LabelPosition_Below; break;
1455 case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;