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