inlib
1.2.0
|
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