#include "precompiled.h" #include "0ad_warning_disable.h" # include # include "sr.h" # include "sr_alg.h" /*-------------------------------------------------------------------*/ /* Functions to solve polynomials of 2nd, 3rt and 4th degree. */ /* Source: graphics gems */ /*-------------------------------------------------------------------*/ //change kai: //# define aMAXFLOAT 3.40282347E+38F # define aMAXFLOAT 3.40282347E+28F # define aEPSILON 1e-9 # define aEPSILON2 0.00001 # define aISZERO(x) ((x) > -aEPSILON && (x) < aEPSILON) # define aCBRT(x) ((x) > 0.0 ? pow((double)(x), 1.0/3.0) : \ ((x) < 0.0 ? -pow((double)-(x), 1.0/3.0) : 0.0)) int sr_solve_quadric_polynomial ( double c[3], double s[2] ) { double p, q, D; // normal form: x^2 + px + q = 0 p = c[1] / (2*c[2]); q = c[0] / c[2]; D = p*p - q; if ( aISZERO(D) ) { s[0] = -p; return 1; } else if ( D<0 ) { return 0; } else // if (D > 0) { double sqrt_D = sqrt(D); s[0] = sqrt_D - p; s[1] = - sqrt_D - p; return 2; } } int sr_solve_cubic_polynomial ( double c[4], double s[3] ) { int i, num; double sub; double A, B, C; double sq_A, p, q; double cb_p, D; // normal form: 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 quadric term: // x^3 +px + q = 0 sq_A = A * A; p = 1.0/3 * (- 1.0/3 * sq_A + B); q = 1.0/2 * (A * (2.0/27 * sq_A - 1.0/3 * B) + C); // use Cardano's formula cb_p = p * p * p; D = q * q + cb_p; if ( aISZERO(D) ) { if ( aISZERO(q) ) // one triple solution { s[0] = 0; num = 1; } else // one single and one double solution { double u = aCBRT(-q); s[0] = 2 * u; s[1] = - u; num = 2; } } else if ( D<0 ) // Casus irreducibilis: three real solutions { double phi = 1.0/3 * acos ( -q/sqrt(-cb_p) ); double t = 2 * sqrt(-p); s[0] = t * cos(phi); s[1] = - t * cos(phi + SR_PI / 3); s[2] = - t * cos(phi - SR_PI / 3); num = 3; } else /* one real solution */ { double sqrt_D = sqrt(D); double u = aCBRT(sqrt_D - q); double v = - aCBRT(sqrt_D + q); s[0] = u + v; num = 1; } // resubstitute sub = 1.0/3 * A; for ( i=0; i 0) u = sqrt(u); else return 0; if (aISZERO(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 = sr_solve_quadric_polynomial ( coeffs, s ); coeffs[0]= z + u; coeffs[1] = q < 0 ? v : -v; coeffs[2] = 1; num += sr_solve_quadric_polynomial ( coeffs, s+num ); } // resubstitute sub = 1.0/4 * A; for ( i=0; i0 ? a : -a; y = 0; return; } c [4] = y; c [3] = f - e; c [2] = 0; c [1] = f + e; c [0] = -y; int nb = sr_solve_quartic_polynomial ( c, s ); double denom, s_theta, c_theta, dist; double test_x [4], test_y [4]; double min_dist = aMAXFLOAT; int i, winner=0; // Find the closest point for ( i=0; i