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