00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
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
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;
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
00147 BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
00148
00149
00150 return CubicCartesianData( solution );
00151 }
00152
00153 const CubicCartesianData calcCubicCuspThroughPoints (
00154 const std::vector<Coordinate>& points )
00155 {
00156
00157
00158
00159
00160
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
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;
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;
00203 break;
00204 case 1:
00205 matrix[numpoints][1] = 1.0;
00206 break;
00207 case 2:
00208 matrix[numpoints][2] = 1.0;
00209 break;
00210 case 3:
00211 matrix[numpoints][3] = 1.0;
00212 break;
00213 case 4:
00214 matrix[numpoints][4] = 1.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
00241 BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
00242
00243
00244 return CubicCartesianData( solution );
00245 }
00246
00247 const CubicCartesianData calcCubicNodeThroughPoints (
00248 const std::vector<Coordinate>& points )
00249 {
00250
00251
00252
00253
00254
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
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;
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
00335 BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
00336
00337
00338 return CubicCartesianData( solution );
00339 }
00340
00341
00342
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
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
00364 double a = a222;
00365
00366 double b = a122*x + a022;
00367
00368 double c = a112*x*x + a012*x + a002;
00369
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
00391
00392
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
00413 d += a000;
00414
00415
00416 d += a001*p.x + a002*p.y;
00417 c += a001*v.x + a002*v.y;
00418
00419
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
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
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 )
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 )
00462 {
00463 a[i][j][j] /= 3.;
00464 a[j][i][j] = a[j][j][i] = a[i][j][j];
00465 }
00466 else
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
00502
00503
00504
00505
00506
00507
00508
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 }