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