1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999-2003 Wagner Toledo Correa, Stéphane Popinet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #define PRINT_HEAP_ELEMENTS 0
40 static tri_data_t
* tri_data_new (GtsTriangle
* t
);
41 static void tri_data_destroy (tri_data_t
* td
);
42 static guint
tri_data_num_unused_neighbors2 (const tri_data_t
* td
,
44 static GHashTable
* tri_data_unused_neighbors2 (const tri_data_t
* td
,
47 static map_t
* map_new (GtsSurface
* s
);
48 static void map_destroy (map_t
* map
);
49 static tri_data_t
* map_lookup (const map_t
* map
, GtsTriangle
* t
);
52 static heap_t
* heap_new (GtsSurface
* s
);
53 static void heap_destroy (heap_t
* heap
);
54 static gboolean
heap_is_empty (const heap_t
* heap
);
55 static GtsTriangle
* heap_top (const heap_t
* heap
);
56 static void heap_remove (heap_t
* heap
, GtsTriangle
* t
);
58 /* helper functions */
60 static gboolean
vertices_are_unique (GtsVertex
* v1
,
64 g_assert (v1
&& v2
&& v3
);
65 return (v1
!= v2
&& v1
!= v3
&& v2
!= v3
);
68 static gboolean
vertex_is_one_of (GtsVertex
* v
,
73 g_assert (v
&& v1
&& v2
&& v3
);
74 return v
== v1
|| v
== v2
|| v
== v3
;
77 static guint
num_shared_vertices (GtsVertex
* u1
,
86 g_assert (u1
&& u2
&& u3
);
87 g_assert (v1
&& v2
&& v3
);
88 g_assert (vertices_are_unique (u1
, u2
, u3
));
89 g_assert (vertices_are_unique (v1
, v2
, v3
));
91 if (vertex_is_one_of (v1
, u1
, u2
, u3
))
93 if (vertex_is_one_of (v2
, u1
, u2
, u3
))
95 if (vertex_is_one_of (v3
, u1
, u2
, u3
))
100 static gboolean
vertices_match (GtsVertex
* v1
,
109 g_assert (v4
&& v5
&& v6
);
110 g_assert (*v4
&& *v5
&& *v6
);
111 g_assert (vertices_are_unique (*v4
, *v5
, *v6
));
113 for (i
= 0; i
< 2; i
++) {
114 if ((!v1
|| (v1
== *v4
)) &&
115 (!v2
|| (v2
== *v5
)) &&
116 (!v3
|| (v3
== *v6
)))
119 GtsVertex
* v7
= * v4
;
126 return ((!v1
|| (v1
== *v4
)) &&
127 (!v2
|| (v2
== *v5
)) &&
128 (!v3
|| (v3
== *v6
)));
131 static GtsVertex
* non_shared_vertex1 (GtsVertex
* u1
,
138 GtsVertex
* u
= NULL
;
140 g_assert (u1
&& u2
&& u3
);
141 g_assert (v1
&& v2
&& v3
);
142 g_assert (vertices_are_unique (u1
, u2
, u3
));
143 g_assert (vertices_are_unique (v1
, v2
, v3
));
144 g_assert (num_shared_vertices (u1
, u2
, u3
, v1
, v2
, v3
) == 2);
146 if (!vertex_is_one_of (u1
, v1
, v2
, v3
)) {
147 g_assert (vertex_is_one_of (u2
, v1
, v2
, v3
));
148 g_assert (vertex_is_one_of (u3
, v1
, v2
, v3
));
150 } else if (!vertex_is_one_of (u2
, v1
, v2
, v3
)) {
151 g_assert (vertex_is_one_of (u1
, v1
, v2
, v3
));
152 g_assert (vertex_is_one_of (u3
, v1
, v2
, v3
));
154 } else if (!vertex_is_one_of (u3
, v1
, v2
, v3
)) {
155 g_assert (vertex_is_one_of (u1
, v1
, v2
, v3
));
156 g_assert (vertex_is_one_of (u2
, v1
, v2
, v3
));
159 g_assert_not_reached ();
164 static void match_vertex (GtsVertex
* v
,
169 g_assert (v
&& v1
&& v2
&& v3
);
170 g_assert (*v1
&& *v2
&& *v3
);
171 g_assert (vertex_is_one_of (v
, *v1
, *v2
, *v3
));
181 /* tri_data_t functions */
183 static tri_data_t
* tri_data_new (GtsTriangle
* t
)
187 td
= g_malloc (sizeof (tri_data_t
));
190 td
->neighbors
= gts_triangle_neighbors (t
);
196 static void tri_data_destroy (tri_data_t
* td
)
200 g_slist_free (td
->neighbors
);
204 static guint
tri_data_num_unused_neighbors2 (const tri_data_t
* td
,
212 h
= tri_data_unused_neighbors2 (td
, map
);
213 n
= g_hash_table_size (h
);
214 g_hash_table_destroy (h
);
218 static void copy_key_to_array (gpointer key
,
222 GtsTriangle
* t
= key
;
223 GtsTriangle
*** p
= user_data
;
232 static gboolean
are_neighbors_unique (GHashTable
*h
)
236 gint i
, j
, n
; /* guint won't work if n == 0 */
239 n
= g_hash_table_size (h
);
242 g_warning ("triangle has %d 2-level neighbors", n
);
244 a
= g_malloc(n
*sizeof (GtsTriangle
*));
246 g_hash_table_foreach (h
, copy_key_to_array
, &p
);
247 for (i
= 0; i
< n
- 1; i
++) {
249 for (j
= i
+ 1; j
< n
; j
++) {
261 static GHashTable
* tri_data_unused_neighbors2 (const tri_data_t
* td
,
264 GHashTable
* h
= g_hash_table_new (NULL
, NULL
);
269 for (li
= td
->neighbors
; li
!= NULL
; li
= li
->next
) {
270 GtsTriangle
* t2
= li
->data
;
271 tri_data_t
* td2
= map_lookup (map
, t2
);
276 g_hash_table_insert (h
, t2
, td2
);
277 for (lj
= td2
->neighbors
; lj
!= NULL
; lj
= lj
->next
) {
278 GtsTriangle
* t3
= lj
->data
;
279 tri_data_t
* td3
= map_lookup (map
, t3
);
282 if (td3
!= td
&& !td3
->used
)
283 g_hash_table_insert (h
, t3
, td3
);
287 g_assert (are_neighbors_unique (h
));
291 #if PRINT_HEAP_ELEMENTS
292 static void tri_data_print (const tri_data_t
* td
, FILE * fp
)
296 fprintf(fp
, "td=%p t=%p used=%d pos=%p key=%f\n",
297 td
, td
->t
, td
->used
, td
->pos
,
298 td
->pos
? td
->pos
->key
: -1.0);
300 #endif /* PRINT_HEAP_ELEMENTS */
302 /* heap_t functions */
304 static gdouble
triangle_priority (gpointer item
, gpointer data
)
306 GtsTriangle
* t
= item
;
313 td
= map_lookup (map
, t
);
315 k
= tri_data_num_unused_neighbors2 (td
, map
);
319 #if PRINT_HEAP_ELEMENTS
320 static void print_heap_element (gpointer data
, gpointer user_data
)
322 GtsTriangle
* t
= data
;
323 map_t
* map
= user_data
;
328 td
= map_lookup (map
, t
);
330 g_assert (!td
->used
);
332 tri_data_print (td
, stderr
);
334 #endif /* PRINT_HEAP_ELEMENTS */
336 static void insert_entry_into_heap (gpointer key
,
340 GtsTriangle
* t
= key
;
341 tri_data_t
* td
= value
;
342 GtsEHeap
* heap
= user_data
;
345 td
->pos
= gts_eheap_insert (heap
, t
);
349 static heap_t
* heap_new (GtsSurface
*s
)
354 heap
= g_malloc (sizeof (heap_t
));
355 heap
->map
= map_new (s
);
356 heap
->heap
= gts_eheap_new (triangle_priority
, heap
->map
);
357 g_hash_table_foreach (heap
->map
->ht
,
358 insert_entry_into_heap
,
360 #if PRINT_HEAP_ELEMENTS
361 gts_eheap_foreach (heap
->heap
, print_heap_element
, heap
->map
);
362 #endif /* PRINT_HEAP_ELEMENTS */
366 static void heap_destroy (heap_t
* heap
)
370 map_destroy (heap
->map
);
371 gts_eheap_destroy (heap
->heap
);
375 static gboolean
heap_is_empty (const heap_t
* heap
)
378 g_assert (heap
->heap
);
379 return gts_eheap_size (heap
->heap
) == 0;
387 static GtsTriangle
* heap_top (const heap_t
* heap
)
392 g_assert (heap
->heap
);
393 t
= gts_eheap_top (heap
->heap
, NULL
);
397 static void decrease_key (gpointer key
, gpointer value
, gpointer user_data
)
399 GtsTriangle
* t
= key
;
400 tri_data_t
* td
= value
;
401 heap_t
*heap
= user_data
;
406 g_assert (heap
->map
);
407 g_assert (heap
->heap
);
409 g_assert (!td
->used
);
412 k
= tri_data_num_unused_neighbors2 (td
, heap
->map
);
413 g_assert (k
<= td
->pos
->key
);
415 if (k
== td
->pos
->key
)
416 g_warning ("same key: %f\n", k
);
418 if (k
!= td
->pos
->key
) {
419 g_assert (k
< td
->pos
->key
);
421 gts_eheap_decrease_key (heap
->heap
, td
->pos
, k
);
425 static void heap_remove (heap_t
* heap
, GtsTriangle
* t
)
432 td
= map_lookup (heap
->map
, t
);
434 g_assert (!td
->used
);
437 gts_eheap_remove (heap
->heap
, td
->pos
);
440 /* fprintf(stderr, "td: %p\n", td); */
441 h
= tri_data_unused_neighbors2 (td
, heap
->map
);
442 g_hash_table_foreach (h
, decrease_key
, heap
);
443 g_hash_table_destroy (h
);
446 /* map_t functions */
448 static gint
create_map_entry (gpointer item
, gpointer data
)
450 GtsTriangle
* t
= item
;
451 GHashTable
* ht
= data
;
456 td
= tri_data_new (t
);
457 g_hash_table_insert (ht
, t
, td
);
461 static void free_map_entry (gpointer key
, gpointer value
, gpointer user_data
)
463 GtsTriangle
* t
= key
;
464 tri_data_t
* td
= value
;
469 g_assert (td
->t
== t
);
470 tri_data_destroy (td
);
473 static map_t
* map_new (GtsSurface
* s
)
477 map
= g_malloc (sizeof (map_t
));
478 map
->ht
= g_hash_table_new (NULL
, NULL
);
479 gts_surface_foreach_face (s
, create_map_entry
, map
->ht
);
483 static void map_destroy (map_t
* map
)
487 g_hash_table_foreach (map
->ht
, free_map_entry
, NULL
);
488 g_hash_table_destroy (map
->ht
);
492 static tri_data_t
* map_lookup (const map_t
* map
, GtsTriangle
* t
)
499 td
= g_hash_table_lookup (map
->ht
, t
);
501 g_assert (td
->t
== t
);
505 /* other helper functions */
507 static GtsTriangle
* find_min_neighbor (heap_t
* heap
, GtsTriangle
* t
)
509 GtsTriangle
* min_neighbor
= NULL
;
510 gdouble min_key
= G_MAXDOUBLE
;
517 td
= map_lookup (heap
->map
, t
);
518 for (li
= td
->neighbors
; li
!= NULL
; li
= li
->next
) {
519 GtsTriangle
* t2
= li
->data
;
520 tri_data_t
* td2
= map_lookup (heap
->map
, t2
);
536 static GtsTriangle
* find_neighbor_forward (heap_t
* heap
,
543 GtsTriangle
* neighbor
= NULL
;
549 g_assert (v1
&& v2
&& v3
);
550 g_assert (vertices_are_unique (*v1
, *v2
, *v3
));
552 td
= map_lookup (heap
->map
, t
);
554 for (li
= td
->neighbors
; li
&& !neighbor
; li
= li
->next
) {
555 GtsTriangle
* t2
= li
->data
;
556 tri_data_t
* td2
= map_lookup (heap
->map
, t2
);
557 GtsVertex
* v4
, * v5
, * v6
;
560 if (t2
== t
|| td2
->used
)
562 gts_triangle_vertices (t2
, &v4
, &v5
, &v6
);
564 if (!vertices_match (*v1
, *v3
, NULL
, &v4
, &v5
, &v6
))
567 if (!vertices_match (*v3
, *v2
, NULL
, &v4
, &v5
, &v6
))
578 static GtsTriangle
* find_neighbor_backward (heap_t
* heap
,
585 GtsTriangle
* neighbor
= NULL
;
591 g_assert (v1
&& v2
&& v3
);
592 g_assert (vertices_are_unique (*v1
, *v2
, *v3
));
594 td
= map_lookup (heap
->map
, t
);
596 for (li
= td
->neighbors
; li
&& !neighbor
; li
= li
->next
) {
597 GtsTriangle
* t2
= li
->data
;
598 tri_data_t
* td2
= map_lookup (heap
->map
, t2
);
599 GtsVertex
* v4
, * v5
, * v6
;
602 if (t2
== t
|| td2
->used
)
604 gts_triangle_vertices (t2
, &v4
, &v5
, &v6
);
606 if (!vertices_match (NULL
, *v2
, *v1
, &v4
, &v5
, &v6
))
608 } else if (!vertices_match(*v1
, NULL
, *v2
, &v4
, &v5
, &v6
))
618 static GSList
* grow_strip_forward (heap_t
* heap
,
628 g_assert (g_slist_length(strip
) == 2);
630 g_assert (v1
&& v2
&& v3
);
631 g_assert (vertices_are_unique (v1
, v2
, v3
));
634 while ((t
= find_neighbor_forward (heap
, t
, &v1
, &v2
, &v3
,
635 left_turn
)) != NULL
) {
636 heap_remove (heap
, t
);
637 strip
= g_slist_prepend (strip
, t
);
638 left_turn
= !left_turn
;
643 static GSList
* grow_strip_backward (heap_t
* heap
,
650 /* we have to make sure we add an even number of triangles */
654 g_assert (g_slist_length(strip
) >= 2);
656 g_assert (v1
&& v2
&& v3
);
657 g_assert (vertices_are_unique (v1
, v2
, v3
));
659 while ((t2
= find_neighbor_backward (heap
, t
, &v1
, &v2
, &v3
,
661 && (t
= find_neighbor_backward (heap
, t2
, &v1
, &v2
, &v3
,
663 heap_remove (heap
, t2
);
664 heap_remove (heap
, t
);
665 strip
= g_slist_prepend (strip
, t2
);
666 strip
= g_slist_prepend (strip
, t
);
671 static gboolean
find_right_turn (GtsVertex
** v1
,
680 g_assert (v1
&& v2
&& v3
);
681 g_assert (v4
&& v5
&& v6
);
682 g_assert (vertices_are_unique (*v1
, *v2
, *v3
));
683 g_assert (vertices_are_unique (*v4
, *v5
, *v6
));
684 g_assert (num_shared_vertices (*v1
, *v2
, *v3
, *v4
, *v5
, *v6
) == 2);
686 v
= non_shared_vertex1 (*v1
, *v2
, *v3
, *v4
, *v5
, *v6
);
687 match_vertex (v
, v1
, v2
, v3
);
688 match_vertex (*v3
, v4
, v5
, v6
);
690 g_assert (v1
&& v2
&& v3
);
691 g_assert (v4
&& v5
&& v6
);
692 g_assert (*v4
== *v3
);
695 g_assert (vertices_are_unique (*v1
, *v2
, *v3
));
696 g_assert (vertices_are_unique (*v4
, *v5
, *v6
));
697 g_assert (num_shared_vertices (*v1
, *v2
, *v3
,
698 *v4
, *v5
, *v6
) == 2);
702 g_warning ("couldn't find a right turn");
712 * Decompose @s into triangle strips for fast-rendering.
714 * Returns: a list of triangle strips containing all the triangles of @s.
715 * A triangle strip is itself a list of successive triangles having one edge
718 GSList
* gts_surface_strip (GtsSurface
*s
)
720 GSList
* strips
= NULL
;
723 g_return_val_if_fail (s
!= NULL
, NULL
);
726 while (!heap_is_empty (heap
)) {
727 GtsTriangle
* t1
, * t2
;
728 GtsVertex
* v1
, * v2
, * v3
, * v4
, * v5
, * v6
;
729 GSList
* strip
= NULL
;
731 /* remove heap top */
732 t1
= heap_top (heap
);
734 heap_remove (heap
, t1
);
736 /* start a new strip */
737 strip
= g_slist_prepend (strip
, t1
);
739 /* find second triangle */
740 t2
= find_min_neighbor (heap
, t1
);
744 /* find right turn */
745 gts_triangle_vertices (t1
, &v1
, &v2
, &v3
);
746 gts_triangle_vertices (t2
, &v4
, &v5
, &v6
);
747 if (find_right_turn (&v1
, &v2
, &v3
, &v4
, &v5
, &v6
)) {
748 heap_remove (heap
, t2
);
749 strip
= g_slist_prepend (strip
, t2
);
751 /* grow strip forward */
752 strip
= grow_strip_forward (heap
, strip
, t2
, v4
, v5
, v6
);
754 strip
= g_slist_reverse (strip
);
756 /* grow strip backward */
757 strip
= grow_strip_backward (heap
, strip
, t1
, v1
, v2
, v3
);
760 strips
= g_slist_prepend (strips
, strip
);
762 strips
= g_slist_reverse (strips
);