// Created on: 1996-07-15 // Created by: Laurent BUCHARD // Copyright (c) 1996-1999 Matra Datavision // Copyright (c) 1999-2014 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. // Modified by skv - Thu Sep 4 11:22:05 2003 OCC578 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // modified by NIZHNY-MKK Mon Jun 21 15:13:40 2004 static Standard_Boolean FaceNormal (const TopoDS_Face& aF, const Standard_Real U, const Standard_Real V, gp_Dir& aDN); 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 gp_Lin& 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 //purpose : //======================================================================= BRepClass3d_SClassifier::BRepClass3d_SClassifier() : myState(0) { } //======================================================================= //function : BRepClass3d_SClassifier //purpose : //======================================================================= BRepClass3d_SClassifier::BRepClass3d_SClassifier(BRepClass3d_SolidExplorer& S, const gp_Pnt& P, const Standard_Real Tol) { if(S.Reject(P)) { myState=3; //-- in ds solid case without face } else { Perform(S,P,Tol); } } //======================================================================= //function : PerformInfinitePoint //purpose : //======================================================================= void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aSE, const Standard_Real /*Tol*/) { //Take a normal to the first extracted face in its random inner point //and intersect this reversed normal with the faces of the solid. //If the min.par.-intersection point is // a) inner point of a face // b) transition is not TANGENT // (the line does not touch the face but pierces it) //then set to IN or OUT according to transition //else take the next random point inside the min.par.-intersected face //and continue if(aSE.Reject(gp_Pnt(0,0,0))) { myState=3; //-- in ds solid case without face return; } // //------------------------------------------------------------ // 1 Standard_Boolean bFound; Standard_Real aParam, aU = 0., aV = 0.; gp_Pnt aPoint; gp_Dir aDN; math_BullardGenerator aRandomGenerator; myFace.Nullify(); myState=2; // Collect faces in sequence to iterate std::vector aFaces; for (aSE.InitShell(); aSE.MoreShell(); aSE.NextShell()) { for (aSE.InitFace(); aSE.MoreFace(); aSE.NextFace()) { aFaces.push_back (aSE.CurrentFace()); } } // iteratively try up to 10 probing points from each face 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) { TopoDS_Face aF = *iFace; TopAbs_State aState = TopAbs_OUT; IntCurveSurface_TransitionOnCurve aTransition = IntCurveSurface_Tangent; aParam = 0.1 + 0.8 * aRandomGenerator.NextReal(); // random number in range [0.1, 0.9] bFound = aSE.FindAPointInTheFace(aF, aPoint, aU, aV, aParam); if (!bFound || !FaceNormal(aF, aU, aV, aDN)) continue; gp_Lin aLin(aPoint, -aDN); Standard_Real parmin = RealLast(); for (aSE.InitShell();aSE.MoreShell();aSE.NextShell()) { if (aSE.RejectShell(aLin) == Standard_False) { for (aSE.InitFace();aSE.MoreFace(); aSE.NextFace()) { if (aSE.RejectFace(aLin) == Standard_False) { TopoDS_Shape aLocalShape = aSE.CurrentFace(); TopoDS_Face CurFace = TopoDS::Face(aLocalShape); IntCurvesFace_Intersector& Intersector3d = aSE.Intersector(CurFace); Intersector3d.Perform(aLin,-RealLast(),parmin); if(Intersector3d.IsDone()) { if(Intersector3d.NbPnt()) { Standard_Integer imin = 1; for (Standard_Integer i = 2; i <= Intersector3d.NbPnt(); i++) if (Intersector3d.WParameter(i) < Intersector3d.WParameter(imin)) imin = i; parmin = Intersector3d.WParameter(imin); aState = Intersector3d.State(imin); aTransition = Intersector3d.Transition(imin); } } } } } else myState = 1; } //end of loop on the whole solid if (aState == TopAbs_IN) { if (aTransition == IntCurveSurface_Out) { //-- The line is going from inside the solid to outside //-- the solid. myState = 3; //-- IN -- return; } else if (aTransition == IntCurveSurface_In) { myState = 4; //-- OUT -- return; } } } // iteration by faces } // iteration by points } //======================================================================= //function : Perform //purpose : //======================================================================= void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer, const gp_Pnt& P, const Standard_Real Tol) { 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; gp_Lin L; Standard_Real Par; // 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; // 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(); if (aCurInd > anIndFace) anIndFace = aCurInd; else { myState = 1; // Faulty. return; } 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()); TopoDS_Vertex V1, V2; TopExp::Vertices(EE, V1, V2); if (LVInts.Contains(V1) || LVInts.Contains(V2)) { continue; } IntCurveSurface_TransitionOnCurve tran = IntCurveSurface_Tangent; 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()) { if (Intersector3d.NbPnt() == 0) { if (Intersector3d.IsParallel()) { //Check distance between surface and point BRepAdaptor_Surface aBAS(f, Standard_False); Extrema_ExtPS aProj(P, aBAS, Precision::PConfusion(), Precision::PConfusion()); if (aProj.IsDone() && aProj.NbExt() > 0) { Standard_Integer i, indmin = 0; Standard_Real d = RealLast(); for (i = 1; i <= aProj.NbExt(); ++i) { if (aProj.SquareDistance(i) < d) { d = aProj.SquareDistance(i); indmin = i; } } if (indmin > 0) { if (d <= Tol * Tol) { const Extrema_POnSurf& aPonS = aProj.Point(indmin); Standard_Real anU, anV; aPonS.Parameter(anU, anV); gp_Pnt2d aP2d(anU, anV); TopAbs_State aSt = Intersector3d.ClassifyUVPoint(aP2d); if (aSt == TopAbs_IN || aSt == TopAbs_ON) { myState = 2; myFace = f; parmin = 0.; break; } } } } } } 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; break; } // 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 std::cout<<"*Problem ds BRepClass3d_SClassifier.cxx"<= Abs(NearFaultPar) - Precision::PConfusion()) { isFaultyLine = Standard_True; } } #ifdef OCCT_DEBUG //################################################# SolidExplorer.DumpSegment(P,L,parmin,State()); //################################################# #endif } 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 { return(myFace); } Standard_Boolean BRepClass3d_SClassifier::Rejected() const { return(myState==1); } Standard_Boolean BRepClass3d_SClassifier::IsOnAFace() const { return(myState==2); } void BRepClass3d_SClassifier::ForceIn() { myState=3; } void BRepClass3d_SClassifier::ForceOut() { myState=4; } Standard_Real GetAddToParam(const gp_Lin& L, const Standard_Real P, const Bnd_Box& B) { Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); Standard_Real x[2] = {aXmin,aXmax}, y[2] = {aYmin,aYmax}, z[2] = {aZmin,aZmax}; Standard_Integer i = 0, j = 0, k = 0; Standard_Real Par = P; for(i = 0 ; i < 2; i++) { for(j = 0; j < 2; j++) { for(k = 0; k < 2; k++) { Standard_Real X = fabs(x[i]-L.Location().X()); Standard_Real Y = fabs(y[j]-L.Location().Y()); Standard_Real Z = fabs(z[k]-L.Location().Z()); if(X < 1.e+20 && Y < 1.e+20 && Z < 1.e+20) { gp_Pnt aP(x[i],y[j],z[k]); Standard_Real par = ElCLib::Parameter(L,aP); if(par > Par) Par = par; } else return 1.e+20; } } } return Par - P; } //======================================================================= //function : FaceNormal //purpose : //======================================================================= Standard_Boolean FaceNormal (const TopoDS_Face& aF, const Standard_Real U, const Standard_Real V, gp_Dir& aDN) { gp_Pnt aPnt ; gp_Vec aD1U, aD1V, aN; Handle(Geom_Surface) aS; aS=BRep_Tool::Surface(aF); aS->D1 (U, V, aPnt, aD1U, aD1V); aN=aD1U.Crossed(aD1V); if (aN.Magnitude() <= gp::Resolution()) return Standard_False; aN.Normalize(); aDN.SetXYZ(aN.XYZ()); if (aF.Orientation() == TopAbs_REVERSED){ aDN.Reverse(); } 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 gp_Lin& 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.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.IsParallel(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 }