curvealgos.h

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; // Midpoint
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   // // Second constructor for iteration part
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 // Possible candidate for thickness achievement
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   // friend ostream & operator <<(ostream &out, const Candi<Vector> &c);
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 // jana page 100
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;//cerr << "No min inside arc,min on endpoint\n";
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;// cerr << "No min inside arc\n";
00127 
00128   return 0; //(new Vector(0,0,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   // First we check the local redii of the arcs
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   // Temporary Bezier points
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       // Now double criticle all 4 possibilities
00196       // excluding next neighbors
00197       // arc a1 - b1
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       // arc a1 - b2
00204       // do not compare neighboring arcs
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       // arc a2 - b1
00212       // if the biarcs are neighbours we do not compare these
00213       // neighboring arcs!
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       // arc a2 - b2
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   //cout << "Criticality candidates : " << CritC.size() <<  endl;
00229 }
00230 
00238 template<class Vector>
00239 void dbl_crit_filter(vector<Candi<Vector> > &C,vector<Candi<Vector> > &CritC) {
00240 
00241   // Double Critical Test
00242   CritC.clear();
00243 
00244   for (candi_it i=C.begin();i!=C.end();i++) {
00245   // for each candidate use the bezier points
00246   // in double_critical_test_v2 and
00247   // put the correct 3 Bezier points in the subdiv arc!!!
00248   // example if we need the left sub arc of a0,a1,a2,m
00249   // subarc Bezier points are given by a0,(a0+a1)/2,m !!!
00250     // arc a1 - b1
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     // arc a1 - b2
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     // arc a2 - b1
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     // arc a2 - b2
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 //    cout << ITERATION << " : No crit : " << CritC.size() << endl;
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   // Initial Thickness Bounds
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   cout << "Bounds : \n";
00315   cout << "max_err/rel_err : " << max_err << "/" << (max_err/D_lb*2.) << endl;
00316   cout << "D_lb/D_ub       : " << lb << "/" << ub << endl;
00317 */
00318 }
00319 
00320 
00325 template<class Vector>
00326 void distance_filter(vector<Candi<Vector> > &C,vector<Candi<Vector> > &Cfiltered) {
00327   //cout << "Distance Test\n";
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   //cout << "Distance Candidates : " << Cfiltered.size() << endl;
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   // Double critical candidates
00355   // Distance check passed candidates
00356   vector<Candi<Vector> > CritC, DistC;
00357 
00358   // Initial double critical test
00359   initial_dbl_crit_filter(c,CritC);
00360 
00361   // Initial Distance Test
00362   distance_filter(CritC,DistC);
00363 
00364   // Initial Thickness Bounds
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   // Bisection loop while relative error larger than our given
00375   // tolerance and while D_lb smaller than the minimal 2*radius
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     // Bisect Candidates
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     // Bounds
00390     compute_thickness_bounds(DistC,min_diam,D_lb,D_ub,max_err);
00391 
00392     // Distance Test
00393     distance_filter(CritC,DistC);
00394 
00395     // Thickness Bounds
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     // Bounds
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   //cout << "Number of iterations : " << ITERATION << endl;
00411   //cout << "Thick upper bound    : " << D_ub << endl;
00412   //cout << "Thick lower bound    : " << D_lb << endl;
00413 //  if (from!=NULL && to!=NULL) {
00414 //    *from = thick_1; *to = thick_2;
00415   CritC.clear(); DistC.clear();
00416   return D_lb;
00417 }
00418 
00419 #endif // CURVE_ALGOS

Generated on Mon Feb 8 17:22:35 2010 for libbiarc by  doxygen 1.5.6