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 vvs
= GTS_EDGE (gts_vertices_are_connected (vs
->v
, v
));
258 g_assert (vvs
!= NULL
);
261 vvs
= gts_edge_new (klass
, v
, vs
->v
);
263 t1
= replace_edge_collapse (e1
, vvs
, cf
, heap
271 t2
= replace_edge_collapse (e2
, vvs
, cf
, heap
279 t
= cf
->t
= t1
? t1
: t2
;
282 /* set up flags necessary to find vvs */
283 if (t
->e1
== vvs
) e2
= t
->e2
;
284 else if (t
->e2
== vvs
) e2
= t
->e3
;
286 g_assert (t
->e3
== vvs
);
289 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2
), v
))
290 CFACE_VVS_DIRECT (cf
);
295 static void find_vvs (GtsVertex
* vs
,
297 GtsVertex
** v
, GtsEdge
** vvs
,
298 gboolean orientation
)
300 GtsEdge
* e1
= t
->e1
, * e2
= t
->e2
, * e3
= t
->e3
, * tmp
;
302 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2
), vs
)) {
303 tmp
= e1
; e1
= e2
; e2
= e3
; e3
= tmp
;
305 else if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e3
), vs
)) {
306 tmp
= e1
; e1
= e3
; e3
= e2
; e2
= tmp
;
309 g_assert (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1
), vs
));
310 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2
), vs
) ||
311 !gts_segments_touch (GTS_SEGMENT (e1
), GTS_SEGMENT (e2
))) {
312 tmp
= e1
; e1
= e2
; e2
= e3
; e3
= tmp
;
313 g_assert (gts_segments_touch (GTS_SEGMENT (e1
), GTS_SEGMENT (e2
)));
316 *vvs
= orientation
? e1
: e3
;
318 if (GTS_SEGMENT (*vvs
)->v1
!= vs
) {
319 g_assert (GTS_SEGMENT (*vvs
)->v2
== vs
);
320 *v
= GTS_SEGMENT (*vvs
)->v1
;
323 *v
= GTS_SEGMENT (*vvs
)->v2
;
326 static void replace_edge_expand (GtsEdge
* e
,
331 GtsTriangle
** i
= a
, * t
;
333 while ((t
= *(i
++))) {
335 g_assert (!IS_CFACE (t
));
336 fprintf (stderr
, "replacing %p->%d: e: %p->%d with: %p->%d\n",
337 t
, id (t
), e
, id (e
), with
, id (with
));
339 TRIANGLE_REPLACE_EDGE (t
, e
, with
);
340 with
->triangles
= g_slist_prepend (with
->triangles
, t
);
341 if (GTS_OBJECT (t
)->reserved
) {
342 /* apart from the triangles having e as an edge, t is the only
344 g_assert (GTS_OBJECT (t
)->reserved
== v
);
345 GTS_OBJECT (t
)->reserved
= NULL
;
348 GTS_OBJECT (t
)->reserved
= v
;
352 static void cface_expand (CFace
* cf
,
359 GtsEdgeClass
* klass
)
362 GtsEdge
* e1
, * e2
, * vvs
;
363 gboolean orientation
;
366 g_return_if_fail (cf
!= NULL
);
367 g_return_if_fail (IS_CFACE (cf
));
368 g_return_if_fail (e
!= NULL
);
369 g_return_if_fail (vs
!= NULL
);
372 orientation
= CFACE_ORIENTATION (cf
);
374 find_vvs (vs
, cf
->t
, &v
, &vvs
, CFACE_VVS (cf
));
377 if (flags
& CFACE_E1
)
378 e1
= GTS_EDGE (gts_vertices_are_connected (v1
, v
));
380 e1
= gts_edge_new (klass
, v
, v1
);
381 if (flags
& CFACE_E2
)
382 e2
= GTS_EDGE (gts_vertices_are_connected (v2
, v
));
384 e2
= gts_edge_new (klass
, v
, v2
);
386 e1
= gts_edge_new (v
, v1
);
387 e2
= gts_edge_new (v
, v2
);
390 replace_edge_expand (vvs
, e1
, a1
, v1
);
391 replace_edge_expand (vvs
, e2
, a2
, v2
);
394 if (!(flags
& CFACE_KEEP_VVS
)) {
395 g_slist_free (vvs
->triangles
);
396 vvs
->triangles
= NULL
;
397 gts_object_destroy (GTS_OBJECT (vvs
));
400 g_slist_free (vvs
->triangles
);
401 vvs
->triangles
= NULL
;
402 gts_object_destroy (GTS_OBJECT (vvs
));
405 /* gts_face_new : because I am "creating" a face */
406 GTS_OBJECT (cf
)->klass
= GTS_OBJECT_CLASS (gts_face_class ());
407 gts_object_init (GTS_OBJECT (cf
), GTS_OBJECT (cf
)->klass
);
410 gts_triangle_set (GTS_TRIANGLE (cf
), e
, e2
, e1
);
412 gts_triangle_set (GTS_TRIANGLE (cf
), e
, e1
, e2
);
415 static void split_destroy (GtsObject
* object
)
417 GtsSplit
* vs
= GTS_SPLIT (object
);
419 GtsSplitCFace
* cf
= vs
->cfaces
;
422 if (IS_CFACE (cf
->f
))
423 gts_object_destroy (GTS_OBJECT (cf
->f
));
430 if (!gts_allow_floating_vertices
&& vs
->v
&& vs
->v
->segments
== NULL
)
431 gts_object_destroy (GTS_OBJECT (vs
->v
));
433 (* GTS_OBJECT_CLASS (gts_split_class ())->parent_class
->destroy
) (object
);
436 static void split_class_init (GtsObjectClass
* klass
)
438 klass
->destroy
= split_destroy
;
441 static void split_init (GtsSplit
* split
)
443 split
->v1
= split
->v2
= NULL
;
445 split
->cfaces
= NULL
;
452 * Returns: the #GtsSplitClass.
454 GtsSplitClass
* gts_split_class (void)
456 static GtsSplitClass
* klass
= NULL
;
459 GtsObjectClassInfo split_info
= {
462 sizeof (GtsSplitClass
),
463 (GtsObjectClassInitFunc
) split_class_init
,
464 (GtsObjectInitFunc
) split_init
,
465 (GtsArgSetFunc
) NULL
,
468 klass
= gts_object_class_new (gts_object_class (),
476 static gboolean
edge_collapse_is_valid (GtsEdge
* e
)
480 g_return_val_if_fail (e
!= NULL
, FALSE
);
482 if (gts_segment_is_duplicate (GTS_SEGMENT (e
))) {
483 g_warning ("collapsing duplicate edge");
487 i
= GTS_SEGMENT (e
)->v1
->segments
;
489 GtsEdge
* e1
= i
->data
;
490 if (e1
!= e
&& GTS_IS_EDGE (e1
)) {
492 GSList
* j
= GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e
)->v1
?
493 GTS_SEGMENT (e1
)->v2
->segments
: GTS_SEGMENT (e1
)->v1
->segments
;
495 GtsEdge
* e1
= j
->data
;
496 if (GTS_IS_EDGE (e1
) &&
497 (GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e
)->v2
||
498 GTS_SEGMENT (e1
)->v2
== GTS_SEGMENT (e
)->v2
))
502 if (e2
&& !gts_triangle_use_edges (e
, e1
, e2
)) {
503 g_warning ("collapsing empty triangle");
510 if (gts_edge_is_boundary (e
, NULL
)) {
511 GtsTriangle
* t
= e
->triangles
->data
;
512 if (gts_edge_is_boundary (t
->e1
, NULL
) &&
513 gts_edge_is_boundary (t
->e2
, NULL
) &&
514 gts_edge_is_boundary (t
->e3
, NULL
)) {
515 g_warning ("collapsing single triangle");
520 if (gts_vertex_is_boundary (GTS_SEGMENT (e
)->v1
, NULL
) &&
521 gts_vertex_is_boundary (GTS_SEGMENT (e
)->v2
, NULL
)) {
522 g_warning ("collapsing two sides of a strip");
525 if (gts_edge_belongs_to_tetrahedron (e
)) {
526 g_warning ("collapsing tetrahedron");
535 /* Not currently used. May be useful for some debug code */
537 static void print_split (GtsSplit
* vs
, FILE * fptr
)
542 g_return_if_fail (vs
!= NULL
);
543 g_return_if_fail (fptr
!= NULL
);
545 fprintf (fptr
, "%p: v: %p v1: %p v2: %p ncf: %u cfaces: %p\n",
546 vs
, vs
->v
, vs
->v1
, vs
->v2
, vs
->ncf
, vs
->cfaces
);
550 fprintf (stderr
, " f: %p a1: %p a2: %p\n",
551 cf
->f
, cf
->a1
, cf
->a2
);
558 * gts_split_collapse:
560 * @klass: a #GtsEdgeClass.
561 * @heap: a #GtsEHeap or %NULL.
563 * Collapses the vertex split @vs. Any new edge created during the process will
564 * be of class @klass. If heap is not %NULL, the new edges will be inserted
565 * into it and the destroyed edges will be removed from it.
567 void gts_split_collapse (GtsSplit
* vs
,
568 GtsEdgeClass
* klass
,
572 GtsVertex
* v
, * v1
, * v2
;
579 gboolean invalid
= FALSE
;
580 static guint ninvalid
= 0;
583 g_return_if_fail (vs
!= NULL
);
584 g_return_if_fail (klass
!= NULL
);
588 g_return_if_fail (v
->segments
== NULL
);
590 /* we don't want to destroy vertices */
591 gts_allow_floating_vertices
= TRUE
;
593 v1
= GTS_SPLIT_V1 (vs
);
594 v2
= GTS_SPLIT_V2 (vs
);
595 e
= GTS_EDGE (gts_vertices_are_connected (v1
, v2
));
596 g_assert (e
!= NULL
);
599 fprintf (stderr
, "collapsing %p: v1: %p v2: %p v: %p\n", vs
, v1
, v2
, v
);
600 if (!edge_collapse_is_valid (e
)) {
603 GSList
* triangles
, * i
;
605 g_warning ("invalid edge collapse");
607 sprintf (fname
, "invalid.%d", ninvalid
);
608 fptr
= fopen (fname
, "wt");
609 gts_write_segment (GTS_SEGMENT (e
), GTS_POINT (v
), fptr
);
610 triangles
= gts_vertex_triangles (v1
, NULL
);
611 triangles
= gts_vertex_triangles (v2
, triangles
);
614 gts_write_triangle (i
->data
, GTS_POINT (v
), fptr
);
617 g_slist_free (triangles
);
633 vs
->ncf
= g_slist_length (i
);
634 g_assert (vs
->ncf
> 0);
635 cf
= vs
->cfaces
= g_malloc (vs
->ncf
*sizeof (GtsSplitCFace
));
636 #endif /* DYNAMIC_SPLIT */
640 g_assert (GTS_IS_FACE (cf
->f
));
641 GTS_OBJECT (cf
->f
)->klass
= GTS_OBJECT_CLASS (cface_class ());
648 cface_new (i
->data
, e
, v1
, v2
, vs
, heap
, klass
, cf
);
650 fprintf (stderr
, "cface: %p->%d t: %p->%d a1: ",
651 cf
->f
, id (cf
->f
), CFACE (cf
->f
)->t
, id (CFACE (cf
->f
)->t
));
653 GtsTriangle
* t
, ** a
;
656 fprintf (stderr
, "%p->%d ", t
, id (t
));
657 fprintf (stderr
, "a2: ");
660 fprintf (stderr
, "%p->%d ", t
, id (t
));
661 fprintf (stderr
, "\n");
669 cface_new (i
->data
, e
, v1
, v2
, vs
, heap
672 #endif /* DYNAMIC_SPLIT */
677 #endif /* DYNAMIC_SPLIT */
681 g_slist_free (e
->triangles
);
683 gts_object_destroy (GTS_OBJECT (e
));
685 gts_allow_floating_vertices
= FALSE
;
690 GtsSegment
* s
= i
->data
;
699 end
->next
= v
->segments
;
700 v
->segments
= v1
->segments
;
707 GtsSegment
* s
= i
->data
;
716 end
->next
= v
->segments
;
717 v
->segments
= v2
->segments
;
725 GSList
* triangles
, * i
;
726 GtsSurface
* surface
= NULL
;
728 sprintf (fname
, "invalid_after.%d", ninvalid
);
729 fptr
= fopen (fname
, "wt");
730 triangles
= gts_vertex_triangles (v
, NULL
);
733 GtsTriangle
* t
= i
->data
;
734 fprintf (stderr
, "checking %p->%d\n", t
, id (t
));
735 g_assert (GTS_IS_FACE (t
));
736 gts_write_triangle (t
, GTS_POINT (v
), fptr
);
737 surface
= GTS_FACE (t
)->surfaces
->data
;
738 if (gts_triangle_is_duplicate (t
))
739 fprintf (stderr
, "%p->%d is duplicate\n", t
, id (t
));
740 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e1
)))
741 fprintf (stderr
, "e1 of %p->%d is duplicate\n", t
, id (t
));
742 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e2
)))
743 fprintf (stderr
, "e2 of %p->%d is duplicate\n", t
, id (t
));
744 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e3
)))
745 fprintf (stderr
, "e3 of %p->%d is duplicate\n", t
, id (t
));
749 g_slist_free (triangles
);
751 gts_split_expand (vs
, surface
);
753 sprintf (fname
, "invalid_after_after.%d", ninvalid
);
754 fptr
= fopen (fname
, "wt");
755 triangles
= gts_vertex_triangles (v1
, NULL
);
756 triangles
= gts_vertex_triangles (v2
, triangles
);
759 GtsTriangle
* t
= i
->data
;
760 gts_write_triangle (t
, GTS_POINT (v
), fptr
);
761 surface
= GTS_FACE (t
)->surfaces
->data
;
762 if (gts_triangle_is_duplicate (t
))
763 fprintf (stderr
, "%p->%d is duplicate\n", t
, id (t
));
764 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e1
)))
765 fprintf (stderr
, "e1 of %p->%d is duplicate\n", t
, id (t
));
766 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e2
)))
767 fprintf (stderr
, "e2 of %p->%d is duplicate\n", t
, id (t
));
768 if (gts_segment_is_duplicate (GTS_SEGMENT (t
->e3
)))
769 fprintf (stderr
, "e3 of %p->%d is duplicate\n", t
, id (t
));
773 g_slist_free (triangles
);
786 * @klass: a #GtsEdgeClass.
788 * Expands the vertex split @vs adding the newly created faces to @s. Any
789 * new edge will be of class @klass.
791 void gts_split_expand (GtsSplit
* vs
,
793 GtsEdgeClass
* klass
)
797 GtsVertex
* v
, * v1
, * v2
;
798 gboolean changed
= FALSE
;
802 g_return_if_fail (vs
!= NULL
);
803 g_return_if_fail (s
!= NULL
);
804 g_return_if_fail (klass
!= NULL
);
806 /* we don't want to destroy vertices */
807 gts_allow_floating_vertices
= TRUE
;
809 v1
= GTS_SPLIT_V1 (vs
);
810 v2
= GTS_SPLIT_V2 (vs
);
813 fprintf (stderr
, "expanding %p->%d: v1: %p->%d v2: %p->%d v: %p->%d\n",
814 vs
, id (vs
), v1
, id (v1
), v2
, id (v2
), v
, id (v
));
816 e
= gts_edge_new (klass
, v1
, v2
);
820 cface_expand (CFACE (cf
->f
), cf
->a1
, cf
->a2
, e
, v1
, v2
, v
, klass
);
821 gts_surface_add_face (s
, cf
->f
);
825 gts_allow_floating_vertices
= FALSE
;
827 /* this part is described by figure "expand.fig" */
830 GtsEdge
* e1
= i
->data
;
831 GtsVertex
* with
= NULL
;
832 GSList
* j
= e1
->triangles
, * next
= i
->next
;
833 // fprintf (stderr, "e1: %p->%d\n", e1, id (e1));
835 with
= GTS_OBJECT (j
->data
)->reserved
;
841 GtsTriangle
* t
= j
->data
;
842 if (GTS_OBJECT (t
)->reserved
) {
843 g_assert (GTS_OBJECT (t
)->reserved
== with
);
844 GTS_OBJECT (t
)->reserved
= NULL
;
847 GTS_OBJECT (t
)->reserved
= with
;
850 if (GTS_SEGMENT (e1
)->v1
== v
)
851 GTS_SEGMENT (e1
)->v1
= with
;
853 GTS_SEGMENT (e1
)->v2
= with
;
855 v
->segments
= g_slist_remove_link (v
->segments
, i
);
856 i
->next
= with
->segments
;
863 /* check for infinite loop (the crossed out case in
864 figure "expand.fig") */
872 #ifndef DYNAMIC_SPLIT
873 static void cface_neighbors (GtsSplitCFace
* cf
,
878 GtsTriangle
* t
= GTS_TRIANGLE (cf
->f
), ** a
;
879 GtsEdge
* e1
= t
->e1
, * e2
= t
->e2
, * e3
= t
->e3
;
883 ROTATE_ORIENT (e
, e1
, e2
, e3
);
884 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1
), v2
)) {
885 e3
= e1
; e1
= e2
; e2
= e3
;
889 size
= g_slist_length (i
)*sizeof (GtsTriangle
*);
890 a
= cf
->a1
= g_malloc (size
> 0 ? size
: sizeof (GtsTriangle
*));
899 size
= g_slist_length (i
)*sizeof (GtsTriangle
*);
900 a
= cf
->a2
= g_malloc (size
> 0 ? size
: sizeof (GtsTriangle
*));
908 #endif /*ifndef DYNAMIC_SPLIT */
912 * @klass: a #GtsSplitClass.
914 * @o1: either a #GtsVertex or a #GtsSplit.
915 * @o2: either a #GtsVertex or a #GtsSplit.
917 * Creates a new #GtsSplit which would collapse @o1 and @o2 into @v. The
918 * collapse itself is not performed.
920 * Returns: the new #GtsSplit.
922 GtsSplit
* gts_split_new (GtsSplitClass
* klass
,
928 #ifndef DYNAMIC_SPLIT
929 GtsVertex
* v1
, * v2
;
935 g_return_val_if_fail (klass
!= NULL
, NULL
);
936 g_return_val_if_fail (v
!= NULL
, NULL
);
937 g_return_val_if_fail (GTS_IS_SPLIT (o1
) || GTS_IS_VERTEX (o1
), NULL
);
938 g_return_val_if_fail (GTS_IS_SPLIT (o2
) || GTS_IS_VERTEX (o2
), NULL
);
940 vs
= GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass
)));
948 v1
= GTS_SPLIT_V1 (vs
);
949 v2
= GTS_SPLIT_V2 (vs
);
950 e
= GTS_EDGE (gts_vertices_are_connected (v1
, v2
));
951 g_assert (e
!= NULL
);
953 vs
->ncf
= g_slist_length (i
);
954 g_assert (vs
->ncf
> 0);
955 cf
= vs
->cfaces
= g_malloc (vs
->ncf
*sizeof (GtsSplitCFace
));
958 cface_neighbors (cf
, e
, v1
, v2
);
968 split_traverse_pre_order (GtsSplit
* vs
,
969 GtsSplitTraverseFunc func
,
974 if (GTS_IS_SPLIT (vs
->v1
) &&
975 split_traverse_pre_order (GTS_SPLIT (vs
->v1
), func
, data
))
977 if (GTS_IS_SPLIT (vs
->v2
) &&
978 split_traverse_pre_order (GTS_SPLIT (vs
->v2
), func
, data
))
984 split_depth_traverse_pre_order (GtsSplit
* vs
,
986 GtsSplitTraverseFunc func
,
996 if (GTS_IS_SPLIT (vs
->v1
) &&
997 split_depth_traverse_pre_order (GTS_SPLIT (vs
->v1
), depth
, func
, data
))
999 if (GTS_IS_SPLIT (vs
->v2
) &&
1000 split_depth_traverse_pre_order (GTS_SPLIT (vs
->v2
), depth
, func
, data
))
1006 split_traverse_post_order (GtsSplit
* vs
,
1007 GtsSplitTraverseFunc func
,
1010 if (GTS_IS_SPLIT (vs
->v1
) &&
1011 split_traverse_post_order (GTS_SPLIT (vs
->v1
), func
, data
))
1013 if (GTS_IS_SPLIT (vs
->v2
) &&
1014 split_traverse_post_order (GTS_SPLIT (vs
->v2
), func
, data
))
1016 if (func (vs
, data
))
1022 split_depth_traverse_post_order (GtsSplit
* vs
,
1024 GtsSplitTraverseFunc func
,
1029 if (GTS_IS_SPLIT (vs
->v1
) &&
1030 split_depth_traverse_post_order (GTS_SPLIT (vs
->v1
),
1033 if (GTS_IS_SPLIT (vs
->v2
) &&
1034 split_depth_traverse_post_order (GTS_SPLIT (vs
->v2
),
1038 if (func (vs
, data
))
1044 * gts_split_traverse:
1045 * @root: the #GtsSplit to start the traversal from.
1046 * @order: the order in which nodes are visited - G_PRE_ORDER or G_POST_ORDER.
1047 * @depth: the maximum depth of the traversal. Nodes below this depth
1048 * will not be visited. If depth is -1 all nodes in the tree are
1049 * visited. If depth is 1, only the root is visited. If depth is 2,
1050 * the root and its children are visited. And so on.
1051 * @func: the function to call for each visited #GtsHSplit.
1052 * @data: user data to pass to the function.
1054 * Traverses the #GtsSplit tree having @root as root. Calls @func for each
1055 * #GtsSplit of the tree in the order specified by @order. If order is set
1056 * to G_PRE_ORDER @func is called for the #GtsSplit then its children, if order
1057 * is set to G_POST_ORDER @func is called for the children and then for the
1060 void gts_split_traverse (GtsSplit
* root
,
1061 GTraverseType order
,
1063 GtsSplitTraverseFunc func
,
1066 g_return_if_fail (root
!= NULL
);
1067 g_return_if_fail (func
!= NULL
);
1068 g_return_if_fail (order
< G_LEVEL_ORDER
);
1069 g_return_if_fail (depth
== -1 || depth
> 0);
1074 split_traverse_pre_order (root
, func
, data
);
1076 split_depth_traverse_pre_order (root
, depth
, func
, data
);
1080 split_traverse_post_order (root
, func
, data
);
1082 split_depth_traverse_post_order (root
, depth
, func
, data
);
1085 g_assert_not_reached ();
1091 * @root: a #GtsSplit.
1093 * Returns: the maximum height of the vertex split tree having @root as root.
1095 guint
gts_split_height (GtsSplit
* root
)
1097 guint height
= 0, tmp_height
;
1099 g_return_val_if_fail (root
!= NULL
, 0);
1101 if (GTS_IS_SPLIT (root
->v1
)) {
1102 tmp_height
= gts_split_height (GTS_SPLIT (root
->v1
));
1103 if (tmp_height
> height
)
1104 height
= tmp_height
;
1106 if (GTS_IS_SPLIT (root
->v2
)) {
1107 tmp_height
= gts_split_height (GTS_SPLIT (root
->v2
));
1108 if (tmp_height
> height
)
1109 height
= tmp_height
;
1115 #ifndef DYNAMIC_SPLIT
1116 static gboolean
list_array_are_identical (GSList
* list
,
1121 gpointer data
= list
->data
;
1122 if (data
!= excluded
) {
1123 gboolean found
= FALSE
;
1124 gpointer
* a
= array
;
1126 while (!found
&& *a
)
1136 #endif /* ifndef DYNAMIC_SPLIT */
1139 gboolean
gts_split_is_collapsable (GtsSplit
* vs
)
1143 GtsVertex
* v1
, * v2
;
1146 g_return_val_if_fail (vs
!= NULL
, FALSE
);
1148 v1
= GTS_SPLIT_V1 (vs
);
1149 v2
= GTS_SPLIT_V2 (vs
);
1150 g_return_val_if_fail ((e
= GTS_EDGE (gts_vertices_are_connected (v1
, v2
))),
1153 #ifdef DYNAMIC_SPLIT
1154 if (!gts_edge_collapse_is_valid (e
))
1160 GtsTriangle
* t
= GTS_TRIANGLE (cf
->f
);
1161 GtsEdge
* e1
= t
->e1
, * e2
= t
->e2
, * e3
= t
->e3
;
1163 ROTATE_ORIENT (e
, e1
, e2
, e3
);
1164 if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1
), v2
)) {
1165 e3
= e1
; e1
= e2
; e2
= e3
;
1168 if (!list_array_are_identical (e1
->triangles
, (gpointer
*) cf
->a1
, t
))
1170 if (!list_array_are_identical (e2
->triangles
, (gpointer
*) cf
->a2
, t
))
1178 #endif /* not NEW */
1180 #ifdef DEBUG_HEXPAND
1181 static guint expand_level
= 0;
1183 static void expand_indent (FILE * fptr
)
1185 guint i
= expand_level
;
1192 * gts_hsplit_force_expand:
1193 * @hs: a #GtsHSplit.
1194 * @hsurface: a #GtsHSurface.
1196 * Forces the expansion of @hs by first expanding all its dependencies not
1199 void gts_hsplit_force_expand (GtsHSplit
* hs
,
1200 GtsHSurface
* hsurface
)
1205 g_return_if_fail (hs
!= NULL
);
1206 g_return_if_fail (hsurface
!= NULL
);
1207 g_return_if_fail (hs
->nchild
== 0);
1209 #ifdef DEBUG_HEXPAND
1213 if (hs
->parent
&& hs
->parent
->nchild
== 0) {
1214 #ifdef DEBUG_HEXPAND
1215 expand_indent (stderr
);
1216 fprintf (stderr
, "expand parent %p\n", hs
->parent
);
1218 gts_hsplit_force_expand (hs
->parent
, hsurface
);
1221 i
= GTS_SPLIT (hs
)->ncf
;
1222 cf
= GTS_SPLIT (hs
)->cfaces
;
1224 GtsTriangle
** j
, * t
;
1227 while ((t
= *(j
++)))
1229 #ifdef DEBUG_HEXPAND
1230 expand_indent (stderr
);
1231 fprintf (stderr
, "expand a1: cf->f: %p t: %p parent_split: %p\n",
1234 GTS_HSPLIT (CFACE (t
)->parent_split
));
1236 gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t
)->parent_split
),
1238 #ifdef DEBUG_HEXPAND
1239 g_assert (!IS_CFACE (t
));
1243 while ((t
= *(j
++)))
1245 #ifdef DEBUG_HEXPAND
1246 expand_indent (stderr
);
1247 fprintf (stderr
, "expand a2: cf->f: %p t: %p parent_split: %p\n",
1250 GTS_HSPLIT (CFACE (t
)->parent_split
));
1252 gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t
)->parent_split
),
1258 gts_hsplit_expand (hs
, hsurface
);
1260 #ifdef DEBUG_HEXPAND
1262 expand_indent (stderr
);
1263 fprintf (stderr
, "%p expanded\n", hs
);
1267 static void index_object (GtsObject
* o
, guint
* n
)
1269 o
->reserved
= GUINT_TO_POINTER ((*n
)++);
1272 static void index_face (GtsFace
* f
, gpointer
* data
)
1274 guint
* nf
= data
[1];
1276 g_hash_table_insert (data
[0], f
, GUINT_TO_POINTER ((*nf
)++));
1280 * gts_psurface_write:
1281 * @ps: a #GtsPSurface.
1282 * @fptr: a file pointer.
1284 * Writes to @fptr a GTS progressive surface description.
1286 void gts_psurface_write (GtsPSurface
* ps
, FILE * fptr
)
1293 g_return_if_fail (ps
!= NULL
);
1294 g_return_if_fail (fptr
!= NULL
);
1295 g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps
));
1297 while (gts_psurface_remove_vertex (ps
))
1300 GTS_POINT_CLASS (ps
->s
->vertex_class
)->binary
= FALSE
;
1301 gts_surface_write (ps
->s
, fptr
);
1303 gts_surface_foreach_vertex (ps
->s
, (GtsFunc
) index_object
, &nv
);
1304 hash
= g_hash_table_new (NULL
, NULL
);
1307 gts_surface_foreach_face (ps
->s
, (GtsFunc
) index_face
, data
);
1309 fprintf (fptr
, "%u\n", ps
->split
->len
);
1311 GtsSplit
* vs
= g_ptr_array_index (ps
->split
, --ps
->pos
);
1312 GtsSplitCFace
* scf
= vs
->cfaces
;
1313 GtsVertex
* v1
, * v2
;
1316 fprintf (fptr
, "%u %u",
1317 GPOINTER_TO_UINT (GTS_OBJECT (vs
->v
)->reserved
),
1319 if (GTS_OBJECT (vs
)->klass
->write
)
1320 (*GTS_OBJECT (vs
)->klass
->write
) (GTS_OBJECT (vs
), fptr
);
1323 v1
= GTS_IS_SPLIT (vs
->v1
) ? GTS_SPLIT (vs
->v1
)->v
: GTS_VERTEX (vs
->v1
);
1324 GTS_OBJECT (v1
)->reserved
= GUINT_TO_POINTER (nv
++);
1325 v2
= GTS_IS_SPLIT (vs
->v2
) ? GTS_SPLIT (vs
->v2
)->v
: GTS_VERTEX (vs
->v2
);
1326 GTS_OBJECT (v2
)->reserved
= GUINT_TO_POINTER (nv
++);
1328 (*GTS_OBJECT (v1
)->klass
->write
) (GTS_OBJECT (v1
), fptr
);
1331 (*GTS_OBJECT (v2
)->klass
->write
) (GTS_OBJECT (v2
), fptr
);
1335 CFace
* cf
= CFACE (scf
->f
);
1336 GtsTriangle
** a
, * t
;
1338 fprintf (fptr
, "%u %u",
1339 GPOINTER_TO_UINT (g_hash_table_lookup (hash
, cf
->t
)),
1341 if (GTS_OBJECT_CLASS (ps
->s
->face_class
)->write
)
1342 (*GTS_OBJECT_CLASS (ps
->s
->face_class
)->write
) (GTS_OBJECT (cf
), fptr
);
1346 while ((t
= *(a
++)))
1347 fprintf (fptr
, "%u ",
1348 GPOINTER_TO_UINT (g_hash_table_lookup (hash
, t
)));
1349 fprintf (fptr
, "\n");
1352 while ((t
= *(a
++)))
1353 fprintf (fptr
, "%u ",
1354 GPOINTER_TO_UINT (g_hash_table_lookup (hash
, t
)));
1355 fprintf (fptr
, "\n");
1357 g_hash_table_insert (hash
, cf
, GUINT_TO_POINTER (nf
++));
1362 gts_split_expand (vs
, ps
->s
, ps
->s
->edge_class
);
1365 gts_surface_foreach_vertex (ps
->s
,
1366 (GtsFunc
) gts_object_reset_reserved
, NULL
);
1367 g_hash_table_destroy (hash
);
1370 static guint
surface_read (GtsSurface
* surface
,
1372 GPtrArray
* vertices
,
1376 guint n
, nv
, ne
, nf
;
1378 g_return_val_if_fail (surface
!= NULL
, 1);
1379 g_return_val_if_fail (f
!= NULL
, 1);
1381 if (f
->type
!= GTS_INT
) {
1382 gts_file_error (f
, "expecting an integer (number of vertices)");
1385 nv
= atoi (f
->token
->str
);
1387 gts_file_next_token (f
);
1388 if (f
->type
!= GTS_INT
) {
1389 gts_file_error (f
, "expecting an integer (number of edges)");
1392 ne
= atoi (f
->token
->str
);
1394 gts_file_next_token (f
);
1395 if (f
->type
!= GTS_INT
) {
1396 gts_file_error (f
, "expecting an integer (number of faces)");
1399 nf
= atoi (f
->token
->str
);
1401 gts_file_next_token (f
);
1402 if (f
->type
== GTS_STRING
) {
1403 if (f
->type
!= GTS_STRING
) {
1404 gts_file_error (f
, "expecting a string (GtsSurfaceClass)");
1407 gts_file_next_token (f
);
1408 if (f
->type
!= GTS_STRING
) {
1409 gts_file_error (f
, "expecting a string (GtsFaceClass)");
1412 gts_file_next_token (f
);
1413 if (f
->type
!= GTS_STRING
) {
1414 gts_file_error (f
, "expecting a string (GtsEdgeClass)");
1417 gts_file_next_token (f
);
1418 if (f
->type
!= GTS_STRING
) {
1419 gts_file_error (f
, "expecting a string (GtsVertexClass)");
1422 if (!strcmp (f
->token
->str
, "GtsVertexBinary"))
1423 GTS_POINT_CLASS (surface
->vertex_class
)->binary
= TRUE
;
1425 gts_file_first_token_after (f
, '\n');
1428 gts_file_first_token_after (f
, '\n');
1430 g_ptr_array_set_size (vertices
, nv
);
1431 g_ptr_array_set_size (faces
, nf
);
1432 /* allocate nv + 1 just in case nv == 0 */
1433 edges
= g_malloc ((ne
+ 1)*sizeof (GtsEdge
*));
1436 while (n
< nv
&& f
->type
!= GTS_ERROR
) {
1437 GtsObject
* new_vertex
=
1438 gts_object_new (GTS_OBJECT_CLASS (surface
->vertex_class
));
1440 (* GTS_OBJECT_CLASS (surface
->vertex_class
)->read
) (&new_vertex
, f
);
1441 if (f
->type
!= GTS_ERROR
) {
1442 if (!GTS_POINT_CLASS (surface
->vertex_class
)->binary
)
1443 gts_file_first_token_after (f
, '\n');
1444 g_ptr_array_index (vertices
, n
++) = new_vertex
;
1447 gts_object_destroy (new_vertex
);
1449 if (f
->type
== GTS_ERROR
)
1451 if (GTS_POINT_CLASS (surface
->vertex_class
)->binary
)
1452 gts_file_first_token_after (f
, '\n');
1455 while (n
< ne
&& f
->type
!= GTS_ERROR
) {
1458 if (f
->type
!= GTS_INT
)
1459 gts_file_error (f
, "expecting an integer (first vertex index)");
1461 p1
= atoi (f
->token
->str
);
1462 if (p1
== 0 || p1
> nv
)
1463 gts_file_error (f
, "vertex index `%d' is out of range `[1,%d]'",
1466 gts_file_next_token (f
);
1467 if (f
->type
!= GTS_INT
)
1468 gts_file_error (f
, "expecting an integer (second vertex index)");
1470 p2
= atoi (f
->token
->str
);
1471 if (p2
== 0 || p2
> nv
)
1472 gts_file_error (f
, "vertex index `%d' is out of range `[1,%d]'",
1475 GtsEdge
* new_edge
=
1476 gts_edge_new (surface
->edge_class
,
1477 g_ptr_array_index (vertices
, p1
- 1),
1478 g_ptr_array_index (vertices
, p2
- 1));
1480 gts_file_next_token (f
);
1481 if (f
->type
!= '\n')
1482 if (GTS_OBJECT_CLASS (surface
->edge_class
)->read
)
1483 (*GTS_OBJECT_CLASS (surface
->edge_class
)->read
)
1484 ((GtsObject
**) &new_edge
, f
);
1485 gts_file_first_token_after (f
, '\n');
1486 edges
[n
++] = new_edge
;
1492 if (f
->type
== GTS_ERROR
)
1496 while (n
< nf
&& f
->type
!= GTS_ERROR
) {
1499 if (f
->type
!= GTS_INT
)
1500 gts_file_error (f
, "expecting an integer (first edge index)");
1502 s1
= atoi (f
->token
->str
);
1503 if (s1
== 0 || s1
> ne
)
1504 gts_file_error (f
, "edge index `%d' is out of range `[1,%d]'",
1507 gts_file_next_token (f
);
1508 if (f
->type
!= GTS_INT
)
1509 gts_file_error (f
, "expecting an integer (second edge index)");
1511 s2
= atoi (f
->token
->str
);
1512 if (s2
== 0 || s2
> ne
)
1513 gts_file_error (f
, "edge index `%d' is out of range `[1,%d]'",
1516 gts_file_next_token (f
);
1517 if (f
->type
!= GTS_INT
)
1518 gts_file_error (f
, "expecting an integer (third edge index)");
1520 s3
= atoi (f
->token
->str
);
1521 if (s3
== 0 || s3
> ne
)
1522 gts_file_error (f
, "edge index `%d' is out of range `[1,%d]'",
1525 GtsFace
* new_face
= gts_face_new (surface
->face_class
,
1530 gts_file_next_token (f
);
1531 if (f
->type
!= '\n')
1532 if (GTS_OBJECT_CLASS (surface
->face_class
)->read
)
1533 (*GTS_OBJECT_CLASS (surface
->face_class
)->read
)
1534 ((GtsObject
**) &new_face
, f
);
1535 gts_file_first_token_after (f
, '\n');
1536 gts_surface_add_face (surface
, new_face
);
1537 g_ptr_array_index (faces
, n
++) = new_face
;
1548 if (f
->type
== GTS_ERROR
) {
1549 gts_allow_floating_vertices
= TRUE
;
1551 gts_object_destroy (GTS_OBJECT (g_ptr_array_index (vertices
, nv
-- - 1)));
1552 gts_allow_floating_vertices
= FALSE
;
1560 * gts_psurface_open:
1561 * @klass: a #GtsPSurfaceClass.
1562 * @s: a #GtsSurface.
1563 * @split_class: a #GtsSplitClass to use for the #GtsSplit.
1566 * Creates a new #GtsPSurface prepared for input from the file @f
1567 * containing a valid GTS representation of a progressive surface. The initial
1568 * shape of the progressive surface is loaded into @s.
1570 * Before being usable as such this progressive surface must be closed using
1571 * gts_psurface_close(). While open however, the functions
1572 * gts_psurface_get_vertex_number(), gts_psurface_min_vertex_number() and
1573 * gts_psurface_max_vertex_number() can still be used.
1575 * Returns: a new #GtsPSurface or %NULL if there was a format error while
1576 * reading the file, in which case @f contains information about the error.
1578 GtsPSurface
* gts_psurface_open (GtsPSurfaceClass
* klass
,
1580 GtsSplitClass
* split_class
,
1585 g_return_val_if_fail (klass
!= NULL
, NULL
);
1586 g_return_val_if_fail (s
!= NULL
, NULL
);
1587 g_return_val_if_fail (split_class
!= NULL
, NULL
);
1588 g_return_val_if_fail (f
!= NULL
, NULL
);
1590 ps
= GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass
)));
1592 ps
->split_class
= split_class
;
1594 ps
->vertices
= g_ptr_array_new ();
1595 ps
->faces
= g_ptr_array_new ();
1597 if (surface_read (s
, f
, ps
->vertices
, ps
->faces
)) {
1599 gts_object_destroy (GTS_OBJECT (ps
));
1603 ps
->min
= gts_surface_vertex_number (ps
->s
);
1606 if (f
->type
== GTS_INT
) {
1607 gint ns
= atoi (f
->token
->str
);
1610 g_ptr_array_set_size (ps
->split
, ns
);
1611 gts_file_first_token_after (f
, '\n');
1619 * gts_psurface_read_vertex:
1620 * @ps: a #GtsPSurface prealably created with gts_psurface_open().
1623 * Reads in one vertex split operation from @fp and performs the expansion.
1625 * If an error occurs while reading the file, the @error field of @fp is set.
1627 * Returns: the newly created #GtsSplit or %NULL if no vertex split could be
1630 GtsSplit
* gts_psurface_read_vertex (GtsPSurface
* ps
, GtsFile
* fp
)
1633 GtsSplit
* vs
, * parent
;
1634 GtsSplitCFace
* scf
;
1636 g_return_val_if_fail (ps
!= NULL
, NULL
);
1637 g_return_val_if_fail (fp
!= NULL
, NULL
);
1638 g_return_val_if_fail (!GTS_PSURFACE_IS_CLOSED (ps
), NULL
);
1640 if (ps
->pos
>= ps
->split
->len
)
1643 if (fp
->type
== GTS_NONE
)
1645 if (fp
->type
!= GTS_INT
) {
1646 gts_file_error (fp
, "expecting an integer (vertex index)");
1649 nv
= atoi (fp
->token
->str
);
1650 if (nv
== 0 || nv
> ps
->vertices
->len
) {
1651 gts_file_error (fp
, "vertex index `%d' is out of range `[1,%d]'",
1652 nv
, ps
->vertices
->len
);
1656 gts_file_next_token (fp
);
1657 if (fp
->type
!= GTS_INT
) {
1658 gts_file_error (fp
, "expecting an integer (ncf)");
1661 ncf
= atoi (fp
->token
->str
);
1663 vs
= GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (ps
->split_class
)));
1665 vs
->v
= g_ptr_array_index (ps
->vertices
, nv
- 1);
1666 vs
->v1
= vs
->v2
= NULL
;
1670 gts_file_next_token (fp
);
1671 if (fp
->type
!= '\n')
1672 if (GTS_OBJECT (vs
)->klass
->read
)
1673 (* GTS_OBJECT (vs
)->klass
->read
) ((GtsObject
**) &vs
, fp
);
1674 gts_file_first_token_after (fp
, '\n');
1676 if (fp
->type
!= GTS_ERROR
) {
1677 vs
->v1
= gts_object_new (GTS_OBJECT_CLASS (ps
->s
->vertex_class
));
1678 (* GTS_OBJECT_CLASS (ps
->s
->vertex_class
)->read
) (&(vs
->v1
), fp
);
1679 if (fp
->type
!= GTS_ERROR
) {
1680 vs
->v1
->reserved
= vs
;
1681 g_ptr_array_add (ps
->vertices
, vs
->v1
);
1683 gts_file_first_token_after (fp
, '\n');
1685 vs
->v2
= gts_object_new (GTS_OBJECT_CLASS (ps
->s
->vertex_class
));
1686 (*GTS_OBJECT_CLASS (ps
->s
->vertex_class
)->read
) (&(vs
->v2
), fp
);
1687 if (fp
->type
!= GTS_ERROR
) {
1688 vs
->v2
->reserved
= vs
;
1689 g_ptr_array_add (ps
->vertices
, vs
->v2
);
1690 gts_file_first_token_after (fp
, '\n');
1695 if (fp
->type
!= GTS_ERROR
) {
1696 scf
= vs
->cfaces
= g_malloc (sizeof (GtsSplitCFace
)*ncf
);
1697 while (fp
->type
!= GTS_ERROR
&& ncf
--) {
1703 if (fp
->type
!= GTS_INT
)
1704 gts_file_error (fp
, "expecting an integer (face index)");
1706 it
= atoi (fp
->token
->str
);
1707 if (it
== 0 || it
> ps
->faces
->len
)
1708 gts_file_error (fp
, "face index `%d' is out of range `[1,%d]'",
1709 it
, ps
->faces
->len
);
1711 gts_file_next_token (fp
);
1712 if (fp
->type
!= GTS_INT
)
1713 gts_file_error (fp
, "expecting an integer (flags)");
1715 flags
= atoi (fp
->token
->str
);
1717 GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (ps
->s
->face_class
)));
1719 gts_file_next_token (fp
);
1720 if (fp
->type
!= '\n')
1721 if (GTS_OBJECT (f
)->klass
->read
)
1722 (*GTS_OBJECT (f
)->klass
->read
) ((GtsObject
**) &f
, fp
);
1723 gts_file_first_token_after (fp
, '\n');
1724 if (fp
->type
!= GTS_ERROR
) {
1728 GTS_OBJECT (cf
)->klass
= GTS_OBJECT_CLASS (cface_class ());
1729 cf
->parent_split
= vs
;
1730 cf
->t
= g_ptr_array_index (ps
->faces
, it
- 1);
1733 a
= g_ptr_array_new ();
1735 if (fp
->type
!= GTS_INT
)
1736 gts_file_error (fp
, "expecting an integer (face index)");
1738 it
= atoi (fp
->token
->str
);
1739 if (it
> ps
->faces
->len
)
1741 "face index `%d' is out of range `[1,%d]'",
1742 it
, ps
->faces
->len
);
1744 g_ptr_array_add (a
, g_ptr_array_index (ps
->faces
,
1746 gts_file_next_token (fp
);
1749 } while (fp
->type
!= GTS_ERROR
&& fp
->type
!= '\n');
1750 gts_file_first_token_after (fp
, '\n');
1751 g_ptr_array_add (a
, NULL
);
1752 scf
->a1
= (GtsTriangle
**) a
->pdata
;
1753 g_ptr_array_free (a
, FALSE
);
1755 if (fp
->type
!= GTS_ERROR
) {
1756 a
= g_ptr_array_new ();
1758 if (fp
->type
!= GTS_INT
)
1759 gts_file_error (fp
, "expecting an integer (face index)");
1761 it
= atoi (fp
->token
->str
);
1762 if (it
> ps
->faces
->len
)
1764 "face index `%d' is out of range `[1,%d]'",
1765 it
, ps
->faces
->len
);
1767 g_ptr_array_add (a
, g_ptr_array_index (ps
->faces
,
1769 gts_file_next_token (fp
);
1772 } while (fp
->type
!= GTS_ERROR
&& fp
->type
!= '\n');
1773 gts_file_first_token_after (fp
, '\n');
1774 g_ptr_array_add (a
, NULL
);
1775 scf
->a2
= (GtsTriangle
**) a
->pdata
;
1776 g_ptr_array_free (a
, FALSE
);
1778 g_ptr_array_add (ps
->faces
, f
);
1790 if (fp
->type
!= GTS_ERROR
) {
1791 if ((parent
= GTS_OBJECT (vs
->v
)->reserved
)) {
1792 GTS_OBJECT (vs
->v
)->reserved
= NULL
;
1793 if (parent
->v1
== GTS_OBJECT (vs
->v
))
1794 parent
->v1
= GTS_OBJECT (vs
);
1796 g_assert (parent
->v2
== GTS_OBJECT (vs
->v
));
1797 parent
->v2
= GTS_OBJECT (vs
);
1800 g_ptr_array_index (ps
->split
, ps
->pos
++) = vs
;
1801 gts_split_expand (vs
, ps
->s
, ps
->s
->edge_class
);
1806 if (vs
->v1
) gts_object_destroy (vs
->v1
);
1807 if (vs
->v2
) gts_object_destroy (vs
->v2
);
1808 gts_object_destroy (GTS_OBJECT (vs
));
1814 * gts_psurface_close:
1815 * @ps: a #GtsPSurface prealably created with gts_psurface_open().
1817 * Closes a progressive surface.
1819 void gts_psurface_close (GtsPSurface
* ps
)
1821 g_return_if_fail (ps
!= NULL
);
1822 g_return_if_fail (!GTS_PSURFACE_IS_CLOSED (ps
));
1824 g_ptr_array_free (ps
->vertices
, TRUE
);
1825 g_ptr_array_free (ps
->faces
, TRUE
);
1826 ps
->faces
= ps
->vertices
= NULL
;
1828 gts_surface_foreach_vertex (ps
->s
,
1829 (GtsFunc
) gts_object_reset_reserved
, NULL
);
1831 g_ptr_array_set_size (ps
->split
, ps
->pos
);
1832 if (ps
->split
->len
> 1) {
1833 guint i
, half
= ps
->split
->len
/2, n
= ps
->split
->len
- 1;
1835 for (i
= 0; i
< half
; i
++) {
1836 gpointer p1
= g_ptr_array_index (ps
->split
, i
);
1837 gpointer p2
= g_ptr_array_index (ps
->split
, n
- i
);
1838 g_ptr_array_index (ps
->split
, n
- i
) = p1
;
1839 g_ptr_array_index (ps
->split
, i
) = p2
;