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