OSGBezierCurve3D.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifdef WIN32
00039 # pragma warning (disable : 985)
00040 #endif
00041 #include "OSGBezierCurve3D.h"
00042 #include "OSGBaseTypes.h"
00043
00044 OSG_USING_NAMESPACE
00045
00046
00047 #ifdef _DEBUG
00048 #ifdef WIN32
00049 #undef THIS_FILE
00050 static char THIS_FILE[] = __FILE__;
00051 #endif
00052 #endif
00053
00054
00055
00056 int BezierCurve3D::setControlPointVector(const DCTPVec4dvector& cps)
00057 {
00058 if(cps.size() < 2)
00059 return -1;
00060 control_points = cps;
00061 return 0;
00062 }
00063
00064
00065
00067
00077 Vec3d BezierCurve3D::computewdeCasteljau(double t, int &error)
00078 {
00079 Vec4d rat_res = computewdeCasteljau4D(t, error);
00080 Vec3d res;
00081
00082 res[0] = rat_res[0] / rat_res[3];
00083 res[1] = rat_res[1] / rat_res[3];
00084 res[2] = rat_res[2] / rat_res[3];
00085
00086 return res;
00087 }
00088
00089
00090 Vec4d BezierCurve3D::computewdeCasteljau4D(double t, int &error)
00091 {
00092
00093
00094 const unsigned int n = control_points.size() - 1;
00095 Vec4d rat_res;
00096
00097 if(n < 1)
00098 {
00099 error = -1;
00100 rat_res = control_points[0];
00101 rat_res[0] = DCTP_EPS * floor(rat_res[0] / DCTP_EPS);
00102 rat_res[1] = DCTP_EPS * floor(rat_res[1] / DCTP_EPS);
00103 rat_res[2] = DCTP_EPS * floor(rat_res[2] / DCTP_EPS);
00104 rat_res[3] = DCTP_EPS * floor(rat_res[3] / DCTP_EPS);
00105 return rat_res;
00106 }
00107
00108 unsigned int i, k;
00109 Vec4d *Q = new Vec4d[n];
00110 const double t2 = 1.0 - t;
00111 const unsigned int n1 = n - 1;
00112
00113 for(i = 0; i < n; ++i)
00114 {
00115 const unsigned int i1 = i + 1;
00116 Q[i] = control_points[i] * t2 + control_points[i1] * t;
00117 }
00118
00119 for(k = 0; k < n1; ++k)
00120 {
00121 const unsigned int nk = n1 - k;
00122
00123 for(i = 0; i < nk; ++i)
00124 {
00125 const unsigned int i1 = i + 1;
00126 Q[i] *= t2;
00127 Q[i] += Q[i1] * t;
00128 }
00129 }
00130
00131 rat_res = Q[0];
00132
00133 delete[] Q;
00134 return rat_res;
00135
00136 }
00137
00139
00148 Vec3d BezierCurve3D::computeLinearApproximation(double t, int &error)
00149 {
00150
00151 DCTPVec4dvector::size_type n = control_points.size() - 1;
00152 Vec3d result(0.0, 0.0, 0.0);
00153 Vec4d rat_res;
00154
00155 if(n < 1)
00156 {
00157 error = -1;
00158 return result;
00159 }
00160 rat_res = control_points[0] * t + control_points[n] * (1 - t);
00161 result[0] = rat_res[0] / rat_res[3];
00162 result[1] = rat_res[1] / rat_res[3];
00163 result[2] = rat_res[2] / rat_res[3];
00164
00165 return (result);
00166 }
00167
00169
00179 int BezierCurve3D::midPointSubDivision(bezier3dvector &newbeziers)
00180 {
00181
00182 DCTPVec4dvector::size_type n = control_points.size();
00183
00184 if(n < 2)
00185 {
00186 return -1;
00187 }
00188
00189 newbeziers.resize(2);
00190 DCTPVec4dvector::size_type i, k;
00191
00192 DCTPVec4dvector &cp1 = newbeziers[0].control_points;
00193 DCTPVec4dvector &cp2 = newbeziers[1].control_points;
00194 cp1.clear();
00195 cp2.clear();
00196 cp1.resize(n);
00197 cp2.resize(n);
00198
00199 for(k = 0; k < n; ++k)
00200 {
00201 cp1[k] = control_points[k];
00202 }
00203
00204 --n;
00205
00206 for(k = 0; k < n; ++k)
00207 {
00208 cp2[n - k] = cp1[n];
00209
00210 for(i = n; i > k; --i)
00211 {
00212 cp1[i] += cp1[i - 1];
00213 cp1[i] *= 0.5;
00214 }
00215 }
00216
00217 cp2[0] = cp1[n];
00218
00219
00220 return 0;
00221 }
00222
00224
00234 int BezierCurve3D::midPointSubDivision(BezierCurve3D &newcurve)
00235 {
00236
00237 DCTPVec4dvector::size_type n = control_points.size();
00238
00239 if(n < 2)
00240 {
00241 return -1;
00242 }
00243
00244 DCTPVec4dvector::size_type i, k;
00245
00246 DCTPVec4dvector &cp1 = control_points;
00247 DCTPVec4dvector &cp2 = newcurve.control_points;
00248
00249 cp2.clear();
00250 cp2.resize(n);
00251
00252 --n;
00253
00254 for(k = 0; k < n; ++k)
00255 {
00256 cp2[n - k] = cp1[n];
00257
00258 for(i = n; i > k; --i)
00259 {
00260 cp1[i] += cp1[i - 1];
00261 cp1[i] *= 0.5;
00262 }
00263 }
00264
00265 cp2[0] = cp1[n];
00266
00267 return 0;
00268 }
00269
00271
00282 int BezierCurve3D::subDivision(double t, bezier3dvector &newbeziers)
00283 {
00284 if(t <= 0.0 || t >= 1.0)
00285 return -1;
00286
00287 newbeziers.resize(2);
00288 DCTPVec4dvector Q = control_points;
00289 DCTPVec4dvector::size_type n = control_points.size() - 1;
00290 DCTPVec4dvector cp1(n + 1);
00291 DCTPVec4dvector cp2(n + 1);
00292 if(n < 1)
00293 {
00294 return -1;
00295 }
00296
00297 for(DCTPVec4dvector::size_type k = 0; k < n; ++k)
00298 {
00299 cp1[k] = Q [0];
00300 cp2[n - k] = Q [n - k];
00301
00302 for(DCTPVec4dvector::size_type i = 0; i < n - k; ++i)
00303 {
00304 Q[i] = Q[i] * (1.0 - t) + Q[i + 1] * t;
00305 }
00306 }
00307
00308 cp1[n] = Q[0];
00309 cp2[0] = Q[0];
00310 newbeziers[0].setControlPointVector(cp1);
00311 newbeziers[1].setControlPointVector(cp2);
00312 return 0;
00313 }
00314
00316
00327 int BezierCurve3D::subDivision(double t, BezierCurve3D &newcurve)
00328 {
00329 if(t <= 0.0 || t >= 1.0)
00330 {
00331 return -1;
00332 }
00333
00334
00335 DCTPVec4dvector::size_type n = control_points.size();
00336
00337 if(n < 2)
00338 {
00339 return -1;
00340 }
00341
00342 double t2 = 1.0 - t;
00343
00344 DCTPVec4dvector::size_type i, k;
00345
00346 DCTPVec4dvector &cp1 = control_points;
00347 DCTPVec4dvector &cp2 = newcurve.control_points;
00348
00349 cp2.clear();
00350 cp2.resize(n);
00351
00352 --n;
00353
00354 for(k = 0; k < n; ++k)
00355 {
00356 cp2[n - k] = cp1[n];
00357
00358 for(i = n; i > k; --i)
00359 {
00360 cp1[i] *= t;
00361 cp1[i] += cp1[i - 1] * t2;
00362 }
00363 }
00364
00365 cp2[0] = cp1[n];
00366
00367 return 0;
00368 }
00369
00371
00380 int BezierCurve3D::approximate(std::vector<double> &vertices, double delta, unsigned char strategy)
00381 {
00382 vertices.resize(0);
00383
00384
00385 if(control_points.size() == 2)
00386 {
00387 vertices.push_back(0.0);
00388 vertices.push_back(1.0);
00389 return 0;
00390 }
00391
00392
00393 return approximate_sub(vertices, delta, 0.0, 1.0, strategy);
00394 }
00395
00396 int BezierCurve3D::approximate_sub(std::vector<double> &vertices, double delta, double min, double max, unsigned char strategy)
00397 {
00398 double max_error = 0;
00399 Vec3d ae;
00400 double aenorm;
00401 double t1, t2;
00402 int worst_i = 0;
00403 Vec3d n0_norm;
00404 DCTPVec3dvector eucl;
00405 DCTPVec4dvector mycps;
00406 int i;
00407 std::vector<double> t;
00408
00409 int n = control_points.size() - 1;
00410
00411 for(i = 0; i <= n; i++)
00412 {
00413 t.push_back((double( n - i ) ) / n);
00414 }
00415
00416
00417
00418 mycps = control_points;
00419
00420 for(i = 0; i <= n; ++i)
00421 {
00422 unsigned int s = mycps.size();
00423 bool ok = true;
00424
00425 mycps.push_back(mycps[s - 1]);
00426 t.push_back(t[s - 1]);
00427
00428 for(int j = s; j > i; --j)
00429 {
00430 mycps[j] = (mycps[j] + mycps[j - 1]) * 0.5f;
00431 t[j] = (t[j] + t[j - 1]) * 0.5f;
00432 if(mycps[j][2] < DCTP_EPS)
00433 ok = false;
00434 }
00435
00436 if(ok)
00437 break;
00438 }
00439
00440 n = mycps.size() - 1;
00441
00442 eucl.resize(n + 1);
00443
00444 for(i = 0; i <= n; ++i)
00445 {
00446 eucl[i][0] = mycps[i][0] / mycps[i][3];
00447 eucl[i][1] = mycps[i][1] / mycps[i][3];
00448 eucl[i][2] = mycps[i][2] / mycps[i][3];
00449 }
00450
00451 if( (strategy & DISTANCE) == LINE_DISTANCE)
00452 {
00453 n0_norm = eucl[n] - eucl[0];
00454 aenorm = n0_norm.squareLength();
00455 if(aenorm > 1e-300)
00456 {
00457 n0_norm *= 1.0 / aenorm;
00458 }
00459 else
00460 {
00461 n0_norm = Vec3d(0.0, 0.0, 0.0);
00462 }
00463 }
00464
00465 for(i = 0; i <= n; i++)
00466 {
00467 if( (strategy & DISTANCE) == POINT_DISTANCE)
00468 {
00469 t2 = 1.0 - t[i];
00470 }
00471 else
00472 {
00473 t2 = (eucl[i] - eucl[0]).dot(n0_norm);
00474 if(t2 < 0.0)
00475 {
00476 t2 = 0.0;
00477 }
00478 else if(t2 > 1.0)
00479 {
00480 t2 = 1.0;
00481 }
00482 }
00483 t1 = 1.0 - t2;
00484 ae = eucl[i] - eucl[0] * t1 - eucl[n] * t2;
00485
00486
00487
00488 aenorm = sqrt(ae.squareLength() );
00489 if(aenorm > max_error)
00490 {
00491 max_error = aenorm;
00492 worst_i = i;
00493 }
00494 }
00495
00496
00497
00498
00499
00500
00501 if(max_error > delta)
00502 {
00503
00504 BezierCurve3D newbez;
00505 int error;
00506 double mid;
00507 if( (strategy & SUBDIVISION) == MIDPOINT_SUBDIVISION)
00508 {
00509 error = midPointSubDivision(newbez);
00510 if(error)
00511 return error;
00512 mid = (min + max) * 0.5;
00513 }
00514 else
00515 {
00516 mid = (double(worst_i) ) / n;
00517 error = subDivision(mid, newbez);
00518 if(error)
00519 return error;
00520 mid = min + (max - min) * mid;
00521 }
00522 approximate_sub(vertices, delta, min, mid, strategy);
00523 newbez.approximate_sub(vertices, delta, mid, max, strategy);
00524 }
00525 else
00526 {
00527
00528 if(!vertices.size() )
00529 {
00530
00531
00532 vertices.push_back(min);
00533 vertices.push_back(max);
00534 }
00535 else
00536 {
00537
00538 vertices.push_back(max);
00539 }
00540 }
00541 return 0;
00542 }
00543
00544
00545 int BezierCurve3D::createCurve(DCTPVec4dvector &points)
00546 {
00547 int n = points.size() - 1;
00548
00549 if(n < 1)
00550 {
00551 return -1;
00552 }
00553
00554 control_points.resize(n + 1);
00555
00556 control_points[0] = points[0];
00557 control_points[n] = points[n];
00558
00559 if(n == 1)
00560 {
00561 return 0;
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 int i;
00578
00579
00580
00581 for(i = 1; i < n; ++i)
00582 {
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 control_points[i] = points[i];
00593 }
00594
00595
00596 double maxerr = 1.0;
00597
00598
00599
00600 unsigned int ui_exit = 0;
00601 while(maxerr > 1e-8)
00602 {
00603 std::vector<Vec4d> vcl_err(n + 1);
00604
00605 maxerr = 0.0;
00606
00607 for(i = 0; i <= n; ++i)
00608 {
00609 int err = 0;
00610 vcl_err[i] = points[i] - computewdeCasteljau4D( (double(i) ) / n, err);
00611
00612 double acterr = (vcl_err[i]).squareLength();
00613
00614 maxerr = osgMax(maxerr, acterr);
00615 }
00616
00617 for(i = 1; i < n; ++i)
00618 {
00619
00620 control_points[i] += vcl_err[i];
00621 }
00622
00623 if( (++ui_exit) > 10000)
00624 {
00625
00626
00627
00628
00629
00630
00631
00632
00633 return -2;
00634 }
00635 }
00636
00637 return 0;
00638 }
00639
00640
00642
00652 bool BezierCurve3D::reduceDegree(double tol)
00653 {
00654 UInt32 n = control_points.size() - 1;
00655 if(n < 2)
00656 {
00657
00658 return false;
00659 }
00660 DCTPVec4dvector b_left(n);
00661 DCTPVec4dvector b_right(n);
00662 UInt32 i;
00663
00664
00665 b_right[0] = control_points[0];
00666
00667 for(i = 1; i < n; ++i)
00668 {
00669 b_right[i] = (control_points[i] * n - b_right[i - 1] * i) *
00670 (1.0 / Real64(n - i));
00671 }
00672
00673
00674 b_left[n - 1] = control_points[n];
00675
00676 for(i = n - 1; i > 0; --i)
00677 {
00678 b_left[i - 1] = (control_points[i] * n - b_left[i] * (n - i)) *
00679 (1.0 / Real64(i));
00680 }
00681
00682
00683 Real64 quad_error = tol * tol;
00684 double dist4d;
00685
00686 unsigned int n_half = n >> 1;
00687 unsigned int n_half1 = (n + 1) >> 1;
00688
00689
00690
00691
00692
00693 for(i = n_half1; i < n; ++i)
00694 {
00695 b_right[i] = b_left[i];
00696 }
00697
00698 if(n_half != n_half1)
00699 {
00700 dist4d = b_right[n_half].dist2(b_left[n_half]);
00701 b_right[n_half] = b_left[n_half] * 0.5 + b_right[n_half] * 0.5;
00702 }
00703 else
00704 {
00705 dist4d = control_points[n_half].dist2(0.5 * (b_right[n_half - 1] + b_left[n_half]));
00706 }
00707
00708
00709
00710
00711 double minweight = b_right[0][3];
00712
00713 for(i = 1; i < n; ++i)
00714 {
00715 if(minweight > b_right[i][3])
00716 minweight = b_right[i][3];
00717 }
00718
00719 if(minweight < DCTP_EPS)
00720 {
00721
00722 return false;
00723 }
00724
00725 if(dist4d / (minweight * minweight) > quad_error)
00726 {
00727 return false;
00728 }
00729
00730 control_points = b_right;
00731
00732
00733 return true;
00734 }