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

kig

cubic-common.cc

Go to the documentation of this file.
00001 // Copyright (C)  2003  Dominique Devriese <devriese@kde.org>
00002 
00003 // This program is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU General Public License
00005 // as published by the Free Software Foundation; either version 2
00006 // of the License, or (at your option) any later version.
00007 
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00016 // 02110-1301, USA.
00017 
00018 #include "cubic-common.h"
00019 #include "kignumerics.h"
00020 #include "kigtransform.h"
00021 
00022 #include <config-kig.h>
00023 
00024 #ifdef HAVE_IEEEFP_H
00025 #include <ieeefp.h>
00026 #endif
00027 
00028 /*
00029  * coefficients of the cartesian equation for cubics
00030  */
00031 
00032 CubicCartesianData::CubicCartesianData()
00033 {
00034   std::fill( coeffs, coeffs + 10, 0 );
00035 }
00036 
00037 CubicCartesianData::CubicCartesianData(
00038             const double incoeffs[10] )
00039 {
00040   std::copy( incoeffs, incoeffs + 10, coeffs );
00041   normalize();
00042 }
00043 
00044 void CubicCartesianData::normalize()
00045 {
00046   double norm = 0.0;
00047   for ( int i = 0; i < 10; ++i )
00048   {
00049     if ( fabs( coeffs[i] ) > norm ) norm = fabs( coeffs[i] );
00050   }
00051   if ( norm < 1e-8 ) return;
00052   for ( int i = 0; i < 10; ++i )
00053   {
00054     coeffs[i] /= norm;
00055   }
00056 }
00057 
00058 const CubicCartesianData calcCubicThroughPoints (
00059     const std::vector<Coordinate>& points )
00060 {
00061   // points is a vector of at most 9 points through which the cubic is
00062   // constrained.
00063   // this routine should compute the coefficients in the cartesian equation
00064   // they are defined up to a multiplicative factor.
00065   // since we don't know (in advance) which one of them is nonzero, we
00066   // simply keep all 10 parameters, obtaining a 9x10 linear system which
00067   // we solve using gaussian elimination with complete pivoting
00068   // If there are too few, then we choose some cool way to fill in the
00069   // empty parts in the matrix according to the LinearConstraints
00070   // given..
00071 
00072   // 9 rows, 10 columns..
00073   double row0[10];
00074   double row1[10];
00075   double row2[10];
00076   double row3[10];
00077   double row4[10];
00078   double row5[10];
00079   double row6[10];
00080   double row7[10];
00081   double row8[10];
00082   double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
00083   double solution[10];
00084   int scambio[10];
00085 
00086   int numpoints = points.size();
00087   int numconstraints = 9;
00088 
00089   // fill in the matrix elements
00090   for ( int i = 0; i < numpoints; ++i )
00091   {
00092     double xi = points[i].x;
00093     double yi = points[i].y;
00094     matrix[i][0] = 1.0;
00095     matrix[i][1] = xi;
00096     matrix[i][2] = yi;
00097     matrix[i][3] = xi*xi;
00098     matrix[i][4] = xi*yi;
00099     matrix[i][5] = yi*yi;
00100     matrix[i][6] = xi*xi*xi;
00101     matrix[i][7] = xi*xi*yi;
00102     matrix[i][8] = xi*yi*yi;
00103     matrix[i][9] = yi*yi*yi;
00104   }
00105 
00106   for ( int i = 0; i < numconstraints; i++ )
00107   {
00108     if (numpoints >= 9) break;    // don't add constraints if we have enough
00109     for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
00110     bool addedconstraint = true;
00111     switch (i)
00112     {
00113       case 0:
00114         matrix[numpoints][7] = 1.0;
00115         matrix[numpoints][8] = -1.0;
00116         break;
00117       case 1:
00118         matrix[numpoints][7] = 1.0;
00119     break;
00120       case 2:
00121         matrix[numpoints][9] = 1.0;
00122     break;
00123       case 3:
00124         matrix[numpoints][4] = 1.0;
00125     break;
00126       case 4:
00127         matrix[numpoints][5] = 1.0;
00128     break;
00129       case 5:
00130         matrix[numpoints][3] = 1.0;
00131     break;
00132       case 6:
00133         matrix[numpoints][1] = 1.0;
00134     break;
00135 
00136       default:
00137         addedconstraint = false;
00138         break;
00139     }
00140 
00141     if (addedconstraint) ++numpoints;
00142   }
00143 
00144   if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
00145     return CubicCartesianData::invalidData();
00146   // fine della fase di eliminazione
00147   BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
00148 
00149   // now solution should contain the correct coefficients..
00150   return CubicCartesianData( solution );
00151 }
00152 
00153 const CubicCartesianData calcCubicCuspThroughPoints (
00154     const std::vector<Coordinate>& points )
00155 {
00156   // points is a vector of at most 4 points through which the cubic is
00157   // constrained. Moreover the cubic is required to have a cusp at the
00158   // origin.
00159 
00160   // 9 rows, 10 columns..
00161   double row0[10];
00162   double row1[10];
00163   double row2[10];
00164   double row3[10];
00165   double row4[10];
00166   double row5[10];
00167   double row6[10];
00168   double row7[10];
00169   double row8[10];
00170   double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
00171   double solution[10];
00172   int scambio[10];
00173 
00174   int numpoints = points.size();
00175   int numconstraints = 9;
00176 
00177   // fill in the matrix elements
00178   for ( int i = 0; i < numpoints; ++i )
00179   {
00180     double xi = points[i].x;
00181     double yi = points[i].y;
00182     matrix[i][0] = 1.0;
00183     matrix[i][1] = xi;
00184     matrix[i][2] = yi;
00185     matrix[i][3] = xi*xi;
00186     matrix[i][4] = xi*yi;
00187     matrix[i][5] = yi*yi;
00188     matrix[i][6] = xi*xi*xi;
00189     matrix[i][7] = xi*xi*yi;
00190     matrix[i][8] = xi*yi*yi;
00191     matrix[i][9] = yi*yi*yi;
00192   }
00193 
00194   for ( int i = 0; i < numconstraints; i++ )
00195   {
00196     if (numpoints >= 9) break;    // don't add constraints if we have enough
00197     for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
00198     bool addedconstraint = true;
00199     switch (i)
00200     {
00201       case 0:
00202     matrix[numpoints][0] = 1.0;   // through the origin
00203     break;
00204       case 1:
00205     matrix[numpoints][1] = 1.0;
00206     break;
00207       case 2:
00208     matrix[numpoints][2] = 1.0;   // no first degree term
00209     break;
00210       case 3:
00211         matrix[numpoints][3] = 1.0;   // a011 (x^2 coeff) = 0
00212     break;
00213       case 4:
00214         matrix[numpoints][4] = 1.0;   // a012 (xy coeff) = 0
00215     break;
00216       case 5:
00217         matrix[numpoints][7] = 1.0;
00218         matrix[numpoints][8] = -1.0;
00219         break;
00220       case 6:
00221         matrix[numpoints][7] = 1.0;
00222     break;
00223       case 7:
00224         matrix[numpoints][9] = 1.0;
00225     break;
00226       case 8:
00227         matrix[numpoints][6] = 1.0;
00228     break;
00229 
00230       default:
00231         addedconstraint = false;
00232         break;
00233     }
00234 
00235     if (addedconstraint) ++numpoints;
00236   }
00237 
00238   if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
00239     return CubicCartesianData::invalidData();
00240   // fine della fase di eliminazione
00241   BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
00242 
00243   // now solution should contain the correct coefficients..
00244   return CubicCartesianData( solution );
00245 }
00246 
00247 const CubicCartesianData calcCubicNodeThroughPoints (
00248     const std::vector<Coordinate>& points )
00249 {
00250   // points is a vector of at most 6 points through which the cubic is
00251   // constrained. Moreover the cubic is required to have a node at the
00252   // origin.
00253 
00254   // 9 rows, 10 columns..
00255   double row0[10];
00256   double row1[10];
00257   double row2[10];
00258   double row3[10];
00259   double row4[10];
00260   double row5[10];
00261   double row6[10];
00262   double row7[10];
00263   double row8[10];
00264   double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
00265   double solution[10];
00266   int scambio[10];
00267 
00268   int numpoints = points.size();
00269   int numconstraints = 9;
00270 
00271   // fill in the matrix elements
00272   for ( int i = 0; i < numpoints; ++i )
00273   {
00274     double xi = points[i].x;
00275     double yi = points[i].y;
00276     matrix[i][0] = 1.0;
00277     matrix[i][1] = xi;
00278     matrix[i][2] = yi;
00279     matrix[i][3] = xi*xi;
00280     matrix[i][4] = xi*yi;
00281     matrix[i][5] = yi*yi;
00282     matrix[i][6] = xi*xi*xi;
00283     matrix[i][7] = xi*xi*yi;
00284     matrix[i][8] = xi*yi*yi;
00285     matrix[i][9] = yi*yi*yi;
00286   }
00287 
00288   for ( int i = 0; i < numconstraints; i++ )
00289   {
00290     if (numpoints >= 9) break;    // don't add constraints if we have enough
00291     for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
00292     bool addedconstraint = true;
00293     switch (i)
00294     {
00295       case 0:
00296     matrix[numpoints][0] = 1.0;
00297     break;
00298       case 1:
00299     matrix[numpoints][1] = 1.0;
00300     break;
00301       case 2:
00302     matrix[numpoints][2] = 1.0;
00303     break;
00304       case 3:
00305         matrix[numpoints][7] = 1.0;
00306         matrix[numpoints][8] = -1.0;
00307         break;
00308       case 4:
00309         matrix[numpoints][7] = 1.0;
00310     break;
00311       case 5:
00312         matrix[numpoints][9] = 1.0;
00313     break;
00314       case 6:
00315         matrix[numpoints][4] = 1.0;
00316     break;
00317       case 7:
00318         matrix[numpoints][5] = 1.0;
00319     break;
00320       case 8:
00321         matrix[numpoints][3] = 1.0;
00322     break;
00323 
00324       default:
00325         addedconstraint = false;
00326         break;
00327     }
00328 
00329     if (addedconstraint) ++numpoints;
00330   }
00331 
00332   if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
00333     return CubicCartesianData::invalidData();
00334   // fine della fase di eliminazione
00335   BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
00336 
00337   // now solution should contain the correct coefficients..
00338   return CubicCartesianData( solution );
00339 }
00340 
00341 /*
00342  * computation of the y value corresponding to some x value
00343  */
00344 
00345 double calcCubicYvalue ( double x, double ymin, double ymax, int root,
00346                          CubicCartesianData data, bool& valid,
00347                          int &numroots )
00348 {
00349   valid = true;
00350 
00351   // compute the third degree polinomial:
00352   double a000 = data.coeffs[0];
00353   double a001 = data.coeffs[1];
00354   double a002 = data.coeffs[2];
00355   double a011 = data.coeffs[3];
00356   double a012 = data.coeffs[4];
00357   double a022 = data.coeffs[5];
00358   double a111 = data.coeffs[6];
00359   double a112 = data.coeffs[7];
00360   double a122 = data.coeffs[8];
00361   double a222 = data.coeffs[9];
00362 
00363   // first the y^3 coefficient, it coming only from a222:
00364   double a = a222;
00365   // next the y^2 coefficient (from a122 and a022):
00366   double b = a122*x + a022;
00367   // next the y coefficient (from a112, a012 and a002):
00368   double c = a112*x*x + a012*x + a002;
00369   // finally the constant coefficient (from a111, a011, a001 and a000):
00370   double d = a111*x*x*x + a011*x*x + a001*x + a000;
00371 
00372   return calcCubicRoot ( ymin, ymax, a, b, c, d, root, valid, numroots );
00373 }
00374 
00375 const Coordinate calcCubicLineIntersect( const CubicCartesianData& cu,
00376                                          const LineData& l,
00377                                          int root, bool& valid )
00378 {
00379   assert( root == 1 || root == 2 || root == 3 );
00380 
00381   double a, b, c, d;
00382   calcCubicLineRestriction ( cu, l.a, l.b-l.a, a, b, c, d );
00383   int numroots;
00384   double param =
00385     calcCubicRoot ( -1e10, 1e10, a, b, c, d, root, valid, numroots );
00386   return l.a + param*(l.b - l.a);
00387 }
00388 
00389 /*
00390  * calculate the cubic polynomial resulting from the restriction
00391  * of a cubic to a line (defined by two "Coordinates": a point and a
00392  * direction)
00393  */
00394 
00395 void calcCubicLineRestriction ( CubicCartesianData data,
00396                                 Coordinate p, Coordinate v,
00397                                 double& a, double& b, double& c, double& d )
00398 {
00399   a = b = c = d = 0;
00400 
00401   double a000 = data.coeffs[0];
00402   double a001 = data.coeffs[1];
00403   double a002 = data.coeffs[2];
00404   double a011 = data.coeffs[3];
00405   double a012 = data.coeffs[4];
00406   double a022 = data.coeffs[5];
00407   double a111 = data.coeffs[6];
00408   double a112 = data.coeffs[7];
00409   double a122 = data.coeffs[8];
00410   double a222 = data.coeffs[9];
00411 
00412   // zero degree term
00413   d += a000;
00414 
00415   // first degree terms
00416   d += a001*p.x + a002*p.y;
00417   c += a001*v.x + a002*v.y;
00418 
00419   // second degree terms
00420   d +=   a011*p.x*p.x + a012*p.x*p.y             +   a022*p.y*p.y;
00421   c += 2*a011*p.x*v.x + a012*(p.x*v.y + v.x*p.y) + 2*a022*p.y*v.y;
00422   b +=   a011*v.x*v.x + a012*v.x*v.y             +   a022*v.y*v.y;
00423 
00424   // third degree terms: a111 x^3 + a222 y^3
00425   d +=    a111*p.x*p.x*p.x + a222*p.y*p.y*p.y;
00426   c += 3*(a111*p.x*p.x*v.x + a222*p.y*p.y*v.y);
00427   b += 3*(a111*p.x*v.x*v.x + a222*p.y*v.y*v.y);
00428   a +=    a111*v.x*v.x*v.x + a222*v.y*v.y*v.y;
00429 
00430   // third degree terms: a112 x^2 y + a122 x y^2
00431   d += a112*p.x*p.x*p.y + a122*p.x*p.y*p.y;
00432   c += a112*(p.x*p.x*v.y + 2*p.x*v.x*p.y) + a122*(v.x*p.y*p.y + 2*p.x*p.y*v.y);
00433   b += a112*(v.x*v.x*p.y + 2*v.x*p.x*v.y) + a122*(p.x*v.y*v.y + 2*v.x*v.y*p.y);
00434   a += a112*v.x*v.x*v.y + a122*v.x*v.y*v.y;
00435 }
00436 
00437 
00438 const CubicCartesianData calcCubicTransformation (
00439   const CubicCartesianData& data,
00440   const Transformation& t, bool& valid )
00441 {
00442   double a[3][3][3];
00443   double b[3][3][3];
00444   CubicCartesianData dataout;
00445 
00446   int icount = 0;
00447   for (int i=0; i < 3; i++)
00448   {
00449     for (int j=i; j < 3; j++)
00450     {
00451       for (int k=j; k < 3; k++)
00452       {
00453     a[i][j][k] = data.coeffs[icount++];
00454     if ( i < k )
00455     {
00456       if ( i == j )    // case aiik
00457       {
00458         a[i][i][k] /= 3.;
00459         a[i][k][i] = a[k][i][i] = a[i][i][k];
00460       }
00461       else if ( j == k )  // case aijj
00462       {
00463         a[i][j][j] /= 3.;
00464         a[j][i][j] = a[j][j][i] = a[i][j][j];
00465       }
00466       else             // case aijk  (i<j<k)
00467       {
00468         a[i][j][k] /= 6.;
00469         a[i][k][j] = a[j][i][k] = a[j][k][i] =
00470                          a[k][i][j] = a[k][j][i] = a[i][j][k];
00471       }
00472     }
00473       }
00474     }
00475   }
00476 
00477   Transformation ti = t.inverse( valid );
00478   if ( ! valid ) return dataout;
00479 
00480   for (int i = 0; i < 3; i++)
00481   {
00482     for (int j = 0; j < 3; j++)
00483     {
00484       for (int k = 0; k < 3; k++)
00485       {
00486     b[i][j][k] = 0.;
00487         for (int ii = 0; ii < 3; ii++)
00488         {
00489           for (int jj = 0; jj < 3; jj++)
00490           {
00491             for (int kk = 0; kk < 3; kk++)
00492             {
00493           b[i][j][k] += a[ii][jj][kk]*ti.data( ii, i )*ti.data( jj, j )*ti.data( kk, k );
00494         }
00495       }
00496     }
00497       }
00498     }
00499   }
00500 
00501 //   assert (fabs(b[0][1][2] - b[1][2][0]) < 1e-8);  // test a couple of cases
00502 //   assert (fabs(b[0][1][1] - b[1][1][0]) < 1e-8);
00503 
00504   // apparently, the above assertions are wrong ( due to rounding
00505   // errors, Maurizio and I hope :) ), so since the symmetry is not
00506   // present, we just take the sum of the parts of the matrix elements
00507   // that should be symmetric, instead of taking one of them, and
00508   // multiplying it..
00509 
00510   dataout.coeffs[0] = b[0][0][0];
00511   dataout.coeffs[1] = b[0][0][1] + b[0][1][0] + b[1][0][0];
00512   dataout.coeffs[2] = b[0][0][2] + b[0][2][0] + b[2][0][0];
00513   dataout.coeffs[3] = b[0][1][1] + b[1][0][1] + b[1][1][0];
00514   dataout.coeffs[4] = b[0][1][2] + b[0][2][1] + b[1][2][0] + b[1][0][2] + b[2][1][0] + b[2][0][1];
00515   dataout.coeffs[5] = b[0][2][2] + b[2][0][2] + b[2][2][0];
00516   dataout.coeffs[6] = b[1][1][1];
00517   dataout.coeffs[7] = b[1][1][2] + b[1][2][1] + b[2][1][1];
00518   dataout.coeffs[8] = b[1][2][2] + b[2][1][2] + b[2][2][1];
00519   dataout.coeffs[9] = b[2][2][2];
00520 
00521   return dataout;
00522 }
00523 
00524 bool operator==( const CubicCartesianData& lhs, const CubicCartesianData& rhs )
00525 {
00526   for ( int i = 0; i < 10; ++i )
00527     if ( lhs.coeffs[i] != rhs.coeffs[i] )
00528       return false;
00529   return true;
00530 }
00531 
00532 CubicCartesianData CubicCartesianData::invalidData()
00533 {
00534   CubicCartesianData ret;
00535   ret.coeffs[0] = double_inf;
00536   return ret;
00537 }
00538 
00539 bool CubicCartesianData::valid() const
00540 {
00541   return finite( coeffs[0] );
00542 }

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
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  •   docs
  •   src
  • parley
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