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