1 // Copyright (C) 2007-2024 CEA, EDF, 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 #include <Standard_Stream.hxx>
25 #include <GEOMUtils.hxx>
27 #include <Utils_ExceptHandlers.hxx>
29 #include <Basics_OCCTVersion.hxx>
32 #include <BRepMesh_IncrementalMesh.hxx>
34 #include <BRepExtrema_DistShapeShape.hxx>
36 #include <BRep_Builder.hxx>
37 #include <BRep_Tool.hxx>
38 #include <BRepBndLib.hxx>
39 #include <BRepGProp.hxx>
40 #include <BRepTools.hxx>
42 #include <BRepClass_FaceClassifier.hxx>
43 #include <BRepClass3d_SolidClassifier.hxx>
45 #include <BRepBuilderAPI_MakeFace.hxx>
46 #include <BRepBuilderAPI_Sewing.hxx>
48 #include <BRepCheck_Analyzer.hxx>
50 #include <Bnd_Box.hxx>
52 #include <BOPAlgo_ArgumentAnalyzer.hxx>
53 #include <BOPTools_AlgoTools.hxx>
58 #include <TopoDS_Edge.hxx>
59 #include <TopoDS_Face.hxx>
60 #include <TopoDS_Shape.hxx>
61 #include <TopoDS_Vertex.hxx>
62 #include <TopoDS_Compound.hxx>
63 #include <TopoDS_Iterator.hxx>
64 #include <TopExp_Explorer.hxx>
65 #include <TopTools_MapOfShape.hxx>
66 #include <TopTools_ListOfShape.hxx>
67 #include <TopTools_ListIteratorOfListOfShape.hxx>
68 #include <TopTools_Array1OfShape.hxx>
70 #include <GeomAPI_ProjectPointOnSurf.hxx>
72 #include <Geom_Circle.hxx>
73 #include <Geom_Surface.hxx>
74 #include <Geom_Plane.hxx>
75 #include <Geom_SphericalSurface.hxx>
76 #include <Geom_ToroidalSurface.hxx>
77 #include <Geom_RectangularTrimmedSurface.hxx>
79 #include <GeomLProp_CLProps.hxx>
80 #include <GeomLProp_SLProps.hxx>
82 #include <GProp_GProps.hxx>
83 #include <GProp_PrincipalProps.hxx>
85 #include <TColStd_Array1OfReal.hxx>
90 #include <ShapeFix_Shape.hxx>
91 #include <ShapeFix_ShapeTolerance.hxx>
93 #include <ProjLib.hxx>
102 #include <Standard_Failure.hxx>
103 #include <Standard_NullObject.hxx>
104 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
106 #define MAX2(X, Y) (Abs(X) > Abs(Y) ? Abs(X) : Abs(Y))
107 #define MAX3(X, Y, Z) (MAX2(MAX2(X,Y), Z))
109 #define STD_SORT_ALGO 1
111 #define DEFAULT_TOLERANCE_TOLERANCE 1.e-02
112 #define DEFAULT_MAX_TOLERANCE_TOLERANCE 1.e-06
114 // When the following macro is defined, ShapeFix_ShapeTolerance function is used to set max tolerance of curve
115 // in GEOMUtils::FixShapeCurves function; otherwise less restrictive BRep_Builder::UpdateEdge/UpdateVertex
117 // VSR (29/12/2014): macro disabled
118 //#define USE_LIMIT_TOLERANCE
123 * This function constructs and returns modified shape from the original one
124 * for singular cases. It is used for the method GetMinDistanceSingular.
126 * \param theShape the original shape
127 * \param theModifiedShape output parameter. The modified shape.
128 * \param theAddDist output parameter. The added distance for modified shape.
129 * \retval true if the shape is modified; false otherwise.
133 Standard_Boolean ModifyShape(const TopoDS_Shape &theShape,
134 TopoDS_Shape &theModifiedShape,
135 Standard_Real &theAddDist)
137 TopExp_Explorer anExp;
141 theModifiedShape.Nullify();
143 for ( anExp.Init( theShape, TopAbs_FACE ); anExp.More(); anExp.Next() ) {
145 theModifiedShape = anExp.Current();
148 TopoDS_Shape sh = theShape;
149 while(sh.ShapeType()==TopAbs_COMPOUND) {
150 TopoDS_Iterator it(sh);
153 Handle(Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(theModifiedShape));
154 if( S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ||
155 S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) ||
157 const Standard_Boolean isShell =
158 (sh.ShapeType()==TopAbs_SHELL || sh.ShapeType()==TopAbs_FACE);
160 if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) {
161 Handle(Geom_SphericalSurface) SS = Handle(Geom_SphericalSurface)::DownCast(S);
162 gp_Pnt PC = SS->Location();
165 B.MakeVertex(V,PC,1.e-7);
166 theModifiedShape = V;
167 theAddDist = SS->Radius();
168 return Standard_True;
170 if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) ) {
171 Handle(Geom_ToroidalSurface) TS = Handle(Geom_ToroidalSurface)::DownCast(S);
172 gp_Ax3 ax3 = TS->Position();
173 Handle(Geom_Circle) C = new Geom_Circle(ax3.Ax2(),TS->MajorRadius());
176 B.MakeEdge(E,C,1.e-7);
177 theModifiedShape = E;
178 theAddDist = TS->MinorRadius();
179 return Standard_True;
182 // non solid case or any periodic surface (Mantis 22454).
184 BRepTools::UVBounds(TopoDS::Face(theModifiedShape),U1,U2,V1,V2);
185 // end of changes for 020677 (dmv)
186 Handle(Geom_RectangularTrimmedSurface) TrS1 =
187 new Geom_RectangularTrimmedSurface(S,U1,(U1+U2)/2.,V1,V2);
188 Handle(Geom_RectangularTrimmedSurface) TrS2 =
189 new Geom_RectangularTrimmedSurface(S,(U1+U2)/2.,U2,V1,V2);
190 TopoDS_Shape aMShape;
192 TopoDS_Face F1 = BRepBuilderAPI_MakeFace(TrS1, Precision::Confusion());
193 TopoDS_Face F2 = BRepBuilderAPI_MakeFace(TrS2, Precision::Confusion());
197 B.MakeCompound(TopoDS::Compound(aMShape));
201 // The original shape is a solid.
202 BRepBuilderAPI_Sewing aSewing (Precision::Confusion()*10.0);
206 aMShape = aSewing.SewedShape();
210 B.Add(aSolid, aMShape);
214 Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape;
216 sfs->SetPrecision(1.e-6);
217 sfs->SetMaxTolerance(1.0);
219 theModifiedShape = sfs->Shape();
220 return Standard_True;
224 theModifiedShape = theShape;
225 return Standard_False;
228 void parseWard( const GEOMUtils::LevelsList &theLevelList, std::string &treeStr )
230 treeStr.append( "{" );
231 for( GEOMUtils::LevelsList::const_iterator j = theLevelList.begin();
232 j != theLevelList.end(); ++j ) {
233 if ( j != theLevelList.begin() ) {
234 treeStr.append( ";" );
236 GEOMUtils::LevelInfo level = (*j);
237 GEOMUtils::LevelInfo::iterator upIter;
238 for ( upIter = level.begin(); upIter != level.end(); ++upIter ) {
239 if ( upIter != level.begin() ) {
240 treeStr.append( "," );
242 treeStr.append( upIter->first );
243 for ( std::vector<std::string>::iterator k = upIter->second.begin(); k != upIter->second.end(); ++k ) {
244 treeStr.append( "_" );
245 treeStr.append( *k );
249 treeStr.append( "}" );
252 GEOMUtils::LevelsList parseWard( const std::string& theData, std::size_t& theCursor )
254 std::size_t indexStart = theData.find( "{", theCursor ) + 1;
255 std::size_t indexEnd = theData.find( "}", indexStart );
257 std::string ward = theData.substr( indexStart, indexEnd - indexStart );
258 std::stringstream ss(ward);
260 std::vector<std::string> levelsListStr;
261 while ( std::getline( ss, substr, ';' ) ) {
262 if ( !substr.empty() )
263 levelsListStr.push_back( substr );
265 GEOMUtils::LevelsList levelsListData;
266 for( size_t level = 0; level < levelsListStr.size(); level++ ) {
267 std::vector<std::string> namesListStr;
268 std::stringstream ss1( levelsListStr[level] );
269 while ( std::getline( ss1, substr, ',' ) ) {
270 if ( !substr.empty() )
271 namesListStr.push_back( substr );
273 GEOMUtils::LevelInfo levelInfoData;
274 for( size_t node = 0; node < namesListStr.size(); node++ ) {
275 std::vector<std::string> linksListStr;
276 std::stringstream ss2( namesListStr[node] );
277 while ( std::getline( ss2, substr, '_' ) ) {
278 if ( !substr.empty() )
279 linksListStr.push_back( substr );
281 std::string nodeItem = linksListStr[0];
282 if( !nodeItem.empty() ) {
283 GEOMUtils::NodeLinks linksListData;
284 for( size_t link = 1; link < linksListStr.size(); link++ ) {
285 std::string linkItem = linksListStr[link];
286 linksListData.push_back( linkItem );
288 levelInfoData[nodeItem] = linksListData;
291 levelsListData.push_back(levelInfoData);
294 theCursor = indexEnd + 1;
295 return levelsListData;
300 //=======================================================================
301 //function : ShapeToDouble
302 //purpose : used by CompareShapes::operator()
303 //=======================================================================
304 std::pair<double, double> GEOMUtils::ShapeToDouble (const TopoDS_Shape& S, bool isOldSorting)
306 // Computing of CentreOfMass
310 if (S.ShapeType() == TopAbs_VERTEX) {
311 GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S));
312 Len = (double)S.Orientation();
316 // BEGIN: fix for Mantis issue 0020842
318 BRepGProp::LinearProperties(S, GPr);
321 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
322 BRepGProp::LinearProperties(S, GPr);
324 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
325 BRepGProp::SurfaceProperties(S, GPr);
328 BRepGProp::VolumeProperties(S, GPr);
331 // END: fix for Mantis issue 0020842
332 GPoint = GPr.CentreOfMass();
336 double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9;
337 return std::make_pair(dMidXYZ, Len);
340 //=======================================================================
341 //function : GetPosition
343 //=======================================================================
344 gp_Ax3 GEOMUtils::GetPosition (const TopoDS_Shape& theShape)
348 if (theShape.IsNull())
352 aResult.Transform(theShape.Location().Transformation());
353 if (theShape.ShapeType() == TopAbs_FACE) {
354 Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(theShape));
355 if (!aGS.IsNull() && aGS->IsKind(STANDARD_TYPE(Geom_Plane))) {
356 Handle(Geom_Plane) aGPlane = Handle(Geom_Plane)::DownCast(aGS);
357 gp_Pln aPln = aGPlane->Pln();
358 aResult = aPln.Position();
359 // In case of reverse orinetation of the face invert the plane normal
360 // (the face's normal does not mathc the plane's normal in this case)
361 if(theShape.Orientation() == TopAbs_REVERSED)
363 gp_Dir Vx = aResult.XDirection();
364 gp_Dir N = aResult.Direction().Mirrored(Vx);
365 gp_Pnt P = aResult.Location();
366 aResult = gp_Ax3(P, N, Vx);
374 TopAbs_ShapeEnum aShType = theShape.ShapeType();
376 if (aShType == TopAbs_VERTEX) {
377 aPnt = BRep_Tool::Pnt(TopoDS::Vertex(theShape));
380 if (aShType == TopAbs_COMPOUND) {
381 aShType = GetTypeOfSimplePart(theShape);
384 GProp_GProps aSystem;
385 if (aShType == TopAbs_EDGE || aShType == TopAbs_WIRE)
386 BRepGProp::LinearProperties(theShape, aSystem);
387 else if (aShType == TopAbs_FACE || aShType == TopAbs_SHELL)
388 BRepGProp::SurfaceProperties(theShape, aSystem);
390 BRepGProp::VolumeProperties(theShape, aSystem);
392 aPnt = aSystem.CentreOfMass();
395 aResult.SetLocation(aPnt);
400 //=======================================================================
401 //function : GetVector
403 //=======================================================================
404 gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape,
405 Standard_Boolean doConsiderOrientation)
407 if (theShape.IsNull())
408 Standard_NullObject::Raise("Null shape is given for a vector");
410 if (theShape.ShapeType() != TopAbs_EDGE)
411 Standard_TypeMismatch::Raise("Invalid shape is given, must be a vector or an edge");
413 TopoDS_Edge anE = TopoDS::Edge(theShape);
415 TopoDS_Vertex V1, V2;
416 TopExp::Vertices(anE, V1, V2, doConsiderOrientation);
418 if (V1.IsNull() || V2.IsNull())
419 Standard_NullObject::Raise("Invalid edge is given, it must have two points");
421 gp_Vec aV (BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
422 if (aV.Magnitude() < gp::Resolution()) {
423 Standard_ConstructionError::Raise("Vector of zero length is given");
429 //=======================================================================
430 //function : CompareShapes::operator()
431 //purpose : used by std::sort(), called from SortShapes()
432 //=======================================================================
433 bool GEOMUtils::CompareShapes::operator() (const TopoDS_Shape& theShape1,
434 const TopoDS_Shape& theShape2)
436 if (!myMap.IsBound(theShape1)) {
437 myMap.Bind(theShape1, ShapeToDouble(theShape1, myIsOldSorting));
440 if (!myMap.IsBound(theShape2)) {
441 myMap.Bind(theShape2, ShapeToDouble(theShape2, myIsOldSorting));
444 std::pair<double, double> val1 = myMap.Find(theShape1);
445 std::pair<double, double> val2 = myMap.Find(theShape2);
447 double tol = Precision::Confusion();
448 bool exchange = Standard_False;
450 double dMidXYZ = val1.first - val2.first;
451 if (dMidXYZ >= tol) {
452 exchange = Standard_True;
454 else if (Abs(dMidXYZ) < tol) {
455 double dLength = val1.second - val2.second;
456 if (dLength >= tol) {
457 exchange = Standard_True;
459 else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) {
461 // equal values possible on shapes such as two halves of a sphere and
462 // a membrane inside the sphere
464 BRepBndLib::Add(theShape1, box1);
465 if (!box1.IsVoid()) {
466 BRepBndLib::Add(theShape2, box2);
467 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
468 if (dSquareExtent >= tol) {
469 exchange = Standard_True;
471 else if (Abs(dSquareExtent) < tol) {
472 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
473 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
474 val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
475 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
476 val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
477 if ((val1 - val2) >= tol) {
478 exchange = Standard_True;
485 //return val1 < val2;
489 //=======================================================================
490 //function : SortShapes
492 //=======================================================================
493 void GEOMUtils::SortShapes (TopTools_ListOfShape& SL,
494 const Standard_Boolean isOldSorting)
497 std::vector<TopoDS_Shape> aShapesVec;
498 aShapesVec.reserve(SL.Extent());
500 TopTools_ListIteratorOfListOfShape it (SL);
501 for (; it.More(); it.Next()) {
502 aShapesVec.push_back(it.Value());
506 CompareShapes shComp (isOldSorting);
507 std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp);
508 //std::sort(aShapesVec.begin(), aShapesVec.end(), shComp);
510 std::vector<TopoDS_Shape>::const_iterator anIter = aShapesVec.begin();
511 for (; anIter != aShapesVec.end(); ++anIter) {
515 // old implementation
516 Standard_Integer MaxShapes = SL.Extent();
517 TopTools_Array1OfShape aShapes (1,MaxShapes);
518 TColStd_Array1OfInteger OrderInd(1,MaxShapes);
519 TColStd_Array1OfReal MidXYZ (1,MaxShapes); //X,Y,Z;
520 TColStd_Array1OfReal Length (1,MaxShapes); //X,Y,Z;
522 // Computing of CentreOfMass
523 Standard_Integer Index;
526 TopTools_ListIteratorOfListOfShape it(SL);
527 for (Index=1; it.More(); Index++)
529 TopoDS_Shape S = it.Value();
530 SL.Remove( it ); // == it.Next()
532 OrderInd.SetValue (Index, Index);
533 if (S.ShapeType() == TopAbs_VERTEX) {
534 GPoint = BRep_Tool::Pnt( TopoDS::Vertex( S ));
535 Length.SetValue( Index, (Standard_Real) S.Orientation());
538 // BEGIN: fix for Mantis issue 0020842
540 BRepGProp::LinearProperties (S, GPr);
543 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
544 BRepGProp::LinearProperties (S, GPr);
546 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
547 BRepGProp::SurfaceProperties(S, GPr);
550 BRepGProp::VolumeProperties(S, GPr);
553 // END: fix for Mantis issue 0020842
554 GPoint = GPr.CentreOfMass();
555 Length.SetValue(Index, GPr.Mass());
557 MidXYZ.SetValue(Index, GPoint.X()*999.0 + GPoint.Y()*99.0 + GPoint.Z()*0.9);
558 //cout << Index << " L: " << Length(Index) << "CG: " << MidXYZ(Index) << endl;
562 Standard_Integer aTemp;
563 Standard_Boolean exchange, Sort = Standard_True;
564 Standard_Real tol = Precision::Confusion();
567 Sort = Standard_False;
568 for (Index=1; Index < MaxShapes; Index++)
570 exchange = Standard_False;
571 Standard_Real dMidXYZ = MidXYZ(OrderInd(Index)) - MidXYZ(OrderInd(Index+1));
572 Standard_Real dLength = Length(OrderInd(Index)) - Length(OrderInd(Index+1));
573 if ( dMidXYZ >= tol ) {
574 // cout << "MidXYZ: " << MidXYZ(OrderInd(Index))<< " > " <<MidXYZ(OrderInd(Index+1))
575 // << " d: " << dMidXYZ << endl;
576 exchange = Standard_True;
578 else if ( Abs(dMidXYZ) < tol && dLength >= tol ) {
579 // cout << "Length: " << Length(OrderInd(Index))<< " > " <<Length(OrderInd(Index+1))
580 // << " d: " << dLength << endl;
581 exchange = Standard_True;
583 else if ( Abs(dMidXYZ) < tol && Abs(dLength) < tol &&
584 aShapes(OrderInd(Index)).ShapeType() <= TopAbs_FACE) {
586 // equal values possible on shapes such as two halves of a sphere and
587 // a membrane inside the sphere
589 BRepBndLib::Add( aShapes( OrderInd(Index) ), box1 );
590 if ( box1.IsVoid() ) continue;
591 BRepBndLib::Add( aShapes( OrderInd(Index+1) ), box2 );
592 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
593 if ( dSquareExtent >= tol ) {
594 // cout << "SquareExtent: " << box1.SquareExtent()<<" > "<<box2.SquareExtent() << endl;
595 exchange = Standard_True;
597 else if ( Abs(dSquareExtent) < tol ) {
598 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
599 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
600 val1 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
601 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
602 val2 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
603 //exchange = val1 > val2;
604 if ((val1 - val2) >= tol) {
605 exchange = Standard_True;
607 //cout << "box: " << val1<<" > "<<val2 << endl;
613 // cout << "exchange " << Index << " & " << Index+1 << endl;
614 aTemp = OrderInd(Index);
615 OrderInd(Index) = OrderInd(Index+1);
616 OrderInd(Index+1) = aTemp;
617 Sort = Standard_True;
622 for (Index=1; Index <= MaxShapes; Index++)
623 SL.Append( aShapes( OrderInd(Index) ));
627 //=======================================================================
628 //function : CompsolidToCompound
630 //=======================================================================
631 TopoDS_Shape GEOMUtils::CompsolidToCompound (const TopoDS_Shape& theCompsolid)
633 if (theCompsolid.ShapeType() != TopAbs_COMPSOLID) {
637 TopoDS_Compound aCompound;
639 B.MakeCompound(aCompound);
641 TopTools_MapOfShape mapShape;
642 TopoDS_Iterator It (theCompsolid, Standard_True, Standard_True);
644 for (; It.More(); It.Next()) {
645 TopoDS_Shape aShape_i = It.Value();
646 if (mapShape.Add(aShape_i)) {
647 B.Add(aCompound, aShape_i);
654 //=======================================================================
655 //function : AddSimpleShapes
657 //=======================================================================
658 void GEOMUtils::AddSimpleShapes (const TopoDS_Shape& theShape, TopTools_ListOfShape& theList)
660 if (theShape.ShapeType() != TopAbs_COMPOUND &&
661 theShape.ShapeType() != TopAbs_COMPSOLID) {
662 theList.Append(theShape);
666 TopTools_MapOfShape mapShape;
667 TopoDS_Iterator It (theShape, Standard_True, Standard_True);
669 for (; It.More(); It.Next()) {
670 TopoDS_Shape aShape_i = It.Value();
671 if (mapShape.Add(aShape_i)) {
672 if (aShape_i.ShapeType() == TopAbs_COMPOUND ||
673 aShape_i.ShapeType() == TopAbs_COMPSOLID) {
674 AddSimpleShapes(aShape_i, theList);
676 theList.Append(aShape_i);
682 //=======================================================================
683 //function : GetTypeOfSimplePart
685 //=======================================================================
686 TopAbs_ShapeEnum GEOMUtils::GetTypeOfSimplePart (const TopoDS_Shape& theShape)
688 TopAbs_ShapeEnum aType = theShape.ShapeType();
689 if (aType == TopAbs_VERTEX) return TopAbs_VERTEX;
690 else if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) return TopAbs_EDGE;
691 else if (aType == TopAbs_FACE || aType == TopAbs_SHELL) return TopAbs_FACE;
692 else if (aType == TopAbs_SOLID || aType == TopAbs_COMPSOLID) return TopAbs_SOLID;
693 else if (aType == TopAbs_COMPOUND) {
694 // Only the iType of the first shape in the compound is taken into account
695 TopoDS_Iterator It (theShape, Standard_False, Standard_False);
697 return GetTypeOfSimplePart(It.Value());
703 //=======================================================================
704 //function : GetEdgeNearPoint
706 //=======================================================================
707 TopoDS_Shape GEOMUtils::GetEdgeNearPoint (const TopoDS_Shape& theShape,
708 const TopoDS_Vertex& thePoint)
710 TopoDS_Shape aResult;
712 // 1. Explode the shape on edges
713 TopTools_MapOfShape mapShape;
714 Standard_Integer nbEdges = 0;
715 TopExp_Explorer exp (theShape, TopAbs_EDGE);
716 for (; exp.More(); exp.Next()) {
717 if (mapShape.Add(exp.Current())) {
723 Standard_NullObject::Raise("Given shape contains no edges");
726 Standard_Integer ind = 1;
727 TopTools_Array1OfShape anEdges (1, nbEdges);
728 TColStd_Array1OfReal aDistances (1, nbEdges);
729 for (exp.Init(theShape, TopAbs_EDGE); exp.More(); exp.Next()) {
730 if (mapShape.Add(exp.Current())) {
731 TopoDS_Shape anEdge = exp.Current();
732 anEdges(ind) = anEdge;
734 // 2. Classify the point relatively each edge
735 BRepExtrema_DistShapeShape aDistTool (thePoint, anEdges(ind));
736 if (!aDistTool.IsDone())
737 Standard_ConstructionError::Raise("Cannot find a distance from the given point to one of edges");
739 aDistances(ind) = aDistTool.Value();
744 // 3. Define edge, having minimum distance to the point
745 Standard_Real nearest = RealLast(), nbFound = 0;
746 Standard_Real prec = Precision::Confusion();
747 for (ind = 1; ind <= nbEdges; ind++) {
748 if (Abs(aDistances(ind) - nearest) < prec) {
751 else if (aDistances(ind) < nearest) {
752 nearest = aDistances(ind);
753 aResult = anEdges(ind);
760 Standard_ConstructionError::Raise("Multiple edges near the given point are found");
762 else if (nbFound == 0) {
763 Standard_ConstructionError::Raise("There are no edges near the given point");
771 //=======================================================================
772 //function : PreciseBoundingBox
774 //=======================================================================
775 Standard_Boolean GEOMUtils::PreciseBoundingBox
776 (const TopoDS_Shape &theShape, Bnd_Box &theBox)
778 if ( theBox.IsVoid() ) BRepBndLib::Add( theShape, theBox );
779 if ( theBox.IsVoid() ) return Standard_False;
781 Standard_Real aBound[6];
782 theBox.Get(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]);
785 const gp_Pnt aMid(0.5*(aBound[1] + aBound[0]), // XMid
786 0.5*(aBound[3] + aBound[2]), // YMid
787 0.5*(aBound[5] + aBound[4])); // ZMid
788 const gp_XYZ aSize(aBound[1] - aBound[0], // DX
789 aBound[3] - aBound[2], // DY
790 aBound[5] - aBound[4]); // DZ
791 const gp_Pnt aPnt[6] =
793 gp_Pnt(aBound[0] - (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMin
794 gp_Pnt(aBound[1] + (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMax
795 gp_Pnt(aMid.X(), aBound[2] - (aBound[3] - aBound[2]), aMid.Z()), // YMin
796 gp_Pnt(aMid.X(), aBound[3] + (aBound[3] - aBound[2]), aMid.Z()), // YMax
797 gp_Pnt(aMid.X(), aMid.Y(), aBound[4] - (aBound[5] - aBound[4])), // ZMin
798 gp_Pnt(aMid.X(), aMid.Y(), aBound[5] + (aBound[5] - aBound[4])) // ZMax
800 const gp_Dir aDir[3] = { gp::DX(), gp::DY(), gp::DZ() };
801 const Standard_Real aPlnSize[3] =
803 0.5*Max(aSize.Y(), aSize.Z()), // XMin, XMax planes
804 0.5*Max(aSize.X(), aSize.Z()), // YMin, YMax planes
805 0.5*Max(aSize.X(), aSize.Y()) // ZMin, ZMax planes
809 for (i = 0; i < 6; i++) {
810 const Standard_Integer iHalf = i/2;
811 const gp_Pln aPln(aPnt[i], aDir[iHalf]);
812 BRepBuilderAPI_MakeFace aMkFace(aPln, -aPlnSize[iHalf], aPlnSize[iHalf],
813 -aPlnSize[iHalf], aPlnSize[iHalf]);
815 if (!aMkFace.IsDone()) {
816 return Standard_False;
819 TopoDS_Shape aFace = aMkFace.Shape();
821 // Get minimal distance between planar face and shape.
822 Standard_Real aMinDist =
823 GEOMUtils::GetMinDistance(aFace, theShape, aPMin[0], aPMin[1]);
826 return Standard_False;
829 aBound[i] = aPMin[1].Coord(iHalf + 1);
832 // Update Bounding box with the new values.
834 theBox.Update(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]);
836 return Standard_True;
839 //=======================================================================
840 //function : GetMinDistanceSingular
842 //=======================================================================
843 double GEOMUtils::GetMinDistanceSingular(const TopoDS_Shape& aSh1,
844 const TopoDS_Shape& aSh2,
845 gp_Pnt& Ptmp1, gp_Pnt& Ptmp2)
849 Standard_Real AddDist1 = 0.;
850 Standard_Real AddDist2 = 0.;
851 Standard_Boolean IsChange1 = ModifyShape(aSh1, tmpSh1, AddDist1);
852 Standard_Boolean IsChange2 = ModifyShape(aSh2, tmpSh2, AddDist2);
854 if( !IsChange1 && !IsChange2 )
857 BRepExtrema_DistShapeShape dst(tmpSh1,tmpSh2);
859 double MinDist = 1.e9;
860 gp_Pnt PMin1, PMin2, P1, P2;
861 for (int i = 1; i <= dst.NbSolution(); i++) {
862 P1 = dst.PointOnShape1(i);
863 P2 = dst.PointOnShape2(i);
864 Standard_Real Dist = P1.Distance(P2);
865 if (MinDist > Dist) {
876 gp_Dir aDir(gp_Vec(PMin1,PMin2));
877 if( MinDist > (AddDist1+AddDist2) ) {
878 Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1,
879 PMin1.Y() + aDir.Y()*AddDist1,
880 PMin1.Z() + aDir.Z()*AddDist1 );
881 Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2,
882 PMin2.Y() - aDir.Y()*AddDist2,
883 PMin2.Z() - aDir.Z()*AddDist2 );
884 return (MinDist - AddDist1 - AddDist2);
888 Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1,
889 PMin1.Y() + aDir.Y()*AddDist1,
890 PMin1.Z() + aDir.Z()*AddDist1 );
894 Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2,
895 PMin2.Y() - aDir.Y()*AddDist2,
896 PMin2.Z() - aDir.Z()*AddDist2 );
901 double res = MinDist - AddDist1 - AddDist2;
902 if(res<0.) res = 0.0;
908 //=======================================================================
909 //function : GetMinDistance
911 //=======================================================================
912 Standard_Real GEOMUtils::GetMinDistance
913 (const TopoDS_Shape& theShape1,
914 const TopoDS_Shape& theShape2,
915 gp_Pnt& thePnt1, gp_Pnt& thePnt2)
917 Standard_Real aResult = 1.e9;
919 // Issue 0020231: A min distance bug with torus and vertex.
920 // Make GetMinDistance() return zero if a sole VERTEX is inside any of SOLIDs
922 // which of shapes consists of only one vertex?
923 TopExp_Explorer exp1(theShape1,TopAbs_VERTEX), exp2(theShape2,TopAbs_VERTEX);
924 TopoDS_Shape V1 = exp1.More() ? exp1.Current() : TopoDS_Shape();
925 TopoDS_Shape V2 = exp2.More() ? exp2.Current() : TopoDS_Shape();
926 exp1.Next(); exp2.Next();
927 if ( exp1.More() ) V1.Nullify();
928 if ( exp2.More() ) V2.Nullify();
929 // vertex and container of solids
930 TopoDS_Shape V = V1.IsNull() ? V2 : V1;
931 TopoDS_Shape S = V1.IsNull() ? theShape1 : theShape2;
933 // classify vertex against solids
934 gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( V ) );
935 for ( exp1.Init( S, TopAbs_SOLID ); exp1.More(); exp1.Next() ) {
936 BRepClass3d_SolidClassifier classifier( exp1.Current(), p, 1e-6);
937 if ( classifier.State() == TopAbs_IN ) {
947 // additional workaround for bugs 19899, 19908 and 19910 from Mantis
948 #if OCC_VERSION_LARGE < 0x07070000
949 aResult = GEOMUtils::GetMinDistanceSingular(theShape1, theShape2, thePnt1, thePnt2);
958 BRepExtrema_DistShapeShape dst (theShape1, theShape2);
962 for (int i = 1; i <= dst.NbSolution(); i++) {
963 P1 = dst.PointOnShape1(i);
964 P2 = dst.PointOnShape2(i);
966 Standard_Real Dist = P1.Distance(P2);
967 if (aResult < 0 || aResult > Dist) {
978 //=======================================================================
979 // function : ProjectPointOnFace()
980 // purpose : Returns the projection (3d point) if found, throws an exception otherwise
981 //=======================================================================
982 gp_Pnt GEOMUtils::ProjectPointOnFace(const gp_Pnt& thePoint,
983 const TopoDS_Shape& theFace,
984 double& theU, double& theV,
987 if (theFace.IsNull() || theFace.ShapeType() != TopAbs_FACE)
988 Standard_TypeMismatch::Raise
989 ("Projection aborted : the target shape is not a face");
991 TopoDS_Face aFace = TopoDS::Face(theFace);
992 Handle(Geom_Surface) surface = BRep_Tool::Surface(aFace);
993 double U1, U2, V1, V2;
994 BRepTools::UVBounds(aFace, U1, U2, V1, V2);
997 GeomAPI_ProjectPointOnSurf proj;
998 proj.Init(surface, U1, U2, V1, V2);
999 proj.Perform(thePoint);
1001 StdFail_NotDone::Raise("Projection aborted : the algorithm failed");
1002 int nbPoints = proj.NbPoints();
1004 Standard_ConstructionError::Raise("Projection aborted : No solution found");
1005 proj.LowerDistanceParameters(theU, theV);
1006 gp_Pnt2d aProjPnt (theU, theV);
1009 Standard_Real tol = Max(theTol, 1.e-4);
1010 BRepClass_FaceClassifier aClsf (aFace, aProjPnt, tol);
1011 if (aClsf.State() != TopAbs_IN && aClsf.State() != TopAbs_ON) {
1013 double minDist = RealLast();
1014 for (int i = 1; i <= nbPoints; i++) {
1015 Standard_Real Ui, Vi;
1016 proj.Parameters(i, Ui, Vi);
1017 aProjPnt = gp_Pnt2d(Ui, Vi);
1018 aClsf.Perform(aFace, aProjPnt, tol);
1019 if (aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON) {
1021 double dist = proj.Distance(i);
1022 if (dist < minDist) {
1030 Standard_ConstructionError::Raise("Projection aborted : No solution found");
1034 gp_Pnt surfPnt = surface->Value(theU, theV);
1038 //=======================================================================
1039 // function : ConvertClickToPoint()
1040 // purpose : Returns the point clicked in 3D view
1041 //=======================================================================
1042 gp_Pnt GEOMUtils::ConvertClickToPoint( int x, int y, Handle(V3d_View) aView )
1044 // We can't rely on Eye and At points to get EyeDir, because they collapse
1045 // for views with flat bounding boxes. For example if you create a circle and
1046 // switch to the top view, then both camera's Eye and At points will fall to zero
1047 // inside V3d_View::FitMinMax() method. It's by occt design.
1048 // So, we should use camera direction instead.
1050 Standard_Real XAt, YAt, ZAt;
1051 aView->At(XAt, YAt, ZAt);
1052 gp_Pnt AtPoint(XAt, YAt, ZAt);
1054 gp_Pln PlaneOfTheView = gp_Pln( AtPoint, aView->Camera()->Direction() );
1055 Standard_Real X, Y, Z;
1056 aView->Convert( x, y, X, Y, Z );
1057 gp_Pnt ConvertedPoint( X, Y, Z );
1059 gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project( PlaneOfTheView, ConvertedPoint );
1060 gp_Pnt ResultPoint = ElSLib::Value( ConvertedPointOnPlane.X(), ConvertedPointOnPlane.Y(), PlaneOfTheView );
1064 //=======================================================================
1065 // function : ConvertTreeToString()
1066 // purpose : Returns the string representation of dependency tree
1067 //=======================================================================
1068 void GEOMUtils::ConvertTreeToString( const TreeModel& tree,
1069 std::string& dependencyStr )
1071 TreeModel::const_iterator i;
1072 for ( i = tree.begin(); i != tree.end(); ++i ) {
1073 dependencyStr.append( i->first );
1074 dependencyStr.append( "-" );
1075 std::vector<LevelInfo> upLevelList = i->second.first;
1076 dependencyStr.append( "upward" );
1077 parseWard( upLevelList, dependencyStr );
1078 std::vector<LevelInfo> downLevelList = i->second.second;
1079 dependencyStr.append( "downward" );
1080 parseWard( downLevelList, dependencyStr );
1084 //=======================================================================
1085 // function : ConvertStringToTree()
1086 // purpose : Returns the dependency tree
1087 //=======================================================================
1088 void GEOMUtils::ConvertStringToTree( const std::string& dependencyStr,
1091 std::size_t cursor = 0;
1093 while( dependencyStr.find('-',cursor) != std::string::npos ) //find next selected object
1095 std::size_t objectIndex = dependencyStr.find( '-', cursor );
1096 std::string objectEntry = dependencyStr.substr( cursor, objectIndex - cursor );
1097 cursor = objectIndex;
1099 //std::size_t upwardIndexBegin = dependencyStr.find("{",cursor) + 1;
1100 //std::size_t upwardIndexFinish = dependencyStr.find("}",upwardIndexBegin);
1101 LevelsList upwardList = parseWard( dependencyStr, cursor );
1103 LevelsList downwardList = parseWard( dependencyStr, cursor );
1105 tree[objectEntry] = std::pair<LevelsList,LevelsList>( upwardList, downwardList );
1109 bool GEOMUtils::CheckShape( TopoDS_Shape& shape,
1110 bool checkGeometry )
1112 BRepCheck_Analyzer analyzer( shape, checkGeometry );
1113 return analyzer.IsValid();
1116 bool GEOMUtils::CheckBOPArguments(const TopoDS_Shape &theShape)
1118 BOPAlgo_ArgumentAnalyzer aChecker;
1120 aChecker.SetShape1(theShape);
1122 // Set default options
1123 aChecker.ArgumentTypeMode() = Standard_True;
1124 aChecker.SelfInterMode() = Standard_True;
1125 aChecker.SmallEdgeMode() = Standard_True;
1126 aChecker.RebuildFaceMode() = Standard_True;
1127 aChecker.ContinuityMode() = Standard_True;
1128 aChecker.CurveOnSurfaceMode() = Standard_True;
1130 aChecker.StopOnFirstFaulty() = Standard_True;
1133 // process result of checking
1134 const bool isValid = !aChecker.HasFaulty();
1139 bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
1140 TopAbs_ShapeEnum type,
1141 Standard_Real tolerance,
1142 bool checkGeometry )
1144 ShapeFix_ShapeTolerance aSft;
1145 aSft.LimitTolerance( shape, tolerance, tolerance, type );
1146 Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape( shape );
1148 shape = aSfs->Shape();
1149 return CheckShape( shape, checkGeometry );
1152 bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
1153 Standard_Real tolerance,
1154 bool checkGeometry )
1156 return FixShapeTolerance( shape, TopAbs_SHAPE, tolerance, checkGeometry );
1159 bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
1160 bool checkGeometry )
1162 return FixShapeTolerance( shape, Precision::Confusion(), checkGeometry );
1165 bool GEOMUtils::FixShapeCurves( TopoDS_Shape& shape )
1167 Standard_Real aT, aTolE, aD, aDMax;
1168 TopExp_Explorer aExpF, aExpE;
1169 NCollection_DataMap<TopoDS_Edge, Standard_Real, TopTools_ShapeMapHasher> aDMETol;
1170 aExpF.Init(shape, TopAbs_FACE);
1171 for (; aExpF.More(); aExpF.Next()) {
1172 const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current();
1173 aExpE.Init(aF, TopAbs_EDGE);
1174 for (; aExpE.More(); aExpE.Next()) {
1175 const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current();
1177 if (!BOPTools_AlgoTools::ComputeTolerance(aF, aE, aDMax, aT)) {
1184 aTolE = BRep_Tool::Tolerance(aE);
1185 if (aDMax < aTolE) continue;
1186 if (aDMETol.IsBound(aE)) {
1187 aD = aDMETol.Find(aE);
1190 aDMETol.Bind(aE, aDMax);
1194 aDMETol.Bind(aE, aDMax);
1198 NCollection_DataMap<TopoDS_Edge, Standard_Real, TopTools_ShapeMapHasher>::Iterator aDMETolIt(aDMETol);
1199 #ifdef USE_LIMIT_TOLERANCE
1200 ShapeFix_ShapeTolerance sat;
1204 for (; aDMETolIt.More(); aDMETolIt.Next()) {
1205 #ifdef USE_LIMIT_TOLERANCE
1206 sat.LimitTolerance(aDMETolIt.Key(), aDMETolIt.Value()*1.001);
1208 TopoDS_Iterator itv(aDMETolIt.Key());
1209 for (; itv.More(); itv.Next())
1210 b.UpdateVertex(TopoDS::Vertex(itv.Value()), aDMETolIt.Value()*1.001);
1211 b.UpdateEdge(aDMETolIt.Key(), aDMETolIt.Value()*1.001);
1214 return CheckShape( shape );
1217 bool GEOMUtils::Write( const TopoDS_Shape& shape, const char* fileName )
1219 return BRepTools::Write( shape, fileName );
1222 TopoDS_Shape GEOMUtils::ReduceCompound( const TopoDS_Shape& shape )
1224 TopoDS_Shape result = shape;
1226 if ( shape.ShapeType() == TopAbs_COMPOUND ||
1227 shape.ShapeType() == TopAbs_COMPSOLID ) {
1229 TopTools_ListOfShape l;
1231 TopoDS_Iterator it ( shape );
1232 for ( ; it.More(); it.Next() )
1233 l.Append( it.Value() );
1234 if ( l.Extent() == 1 && l.First() != shape )
1235 result = ReduceCompound( l.First() );
1241 //=======================================================================
1242 //function : DefaultDeflection
1244 //=======================================================================
1245 double GEOMUtils::DefaultDeflection()
1250 //=======================================================================
1251 //function : CanBeMeshed
1253 //=======================================================================
1254 static bool GEOMUtils_CanBeMeshed (const TopoDS_Shape& theShape,
1255 const bool theCheckMesh,
1258 // Is shape triangulated?
1261 TopExp_Explorer ex (theShape, TopAbs_FACE);
1262 TopLoc_Location aLoc;
1265 for ( ; ex.More() && theHasMesh; ex.Next() ) {
1266 const TopoDS_Face& aFace = TopoDS::Face( ex.Current() );
1267 Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation( aFace, aLoc );
1268 theHasMesh = !aPoly.IsNull();
1272 else { // no faces, try edges
1273 ex.Init(theShape, TopAbs_EDGE);
1275 return false; // nothing to mesh
1278 for ( ; ex.More() && theHasMesh; ex.Next() ) {
1279 Handle(Poly_Polygon3D) aPE = BRep_Tool::Polygon3D(TopoDS::Edge(ex.Current()), aLoc);
1280 theHasMesh = !aPE.IsNull();
1288 //=======================================================================
1289 //function : MeshShape
1291 //=======================================================================
1292 bool GEOMUtils::MeshShape( const TopoDS_Shape theShape,
1293 const double theDeflection,
1294 const bool theForced,
1295 const double theAngleDeflection,
1296 const bool isRelative,
1297 const bool doPostCheck)
1299 Standard_Real aDeflection = (theDeflection <= 0) ? DefaultDeflection() : theDeflection;
1301 // Is shape triangulated?
1302 bool alreadyMeshed = true;
1303 if (!GEOMUtils_CanBeMeshed (theShape, /*theCheckMesh*/true, alreadyMeshed))
1306 if (alreadyMeshed && !theForced)
1310 // Compute bounding box
1312 BRepBndLib::Add(theShape, B);
1314 return false; // NPAL15983 (Bug when displaying empty groups)
1316 Standard_Real aDeviationCoeff = aDeflection;
1317 Standard_Real aMaxChordialDeviation = aDeflection;
1318 aDeflection = Prs3d::GetDeflection(B, aDeviationCoeff, aMaxChordialDeviation);
1321 // Clean triangulation before compute incremental mesh
1322 BRepTools::Clean(theShape);
1324 // Compute triangulation
1325 BRepMesh_IncrementalMesh mesh (theShape, aDeflection, Standard_False, theAngleDeflection);
1333 GEOMUtils_CanBeMeshed(theShape, /*theCheckMesh*/true, alreadyMeshed);
1334 return alreadyMeshed;
1337 //=======================================================================
1338 //function : CheckTriangulation
1340 //=======================================================================
1341 bool GEOMUtils::CheckTriangulation (const TopoDS_Shape& theShape)
1343 Standard_Real aHLRAngle = 0.349066;
1344 return MeshShape(theShape, DefaultDeflection(), false, aHLRAngle);
1347 //=======================================================================
1348 //function : IsOpenPath
1350 //=======================================================================
1351 bool GEOMUtils::IsOpenPath(const TopoDS_Shape &theShape)
1355 if (theShape.IsNull() == Standard_False) {
1356 if (theShape.Closed()) {
1357 // The shape is closed
1360 const TopAbs_ShapeEnum aType = theShape.ShapeType();
1362 if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) {
1363 // Check if path ends are coincident.
1364 TopoDS_Vertex aV[2];
1366 if (aType == TopAbs_EDGE) {
1368 TopExp::Vertices(TopoDS::Edge(theShape), aV[0], aV[1]);
1371 TopExp::Vertices(TopoDS::Wire(theShape), aV[0], aV[1]);
1374 if (aV[0].IsNull() == Standard_False &&
1375 aV[1].IsNull() == Standard_False) {
1376 if (aV[0].IsSame(aV[1])) {
1377 // The shape is closed
1380 const Standard_Real aTol1 = BRep_Tool::Tolerance(aV[0]);
1381 const Standard_Real aTol2 = BRep_Tool::Tolerance(aV[1]);
1382 const gp_Pnt aPnt1 = BRep_Tool::Pnt(aV[0]);
1383 const gp_Pnt aPnt2 = BRep_Tool::Pnt(aV[1]);
1385 if (aPnt1.Distance(aPnt2) <= aTol1 + aTol2) {
1386 // The shape is closed
1398 //=======================================================================
1399 //function : CompareToleranceValues
1401 //=======================================================================
1402 int GEOMUtils::CompareToleranceValues(const double theTolShape,
1403 const double theTolRef)
1405 const double aTolTol = Min(DEFAULT_MAX_TOLERANCE_TOLERANCE,
1406 theTolRef*DEFAULT_TOLERANCE_TOLERANCE);
1410 if (theTolShape < theTolRef - aTolTol) {
1412 } else if (theTolShape > theTolRef + aTolTol) {
1419 //=======================================================================
1420 //function : IsFitCondition
1422 //=======================================================================
1423 bool GEOMUtils::IsFitCondition(const ComparisonCondition theCondition,
1424 const double theTolShape,
1425 const double theTolRef)
1427 const int aCompValue = CompareToleranceValues(theTolShape, theTolRef);
1430 switch (theCondition) {
1432 isFit = aCompValue == 1;
1434 case GEOMUtils::CC_GE:
1435 isFit = aCompValue != -1;
1437 case GEOMUtils::CC_LT:
1438 isFit = aCompValue == -1;
1440 case GEOMUtils::CC_LE:
1441 isFit = aCompValue != 1;