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