1 // Copyright (C) 2007-2016 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, or (at your option) any later version.
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 <BRepTools.hxx>
45 #include <BRepAdaptor_Curve.hxx>
46 #include <BRepAdaptor_Surface.hxx>
47 #include <BRepBndLib.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>
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>
79 #if OCC_VERSION_LARGE >= 0x07010000
80 #include <Quantity_Parameter.hxx>
84 // plane associated with custom data
85 struct 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; }
92 MeasureGUI_DimensionCreateTool::Segment seg;
95 typedef NCollection_Sequence<PlaneAndSegment> SeqOfPlnsAndSegments;
97 //=================================================================================
98 // function : Constructor
100 //=================================================================================
101 MeasureGUI_DimensionCreateTool::MeasureGUI_DimensionCreateTool()
103 Settings.DefaultFlyout = 0.0;
104 Settings.ActiveView = NULL;
107 //=================================================================================
108 // function : LengthOnEdge
110 //=================================================================================
111 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthOnEdge( const GEOM::GeomObjPtr& theMeasuredObj ) const
113 /* ---------------------------------------------------------------- *
114 * get the edge and parent shape *
115 * ---------------------------------------------------------------- */
117 TopoDS_Shape aMeasuredShape;
118 TopoDS_Shape aMainShape;
119 if ( !GEOMBase::GetShape( theMeasuredObj.operator ->(), aMeasuredShape ) )
124 if ( !GEOMBase::GetShape( GetMainShape( theMeasuredObj ).get(), aMainShape ) )
129 /* ------------------------------------------------- */
130 /* check the input geometry */
131 /* ------------------------------------------------- */
133 TopoDS_Edge anEdge = TopoDS::Edge( aMeasuredShape );
135 TopoDS_Vertex aVertex1;
136 TopoDS_Vertex aVertex2;
137 TopExp::Vertices( anEdge, aVertex1, aVertex2 );
139 gp_Pnt aPnt1 = BRep_Tool::Pnt( aVertex1 );
140 gp_Pnt aPnt2 = BRep_Tool::Pnt( aVertex2 );
141 if ( aPnt1.Distance( aPnt2 ) <= Precision::Confusion() )
146 /* ------------------------- *
147 * position the dimension
148 * ------------------------- */
151 BRepBndLib::AddClose( aMainShape, aBnd );
154 TopTools_IndexedDataMapOfShapeListOfShape aRelationMap;
155 TopExp::MapShapesAndAncestors( aMainShape, TopAbs_EDGE, TopAbs_FACE, aRelationMap );
156 const TopTools_ListOfShape& aRelatedFaces = aRelationMap.FindFromKey( anEdge );
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() );
163 gp_Pnt aMiddlePnt = gp_Pnt( ( aPnt1.XYZ() + aPnt2.XYZ() ) * 0.5 );
165 TopTools_ListIteratorOfListOfShape aFaceIt( aRelatedFaces );
167 // get face side directions
168 if ( aFaceIt.More() )
170 TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
173 if ( GetFaceSide( aFace, anEdge, aSideDir ) )
178 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( aFace );
180 Standard_Real aU = 0.0, aV = 0.0;
181 GeomLib_Tool::Parameters( aSurface, aMiddlePnt, Precision::Confusion(), aU, aV );
184 if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aU, aV ), Precision::Confusion(), aNorm ) <= 1 )
186 aFaceN1 = aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm;
192 if ( aFaceIt.More() )
194 TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
197 if ( GetFaceSide( aFace, anEdge, aSideDir ) )
202 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( aFace );
204 Standard_Real aU = 0.0, aV = 0.0;
205 GeomLib_Tool::Parameters( aSurface, aMiddlePnt, Precision::Confusion(), aU, aV );
208 if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aU, aV ), Precision::Confusion(), aNorm ) <= 1 )
210 aFaceN2 = aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm;
215 PositionLength( aBnd, aFaceN1, aFaceN2, aFaceS1, aFaceS2, aPnt1, aPnt2, aPln );
217 /* --------------------------------------------------------- *
218 * construct the dimension for the best selected position
219 * --------------------------------------------------------- */
221 Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension( anEdge, aPln );
223 aDimension->SetFlyout( Settings.DefaultFlyout );
225 if ( !aDimension->IsValid() )
233 //=================================================================================
234 // function : LengthByPoints
236 //=================================================================================
237 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthByPoints( const GEOM::GeomObjPtr& theMeasuredObj1,
238 const GEOM::GeomObjPtr& theMeasuredObj2 ) const
240 /* ---------------------------------------------------------------- *
241 * get the edge and parent shape *
242 * ---------------------------------------------------------------- */
244 TopoDS_Shape aMeasuredShape1;
245 TopoDS_Shape aMeasuredShape2;
246 TopoDS_Shape aMainShape;
248 if ( !GEOMBase::GetShape( theMeasuredObj1.operator ->(), aMeasuredShape1 ) )
253 if ( !GEOMBase::GetShape( theMeasuredObj2.operator ->(), aMeasuredShape2 ) )
258 if ( !GEOMBase::GetShape( GetMainShape( theMeasuredObj1 ).get(), aMainShape ) )
263 /* ------------------------------------------------- */
264 /* check the input geometry */
265 /* ------------------------------------------------- */
267 TopoDS_Vertex aVertex1 = TopoDS::Vertex( aMeasuredShape1 );
268 TopoDS_Vertex aVertex2 = TopoDS::Vertex( aMeasuredShape2 );
270 gp_Pnt aPnt1 = BRep_Tool::Pnt( aVertex1 );
271 gp_Pnt aPnt2 = BRep_Tool::Pnt( aVertex2 );
272 if ( aPnt1.Distance( aPnt2 ) <= Precision::Confusion() )
277 /* ------------------------- *
278 * position the dimension
279 * ------------------------- */
282 BRepBndLib::AddClose( aMainShape, aBnd );
284 // check whether the points share same edge
285 TopExp_Explorer anEdgeExp( aMainShape, TopAbs_EDGE, TopAbs_EDGE );
286 for ( ; anEdgeExp.More(); anEdgeExp.Next() )
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 );
294 if ( aPnt1.Distance( anEdgePnt1 ) <= Precision::Confusion() )
296 if ( aPnt2.Distance( anEdgePnt2 ) <= Precision::Confusion() )
302 if ( aPnt2.Distance( anEdgePnt1 ) <= Precision::Confusion() )
304 if ( aPnt1.Distance( anEdgePnt2 ) <= Precision::Confusion() )
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() );
317 if ( anEdgeExp.More() )
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 );
324 gp_Pnt aMiddlePnt = gp_Pnt( ( aPnt1.XYZ() + aPnt2.XYZ() ) * 0.5 );
326 TopTools_ListIteratorOfListOfShape aFaceIt( aRelatedFaces );
328 // get face side directions
329 if ( aFaceIt.More() )
331 TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
334 if ( GetFaceSide( aFace, anEdge, aSideDir ) )
339 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( aFace );
341 Standard_Real aU = 0.0, aV = 0.0;
342 GeomLib_Tool::Parameters( aSurface, aMiddlePnt, Precision::Confusion(), aU, aV );
345 if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aU, aV ), Precision::Confusion(), aNorm ) <= 1 )
347 aFaceN1 = aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm;
353 if ( aFaceIt.More() )
355 TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
358 if ( GetFaceSide( aFace, anEdge, aSideDir ) )
363 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( aFace );
365 Standard_Real aU = 0.0, aV = 0.0;
366 GeomLib_Tool::Parameters( aSurface, aMiddlePnt, Precision::Confusion(), aU, aV );
369 if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aU, aV ), Precision::Confusion(), aNorm ) <= 1 )
371 aFaceN2 = aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm;
377 PositionLength( aBnd, aFaceN1, aFaceN2, aFaceS1, aFaceS2, aPnt1, aPnt2, aPln );
379 /* --------------------------------------------------------- *
380 * construct the dimension for the best selected position
381 * --------------------------------------------------------- */
383 Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension( aPnt1, aPnt2, aPln );
385 aDimension->SetFlyout( Settings.DefaultFlyout );
387 if ( !aDimension->IsValid() )
395 //=================================================================================
396 // function : LengthByParallelEdges
398 //=================================================================================
399 Handle(AIS_LengthDimension) MeasureGUI_DimensionCreateTool::LengthByParallelEdges( const GEOM::GeomObjPtr& theEdge1,
400 const GEOM::GeomObjPtr& theEdge2 ) const
402 TopoDS_Shape aFirstSh;
403 if ( !GEOMBase::GetShape( theEdge1.operator ->(), aFirstSh ) )
408 TopoDS_Shape aSecondSh;
409 if ( !GEOMBase::GetShape( theEdge2.operator ->(), aSecondSh ) )
414 if( aFirstSh == aSecondSh )
417 TopoDS_Edge aFirstEdge = TopoDS::Edge( aFirstSh );
418 TopoDS_Edge aSecondEdge = TopoDS::Edge( aSecondSh );
420 // Build plane through three points
421 BRepAdaptor_Curve aCurve1( aFirstEdge );
422 BRepAdaptor_Curve aCurve2( aSecondEdge );
424 gp_Pnt aPnt1 = aCurve1.Value( 0.1 );
425 gp_Pnt aPnt2 = aCurve1.Value( 0.9 );
426 gp_Pnt aPnt3 = aCurve2.Value( 0.5 );
428 GC_MakePlane aMkPlane( aPnt1, aPnt2, aPnt3 );
429 Handle(Geom_Plane) aPlane = aMkPlane.Value();
431 // check whether it is possible to compute valid dimension
432 Handle(AIS_LengthDimension) aDimension = new AIS_LengthDimension ( aFirstEdge, aSecondEdge, aPlane->Pln() );
434 aDimension->SetFlyout( Settings.DefaultFlyout );
436 if ( !aDimension->IsValid() )
444 //=================================================================================
445 // function : Diameter
447 //=================================================================================
448 Handle(AIS_DiameterDimension) MeasureGUI_DimensionCreateTool::Diameter( const GEOM::GeomObjPtr& theMeasuredObj ) const
450 /* ------------------------------------------------ *
451 * get the shape and its parent (if exist) *
452 * ------------------------------------------------ */
454 TopoDS_Shape aMeasuredShape;
455 TopoDS_Shape aMainShape;
456 if ( !GEOMBase::GetShape( theMeasuredObj.operator ->(), aMeasuredShape ) )
461 if ( !GEOMBase::GetShape( GetMainShape( theMeasuredObj ).get(), aMainShape ) )
467 BRepBndLib::AddClose( aMainShape, aBnd );
469 /* ------------------------------------------------ *
470 * get the dimension construction arguments *
471 * ------------------------------------------------ */
473 Handle(Geom_Circle) aCircle;
475 Standard_Real aPmin = 0, aPmax = 2 * M_PI;
477 gp_Vec aFaceN( gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(0.0, 0.0, 0.0) );
479 switch ( aMeasuredShape.ShapeType() )
483 TopoDS_Face aMeasuredFace = TopoDS::Face(aMeasuredShape);
485 BRepAdaptor_Surface aSurf( aMeasuredFace );
487 Standard_Real aUmin = aSurf.FirstUParameter();
488 Standard_Real aUmax = aSurf.LastUParameter();
489 Standard_Real aVmin = aSurf.FirstVParameter();
490 Standard_Real aVmax = aSurf.LastVParameter();
492 // get arguments of sphere (the sphere should not be cutted at v-center)
493 if ( aSurf.GetType() == GeomAbs_Sphere )
495 if ( aVmax <= Precision::PConfusion() || aVmin >= Precision::PConfusion() )
500 Handle(Geom_Surface) aBasisSurface = Handle(Geom_Surface)::DownCast(
501 aSurf.Surface().Surface()->Transformed( aSurf.Trsf() ) );
503 Handle(Geom_Curve) aCurve = aBasisSurface->VIso( 0.0 );
505 if ( aCurve->IsKind( STANDARD_TYPE( Geom_Circle ) ) )
509 aCircle = Handle(Geom_Circle)::DownCast( aCurve );
511 else if ( aCurve->IsKind( STANDARD_TYPE( Geom_TrimmedCurve ) ) )
513 Handle(Geom_TrimmedCurve) aTrimmedCurve = Handle(Geom_TrimmedCurve)::DownCast( aCurve );
514 aPmin = aTrimmedCurve->FirstParameter();
515 aPmax = aTrimmedCurve->LastParameter();
517 aCircle = Handle(Geom_Circle)::DownCast( aTrimmedCurve );
522 // get arguments of cone
523 if ( aSurf.GetType() == GeomAbs_Cone )
528 gp_Cone aCone = aSurf.Cone();
529 gp_Ax2 anAx2 = aCone.Position().Ax2();
530 aCircle = new Geom_Circle( anAx2, aCone.RefRadius() );
532 aFaceN = aCone.SemiAngle() > 0.0
533 ? anAx2.Axis().Direction()
534 : -anAx2.Axis().Direction();
538 // get arguments of closed torus or cylinder
539 if ( aSurf.GetType() == GeomAbs_Torus || aSurf.GetType() == GeomAbs_Cylinder )
541 Handle(Geom_Surface) aBasisSurface = Handle(Geom_Surface)::DownCast(
542 aSurf.Surface().Surface()->Transformed( aSurf.Trsf() ) );
544 Handle(Geom_Curve) aCurve = aBasisSurface->VIso( (aVmax + aVmin) * 0.5 );
546 if ( aCurve->IsKind( STANDARD_TYPE( Geom_Circle ) ) )
550 aCircle = Handle(Geom_Circle)::DownCast( aCurve );
552 else if ( aCurve->IsKind( STANDARD_TYPE( Geom_TrimmedCurve ) ) )
554 Handle(Geom_TrimmedCurve) aTrimmedCurve = Handle(Geom_TrimmedCurve)::DownCast( aCurve );
555 aPmin = aTrimmedCurve->FirstParameter();
556 aPmax = aTrimmedCurve->LastParameter();
558 aCircle = Handle(Geom_Circle)::DownCast( aTrimmedCurve );
564 // face containing edge?
565 TopExp_Explorer anExp( aMeasuredShape, TopAbs_EDGE );
571 TopoDS_Shape anExpEdge = anExp.Current();
572 if ( anExpEdge.IsNull() )
577 // only a single edge is expected
584 // do not break, go to edge checking
585 aMeasuredShape = anExpEdge;
590 TopoDS_Edge aMeasureEdge = TopoDS::Edge( aMeasuredShape );
592 BRepAdaptor_Curve aCurve(aMeasureEdge);
594 if ( aCurve.GetType() != GeomAbs_Circle )
599 aPmin = aCurve.FirstParameter();
600 aPmax = aCurve.LastParameter();
602 aCircle = new Geom_Circle( aCurve.Circle() );
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 );
609 TopTools_ListIteratorOfListOfShape aFaceIt( aFaces );
610 for ( ; aFaceIt.More(); aFaceIt.Next() )
612 TopoDS_Face aFace = TopoDS::Face( aFaceIt.Value() );
614 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( TopoDS::Face( aFace ) );
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 );
621 if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aCircU, aCircV ), Precision::Confusion(), aNorm ) > 1 )
626 if ( aNorm.Angle( aCircle->Circ().Axis().Direction() ) > M_PI * 0.25 )
631 aFaceN = gp_Vec( aFace.Orientation() == TopAbs_REVERSED ? -aNorm : aNorm );
637 if ( aCircle.IsNull() )
642 ElCLib::AdjustPeriodic( 0.0, M_PI * 2, Precision::PConfusion(), aPmin, aPmax );
644 /* ------------------------- *
645 * position the dimension
646 * ------------------------- */
652 // diameter for closed circle
653 if ( Abs( ( aPmax - aPmin ) - M_PI * 2 ) <= Precision::PConfusion() )
655 PositionDiameter( aBnd, aFaceN, aCircle->Circ(), aPnt1, aPnt2, aPln );
657 // diameter for half-closed circle
658 else if ( Abs( aPmax - aPmin ) > M_PI )
660 Standard_Real anAnchor = aPmin + ( ( aPmax - aPmin ) - M_PI ) * 0.5;
662 PositionDiameter( aBnd, aFaceN, aCircle->Circ(), anAnchor, aPln );
664 aPnt1 = ElCLib::Value( anAnchor, aCircle->Circ() );
665 aPnt2 = ElCLib::Value( anAnchor + M_PI, aCircle->Circ() );
667 // diameter for less than half-closed circle
670 Standard_Real anAnchor = aPmin + ( aPmax - aPmin ) * 0.5;
672 PositionDiameter( aBnd, aFaceN, aCircle->Circ(), anAnchor, aPln );
674 aPnt1 = ElCLib::Value( anAnchor, aCircle->Circ() );
675 aPnt2 = ElCLib::Value( anAnchor + M_PI, aCircle->Circ() );
678 /* --------------------------------------------------------- *
679 * construct the dimension for the best selected position
680 * --------------------------------------------------------- */
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();
687 // construct closed circle as base for the diameter dimension
688 Standard_Boolean isReversed = ( ( aPln.Axis().Direction() ^ aCircX ) * aCircN ) < 0.0;
690 gp_Circ aRuledCirc = gce_MakeCirc( gp_Ax2( aCircP, isReversed ? -aCircN : aCircN, aCircX ), aCircR );
692 Handle(AIS_DiameterDimension) aDimension = new AIS_DiameterDimension( aRuledCirc, aPln );
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;
698 aDimension->SetFlyout(aFlyout);
700 if ( !aDimension->IsValid() )
708 //=================================================================================
709 // function : AngleByTwoEdges
711 //=================================================================================
712 Handle(AIS_AngleDimension) MeasureGUI_DimensionCreateTool::AngleByTwoEdges( const GEOM::GeomObjPtr& theEdge1,
713 const GEOM::GeomObjPtr& theEdge2 ) const
715 /* --------------------------------------------------- */
716 /* get construction and parent shapes */
717 /* --------------------------------------------------- */
719 TopoDS_Shape aShapeEdge1;
720 TopoDS_Shape aShapeMain1;
721 if ( !GEOMBase::GetShape( theEdge1.get(), aShapeEdge1 ) )
725 if ( !GEOMBase::GetShape( GetMainShape( theEdge1 ).get(), aShapeMain1 ) )
730 TopoDS_Shape aShapeEdge2;
731 TopoDS_Shape aShapeMain2;
732 if ( !GEOMBase::GetShape( theEdge2.get(), aShapeEdge2 ) )
736 if ( !GEOMBase::GetShape( GetMainShape( theEdge2 ).get(), aShapeMain2 ) )
741 /* ---------------------------------------------------- */
742 /* check construction edges */
743 /* ---------------------------------------------------- */
745 TopoDS_Edge aFirstEdge = TopoDS::Edge( aShapeEdge1 );
746 TopoDS_Edge aSecondEdge = TopoDS::Edge( aShapeEdge2 );
748 // check whether it is possible to compute dimension on the passed edges
749 Handle(AIS_AngleDimension) aDimension = new AIS_AngleDimension( aFirstEdge, aSecondEdge );
751 if ( !aDimension->IsValid() )
756 const gp_Pnt& aFirstPoint = aDimension->FirstPoint();
757 const gp_Pnt& aSecondPoint = aDimension->SecondPoint();
758 const gp_Pnt& aCenterPoint = aDimension->CenterPoint();
760 gp_Vec aVec1( aCenterPoint, aFirstPoint );
761 gp_Vec aVec2( aCenterPoint, aSecondPoint );
763 Standard_Real anAngle = aVec2.AngleWithRef( aVec1, aDimension->GetPlane().Axis().Direction() );
767 aDimension = new AIS_AngleDimension( aSecondPoint, aCenterPoint, aFirstPoint );
770 aDimension->SetFlyout( Settings.DefaultFlyout );
775 //=================================================================================
776 // function : AngleByThreePoints
778 //=================================================================================
779 Handle(AIS_AngleDimension) MeasureGUI_DimensionCreateTool::AngleByThreePoints( const GEOM::GeomObjPtr& thePoint1,
780 const GEOM::GeomObjPtr& thePoint2,
781 const GEOM::GeomObjPtr& thePoint3 ) const
783 TopoDS_Shape aFirstSh;
784 if ( !GEOMBase::GetShape( thePoint1.operator ->(), aFirstSh ) )
789 TopoDS_Shape aSecondSh;
790 if ( !GEOMBase::GetShape( thePoint2.operator ->(), aSecondSh ) )
795 TopoDS_Shape aThirdSh;
796 if ( !GEOMBase::GetShape( thePoint3.operator ->(), aThirdSh ) )
801 TopoDS_Vertex aFirstVertex = TopoDS::Vertex( aFirstSh );
802 TopoDS_Vertex aSecondVertex = TopoDS::Vertex( aSecondSh );
803 TopoDS_Vertex aThirdVertex = TopoDS::Vertex( aThirdSh );
805 gp_Pnt aPnt1 = BRep_Tool::Pnt( aFirstVertex );
806 gp_Pnt aPnt2 = BRep_Tool::Pnt( aSecondVertex );
807 gp_Pnt aPnt3 = BRep_Tool::Pnt( aThirdVertex );
809 // check whether it is possible to compute dimension on the passed points
810 Handle(AIS_AngleDimension) aDimension = new AIS_AngleDimension( aPnt1, aPnt2, aPnt3 );
812 if ( !aDimension->IsValid() )
817 aDimension->SetFlyout( Settings.DefaultFlyout );
822 //=================================================================================
823 // function : PositionLength
824 // purpose : The method provides preliminary positioning algorithm for
825 // for length dimensions measuring the length between two points.
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
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) );
852 // get average direction in case of two non-sharp angled faces
853 if ( isFace1 && isFace2 )
855 Standard_Boolean isSame = theFaceN1.IsParallel( theFaceN2, Precision::Angular() );
858 gp_Dir aReferenceDir = theFaceN1 ^ theFaceN2;
859 // compute angle between face sides [0 - 2PI]
860 Standard_Real aDirAngle = theFaceN1.AngleWithRef( theFaceN2, aReferenceDir );
863 aDirAngle = ( M_PI * 2.0 ) - aDirAngle;
866 // non-sharp angle, use averaged directio
867 if ( aDirAngle > M_PI * 0.5 )
869 anAverageN = theFaceN1 + theFaceN2;
872 if ( aDirAngle > M_PI )
874 isFace1 = Standard_False;
875 isFace2 = Standard_False;
880 Standard_Boolean isAverage = anAverageN.Magnitude() > Precision::Confusion();
882 SeqOfDirs aFlyoutDirs;
885 aFlyoutDirs.Append( theFaceN1 );
886 aFlyoutDirs.Append( theFaceS1 );
890 aFlyoutDirs.Append( theFaceN2 );
891 aFlyoutDirs.Append( theFaceS2 );
895 aFlyoutDirs.Append( anAverageN );
898 ChooseLengthFlyoutsFromBnd( aFlyoutDirs, thePnt1, thePnt2, theBnd );
900 if ( aFlyoutDirs.IsEmpty() )
905 gp_Dir aPointDir = gce_MakeDir( thePnt1, thePnt2 );
907 // make planes for dimension presentation according to flyout directions
908 SeqOfPlanes aSeqOfPlanes;
909 for ( Standard_Integer aFlyoutIt = 1; aFlyoutIt <= aFlyoutDirs.Length(); ++aFlyoutIt )
911 gp_Pln aPlane( thePnt1, aPointDir ^ aFlyoutDirs.Value( aFlyoutIt ) );
912 aSeqOfPlanes.Append( aPlane );
915 Handle(V3d_View) aView = Settings.ActiveView;
917 thePln = !aView.IsNull()
918 ? SelectPlaneForProjection( aSeqOfPlanes, aView )
919 : aSeqOfPlanes.First();
922 //=================================================================================
923 // function : PositionDiameter
924 // purpose : The method provides preliminary positioning algorithm for
925 // for diameter dimensions measuring the circle.
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,
946 gp_Pln& thePln ) const
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() );
954 SeqOfSegments aMeasureSegments = GetInPlaneSegments( theCirc, aProjectionDirs );
956 SeqOfPlnsAndSegments aSelectedPlanes;
958 // select in-circle-plane direction for flyout closest to border of bounding box
959 for ( Standard_Integer aSegmentIt = 1; aSegmentIt <= aMeasureSegments.Length(); ++aSegmentIt )
961 const Segment& aSegment = aMeasureSegments.Value(aSegmentIt);
963 Standard_Real anAnchor = ElCLib::Parameter( theCirc, aSegment.First );
965 gp_Pln aSelectedPlane;
967 PositionDiameter( theBnd, theFaceN, theCirc, anAnchor, aSelectedPlane );
969 aSelectedPlanes.Append( PlaneAndSegment( aSelectedPlane, aSegment ) );
972 Handle(V3d_View) aView = Settings.ActiveView;
974 PlaneAndSegment aChoosenParams = !aView.IsNull()
975 ? SelectPlaneForProjection( aSelectedPlanes, aView )
976 : aSelectedPlanes.First();
978 thePnt1 = ((Segment)aChoosenParams).First;
979 thePnt2 = ((Segment)aChoosenParams).Last;
980 thePln = ((gp_Pln)aChoosenParams);
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.
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,
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
1004 gp_Dir aCircN = theCirc.Axis().Direction();
1005 gp_Pnt aCircP = theCirc.Location();
1007 // select tangent direction for flyout closest to border of bounding box
1008 gp_Dir aSelectedTanDir;
1009 if ( theFaceN.Magnitude() < Precision::Confusion() )
1011 SeqOfDirs aTangentDirs;
1012 aTangentDirs.Append( aCircN );
1013 aTangentDirs.Append( -aCircN );
1014 aSelectedTanDir = ChooseDirFromBnd( aTangentDirs, aCircP, theBnd );
1018 aSelectedTanDir = gp_Dir( theFaceN );
1021 gp_Pnt aPnt1 = ElCLib::Value( theAnchorAt, theCirc );
1022 gp_Pnt aPnt2 = ElCLib::Value( theAnchorAt + M_PI, theCirc );
1024 gp_Dir aSegmentDir = gce_MakeDir( aPnt1, aPnt2 );
1026 SeqOfDirs aSegmentDirs;
1027 aSegmentDirs.Append( aCircN ^ aSegmentDir );
1028 aSegmentDirs.Append( -aCircN ^ aSegmentDir );
1029 gp_Dir aSelectedSegDir = ChooseDirFromBnd( aSegmentDirs, aCircP, theBnd );
1031 gp_Pln aTangentFlyout( aCircP, aSegmentDir ^ aSelectedTanDir );
1032 gp_Pln aCoplanarFlyout( aCircP, aSegmentDir ^ aSelectedSegDir );
1034 SeqOfPlanes aSelectedPlanes;
1035 aSelectedPlanes.Append( aTangentFlyout );
1036 aSelectedPlanes.Append( aCoplanarFlyout );
1038 Handle(V3d_View) aView = Settings.ActiveView;
1040 thePln = !aView.IsNull()
1041 ? SelectPlaneForProjection( aSelectedPlanes, aView )
1042 : aSelectedPlanes.First();
1045 //=================================================================================
1046 // function : ChooseLengthFlyoutsFromBnd
1048 //=================================================================================
1049 void MeasureGUI_DimensionCreateTool::ChooseLengthFlyoutsFromBnd( SeqOfDirs& theDirs,
1050 const gp_Pnt& thePnt1,
1051 const gp_Pnt& thePnt2,
1052 const Bnd_Box& theBnd ) const
1054 // compose a list of axis-aligned planes for lying-in flyouts
1055 NCollection_Sequence<gp_Pln> anAAPlanes;
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() };
1062 for ( int anIt = 0; anIt < 3; ++anIt )
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() )
1072 anAAPlanes.Append( aMakePlane.Value() );
1075 // find out what is the closest direction outside of the bounding box
1076 NCollection_Sequence<gp_Pln>::Iterator aPlaneIt( anAAPlanes );
1078 gp_Dir aPointDir = gce_MakeDir( thePnt1, thePnt2 );
1080 for ( ; aPlaneIt.More(); aPlaneIt.Next() )
1082 const gp_Pln& aPlane = aPlaneIt.Value();
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 );
1090 gp_Trsf aRelativeTransform;
1091 aRelativeTransform.SetTransformation( gp_Ax3(), aFlyoutSpace );
1092 Bnd_Box aRelativeBounds = theBnd.Transformed( aRelativeTransform );
1094 Standard_Real aXmin, aXmax, aYmin, aYmax, aZmin, aZmax;
1095 aRelativeBounds.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
1097 gp_Dir aPosFlyout = aPlane.Axis().Direction() ^ aPointDir;
1098 gp_Dir aNegFlyout = aPosFlyout.Reversed();
1100 // select positive or negative flyout
1101 theDirs.Append( Abs( aYmax ) < Abs( aYmin ) ? aPosFlyout : aNegFlyout );
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.
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
1120 Standard_Real aBestDistance = RealLast();
1122 SeqOfDirs::Iterator anIt( theCandidates );
1123 for ( ; anIt.More(); anIt.Next() )
1125 const gp_Dir& aDir = anIt.Value();
1127 gp_Ax3 aFlyoutSpace( thePos, aDir );
1129 gp_Trsf aRelativeTransform;
1130 aRelativeTransform.SetTransformation( gp_Ax3(), aFlyoutSpace );
1131 Bnd_Box aRelativeBounds = theBnd.Transformed( aRelativeTransform );
1133 Standard_Real aXmin, aXmax, aYmin, aYmax, aZmin, aZmax;
1134 aRelativeBounds.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
1136 if ( aYmax < aBestDistance )
1139 aBestDistance = aYmax;
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
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] );
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] );
1162 TPlane aBestPlane = thePlanes.First();
1164 Standard_Real aBestDotProduct = RealFirst();
1166 for ( Standard_Integer aPlnIt = 1; aPlnIt <= thePlanes.Length(); ++aPlnIt )
1168 const TPlane& aPlane = thePlanes.Value( aPlnIt );
1170 Standard_Real aDotProduct = Abs( ((gp_Pln)aPlane).Axis().Direction() * aViewN );
1172 // preferred plane is "view parallel"
1173 if ( aDotProduct <= aBestDotProduct )
1178 aBestPlane = aPlane;
1180 aBestDotProduct = aDotProduct;
1186 //=================================================================================
1187 // function : GetMainShape
1189 //=================================================================================
1190 GEOM::GeomObjPtr MeasureGUI_DimensionCreateTool::GetMainShape( const GEOM::GeomObjPtr& theShape ) const
1192 // iterate over top-level objects to search for main shape
1193 GEOM::GeomObjPtr aMainShapeIt = theShape;
1194 while ( !aMainShapeIt->IsMainShape() )
1196 aMainShapeIt = aMainShapeIt->GetMainShape();
1198 return aMainShapeIt;
1201 //=================================================================================
1202 // function : GetFaceSide
1204 //=================================================================================
1205 bool MeasureGUI_DimensionCreateTool::GetFaceSide( const TopoDS_Face& theFace, const TopoDS_Edge& theEdge, gp_Dir& theDir ) const
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() )
1212 TopoDS_Edge aCurrentEdge = TopoDS::Edge( anExplorer.Current() );
1213 if ( theEdge.IsSame( aCurrentEdge ) )
1215 anEdgeFromFace = aCurrentEdge;
1220 if ( anEdgeFromFace.IsNull() )
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) ) )
1234 BRepAdaptor_Curve aSurfCurve( anEdgeFromFace, theFace );
1235 if ( !aSurfCurve.IsCurveOnSurface() )
1240 Standard_Real aHalfRange = ( aSurfCurve.FirstParameter() + aSurfCurve.LastParameter() ) / 2.0;
1242 gp_Pnt aPoint = aSurfCurve.Value( aHalfRange );
1244 Standard_Real aPointU = 0.0;
1245 Standard_Real aPointV = 0.0;
1246 GeomLib_Tool::Parameters( aSurface, aPoint, Precision::Confusion(), aPointU, aPointV );
1249 if ( GeomLib::NormEstim( aSurface, gp_Pnt2d( aPointU, aPointV ), Precision::Confusion(), aNorm ) > 1 )
1254 gp_Vec aTangent = aSurfCurve.DN( aHalfRange, 1 );
1255 if ( aTangent.Magnitude() < Precision::Confusion() )
1260 TopAbs_Orientation anEdgeOrientation = anEdgeFromFace.Orientation();
1261 if ( anEdgeOrientation == TopAbs_REVERSED )
1266 theDir = gp_Dir( aTangent ) ^ aNorm;
1270 //=================================================================================
1271 // function : GetInPlaneSegments
1272 // purpose : The method finds segments crossing the passed circle,
1273 // which lie in the passed planes.
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
1282 SeqOfSegments aResult;
1284 gp_Pnt aCircP = theCirc.Location();
1285 gp_Dir aCircN = theCirc.Axis().Direction();
1286 Standard_Real aCircR = theCirc.Radius();
1288 SeqOfDirs::Iterator anIt( thePlanes );
1289 for ( ; anIt.More(); anIt.Next() )
1291 const gp_Dir& aDir = anIt.Value();
1293 if ( aDir.IsParallel( aCircN, Precision::Angular() ) )
1298 gp_Dir aIntDir = aDir ^ aCircN;
1300 gp_Pnt aPnt1 = gp_Pnt( aCircP.XYZ() - aIntDir.XYZ() * aCircR );
1301 gp_Pnt aPnt2 = gp_Pnt( aCircP.XYZ() + aIntDir.XYZ() * aCircR );
1303 aSegment.First = aPnt1;
1304 aSegment.Last = aPnt2;
1305 aResult.Append( aSegment );