Salome HOME
21854: Add persistent dimensions
[modules/geom.git] / src / MeasureGUI / MeasureGUI_DimensionCreateTool.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // GEOM GEOMGUI : GUI for Geometry component
24 // File   : MeasureGUI_DimensionCreateTool.cxx
25 // Author : Anton POLETAEV, Open CASCADE S.A.S.
26
27 #include "MeasureGUI_DimensionCreateTool.h"
28
29 // GEOM includes
30 #include <GEOMBase.h>
31
32 // GUI includes
33 #include <SalomeApp_Application.h>
34
35 // SUIT includes
36 #include <OCCViewer_ViewModel.h>
37 #include <OCCViewer_ViewManager.h>
38 #include <OCCViewer_ViewWindow.h>
39 #include <OCCViewer_ViewPort3d.h>
40
41 // OCCT includes
42 #include <Adaptor3d_CurveOnSurface.hxx>
43 #include <BRep_Tool.hxx>
44 #include <BRepTools.hxx>
45 #include <BRepAdaptor_Curve.hxx>
46 #include <BRepAdaptor_Surface.hxx>
47 #include <BRepBndLib.hxx>
48 #include <ElCLib.hxx>
49 #include <gp_Pnt.hxx>
50 #include <gp_Circ.hxx>
51 #include <gp_Sphere.hxx>
52 #include <gp_Cone.hxx>
53 #include <gp_Torus.hxx>
54 #include <gce_MakeDir.hxx>
55 #include <gce_MakePln.hxx>
56 #include <gce_MakeCirc.hxx>
57 #include <GC_MakePlane.hxx>
58 #include <Geom_Circle.hxx>
59 #include <Geom_Plane.hxx>
60 #include <Geom_ElementarySurface.hxx>
61 #include <Geom_Surface.hxx>
62 #include <Geom_ConicalSurface.hxx>
63 #include <Geom_SphericalSurface.hxx>
64 #include <Geom_ToroidalSurface.hxx>
65 #include <Geom_TrimmedCurve.hxx>
66 #include <GeomLib.hxx>
67 #include <GeomLib_Tool.hxx>
68 #include <TopoDS_Shape.hxx>
69 #include <TopoDS_Vertex.hxx>
70 #include <TopoDS_Edge.hxx>
71 #include <TopExp.hxx>
72 #include <TopExp_Explorer.hxx>
73 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
74 #include <TopTools_ListOfShape.hxx>
75 #include <TopTools_ListIteratorOfListOfShape.hxx>
76 #include <TColgp_SequenceOfDir.hxx>
77 #include <V3d_View.hxx>
78
79 //=================================================================================
80 // function : Constructor
81 // purpose  :
82 //=================================================================================
83 MeasureGUI_DimensionCreateTool::MeasureGUI_DimensionCreateTool()
84 {
85   Settings.DefaultFlyout = 0.0;
86   Settings.ActiveView = NULL;
87 }
88
89 //=================================================================================
90 // function : LengthOnEdge
91 // purpose  :
92 //=================================================================================
93 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthOnEdge( const GEOM::GeomObjPtr& theMeasuredObj ) const
94 {
95   /* ---------------------------------------------------------------- *
96    *                  get the edge and parent shape                   *
97    * ---------------------------------------------------------------- */
98
99   TopoDS_Shape aMeasuredShape;
100   TopoDS_Shape aMainShape;
101   if ( !GEOMBase::GetShape( theMeasuredObj.operator ->(), aMeasuredShape ) )
102   {
103     return NULL;
104   }
105
106   if ( !GEOMBase::GetShape( GetMainShape( theMeasuredObj ).get(), aMainShape ) )
107   {
108     return NULL;
109   }
110
111   /* ------------------------------------------------- */
112   /*            check the input geometry               */
113   /* ------------------------------------------------- */
114
115   TopoDS_Edge anEdge = TopoDS::Edge( aMeasuredShape );
116
117   TopoDS_Vertex aVertex1;
118   TopoDS_Vertex aVertex2;
119   TopExp::Vertices( anEdge, aVertex1, aVertex2 );
120
121   gp_Pnt aPnt1 = BRep_Tool::Pnt( aVertex1 );
122   gp_Pnt aPnt2 = BRep_Tool::Pnt( aVertex2 );
123   if ( aPnt1.Distance( aPnt2 ) <= Precision::Confusion() )
124   {
125     return NULL;
126   }
127
128   /* ------------------------- *
129    *   position the dimension 
130    * ------------------------- */
131
132   Bnd_Box aBnd;
133   BRepBndLib::AddClose( aMainShape, aBnd );
134
135   // get face sides
136   TopTools_IndexedDataMapOfShapeListOfShape aRelationMap;
137   TopExp::MapShapesAndAncestors( aMainShape, TopAbs_EDGE, TopAbs_FACE, aRelationMap );
138   const TopTools_ListOfShape& aRelatedFaces = aRelationMap.FindFromKey( anEdge );
139
140   gp_Vec aFaceN1( gp::Origin(), gp::Origin() );
141   gp_Vec aFaceN2( gp::Origin(), gp::Origin() );
142   gp_Vec aFaceS1( gp::Origin(), gp::Origin() );
143   gp_Vec aFaceS2( gp::Origin(), gp::Origin() );
144
145   gp_Pnt aMiddlePnt = gp_Pnt( ( aPnt1.XYZ() + aPnt2.XYZ() ) * 0.5 );
146
147   TopTools_ListIteratorOfListOfShape aFaceIt( aRelatedFaces );
148
149   // get face side directions
150   if ( aFaceIt.More() )
151   {
152     TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
153
154     gp_Dir aSideDir;
155     if ( GetFaceSide( aFace, anEdge, aSideDir ) )
156     {
157       aFaceS1 = aSideDir;
158     }
159
160     Handle(Geom_Surface) aSurface = BRep_Tool::Surface( aFace );
161
162     Standard_Real aU = 0.0, aV = 0.0;
163     GeomLib_Tool::Parameters( aSurface, aMiddlePnt, Precision::Confusion(), aU, aV );
164
165     gp_Dir aNorm;
166     if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aU, aV ), Precision::Confusion(), aNorm ) <= 1 )
167     {
168       aFaceN1 = aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm;
169     }
170
171     aFaceIt.Next();
172   }
173
174   if ( aFaceIt.More() )
175   {
176     TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
177
178     gp_Dir aSideDir;
179     if ( GetFaceSide( aFace, anEdge, aSideDir ) )
180     {
181       aFaceS2 = aSideDir;
182     }
183
184     Handle(Geom_Surface) aSurface = BRep_Tool::Surface( aFace );
185
186     Standard_Real aU = 0.0, aV = 0.0;
187     GeomLib_Tool::Parameters( aSurface, aMiddlePnt, Precision::Confusion(), aU, aV );
188
189     gp_Dir aNorm;
190     if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aU, aV ), Precision::Confusion(), aNorm ) <= 1 )
191     {
192       aFaceN2 = aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm;
193     }
194   }
195
196   gp_Pln aPln;
197   PositionLength( aBnd, aFaceN1, aFaceN2, aFaceS1, aFaceS2, aPnt1, aPnt2, aPln );
198
199   /* --------------------------------------------------------- *
200    *   construct the dimension for the best selected position
201    * --------------------------------------------------------- */
202
203   Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension( anEdge, aPln );
204
205   aDimension->SetFlyout( Settings.DefaultFlyout );
206
207   if ( !aDimension->IsValid() )
208   {
209     return NULL;
210   }
211
212   return aDimension;
213 }
214
215 //=================================================================================
216 // function : LengthByPoints
217 // purpose  :
218 //=================================================================================
219 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthByPoints( const GEOM::GeomObjPtr& theMeasuredObj1,
220                                                                             const GEOM::GeomObjPtr& theMeasuredObj2 ) const
221 {
222   /* ---------------------------------------------------------------- *
223    *                  get the edge and parent shape                   *
224    * ---------------------------------------------------------------- */
225
226   TopoDS_Shape aMeasuredShape1;
227   TopoDS_Shape aMeasuredShape2;
228   TopoDS_Shape aMainShape;
229
230   if ( !GEOMBase::GetShape( theMeasuredObj1.operator ->(), aMeasuredShape1 ) )
231   {
232     return NULL;
233   }
234
235   if ( !GEOMBase::GetShape( theMeasuredObj2.operator ->(), aMeasuredShape2 ) )
236   {
237     return NULL;
238   }
239
240   if ( !GEOMBase::GetShape( GetMainShape( theMeasuredObj1 ).get(), aMainShape ) )
241   {
242     return NULL;
243   }
244
245   /* ------------------------------------------------- */
246   /*            check the input geometry               */
247   /* ------------------------------------------------- */
248
249   TopoDS_Vertex aVertex1 = TopoDS::Vertex( aMeasuredShape1 );
250   TopoDS_Vertex aVertex2 = TopoDS::Vertex( aMeasuredShape2 );
251
252   gp_Pnt aPnt1 = BRep_Tool::Pnt( aVertex1 );
253   gp_Pnt aPnt2 = BRep_Tool::Pnt( aVertex2 );
254   if ( aPnt1.Distance( aPnt2 ) <= Precision::Confusion() )
255   {
256     return NULL;
257   }
258
259   /* ------------------------- *
260    *   position the dimension 
261    * ------------------------- */
262
263   Bnd_Box aBnd;
264   BRepBndLib::AddClose( aMainShape, aBnd );
265
266   // check whether the points share same edge
267   TopExp_Explorer anEdgeExp( aMainShape, TopAbs_EDGE, TopAbs_EDGE );
268   for ( ; anEdgeExp.More(); anEdgeExp.Next() )
269   {
270     TopoDS_Vertex anEdgeV1;
271     TopoDS_Vertex anEdgeV2;
272     TopExp::Vertices( TopoDS::Edge( anEdgeExp.Current() ), anEdgeV1, anEdgeV2 );
273     gp_Pnt anEdgePnt1 = BRep_Tool::Pnt( anEdgeV1 );
274     gp_Pnt anEdgePnt2 = BRep_Tool::Pnt( anEdgeV2 );
275
276     if ( aPnt1.Distance( anEdgePnt1 ) <= Precision::Confusion() )
277     {
278       if ( aPnt2.Distance( anEdgePnt2 ) <= Precision::Confusion() )
279       {
280         break;
281       }
282     }
283
284     if ( aPnt2.Distance( anEdgePnt1 ) <= Precision::Confusion() )
285     {
286       if ( aPnt1.Distance( anEdgePnt2 ) <= Precision::Confusion() )
287       {
288         break;
289       }
290     }
291   }
292
293   gp_Vec aFaceN1( gp::Origin(), gp::Origin() );
294   gp_Vec aFaceN2( gp::Origin(), gp::Origin() );
295   gp_Vec aFaceS1( gp::Origin(), gp::Origin() );
296   gp_Vec aFaceS2( gp::Origin(), gp::Origin() );
297
298   // have shared edge
299   if ( anEdgeExp.More() )
300   {
301     TopoDS_Edge anEdge = TopoDS::Edge( anEdgeExp.Current() );
302     TopTools_IndexedDataMapOfShapeListOfShape aRelationMap;
303     TopExp::MapShapesAndAncestors( aMainShape, TopAbs_EDGE, TopAbs_FACE, aRelationMap );
304     const TopTools_ListOfShape& aRelatedFaces = aRelationMap.FindFromKey( anEdge );
305
306     gp_Pnt aMiddlePnt = gp_Pnt( ( aPnt1.XYZ() + aPnt2.XYZ() ) * 0.5 );
307
308     TopTools_ListIteratorOfListOfShape aFaceIt( aRelatedFaces );
309
310     // get face side directions
311     if ( aFaceIt.More() )
312     {
313       TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
314
315       gp_Dir aSideDir;
316       if ( GetFaceSide( aFace, anEdge, aSideDir ) )
317       {
318         aFaceS1 = aSideDir;
319       }
320
321       Handle(Geom_Surface) aSurface = BRep_Tool::Surface( aFace );
322
323       Standard_Real aU = 0.0, aV = 0.0;
324       GeomLib_Tool::Parameters( aSurface, aMiddlePnt, Precision::Confusion(), aU, aV );
325
326       gp_Dir aNorm;
327       if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aU, aV ), Precision::Confusion(), aNorm ) <= 1 )
328       {
329         aFaceN1 = aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm;
330       }
331
332       aFaceIt.Next();
333     }
334
335     if ( aFaceIt.More() )
336     {
337       TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
338
339       gp_Dir aSideDir;
340       if ( GetFaceSide( aFace, anEdge, aSideDir ) )
341       {
342         aFaceS2 = aSideDir;
343       }
344
345       Handle(Geom_Surface) aSurface = BRep_Tool::Surface( aFace );
346
347       Standard_Real aU = 0.0, aV = 0.0;
348       GeomLib_Tool::Parameters( aSurface, aMiddlePnt, Precision::Confusion(), aU, aV );
349
350       gp_Dir aNorm;
351       if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aU, aV ), Precision::Confusion(), aNorm ) <= 1 )
352       {
353         aFaceN2 = aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm;
354       }
355     }
356   }
357
358   gp_Pln aPln;
359   PositionLength( aBnd, aFaceN1, aFaceN2, aFaceS1, aFaceS2, aPnt1, aPnt2, aPln );
360
361   /* --------------------------------------------------------- *
362    *   construct the dimension for the best selected position
363    * --------------------------------------------------------- */
364
365   Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension( aPnt1, aPnt2, aPln );
366
367   aDimension->SetFlyout( Settings.DefaultFlyout );
368
369   if ( !aDimension->IsValid() )
370   {
371     return NULL;
372   }
373
374   return aDimension;
375 }
376
377 //=================================================================================
378 // function : LengthByParallelEdges
379 // purpose  :
380 //=================================================================================
381 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthByParallelEdges( const GEOM::GeomObjPtr& theEdge1,
382                                                                                    const GEOM::GeomObjPtr& theEdge2 ) const
383 {
384   TopoDS_Shape aFirstSh;
385   if ( !GEOMBase::GetShape( theEdge1.operator ->(), aFirstSh ) )
386   {
387     return NULL;
388   }
389
390   TopoDS_Shape aSecondSh;
391   if ( !GEOMBase::GetShape( theEdge2.operator ->(), aSecondSh ) )
392   {
393     return NULL;
394   }
395
396   TopoDS_Edge aFirstEdge  = TopoDS::Edge( aFirstSh );
397   TopoDS_Edge aSecondEdge = TopoDS::Edge( aSecondSh );
398
399   // Build plane through three points
400   BRepAdaptor_Curve aCurve1( aFirstEdge );
401   BRepAdaptor_Curve aCurve2( aSecondEdge );
402
403   gp_Pnt aPnt1 = aCurve1.Value( 0.1 );
404   gp_Pnt aPnt2 = aCurve1.Value( 0.9 );
405   gp_Pnt aPnt3 = aCurve2.Value( 0.5 );
406
407   GC_MakePlane aMkPlane( aPnt1, aPnt2, aPnt3 );
408   Handle(Geom_Plane) aPlane = aMkPlane.Value();
409
410   // check whether it is possible to compute valid dimension
411   Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension ( aFirstEdge, aSecondEdge, aPlane->Pln() );
412
413   aDimension->SetFlyout( Settings.DefaultFlyout );
414
415   if ( !aDimension->IsValid() )
416   {
417     return NULL;
418   }
419
420   return aDimension;
421 }
422
423 //=================================================================================
424 // function : Diameter
425 // purpose  :
426 //=================================================================================
427 Handle(AIS_DiameterDimension) MeasureGUI_DimensionCreateTool::Diameter( const GEOM::GeomObjPtr& theMeasuredObj ) const
428 {
429   /* ------------------------------------------------ *
430    *     get the shape and its parent (if exist)      *
431    * ------------------------------------------------ */
432
433   TopoDS_Shape aMeasuredShape;
434   TopoDS_Shape aMainShape;
435   if ( !GEOMBase::GetShape( theMeasuredObj.operator ->(), aMeasuredShape ) )
436   {
437     return NULL;
438   }
439
440   if ( !GEOMBase::GetShape( GetMainShape( theMeasuredObj ).get(), aMainShape ) )
441   {
442     return NULL;
443   }
444
445   Bnd_Box aBnd;
446   BRepBndLib::AddClose( aMainShape, aBnd );
447
448   /* ------------------------------------------------ *
449    *    get the dimension construction arguments      *
450    * ------------------------------------------------ */
451
452   Handle(Geom_Circle) aCircle;
453
454   Standard_Real aPmin = 0, aPmax = 2 * M_PI;
455
456   gp_Vec aFaceN( gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(0.0, 0.0, 0.0) );
457
458   switch ( aMeasuredShape.ShapeType() )
459   {
460     case TopAbs_FACE:
461     {
462       TopoDS_Face aMeasuredFace = TopoDS::Face(aMeasuredShape);
463
464       BRepAdaptor_Surface aSurf( aMeasuredFace );
465
466       Standard_Real aVmin = aSurf.FirstVParameter();
467       Standard_Real aVmax = aSurf.LastVParameter();
468
469       // get arguments of closed sphere
470       if ( aSurf.GetType() == GeomAbs_Sphere )
471       {
472         if ( !aSurf.IsUClosed() || !aSurf.IsVClosed() )
473         {
474           return NULL;
475         }
476
477         // take circle in XOY plane from sphere
478         gp_Sphere aSphere = aSurf.Sphere();
479         gp_Ax2 anAx2 = gp_Ax2( aSphere.Location(), gp::DZ() );
480         aCircle = new Geom_Circle( anAx2, aSphere.Radius() );
481         break;
482       }
483
484
485       // get arguments of closed torus
486       if ( aSurf.GetType() == GeomAbs_Torus )
487       {
488         if ( !aSurf.IsUClosed() || !aSurf.IsVClosed() )
489         {
490           return NULL;
491         }
492
493         gp_Torus aTorus = aSurf.Torus();
494         gp_Ax2 anAx2 = aTorus.Position().Ax2();
495         aCircle = new Geom_Circle( anAx2, aTorus.MinorRadius() );
496         break;
497       }
498
499       // get arguments of closed cone
500       if ( aSurf.GetType() == GeomAbs_Cone )
501       {
502         if ( !aSurf.IsUClosed() || !aSurf.IsVClosed() )
503         {
504           return NULL;
505         }
506
507         gp_Cone aCone = aSurf.Cone();
508         gp_Ax2 anAx2 = aCone.Position().Ax2();
509         aCircle = new Geom_Circle( anAx2, aCone.RefRadius() );
510
511         aFaceN = aCone.SemiAngle() > 0.0 
512           ?  anAx2.Axis().Direction()
513           : -anAx2.Axis().Direction();
514         break;
515       }
516
517       // get arguments of closed/opened cylinder
518       if ( aSurf.GetType() == GeomAbs_Cylinder )
519       {
520         Handle(Geom_Curve) aCurve = aSurf.Surface().Surface()->VIso( (aVmax + aVmin) * 0.5 );
521
522         if ( aCurve->IsKind( STANDARD_TYPE( Geom_Circle ) ) )
523         {
524           aPmin = aSurf.FirstUParameter();
525           aPmax = aSurf.LastUParameter();
526           aCircle = Handle(Geom_Circle)::DownCast( aCurve );
527         }
528         else if (  aCurve->IsKind( STANDARD_TYPE( Geom_TrimmedCurve ) ) )
529         {
530           Handle(Geom_TrimmedCurve) aTrimmedCurve = Handle(Geom_TrimmedCurve)::DownCast( aCurve );
531           aPmin = aTrimmedCurve->FirstParameter();
532           aPmax = aTrimmedCurve->LastParameter();
533
534           aCircle = Handle(Geom_Circle)::DownCast( aTrimmedCurve );
535         }
536
537         break;
538       }
539
540       // face containing edge?
541       TopExp_Explorer anExp( aMeasuredShape, TopAbs_EDGE );
542       if ( !anExp.More() )
543       {
544         return NULL;
545       }
546
547       TopoDS_Shape anExpEdge = anExp.Current();
548       if ( anExpEdge.IsNull() )
549       {
550         return NULL;
551       }
552
553       // only a single edge is expected
554       anExp.Next();
555       if ( anExp.More() )
556       {
557         return NULL;
558       }
559
560       // do not break, go to edge checking
561       aMeasuredShape = anExpEdge;
562     }
563
564     case TopAbs_EDGE:
565     {
566       TopoDS_Edge aMeasureEdge = TopoDS::Edge( aMeasuredShape );
567
568       BRepAdaptor_Curve aCurve(aMeasureEdge);
569
570       if ( aCurve.GetType() != GeomAbs_Circle )
571       {
572         return NULL;
573       }
574
575       aPmin = aCurve.FirstParameter();
576       aPmax = aCurve.LastParameter();
577
578       aCircle = new Geom_Circle( aCurve.Circle() );
579
580       // check if there is an parent face containing the edge
581       TopTools_IndexedDataMapOfShapeListOfShape aShapeMap;
582       TopExp::MapShapesAndAncestors( aMainShape, TopAbs_EDGE, TopAbs_FACE, aShapeMap );
583       const TopTools_ListOfShape& aFaces = aShapeMap.FindFromKey( aMeasureEdge );
584
585       TopTools_ListIteratorOfListOfShape aFaceIt( aFaces );
586       for ( ; aFaceIt.More(); aFaceIt.Next() )
587       {
588         Handle(Geom_Surface) aSurface = BRep_Tool::Surface( TopoDS::Face( aFaceIt.Value() ) );
589
590         gp_Pnt aCircCenter = aCircle->Circ().Location();
591         Standard_Real aCircU = 0.0, aCircV = 0.0;
592         GeomLib_Tool::Parameters( aSurface, aCircCenter, Precision::Confusion(), aCircU, aCircV );
593
594         gp_Dir aNorm;
595         if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aCircU, aCircV ), Precision::Confusion(), aNorm ) > 1 )
596         {
597           break;
598         }
599
600         if ( aNorm.Angle( aCircle->Circ().Axis().Direction() ) > M_PI * 0.25 )
601         {
602           continue;
603         }
604
605         aFaceN = gp_Vec( aNorm );
606       }
607     }
608     break;
609   }
610
611   if ( aCircle.IsNull() )
612   {
613     return NULL;
614   }
615
616   ElCLib::AdjustPeriodic( 0.0, M_PI * 2, Precision::PConfusion(), aPmin, aPmax );
617
618   /* ------------------------- *
619    *   position the dimension 
620    * ------------------------- */
621
622   gp_Pnt aPnt1;
623   gp_Pnt aPnt2;
624   gp_Pln aPln;
625
626   // diameter for closed circle
627   if ( Abs( ( aPmax - aPmin ) - M_PI * 2 ) <= Precision::PConfusion() )
628   {
629     PositionDiameter( aBnd, aFaceN, aCircle->Circ(), aPnt1, aPnt2, aPln );
630   }
631   // diameter for half-closed circle
632   else if ( Abs( aPmax - aPmin ) > M_PI )
633   {
634     Standard_Real anAnchor = aPmin + ( ( aPmax - aPmin ) - M_PI ) * 0.5;
635
636     PositionDiameter( aBnd, aFaceN, aCircle->Circ(), anAnchor, aPln );
637
638     aPnt1 = ElCLib::Value( anAnchor, aCircle->Circ() );
639     aPnt2 = ElCLib::Value( anAnchor + M_PI, aCircle->Circ() );
640   }
641   // diameter for less than half-closed circle
642   else
643   {
644     Standard_Real anAnchor = aPmin + ( aPmax - aPmin ) * 0.5;
645
646     PositionDiameter( aBnd, aFaceN, aCircle->Circ(), anAnchor, aPln );
647
648     aPnt1 = ElCLib::Value( anAnchor, aCircle->Circ() );
649     aPnt2 = ElCLib::Value( anAnchor + M_PI, aCircle->Circ() );
650   }
651
652   /* --------------------------------------------------------- *
653    *   construct the dimension for the best selected position
654    * --------------------------------------------------------- */
655
656   gp_Pnt aCircP = aCircle->Circ().Location();
657   gp_Dir aCircN = aCircle->Circ().Axis().Direction();
658   gp_Dir aCircX = gce_MakeDir( aPnt1, aPnt2 );
659   Standard_Real aCircR = aCircle->Circ().Radius();
660
661   // construct closed circle as base for the diameter dimension
662   gp_Circ aRuledCirc = gce_MakeCirc( gp_Ax2( aCircP, aCircN, aCircX ), aCircR );
663
664   Handle(AIS_DiameterDimension) aDimension = new AIS_DiameterDimension( aRuledCirc, aPln );
665
666   // if flyout is extended in tangent direction to circle, the default flyout value is used
667   // if flyout is extended in plane of circle, the zero flyout value is choosen initially
668   Standard_Real aFlyout = aCircN.IsParallel( aPln.Axis().Direction(), Precision::Angular() ) ? 0.0 : Settings.DefaultFlyout;
669
670   aDimension->SetFlyout(aFlyout);
671
672   if ( !aDimension->IsValid() )
673   {
674     return NULL;
675   }
676
677   return aDimension;
678 }
679
680 //=================================================================================
681 // function : AngleByTwoEdges
682 // purpose  :
683 //=================================================================================
684 Handle(AIS_AngleDimension) MeasureGUI_DimensionCreateTool::AngleByTwoEdges( const GEOM::GeomObjPtr& theEdge1,
685                                                                             const GEOM::GeomObjPtr& theEdge2 ) const
686 {
687   /* --------------------------------------------------- */
688   /*         get construction and parent shapes          */
689   /* --------------------------------------------------- */
690
691   TopoDS_Shape aShapeEdge1;
692   TopoDS_Shape aShapeMain1;
693   if ( !GEOMBase::GetShape( theEdge1.get(), aShapeEdge1 ) )
694   {
695     return NULL;
696   }
697   if ( !GEOMBase::GetShape( GetMainShape( theEdge1 ).get(), aShapeMain1 ) )
698   {
699     return NULL;
700   }
701
702   TopoDS_Shape aShapeEdge2;
703   TopoDS_Shape aShapeMain2;
704   if ( !GEOMBase::GetShape( theEdge2.get(), aShapeEdge2 ) )
705   {
706     return NULL;
707   }
708   if ( !GEOMBase::GetShape( GetMainShape( theEdge2 ).get(), aShapeMain2 ) )
709   {
710     return NULL;
711   }
712
713   /* ---------------------------------------------------- */
714   /*             check construction edges                 */
715   /* ---------------------------------------------------- */
716
717   TopoDS_Edge aFirstEdge  = TopoDS::Edge( aShapeEdge1 );
718   TopoDS_Edge aSecondEdge = TopoDS::Edge( aShapeEdge2 );
719
720   // check whether it is possible to compute dimension on the passed edges
721   Handle(AIS_AngleDimension) aDimension = new AIS_AngleDimension( aFirstEdge, aSecondEdge );
722
723   if ( !aDimension->IsValid() )
724   {
725     return NULL;
726   }
727
728   const gp_Pnt& aFirstPoint  = aDimension->FirstPoint();
729   const gp_Pnt& aSecondPoint = aDimension->SecondPoint();
730   const gp_Pnt& aCenterPoint = aDimension->CenterPoint();
731
732   gp_Vec aVec1( aCenterPoint, aFirstPoint );
733   gp_Vec aVec2( aCenterPoint, aSecondPoint );
734
735   Standard_Real anAngle = aVec2.AngleWithRef( aVec1, aDimension->GetPlane().Axis().Direction() );
736
737   if ( anAngle < 0.0 )
738   {
739     aDimension = new AIS_AngleDimension( aSecondPoint, aCenterPoint, aFirstPoint );
740   }
741
742   aDimension->SetFlyout( Settings.DefaultFlyout );
743
744   return aDimension;
745 }
746
747 //=================================================================================
748 // function : AngleByThreePoints
749 // purpose  :
750 //=================================================================================
751 Handle(AIS_AngleDimension) MeasureGUI_DimensionCreateTool::AngleByThreePoints( const GEOM::GeomObjPtr& thePoint1,
752                                                                                const GEOM::GeomObjPtr& thePoint2,
753                                                                                const GEOM::GeomObjPtr& thePoint3 ) const
754 {
755   TopoDS_Shape aFirstSh;
756   if ( !GEOMBase::GetShape( thePoint1.operator ->(), aFirstSh ) )
757   {
758     return NULL;
759   }
760
761   TopoDS_Shape aSecondSh;
762   if ( !GEOMBase::GetShape( thePoint2.operator ->(), aSecondSh ) )
763   {
764     return NULL;
765   }
766
767   TopoDS_Shape aThirdSh;
768   if ( !GEOMBase::GetShape( thePoint3.operator ->(), aThirdSh ) )
769   {
770     return NULL;
771   }
772
773   TopoDS_Vertex aFirstVertex  = TopoDS::Vertex( aFirstSh );
774   TopoDS_Vertex aSecondVertex = TopoDS::Vertex( aSecondSh );
775   TopoDS_Vertex aThirdVertex  = TopoDS::Vertex( aThirdSh );
776
777   gp_Pnt aPnt1 = BRep_Tool::Pnt( aFirstVertex );
778   gp_Pnt aPnt2 = BRep_Tool::Pnt( aSecondVertex );
779   gp_Pnt aPnt3 = BRep_Tool::Pnt( aThirdVertex );
780
781   // check whether it is possible to compute dimension on the passed points
782   Handle(AIS_AngleDimension) aDimension = new AIS_AngleDimension( aPnt1, aPnt2, aPnt3 );
783
784   if ( !aDimension->IsValid() )
785   {
786     return NULL;
787   }
788
789   return aDimension;
790 }
791
792 //=================================================================================
793 // function : PositionLength
794 // purpose  : The method provides preliminary positioning algorithm for
795 //            for length dimensions measuring the length between two points.
796 //            Parameters:
797 //              theBnd [in] - the bounding box of the main shape
798 //              theFaceN1 [in] - the normal to a first face of edge length (if any)
799 //              theFaceN2 [in] - the normal to a second face of edge length (if any)
800 //              theFaceS1 [in] - the side vector from a first face of edge length (if any)
801 //              theFaceS2 [in] - the side vector from a second face of edge length (if any)
802 //              thePnt1 [in] - the first measured point
803 //              thePnt2 [in] - the last measured point
804 //            The method selects flyout plane to best match the current
805 //            view projection. If edge length is constructed, then the flyout
806 //            can go in line with sides of faces, normal to the faces, or
807 //            aligned to XOY, YOZ, ZOX planes.
808 //=================================================================================
809 void MeasureGUI_DimensionCreateTool::PositionLength( const Bnd_Box& theBnd,
810                                                      const gp_Vec& theFaceN1,
811                                                      const gp_Vec& theFaceN2,
812                                                      const gp_Vec& theFaceS1,
813                                                      const gp_Vec& theFaceS2,
814                                                      const gp_Pnt& thePnt1,
815                                                      const gp_Pnt& thePnt2,
816                                                      gp_Pln& thePln ) const
817 {
818   Standard_Boolean isFace1 = theFaceN1.Magnitude() > Precision::Confusion();
819   Standard_Boolean isFace2 = theFaceN2.Magnitude() > Precision::Confusion();
820   gp_Vec anAverageN( gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(0.0, 0.0, 0.0) );
821
822   // get average direction in case of two non-sharp angled faces
823   if ( isFace1 && isFace2 )
824   {
825     Standard_Boolean isSame = theFaceN1.IsParallel( theFaceN2, Precision::Angular() );
826     if ( !isSame )
827     {
828       gp_Dir aReferenceDir = theFaceN1 ^ theFaceN2;
829       // compute angle between face sides [0 - 2PI]
830       Standard_Real aDirAngle = theFaceN1.AngleWithRef( theFaceN2, aReferenceDir );
831       if ( aDirAngle < 0 )
832       {
833         aDirAngle = ( M_PI * 2.0 ) - aDirAngle;
834       }
835
836       // non-sharp angle, use averaged directio
837       if ( aDirAngle > M_PI * 0.5 )
838       {
839         anAverageN = theFaceN1 + theFaceN2;
840       }
841
842       if ( aDirAngle > M_PI )
843       {
844         isFace1 = Standard_False;
845         isFace2 = Standard_False;
846       }
847     }
848   }
849
850   Standard_Boolean isAverage = anAverageN.Magnitude() > Precision::Confusion();
851
852   SeqOfDirs aFlyoutDirs;
853   if ( isFace1 )
854   {
855     aFlyoutDirs.Append( theFaceN1 );
856     aFlyoutDirs.Append( theFaceS1 );
857   }
858   if ( isFace2 )
859   {
860     aFlyoutDirs.Append( theFaceN2 );
861     aFlyoutDirs.Append( theFaceS2 );
862   }
863   if ( isAverage )
864   {
865     aFlyoutDirs.Append( anAverageN );
866   }
867
868   ChooseLengthFlyoutsFromBnd( aFlyoutDirs, thePnt1, thePnt2, theBnd );
869
870   if ( aFlyoutDirs.IsEmpty() )
871   {
872     return;
873   }
874
875   gp_Dir aPointDir = gce_MakeDir( thePnt1, thePnt2 );
876
877   // make planes for dimension presentation according to flyout directions
878   SeqOfPlanes aSeqOfPlanes;
879   for ( Standard_Integer aFlyoutIt = 1; aFlyoutIt <= aFlyoutDirs.Length(); ++aFlyoutIt )
880   {
881     gp_Pln aPlane( thePnt1, aPointDir ^ aFlyoutDirs.Value( aFlyoutIt ) );
882     aSeqOfPlanes.Append( aPlane );
883   }
884
885   Handle(V3d_View) aView = Settings.ActiveView;
886
887   thePln = !aView.IsNull()
888     ? SelectPlaneForProjection( aSeqOfPlanes, aView )
889     : aSeqOfPlanes.First();
890 }
891
892 //=================================================================================
893 // function : PositionDiameter
894 // purpose  : The method provides preliminary positioning algorithm for
895 //            for diameter dimensions measuring the circle.
896 //            Parameters:
897 //              theBnd [in] - the bounding box of the shape
898 //              theFaceN [in] - the circle face normal (can be void)
899 //              theCirc [in] - the measured circle
900 //              thePnt1 [out] - first dimension point
901 //              thePnt2 [out] - second dimension point
902 //              thePln [out] - dimension flyout plane
903 //            The method selects points on the circle for diameter dimension and
904 //            flyout plane to best match the current view projection (if any)
905 //            The points are aligned to XOY, YOZ, ZOX planes.
906 //            The flyout takes into account bounding box of main shape of face normal
907 //            vector. The flyouts tangetial to the circle plane are directed in 
908 //            accordance with the face normal (if not-null), otherwise the flyouts
909 //            are turned to direct to the closest border of bounding box.
910 //=================================================================================
911 void MeasureGUI_DimensionCreateTool::PositionDiameter( const Bnd_Box& theBnd,
912                                                        const gp_Vec& theFaceN,
913                                                        const gp_Circ& theCirc,
914                                                        gp_Pnt& thePnt1,
915                                                        gp_Pnt& thePnt2,
916                                                        gp_Pln& thePln ) const
917 {
918   // plane associated with custom data
919   struct PlaneAndSegment
920   {
921     PlaneAndSegment() {}
922     PlaneAndSegment(const gp_Pln& thePlane, const Segment& theSegment) : pln(thePlane), seg(theSegment) {}
923     operator gp_Pln () const { return pln; }
924     operator Segment () const { return seg; }
925     gp_Pln pln;
926     Segment seg;
927   };
928   typedef NCollection_Sequence<PlaneAndSegment> SeqOfPlnsAndSegments;
929
930   // select list of measured segments aligned to projection planes
931   SeqOfDirs aProjectionDirs;
932   aProjectionDirs.Append( gp::DX() );
933   aProjectionDirs.Append( gp::DY() );
934   aProjectionDirs.Append( gp::DZ() );
935
936   SeqOfSegments aMeasureSegments = GetInPlaneSegments( theCirc, aProjectionDirs );
937
938   SeqOfPlnsAndSegments aSelectedPlanes;
939
940   // select in-circle-plane direction for flyout closest to border of bounding box
941   for ( Standard_Integer aSegmentIt = 1; aSegmentIt <= aMeasureSegments.Length(); ++aSegmentIt )
942   {
943     const Segment& aSegment = aMeasureSegments.Value(aSegmentIt);
944
945     Standard_Real anAnchor = ElCLib::Parameter( theCirc, aSegment.First );
946
947     gp_Pln aSelectedPlane;
948
949     PositionDiameter( theBnd, theFaceN, theCirc, anAnchor, aSelectedPlane );
950
951     aSelectedPlanes.Append( PlaneAndSegment( aSelectedPlane, aSegment ) );
952   }
953
954   Handle(V3d_View) aView = Settings.ActiveView;
955
956   PlaneAndSegment aChoosenParams = !aView.IsNull()
957     ? SelectPlaneForProjection( aSelectedPlanes, aView )
958     : aSelectedPlanes.First();
959
960   thePnt1 = ((Segment)aChoosenParams).First;
961   thePnt2 = ((Segment)aChoosenParams).Last;
962   thePln  = ((gp_Pln)aChoosenParams);
963 }
964
965 //=================================================================================
966 // function : PositionDiameter
967 // purpose  : The method provides preliminary positioning algorithm for
968 //            for diameter dimensions measuring the circle. The diameter
969 //            dimension is bound at anchor point on the circle.
970 //            Parameters:
971 //              theBnd [in] the bounding box of the shape
972 //              theFaceN [in] - the circle face normal (can be void)
973 //              theCirc [in] - the measured circle
974 //              theAnchorAt [in] - the anchoring parameter
975 //              thePln [out] - dimension flyout plane
976 //            The method selects flyout plane to best match the current
977 //            view projection. The flyout plane can be parallel to circle,
978 //            or tangent to it.
979 //=================================================================================
980 void MeasureGUI_DimensionCreateTool::PositionDiameter( const Bnd_Box& theBnd,
981                                                        const gp_Vec& theFaceN,
982                                                        const gp_Circ& theCirc,
983                                                        const Standard_Real& theAnchorAt,
984                                                        gp_Pln& thePln ) const
985 {
986   gp_Dir aCircN = theCirc.Axis().Direction();
987   gp_Pnt aCircP = theCirc.Location();
988
989   // select tangent direction for flyout closest to border of bounding box
990   gp_Dir aSelectedTanDir;
991   if ( theFaceN.Magnitude() < Precision::Confusion() )
992   {
993     SeqOfDirs aTangentDirs;
994     aTangentDirs.Append(  aCircN );
995     aTangentDirs.Append( -aCircN );
996     aSelectedTanDir = ChooseDirFromBnd( aTangentDirs, aCircP, theBnd );
997   }
998   else
999   {
1000     aSelectedTanDir = gp_Dir( theFaceN );
1001   }
1002
1003   gp_Pnt aPnt1 = ElCLib::Value( theAnchorAt, theCirc );
1004   gp_Pnt aPnt2 = ElCLib::Value( theAnchorAt + M_PI, theCirc );
1005
1006   gp_Dir aSegmentDir = gce_MakeDir( aPnt1, aPnt2 );
1007
1008   SeqOfDirs aSegmentDirs;
1009   aSegmentDirs.Append(  aCircN ^ aSegmentDir );
1010   aSegmentDirs.Append( -aCircN ^ aSegmentDir );
1011   gp_Dir aSelectedSegDir = ChooseDirFromBnd( aSegmentDirs, aCircP, theBnd );
1012
1013   gp_Pln aTangentFlyout( aCircP, aSegmentDir ^ aSelectedTanDir );
1014   gp_Pln aCoplanarFlyout( aCircP, aSegmentDir ^ aSelectedSegDir );
1015
1016   SeqOfPlanes aSelectedPlanes;
1017   aSelectedPlanes.Append( aTangentFlyout );
1018   aSelectedPlanes.Append( aCoplanarFlyout );
1019
1020   Handle(V3d_View) aView = Settings.ActiveView;
1021
1022   thePln = !aView.IsNull()
1023     ? SelectPlaneForProjection( aSelectedPlanes, aView )
1024     : aSelectedPlanes.First();
1025 }
1026
1027 //=================================================================================
1028 // function : ChooseLengthFlyoutsFromBnd
1029 // purpose  :
1030 //=================================================================================
1031 void MeasureGUI_DimensionCreateTool::ChooseLengthFlyoutsFromBnd( SeqOfDirs& theDirs,
1032                                                                  const gp_Pnt& thePnt1,
1033                                                                  const gp_Pnt& thePnt2,
1034                                                                  const Bnd_Box& theBnd ) const
1035 {
1036   // compose a list of axis-aligned planes for lying-in flyouts
1037   NCollection_Sequence<gp_Pln> anAAPlanes;
1038
1039   // the axis-aligned planes for flyouts are built from
1040   // three points (P1, P2, and P1 translated in orthogonal
1041   // direction dx, dy, dz)
1042   gp_Dir anAxes[3] = { gp::DX(), gp::DY(), gp::DZ() };
1043
1044   for ( int anIt = 0; anIt < 3; ++anIt )
1045   {
1046     const gp_Dir& anAxisDir = anAxes[anIt];
1047     gp_Pnt aPnt3 = thePnt1.Translated( gp_Vec( anAxisDir ) );
1048     gce_MakePln aMakePlane( thePnt1, thePnt2, aPnt3 );
1049     if ( !aMakePlane.IsDone() )
1050     {
1051       continue;
1052     }
1053
1054     anAAPlanes.Append( aMakePlane.Value() );
1055   }
1056
1057   // find out what is the closest direction outside of the bounding box
1058   NCollection_Sequence<gp_Pln>::Iterator aPlaneIt( anAAPlanes );
1059
1060   gp_Dir aPointDir = gce_MakeDir( thePnt1, thePnt2 );
1061
1062   for ( ; aPlaneIt.More(); aPlaneIt.Next() )
1063   {
1064     const gp_Pln& aPlane = aPlaneIt.Value();
1065
1066     // transform bounding box to orthogonal coordiantes relative to
1067     // dimension points P1, P2 (x-axis) and plane direction (z-axis),
1068     // where y coordinates will correspond to flyout direction against
1069     // the dimension point line
1070     gp_Ax3 aFlyoutSpace( thePnt1, aPlane.Axis().Direction(), aPointDir );
1071
1072     gp_Trsf aRelativeTransform;
1073     aRelativeTransform.SetTransformation( gp_Ax3(), aFlyoutSpace );
1074     Bnd_Box aRelativeBounds = theBnd.Transformed( aRelativeTransform );
1075
1076     Standard_Real aXmin, aXmax, aYmin, aYmax, aZmin, aZmax;
1077     aRelativeBounds.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
1078
1079     gp_Dir aPosFlyout = aPlane.Axis().Direction() ^ aPointDir;
1080     gp_Dir aNegFlyout = aPosFlyout.Reversed();
1081
1082     // select positive or negative flyout
1083     theDirs.Append( Abs( aYmax ) < Abs( aYmin ) ? aPosFlyout : aNegFlyout );
1084   }
1085 }
1086
1087 //=================================================================================
1088 // function : ChooseDirFromBnd
1089 // purpose  : The method chooses the best direction from the passed list of
1090 //            directions, which is closest to the bounding box border.
1091 //            Parameters:
1092 //              theCandidates [in] the list of candidate directions
1093 //              thePos [in] the position from where the directions are traced
1094 //              theBnd [in] the bounding box of main shape
1095 //=================================================================================
1096 gp_Dir MeasureGUI_DimensionCreateTool::ChooseDirFromBnd( const SeqOfDirs& theCandidates,
1097                                                          const gp_Pnt& thePos,
1098                                                          const Bnd_Box& theBnd ) const
1099 {
1100   gp_Dir aBestDir;
1101
1102   Standard_Real aBestDistance = RealLast();
1103
1104   SeqOfDirs::Iterator anIt( theCandidates );
1105   for ( ; anIt.More(); anIt.Next() )
1106   {
1107     const gp_Dir& aDir = anIt.Value();
1108
1109     gp_Ax3 aFlyoutSpace( thePos, aDir );
1110
1111     gp_Trsf aRelativeTransform;
1112     aRelativeTransform.SetTransformation( gp_Ax3(), aFlyoutSpace );
1113     Bnd_Box aRelativeBounds = theBnd.Transformed( aRelativeTransform );
1114
1115     Standard_Real aXmin, aXmax, aYmin, aYmax, aZmin, aZmax;
1116     aRelativeBounds.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
1117
1118     if ( aYmax < aBestDistance )
1119     {
1120       aBestDir = aDir;
1121       aBestDistance = aYmax;
1122     }
1123   }
1124
1125   return aBestDir;
1126 }
1127
1128 //=================================================================================
1129 // function : SelectPlaneForProjection
1130 // purpose  : Select best matching plane in current view projection
1131 //=================================================================================
1132 template <typename TPlane>
1133 TPlane MeasureGUI_DimensionCreateTool::SelectPlaneForProjection( const NCollection_Sequence<TPlane>& thePlanes,
1134                                                                  const Handle(V3d_View)& theView ) const
1135 {
1136   Quantity_Parameter U[3];
1137   Quantity_Parameter N[3];
1138   theView->Up( U[0], U[1], U[2] );
1139   theView->Proj( N[0], N[1], N[2] );
1140
1141   gp_Dir aViewN( (Standard_Real)N[0], (Standard_Real)N[1], (Standard_Real)N[2] );
1142   gp_Dir aViewU( (Standard_Real)U[0], (Standard_Real)U[1], (Standard_Real)U[2] );
1143
1144   TPlane aBestPlane = thePlanes.First();
1145
1146   Standard_Real aBestDotProduct = RealFirst();
1147
1148   for ( Standard_Integer aPlnIt = 1; aPlnIt <= thePlanes.Length(); ++aPlnIt )
1149   {
1150     const TPlane& aPlane = thePlanes.Value( aPlnIt );
1151
1152     Standard_Real aDotProduct = Abs( ((gp_Pln)aPlane).Axis().Direction() * aViewN );
1153
1154     // preferred plane is "view parallel"
1155     if ( aDotProduct <= aBestDotProduct )
1156     {
1157       continue;
1158     }
1159
1160     aBestPlane = aPlane;
1161
1162     aBestDotProduct = aDotProduct;
1163   }
1164
1165   return aBestPlane;
1166 }
1167
1168 //=================================================================================
1169 // function : GetMainShape
1170 // purpose  :
1171 //=================================================================================
1172 GEOM::GeomObjPtr MeasureGUI_DimensionCreateTool::GetMainShape( const GEOM::GeomObjPtr& theShape ) const
1173 {
1174   // iterate over top-level objects to search for main shape
1175   GEOM::GeomObjPtr aMainShapeIt = theShape;
1176   while ( !aMainShapeIt->IsMainShape() )
1177   {
1178     aMainShapeIt = aMainShapeIt->GetMainShape();
1179   }
1180   return aMainShapeIt;
1181 }
1182
1183 //=================================================================================
1184 // function : GetFaceSide
1185 // purpose  :
1186 //=================================================================================
1187 bool MeasureGUI_DimensionCreateTool::GetFaceSide( const TopoDS_Face& theFace, const TopoDS_Edge& theEdge, gp_Dir& theDir ) const
1188 {
1189   // get correctly oriented edge from main shape
1190   TopoDS_Edge anEdgeFromFace;
1191   TopExp_Explorer anExplorer( theFace.Oriented( TopAbs_FORWARD ), TopAbs_EDGE );
1192   for ( ; anExplorer.More(); anExplorer.Next() )
1193   {
1194     TopoDS_Edge aCurrentEdge = TopoDS::Edge( anExplorer.Current() );
1195     if ( theEdge.IsSame( aCurrentEdge ) )
1196     {
1197       anEdgeFromFace = aCurrentEdge;
1198       break;
1199     }
1200   }
1201
1202   if ( anEdgeFromFace.IsNull() )
1203   {
1204     return false;
1205   }
1206
1207   // check out the direction of face extensions from its boundaries at the edge location
1208   // made assumption here that for any linear bounding edge the
1209   // normals are same on the whole length of that edge
1210   Handle(Geom_Surface) aSurface = BRep_Tool::Surface( theFace );
1211   if ( aSurface.IsNull() || !aSurface->IsKind( STANDARD_TYPE(Geom_ElementarySurface) ) )
1212   {
1213     return false;
1214   }
1215
1216   BRepAdaptor_Curve aSurfCurve( anEdgeFromFace, theFace );
1217   if ( !aSurfCurve.IsCurveOnSurface() )
1218   {
1219     return false;
1220   }
1221
1222   Standard_Real aHalfRange = ( aSurfCurve.FirstParameter() + aSurfCurve.LastParameter() ) / 2.0;
1223
1224   gp_Pnt aPoint = aSurfCurve.Value( aHalfRange );
1225
1226   Standard_Real aPointU = 0.0;
1227   Standard_Real aPointV = 0.0;
1228   GeomLib_Tool::Parameters( aSurface, aPoint, Precision::Confusion(), aPointU, aPointV );
1229
1230   gp_Dir aNorm;
1231   if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aPointU, aPointV ), Precision::Confusion(), aNorm ) > 1 )
1232   {
1233     return false;
1234   }
1235
1236   gp_Vec aTangent = aSurfCurve.DN( aHalfRange, 1 );
1237   if ( aTangent.Magnitude() < Precision::Confusion() )
1238   {
1239     return false;
1240   }
1241
1242   TopAbs_Orientation anEdgeOrientation = anEdgeFromFace.Orientation();
1243   if ( anEdgeOrientation == TopAbs_REVERSED )
1244   {
1245     aTangent.Reverse();
1246   }
1247
1248   theDir = gp_Dir( aTangent ) ^ aNorm;
1249   return true;
1250 }
1251
1252 //=================================================================================
1253 // function : GetInPlaneSegments
1254 // purpose  : The method finds segments crossing the passed circle,
1255 //            which lie in the passed planes.
1256 //            Parameters:
1257 //              theCirc [in] the circle to be crossed.
1258 //              thePlanes [in] the projection planes crossing the circle.
1259 //=================================================================================
1260 MeasureGUI_DimensionCreateTool::SeqOfSegments
1261   MeasureGUI_DimensionCreateTool::GetInPlaneSegments( const gp_Circ& theCirc,
1262                                                       const SeqOfDirs& thePlanes ) const
1263 {
1264   SeqOfSegments aResult;
1265
1266   gp_Pnt aCircP = theCirc.Location();
1267   gp_Dir aCircN = theCirc.Axis().Direction();
1268   Standard_Real aCircR = theCirc.Radius();
1269
1270   SeqOfDirs::Iterator anIt( thePlanes );
1271   for ( ; anIt.More(); anIt.Next() )
1272   {
1273     const gp_Dir& aDir = anIt.Value();
1274
1275     if ( aDir.IsParallel( aCircN, Precision::Angular() ) )
1276     {
1277       continue;
1278     }
1279
1280     gp_Dir aIntDir = aDir ^ aCircN;
1281
1282     gp_Pnt aPnt1 = gp_Pnt( aCircP.XYZ() - aIntDir.XYZ() * aCircR );
1283     gp_Pnt aPnt2 = gp_Pnt( aCircP.XYZ() + aIntDir.XYZ() * aCircR );
1284     Segment aSegment;
1285     aSegment.First = aPnt1;
1286     aSegment.Last  = aPnt2;
1287     aResult.Append( aSegment );
1288   }
1289
1290   return aResult;
1291 }