1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 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.
29 #define DEBUG_EXPAND */
31 struct _GtsSplitCFace
{
33 GtsTriangle
** a1
, ** a2
;
36 typedef struct _CFace CFace
;
37 typedef struct _CFaceClass CFaceClass
;
42 GtsSplit
* parent_split
;
46 /* the size of the CFace structure must be smaller or equal to the size
47 of the GtsFace structure as both structures use the same memory location */
50 GtsObjectClass parent_class
;
53 #define IS_CFACE(obj) (gts_object_is_from_class (obj, cface_class ()))
54 #define CFACE(obj) ((CFace *) obj)
55 #define CFACE_ORIENTATION(cf) ((cf)->flags & 0x1)
56 #define CFACE_ORIENTATION_DIRECT(cf) ((cf)->flags |= 0x1)
57 #define CFACE_VVS(cf) ((cf)->flags & 0x2)
58 #define CFACE_VVS_DIRECT(cf) ((cf)->flags |= 0x2)
61 #define CFACE_KEEP_VVS 0x10
63 #define ROTATE_ORIENT(e, e1, e2, e3) { if (e1 == e) { e1 = e2; e2 = e3; }\
64 else if (e2 == e) { e2 = e1; e1 = e3; }\
65 else g_assert (e3 == e); }
66 #define SEGMENT_USE_VERTEX(s, v) ((s)->v1 == v || (s)->v2 == v)
67 #define TRIANGLE_REPLACE_EDGE(t, e, with) { if ((t)->e1 == e)\
69 else if ((t)->e2 == e)\
72 g_assert ((t)->e3 == e);\
77 #define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\
78 gts_eheap_insert (h, e))
79 #define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\
80 GTS_OBJECT (e)->reserved = NULL)
82 static GtsObjectClass
* cface_class (void)
84 static GtsObjectClass
* klass
= NULL
;
87 GtsObjectClassInfo cface_info
= {
91 (GtsObjectClassInitFunc
) NULL
,
92 (GtsObjectInitFunc
) NULL
,
96 klass
= gts_object_class_new (gts_object_class (), &cface_info
);
97 g_assert (sizeof (CFace
) <= sizeof (GtsFace
));
103 /* Replace @e with @with for all the triangles using @e but @f.
104 Destroys @e and removes it from @heap (if not %NULL).
105 Returns a triangle using e different from f or %NULL. */
106 static GtsTriangle
* replace_edge_collapse (GtsEdge
* e
,
119 GtsTriangle
* rt
= NULL
;
128 size
= g_slist_length (i
)*sizeof (GtsTriangle
*);
129 *a1
= a
= g_malloc (size
> 0 ? size
: sizeof (GtsTriangle
*));
131 GtsTriangle
* t
= i
->data
;
132 GSList
* next
= i
->next
;
133 if (t
!= ((GtsTriangle
*) cf
)) {
135 i
->next
= e
->triangles
;
137 /* set the edge given by edge_flag (CFACE_E1 or CFACE_E2) */
138 GTS_OBJECT (t
)->reserved
= GUINT_TO_POINTER (edge_flag
);
139 cf
->flags
|= CFACE_KEEP_VVS
;
142 TRIANGLE_REPLACE_EDGE (t
, e
, with
);
143 i
->next
= with
->triangles
;
156 HEAP_REMOVE_OBJECT (heap
, e
);
157 gts_object_destroy (GTS_OBJECT (e
));
162 size
= g_slist_length (i
)*sizeof (GtsTriangle
*);
163 *a1
= a
= g_malloc (size
> 0 ? size
: sizeof (GtsTriangle
*));
166 GtsTriangle
* t
= i
->data
;
167 GSList
* next
= i
->next
;
168 if (t
!= ((GtsTriangle
*) cf
)) {
169 TRIANGLE_REPLACE_EDGE (t
, e
, with
);
170 i
->next
= with
->triangles
;
185 HEAP_REMOVE_OBJECT (heap
, e
);
187 gts_object_destroy (GTS_OBJECT (e
));
193 static CFace
* cface_new (GtsFace
* f
,
201 , GtsSplitCFace
* scf
207 GtsEdge
* e1
, * e2
, * e3
, * vvs
;
209 GtsTriangle
* t
, * t1
= NULL
, * t2
= NULL
;
212 g_return_val_if_fail (f
!= NULL
, NULL
);
214 g_return_val_if_fail (GTS_IS_FACE (f
), NULL
);
216 g_return_val_if_fail (e
!= NULL
, NULL
);
217 g_return_val_if_fail (vs
!= NULL
, NULL
);
219 t
= ((GtsTriangle
*) f
);
221 g_return_val_if_fail (!gts_triangle_is_duplicate (t
), NULL
);
224 /* get CFACE_E1 and CFACE_E2 info */
225 flags
= GPOINTER_TO_UINT (GTS_OBJECT (f
)->reserved
);
227 GTS_OBJECT_SET_FLAGS (f
, GTS_DESTROYED
);
231 GSList
* next
= i
->next
;
232 gts_surface_remove_face (i
->data
, f
);
235 g_slist_free (f
->surfaces
);
237 e1
= t
->e1
; e2
= t
->e2
; e3
= t
->e3
;
238 ROTATE_ORIENT (e
, e1
, e2
, e3
);
242 GTS_OBJECT (cf
)->klass
= cface_class ();
246 gts_object_init (GTS_OBJECT (cf
), cface_class ());
247 cf
->parent_split
= vs
;
249 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1
), v2
)) {
250 CFACE_ORIENTATION_DIRECT (cf
); /* v1->v2->v */
251 e3
= e1
; e1
= e2
; e2
= e3
;
253 v
= GTS_SEGMENT (e1
)->v1
== v1
?
254 GTS_SEGMENT (e1
)->v2
: GTS_SEGMENT (e1
)->v1
;
256 if ((cf
->flags
& CFACE_E1
) || (cf
->flags
& CFACE_E2
))
257 g_assert ((vvs
= GTS_EDGE (gts_vertices_are_connected (vs
->v
, v
))));
260 vvs
= gts_edge_new (klass
, v
, vs
->v
);
262 t1
= replace_edge_collapse (e1
, vvs
, cf
, heap
270 t2
= replace_edge_collapse (e2
, vvs
, cf
, heap
278 t
= cf
->t
= t1
? t1
: t2
;
281 /* set up flags necessary to find vvs */
282 if (t
->e1
== vvs
) e2
= t
->e2
;
283 else if (t
->e2
== vvs
) e2
= t
->e3
;
285 g_assert (t
->e3
== vvs
);
288 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2
), v
))
289 CFACE_VVS_DIRECT (cf
);
294 static void find_vvs (GtsVertex
* vs
,
296 GtsVertex
** v
, GtsEdge
** vvs
,
297 gboolean orientation
)
299 GtsEdge
* e1
= t
->e1
, * e2
= t
->e2
, * e3
= t
->e3
, * tmp
;
301 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2
), vs
)) {
302 tmp
= e1
; e1
= e2
; e2
= e3
; e3
= tmp
;
304 else if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e3
), vs
)) {
305 tmp
= e1
; e1
= e3
; e3
= e2
; e2
= tmp
;
308 g_assert (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1
), vs
));
309 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2
), vs
) ||
310 !gts_segments_touch (GTS_SEGMENT (e1
), GTS_SEGMENT (e2
))) {
311 tmp
= e1
; e1
= e2
; e2
= e3
; e3
= tmp
;
312 g_assert (gts_segments_touch (GTS_SEGMENT (e1
), GTS_SEGMENT (e2
)));
315 *vvs
= orientation
? e1
: e3
;
317 if (GTS_SEGMENT (*vvs
)->v1
!= vs
) {
318 g_assert (GTS_SEGMENT (*vvs
)->v2
== vs
);
319 *v
= GTS_SEGMENT (*vvs
)->v1
;
322 *v
= GTS_SEGMENT (*vvs
)->v2
;
325 static void replace_edge_expand (GtsEdge
* e
,
330 GtsTriangle
** i
= a
, * t
;
332 while ((t
= *(i
++))) {
334 g_assert (!IS_CFACE (t
));
335 fprintf (stderr
, "replacing %p->%d: e: %p->%d with: %p->%d\n",
336 t
, id (t
), e
, id (e
), with
, id (with
));
338 TRIANGLE_REPLACE_EDGE (t
, e
, with
);
339 with
->triangles
= g_slist_prepend (with
->triangles
, t
);
340 if (GTS_OBJECT (t
)->reserved
) {
341 /* apart from the triangles having e as an edge, t is the only
343 g_assert (GTS_OBJECT (t
)->reserved
== v
);
344 GTS_OBJECT (t
)->reserved
= NULL
;
347 GTS_OBJECT (t
)->reserved
= v
;
351 static void cface_expand (CFace
* cf
,
358 GtsEdgeClass
* klass
)
361 GtsEdge
* e1
, * e2
, * vvs
;
362 gboolean orientation
;
365 g_return_if_fail (cf
!= NULL
);
366 g_return_if_fail (IS_CFACE (cf
));
367 g_return_if_fail (e
!= NULL
);
368 g_return_if_fail (vs
!= NULL
);
371 orientation
= CFACE_ORIENTATION (cf
);
373 find_vvs (vs
, cf
->t
, &v
, &vvs
, CFACE_VVS (cf
));
376 if (flags
& CFACE_E1
)
377 e1
= GTS_EDGE (gts_vertices_are_connected (v1
, v
));
379 e1
= gts_edge_new (klass
, v
, v1
);
380 if (flags
& CFACE_E2
)
381 e2
= GTS_EDGE (gts_vertices_are_connected (v2
, v
));
383 e2
= gts_edge_new (klass
, v
, v2
);
385 e1
= gts_edge_new (v
, v1
);
386 e2
= gts_edge_new (v
, v2
);
389 replace_edge_expand (vvs
, e1
, a1
, v1
);
390 replace_edge_expand (vvs
, e2
, a2
, v2
);
393 if (!(flags
& CFACE_KEEP_VVS
)) {
394 g_slist_free (vvs
->triangles
);
395 vvs
->triangles
= NULL
;
396 gts_object_destroy (GTS_OBJECT (vvs
));
399 g_slist_free (vvs
->triangles
);
400 vvs
->triangles
= NULL
;
401 gts_object_destroy (GTS_OBJECT (vvs
));
404 /* gts_face_new : because I am "creating" a face */
405 GTS_OBJECT (cf
)->klass
= GTS_OBJECT_CLASS (gts_face_class ());
406 gts_object_init (GTS_OBJECT (cf
), GTS_OBJECT (cf
)->klass
);
409 gts_triangle_set (GTS_TRIANGLE (cf
), e
, e2
, e1
);
411 gts_triangle_set (GTS_TRIANGLE (cf
), e
, e1
, e2
);
414 static void split_destroy (GtsObject
* object
)
416 GtsSplit
* vs
= GTS_SPLIT (object
);
418 GtsSplitCFace
* cf
= vs
->cfaces
;
421 if (IS_CFACE (cf
->f
))
422 gts_object_destroy (GTS_OBJECT (cf
->f
));
429 if (!gts_allow_floating_vertices
&& vs
->v
&& vs
->v
->segments
== NULL
)
430 gts_object_destroy (GTS_OBJECT (vs
->v
));
432 (* GTS_OBJECT_CLASS (gts_split_class ())->parent_class
->destroy
) (object
);
435 static void split_class_init (GtsObjectClass
* klass
)
437 klass
->destroy
= split_destroy
;
440 static void split_init (GtsSplit
* split
)
442 split
->v1
= split
->v2
= NULL
;
444 split
->cfaces
= NULL
;
451 * Returns: the #GtsSplitClass.
453 GtsSplitClass
* gts_split_class (void)
455 static GtsSplitClass
* klass
= NULL
;
458 GtsObjectClassInfo split_info
= {
461 sizeof (GtsSplitClass
),
462 (GtsObjectClassInitFunc
) split_class_init
,
463 (GtsObjectInitFunc
) split_init
,
464 (GtsArgSetFunc
) NULL
,
467 klass
= gts_object_class_new (gts_object_class (),
475 static gboolean
edge_collapse_is_valid (GtsEdge
* e
)
479 g_return_val_if_fail (e
!= NULL
, FALSE
);
481 if (gts_segment_is_duplicate (GTS_SEGMENT (e
))) {
482 g_warning ("collapsing duplicate edge");
486 i
= GTS_SEGMENT (e
)->v1
->segments
;
488 GtsEdge
* e1
= i
->data
;
489 if (e1
!= e
&& GTS_IS_EDGE (e1
)) {
491 GSList
* j
= GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e
)->v1
?
492 GTS_SEGMENT (e1
)->v2
->segments
: GTS_SEGMENT (e1
)->v1
->segments
;
494 GtsEdge
* e1
= j
->data
;
495 if (GTS_IS_EDGE (e1
) &&
496 (GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e
)->v2
||
497 GTS_SEGMENT (e1
)->v2
== GTS_SEGMENT (e
)->v2
))
501 if (e2
&& !gts_triangle_use_edges (e
, e1
, e2
)) {
502 g_warning ("collapsing empty triangle");
509 if (gts_edge_is_boundary (e
, NULL
)) {
510 GtsTriangle
* t
= e
->triangles
->data
;
511 if (gts_edge_is_boundary (t
->e1
, NULL
) &&
512 gts_edge_is_boundary (t
->e2
, NULL
) &&
513 gts_edge_is_boundary (t
->e3
, NULL
)) {
514 g_warning ("collapsing single triangle");
519 if (gts_vertex_is_boundary (GTS_SEGMENT (e
)->v1
, NULL
) &&
520 gts_vertex_is_boundary (GTS_SEGMENT (e
)->v2
, NULL
)) {
521 g_warning ("collapsing two sides of a strip");
524 if (gts_edge_belongs_to_tetrahedron (e
)) {
525 g_warning ("collapsing tetrahedron");
534 /* Not currently used. May be useful for some debug code */
536 static void print_split (GtsSplit
* vs
, FILE * fptr
)
541 g_return_if_fail (vs
!= NULL
);
542 g_return_if_fail (fptr
!= NULL
);
544 fprintf (fptr
, "%p: v: %p v1: %p v2: %p ncf: %u cfaces: %p\n",
545 vs
, vs
->v
, vs
->v1
, vs
->v2
, vs
->ncf
, vs
->cfaces
);
549 fprintf (stderr
, " f: %p a1: %p a2: %p\n",
550 cf
->f
, cf
->a1
, cf
->a2
);
557 * gts_split_collapse:
559 * @klass: a #GtsEdgeClass.
560 * @heap: a #GtsEHeap or %NULL.
562 * Collapses the vertex split @vs. Any new edge created during the process will
563 * be of class @klass. If heap is not %NULL, the new edges will be inserted
564 * into it and the destroyed edges will be removed from it.
566 void gts_split_collapse (GtsSplit
* vs
,
567 GtsEdgeClass
* klass
,
571 GtsVertex
* v
, * v1
, * v2
;
578 gboolean invalid
= FALSE
;
579 static guint ninvalid
= 0;
582 g_return_if_fail (vs
!= NULL
);
583 g_return_if_fail (klass
!= NULL
);
587 g_return_if_fail (v
->segments
== NULL
);
589 /* we don't want to destroy vertices */
590 gts_allow_floating_vertices
= TRUE
;
592 v1
= GTS_SPLIT_V1 (vs
);
593 v2
= GTS_SPLIT_V2 (vs
);
594 g_assert ((e
= GTS_EDGE (gts_vertices_are_connected (v1
, v2
))));
597 fprintf (stderr
, "collapsing %p: v1: %p v2: %p v: %p\n", vs
, v1
, v2
, v
);
598 if (!edge_collapse_is_valid (e
)) {
601 GSList
* triangles
, * i
;
603 g_warning ("invalid edge collapse");
605 sprintf (fname
, "invalid.%d", ninvalid
);
606 fptr
= fopen (fname
, "wt");
607 gts_write_segment (GTS_SEGMENT (e
), GTS_POINT (v
), fptr
);
608 triangles
= gts_vertex_triangles (v1
, NULL
);
609 triangles
= gts_vertex_triangles (v2
, triangles
);
612 gts_write_triangle (i
->data
, GTS_POINT (v
), fptr
);
615 g_slist_free (triangles
);
631 vs
->ncf
= g_slist_length (i
);
632 g_assert (vs
->ncf
> 0);
633 cf
= vs
->cfaces
= g_malloc (vs
->ncf
*sizeof (GtsSplitCFace
));
634 #endif /* DYNAMIC_SPLIT */
638 g_assert (GTS_IS_FACE (cf
->f
));
639 GTS_OBJECT (cf
->f
)->klass
= GTS_OBJECT_CLASS (cface_class ());
646 cface_new (i
->data
, e
, v1
, v2
, vs
, heap
, klass
, cf
);
648 fprintf (stderr
, "cface: %p->%d t: %p->%d a1: ",
649 cf
->f
, id (cf
->f
), CFACE (cf
->f
)->t
, id (CFACE (cf
->f
)->t
));
651 GtsTriangle
* t
, ** a
;
654 fprintf (stderr
, "%p->%d ", t
, id (t
));
655 fprintf (stderr
, "a2: ");
658 fprintf (stderr
, "%p->%d ", t
, id (t
));
659 fprintf (stderr
, "\n");
667 cface_new (i
->data
, e
, v1
, v2
, vs
, heap
670 #endif /* DYNAMIC_SPLIT */
675 #endif /* DYNAMIC_SPLIT */
679 g_slist_free (e
->triangles
);
681 gts_object_destroy (GTS_OBJECT (e
));
683 gts_allow_floating_vertices
= FALSE
;
688 GtsSegment
* s
= i
->data
;
697 end
->next
= v
->segments
;
698 v
->segments
= v1
->segments
;
705 GtsSegment
* s
= i
->data
;
714 end
->next
= v
->segments
;
715 v
->segments
= v2
->segments
;
723 GSList
* triangles
, * i
;
724 GtsSurface
* surface
= NULL
;
726 sprintf (fname
, "invalid_after.%d", ninvalid
);
727 fptr
= fopen (fname
, "wt");
728 triangles
= gts_vertex_triangles (v
, NULL
);
731 GtsTriangle
* t
= i
->data
;
732 fprintf (stderr
, "checking %p->%d\n", t
, id (t
));
733 g_assert (GTS_IS_FACE (t
));
734 gts_write_triangle (t
, GTS_POINT (v
), fptr
);
735 surface
= GTS_FACE (t
)->surfaces
->data
;
736 if (gts_triangle_is_duplicate (t
))
737 fprintf (stderr
, "%p->%d is duplicate\n", t
, id (t
));
738 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e1
)))
739 fprintf (stderr
, "e1 of %p->%d is duplicate\n", t
, id (t
));
740 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e2
)))
741 fprintf (stderr
, "e2 of %p->%d is duplicate\n", t
, id (t
));
742 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e3
)))
743 fprintf (stderr
, "e3 of %p->%d is duplicate\n", t
, id (t
));
747 g_slist_free (triangles
);
749 gts_split_expand (vs
, surface
);
751 sprintf (fname
, "invalid_after_after.%d", ninvalid
);
752 fptr
= fopen (fname
, "wt");
753 triangles
= gts_vertex_triangles (v1
, NULL
);
754 triangles
= gts_vertex_triangles (v2
, triangles
);
757 GtsTriangle
* t
= i
->data
;
758 gts_write_triangle (t
, GTS_POINT (v
), fptr
);
759 surface
= GTS_FACE (t
)->surfaces
->data
;
760 if (gts_triangle_is_duplicate (t
))
761 fprintf (stderr
, "%p->%d is duplicate\n", t
, id (t
));
762 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e1
)))
763 fprintf (stderr
, "e1 of %p->%d is duplicate\n", t
, id (t
));
764 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e2
)))
765 fprintf (stderr
, "e2 of %p->%d is duplicate\n", t
, id (t
));
766 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e3
)))
767 fprintf (stderr
, "e3 of %p->%d is duplicate\n", t
, id (t
));
771 g_slist_free (triangles
);
784 * @klass: a #GtsEdgeClass.
786 * Expands the vertex split @vs adding the newly created faces to @s. Any
787 * new edge will be of class @klass.
789 void gts_split_expand (GtsSplit
* vs
,
791 GtsEdgeClass
* klass
)
795 GtsVertex
* v
, * v1
, * v2
;
796 gboolean changed
= FALSE
;
800 g_return_if_fail (vs
!= NULL
);
801 g_return_if_fail (s
!= NULL
);
802 g_return_if_fail (klass
!= NULL
);
804 /* we don't want to destroy vertices */
805 gts_allow_floating_vertices
= TRUE
;
807 v1
= GTS_SPLIT_V1 (vs
);
808 v2
= GTS_SPLIT_V2 (vs
);
811 fprintf (stderr
, "expanding %p->%d: v1: %p->%d v2: %p->%d v: %p->%d\n",
812 vs
, id (vs
), v1
, id (v1
), v2
, id (v2
), v
, id (v
));
814 e
= gts_edge_new (klass
, v1
, v2
);
818 cface_expand (CFACE (cf
->f
), cf
->a1
, cf
->a2
, e
, v1
, v2
, v
, klass
);
819 gts_surface_add_face (s
, cf
->f
);
823 gts_allow_floating_vertices
= FALSE
;
825 /* this part is described by figure "expand.fig" */
828 GtsEdge
* e1
= i
->data
;
829 GtsVertex
* with
= NULL
;
830 GSList
* j
= e1
->triangles
, * next
= i
->next
;
831 // fprintf (stderr, "e1: %p->%d\n", e1, id (e1));
833 with
= GTS_OBJECT (j
->data
)->reserved
;
839 GtsTriangle
* t
= j
->data
;
840 if (GTS_OBJECT (t
)->reserved
) {
841 g_assert (GTS_OBJECT (t
)->reserved
== with
);
842 GTS_OBJECT (t
)->reserved
= NULL
;
845 GTS_OBJECT (t
)->reserved
= with
;
848 if (GTS_SEGMENT (e1
)->v1
== v
)
849 GTS_SEGMENT (e1
)->v1
= with
;
851 GTS_SEGMENT (e1
)->v2
= with
;
853 v
->segments
= g_slist_remove_link (v
->segments
, i
);
854 i
->next
= with
->segments
;
861 /* check for infinite loop (the crossed out case in
862 figure "expand.fig") */
870 #ifndef DYNAMIC_SPLIT
871 static void cface_neighbors (GtsSplitCFace
* cf
,
876 GtsTriangle
* t
= GTS_TRIANGLE (cf
->f
), ** a
;
877 GtsEdge
* e1
= t
->e1
, * e2
= t
->e2
, * e3
= t
->e3
;
881 ROTATE_ORIENT (e
, e1
, e2
, e3
);
882 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1
), v2
)) {
883 e3
= e1
; e1
= e2
; e2
= e3
;
887 size
= g_slist_length (i
)*sizeof (GtsTriangle
*);
888 a
= cf
->a1
= g_malloc (size
> 0 ? size
: sizeof (GtsTriangle
*));
897 size
= g_slist_length (i
)*sizeof (GtsTriangle
*);
898 a
= cf
->a2
= g_malloc (size
> 0 ? size
: sizeof (GtsTriangle
*));
906 #endif /*ifndef DYNAMIC_SPLIT */
910 * @klass: a #GtsSplitClass.
912 * @o1: either a #GtsVertex or a #GtsSplit.
913 * @o2: either a #GtsVertex or a #GtsSplit.
915 * Creates a new #GtsSplit which would collapse @o1 and @o2 into @v. The
916 * collapse itself is not performed.
918 * Returns: the new #GtsSplit.
920 GtsSplit
* gts_split_new (GtsSplitClass
* klass
,
926 GtsVertex
* v1
, * v2
;
927 #ifndef DYNAMIC_SPLIT
933 g_return_val_if_fail (klass
!= NULL
, NULL
);
934 g_return_val_if_fail (v
!= NULL
, NULL
);
935 g_return_val_if_fail (GTS_IS_SPLIT (o1
) || GTS_IS_VERTEX (o1
), NULL
);
936 g_return_val_if_fail (GTS_IS_SPLIT (o2
) || GTS_IS_VERTEX (o2
), NULL
);
938 vs
= GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass
)));
942 v1
= GTS_SPLIT_V1 (vs
);
943 v2
= GTS_SPLIT_V2 (vs
);
948 g_assert ((e
= GTS_EDGE (gts_vertices_are_connected (v1
, v2
))));
950 vs
->ncf
= g_slist_length (i
);
951 g_assert (vs
->ncf
> 0);
952 cf
= vs
->cfaces
= g_malloc (vs
->ncf
*sizeof (GtsSplitCFace
));
955 cface_neighbors (cf
, e
, v1
, v2
);
965 split_traverse_pre_order (GtsSplit
* vs
,
966 GtsSplitTraverseFunc func
,
971 if (GTS_IS_SPLIT (vs
->v1
) &&
972 split_traverse_pre_order (GTS_SPLIT (vs
->v1
), func
, data
))
974 if (GTS_IS_SPLIT (vs
->v2
) &&
975 split_traverse_pre_order (GTS_SPLIT (vs
->v2
), func
, data
))
981 split_depth_traverse_pre_order (GtsSplit
* vs
,
983 GtsSplitTraverseFunc func
,
993 if (GTS_IS_SPLIT (vs
->v1
) &&
994 split_depth_traverse_pre_order (GTS_SPLIT (vs
->v1
), depth
, func
, data
))
996 if (GTS_IS_SPLIT (vs
->v2
) &&
997 split_depth_traverse_pre_order (GTS_SPLIT (vs
->v2
), depth
, func
, data
))
1003 split_traverse_post_order (GtsSplit
* vs
,
1004 GtsSplitTraverseFunc func
,
1007 if (GTS_IS_SPLIT (vs
->v1
) &&
1008 split_traverse_post_order (GTS_SPLIT (vs
->v1
), func
, data
))
1010 if (GTS_IS_SPLIT (vs
->v2
) &&
1011 split_traverse_post_order (GTS_SPLIT (vs
->v2
), func
, data
))
1013 if (func (vs
, data
))
1019 split_depth_traverse_post_order (GtsSplit
* vs
,
1021 GtsSplitTraverseFunc func
,
1026 if (GTS_IS_SPLIT (vs
->v1
) &&
1027 split_depth_traverse_post_order (GTS_SPLIT (vs
->v1
),
1030 if (GTS_IS_SPLIT (vs
->v2
) &&
1031 split_depth_traverse_post_order (GTS_SPLIT (vs
->v2
),
1035 if (func (vs
, data
))
1041 * gts_split_traverse:
1042 * @root: the #GtsSplit to start the traversal from.
1043 * @order: the order in which nodes are visited - G_PRE_ORDER or G_POST_ORDER.
1044 * @depth: the maximum depth of the traversal. Nodes below this depth
1045 * will not be visited. If depth is -1 all nodes in the tree are
1046 * visited. If depth is 1, only the root is visited. If depth is 2,
1047 * the root and its children are visited. And so on.
1048 * @func: the function to call for each visited #GtsHSplit.
1049 * @data: user data to pass to the function.
1051 * Traverses the #GtsSplit tree having @root as root. Calls @func for each
1052 * #GtsSplit of the tree in the order specified by @order. If order is set
1053 * to G_PRE_ORDER @func is called for the #GtsSplit then its children, if order
1054 * is set to G_POST_ORDER @func is called for the children and then for the
1057 void gts_split_traverse (GtsSplit
* root
,
1058 GTraverseType order
,
1060 GtsSplitTraverseFunc func
,
1063 g_return_if_fail (root
!= NULL
);
1064 g_return_if_fail (func
!= NULL
);
1065 g_return_if_fail (order
< G_LEVEL_ORDER
);
1066 g_return_if_fail (depth
== -1 || depth
> 0);
1071 split_traverse_pre_order (root
, func
, data
);
1073 split_depth_traverse_pre_order (root
, depth
, func
, data
);
1077 split_traverse_post_order (root
, func
, data
);
1079 split_depth_traverse_post_order (root
, depth
, func
, data
);
1082 g_assert_not_reached ();
1088 * @root: a #GtsSplit.
1090 * Returns: the maximum height of the vertex split tree having @root as root.
1092 guint
gts_split_height (GtsSplit
* root
)
1094 guint height
= 0, tmp_height
;
1096 g_return_val_if_fail (root
!= NULL
, 0);
1098 if (GTS_IS_SPLIT (root
->v1
)) {
1099 tmp_height
= gts_split_height (GTS_SPLIT (root
->v1
));
1100 if (tmp_height
> height
)
1101 height
= tmp_height
;
1103 if (GTS_IS_SPLIT (root
->v2
)) {
1104 tmp_height
= gts_split_height (GTS_SPLIT (root
->v2
));
1105 if (tmp_height
> height
)
1106 height
= tmp_height
;
1112 #ifndef DYNAMIC_SPLIT
1113 static gboolean
list_array_are_identical (GSList
* list
,
1118 gpointer data
= list
->data
;
1119 if (data
!= excluded
) {
1120 gboolean found
= FALSE
;
1121 gpointer
* a
= array
;
1123 while (!found
&& *a
)
1133 #endif /* ifndef DYNAMIC_SPLIT */
1136 gboolean
gts_split_is_collapsable (GtsSplit
* vs
)
1140 GtsVertex
* v1
, * v2
;
1143 g_return_val_if_fail (vs
!= NULL
, FALSE
);
1145 v1
= GTS_SPLIT_V1 (vs
);
1146 v2
= GTS_SPLIT_V2 (vs
);
1147 g_return_val_if_fail ((e
= GTS_EDGE (gts_vertices_are_connected (v1
, v2
))),
1150 #ifdef DYNAMIC_SPLIT
1151 if (!gts_edge_collapse_is_valid (e
))
1157 GtsTriangle
* t
= GTS_TRIANGLE (cf
->f
);
1158 GtsEdge
* e1
= t
->e1
, * e2
= t
->e2
, * e3
= t
->e3
;
1160 ROTATE_ORIENT (e
, e1
, e2
, e3
);
1161 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1
), v2
)) {
1162 e3
= e1
; e1
= e2
; e2
= e3
;
1165 if (!list_array_are_identical (e1
->triangles
, (gpointer
*) cf
->a1
, t
))
1167 if (!list_array_are_identical (e2
->triangles
, (gpointer
*) cf
->a2
, t
))
1175 #endif /* not NEW */
1177 #ifdef DEBUG_HEXPAND
1178 static guint expand_level
= 0;
1180 static void expand_indent (FILE * fptr
)
1182 guint i
= expand_level
;
1189 * gts_hsplit_force_expand:
1190 * @hs: a #GtsHSplit.
1191 * @hsurface: a #GtsHSurface.
1193 * Forces the expansion of @hs by first expanding all its dependencies not
1196 void gts_hsplit_force_expand (GtsHSplit
* hs
,
1197 GtsHSurface
* hsurface
)
1202 g_return_if_fail (hs
!= NULL
);
1203 g_return_if_fail (hsurface
!= NULL
);
1204 g_return_if_fail (hs
->nchild
== 0);
1206 #ifdef DEBUG_HEXPAND
1210 if (hs
->parent
&& hs
->parent
->nchild
== 0) {
1211 #ifdef DEBUG_HEXPAND
1212 expand_indent (stderr
);
1213 fprintf (stderr
, "expand parent %p\n", hs
->parent
);
1215 gts_hsplit_force_expand (hs
->parent
, hsurface
);
1218 i
= GTS_SPLIT (hs
)->ncf
;
1219 cf
= GTS_SPLIT (hs
)->cfaces
;
1221 GtsTriangle
** j
, * t
;
1224 while ((t
= *(j
++)))
1226 #ifdef DEBUG_HEXPAND
1227 expand_indent (stderr
);
1228 fprintf (stderr
, "expand a1: cf->f: %p t: %p parent_split: %p\n",
1231 GTS_HSPLIT (CFACE (t
)->parent_split
));
1233 gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t
)->parent_split
),
1235 #ifdef DEBUG_HEXPAND
1236 g_assert (!IS_CFACE (t
));
1240 while ((t
= *(j
++)))
1242 #ifdef DEBUG_HEXPAND
1243 expand_indent (stderr
);
1244 fprintf (stderr
, "expand a2: cf->f: %p t: %p parent_split: %p\n",
1247 GTS_HSPLIT (CFACE (t
)->parent_split
));
1249 gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t
)->parent_split
),
1255 gts_hsplit_expand (hs
, hsurface
);
1257 #ifdef DEBUG_HEXPAND
1259 expand_indent (stderr
);
1260 fprintf (stderr
, "%p expanded\n", hs
);
1264 static void index_object (GtsObject
* o
, guint
* n
)
1266 o
->reserved
= GUINT_TO_POINTER ((*n
)++);
1269 static void index_face (GtsFace
* f
, gpointer
* data
)
1271 guint
* nf
= data
[1];
1273 g_hash_table_insert (data
[0], f
, GUINT_TO_POINTER ((*nf
)++));
1277 * gts_psurface_write:
1278 * @ps: a #GtsPSurface.
1279 * @fptr: a file pointer.
1281 * Writes to @fptr a GTS progressive surface description.
1283 void gts_psurface_write (GtsPSurface
* ps
, FILE * fptr
)
1290 g_return_if_fail (ps
!= NULL
);
1291 g_return_if_fail (fptr
!= NULL
);
1292 g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps
));
1294 while (gts_psurface_remove_vertex (ps
))
1297 GTS_POINT_CLASS (ps
->s
->vertex_class
)->binary
= FALSE
;
1298 gts_surface_write (ps
->s
, fptr
);
1300 gts_surface_foreach_vertex (ps
->s
, (GtsFunc
) index_object
, &nv
);
1301 hash
= g_hash_table_new (NULL
, NULL
);
1304 gts_surface_foreach_face (ps
->s
, (GtsFunc
) index_face
, data
);
1306 fprintf (fptr
, "%u\n", ps
->split
->len
);
1308 GtsSplit
* vs
= g_ptr_array_index (ps
->split
, --ps
->pos
);
1309 GtsSplitCFace
* scf
= vs
->cfaces
;
1310 GtsVertex
* v1
, * v2
;
1313 fprintf (fptr
, "%u %u",
1314 GPOINTER_TO_UINT (GTS_OBJECT (vs
->v
)->reserved
),
1316 if (GTS_OBJECT (vs
)->klass
->write
)
1317 (*GTS_OBJECT (vs
)->klass
->write
) (GTS_OBJECT (vs
), fptr
);
1320 v1
= GTS_IS_SPLIT (vs
->v1
) ? GTS_SPLIT (vs
->v1
)->v
: GTS_VERTEX (vs
->v1
);
1321 GTS_OBJECT (v1
)->reserved
= GUINT_TO_POINTER (nv
++);
1322 v2
= GTS_IS_SPLIT (vs
->v2
) ? GTS_SPLIT (vs
->v2
)->v
: GTS_VERTEX (vs
->v2
);
1323 GTS_OBJECT (v2
)->reserved
= GUINT_TO_POINTER (nv
++);
1325 (*GTS_OBJECT (v1
)->klass
->write
) (GTS_OBJECT (v1
), fptr
);
1328 (*GTS_OBJECT (v2
)->klass
->write
) (GTS_OBJECT (v2
), fptr
);
1332 CFace
* cf
= CFACE (scf
->f
);
1333 GtsTriangle
** a
, * t
;
1335 fprintf (fptr
, "%u %u",
1336 GPOINTER_TO_UINT (g_hash_table_lookup (hash
, cf
->t
)),
1338 if (GTS_OBJECT_CLASS (ps
->s
->face_class
)->write
)
1339 (*GTS_OBJECT_CLASS (ps
->s
->face_class
)->write
) (GTS_OBJECT (cf
), fptr
);
1343 while ((t
= *(a
++)))
1344 fprintf (fptr
, "%u ",
1345 GPOINTER_TO_UINT (g_hash_table_lookup (hash
, t
)));
1346 fprintf (fptr
, "\n");
1349 while ((t
= *(a
++)))
1350 fprintf (fptr
, "%u ",
1351 GPOINTER_TO_UINT (g_hash_table_lookup (hash
, t
)));
1352 fprintf (fptr
, "\n");
1354 g_hash_table_insert (hash
, cf
, GUINT_TO_POINTER (nf
++));
1359 gts_split_expand (vs
, ps
->s
, ps
->s
->edge_class
);
1362 gts_surface_foreach_vertex (ps
->s
,
1363 (GtsFunc
) gts_object_reset_reserved
, NULL
);
1364 g_hash_table_destroy (hash
);
1367 static guint
surface_read (GtsSurface
* surface
,
1369 GPtrArray
* vertices
,
1373 guint n
, nv
, ne
, nf
;
1375 g_return_val_if_fail (surface
!= NULL
, 1);
1376 g_return_val_if_fail (f
!= NULL
, 1);
1378 if (f
->type
!= GTS_INT
) {
1379 gts_file_error (f
, "expecting an integer (number of vertices)");
1382 nv
= atoi (f
->token
->str
);
1384 gts_file_next_token (f
);
1385 if (f
->type
!= GTS_INT
) {
1386 gts_file_error (f
, "expecting an integer (number of edges)");
1389 ne
= atoi (f
->token
->str
);
1391 gts_file_next_token (f
);
1392 if (f
->type
!= GTS_INT
) {
1393 gts_file_error (f
, "expecting an integer (number of faces)");
1396 nf
= atoi (f
->token
->str
);
1398 gts_file_next_token (f
);
1399 if (f
->type
== GTS_STRING
) {
1400 if (f
->type
!= GTS_STRING
) {
1401 gts_file_error (f
, "expecting a string (GtsSurfaceClass)");
1404 gts_file_next_token (f
);
1405 if (f
->type
!= GTS_STRING
) {
1406 gts_file_error (f
, "expecting a string (GtsFaceClass)");
1409 gts_file_next_token (f
);
1410 if (f
->type
!= GTS_STRING
) {
1411 gts_file_error (f
, "expecting a string (GtsEdgeClass)");
1414 gts_file_next_token (f
);
1415 if (f
->type
!= GTS_STRING
) {
1416 gts_file_error (f
, "expecting a string (GtsVertexClass)");
1419 if (!strcmp (f
->token
->str
, "GtsVertexBinary"))
1420 GTS_POINT_CLASS (surface
->vertex_class
)->binary
= TRUE
;
1422 gts_file_first_token_after (f
, '\n');
1425 gts_file_first_token_after (f
, '\n');
1427 g_ptr_array_set_size (vertices
, nv
);
1428 g_ptr_array_set_size (faces
, nf
);
1429 /* allocate nv + 1 just in case nv == 0 */
1430 edges
= g_malloc ((ne
+ 1)*sizeof (GtsEdge
*));
1433 while (n
< nv
&& f
->type
!= GTS_ERROR
) {
1434 GtsObject
* new_vertex
=
1435 gts_object_new (GTS_OBJECT_CLASS (surface
->vertex_class
));
1437 (* GTS_OBJECT_CLASS (surface
->vertex_class
)->read
) (&new_vertex
, f
);
1438 if (f
->type
!= GTS_ERROR
) {
1439 if (!GTS_POINT_CLASS (surface
->vertex_class
)->binary
)
1440 gts_file_first_token_after (f
, '\n');
1441 g_ptr_array_index (vertices
, n
++) = new_vertex
;
1444 gts_object_destroy (new_vertex
);
1446 if (f
->type
== GTS_ERROR
)
1448 if (GTS_POINT_CLASS (surface
->vertex_class
)->binary
)
1449 gts_file_first_token_after (f
, '\n');
1452 while (n
< ne
&& f
->type
!= GTS_ERROR
) {
1455 if (f
->type
!= GTS_INT
)
1456 gts_file_error (f
, "expecting an integer (first vertex index)");
1458 p1
= atoi (f
->token
->str
);
1459 if (p1
== 0 || p1
> nv
)
1460 gts_file_error (f
, "vertex index `%d' is out of range `[1,%d]'",
1463 gts_file_next_token (f
);
1464 if (f
->type
!= GTS_INT
)
1465 gts_file_error (f
, "expecting an integer (second vertex index)");
1467 p2
= atoi (f
->token
->str
);
1468 if (p2
== 0 || p2
> nv
)
1469 gts_file_error (f
, "vertex index `%d' is out of range `[1,%d]'",
1472 GtsEdge
* new_edge
=
1473 gts_edge_new (surface
->edge_class
,
1474 g_ptr_array_index (vertices
, p1
- 1),
1475 g_ptr_array_index (vertices
, p2
- 1));
1477 gts_file_next_token (f
);
1478 if (f
->type
!= '\n')
1479 if (GTS_OBJECT_CLASS (surface
->edge_class
)->read
)
1480 (*GTS_OBJECT_CLASS (surface
->edge_class
)->read
)
1481 ((GtsObject
**) &new_edge
, f
);
1482 gts_file_first_token_after (f
, '\n');
1483 edges
[n
++] = new_edge
;
1489 if (f
->type
== GTS_ERROR
)
1493 while (n
< nf
&& f
->type
!= GTS_ERROR
) {
1496 if (f
->type
!= GTS_INT
)
1497 gts_file_error (f
, "expecting an integer (first edge index)");
1499 s1
= atoi (f
->token
->str
);
1500 if (s1
== 0 || s1
> ne
)
1501 gts_file_error (f
, "edge index `%d' is out of range `[1,%d]'",
1504 gts_file_next_token (f
);
1505 if (f
->type
!= GTS_INT
)
1506 gts_file_error (f
, "expecting an integer (second edge index)");
1508 s2
= atoi (f
->token
->str
);
1509 if (s2
== 0 || s2
> ne
)
1510 gts_file_error (f
, "edge index `%d' is out of range `[1,%d]'",
1513 gts_file_next_token (f
);
1514 if (f
->type
!= GTS_INT
)
1515 gts_file_error (f
, "expecting an integer (third edge index)");
1517 s3
= atoi (f
->token
->str
);
1518 if (s3
== 0 || s3
> ne
)
1519 gts_file_error (f
, "edge index `%d' is out of range `[1,%d]'",
1522 GtsFace
* new_face
= gts_face_new (surface
->face_class
,
1527 gts_file_next_token (f
);
1528 if (f
->type
!= '\n')
1529 if (GTS_OBJECT_CLASS (surface
->face_class
)->read
)
1530 (*GTS_OBJECT_CLASS (surface
->face_class
)->read
)
1531 ((GtsObject
**) &new_face
, f
);
1532 gts_file_first_token_after (f
, '\n');
1533 gts_surface_add_face (surface
, new_face
);
1534 g_ptr_array_index (faces
, n
++) = new_face
;
1545 if (f
->type
== GTS_ERROR
) {
1546 gts_allow_floating_vertices
= TRUE
;
1548 gts_object_destroy (GTS_OBJECT (g_ptr_array_index (vertices
, nv
-- - 1)));
1549 gts_allow_floating_vertices
= FALSE
;
1557 * gts_psurface_open:
1558 * @klass: a #GtsPSurfaceClass.
1559 * @s: a #GtsSurface.
1560 * @split_class: a #GtsSplitClass to use for the #GtsSplit.
1563 * Creates a new #GtsPSurface prepared for input from the file @f
1564 * containing a valid GTS representation of a progressive surface. The initial
1565 * shape of the progressive surface is loaded into @s.
1567 * Before being usable as such this progressive surface must be closed using
1568 * gts_psurface_close(). While open however, the functions
1569 * gts_psurface_get_vertex_number(), gts_psurface_min_vertex_number() and
1570 * gts_psurface_max_vertex_number() can still be used.
1572 * Returns: a new #GtsPSurface or %NULL if there was a format error while
1573 * reading the file, in which case @f contains information about the error.
1575 GtsPSurface
* gts_psurface_open (GtsPSurfaceClass
* klass
,
1577 GtsSplitClass
* split_class
,
1582 g_return_val_if_fail (klass
!= NULL
, NULL
);
1583 g_return_val_if_fail (s
!= NULL
, NULL
);
1584 g_return_val_if_fail (split_class
!= NULL
, NULL
);
1585 g_return_val_if_fail (f
!= NULL
, NULL
);
1587 ps
= GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass
)));
1589 ps
->split_class
= split_class
;
1591 ps
->vertices
= g_ptr_array_new ();
1592 ps
->faces
= g_ptr_array_new ();
1594 if (surface_read (s
, f
, ps
->vertices
, ps
->faces
)) {
1596 gts_object_destroy (GTS_OBJECT (ps
));
1600 ps
->min
= gts_surface_vertex_number (ps
->s
);
1603 if (f
->type
== GTS_INT
) {
1604 gint ns
= atoi (f
->token
->str
);
1607 g_ptr_array_set_size (ps
->split
, ns
);
1608 gts_file_first_token_after (f
, '\n');
1616 * gts_psurface_read_vertex:
1617 * @ps: a #GtsPSurface prealably created with gts_psurface_open().
1620 * Reads in one vertex split operation from @fp and performs the expansion.
1622 * If an error occurs while reading the file, the @error field of @fp is set.
1624 * Returns: the newly created #GtsSplit or %NULL if no vertex split could be
1627 GtsSplit
* gts_psurface_read_vertex (GtsPSurface
* ps
, GtsFile
* fp
)
1630 GtsSplit
* vs
, * parent
;
1631 GtsSplitCFace
* scf
;
1633 g_return_val_if_fail (ps
!= NULL
, NULL
);
1634 g_return_val_if_fail (fp
!= NULL
, NULL
);
1635 g_return_val_if_fail (!GTS_PSURFACE_IS_CLOSED (ps
), NULL
);
1637 if (ps
->pos
>= ps
->split
->len
)
1640 if (fp
->type
== GTS_NONE
)
1642 if (fp
->type
!= GTS_INT
) {
1643 gts_file_error (fp
, "expecting an integer (vertex index)");
1646 nv
= atoi (fp
->token
->str
);
1647 if (nv
== 0 || nv
> ps
->vertices
->len
) {
1648 gts_file_error (fp
, "vertex index `%d' is out of range `[1,%d]'",
1649 nv
, ps
->vertices
->len
);
1653 gts_file_next_token (fp
);
1654 if (fp
->type
!= GTS_INT
) {
1655 gts_file_error (fp
, "expecting an integer (ncf)");
1658 ncf
= atoi (fp
->token
->str
);
1660 vs
= GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (ps
->split_class
)));
1662 vs
->v
= g_ptr_array_index (ps
->vertices
, nv
- 1);
1663 vs
->v1
= vs
->v2
= NULL
;
1667 gts_file_next_token (fp
);
1668 if (fp
->type
!= '\n')
1669 if (GTS_OBJECT (vs
)->klass
->read
)
1670 (* GTS_OBJECT (vs
)->klass
->read
) ((GtsObject
**) &vs
, fp
);
1671 gts_file_first_token_after (fp
, '\n');
1673 if (fp
->type
!= GTS_ERROR
) {
1674 vs
->v1
= gts_object_new (GTS_OBJECT_CLASS (ps
->s
->vertex_class
));
1675 (* GTS_OBJECT_CLASS (ps
->s
->vertex_class
)->read
) (&(vs
->v1
), fp
);
1676 if (fp
->type
!= GTS_ERROR
) {
1677 vs
->v1
->reserved
= vs
;
1678 g_ptr_array_add (ps
->vertices
, vs
->v1
);
1680 gts_file_first_token_after (fp
, '\n');
1682 vs
->v2
= gts_object_new (GTS_OBJECT_CLASS (ps
->s
->vertex_class
));
1683 (*GTS_OBJECT_CLASS (ps
->s
->vertex_class
)->read
) (&(vs
->v2
), fp
);
1684 if (fp
->type
!= GTS_ERROR
) {
1685 vs
->v2
->reserved
= vs
;
1686 g_ptr_array_add (ps
->vertices
, vs
->v2
);
1687 gts_file_first_token_after (fp
, '\n');
1692 if (fp
->type
!= GTS_ERROR
) {
1693 scf
= vs
->cfaces
= g_malloc (sizeof (GtsSplitCFace
)*ncf
);
1694 while (fp
->type
!= GTS_ERROR
&& ncf
--) {
1700 if (fp
->type
!= GTS_INT
)
1701 gts_file_error (fp
, "expecting an integer (face index)");
1703 it
= atoi (fp
->token
->str
);
1704 if (it
== 0 || it
> ps
->faces
->len
)
1705 gts_file_error (fp
, "face index `%d' is out of range `[1,%d]'",
1706 it
, ps
->faces
->len
);
1708 gts_file_next_token (fp
);
1709 if (fp
->type
!= GTS_INT
)
1710 gts_file_error (fp
, "expecting an integer (flags)");
1712 flags
= atoi (fp
->token
->str
);
1714 GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (ps
->s
->face_class
)));
1716 gts_file_next_token (fp
);
1717 if (fp
->type
!= '\n')
1718 if (GTS_OBJECT (f
)->klass
->read
)
1719 (*GTS_OBJECT (f
)->klass
->read
) ((GtsObject
**) &f
, fp
);
1720 gts_file_first_token_after (fp
, '\n');
1721 if (fp
->type
!= GTS_ERROR
) {
1725 GTS_OBJECT (cf
)->klass
= GTS_OBJECT_CLASS (cface_class ());
1726 cf
->parent_split
= vs
;
1727 cf
->t
= g_ptr_array_index (ps
->faces
, it
- 1);
1730 a
= g_ptr_array_new ();
1732 if (fp
->type
!= GTS_INT
)
1733 gts_file_error (fp
, "expecting an integer (face index)");
1735 it
= atoi (fp
->token
->str
);
1736 if (it
> ps
->faces
->len
)
1738 "face index `%d' is out of range `[1,%d]'",
1739 it
, ps
->faces
->len
);
1741 g_ptr_array_add (a
, g_ptr_array_index (ps
->faces
,
1743 gts_file_next_token (fp
);
1746 } while (fp
->type
!= GTS_ERROR
&& fp
->type
!= '\n');
1747 gts_file_first_token_after (fp
, '\n');
1748 g_ptr_array_add (a
, NULL
);
1749 scf
->a1
= (GtsTriangle
**) a
->pdata
;
1750 g_ptr_array_free (a
, FALSE
);
1752 if (fp
->type
!= GTS_ERROR
) {
1753 a
= g_ptr_array_new ();
1755 if (fp
->type
!= GTS_INT
)
1756 gts_file_error (fp
, "expecting an integer (face index)");
1758 it
= atoi (fp
->token
->str
);
1759 if (it
> ps
->faces
->len
)
1761 "face index `%d' is out of range `[1,%d]'",
1762 it
, ps
->faces
->len
);
1764 g_ptr_array_add (a
, g_ptr_array_index (ps
->faces
,
1766 gts_file_next_token (fp
);
1769 } while (fp
->type
!= GTS_ERROR
&& fp
->type
!= '\n');
1770 gts_file_first_token_after (fp
, '\n');
1771 g_ptr_array_add (a
, NULL
);
1772 scf
->a2
= (GtsTriangle
**) a
->pdata
;
1773 g_ptr_array_free (a
, FALSE
);
1775 g_ptr_array_add (ps
->faces
, f
);
1787 if (fp
->type
!= GTS_ERROR
) {
1788 if ((parent
= GTS_OBJECT (vs
->v
)->reserved
)) {
1789 GTS_OBJECT (vs
->v
)->reserved
= NULL
;
1790 if (parent
->v1
== GTS_OBJECT (vs
->v
))
1791 parent
->v1
= GTS_OBJECT (vs
);
1793 g_assert (parent
->v2
== GTS_OBJECT (vs
->v
));
1794 parent
->v2
= GTS_OBJECT (vs
);
1797 g_ptr_array_index (ps
->split
, ps
->pos
++) = vs
;
1798 gts_split_expand (vs
, ps
->s
, ps
->s
->edge_class
);
1803 if (vs
->v1
) gts_object_destroy (vs
->v1
);
1804 if (vs
->v2
) gts_object_destroy (vs
->v2
);
1805 gts_object_destroy (GTS_OBJECT (vs
));
1811 * gts_psurface_close:
1812 * @ps: a #GtsPSurface prealably created with gts_psurface_open().
1814 * Closes a progressive surface.
1816 void gts_psurface_close (GtsPSurface
* ps
)
1818 g_return_if_fail (ps
!= NULL
);
1819 g_return_if_fail (!GTS_PSURFACE_IS_CLOSED (ps
));
1821 g_ptr_array_free (ps
->vertices
, TRUE
);
1822 g_ptr_array_free (ps
->faces
, TRUE
);
1823 ps
->faces
= ps
->vertices
= NULL
;
1825 gts_surface_foreach_vertex (ps
->s
,
1826 (GtsFunc
) gts_object_reset_reserved
, NULL
);
1828 g_ptr_array_set_size (ps
->split
, ps
->pos
);
1829 if (ps
->split
->len
> 1) {
1830 guint i
, half
= ps
->split
->len
/2, n
= ps
->split
->len
- 1;
1832 for (i
= 0; i
< half
; i
++) {
1833 gpointer p1
= g_ptr_array_index (ps
->split
, i
);
1834 gpointer p2
= g_ptr_array_index (ps
->split
, n
- i
);
1835 g_ptr_array_index (ps
->split
, n
- i
) = p1
;
1836 g_ptr_array_index (ps
->split
, i
) = p2
;