// 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. // modified by Edward AGAPOV (eap) Tue Apr 2 2002 (occ265) // -- stop cutting an interval to approximate if next decisions // -- get worse on and on #include #include #include #include #include #include const static Standard_Integer MAXSEGM = 1000; //======================================================================= //function : Approx_ComputeCLine //purpose : The MultiLine will be approximated until tolerances // will be reached. // The approximation will be done from degreemin to degreemax // with a cutting if the corresponding boolean is True. //======================================================================= Approx_ComputeCLine::Approx_ComputeCLine (const MultiLine& Line, const Standard_Integer degreemin, const Standard_Integer degreemax, const Standard_Real Tolerance3d, const Standard_Real Tolerance2d, const Standard_Boolean cutting, const AppParCurves_Constraint FirstC, const AppParCurves_Constraint LastC) { mydegremin = degreemin; mydegremax = degreemax; mytol3d = Tolerance3d; mytol2d = Tolerance2d; mycut = cutting; myfirstC = FirstC; mylastC = LastC; myMaxSegments = MAXSEGM; myInvOrder = Standard_True; alldone = Standard_False; Perform(Line); } //======================================================================= //function : Approx_ComputeCLine //purpose : Initializes the fields of the algorithm. //======================================================================= Approx_ComputeCLine::Approx_ComputeCLine (const Standard_Integer degreemin, const Standard_Integer degreemax, const Standard_Real Tolerance3d, const Standard_Real Tolerance2d, const Standard_Boolean cutting, const AppParCurves_Constraint FirstC, const AppParCurves_Constraint LastC) { alldone = Standard_False; mydegremin = degreemin; mydegremax = degreemax; mytol3d = Tolerance3d; mytol2d = Tolerance2d; mycut = cutting; myfirstC = FirstC; mylastC = LastC; myMaxSegments = MAXSEGM; myInvOrder = Standard_True; } //======================================================================= //function : Perform //purpose : runs the algorithm after having initialized the fields. //======================================================================= void Approx_ComputeCLine::Perform(const MultiLine& Line) { Standard_Real UFirst, ULast; Standard_Boolean Finish = Standard_False, begin = Standard_True, Ok = Standard_False; Standard_Real thetol3d = Precision::Confusion(), thetol2d = Precision::Confusion(); UFirst = Line.FirstParameter(); ULast = Line.LastParameter(); Standard_Real TolU = Max((ULast - UFirst)*1.e-03, Precision::Confusion()); Standard_Real myfirstU = UFirst; Standard_Real mylastU = ULast; Standard_Integer aMaxSegments = 0; Standard_Integer aMaxSegments1 = myMaxSegments - 1; Standard_Integer aNbCut = 0, aNbImp = 0, aNbComp = 5; if (!mycut) { alldone = Compute(Line, UFirst, ULast, thetol3d, thetol2d); if (!alldone) { tolreached = Standard_False; myfirstparam.Append(UFirst); mylastparam.Append(ULast); myMultiCurves.Append(TheMultiCurve); Tolers3d.Append(currenttol3d); Tolers2d.Append(currenttol2d); } } else { // previous decision to be taken if we get worse with next cut (eap) AppParCurves_MultiCurve KeptMultiCurve; Standard_Real KeptUfirst = 0., KeptUlast = 0., KeptT3d = RealLast(), KeptT2d = 0.; while (!Finish) { // Gestion du decoupage de la multiline pour approximer: if (!begin) { if (Ok) { // Calcul de la partie a approximer. myfirstU = mylastU; mylastU = ULast; aNbCut = 0; aNbImp = 0; if (Abs(ULast - myfirstU) <= RealEpsilon() || aMaxSegments >= myMaxSegments) { Finish = Standard_True; alldone = Standard_True; return; } KeptT3d = RealLast(); KeptT2d = 0; KeptUfirst = myfirstU; KeptUlast = mylastU; } else { // keep best decison if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d)) { KeptMultiCurve = TheMultiCurve; KeptUfirst = myfirstU; KeptUlast = mylastU; KeptT3d = thetol3d; KeptT2d = thetol2d; aNbImp++; } // cut an interval mylastU = (myfirstU + mylastU) / 2; aNbCut++; } } // Calcul des parametres sur ce nouvel intervalle. Ok = Compute(Line, myfirstU, mylastU, thetol3d, thetol2d); if (Ok) { aMaxSegments++; } //cout << myfirstU << " - " << mylastU << " tol : " << thetol3d << " " << thetol2d << endl; Standard_Boolean aStopCutting = Standard_False; if (aNbCut >= aNbComp) { if (aNbCut > aNbImp) { aStopCutting = Standard_True; } } // is new decision better? if (!Ok && (Abs(myfirstU - mylastU) <= TolU || aMaxSegments >= aMaxSegments1 || aStopCutting )) { Ok = Standard_True; // stop interval cutting, approx the rest part if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d)) { KeptMultiCurve = TheMultiCurve; KeptUfirst = myfirstU; KeptUlast = mylastU; KeptT3d = thetol3d; KeptT2d = thetol2d; } mylastU = KeptUlast; tolreached = Standard_False; // helas myMultiCurves.Append(KeptMultiCurve); aMaxSegments++; Tolers3d.Append(KeptT3d); Tolers2d.Append(KeptT2d); myfirstparam.Append(KeptUfirst); mylastparam.Append(KeptUlast); } begin = Standard_False; } // while (!Finish) } } //======================================================================= //function : NbMultiCurves //purpose : Returns the number of MultiCurve doing the approximation // of the MultiLine. //======================================================================= Standard_Integer Approx_ComputeCLine::NbMultiCurves()const { return myMultiCurves.Length(); } //======================================================================= //function : Value //purpose : returns the approximation MultiCurve of range . //======================================================================= AppParCurves_MultiCurve Approx_ComputeCLine::Value(const Standard_Integer Index) const { return myMultiCurves.Value(Index); } //======================================================================= //function : Compute //purpose : is internally used by the algorithms. //======================================================================= Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line, const Standard_Real Ufirst, const Standard_Real Ulast, Standard_Real& TheTol3d, Standard_Real& TheTol2d) { const Standard_Integer NbPointsMax = 24; const Standard_Real aMinRatio = 0.05; const Standard_Integer aMaxDeg = 8; // Standard_Integer deg, NbPoints; Standard_Boolean mydone; Standard_Real Fv; AppParCurves_MultiCurve aPrevCurve; Standard_Real aPrevTol3d = RealLast(), aPrevTol2d = RealLast(); Standard_Boolean aPrevIsOk = Standard_False; Standard_Boolean anInvOrder = myInvOrder; if (anInvOrder && mydegremax > aMaxDeg) { if ((Ulast - Ufirst) / (Line.LastParameter() - Line.FirstParameter()) < aMinRatio) { anInvOrder = Standard_False; } } if (anInvOrder) { for (deg = mydegremax; deg >= mydegremin; deg--) { NbPoints = Min(2 * deg + 1, NbPointsMax); AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints); mydone = LSquare.IsDone(); if (mydone) { LSquare.Error(Fv, TheTol3d, TheTol2d); if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) { if (deg == mydegremin) { // Stockage de la multicurve approximee. tolreached = Standard_True; myMultiCurves.Append(LSquare.Value()); myfirstparam.Append(Ufirst); mylastparam.Append(Ulast); Tolers3d.Append(TheTol3d); Tolers2d.Append(TheTol2d); return Standard_True; } aPrevTol3d = TheTol3d; aPrevTol2d = TheTol2d; aPrevCurve = LSquare.Value(); aPrevIsOk = Standard_True; continue; } else if (aPrevIsOk) { // Stockage de la multicurve approximee. tolreached = Standard_True; TheTol3d = aPrevTol3d; TheTol2d = aPrevTol2d; myMultiCurves.Append(aPrevCurve); myfirstparam.Append(Ufirst); mylastparam.Append(Ulast); Tolers3d.Append(aPrevTol3d); Tolers2d.Append(aPrevTol2d); return Standard_True; } } else if (aPrevIsOk) { // Stockage de la multicurve approximee. tolreached = Standard_True; TheTol3d = aPrevTol3d; TheTol2d = aPrevTol2d; myMultiCurves.Append(aPrevCurve); myfirstparam.Append(Ufirst); mylastparam.Append(Ulast); Tolers3d.Append(aPrevTol3d); Tolers2d.Append(aPrevTol2d); return Standard_True; } if (!aPrevIsOk && deg == mydegremax) { TheMultiCurve = LSquare.Value(); currenttol3d = TheTol3d; currenttol2d = TheTol2d; aPrevTol3d = TheTol3d; aPrevTol2d = TheTol2d; aPrevCurve = TheMultiCurve; break; } } } else { for (deg = mydegremin; deg <= mydegremax; deg++) { NbPoints = Min(2 * deg + 1, NbPointsMax); AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints); mydone = LSquare.IsDone(); if (mydone) { LSquare.Error(Fv, TheTol3d, TheTol2d); if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) { // Stockage de la multicurve approximee. tolreached = Standard_True; myMultiCurves.Append(LSquare.Value()); myfirstparam.Append(Ufirst); mylastparam.Append(Ulast); Tolers3d.Append(TheTol3d); Tolers2d.Append(TheTol2d); return Standard_True; } } if (deg == mydegremax) { TheMultiCurve = LSquare.Value(); currenttol3d = TheTol3d; currenttol2d = TheTol2d; } } } return Standard_False; } //======================================================================= //function : Parameters //purpose : returns the first and last parameters of the // MultiCurve. //======================================================================= void Approx_ComputeCLine::Parameters(const Standard_Integer Index, Standard_Real& firstpar, Standard_Real& lastpar) const { firstpar = myfirstparam.Value(Index); lastpar = mylastparam.Value(Index); } //======================================================================= //function : SetDegrees //purpose : changes the degrees of the approximation. //======================================================================= void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin, const Standard_Integer degreemax) { mydegremin = degreemin; mydegremax = degreemax; } //======================================================================= //function : SetTolerances //purpose : Changes the tolerances of the approximation. //======================================================================= void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d, const Standard_Real Tolerance2d) { mytol3d = Tolerance3d; mytol2d = Tolerance2d; } //======================================================================= //function : SetConstraints //purpose : Changes the constraints of the approximation. //======================================================================= void Approx_ComputeCLine::SetConstraints(const AppParCurves_Constraint FirstC, const AppParCurves_Constraint LastC) { myfirstC = FirstC; mylastC = LastC; } //======================================================================= //function : SetMaxSegments //purpose : Changes the max number of segments, which is allowed for cutting. //======================================================================= void Approx_ComputeCLine::SetMaxSegments(const Standard_Integer theMaxSegments) { myMaxSegments = theMaxSegments; } //======================================================================= //function : SetInvOrder //purpose : //======================================================================= void Approx_ComputeCLine::SetInvOrder(const Standard_Boolean theInvOrder) { myInvOrder = theInvOrder; } //======================================================================= //function : IsAllApproximated //purpose : returns False if at a moment of the approximation, // the status NoApproximation has been sent by the user // when more points were needed. //======================================================================= Standard_Boolean Approx_ComputeCLine::IsAllApproximated() const { return alldone; } //======================================================================= //function : IsToleranceReached //purpose : returns False if the status NoPointsAdded has been sent. //======================================================================= Standard_Boolean Approx_ComputeCLine::IsToleranceReached() const { return tolreached; } //======================================================================= //function : Error //purpose : returns the tolerances 2d and 3d of the MultiCurve. //======================================================================= void Approx_ComputeCLine::Error(const Standard_Integer Index, Standard_Real& tol3d, Standard_Real& tol2d) const { tol3d = Tolers3d.Value(Index); tol2d = Tolers2d.Value(Index); }