1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // GEOM GEOMGUI : GUI for Geometry component
24 // File : MeasureGUI_DimensionCreateTool.cxx
25 // Author : Anton POLETAEV, Open CASCADE S.A.S.
27 #include "MeasureGUI_DimensionCreateTool.h"
33 #include <SalomeApp_Application.h>
36 #include <OCCViewer_ViewModel.h>
37 #include <OCCViewer_ViewManager.h>
38 #include <OCCViewer_ViewWindow.h>
39 #include <OCCViewer_ViewPort3d.h>
42 #include <Adaptor3d_CurveOnSurface.hxx>
43 #include <BRep_Tool.hxx>
44 #include <BRepAdaptor_Curve.hxx>
45 #include <BRepBndLib.hxx>
46 #include <gce_MakeDir.hxx>
47 #include <gce_MakePln.hxx>
48 #include <GC_MakePlane.hxx>
49 #include <Geom_Plane.hxx>
50 #include <Geom_ElementarySurface.hxx>
51 #include <Geom_Surface.hxx>
52 #include <GeomLib.hxx>
53 #include <GeomLib_Tool.hxx>
54 #include <TopoDS_Shape.hxx>
55 #include <TopoDS_Vertex.hxx>
56 #include <TopoDS_Edge.hxx>
58 #include <TopExp_Explorer.hxx>
59 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
60 #include <TopTools_ListOfShape.hxx>
61 #include <TColgp_SequenceOfDir.hxx>
63 #include <V3d_View.hxx>
65 //=================================================================================
66 // function : Constructor
68 //=================================================================================
69 MeasureGUI_DimensionCreateTool::MeasureGUI_DimensionCreateTool( GeometryGUI* theGeomGUI )
70 : myGeomGUI( theGeomGUI )
74 //=================================================================================
75 // function : LengthOnEdge
77 //=================================================================================
78 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthOnEdge( const GEOM::GeomObjPtr& theEdge )
80 /* ---------------------------------------------------------------- *
81 * get the edge and parent shape *
82 * ---------------------------------------------------------------- */
84 TopoDS_Shape aShapeEdge;
85 TopoDS_Shape aShapeMain;
86 if ( !GEOMBase::GetShape( theEdge.get(), aShapeEdge ) )
90 if ( !GEOMBase::GetShape( GetMainShape( theEdge ).get(), aShapeMain ) )
95 /* ------------------------------------------------- */
96 /* check the input geometry */
97 /* ------------------------------------------------- */
99 TopoDS_Edge anEdge = TopoDS::Edge( aShapeEdge );
101 TopoDS_Vertex aVertex1;
102 TopoDS_Vertex aVertex2;
103 TopExp::Vertices( anEdge, aVertex1, aVertex2 );
105 gp_Pnt aPnt1 = BRep_Tool::Pnt( aVertex1 );
106 gp_Pnt aPnt2 = BRep_Tool::Pnt( aVertex2 );
107 if ( aPnt1.Distance( aPnt2 ) <= Precision::Confusion() )
112 /* ------------------------------------------------- *
113 * compose list of possible flyout directions *
114 * ------------------------------------------------- */
117 BRepBndLib::AddClose( aShapeMain, aBnd );
119 TColgp_SequenceOfDir aSeqOfFlyout;
120 ChooseLengthFlyoutsFromShape( aSeqOfFlyout, anEdge, aShapeMain );
121 ChooseLengthFlyoutsFromBnd( aSeqOfFlyout, aPnt1, aPnt2, aBnd );
122 if ( aSeqOfFlyout.IsEmpty() )
127 gp_Dir aPointDir = gce_MakeDir( aPnt1, aPnt2 );
129 // make planes for dimension presentation according to flyout directions
130 NCollection_Sequence<gp_Pln> aSeqOfPlanes;
131 for ( Standard_Integer aFlyoutIt = 1; aFlyoutIt <= aSeqOfFlyout.Length(); ++aFlyoutIt )
133 gp_Pln aPlane( aPnt1, aPointDir ^ aSeqOfFlyout.Value( aFlyoutIt ) );
134 aSeqOfPlanes.Append( aPlane );
137 /* --------------------------------------------------------------------- *
138 * select best matching dimension plane for view projection *
139 * --------------------------------------------------------------------- */
141 OCCViewer_ViewWindow* anActiveView = NULL;
143 if ( myGeomGUI != NULL )
145 SalomeApp_Application* anApp = myGeomGUI->getApp();
148 OCCViewer_ViewManager* aViewMgr = (OCCViewer_ViewManager*) anApp->getViewManager( OCCViewer_Viewer::Type(), false );
151 anActiveView = (OCCViewer_ViewWindow*) aViewMgr->getActiveView();
156 gp_Pln aChoosenPlane = anActiveView
157 ? SelectPlaneForProjection( aSeqOfPlanes, anActiveView->getViewPort()->getView() )
158 : aSeqOfPlanes.First();
160 /* ------------------------------------------------------------------------------------ *
161 * construct interactive presentation *
162 * ------------------------------------------------------------------------------------ */
164 Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension( anEdge, aChoosenPlane );
165 if ( !aDimension->IsValid() )
173 //=================================================================================
174 // function : LengthByPoints
176 //=================================================================================
177 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthByPoints( const GEOM::GeomObjPtr& thePoint1,
178 const GEOM::GeomObjPtr& thePoint2 )
180 TopoDS_Shape aFirstSh;
181 if ( !GEOMBase::GetShape( thePoint1.operator ->(), aFirstSh ) )
186 TopoDS_Shape aSecondSh;
187 if ( !GEOMBase::GetShape( thePoint2.operator ->(), aSecondSh ) )
192 TopoDS_Vertex aFirstVertex = TopoDS::Vertex( aFirstSh );
193 TopoDS_Vertex aSecondVertex = TopoDS::Vertex( aSecondSh );
195 gp_Pnt aPnt1 = BRep_Tool::Pnt( aFirstVertex );
196 gp_Pnt aPnt2 = BRep_Tool::Pnt( aSecondVertex );
198 gp_Vec aDir( aPnt1, aPnt2 );
199 gp_Dir aUnitVecs[] = { gp::DZ(), gp::DY(), gp::DX() };
201 for ( ; aUnitVecIt < 3; ++aUnitVecIt )
203 if ( aDir.Dot( aUnitVecs[aUnitVecIt] ) <= 0.5 )
209 gp_Pnt aPnt3 = aPnt2.Translated( aUnitVecs[aUnitVecIt] );
211 GC_MakePlane aMkPlane( aPnt1, aPnt2, aPnt3 );
212 Handle(Geom_Plane) aPlane = aMkPlane.Value();
214 // check whether it is possible to compute valid dimension
215 Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension ( aFirstVertex, aSecondVertex, aPlane->Pln() );
217 if ( !aDimension->IsValid() )
225 //=================================================================================
226 // function : LengthByParallelEdges
228 //=================================================================================
229 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthByParallelEdges( const GEOM::GeomObjPtr& theEdge1,
230 const GEOM::GeomObjPtr& theEdge2 )
232 TopoDS_Shape aFirstSh;
233 if ( !GEOMBase::GetShape( theEdge1.operator ->(), aFirstSh ) )
238 TopoDS_Shape aSecondSh;
239 if ( !GEOMBase::GetShape( theEdge2.operator ->(), aSecondSh ) )
244 TopoDS_Edge aFirstEdge = TopoDS::Edge( aFirstSh );
245 TopoDS_Edge aSecondEdge = TopoDS::Edge( aSecondSh );
247 // Build plane through three points
248 BRepAdaptor_Curve aCurve1( aFirstEdge );
249 BRepAdaptor_Curve aCurve2( aSecondEdge );
251 gp_Pnt aPnt1 = aCurve1.Value( 0.1 );
252 gp_Pnt aPnt2 = aCurve1.Value( 0.9 );
253 gp_Pnt aPnt3 = aCurve2.Value( 0.5 );
255 GC_MakePlane aMkPlane( aPnt1, aPnt2, aPnt3 );
256 Handle(Geom_Plane) aPlane = aMkPlane.Value();
258 // check whether it is possible to compute valid dimension
259 Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension ( aFirstEdge, aSecondEdge, aPlane->Pln() );
261 if ( !aDimension->IsValid() )
269 //=================================================================================
270 // function : Diameter
272 //=================================================================================
273 Handle(AIS_DiameterDimension) MeasureGUI_DimensionCreateTool::Diameter( const GEOM::GeomObjPtr& theShape )
276 if ( !GEOMBase::GetShape( theShape.operator ->(), aShape ) )
281 if ( aShape.ShapeType() != TopAbs_EDGE &&
282 aShape.ShapeType() != TopAbs_FACE &&
283 aShape.ShapeType() != TopAbs_WIRE )
288 // check whether it is possible to compute dimension on the passed geometry
289 Handle(AIS_DiameterDimension) aDimension = new AIS_DiameterDimension( aShape );
291 if ( !aDimension->IsValid() )
299 //=================================================================================
300 // function : AngleByTwoEdges
302 //=================================================================================
303 Handle(AIS_AngleDimension) MeasureGUI_DimensionCreateTool::AngleByTwoEdges( const GEOM::GeomObjPtr& theEdge1,
304 const GEOM::GeomObjPtr& theEdge2 )
306 /* --------------------------------------------------- */
307 /* get construction and parent shapes */
308 /* --------------------------------------------------- */
310 TopoDS_Shape aShapeEdge1;
311 TopoDS_Shape aShapeMain1;
312 if ( !GEOMBase::GetShape( theEdge1.get(), aShapeEdge1 ) )
316 if ( !GEOMBase::GetShape( GetMainShape( theEdge1 ).get(), aShapeMain1 ) )
321 TopoDS_Shape aShapeEdge2;
322 TopoDS_Shape aShapeMain2;
323 if ( !GEOMBase::GetShape( theEdge2.get(), aShapeEdge2 ) )
327 if ( !GEOMBase::GetShape( GetMainShape( theEdge2 ).get(), aShapeMain2 ) )
332 /* ---------------------------------------------------- */
333 /* check construction edges */
334 /* ---------------------------------------------------- */
336 TopoDS_Edge aFirstEdge = TopoDS::Edge( aShapeEdge1 );
337 TopoDS_Edge aSecondEdge = TopoDS::Edge( aShapeEdge2 );
339 // check whether it is possible to compute dimension on the passed edges
340 Handle(AIS_AngleDimension) aDimension = new AIS_AngleDimension( aFirstEdge, aSecondEdge );
342 if ( !aDimension->IsValid() )
347 const gp_Pnt& aFirstPoint = aDimension->FirstPoint();
348 const gp_Pnt& aSecondPoint = aDimension->SecondPoint();
349 const gp_Pnt& aCenterPoint = aDimension->CenterPoint();
351 gp_Vec aVec1( aCenterPoint, aFirstPoint );
352 gp_Vec aVec2( aCenterPoint, aSecondPoint );
354 Standard_Real anAngle = aVec2.AngleWithRef( aVec1, aDimension->GetPlane().Axis().Direction() );
358 aDimension = new AIS_AngleDimension( aSecondPoint, aCenterPoint, aFirstPoint );
364 //=================================================================================
365 // function : AngleByThreePoints
367 //=================================================================================
368 Handle(AIS_AngleDimension) MeasureGUI_DimensionCreateTool::AngleByThreePoints( const GEOM::GeomObjPtr& thePoint1,
369 const GEOM::GeomObjPtr& thePoint2,
370 const GEOM::GeomObjPtr& thePoint3 )
372 TopoDS_Shape aFirstSh;
373 if ( !GEOMBase::GetShape( thePoint1.operator ->(), aFirstSh ) )
378 TopoDS_Shape aSecondSh;
379 if ( !GEOMBase::GetShape( thePoint2.operator ->(), aSecondSh ) )
384 TopoDS_Shape aThirdSh;
385 if ( !GEOMBase::GetShape( thePoint3.operator ->(), aThirdSh ) )
390 TopoDS_Vertex aFirstVertex = TopoDS::Vertex( aFirstSh );
391 TopoDS_Vertex aSecondVertex = TopoDS::Vertex( aSecondSh );
392 TopoDS_Vertex aThirdVertex = TopoDS::Vertex( aThirdSh );
394 gp_Pnt aPnt1 = BRep_Tool::Pnt( aFirstVertex );
395 gp_Pnt aPnt2 = BRep_Tool::Pnt( aSecondVertex );
396 gp_Pnt aPnt3 = BRep_Tool::Pnt( aThirdVertex );
398 // check whether it is possible to compute dimension on the passed points
399 Handle(AIS_AngleDimension) aDimension = new AIS_AngleDimension( aPnt1, aPnt2, aPnt3 );
401 if ( !aDimension->IsValid() )
409 //=================================================================================
410 // function : ChooseLengthFlyoutsFromShape
412 //=================================================================================
413 void MeasureGUI_DimensionCreateTool::ChooseLengthFlyoutsFromShape( TColgp_SequenceOfDir& theDirs,
414 const TopoDS_Vertex& theVertex1,
415 const TopoDS_Vertex& theVertex2,
416 const TopoDS_Shape& theShape )
420 //=================================================================================
421 // function : ChooseLengthFlyoutsFromShape
423 //=================================================================================
424 void MeasureGUI_DimensionCreateTool::ChooseLengthFlyoutsFromShape( TColgp_SequenceOfDir& theDirs,
425 const TopoDS_Edge& theEdge,
426 const TopoDS_Shape& theShape )
428 TopTools_IndexedDataMapOfShapeListOfShape aRelationMap;
429 TopExp::MapShapesAndAncestors( theShape, TopAbs_EDGE, TopAbs_FACE, aRelationMap );
430 const TopTools_ListOfShape& aRelatedFaces = aRelationMap.FindFromKey( theEdge );
432 // get face side directions
434 if ( aRelatedFaces.Extent() > 0 && GetFaceSide( TopoDS::Face( aRelatedFaces.First() ), theEdge, aSideDir ) )
436 theDirs.Append( aSideDir );
438 if ( aRelatedFaces.Extent() > 1 && GetFaceSide( TopoDS::Face( aRelatedFaces.Last() ), theEdge, aSideDir ) )
440 theDirs.Append( aSideDir );
443 // get average direction in case of two non-sharp angled faces
444 if ( theDirs.Length() == 2 )
446 const gp_Dir& aDir1 = theDirs.First();
447 const gp_Dir& aDir2 = theDirs.Last();
448 Standard_Boolean isSame = aDir1.IsParallel( aDir2, Precision::Angular() );
451 gp_Dir aReferenceDir = aDir1 ^ aDir2;
452 // compute angle between face sides [0 - 2PI]
453 Standard_Real aDirAngle = aDir1.AngleWithRef( aDir2, aReferenceDir );
456 aDirAngle = ( M_PI * 2.0 ) - aDirAngle;
459 // non-sharp angle, use averaged direction
460 if ( aDirAngle > M_PI )
463 theDirs.Append( aDir1.Rotated( gp_Ax1( gp::Origin(), aReferenceDir ), aDirAngle * 0.5 ) );
469 //=================================================================================
470 // function : ChooseLengthFlyoutsFromBnd
472 //=================================================================================
473 void MeasureGUI_DimensionCreateTool::ChooseLengthFlyoutsFromBnd( TColgp_SequenceOfDir& theDirs,
474 const gp_Pnt& thePnt1,
475 const gp_Pnt& thePnt2,
476 const Bnd_Box& theBnd )
478 // compose a list of axis-aligned planes for lying-in flyouts
479 NCollection_Sequence<gp_Pln> anAAPlanes;
481 // the axis-aligned planes for flyouts are built from
482 // three points (P1, P2, and P1 translated in orthogonal
483 // direction dx, dy, dz)
484 gp_Dir anAxes[3] = { gp::DX(), gp::DY(), gp::DZ() };
486 for ( int anIt = 0; anIt < 3; ++anIt )
488 const gp_Dir& anAxisDir = anAxes[anIt];
489 gp_Pnt aPnt3 = thePnt1.Translated( gp_Vec( anAxisDir ) );
490 gce_MakePln aMakePlane( thePnt1, thePnt2, aPnt3 );
491 if ( !aMakePlane.IsDone() )
496 anAAPlanes.Append( aMakePlane.Value() );
499 // find out what is the closest direction outside of the bounding box
500 NCollection_Sequence<gp_Pln>::Iterator aPlaneIt( anAAPlanes );
502 gp_Dir aPointDir = gce_MakeDir( thePnt1, thePnt2 );
504 for ( ; aPlaneIt.More(); aPlaneIt.Next() )
506 const gp_Pln& aPlane = aPlaneIt.Value();
508 // transform bounding box to orthogonal coordiantes relative to
509 // dimension points P1, P2 (x-axis) and plane direction (z-axis),
510 // where y coordinates will correspond to flyout direction against
511 // the dimension point line
512 gp_Ax3 aFlyoutSpace( thePnt1, aPlane.Axis().Direction(), aPointDir );
514 gp_Trsf aRelativeTransform;
515 aRelativeTransform.SetTransformation( gp_Ax3(), aFlyoutSpace );
516 Bnd_Box aRelativeBounds = theBnd.Transformed( aRelativeTransform );
518 Standard_Real aXmin, aXmax, aYmin, aYmax, aZmin, aZmax;
519 aRelativeBounds.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
521 gp_Dir aPosFlyout = aPlane.Axis().Direction() ^ aPointDir;
522 gp_Dir aNegFlyout = aPosFlyout.Reversed();
524 // select positive or negative flyout
525 theDirs.Append( Abs( aYmax ) < Abs( aYmin ) ? aPosFlyout : aNegFlyout );
529 //=================================================================================
530 // function : SelectPlaneForProjection
531 // purpose : Select best matching plane in current view projection
532 //=================================================================================
533 gp_Pln MeasureGUI_DimensionCreateTool::SelectPlaneForProjection( const NCollection_Sequence<gp_Pln>& thePlanes,
534 const Handle(V3d_View)& theView )
536 Quantity_Parameter U[3];
537 Quantity_Parameter N[3];
538 theView->Up( U[0], U[1], U[2] );
539 theView->Proj( N[0], N[1], N[2] );
541 gp_Dir aViewN( (Standard_Real)N[0], (Standard_Real)N[1], (Standard_Real)N[2] );
542 gp_Dir aViewU( (Standard_Real)U[0], (Standard_Real)U[1], (Standard_Real)U[2] );
544 gp_Pln aBestPlane = thePlanes.First();
546 Standard_Real aBestDotProduct = RealFirst();
548 for ( Standard_Integer aPlnIt = 1; aPlnIt <= thePlanes.Length(); ++aPlnIt )
550 const gp_Pln& aPlane = thePlanes.Value( aPlnIt );
552 Standard_Real aDotProduct = Abs( aPlane.Axis().Direction() * aViewN );
554 // preferred plane is "view parallel"
555 if ( aDotProduct <= aBestDotProduct )
562 aBestDotProduct = aDotProduct;
568 //=================================================================================
569 // function : GetMainShape
571 //=================================================================================
572 GEOM::GeomObjPtr MeasureGUI_DimensionCreateTool::GetMainShape( const GEOM::GeomObjPtr& theShape )
574 // iterate over top-level objects to search for main shape
575 GEOM::GeomObjPtr aMainShapeIt = theShape;
576 while ( !aMainShapeIt->IsMainShape() )
578 aMainShapeIt = aMainShapeIt->GetMainShape();
583 //=================================================================================
584 // function : GetFaceSide
586 //=================================================================================
587 bool MeasureGUI_DimensionCreateTool::GetFaceSide( const TopoDS_Face& theFace, const TopoDS_Edge& theEdge, gp_Dir& theDir )
589 // get correctly oriented edge from main shape
590 TopoDS_Edge anEdgeFromFace;
591 TopExp_Explorer anExplorer( theFace.Oriented( TopAbs_FORWARD ), TopAbs_EDGE );
592 for ( ; anExplorer.More(); anExplorer.Next() )
594 TopoDS_Edge aCurrentEdge = TopoDS::Edge( anExplorer.Current() );
595 if ( theEdge.IsSame( aCurrentEdge ) )
597 anEdgeFromFace = aCurrentEdge;
602 if ( anEdgeFromFace.IsNull() )
607 // check out the direction of face extensions from its boundaries at the edge location
608 // made assumption here that for any linear bounding edge the
609 // normals are same on the whole length of that edge
610 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( theFace );
611 if ( aSurface.IsNull() || !aSurface->IsKind( STANDARD_TYPE(Geom_ElementarySurface) ) )
616 BRepAdaptor_Curve aSurfCurve( anEdgeFromFace, theFace );
617 if ( !aSurfCurve.IsCurveOnSurface() )
622 Standard_Real aHalfRange = ( aSurfCurve.FirstParameter() + aSurfCurve.LastParameter() ) / 2.0;
624 gp_Pnt aPoint = aSurfCurve.Value( aHalfRange );
626 Standard_Real aPointU = 0.0;
627 Standard_Real aPointV = 0.0;
628 GeomLib_Tool::Parameters( aSurface, aPoint, Precision::Confusion(), aPointU, aPointV );
631 if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aPointU, aPointV ), Precision::Confusion(), aNorm ) > 1 )
636 gp_Vec aTangent = aSurfCurve.DN( aHalfRange, 1 );
637 if ( aTangent.Magnitude() < Precision::Confusion() )
642 TopAbs_Orientation anEdgeOrientation = anEdgeFromFace.Orientation();
643 if ( anEdgeOrientation == TopAbs_REVERSED )
648 theDir = gp_Dir( aTangent ) ^ aNorm;