File indexing completed on 2026-09-28 09:20:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathPoly_Cubic_HeaderFile
0015 #define _MathPoly_Cubic_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Core.hxx>
0019 #include <MathUtils_Poly.hxx>
0020 #include <MathPoly_Quadratic.hxx>
0021
0022 #include <cmath>
0023
0024
0025 namespace MathPoly
0026 {
0027 using namespace MathUtils;
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 inline MathUtils::PolyResult Cubic(double theA, double theB, double theC, double theD)
0047 {
0048 MathUtils::PolyResult aResult;
0049
0050
0051 if (MathUtils::IsZero(theA))
0052 {
0053 return Quadratic(theB, theC, theD);
0054 }
0055
0056
0057 const double aScale = std::max({std::abs(theA), std::abs(theB), std::abs(theC), std::abs(theD)});
0058 if (aScale < MathUtils::THE_ZERO_TOL)
0059 {
0060 aResult.Status = MathUtils::Status::InfiniteSolutions;
0061 return aResult;
0062 }
0063
0064
0065 const double aP = theB / theA;
0066 const double aQ = theC / theA;
0067 const double aR = theD / theA;
0068
0069
0070 const double aP3 = aP / 3.0;
0071 const double aP3_sq = aP3 * aP3;
0072 const double a = aQ - 3.0 * aP3_sq;
0073 const double b = aR - aP3 * aQ + 2.0 * aP3_sq * aP3;
0074
0075
0076 const double aHalfB = b / 2.0;
0077 const double aThirdA = a / 3.0;
0078 const double aDisc = aHalfB * aHalfB + aThirdA * aThirdA * aThirdA;
0079
0080
0081 const double aDiscTol =
0082 MathUtils::THE_ZERO_TOL * std::max(aHalfB * aHalfB, std::abs(aThirdA * aThirdA * aThirdA));
0083
0084
0085 const double aCoeffs[4] = {theD, theC, theB, theA};
0086
0087 if (aDisc > aDiscTol)
0088 {
0089
0090
0091 const double aSqrtDisc = std::sqrt(aDisc);
0092 const double aU = MathUtils::CubeRoot(-aHalfB + aSqrtDisc);
0093 const double aV = MathUtils::CubeRoot(-aHalfB - aSqrtDisc);
0094
0095 aResult.Status = MathUtils::Status::OK;
0096 aResult.NbRoots = 1;
0097 aResult.Roots[0] = aU + aV - aP3;
0098
0099
0100 aResult.Roots[0] = MathUtils::RefinePolyRoot(aCoeffs, 3, aResult.Roots[0]);
0101 }
0102 else if (aDisc < -aDiscTol)
0103 {
0104
0105
0106
0107
0108 const double aR_val = std::sqrt(-aThirdA * aThirdA * aThirdA);
0109 const double aCosArg = MathUtils::Clamp(-aHalfB / aR_val, -1.0, 1.0);
0110 const double aTheta = std::acos(aCosArg);
0111 const double aTwoSqrtNegA3 = 2.0 * std::sqrt(-aThirdA);
0112
0113 aResult.Status = MathUtils::Status::OK;
0114 aResult.NbRoots = 3;
0115 aResult.Roots[0] = aTwoSqrtNegA3 * std::cos(aTheta / 3.0) - aP3;
0116 aResult.Roots[1] = aTwoSqrtNegA3 * std::cos((aTheta + 2.0 * MathUtils::THE_PI) / 3.0) - aP3;
0117 aResult.Roots[2] = aTwoSqrtNegA3 * std::cos((aTheta + 4.0 * MathUtils::THE_PI) / 3.0) - aP3;
0118
0119
0120 for (int i = 0; i < 3; ++i)
0121 {
0122 aResult.Roots[i] = MathUtils::RefinePolyRoot(aCoeffs, 3, aResult.Roots[i]);
0123 }
0124
0125
0126 MathUtils::SortRoots(aResult.Roots.data(), 3);
0127 }
0128 else
0129 {
0130
0131 const double aU = MathUtils::CubeRoot(-aHalfB);
0132
0133 aResult.Status = MathUtils::Status::OK;
0134
0135 if (MathUtils::IsZero(aU))
0136 {
0137
0138 aResult.NbRoots = 1;
0139 aResult.Roots[0] = -aP3;
0140 }
0141 else
0142 {
0143
0144 aResult.NbRoots = 2;
0145 aResult.Roots[0] = 2.0 * aU - aP3;
0146 aResult.Roots[1] = -aU - aP3;
0147
0148
0149 aResult.Roots[0] = MathUtils::RefinePolyRoot(aCoeffs, 3, aResult.Roots[0]);
0150 aResult.Roots[1] = MathUtils::RefinePolyRoot(aCoeffs, 3, aResult.Roots[1]);
0151
0152
0153 if (aResult.Roots[0] > aResult.Roots[1])
0154 {
0155 std::swap(aResult.Roots[0], aResult.Roots[1]);
0156 }
0157 }
0158 }
0159
0160 return aResult;
0161 }
0162
0163 }
0164
0165 #endif