File indexing completed on 2026-09-28 09:19:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _ExtremaPC_Circle_HeaderFile
0015 #define _ExtremaPC_Circle_HeaderFile
0016
0017 #include <ElCLib.hxx>
0018 #include <ExtremaPC.hxx>
0019 #include <gp_Circ.hxx>
0020 #include <gp_Pnt.hxx>
0021 #include <gp_Vec.hxx>
0022 #include <Precision.hxx>
0023 #include <Standard_DefineAlloc.hxx>
0024
0025 #include <cmath>
0026 #include <optional>
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 class ExtremaPC_Circle
0048 {
0049 public:
0050 DEFINE_STANDARD_ALLOC
0051
0052
0053
0054 explicit ExtremaPC_Circle(const gp_Circ& theCircle)
0055 : myCircle(theCircle),
0056 myDomain(std::nullopt)
0057 {
0058 }
0059
0060
0061
0062
0063 ExtremaPC_Circle(const gp_Circ& theCircle, const ExtremaPC::Domain1D& theDomain)
0064 : myCircle(theCircle),
0065 myDomain(theDomain.IsFullPeriod(2.0 * M_PI) ? std::nullopt
0066 : std::optional<ExtremaPC::Domain1D>(theDomain))
0067 {
0068 }
0069
0070
0071 ExtremaPC_Circle(const ExtremaPC_Circle&) = delete;
0072
0073
0074 ExtremaPC_Circle& operator=(const ExtremaPC_Circle&) = delete;
0075
0076
0077 ExtremaPC_Circle(ExtremaPC_Circle&&) = default;
0078
0079
0080 ExtremaPC_Circle& operator=(ExtremaPC_Circle&&) = default;
0081
0082
0083
0084
0085 gp_Pnt Value(double theU) const { return ElCLib::Value(theU, myCircle); }
0086
0087
0088 bool IsBounded() const { return myDomain.has_value(); }
0089
0090
0091 const ExtremaPC::Domain1D& Domain() const { return *myDomain; }
0092
0093
0094
0095
0096
0097
0098
0099 [[nodiscard]] const ExtremaPC::Result& Perform(
0100 const gp_Pnt& theP,
0101 double theTol,
0102 ExtremaPC::SearchMode theMode = ExtremaPC::SearchMode::MinMax) const
0103 {
0104 myResult.Clear();
0105
0106
0107 const gp_Pnt& aCenter = myCircle.Location();
0108 const gp_Dir& aAxis = myCircle.Axis().Direction();
0109 gp_Vec aToP(aCenter, theP);
0110 double aHeight = aToP.Dot(gp_Vec(aAxis));
0111 gp_Vec aTrsl = gp_Vec(aAxis) * (-aHeight);
0112 gp_Pnt aPp = theP.Translated(aTrsl);
0113
0114
0115 gp_Vec aOPp(aCenter, aPp);
0116 double aOPpMag = aOPp.Magnitude();
0117
0118 if (aOPpMag < theTol)
0119 {
0120
0121 myResult.Status = ExtremaPC::Status::InfiniteSolutions;
0122 double aRadius = myCircle.Radius();
0123 myResult.InfiniteSquareDistance = aRadius * aRadius + aHeight * aHeight;
0124 return myResult;
0125 }
0126
0127
0128
0129 double aUs1 = myCircle.XAxis().Direction().AngleWithRef(aOPp, aAxis);
0130
0131
0132 constexpr double aAngTol = Precision::Angular();
0133 if (aUs1 + M_PI < aAngTol)
0134 {
0135 aUs1 = -M_PI;
0136 }
0137 else if (aUs1 - M_PI > -aAngTol)
0138 {
0139 aUs1 = M_PI;
0140 }
0141
0142
0143 double aUs2 = aUs1 + M_PI;
0144
0145
0146 double aTolU = Precision::Angular();
0147 if (myDomain.has_value())
0148 {
0149 const double theUMin = myDomain->Min;
0150
0151 double aRadius = myCircle.Radius();
0152 if (aRadius > gp::Resolution())
0153 {
0154 aTolU = theTol / aRadius;
0155 }
0156
0157
0158 double aUinf = theUMin;
0159 ElCLib::AdjustPeriodic(theUMin, theUMin + 2.0 * M_PI, aTolU, aUinf, aUs1);
0160 ElCLib::AdjustPeriodic(theUMin, theUMin + 2.0 * M_PI, aTolU, aUinf, aUs2);
0161
0162
0163 if (std::abs(aUs1 - 2.0 * M_PI - theUMin) < aTolU)
0164 {
0165 aUs1 = theUMin;
0166 }
0167 if (std::abs(aUs2 - 2.0 * M_PI - theUMin) < aTolU)
0168 {
0169 aUs2 = theUMin;
0170 }
0171 }
0172
0173
0174
0175 int aStart = (theMode == ExtremaPC::SearchMode::Max) ? 1 : 0;
0176 int aEnd = (theMode == ExtremaPC::SearchMode::Min) ? 1 : 2;
0177
0178 double aSolutions[2] = {aUs1, aUs2};
0179
0180 for (int i = aStart; i < aEnd; ++i)
0181 {
0182 double aU = aSolutions[i];
0183
0184
0185 if (myDomain.has_value())
0186 {
0187 if (aU < myDomain->Min - aTolU || aU > myDomain->Max + aTolU)
0188 continue;
0189 }
0190
0191 gp_Pnt aCurvePt = ElCLib::Value(aU, myCircle);
0192
0193 ExtremaPC::ExtremumResult anExt;
0194 anExt.Parameter = aU;
0195 anExt.Point = aCurvePt;
0196 anExt.SquareDistance = theP.SquareDistance(aCurvePt);
0197 anExt.IsMinimum = (i == 0);
0198
0199 myResult.Extrema.Append(anExt);
0200 }
0201
0202 myResult.Status = ExtremaPC::Status::OK;
0203 return myResult;
0204 }
0205
0206
0207
0208
0209
0210
0211
0212
0213 [[nodiscard]] const ExtremaPC::Result& PerformWithEndpoints(
0214 const gp_Pnt& theP,
0215 double theTol,
0216 ExtremaPC::SearchMode theMode = ExtremaPC::SearchMode::MinMax) const
0217 {
0218 (void)Perform(theP, theTol, theMode);
0219
0220
0221 if (myResult.Status == ExtremaPC::Status::OK && myDomain.has_value())
0222 {
0223 ExtremaPC::AddEndpointExtrema(myResult, theP, *myDomain, *this, theTol, theMode);
0224 }
0225
0226 return myResult;
0227 }
0228
0229
0230 const gp_Circ& Circle() const { return myCircle; }
0231
0232 private:
0233 gp_Circ myCircle;
0234 std::optional<ExtremaPC::Domain1D> myDomain;
0235 mutable ExtremaPC::Result myResult;
0236 };
0237
0238 #endif