1 // Copyright (C) 2007-2015 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 #include <Standard_Stream.hxx>
25 #include <GEOMUtils.hxx>
27 #include <Basics_OCCTVersion.hxx>
30 #include <Utils_ExceptHandlers.hxx>
33 #include <BRepMesh_IncrementalMesh.hxx>
35 #include <BRepExtrema_DistShapeShape.hxx>
37 #include <BRep_Builder.hxx>
38 #include <BRep_Tool.hxx>
39 #include <BRepBndLib.hxx>
40 #include <BRepGProp.hxx>
41 #include <BRepTools.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 <BOPTools_AlgoTools.hxx>
57 #include <TopoDS_Edge.hxx>
58 #include <TopoDS_Face.hxx>
59 #include <TopoDS_Shape.hxx>
60 #include <TopoDS_Vertex.hxx>
61 #include <TopoDS_Compound.hxx>
62 #include <TopoDS_Iterator.hxx>
63 #include <TopExp_Explorer.hxx>
64 #include <TopTools_MapOfShape.hxx>
65 #include <TopTools_ListOfShape.hxx>
66 #include <TopTools_ListIteratorOfListOfShape.hxx>
67 #include <TopTools_Array1OfShape.hxx>
69 #include <Geom_Circle.hxx>
70 #include <Geom_Surface.hxx>
71 #include <Geom_Plane.hxx>
72 #include <Geom_SphericalSurface.hxx>
73 #include <Geom_ToroidalSurface.hxx>
74 #include <Geom_RectangularTrimmedSurface.hxx>
76 #include <GeomLProp_CLProps.hxx>
77 #include <GeomLProp_SLProps.hxx>
79 #include <GProp_GProps.hxx>
80 #include <GProp_PrincipalProps.hxx>
82 #include <TColStd_Array1OfReal.hxx>
87 #include <ShapeAnalysis.hxx>
88 #include <ShapeFix_Shape.hxx>
89 #include <ShapeFix_ShapeTolerance.hxx>
91 #include <ProjLib.hxx>
98 #include <Standard_Failure.hxx>
99 #include <Standard_NullObject.hxx>
100 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
102 #define STD_SORT_ALGO 1
104 // When the following macro is defined, ShapeFix_ShapeTolerance function is used to set max tolerance of curve
105 // in GEOMUtils::FixShapeCurves function; otherwise less restrictive BRep_Builder::UpdateEdge/UpdateVertex
107 // VSR (29/12/2014): macro disabled
108 //#define USE_LIMIT_TOLERANCE
113 * This function constructs and returns modified shape from the original one
114 * for singular cases. It is used for the method GetMinDistanceSingular.
116 * \param theShape the original shape
117 * \param theModifiedShape output parameter. The modified shape.
118 * \param theAddDist output parameter. The added distance for modified shape.
119 * \retval true if the shape is modified; false otherwise.
123 Standard_Boolean ModifyShape(const TopoDS_Shape &theShape,
124 TopoDS_Shape &theModifiedShape,
125 Standard_Real &theAddDist)
127 TopExp_Explorer anExp;
131 theModifiedShape.Nullify();
133 for ( anExp.Init( theShape, TopAbs_FACE ); anExp.More(); anExp.Next() ) {
135 theModifiedShape = anExp.Current();
138 TopoDS_Shape sh = theShape;
139 while(sh.ShapeType()==TopAbs_COMPOUND) {
140 TopoDS_Iterator it(sh);
143 Handle(Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(theModifiedShape));
144 if( S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ||
145 S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) ||
147 const Standard_Boolean isShell =
148 (sh.ShapeType()==TopAbs_SHELL || sh.ShapeType()==TopAbs_FACE);
150 if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) {
151 Handle(Geom_SphericalSurface) SS = Handle(Geom_SphericalSurface)::DownCast(S);
152 gp_Pnt PC = SS->Location();
155 B.MakeVertex(V,PC,1.e-7);
156 theModifiedShape = V;
157 theAddDist = SS->Radius();
158 return Standard_True;
160 if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) ) {
161 Handle(Geom_ToroidalSurface) TS = Handle(Geom_ToroidalSurface)::DownCast(S);
162 gp_Ax3 ax3 = TS->Position();
163 Handle(Geom_Circle) C = new Geom_Circle(ax3.Ax2(),TS->MajorRadius());
166 B.MakeEdge(E,C,1.e-7);
167 theModifiedShape = E;
168 theAddDist = TS->MinorRadius();
169 return Standard_True;
172 // non solid case or any periodic surface (Mantis 22454).
174 // changes for 0020677: EDF 1219 GEOM: MinDistance gives 0 instead of 20.88
175 //S->Bounds(U1,U2,V1,V2); changed by
176 ShapeAnalysis::GetFaceUVBounds(TopoDS::Face(theModifiedShape),U1,U2,V1,V2);
177 // end of changes for 020677 (dmv)
178 Handle(Geom_RectangularTrimmedSurface) TrS1 =
179 new Geom_RectangularTrimmedSurface(S,U1,(U1+U2)/2.,V1,V2);
180 Handle(Geom_RectangularTrimmedSurface) TrS2 =
181 new Geom_RectangularTrimmedSurface(S,(U1+U2)/2.,U2,V1,V2);
182 TopoDS_Shape aMShape;
184 TopoDS_Face F1 = BRepBuilderAPI_MakeFace(TrS1, Precision::Confusion());
185 TopoDS_Face F2 = BRepBuilderAPI_MakeFace(TrS2, Precision::Confusion());
189 B.MakeCompound(TopoDS::Compound(aMShape));
193 // The original shape is a solid.
194 BRepBuilderAPI_Sewing aSewing (Precision::Confusion()*10.0);
198 aMShape = aSewing.SewedShape();
202 B.Add(aSolid, aMShape);
206 Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape;
208 sfs->SetPrecision(1.e-6);
209 sfs->SetMaxTolerance(1.0);
211 theModifiedShape = sfs->Shape();
212 return Standard_True;
216 theModifiedShape = theShape;
217 return Standard_False;
220 void parseWard( const GEOMUtils::LevelsList &theLevelList, std::string &treeStr )
222 treeStr.append( "{" );
223 for( GEOMUtils::LevelsList::const_iterator j = theLevelList.begin();
224 j != theLevelList.end(); ++j ) {
225 if ( j != theLevelList.begin() ) {
226 treeStr.append( ";" );
228 GEOMUtils::LevelInfo level = (*j);
229 GEOMUtils::LevelInfo::iterator upIter;
230 for ( upIter = level.begin(); upIter != level.end(); ++upIter ) {
231 if ( upIter != level.begin() ) {
232 treeStr.append( "," );
234 treeStr.append( upIter->first );
235 for ( std::vector<std::string>::iterator k = upIter->second.begin(); k != upIter->second.end(); ++k ) {
236 treeStr.append( "_" );
237 treeStr.append( *k );
241 treeStr.append( "}" );
244 GEOMUtils::LevelsList parseWard( const std::string& theData, std::size_t& theCursor )
246 std::size_t indexStart = theData.find( "{", theCursor ) + 1;
247 std::size_t indexEnd = theData.find( "}", indexStart );
249 std::string ward = theData.substr( indexStart, indexEnd - indexStart );
250 std::stringstream ss(ward);
252 std::vector<std::string> levelsListStr;
253 while ( std::getline( ss, substr, ';' ) ) {
254 if ( !substr.empty() )
255 levelsListStr.push_back( substr );
257 GEOMUtils::LevelsList levelsListData;
258 for( int level = 0; level < levelsListStr.size(); level++ ) {
259 std::vector<std::string> namesListStr;
260 std::stringstream ss1( levelsListStr[level] );
261 while ( std::getline( ss1, substr, ',' ) ) {
262 if ( !substr.empty() )
263 namesListStr.push_back( substr );
265 GEOMUtils::LevelInfo levelInfoData;
266 for( int node = 0; node < namesListStr.size(); node++ ) {
267 std::vector<std::string> linksListStr;
268 std::stringstream ss2( namesListStr[node] );
269 while ( std::getline( ss2, substr, '_' ) ) {
270 if ( !substr.empty() )
271 linksListStr.push_back( substr );
273 std::string nodeItem = linksListStr[0];
274 if( !nodeItem.empty() ) {
275 GEOMUtils::NodeLinks linksListData;
276 for( int link = 1; link < linksListStr.size(); link++ ) {
277 std::string linkItem = linksListStr[link];
278 linksListData.push_back( linkItem );
280 levelInfoData[nodeItem] = linksListData;
283 levelsListData.push_back(levelInfoData);
286 theCursor = indexEnd + 1;
287 return levelsListData;
292 //=======================================================================
293 //function : ShapeToDouble
294 //purpose : used by CompareShapes::operator()
295 //=======================================================================
296 std::pair<double, double> GEOMUtils::ShapeToDouble (const TopoDS_Shape& S, bool isOldSorting)
298 // Computing of CentreOfMass
302 if (S.ShapeType() == TopAbs_VERTEX) {
303 GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S));
304 Len = (double)S.Orientation();
308 // BEGIN: fix for Mantis issue 0020842
310 BRepGProp::LinearProperties(S, GPr);
313 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
314 BRepGProp::LinearProperties(S, GPr);
316 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
317 BRepGProp::SurfaceProperties(S, GPr);
320 BRepGProp::VolumeProperties(S, GPr);
323 // END: fix for Mantis issue 0020842
324 GPoint = GPr.CentreOfMass();
328 double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9;
329 return std::make_pair(dMidXYZ, Len);
332 //=======================================================================
333 //function : GetPosition
335 //=======================================================================
336 gp_Ax3 GEOMUtils::GetPosition (const TopoDS_Shape& theShape)
340 if (theShape.IsNull())
344 aResult.Transform(theShape.Location().Transformation());
345 if (theShape.ShapeType() == TopAbs_FACE) {
346 Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(theShape));
347 if (!aGS.IsNull() && aGS->IsKind(STANDARD_TYPE(Geom_Plane))) {
348 Handle(Geom_Plane) aGPlane = Handle(Geom_Plane)::DownCast(aGS);
349 gp_Pln aPln = aGPlane->Pln();
350 aResult = aPln.Position();
351 // In case of reverse orinetation of the face invert the plane normal
352 // (the face's normal does not mathc the plane's normal in this case)
353 if(theShape.Orientation() == TopAbs_REVERSED)
355 gp_Dir Vx = aResult.XDirection();
356 gp_Dir N = aResult.Direction().Mirrored(Vx);
357 gp_Pnt P = aResult.Location();
358 aResult = gp_Ax3(P, N, Vx);
366 TopAbs_ShapeEnum aShType = theShape.ShapeType();
368 if (aShType == TopAbs_VERTEX) {
369 aPnt = BRep_Tool::Pnt(TopoDS::Vertex(theShape));
372 if (aShType == TopAbs_COMPOUND) {
373 aShType = GetTypeOfSimplePart(theShape);
376 GProp_GProps aSystem;
377 if (aShType == TopAbs_EDGE || aShType == TopAbs_WIRE)
378 BRepGProp::LinearProperties(theShape, aSystem);
379 else if (aShType == TopAbs_FACE || aShType == TopAbs_SHELL)
380 BRepGProp::SurfaceProperties(theShape, aSystem);
382 BRepGProp::VolumeProperties(theShape, aSystem);
384 aPnt = aSystem.CentreOfMass();
387 aResult.SetLocation(aPnt);
392 //=======================================================================
393 //function : GetVector
395 //=======================================================================
396 gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape,
397 Standard_Boolean doConsiderOrientation)
399 if (theShape.IsNull())
400 Standard_NullObject::Raise("Null shape is given for a vector");
402 if (theShape.ShapeType() != TopAbs_EDGE)
403 Standard_TypeMismatch::Raise("Invalid shape is given, must be a vector or an edge");
405 TopoDS_Edge anE = TopoDS::Edge(theShape);
407 TopoDS_Vertex V1, V2;
408 TopExp::Vertices(anE, V1, V2, doConsiderOrientation);
410 if (V1.IsNull() || V2.IsNull())
411 Standard_NullObject::Raise("Invalid edge is given, it must have two points");
413 gp_Vec aV (BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
414 if (aV.Magnitude() < gp::Resolution()) {
415 Standard_ConstructionError::Raise("Vector of zero length is given");
421 //=======================================================================
422 //function : CompareShapes::operator()
423 //purpose : used by std::sort(), called from SortShapes()
424 //=======================================================================
425 bool GEOMUtils::CompareShapes::operator() (const TopoDS_Shape& theShape1,
426 const TopoDS_Shape& theShape2)
428 if (!myMap.IsBound(theShape1)) {
429 myMap.Bind(theShape1, ShapeToDouble(theShape1, myIsOldSorting));
432 if (!myMap.IsBound(theShape2)) {
433 myMap.Bind(theShape2, ShapeToDouble(theShape2, myIsOldSorting));
436 std::pair<double, double> val1 = myMap.Find(theShape1);
437 std::pair<double, double> val2 = myMap.Find(theShape2);
439 double tol = Precision::Confusion();
440 bool exchange = Standard_False;
442 double dMidXYZ = val1.first - val2.first;
443 if (dMidXYZ >= tol) {
444 exchange = Standard_True;
446 else if (Abs(dMidXYZ) < tol) {
447 double dLength = val1.second - val2.second;
448 if (dLength >= tol) {
449 exchange = Standard_True;
451 else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) {
453 // equal values possible on shapes such as two halves of a sphere and
454 // a membrane inside the sphere
456 BRepBndLib::Add(theShape1, box1);
457 if (!box1.IsVoid()) {
458 BRepBndLib::Add(theShape2, box2);
459 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
460 if (dSquareExtent >= tol) {
461 exchange = Standard_True;
463 else if (Abs(dSquareExtent) < tol) {
464 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
465 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
466 val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
467 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
468 val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
469 if ((val1 - val2) >= tol) {
470 exchange = Standard_True;
477 //return val1 < val2;
481 //=======================================================================
482 //function : SortShapes
484 //=======================================================================
485 void GEOMUtils::SortShapes (TopTools_ListOfShape& SL,
486 const Standard_Boolean isOldSorting)
489 std::vector<TopoDS_Shape> aShapesVec;
490 aShapesVec.reserve(SL.Extent());
492 TopTools_ListIteratorOfListOfShape it (SL);
493 for (; it.More(); it.Next()) {
494 aShapesVec.push_back(it.Value());
498 CompareShapes shComp (isOldSorting);
499 std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp);
500 //std::sort(aShapesVec.begin(), aShapesVec.end(), shComp);
502 std::vector<TopoDS_Shape>::const_iterator anIter = aShapesVec.begin();
503 for (; anIter != aShapesVec.end(); ++anIter) {
507 // old implementation
508 Standard_Integer MaxShapes = SL.Extent();
509 TopTools_Array1OfShape aShapes (1,MaxShapes);
510 TColStd_Array1OfInteger OrderInd(1,MaxShapes);
511 TColStd_Array1OfReal MidXYZ (1,MaxShapes); //X,Y,Z;
512 TColStd_Array1OfReal Length (1,MaxShapes); //X,Y,Z;
514 // Computing of CentreOfMass
515 Standard_Integer Index;
518 TopTools_ListIteratorOfListOfShape it(SL);
519 for (Index=1; it.More(); Index++)
521 TopoDS_Shape S = it.Value();
522 SL.Remove( it ); // == it.Next()
524 OrderInd.SetValue (Index, Index);
525 if (S.ShapeType() == TopAbs_VERTEX) {
526 GPoint = BRep_Tool::Pnt( TopoDS::Vertex( S ));
527 Length.SetValue( Index, (Standard_Real) S.Orientation());
530 // BEGIN: fix for Mantis issue 0020842
532 BRepGProp::LinearProperties (S, GPr);
535 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
536 BRepGProp::LinearProperties (S, GPr);
538 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
539 BRepGProp::SurfaceProperties(S, GPr);
542 BRepGProp::VolumeProperties(S, GPr);
545 // END: fix for Mantis issue 0020842
546 GPoint = GPr.CentreOfMass();
547 Length.SetValue(Index, GPr.Mass());
549 MidXYZ.SetValue(Index, GPoint.X()*999.0 + GPoint.Y()*99.0 + GPoint.Z()*0.9);
550 //cout << Index << " L: " << Length(Index) << "CG: " << MidXYZ(Index) << endl;
554 Standard_Integer aTemp;
555 Standard_Boolean exchange, Sort = Standard_True;
556 Standard_Real tol = Precision::Confusion();
559 Sort = Standard_False;
560 for (Index=1; Index < MaxShapes; Index++)
562 exchange = Standard_False;
563 Standard_Real dMidXYZ = MidXYZ(OrderInd(Index)) - MidXYZ(OrderInd(Index+1));
564 Standard_Real dLength = Length(OrderInd(Index)) - Length(OrderInd(Index+1));
565 if ( dMidXYZ >= tol ) {
566 // cout << "MidXYZ: " << MidXYZ(OrderInd(Index))<< " > " <<MidXYZ(OrderInd(Index+1))
567 // << " d: " << dMidXYZ << endl;
568 exchange = Standard_True;
570 else if ( Abs(dMidXYZ) < tol && dLength >= tol ) {
571 // cout << "Length: " << Length(OrderInd(Index))<< " > " <<Length(OrderInd(Index+1))
572 // << " d: " << dLength << endl;
573 exchange = Standard_True;
575 else if ( Abs(dMidXYZ) < tol && Abs(dLength) < tol &&
576 aShapes(OrderInd(Index)).ShapeType() <= TopAbs_FACE) {
578 // equal values possible on shapes such as two halves of a sphere and
579 // a membrane inside the sphere
581 BRepBndLib::Add( aShapes( OrderInd(Index) ), box1 );
582 if ( box1.IsVoid() ) continue;
583 BRepBndLib::Add( aShapes( OrderInd(Index+1) ), box2 );
584 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
585 if ( dSquareExtent >= tol ) {
586 // cout << "SquareExtent: " << box1.SquareExtent()<<" > "<<box2.SquareExtent() << endl;
587 exchange = Standard_True;
589 else if ( Abs(dSquareExtent) < tol ) {
590 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
591 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
592 val1 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
593 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
594 val2 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
595 //exchange = val1 > val2;
596 if ((val1 - val2) >= tol) {
597 exchange = Standard_True;
599 //cout << "box: " << val1<<" > "<<val2 << endl;
605 // cout << "exchange " << Index << " & " << Index+1 << endl;
606 aTemp = OrderInd(Index);
607 OrderInd(Index) = OrderInd(Index+1);
608 OrderInd(Index+1) = aTemp;
609 Sort = Standard_True;
614 for (Index=1; Index <= MaxShapes; Index++)
615 SL.Append( aShapes( OrderInd(Index) ));
619 //=======================================================================
620 //function : CompsolidToCompound
622 //=======================================================================
623 TopoDS_Shape GEOMUtils::CompsolidToCompound (const TopoDS_Shape& theCompsolid)
625 if (theCompsolid.ShapeType() != TopAbs_COMPSOLID) {
629 TopoDS_Compound aCompound;
631 B.MakeCompound(aCompound);
633 TopTools_MapOfShape mapShape;
634 TopoDS_Iterator It (theCompsolid, Standard_True, Standard_True);
636 for (; It.More(); It.Next()) {
637 TopoDS_Shape aShape_i = It.Value();
638 if (mapShape.Add(aShape_i)) {
639 B.Add(aCompound, aShape_i);
646 //=======================================================================
647 //function : AddSimpleShapes
649 //=======================================================================
650 void GEOMUtils::AddSimpleShapes (const TopoDS_Shape& theShape, TopTools_ListOfShape& theList)
652 if (theShape.ShapeType() != TopAbs_COMPOUND &&
653 theShape.ShapeType() != TopAbs_COMPSOLID) {
654 theList.Append(theShape);
658 TopTools_MapOfShape mapShape;
659 TopoDS_Iterator It (theShape, Standard_True, Standard_True);
661 for (; It.More(); It.Next()) {
662 TopoDS_Shape aShape_i = It.Value();
663 if (mapShape.Add(aShape_i)) {
664 if (aShape_i.ShapeType() == TopAbs_COMPOUND ||
665 aShape_i.ShapeType() == TopAbs_COMPSOLID) {
666 AddSimpleShapes(aShape_i, theList);
668 theList.Append(aShape_i);
674 //=======================================================================
675 //function : CheckTriangulation
677 //=======================================================================
678 bool GEOMUtils::CheckTriangulation (const TopoDS_Shape& aShape)
680 bool isTriangulation = true;
682 TopExp_Explorer exp (aShape, TopAbs_FACE);
685 TopLoc_Location aTopLoc;
686 Handle(Poly_Triangulation) aTRF;
687 aTRF = BRep_Tool::Triangulation(TopoDS::Face(exp.Current()), aTopLoc);
689 isTriangulation = false;
692 else // no faces, try edges
694 TopExp_Explorer expe (aShape, TopAbs_EDGE);
698 TopLoc_Location aLoc;
699 Handle(Poly_Polygon3D) aPE = BRep_Tool::Polygon3D(TopoDS::Edge(expe.Current()), aLoc);
701 isTriangulation = false;
705 if (!isTriangulation) {
706 // calculate deflection
707 Standard_Real aDeviationCoefficient = 0.001;
710 BRepBndLib::Add(aShape, B);
711 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
712 B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
714 Standard_Real dx = aXmax - aXmin, dy = aYmax - aYmin, dz = aZmax - aZmin;
715 Standard_Real aDeflection = Max(Max(dx, dy), dz) * aDeviationCoefficient * 4;
716 Standard_Real aHLRAngle = 0.349066;
718 BRepMesh_IncrementalMesh Inc (aShape, aDeflection, Standard_False, aHLRAngle);
724 //=======================================================================
725 //function : GetTypeOfSimplePart
727 //=======================================================================
728 TopAbs_ShapeEnum GEOMUtils::GetTypeOfSimplePart (const TopoDS_Shape& theShape)
730 TopAbs_ShapeEnum aType = theShape.ShapeType();
731 if (aType == TopAbs_VERTEX) return TopAbs_VERTEX;
732 else if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) return TopAbs_EDGE;
733 else if (aType == TopAbs_FACE || aType == TopAbs_SHELL) return TopAbs_FACE;
734 else if (aType == TopAbs_SOLID || aType == TopAbs_COMPSOLID) return TopAbs_SOLID;
735 else if (aType == TopAbs_COMPOUND) {
736 // Only the iType of the first shape in the compound is taken into account
737 TopoDS_Iterator It (theShape, Standard_False, Standard_False);
739 return GetTypeOfSimplePart(It.Value());
745 //=======================================================================
746 //function : GetEdgeNearPoint
748 //=======================================================================
749 TopoDS_Shape GEOMUtils::GetEdgeNearPoint (const TopoDS_Shape& theShape,
750 const TopoDS_Vertex& thePoint)
752 TopoDS_Shape aResult;
754 // 1. Explode the shape on edges
755 TopTools_MapOfShape mapShape;
756 Standard_Integer nbEdges = 0;
757 TopExp_Explorer exp (theShape, TopAbs_EDGE);
758 for (; exp.More(); exp.Next()) {
759 if (mapShape.Add(exp.Current())) {
765 Standard_NullObject::Raise("Given shape contains no edges");
768 Standard_Integer ind = 1;
769 TopTools_Array1OfShape anEdges (1, nbEdges);
770 TColStd_Array1OfReal aDistances (1, nbEdges);
771 for (exp.Init(theShape, TopAbs_EDGE); exp.More(); exp.Next()) {
772 if (mapShape.Add(exp.Current())) {
773 TopoDS_Shape anEdge = exp.Current();
774 anEdges(ind) = anEdge;
776 // 2. Classify the point relatively each edge
777 BRepExtrema_DistShapeShape aDistTool (thePoint, anEdges(ind));
778 if (!aDistTool.IsDone())
779 Standard_ConstructionError::Raise("Cannot find a distance from the given point to one of edges");
781 aDistances(ind) = aDistTool.Value();
786 // 3. Define edge, having minimum distance to the point
787 Standard_Real nearest = RealLast(), nbFound = 0;
788 Standard_Real prec = Precision::Confusion();
789 for (ind = 1; ind <= nbEdges; ind++) {
790 if (Abs(aDistances(ind) - nearest) < prec) {
793 else if (aDistances(ind) < nearest) {
794 nearest = aDistances(ind);
795 aResult = anEdges(ind);
802 Standard_ConstructionError::Raise("Multiple edges near the given point are found");
804 else if (nbFound == 0) {
805 Standard_ConstructionError::Raise("There are no edges near the given point");
813 //=======================================================================
814 //function : PreciseBoundingBox
816 //=======================================================================
817 Standard_Boolean GEOMUtils::PreciseBoundingBox
818 (const TopoDS_Shape &theShape, Bnd_Box &theBox)
820 if ( theBox.IsVoid() ) BRepBndLib::Add( theShape, theBox );
821 if ( theBox.IsVoid() ) return Standard_False;
823 Standard_Real aBound[6];
824 theBox.Get(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]);
827 const gp_Pnt aMid(0.5*(aBound[1] + aBound[0]), // XMid
828 0.5*(aBound[3] + aBound[2]), // YMid
829 0.5*(aBound[5] + aBound[4])); // ZMid
830 const gp_XYZ aSize(aBound[1] - aBound[0], // DX
831 aBound[3] - aBound[2], // DY
832 aBound[5] - aBound[4]); // DZ
833 const gp_Pnt aPnt[6] =
835 gp_Pnt(aBound[0] - (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMin
836 gp_Pnt(aBound[1] + (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMax
837 gp_Pnt(aMid.X(), aBound[2] - (aBound[3] - aBound[2]), aMid.Z()), // YMin
838 gp_Pnt(aMid.X(), aBound[3] + (aBound[3] - aBound[2]), aMid.Z()), // YMax
839 gp_Pnt(aMid.X(), aMid.Y(), aBound[4] - (aBound[5] - aBound[4])), // ZMin
840 gp_Pnt(aMid.X(), aMid.Y(), aBound[5] + (aBound[5] - aBound[4])) // ZMax
842 const gp_Dir aDir[3] = { gp::DX(), gp::DY(), gp::DZ() };
843 const Standard_Real aPlnSize[3] =
845 0.5*Max(aSize.Y(), aSize.Z()), // XMin, XMax planes
846 0.5*Max(aSize.X(), aSize.Z()), // YMin, YMax planes
847 0.5*Max(aSize.X(), aSize.Y()) // ZMin, ZMax planes
851 for (i = 0; i < 6; i++) {
852 const Standard_Integer iHalf = i/2;
853 const gp_Pln aPln(aPnt[i], aDir[iHalf]);
854 BRepBuilderAPI_MakeFace aMkFace(aPln, -aPlnSize[iHalf], aPlnSize[iHalf],
855 -aPlnSize[iHalf], aPlnSize[iHalf]);
857 if (!aMkFace.IsDone()) {
858 return Standard_False;
861 TopoDS_Shape aFace = aMkFace.Shape();
863 // Get minimal distance between planar face and shape.
864 Standard_Real aMinDist =
865 GEOMUtils::GetMinDistance(aFace, theShape, aPMin[0], aPMin[1]);
868 return Standard_False;
871 aBound[i] = aPMin[1].Coord(iHalf + 1);
874 // Update Bounding box with the new values.
876 theBox.Update(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]);
878 return Standard_True;
881 //=======================================================================
882 //function : GetMinDistanceSingular
884 //=======================================================================
885 double GEOMUtils::GetMinDistanceSingular(const TopoDS_Shape& aSh1,
886 const TopoDS_Shape& aSh2,
887 gp_Pnt& Ptmp1, gp_Pnt& Ptmp2)
891 Standard_Real AddDist1 = 0.;
892 Standard_Real AddDist2 = 0.;
893 Standard_Boolean IsChange1 = ModifyShape(aSh1, tmpSh1, AddDist1);
894 Standard_Boolean IsChange2 = ModifyShape(aSh2, tmpSh2, AddDist2);
896 if( !IsChange1 && !IsChange2 )
899 BRepExtrema_DistShapeShape dst(tmpSh1,tmpSh2);
901 double MinDist = 1.e9;
902 gp_Pnt PMin1, PMin2, P1, P2;
903 for (int i = 1; i <= dst.NbSolution(); i++) {
904 P1 = dst.PointOnShape1(i);
905 P2 = dst.PointOnShape2(i);
906 Standard_Real Dist = P1.Distance(P2);
907 if (MinDist > Dist) {
918 gp_Dir aDir(gp_Vec(PMin1,PMin2));
919 if( MinDist > (AddDist1+AddDist2) ) {
920 Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1,
921 PMin1.Y() + aDir.Y()*AddDist1,
922 PMin1.Z() + aDir.Z()*AddDist1 );
923 Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2,
924 PMin2.Y() - aDir.Y()*AddDist2,
925 PMin2.Z() - aDir.Z()*AddDist2 );
926 return (MinDist - AddDist1 - AddDist2);
930 Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1,
931 PMin1.Y() + aDir.Y()*AddDist1,
932 PMin1.Z() + aDir.Z()*AddDist1 );
936 Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2,
937 PMin2.Y() - aDir.Y()*AddDist2,
938 PMin2.Z() - aDir.Z()*AddDist2 );
943 double res = MinDist - AddDist1 - AddDist2;
944 if(res<0.) res = 0.0;
950 //=======================================================================
951 //function : GetMinDistance
953 //=======================================================================
954 Standard_Real GEOMUtils::GetMinDistance
955 (const TopoDS_Shape& theShape1,
956 const TopoDS_Shape& theShape2,
957 gp_Pnt& thePnt1, gp_Pnt& thePnt2)
959 Standard_Real aResult = 1.e9;
961 // Issue 0020231: A min distance bug with torus and vertex.
962 // Make GetMinDistance() return zero if a sole VERTEX is inside any of SOLIDs
964 // which of shapes consists of only one vertex?
965 TopExp_Explorer exp1(theShape1,TopAbs_VERTEX), exp2(theShape2,TopAbs_VERTEX);
966 TopoDS_Shape V1 = exp1.More() ? exp1.Current() : TopoDS_Shape();
967 TopoDS_Shape V2 = exp2.More() ? exp2.Current() : TopoDS_Shape();
968 exp1.Next(); exp2.Next();
969 if ( exp1.More() ) V1.Nullify();
970 if ( exp2.More() ) V2.Nullify();
971 // vertex and container of solids
972 TopoDS_Shape V = V1.IsNull() ? V2 : V1;
973 TopoDS_Shape S = V1.IsNull() ? theShape1 : theShape2;
975 // classify vertex against solids
976 gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( V ) );
977 for ( exp1.Init( S, TopAbs_SOLID ); exp1.More(); exp1.Next() ) {
978 BRepClass3d_SolidClassifier classifier( exp1.Current(), p, 1e-6);
979 if ( classifier.State() == TopAbs_IN ) {
989 // additional workaround for bugs 19899, 19908 and 19910 from Mantis
990 double dist = GEOMUtils::GetMinDistanceSingular
991 (theShape1, theShape2, thePnt1, thePnt2);
997 BRepExtrema_DistShapeShape dst (theShape1, theShape2);
1001 for (int i = 1; i <= dst.NbSolution(); i++) {
1002 P1 = dst.PointOnShape1(i);
1003 P2 = dst.PointOnShape2(i);
1005 Standard_Real Dist = P1.Distance(P2);
1006 if (aResult > Dist) {
1017 //=======================================================================
1018 // function : ConvertClickToPoint()
1019 // purpose : Returns the point clicked in 3D view
1020 //=======================================================================
1021 gp_Pnt GEOMUtils::ConvertClickToPoint( int x, int y, Handle(V3d_View) aView )
1023 V3d_Coordinate XEye, YEye, ZEye, XAt, YAt, ZAt;
1024 aView->Eye( XEye, YEye, ZEye );
1026 aView->At( XAt, YAt, ZAt );
1027 gp_Pnt EyePoint( XEye, YEye, ZEye );
1028 gp_Pnt AtPoint( XAt, YAt, ZAt );
1030 gp_Vec EyeVector( EyePoint, AtPoint );
1031 gp_Dir EyeDir( EyeVector );
1033 gp_Pln PlaneOfTheView = gp_Pln( AtPoint, EyeDir );
1034 Standard_Real X, Y, Z;
1035 aView->Convert( x, y, X, Y, Z );
1036 gp_Pnt ConvertedPoint( X, Y, Z );
1038 gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project( PlaneOfTheView, ConvertedPoint );
1039 gp_Pnt ResultPoint = ElSLib::Value( ConvertedPointOnPlane.X(), ConvertedPointOnPlane.Y(), PlaneOfTheView );
1043 //=======================================================================
1044 // function : ConvertTreeToString()
1045 // purpose : Returns the string representation of dependency tree
1046 //=======================================================================
1047 void GEOMUtils::ConvertTreeToString( const TreeModel& tree,
1048 std::string& dependencyStr )
1050 TreeModel::const_iterator i;
1051 for ( i = tree.begin(); i != tree.end(); ++i ) {
1052 dependencyStr.append( i->first );
1053 dependencyStr.append( "-" );
1054 std::vector<LevelInfo> upLevelList = i->second.first;
1055 dependencyStr.append( "upward" );
1056 parseWard( upLevelList, dependencyStr );
1057 std::vector<LevelInfo> downLevelList = i->second.second;
1058 dependencyStr.append( "downward" );
1059 parseWard( downLevelList, dependencyStr );
1063 //=======================================================================
1064 // function : ConvertStringToTree()
1065 // purpose : Returns the dependency tree
1066 //=======================================================================
1067 void GEOMUtils::ConvertStringToTree( const std::string& dependencyStr,
1070 std::size_t cursor = 0;
1072 while( dependencyStr.find('-',cursor) != std::string::npos ) //find next selected object
1074 std::size_t objectIndex = dependencyStr.find( '-', cursor );
1075 std::string objectEntry = dependencyStr.substr( cursor, objectIndex - cursor );
1076 cursor = objectIndex;
1078 std::size_t upwardIndexBegin = dependencyStr.find("{",cursor) + 1;
1079 std::size_t upwardIndexFinish = dependencyStr.find("}",upwardIndexBegin);
1080 LevelsList upwardList = parseWard( dependencyStr, cursor );
1082 LevelsList downwardList = parseWard( dependencyStr, cursor );
1084 tree[objectEntry] = std::pair<LevelsList,LevelsList>( upwardList, downwardList );
1088 bool GEOMUtils::CheckShape( TopoDS_Shape& shape,
1089 bool checkGeometry )
1091 BRepCheck_Analyzer analyzer( shape, checkGeometry );
1092 return analyzer.IsValid();
1095 bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
1096 TopAbs_ShapeEnum type,
1097 Standard_Real tolerance,
1098 bool checkGeometry )
1100 ShapeFix_ShapeTolerance aSft;
1101 aSft.LimitTolerance( shape, tolerance, tolerance, type );
1102 Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape( shape );
1104 shape = aSfs->Shape();
1105 return CheckShape( shape, checkGeometry );
1108 bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
1109 Standard_Real tolerance,
1110 bool checkGeometry )
1112 return FixShapeTolerance( shape, TopAbs_SHAPE, tolerance, checkGeometry );
1115 bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
1116 bool checkGeometry )
1118 return FixShapeTolerance( shape, Precision::Confusion(), checkGeometry );
1121 bool GEOMUtils::FixShapeCurves( TopoDS_Shape& shape )
1123 Standard_Real aT, aTolE, aD, aDMax;
1124 TopExp_Explorer aExpF, aExpE;
1125 NCollection_DataMap<TopoDS_Edge, Standard_Real, TopTools_ShapeMapHasher> aDMETol;
1126 aExpF.Init(shape, TopAbs_FACE);
1127 for (; aExpF.More(); aExpF.Next()) {
1128 const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current();
1129 aExpE.Init(aF, TopAbs_EDGE);
1130 for (; aExpE.More(); aExpE.Next()) {
1131 const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current();
1133 if (!BOPTools_AlgoTools::ComputeTolerance(aF, aE, aDMax, aT)) {
1140 aTolE = BRep_Tool::Tolerance(aE);
1141 if (aDMax < aTolE) continue;
1142 if (aDMETol.IsBound(aE)) {
1143 aD = aDMETol.Find(aE);
1146 aDMETol.Bind(aE, aDMax);
1150 aDMETol.Bind(aE, aDMax);
1154 NCollection_DataMap<TopoDS_Edge, Standard_Real, TopTools_ShapeMapHasher>::Iterator aDMETolIt(aDMETol);
1155 #ifdef USE_LIMIT_TOLERANCE
1156 ShapeFix_ShapeTolerance sat;
1160 for (; aDMETolIt.More(); aDMETolIt.Next()) {
1161 #ifdef USE_LIMIT_TOLERANCE
1162 sat.LimitTolerance(aDMETolIt.Key(), aDMETolIt.Value()*1.001);
1164 TopoDS_Iterator itv(aDMETolIt.Key());
1165 for (; itv.More(); itv.Next())
1166 b.UpdateVertex(TopoDS::Vertex(itv.Value()), aDMETolIt.Value()*1.001);
1167 b.UpdateEdge(aDMETolIt.Key(), aDMETolIt.Value()*1.001);
1170 return CheckShape( shape );
1173 bool GEOMUtils::Write( const TopoDS_Shape& shape, const char* fileName )
1175 return BRepTools::Write( shape, fileName );
1178 TopoDS_Shape GEOMUtils::ReduceCompound( const TopoDS_Shape& shape )
1180 TopoDS_Shape result = shape;
1182 if ( shape.ShapeType() == TopAbs_COMPOUND ||
1183 shape.ShapeType() == TopAbs_COMPSOLID ) {
1185 TopTools_ListOfShape l;
1187 TopoDS_Iterator it ( shape );
1188 for ( ; it.More(); it.Next() )
1189 l.Append( it.Value() );
1190 if ( l.Extent() == 1 && l.First() != shape )
1191 result = ReduceCompound( l.First() );