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