// Created on: 1995-03-22 // Created by: Laurent BUCHARD // Copyright (c) 1995-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. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_PCLASS_POLYGON #ifdef DEBUG_PCLASS_POLYGON #include #include #endif //======================================================================= //function : IntTools_FClass2d:IntTools:_FClass2d //purpose : //======================================================================= IntTools_FClass2d::IntTools_FClass2d() { } //======================================================================= //function : IntTools_FClass2d::IntTools_FClass2d //purpose : //======================================================================= IntTools_FClass2d::IntTools_FClass2d(const TopoDS_Face& aFace, const Standard_Real TolUV) : Toluv(TolUV), Face(aFace) { Init(Face, Toluv); } //======================================================================= //function : IsHole //purpose : //======================================================================= Standard_Boolean IntTools_FClass2d::IsHole() const { return myIsHole; } //======================================================================= //function : Init //purpose : //======================================================================= void IntTools_FClass2d::Init(const TopoDS_Face& aFace, const Standard_Real TolUV) { Standard_Boolean WireIsNotEmpty, Ancienpnt3dinitialise, degenerated; Standard_Integer firstpoint, NbEdges; Standard_Integer iX, aNbs1, nbs, Avant, BadWire; Standard_Real u, du, Tole, Tol, pfbid, plbid; Standard_Real FlecheU, FlecheV, TolVertex1, TolVertex; Standard_Real uFirst, uLast; Standard_Real aPrCf, aPrCf2; // TopoDS_Edge edge; TopoDS_Vertex Va,Vb; TopAbs_Orientation Or; BRepTools_WireExplorer aWExp; TopExp_Explorer aExpF, aExp; Handle(Geom2d_Curve) aC2D; gp_Pnt Ancienpnt3d; TColgp_SequenceOfPnt2d SeqPnt2d; TColStd_DataMapOfIntegerInteger anIndexMap; TColgp_SequenceOfVec2d aD1Prev; TColgp_SequenceOfVec2d aD1Next; // aPrCf=Precision::Confusion(); aPrCf2=aPrCf*aPrCf; myIsHole=Standard_True; // Toluv=TolUV; Face=aFace; Face.Orientation(TopAbs_FORWARD); Handle(BRepAdaptor_HSurface) surf = new BRepAdaptor_HSurface(); surf->ChangeSurface().Initialize(aFace, Standard_False); // Tole = 0.; Tol=0.; Umin = Vmin = RealLast(); Umax = Vmax = -Umin; BadWire=0; // //if face has several wires and one of them is bad, //it is necessary to process all of them for correct //calculation of Umin, Umax, Vmin, Vmax - ifv, 23.08.06 // aExpF.Init(Face,TopAbs_WIRE); for(; aExpF.More(); aExpF.Next()) { const TopoDS_Wire& aW=*((TopoDS_Wire*)&aExpF.Current()); // firstpoint =1; FlecheU = 0.; FlecheV = 0.; TolVertex1=0.; TolVertex=0.; WireIsNotEmpty = Standard_False; Ancienpnt3dinitialise=Standard_False; Ancienpnt3d.SetCoord(0.,0.,0.); // SeqPnt2d.Clear(); anIndexMap.Clear(); aD1Prev.Clear(); aD1Next.Clear(); // // NbEdges NbEdges=0; aExp.Init(aW, TopAbs_EDGE); for(; aExp.More(); aExp.Next()) { NbEdges++; } // aWExp.Init(aW, Face); for(;aWExp.More(); aWExp.Next()) { NbEdges--; edge = aWExp.Current(); Or = edge.Orientation(); if(!(Or==TopAbs_FORWARD || Or==TopAbs_REVERSED)) { continue; } // aC2D=BRep_Tool::CurveOnSurface(edge, Face, pfbid, plbid); if (aC2D.IsNull()) { return; } // BRepAdaptor_Curve2d C(edge,Face); BRepAdaptor_Curve C3d; //------------------------------------------ degenerated=Standard_False; if(BRep_Tool::Degenerated(edge) || BRep_Tool::IsClosed(edge, Face)) { degenerated=Standard_True; } // TopExp::Vertices(edge,Va,Vb); // TolVertex1=0.; TolVertex=0.; if (Va.IsNull()) { degenerated=Standard_True; } else { TolVertex1=BRep_Tool::Tolerance(Va); } if (Vb.IsNull()){ degenerated=Standard_True; } else { TolVertex=BRep_Tool::Tolerance(Vb); } // if(TolVertex aPrec2) { degenerated = Standard_False; break; } } }//if(!degenerated) //-- ---------------------------------------- Tole = BRep_Tool::Tolerance(edge); if(Tole>Tol) { Tol=Tole; } // // NbSamples +> nbs nbs = Geom2dInt_Geom2dCurveTool::NbSamples(C); if (nbs > 2) { nbs*=4; } du = (plbid-pfbid)/(Standard_Real)(nbs-1); // if(Or==TopAbs_FORWARD) { u = pfbid; uFirst=pfbid; uLast=plbid; } else { u = plbid; uFirst=plbid; uLast=pfbid; du=-du; } // // aPrms aNbs1=nbs+1; TColStd_Array1OfReal aPrms(1, aNbs1); // if (nbs==2) { Standard_Real aCoef=0.0025; aPrms(1)=uFirst; aPrms(2)=uFirst+aCoef*(uLast-uFirst); aPrms(3)=uLast; } else if (nbs>2) { aNbs1=nbs; aPrms(1)=uFirst; for (iX=2; iXUmax) Umax = P2d.X(); if(P2d.Y()Vmax) Vmax = P2d.Y(); // aDstX=RealLast(); if(degenerated==Standard_False) { P3d=C3d.Value(u); if(!SeqPnt2d.IsEmpty()) { if(Ancienpnt3dinitialise) { aDstX=P3d.SquareDistance(Ancienpnt3d); } } } // IsRealCurve3d = Standard_True; if (aDstX < aPrCf2) { if(iX>1) { Standard_Real aDstX1; gp_Pnt MidP3d; // MidP3d = C3d.Value(0.5*(u+aPrms(iX-1))); aDstX1=P3d.SquareDistance( MidP3d ); if (aDstX1 < aPrCf2){ IsRealCurve3d = Standard_False; } } } // if (IsRealCurve3d) { if(degenerated==Standard_False) { Ancienpnt3d=P3d; Ancienpnt3dinitialise=Standard_True; } SeqPnt2d.Append(P2d); } // ii= SeqPnt2d.Length(); if(ii>(Avant+4)) { Standard_Real ul, dU, dV; gp_Pnt2d Pp; // gp_Lin2d Lin(SeqPnt2d(ii-2),gp_Dir2d(gp_Vec2d(SeqPnt2d(ii-2),SeqPnt2d(ii)))); ul = ElCLib::Parameter(Lin,SeqPnt2d(ii-1)); Pp = ElCLib::Value(ul,Lin); dU = Abs(Pp.X()-SeqPnt2d(ii-1).X()); dV = Abs(Pp.Y()-SeqPnt2d(ii-1).Y()); if(dU>FlecheU) { FlecheU = dU; } if(dV>FlecheV) { FlecheV = dV; } } }// for(iX=firstpoint; iX<=aNbs1; iX++) { // if(BadWire) { continue; //if face has several wires and one of them is bad, //it is necessary to process all of them for correct //calculation of Umin, Umax, Vmin, Vmax - ifv, 23.08.06 } // if(firstpoint==1) firstpoint=2; WireIsNotEmpty = Standard_True; // Append the derivative of the first parameter. Standard_Real aU = aPrms(1); gp_Pnt2d aP; gp_Vec2d aV; C.D1(aU, aP, aV); if(Or == TopAbs_REVERSED) aV.Reverse(); aD1Next.Append(aV); // Append the derivative of the last parameter. aU = aPrms(aNbs1); C.D1(aU, aP, aV); if(Or == TopAbs_REVERSED) aV.Reverse(); if (NbEdges > 0) aD1Prev.Append(aV); else aD1Prev.Prepend(aV); // Fill the map anIndexMap. if (Avant > 0) anIndexMap.Bind(Avant, aD1Next.Length()); else anIndexMap.Bind(1, aD1Next.Length()); } //for(;aWExp.More(); aWExp.Next()) { // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // if(NbEdges) { //-- count ++ with normal explorer and -- with Wire Explorer TColgp_Array1OfPnt2d PClass(1,2); gp_Pnt2d anInitPnt(0., 0.); // PClass.Init(anInitPnt); TabClass.Append((void *)new CSLib_Class2d(PClass, FlecheU, FlecheV, Umin,Vmin,Umax,Vmax)); BadWire=1; TabOrien.Append(-1); } // else if(WireIsNotEmpty) { if (SeqPnt2d.Length() > 3) { #ifdef DEBUG_PCLASS_POLYGON TColgp_Array1OfPnt2d PClass(1, nbpnts); TColStd_Array1OfReal aKnots(1, nbpnts); TColStd_Array1OfInteger aMults(1, nbpnts); for (int i = 1; i <= nbpnts; i++) { aKnots(i) = i; aMults(i) = 1; PClass(ii) = SeqPnt2d.Value(ii); } aMults(1) = aMults(nbpnts) = 2; Handle(Geom2d_BSplineCurve) aPol = new Geom2d_BSplineCurve(PClass, aKnots, aMults, 1); DrawTrSurf::Set("pol", aPol); #endif Standard_Real aS = 0.; Standard_Real aPer = 0.; Poly::PolygonProperties(SeqPnt2d, aS, aPer); Standard_Real anExpThick = Max(2. * Abs(aS) / aPer, 1e-7); Standard_Real aDefl = Max(FlecheU, FlecheV); Standard_Real aDiscrDefl = Min(aDefl*0.1, anExpThick * 10.); Standard_Boolean isChanged = Standard_False; while (aDefl > anExpThick && aDiscrDefl > 1e-7) { // Deflection of the polygon is too much for this ratio of area and perimeter, // and this might lead to self-intersections. // Discretize the wire more tightly to eliminate the error. firstpoint = 1; isChanged = Standard_True; SeqPnt2d.Clear(); FlecheU = 0.0; FlecheV = 0.0; for (aWExp.Init(TopoDS::Wire(aExpF.Current()), Face); aWExp.More(); aWExp.Next()) { edge = aWExp.Current(); Or = edge.Orientation(); if (Or == TopAbs_FORWARD || Or == TopAbs_REVERSED) { BRep_Tool::Range(edge, Face, pfbid, plbid); if (Abs(plbid - pfbid) < 1.e-9) continue; BRepAdaptor_Curve2d C(edge, Face); GCPnts_QuasiUniformDeflection aDiscr(C, aDiscrDefl); if (!aDiscr.IsDone()) break; Standard_Integer nbp = aDiscr.NbPoints(); Standard_Integer iStep = 1, i = 1, iEnd = nbp + 1; if (Or == TopAbs_REVERSED) { iStep = -1; i = nbp; iEnd = 0; } if (firstpoint == 2) i += iStep; for (; i != iEnd; i += iStep) { gp_Pnt2d aP2d = C.Value(aDiscr.Parameter(i)); SeqPnt2d.Append(aP2d); } if (nbp > 2) { Standard_Integer ii = SeqPnt2d.Length(); gp_Lin2d Lin(SeqPnt2d(ii - 2), gp_Dir2d(gp_Vec2d(SeqPnt2d(ii - 2), SeqPnt2d(ii)))); Standard_Real ul = ElCLib::Parameter(Lin, SeqPnt2d(ii - 1)); gp_Pnt2d Pp = ElCLib::Value(ul, Lin); Standard_Real dU = Abs(Pp.X() - SeqPnt2d(ii - 1).X()); Standard_Real dV = Abs(Pp.Y() - SeqPnt2d(ii - 1).Y()); if (dU > FlecheU) FlecheU = dU; if (dV > FlecheV) FlecheV = dV; } firstpoint = 2; } } anExpThick = Max(2. * Abs(aS) / aPer, 1e-7); aDefl = Max(FlecheU, FlecheV); aDiscrDefl = Min(aDiscrDefl * 0.1, anExpThick * 10.); } if (isChanged) { Poly::PolygonProperties(SeqPnt2d, aS, aPer); } // if(FlecheU 0.0) { myIsHole = Standard_False; TabOrien.Append(1); } else { myIsHole = Standard_True; TabOrien.Append(0); } } } else { BadWire=1; TabOrien.Append(-1); TColgp_Array1OfPnt2d PPClass(1,2); SeqPnt2d.Clear(); TabClass.Append((void *)new CSLib_Class2d(SeqPnt2d, FlecheU, FlecheV, Umin,Vmin,Umax,Vmax)); } }// else if(WireIsNotEmpty) } // for(; aExpF.More(); aExpF.Next()) { // Standard_Integer nbtabclass = TabClass.Length(); // if(nbtabclass>0) { //-- if an error on a wire was detected : all TabOrien set to -1 if(BadWire) { TabOrien(1)=-1; } if( surf->GetType()==GeomAbs_Cone || surf->GetType()==GeomAbs_Cylinder || surf->GetType()==GeomAbs_Torus || surf->GetType()==GeomAbs_Sphere || surf->GetType()==GeomAbs_SurfaceOfRevolution) { Standard_Real uuu=M_PI+M_PI-(Umax-Umin); if(uuu<0) uuu=0; U1 = Umin-uuu*0.5; U2 = U1+M_PI+M_PI; } else { U1=U2=0.0; } if(surf->GetType()==GeomAbs_Torus) { Standard_Real uuu=M_PI+M_PI-(Vmax-Vmin); if(uuu<0) uuu=0; V1 = Vmin-uuu*0.5; V2 = V1+M_PI+M_PI; } else { V1=V2=0.0; } } } //======================================================================= //function : PerformInfinitePoint //purpose : //======================================================================= TopAbs_State IntTools_FClass2d::PerformInfinitePoint() const { if(Umax==-RealLast() || Vmax==-RealLast() || Umin==RealLast() || Vmin==RealLast()) { return(TopAbs_IN); } gp_Pnt2d P(Umin-(Umax-Umin),Vmin-(Vmax-Vmin)); return(Perform(P,Standard_False)); } //======================================================================= //function : Perform //purpose : //======================================================================= TopAbs_State IntTools_FClass2d::Perform (const gp_Pnt2d& _Puv, const Standard_Boolean RecadreOnPeriodic) const { Standard_Integer nbtabclass = TabClass.Length(); if (nbtabclass == 0) { return TopAbs_IN; } //-- U1 is the First Param and U2 is in this case U1+Period Standard_Real u = _Puv.X(); Standard_Real v = _Puv.Y(); Standard_Real uu = u; Standard_Real vv = v; TopAbs_State aStatus = TopAbs_UNKNOWN; Handle(BRepAdaptor_HSurface) surf = new BRepAdaptor_HSurface(); surf->ChangeSurface().Initialize( Face, Standard_False ); const Standard_Boolean IsUPer = surf->IsUPeriodic(); const Standard_Boolean IsVPer = surf->IsVPeriodic(); const Standard_Real uperiod = IsUPer ? surf->UPeriod() : 0.0; const Standard_Real vperiod = IsVPer ? surf->VPeriod() : 0.0; Standard_Boolean urecadre, vrecadre, bUseClassifier; Standard_Integer dedans = 1; // urecadre = Standard_False; vrecadre = Standard_False; // if (RecadreOnPeriodic) { Standard_Real du, dv; if (IsUPer) { GeomInt::AdjustPeriodic(uu, Umin, Umax, uperiod, uu, du); }// if (IsUPer) { // if (IsVPer) { GeomInt::AdjustPeriodic(vv, Vmin, Vmax, vperiod, vv, dv); }//if (IsVPer) { } // for(;;) { dedans = 1; gp_Pnt2d Puv(u,v); bUseClassifier = (TabOrien(1) == -1); if(!bUseClassifier) { Standard_Integer n, cur, TabOrien_n ; for(n=1; n<=nbtabclass; n++) { cur = ((CSLib_Class2d *)TabClass(n))->SiDans(Puv); TabOrien_n=TabOrien(n); if(cur==1) { if(TabOrien_n==0) { dedans = -1; break; } } else if(cur==-1) { if(TabOrien_n==1) { dedans = -1; break; } } else { dedans = 0; break; } } // for(n=1; n<=nbtabclass; n++) if(dedans==0) { bUseClassifier = Standard_True; } else { aStatus = (dedans == 1) ? TopAbs_IN : TopAbs_OUT; } } // if(TabOrien(1)!=-1) { //compute state of the point using face classifier if (bUseClassifier) { //compute tolerance to use in face classifier Standard_Real aURes, aVRes, aFCTol; Standard_Boolean bUIn, bVIn; // aURes = surf->UResolution(Toluv); aVRes = surf->VResolution(Toluv); // bUIn = (u >= Umin) && (u <= Umax); bVIn = (v >= Vmin) && (v <= Vmax); // if (bUIn==bVIn) { aFCTol = Min(aURes, aVRes); } else { aFCTol = (!bUIn) ? aURes : aVRes; } // if (myFExplorer.get() == NULL) myFExplorer.reset (new BRepClass_FaceExplorer (Face)); BRepClass_FClassifier aClassifier; aClassifier.Perform(*myFExplorer, Puv, aFCTol); aStatus = aClassifier.State(); } if (!RecadreOnPeriodic || (!IsUPer && !IsVPer)) return aStatus; if (aStatus == TopAbs_IN || aStatus == TopAbs_ON) return aStatus; if (!urecadre){ u = uu; urecadre = Standard_True; } else { if (IsUPer){ u += uperiod; } } if (u > Umax || !IsUPer) { if (!vrecadre){ v = vv; vrecadre = Standard_True; } else { if (IsVPer){ v += vperiod; } } u = uu; if (v > Vmax || !IsVPer) { return aStatus; } } } //while (1) } //======================================================================= //function : TestOnRestriction //purpose : //======================================================================= TopAbs_State IntTools_FClass2d::TestOnRestriction (const gp_Pnt2d& _Puv, const Standard_Real Tol, const Standard_Boolean RecadreOnPeriodic) const { Standard_Integer nbtabclass = TabClass.Length(); if (nbtabclass == 0) { return TopAbs_IN; } //-- U1 is the First Param and U2 in this case is U1+Period Standard_Real u=_Puv.X(); Standard_Real v=_Puv.Y(); Standard_Real uu = u, vv = v; Handle(BRepAdaptor_HSurface) surf = new BRepAdaptor_HSurface(); surf->ChangeSurface().Initialize( Face, Standard_False ); const Standard_Boolean IsUPer = surf->IsUPeriodic(); const Standard_Boolean IsVPer = surf->IsVPeriodic(); const Standard_Real uperiod = IsUPer ? surf->UPeriod() : 0.0; const Standard_Real vperiod = IsVPer ? surf->VPeriod() : 0.0; TopAbs_State aStatus = TopAbs_UNKNOWN; Standard_Boolean urecadre = Standard_False, vrecadre = Standard_False; Standard_Integer dedans = 1; if (RecadreOnPeriodic) { Standard_Real du, dv; if (IsUPer) { GeomInt::AdjustPeriodic(uu, Umin, Umax, uperiod, uu, du); }// if (IsUPer) { // if (IsVPer) { GeomInt::AdjustPeriodic(vv, Vmin, Vmax, vperiod, vv, dv); }//if (IsVPer) { } // for (;;) { dedans = 1; gp_Pnt2d Puv(u,v); if(TabOrien(1)!=-1) { for(Standard_Integer n=1; n<=nbtabclass; n++) { Standard_Integer cur = ((CSLib_Class2d *)TabClass(n))->SiDans_OnMode(Puv,Tol); if(cur==1) { if(TabOrien(n)==0) { dedans = -1; break; } } else if(cur==-1) { if(TabOrien(n)==1) { dedans = -1; break; } } else { dedans = 0; break; } } if(dedans==0) { aStatus = TopAbs_ON; } if(dedans == 1) { aStatus = TopAbs_IN; } if(dedans == -1) { aStatus = TopAbs_OUT; } } else { //-- TabOrien(1)=-1 Wrong Wire if (myFExplorer.get() == NULL) myFExplorer.reset (new BRepClass_FaceExplorer (Face)); BRepClass_FClassifier aClassifier; aClassifier.Perform(*myFExplorer, Puv, Tol); aStatus = aClassifier.State(); } if (!RecadreOnPeriodic || (!IsUPer && !IsVPer)) return aStatus; if (aStatus == TopAbs_IN || aStatus == TopAbs_ON) return aStatus; if (!urecadre) { u = uu; urecadre = Standard_True; } else if (IsUPer) u += uperiod; if (u > Umax || !IsUPer) { if (!vrecadre) { v = vv; vrecadre = Standard_True; } else if (IsVPer) v += vperiod; u = uu; if (v > Vmax || !IsVPer) return aStatus; } } //for (;;) } //======================================================================= //function : Destroy //purpose : //======================================================================= void IntTools_FClass2d::Destroy() { Standard_Integer nbtabclass = TabClass.Length(); for(Standard_Integer d=1; d<=nbtabclass;d++) { if(TabClass(d)) { delete ((CSLib_Class2d *)TabClass(d)); TabClass(d)=NULL; } } }