Warning, /include/opencascade/Approx_ComputeCLine.gxx is written in an unsupported language. File is not indexed.
0001 // Copyright (c) 1995-1999 Matra Datavision
0002 // Copyright (c) 1999-2014 OPEN CASCADE SAS
0003 //
0004 // This file is part of Open CASCADE Technology software library.
0005 //
0006 // This library is free software; you can redistribute it and/or modify it under
0007 // the terms of the GNU Lesser General Public License version 2.1 as published
0008 // by the Free Software Foundation, with special exception defined in the file
0009 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0010 // distribution for complete text of the license and disclaimer of any warranty.
0011 //
0012 // Alternatively, this file may be used under the terms of Open CASCADE
0013 // commercial license or contractual agreement.
0014
0015 // modified by Edward AGAPOV (eap) Tue Apr 2 2002 (occ265)
0016 // -- stop cutting an interval to approximate if next decisions
0017 // -- get worse on and on
0018
0019
0020
0021 #include <Approx_ParametrizationType.hxx>
0022 #include <AppCont_LeastSquare.hxx>
0023 #include <TColStd_Array1OfReal.hxx>
0024 #include <AppParCurves_Constraint.hxx>
0025 #include <Approx_Status.hxx>
0026 #include <Precision.hxx>
0027
0028 const static Standard_Integer MAXSEGM = 1000;
0029
0030 //=======================================================================
0031 //function : Approx_ComputeCLine
0032 //purpose : The MultiLine <Line> will be approximated until tolerances
0033 // will be reached.
0034 // The approximation will be done from degreemin to degreemax
0035 // with a cutting if the corresponding boolean is True.
0036 //=======================================================================
0037
0038 Approx_ComputeCLine::Approx_ComputeCLine
0039 (const MultiLine& Line,
0040 const Standard_Integer degreemin,
0041 const Standard_Integer degreemax,
0042 const Standard_Real Tolerance3d,
0043 const Standard_Real Tolerance2d,
0044 const Standard_Boolean cutting,
0045 const AppParCurves_Constraint FirstC,
0046 const AppParCurves_Constraint LastC)
0047 {
0048 mydegremin = degreemin;
0049 mydegremax = degreemax;
0050 mytol3d = Tolerance3d;
0051 mytol2d = Tolerance2d;
0052 mycut = cutting;
0053 myfirstC = FirstC;
0054 mylastC = LastC;
0055 myMaxSegments = MAXSEGM;
0056 myInvOrder = Standard_True;
0057 myHangChecking = Standard_True;
0058 alldone = Standard_False;
0059 tolreached = Standard_False;
0060 currenttol3d = 0.0;
0061 currenttol2d = 0.0;
0062 Perform(Line);
0063 }
0064
0065 //=======================================================================
0066 //function : Approx_ComputeCLine
0067 //purpose : Initializes the fields of the algorithm.
0068 //=======================================================================
0069
0070 Approx_ComputeCLine::Approx_ComputeCLine
0071 (const Standard_Integer degreemin,
0072 const Standard_Integer degreemax,
0073 const Standard_Real Tolerance3d,
0074 const Standard_Real Tolerance2d,
0075 const Standard_Boolean cutting,
0076 const AppParCurves_Constraint FirstC,
0077 const AppParCurves_Constraint LastC)
0078 {
0079 alldone = Standard_False;
0080 mydegremin = degreemin;
0081 mydegremax = degreemax;
0082 mytol3d = Tolerance3d;
0083 mytol2d = Tolerance2d;
0084 mycut = cutting;
0085 myfirstC = FirstC;
0086 mylastC = LastC;
0087 myMaxSegments = MAXSEGM;
0088 myInvOrder = Standard_True;
0089 myHangChecking = Standard_True;
0090 tolreached = Standard_False;
0091 currenttol3d = 0.0;
0092 currenttol2d = 0.0;
0093 }
0094
0095 //=======================================================================
0096 //function : Perform
0097 //purpose : runs the algorithm after having initialized the fields.
0098 //=======================================================================
0099
0100 void Approx_ComputeCLine::Perform(const MultiLine& Line)
0101 {
0102 Standard_Real UFirst, ULast;
0103 Standard_Boolean Finish = Standard_False,
0104 begin = Standard_True, Ok = Standard_False;
0105 Standard_Real thetol3d = Precision::Confusion(), thetol2d = Precision::Confusion();
0106 UFirst = Line.FirstParameter();
0107 ULast = Line.LastParameter();
0108 Standard_Real TolU = 0.;
0109 if (myHangChecking)
0110 {
0111 TolU = Max((ULast - UFirst)*1.e-03, Precision::Confusion());
0112 }
0113 else
0114 {
0115 TolU = Max((ULast - UFirst)*1.e-05, Precision::PApproximation());
0116 }
0117 Standard_Real myfirstU = UFirst;
0118 Standard_Real mylastU = ULast;
0119 Standard_Integer aMaxSegments = 0;
0120 Standard_Integer aMaxSegments1 = myMaxSegments - 1;
0121 Standard_Integer aNbCut = 0, aNbImp = 0, aNbComp = 10;
0122
0123 if (!mycut)
0124 {
0125 alldone = Compute(Line, UFirst, ULast, thetol3d, thetol2d);
0126 if (!alldone)
0127 {
0128 tolreached = Standard_False;
0129 myfirstparam.Append(UFirst);
0130 mylastparam.Append(ULast);
0131 myMultiCurves.Append(TheMultiCurve);
0132 Tolers3d.Append(currenttol3d);
0133 Tolers2d.Append(currenttol2d);
0134 }
0135 }
0136 else
0137 {
0138
0139 // previous decision to be taken if we get worse with next cut (eap)
0140 AppParCurves_MultiCurve KeptMultiCurve;
0141 Standard_Real KeptUfirst = 0., KeptUlast = 0., KeptT3d = RealLast(), KeptT2d = 0.;
0142
0143 while (!Finish)
0144 {
0145
0146 // Gestion du decoupage de la multiline pour approximer:
0147 if (!begin)
0148 {
0149 if (Ok)
0150 {
0151 // Calcul de la partie a approximer.
0152 myfirstU = mylastU;
0153 mylastU = ULast;
0154 aNbCut = 0;
0155 aNbImp = 0;
0156 if (Abs(ULast - myfirstU) <= RealEpsilon()
0157 || aMaxSegments >= myMaxSegments)
0158 {
0159 Finish = Standard_True;
0160 alldone = Standard_True;
0161 return;
0162 }
0163 KeptT3d = RealLast(); KeptT2d = 0;
0164 KeptUfirst = myfirstU;
0165 KeptUlast = mylastU;
0166 }
0167 else
0168 {
0169 // keep best decision
0170 if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
0171 {
0172 KeptMultiCurve = TheMultiCurve;
0173 KeptUfirst = myfirstU;
0174 KeptUlast = mylastU;
0175 KeptT3d = thetol3d;
0176 KeptT2d = thetol2d;
0177 aNbImp++;
0178 }
0179
0180 // cut an interval
0181 mylastU = (myfirstU + mylastU) / 2;
0182 aNbCut++;
0183 }
0184 }
0185
0186 // Calcul des parametres sur ce nouvel intervalle.
0187 Ok = Compute(Line, myfirstU, mylastU, thetol3d, thetol2d);
0188 if (Ok)
0189 {
0190 aMaxSegments++;
0191 }
0192
0193 //cout << myfirstU << " - " << mylastU << " tol : " << thetol3d << " " << thetol2d << endl;
0194 Standard_Boolean aStopCutting = Standard_False;
0195 if (myHangChecking && aNbCut >= aNbComp)
0196 {
0197 if (aNbCut > aNbImp + 1)
0198 {
0199 aStopCutting = Standard_True;
0200 }
0201 aNbCut = 0;
0202 aNbImp = 0;
0203 }
0204 // is new decision better?
0205 if (!Ok && (Abs(myfirstU - mylastU) <= TolU || aMaxSegments >= aMaxSegments1 || aStopCutting ))
0206 {
0207 Ok = Standard_True; // stop interval cutting, approx the rest part
0208
0209 if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
0210 {
0211 KeptMultiCurve = TheMultiCurve;
0212 KeptUfirst = myfirstU;
0213 KeptUlast = mylastU;
0214 KeptT3d = thetol3d;
0215 KeptT2d = thetol2d;
0216 }
0217
0218 mylastU = KeptUlast;
0219
0220 tolreached = Standard_False; // helas
0221 myMultiCurves.Append(KeptMultiCurve);
0222 aMaxSegments++;
0223 Tolers3d.Append(KeptT3d);
0224 Tolers2d.Append(KeptT2d);
0225 myfirstparam.Append(KeptUfirst);
0226 mylastparam.Append(KeptUlast);
0227 }
0228
0229 begin = Standard_False;
0230 } // while (!Finish)
0231 }
0232 }
0233
0234 //=======================================================================
0235 //function : NbMultiCurves
0236 //purpose : Returns the number of MultiCurve doing the approximation
0237 // of the MultiLine.
0238 //=======================================================================
0239
0240 Standard_Integer Approx_ComputeCLine::NbMultiCurves()const
0241 {
0242 return myMultiCurves.Length();
0243 }
0244
0245 //=======================================================================
0246 //function : Value
0247 //purpose : returns the approximation MultiCurve of range <Index>.
0248 //=======================================================================
0249
0250 AppParCurves_MultiCurve Approx_ComputeCLine::Value(const Standard_Integer Index)
0251 const
0252 {
0253 return myMultiCurves.Value(Index);
0254 }
0255
0256 //=======================================================================
0257 //function : Compute
0258 //purpose : is internally used by the algorithms.
0259 //=======================================================================
0260
0261 Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line,
0262 const Standard_Real Ufirst,
0263 const Standard_Real Ulast,
0264 Standard_Real& TheTol3d,
0265 Standard_Real& TheTol2d)
0266 {
0267
0268
0269 const Standard_Integer NbPointsMax = 24;
0270 const Standard_Real aMinRatio = 0.05;
0271 const Standard_Integer aMaxDeg = 8;
0272 //
0273 Standard_Integer deg, NbPoints;
0274 Standard_Boolean mydone;
0275 Standard_Real Fv;
0276
0277 AppParCurves_MultiCurve aPrevCurve;
0278 Standard_Real aPrevTol3d = RealLast(), aPrevTol2d = RealLast();
0279 Standard_Boolean aPrevIsOk = Standard_False;
0280 Standard_Boolean anInvOrder = myInvOrder;
0281 if (anInvOrder && mydegremax > aMaxDeg)
0282 {
0283 if ((Ulast - Ufirst) / (Line.LastParameter() - Line.FirstParameter()) < aMinRatio)
0284 {
0285 anInvOrder = Standard_False;
0286 }
0287 }
0288 if (anInvOrder)
0289 {
0290 for (deg = mydegremax; deg >= mydegremin; deg--) {
0291 NbPoints = Min(2 * deg + 1, NbPointsMax);
0292 AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
0293 mydone = LSquare.IsDone();
0294 if (mydone)
0295 {
0296 LSquare.Error(Fv, TheTol3d, TheTol2d);
0297 if (TheTol3d <= mytol3d && TheTol2d <= mytol2d)
0298 {
0299 if (deg == mydegremin)
0300 {
0301 // Stockage de la multicurve approximee.
0302 tolreached = Standard_True;
0303 myMultiCurves.Append(LSquare.Value());
0304 myfirstparam.Append(Ufirst);
0305 mylastparam.Append(Ulast);
0306 Tolers3d.Append(TheTol3d);
0307 Tolers2d.Append(TheTol2d);
0308 return Standard_True;
0309 }
0310 aPrevTol3d = TheTol3d;
0311 aPrevTol2d = TheTol2d;
0312 aPrevCurve = LSquare.Value();
0313 aPrevIsOk = Standard_True;
0314 continue;
0315 }
0316 else if (aPrevIsOk)
0317 {
0318 // Stockage de la multicurve approximee.
0319 tolreached = Standard_True;
0320 TheTol3d = aPrevTol3d;
0321 TheTol2d = aPrevTol2d;
0322 myMultiCurves.Append(aPrevCurve);
0323 myfirstparam.Append(Ufirst);
0324 mylastparam.Append(Ulast);
0325 Tolers3d.Append(aPrevTol3d);
0326 Tolers2d.Append(aPrevTol2d);
0327 return Standard_True;
0328 }
0329 }
0330 else if (aPrevIsOk)
0331 {
0332 // Stockage de la multicurve approximee.
0333 tolreached = Standard_True;
0334 TheTol3d = aPrevTol3d;
0335 TheTol2d = aPrevTol2d;
0336 myMultiCurves.Append(aPrevCurve);
0337 myfirstparam.Append(Ufirst);
0338 mylastparam.Append(Ulast);
0339 Tolers3d.Append(aPrevTol3d);
0340 Tolers2d.Append(aPrevTol2d);
0341 return Standard_True;
0342 }
0343 if (!aPrevIsOk && deg == mydegremax)
0344 {
0345 TheMultiCurve = LSquare.Value();
0346 currenttol3d = TheTol3d;
0347 currenttol2d = TheTol2d;
0348 aPrevTol3d = TheTol3d;
0349 aPrevTol2d = TheTol2d;
0350 aPrevCurve = TheMultiCurve;
0351 break;
0352 }
0353 }
0354 }
0355 else
0356 {
0357 for (deg = mydegremin; deg <= mydegremax; deg++) {
0358 NbPoints = Min(2 * deg + 1, NbPointsMax);
0359 AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
0360 mydone = LSquare.IsDone();
0361 if (mydone) {
0362 LSquare.Error(Fv, TheTol3d, TheTol2d);
0363 if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) {
0364 // Stockage de la multicurve approximee.
0365 tolreached = Standard_True;
0366 myMultiCurves.Append(LSquare.Value());
0367 myfirstparam.Append(Ufirst);
0368 mylastparam.Append(Ulast);
0369 Tolers3d.Append(TheTol3d);
0370 Tolers2d.Append(TheTol2d);
0371 return Standard_True;
0372 }
0373 }
0374 if (deg == mydegremax) {
0375 TheMultiCurve = LSquare.Value();
0376 currenttol3d = TheTol3d;
0377 currenttol2d = TheTol2d;
0378 }
0379 }
0380 }
0381 return Standard_False;
0382 }
0383
0384 //=======================================================================
0385 //function : Parameters
0386 //purpose : returns the first and last parameters of the
0387 // <Index> MultiCurve.
0388 //=======================================================================
0389
0390 void Approx_ComputeCLine::Parameters(const Standard_Integer Index,
0391 Standard_Real& firstpar,
0392 Standard_Real& lastpar) const
0393 {
0394 firstpar = myfirstparam.Value(Index);
0395 lastpar = mylastparam.Value(Index);
0396 }
0397
0398 //=======================================================================
0399 //function : SetDegrees
0400 //purpose : changes the degrees of the approximation.
0401 //=======================================================================
0402
0403 void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin,
0404 const Standard_Integer degreemax)
0405 {
0406 mydegremin = degreemin;
0407 mydegremax = degreemax;
0408 }
0409
0410 //=======================================================================
0411 //function : SetTolerances
0412 //purpose : Changes the tolerances of the approximation.
0413 //=======================================================================
0414
0415 void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d,
0416 const Standard_Real Tolerance2d)
0417 {
0418 mytol3d = Tolerance3d;
0419 mytol2d = Tolerance2d;
0420 }
0421
0422 //=======================================================================
0423 //function : SetConstraints
0424 //purpose : Changes the constraints of the approximation.
0425 //=======================================================================
0426
0427 void Approx_ComputeCLine::SetConstraints(const AppParCurves_Constraint FirstC,
0428 const AppParCurves_Constraint LastC)
0429 {
0430 myfirstC = FirstC;
0431 mylastC = LastC;
0432 }
0433
0434 //=======================================================================
0435 //function : SetMaxSegments
0436 //purpose : Changes the max number of segments, which is allowed for cutting.
0437 //=======================================================================
0438
0439 void Approx_ComputeCLine::SetMaxSegments(const Standard_Integer theMaxSegments)
0440 {
0441 myMaxSegments = theMaxSegments;
0442 }
0443
0444 //=======================================================================
0445 //function : SetInvOrder
0446 //purpose :
0447 //=======================================================================
0448 void Approx_ComputeCLine::SetInvOrder(const Standard_Boolean theInvOrder)
0449 {
0450 myInvOrder = theInvOrder;
0451 }
0452
0453 //=======================================================================
0454 //function : SetHangChecking
0455 //purpose :
0456 //=======================================================================
0457 void Approx_ComputeCLine::SetHangChecking(const Standard_Boolean theHangChecking)
0458 {
0459 myHangChecking = theHangChecking;
0460 }
0461
0462 //=======================================================================
0463 //function : IsAllApproximated
0464 //purpose : returns False if at a moment of the approximation,
0465 // the status NoApproximation has been sent by the user
0466 // when more points were needed.
0467 //=======================================================================
0468
0469 Standard_Boolean Approx_ComputeCLine::IsAllApproximated()
0470 const {
0471 return alldone;
0472 }
0473
0474 //=======================================================================
0475 //function : IsToleranceReached
0476 //purpose : returns False if the status NoPointsAdded has been sent.
0477 //=======================================================================
0478
0479 Standard_Boolean Approx_ComputeCLine::IsToleranceReached()
0480 const {
0481 return tolreached;
0482 }
0483
0484 //=======================================================================
0485 //function : Error
0486 //purpose : returns the tolerances 2d and 3d of the <Index> MultiCurve.
0487 //=======================================================================
0488
0489 void Approx_ComputeCLine::Error(const Standard_Integer Index,
0490 Standard_Real& tol3d,
0491 Standard_Real& tol2d) const
0492 {
0493 tol3d = Tolers3d.Value(Index);
0494 tol2d = Tolers2d.Value(Index);
0495 }