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