File indexing completed on 2026-09-13 09:16:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef _Extrema_GGExtPC_HeaderFile
0018 #define _Extrema_GGExtPC_HeaderFile
0019
0020 #include <Standard.hxx>
0021 #include <Standard_DefineAlloc.hxx>
0022
0023 #include <ElCLib.hxx>
0024 #include <GeomAbs_CurveType.hxx>
0025 #include <NCollection_Array1.hxx>
0026 #include <Precision.hxx>
0027 #include <Standard_Failure.hxx>
0028 #include <Standard_OutOfRange.hxx>
0029 #include <StdFail_NotDone.hxx>
0030 #include <NCollection_HArray1.hxx>
0031 #include <NCollection_Sequence.hxx>
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 template <typename TheCurve,
0048 typename TheCurveTool,
0049 typename TheExtPElC,
0050 typename ThePoint,
0051 typename TheVector,
0052 typename ThePOnC,
0053 typename TheSequenceOfPOnC,
0054 typename TheEPC>
0055 class Extrema_GGExtPC
0056 {
0057 public:
0058 DEFINE_STANDARD_ALLOC
0059
0060
0061 Extrema_GGExtPC()
0062 : myC(nullptr),
0063 mydone(false),
0064 mydist1(RealLast()),
0065 mydist2(RealLast()),
0066 mytolu(0.0),
0067 mytolf(0.0),
0068 mysample(17),
0069 myintuinf(Precision::Infinite()),
0070 myintusup(Precision::Infinite()),
0071 myuinf(Precision::Infinite()),
0072 myusup(Precision::Infinite()),
0073 type(GeomAbs_OtherCurve)
0074 {
0075 }
0076
0077
0078
0079
0080
0081
0082
0083
0084 Extrema_GGExtPC(const ThePoint& theP,
0085 const TheCurve& theC,
0086 const double theUinf,
0087 const double theUsup,
0088 const double theTolF = 1.0e-10)
0089 {
0090 Initialize(theC, theUinf, theUsup, theTolF);
0091 Perform(theP);
0092 }
0093
0094
0095
0096
0097
0098
0099 Extrema_GGExtPC(const ThePoint& theP, const TheCurve& theC, const double theTolF = 1.0e-10)
0100 {
0101 Initialize(theC,
0102 TheCurveTool::FirstParameter(theC),
0103 TheCurveTool::LastParameter(theC),
0104 theTolF);
0105 Perform(theP);
0106 }
0107
0108
0109
0110
0111
0112
0113 void Initialize(const TheCurve& theC,
0114 const double theUinf,
0115 const double theUsup,
0116 const double theTolF = 1.0e-10)
0117 {
0118 myC = const_cast<TheCurve*>(&theC);
0119 myintuinf = myuinf = theUinf;
0120 myintusup = myusup = theUsup;
0121 mytolf = theTolF;
0122 mytolu = TheCurveTool::Resolution(*myC, Precision::Confusion());
0123 type = TheCurveTool::GetType(theC);
0124 mydone = false;
0125 mydist1 = RealLast();
0126 mydist2 = RealLast();
0127 mysample = 17;
0128 }
0129
0130
0131
0132 void Perform(const ThePoint& theP)
0133 {
0134 mySqDist.Clear();
0135 mypoint.Clear();
0136 myismin.Clear();
0137 int i, NbExt, n;
0138 double U;
0139 mysample = 17;
0140 constexpr double t3d = Precision::Confusion();
0141
0142 if (Precision::IsInfinite(myuinf))
0143 mydist1 = RealLast();
0144 else
0145 {
0146 Pf = TheCurveTool::Value(*myC, myuinf);
0147 mydist1 = theP.SquareDistance(Pf);
0148 }
0149
0150 if (Precision::IsInfinite(myusup))
0151 mydist2 = RealLast();
0152 else
0153 {
0154 Pl = TheCurveTool::Value(*myC, myusup);
0155 mydist2 = theP.SquareDistance(Pl);
0156 }
0157
0158 TheCurve& aCurve = *myC;
0159
0160 switch (type)
0161 {
0162 case GeomAbs_Circle: {
0163 myExtPElC.Perform(theP, TheCurveTool::Circle(aCurve), t3d, myuinf, myusup);
0164 break;
0165 }
0166 case GeomAbs_Ellipse: {
0167 myExtPElC.Perform(theP, TheCurveTool::Ellipse(aCurve), t3d, myuinf, myusup);
0168 break;
0169 }
0170 case GeomAbs_Parabola: {
0171 myExtPElC.Perform(theP, TheCurveTool::Parabola(aCurve), t3d, myuinf, myusup);
0172 break;
0173 }
0174 case GeomAbs_Hyperbola: {
0175 myExtPElC.Perform(theP, TheCurveTool::Hyperbola(aCurve), t3d, myuinf, myusup);
0176 break;
0177 }
0178 case GeomAbs_Line: {
0179 myExtPElC.Perform(theP, TheCurveTool::Line(aCurve), t3d, myuinf, myusup);
0180 break;
0181 }
0182 case GeomAbs_BezierCurve: {
0183 myintuinf = myuinf;
0184 myintusup = myusup;
0185 mysample = (TheCurveTool::Bezier(aCurve))->NbPoles() * 2;
0186 myExtPC.Initialize(aCurve);
0187 IntervalPerform(theP);
0188 return;
0189 }
0190 case GeomAbs_BSplineCurve: {
0191 auto aBSpline = TheCurveTool::BSpline(aCurve);
0192 const int aFirstIdx = aBSpline->FirstUKnotIndex();
0193 const int aLastIdx = aBSpline->LastUKnotIndex();
0194 const NCollection_Array1<double>& aKnots = aBSpline->Knots();
0195
0196 double aPeriodJump = 0.0;
0197 const double aTolCoeff = (myusup - myuinf) * Precision::PConfusion();
0198 if (TheCurveTool::IsPeriodic(aCurve))
0199 {
0200 int aPeriodShift = int((myuinf - aKnots(aFirstIdx)) / TheCurveTool::Period(aCurve));
0201 if (myuinf < aKnots(aFirstIdx) - aTolCoeff)
0202 aPeriodShift--;
0203 aPeriodJump = TheCurveTool::Period(aCurve) * aPeriodShift;
0204 }
0205
0206 int anIdx;
0207 int aFirstUsedKnot = aFirstIdx, aLastUsedKnot = aLastIdx;
0208 for (anIdx = aFirstIdx; anIdx <= aLastIdx; anIdx++)
0209 {
0210 double aKnot = aKnots(anIdx) + aPeriodJump;
0211 if (myuinf >= aKnot - aTolCoeff)
0212 aFirstUsedKnot = anIdx;
0213 else
0214 break;
0215 }
0216 for (anIdx = aLastIdx; anIdx >= aFirstIdx; anIdx--)
0217 {
0218 double aKnot = aKnots(anIdx) + aPeriodJump;
0219 if (myusup <= aKnot + aTolCoeff)
0220 aLastUsedKnot = anIdx;
0221 else
0222 break;
0223 }
0224
0225 if (aFirstUsedKnot == aLastUsedKnot)
0226 {
0227 aFirstUsedKnot = aFirstIdx;
0228 aLastUsedKnot = aFirstIdx + 1;
0229 }
0230
0231 mysample = aBSpline->Degree() + 1;
0232
0233 if (mysample == 2)
0234 {
0235 ThePoint aPmin;
0236 double tmin = 0., distmin = RealLast();
0237 double aMin1 = 0., aMin2 = 0.;
0238 myExtPC.Initialize(aCurve);
0239 for (anIdx = aFirstUsedKnot; anIdx < aLastUsedKnot; anIdx++)
0240 {
0241 double aF = aKnots(anIdx) + aPeriodJump, aL = aKnots(anIdx + 1) + aPeriodJump;
0242
0243 if (anIdx == aFirstUsedKnot)
0244 aF = myuinf;
0245 else if (anIdx == aLastUsedKnot - 1)
0246 aL = myusup;
0247
0248 ThePoint aP1, aP2;
0249 TheCurveTool::D0(aCurve, aF, aP1);
0250 TheCurveTool::D0(aCurve, aL, aP2);
0251 TheVector aBase1(theP, aP1), aBase2(theP, aP2);
0252 TheVector aV(aP2, aP1);
0253 double aVal1 = aV.Dot(aBase1);
0254 double aVal2 = aV.Dot(aBase2);
0255 if (anIdx == aFirstUsedKnot)
0256 aMin1 = theP.SquareDistance(aP1);
0257 else
0258 {
0259 aMin1 = aMin2;
0260 if (distmin > aMin1)
0261 {
0262 distmin = aMin1;
0263 tmin = aF;
0264 aPmin = aP1;
0265 }
0266 }
0267 aMin2 = theP.SquareDistance(aP2);
0268 double aMinSqDist = std::min(aMin1, aMin2);
0269 double aMinDer = std::min(std::abs(aVal1), std::abs(aVal2));
0270 if (!(Precision::IsInfinite(aVal1) || Precision::IsInfinite(aVal2)))
0271 {
0272 if (aVal1 * aVal2 <= 0.0 || aMinSqDist < 100. * Precision::SquareConfusion()
0273 || 2. * aMinDer < Precision::Confusion())
0274 {
0275 myintuinf = aF;
0276 myintusup = aL;
0277 IntervalPerform(theP);
0278 }
0279 }
0280 }
0281 if (!Precision::IsInfinite(distmin))
0282 {
0283 bool isToAdd = true;
0284 NbExt = mypoint.Length();
0285 for (i = 1; i <= NbExt && isToAdd; i++)
0286 {
0287 double t = mypoint.Value(i).Parameter();
0288 isToAdd = (distmin < mySqDist(i)) && (std::abs(t - tmin) > mytolu);
0289 }
0290 if (isToAdd)
0291 {
0292 ThePOnC PC(tmin, aPmin);
0293 mySqDist.Append(distmin);
0294 myismin.Append(true);
0295 mypoint.Append(PC);
0296 }
0297 }
0298 }
0299 else
0300 {
0301 int aValIdx = 1;
0302 NCollection_Array1<double> aVal(1, (mysample) * (aLastUsedKnot - aFirstUsedKnot) + 1);
0303 NCollection_Array1<double> aParam(1, (mysample) * (aLastUsedKnot - aFirstUsedKnot) + 1);
0304 for (anIdx = aFirstUsedKnot; anIdx < aLastUsedKnot; anIdx++)
0305 {
0306 double aF = aKnots(anIdx) + aPeriodJump, aL = aKnots(anIdx + 1) + aPeriodJump;
0307
0308 if (anIdx == aFirstUsedKnot)
0309 aF = myuinf;
0310 if (anIdx == aLastUsedKnot - 1)
0311 aL = myusup;
0312
0313 double aStep = (aL - aF) / mysample;
0314 for (int aPntIdx = 0; aPntIdx < mysample; aPntIdx++)
0315 {
0316 double aCurrentParam = aF + aStep * aPntIdx;
0317 aVal(aValIdx) = TheCurveTool::Value(aCurve, aCurrentParam).SquareDistance(theP);
0318 aParam(aValIdx) = aCurrentParam;
0319 aValIdx++;
0320 }
0321 }
0322 aVal(aValIdx) = TheCurveTool::Value(aCurve, myusup).SquareDistance(theP);
0323 aParam(aValIdx) = myusup;
0324
0325 myExtPC.Initialize(aCurve);
0326
0327 for (anIdx = aVal.Lower() + 1; anIdx < aVal.Upper(); anIdx++)
0328 {
0329 if (aVal(anIdx) <= Precision::SquareConfusion())
0330 {
0331 mySqDist.Append(aVal(anIdx));
0332 myismin.Append(true);
0333 mypoint.Append(ThePOnC(aParam(anIdx), TheCurveTool::Value(aCurve, aParam(anIdx))));
0334 }
0335 if ((aVal(anIdx) >= aVal(anIdx + 1) && aVal(anIdx) >= aVal(anIdx - 1))
0336 || (aVal(anIdx) <= aVal(anIdx + 1) && aVal(anIdx) <= aVal(anIdx - 1)))
0337 {
0338 myintuinf = aParam(anIdx - 1);
0339 myintusup = aParam(anIdx + 1);
0340 IntervalPerform(theP);
0341 }
0342 }
0343
0344 if (mydist1 > Precision::SquareConfusion() && !Precision::IsPositiveInfinite(mydist1))
0345 {
0346 ThePoint aP1, aP2;
0347 TheVector aV1, aV2;
0348 TheCurveTool::D1(aCurve, aParam.Value(aParam.Lower()), aP1, aV1);
0349 TheCurveTool::D1(aCurve, aParam.Value(aParam.Lower() + 1), aP2, aV2);
0350 TheVector aBase1(theP, aP1), aBase2(theP, aP2);
0351 double aVal1 = aV1.Dot(aBase1);
0352 double aVal2 = aV2.Dot(aBase2);
0353 if (!(Precision::IsInfinite(aVal1) || Precision::IsInfinite(aVal2)))
0354 {
0355 if (aVal1 * aVal2 <= 0.0 || aBase1.Dot(aBase2) <= 0.0
0356 || 2.0 * std::abs(aVal1) < Precision::Confusion())
0357 {
0358 myintuinf = aParam(aVal.Lower());
0359 myintusup = aParam(aVal.Lower() + 1);
0360 IntervalPerform(theP);
0361 }
0362 }
0363 }
0364
0365 if (mydist2 > Precision::SquareConfusion() && !Precision::IsPositiveInfinite(mydist2))
0366 {
0367 ThePoint aP1, aP2;
0368 TheVector aV1, aV2;
0369 TheCurveTool::D1(aCurve, aParam.Value(aParam.Upper() - 1), aP1, aV1);
0370 TheCurveTool::D1(aCurve, aParam.Value(aParam.Upper()), aP2, aV2);
0371 TheVector aBase1(theP, aP1), aBase2(theP, aP2);
0372 double aVal1 = aV1.Dot(aBase1);
0373 double aVal2 = aV2.Dot(aBase2);
0374
0375 if (!(Precision::IsInfinite(aVal1) || Precision::IsInfinite(aVal2)))
0376 {
0377 if (aVal1 * aVal2 <= 0.0 || aBase1.Dot(aBase2) <= 0.0
0378 || 2.0 * std::abs(aVal2) < Precision::Confusion())
0379 {
0380 myintuinf = aParam(aVal.Upper() - 1);
0381 myintusup = aParam(aVal.Upper());
0382 IntervalPerform(theP);
0383 }
0384 }
0385 }
0386 }
0387 mydone = true;
0388 break;
0389 }
0390 default: {
0391 constexpr int aMaxSample = 17;
0392 bool IntExtIsDone = false;
0393 bool IntIsNotValid;
0394 occ::handle<NCollection_HArray1<double>> theHInter;
0395 n = TheCurveTool::NbIntervals(aCurve, GeomAbs_C2);
0396 if (n > 1)
0397 {
0398 theHInter = new NCollection_HArray1<double>(1, n + 1);
0399 TheCurveTool::Intervals(aCurve, theHInter->ChangeArray1(), GeomAbs_C2);
0400 }
0401 else
0402 {
0403 theHInter = TheCurveTool::DeflCurvIntervals(aCurve);
0404 n = theHInter->Length() - 1;
0405 }
0406 mysample = std::max(mysample / n, aMaxSample);
0407 double maxint = 0.;
0408 for (i = 1; i <= n; ++i)
0409 {
0410 double dt = theHInter->Value(i + 1) - theHInter->Value(i);
0411 if (maxint < dt)
0412 maxint = dt;
0413 }
0414 bool isPeriodic = TheCurveTool::IsPeriodic(aCurve);
0415 TheVector V1;
0416 ThePoint PP;
0417 double s1 = 0.0;
0418 double s2 = 0.0;
0419 myExtPC.Initialize(aCurve);
0420 for (i = 1; i <= n; i++)
0421 {
0422 myintuinf = theHInter->Value(i);
0423 myintusup = theHInter->Value(i + 1);
0424 mysample = std::max(RealToInt(aMaxSample * (myintusup - myintuinf) / maxint), 3);
0425
0426 double anInfToCheck = myintuinf;
0427 double aSupToCheck = myintusup;
0428
0429 if (isPeriodic)
0430 {
0431 double aPeriod = TheCurveTool::Period(aCurve);
0432 anInfToCheck = ElCLib::InPeriod(myintuinf, myuinf, myuinf + aPeriod);
0433 aSupToCheck = myintusup + (anInfToCheck - myintuinf);
0434 }
0435 IntIsNotValid = (myuinf > aSupToCheck) || (myusup < anInfToCheck);
0436
0437 if (IntIsNotValid)
0438 continue;
0439
0440 if (myuinf >= anInfToCheck)
0441 anInfToCheck = myuinf;
0442 if (myusup <= aSupToCheck)
0443 aSupToCheck = myusup;
0444 if ((aSupToCheck - anInfToCheck) <= mytolu)
0445 continue;
0446
0447 if (i != 1)
0448 {
0449 TheCurveTool::D1(aCurve, myintuinf, PP, V1);
0450 s1 = (TheVector(theP, PP)) * V1;
0451 if (s1 * s2 < 0.0)
0452 {
0453 mySqDist.Append(PP.SquareDistance(theP));
0454 myismin.Append((s1 < 0.0));
0455 mypoint.Append(ThePOnC(myintuinf, PP));
0456 }
0457 }
0458 if (i != n)
0459 {
0460 TheCurveTool::D1(aCurve, myintusup, PP, V1);
0461 s2 = (TheVector(theP, PP)) * V1;
0462 }
0463
0464 IntervalPerform(theP);
0465 IntExtIsDone = IntExtIsDone || mydone;
0466 }
0467
0468 mydone = IntExtIsDone;
0469 break;
0470 }
0471 }
0472
0473
0474 if (type == GeomAbs_BSplineCurve || type == GeomAbs_OffsetCurve || type == GeomAbs_OtherCurve)
0475 {
0476 if (mydist1 < Precision::SquareConfusion() || mydist2 < Precision::SquareConfusion())
0477 {
0478 bool isFirstAdded = false;
0479 bool isLastAdded = false;
0480 int aNbPoints = mypoint.Length();
0481 for (i = 1; i <= aNbPoints; i++)
0482 {
0483 U = mypoint.Value(i).Parameter();
0484 if (std::abs(U - myuinf) < mytolu)
0485 isFirstAdded = true;
0486 else if (std::abs(myusup - U) < mytolu)
0487 isLastAdded = true;
0488 }
0489 if (!isFirstAdded && mydist1 < Precision::SquareConfusion())
0490 {
0491 mySqDist.Prepend(mydist1);
0492 myismin.Prepend(true);
0493 mypoint.Prepend(ThePOnC(myuinf, Pf));
0494 }
0495 if (!isLastAdded && mydist2 < Precision::SquareConfusion())
0496 {
0497 mySqDist.Append(mydist2);
0498 myismin.Append(true);
0499 mypoint.Append(ThePOnC(myusup, Pl));
0500 }
0501 mydone = true;
0502 }
0503 }
0504 else
0505 {
0506 mydone = myExtPElC.IsDone();
0507 if (mydone)
0508 {
0509 NbExt = myExtPElC.NbExt();
0510 for (i = 1; i <= NbExt; i++)
0511 {
0512 ThePOnC PC = myExtPElC.Point(i);
0513 U = PC.Parameter();
0514 if (TheCurveTool::IsPeriodic(aCurve))
0515 {
0516 U = ElCLib::InPeriod(U, myuinf, myuinf + TheCurveTool::Period(aCurve));
0517 }
0518 if ((U >= myuinf - mytolu) && (U <= myusup + mytolu))
0519 {
0520 PC.SetValues(U, myExtPElC.Point(i).Value());
0521 mySqDist.Append(myExtPElC.SquareDistance(i));
0522 myismin.Append(myExtPElC.IsMin(i));
0523 mypoint.Append(PC);
0524 }
0525 }
0526 }
0527 }
0528 }
0529
0530
0531 bool IsDone() const { return mydone; }
0532
0533
0534
0535
0536 double SquareDistance(const int theN) const
0537 {
0538 if ((theN < 1) || (theN > NbExt()))
0539 throw Standard_OutOfRange();
0540 return mySqDist.Value(theN);
0541 }
0542
0543
0544
0545 int NbExt() const
0546 {
0547 if (!IsDone())
0548 throw StdFail_NotDone();
0549 return mySqDist.Length();
0550 }
0551
0552
0553
0554
0555 bool IsMin(const int theN) const
0556 {
0557 if ((theN < 1) || (theN > NbExt()))
0558 throw Standard_OutOfRange();
0559 return myismin.Value(theN);
0560 }
0561
0562
0563
0564
0565 const ThePOnC& Point(const int theN) const
0566 {
0567 if ((theN < 1) || (theN > NbExt()))
0568 throw Standard_OutOfRange();
0569 return mypoint.Value(theN);
0570 }
0571
0572
0573
0574
0575
0576
0577 void TrimmedSquareDistances(double& theDist1,
0578 double& theDist2,
0579 ThePoint& theP1,
0580 ThePoint& theP2) const
0581 {
0582 theDist1 = mydist1;
0583 theDist2 = mydist2;
0584 theP1 = Pf;
0585 theP2 = Pl;
0586 }
0587
0588 protected:
0589
0590 void IntervalPerform(const ThePoint& theP)
0591 {
0592 int i;
0593 double U;
0594 myExtPC.Initialize(mysample, myintuinf, myintusup, mytolu, mytolf);
0595 myExtPC.Perform(theP);
0596 mydone = myExtPC.IsDone();
0597 if (mydone)
0598 {
0599 int NbExt = myExtPC.NbExt();
0600 for (i = 1; i <= NbExt; i++)
0601 {
0602 ThePOnC PC = myExtPC.Point(i);
0603 U = PC.Parameter();
0604 if (TheCurveTool::IsPeriodic(*myC))
0605 {
0606 U = ElCLib::InPeriod(U, myuinf, myuinf + TheCurveTool::Period(*myC));
0607 }
0608 if ((U >= myuinf - mytolu) && (U <= myusup + mytolu))
0609 {
0610 AddSol(U, PC.Value(), myExtPC.SquareDistance(i), myExtPC.IsMin(i));
0611 }
0612 }
0613 }
0614 }
0615
0616
0617 void AddSol(const double theU, const ThePoint& theP, const double theSqDist, const bool isMin)
0618 {
0619 int i, NbExt = mypoint.Length();
0620 for (i = 1; i <= NbExt; i++)
0621 {
0622 double t = mypoint.Value(i).Parameter();
0623 if (std::abs(t - theU) <= mytolu)
0624 {
0625 return;
0626 }
0627 }
0628 ThePOnC PC(theU, theP);
0629 mySqDist.Append(theSqDist);
0630 myismin.Append(isMin);
0631 mypoint.Append(PC);
0632 }
0633
0634 private:
0635 TheCurve* myC;
0636 ThePoint Pf;
0637 ThePoint Pl;
0638 TheExtPElC myExtPElC;
0639 TheSequenceOfPOnC mypoint;
0640 bool mydone;
0641 double mydist1;
0642 double mydist2;
0643 TheEPC myExtPC;
0644 double mytolu;
0645 double mytolf;
0646 int mysample;
0647 double myintuinf;
0648 double myintusup;
0649 double myuinf;
0650 double myusup;
0651 GeomAbs_CurveType type;
0652 NCollection_Sequence<bool> myismin;
0653 NCollection_Sequence<double> mySqDist;
0654 };
0655
0656 #endif