Salome HOME
Issue #1299, #1393. The presentation should not be changed automatically by distance...
[modules/shaper.git] / src / SketcherPrs / AIS_AngleDimension.cxx
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
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <AIS_AngleDimension.hxx>
18
19 #include <AIS.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>
25 #include <ElCLib.hxx>
26 #include <GCPnts_UniformAbscissa.hxx>
27 #include <GC_MakeArcOfCircle.hxx>
28 #include <gce_MakeLin2d.hxx>
29 #include <gce_MakeLin.hxx>
30 #include <gce_MakeCirc.hxx>
31 #include <gce_MakeCone.hxx>
32 #include <gce_MakePln.hxx>
33 #include <gce_MakeDir.hxx>
34 #include <Geom_Circle.hxx>
35 #include <Geom_TrimmedCurve.hxx>
36 #include <Geom_ConicalSurface.hxx>
37 #include <Geom_SurfaceOfRevolution.hxx>
38 #include <Geom_OffsetSurface.hxx>
39 #include <Graphic3d_ArrayOfSegments.hxx>
40 #include <Graphic3d_Group.hxx>
41 #include <Graphic3d_ArrayOfPolylines.hxx>
42 #include <IntAna2d_AnaIntersection.hxx>
43 #include <ProjLib.hxx>
44 #include <Prs3d_Root.hxx>
45 #include <Prs3d_ShadingAspect.hxx>
46 #include <PrsMgr_PresentationManager3d.hxx>
47 #include <Select3D_SensitiveGroup.hxx>
48 #include <Select3D_SensitiveSegment.hxx>
49 #include <SelectMgr_Selection.hxx>
50 #include <Standard_ProgramError.hxx>
51 #include <UnitsAPI.hxx>
52
53 IMPLEMENT_STANDARD_HANDLE (AIS_AngleDimension, AIS_Dimension)
54 IMPLEMENT_STANDARD_RTTIEXT (AIS_AngleDimension, AIS_Dimension)
55
56 namespace
57 {
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;
62 };
63
64 //=======================================================================
65 //function : Constructor
66 //purpose  : 
67 //=======================================================================
68 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
69                                         const TopoDS_Edge& theSecondEdge,
70                                         const Standard_Boolean& theUseLongestDistance)
71 : AIS_Dimension (AIS_KOD_PLANEANGLE)
72 {
73   Init();
74   SetMeasuredGeometry (theFirstEdge, theSecondEdge, theUseLongestDistance);
75 }
76
77 //=======================================================================
78 //function : Constructor
79 //purpose  : 
80 //=======================================================================
81 AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint,
82                                         const gp_Pnt& theSecondPoint,
83                                         const gp_Pnt& theThirdPoint)
84 : AIS_Dimension (AIS_KOD_PLANEANGLE)
85 {
86   Init();
87   SetMeasuredGeometry (theFirstPoint, theSecondPoint, theThirdPoint);
88 }
89
90 //=======================================================================
91 //function : Constructor
92 //purpose  : 
93 //=======================================================================
94 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Vertex& theFirstVertex,
95                                         const TopoDS_Vertex& theSecondVertex,
96                                         const TopoDS_Vertex& theThirdVertex)
97 : AIS_Dimension (AIS_KOD_PLANEANGLE)
98 {
99   Init();
100   SetMeasuredGeometry (theFirstVertex, theSecondVertex, theThirdVertex);
101 }
102
103 //=======================================================================
104 //function : Constructor
105 //purpose  : 
106 //=======================================================================
107 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theCone)
108 : AIS_Dimension (AIS_KOD_PLANEANGLE)
109 {
110   Init();
111   SetMeasuredGeometry (theCone);
112 }
113
114 //=======================================================================
115 //function : Constructor
116 //purpose  : 
117 //=======================================================================
118 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
119                                         const TopoDS_Face& theSecondFace)
120 : AIS_Dimension (AIS_KOD_PLANEANGLE)
121 {
122   Init();
123   SetMeasuredGeometry (theFirstFace, theSecondFace);
124 }
125
126 //=======================================================================
127 //function : Constructor
128 //purpose  : 
129 //=======================================================================
130 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
131                                         const TopoDS_Face& theSecondFace,
132                                         const gp_Pnt& thePoint)
133 : AIS_Dimension (AIS_KOD_PLANEANGLE)
134 {
135   Init();
136   SetMeasuredGeometry (theFirstFace, theSecondFace, thePoint);
137 }
138
139 //=======================================================================
140 //function : SetMeasuredGeometry
141 //purpose  : 
142 //=======================================================================
143 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge,
144                                               const TopoDS_Edge& theSecondEdge,
145                                               const Standard_Boolean& theUseLongestDistance)
146 {
147   gp_Pln aComputedPlane;
148
149   myFirstShape      = theFirstEdge;
150   mySecondShape     = theSecondEdge;
151   myThirdShape      = TopoDS_Shape();
152   myGeometryType    = GeometryType_Edges;
153   myIsGeometryValid = InitTwoEdgesAngle (aComputedPlane, theUseLongestDistance);
154
155   if (myIsGeometryValid && !myIsPlaneCustom)
156   {
157     ComputePlane();
158   }
159
160   SetToUpdate();
161 }
162
163 //=======================================================================
164 //function : SetMeasuredGeometry
165 //purpose  : 
166 //=======================================================================
167 void AIS_AngleDimension::SetMeasuredGeometry (const gp_Pnt& theFirstPoint,
168                                               const gp_Pnt& theSecondPoint,
169                                               const gp_Pnt& theThirdPoint)
170 {
171   myFirstPoint    = theFirstPoint;
172   myCenterPoint   = theSecondPoint;
173   mySecondPoint   = theThirdPoint;
174   myFirstShape    = BRepLib_MakeVertex (myFirstPoint);
175   mySecondShape   = BRepLib_MakeVertex (myCenterPoint);
176   myThirdShape    = BRepLib_MakeVertex (mySecondPoint);
177   myGeometryType  = GeometryType_Points;
178   myIsGeometryValid       = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
179
180   if (myIsGeometryValid && !myIsPlaneCustom)
181   {
182     ComputePlane();
183   }
184
185   SetToUpdate();
186 }
187
188 //=======================================================================
189 //function : SetMeasuredGeometry
190 //purpose  : 
191 //=======================================================================
192 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Vertex& theFirstVertex,
193                                               const TopoDS_Vertex& theSecondVertex,
194                                               const TopoDS_Vertex& theThirdVertex)
195 {
196   myFirstShape      = theFirstVertex;
197   mySecondShape     = theSecondVertex;
198   myThirdShape      = theThirdVertex;
199   myFirstPoint      = BRep_Tool::Pnt (theFirstVertex);
200   myCenterPoint     = BRep_Tool::Pnt (theSecondVertex);
201   mySecondPoint     = BRep_Tool::Pnt (theThirdVertex);
202   myGeometryType    = GeometryType_Points;
203   myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
204
205   if (myIsGeometryValid && !myIsPlaneCustom)
206   {
207     ComputePlane();
208   }
209
210   SetToUpdate();
211 }
212
213 //=======================================================================
214 //function : SetMeasuredGeometry
215 //purpose  : 
216 //=======================================================================
217 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theCone)
218 {
219   myFirstShape      = theCone;
220   mySecondShape     = TopoDS_Shape();
221   myThirdShape      = TopoDS_Shape();
222   myGeometryType    = GeometryType_Face;
223   myIsGeometryValid = InitConeAngle();
224
225   if (myIsGeometryValid && !myIsPlaneCustom)
226   {
227     ComputePlane();
228   }
229
230   SetToUpdate();
231 }
232
233 //=======================================================================
234 //function : SetMeasuredGeometry
235 //purpose  : 
236 //=======================================================================
237 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
238                                               const TopoDS_Face& theSecondFace)
239 {
240   myFirstShape      = theFirstFace;
241   mySecondShape     = theSecondFace;
242   myThirdShape      = TopoDS_Shape();
243   myGeometryType    = GeometryType_Faces;
244   myIsGeometryValid = InitTwoFacesAngle();
245
246   if (myIsGeometryValid && !myIsPlaneCustom)
247   {
248     ComputePlane();
249   }
250
251   SetToUpdate();
252 }
253
254 //=======================================================================
255 //function : SetMeasuredGeometry
256 //purpose  : 
257 //=======================================================================
258 void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
259                                               const TopoDS_Face& theSecondFace,
260                                               const gp_Pnt& thePoint)
261 {
262   myFirstShape      = theFirstFace;
263   mySecondShape     = theSecondFace;
264   myThirdShape      = TopoDS_Shape();
265   myGeometryType    = GeometryType_Faces;
266   myIsGeometryValid = InitTwoFacesAngle (thePoint);
267
268   if (myIsGeometryValid && !myIsPlaneCustom)
269   {
270     ComputePlane();
271   }
272
273   SetToUpdate();
274 }
275
276 //=======================================================================
277 //function : Init
278 //purpose  : 
279 //=======================================================================
280 void AIS_AngleDimension::Init()
281 {
282   SetAngleReversed (Standard_False);
283   SetArrowVisible (Standard_True, Standard_True);
284   SetSpecialSymbol (THE_DEGREE_SYMBOL);
285   SetDisplaySpecialSymbol (AIS_DSS_After);
286   SetFlyout (15.0);
287 }
288
289 //=======================================================================
290 //function: GetCenterOnArc
291 //purpose :
292 //=======================================================================
293 gp_Pnt AIS_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach,
294                                            const gp_Pnt& theSecondAttach,
295                                            const gp_Pnt& theCenter) const
296 {
297   // construct plane where the circle and the arc are located
298   gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
299   if (!aConstructPlane.IsDone())
300   {
301     return gp::Origin();
302   }
303   
304   gp_Pln aPlane = aConstructPlane.Value();
305
306   Standard_Real aRadius = theFirstAttach.Distance (theCenter);
307
308   // construct circle forming the arc
309   gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
310   if (!aConstructCircle.IsDone())
311   {
312     return gp::Origin();
313   }
314
315   gp_Circ aCircle = aConstructCircle.Value();
316
317   // compute angle parameters of arc end-points on circle
318   Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
319   Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
320   ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
321
322   return ElCLib::Value ((aParamBeg + aParamEnd) * 0.5, aCircle);
323 }
324
325 //=======================================================================
326 //function : DrawArc
327 //purpose  : draws the arc between two attach points
328 //=======================================================================
329 void AIS_AngleDimension::DrawArc (const Handle(Prs3d_Presentation)& thePresentation,
330                                   const gp_Pnt& theFirstAttach,
331                                   const gp_Pnt& theSecondAttach,
332                                   const gp_Pnt& theCenter,
333                                   const Standard_Real theRadius,
334                                   const Standard_Integer theMode)
335 {
336   // construct plane where the circle and the arc are located
337   gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
338   if (!aConstructPlane.IsDone())
339   {
340     return;
341   }
342
343   gp_Pln aPlane = aConstructPlane.Value();
344   if (myUseReverse) {
345     gp_Ax1 anAxis = aPlane.Axis();
346     gp_Dir aDir = anAxis.Direction();
347     aDir.Reverse();
348     aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
349   }
350   
351   // construct circle forming the arc
352   gce_MakeCirc aConstructCircle (theCenter, aPlane, theRadius);
353   if (!aConstructCircle.IsDone())
354   {
355     return;
356   }
357
358   gp_Circ aCircle = aConstructCircle.Value();
359
360   // construct the arc
361   GC_MakeArcOfCircle aConstructArc(aCircle, theFirstAttach, theSecondAttach, Standard_True);
362   if (!aConstructArc.IsDone())
363   {
364     return;
365   }
366
367   // generate points with specified deflection
368   const Handle(Geom_TrimmedCurve)& anArcCurve = aConstructArc.Value();
369   
370   GeomAdaptor_Curve anArcAdaptor (anArcCurve, anArcCurve->FirstParameter(), anArcCurve->LastParameter());
371
372   // compute number of discretization elements in old-fanshioned way
373   gp_Vec aCenterToFirstVec  (theCenter, theFirstAttach);
374   gp_Vec aCenterToSecondVec (theCenter, theSecondAttach);
375
376   gp_Ax1 anAxis = aPlane.Axis();
377   gp_Dir aDir = anAxis.Direction();
378   gp_Vec aRefVec(aDir);
379   Standard_Real anAngle = aCenterToFirstVec.AngleWithRef (aCenterToSecondVec, aRefVec);
380   if (anAngle < 0)
381     anAngle = 2.0 * M_PI + anAngle;
382   const Standard_Integer aNbPoints = Max (4, Standard_Integer (50.0 * anAngle / M_PI));
383
384   GCPnts_UniformAbscissa aMakePnts (anArcAdaptor, aNbPoints);
385   if (!aMakePnts.IsDone())
386   {
387     return;
388   }
389
390   // init data arrays for graphical and selection primitives
391   Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aNbPoints);
392
393   SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
394
395   // load data into arrays
396   for (Standard_Integer aPntIt = 1; aPntIt <= aMakePnts.NbPoints(); ++aPntIt)
397   {
398     gp_Pnt aPnt = anArcAdaptor.Value (aMakePnts.Parameter (aPntIt));
399
400     aPrimSegments->AddVertex (aPnt);
401
402     aSensitiveCurve.Append (aPnt);
403   }
404
405   // add display presentation
406   if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
407   {
408     Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True);
409   }
410   Handle(Graphic3d_AspectLine3d) aDimensionLineStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
411   Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionLineStyle);
412   Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
413   if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
414   {
415     Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False);
416   }
417 }
418
419 //=======================================================================
420 //function: DrawArcWithText
421 //purpose :
422 //=======================================================================
423 void AIS_AngleDimension::DrawArcWithText (const Handle(Prs3d_Presentation)& thePresentation,
424                                           const gp_Pnt& theFirstAttach,
425                                           const gp_Pnt& theSecondAttach,
426                                           const gp_Pnt& theCenter,
427                                           const TCollection_ExtendedString& theText,
428                                           const Standard_Real theTextWidth,
429                                           const Standard_Integer theMode,
430                                           const Standard_Integer theLabelPosition)
431 {
432   // construct plane where the circle and the arc are located
433   gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
434   if (!aConstructPlane.IsDone())
435   {
436     return;
437   }
438
439   gp_Pln aPlane = aConstructPlane.Value();
440
441   Standard_Real aRadius = theFirstAttach.Distance (myCenterPoint);
442
443   // construct circle forming the arc
444   gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
445   if (!aConstructCircle.IsDone())
446   {
447     return;
448   }
449
450   gp_Circ aCircle = aConstructCircle.Value();
451
452   // compute angle parameters of arc end-points on circle
453   Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
454   Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
455   ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
456
457   // middle point of arc parameter on circle
458   Standard_Real aParamMid = (aParamBeg + aParamEnd) * 0.5;
459
460   // add text graphical primitives
461   if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
462   {
463     gp_Pnt aTextPos = ElCLib::Value (aParamMid, aCircle);
464     gp_Dir aTextDir = gce_MakeDir (theFirstAttach, theSecondAttach);
465
466     // Drawing text
467     DrawText (thePresentation,
468               aTextPos,
469               aTextDir,
470               theText,
471               theLabelPosition);
472   }
473
474   if (theMode != ComputeMode_All && theMode != ComputeMode_Line)
475   {
476     return;
477   }
478
479   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
480
481   Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
482                               && aDimensionAspect->IsText3d();
483
484   if (isLineBreak)
485   {
486     // compute gap for label as parameteric size of sector on circle segment
487     Standard_Real aSectorOnCircle = theTextWidth / aRadius;
488   
489     gp_Pnt aTextPntBeg = ElCLib::Value (aParamMid - aSectorOnCircle * 0.5, aCircle);
490     gp_Pnt aTextPntEnd = ElCLib::Value (aParamMid + aSectorOnCircle * 0.5, aCircle);
491
492     // Drawing arcs
493     DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode);
494     DrawArc (thePresentation, theSecondAttach, aTextPntEnd, theCenter, aRadius, theMode);
495   }
496   else
497   {
498     DrawArc (thePresentation, theFirstAttach, theSecondAttach, theCenter, aRadius, theMode);
499   }
500 }
501
502 //=======================================================================
503 //function : CheckPlane
504 //purpose  : 
505 //=======================================================================
506 Standard_Boolean AIS_AngleDimension::CheckPlane (const gp_Pln& thePlane)const
507 {
508   if (!thePlane.Contains (myFirstPoint, Precision::Confusion()) &&
509       !thePlane.Contains (mySecondPoint, Precision::Confusion()) &&
510       !thePlane.Contains (myCenterPoint, Precision::Confusion()))
511   {
512     return Standard_False;
513   }
514
515   return Standard_True;
516 }
517
518 //=======================================================================
519 //function : ComputePlane
520 //purpose  : 
521 //=======================================================================
522 void AIS_AngleDimension::ComputePlane()
523 {
524   if (!myIsGeometryValid)
525   {
526     return;
527   }
528
529   gp_Vec aFirstVec   = gp_Vec (myCenterPoint, myFirstPoint).Normalized();
530   gp_Vec aSecondVec  = gp_Vec (myCenterPoint, mySecondPoint).Normalized();
531   gp_Vec aDirectionN = aSecondVec.Crossed (aFirstVec).Normalized();
532   gp_Vec aDirectionY = (aFirstVec + aSecondVec).Normalized();
533   gp_Vec aDirectionX = aDirectionY.Crossed (aDirectionN).Normalized();
534
535   myPlane = gp_Pln (gp_Ax3 (myCenterPoint, gp_Dir (aDirectionN), gp_Dir (aDirectionX)));
536 }
537
538 //=======================================================================
539 //function : GetModelUnits
540 //purpose  :
541 //=======================================================================
542 const TCollection_AsciiString& AIS_AngleDimension::GetModelUnits() const
543 {
544   return myDrawer->DimAngleModelUnits();
545 }
546
547 //=======================================================================
548 //function : GetDisplayUnits
549 //purpose  :
550 //=======================================================================
551 const TCollection_AsciiString& AIS_AngleDimension::GetDisplayUnits() const
552 {
553   return myDrawer->DimAngleDisplayUnits();
554 }
555
556 //=======================================================================
557 //function : SetModelUnits
558 //purpose  :
559 //=======================================================================
560 void AIS_AngleDimension::SetModelUnits (const TCollection_AsciiString& theUnits)
561 {
562   myDrawer->SetDimAngleModelUnits (theUnits);
563 }
564
565 //=======================================================================
566 //function : SetDisplayUnits
567 //purpose  :
568 //=======================================================================
569 void AIS_AngleDimension::SetDisplayUnits (const TCollection_AsciiString& theUnits)
570 {
571   myDrawer->SetDimAngleDisplayUnits (theUnits);
572 }
573
574 //=======================================================================
575 //function : ComputeValue
576 //purpose  : 
577 //=======================================================================
578 Standard_Real AIS_AngleDimension::ComputeValue() const
579 {
580   if (!IsValid())
581   {
582     return 0.0;
583   }
584
585   gp_Vec aVec1 (myCenterPoint, myFirstPoint);
586   gp_Vec aVec2 (myCenterPoint, mySecondPoint);
587
588   Standard_Real anAngle = aVec2.AngleWithRef (aVec1, GetPlane().Axis().Direction());
589
590   return anAngle > 0.0 ? anAngle : (2.0 * M_PI + anAngle);
591 }
592
593 //=======================================================================
594 //function : Compute
595 //purpose  : Having three gp_Pnt points compute presentation
596 //=======================================================================
597 void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePM*/,
598                                   const Handle(Prs3d_Presentation)& thePresentation,
599                                   const Standard_Integer theMode)
600 {
601   thePresentation->Clear();
602   mySelectionGeom.Clear (theMode);
603
604   if (!IsValid())
605   {
606     return;
607   }
608
609   // Parameters for presentation
610   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
611
612   Prs3d_Root::CurrentGroup(thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
613
614   Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
615
616   // prepare label string and compute its geometrical width
617   Standard_Real aLabelWidth;
618   TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
619
620   // add margins to label width
621   if (aDimensionAspect->IsText3d())
622   {
623     aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
624   }
625
626   // Get parameters from aspect or adjust it according with custom text position
627   Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
628   Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition();
629
630   if (IsTextPositionCustom())
631   {
632     AdjustParameters (myFixedTextPosition,anExtensionSize, aHorisontalTextPos, myFlyout);
633   }
634
635   // Handle user-defined and automatic arrow placement
636   Standard_Boolean isArrowsExternal = Standard_False;
637   Standard_Integer aLabelPosition = LabelPosition_None;
638
639   FitTextAlignment (aHorisontalTextPos, aLabelPosition, isArrowsExternal);
640
641   gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
642   gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
643
644   //Arrows positions and directions
645   gp_Vec aWPDir = gp_Vec (GetPlane().Axis().Direction());
646
647   gp_Dir aFirstExtensionDir  = aWPDir            ^ gp_Vec (myCenterPoint, aFirstAttach);
648   gp_Dir aSecondExtensionDir = aWPDir.Reversed() ^ gp_Vec (myCenterPoint, aSecondAttach);
649
650   gp_Vec aFirstArrowVec  = gp_Vec (aFirstExtensionDir)  * anArrowLength;
651   gp_Vec aSecondArrowVec = gp_Vec (aSecondExtensionDir) * anArrowLength;
652
653   gp_Pnt aFirstArrowBegin  (0.0, 0.0, 0.0);
654   gp_Pnt aFirstArrowEnd    (0.0, 0.0, 0.0);
655   gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0);
656   gp_Pnt aSecondArrowEnd   (0.0, 0.0, 0.0);
657
658   if (isArrowsExternal)
659   {
660     aFirstArrowVec.Reverse();
661     aSecondArrowVec.Reverse();
662   }
663
664   aFirstArrowBegin  = aFirstAttach;
665   aSecondArrowBegin = aSecondAttach;
666   aFirstArrowEnd    = aFirstAttach.Translated (-aFirstArrowVec);
667   aSecondArrowEnd   = aSecondAttach.Translated (-aSecondArrowVec);
668
669   // Group1: stenciling text and the angle dimension arc
670   Prs3d_Root::NewGroup (thePresentation);
671
672   Standard_Integer aHPosition = aLabelPosition & LabelPosition_HMask;
673
674   // draw text label
675   switch (aHPosition)
676   {
677     case LabelPosition_HCenter :
678     {
679       Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
680                                   && aDimensionAspect->IsText3d();
681
682       if (isLineBreak)
683       {
684         DrawArcWithText (thePresentation,
685                          aFirstAttach,
686                          aSecondAttach,
687                          myCenterPoint,
688                          aLabelString,
689                          aLabelWidth,
690                          theMode,
691                          aLabelPosition);
692         break;
693       }
694
695       // compute text primitives
696       if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
697       {
698         gp_Vec aDimensionDir (aFirstAttach, aSecondAttach);
699         gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition
700                                                 : GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
701         gp_Dir aTextDir = aDimensionDir;
702
703         DrawText (thePresentation,
704                   aTextPos,
705                   aTextDir,
706                   aLabelString,
707                   aLabelPosition);
708       }
709
710       if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
711       {
712         DrawArc (thePresentation,
713                  (isArrowsExternal || !myFirstArrowVisible) ? aFirstAttach : aFirstArrowEnd,
714                  (isArrowsExternal || !mySecondArrowVisible) ? aSecondAttach : aSecondArrowEnd,
715                  myCenterPoint,
716                  Abs (GetFlyout()),
717                  theMode);
718       }
719     }
720     break;
721
722     case LabelPosition_Left :
723     {
724       DrawExtension (thePresentation,
725                      anExtensionSize,
726                      (isArrowsExternal && myFirstArrowVisible) ? aFirstArrowEnd : aFirstAttach,
727                      aFirstExtensionDir,
728                      aLabelString,
729                      aLabelWidth,
730                      theMode,
731                      aLabelPosition);
732     }
733     break;
734
735     case LabelPosition_Right :
736     {
737       DrawExtension (thePresentation,
738                      anExtensionSize,
739                      (isArrowsExternal && mySecondArrowVisible) ? aSecondArrowEnd : aSecondAttach,
740                      aSecondExtensionDir,
741                      aLabelString,
742                      aLabelWidth,
743                      theMode,
744                      aLabelPosition);
745     }
746     break;
747   }
748
749   // dimension arc without text
750   if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && aHPosition != LabelPosition_HCenter)
751   {
752     Prs3d_Root::NewGroup (thePresentation);
753
754     DrawArc (thePresentation,
755              (isArrowsExternal || !myFirstArrowVisible) ? aFirstAttach  : aFirstArrowEnd,
756              (isArrowsExternal || !mySecondArrowVisible) ? aSecondAttach : aSecondArrowEnd,
757              myCenterPoint,
758              Abs(GetFlyout ()),
759              theMode);
760   }
761
762   // arrows and arrow extensions
763   if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
764   {
765     Prs3d_Root::NewGroup (thePresentation);
766
767     if (myFirstArrowVisible)
768       DrawArrow (thePresentation, aFirstArrowBegin,  gp_Dir (aFirstArrowVec));
769     if (mySecondArrowVisible)
770       DrawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec));
771   }
772
773   if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && isArrowsExternal)
774   {
775     Prs3d_Root::NewGroup (thePresentation);
776
777     if (aHPosition != LabelPosition_Left && myFirstArrowVisible)
778     {
779       DrawExtension (thePresentation,
780                      aDimensionAspect->ArrowTailSize(),
781                      aFirstArrowEnd,
782                      aFirstExtensionDir,
783                      THE_EMPTY_LABEL_STRING,
784                      THE_EMPTY_LABEL_WIDTH,
785                      theMode,
786                      LabelPosition_None);
787     }
788
789     if (aHPosition != LabelPosition_Right && mySecondArrowVisible)
790     {
791       DrawExtension (thePresentation,
792                      aDimensionAspect->ArrowTailSize(),
793                      aSecondArrowEnd,
794                      aSecondExtensionDir,
795                      THE_EMPTY_LABEL_STRING,
796                      THE_EMPTY_LABEL_WIDTH,
797                      theMode,
798                      LabelPosition_None);
799     }
800   }
801
802   // flyouts
803   if (theMode == ComputeMode_All)
804   {
805     Prs3d_Root::NewGroup (thePresentation);
806
807     Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (4);
808     aPrimSegments->AddVertex (myCenterPoint);
809     aPrimSegments->AddVertex (aFirstAttach);
810     aPrimSegments->AddVertex (myCenterPoint);
811     aPrimSegments->AddVertex (aSecondAttach);
812
813     Handle(Graphic3d_AspectLine3d) aFlyoutStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
814     Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aFlyoutStyle);
815     Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
816   }
817
818   mySelectionGeom.IsComputed = Standard_True;
819 }
820
821 //=======================================================================
822 //function : ComputeFlyoutSelection
823 //purpose  : computes selection for flyouts
824 //=======================================================================
825 void AIS_AngleDimension::ComputeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection,
826                                                  const Handle(SelectMgr_EntityOwner)& theOwner)
827 {
828   gp_Pnt aFirstAttach  = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized()  * GetFlyout());
829   gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
830
831   Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner);
832   aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aFirstAttach));
833   aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aSecondAttach));
834
835   theSelection->Add (aSensitiveEntity);
836 }
837
838 //=======================================================================
839 //function : InitTwoEdgesAngle
840 //purpose  : 
841 //=======================================================================
842 Standard_Boolean AIS_AngleDimension::InitTwoEdgesAngle (gp_Pln& theComputedPlane,
843                                                         const Standard_Boolean& theUseLongestDistance)
844 {
845   TopoDS_Edge aFirstEdge  = TopoDS::Edge (myFirstShape);
846   TopoDS_Edge aSecondEdge = TopoDS::Edge (mySecondShape);
847
848   BRepAdaptor_Curve aMakeFirstLine  (aFirstEdge);
849   BRepAdaptor_Curve aMakeSecondLine (aSecondEdge);
850
851   if (aMakeFirstLine.GetType() != GeomAbs_Line || aMakeSecondLine.GetType() != GeomAbs_Line)
852   {
853     return  Standard_False;
854   }
855
856   Handle(Geom_Line) aFirstLine  = new Geom_Line (aMakeFirstLine.Line());
857   Handle(Geom_Line) aSecondLine = new Geom_Line (aMakeSecondLine.Line());
858
859   gp_Lin aFirstLin  = aFirstLine->Lin();
860   gp_Lin aSecondLin = aSecondLine->Lin();
861
862   Standard_Boolean isParallelLines = Abs (aFirstLin.Angle (aSecondLin) - M_PI) <= Precision::Angular();
863
864   gp_Pnt aPoint  = aFirstLine->Value (0.0);
865   gp_Dir aNormal = isParallelLines
866                      ? gp_Vec (aSecondLin.Normal (aPoint).Direction()) ^ gp_Vec (aSecondLin.Direction())
867                      : gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction());
868
869   theComputedPlane = gp_Pln (aPoint, aNormal);
870
871     // Compute geometry for this plane and edges
872   Standard_Boolean isInfinite1,isInfinite2;
873   gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2;
874   gp_Lin2d aFirstLin2d, aSecondLin2d;
875
876   if (!AIS::ComputeGeometry (aFirstEdge, aSecondEdge,
877                              aFirstLine, aSecondLine,
878                              aFirstPoint1, aLastPoint1,
879                              aFirstPoint2, aLastPoint2,
880                              isInfinite1, isInfinite2))
881   {
882     return Standard_False;
883   }
884
885   if (aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular()))
886   {
887     myFirstPoint  = aFirstLin.Location();
888     mySecondPoint = ElCLib::Value (ElCLib::Parameter (aFirstLin, myFirstPoint), aSecondLin);
889
890     if (mySecondPoint.Distance (myFirstPoint) <= Precision::Confusion())
891     {
892       mySecondPoint.Translate (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout()));
893     }
894
895     myCenterPoint.SetXYZ ((myFirstPoint.XYZ() + mySecondPoint.XYZ()) / 2.0);
896   }
897   else
898   {
899     // Find intersection
900     gp_Lin2d aFirstLin2d  = ProjLib::Project (theComputedPlane, aFirstLin);
901     gp_Lin2d aSecondLin2d = ProjLib::Project (theComputedPlane, aSecondLin);
902
903     IntAna2d_AnaIntersection anInt2d (aFirstLin2d, aSecondLin2d);
904     gp_Pnt2d anIntersectPoint;
905     if (!anInt2d.IsDone() || anInt2d.IsEmpty())
906     {
907       return Standard_False;
908     }
909
910     anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value());
911     myCenterPoint = ElCLib::To3d (theComputedPlane.Position().Ax2(), anIntersectPoint);
912
913     if (isInfinite1 || isInfinite2)
914     {
915       myFirstPoint  = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
916       mySecondPoint = myCenterPoint.Translated (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout()));
917
918       return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
919     }
920
921     // |
922     // | <- dimension should be here
923     // *----
924     if (theUseLongestDistance) {
925       myFirstPoint  = myCenterPoint.Distance (aFirstPoint1) > myCenterPoint.Distance (aLastPoint1)
926                     ? aFirstPoint1
927                     : aLastPoint1;
928
929       mySecondPoint = myCenterPoint.Distance (aFirstPoint2) > myCenterPoint.Distance (aLastPoint2)
930                     ? aFirstPoint2
931                     : aLastPoint2;
932     } else {
933       myFirstPoint  = !myCenterPoint.IsEqual(aFirstPoint1, Precision::Confusion())
934                       ? aFirstPoint1
935                       : aLastPoint1;
936       mySecondPoint = !myCenterPoint.IsEqual(aFirstPoint2, Precision::Confusion())
937                       ? aFirstPoint2
938                       : aLastPoint2;
939     }
940   }
941
942   return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
943 }
944
945 //=======================================================================
946 //function : InitTwoFacesAngle
947 //purpose  : initialization of angle dimension between two faces
948 //=======================================================================
949 Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle()
950 {
951   TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
952   TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
953
954   gp_Dir aFirstDir, aSecondDir;
955   gp_Pln aFirstPlane, aSecondPlane;
956   Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
957   AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
958   Standard_Real aFirstOffset, aSecondOffset;
959
960   AIS::GetPlaneFromFace (aFirstFace, aFirstPlane,
961                          aFirstBasisSurf,aFirstSurfType,aFirstOffset);
962
963   AIS::GetPlaneFromFace (aSecondFace, aSecondPlane,
964                          aSecondBasisSurf, aSecondSurfType, aSecondOffset);
965
966   if (aFirstSurfType == AIS_KOS_Plane && aSecondSurfType == AIS_KOS_Plane)
967   {
968     //Planar faces angle
969     Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
970     Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
971     return AIS::InitAngleBetweenPlanarFaces (aFirstFace,
972                                              aSecondFace,
973                                              myCenterPoint,
974                                              myFirstPoint,
975                                              mySecondPoint)
976            && IsValidPoints (myFirstPoint,
977                              myCenterPoint,
978                              mySecondPoint);
979   }
980   else
981   {
982     // Curvilinear faces angle
983     return AIS::InitAngleBetweenCurvilinearFaces (aFirstFace,
984                                                   aSecondFace,
985                                                   aFirstSurfType,
986                                                   aSecondSurfType,
987                                                   myCenterPoint,
988                                                   myFirstPoint,
989                                                   mySecondPoint)
990            && IsValidPoints (myFirstPoint,
991                              myCenterPoint,
992                              mySecondPoint);
993   }
994 }
995
996 //=======================================================================
997 //function : InitTwoFacesAngle
998 //purpose  : initialization of angle dimension between two faces
999 //=======================================================================
1000 Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle (const gp_Pnt thePointOnFirstFace)
1001 {
1002   TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
1003   TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
1004
1005   gp_Dir aFirstDir, aSecondDir;
1006   gp_Pln aFirstPlane, aSecondPlane;
1007   Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
1008   AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
1009   Standard_Real aFirstOffset, aSecondOffset;
1010
1011   AIS::GetPlaneFromFace (aFirstFace, aFirstPlane,
1012                          aFirstBasisSurf,aFirstSurfType,aFirstOffset);
1013
1014   AIS::GetPlaneFromFace (aSecondFace, aSecondPlane,
1015                          aSecondBasisSurf, aSecondSurfType, aSecondOffset);
1016
1017   myFirstPoint = thePointOnFirstFace;
1018   if (aFirstSurfType == AIS_KOS_Plane && aSecondSurfType == AIS_KOS_Plane)
1019   {
1020     //Planar faces angle
1021     Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
1022     Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
1023     return AIS::InitAngleBetweenPlanarFaces (aFirstFace,
1024                                              aSecondFace,
1025                                              myCenterPoint,
1026                                              myFirstPoint,
1027                                              mySecondPoint,
1028                                              Standard_True)
1029            && IsValidPoints (myFirstPoint,
1030                              myCenterPoint,
1031                              mySecondPoint);
1032   }
1033   else
1034   {
1035     // Curvilinear faces angle
1036     return AIS::InitAngleBetweenCurvilinearFaces (aFirstFace,
1037                                                   aSecondFace,
1038                                                   aFirstSurfType,
1039                                                   aSecondSurfType,
1040                                                   myCenterPoint,
1041                                                   myFirstPoint,
1042                                                   mySecondPoint,
1043                                                   Standard_True)
1044            && IsValidPoints (myFirstPoint,
1045                              myCenterPoint,
1046                              mySecondPoint);
1047   }
1048 }
1049
1050 //=======================================================================
1051 //function : InitConeAngle
1052 //purpose  : initialization of the cone angle
1053 //=======================================================================
1054 Standard_Boolean AIS_AngleDimension::InitConeAngle()
1055 {
1056   if (myFirstShape.IsNull())
1057   {
1058     return Standard_False;
1059   }
1060
1061   TopoDS_Face aConeShape = TopoDS::Face (myFirstShape);
1062   gp_Pln aPln;
1063   gp_Cone aCone;
1064   gp_Circ aCircle;
1065   // A surface from the Face
1066   Handle(Geom_Surface) aSurf;
1067   Handle(Geom_OffsetSurface) aOffsetSurf; 
1068   Handle(Geom_ConicalSurface) aConicalSurf;
1069   Handle(Geom_SurfaceOfRevolution) aRevSurf;
1070   Handle(Geom_Line) aLine;
1071   BRepAdaptor_Surface aConeAdaptor (aConeShape);
1072   TopoDS_Face aFace;
1073   AIS_KindOfSurface aSurfType;
1074   Standard_Real anOffset = 0.;
1075   Handle(Standard_Type) aType;
1076
1077   Standard_Real aMaxV = aConeAdaptor.FirstVParameter();
1078   Standard_Real aMinV = aConeAdaptor.LastVParameter();
1079
1080   AIS::GetPlaneFromFace (aConeShape, aPln, aSurf, aSurfType, anOffset);
1081
1082   if (aSurfType == AIS_KOS_Revolution)
1083   {
1084     // Surface of revolution
1085     aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aSurf);
1086     gp_Lin aLin (aRevSurf->Axis());
1087     Handle(Geom_Curve) aBasisCurve = aRevSurf->BasisCurve();
1088     //Must be a part of line (basis curve should be linear)
1089     if (aBasisCurve ->DynamicType() != STANDARD_TYPE(Geom_Line))
1090       return Standard_False;
1091
1092     gp_Pnt aFirst1 = aConeAdaptor.Value (0., aMinV);
1093     gp_Pnt aLast1 = aConeAdaptor.Value (0., aMaxV);
1094     gp_Vec aVec1 (aFirst1, aLast1);
1095
1096     //Projection <aFirst> on <aLin>
1097     gp_Pnt aFirst2 = ElCLib::Value (ElCLib::Parameter (aLin, aFirst1), aLin);
1098     // Projection <aLast> on <aLin>
1099     gp_Pnt aLast2 = ElCLib::Value (ElCLib::Parameter (aLin, aLast1), aLin);
1100
1101     gp_Vec aVec2 (aFirst2, aLast2);
1102
1103     // Check if two parts of revolution are parallel (it's a cylinder) or normal (it's a circle).
1104     if (aVec1.IsParallel (aVec2, Precision::Angular())
1105         || aVec1.IsNormal (aVec2,Precision::Angular()))
1106       return Standard_False;
1107
1108     gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1);
1109     aCone =  aMkCone.Value();
1110     myCenterPoint = aCone.Apex();
1111   }
1112   else
1113   {
1114     aType = aSurf->DynamicType();
1115     if (aType == STANDARD_TYPE(Geom_OffsetSurface) || anOffset > 0.01)
1116     {
1117       // Offset surface
1118       aOffsetSurf = new Geom_OffsetSurface (aSurf, anOffset);
1119       aSurf = aOffsetSurf->Surface();
1120       BRepBuilderAPI_MakeFace aMkFace(aSurf, Precision::Confusion());
1121       aMkFace.Build();
1122       if (!aMkFace.IsDone())
1123         return Standard_False;
1124       aConeAdaptor.Initialize (aMkFace.Face());
1125     }
1126     aCone = aConeAdaptor.Cone();
1127     aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf);
1128     myCenterPoint =  aConicalSurf->Apex();
1129   }
1130
1131   // A circle where the angle is drawn
1132   Handle(Geom_Curve) aCurve;
1133   Standard_Real aMidV = ( aMinV + aMaxV ) / 2.5;
1134   aCurve = aSurf->VIso (aMidV);
1135   aCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
1136
1137   aCurve = aSurf->VIso(aMaxV);
1138   gp_Circ aCircVmax = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1139   aCurve = aSurf->VIso(aMinV);
1140   gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1141
1142   if (aCircVmax.Radius() < aCircVmin.Radius())
1143   {
1144    gp_Circ aTmpCirc = aCircVmax;
1145    aCircVmax = aCircVmin;
1146    aCircVmin = aTmpCirc;
1147   }
1148
1149   myFirstPoint  = ElCLib::Value (0, aCircle);
1150   mySecondPoint = ElCLib::Value (M_PI, aCircle);
1151   return Standard_True;
1152 }
1153
1154 //=======================================================================
1155 //function : IsValidPoints
1156 //purpose  : 
1157 //=======================================================================
1158 Standard_Boolean AIS_AngleDimension::IsValidPoints (const gp_Pnt& theFirstPoint,
1159                                                     const gp_Pnt& theCenterPoint,
1160                                                     const gp_Pnt& theSecondPoint) const
1161 {
1162   return theFirstPoint.Distance (theCenterPoint) > Precision::Confusion()
1163       && theSecondPoint.Distance (theCenterPoint) > Precision::Confusion()
1164       && gp_Vec (theCenterPoint, theFirstPoint).Angle (
1165            gp_Vec (theCenterPoint, theSecondPoint)) > Precision::Angular();
1166 }
1167
1168 //=======================================================================
1169 //function : GetTextPosition
1170 //purpose  : 
1171 //=======================================================================
1172 const gp_Pnt AIS_AngleDimension::GetTextPosition() const
1173 {
1174   if (!IsValid())
1175   {
1176     return gp::Origin();
1177   }
1178
1179   if (IsTextPositionCustom())
1180   {
1181     return myFixedTextPosition;
1182   }
1183
1184   // Counts text position according to the dimension parameters
1185   gp_Pnt aTextPosition (gp::Origin());
1186
1187   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1188
1189   // Prepare label string and compute its geometrical width
1190   Standard_Real aLabelWidth;
1191   TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1192
1193   gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1194   gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1195
1196   // Handle user-defined and automatic arrow placement
1197   Standard_Boolean isArrowsExternal = Standard_False;
1198   Standard_Integer aLabelPosition = LabelPosition_None;
1199   FitTextAlignment (aDimensionAspect->TextHorizontalPosition(),
1200                     aLabelPosition, isArrowsExternal);
1201
1202   // Get text position
1203   switch (aLabelPosition & LabelPosition_HMask)
1204   {
1205   case LabelPosition_HCenter:
1206     {
1207       aTextPosition = GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
1208     }
1209     break;
1210   case LabelPosition_Left:
1211     {
1212       gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1213       gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aFirstAttach);
1214       Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1215       Standard_Real anOffset = isArrowsExternal
1216           ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1217           : anExtensionSize;
1218       gp_Vec anExtensionVec  = gp_Vec (anExtensionDir) * -anOffset;
1219       aTextPosition = aFirstAttach.Translated (anExtensionVec);
1220     }
1221     break;
1222   case LabelPosition_Right:
1223     {
1224       gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1225       gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aSecondAttach);
1226       Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1227       Standard_Real anOffset = isArrowsExternal
1228           ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1229           : anExtensionSize;
1230       gp_Vec anExtensionVec  = gp_Vec (anExtensionDir) * anOffset;
1231       aTextPosition = aSecondAttach.Translated (anExtensionVec);
1232     }
1233     break;
1234   }
1235
1236   return aTextPosition;
1237 }
1238
1239 //=======================================================================
1240 //function : SetTextPosition
1241 //purpose  : 
1242 //=======================================================================
1243 void AIS_AngleDimension::SetTextPosition (const gp_Pnt& theTextPos)
1244 {
1245   if (!IsValid())
1246   {
1247     return;
1248   }
1249
1250   // The text position point for angle dimension should belong to the working plane.
1251   if (!GetPlane().Contains (theTextPos, Precision::Confusion()))
1252   {
1253     Standard_ProgramError::Raise ("The text position point for angle dimension doesn't belong to the working plane.");
1254   }
1255
1256   myIsTextPositionFixed = Standard_True;
1257   myFixedTextPosition = theTextPos;
1258 }
1259
1260 //=======================================================================
1261 //function : SetAngleReversed
1262 //purpose  : 
1263 //=======================================================================
1264 void AIS_AngleDimension::SetAngleReversed(const Standard_Boolean& theUseReverse)
1265 {
1266   myUseReverse = theUseReverse;
1267 }
1268
1269 //=======================================================================
1270 //function : SetArrowVisible
1271 //purpose  : 
1272 //=======================================================================
1273 void AIS_AngleDimension::SetArrowVisible(const Standard_Boolean& theFirstArrowVisible,
1274                                          const Standard_Boolean& theSecondArrowVisible)
1275 {
1276   myFirstArrowVisible = theFirstArrowVisible;
1277   mySecondArrowVisible = theSecondArrowVisible;
1278 }
1279
1280 //=======================================================================
1281 //function : AdjustParameters
1282 //purpose  : 
1283 //=======================================================================
1284 void AIS_AngleDimension::AdjustParameters (const gp_Pnt& theTextPos,
1285                                            Standard_Real& theExtensionSize,
1286                                            Prs3d_DimensionTextHorizontalPosition& theAlignment,
1287                                            Standard_Real& theFlyout) const
1288 {
1289   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1290   Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1291
1292   // Build circle with radius that is equal to distance from text position to the center point.
1293   Standard_Real aRadius = gp_Vec (myCenterPoint, theTextPos).Magnitude();
1294
1295   // Set attach points in positive direction of the flyout.
1296   gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * aRadius);
1297   gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * aRadius);
1298
1299   gce_MakeCirc aConstructCircle (myCenterPoint, GetPlane(), aRadius);
1300   if (!aConstructCircle.IsDone())
1301   {
1302     return;
1303   }
1304   gp_Circ aCircle = aConstructCircle.Value();
1305
1306   // Default values
1307   theExtensionSize = aDimensionAspect->ArrowAspect()->Length();
1308   theAlignment = Prs3d_DTHP_Center;
1309
1310   Standard_Real aParamBeg = ElCLib::Parameter (aCircle, aFirstAttach);
1311   Standard_Real aParamEnd = ElCLib::Parameter (aCircle, aSecondAttach);
1312   if (aParamEnd < aParamBeg)
1313   {
1314     Standard_Real aParam = aParamEnd;
1315     aParamEnd = aParamBeg;
1316     aParamBeg = aParam;
1317   }
1318
1319   ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1320   Standard_Real aTextPar = ElCLib::Parameter (aCircle , theTextPos);
1321
1322   // Horizontal center
1323   if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1324   {
1325     theFlyout = aRadius;
1326     return;
1327   }
1328
1329   aParamBeg += M_PI;
1330   aParamEnd += M_PI;
1331   ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1332
1333   if (aTextPar > aParamBeg  && aTextPar < aParamEnd)
1334   {
1335     theFlyout = -aRadius;
1336     return;
1337   }
1338
1339   // Text on the extensions
1340   gp_Lin aFirstLine = gce_MakeLin (myCenterPoint, myFirstPoint);
1341   gp_Lin aSecondLine = gce_MakeLin (myCenterPoint, mySecondPoint);
1342   gp_Pnt aFirstTextProj = AIS::Nearest (aFirstLine, theTextPos);
1343   gp_Pnt aSecondTextProj = AIS::Nearest (aSecondLine, theTextPos);
1344   Standard_Real aFirstDist = aFirstTextProj.Distance (theTextPos);
1345   Standard_Real aSecondDist = aSecondTextProj.Distance (theTextPos);
1346
1347   if (aFirstDist <= aSecondDist)
1348   {
1349     aRadius = myCenterPoint.Distance (aFirstTextProj);
1350     Standard_Real aNewExtensionSize = aFirstDist - anArrowLength;
1351     theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1352
1353     theAlignment = Prs3d_DTHP_Left;
1354
1355     gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, myFirstPoint).Normalized().Scaled (aRadius);
1356
1357     theFlyout = aFirstTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1358                 ? -aRadius : aRadius;
1359   }
1360   else
1361   {
1362     aRadius = myCenterPoint.Distance (aSecondTextProj);
1363
1364     Standard_Real aNewExtensionSize = aSecondDist - anArrowLength;
1365
1366     theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1367
1368     theAlignment = Prs3d_DTHP_Right;
1369
1370     gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, mySecondPoint).Normalized().Scaled (aRadius);
1371
1372     theFlyout = aSecondTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1373                 ? -aRadius : aRadius;
1374   }
1375 }
1376
1377 //=======================================================================
1378 //function : FitTextAlignment
1379 //purpose  : 
1380 //=======================================================================
1381 void AIS_AngleDimension::FitTextAlignment (const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos,
1382                                            Standard_Integer& theLabelPosition,
1383                                            Standard_Boolean& theIsArrowsExternal) const
1384 {
1385   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1386
1387   Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1388
1389   // Prepare label string and compute its geometrical width
1390   Standard_Real aLabelWidth;
1391   TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1392
1393   // add margins to label width
1394   if (aDimensionAspect->IsText3d())
1395   {
1396     aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
1397   }
1398
1399   gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1400   gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1401
1402   // Handle user-defined and automatic arrow placement
1403   switch (aDimensionAspect->ArrowOrientation())
1404   {
1405     case Prs3d_DAO_External: theIsArrowsExternal = true; break;
1406     case Prs3d_DAO_Internal: theIsArrowsExternal = false; break;
1407     case Prs3d_DAO_Fit:
1408     {
1409       gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1410       Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1411
1412       // Add margin to ensure a small tail between text and arrow
1413       Standard_Real anArrowMargin   = aDimensionAspect->IsText3d() 
1414                                     ? aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN
1415                                     : 0.0;
1416
1417       Standard_Real anArrowsWidth   = (anArrowLength + anArrowMargin) * 2.0;
1418
1419       theIsArrowsExternal = aDimensionWidth < aLabelWidth + anArrowsWidth;
1420       break;
1421     }
1422   }
1423
1424   // Handle user-defined and automatic text placement
1425   switch (theHorizontalTextPos)
1426   {
1427     case Prs3d_DTHP_Left  : theLabelPosition |= LabelPosition_Left; break;
1428     case Prs3d_DTHP_Right : theLabelPosition |= LabelPosition_Right; break;
1429     case Prs3d_DTHP_Center: theLabelPosition |= LabelPosition_HCenter; break;
1430     case Prs3d_DTHP_Fit:
1431     {
1432       gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1433       Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1434       Standard_Real anArrowsWidth   = anArrowLength * 2.0;
1435       Standard_Real aContentWidth   = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth;
1436
1437       theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter;
1438       break;
1439     }
1440   }
1441
1442   switch (aDimensionAspect->TextVerticalPosition())
1443   {
1444     case Prs3d_DTVP_Above  : theLabelPosition |= LabelPosition_Above; break;
1445     case Prs3d_DTVP_Below  : theLabelPosition |= LabelPosition_Below; break;
1446     case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;
1447   }
1448 }