00001 #ifndef CURVE_ALGOS
00002 #define CURVE_ALGOS
00003
00004 #include "minsegdist.h"
00005 #include "segdist.h"
00006
00007 #define ITERATE
00008 static int ITERATION;
00009
00010 template<class Vector>
00011 class ArcInfo{
00012 public:
00013 Vector b0,b1,b2;
00014 Vector m;
00015 float err,ferr,omega;
00016 ArcInfo(const Vector &a0,const Vector &a1,const Vector &a2)
00017 : b0(a0),b1(a1),b2(a2)
00018 {
00019 Vector b1b0 = b1-b0, b2b0 = b2-b0;
00020 b1b0.normalize(); b2b0.normalize();
00021 omega = b1b0.dot(b2b0);
00022 m = (b0+2.*omega*b1+b2)/(2.+2.*omega);
00023 err = (m-.5*(b0+b2)).norm();
00024 ferr = 2.+sqrt(2.+2.*omega);
00025 }
00026
00027 ArcInfo(const Vector &a0,const Vector &a1,const Vector &a2,
00028 const float &Err, const float &FErr)
00029 : b0(a0),b1(a1),b2(a2),err(Err),ferr(FErr)
00030 {
00031 Vector b1b0 = b1-b0, b2b0 = b2-b0;
00032 b1b0.normalize(); b2b0.normalize();
00033 omega = b1b0.dot(b2b0);
00034 m = (b0+2.*omega*b1+b2)/(2.+2.*omega);
00035 }
00036 };
00037
00038
00039 template<class Vector>
00040 class Candi {
00041 public:
00042 ArcInfo<Vector> a,b;
00043 float d;
00044
00045 Candi(const Vector &a0,const Vector &a1,const Vector &a2,
00046 const Vector &b0,const Vector &b1,const Vector &b2)
00047 : a(a0,a1,a2), b(b0,b1,b2)
00048 {
00049 static float dum1,dum2;
00050 d = min_seg_dist(a0,a2,b0,b2,dum1,dum2);
00051 }
00052
00053 Candi(const Vector &a0,const Vector &a1,const Vector &a2,
00054 const float &a_err,const float &a_ferr,
00055 const Vector &b0,const Vector &b1,const Vector &b2,
00056 const float &b_err,const float &b_ferr)
00057 : a(a0,a1,a2,a_err,a_ferr), b(b0,b1,b2,b_err,b_ferr)
00058 {
00059 static float dum1,dum2;
00060 d = min_seg_dist(a0,a2,b0,b2,dum1,dum2);
00061 }
00062
00063
00064 };
00065
00066 template<class Vector>
00067 inline ostream & operator<< (ostream &out, const Candi<Vector> &c) {
00068 Vector3 ta0 = (c.a.b1-c.a.b0); ta0.normalize();
00069 Vector3 ta1 = (c.a.b2-c.a.b1); ta1.normalize();
00070
00071 Vector3 tb0 = (c.b.b1-c.b.b0); tb0.normalize();
00072 Vector3 tb1 = (c.b.b2-c.b.b1); tb1.normalize();
00073
00074 out << c.a.b0 << " " << c.a.b2 << " " << ta0 << " " << ta1 << " "
00075 << c.b.b0 << " " << c.b.b2 << " " << tb0 << " " << tb1 << " " << c.d;
00076 return out;
00077 }
00078
00079 #define candi_it typename vector<Candi<Vector> >::iterator
00080
00081 template<class Vector>
00082 void get_it(Vector b0,Vector b1,Vector b2,float r,Vector &b, Vector &c) {
00083 b = (b0-b1).cross(b2-b1); b.normalize();
00084 Vector t0=(b1-b0); t0.normalize();
00085 c = (b0 + t0.cross(b)*r);
00086 }
00087
00088
00089 template<class Vector>
00090 int rhopt(Vector p, Vector b0,Vector b1,Vector b2,float r,Vector &v) {
00091 Vector b,c,aux;
00092 float val0 = (b1-b0).dot(b0-p),val1 = (b2-b1).dot(b2-p);
00093 if (val0<0 && val1 < 0) return 0;
00094 else if (val0<=0.0 && val1>=0.0) {
00095 get_it(b0,b1,b2,r,b,c);
00096 aux = p-c-b*b.dot(p-c);
00097 aux.normalize();
00098 v = c+aux*r;
00099 return 1;
00100 }
00101 else if (val0>=0.0 && val1<=0.0) {
00102 if (((b0-b1).cross(b2-b1)).dot(p-b1)==0.0) {
00103 get_it(b0,b1,b2,r,b,c);
00104 if (r<(p-c).norm()) {
00105 aux = p-c-b*b.dot(p-c);
00106 aux.normalize();
00107 v = c-aux*r;
00108 return 1;
00109 }
00110 else return 0;
00111 }
00112 else {
00113 get_it(b0,b1,b2,r,b,c);
00114 Vector centersph=c+b*(b.dot(p-c));
00115 float circ_cos= (b0-centersph).dot(b)/(b0-centersph).norm();
00116 float point_cos=(p-centersph).dot(b)/(p-centersph).norm();
00117 if (point_cos < circ_cos) {
00118 aux = p-c-b*b.dot(p-c);
00119 aux.normalize();
00120 v = c-aux*r;
00121 return 1;
00122 }
00123 else return 0;
00124 }
00125 }
00126 else if (val0>0 && val1>0) return 0;
00127
00128 return 0;
00129 }
00130
00134 template<class Vector>
00135 void dump_candidates(vector<Candi<Vector > > *C,int iter = 0) {
00136 for (candi_it i=C->begin();i!=C->end();++i)
00137 cerr << iter << " " << (*i) << endl;
00138 }
00139
00144 template<class Vector>
00145 float check_local_curvature(Curve<Vector>* c) {
00146
00147 float tmpf, min_diam = 2.*c->begin()->radius0();
00148 for (biarc_it it=c->begin();it!=c->end()-(c->isClosed()?0:1);++it) {
00149 tmpf = 2.0*it->radius0();
00150 if (tmpf < min_diam)
00151 if (tmpf > 0)
00152 min_diam = tmpf;
00153 tmpf = 2.0*it->radius1();
00154 if (tmpf < min_diam)
00155 if (tmpf > 0)
00156 min_diam = tmpf;
00157 }
00158 return min_diam;
00159 }
00160
00167 template<class Vector>
00168 void initial_dbl_crit_filter(Curve<Vector>* c,vector<Candi<Vector> > &CritC) {
00169
00170 Vector a0,am,a1,b0,bm,b1,t0a,tma,t1a,t0b,tmb,t1b;
00171
00172 Vector Ba0,Ba1,Ba2,Bb0,Bb1,Bb2;
00173
00174 for (biarc_it i=c->begin();i!=c->end()-(c->isClosed()?0:1);i++) {
00175 a0 = i->getPoint(); t0a = i->getTangent();
00176 am = i->getMidPoint(); tma = i->getMidTangent();
00177
00178 if (c->isClosed()) {
00179 if (i==c->end()-1) {
00180 a1 = c->begin()->getPoint(); t1a = c->begin()->getTangent();
00181 }
00182 else {
00183 a1 = (i+1)->getPoint(); t1a = (i+1)->getTangent();
00184 }
00185 }
00186 else {
00187 a1 = (i+1)->getPoint(); t1a = (i+1)->getTangent();
00188 }
00189
00190 for (biarc_it j=c->begin();j!=i;j++) {
00191 b0 = j->getPoint(); t0b = j->getTangent();
00192 bm = j->getMidPoint(); tmb = j->getMidTangent();
00193 b1 = (j+1)->getPoint(); t1b = (j+1)->getTangent();
00194
00195
00196
00197
00198 if (double_critical_test(a0,am,t0a,tma,b0,bm,t0b,tmb)) {
00199 i->getBezierArc0(Ba0,Ba1,Ba2); j->getBezierArc0(Bb0,Bb1,Bb2);
00200 CritC.push_back(Candi<Vector>(Ba0,Ba1,Ba2,Bb0,Bb1,Bb2));
00201 }
00202
00203
00204
00205 if ((i-1)!=j) {
00206 if (double_critical_test(a0,am,t0a,tma,bm,b1,tmb,t1b)) {
00207 i->getBezierArc0(Ba0,Ba1,Ba2); j->getBezierArc1(Bb0,Bb1,Bb2);
00208 CritC.push_back(Candi<Vector>(Ba0,Ba1,Ba2,Bb0,Bb1,Bb2));
00209 }
00210 }
00211
00212
00213
00214 if (i!=c->end()-1 && j==c->begin()){
00215 if (double_critical_test(am,a1,tma,t1a,b0,bm,t0b,tmb)) {
00216 i->getBezierArc1(Ba0,Ba1,Ba2); j->getBezierArc0(Bb0,Bb1,Bb2);
00217 CritC.push_back(Candi<Vector>(Ba0,Ba1,Ba2,Bb0,Bb1,Bb2));
00218 }
00219 }
00220
00221 if (double_critical_test(am,a1,tma,t1a,bm,b1,tmb,t1b)) {
00222 i->getBezierArc1(Ba0,Ba1,Ba2); j->getBezierArc1(Bb0,Bb1,Bb2);
00223 CritC.push_back(Candi<Vector>(Ba0,Ba1,Ba2,Bb0,Bb1,Bb2));
00224 }
00225 }
00226 }
00227
00228
00229 }
00230
00238 template<class Vector>
00239 void dbl_crit_filter(vector<Candi<Vector> > &C,vector<Candi<Vector> > &CritC) {
00240
00241
00242 CritC.clear();
00243
00244 for (candi_it i=C.begin();i!=C.end();i++) {
00245
00246
00247
00248
00249
00250
00251 if (double_critical_test_v2(i->a.b0,.5*(i->a.b0+i->a.b1),i->a.m,
00252 i->b.b0,.5*(i->b.b0+i->b.b1),i->b.m)) {
00253 CritC.push_back(Candi<Vector>(
00254 i->a.b0,.5*(i->a.b0+i->a.b1),i->a.m,i->a.err/i->a.ferr,i->a.ferr,
00255 i->b.b0,.5*(i->b.b0+i->b.b1),i->b.m,i->b.err/i->b.ferr,i->b.ferr
00256 ));
00257 }
00258
00259 if (double_critical_test_v2(i->a.b0,.5*(i->a.b0+i->a.b1),i->a.m,
00260 i->b.m,.5*(i->b.b1+i->b.b2),i->b.b2)) {
00261 CritC.push_back(Candi<Vector>(
00262 i->a.b0,.5*(i->a.b0+i->a.b1),i->a.m,i->a.err/i->a.ferr,i->a.ferr,
00263 i->b.m,.5*(i->b.b1+i->b.b2),i->b.b2,i->b.err/i->b.ferr,i->b.ferr
00264 ));
00265 }
00266
00267 if (double_critical_test_v2(i->a.m,.5*(i->a.b1+i->a.b2),i->a.b2,
00268 i->b.b0,.5*(i->b.b0+i->b.b1),i->b.m)) {
00269 CritC.push_back(Candi<Vector>(
00270 i->a.m,.5*(i->a.b1+i->a.b2),i->a.b2,i->a.err/i->a.ferr,i->a.ferr,
00271 i->b.b0,.5*(i->b.b0+i->b.b1),i->b.m,i->b.err/i->b.ferr,i->b.ferr
00272 ));
00273 }
00274
00275 if (double_critical_test_v2(i->a.m,.5*(i->a.b1+i->a.b2),i->a.b2,
00276 i->b.m,.5*(i->b.b1+i->b.b2),i->b.b2)) {
00277 CritC.push_back(Candi<Vector>(
00278 i->a.m,.5*(i->a.b1+i->a.b2),i->a.b2,i->a.err/i->a.ferr,i->a.ferr,
00279 i->b.m,.5*(i->b.b1+i->b.b2),i->b.b2,i->b.err/i->b.ferr,i->b.ferr
00280 ));
00281 }
00282 }
00283
00284
00285 }
00286
00287
00294 template<class Vector>
00295 void compute_thickness_bounds(vector<Candi<Vector> > &C,float md, float &lb, float &ub, float &err) {
00296
00297 float D_lb = 1e8, D_ub = 1e8;
00298 float max_err = 0, rel_err, tmperr, tmpf;
00299
00300 for (candi_it i=C.begin();i!=C.end();i++) {
00301 tmperr = i->a.err+i->b.err;
00302 if (tmperr>max_err) max_err = tmperr;
00303
00304 tmpf = i->d - tmperr;
00305 if (tmpf<D_lb) D_lb = tmpf;
00306 tmpf = i->d + tmperr;
00307 if (tmpf<D_ub) D_ub = tmpf;
00308 }
00309 lb = (D_lb<md?D_lb:md);
00310 ub = (D_ub<md?D_ub:md);
00311 err = max_err;
00312
00313
00314
00315
00316
00317
00318 }
00319
00320
00325 template<class Vector>
00326 void distance_filter(vector<Candi<Vector> > &C,vector<Candi<Vector> > &Cfiltered) {
00327
00328 float d_b = 1e8, tmpf;
00329 if (Cfiltered.size()!=0)
00330 Cfiltered.clear();
00331 for (candi_it i=C.begin();i!=C.end();i++) {
00332 tmpf = i->a.err+i->b.err+i->d;
00333 if (tmpf<d_b) d_b = tmpf;
00334 }
00335 for (candi_it i=C.begin();i!=C.end();i++) {
00336 tmpf = i->d - i->a.err - i->b.err;
00337 if (tmpf<=d_b) {
00338 Cfiltered.push_back(*i);
00339 }
00340 }
00341
00342 }
00343
00344 template<class Vector>
00345 float compute_thickness(Curve<Vector> *c, Vector *from = NULL, Vector *to = NULL) {
00346
00347 const float rel_err_tol = 1e-12;
00348
00349 biarc_it current, var;
00350 Vector *tmp, *tmpmin; static int cbiarc = 0;
00351 float min_diam = 1e8, tmpf; Vector thick_1, thick_2;
00352 min_diam = check_local_curvature(c);
00353
00354
00355
00356 vector<Candi<Vector> > CritC, DistC;
00357
00358
00359 initial_dbl_crit_filter(c,CritC);
00360
00361
00362 distance_filter(CritC,DistC);
00363
00364
00365 float D_lb = 1e8, D_ub = 1e8;
00366 float max_err = 0, rel_err;
00367 compute_thickness_bounds(DistC,min_diam,D_lb,D_ub,max_err);
00368 rel_err = max_err/D_lb*2.;
00369
00370 ITERATION = 0;
00371
00372 #ifdef ITERATE
00373
00374
00375
00376 if (min_diam <= D_lb) cout << "Curvature active!\n";
00377 while(rel_err > rel_err_tol && min_diam > D_lb) {
00378 ++ITERATION;
00379
00380
00381 dbl_crit_filter(DistC,CritC);
00382
00383 if (CritC.size()==0) {
00384 cout << "CritIter : CritC is empty (curvature active?)\n";
00385 D_lb = D_ub = min_diam;
00386 break;
00387 }
00388
00389
00390 compute_thickness_bounds(DistC,min_diam,D_lb,D_ub,max_err);
00391
00392
00393 distance_filter(CritC,DistC);
00394
00395
00396 if (DistC.size()==0) {
00397 cout << "BoundsIter : DistC is empty (curvature active?)\n";
00398 D_lb = D_ub = min_diam;
00399 break;
00400 }
00401
00402
00403 compute_thickness_bounds(DistC,min_diam,D_lb,D_ub,max_err);
00404
00405 rel_err = max_err/D_lb*2.;
00406 }
00407
00408 #endif // ITERATE
00409
00410
00411
00412
00413
00414
00415 CritC.clear(); DistC.clear();
00416 return D_lb;
00417 }
00418
00419 #endif // CURVE_ALGOS