00001
00002
00003
00004
00005
00006
00007
00008 #include "points.h"
00009 #include "BiArc.h"
00010 #include "euler.h"
00011 #include <utils/common/StdDefs.h>
00012 #include <complex>
00013 #include <iostream>
00014
00015 #define eGamma 1e-8
00016
00017
00018 static EulerSpiralLookupTable *globalEulerSpiralLookupTable;
00019
00020
00021 EulerSpiralLookupTable* EulerSpiralLookupTable::get_globalEulerSpiralLookupTable()
00022 {
00023 if (! globalEulerSpiralLookupTable)
00024 globalEulerSpiralLookupTable = new EulerSpiralLookupTable();
00025
00026 return globalEulerSpiralLookupTable;
00027 }
00028
00029 EulerSpiralLookupTable::EulerSpiralLookupTable()
00030 {
00031 int i,j;
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 }
00096
00097 EulerSpiralLookupTable::~EulerSpiralLookupTable()
00098 {
00099 int i;
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 }
00130
00131
00132 double EulerSpiralLookupTable::dt()
00133 {
00134 return _dt;
00135 }
00136
00137 double EulerSpiralLookupTable::theta(int N)
00138 {
00139 return _theta[N];
00140 }
00141
00142 double EulerSpiralLookupTable::k0(double start_angle, double end_angle)
00143 {
00144
00145 double sangle, eangle;
00146
00147 if (start_angle>M_PI) sangle = start_angle-2*M_PI;
00148 else sangle = start_angle;
00149
00150 if (end_angle>M_PI) eangle = end_angle-2*M_PI;
00151 else eangle = end_angle;
00152
00153
00154 int ilow, ihigh, jlow, jhigh;
00155
00156 ilow = (int)floor((sangle+M_PI)/_dt);
00157 ihigh = (int)ceil((sangle+M_PI)/_dt);
00158
00159 jlow = (int)floor((eangle+M_PI)/_dt);
00160 jhigh = (int)ceil((eangle+M_PI)/_dt);
00161
00162 double slow = _theta[ilow];
00163 double shigh = _theta[ihigh];
00164 double elow = _theta[jlow];
00165 double ehigh = _theta[jhigh];
00166
00167 double a = (sangle - slow)/_dt;
00168 double b = (eangle - elow)/_dt;
00169
00170 double k0 = (1-a)*(1-b)*ES_k0[ilow][jlow] + a*(1-b)*ES_k0[ihigh][jlow] +
00171 (1-a)*b*ES_k0[ilow][jhigh] + a*b*ES_k0[ihigh][jhigh];
00172
00173 return k0;
00174 }
00175
00176 double EulerSpiralLookupTable::k1(double start_angle, double end_angle)
00177 {
00178
00179
00180
00181 double sangle, eangle;
00182
00183 if (start_angle>M_PI) sangle = start_angle-2*M_PI;
00184 else sangle = start_angle;
00185
00186 if (end_angle>M_PI) eangle = end_angle-2*M_PI;
00187 else eangle = end_angle;
00188
00189
00190 int ilow, ihigh, jlow, jhigh;
00191
00192 ilow = (int)floor((sangle+M_PI)/_dt);
00193 ihigh = (int)ceil((sangle+M_PI)/_dt);
00194
00195 jlow = (int)floor((eangle+M_PI)/_dt);
00196 jhigh = (int)ceil((eangle+M_PI)/_dt);
00197
00198 double slow = _theta[ilow];
00199 double shigh = _theta[ihigh];
00200 double elow = _theta[jlow];
00201 double ehigh = _theta[jhigh];
00202
00203 double a = (sangle - slow)/_dt;
00204 double b = (eangle - elow)/_dt;
00205
00206 double k1 = (1-a)*(1-b)*ES_k1[ilow][jlow] + a*(1-b)*ES_k1[ihigh][jlow] +
00207 (1-a)*b*ES_k1[ilow][jhigh] + a*b*ES_k1[ihigh][jhigh];
00208
00209 return k1;
00210 }
00211
00212 double EulerSpiralLookupTable::gamma(double start_angle, double end_angle)
00213 {
00214
00215
00216
00217 double sangle, eangle;
00218
00219 if (start_angle>M_PI) sangle = start_angle-2*M_PI;
00220 else sangle = start_angle;
00221
00222 if (end_angle>M_PI) eangle = end_angle-2*M_PI;
00223 else eangle = end_angle;
00224
00225
00226 int ilow, ihigh, jlow, jhigh;
00227
00228 ilow = (int)floor((sangle+M_PI)/_dt);
00229 ihigh = (int)ceil((sangle+M_PI)/_dt);
00230
00231 jlow = (int)floor((eangle+M_PI)/_dt);
00232 jhigh = (int)ceil((eangle+M_PI)/_dt);
00233
00234 double slow = _theta[ilow];
00235 double shigh = _theta[ihigh];
00236 double elow = _theta[jlow];
00237 double ehigh = _theta[jhigh];
00238
00239 double a = (sangle - slow)/_dt;
00240 double b = (eangle - elow)/_dt;
00241
00242 double gamma = (1-a)*(1-b)*ES_gamma[ilow][jlow] + a*(1-b)*ES_gamma[ihigh][jlow] +
00243 (1-a)*b*ES_gamma[ilow][jhigh] + a*b*ES_gamma[ihigh][jhigh];
00244
00245 return gamma;
00246 }
00247
00248 double EulerSpiralLookupTable::L(double start_angle, double end_angle)
00249 {
00250
00251
00252
00253 double sangle, eangle;
00254
00255 if (start_angle>M_PI) sangle = start_angle-2*M_PI;
00256 else sangle = start_angle;
00257
00258 if (end_angle>M_PI) eangle = end_angle-2*M_PI;
00259 else eangle = end_angle;
00260
00261
00262 int ilow, ihigh, jlow, jhigh;
00263
00264 ilow = (int)floor((sangle+M_PI)/_dt);
00265 ihigh = (int)ceil((sangle+M_PI)/_dt);
00266
00267 jlow = (int)floor((eangle+M_PI)/_dt);
00268 jhigh = (int)ceil((eangle+M_PI)/_dt);
00269
00270 double slow = _theta[ilow];
00271 double shigh = _theta[ihigh];
00272 double elow = _theta[jlow];
00273 double ehigh = _theta[jhigh];
00274
00275 double a = (sangle - slow)/_dt;
00276 double b = (eangle - elow)/_dt;
00277
00278 double L = (1-a)*(1-b)*ES_L[ilow][jlow] + a*(1-b)*ES_L[ihigh][jlow] +
00279 (1-a)*b*ES_L[ilow][jhigh] + a*b*ES_L[ihigh][jhigh];
00280
00281 return L;
00282 }
00283
00284
00285
00286
00287
00288 void EulerSpiral::compute_es_params ()
00289 {
00290
00291 double d = euc_distance(params.start_pt, params.end_pt);
00292 params.psi = angle0To2Pi(atan2(params.end_pt.y()-params.start_pt.y(),params.end_pt.x()-params.start_pt.x()));
00293
00294
00295 if (d<eError)
00296 return;
00297
00298
00299 _bi_arc_estimate.set_start_params(params.start_pt, params.start_angle);
00300 _bi_arc_estimate.set_end_params(params.end_pt, params.end_angle);
00301 _bi_arc_estimate.compute_biarc_params();
00302
00303
00304
00305 params.turningAngle = _bi_arc_estimate.params.K1*_bi_arc_estimate.params.L1 +
00306 _bi_arc_estimate.params.K2*_bi_arc_estimate.params.L2;
00307
00308
00309
00310 double k0_init_est = _bi_arc_estimate.params.K1*d;
00311 double L_init_est = _bi_arc_estimate.params.L()/d;
00312 double dstep = 0.1;
00313
00314
00315
00316
00317
00318
00319
00320
00321 double error = compute_error(k0_init_est, L_init_est);
00322 double prev_error = error;
00323
00324 double k0 = k0_init_est;
00325 double L = L_init_est;
00326
00327 double e1, e2, e3, e4;
00328
00329 for (int i=0;i<MAX_NUM_ITERATIONS;i++)
00330 {
00331 if (error<eError)
00332 break;
00333
00334 e1 = compute_error(k0 + dstep, L);
00335 e2 = compute_error(k0 - dstep, L);
00336 e3 = compute_error(k0, L + dstep);
00337 if (L>dstep) e4 = compute_error(k0, L - dstep);
00338
00339 error = MIN2(MIN2(e1,e2),MIN2(e3,e4));
00340
00341 if (error>prev_error)
00342 {
00343 dstep = dstep/2;
00344 continue;
00345 }
00346
00347 if (error==e1) k0 = k0 + dstep;
00348 else if (error==e2) k0 = k0 - dstep;
00349 else if (error==e3) L = L + dstep;
00350 else if (error==e4) L = L - dstep;
00351
00352 prev_error = error;
00353 }
00354
00355
00356 params.K0 = k0/d;
00357 params.L = L*d;
00358 params.gamma = 2*(params.turningAngle - k0*L)/(L*L)/(d*d);
00359 params.K2 = (k0 + params.gamma*L)/d;
00360 params.error = error;
00361 }
00362
00363
00364 void EulerSpiral::computeSpiral(std::vector<Point2D<double> > &spiral, double ds, int NPts)
00365 {
00366 if (ds==0 && NPts==0){
00367
00368 NPts = 100;
00369 ds = params.L/NPts;
00370 }
00371
00372 spiral.clear();
00373 spiral.push_back(params.start_pt);
00374
00375 double s=ds;
00376 if (NPts == 0)
00377 NPts = (int) (params.L / ds);
00378 for (int i=1; i<NPts; i++,s+=ds){
00379 Point2D<double> cur_pt = compute_end_pt(s);
00380 spiral.push_back(cur_pt);
00381 }
00382 spiral.push_back(params.end_pt);
00383 }
00384
00386
00388
00389 Point2D<double> EulerSpiral::compute_es_point(EulerSpiralParams& es_params, double arclength, bool bNormalized)
00390 {
00391 params = es_params;
00392 return compute_end_pt(params.K0, params.gamma, arclength, bNormalized);
00393 }
00394
00395 Point2D<double> EulerSpiral::compute_end_pt(double arclength, bool bNormalized)
00396 {
00397 return compute_end_pt(params.K0, params.gamma, arclength, bNormalized);
00398 }
00399
00400 Point2D<double> EulerSpiral::compute_end_pt(double k0, double gamma, double L, bool bNormalized)
00401 {
00402 Point2D<double> start_pt;
00403 Point2D<double> end_pt;
00404
00405 double theta;
00406
00407 if (bNormalized){
00408 start_pt = Point2D<double>(0,0);
00409 theta = CCW(params.psi, params.start_angle);
00410 }
00411 else {
00412 start_pt = params.start_pt;
00413 theta = params.start_angle;
00414 }
00415
00416 if (L==0)
00417 return start_pt;
00418
00419 if (fabs(gamma)<eGamma)
00420 {
00421 if (fabs(k0)<eK)
00422 {
00423
00424 end_pt.setX(start_pt.getX()+L*cos(theta));
00425 end_pt.setY(start_pt.getY()+L*sin(theta));
00426 }
00427 else
00428 {
00429
00430 double const_term = 1.0/k0;
00431 end_pt.setX(start_pt.getX()+const_term*(sin(k0*L+theta)-sin(theta)));
00432 end_pt.setY(start_pt.getY()-const_term*(cos(k0*L+theta)-cos(theta)));
00433 }
00434 return end_pt;
00435 }
00436
00437 double const1 = sqrt(M_PI*fabs(gamma));
00438 double const2 = sqrt(M_PI/fabs(gamma));
00439
00440 Point2D<double> fresnel1 = get_fresnel_integral((k0+gamma*L)/const1);
00441 Point2D<double> fresnel2 = get_fresnel_integral(k0/const1);
00442
00443 double C = (fresnel1.getX() - fresnel2.getX());
00444 if(gamma<0) {
00445 C *= -1.;
00446 }
00447 double S = fresnel1.getY() - fresnel2.getY();
00448
00449 double cos_term = cos(theta-((k0*k0)/(2.0*gamma)));
00450 double sin_term = sin(theta-((k0*k0)/(2.0*gamma)));
00451
00452 end_pt.setX(start_pt.getX() + const2*(C*cos_term - S*sin_term));
00453 end_pt.setY(start_pt.getY() + const2*(C*sin_term + S*cos_term));
00454
00455 return end_pt;
00456 }
00457
00458 inline double EulerSpiral::compute_error(double k0, double L)
00459 {
00460
00461
00462
00463 double gamma = 2*(params.turningAngle - k0*L)/(L*L);
00464 Point2D<double> cur_end_pt = compute_end_pt(k0, gamma, L, true);
00465
00466
00467 return euc_distance(Point2D<double>(1,0), cur_end_pt);
00468 }
00469
00470
00471
00472
00473
00474
00475
00476 #define EPS 6.0e-8
00477 #define MAXIT 100
00478 #define FPMIN 1.0e-30
00479 #define XMIN 1.5
00480
00481
00482 Point2D<double> EulerSpiral::get_fresnel_integral(double x)
00483 {
00484 bool odd;
00485 int k,n;
00486 double a,ax,fact,pix2,sign,sum,sumc,sums,term,test;
00487
00488 std::complex<double> b,cc,d,h,del,cs;
00489 Point2D<double> result;
00490
00491 ax=fabs(x);
00492 if (ax < sqrt(FPMIN))
00493 {
00494
00495 result.setY(0.0);
00496 result.setX(ax);
00497 }
00498 else {
00499 if (ax <= XMIN)
00500 {
00501
00502 sum=sums=0.0;
00503 sumc=ax;
00504 sign=1.0;
00505 fact=(M_PI/2.0)*ax*ax;
00506 odd=true;
00507 term=ax;
00508 n=3;
00509
00510 for (k=1;k<=MAXIT;k++)
00511 {
00512 term *= fact/k;
00513 sum += sign*term/n;
00514 test=fabs(sum)*EPS;
00515 if (odd)
00516 {
00517 sign = -sign;
00518 sums=sum;
00519 sum=sumc;
00520 }
00521 else {
00522 sumc=sum;
00523 sum=sums;
00524 }
00525
00526 if (term < test) break;
00527 odd=!odd;
00528 n +=2;
00529 }
00530
00531 if (k > MAXIT)
00532 std::cout << "series failed in fresnel" << std::endl;
00533
00534 result.setY(sums);
00535 result.setX(sumc);
00536 }
00537 else {
00538
00539 pix2=M_PI*ax*ax;
00540 b = std::complex<double>(1.0,-pix2);
00541 cc = std::complex<double>(1.0/FPMIN,0.0);
00542 d=h = std::complex<double>(1.0,0.0)/b;
00543 n = -1;
00544
00545 for (k=2;k<=MAXIT;k++)
00546 {
00547 n +=2;
00548 a = -n*(n+1);
00549 b= b+std::complex<double>(4.0,0.0);
00550 d=(std::complex<double>(1.0,0.0)/((a*d)+b));
00551
00552
00553 cc=(b+(std::complex<double>(a,0.0)/cc));
00554
00555 del=(cc*d);
00556 h=h*del;
00557 if ((fabs(del.real()-1.0)+fabs(del.imag())) < EPS)
00558 break;
00559 }
00560 if (k > MAXIT)
00561 std::cout << "cf failed in frenel" << std::endl;
00562
00563 h=std::complex<double>(ax,-ax)*h;
00564 cs=std::complex<double>(0.5,0.5)*(std::complex<double>(1.0,0.0) - std::complex<double>(cos(0.5*pix2),sin(0.5*pix2))*h );
00565
00566 result.setX(cs.real());
00567 result.setY(cs.imag());
00568 }
00569 }
00570
00571 if (x<0){
00572 result = -1*result;
00573 }
00574
00575 return result;
00576 }
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610