Skip to content

Commit 9bf5d64

Browse files
committed
Adding root polishing step to solve_quartic function.
Newton-Raphson step added to polish initial roots found by the solve_quartic function. The core solve_quartic tolerance allows roots to drift from <0.0 to >0.0 values with the latter causing artifacts and additional root filtering. This the very likely the reason for the long too large 1e-2 intersection depth value in blob.cpp now reduced to MIN_ISECT_DEPTH_RETURNED. As part of this change created a new FUDGE_FACTOR4(1e-8) constant DBL value to replace previous use of SMALL_ENOUGH(1e-10) within solve_quartic. Looks like the value had been smaller to make roots more accurate, but at the cost of missing roots in some difficult equation cases. With the root polishing can move back to a larger value so as to always get roots. Yes, this better addresses most of what the already remove difficult_coeffs() function and bump into polysolve was trying to do.
1 parent 4e2135d commit 9bf5d64

File tree

1 file changed

+43
-2
lines changed

1 file changed

+43
-2
lines changed

source/core/math/polynomialsolver.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ const DBL FUDGE_FACTOR2 = -1.0e-5;
8585
///
8686
const DBL FUDGE_FACTOR3 = 1.0e-7;
8787

88+
/// @var FUDGE_FACTOR4
89+
/// @brief const DBL value used in the active solve_quartic() function.
90+
///
91+
/// Roughly acts as @ref FUDGE_FACTOR2 and @ref FUDGE_FACTOR3 did for the
92+
/// original solve_quartic() versions but for the current solve_quartic() code.
93+
/// Value arrived at by running many scenes and settling on what worked best.
94+
///
95+
const DBL FUDGE_FACTOR4 = 1.0e-8;
96+
8897
/// @var TWO_M_PI_3
8998
/// const DBL value used in solve_cubic() equal to 2.0 * pi / 3.0.
9099
///
@@ -1391,7 +1400,7 @@ static int solve_quartic(const DBL *x, DBL *results)
13911400

13921401
if (d1 < 0.0)
13931402
{
1394-
if (d1 > -SMALL_ENOUGH)
1403+
if (d1 > -FUDGE_FACTOR4)
13951404
{
13961405
d1 = 0.0;
13971406
}
@@ -1401,7 +1410,7 @@ static int solve_quartic(const DBL *x, DBL *results)
14011410
}
14021411
}
14031412

1404-
if (d1 < SMALL_ENOUGH)
1413+
if (d1 < FUDGE_FACTOR4)
14051414
{
14061415
d2 = z * z - r;
14071416

@@ -1461,6 +1470,38 @@ static int solve_quartic(const DBL *x, DBL *results)
14611470
}
14621471
}
14631472

1473+
// The quartic root finding method above somewhat inaccurate and more so at
1474+
// large scales. The follow code polishes the found roots so, for example,
1475+
// negative roots which otherwise drift positive and cause artifacts are
1476+
// corrected. A reason for the historically too large 1e-2 minimum intersection
1477+
// depth used with blobs that itself caused artifacts of other kinds. Further,
1478+
// the blob 1e-2 value was not large enough to filter all drift to 0+ roots in
1479+
// any case. Newton-Raphson method.
1480+
//
1481+
DBL pv, dpv, t, dt;
1482+
for (int c = 0; c < i; c++)
1483+
{
1484+
t = results[c];
1485+
for (int j = 0; j < 7; j++)
1486+
{
1487+
pv = x[0] * t + x[1];
1488+
dpv = x[0];
1489+
for (int k=2; k<=4; k++)
1490+
{
1491+
dpv = dpv * t + pv;
1492+
pv = pv * t + x[k];
1493+
}
1494+
1495+
dt = pv / dpv;
1496+
t -= dt;
1497+
if (fabs(dt) < SMALL_ENOUGH)
1498+
{
1499+
results[c] = t;
1500+
break;
1501+
}
1502+
}
1503+
}
1504+
14641505
return(i);
14651506
}
14661507
#endif

0 commit comments

Comments
 (0)