pcb 4.1.1
An interactive printed circuit board layout editor.

stripe.c

Go to the documentation of this file.
00001 /* GTS - Library for the manipulation of triangulated surfaces
00002  * Copyright (C) 1999-2003  Wagner Toledo Correa, Stéphane Popinet
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #include "gts.h"
00021 
00022 #define PRINT_HEAP_ELEMENTS 0
00023 
00024 typedef struct {
00025   GtsTriangle * t;
00026   gboolean used;
00027   GSList * neighbors;
00028   GtsEHeapPair *pos;
00029 } tri_data_t;
00030 
00031 typedef struct {
00032   GHashTable * ht;
00033 } map_t;
00034 
00035 typedef struct {
00036   map_t * map;
00037   GtsEHeap * heap;
00038 } heap_t;
00039 
00040 static tri_data_t    * tri_data_new (GtsTriangle * t);
00041 static void            tri_data_destroy (tri_data_t * td);
00042 static guint           tri_data_num_unused_neighbors2 (const tri_data_t * td,
00043                                                        const map_t * map);
00044 static GHashTable    * tri_data_unused_neighbors2 (const tri_data_t * td,
00045                                                    const map_t * map);
00046 
00047 static map_t         * map_new (GtsSurface * s);
00048 static void            map_destroy (map_t * map);
00049 static tri_data_t    * map_lookup (const map_t * map, GtsTriangle * t);
00050 
00051 
00052 static heap_t        * heap_new (GtsSurface * s);
00053 static void            heap_destroy (heap_t * heap);
00054 static gboolean        heap_is_empty (const heap_t * heap);
00055 static GtsTriangle   * heap_top (const heap_t * heap);
00056 static void            heap_remove (heap_t * heap, GtsTriangle * t);
00057 
00058 /* helper functions */
00059 
00060 static gboolean vertices_are_unique (GtsVertex * v1,
00061                                      GtsVertex * v2,
00062                                      GtsVertex * v3)
00063 {
00064   g_assert (v1 && v2 && v3);
00065   return (v1 != v2 && v1 != v3 && v2 != v3);
00066 }
00067 
00068 static gboolean vertex_is_one_of (GtsVertex * v,
00069                                   GtsVertex * v1,
00070                                   GtsVertex * v2,
00071                                   GtsVertex * v3)
00072 {
00073   g_assert (v && v1 && v2 && v3);
00074   return v == v1 || v == v2 || v == v3;
00075 }
00076 
00077 static guint num_shared_vertices (GtsVertex * u1,
00078                                   GtsVertex * u2,
00079                                   GtsVertex * u3,
00080                                   GtsVertex * v1,
00081                                   GtsVertex * v2,
00082                                   GtsVertex * v3)
00083 {
00084   guint n = 0;
00085   
00086   g_assert (u1 && u2 && u3);
00087   g_assert (v1 && v2 && v3);
00088   g_assert (vertices_are_unique (u1, u2, u3));
00089   g_assert (vertices_are_unique (v1, v2, v3));
00090   
00091   if (vertex_is_one_of (v1, u1, u2, u3))
00092     n++;
00093   if (vertex_is_one_of (v2, u1, u2, u3))
00094     n++;
00095   if (vertex_is_one_of (v3, u1, u2, u3))
00096     n++;
00097   return n;
00098 }
00099 
00100 static gboolean vertices_match (GtsVertex * v1,
00101                                 GtsVertex * v2,
00102                                 GtsVertex * v3,
00103                                 GtsVertex ** v4,
00104                                 GtsVertex ** v5,
00105                                 GtsVertex ** v6)
00106 {
00107   guint i;
00108 
00109   g_assert (v4 && v5 && v6);
00110   g_assert (*v4 && *v5 && *v6);
00111   g_assert (vertices_are_unique (*v4, *v5, *v6));
00112   
00113   for (i = 0; i < 2; i++) {
00114     if ((!v1 || (v1 == *v4)) &&
00115         (!v2 || (v2 == *v5)) &&
00116         (!v3 || (v3 == *v6)))
00117       return TRUE;
00118     else {
00119       GtsVertex * v7 = * v4;
00120 
00121       *v4 = *v5;
00122       *v5 = *v6;
00123       *v6 = v7;
00124     }
00125   }
00126   return ((!v1 || (v1 == *v4)) &&
00127           (!v2 || (v2 == *v5)) &&
00128           (!v3 || (v3 == *v6)));
00129 }
00130 
00131 static GtsVertex * non_shared_vertex1 (GtsVertex * u1,
00132                                        GtsVertex * u2,
00133                                        GtsVertex * u3,
00134                                        GtsVertex * v1,
00135                                        GtsVertex * v2,
00136                                        GtsVertex * v3)
00137 {
00138   GtsVertex * u = NULL;
00139 
00140   g_assert (u1 && u2 && u3);
00141   g_assert (v1 && v2 && v3);
00142   g_assert (vertices_are_unique (u1, u2, u3));
00143   g_assert (vertices_are_unique (v1, v2, v3));
00144   g_assert (num_shared_vertices (u1, u2, u3, v1, v2, v3) == 2);
00145 
00146   if (!vertex_is_one_of (u1, v1, v2, v3)) {
00147     g_assert (vertex_is_one_of (u2, v1, v2, v3));
00148     g_assert (vertex_is_one_of (u3, v1, v2, v3));
00149     u = u1;
00150   } else if (!vertex_is_one_of (u2, v1, v2, v3)) {
00151     g_assert (vertex_is_one_of (u1, v1, v2, v3));
00152     g_assert (vertex_is_one_of (u3, v1, v2, v3));
00153     u = u2;
00154   } else if (!vertex_is_one_of (u3, v1, v2, v3)) {
00155     g_assert (vertex_is_one_of (u1, v1, v2, v3));
00156     g_assert (vertex_is_one_of (u2, v1, v2, v3));
00157     u = u3;
00158   } else 
00159     g_assert_not_reached ();
00160 
00161   return u;
00162 }
00163 
00164 static void match_vertex (GtsVertex * v,
00165                           GtsVertex ** v1,
00166                           GtsVertex ** v2,
00167                           GtsVertex ** v3)
00168 {
00169   g_assert (v && v1 && v2 && v3);
00170   g_assert (*v1 && *v2 && *v3);
00171   g_assert (vertex_is_one_of (v, *v1, *v2, *v3));
00172   while (*v1 != v) {
00173     GtsVertex *v0 = *v1;
00174 
00175     *v1 = *v2;
00176     *v2 = *v3;
00177     *v3 = v0;
00178   }
00179 }
00180 
00181 /* tri_data_t functions */
00182 
00183 static tri_data_t * tri_data_new (GtsTriangle * t)
00184 {
00185   tri_data_t * td;
00186   
00187   td = g_malloc (sizeof (tri_data_t));
00188   td->t = t;
00189   td->used = FALSE;
00190   td->neighbors = gts_triangle_neighbors (t);
00191   td->pos = NULL;
00192 
00193   return td;
00194 }
00195 
00196 static void tri_data_destroy (tri_data_t * td)
00197 {
00198   if (!td)
00199     return;
00200   g_slist_free (td->neighbors);
00201   g_free (td);
00202 }
00203 
00204 static guint tri_data_num_unused_neighbors2 (const tri_data_t * td,
00205                                              const map_t * map)
00206 {
00207   GHashTable *h;
00208   guint n;
00209 
00210   g_assert (td);
00211   g_assert (map);
00212   h = tri_data_unused_neighbors2 (td, map);
00213   n = g_hash_table_size (h);
00214   g_hash_table_destroy (h);
00215   return n;
00216 }
00217 
00218 static void copy_key_to_array (gpointer key,
00219                                gpointer value,
00220                                gpointer user_data)
00221 {
00222   GtsTriangle * t = key;
00223   GtsTriangle *** p = user_data;
00224 
00225   (void) value;
00226   g_assert (t);
00227   g_assert (p && *p);
00228   **p = t;
00229   (*p)++;
00230 }
00231 
00232 static gboolean are_neighbors_unique (GHashTable *h)
00233 {
00234   GtsTriangle ** a;
00235   GtsTriangle ** p;
00236   gint i, j, n;         /* guint won't work if n == 0 */
00237 
00238   g_assert (h);
00239   n = g_hash_table_size (h);
00240 #ifdef DEBUG
00241   if (n > 9)
00242     g_warning ("triangle has %d 2-level neighbors", n);
00243 #endif /* DEBUG */
00244   a = g_malloc(n*sizeof (GtsTriangle *));
00245   p = a;
00246   g_hash_table_foreach (h, copy_key_to_array, &p);
00247   for (i = 0; i < n - 1; i++) {
00248     g_assert (a[i]);
00249     for (j = i + 1; j < n; j++) {
00250       g_assert (a[j]);
00251       if (a[i] == a[j]) {
00252         g_free (a);
00253         return FALSE;
00254       }
00255     }
00256   }
00257   g_free (a);
00258   return TRUE;
00259 }
00260 
00261 static GHashTable * tri_data_unused_neighbors2 (const tri_data_t * td,
00262                                                 const map_t * map)
00263 {
00264   GHashTable * h = g_hash_table_new (NULL, NULL);
00265   GSList * li;
00266 
00267   g_assert (td);
00268   g_assert (map);
00269   for (li = td->neighbors; li != NULL; li = li->next) {
00270     GtsTriangle * t2 = li->data;
00271     tri_data_t * td2 = map_lookup (map, t2);
00272     GSList * lj;
00273 
00274     g_assert (td2);
00275     if (!td2->used) {
00276       g_hash_table_insert (h, t2, td2);
00277       for (lj = td2->neighbors; lj != NULL; lj = lj->next) {
00278         GtsTriangle * t3 = lj->data;
00279         tri_data_t * td3 = map_lookup (map, t3);
00280 
00281         g_assert (td3);
00282         if (td3 != td && !td3->used)
00283           g_hash_table_insert (h, t3, td3);
00284       }
00285     }
00286   }
00287   g_assert (are_neighbors_unique (h));
00288   return h;
00289 }
00290 
00291 #if PRINT_HEAP_ELEMENTS
00292 static void tri_data_print (const tri_data_t * td, FILE * fp)
00293 {
00294   g_assert (td);
00295   g_assert (fp);
00296   fprintf(fp, "td=%p t=%p used=%d pos=%p key=%f\n",
00297           td, td->t, td->used, td->pos,
00298           td->pos ? td->pos->key : -1.0);
00299 }
00300 #endif /* PRINT_HEAP_ELEMENTS */
00301 
00302 /* heap_t functions */
00303 
00304 static gdouble triangle_priority (gpointer item, gpointer data)
00305 {
00306   GtsTriangle * t = item;
00307   map_t * map = data;
00308   tri_data_t * td;
00309   gdouble k;
00310   
00311   g_assert (t);
00312   g_assert (map);
00313   td = map_lookup (map, t);
00314   g_assert (td);
00315   k = tri_data_num_unused_neighbors2 (td, map);
00316   return k;
00317 }
00318 
00319 #if PRINT_HEAP_ELEMENTS
00320 static void print_heap_element (gpointer data, gpointer user_data)
00321 {
00322   GtsTriangle * t = data;
00323   map_t * map = user_data;
00324   tri_data_t * td;
00325   
00326   g_assert (t);
00327   g_assert (map);
00328   td = map_lookup (map, t);
00329   g_assert (td);
00330   g_assert (!td->used);
00331   g_assert (td->pos);
00332   tri_data_print (td, stderr);
00333 }
00334 #endif /* PRINT_HEAP_ELEMENTS */
00335 
00336 static void insert_entry_into_heap (gpointer key,
00337                                     gpointer value,
00338                                     gpointer user_data)
00339 {
00340   GtsTriangle * t = key;
00341   tri_data_t * td = value;
00342   GtsEHeap * heap = user_data;
00343   
00344   g_assert (!td->pos);
00345   td->pos = gts_eheap_insert (heap, t);
00346   g_assert (td->pos);
00347 }
00348 
00349 static heap_t * heap_new (GtsSurface *s)
00350 {
00351   heap_t * heap;
00352 
00353   g_assert (s);
00354   heap = g_malloc (sizeof (heap_t));
00355   heap->map = map_new (s);
00356   heap->heap = gts_eheap_new (triangle_priority, heap->map);
00357   g_hash_table_foreach (heap->map->ht,
00358                         insert_entry_into_heap,
00359                         heap->heap);
00360 #if PRINT_HEAP_ELEMENTS
00361   gts_eheap_foreach (heap->heap, print_heap_element, heap->map);
00362 #endif /* PRINT_HEAP_ELEMENTS */
00363   return heap;
00364 }
00365 
00366 static void heap_destroy (heap_t * heap)
00367 {
00368   if (!heap)
00369     return;
00370   map_destroy (heap->map);
00371   gts_eheap_destroy (heap->heap);
00372   g_free (heap);
00373 }
00374 
00375 static gboolean heap_is_empty (const heap_t * heap)
00376 {
00377   g_assert (heap);
00378   g_assert (heap->heap);
00379   return gts_eheap_size (heap->heap) == 0;
00380 }
00381 
00382 typedef struct {
00383   const heap_t * heap;
00384   double min_key;
00385 } min_key_t;
00386 
00387 static GtsTriangle * heap_top (const heap_t * heap)
00388 {
00389   GtsTriangle * t;
00390   
00391   g_assert (heap);
00392   g_assert (heap->heap);
00393   t = gts_eheap_top (heap->heap, NULL);
00394   return t;
00395 }
00396 
00397 static void decrease_key (gpointer key, gpointer value, gpointer user_data)
00398 {
00399   GtsTriangle * t = key;
00400   tri_data_t * td = value;
00401   heap_t *heap = user_data;
00402   gdouble k;
00403   
00404   (void) t;
00405   g_assert (heap);
00406   g_assert (heap->map);
00407   g_assert (heap->heap);
00408   g_assert (td);
00409   g_assert (!td->used);
00410   g_assert (td->pos);
00411   
00412   k = tri_data_num_unused_neighbors2 (td, heap->map);
00413   g_assert (k <= td->pos->key);
00414 #ifdef DEBUG
00415   if (k == td->pos->key)
00416     g_warning ("same key: %f\n", k);
00417 #endif /* DEBUG */
00418   if (k != td->pos->key) {
00419     g_assert (k < td->pos->key);
00420     g_assert (k >= 0.0);
00421     gts_eheap_decrease_key (heap->heap, td->pos, k);
00422   }
00423 }
00424 
00425 static void heap_remove (heap_t * heap, GtsTriangle * t)
00426 {
00427   tri_data_t * td;
00428   GHashTable * h;
00429   
00430   g_assert (heap);
00431   g_assert (t);
00432   td = map_lookup (heap->map, t);
00433   g_assert (td);
00434   g_assert (!td->used);
00435   g_assert (td->pos);
00436   td->used = TRUE;
00437   gts_eheap_remove (heap->heap, td->pos);
00438   td->pos = NULL;
00439   
00440   /*    fprintf(stderr, "td: %p\n", td); */
00441   h = tri_data_unused_neighbors2 (td, heap->map);
00442   g_hash_table_foreach (h, decrease_key, heap);
00443   g_hash_table_destroy (h);
00444 }
00445 
00446 /* map_t functions */
00447 
00448 static gint create_map_entry (gpointer item, gpointer data)
00449 {
00450   GtsTriangle * t = item;
00451   GHashTable * ht = data;
00452   tri_data_t * td;
00453 
00454   g_assert (t);
00455   g_assert (ht);
00456   td = tri_data_new (t);
00457   g_hash_table_insert (ht, t, td);
00458   return 0;
00459 }
00460 
00461 static void free_map_entry (gpointer key, gpointer value, gpointer user_data)
00462 {
00463   GtsTriangle * t = key;
00464   tri_data_t * td = value;
00465 
00466   (void) user_data;
00467   g_assert (t);
00468   g_assert (td);
00469   g_assert (td->t == t);
00470   tri_data_destroy (td);
00471 }
00472 
00473 static map_t * map_new (GtsSurface * s)
00474 {
00475   map_t * map;
00476 
00477   map = g_malloc (sizeof (map_t));
00478   map->ht = g_hash_table_new (NULL, NULL);
00479   gts_surface_foreach_face (s, create_map_entry, map->ht);
00480   return map;
00481 }
00482 
00483 static void map_destroy (map_t * map)
00484 {
00485   if (!map)
00486     return;
00487   g_hash_table_foreach (map->ht, free_map_entry, NULL);
00488   g_hash_table_destroy (map->ht);
00489   g_free (map);
00490 }
00491 
00492 static tri_data_t * map_lookup (const map_t * map, GtsTriangle * t)
00493 {
00494   tri_data_t * td;
00495 
00496   g_assert (map);
00497   g_assert (map->ht);
00498   g_assert (t);
00499   td = g_hash_table_lookup (map->ht, t);
00500   g_assert (td);
00501   g_assert (td->t == t);
00502   return td;
00503 }
00504 
00505 /* other helper functions */
00506 
00507 static GtsTriangle * find_min_neighbor (heap_t * heap, GtsTriangle * t)
00508 {
00509   GtsTriangle * min_neighbor = NULL;
00510   gdouble min_key = G_MAXDOUBLE;
00511   tri_data_t * td;
00512   GSList * li;
00513 
00514   g_assert (heap);
00515   g_assert (t);
00516 
00517   td = map_lookup (heap->map, t);
00518   for (li = td->neighbors; li != NULL; li = li->next) {
00519     GtsTriangle * t2 = li->data;
00520     tri_data_t * td2 = map_lookup (heap->map, t2);
00521     gdouble k;
00522     
00523     g_assert (td2);
00524     if (td2->used)
00525       continue;
00526     g_assert (td2->pos);
00527     k = td2->pos->key;
00528     if (k < min_key) {
00529       min_key = k;
00530       min_neighbor = t2;
00531     }
00532   }
00533   return min_neighbor;
00534 }
00535 
00536 static GtsTriangle * find_neighbor_forward (heap_t * heap,
00537                                             GtsTriangle * t,
00538                                             GtsVertex ** v1,
00539                                             GtsVertex ** v2,
00540                                             GtsVertex ** v3,
00541                                             gboolean left_turn)
00542 {
00543   GtsTriangle * neighbor = NULL;
00544   tri_data_t * td;
00545   GSList * li;
00546 
00547   g_assert (heap);
00548   g_assert (t);
00549   g_assert (v1 && v2 && v3);
00550   g_assert (vertices_are_unique (*v1, *v2, *v3));
00551   
00552   td = map_lookup (heap->map, t);
00553   g_assert (td);
00554   for (li = td->neighbors; li && !neighbor; li = li->next) {
00555     GtsTriangle * t2 = li->data;
00556     tri_data_t * td2 = map_lookup (heap->map, t2);
00557     GtsVertex * v4, * v5, * v6;
00558     
00559     g_assert (td2);
00560     if (t2 == t || td2->used)
00561       continue;
00562     gts_triangle_vertices (t2, &v4, &v5, &v6);
00563     if (left_turn) {
00564       if (!vertices_match (*v1, *v3, NULL, &v4, &v5, &v6))
00565         continue;
00566     } else {
00567       if (!vertices_match (*v3, *v2, NULL, &v4, &v5, &v6))
00568         continue;
00569     }
00570     neighbor = t2;
00571     *v1 = v4;
00572     *v2 = v5;
00573     *v3 = v6;
00574   }
00575   return neighbor;
00576 }
00577 
00578 static GtsTriangle * find_neighbor_backward (heap_t * heap,
00579                                              GtsTriangle * t,
00580                                              GtsVertex ** v1,
00581                                              GtsVertex ** v2,
00582                                              GtsVertex ** v3,
00583                                              gboolean left_turn)
00584 {
00585   GtsTriangle * neighbor = NULL;
00586   tri_data_t * td;
00587   GSList * li;
00588 
00589   g_assert (heap);
00590   g_assert (t);
00591   g_assert (v1 && v2 && v3);
00592   g_assert (vertices_are_unique (*v1, *v2, *v3));
00593 
00594   td = map_lookup (heap->map, t);
00595   g_assert (td);
00596   for (li = td->neighbors; li && !neighbor; li = li->next) {
00597     GtsTriangle * t2 = li->data;
00598     tri_data_t * td2 = map_lookup (heap->map, t2);
00599     GtsVertex * v4, * v5, * v6;
00600     
00601     g_assert (td2);
00602     if (t2 == t || td2->used)
00603       continue;
00604     gts_triangle_vertices (t2, &v4, &v5, &v6);
00605     if (left_turn) {
00606       if (!vertices_match (NULL, *v2, *v1, &v4, &v5, &v6))
00607         continue;
00608     } else if (!vertices_match(*v1, NULL, *v2, &v4, &v5, &v6))
00609       continue;
00610     neighbor = t2;
00611     *v1 = v4;
00612     *v2 = v5;
00613     *v3 = v6;
00614   }
00615   return neighbor;
00616 }
00617 
00618 static GSList * grow_strip_forward (heap_t * heap,
00619                                     GSList * strip,
00620                                     GtsTriangle * t,
00621                                     GtsVertex * v1,
00622                                     GtsVertex * v2,
00623                                     GtsVertex * v3)
00624 {
00625   gboolean left_turn;
00626   
00627   g_assert (heap);
00628   g_assert (g_slist_length(strip) == 2);
00629   g_assert (t);
00630   g_assert (v1 && v2 && v3);
00631   g_assert (vertices_are_unique (v1, v2, v3));
00632 
00633   left_turn = TRUE;
00634   while ((t = find_neighbor_forward (heap, t, &v1, &v2, &v3, 
00635                                      left_turn)) != NULL) {
00636     heap_remove (heap, t);
00637     strip = g_slist_prepend (strip, t);
00638     left_turn = !left_turn;
00639   }
00640   return strip;
00641 }
00642 
00643 static GSList * grow_strip_backward (heap_t * heap,
00644                                      GSList * strip,
00645                                      GtsTriangle * t,
00646                                      GtsVertex * v1,
00647                                      GtsVertex * v2,
00648                                      GtsVertex * v3)
00649 {
00650   /* we have to make sure we add an even number of triangles */
00651   GtsTriangle * t2;
00652 
00653   g_assert (heap);
00654   g_assert (g_slist_length(strip) >= 2);
00655   g_assert (t);
00656   g_assert (v1 && v2 && v3);
00657   g_assert (vertices_are_unique (v1, v2, v3));
00658 
00659   while ((t2 = find_neighbor_backward (heap, t, &v1, &v2, &v3,
00660                                        FALSE)) != NULL
00661          && (t = find_neighbor_backward (heap, t2, &v1, &v2, &v3,
00662                                          TRUE)) != NULL) {
00663     heap_remove (heap, t2);
00664     heap_remove (heap, t);
00665     strip = g_slist_prepend (strip, t2);
00666     strip = g_slist_prepend (strip, t);
00667   }
00668   return strip;
00669 }
00670 
00671 static gboolean find_right_turn (GtsVertex ** v1,
00672                                  GtsVertex ** v2,
00673                                  GtsVertex ** v3,
00674                                  GtsVertex ** v4,
00675                                  GtsVertex ** v5,
00676                                  GtsVertex ** v6)
00677 {
00678   GtsVertex * v;
00679 
00680   g_assert (v1 && v2 && v3);
00681   g_assert (v4 && v5 && v6);
00682   g_assert (vertices_are_unique (*v1, *v2, *v3));
00683   g_assert (vertices_are_unique (*v4, *v5, *v6));
00684   g_assert (num_shared_vertices (*v1, *v2, *v3, *v4, *v5, *v6) == 2);
00685 
00686   v = non_shared_vertex1 (*v1, *v2, *v3, *v4, *v5, *v6);
00687   match_vertex (v, v1, v2, v3);
00688   match_vertex (*v3, v4, v5, v6);
00689 
00690   g_assert (v1 && v2 && v3);
00691   g_assert (v4 && v5 && v6);
00692   g_assert (*v4 == *v3);
00693 
00694   if (*v5 == *v2) {
00695     g_assert (vertices_are_unique (*v1, *v2, *v3));
00696     g_assert (vertices_are_unique (*v4, *v5, *v6));
00697     g_assert (num_shared_vertices (*v1, *v2, *v3,
00698                                         *v4, *v5, *v6) == 2);
00699     return TRUE;
00700   } else {
00701 #ifdef DEBUG
00702     g_warning ("couldn't find a right turn");
00703 #endif /* DEBUG */
00704     return FALSE;
00705   }
00706 }
00707 
00718 GSList * gts_surface_strip (GtsSurface *s)
00719 {
00720   GSList * strips = NULL;
00721   heap_t * heap;
00722 
00723   g_return_val_if_fail (s != NULL, NULL);
00724 
00725   heap = heap_new (s);
00726   while (!heap_is_empty (heap)) {
00727     GtsTriangle * t1, * t2;
00728     GtsVertex * v1, * v2, * v3, * v4, * v5, * v6;
00729     GSList * strip = NULL;
00730 
00731     /* remove heap top */
00732     t1 = heap_top (heap);
00733     g_assert (t1);
00734     heap_remove (heap, t1);
00735 
00736     /* start a new strip */
00737     strip = g_slist_prepend (strip, t1);
00738 
00739     /* find second triangle */
00740     t2 = find_min_neighbor (heap, t1);
00741     if (t2) {
00742       g_assert (t2 != t1);
00743 
00744       /* find right turn */
00745       gts_triangle_vertices (t1, &v1, &v2, &v3);
00746       gts_triangle_vertices (t2, &v4, &v5, &v6);
00747       if (find_right_turn (&v1, &v2, &v3, &v4, &v5, &v6)) {
00748         heap_remove (heap, t2);
00749         strip = g_slist_prepend (strip, t2);
00750 
00751         /* grow strip forward */
00752         strip = grow_strip_forward (heap, strip, t2, v4, v5, v6);
00753 
00754         strip = g_slist_reverse (strip);
00755 
00756         /* grow strip backward */
00757         strip = grow_strip_backward (heap, strip, t1, v1, v2, v3);
00758       }
00759     }
00760     strips = g_slist_prepend (strips, strip);
00761   }
00762   strips = g_slist_reverse (strips);
00763   heap_destroy (heap);
00764 
00765   return strips;
00766 }