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