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