0024133: Development of improvement of dimensions implementation; new length, radius...
[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-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21 #include <AIS_AngleDimension.hxx>
22
23 #include <AIS.hxx>
24 #include <AIS_Dimension.hxx>
25 #include <AIS_DimensionOwner.hxx>
26 #include <AIS_Drawer.hxx>
27 #include <BRep_Tool.hxx>
28 #include <BRepBuilderAPI_MakeFace.hxx>
29 #include <BRepAdaptor_Curve.hxx>
30 #include <BRepAdaptor_Surface.hxx>
31 #include <BRepLib_MakeVertex.hxx>
32
33 #include <DsgPrs.hxx>
34 #include <DsgPrs_AnglePresentation.hxx>
35
36 #include <ElCLib.hxx>
37 #include <ElSLib.hxx>
38
39 #include <GC_MakeCircle.hxx>
40 #include <GC_MakeConicalSurface.hxx>
41 #include <gce_MakeLin.hxx>
42 #include <gce_MakeLin2d.hxx>
43 #include <gce_MakePln.hxx>
44 #include <gce_MakeCirc.hxx>
45 #include <gce_MakeCone.hxx>
46 #include <Geom2d_Circle.hxx>
47 #include <Geom2d_Curve.hxx>
48 #include <Geom2d_Line.hxx>
49 #include <Geom2dAPI_ExtremaCurveCurve.hxx>
50 #include <GeomAPI.hxx>
51 #include <Geom_Circle.hxx>
52 #include <Geom_Line.hxx>
53 #include <Geom_Plane.hxx>
54 #include <Geom_TrimmedCurve.hxx>
55 #include <Geom_Surface.hxx>
56 #include <Geom_CylindricalSurface.hxx>
57 #include <Geom_ConicalSurface.hxx>
58 #include <Geom_SurfaceOfRevolution.hxx>
59 #include <Geom_SurfaceOfLinearExtrusion.hxx>
60 #include <Geom_OffsetSurface.hxx>
61 #include <GeomAPI_ExtremaCurveCurve.hxx>
62 #include <Graphic3d_ArrayOfSegments.hxx>
63 #include <Graphic3d_AspectLine3d.hxx>
64 #include <gp.hxx>
65 #include <gp_Ax1.hxx>
66 #include <gp_Lin.hxx>
67 #include <gp_Cone.hxx>
68 #include <gp_Pln.hxx>
69 #include <gp_Pnt.hxx>
70 #include <gp_Pnt2d.hxx>
71 #include <gp_Vec.hxx> 
72 #include <gp_XYZ.hxx>
73 #include <Graphic3d_Group.hxx>
74 #include <Graphic3d_ArrayOfPrimitives.hxx>
75 #include <Graphic3d_ArrayOfPolylines.hxx>
76
77 #include <IntAna2d_AnaIntersection.hxx>
78 #include <IntAna2d_IntPoint.hxx>
79 #include <IntAna_QuadQuadGeo.hxx>
80 #include <IntAna_ResultType.hxx>
81 #include <Poly_Polygon3D.hxx>
82 #include <Precision.hxx>
83 #include <ProjLib.hxx>
84 #include <Prs3d_ArrowAspect.hxx>
85 #include <Prs3d_DimensionAspect.hxx>
86 #include <Prs3d_Drawer.hxx>
87 #include <Prs3d_Root.hxx>
88 #include <PrsMgr_PresentationManager3d.hxx>
89 #include <Select3D_SensitiveCurve.hxx>
90 #include <Select3D_SensitiveSegment.hxx>
91 #include <Select3D_SensitiveBox.hxx>
92 #include <SelectMgr_EntityOwner.hxx>
93 #include <SelectMgr_Selection.hxx>
94 #include <Standard_NotImplemented.hxx>
95 #include <Standard_Type.hxx>
96 #include <Standard_Macro.hxx>
97 #include <Standard_DefineHandle.hxx>
98
99 #include <TColStd_Array1OfReal.hxx>
100 #include <TopExp.hxx>
101 #include <TopExp_Explorer.hxx>
102 #include <TopoDS.hxx>
103 #include <TopoDS_Shape.hxx>
104 #include <TopoDS_Vertex.hxx>
105 #include <UnitsAPI.hxx>
106
107 IMPLEMENT_STANDARD_HANDLE (AIS_AngleDimension, AIS_Dimension)
108 IMPLEMENT_STANDARD_RTTIEXT (AIS_AngleDimension, AIS_Dimension)
109
110 //=======================================================================
111 //function : init
112 //purpose  : Private constructor for default initialization
113 //=======================================================================
114
115 void AIS_AngleDimension::init()
116 {
117   // Default values of units
118   UnitsAPI::SetLocalSystem (UnitsAPI_SI);
119   SetUnitsQuantity ("PLANE ANGLE");
120   SetModelUnits ("rad");
121   SetDisplayUnits ("deg");
122   SetSpecialSymbol (0x00B0);
123   SetDisplaySpecialSymbol (AIS_DSS_After);
124   MakeUnitsDisplayed (Standard_False);
125 }
126
127 //=======================================================================
128 //function : Constructor
129 //purpose  : Two edges dimension
130 //=======================================================================
131
132 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
133                                         const TopoDS_Edge& theSecondEdge)
134 : AIS_Dimension(),
135   myIsFlyoutLines (Standard_True),
136   myFlyout (15.0)
137 {
138   init();
139   myShapesNumber = 2;
140   SetKindOfDimension (AIS_KOD_PLANEANGLE);
141   myFirstShape  = theFirstEdge;
142   mySecondShape = theSecondEdge;
143 }
144
145 //=======================================================================
146 //function : Constructor
147 //purpose  : Two edges dimension
148 //           <thePlane> is used in case of Angle=PI
149 //=======================================================================
150
151 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
152                                         const TopoDS_Edge& theSecondEdge,
153                                         const gp_Pln& thePlane)
154 : AIS_Dimension(),
155   myIsFlyoutLines (Standard_True),
156   myFlyout (15.0)
157 {
158   init();
159   myShapesNumber = 2;
160   SetKindOfDimension (AIS_KOD_PLANEANGLE);
161   myFirstShape  = theFirstEdge;
162   mySecondShape = theSecondEdge;
163   SetWorkingPlane (thePlane);
164 }
165
166 //=======================================================================
167 //function : Constructor
168 //purpose  : Two edges dimension with aspect
169 //           <thePlane> is used in case of Angle=PI
170 //=======================================================================
171
172 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
173                                         const TopoDS_Edge& theSecondEdge,
174                                         const gp_Pln& thePlane,
175                                         const Handle(Prs3d_DimensionAspect)& theDimensionAspect,
176                                         const Standard_Real theExtensionSize)
177 : AIS_Dimension (theDimensionAspect,theExtensionSize),
178   myIsFlyoutLines (Standard_True),
179   myFlyout (15.0)
180 {
181   myShapesNumber = 2;
182   SetKindOfDimension (AIS_KOD_PLANEANGLE);
183   myFirstShape  = theFirstEdge;
184   mySecondShape = theSecondEdge;
185   SetWorkingPlane (thePlane);
186 }
187
188 //=======================================================================
189 //function : Constructor
190 //purpose  : Three points dimension
191 //=======================================================================
192
193 AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint,
194                                         const gp_Pnt& theSecondPoint,
195                                         const gp_Pnt& theThirdPoint)
196 : AIS_Dimension(),
197   myIsFlyoutLines (Standard_True),
198   myFlyout (15.0)
199 {
200   init();
201   myIsInitialized = Standard_True;
202   SetKindOfDimension (AIS_KOD_PLANEANGLE);
203   myFirstPoint   = theFirstPoint;
204   myCenter       = theSecondPoint;
205   mySecondPoint  = theThirdPoint;
206   myShapesNumber = 3;
207 }
208
209 //=======================================================================
210 //function : Constructor
211 //purpose  : Three points dimension
212 //=======================================================================
213
214 AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint,
215                                         const gp_Pnt& theSecondPoint,
216                                         const gp_Pnt& theThirdPoint,
217                                         const Handle(Prs3d_DimensionAspect)& theDimensionAspect,
218                                         const Standard_Real theExtensionSize)
219 : AIS_Dimension (theDimensionAspect,theExtensionSize),
220   myIsFlyoutLines (Standard_True),
221   myFlyout (15.0)
222 {
223   myIsInitialized = Standard_True;
224   SetKindOfDimension (AIS_KOD_PLANEANGLE);
225   myFirstPoint   = theFirstPoint;
226   myCenter       = theSecondPoint;
227   mySecondPoint  = theThirdPoint;
228   myShapesNumber =3;
229 }
230
231 //=======================================================================
232 //function : Constructor
233 //purpose  : Cone dimension
234 //=======================================================================
235
236 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theCone)
237 : AIS_Dimension(),
238   myIsFlyoutLines (Standard_True),
239   myFlyout (15.0)
240 {
241   init();
242   myIsInitialized = Standard_False;
243   SetKindOfDimension (AIS_KOD_PLANEANGLE);
244   myFirstShape   = theCone;
245   myShapesNumber = 1;
246 }
247
248 //=======================================================================
249 //function : Constructor
250 //purpose  : Two faces dimension
251 //=======================================================================
252
253 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
254                                         const TopoDS_Face& theSecondFace,
255                                         const gp_Ax1& theAxis)
256 : AIS_Dimension(),
257   myIsFlyoutLines (Standard_True),
258   myFlyout (15.0)
259 {
260   init();
261   myIsInitialized = Standard_False;
262   SetKindOfDimension (AIS_KOD_PLANEANGLE);
263   myFirstShape   = theFirstFace;
264   mySecondShape  = theSecondFace;
265   myShapesNumber = 2;
266   gp_Pln aPlane;
267   aPlane.SetAxis (theAxis);
268   SetWorkingPlane (aPlane);
269 }
270
271 //=======================================================================
272 //function : SetFirstShape
273 //purpose  : 
274 //=======================================================================
275
276 void AIS_AngleDimension::SetFirstShape (const TopoDS_Shape& theShape,
277                                         const Standard_Boolean isSingleShape /*= Standard_False*/)
278 {
279   AIS_Dimension::SetFirstShape (theShape);
280   if (isSingleShape)
281     myShapesNumber = 1;
282 }
283
284 //=======================================================================
285 //function : aboveInBelowCone
286 //purpose  : Returns 1 if <theC> center is above of <theCMin> center;
287 //                   0 if <theC> center is between <theCMin> and
288 //                        <theCMax> centers;
289 //                  -1 if <theC> center is below <theCMax> center.
290 //=======================================================================
291
292 Standard_Integer AIS_AngleDimension::aboveInBelowCone (const gp_Circ &theCMax,
293                                                        const gp_Circ &theCMin,
294                                                        const gp_Circ &theC)
295 {
296   const Standard_Real aD  = theCMax.Location().Distance (theCMin.Location());
297   const Standard_Real aD1 = theCMax.Location().Distance (theC.Location());
298   const Standard_Real aD2 = theCMin.Location().Distance (theC.Location());
299
300   if (aD >= aD1 && aD >= aD2) return  0;
301   if (aD  < aD2 && aD1 < aD2) return -1;
302   if (aD  < aD1 && aD2 < aD1) return  1;
303   return 0;
304 }
305
306 //=======================================================================
307 //function : initConeAngle
308 //purpose  : initialization of the cone angle
309 //=======================================================================
310
311 Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone)
312 {
313   if (theCone.IsNull ())
314     return Standard_False;
315
316   gp_Pln aPln;
317   gp_Cone aCone;
318   gp_Circ aCircle;
319   // A surface from the Face
320   Handle(Geom_Surface) aSurf;
321   Handle(Geom_OffsetSurface) aOffsetSurf; 
322   Handle(Geom_ConicalSurface) aConicalSurf;
323   Handle(Geom_SurfaceOfRevolution) aRevSurf;
324   Handle(Geom_Line) aLine;
325   BRepAdaptor_Surface aConeAdaptor (theCone);
326   TopoDS_Face aFace;
327   AIS_KindOfSurface aSurfType;
328   Standard_Real anOffset = 0.;
329   Handle(Standard_Type) aType;
330
331   Standard_Real aMaxV = aConeAdaptor.FirstVParameter();
332   Standard_Real aMinV = aConeAdaptor.LastVParameter();
333
334   AIS::GetPlaneFromFace(theCone, aPln, aSurf, aSurfType, anOffset);
335
336   if (aSurfType == AIS_KOS_Revolution)
337   {
338     // Surface of revolution
339     aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aSurf);
340     gp_Lin aLin (aRevSurf->Axis());
341     Handle(Geom_Curve) aBasisCurve = aRevSurf->BasisCurve();
342     //Must be a part of line (basis curve should be linear)
343     if (aBasisCurve ->DynamicType() != STANDARD_TYPE(Geom_Line))
344       return Standard_False;
345
346     gp_Pnt aFirst1 = aConeAdaptor.Value (0., aMinV);
347     gp_Pnt aLast1 = aConeAdaptor.Value (0., aMaxV);
348     gp_Vec aVec1 (aFirst1, aLast1);
349
350     //Projection <aFirst> on <aLin>
351     gp_Pnt aFirst2 = ElCLib::Value (ElCLib::Parameter (aLin, aFirst1), aLin);
352     // Projection <aLast> on <aLin>
353     gp_Pnt aLast2 = ElCLib::Value (ElCLib::Parameter (aLin, aLast1), aLin);
354
355     gp_Vec aVec2 (aFirst2, aLast2);
356
357     // Check if two parts of revolution are parallel (it's a cylinder) or normal (it's a circle).
358     if (aVec1.IsParallel (aVec2, Precision::Angular())
359         || aVec1.IsNormal (aVec2,Precision::Angular()))
360       return Standard_False;
361
362     gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1);
363     aCone =  aMkCone.Value();
364     myCenter = aCone.Apex();
365   }
366   else
367   {
368     aType = aSurf->DynamicType();
369     if (aType == STANDARD_TYPE(Geom_OffsetSurface) || anOffset > 0.01)
370     {
371       // Offset surface
372       aOffsetSurf = new Geom_OffsetSurface (aSurf, anOffset);
373       aSurf = aOffsetSurf->Surface();
374       BRepBuilderAPI_MakeFace aMkFace(aSurf, Precision::Confusion());
375       aMkFace.Build();
376       if (!aMkFace.IsDone())
377         return Standard_False;
378       aConeAdaptor.Initialize (aMkFace.Face());
379     }
380     aCone = aConeAdaptor.Cone();
381     aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf);
382     myCenter =  aConicalSurf->Apex();
383   }
384
385   // A circle where the angle is drawn
386   Handle(Geom_Curve) aCurve;
387   Standard_Real aMidV = ( aMinV + aMaxV ) / 2.5;
388   aCurve = aSurf->VIso (aMidV);
389   aCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
390
391   aCurve = aSurf->VIso(aMaxV);
392   gp_Circ aCircVmax = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
393   aCurve = aSurf->VIso(aMinV);
394   gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
395
396
397   if (aCircVmax.Radius() < aCircVmin.Radius())
398   {
399    gp_Circ aTmpCirc = aCircVmax;
400    aCircVmax = aCircVmin;
401    aCircVmin = aTmpCirc;
402   }
403
404   myFirstPoint  = ElCLib::Value (0, aCircle);
405   mySecondPoint = ElCLib::Value (M_PI, aCircle);
406   return Standard_True;
407 }
408
409 //=======================================================================
410 //function : initTwoFacesAngle
411 //purpose  : initialization of angle dimension between two faces
412 //=======================================================================
413
414 Standard_Boolean AIS_AngleDimension::initTwoFacesAngle ()
415 {
416   TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
417   TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
418   gp_Dir aFirstDir, aSecondDir;
419   gp_Pln aFirstPlane, aSecondPlane;
420   Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
421   AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
422   Standard_Real aFirstOffset, aSecondOffset;
423   
424   AIS::GetPlaneFromFace (aFirstFace, aFirstPlane,
425                          aFirstBasisSurf,aFirstSurfType,aFirstOffset);
426   AIS::GetPlaneFromFace (aSecondFace, aSecondPlane,
427                          aSecondBasisSurf, aSecondSurfType, aSecondOffset);
428
429   if (aFirstSurfType == AIS_KOS_Plane)
430   {
431     //Planar faces angle
432     AIS::ComputeAngleBetweenPlanarFaces (aFirstFace,
433                                         aSecondFace,
434                                         aSecondBasisSurf,
435                                         GetWorkingPlane().Axis(),
436                                         myValue,
437                                         Standard_True,
438                                         myGeom.myTextPosition,
439                                         myCenter,
440                                         myFirstPoint,
441                                         mySecondPoint,
442                                         aFirstDir,
443                                         aSecondDir);
444   }
445   else
446   {
447         // Curvilinear faces angle
448     Handle(Geom_Plane) aPlane = new Geom_Plane (GetWorkingPlane());
449     AIS::ComputeAngleBetweenCurvilinearFaces (aFirstFace,
450                                              aSecondFace,
451                                              aFirstBasisSurf,
452                                              aSecondBasisSurf,
453                                              aFirstSurfType,
454                                              aSecondSurfType,
455                                              GetWorkingPlane().Axis(),
456                                              myValue,
457                                              Standard_True,
458                                              myGeom.myTextPosition,
459                                              myCenter,
460                                              myFirstPoint,
461                                              mySecondPoint,
462                                              aFirstDir,
463                                              aSecondDir,
464                                              aPlane);
465     SetWorkingPlane (aPlane->Pln());
466   }
467   return Standard_True;
468 }
469
470 //=======================================================================
471 //function : SetFlyout
472 //purpose  : 
473 //=======================================================================
474
475 void AIS_AngleDimension::SetFlyout (const Standard_Real theFlyout)
476 {
477   myFlyout = theFlyout;
478 }
479
480 //=======================================================================
481 //function : GetFlyout
482 //purpose  : 
483 //=======================================================================
484
485 Standard_Real AIS_AngleDimension::GetFlyout () const
486 {
487   return myFlyout;
488 }
489
490 //=======================================================================
491 //function : countDefaultPlane
492 //purpose  : 
493 //=======================================================================
494
495 void AIS_AngleDimension::countDefaultPlane ()
496 {
497   if (!myIsInitialized)
498     return;
499   // Compute normal of the default plane.
500   gp_Vec aVec1(myCenter, myFirstPoint),
501          aVec2(myCenter, mySecondPoint);
502   myDefaultPlane = gp_Pln(myCenter, aVec1^aVec2);
503   // Set computed value to <myWorkingPlane>
504   ResetWorkingPlane ();
505 }
506
507 //=======================================================================
508 //function : computeValue
509 //purpose  : 
510 //=======================================================================
511
512 void AIS_AngleDimension::computeValue ()
513 {
514   gp_Vec aVec1 (myCenter, myFirstPoint),
515          aVec2 (myCenter, mySecondPoint);
516   myValue = aVec1.Angle (aVec2);
517   // To model units
518   AIS_Dimension::computeValue();
519 }
520
521 //=======================================================================
522 //function : initTwoEdgesAngle
523 //purpose  : Fill gp_Pnt fields for further presentation computation
524 //           If intersection between two edges doesn't exist
525 //           <myIsInitialized> is set to false
526 //=======================================================================
527
528 Standard_Boolean AIS_AngleDimension::initTwoEdgesAngle ()
529 {
530   // Data initialization
531   TopoDS_Edge aFirstEdge = TopoDS::Edge (myFirstShape);
532   TopoDS_Edge aSecondEdge = TopoDS::Edge (mySecondShape);
533   BRepAdaptor_Curve aMakeFirstLine (aFirstEdge);
534   BRepAdaptor_Curve aMakeSecondLine (aSecondEdge);
535
536   if (aMakeFirstLine.GetType() != GeomAbs_Line || aMakeSecondLine.GetType() != GeomAbs_Line)
537   {
538     return  Standard_False;
539   }
540
541   Handle(Geom_Line) aFirstLine  = new Geom_Line (aMakeFirstLine.Line());
542   Handle(Geom_Line) aSecondLine = new Geom_Line (aMakeSecondLine.Line());
543
544   gp_Lin aFirstLin  = aFirstLine->Lin ();
545   gp_Lin aSecondLin = aSecondLine->Lin ();
546   gp_Lin2d aFirstLin2d, aSecondLin2d;
547   Standard_Boolean isParallelLines = aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular());
548   Standard_Boolean isSameLines = isParallelLines && aFirstLin.Distance (aSecondLin.Location()) <= Precision::Confusion();
549   // In case where we can't compute plane automatically
550   if ((isParallelLines || isSameLines) && !myIsWorkingPlaneCustom)
551   {
552     return Standard_False;
553   }
554
555   gp_Pln aPlane;
556
557   /// PART 1 is for automatic plane computation from two edges if it is possible
558   // Build plane
559   if (!myIsWorkingPlaneCustom)
560   {
561     gp_Pnt aPoint = aFirstLine->Value (0.);
562     gp_Dir aNormal = isParallelLines
563                      ? gp_Vec(aSecondLin.Normal (aPoint).Direction()) ^ gp_Vec (aSecondLin.Direction())
564                      : gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction());
565     aPlane = gp_Pln (aPoint, aNormal);
566     resetWorkingPlane (aPlane);
567   }
568   else
569   {
570     aPlane = GetWorkingPlane();
571   }
572
573   // Compute geometry for this plane and edges
574   Standard_Boolean isInfinite1,isInfinite2;
575   gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2;
576   Standard_Integer anExtIndex = -1;
577   Handle(Geom_Curve) anExtCurve;
578   Handle(Geom_Plane) aGeomPlane = new Geom_Plane (aPlane);
579   if (!AIS::ComputeGeometry (aFirstEdge, aSecondEdge,
580                              anExtIndex,
581                              aFirstLine, aSecondLine,
582                              aFirstPoint1, aLastPoint1,
583                              aFirstPoint2, aLastPoint2,
584                              anExtCurve,
585                              isInfinite1, isInfinite2,
586                              aGeomPlane))
587   {
588     return Standard_False;
589   }
590
591   // Check if both edges are on this plane
592   if (!anExtCurve.IsNull())
593   {
594     if (anExtIndex == 1) // First curve is out of the plane
595     {
596       // Project curve on the plane
597       if (myIsWorkingPlaneCustom)
598       {
599         aFirstLin2d = ProjLib::Project (aPlane, aFirstLin);
600         aFirstLin = ElCLib::To3d (aPlane.Position().Ax2(), aFirstLin2d);
601       }
602       else
603       {
604         aFirstLin.Translate (gp_Vec (aFirstLin.Location(), aSecondLin.Location()));
605       }
606
607       aFirstLine = new Geom_Line (aFirstLin);
608     }
609     else if (anExtIndex == 2) // Second curve is out of the plane
610     {
611       if (myIsWorkingPlaneCustom)
612       {
613         aSecondLin2d = ProjLib::Project (aPlane, aSecondLin);
614         aSecondLin = ElCLib::To3d (aPlane.Position().Ax2(), aSecondLin2d);
615       }
616       else
617       {
618         aSecondLin.Translate (gp_Vec (aSecondLin.Location(), aFirstLin.Location()));
619       }
620
621       aSecondLine = new Geom_Line (aSecondLin);
622     }
623   }
624
625   /// PART 2 is for dimension computation using the working plane
626
627   if (aFirstLin.Direction ().IsParallel (aSecondLin.Direction (), Precision::Angular ()))
628   {
629     // Parallel lines
630     isSameLines = aFirstLin.Distance(aSecondLin.Location()) <= Precision::Confusion();
631     if (!isSameLines)
632       return Standard_False;
633
634      myFirstPoint = aFirstLin.Location();
635      mySecondPoint = ElCLib::Value (ElCLib::Parameter (aFirstLin, myFirstPoint), aSecondLin);
636      if (mySecondPoint.Distance (mySecondPoint) <= Precision::Confusion ())
637        mySecondPoint.Translate (gp_Vec (aSecondLin.Direction ())*Abs(GetFlyout()));
638      myCenter.SetXYZ( (myFirstPoint.XYZ() + mySecondPoint.XYZ()) / 2. );
639   }
640   else
641   {
642     // Find intersection
643     aFirstLin2d = ProjLib::Project (aPlane, aFirstLin);
644     aSecondLin2d = ProjLib::Project (aPlane, aSecondLin);
645
646     IntAna2d_AnaIntersection anInt2d (aFirstLin2d, aSecondLin2d);
647     gp_Pnt2d anIntersectPoint;
648     if (!anInt2d.IsDone() || anInt2d.IsEmpty())
649     {
650       return Standard_False;
651     }
652
653     anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value());
654     myCenter = ElCLib::To3d(aPlane.Position().Ax2(), anIntersectPoint);
655
656     if (isInfinite1 || isInfinite2)
657     {
658       myFirstPoint  = myCenter.Translated (gp_Vec (aFirstLin.Direction())*Abs (GetFlyout()));
659       mySecondPoint = myCenter.Translated (gp_Vec (aSecondLin.Direction())*Abs (GetFlyout()));
660       return Standard_True;
661     }
662
663     // |
664     // | <- dimension should be here
665     // *----
666     myFirstPoint  = myCenter.Distance (aFirstPoint1) > myCenter.Distance (aLastPoint1) ? aFirstPoint1 : aLastPoint1;
667     mySecondPoint = myCenter.Distance (aFirstPoint2) > myCenter.Distance (aLastPoint2) ? aFirstPoint2 : aLastPoint2;
668   }
669   return Standard_True;
670 }
671
672 //=======================================================================
673 //function : canTextBeInCenter
674 //purpose  : Auxiliary method to arrange text and arrows
675 //=======================================================================
676
677 Standard_Boolean AIS_AngleDimension::canTextBeInCenter (const gp_Pnt& theFirstAttach,
678                                                         const gp_Pnt& theSecondAttach,
679                                                         const Quantity_Length& theTextLength,
680                                                         const Quantity_Length& theArrowLength)
681 {
682   gp_Vec anAttachVector (theFirstAttach, theSecondAttach);
683   Standard_Real aValue = anAttachVector.Magnitude();
684   return (aValue < theTextLength + 2.*theArrowLength) ? Standard_False : Standard_True;
685 }
686
687 //=======================================================================
688 //function: getCenterOnArc
689 //purpose :
690 //=======================================================================
691 gp_Pnt AIS_AngleDimension::getCenterOnArc (const gp_Pnt& theFirstAttach,
692                                            const gp_Pnt& theSecondAttach)
693 {
694   gp_Pnt2d aCenter2d       = ProjLib::Project (GetWorkingPlane(), myCenter),
695            aFirstAttach2d  = ProjLib::Project (GetWorkingPlane(), theFirstAttach),
696            aSecondAttach2d = ProjLib::Project (GetWorkingPlane(), theSecondAttach);
697   gp_Lin2d anAttachLine2d = gce_MakeLin2d (aFirstAttach2d, aSecondAttach2d);
698
699   // Getting text center
700   gp_Pnt2d aTextCenterPnt = ElCLib::Value ((ElCLib::Parameter (anAttachLine2d, aFirstAttach2d) + ElCLib::Parameter (anAttachLine2d, aSecondAttach2d)) / 2., anAttachLine2d);
701   gp_Lin2d aCenterToTextCenterLin = gce_MakeLin2d (aCenter2d, aTextCenterPnt);
702
703   // Drawing circle
704   Standard_Real aRadius = theFirstAttach.Distance (myCenter);
705   gp_Circ2d aCircle (gp_Ax22d (aCenter2d, gp_Dir2d (1, 0)), aRadius);
706
707   // Getting text position in the center of arc
708   IntAna2d_AnaIntersection anInt2d (aCenterToTextCenterLin, aCircle);
709   gp_Pnt2d aTextCenterOnArc2d;
710   if (anInt2d.IsDone())
711     if (!anInt2d.IsEmpty())
712       aTextCenterOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value());
713   gp_Pnt aCenterOnArc = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextCenterOnArc2d);
714   return aCenterOnArc;
715 }
716
717 //=======================================================================
718 //function: drawArcWithText
719 //purpose :
720 //=======================================================================
721
722 void AIS_AngleDimension::drawArcWithText (const Handle(Prs3d_Presentation)& thePresentation,
723                                           const gp_Pnt& theFirstAttach,
724                                           const gp_Pnt& theSecondAttach,
725                                           const TCollection_ExtendedString& theText,
726                                           const AIS_DimensionDisplayMode theMode)
727 {
728   gp_Pnt2d aCenter2d       = ProjLib::Project (GetWorkingPlane(), myCenter),
729            aFirstAttach2d  = ProjLib::Project (GetWorkingPlane(), theFirstAttach),
730            aSecondAttach2d = ProjLib::Project (GetWorkingPlane(), theSecondAttach);
731   gp_Lin2d anAttachLine2d = gce_MakeLin2d (aFirstAttach2d, aSecondAttach2d);
732
733   // Getting text center
734   gp_Pnt2d aTextCenterPnt = ElCLib::Value ((ElCLib::Parameter (anAttachLine2d, aFirstAttach2d) + ElCLib::Parameter (anAttachLine2d, aSecondAttach2d)) / 2., anAttachLine2d);
735   gp_Lin2d aCenterToTextCenterLin = gce_MakeLin2d (aCenter2d, aTextCenterPnt);
736
737   // Drawing circle
738   Standard_Real aRadius = theFirstAttach.Distance (myCenter);
739   gp_Circ2d aCircle (gp_Ax22d (aCenter2d, gp_Dir2d (1, 0)), aRadius);
740
741   // Getting text position in the center of arc
742   IntAna2d_AnaIntersection anInt2d (aCenterToTextCenterLin, aCircle);
743   gp_Pnt2d aTextCenterOnArc2d;
744   if (anInt2d.IsDone())
745     if (!anInt2d.IsEmpty())
746       aTextCenterOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value());
747   myGeom.myTextPosition = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextCenterOnArc2d);
748
749   // Drawing text
750   gp_Vec aVec (theFirstAttach, theSecondAttach);
751   Standard_Real aTextWidth = drawText (thePresentation,
752                                        myIsTextReversed ? aVec.Reversed() : aVec,
753                                        theText,theMode);
754
755   // Getting text begin and end points
756   gp_Pnt2d aTextBeginPnt = ElCLib::Value ((ElCLib::Parameter (anAttachLine2d, aFirstAttach2d) +
757                                            ElCLib::Parameter (anAttachLine2d, aSecondAttach2d) -
758                                            aTextWidth) / 2., anAttachLine2d),
759            aTextEndPnt   = ElCLib::Value (ElCLib::Parameter (anAttachLine2d,aTextBeginPnt) + aTextWidth, anAttachLine2d);
760
761
762   gp_Lin2d aCenterToTextBeginLin = gce_MakeLin2d (aCenter2d, aTextBeginPnt),
763            aCenterToTextEndLin   = gce_MakeLin2d (aCenter2d, aTextEndPnt);
764
765   // Text begin and end on the dimension arc
766   gp_Pnt2d aTextBeginOnArc2d, aTextEndOnArc2d;
767   anInt2d.Perform (aCenterToTextBeginLin, aCircle);
768   if (anInt2d.IsDone())
769     if (!anInt2d.IsEmpty())
770       aTextBeginOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value());
771
772   anInt2d.Perform (aCenterToTextEndLin, aCircle);
773   if (anInt2d.IsDone())
774     if (!anInt2d.IsEmpty())
775       aTextEndOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value());
776
777   gp_Pnt aTextBeginOnArc = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextBeginOnArc2d);
778   gp_Pnt aTextEndOnArc   = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextEndOnArc2d);
779
780   // Drawing arcs
781   if (theMode != AIS_DDM_Text)
782   {
783     drawArc (thePresentation, theFirstAttach, aTextBeginOnArc, myCenter, aRadius, theMode);
784     drawArc (thePresentation, aTextEndOnArc, theSecondAttach, myCenter, aRadius, theMode);
785   }
786
787 }
788
789 //=======================================================================
790 //function : drawArc
791 //purpose  : draws the arc between two attach points
792 //=======================================================================
793
794 void AIS_AngleDimension::drawArc (const Handle(Prs3d_Presentation)& thePresentation,
795                                   const gp_Pnt& theFirstAttach,
796                                   const gp_Pnt& theSecondAttach,
797                                   const gp_Pnt& theCenter,
798                                   const Standard_Real theRadius,
799                                   const AIS_DimensionDisplayMode theMode)
800 {
801   Handle(SelectMgr_EntityOwner) anEmptyOwner;
802   Prs3d_Root::CurrentGroup (thePresentation)->
803     SetPrimitivesAspect(myDrawer->DimensionAspect()->LineAspect()->Aspect());
804
805   gp_Vec aCenterToFirstVec (theCenter,theFirstAttach);
806   gp_Vec aCenterToSecondVec (theCenter,theSecondAttach);
807   gp_Dir aCenterToFirstDir (aCenterToFirstVec);
808   gp_Dir aPlaneNormal = GetWorkingPlane().Axis().Direction();
809   gp_Dir aCenterToSecondDir = aPlaneNormal.Crossed (aCenterToFirstDir);
810
811   const Standard_Real anAngle = aCenterToFirstVec.Angle(aCenterToSecondVec);
812   const Standard_Integer aPointsOnArc = Max (4 , Standard_Integer (50. * anAngle / M_PI));
813   const Standard_Real anAngleStep = anAngle / (aPointsOnArc - 1);
814   TColgp_Array1OfPnt aPointArray (0,aPointsOnArc-1);
815   Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aPointsOnArc,2);
816   aPrimSegments->AddVertex (theFirstAttach);
817   aPointArray.SetValue(0, theFirstAttach);
818   gp_Pnt aPoint = theFirstAttach;
819   gp_Vec aVector;
820
821   for (Standard_Integer anI = 1; anI < aPointsOnArc - 1; ++anI)
822   {
823     aVector = (gp_Vec(aCenterToFirstDir) * Cos ( (anI - 1) * anAngleStep) + gp_Vec(aCenterToSecondDir) * Sin ( (anI - 1) * anAngleStep)) * theRadius;
824     aPoint = theCenter.Translated(aVector);
825     aPrimSegments->AddVertex(aPoint);
826     aPointArray.SetValue (anI,aPoint);
827   }
828   aPrimSegments->AddVertex (theSecondAttach);
829   aPointArray.SetValue (aPointsOnArc - 1,theSecondAttach);
830
831   // Fill sensitive list
832   myGeom.mySensitiveSegments.Append(new Select3D_SensitiveCurve(anEmptyOwner,aPointArray));
833
834   // Fill display presentation
835   if (!myDrawer->DimensionAspect()->IsText3d() && theMode == AIS_DDM_All)
836   {
837     Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True);
838   }
839   Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
840   if (!myDrawer->DimensionAspect()->IsText3d() && theMode == AIS_DDM_All)
841   {
842     Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False);
843   }
844 }
845
846 //=======================================================================
847 //function : Compute
848 //purpose  : Having three gp_Pnt points compute presentation
849 //=======================================================================
850
851 void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePM*/,
852                                   const Handle(Prs3d_Presentation)& thePresentation,
853                                   const Standard_Integer theMode)
854 {
855   thePresentation->Clear();
856   myGeom.mySensitiveSegments.Clear();
857   Handle(SelectMgr_EntityOwner) anEmptyOwner;
858
859   if (!myIsInitialized)
860   {
861     if (myShapesNumber == 1)
862     {
863       myIsInitialized = initConeAngle (TopoDS::Face (myFirstShape));
864     }
865     else if (myShapesNumber == 2)
866     {
867       switch (myFirstShape.ShapeType())
868       {
869       case TopAbs_FACE:
870         {
871           myIsInitialized = initTwoFacesAngle ();
872         }
873         break;
874       case TopAbs_EDGE:
875         {
876           myIsInitialized = initTwoEdgesAngle ();
877         }
878         break;
879       default:
880         return;
881       }
882     }
883     else
884       return;
885   }
886
887   // If initialization failed
888   if (!myIsInitialized)
889     return;
890
891   // Parameters for presentation
892   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
893   Prs3d_Root::CurrentGroup(thePresentation)->
894     SetPrimitivesAspect(aDimensionAspect->LineAspect()->Aspect());
895   Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
896   if (!myIsValueCustom)
897     computeValue ();
898   TCollection_ExtendedString aValueString;
899   Standard_Real aTextLength;
900   getTextWidthAndString (aTextLength, aValueString);
901   if (!myIsWorkingPlaneCustom)
902     countDefaultPlane();
903   gp_Pnt aFirstAttach = myCenter.Translated (gp_Vec(myCenter, myFirstPoint).Normalized() * GetFlyout());
904   gp_Pnt aSecondAttach = myCenter.Translated (gp_Vec(myCenter, mySecondPoint).Normalized() * GetFlyout());
905   // Attach points and radius
906   if (aDimensionAspect->HorizontalTextAlignment () == Prs3d_HTA_Center)
907   {
908     aDimensionAspect->SetArrowOrientation (Prs3d_DAO_Internal);
909
910     if (!canTextBeInCenter (aFirstAttach, aSecondAttach, aTextLength, anArrowLength))
911     {
912       aDimensionAspect->SetArrowOrientation (Prs3d_DAO_External);
913       aDimensionAspect->SetHorizontalTextAlignment (Prs3d_HTA_Left);
914     }
915   }
916   else
917     aDimensionAspect->SetArrowOrientation (Prs3d_DAO_External);
918
919   //Arrows positions and directions
920   gp_Vec aFirstArrowVec = (gp_Vec(myCenter, aFirstAttach)^gp_Vec(GetWorkingPlane().Axis().Direction())).Normalized().Reversed()*anArrowLength;
921   gp_Vec aSecondArrowVec = (gp_Vec(myCenter, aSecondAttach)^gp_Vec(GetWorkingPlane().Axis().Direction())).Normalized()*anArrowLength;
922
923   gp_Pnt aFirstArrowBegin,
924          aFirstArrowEnd,
925          aSecondArrowBegin,
926          aSecondArrowEnd;
927
928   if (aDimensionAspect->GetArrowOrientation() == Prs3d_DAO_External)
929   {
930     aFirstArrowVec.Reverse();
931     aSecondArrowVec.Reverse();
932
933     aFirstArrowBegin = aFirstAttach.Translated (aFirstArrowVec);
934     aFirstArrowEnd = aFirstAttach;
935     aSecondArrowBegin = aSecondAttach;
936     aSecondArrowEnd = aSecondAttach.Translated (aSecondArrowVec);
937   }
938   else
939   {
940     aFirstArrowBegin = aFirstAttach;
941     aFirstArrowEnd = aFirstAttach.Translated (aFirstArrowVec);
942     aSecondArrowBegin = aSecondAttach.Translated (aSecondArrowVec);
943     aSecondArrowEnd = aSecondAttach;
944   }
945
946   // Fill presentation
947   Handle(Graphic3d_ArrayOfSegments) aPrimSegments;
948   Standard_Boolean isTextInCenter = aDimensionAspect->VerticalTextAlignment() == Prs3d_VTA_Center;
949   if (aDimensionAspect->HorizontalTextAlignment() == Prs3d_HTA_Center)
950   {
951     // Important! Current implementation doesn't draw the extensions here
952     aPrimSegments = new Graphic3d_ArrayOfSegments (4);
953     // Get text begin and end positions (text is positioned in the center between two attach points)
954     gp_Pnt aTextBeginOnArc, aTextEndOnArc, anArcCenter;
955     if (isTextInCenter && aDimensionAspect->IsText3d())
956     {
957       drawArcWithText (thePresentation, aFirstAttach, aSecondAttach, aValueString, (AIS_DimensionDisplayMode)theMode);
958     }
959     else
960     {
961       gp_Vec aTextDir (aFirstArrowEnd, aSecondArrowBegin);
962       myGeom.myTextPosition = getCenterOnArc (aFirstArrowEnd, aSecondArrowBegin);
963       drawText (thePresentation,
964                 myIsTextReversed ? aTextDir.Reversed() : aTextDir,
965                 aValueString, (AIS_DimensionDisplayMode)theMode);
966       if (theMode != AIS_DDM_Text)
967         drawArc (thePresentation, aFirstArrowEnd, aSecondArrowBegin, myCenter, Abs (GetFlyout()), (AIS_DimensionDisplayMode)theMode);
968     }
969   }
970   else
971   {
972     // Lines for extensions
973     gp_Lin aLeftExtension (aFirstAttach,gp_Dir(aFirstArrowVec));
974     gp_Lin aRightExtension (aSecondAttach, gp_Dir(aSecondArrowVec));
975     aPrimSegments = new Graphic3d_ArrayOfSegments (6);
976     gp_Pnt aStartPoint;
977     if (aDimensionAspect->HorizontalTextAlignment() == Prs3d_HTA_Left)
978     {
979        aStartPoint = aFirstArrowBegin;
980        // Short extension
981        aPrimSegments->AddVertex (aSecondArrowEnd);
982        aPrimSegments->AddVertex (aSecondArrowEnd.Translated(gp_Vec(aRightExtension.Direction())*anArrowLength));
983        myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment(anEmptyOwner,
984                                           aSecondArrowEnd,
985                                           aSecondArrowEnd.Translated(gp_Vec(aRightExtension.Direction())*anArrowLength)));
986
987        // Long extension
988        drawExtensionWithText (thePresentation, aStartPoint, aLeftExtension, aValueString, (AIS_DimensionDisplayMode)theMode);
989     }
990     else // Prs3d_HTA_Right
991     {
992        aStartPoint = aSecondArrowEnd;
993        // Short extension
994        aPrimSegments->AddVertex (aFirstArrowBegin);
995        aPrimSegments->AddVertex (aFirstArrowBegin.Translated (gp_Vec (aLeftExtension.Direction()) * anArrowLength));
996        myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment(anEmptyOwner,
997                                           aFirstArrowBegin,
998                                           aFirstArrowBegin.Translated (gp_Vec (aLeftExtension.Direction()) * anArrowLength)));
999
1000        // Long extension
1001        drawExtensionWithText (thePresentation, aStartPoint, aRightExtension, aValueString, (AIS_DimensionDisplayMode)theMode);
1002     }
1003
1004     if (theMode != AIS_DDM_Text)
1005     {
1006       // Draw main arc
1007       drawArc (thePresentation, aFirstArrowEnd, aSecondArrowBegin, myCenter, Abs(GetFlyout ()), (AIS_DimensionDisplayMode)theMode);
1008     }
1009   }
1010
1011   // Draw flyout lines and arrows in new group.
1012   Prs3d_Root::NewGroup (thePresentation)
1013     ->SetPrimitivesAspect (myDrawer->DimensionAspect()->LineAspect()->Aspect());
1014   if (theMode == AIS_DDM_All && myIsFlyoutLines)
1015   {
1016     aPrimSegments->AddVertex (myCenter);
1017     aPrimSegments->AddVertex (aFirstAttach);
1018     aPrimSegments->AddVertex (myCenter);
1019     aPrimSegments->AddVertex (aSecondAttach);
1020   }
1021   if (theMode != AIS_DDM_Text)
1022   {
1023     Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
1024     drawArrow (thePresentation, aFirstAttach, gp_Dir (aFirstArrowVec));
1025     drawArrow (thePresentation, aSecondAttach, gp_Dir (aSecondArrowVec));
1026   }
1027
1028   setComputed (Standard_True);
1029 }