// Created on: 1993-03-30 // Created by: Laurent BUCHARD // Copyright (c) 1993-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 // If quantity of points is less than aMinNbPointsForApprox // then interpolation is used. const Standard_Integer aMinNbPointsForApprox = 5; // This constant should be removed in the future. const Standard_Real RatioTol = 1.5 ; //======================================================================= //function : ComputeTrsf3d //purpose : //======================================================================= static void ComputeTrsf3d(const Handle(TheWLine)& theline, Standard_Real& theXo, Standard_Real& theYo, Standard_Real& theZo) { const Standard_Integer aNbPnts = theline->NbPnts(); Standard_Real aXmin = RealLast(), aYmin = RealLast(), aZmin = RealLast(); for(Standard_Integer i=1;i<=aNbPnts;i++) { const gp_Pnt& P = theline->Point(i).Value(); aXmin = Min(P.X(), aXmin); aYmin = Min(P.Y(), aYmin); aZmin = Min(P.Z(), aZmin); } theXo = -aXmin; theYo = -aYmin; theZo = -aZmin; } //======================================================================= //function : ComputeTrsf2d //purpose : //======================================================================= static void ComputeTrsf2d(const Handle(TheWLine)& theline, const Standard_Boolean onFirst, Standard_Real& theUo, Standard_Real& theVo) { const Standard_Integer aNbPnts = theline->NbPnts(); Standard_Real aUmin = RealLast(), aVmin = RealLast(); // pointer to a member-function void (IntSurf_PntOn2S::* pfunc)(Standard_Real&,Standard_Real&) const; if (onFirst) pfunc = &IntSurf_PntOn2S::ParametersOnS1; else pfunc = &IntSurf_PntOn2S::ParametersOnS2; for(Standard_Integer i=1; i<=aNbPnts; i++) { const IntSurf_PntOn2S& POn2S = theline->Point(i); Standard_Real U,V; (POn2S.*pfunc)(U,V); aUmin = Min(U, aUmin); aVmin = Min(V, aVmin); } theUo = -aUmin; theVo = -aVmin; } //======================================================================= //function : Parameters //purpose : //======================================================================= static void Parameters(const ApproxInt_TheMultiLine& Line, const Standard_Integer firstP, const Standard_Integer lastP, const Approx_ParametrizationType Par, math_Vector& TheParameters) { Standard_Integer i, j, nbP2d, nbP3d; Standard_Real dist; gp_Pnt P1, P2; gp_Pnt2d P12d, P22d; if (Par == Approx_ChordLength || Par == Approx_Centripetal) { nbP3d = ApproxInt_TheMultiLineTool::NbP3d(Line); nbP2d = ApproxInt_TheMultiLineTool::NbP2d(Line); Standard_Integer mynbP3d=nbP3d, mynbP2d=nbP2d; if (nbP3d == 0) mynbP3d = 1; if (nbP2d == 0) mynbP2d = 1; TheParameters(firstP) = 0.0; dist = 0.0; TColgp_Array1OfPnt tabP(1, mynbP3d); TColgp_Array1OfPnt tabPP(1, mynbP3d); TColgp_Array1OfPnt2d tabP2d(1, mynbP2d); TColgp_Array1OfPnt2d tabPP2d(1, mynbP2d); for (i = firstP+1; i <= lastP; i++) { if (nbP3d != 0 && nbP2d != 0) ApproxInt_TheMultiLineTool::Value(Line, i-1, tabP, tabP2d); else if (nbP2d != 0) ApproxInt_TheMultiLineTool::Value(Line, i-1, tabP2d); else if (nbP3d != 0) ApproxInt_TheMultiLineTool::Value(Line, i-1, tabP); if (nbP3d != 0 && nbP2d != 0) ApproxInt_TheMultiLineTool::Value(Line, i, tabPP, tabPP2d); else if (nbP2d != 0) ApproxInt_TheMultiLineTool::Value(Line, i, tabPP2d); else if (nbP3d != 0) ApproxInt_TheMultiLineTool::Value(Line, i, tabPP); dist = 0; for (j = 1; j <= nbP3d; j++) { P1 = tabP(j); P2 = tabPP(j); dist += P2.Distance(P1); } for (j = 1; j <= nbP2d; j++) { P12d = tabP2d(j); P22d = tabPP2d(j); dist += P22d.Distance(P12d); } if(Par == Approx_ChordLength) TheParameters(i) = TheParameters(i-1) + dist; else {// Par == Approx_Centripetal TheParameters(i) = TheParameters(i-1) + Sqrt(dist); } } for (i = firstP; i <= lastP; i++) TheParameters(i) /= TheParameters(lastP); } else { for (i = firstP; i <= lastP; i++) { TheParameters(i) = (Standard_Real(i)-firstP)/ (Standard_Real(lastP)-Standard_Real(firstP)); } } } //======================================================================= //function : Default constructor //purpose : //======================================================================= ApproxInt_Approx::ApproxInt_Approx(): myComputeLine(4, 8, 0.001, 0.001, 5), myComputeLineBezier(4, 8, 0.001, 0.001, 5), myWithTangency(Standard_True), myTol3d(0.001), myTol2d(0.001), myDegMin(4), myDegMax(8), myNbIterMax(5), myTolReached3d(0.0), myTolReached2d(0.0) { myComputeLine.SetContinuity(2); //myComputeLineBezier.SetContinuity(2); } //======================================================================= //function : Perform //purpose : Build without surfaces information. //======================================================================= void ApproxInt_Approx::Perform(const Handle(TheWLine)& theline, const Standard_Boolean ApproxXYZ, const Standard_Boolean ApproxU1V1, const Standard_Boolean ApproxU2V2, const Standard_Integer indicemin, const Standard_Integer indicemax) { // Prepare DS. prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax); const Standard_Integer nbpntbez = myData.indicemax - myData.indicemin; if(nbpntbez < aMinNbPointsForApprox) myData.myBezierApprox = Standard_False; else myData.myBezierApprox = Standard_True; // Fill data structure. fillData(theline); // Build knots. buildKnots(theline, NULL); if (myKnots.Length() == 2 && indicemax - indicemin > 2 * myData.myNbPntMax) { // At least 3 knots for BrepApprox. myKnots.ChangeLast() = (indicemax - indicemin) / 2; myKnots.Append(indicemax); } myComputeLine.Init (myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, myData.parametrization); myComputeLineBezier.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, myData.parametrization); buildCurve(theline, NULL); } //======================================================================= //function : Perform //purpose : Definition of next steps according to surface types // (i.e. coordination algorithm). //======================================================================= void ApproxInt_Approx::Perform(const ThePSurface& Surf1, const ThePSurface& Surf2, const Handle(TheWLine)& theline, const Standard_Boolean ApproxXYZ, const Standard_Boolean ApproxU1V1, const Standard_Boolean ApproxU2V2, const Standard_Integer indicemin, const Standard_Integer indicemax) { myTolReached3d = myTolReached2d = 0.; const GeomAbs_SurfaceType typeS1 = ThePSurfaceTool::GetType(Surf1); const GeomAbs_SurfaceType typeS2 = ThePSurfaceTool::GetType(Surf2); const Standard_Boolean isQuadric = ((typeS1 == GeomAbs_Plane) || (typeS1 == GeomAbs_Cylinder) || (typeS1 == GeomAbs_Sphere) || (typeS1 == GeomAbs_Cone) || (typeS2 == GeomAbs_Plane) || (typeS2 == GeomAbs_Cylinder) || (typeS2 == GeomAbs_Sphere) || (typeS2 == GeomAbs_Cone)); if(isQuadric) { IntSurf_Quadric Quad; Standard_Boolean SecondIsImplicit=Standard_False; switch (typeS1) { case GeomAbs_Plane: Quad.SetValue(ThePSurfaceTool::Plane(Surf1)); break; case GeomAbs_Cylinder: Quad.SetValue(ThePSurfaceTool::Cylinder(Surf1)); break; case GeomAbs_Sphere: Quad.SetValue(ThePSurfaceTool::Sphere(Surf1)); break; case GeomAbs_Cone: Quad.SetValue(ThePSurfaceTool::Cone(Surf1)); break; default: { SecondIsImplicit = Standard_True; switch (typeS2) { case GeomAbs_Plane: Quad.SetValue(ThePSurfaceTool::Plane(Surf2)); break; case GeomAbs_Cylinder: Quad.SetValue(ThePSurfaceTool::Cylinder(Surf2)); break; case GeomAbs_Sphere: Quad.SetValue(ThePSurfaceTool::Sphere(Surf2)); break; case GeomAbs_Cone: Quad.SetValue(ThePSurfaceTool::Cone(Surf2)); break; default: break; }//switch (typeS2) } break; }//switch (typeS1) Perform(Quad, (SecondIsImplicit? Surf1: Surf2), theline, ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax, !SecondIsImplicit); return; } // Here, isQuadric == FALSE. // Prepare DS. prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax); // Non-analytical case: Param-Param perform. ApproxInt_ThePrmPrmSvSurfaces myPrmPrmSvSurfaces(Surf1,Surf2); Standard_Integer nbpntbez = indicemax-indicemin; if(nbpntbez < aMinNbPointsForApprox) { myData.myBezierApprox = Standard_False; } else { myData.myBezierApprox = Standard_True; } // Fill data structure. fillData(theline); const Standard_Boolean cut = myData.myBezierApprox; const Standard_Address ptrsvsurf = &myPrmPrmSvSurfaces; // Build knots. buildKnots(theline, ptrsvsurf); myComputeLine.Init ( myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, cut, myData.parametrization); myComputeLineBezier.Init( myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, cut, myData.parametrization); buildCurve(theline, ptrsvsurf); } //======================================================================= //function : Perform //purpose : Analytic-Param perform. //======================================================================= void ApproxInt_Approx::Perform(const TheISurface& ISurf, const ThePSurface& PSurf, const Handle(TheWLine)& theline, const Standard_Boolean ApproxXYZ, const Standard_Boolean ApproxU1V1, const Standard_Boolean ApproxU2V2, const Standard_Integer indicemin, const Standard_Integer indicemax, const Standard_Boolean isTheQuadFirst) { // Prepare DS. prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax); // Non-analytical case: Analytic-Param perform. ApproxInt_TheImpPrmSvSurfaces myImpPrmSvSurfaces = isTheQuadFirst? ApproxInt_TheImpPrmSvSurfaces(ISurf, PSurf): ApproxInt_TheImpPrmSvSurfaces(PSurf, ISurf); const Standard_Integer nbpntbez = indicemax-indicemin; if(nbpntbez < aMinNbPointsForApprox) { myData.myBezierApprox = Standard_False; } else { myData.myBezierApprox = Standard_True; } const Standard_Boolean cut = myData.myBezierApprox; const Standard_Address ptrsvsurf = &myImpPrmSvSurfaces; // Fill data structure. fillData(theline); // Build knots. buildKnots(theline, ptrsvsurf); myComputeLine.Init ( myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, cut, myData.parametrization); myComputeLineBezier.Init( myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, cut, myData.parametrization); buildCurve(theline, ptrsvsurf); } //======================================================================= //function : SetParameters //purpose : //======================================================================= void ApproxInt_Approx::SetParameters( const Standard_Real Tol3d, const Standard_Real Tol2d, const Standard_Integer DegMin, const Standard_Integer DegMax, const Standard_Integer NbIterMax, const Standard_Integer NbPntMax, const Standard_Boolean ApproxWithTangency, const Approx_ParametrizationType Parametrization) { myData.myNbPntMax = NbPntMax; myWithTangency = ApproxWithTangency; myTol3d = Tol3d/RatioTol; myTol2d = Tol2d/RatioTol; myDegMin = DegMin; myDegMax = DegMax; myNbIterMax = NbIterMax; myComputeLine.Init ( myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, Parametrization); myComputeLineBezier.Init( myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, Parametrization); if(!ApproxWithTangency) { myComputeLine.SetConstraints(AppParCurves_PassPoint,AppParCurves_PassPoint); myComputeLineBezier.SetConstraints(AppParCurves_PassPoint,AppParCurves_PassPoint); } myData.myBezierApprox = Standard_True; } //======================================================================= //function : NbMultiCurves //purpose : //======================================================================= Standard_Integer ApproxInt_Approx::NbMultiCurves() const { return 1; } //======================================================================= //function : UpdateTolReached //purpose : //======================================================================= void ApproxInt_Approx::UpdateTolReached() { if (myData.myBezierApprox) { const Standard_Integer NbCurves = myComputeLineBezier.NbMultiCurves() ; for (Standard_Integer ICur = 1 ; ICur <= NbCurves ; ICur++) { Standard_Real Tol3D, Tol2D ; myComputeLineBezier.Error (ICur, Tol3D, Tol2D) ; myTolReached3d = Max(myTolReached3d, Tol3D); myTolReached2d = Max(myTolReached2d, Tol2D); } } else { myComputeLine.Error (myTolReached3d, myTolReached2d); } } //======================================================================= //function : TolReached3d //purpose : //======================================================================= Standard_Real ApproxInt_Approx::TolReached3d() const { return myTolReached3d * RatioTol; } //======================================================================= //function : TolReached2d //purpose : //======================================================================= Standard_Real ApproxInt_Approx::TolReached2d() const { return myTolReached2d * RatioTol; } //======================================================================= //function : IsDone //purpose : //======================================================================= Standard_Boolean ApproxInt_Approx::IsDone() const { if(myData.myBezierApprox) { return(myComputeLineBezier.NbMultiCurves() > 0); } else { return(myComputeLine.IsToleranceReached()); } } //======================================================================= //function : Value //purpose : //======================================================================= const AppParCurves_MultiBSpCurve& ApproxInt_Approx::Value(const Standard_Integer ) const { if(myData.myBezierApprox) { return(myBezToBSpl.Value()); } else { return(myComputeLine.Value()); } } //======================================================================= //function : fillData //purpose : Fill ApproxInt data structure. //======================================================================= void ApproxInt_Approx::fillData(const Handle(TheWLine)& theline) { if(myData.ApproxXYZ) ComputeTrsf3d(theline, myData.Xo, myData.Yo, myData.Zo); else myData.Xo = myData.Yo = myData.Zo = 0.0; if(myData.ApproxU1V1) ComputeTrsf2d(theline, Standard_True, myData.U1o, myData.V1o); else myData.U1o = myData.V1o = 0.0; if(myData.ApproxU2V2) ComputeTrsf2d(theline, Standard_False, myData.U2o, myData.V2o); else myData.U2o = myData.V2o = 0.0; } //======================================================================= //function : prepareDS //purpose : //======================================================================= void ApproxInt_Approx::prepareDS(const Standard_Boolean theApproxXYZ, const Standard_Boolean theApproxU1V1, const Standard_Boolean theApproxU2V2, const Standard_Integer theIndicemin, const Standard_Integer theIndicemax) { myTolReached3d = myTolReached2d = 0.0; myData.ApproxU1V1 = theApproxU1V1; myData.ApproxU2V2 = theApproxU2V2; myData.ApproxXYZ = theApproxXYZ; myData.indicemin = theIndicemin; myData.indicemax = theIndicemax; myData.parametrization = myComputeLineBezier.Parametrization(); } //======================================================================= //function : buildKnots //purpose : //======================================================================= void ApproxInt_Approx::buildKnots(const Handle(TheWLine)& theline, const Standard_Address thePtrSVSurf) { myKnots.Clear(); if(!myData.myBezierApprox) { myKnots.Append(myData.indicemin); myKnots.Append(myData.indicemax); return; } const ApproxInt_TheMultiLine aTestLine( theline, thePtrSVSurf, ((myData.ApproxXYZ)? 1 : 0), ((myData.ApproxU1V1)? 1: 0) + ((myData.ApproxU2V2)? 1: 0), myData.Xo, myData.Yo, myData.Zo, myData.U1o, myData.V1o, myData.U2o, myData.V2o, myData.ApproxU1V1, myData.indicemin, myData.indicemax); const Standard_Integer nbp3d = aTestLine.NbP3d(), nbp2d = aTestLine.NbP2d(); TColgp_Array1OfPnt aTabPnt3d(1, Max(1, nbp3d)); TColgp_Array1OfPnt2d aTabPnt2d(1, Max(1, nbp2d)); TColgp_Array1OfPnt aPntXYZ(myData.indicemin, myData.indicemax); TColgp_Array1OfPnt2d aPntU1V1(myData.indicemin, myData.indicemax); TColgp_Array1OfPnt2d aPntU2V2(myData.indicemin, myData.indicemax); for(Standard_Integer i = myData.indicemin; i <= myData.indicemax; ++i) { if (nbp3d != 0 && nbp2d != 0) aTestLine.Value(i, aTabPnt3d, aTabPnt2d); else if (nbp2d != 0) aTestLine.Value(i, aTabPnt2d); else if (nbp3d != 0) aTestLine.Value(i, aTabPnt3d); // if(nbp3d > 0) { aPntXYZ(i) = aTabPnt3d(1); } if(nbp2d > 1) { aPntU1V1(i) = aTabPnt2d(1); aPntU2V2(i) = aTabPnt2d(2); } else if(nbp2d > 0) { if(myData.ApproxU1V1) { aPntU1V1(i) = aTabPnt2d(1); } else { aPntU2V2(i) = aTabPnt2d(1); } } } Standard_Integer aMinNbPnts = myData.myNbPntMax; // Expected parametrization. math_Vector aPars(myData.indicemin, myData.indicemax); Parameters(aTestLine, myData.indicemin, myData.indicemax, myData.parametrization, aPars); ApproxInt_KnotTools::BuildKnots(aPntXYZ, aPntU1V1, aPntU2V2, aPars, myData.ApproxXYZ, myData.ApproxU1V1, myData.ApproxU2V2, aMinNbPnts, myKnots); } //======================================================================= //function : buildCurve //purpose : //======================================================================= void ApproxInt_Approx::buildCurve(const Handle(TheWLine)& theline, const Standard_Address thePtrSVSurf) { if(myData.myBezierApprox) { myBezToBSpl.Reset(); } Standard_Integer kind = myKnots.Lower(); Standard_Integer imin = 0, imax = 0; Standard_Boolean OtherInter = Standard_False; do { // Base cycle: iterate over knots. imin = myKnots(kind); imax = myKnots(kind+1); ApproxInt_TheMultiLine myMultiLine(theline, thePtrSVSurf, ((myData.ApproxXYZ)? 1 : 0), ((myData.ApproxU1V1)? 1: 0) + ((myData.ApproxU2V2)? 1: 0), myData.Xo, myData.Yo, myData.Zo, myData.U1o, myData.V1o, myData.U2o, myData.V2o, myData.ApproxU1V1, imin, imax); if(myData.myBezierApprox) { myComputeLineBezier.Perform(myMultiLine); if (myComputeLineBezier.NbMultiCurves() == 0) return; } else { myComputeLine.Perform(myMultiLine); } UpdateTolReached(); Standard_Integer indice3d = 1, indice2d1 = 2, indice2d2 = 3; if(!myData.ApproxXYZ) { indice2d1--; indice2d2--; } if(!myData.ApproxU1V1) { indice2d2--; } if(myData.ApproxXYZ) { if(myData.myBezierApprox) { for(Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves() ; nbmc>=1; nbmc--) { myComputeLineBezier.ChangeValue(nbmc).Transform(indice3d, -myData.Xo, 1.0, -myData.Yo, 1.0, -myData.Zo, 1.0); } } else { myComputeLine.ChangeValue().Transform(indice3d, -myData.Xo, 1.0, -myData.Yo, 1.0, -myData.Zo, 1.0); } } if(myData.ApproxU1V1) { if(myData.myBezierApprox) { for(Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves() ; nbmc>=1; nbmc--) { myComputeLineBezier.ChangeValue(nbmc).Transform2d(indice2d1, -myData.U1o, 1.0, -myData.V1o, 1.0); } } else { myComputeLine.ChangeValue().Transform2d(indice2d1, -myData.U1o, 1.0, -myData.V1o, 1.0); } } if(myData.ApproxU2V2) { if(myData.myBezierApprox) { for(Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves() ; nbmc>=1; nbmc--) { myComputeLineBezier.ChangeValue(nbmc).Transform2d(indice2d2, -myData.U2o, 1.0, -myData.V2o, 1.0); } } else { myComputeLine.ChangeValue().Transform2d(indice2d2, -myData.U2o, 1.0, -myData.V2o, 1.0); } } OtherInter = Standard_False; if(myData.myBezierApprox) { for(Standard_Integer nbmc = 1; nbmc <= myComputeLineBezier.NbMultiCurves(); nbmc++) { myBezToBSpl.Append(myComputeLineBezier.Value(nbmc)); } kind++; if(kind < myKnots.Upper()) { OtherInter = Standard_True; } } } while(OtherInter); if(myData.myBezierApprox) { myBezToBSpl.Perform(); } }