diff --git a/src/BRepClass3d/BRepClass3d_BndBoxTree.cxx b/src/BRepClass3d/BRepClass3d_BndBoxTree.cxx new file mode 100644 index 0000000000..a57322571e --- /dev/null +++ b/src/BRepClass3d/BRepClass3d_BndBoxTree.cxx @@ -0,0 +1,139 @@ +// Copyright (c) 1994-1999 Matra Datavision +// Copyright (c) 1999-2016 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include + + +//======================================================================= +//function : Accept +//purpose : +//======================================================================= +Standard_Boolean BRepClass3d_BndBoxTreeSelectorPoint::Accept (const Standard_Integer& theObj) +{ + // Box-point collision. + if (theObj > myMapOfShape.Extent()) + return Standard_False; + const TopoDS_Shape& shp = myMapOfShape(theObj); + TopAbs_ShapeEnum sht = shp.ShapeType(); + if (sht == TopAbs_EDGE) + { + const TopoDS_Edge& E = TopoDS::Edge(shp); + Standard_Real EdgeTSq = BRep_Tool::Tolerance(E); + EdgeTSq *= EdgeTSq; + Standard_Real f, l; + BRepAdaptor_Curve C(E); + BRep_Tool::Range(E,f,l); + + // Edge-Point interference. + Extrema_ExtPC ExtPC(myP, C, f, l ); + if (ExtPC.IsDone() && ExtPC.NbExt() > 0) + { + for (Standard_Integer i = 1; i <= ExtPC.NbExt(); i++) + if (ExtPC.SquareDistance(i) < EdgeTSq) + { + myStop = 1; //exit from selector + return Standard_True; + } + } + } + else if (sht == TopAbs_VERTEX) + { + const TopoDS_Vertex &V = TopoDS::Vertex(shp); + gp_Pnt VPnt = BRep_Tool::Pnt(V); + Standard_Real VertTSq = BRep_Tool::Tolerance(V); + VertTSq *= VertTSq; + // Vertex-Point interference. + if (VPnt.SquareDistance(myP) < VertTSq) + { + myStop = 1; + return Standard_True; + } + } + return Standard_False; +} + +//======================================================================= +//function : Accept +//purpose : +//======================================================================= +Standard_Boolean BRepClass3d_BndBoxTreeSelectorLine::Accept (const Standard_Integer& theObj) +{ + //box-line collision + if (theObj > myMapOfShape.Extent()) + return Standard_False; + const TopoDS_Shape& shp = myMapOfShape(theObj); + TopAbs_ShapeEnum sht = shp.ShapeType(); + if (sht == TopAbs_EDGE) + { + const TopoDS_Edge& E = TopoDS::Edge(shp); + Standard_Real EdgeTSq = BRep_Tool::Tolerance(E); + EdgeTSq *= EdgeTSq; + Standard_Real f, l; + BRepAdaptor_Curve C(E); + BRep_Tool::Range(E,f,l); + + // Edge-Line interference. + Extrema_ExtCC ExtCC(C, myLC, f, l, myLC.FirstParameter(), myLC.LastParameter()); + if (ExtCC.IsDone() && ExtCC.NbExt() > 0) + { + Standard_Boolean IsInside = Standard_False; + for (Standard_Integer i = 1; i <= ExtCC.NbExt(); i++) + { + if (ExtCC.SquareDistance(i) < EdgeTSq) + { + Extrema_POnCurv P1, P2; + ExtCC.Points(i,P1, P2); + + EdgeParam EP; + EP.myE = E; + EP.myParam = P1.Parameter(); // Original curve is the first parameter. + EP.myLParam = P2.Parameter(); // Linear curve is the second parameter. + + myEP.Append(EP); + IsInside = Standard_True; + } + } + if (IsInside) + return Standard_True; + } + } + else if (sht == TopAbs_VERTEX) + { + const TopoDS_Vertex &V = TopoDS::Vertex(shp); + Standard_Real VertTSq = BRep_Tool::Tolerance(V); + VertTSq *= VertTSq; + // Vertex-Line interference. + Extrema_ExtPElC ExtPL(BRep_Tool::Pnt(V), myL, Precision::Confusion(), -Precision::Infinite(), Precision::Infinite()); + if (ExtPL.IsDone() && ExtPL.NbExt() > 0) + if (ExtPL.SquareDistance(1) < VertTSq) + { + Extrema_POnCurv PP; + Standard_Real paramL; + PP = ExtPL.Point(1); + paramL = PP.Parameter(); + VertParam VP; + VP.myV = V; + VP.myLParam = paramL; + myVP.Append(VP); + return Standard_True; + } + } + return Standard_False; +} \ No newline at end of file diff --git a/src/BRepClass3d/BRepClass3d_BndBoxTree.hxx b/src/BRepClass3d/BRepClass3d_BndBoxTree.hxx new file mode 100644 index 0000000000..8f6174d36e --- /dev/null +++ b/src/BRepClass3d/BRepClass3d_BndBoxTree.hxx @@ -0,0 +1,152 @@ +// Copyright (c) 1994-1999 Matra Datavision +// Copyright (c) 1999-2016 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _BRepClass3d_BndBoxTree_HeaderFile +#define _BRepClass3d_BndBoxTree_HeaderFile + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Typedef to reduce code complexity. +typedef NCollection_UBTree BRepClass3d_BndBoxTree; + +// Class representing tree selector for point object. +class BRepClass3d_BndBoxTreeSelectorPoint : public BRepClass3d_BndBoxTree::Selector +{ +public: + BRepClass3d_BndBoxTreeSelectorPoint(const TopTools_IndexedMapOfShape& theMapOfShape) + : BRepClass3d_BndBoxTreeSelectorPoint::Selector(), myMapOfShape (theMapOfShape) + {} + + Standard_Boolean Reject (const Bnd_Box& theBox) const + { + return (theBox.IsOut (myP)); + } + + Standard_Boolean Accept (const Standard_Integer& theObj); + + // Sets current point for boxes-point collisions. + void SetCurrentPoint (const gp_Pnt& theP) + { + myP = theP; + } + +private: + BRepClass3d_BndBoxTreeSelectorPoint(const BRepClass3d_BndBoxTreeSelectorPoint& ); + BRepClass3d_BndBoxTreeSelectorPoint& operator=(const BRepClass3d_BndBoxTreeSelectorPoint& ); + +private: + const TopTools_IndexedMapOfShape& myMapOfShape; //shapes (vertices + edges) + gp_Pnt myP; +}; + +// Class representing tree selector for line object. +class BRepClass3d_BndBoxTreeSelectorLine : public BRepClass3d_BndBoxTree::Selector +{ +public: + + struct EdgeParam + { + TopoDS_Edge myE; + Standard_Real myParam; //par on myE + Standard_Real myLParam; //par on line + }; + + struct VertParam + { + TopoDS_Vertex myV; + Standard_Real myLParam; //par on line + }; + + +public: + BRepClass3d_BndBoxTreeSelectorLine(const TopTools_IndexedMapOfShape& theMapOfShape) + : BRepClass3d_BndBoxTreeSelectorLine::Selector(), myMapOfShape (theMapOfShape) + {} + + Standard_Boolean Reject (const Bnd_Box& theBox) const + { + return (theBox.IsOut (myL)); + } + + Standard_Boolean Accept (const Standard_Integer& theObj); + + //Sets current line for boxes-line collisions + void SetCurrentLine (const gp_Lin& theL, + const Standard_Real theMaxParam) + { + myL = theL; + myLC.Load(new Geom_Line(theL), -Precision::PConfusion(), theMaxParam); + } + + void GetEdgeParam(const Standard_Integer i, + TopoDS_Edge& theOutE, + Standard_Real &theOutParam, + Standard_Real &outLParam ) const + { + const EdgeParam& EP = myEP.Value(i); + theOutE = EP.myE; + theOutParam = EP.myParam; + outLParam = EP.myLParam; + } + + void GetVertParam(const Standard_Integer i, + TopoDS_Vertex& theOutV, + Standard_Real &outLParam ) const + { + const VertParam& VP = myVP.Value(i); + theOutV = VP.myV; + outLParam = VP.myLParam; + } + + Standard_Integer GetNbEdgeParam() const + { + return myEP.Length(); + } + + Standard_Integer GetNbVertParam() const + { + return myVP.Length(); + } + + void ClearResults() + { + myEP.Clear(); + myVP.Clear(); + } + +private: + BRepClass3d_BndBoxTreeSelectorLine(const BRepClass3d_BndBoxTreeSelectorLine& ); + BRepClass3d_BndBoxTreeSelectorLine& operator=(const BRepClass3d_BndBoxTreeSelectorLine& ); + +private: + const TopTools_IndexedMapOfShape& myMapOfShape; //shapes (vertices + edges) + gp_Lin myL; + NCollection_Sequence myEP; //output result (edge vs line) + NCollection_Sequence myVP; //output result (vertex vs line) + GeomAdaptor_Curve myLC; +}; + +#endif diff --git a/src/BRepClass3d/BRepClass3d_SClassifier.cxx b/src/BRepClass3d/BRepClass3d_SClassifier.cxx index 07833c17d5..6a68919587 100644 --- a/src/BRepClass3d/BRepClass3d_SClassifier.cxx +++ b/src/BRepClass3d/BRepClass3d_SClassifier.cxx @@ -28,10 +28,11 @@ #include #include #include -#include #include #include -#include +#include +#include +#include #include @@ -45,7 +46,14 @@ static static Standard_Real GetAddToParam(const gp_Lin& L,const Standard_Real P,const Bnd_Box& B); +//gets transition of line passing through/near the edge of faces , . is +// a parameter on the edge where the minimum distance between and was found +static Standard_Integer GetTransi(const TopoDS_Face& f1, const TopoDS_Face& f2, const TopoDS_Edge e, + Standard_Real param, const Geom_Line& L, IntCurveSurface_TransitionOnCurve& trans); +static Standard_Boolean GetNormalOnFaceBound(const TopoDS_Edge& E, const TopoDS_Face& F, Standard_Real param, gp_Dir& OutDir); + +static void Trans(Standard_Real parmin, IntCurveSurface_TransitionOnCurve& tran, int& state); //======================================================================= //function : BRepClass3d_SClassifier @@ -116,8 +124,8 @@ void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aS } // iteratively try up to 10 probing points from each face - const int NB_MAX_POINTS_PER_FACE = 10; - for (int itry = 0; itry < NB_MAX_POINTS_PER_FACE; itry++) + const Standard_Integer NB_MAX_POINTS_PER_FACE = 10; + for (Standard_Integer itry = 0; itry < NB_MAX_POINTS_PER_FACE; itry++) { for (std::vector::iterator iFace = aFaces.begin(); iFace != aFaces.end(); ++iFace) { @@ -182,230 +190,263 @@ void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aS //purpose : //======================================================================= void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer, - const gp_Pnt& P, - const Standard_Real Tol) + const gp_Pnt& P, + const Standard_Real Tol) { - - - if(SolidExplorer.Reject(P)) { - myState=3; //-- in ds solid case without face + if(SolidExplorer.Reject(P)) + { + // Solid without faces => the whole space. Always in. + myState = 3; // IN return; } + const BRepClass3d_BndBoxTree & aTree = SolidExplorer.GetTree(); + const TopTools_IndexedMapOfShape & aMapEV = SolidExplorer.GetMapEV(); + + // Vertices/Edges vs Point. + BRepClass3d_BndBoxTreeSelectorPoint aSelectorPoint(aMapEV); + aSelectorPoint.SetCurrentPoint(P); + + Standard_Integer SelsVE = 0; + SelsVE = aTree.Select(aSelectorPoint); + + if (SelsVE > 0) + { + // The point P lays inside the tolerance area of vertices/edges => return ON state. + myState = 2; // ON. + return; + } + + TopTools_IndexedDataMapOfShapeListOfShape mapEF; + TopExp::MapShapesAndAncestors(SolidExplorer.GetShape(), TopAbs_EDGE, TopAbs_FACE, mapEF); + + BRepClass3d_BndBoxTreeSelectorLine aSelectorLine(aMapEV); myFace.Nullify(); myState = 0; - if(SolidExplorer.Reject(P) == Standard_False) { - gp_Lin L; - Standard_Real Par; - //-- We compute the intersection betwwen the line builded in the Solid Explorer - //-- and the shape. - //-- -------------------------------------------------------------------------------- - //-- Calculate intersection with the face closest to the direction of bounding boxes - //-- by priority so that to have the smallest possible parmin. - //-- optimization to produce as much as possible rejections with other faces. - Standard_Integer iFlag; - // + gp_Lin L; + Standard_Real Par; - // Modified by skv - Thu Sep 4 11:22:05 2003 OCC578 Begin - // If found line passes through a bound of any face, it means that the line - // is not found properly and it is necessary to repeat whole procedure. - // That's why the main loop while is added. - Standard_Boolean isFaultyLine = Standard_True; - Standard_Integer anIndFace = 0; - Standard_Real parmin = 0.; + // We compute the intersection between the line built in the Solid Explorer and the shape. + //-- -------------------------------------------------------------------------------- + // Calculate intersection with the face closest to the direction of bounding boxes + // by priority so that to have the smallest possible parmin. + // Optimization to produce as much as possible rejections with other faces. + Standard_Integer iFlag; - while (isFaultyLine) { - if (anIndFace == 0) { - iFlag = SolidExplorer.Segment(P,L,Par); - } else { - iFlag = SolidExplorer.OtherSegment(P,L,Par); - } + // If found line passes through a bound of any face, it means that the line + // is not found properly and it is necessary to repeat whole procedure. + // That's why the main loop while is added. + Standard_Boolean isFaultyLine = Standard_True; + Standard_Integer anIndFace = 0; + Standard_Real parmin = 0.0; + while (isFaultyLine) + { + if (anIndFace == 0) + iFlag = SolidExplorer.Segment(P,L,Par); + else + iFlag = SolidExplorer.OtherSegment(P,L,Par); - Standard_Integer aCurInd = SolidExplorer.GetFaceSegmentIndex(); + Standard_Integer aCurInd = SolidExplorer.GetFaceSegmentIndex(); - if (aCurInd > anIndFace) { - anIndFace = aCurInd; - } else { - myState = 1; - - return; - } - // Modified by skv - Thu Sep 4 11:22:10 2003 OCC578 End - - if (iFlag==1) { - // IsOnFace - // iFlag==1 i.e face is Infinite - myState=2; - - return; - } - //SolidExplorer.Segment(P,L,Par); - // - //process results from uncorrected shells - // - //if(Par > 1.e+100 && L.Direction().IsParallel(gp_Dir(0.,0.,1.),1.e-8)) { - if (iFlag==2) { - myState = 4; - return; - } - //-- BRepClass3d_Intersector3d Intersector3d; - - // Modified by skv - Thu Sep 4 13:48:27 2003 OCC578 Begin - // Check if the point is ON surface but OUT of the face. - // Just skip this face because it is bad for classification. - if (iFlag == 3) - continue; - - isFaultyLine = Standard_False; -// Standard_Real parmin = RealLast(); - -// for(SolidExplorer.InitShell(); -// SolidExplorer.MoreShell(); -// SolidExplorer.NextShell()) { - parmin = RealLast(); - - for(SolidExplorer.InitShell(); - SolidExplorer.MoreShell() && !isFaultyLine; - SolidExplorer.NextShell()) { -// Modified by skv - Thu Sep 4 13:48:27 2003 OCC578 End - - if(SolidExplorer.RejectShell(L) == Standard_False) { - -// Modified by skv - Thu Sep 4 13:48:27 2003 OCC578 Begin -// for(SolidExplorer.InitFace(); -// SolidExplorer.MoreFace(); -// SolidExplorer.NextFace()) { - for(SolidExplorer.InitFace(); - SolidExplorer.MoreFace() && !isFaultyLine; - SolidExplorer.NextFace()) { -// Modified by skv - Thu Sep 4 13:48:27 2003 OCC578 End - - if(SolidExplorer.RejectFace(L) == Standard_False) { - - //-- Intersector3d.Perform(L,Par,Tol,SolidExplorer.CurrentFace()); - TopoDS_Shape aLocalShape = SolidExplorer.CurrentFace(); - TopoDS_Face f = TopoDS::Face(aLocalShape); - // TopoDS_Face f = TopoDS::Face(SolidExplorer.CurrentFace()); - IntCurvesFace_Intersector& Intersector3d = SolidExplorer.Intersector(f); - - // MSV Oct 25, 2001: prolong segment, since there are cases when - // the intersector does not find intersection points with the original - // segment due to rough triangulation of a parametrized surface - Standard_Real addW = Max(10*Tol, 0.01*Par); - Standard_Real AddW = addW; - - Bnd_Box aBoxF = Intersector3d.Bounding(); - - // MSV 23.09.2004: the box must be finite in order to - // correctly prolong the segment to its bounds - if (!aBoxF.IsVoid() && !aBoxF.IsWhole()) { - Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; - aBoxF.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); - - Standard_Real boxaddW = GetAddToParam(L,Par,aBoxF); - addW = Max(addW,boxaddW); - } - - Standard_Real minW = -AddW;//-addW; - Standard_Real maxW = Min(Par*10,Par+addW);//Par+addW; - //cout << "range [" << minW << "," << maxW << "]" << endl << endl; - Intersector3d.Perform(L,minW,maxW); - //Intersector3d.Perform(L,-Tol,Par+10.0*Tol); - if(Intersector3d.IsDone()) { - Standard_Integer i; - for (i=1; i <= Intersector3d.NbPnt(); i++) { - if(Abs(Intersector3d.WParameter(i)) < Abs(parmin) - Precision::PConfusion()) { - - parmin = Intersector3d.WParameter(i); - // Modified by skv - Thu Sep 4 12:46:32 2003 OCC578 Begin - TopAbs_State aState = Intersector3d.State(i); - // Modified by skv - Thu Sep 4 12:46:33 2003 OCC578 End - if(Abs(parmin)<=Tol) { - myState = 2; - myFace = f; - } - // Modified by skv - Thu Sep 4 12:46:32 2003 OCC578 Begin - // Treatment of case TopAbs_ON separately. - - else if(aState==TopAbs_IN) { - // Modified by skv - Thu Sep 4 12:46:32 2003 OCC578 End - - //-- The intersection point between the line and a face F - // -- of the solid is in the face F - - IntCurveSurface_TransitionOnCurve tran = Intersector3d.Transition(i); - if (tran == IntCurveSurface_Tangent) { -#ifdef OCCT_DEBUG - cout<<"*Problem ds BRepClass3d_SClassifier.cxx"< anIndFace) + anIndFace = aCurInd; + else + { + myState = 1; // Faulty. + return; } - // Modified by skv - Thu Sep 4 11:42:03 2003 OCC578 End + + if (iFlag==1) + { + // IsOnFace iFlag==1 i.e face is Infinite + myState = 2; // ON. + return; + } + if (iFlag == 2) + { + myState = 4; // OUT. + return; + } + + // Check if the point is ON surface but OUT of the face. + // Just skip this face because it is bad for classification. + if (iFlag == 3) + continue; + + isFaultyLine = Standard_False; + parmin = RealLast(); + + Standard_Real NearFaultPar = RealLast(); // Parameter on line. + aSelectorLine.ClearResults(); + aSelectorLine.SetCurrentLine(L, Par); + Standard_Integer SelsEVL = 0; + SelsEVL = aTree.Select(aSelectorLine); //SelsEE > 0 => Line/Edges & Line/Vertex intersection + if (SelsEVL > 0 ) + { + // Line and edges / vertices interference. + Standard_Integer VLInterNb = aSelectorLine.GetNbVertParam(); + TopoDS_Vertex NearIntVert; + TopTools_MapOfShape LVInts; + for (Standard_Integer i = 1; i <= VLInterNb; i++) + { + // Line and vertex. + Standard_Real LP = 0; + TopoDS_Vertex V; + aSelectorLine.GetVertParam(i, V, LP); + + LVInts.Add(V); + if (Abs(LP) < Abs(NearFaultPar)) + NearFaultPar = LP; + } + + Standard_Real param = 0.0; + TopoDS_Edge EE; + Standard_Real Lpar = RealLast(); + for (Standard_Integer i = 1; i <= aSelectorLine.GetNbEdgeParam(); i++) + { + // Line and edge. + aSelectorLine.GetEdgeParam(i, EE, param, Lpar); + const TopTools_ListOfShape& ffs = mapEF.FindFromKey(EE); //ffs size == 2 + if (ffs.Extent() != 2) + continue; + TopoDS_Face f1 = TopoDS::Face(ffs.First()); + TopoDS_Face f2 = TopoDS::Face(ffs.Last()); + IntCurveSurface_TransitionOnCurve tran; + TopoDS_Vertex V1, V2; + TopExp::Vertices(EE, V1, V2); + if (LVInts.Contains(V1) || LVInts.Contains(V2)) + continue; + Standard_Integer Tst = GetTransi(f1, f2, EE, param, L, tran); + if (Tst == 1 && Abs(Lpar) < Abs(parmin)) + { + parmin = Lpar; + Trans(parmin, tran, myState); + } + else if (Abs(Lpar) < Abs(NearFaultPar)) + NearFaultPar = Lpar; + } + } + + for(SolidExplorer.InitShell(); + SolidExplorer.MoreShell() && !isFaultyLine; + SolidExplorer.NextShell()) + { + if(SolidExplorer.RejectShell(L) == Standard_False) + { + for(SolidExplorer.InitFace(); + SolidExplorer.MoreFace() && !isFaultyLine; + SolidExplorer.NextFace()) + { + if(SolidExplorer.RejectFace(L) == Standard_False) + { + TopoDS_Shape aLocalShape = SolidExplorer.CurrentFace(); + TopoDS_Face f = TopoDS::Face(aLocalShape); + IntCurvesFace_Intersector& Intersector3d = SolidExplorer.Intersector(f); + + // Prolong segment, since there are cases when + // the intersector does not find intersection points with the original + // segment due to rough triangulation of a parameterized surface. + Standard_Real addW = Max(10*Tol, 0.01*Par); + Standard_Real AddW = addW; + + Bnd_Box aBoxF = Intersector3d.Bounding(); + + // The box must be finite in order to correctly prolong the segment to its bounds. + if (!aBoxF.IsVoid() && !aBoxF.IsWhole()) + { + Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; + aBoxF.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + + Standard_Real boxaddW = GetAddToParam(L,Par,aBoxF); + addW = Max(addW,boxaddW); + } + + Standard_Real minW = -AddW; + Standard_Real maxW = Min(Par*10,Par+addW); + Intersector3d.Perform(L,minW,maxW); + if(Intersector3d.IsDone()) + { + for (Standard_Integer i = 1; i <= Intersector3d.NbPnt(); i++) + { + if(Abs(Intersector3d.WParameter(i)) < Abs(parmin) - Precision::PConfusion()) + { + parmin = Intersector3d.WParameter(i); + TopAbs_State aState = Intersector3d.State(i); + if(Abs(parmin)<=Tol) + { + myState = 2; + myFace = f; + } + // Treatment of case TopAbs_ON separately. + else if(aState==TopAbs_IN) + { + //-- The intersection point between the line and a face F + // -- of the solid is in the face F + + IntCurveSurface_TransitionOnCurve tran = Intersector3d.Transition(i); + if (tran == IntCurveSurface_Tangent) + { + #ifdef OCCT_DEBUG + cout<<"*Problem ds BRepClass3d_SClassifier.cxx"<= Abs(NearFaultPar) - Precision::PConfusion()) + { + isFaultyLine = Standard_True; + } + } #ifdef OCCT_DEBUG - //################################################# - SolidExplorer.DumpSegment(P,L,parmin,State()); - //################################################# + //################################################# + SolidExplorer.DumpSegment(P,L,parmin,State()); + //################################################# #endif - - } //-- Solid has not been rejected - else { - myState = 1; - } } -TopAbs_State BRepClass3d_SClassifier::State() const { - if(myState==2) return(TopAbs_ON); - if(myState==4) return(TopAbs_OUT); //-- - else if(myState==3) return(TopAbs_IN); //-- - return(TopAbs_OUT); +TopAbs_State BRepClass3d_SClassifier::State() const +{ + if(myState == 2) + return(TopAbs_ON); + else if(myState == 3) + return(TopAbs_IN); + else if(myState == 4) + return(TopAbs_OUT); + + // return OUT state when there is an error during execution. + return(TopAbs_OUT); } TopoDS_Face BRepClass3d_SClassifier::Face() const { @@ -484,3 +525,103 @@ Standard_Boolean FaceNormal (const TopoDS_Face& aF, } return Standard_True; } + +//======================================================================= +//function : GetNormalOnFaceBound +//purpose : +//======================================================================= +static Standard_Boolean GetNormalOnFaceBound(const TopoDS_Edge& E, + const TopoDS_Face& F, + const Standard_Real param, + gp_Dir& OutDir) +{ + Standard_Real f = 0, l = 0; + + gp_Pnt2d P2d; + Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface(E, F, f, l); + if (c2d.IsNull()) + return Standard_False; + if (param < f || param > l) + return Standard_False; + c2d->D0(param, P2d); + if (!FaceNormal(F, P2d.X(), P2d.Y(), OutDir)) + return Standard_False; + return Standard_True; +} + +//======================================================================= +//function : GetTransi +//purpose : +//======================================================================= +static Standard_Integer GetTransi(const TopoDS_Face& f1, + const TopoDS_Face& f2, + const TopoDS_Edge e, + const Standard_Real param, + const Geom_Line& L, + IntCurveSurface_TransitionOnCurve& trans) +{ + //return statuses: + //1 => OK + //0 => skip + //-1 => probably a faulty line + gp_Dir nf1, nf2; + if (!GetNormalOnFaceBound(e, f1, param, nf1)) + return -1; + if (!GetNormalOnFaceBound(e, f2, param, nf2)) + return -1; + + const gp_Dir& LDir = L.Lin().Direction(); + + if(Abs(LDir.Dot(nf1)) < Precision::Angular() || Abs(LDir.Dot(nf2)) < Precision::Angular()) + { + //line is orthogonal to normal(s) + //trans = IntCurveSurface_Tangent; + return -1; + } + + if (nf1.IsEqual(nf2, Precision::Angular())) + { + Standard_Real angD = nf1.Dot(LDir); + if (Abs(angD) < Precision::Angular()) + return -1; + else if (angD > 0) + trans = IntCurveSurface_Out; + else //angD < -Precision::Angular()) + trans = IntCurveSurface_In; + return 1; + } + + gp_Vec N = nf1^nf2; + gp_Dir ProjL = N.XYZ() ^ LDir.XYZ() ^ N.XYZ(); //proj LDir on the plane defined by nf1/nf2 directions + + Standard_Real fAD = nf1.Dot(ProjL); + Standard_Real sAD = nf2.Dot(ProjL); + + if (fAD < -Precision::Angular() && sAD < -Precision::Angular()) + trans = IntCurveSurface_In; + else if (fAD > Precision::Angular() && sAD > Precision::Angular()) + trans = IntCurveSurface_Out; + else + return 0; + return 1; +} + +//======================================================================= +//function : Trans +//purpose : +//======================================================================= +static void Trans(const Standard_Real parmin, + IntCurveSurface_TransitionOnCurve& tran, + int& state) +{ + // if parmin is negative we should reverse transition + if (parmin < 0) + tran = (tran == IntCurveSurface_Out ? IntCurveSurface_In : IntCurveSurface_Out); + + if(tran == IntCurveSurface_Out) + //-- The line is going from inside the solid to outside + //-- the solid. + state = 3; // IN + else + state = 4; // OUT +} \ No newline at end of file diff --git a/src/BRepClass3d/BRepClass3d_SClassifier.hxx b/src/BRepClass3d/BRepClass3d_SClassifier.hxx index 7fa46317e7..be08d73de1 100644 --- a/src/BRepClass3d/BRepClass3d_SClassifier.hxx +++ b/src/BRepClass3d/BRepClass3d_SClassifier.hxx @@ -91,6 +91,14 @@ private: TopoDS_Face myFace; + + //! This variable stores information about algorithm internal state. + //! Type of this variable differs from TopAbs_State since it contains + //! additional information about error status. + //! 1 - Error inside of the algorithm. + //! 2 - ON. + //! 3 - IN. + //! 4 - OUT. Standard_Integer myState; diff --git a/src/BRepClass3d/BRepClass3d_SolidExplorer.cxx b/src/BRepClass3d/BRepClass3d_SolidExplorer.cxx index ce51048866..1d81f31177 100644 --- a/src/BRepClass3d/BRepClass3d_SolidExplorer.cxx +++ b/src/BRepClass3d/BRepClass3d_SolidExplorer.cxx @@ -55,6 +55,7 @@ #include #include #include +#include #include //OCC454(apo)-> @@ -466,7 +467,7 @@ Standard_Integer BRepClass3d_SolidExplorer::OtherSegment(const gp_Pnt& P, { myMapOfInter.UnBind(face); void *ptr = (void *)(new IntCurvesFace_Intersector(face, Precision::Confusion(), - aRestr)); + aRestr, Standard_False)); myMapOfInter.Bind(face,ptr); } } @@ -804,6 +805,9 @@ void BRepClass3d_SolidExplorer::Destroy() { void BRepClass3d_SolidExplorer::InitShape(const TopoDS_Shape& S) { + myMapEV.Clear(); + myTree.Clear(); + myShape = S; myFirstFace = 0; myParamOnEdge = 0.512345; @@ -828,7 +832,7 @@ void BRepClass3d_SolidExplorer::InitShape(const TopoDS_Shape& S) Expl.More(); Expl.Next()) { const TopoDS_Face Face = TopoDS::Face(Expl.Current()); - void *ptr = (void *)(new IntCurvesFace_Intersector(Face,Precision::Confusion())); + void *ptr = (void *)(new IntCurvesFace_Intersector(Face,Precision::Confusion(),Standard_True, Standard_False)); myMapOfInter.Bind(Face,ptr); myReject=Standard_False; //-- at least one face in the solid } @@ -837,11 +841,31 @@ void BRepClass3d_SolidExplorer::InitShape(const TopoDS_Shape& S) if(myReject) { cout<<"\nWARNING : BRepClass3d_SolidExplorer.cxx (Solid without face)"< aTreeFiller (myTree); + + for (Standard_Integer i = 1; i <= myMapEV.Extent(); i++) + { + Bnd_Box B; + const TopoDS_Shape& Sh = myMapEV(i); + TopAbs_Orientation ori = Sh.Orientation(); + if (ori == TopAbs_EXTERNAL || ori == TopAbs_INTERNAL) + continue; + if (Sh.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(Sh))) + continue; + BRepBndLib::Add(Sh,B); + aTreeFiller.Add(i, B); + } + aTreeFiller.Fill(); } //======================================================================= @@ -1009,3 +1033,8 @@ void BRepClass3d_SolidExplorer::DumpSegment(const gp_Pnt&, #endif } + +const TopoDS_Shape& BRepClass3d_SolidExplorer::GetShape() const +{ + return(myShape); +} diff --git a/src/BRepClass3d/BRepClass3d_SolidExplorer.hxx b/src/BRepClass3d/BRepClass3d_SolidExplorer.hxx index 8db650a8f3..83aa746f74 100644 --- a/src/BRepClass3d/BRepClass3d_SolidExplorer.hxx +++ b/src/BRepClass3d/BRepClass3d_SolidExplorer.hxx @@ -29,6 +29,9 @@ #include #include #include +#include +#include + class TopoDS_Shape; class gp_Pnt; class TopoDS_Face; @@ -39,9 +42,8 @@ class gp_Lin; class Bnd_Box; class IntCurvesFace_Intersector; - -//! Provide an exploration of a BRep Shape for the -//! classification. +//! Provide an exploration of a BRep Shape for the classification. +//! Provide access to the special UB tree to obtain fast search. class BRepClass3d_SolidExplorer { public: @@ -138,8 +140,15 @@ public: Standard_EXPORT virtual void DumpSegment (const gp_Pnt& P, const gp_Lin& L, const Standard_Real Par, const TopAbs_State S) const; Standard_EXPORT const Bnd_Box& Box() const; + + Standard_EXPORT const TopoDS_Shape& GetShape() const; Standard_EXPORT IntCurvesFace_Intersector& Intersector (const TopoDS_Face& F) const; + + //! Return UB-tree instance which is used for edge / vertex checks. + const BRepClass3d_BndBoxTree& GetTree () {return myTree;} + //! Return edge/vertices map for current shape. + const TopTools_IndexedMapOfShape& GetMapEV () {return myMapEV;} Standard_EXPORT void Destroy(); @@ -164,6 +173,8 @@ private: TopExp_Explorer myShellExplorer; TopExp_Explorer myFaceExplorer; BRepClass3d_MapOfInter myMapOfInter; + BRepClass3d_BndBoxTree myTree; + TopTools_IndexedMapOfShape myMapEV; }; diff --git a/src/BRepClass3d/FILES b/src/BRepClass3d/FILES index 5801626254..30b674213a 100644 --- a/src/BRepClass3d/FILES +++ b/src/BRepClass3d/FILES @@ -1,5 +1,7 @@ BRepClass3d.cxx BRepClass3d.hxx +BRepClass3d_BndBoxTree.hxx +BRepClass3d_BndBoxTree.cxx BRepClass3d_DataMapIteratorOfMapOfInter.hxx BRepClass3d_Intersector3d.cxx BRepClass3d_Intersector3d.hxx diff --git a/src/IntCurvesFace/IntCurvesFace_Intersector.cxx b/src/IntCurvesFace/IntCurvesFace_Intersector.cxx index e1481e7ad9..b43438ab3b 100644 --- a/src/IntCurvesFace/IntCurvesFace_Intersector.cxx +++ b/src/IntCurvesFace/IntCurvesFace_Intersector.cxx @@ -57,14 +57,16 @@ GeomAbs_SurfaceType IntCurvesFace_Intersector::SurfaceType() const //======================================================================= IntCurvesFace_Intersector::IntCurvesFace_Intersector(const TopoDS_Face& Face, const Standard_Real aTol, - const Standard_Boolean aRestr) + const Standard_Boolean aRestr, + const Standard_Boolean UseBToler) : Tol(aTol), done(Standard_False), nbpnt(0), PtrOnPolyhedron(NULL), - PtrOnBndBounding(NULL) + PtrOnBndBounding(NULL), + myUseBoundTol (UseBToler) { BRepAdaptor_Surface surface; face = Face; @@ -146,8 +148,8 @@ void IntCurvesFace_Intersector::InternalCall(const IntCurveSurface_HInter &HICS, gp_Pnt2d Puv(HICSPointindex.U(),HICSPointindex.V()); //TopAbs_State currentstate = myTopolTool->Classify(Puv,Tol); - TopAbs_State currentstate = myTopolTool->Classify(Puv, mintol2d); - if(currentstate == TopAbs_OUT && maxtol2d > mintol2d) { + TopAbs_State currentstate = myTopolTool->Classify(Puv, !myUseBoundTol ? 0 : mintol2d); + if(myUseBoundTol && currentstate == TopAbs_OUT && maxtol2d > mintol2d) { if(anAdditionalTool.IsNull()) { anAdditionalTool = new BRepTopAdaptor_TopolTool(Hsurface); @@ -399,5 +401,13 @@ void IntCurvesFace_Intersector::Destroy() { } } + void IntCurvesFace_Intersector::SetUseBoundToler(Standard_Boolean UseBToler) + { + myUseBoundTol = UseBToler; + } + Standard_Boolean IntCurvesFace_Intersector::GetUseBoundToler() const + { + return myUseBoundTol; + } diff --git a/src/IntCurvesFace/IntCurvesFace_Intersector.hxx b/src/IntCurvesFace/IntCurvesFace_Intersector.hxx index d853d39135..3a4ddd7ea3 100644 --- a/src/IntCurvesFace/IntCurvesFace_Intersector.hxx +++ b/src/IntCurvesFace/IntCurvesFace_Intersector.hxx @@ -58,9 +58,13 @@ public: //! on the line can be a negative value (greater than -Tol). //! If aRestr = true UV bounding box of face is used to restrict //! it's underlined surface, - //! otherwise surface is not restricted + //! otherwise surface is not restricted. + //! If UseBToler = false then the 2d-point of intersection is classified with null-tolerance + //! (relative to face); + //! otherwise it's using maximium between input tolerance(aTol) and tolerances of face bounds (edges). Standard_EXPORT IntCurvesFace_Intersector(const TopoDS_Face& F, const Standard_Real aTol, - const Standard_Boolean aRestr = Standard_True); + const Standard_Boolean aRestr = Standard_True, + const Standard_Boolean UseBToler = Standard_True); //! Perform the intersection between the //! segment L and the loaded face. @@ -117,6 +121,12 @@ public: Standard_EXPORT TopAbs_State ClassifyUVPoint (const gp_Pnt2d& Puv) const; Standard_EXPORT Bnd_Box Bounding() const; + + //! Sets the boundary tolerance flag + Standard_EXPORT void SetUseBoundToler(Standard_Boolean UseBToler ); + + //! Returns the boundary tolerance flag + Standard_EXPORT Standard_Boolean GetUseBoundToler() const; Standard_EXPORT void Destroy(); ~IntCurvesFace_Intersector() @@ -149,6 +159,7 @@ private: TopoDS_Face face; Standard_Address PtrOnPolyhedron; Standard_Address PtrOnBndBounding; + Standard_Boolean myUseBoundTol; }; diff --git a/tests/boolean/gdml_private/ZH2 b/tests/boolean/gdml_private/ZH2 index 7ca79cafd7..77bd9e25f8 100644 --- a/tests/boolean/gdml_private/ZH2 +++ b/tests/boolean/gdml_private/ZH2 @@ -1,2 +1,3 @@ +puts "TODO OCC26018 ALL: Faulty shapes in variables faulty_1 to faulty_" source [locate_data_file 51678_flame-sbr.prt.1.gdml.tcl] diff --git a/tests/boolean/gdml_private/ZI7 b/tests/boolean/gdml_private/ZI7 index b3d4723895..fa231d1e9c 100644 --- a/tests/boolean/gdml_private/ZI7 +++ b/tests/boolean/gdml_private/ZI7 @@ -1,6 +1,6 @@ puts "TODO ?OCC27052 ALL: Faulty shapes in variables faulty_1 to" puts "TODO OCC27052 Windows: Error : The command is not valid. The area is" -puts "TODO OCC27052 Windows: Error : The area of result shape is" +puts "TODO OCC27052 ALL: Error : The area of result shape is" puts "TODO OCC26018 Linux: bopcheck failed" source [locate_data_file mos2014-asm-scf-final.asm.1.gdml.tcl] diff --git a/tests/boolean/gdml_private/ZJ7 b/tests/boolean/gdml_private/ZJ7 index ae81a38f15..acd902c51a 100644 --- a/tests/boolean/gdml_private/ZJ7 +++ b/tests/boolean/gdml_private/ZJ7 @@ -1,6 +1,6 @@ puts "TODO ?OCC27052 ALL: Faulty shapes in variables faulty_1 to" puts "TODO OCC27052 Windows: Error : The command is not valid. The area is" -puts "TODO OCC27052 Windows: Error : The area of result shape is" +puts "TODO OCC27052 ALL: Error : The area of result shape is" puts "TODO OCC26018 Linux: bopcheck failed" source [locate_data_file mos2014-scf-final.prt.1.gdml.tcl] diff --git a/tests/boolean/volumemaker/C9 b/tests/boolean/volumemaker/C9 index de1638a3db..b6f66c461b 100644 --- a/tests/boolean/volumemaker/C9 +++ b/tests/boolean/volumemaker/C9 @@ -1,6 +1,3 @@ -puts "TODO OCC26020 ALL: Error : The area of result shape is" -puts "TODO OCC26020 ALL: Faulty shapes in variables faulty_1 to faulty_" - # test script on make volume operation # cylinder plane unstable diff --git a/tests/bugs/modalg_6/bug27117 b/tests/bugs/modalg_6/bug27117 new file mode 100644 index 0000000000..4bc18ddf89 --- /dev/null +++ b/tests/bugs/modalg_6/bug27117 @@ -0,0 +1,17 @@ +puts "============" +puts "OCC27117" +puts "============" +puts "" +############################################################################ +# BRepClass3d_SolidClassifier doesn't take into account vertex/edge/face tolerances +############################################################################ + +restore [locate_data_file bug27117.brep] s +point p 103.740000000001 1.85e-014 24.3498644581774 + +set cls [bclassify s p] +if { [regexp {IN} $cls] } { + puts "Error : Wrong result obtained by solid classifier algorithm" +} else { + puts "OK : Good result obtained by solid classifier algorithm" +}