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