X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGEOMUtils%2FGEOMUtils.cxx;h=c359c25676034168ea8bb651a3c41c5d9db17964;hb=e6bcaa307fef3efd962a0959d0830ccb7dc659fb;hp=292ab5c449580e06ce72498a810d9297b6b909fd;hpb=465e84c52edb243fa36d581abc659b1c97156c64;p=modules%2Fgeom.git diff --git a/src/GEOMUtils/GEOMUtils.cxx b/src/GEOMUtils/GEOMUtils.cxx index 292ab5c44..c359c2567 100644 --- a/src/GEOMUtils/GEOMUtils.cxx +++ b/src/GEOMUtils/GEOMUtils.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -6,7 +6,7 @@ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either -// version 2.1 of the License. +// version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,6 +18,7 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include @@ -25,21 +26,31 @@ #include -#include #include #include // OCCT Includes #include +#include + #include #include #include #include #include +#include + +#include +#include + +#include + #include +#include + #include #include #include @@ -53,9 +64,14 @@ #include #include #include +#include +#include #include #include +#include +#include +#include #include #include @@ -63,17 +79,262 @@ #include #include +#include + #include #include +#include +#include +#include + +#include +#include + #include +#include +#include #include #include #include // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC +#define MAX2(X, Y) (Abs(X) > Abs(Y) ? Abs(X) : Abs(Y)) +#define MAX3(X, Y, Z) (MAX2(MAX2(X,Y), Z)) + #define STD_SORT_ALGO 1 +#define DEFAULT_TOLERANCE_TOLERANCE 1.e-02 +#define DEFAULT_MAX_TOLERANCE_TOLERANCE 1.e-06 + +// When the following macro is defined, ShapeFix_ShapeTolerance function is used to set max tolerance of curve +// in GEOMUtils::FixShapeCurves function; otherwise less restrictive BRep_Builder::UpdateEdge/UpdateVertex +// approach is used +// VSR (29/12/2014): macro disabled +//#define USE_LIMIT_TOLERANCE + +namespace +{ + /** + * This function constructs and returns modified shape from the original one + * for singular cases. It is used for the method GetMinDistanceSingular. + * + * \param theShape the original shape + * \param theModifiedShape output parameter. The modified shape. + * \param theAddDist output parameter. The added distance for modified shape. + * \retval true if the shape is modified; false otherwise. + * + * \internal + */ + Standard_Boolean ModifyShape(const TopoDS_Shape &theShape, + TopoDS_Shape &theModifiedShape, + Standard_Real &theAddDist) + { + TopExp_Explorer anExp; + int nbf = 0; + + theAddDist = 0.; + theModifiedShape.Nullify(); + + for ( anExp.Init( theShape, TopAbs_FACE ); anExp.More(); anExp.Next() ) { + nbf++; + theModifiedShape = anExp.Current(); + } + if(nbf==1) { + TopoDS_Shape sh = theShape; + while(sh.ShapeType()==TopAbs_COMPOUND) { + TopoDS_Iterator it(sh); + sh = it.Value(); + } + Handle(Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(theModifiedShape)); + if( S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) || + S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) || + S->IsUPeriodic()) { + const Standard_Boolean isShell = + (sh.ShapeType()==TopAbs_SHELL || sh.ShapeType()==TopAbs_FACE); + + if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) { + Handle(Geom_SphericalSurface) SS = Handle(Geom_SphericalSurface)::DownCast(S); + gp_Pnt PC = SS->Location(); + BRep_Builder B; + TopoDS_Vertex V; + B.MakeVertex(V,PC,1.e-7); + theModifiedShape = V; + theAddDist = SS->Radius(); + return Standard_True; + } + if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) ) { + Handle(Geom_ToroidalSurface) TS = Handle(Geom_ToroidalSurface)::DownCast(S); + gp_Ax3 ax3 = TS->Position(); + Handle(Geom_Circle) C = new Geom_Circle(ax3.Ax2(),TS->MajorRadius()); + BRep_Builder B; + TopoDS_Edge E; + B.MakeEdge(E,C,1.e-7); + theModifiedShape = E; + theAddDist = TS->MinorRadius(); + return Standard_True; + } + + // non solid case or any periodic surface (Mantis 22454). + double U1,U2,V1,V2; + // changes for 0020677: EDF 1219 GEOM: MinDistance gives 0 instead of 20.88 + //S->Bounds(U1,U2,V1,V2); changed by + ShapeAnalysis::GetFaceUVBounds(TopoDS::Face(theModifiedShape),U1,U2,V1,V2); + // end of changes for 020677 (dmv) + Handle(Geom_RectangularTrimmedSurface) TrS1 = + new Geom_RectangularTrimmedSurface(S,U1,(U1+U2)/2.,V1,V2); + Handle(Geom_RectangularTrimmedSurface) TrS2 = + new Geom_RectangularTrimmedSurface(S,(U1+U2)/2.,U2,V1,V2); + TopoDS_Shape aMShape; + + TopoDS_Face F1 = BRepBuilderAPI_MakeFace(TrS1, Precision::Confusion()); + TopoDS_Face F2 = BRepBuilderAPI_MakeFace(TrS2, Precision::Confusion()); + + if (isShell) { + BRep_Builder B; + B.MakeCompound(TopoDS::Compound(aMShape)); + B.Add(aMShape, F1); + B.Add(aMShape, F2); + } else { + // The original shape is a solid. + BRepBuilderAPI_Sewing aSewing (Precision::Confusion()*10.0); + aSewing.Add(F1); + aSewing.Add(F2); + aSewing.Perform(); + aMShape = aSewing.SewedShape(); + BRep_Builder B; + TopoDS_Solid aSolid; + B.MakeSolid(aSolid); + B.Add(aSolid, aMShape); + aMShape = aSolid; + } + + Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape; + sfs->Init(aMShape); + sfs->SetPrecision(1.e-6); + sfs->SetMaxTolerance(1.0); + sfs->Perform(); + theModifiedShape = sfs->Shape(); + return Standard_True; + } + } + + theModifiedShape = theShape; + return Standard_False; + } + + void parseWard( const GEOMUtils::LevelsList &theLevelList, std::string &treeStr ) + { + treeStr.append( "{" ); + for( GEOMUtils::LevelsList::const_iterator j = theLevelList.begin(); + j != theLevelList.end(); ++j ) { + if ( j != theLevelList.begin() ) { + treeStr.append( ";" ); + } + GEOMUtils::LevelInfo level = (*j); + GEOMUtils::LevelInfo::iterator upIter; + for ( upIter = level.begin(); upIter != level.end(); ++upIter ) { + if ( upIter != level.begin() ) { + treeStr.append( "," ); + } + treeStr.append( upIter->first ); + for ( std::vector::iterator k = upIter->second.begin(); k != upIter->second.end(); ++k ) { + treeStr.append( "_" ); + treeStr.append( *k ); + } + } + } + treeStr.append( "}" ); + } + + GEOMUtils::LevelsList parseWard( const std::string& theData, std::size_t& theCursor ) + { + std::size_t indexStart = theData.find( "{", theCursor ) + 1; + std::size_t indexEnd = theData.find( "}", indexStart ); + + std::string ward = theData.substr( indexStart, indexEnd - indexStart ); + std::stringstream ss(ward); + std::string substr; + std::vector levelsListStr; + while ( std::getline( ss, substr, ';' ) ) { + if ( !substr.empty() ) + levelsListStr.push_back( substr ); + } + GEOMUtils::LevelsList levelsListData; + for( int level = 0; level < levelsListStr.size(); level++ ) { + std::vector namesListStr; + std::stringstream ss1( levelsListStr[level] ); + while ( std::getline( ss1, substr, ',' ) ) { + if ( !substr.empty() ) + namesListStr.push_back( substr ); + } + GEOMUtils::LevelInfo levelInfoData; + for( int node = 0; node < namesListStr.size(); node++ ) { + std::vector linksListStr; + std::stringstream ss2( namesListStr[node] ); + while ( std::getline( ss2, substr, '_' ) ) { + if ( !substr.empty() ) + linksListStr.push_back( substr ); + } + std::string nodeItem = linksListStr[0]; + if( !nodeItem.empty() ) { + GEOMUtils::NodeLinks linksListData; + for( int link = 1; link < linksListStr.size(); link++ ) { + std::string linkItem = linksListStr[link]; + linksListData.push_back( linkItem ); + }// Links + levelInfoData[nodeItem] = linksListData; + } + }// Level's objects + levelsListData.push_back(levelInfoData); + }// Levels + + theCursor = indexEnd + 1; + return levelsListData; + } + +} + +//======================================================================= +//function : ShapeToDouble +//purpose : used by CompareShapes::operator() +//======================================================================= +std::pair GEOMUtils::ShapeToDouble (const TopoDS_Shape& S, bool isOldSorting) +{ + // Computing of CentreOfMass + gp_Pnt GPoint; + double Len; + + if (S.ShapeType() == TopAbs_VERTEX) { + GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S)); + Len = (double)S.Orientation(); + } + else { + GProp_GProps GPr; + // BEGIN: fix for Mantis issue 0020842 + if (isOldSorting) { + BRepGProp::LinearProperties(S, GPr); + } + else { + if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) { + BRepGProp::LinearProperties(S, GPr); + } + else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) { + BRepGProp::SurfaceProperties(S, GPr); + } + else { + BRepGProp::VolumeProperties(S, GPr); + } + } + // END: fix for Mantis issue 0020842 + GPoint = GPr.CentreOfMass(); + Len = GPr.Mass(); + } + + double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9; + return std::make_pair(dMidXYZ, Len); +} + //======================================================================= //function : GetPosition //purpose : @@ -138,7 +399,8 @@ gp_Ax3 GEOMUtils::GetPosition (const TopoDS_Shape& theShape) //function : GetVector //purpose : //======================================================================= -gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape) +gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape, + Standard_Boolean doConsiderOrientation) { if (theShape.IsNull()) Standard_NullObject::Raise("Null shape is given for a vector"); @@ -149,7 +411,7 @@ gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape) TopoDS_Edge anE = TopoDS::Edge(theShape); TopoDS_Vertex V1, V2; - TopExp::Vertices(anE, V1, V2, Standard_True); + TopExp::Vertices(anE, V1, V2, doConsiderOrientation); if (V1.IsNull() || V2.IsNull()) Standard_NullObject::Raise("Invalid edge is given, it must have two points"); @@ -162,46 +424,6 @@ gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape) return aV; } -//======================================================================= -//function : ShapeToDouble -//purpose : used by CompareShapes::operator() -//======================================================================= -std::pair ShapeToDouble (const TopoDS_Shape& S, bool isOldSorting) -{ - // Computing of CentreOfMass - gp_Pnt GPoint; - double Len; - - if (S.ShapeType() == TopAbs_VERTEX) { - GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S)); - Len = (double)S.Orientation(); - } - else { - GProp_GProps GPr; - // BEGIN: fix for Mantis issue 0020842 - if (isOldSorting) { - BRepGProp::LinearProperties(S, GPr); - } - else { - if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) { - BRepGProp::LinearProperties(S, GPr); - } - else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) { - BRepGProp::SurfaceProperties(S, GPr); - } - else { - BRepGProp::VolumeProperties(S, GPr); - } - } - // END: fix for Mantis issue 0020842 - GPoint = GPr.CentreOfMass(); - Len = GPr.Mass(); - } - - double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9; - return std::make_pair(dMidXYZ, Len); -} - //======================================================================= //function : CompareShapes::operator() //purpose : used by std::sort(), called from SortShapes() @@ -427,6 +649,34 @@ TopoDS_Shape GEOMUtils::CompsolidToCompound (const TopoDS_Shape& theCompsolid) return aCompound; } +//======================================================================= +//function : AddSimpleShapes +//purpose : +//======================================================================= +void GEOMUtils::AddSimpleShapes (const TopoDS_Shape& theShape, TopTools_ListOfShape& theList) +{ + if (theShape.ShapeType() != TopAbs_COMPOUND && + theShape.ShapeType() != TopAbs_COMPSOLID) { + theList.Append(theShape); + return; + } + + TopTools_MapOfShape mapShape; + TopoDS_Iterator It (theShape, Standard_True, Standard_True); + + for (; It.More(); It.Next()) { + TopoDS_Shape aShape_i = It.Value(); + if (mapShape.Add(aShape_i)) { + if (aShape_i.ShapeType() == TopAbs_COMPOUND || + aShape_i.ShapeType() == TopAbs_COMPSOLID) { + AddSimpleShapes(aShape_i, theList); + } else { + theList.Append(aShape_i); + } + } + } +} + //======================================================================= //function : CheckTriangulation //purpose : @@ -497,3 +747,598 @@ TopAbs_ShapeEnum GEOMUtils::GetTypeOfSimplePart (const TopoDS_Shape& theShape) } return TopAbs_SHAPE; } + +//======================================================================= +//function : GetEdgeNearPoint +//purpose : +//======================================================================= +TopoDS_Shape GEOMUtils::GetEdgeNearPoint (const TopoDS_Shape& theShape, + const TopoDS_Vertex& thePoint) +{ + TopoDS_Shape aResult; + + // 1. Explode the shape on edges + TopTools_MapOfShape mapShape; + Standard_Integer nbEdges = 0; + TopExp_Explorer exp (theShape, TopAbs_EDGE); + for (; exp.More(); exp.Next()) { + if (mapShape.Add(exp.Current())) { + nbEdges++; + } + } + + if (nbEdges == 0) + Standard_NullObject::Raise("Given shape contains no edges"); + + mapShape.Clear(); + Standard_Integer ind = 1; + TopTools_Array1OfShape anEdges (1, nbEdges); + TColStd_Array1OfReal aDistances (1, nbEdges); + for (exp.Init(theShape, TopAbs_EDGE); exp.More(); exp.Next()) { + if (mapShape.Add(exp.Current())) { + TopoDS_Shape anEdge = exp.Current(); + anEdges(ind) = anEdge; + + // 2. Classify the point relatively each edge + BRepExtrema_DistShapeShape aDistTool (thePoint, anEdges(ind)); + if (!aDistTool.IsDone()) + Standard_ConstructionError::Raise("Cannot find a distance from the given point to one of edges"); + + aDistances(ind) = aDistTool.Value(); + ind++; + } + } + + // 3. Define edge, having minimum distance to the point + Standard_Real nearest = RealLast(), nbFound = 0; + Standard_Real prec = Precision::Confusion(); + for (ind = 1; ind <= nbEdges; ind++) { + if (Abs(aDistances(ind) - nearest) < prec) { + nbFound++; + } + else if (aDistances(ind) < nearest) { + nearest = aDistances(ind); + aResult = anEdges(ind); + nbFound = 1; + } + else { + } + } + if (nbFound > 1) { + Standard_ConstructionError::Raise("Multiple edges near the given point are found"); + } + else if (nbFound == 0) { + Standard_ConstructionError::Raise("There are no edges near the given point"); + } + else { + } + + return aResult; +} + +//======================================================================= +//function : PreciseBoundingBox +//purpose : +//======================================================================= +Standard_Boolean GEOMUtils::PreciseBoundingBox + (const TopoDS_Shape &theShape, Bnd_Box &theBox) +{ + if ( theBox.IsVoid() ) BRepBndLib::Add( theShape, theBox ); + if ( theBox.IsVoid() ) return Standard_False; + + Standard_Real aBound[6]; + theBox.Get(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]); + + Standard_Integer i; + const gp_Pnt aMid(0.5*(aBound[1] + aBound[0]), // XMid + 0.5*(aBound[3] + aBound[2]), // YMid + 0.5*(aBound[5] + aBound[4])); // ZMid + const gp_XYZ aSize(aBound[1] - aBound[0], // DX + aBound[3] - aBound[2], // DY + aBound[5] - aBound[4]); // DZ + const gp_Pnt aPnt[6] = + { + gp_Pnt(aBound[0] - (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMin + gp_Pnt(aBound[1] + (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMax + gp_Pnt(aMid.X(), aBound[2] - (aBound[3] - aBound[2]), aMid.Z()), // YMin + gp_Pnt(aMid.X(), aBound[3] + (aBound[3] - aBound[2]), aMid.Z()), // YMax + gp_Pnt(aMid.X(), aMid.Y(), aBound[4] - (aBound[5] - aBound[4])), // ZMin + gp_Pnt(aMid.X(), aMid.Y(), aBound[5] + (aBound[5] - aBound[4])) // ZMax + }; + const gp_Dir aDir[3] = { gp::DX(), gp::DY(), gp::DZ() }; + const Standard_Real aPlnSize[3] = + { + 0.5*Max(aSize.Y(), aSize.Z()), // XMin, XMax planes + 0.5*Max(aSize.X(), aSize.Z()), // YMin, YMax planes + 0.5*Max(aSize.X(), aSize.Y()) // ZMin, ZMax planes + }; + gp_Pnt aPMin[2]; + + for (i = 0; i < 6; i++) { + const Standard_Integer iHalf = i/2; + const gp_Pln aPln(aPnt[i], aDir[iHalf]); + BRepBuilderAPI_MakeFace aMkFace(aPln, -aPlnSize[iHalf], aPlnSize[iHalf], + -aPlnSize[iHalf], aPlnSize[iHalf]); + + if (!aMkFace.IsDone()) { + return Standard_False; + } + + TopoDS_Shape aFace = aMkFace.Shape(); + + // Get minimal distance between planar face and shape. + Standard_Real aMinDist = + GEOMUtils::GetMinDistance(aFace, theShape, aPMin[0], aPMin[1]); + + if (aMinDist < 0.) { + return Standard_False; + } + + aBound[i] = aPMin[1].Coord(iHalf + 1); + } + + // Update Bounding box with the new values. + theBox.SetVoid(); + theBox.Update(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]); + + return Standard_True; +} + +//======================================================================= +//function : GetMinDistanceSingular +//purpose : +//======================================================================= +double GEOMUtils::GetMinDistanceSingular(const TopoDS_Shape& aSh1, + const TopoDS_Shape& aSh2, + gp_Pnt& Ptmp1, gp_Pnt& Ptmp2) +{ + TopoDS_Shape tmpSh1; + TopoDS_Shape tmpSh2; + Standard_Real AddDist1 = 0.; + Standard_Real AddDist2 = 0.; + Standard_Boolean IsChange1 = ModifyShape(aSh1, tmpSh1, AddDist1); + Standard_Boolean IsChange2 = ModifyShape(aSh2, tmpSh2, AddDist2); + + if( !IsChange1 && !IsChange2 ) + return -2.0; + + BRepExtrema_DistShapeShape dst(tmpSh1,tmpSh2); + if (dst.IsDone()) { + double MinDist = 1.e9; + gp_Pnt PMin1, PMin2, P1, P2; + for (int i = 1; i <= dst.NbSolution(); i++) { + P1 = dst.PointOnShape1(i); + P2 = dst.PointOnShape2(i); + Standard_Real Dist = P1.Distance(P2); + if (MinDist > Dist) { + MinDist = Dist; + PMin1 = P1; + PMin2 = P2; + } + } + if(MinDist<1.e-7) { + Ptmp1 = PMin1; + Ptmp2 = PMin2; + } + else { + gp_Dir aDir(gp_Vec(PMin1,PMin2)); + if( MinDist > (AddDist1+AddDist2) ) { + Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1, + PMin1.Y() + aDir.Y()*AddDist1, + PMin1.Z() + aDir.Z()*AddDist1 ); + Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2, + PMin2.Y() - aDir.Y()*AddDist2, + PMin2.Z() - aDir.Z()*AddDist2 ); + return (MinDist - AddDist1 - AddDist2); + } + else { + if( AddDist1 > 0 ) { + Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1, + PMin1.Y() + aDir.Y()*AddDist1, + PMin1.Z() + aDir.Z()*AddDist1 ); + Ptmp2 = Ptmp1; + } + else { + Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2, + PMin2.Y() - aDir.Y()*AddDist2, + PMin2.Z() - aDir.Z()*AddDist2 ); + Ptmp1 = Ptmp2; + } + } + } + double res = MinDist - AddDist1 - AddDist2; + if(res<0.) res = 0.0; + return res; + } + return -2.0; +} + +//======================================================================= +//function : GetMinDistance +//purpose : +//======================================================================= +Standard_Real GEOMUtils::GetMinDistance + (const TopoDS_Shape& theShape1, + const TopoDS_Shape& theShape2, + gp_Pnt& thePnt1, gp_Pnt& thePnt2) +{ + Standard_Real aResult = 1.e9; + + // Issue 0020231: A min distance bug with torus and vertex. + // Make GetMinDistance() return zero if a sole VERTEX is inside any of SOLIDs + + // which of shapes consists of only one vertex? + TopExp_Explorer exp1(theShape1,TopAbs_VERTEX), exp2(theShape2,TopAbs_VERTEX); + TopoDS_Shape V1 = exp1.More() ? exp1.Current() : TopoDS_Shape(); + TopoDS_Shape V2 = exp2.More() ? exp2.Current() : TopoDS_Shape(); + exp1.Next(); exp2.Next(); + if ( exp1.More() ) V1.Nullify(); + if ( exp2.More() ) V2.Nullify(); + // vertex and container of solids + TopoDS_Shape V = V1.IsNull() ? V2 : V1; + TopoDS_Shape S = V1.IsNull() ? theShape1 : theShape2; + if ( !V.IsNull() ) { + // classify vertex against solids + gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( V ) ); + for ( exp1.Init( S, TopAbs_SOLID ); exp1.More(); exp1.Next() ) { + BRepClass3d_SolidClassifier classifier( exp1.Current(), p, 1e-6); + if ( classifier.State() == TopAbs_IN ) { + thePnt1 = p; + thePnt2 = p; + return 0.0; + } + } + } + // End Issue 0020231 + + // skl 30.06.2008 + // additional workaround for bugs 19899, 19908 and 19910 from Mantis + double dist = GEOMUtils::GetMinDistanceSingular + (theShape1, theShape2, thePnt1, thePnt2); + + if (dist > -1.0) { + return dist; + } + + BRepExtrema_DistShapeShape dst (theShape1, theShape2); + if (dst.IsDone()) { + gp_Pnt P1, P2; + + for (int i = 1; i <= dst.NbSolution(); i++) { + P1 = dst.PointOnShape1(i); + P2 = dst.PointOnShape2(i); + + Standard_Real Dist = P1.Distance(P2); + if (aResult > Dist) { + aResult = Dist; + thePnt1 = P1; + thePnt2 = P2; + } + } + } + + return aResult; +} + +//======================================================================= +// function : ConvertClickToPoint() +// purpose : Returns the point clicked in 3D view +//======================================================================= +gp_Pnt GEOMUtils::ConvertClickToPoint( int x, int y, Handle(V3d_View) aView ) +{ + V3d_Coordinate XEye, YEye, ZEye, XAt, YAt, ZAt; + aView->Eye( XEye, YEye, ZEye ); + + aView->At( XAt, YAt, ZAt ); + gp_Pnt EyePoint( XEye, YEye, ZEye ); + gp_Pnt AtPoint( XAt, YAt, ZAt ); + + gp_Vec EyeVector( EyePoint, AtPoint ); + gp_Dir EyeDir( EyeVector ); + + gp_Pln PlaneOfTheView = gp_Pln( AtPoint, EyeDir ); + Standard_Real X, Y, Z; + aView->Convert( x, y, X, Y, Z ); + gp_Pnt ConvertedPoint( X, Y, Z ); + + gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project( PlaneOfTheView, ConvertedPoint ); + gp_Pnt ResultPoint = ElSLib::Value( ConvertedPointOnPlane.X(), ConvertedPointOnPlane.Y(), PlaneOfTheView ); + return ResultPoint; +} + +//======================================================================= +// function : ConvertTreeToString() +// purpose : Returns the string representation of dependency tree +//======================================================================= +void GEOMUtils::ConvertTreeToString( const TreeModel& tree, + std::string& dependencyStr ) +{ + TreeModel::const_iterator i; + for ( i = tree.begin(); i != tree.end(); ++i ) { + dependencyStr.append( i->first ); + dependencyStr.append( "-" ); + std::vector upLevelList = i->second.first; + dependencyStr.append( "upward" ); + parseWard( upLevelList, dependencyStr ); + std::vector downLevelList = i->second.second; + dependencyStr.append( "downward" ); + parseWard( downLevelList, dependencyStr ); + } +} + +//======================================================================= +// function : ConvertStringToTree() +// purpose : Returns the dependency tree +//======================================================================= +void GEOMUtils::ConvertStringToTree( const std::string& dependencyStr, + TreeModel& tree ) +{ + std::size_t cursor = 0; + + while( dependencyStr.find('-',cursor) != std::string::npos ) //find next selected object + { + std::size_t objectIndex = dependencyStr.find( '-', cursor ); + std::string objectEntry = dependencyStr.substr( cursor, objectIndex - cursor ); + cursor = objectIndex; + + std::size_t upwardIndexBegin = dependencyStr.find("{",cursor) + 1; + std::size_t upwardIndexFinish = dependencyStr.find("}",upwardIndexBegin); + LevelsList upwardList = parseWard( dependencyStr, cursor ); + + LevelsList downwardList = parseWard( dependencyStr, cursor ); + + tree[objectEntry] = std::pair( upwardList, downwardList ); + } +} + +bool GEOMUtils::CheckShape( TopoDS_Shape& shape, + bool checkGeometry ) +{ + BRepCheck_Analyzer analyzer( shape, checkGeometry ); + return analyzer.IsValid(); +} + +bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape, + TopAbs_ShapeEnum type, + Standard_Real tolerance, + bool checkGeometry ) +{ + ShapeFix_ShapeTolerance aSft; + aSft.LimitTolerance( shape, tolerance, tolerance, type ); + Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape( shape ); + aSfs->Perform(); + shape = aSfs->Shape(); + return CheckShape( shape, checkGeometry ); +} + +bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape, + Standard_Real tolerance, + bool checkGeometry ) +{ + return FixShapeTolerance( shape, TopAbs_SHAPE, tolerance, checkGeometry ); +} + +bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape, + bool checkGeometry ) +{ + return FixShapeTolerance( shape, Precision::Confusion(), checkGeometry ); +} + +bool GEOMUtils::FixShapeCurves( TopoDS_Shape& shape ) +{ + Standard_Real aT, aTolE, aD, aDMax; + TopExp_Explorer aExpF, aExpE; + NCollection_DataMap aDMETol; + aExpF.Init(shape, TopAbs_FACE); + for (; aExpF.More(); aExpF.Next()) { + const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current(); + aExpE.Init(aF, TopAbs_EDGE); + for (; aExpE.More(); aExpE.Next()) { + const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current(); + try { + if (!BOPTools_AlgoTools::ComputeTolerance(aF, aE, aDMax, aT)) { + continue; + } + } + catch(...) { + continue; + } + aTolE = BRep_Tool::Tolerance(aE); + if (aDMax < aTolE) continue; + if (aDMETol.IsBound(aE)) { + aD = aDMETol.Find(aE); + if (aDMax > aD) { + aDMETol.UnBind(aE); + aDMETol.Bind(aE, aDMax); + } + } + else { + aDMETol.Bind(aE, aDMax); + } + } + } + NCollection_DataMap::Iterator aDMETolIt(aDMETol); +#ifdef USE_LIMIT_TOLERANCE + ShapeFix_ShapeTolerance sat; +#else + BRep_Builder b; +#endif + for (; aDMETolIt.More(); aDMETolIt.Next()) { +#ifdef USE_LIMIT_TOLERANCE + sat.LimitTolerance(aDMETolIt.Key(), aDMETolIt.Value()*1.001); +#else + TopoDS_Iterator itv(aDMETolIt.Key()); + for (; itv.More(); itv.Next()) + b.UpdateVertex(TopoDS::Vertex(itv.Value()), aDMETolIt.Value()*1.001); + b.UpdateEdge(aDMETolIt.Key(), aDMETolIt.Value()*1.001); +#endif + } + return CheckShape( shape ); +} + +bool GEOMUtils::Write( const TopoDS_Shape& shape, const char* fileName ) +{ + return BRepTools::Write( shape, fileName ); +} + +TopoDS_Shape GEOMUtils::ReduceCompound( const TopoDS_Shape& shape ) +{ + TopoDS_Shape result = shape; + + if ( shape.ShapeType() == TopAbs_COMPOUND || + shape.ShapeType() == TopAbs_COMPSOLID ) { + + TopTools_ListOfShape l; + + TopoDS_Iterator it ( shape ); + for ( ; it.More(); it.Next() ) + l.Append( it.Value() ); + if ( l.Extent() == 1 && l.First() != shape ) + result = ReduceCompound( l.First() ); + } + + return result; +} + +void GEOMUtils::MeshShape( const TopoDS_Shape shape, + double deflection, bool theForced ) +{ + Standard_Real aDeflection = ( deflection <= 0 ) ? DefaultDeflection() : deflection; + + // Is shape triangulated? + Standard_Boolean alreadyMeshed = true; + TopExp_Explorer ex; + TopLoc_Location aLoc; + for ( ex.Init( shape, TopAbs_FACE ); ex.More() && alreadyMeshed; ex.Next() ) { + const TopoDS_Face& aFace = TopoDS::Face( ex.Current() ); + Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation( aFace, aLoc ); + alreadyMeshed = !aPoly.IsNull(); + } + + if ( !alreadyMeshed || theForced ) { + // Compute bounding box + Bnd_Box B; + BRepBndLib::Add( shape, B ); + if ( B.IsVoid() ) + return; // NPAL15983 (Bug when displaying empty groups) + Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; + B.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax ); + + // This magic line comes from Prs3d_ShadedShape.gxx in OCCT + aDeflection = MAX3(aXmax-aXmin, aYmax-aYmin, aZmax-aZmin) * aDeflection * 4; + + // Clean triangulation before compute incremental mesh + BRepTools::Clean( shape ); + + // Compute triangulation + BRepMesh_IncrementalMesh mesh( shape, aDeflection ); + } +} + +double GEOMUtils::DefaultDeflection() +{ + return 0.001; +} + +//======================================================================= +//function : IsOpenPath +//purpose : +//======================================================================= +bool GEOMUtils::IsOpenPath(const TopoDS_Shape &theShape) +{ + bool isOpen = true; + + if (theShape.IsNull() == Standard_False) { + if (theShape.Closed()) { + // The shape is closed + isOpen = false; + } else { + const TopAbs_ShapeEnum aType = theShape.ShapeType(); + + if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) { + // Check if path ends are coinsident. + TopoDS_Vertex aV[2]; + + if (aType == TopAbs_EDGE) { + // Edge + TopExp::Vertices(TopoDS::Edge(theShape), aV[0], aV[1]); + } else { + // Wire + TopExp::Vertices(TopoDS::Wire(theShape), aV[0], aV[1]); + } + + if (aV[0].IsNull() == Standard_False && + aV[1].IsNull() == Standard_False) { + if (aV[0].IsSame(aV[1])) { + // The shape is closed + isOpen = false; + } else { + const Standard_Real aTol1 = BRep_Tool::Tolerance(aV[0]); + const Standard_Real aTol2 = BRep_Tool::Tolerance(aV[1]); + const gp_Pnt aPnt1 = BRep_Tool::Pnt(aV[0]); + const gp_Pnt aPnt2 = BRep_Tool::Pnt(aV[1]); + + if (aPnt1.Distance(aPnt2) <= aTol1 + aTol2) { + // The shape is closed + isOpen = false; + } + } + } + } + } + } + + return isOpen; +} + +//======================================================================= +//function : CompareToleranceValues +//purpose : +//======================================================================= +int GEOMUtils::CompareToleranceValues(const double theTolShape, + const double theTolRef) +{ + const double aTolTol = Min(DEFAULT_MAX_TOLERANCE_TOLERANCE, + theTolRef*DEFAULT_TOLERANCE_TOLERANCE); + + int aResult = 0; + + if (theTolShape < theTolRef - aTolTol) { + aResult = -1; + } else if (theTolShape > theTolRef + aTolTol) { + aResult = 1; + } + + return aResult; +} + +//======================================================================= +//function : IsFitCondition +//purpose : +//======================================================================= +bool GEOMUtils::IsFitCondition(const ComparisonCondition theCondition, + const double theTolShape, + const double theTolRef) +{ + const int aCompValue = CompareToleranceValues(theTolShape, theTolRef); + bool isFit = false; + + switch (theCondition) { + case CC_GT: + isFit = aCompValue == 1; + break; + case GEOMUtils::CC_GE: + isFit = aCompValue != -1; + break; + case GEOMUtils::CC_LT: + isFit = aCompValue == -1; + break; + case GEOMUtils::CC_LE: + isFit = aCompValue != 1; + break; + default: + break; + } + + return isFit; +}