DLLEXPORT int solveCubic(double c3, double c2, double c1, double c0, double & s0, double & s1, double & s2) { int i, num; double sub, A, B, C, sq_A, p, q, cb_p, D; if (isZero(c3)) return solveQuadric(c2, c1, c0, s0, s1); // normalize the equation:x ^ 3 + Ax ^ 2 + Bx + C = 0 A = c2 / c3; B = c1 / c3; C = c0 / c3; // substitute x = y - A / 3 to eliminate the quadric term: x^3 + px + q = 0 sq_A = A * A; p = 1.0/3.0 * (-1.0/3.0 * sq_A + B); q = 1.0/2.0 * (2.0/27.0 * A *sq_A - 1.0/3.0 * A * B + C); // use Cardano's formula cb_p = p * p * p; D = q * q + cb_p; if (isZero(D)) { if (isZero(q)) { // one triple solution s0 = 0.0; num = 1; } else { // one single and one double solution double u = cbrt(-q); s0 = 2.0 * u; s1 = - u; num = 2; } } else if (D < 0.0) { // casus irreductibilis: three real solutions double phi = 1.0/3.0 * acos(-q / sqrt(-cb_p)); double t = 2.0 * sqrt(-p); s0 = t * cos(phi); s1 = -t * cos(phi + M_PI / 3.0); s2 = -t * cos(phi - M_PI / 3.0); num = 3; } else { // one real solution double sqrt_D = sqrt(D); double u = cbrt(sqrt_D + fabs(q)); if (q > 0.0) s0 = - u + p / u ; else s0 = u - p / u; num = 1; } // resubstitute sub = 1.0 / 3.0 * A; s0 -= sub; s1 -= sub; s2 -= sub; return num; }
void Photon::choosePointInRect(Float& x, Float& y, const int rectNum, const Float randX, const Float randY) { Rect& rect = m_chunk->m_rects[rectNum]; Float b1 = m_knotValues[rect.tl]; Float b2 = m_knotValues[rect.tr] - b1; Float b3 = m_knotValues[rect.bl] - b1; Float b4 = b1 - m_knotValues[rect.tr] - m_knotValues[rect.bl] + m_knotValues[rect.br]; int roots; { Float x1, x2; roots = solveQuadric(b2 + 0.5*b4, 0.5*(b1 + 0.5*b3), -randX*(b2+0.5*b4+0.5*b1+0.25*b3), x1, x2); if (roots == 1) x = x1; else if (roots == 2) { if (x1 >= 0. && x1 < 1.) { x = x1; } else if (x2 >= 0. && x2 < 1.) { x = x2; } else { x = 0.5; fprintf(stderr, "x out of range, %f\t%f\n", x1, x2); } } } { Float y1, y2; roots = solveQuadric(0.5*(b3 + b4*x), b1 + b2*x, -randY*(b1+b2*x + 0.5*(b3+b4*x)), y1, y2); if (roots == 1) y = y1; else if (roots == 2) { if (y1 >= 0. && y1 < 1.) { y = y1; } else if (y2 >= 0. && y2 < 1.) { y = y2; } else { y = 0.5; fprintf(stderr, "y out of range, %f\t%f\n", y1, y2); } } } x *= rect.width; y *= rect.height; x += m_chunk->m_knots[rect.tl].x; y += m_chunk->m_knots[rect.tl].y; }
int PolynomialSolver::solveQuartic(float c[5], float s[4]) { float coeffs[4], z, u, v, sub, A, B, C, D, sq_A, p, q, r; int i, num; // normalize the equation:x ^ 4 + Ax ^ 3 + Bx ^ 2 + Cx + D = 0 A = c[3] / c[4]; B = c[2] / c[4]; C = c[1] / c[4]; D = c[0] / c[4]; // subsitute x = y - A / 4 to eliminate the cubic term: x^4 + px^2 + qx + r = 0 sq_A = A * A; p = -3.0f / 8.0f * sq_A + B; q = 1.0f / 8.0f * sq_A * A - 1.0f / 2.0f * A * B + C; r = -3.0f / 256.0f * sq_A * sq_A + 1.0f / 16.0f * sq_A * B - 1.0f / 4.0f * A * C + D; if(isZero(r)) { // no absolute term:y(y ^ 3 + py + q) = 0 coeffs[0] = q; coeffs[1] = p; coeffs[2] = 0.0; coeffs[3] = 1.0; num = solveCubic(coeffs, s); s[num++] = 0; } else { // solve the resolvent cubic... coeffs[0] = 1.0f / 2.0f * r * p - 1.0f / 8.0f * q * q; coeffs[1] = -r; coeffs[2] = -1.0f / 2.0f * p; coeffs[3] = 1.0f; (void) solveCubic(coeffs, s); // ...and take the one real solution... z = s[0]; // ...to build two quadratic equations u = z * z - r; v = 2.0f * z - p; if(isZero(u)) u = 0.0; else if(u > 0.0f) u = std::sqrt(u); else return 0; if(isZero(v)) v = 0; else if(v > 0.0f) v = std::sqrt(v); else return 0; coeffs[0] = z - u; coeffs[1] = q < 0 ? -v : v; coeffs[2] = 1.0f; num = solveQuadric(coeffs, s); coeffs[0] = z + u; coeffs[1] = q < 0 ? v : -v; coeffs[2] = 1.0f; num += solveQuadric(coeffs, s + num); } // resubstitute sub = 1.0f / 4 * A; for(i = 0; i < num; i++) s[i] -= sub; return num; }
int PolySolver::solveCubic(FCL_REAL c[4], FCL_REAL s[3]) { int i, num; FCL_REAL sub, A, B, C, sq_A, p, q, cb_p, D; const FCL_REAL ONE_OVER_THREE = 1 / 3.0; const FCL_REAL PI = 3.14159265358979323846; // make sure we have a d2 equation if(isZero(c[3])) return solveQuadric(c, s); // normalize the equation:x ^ 3 + Ax ^ 2 + Bx + C = 0 A = c[2] / c[3]; B = c[1] / c[3]; C = c[0] / c[3]; // substitute x = y - A / 3 to eliminate the quadratic term: x^3 + px + q = 0 sq_A = A * A; p = (-ONE_OVER_THREE * sq_A + B) * ONE_OVER_THREE; q = 0.5 * (2.0 / 27.0 * A * sq_A - ONE_OVER_THREE * A * B + C); // use Cardano's formula cb_p = p * p * p; D = q * q + cb_p; if(isZero(D)) { if(isZero(q)) { // one triple solution s[0] = 0.0; num = 1; } else { // one single and one FCL_REAL solution FCL_REAL u = cbrt(-q); s[0] = 2.0 * u; s[1] = -u; num = 2; } } else { if(D < 0.0) { // three real solutions FCL_REAL phi = ONE_OVER_THREE * acos(-q / sqrt(-cb_p)); FCL_REAL t = 2.0 * sqrt(-p); s[0] = t * cos(phi); s[1] = -t * cos(phi + PI / 3.0); s[2] = -t * cos(phi - PI / 3.0); num = 3; } else { // one real solution FCL_REAL sqrt_D = sqrt(D); FCL_REAL u = cbrt(sqrt_D + fabs(q)); if(q > 0.0) s[0] = - u + p / u ; else s[0] = u - p / u; num = 1; } } // re-substitute sub = ONE_OVER_THREE * A; for(i = 0; i < num; i++) s[i] -= sub; return num; }
int solveQuartic(float c[5], float s[4]) { float coeffs[4]; float z, u, v, sub; float A, B, C, D; float sq_A, p, q, r; int i, num; /* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */ A = c[ 3 ] / c[ 4 ]; B = c[ 2 ] / c[ 4 ]; C = c[ 1 ] / c[ 4 ]; D = c[ 0 ] / c[ 4 ]; /* substitute x = y - A/4 to eliminate cubic term: x^4 + px^2 + qx + r = 0 */ sq_A = A * A; p = - 3.0/8 * sq_A + B; q = 1.0/8 * sq_A * A - 1.0/2 * A * B + C; r = - 3.0/256*sq_A*sq_A + 1.0/16*sq_A*B - 1.0/4*A*C + D; if (IS_ZERO(r)) { /* no absolute term: y(y^3 + py + q) = 0 */ coeffs[ 0 ] = q; coeffs[ 1 ] = p; coeffs[ 2 ] = 0; coeffs[ 3 ] = 1; num = solveCubic(coeffs, s); s[ num++ ] = 0; } else { /* solve the resolvent cubic ... */ coeffs[ 0 ] = 1.0/2 * r * p - 1.0/8 * q * q; coeffs[ 1 ] = - r; coeffs[ 2 ] = - 1.0/2 * p; coeffs[ 3 ] = 1; (void) solveCubic(coeffs, s); /* ... and take the one real solution ... */ z = s[ 0 ]; /* ... to build two quadric equations */ u = z * z - r; v = 2 * z - p; if (IS_ZERO(u)) u = 0; else if (u > 0) u = sqrt(u); else return 0; if (IS_ZERO(v)) v = 0; else if (v > 0) v = sqrt(v); else return 0; coeffs[ 0 ] = z - u; coeffs[ 1 ] = q < 0 ? -v : v; coeffs[ 2 ] = 1; num = solveQuadric(coeffs, s); coeffs[ 0 ]= z + u; coeffs[ 1 ] = q < 0 ? v : -v; coeffs[ 2 ] = 1; num += solveQuadric(coeffs, s + num); } /* resubstitute */ sub = 1.0/4 * A; for (i = 0; i < num; ++i) s[ i ] -= sub; return num; }