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