inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/dct
Go to the documentation of this file.
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
00002 // See the file inlib.license for terms.
00003 
00004 #ifndef inlib_dct
00005 #define inlib_dct
00006 
00007 // A Delaunay triangulation algorithm.
00008 // From Geoff Leach dct C code. See credit at end.
00009 // C++ version done by G.Barrand in June 2010.
00010 
00011 #include <vector>
00012 #include <string>
00013 #include <ostream>
00014 
00015 namespace inlib {
00016 namespace dct {
00017 
00018 typedef float real;
00019 
00020 class edge;
00021 
00022 class point {
00023 public:
00024   real x,y;
00025   edge* entry_pt;
00026 };
00027 
00028 class edge {
00029 public:
00030   point* org;
00031   point* dest;
00032   edge* onext;
00033   edge* oprev;
00034   edge* dnext;
00035   edge* dprev;
00036 };
00037 
00038 class triangle {
00039 public:
00040   triangle(unsigned int a_1,unsigned int a_2,unsigned int a_3)
00041   :m_1(a_1),m_2(a_2),m_3(a_3)
00042   {}
00043 public:
00044   triangle(const triangle& a_from)
00045   :m_1(a_from.m_1),m_2(a_from.m_2),m_3(a_from.m_3)
00046   {}
00047   triangle& operator=(const triangle& a_from) {
00048     m_1 = a_from.m_1;
00049     m_2 = a_from.m_2;
00050     m_3 = a_from.m_3;
00051     return *this;
00052   }
00053   unsigned int index_1() const { return m_1;}
00054   unsigned int index_2() const { return m_2;}
00055   unsigned int index_3() const { return m_3;}
00056 private:
00057   unsigned int m_1;
00058   unsigned int m_2;
00059   unsigned int m_3;
00060 };
00061 
00062 class alg {
00063 public:
00064   typedef enum {right, left} side;
00065   typedef unsigned int index_t; /* G.Barrand : have _t. */
00066 
00067 public:
00068   alg(std::ostream& a_out)
00069   :m_out(a_out)
00070   ,p_number(0),p_array(0)
00071   ,e_array(0)
00072   ,free_list_e(0)
00073   ,n_free_e(0)
00074   {}
00075   virtual ~alg(){
00076     delete [] p_array;
00077     delete [] e_array;  
00078     delete [] free_list_e;  
00079   }
00080 private:
00081   alg(const alg& a_from):m_out(a_from.m_out){}
00082   alg& operator=(const alg&){return *this;}
00083 public:
00084   bool process(const std::vector< std::pair<real,real> >& a_data){
00085     delete [] p_array;
00086     delete [] e_array;  
00087     delete [] free_list_e;  
00088 
00089     p_number = a_data.size();
00090     //alloc :
00091     p_array = new point[p_number];
00092     // edges :
00093     n_free_e = 3 * p_number;   /* Eulers relation */
00094     e_array = new edge[n_free_e];
00095     if(!e_array) {
00096       panic("Not enough memory\n");
00097       return false;
00098     }
00099     typedef edge* ept;
00100     free_list_e = new ept[n_free_e];
00101     if(!free_list_e) {
00102       panic("Not enough memory\n");
00103       return false;
00104     }
00105    {edge* e = e_array;
00106     for(unsigned int i=0;i<n_free_e;i++,e++) free_list_e[i] = e;}
00107   
00108     point* pos = p_array;
00109     std::vector< std::pair<real,real> >::const_iterator it;  
00110     for (it=a_data.begin();it!=a_data.end();++it,++pos) {
00111       (*pos).x = (*it).first;
00112       (*pos).y = (*it).second;
00113       (*pos).entry_pt = 0;
00114     }
00115 
00116 
00117     // sort :
00118     typedef point* ppt;
00119     ppt* p_sorted = new ppt[p_number];
00120     if(!p_sorted) {
00121       panic("Not enough memory\n");
00122       return false;
00123     }
00124 
00125     ppt* p_temp = new ppt[p_number];
00126     if(!p_temp) {
00127       panic("Not enough memory\n");
00128       return false;
00129     }
00130    {for (unsigned int i = 0; i < p_number; i++) p_sorted[i] = p_array + i;}
00131     merge_sort(p_sorted, p_temp, 0, p_number-1);  
00132     delete [] p_temp;
00133 
00134 
00135     // triangulate :
00136     edge* l_cw;
00137     edge* r_ccw;
00138     divide(p_sorted, 0, p_number-1, &l_cw, &r_ccw);
00139   
00140     delete [] p_sorted;
00141 
00142     return true;
00143   }
00144 
00145   std::vector<triangle> get_triangles() {
00146     std::vector<triangle> ts;
00147     //  Print the ring of triangles about each vertex.
00148     edge *e_start, *e, *next;
00149     point *u, *v, *w;
00150     index_t i;
00151     point *t;
00152   
00153     for (i = 0; i < p_number; i++) {
00154       u = &p_array[i];
00155       e_start = e = u->entry_pt;
00156       do
00157       {
00158         v = Other_point(e, u);
00159         if (u < v) {
00160         next = Next(e, u);
00161         w = Other_point(next, u);
00162         if (u < w)
00163           if (Identical_refs(Next(next, w), Prev(e, v))) {  
00164             /* Triangle. */
00165             if (v > w) { t = v; v = w; w = t; }
00166 
00167             ts.push_back(triangle((unsigned int)(u - p_array),
00168                                   (unsigned int)(v - p_array),
00169                                   (unsigned int)(w - p_array)));
00170           }
00171         }
00172   
00173         /* Next edge around u. */
00174         e = Next(e, u);
00175       } while (!Identical_refs(e, e_start));
00176     }
00177 
00178     return ts;
00179   }
00180 
00181   void print_triangles() {
00182     //  Print the ring of triangles about each vertex.
00183     edge *e_start, *e, *next;
00184     point *u, *v, *w;
00185     index_t i;
00186     point *t;
00187   
00188     for (i = 0; i < p_number; i++) {
00189       u = &p_array[i];
00190       e_start = e = u->entry_pt;
00191       do
00192       {
00193         v = Other_point(e, u);
00194         if (u < v) {
00195         next = Next(e, u);
00196         w = Other_point(next, u);
00197         if (u < w)
00198           if (Identical_refs(Next(next, w), Prev(e, v))) {  
00199             /* Triangle. */
00200             if (v > w) { t = v; v = w; w = t; }
00201             m_out << (unsigned long)(u - p_array)
00202                   << " " << (unsigned long)(v - p_array)
00203                   << " " << (unsigned long)(w - p_array)
00204                   << std::endl;
00205           }
00206         }
00207   
00208         /* Next edge around u. */
00209         e = Next(e, u);
00210       } while (!Identical_refs(e, e_start));
00211     }
00212   }
00213 
00214   void divide(point *p_sorted[], index_t l, index_t r, edge **l_ccw, edge **r_cw)
00215   {
00216     unsigned int n;
00217     index_t split;
00218     edge *l_ccw_l, *r_cw_l, *l_ccw_r, *r_cw_r, *l_tangent;
00219     edge *a, *b, *c;
00220     real c_p;
00221     
00222     n = r - l + 1;
00223     if (n == 2) {
00224       /* Bottom of the recursion. Make an edge */
00225       *l_ccw = *r_cw = make_edge(p_sorted[l], p_sorted[r]);
00226     } else if (n == 3) {
00227       /* Bottom of the recursion. Make a triangle or two edges */
00228       a = make_edge(p_sorted[l], p_sorted[l+1]);
00229       b = make_edge(p_sorted[l+1], p_sorted[r]);
00230       splice(a, b, p_sorted[l+1]);
00231       c_p = Cross_product_3p(p_sorted[l], p_sorted[l+1], p_sorted[r]);
00232       
00233       if (c_p > 0.0)
00234       {
00235         /* Make a triangle */
00236         c = join(a, p_sorted[l], b, p_sorted[r], right);
00237         *l_ccw = a;
00238         *r_cw = b;
00239       } else if (c_p < 0.0) {
00240         /* Make a triangle */
00241         c = join(a, p_sorted[l], b, p_sorted[r], left);
00242         *l_ccw = c;
00243         *r_cw = c;
00244       } else {
00245         /* Points are collinear,  no triangle */ 
00246         *l_ccw = a;
00247         *r_cw = b;
00248       }
00249     } else if (n  > 3) {
00250       /* Continue to divide */
00251   
00252       /* Calculate the split point */
00253       split = (l + r) / 2;
00254     
00255       /* Divide */
00256       divide(p_sorted, l, split, &l_ccw_l, &r_cw_l);
00257       divide(p_sorted, split+1, r, &l_ccw_r, &r_cw_r);
00258   
00259       /* Merge */
00260       merge(r_cw_l, p_sorted[split], l_ccw_r, p_sorted[split+1], &l_tangent);
00261   
00262       /* The lower tangent added by merge may have invalidated 
00263          l_ccw_l or r_cw_r. Update them if necessary. */
00264       if (Org(l_tangent) == p_sorted[l])
00265         l_ccw_l = l_tangent;
00266       if (Dest(l_tangent) == p_sorted[r])
00267         r_cw_r = l_tangent;
00268   
00269       /* Update edge refs to be passed back */ 
00270       *l_ccw = l_ccw_l;
00271       *r_cw = r_cw_r;
00272     }
00273   }
00274   
00275 private:
00276   /*
00277    *  Determines the lower tangent of two triangulations. 
00278    */
00279   void lower_tangent(edge *r_cw_l, point *s, edge *l_ccw_r, point *u,
00280                             edge **l_lower, point **org_l_lower,
00281                             edge **r_lower, point **org_r_lower)
00282   {
00283     edge *l, *r;
00284     point *o_l, *o_r, *d_l, *d_r;
00285     bool finished;
00286   
00287     l = r_cw_l;
00288     r = l_ccw_r;
00289     o_l = s;
00290     d_l = Other_point(l, s);
00291     o_r = u;
00292     d_r = Other_point(r, u);
00293     finished = false;
00294   
00295     while (!finished)
00296       if (Cross_product_3p(o_l, d_l, o_r) > 0.0) {
00297         l = Prev(l, d_l);
00298         o_l = d_l;
00299         d_l = Other_point(l, o_l);
00300       } else if (Cross_product_3p(o_r, d_r, o_l) < 0.0) {
00301         r = Next(r, d_r);
00302         o_r = d_r;
00303         d_r = Other_point(r, o_r);
00304       } else
00305         finished = true;
00306   
00307     *l_lower = l;
00308     *r_lower = r;
00309     *org_l_lower = o_l;
00310     *org_r_lower = o_r;
00311   }
00312   
00313   /* 
00314    *  The merge function is where most of the work actually gets done.  It is
00315    *  written as one (longish) function for speed.
00316    */ 
00317   void merge(edge *r_cw_l, point *s, edge *l_ccw_r, point *u, edge **l_tangent)
00318   {
00319     edge *base, *l_cand, *r_cand;
00320     point *org_base, *dest_base;
00321     real u_l_c_o_b, v_l_c_o_b, u_l_c_d_b, v_l_c_d_b;
00322     real u_r_c_o_b, v_r_c_o_b, u_r_c_d_b, v_r_c_d_b;
00323     real c_p_l_cand, c_p_r_cand;
00324     real d_p_l_cand, d_p_r_cand;
00325     bool above_l_cand, above_r_cand, above_next, above_prev;
00326     point *dest_l_cand, *dest_r_cand;
00327     real cot_l_cand, cot_r_cand;
00328     edge *l_lower, *r_lower;
00329     point *org_r_lower, *org_l_lower;
00330   
00331     /* Create first cross edge by joining lower common tangent */
00332     lower_tangent(r_cw_l, s, l_ccw_r, u, &l_lower, &org_l_lower, &r_lower, &org_r_lower);
00333     base = join(l_lower, org_l_lower, r_lower, org_r_lower, right);
00334     org_base = org_l_lower;
00335     dest_base = org_r_lower;
00336     
00337     /* Need to return lower tangent. */
00338     *l_tangent = base;
00339   
00340     /* Main merge loop */
00341     do 
00342     {
00343       /* Initialise l_cand and r_cand */
00344       l_cand = Next(base, org_base);
00345       r_cand = Prev(base, dest_base);
00346       dest_l_cand = Other_point(l_cand, org_base);
00347       dest_r_cand = Other_point(r_cand, dest_base);
00348   
00349       /* Vectors for above and "in_circle" tests. */
00350       Vector(dest_l_cand, org_base, u_l_c_o_b, v_l_c_o_b);
00351       Vector(dest_l_cand, dest_base, u_l_c_d_b, v_l_c_d_b);
00352       Vector(dest_r_cand, org_base, u_r_c_o_b, v_r_c_o_b);
00353       Vector(dest_r_cand, dest_base, u_r_c_d_b, v_r_c_d_b);
00354   
00355       /* Above tests. */
00356       c_p_l_cand = Cross_product_2v(u_l_c_o_b, v_l_c_o_b, u_l_c_d_b, v_l_c_d_b);
00357       c_p_r_cand = Cross_product_2v(u_r_c_o_b, v_r_c_o_b, u_r_c_d_b, v_r_c_d_b);
00358       above_l_cand = c_p_l_cand > 0.0;
00359       above_r_cand = c_p_r_cand > 0.0;
00360       if (!above_l_cand && !above_r_cand)
00361         break;        /* Finished. */
00362   
00363       /* Advance l_cand ccw,  deleting the old l_cand edge,  until the 
00364          "in_circle" test fails. */
00365       if (above_l_cand)
00366       {
00367         real u_n_o_b, v_n_o_b, u_n_d_b, v_n_d_b;
00368         real c_p_next, d_p_next, cot_next;
00369         edge *next;
00370         point *dest_next;
00371   
00372         d_p_l_cand = Dot_product_2v(u_l_c_o_b, v_l_c_o_b, u_l_c_d_b, v_l_c_d_b);
00373         cot_l_cand = d_p_l_cand / c_p_l_cand;
00374   
00375         do 
00376         {
00377           next = Next(l_cand, org_base);
00378           dest_next = Other_point(next, org_base);
00379           Vector(dest_next, org_base, u_n_o_b, v_n_o_b);
00380           Vector(dest_next, dest_base, u_n_d_b, v_n_d_b);
00381           c_p_next = Cross_product_2v(u_n_o_b, v_n_o_b, u_n_d_b, v_n_d_b);
00382           above_next = c_p_next > 0.0;
00383   
00384           if (!above_next) 
00385             break;    /* Finished. */
00386   
00387           d_p_next = Dot_product_2v(u_n_o_b, v_n_o_b, u_n_d_b, v_n_d_b);
00388           cot_next = d_p_next / c_p_next;
00389   
00390           if (cot_next > cot_l_cand)
00391             break;    /* Finished. */
00392   
00393           delete_edge(l_cand);
00394           l_cand = next;
00395           cot_l_cand = cot_next;
00396     
00397         } while (true);
00398       }
00399   
00400       /* Now do the symmetrical for r_cand */
00401       if (above_r_cand)
00402       {
00403         real u_p_o_b, v_p_o_b, u_p_d_b, v_p_d_b;
00404         real c_p_prev, d_p_prev, cot_prev;
00405         edge *prev;
00406         point *dest_prev;
00407   
00408         d_p_r_cand = Dot_product_2v(u_r_c_o_b, v_r_c_o_b, u_r_c_d_b, v_r_c_d_b);
00409         cot_r_cand = d_p_r_cand / c_p_r_cand;
00410   
00411         do
00412         {
00413           prev = Prev(r_cand, dest_base);
00414           dest_prev = Other_point(prev, dest_base);
00415           Vector(dest_prev, org_base, u_p_o_b, v_p_o_b);
00416           Vector(dest_prev, dest_base, u_p_d_b, v_p_d_b);
00417           c_p_prev = Cross_product_2v(u_p_o_b, v_p_o_b, u_p_d_b, v_p_d_b);
00418           above_prev = c_p_prev > 0.0;
00419   
00420           if (!above_prev) 
00421             break;    /* Finished. */
00422   
00423           d_p_prev = Dot_product_2v(u_p_o_b, v_p_o_b, u_p_d_b, v_p_d_b);
00424           cot_prev = d_p_prev / c_p_prev;
00425   
00426           if (cot_prev > cot_r_cand)
00427             break;    /* Finished. */
00428   
00429           delete_edge(r_cand);
00430           r_cand = prev;
00431           cot_r_cand = cot_prev;
00432   
00433         } while (true);
00434       }
00435   
00436       /*
00437        *  Now add a cross edge from base to either l_cand or r_cand. 
00438        *  If both are valid choose on the basis of the in_circle test . 
00439        *  Advance base and  whichever candidate was chosen.
00440        */
00441       dest_l_cand = Other_point(l_cand, org_base);
00442       dest_r_cand = Other_point(r_cand, dest_base);
00443       if (!above_l_cand || (above_l_cand && above_r_cand && cot_r_cand < cot_l_cand))
00444       {
00445         /* Connect to the right */
00446         base = join(base, org_base, r_cand, dest_r_cand, right);
00447         dest_base = dest_r_cand;
00448       } else {
00449         /* Connect to the left */
00450         base = join(l_cand, dest_l_cand, base, dest_base, right);
00451         org_base = dest_l_cand;
00452       }
00453   
00454     } while (true);
00455   }
00456 
00457 private:
00461   edge *make_edge(point *u, point *v)
00462   {
00463     edge *e;
00464   
00465     e = get_edge();
00466   
00467     e->onext = e->oprev = e->dnext = e->dprev = e;
00468     e->org = u;
00469     e->dest = v;
00470     if (u->entry_pt == NULL)
00471       u->entry_pt = e;
00472     if (v->entry_pt == NULL)
00473       v->entry_pt = e;
00474     
00475   
00476     return e;
00477   }
00478   
00479   /* 
00480    *  Add an edge to a ring of edges. 
00481    */
00482   void splice(edge *a, edge *b, point *v)
00483   {
00484     edge *next;
00485   
00486     
00487     /* b must be the unnattached edge and a must be the previous 
00488        ccw edge to b. */
00489   
00490     if (Org(a) == v) { 
00491       next = Onext(a);
00492       Onext(a) = b;
00493     } else {
00494       next = Dnext(a);
00495       Dnext(a) = b;
00496     }
00497   
00498     if (Org(next) == v)
00499       Oprev(next) = b;
00500     else
00501       Dprev(next) = b;
00502   
00503     if (Org(b) == v) {
00504       Onext(b) = next;
00505       Oprev(b) = a;
00506     } else {
00507       Dnext(b) = next;
00508       Dprev(b) = a;
00509     }
00510   }
00511   
00512   /* 
00513    *  Creates a new edge and adds it to two rings of edges.
00514    */
00515   edge *join(edge *a, point *u, edge *b, point *v, side s)
00516   {
00517     edge *e;
00518   
00519     /* u and v are the two vertices which are being joined.
00520        a and b are the two edges associated with u and v res.  */
00521   
00522     e = make_edge(u, v);
00523     
00524     if (s == left) {
00525       if (Org(a) == u)
00526         splice(Oprev(a), e, u);
00527       else
00528         splice(Dprev(a), e, u);
00529       splice(b, e, v);
00530     } else {
00531       splice(a, e, u);
00532       if (Org(b) == v)
00533         splice(Oprev(b), e, v);
00534       else
00535         splice(Dprev(b), e, v);
00536     }
00537   
00538     return e;
00539   }
00540   
00541   /* 
00542    *  Remove an edge.
00543    */
00544   void delete_edge(edge *e)
00545   {
00546     point *u, *v;
00547   
00548     /* Cache origin and destination. */
00549     u = Org(e);
00550     v = Dest(e);
00551   
00552     /* Adjust entry points. */
00553     if (u->entry_pt == e)
00554       u->entry_pt = e->onext;
00555     if (v->entry_pt == e)
00556       v->entry_pt = e->dnext;
00557   
00558      /* Four edge links to change */
00559     if (Org(e->onext) == u)
00560       e->onext->oprev = e->oprev;
00561     else
00562       e->onext->dprev = e->oprev;
00563   
00564     if (Org(e->oprev) == u)
00565       e->oprev->onext = e->onext;
00566     else
00567       e->oprev->dnext = e->onext;
00568   
00569     if (Org(e->dnext) == v)
00570       e->dnext->oprev = e->dprev;
00571     else
00572       e->dnext->dprev = e->dprev;
00573   
00574     if (Org(e->dprev) == v)
00575       e->dprev->onext = e->dnext;
00576     else
00577       e->dprev->dnext = e->dnext;
00578   
00579     free_edge(e);
00580   }
00581 
00582   edge *get_edge()
00583   {
00584     if (n_free_e == 0)
00585       panic("Out of memory for edges\n");
00586   
00587      return (free_list_e[--n_free_e]);
00588   }
00589   
00590   void free_edge(edge *e)
00591   {
00592      free_list_e[n_free_e++] = e;
00593   }
00597 
00598   static void merge_sort(point *p[], point *p_temp[], index_t l, index_t r)
00599   {
00600     index_t i, j, k, m;
00601   
00602     if (r - l > 0)
00603     {
00604       m = (r + l) / 2;
00605       merge_sort(p, p_temp, l, m);
00606       merge_sort(p, p_temp, m+1, r);
00607   
00608       for (i = m+1; i > l; i--)
00609         p_temp[i-1] = p[i-1];
00610       for (j = m; j < r; j++)
00611         p_temp[r+m-j] = p[j+1];
00612       for (k = l; k <= r; k++)
00613         if (p_temp[i]->x < p_temp[j]->x) {
00614           p[k] = p_temp[i];
00615           i = i + 1;
00616         } else if (p_temp[i]->x == p_temp[j]->x && p_temp[i]->y < p_temp[j]->y) {
00617           p[k] = p_temp[i];
00618           i = i + 1;
00619         } else {
00620           p[k] = p_temp[j];
00621           j = j - 1;
00622         }
00623     }
00624   }
00625 
00626   void panic(const char *m){m_out << std::string(m);}
00627 
00628 private:
00629   static point*& Org(edge* e) {return e->org;}
00630   static point*& Dest(edge* e) {return e->dest;}
00631   static edge*& Onext(edge* e) {return e->onext;}
00632   static edge*& Oprev(edge* e) {return e->oprev;}
00633   static edge*& Dnext(edge* e) {return e->dnext;}
00634   static edge*& Dprev(edge* e) {return e->dprev;}
00635 
00636   static point* Other_point(edge* e,point* p) {
00637     return (e->org == p ? e->dest : e->org);
00638   }
00639   static edge* Next(edge* e,point* p) {
00640     return (e->org == p ? e->onext : e->dnext);
00641   }
00642   static edge* Prev(edge* e,point* p) {
00643     return (e->org == p ? e->oprev : e->dprev);
00644   }
00645 
00646   static void Vector(point* p1,point* p2,real& u,real& v) {
00647     u = p2->x - p1->x;
00648     v = p2->y - p1->y;
00649   }
00650   static real Cross_product_2v(real u1,real v1,real u2,real v2) {
00651     return u1 * v2 - v1 * u2;
00652   }
00653   static real Cross_product_3p(point* p1,point* p2,point* p3) {
00654     return (p2->x - p1->x)*(p3->y - p1->y) - (p2->y - p1->y)*(p3->x - p1->x);
00655   }
00656 
00657   static real Dot_product_2v(real u1,real v1,real u2,real v2) {
00658     return u1 * u2 + v1 * v2;
00659   }
00660 
00661   static bool Identical_refs(edge* e1,edge* e2) {
00662     return (e1==e2 ? true:false);
00663   }
00664 
00665 private:
00666   std::ostream& m_out;
00667   unsigned int p_number;
00668   point* p_array;
00669   edge* e_array;
00670   edge** free_list_e;
00671   unsigned int n_free_e;
00672 };
00673 
00674 }}
00675 
00676 #endif
00677 
00678 /*   Author: Geoff Leach, Department of Computer Science, RMIT.
00679  *   email: gl@cs.rmit.edu.au
00680  *
00681  *   Date: 6/10/93
00682  *
00683  *   Version 1.0
00684  *   
00685  *   Copyright (c) RMIT 1993. All rights reserved.
00686  *
00687  *   License to copy and use this software purposes is granted provided 
00688  *   that appropriate credit is given to both RMIT and the author.
00689  *
00690  *   License is also granted to make and use derivative works provided
00691  *   that appropriate credit is given to both RMIT and the author.
00692  *
00693  *   RMIT makes no representations concerning either the merchantability 
00694  *   of this software or the suitability of this software for any particular 
00695  *   purpose.  It is provided "as is" without express or implied warranty 
00696  *   of any kind.
00697  *
00698  *   These notices must be retained in any copies of any part of this software.
00699  */
00700 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines