• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdeedu
  • Sitemap
  • Contact Us
 

kig

conic-common.cpp

Go to the documentation of this file.
00001 
00021 #include "conic-common.h"
00022 
00023 #include <math.h>
00024 
00025 #include "common.h"
00026 #include "kigtransform.h"
00027 
00028 #include <cmath>
00029 #include <algorithm>
00030 
00031 #include <config-kig.h>
00032 
00033 #ifdef HAVE_IEEEFP_H
00034 #include <ieeefp.h>
00035 #endif
00036 
00037 ConicCartesianData::ConicCartesianData(
00038   const ConicPolarData& polardata
00039   )
00040 {
00041   double ec = polardata.ecostheta0;
00042   double es = polardata.esintheta0;
00043   double p = polardata.pdimen;
00044   double fx = polardata.focus1.x;
00045   double fy = polardata.focus1.y;
00046 
00047   double a = 1 - ec*ec;
00048   double b = 1 - es*es;
00049   double c = - 2*ec*es;
00050   double d = - 2*p*ec;
00051   double e = - 2*p*es;
00052   double f = - p*p;
00053 
00054   f += a*fx*fx + b*fy*fy + c*fx*fy - d*fx - e*fy;
00055   d -= 2*a*fx + c*fy;
00056   e -= 2*b*fy + c*fx;
00057 
00058   coeffs[0] = a;
00059   coeffs[1] = b;
00060   coeffs[2] = c;
00061   coeffs[3] = d;
00062   coeffs[4] = e;
00063   coeffs[5] = f;
00064 }
00065 
00066 ConicPolarData::ConicPolarData( const ConicCartesianData& cartdata )
00067 {
00068   double a = cartdata.coeffs[0];
00069   double b = cartdata.coeffs[1];
00070   double c = cartdata.coeffs[2];
00071   double d = cartdata.coeffs[3];
00072   double e = cartdata.coeffs[4];
00073   double f = cartdata.coeffs[5];
00074 
00075   // 1. Compute theta (tilt of conic)
00076   double theta = std::atan2(c, b - a)/2;
00077 
00078   // now I should possibly add pi/2...
00079   double costheta = std::cos(theta);
00080   double sintheta = std::sin(theta);
00081   // compute new coefficients (c should now be zero)
00082   double aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
00083   double bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
00084   if (aa*bb < 0)
00085   {   // we have a hyperbola we need to check the correct orientation
00086     double dd = d*costheta - e*sintheta;
00087     double ee = d*sintheta + e*costheta;
00088     double xc = - dd / ( 2*aa );
00089     double yc = - ee / ( 2*bb );
00090     double ff = f + aa*xc*xc + bb*yc*yc + dd*xc + ee*yc;
00091     if (ff*aa > 0)    // wrong orientation
00092     {
00093       if (theta > 0) theta -= M_PI/2;
00094       else theta += M_PI/2;
00095       costheta = cos(theta);
00096       sintheta = sin(theta);
00097       aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
00098       bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
00099     }
00100   }
00101   else
00102   {
00103     if ( std::fabs (bb) < std::fabs (aa) )
00104     {
00105       if (theta > 0) theta -= M_PI/2;
00106       else theta += M_PI/2;
00107       costheta = cos(theta);
00108       sintheta = sin(theta);
00109       aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
00110       bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
00111     }
00112   }
00113 
00114   double cc = 2*(a - b)*sintheta*costheta +
00115               c*(costheta*costheta - sintheta*sintheta);
00116   //  cc should be zero!!!   cout << "cc = " << cc << "\n";
00117   double dd = d*costheta - e*sintheta;
00118   double ee = d*sintheta + e*costheta;
00119 
00120   a = aa;
00121   b = bb;
00122   c = cc;
00123   d = dd;
00124   e = ee;
00125 
00126   // now b cannot be zero (otherwise conic is degenerate)
00127   a /= b;
00128   c /= b;
00129   d /= b;
00130   e /= b;
00131   f /= b;
00132   b = 1.0;
00133 
00134   // 2. compute y coordinate of focuses
00135 
00136   double yf = - e/2;
00137 
00138   // new values:
00139   f += yf*yf + e*yf;
00140   e += 2*yf;   // this should be zero!
00141 
00142   // now: a > 0 -> ellipse
00143   //      a = 0 -> parabula
00144   //      a < 0 -> hyperbola
00145 
00146   double eccentricity = sqrt(1.0 - a);
00147 
00148   double sqrtdiscrim = sqrt(d*d - 4*a*f);
00149   if (d < 0.0) sqrtdiscrim = -sqrtdiscrim;
00150   double xf = (4*a*f - 4*f - d*d)/(d + eccentricity*sqrtdiscrim) / 2;
00151 
00152   // 3. the focus needs to be rotated back into position
00153   focus1.x = xf*costheta + yf*sintheta;
00154   focus1.y = -xf*sintheta + yf*costheta;
00155 
00156   // 4. final touch: the pdimen
00157   pdimen = -sqrtdiscrim/2;
00158 
00159   ecostheta0 = eccentricity*costheta;
00160   esintheta0 = -eccentricity*sintheta;
00161   if ( pdimen < 0)
00162   {
00163     pdimen = -pdimen;
00164     ecostheta0 = -ecostheta0;
00165     esintheta0 = -esintheta0;
00166   }
00167 }
00168 
00169 const ConicCartesianData calcConicThroughPoints (
00170   const std::vector<Coordinate>& points,
00171   const LinearConstraints c1,
00172   const LinearConstraints c2,
00173   const LinearConstraints c3,
00174   const LinearConstraints c4,
00175   const LinearConstraints c5 )
00176 {
00177   assert( 0 < points.size() && points.size() <= 5 );
00178   // points is a vector of up to 5 points through which the conic is
00179   // constrained.
00180   // this routine should compute the coefficients in the cartesian equation
00181   //    a x^2 + b y^2 + c xy + d x + e y + f = 0
00182   // they are defined up to a multiplicative factor.
00183   // since we don't know (in advance) which one of them is nonzero, we
00184   // simply keep all 6 parameters, obtaining a 5x6 linear system which
00185   // we solve using gaussian elimination with complete pivoting
00186   // If there are too few, then we choose some cool way to fill in the
00187   // empty parts in the matrix according to the LinearConstraints
00188   // given..
00189 
00190   // 5 rows, 6 columns..
00191   double row0[6];
00192   double row1[6];
00193   double row2[6];
00194   double row3[6];
00195   double row4[6];
00196   double *matrix[5] = {row0, row1, row2, row3, row4};
00197   double solution[6];
00198   int scambio[6];
00199   LinearConstraints constraints[] = {c1, c2, c3, c4, c5};
00200 
00201   int numpoints = points.size();
00202   int numconstraints = 5;
00203 
00204   // fill in the matrix elements
00205   for ( int i = 0; i < numpoints; ++i )
00206   {
00207     double xi = points[i].x;
00208     double yi = points[i].y;
00209     matrix[i][0] = xi*xi;
00210     matrix[i][1] = yi*yi;
00211     matrix[i][2] = xi*yi;
00212     matrix[i][3] = xi;
00213     matrix[i][4] = yi;
00214     matrix[i][5] = 1.0;
00215   }
00216 
00217   for ( int i = 0; i < numconstraints; i++ )
00218   {
00219     if (numpoints >= 5) break;    // don't add constraints if we have enough
00220     for (int j = 0; j < 6; ++j) matrix[numpoints][j] = 0.0;
00221     // force the symmetry axes to be
00222     // parallel to the coordinate system (zero tilt): c = 0
00223     if (constraints[i] == zerotilt) matrix[numpoints][2] = 1.0;
00224     // force a parabula (if zerotilt): b = 0
00225     if (constraints[i] == parabolaifzt) matrix[numpoints][1] = 1.0;
00226     // force a circle (if zerotilt): a = b
00227     if (constraints[i] == circleifzt) {
00228       matrix[numpoints][0] = 1.0;
00229       matrix[numpoints][1] = -1.0; }
00230     // force an equilateral hyperbola: a + b = 0
00231     if (constraints[i] == equilateral) {
00232       matrix[numpoints][0] = 1.0;
00233       matrix[numpoints][1] = 1.0; }
00234     // force symmetry about y-axis: d = 0
00235     if (constraints[i] == ysymmetry) matrix[numpoints][3] = 1.0;
00236     // force symmetry about x-axis: e = 0
00237     if (constraints[i] == xsymmetry) matrix[numpoints][4] = 1.0;
00238 
00239     if (constraints[i] != noconstraint) ++numpoints;
00240   }
00241 
00242   if ( ! GaussianElimination( matrix, numpoints, 6, scambio ) )
00243     return ConicCartesianData::invalidData();
00244   // fine della fase di eliminazione
00245   BackwardSubstitution( matrix, numpoints, 6, scambio, solution );
00246 
00247   // now solution should contain the correct coefficients..
00248   return ConicCartesianData( solution );
00249 }
00250 
00251 const ConicPolarData calcConicBFFP(
00252   const std::vector<Coordinate>& args,
00253   int type )
00254 {
00255   assert( args.size() >= 2 && args.size() <= 3 );
00256   assert( type == 1 || type == -1 );
00257 
00258   ConicPolarData ret;
00259 
00260   Coordinate f1 = args[0];
00261   Coordinate f2 = args[1];
00262   Coordinate d;
00263   double eccentricity, d1, d2, dl;
00264 
00265   Coordinate f2f1 = f2 - f1;
00266   double f2f1l = f2f1.length();
00267   ret.ecostheta0 = f2f1.x / f2f1l;
00268   ret.esintheta0 = f2f1.y / f2f1l;
00269 
00270   if ( args.size() == 3 )
00271   {
00272     d = args[2];
00273     d1 = ( d - f1 ).length();
00274     d2 = ( d - f2 ).length();
00275     dl = fabs( d1 + type * d2 );
00276     eccentricity = f2f1l/dl;
00277   }
00278   else
00279   {
00280     if ( type > 0 ) eccentricity = 0.7; else eccentricity = 2.0;
00281     dl = f2f1l/eccentricity;
00282   }
00283 
00284   double rhomax = (dl + f2f1l) /2.0;
00285 
00286   ret.ecostheta0 *= eccentricity;
00287   ret.esintheta0 *= eccentricity;
00288   ret.pdimen = type*(1 - eccentricity)*rhomax;
00289   ret.focus1 = type == 1 ? f1 : f2;
00290   return ret;
00291 }
00292 
00293 const LineData calcConicPolarLine (
00294   const ConicCartesianData& data,
00295   const Coordinate& cpole,
00296   bool& valid )
00297 {
00298   double x = cpole.x;
00299   double y = cpole.y;
00300   double a = data.coeffs[0];
00301   double b = data.coeffs[1];
00302   double c = data.coeffs[2];
00303   double d = data.coeffs[3];
00304   double e = data.coeffs[4];
00305   double f = data.coeffs[5];
00306 
00307   double alpha = 2*a*x + c*y + d;
00308   double beta = c*x + 2*b*y + e;
00309   double gamma = d*x + e*y + 2*f;
00310 
00311   double normsq = alpha*alpha + beta*beta;
00312 
00313   if (normsq < 1e-10)          // line at infinity
00314   {
00315     valid = false;
00316     return LineData();
00317   }
00318   valid = true;
00319 
00320   Coordinate reta = -gamma/normsq * Coordinate (alpha, beta);
00321   Coordinate retb = reta + Coordinate (-beta, alpha);
00322   return LineData( reta, retb );
00323 }
00324 
00325 const Coordinate calcConicPolarPoint (
00326   const ConicCartesianData& data,
00327   const LineData& polar )
00328 {
00329   Coordinate p1 = polar.a;
00330   Coordinate p2 = polar.b;
00331 
00332   double alpha = p2.y - p1.y;
00333   double beta = p1.x - p2.x;
00334   double gamma = p1.y*p2.x - p1.x*p2.y;
00335 
00336   double a11 = data.coeffs[0];
00337   double a22 = data.coeffs[1];
00338   double a12 = data.coeffs[2]/2.0;
00339   double a13 = data.coeffs[3]/2.0;
00340   double a23 = data.coeffs[4]/2.0;
00341   double a33 = data.coeffs[5];
00342 
00343 //  double detA = a11*a22*a33 - a11*a23*a23 - a22*a13*a13 - a33*a12*a12 +
00344 //                2*a12*a23*a13;
00345 
00346   double a11inv = a22*a33 - a23*a23;
00347   double a22inv = a11*a33 - a13*a13;
00348   double a33inv = a11*a22 - a12*a12;
00349   double a12inv = a23*a13 - a12*a33;
00350   double a23inv = a12*a13 - a23*a11;
00351   double a13inv = a12*a23 - a13*a22;
00352 
00353   double x = a11inv*alpha + a12inv*beta + a13inv*gamma;
00354   double y = a12inv*alpha + a22inv*beta + a23inv*gamma;
00355   double z = a13inv*alpha + a23inv*beta + a33inv*gamma;
00356 
00357   if (fabs(z) < 1e-10)          // point at infinity
00358   {
00359     return Coordinate::invalidCoord();
00360   }
00361 
00362   x /= z;
00363   y /= z;
00364   return Coordinate (x, y);
00365 }
00366 
00367 const Coordinate calcConicLineIntersect( const ConicCartesianData& c,
00368                                          const LineData& l,
00369                      double knownparam,
00370                                          int which )
00371 {
00372   assert( which == 1 || which == -1 || which == 0 );
00373 
00374   double aa = c.coeffs[0];
00375   double bb = c.coeffs[1];
00376   double cc = c.coeffs[2];
00377   double dd = c.coeffs[3];
00378   double ee = c.coeffs[4];
00379   double ff = c.coeffs[5];
00380 
00381   double x = l.a.x;
00382   double y = l.a.y;
00383   double dx = l.b.x - l.a.x;
00384   double dy = l.b.y - l.a.y;
00385 
00386   double aaa = aa*dx*dx + bb*dy*dy + cc*dx*dy;
00387   double bbb = 2*aa*x*dx + 2*bb*y*dy + cc*x*dy + cc*y*dx + dd*dx + ee*dy;
00388   double ccc = aa*x*x + bb*y*y + cc*x*y + dd*x + ee*y + ff;
00389 
00390   double t;
00391   if ( which == 0 )  /* i.e. we have a known intersection */
00392   {
00393     t = - bbb/aaa - knownparam;
00394     return l.a + t*(l.b - l.a);
00395   }
00396 
00397   double discrim = bbb*bbb - 4*aaa*ccc;
00398   if (discrim < 0.0)
00399   {
00400     return Coordinate::invalidCoord();
00401   }
00402   else
00403   {
00404     if ( which*bbb > 0 )
00405     {
00406       t = bbb + which*sqrt(discrim);
00407       t = - 2*ccc/t;
00408     } else {
00409       t = -bbb + which*sqrt(discrim);
00410       t /= 2*aaa;
00411     }
00412 
00413     return l.a + t*(l.b - l.a);
00414   }
00415 }
00416 
00417 ConicPolarData::ConicPolarData(
00418   const Coordinate& f, double d,
00419   double ec, double es )
00420   : focus1( f ), pdimen( d ), ecostheta0( ec ), esintheta0( es )
00421 {
00422 }
00423 
00424 ConicPolarData::ConicPolarData()
00425   : focus1(), pdimen( 0 ), ecostheta0( 0 ), esintheta0( 0 )
00426 {
00427 }
00428 
00429 const ConicPolarData calcConicBDFP(
00430   const LineData& directrix,
00431   const Coordinate& cfocus,
00432   const Coordinate& cpoint )
00433 {
00434   ConicPolarData ret;
00435 
00436   Coordinate ba = directrix.dir();
00437   double bal = ba.length();
00438   ret.ecostheta0 = -ba.y / bal;
00439   ret.esintheta0 = ba.x / bal;
00440 
00441   Coordinate pa = cpoint - directrix.a;
00442 
00443   double distpf = (cpoint - cfocus).length();
00444   double distpd = ( pa.y*ba.x - pa.x*ba.y)/bal;
00445 
00446   double eccentricity = distpf/distpd;
00447   ret.ecostheta0 *= eccentricity;
00448   ret.esintheta0 *= eccentricity;
00449 
00450   Coordinate fa = cfocus - directrix.a;
00451   ret.pdimen = ( fa.y*ba.x - fa.x*ba.y )/bal;
00452   ret.pdimen *= eccentricity;
00453   ret.focus1 = cfocus;
00454 
00455   return ret;
00456 }
00457 
00458 ConicCartesianData::ConicCartesianData( const double incoeffs[6] )
00459 {
00460   std::copy( incoeffs, incoeffs + 6, coeffs );
00461 }
00462 
00463 const LineData calcConicAsymptote(
00464   const ConicCartesianData data,
00465   int which, bool &valid )
00466 {
00467   assert( which == -1 || which == 1 );
00468 
00469   LineData ret;
00470   double a=data.coeffs[0];
00471   double b=data.coeffs[1];
00472   double c=data.coeffs[2];
00473   double d=data.coeffs[3];
00474   double e=data.coeffs[4];
00475 
00476   double normabc = a*a + b*b + c*c;
00477   double delta = c*c - 4*a*b;
00478   if (fabs(delta) < 1e-6*normabc) { valid = false; return ret; }
00479 
00480   double yc = (2*a*e - c*d)/delta;
00481   double xc = (2*b*d - c*e)/delta;
00482   // let c be nonnegative; we no longer need d, e, f.
00483   if (c < 0)
00484   {
00485     c *= -1;
00486     a *= -1;
00487     b *= -1;
00488   }
00489 
00490   if ( delta < 0 )
00491   {
00492     valid = false;
00493     return ret;
00494   }
00495 
00496   double sqrtdelta = sqrt(delta);
00497   Coordinate displacement;
00498   if (which > 0)
00499     displacement = Coordinate(-2*b, c + sqrtdelta);
00500   else
00501     displacement = Coordinate(c + sqrtdelta, -2*a);
00502   ret.a = Coordinate(xc, yc);
00503   ret.b = ret.a + displacement;
00504   return ret;
00505 }
00506 
00507 const ConicCartesianData calcConicByAsymptotes(
00508   const LineData& line1,
00509   const LineData& line2,
00510   const Coordinate& p )
00511 {
00512   Coordinate p1 = line1.a;
00513   Coordinate p2 = line1.b;
00514   double x = p.x;
00515   double y = p.y;
00516 
00517   double c1 = p1.x*p2.y - p2.x*p1.y;
00518   double b1 = p2.x - p1.x;
00519   double a1 = p1.y - p2.y;
00520 
00521   p1 = line2.a;
00522   p2 = line2.b;
00523 
00524   double c2 = p1.x*p2.y - p2.x*p1.y;
00525   double b2 = p2.x - p1.x;
00526   double a2 = p1.y - p2.y;
00527 
00528   double a = a1*a2;
00529   double b = b1*b2;
00530   double c = a1*b2 + a2*b1;
00531   double d = a1*c2 + a2*c1;
00532   double e = b1*c2 + c1*b2;
00533 
00534   double f = a*x*x + b*y*y + c*x*y + d*x + e*y;
00535   f = -f;
00536 
00537   return ConicCartesianData( a, b, c, d, e, f );
00538 }
00539 
00540 const LineData calcConicRadical( const ConicCartesianData& cequation1,
00541                                  const ConicCartesianData& cequation2,
00542                                  int which, int zeroindex, bool& valid )
00543 {
00544   assert( which == 1 || which == -1 );
00545   assert( 0 < zeroindex && zeroindex < 4 );
00546   LineData ret;
00547   valid = true;
00548 
00549   double a = cequation1.coeffs[0];
00550   double b = cequation1.coeffs[1];
00551   double c = cequation1.coeffs[2];
00552   double d = cequation1.coeffs[3];
00553   double e = cequation1.coeffs[4];
00554   double f = cequation1.coeffs[5];
00555 
00556   double a2 = cequation2.coeffs[0];
00557   double b2 = cequation2.coeffs[1];
00558   double c2 = cequation2.coeffs[2];
00559   double d2 = cequation2.coeffs[3];
00560   double e2 = cequation2.coeffs[4];
00561   double f2 = cequation2.coeffs[5];
00562 
00563 // background: the family of conics c + lambda*c2 has members that
00564 // degenerate into a union of two lines. The values of lambda giving
00565 // such degenerate conics is the solution of a third degree equation.
00566 // The coefficients of such equation are given by:
00567 // (Thanks to Dominique Devriese for the suggestion of this approach)
00568 // domi: (And thanks to Maurizio for implementing it :)
00569 
00570   double df = 4*a*b*f - a*e*e - b*d*d - c*c*f + c*d*e;
00571   double cf = 4*a2*b*f + 4*a*b2*f + 4*a*b*f2
00572      - 2*a*e*e2 - 2*b*d*d2 - 2*f*c*c2
00573      - a2*e*e - b2*d*d - f2*c*c
00574      + c2*d*e + c*d2*e + c*d*e2;
00575   double bf = 4*a*b2*f2 + 4*a2*b*f2 + 4*a2*b2*f
00576      - 2*a2*e2*e - 2*b2*d2*d - 2*f2*c2*c
00577      - a*e2*e2 - b*d2*d2 - f*c2*c2
00578      + c*d2*e2 + c2*d*e2 + c2*d2*e;
00579   double af = 4*a2*b2*f2 - a2*e2*e2 - b2*d2*d2 - c2*c2*f2 + c2*d2*e2;
00580 
00581 // assume both conics are nondegenerate, renormalize so that af = 1
00582 
00583   df /= af;
00584   cf /= af;
00585   bf /= af;
00586   af = 1.0;   // not needed, just for consistency
00587 
00588 // computing the coefficients of the Sturm sequence
00589 
00590   double p1a = 2*bf*bf - 6*cf;
00591   double p1b = bf*cf - 9*df;
00592   double p0a = cf*p1a*p1a + p1b*(3*p1b - 2*bf*p1a);
00593   double fval, fpval, lambda;
00594 
00595   if (p0a < 0 && p1a < 0)
00596   {
00597     // -+--   ---+
00598     valid = false;
00599     return ret;
00600   }
00601 
00602   lambda = -bf/3.0;    //inflection point
00603   double displace = 1.0;
00604   if (p1a > 0)         // with two stationary points
00605   {
00606     displace += sqrt(p1a);  // should be enough.  The important
00607                             // thing is that it is larger than the
00608                             // semidistance between the stationary points
00609   }
00610   // compute the value at the inflection point using Horner scheme
00611   fval = bf + lambda;              // b + x
00612   fval = cf + lambda*fval;         // c + xb + xx
00613   fval = df + lambda*fval;         // d + xc + xxb + xxx
00614 
00615   if (fabs(p0a) < 1e-7)
00616   {   // this is the case if we intersect two vertical parabulas!
00617     p0a = 1e-7;  // fall back to the one zero case
00618   }
00619   if (p0a < 0)
00620   {
00621     // we have three roots..
00622     // we select the one we want ( defined by mzeroindex.. )
00623     lambda += ( 2 - zeroindex )* displace;
00624   }
00625   else
00626   {
00627     // we have just one root
00628     if( zeroindex > 1 )  // cannot find second and third root
00629     {
00630       valid = false;
00631       return ret;
00632     }
00633 
00634     if (fval > 0)      // zero on the left
00635     {
00636       lambda -= displace;
00637     } else {           // zero on the right
00638       lambda += displace;
00639     }
00640 
00641     // p0a = 0 means we have a root with multiplicity two
00642   }
00643 
00644 //
00645 // find a root of af*lambda^3 + bf*lambda^2 + cf*lambda + df = 0
00646 // (use a Newton method starting from lambda = 0.  Hope...)
00647 //
00648 
00649   double delta;
00650 
00651   int iterations = 0;
00652   const int maxiterations = 30;
00653   while (iterations++ < maxiterations)   // using Newton, iterations should be very few
00654   {
00655     // compute value of function and polinomial
00656     fval = fpval = af;
00657     fval = bf + lambda*fval;         // b + xa
00658     fpval = fval + lambda*fpval;     // b + 2xa
00659     fval = cf + lambda*fval;         // c + xb + xxa
00660     fpval = fval + lambda*fpval;     // c + 2xb + 3xxa
00661     fval = df + lambda*fval;         // d + xc + xxb + xxxa
00662 
00663     delta = fval/fpval;
00664     lambda -= delta;
00665     if (fabs(delta) < 1e-6) break;
00666   }
00667   if (iterations >= maxiterations) { valid = false; return ret; }
00668 
00669   // now we have the degenerate conic: a, b, c, d, e, f
00670 
00671   a += lambda*a2;
00672   b += lambda*b2;
00673   c += lambda*c2;
00674   d += lambda*d2;
00675   e += lambda*e2;
00676   f += lambda*f2;
00677 
00678   // domi:
00679   // this is the determinant of the matrix of the new conic.  It
00680   // should be zero, for the new conic to be degenerate.
00681   df = 4*a*b*f - a*e*e - b*d*d - c*c*f + c*d*e;
00682 
00683   //lets work in homogeneous coordinates...
00684 
00685   double dis1 = e*e - 4*b*f;
00686   double maxval = fabs(dis1);
00687   int maxind = 1;
00688   double dis2 = d*d - 4*a*f;
00689   if (fabs(dis2) > maxval)
00690   {
00691     maxval = fabs(dis2);
00692     maxind = 2;
00693   }
00694   double dis3 = c*c - 4*a*b;
00695   if (fabs(dis3) > maxval)
00696   {
00697     maxval = fabs(dis3);
00698     maxind = 3;
00699   }
00700   // one of these must be nonzero (otherwise the matrix is ...)
00701   // exchange elements so that the largest is the determinant of the
00702   // first 2x2 minor
00703   double temp;
00704   switch (maxind)
00705   {
00706     case 1:  // exchange 1 <-> 3
00707     temp = a; a = f; f = temp;
00708     temp = c; c = e; e = temp;
00709     temp = dis1; dis1 = dis3; dis3 = temp;
00710     break;
00711 
00712     case 2:  // exchange 2 <-> 3
00713     temp = b; b = f; f = temp;
00714     temp = c; c = d; d = temp;
00715     temp = dis2; dis2 = dis3; dis3 = temp;
00716     break;
00717   }
00718 
00719   // domi:
00720   // this is the negative of the determinant of the top left of the
00721   // matrix.  If it is 0, then the conic is a parabola, if it is < 0,
00722   // then the conic is an ellipse, if positive, the conic is a
00723   // hyperbola.  In this case, it should be positive, since we have a
00724   // degenerate conic, which is a degenerate case of a hyperbola..
00725   // note that it is negative if there is no valid conic to be
00726   // found ( e.g. not enough intersections.. )
00727   //  double discrim = c*c - 4*a*b;
00728 
00729   if (dis3 < 0)
00730   {
00731     // domi:
00732     // i would put an assertion here, but well, i guess it doesn't
00733     // really matter, and this prevents crashes if the math i still
00734     // recall from high school happens to be wrong :)
00735     valid = false;
00736     return ret;
00737   };
00738 
00739   double r[3];   // direction of the null space
00740   r[0] = 2*b*d - c*e;
00741   r[1] = 2*a*e - c*d;
00742   r[2] = dis3;
00743 
00744   // now remember the switch:
00745   switch (maxind)
00746   {
00747     case 1:  // exchange 1 <-> 3
00748     temp = a; a = f; f = temp;
00749     temp = c; c = e; e = temp;
00750     temp = dis1; dis1 = dis3; dis3 = temp;
00751     temp = r[0]; r[0] = r[2]; r[2] = temp;
00752     break;
00753 
00754     case 2:  // exchange 2 <-> 3
00755     temp = b; b = f; f = temp;
00756     temp = c; c = d; d = temp;
00757     temp = dis2; dis2 = dis3; dis3 = temp;
00758     temp = r[1]; r[1] = r[2]; r[2] = temp;
00759     break;
00760   }
00761 
00762   // Computing a Householder reflection transformation that
00763   // maps r onto [0, 0, k]
00764 
00765   double w[3];
00766   double rnormsq = r[0]*r[0] + r[1]*r[1] + r[2]*r[2];
00767   double k = sqrt( rnormsq );
00768   if ( k*r[2] < 0) k = -k;
00769   double wnorm = sqrt( 2*rnormsq + 2*k*r[2] );
00770   w[0] = r[0]/wnorm;
00771   w[1] = r[1]/wnorm;
00772   w[2] = (r[2] + k)/wnorm;
00773 
00774   // matrix transformation using Householder matrix, the resulting
00775   // matrix is zero on third row and column
00776   // [q0,q1,q2]^t = A w
00777   // alpha = w^t A w
00778   double q0 = a*w[0] + c*w[1]/2 + d*w[2]/2;
00779   double q1 = b*w[1] + c*w[0]/2 + e*w[2]/2;
00780   double alpha = a*w[0]*w[0] + b*w[1]*w[1] + c*w[0]*w[1] +
00781                  d*w[0]*w[2] + e*w[1]*w[2] + f*w[2]*w[2];
00782   double a00 = a - 4*w[0]*q0 + 4*w[0]*w[0]*alpha;
00783   double a11 = b - 4*w[1]*q1 + 4*w[1]*w[1]*alpha;
00784   double a01 = c/2 - 2*w[1]*q0 - 2*w[0]*q1 + 4*w[0]*w[1]*alpha;
00785 
00786   double dis = a01*a01 - a00*a11;
00787   assert ( dis >= 0 );
00788   double sqrtdis = sqrt( dis );
00789   double px, py;
00790   if ( which*a01 > 0 )
00791   {
00792     px = a01 + which*sqrtdis;
00793     py = a11;
00794   } else {
00795     px = a00;
00796     py = a01 - which*sqrtdis;
00797   }
00798   double p[3];   // vector orthogonal to one of the two planes
00799   double pscalw = w[0]*px + w[1]*py;
00800   p[0] = px - 2*pscalw*w[0];
00801   p[1] = py - 2*pscalw*w[1];
00802   p[2] =    - 2*pscalw*w[2];
00803 
00804   // "r" is the solution of the equation A*(x,y,z) = (0,0,0) where
00805   // A is the matrix of the degenerate conic.  This is what we
00806   // called in the conic theory we saw in high school a "double
00807   // point".  It has the unique property that any line going through
00808   // it is a "polar line" of the conic at hand.  It only exists for
00809   // degenerate conics.  It has another unique property that if you
00810   // take any other point on the conic, then the line between it and
00811   // the double point is part of the conic.
00812   // this is what we use here: we find the double point ( ret.a
00813   // ), and then find another points on the conic.
00814 
00815   ret.a = -p[2]/(p[0]*p[0] + p[1]*p[1]) * Coordinate (p[0],p[1]);
00816   ret.b = ret.a + Coordinate (-p[1],p[0]);
00817   valid = true;
00818 
00819   return ret;
00820 }
00821 
00822 const ConicCartesianData calcConicTransformation (
00823   const ConicCartesianData& data, const Transformation& t, bool& valid )
00824 {
00825   double a[3][3];
00826   double b[3][3];
00827 
00828   a[1][1] = data.coeffs[0];
00829   a[2][2] = data.coeffs[1];
00830   a[1][2] = a[2][1] = data.coeffs[2]/2;
00831   a[0][1] = a[1][0] = data.coeffs[3]/2;
00832   a[0][2] = a[2][0] = data.coeffs[4]/2;
00833   a[0][0] = data.coeffs[5];
00834 
00835   Transformation ti = t.inverse( valid );
00836   if ( ! valid ) return ConicCartesianData();
00837 
00838   double supnorm = 0.0;
00839   for (int i = 0; i < 3; i++)
00840   {
00841     for (int j = 0; j < 3; j++)
00842     {
00843       b[i][j] = 0.;
00844       for (int ii = 0; ii < 3; ii++)
00845       {
00846         for (int jj = 0; jj < 3; jj++)
00847         {
00848       b[i][j] += a[ii][jj]*ti.data( ii, i )*ti.data( jj, j );
00849     }
00850       }
00851       if ( std::fabs( b[i][j] ) > supnorm ) supnorm = std::fabs( b[i][j] );
00852     }
00853   }
00854 
00855   for (int i = 0; i < 3; i++)
00856   {
00857     for (int j = 0; j < 3; j++)
00858     {
00859       b[i][j] /= supnorm;
00860     }
00861   }
00862 
00863   return ConicCartesianData ( b[1][1], b[2][2], b[1][2] + b[2][1],
00864                               b[0][1] + b[1][0], b[0][2] + b[2][0], b[0][0] );
00865 }
00866 
00867 ConicCartesianData::ConicCartesianData()
00868 {
00869 }
00870 
00871 bool operator==( const ConicPolarData& lhs, const ConicPolarData& rhs )
00872 {
00873   return lhs.focus1 == rhs.focus1 &&
00874          lhs.pdimen == rhs.pdimen &&
00875      lhs.ecostheta0 == rhs.ecostheta0 &&
00876      lhs.esintheta0 == rhs.esintheta0;
00877 }
00878 
00879 ConicCartesianData ConicCartesianData::invalidData()
00880 {
00881   ConicCartesianData ret;
00882   ret.coeffs[0] = double_inf;
00883   return ret;
00884 }
00885 
00886 bool ConicCartesianData::valid() const
00887 {
00888   return finite( coeffs[0] );
00889 }
00890 

kig

Skip menu "kig"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

kdeedu

Skip menu "kdeedu"
  • kalzium
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  •   docs
  •   src
  • parley
  •   stepcore
Generated for kdeedu by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal