pcb 4.1.1
An interactive printed circuit board layout editor.

split.c

Go to the documentation of this file.
00001 /* GTS - Library for the manipulation of triangulated surfaces
00002  * Copyright (C) 1999 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 <stdlib.h>
00021 #include <string.h>
00022 #include "gts.h"
00023 #ifdef DEBUG
00024   #ifdef DEBUG_FUNCTIONS
00025     #include "gts-private.h"
00026   #else
00027     #define DEBUG_FUNCTIONS
00028     #include "gts-private.h"
00029     #undef DEBUG_FUNCTIONS
00030   #endif
00031 #endif
00032 
00033 #define DYNAMIC_SPLIT
00034 #define NEW
00035 
00036 /* #define DEBUG
00037    #define DEBUG_HEXPAND
00038    #define DEBUG_EXPAND */
00039 
00040 struct _GtsSplitCFace {
00041   GtsFace * f;
00042   GtsTriangle ** a1, ** a2;
00043 };
00044 
00045 typedef struct _CFace      CFace;
00046 typedef struct _CFaceClass CFaceClass;
00047 
00048 struct _CFace {
00049   GtsObject object; 
00050 
00051   GtsSplit * parent_split;
00052   GtsTriangle * t;
00053   guint flags;
00054 };
00055 /* the size of the CFace structure must be smaller or equal to the size
00056    of the GtsFace structure as both structures use the same memory location */
00057 
00058 struct _CFaceClass {
00059   GtsObjectClass parent_class;
00060 };
00061 
00062 #define IS_CFACE(obj) (gts_object_is_from_class (obj, cface_class ()))
00063 #define CFACE(obj)    ((CFace *) obj)
00064 #define CFACE_ORIENTATION(cf) ((cf)->flags & 0x1)
00065 #define CFACE_ORIENTATION_DIRECT(cf) ((cf)->flags |= 0x1)
00066 #define CFACE_VVS(cf)                ((cf)->flags & 0x2)
00067 #define CFACE_VVS_DIRECT(cf)         ((cf)->flags |= 0x2)
00068 #define CFACE_E1                     0x4
00069 #define CFACE_E2                     0x8
00070 #define CFACE_KEEP_VVS               0x10
00071 
00072 #define ROTATE_ORIENT(e, e1, e2, e3)  { if (e1 == e) { e1 = e2; e2 = e3; }\
00073                                  else if (e2 == e) { e2 = e1; e1 = e3; }\
00074                                  else g_assert (e3 == e); }
00075 #define SEGMENT_USE_VERTEX(s, v) ((s)->v1 == v || (s)->v2 == v)
00076 #define TRIANGLE_REPLACE_EDGE(t, e, with) { if ((t)->e1 == e)\
00077                                               (t)->e1 = with;\
00078                                             else if ((t)->e2 == e)\
00079                                               (t)->e2 = with;\
00080                                             else {\
00081                                               g_assert ((t)->e3 == e);\
00082                                               (t)->e3 = with;\
00083                                             }\
00084                                           }
00085 
00086 #define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\
00087                                   gts_eheap_insert (h, e))
00088 #define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\
00089                                    GTS_OBJECT (e)->reserved = NULL)
00090 
00091 static GtsObjectClass * cface_class (void)
00092 {
00093   static GtsObjectClass * klass = NULL;
00094 
00095   if (klass == NULL) {
00096     GtsObjectClassInfo cface_info = {
00097       "GtsCFace",
00098       sizeof (CFace),
00099       sizeof (CFaceClass),
00100       (GtsObjectClassInitFunc) NULL,
00101       (GtsObjectInitFunc) NULL,
00102       (GtsArgSetFunc) NULL,
00103       (GtsArgGetFunc) NULL
00104     };
00105     klass = gts_object_class_new (gts_object_class (), &cface_info);
00106     g_assert (sizeof (CFace) <= sizeof (GtsFace));
00107   }
00108 
00109   return klass;
00110 }
00111 
00112 /* Replace @e with @with for all the triangles using @e but @f.
00113    Destroys @e and removes it from @heap (if not %NULL). 
00114    Returns a triangle using e different from f or %NULL. */
00115 static GtsTriangle * replace_edge_collapse (GtsEdge * e, 
00116                                             GtsEdge * with, 
00117                                             CFace * cf,
00118                                             GtsEHeap * heap
00119 #ifdef DYNAMIC_SPLIT
00120                                             , GtsTriangle *** a1
00121 #endif
00122 #ifdef NEW
00123                                             , guint edge_flag
00124 #endif
00125                                             )
00126 {
00127   GSList * i;
00128   GtsTriangle * rt = NULL;
00129 #ifdef DYNAMIC_SPLIT
00130   guint size;
00131   GtsTriangle ** a;
00132 #endif
00133 
00134 #ifdef NEW
00135   i = e->triangles;
00136   e->triangles = NULL;
00137   size = g_slist_length (i)*sizeof (GtsTriangle *);
00138   *a1 = a = g_malloc (size > 0 ? size : sizeof (GtsTriangle *));
00139   while (i) {
00140     GtsTriangle * t = i->data;
00141     GSList * next = i->next;
00142     if (t != ((GtsTriangle *) cf)) {
00143       if (IS_CFACE (t)) {
00144         i->next = e->triangles;
00145         e->triangles = i;
00146         /* set the edge given by edge_flag (CFACE_E1 or CFACE_E2) */
00147         GTS_OBJECT (t)->reserved = GUINT_TO_POINTER (edge_flag);
00148         cf->flags |= CFACE_KEEP_VVS;
00149       }
00150       else {
00151         TRIANGLE_REPLACE_EDGE (t, e, with);
00152         i->next = with->triangles;
00153         with->triangles = i;
00154         rt = t;
00155         *(a++) = t;
00156       }
00157     }
00158     else
00159       g_slist_free_1 (i);
00160     i = next;
00161   }
00162   *a = NULL;
00163   if (!e->triangles) {
00164     if (heap)
00165       HEAP_REMOVE_OBJECT (heap, e);
00166     gts_object_destroy (GTS_OBJECT (e));
00167   }
00168 #else /* not NEW */
00169   i = e->triangles;
00170 #ifdef DYNAMIC_SPLIT
00171   size = g_slist_length (i)*sizeof (GtsTriangle *);
00172   *a1 = a = g_malloc (size > 0 ? size : sizeof (GtsTriangle *));
00173 #endif
00174   while (i) {
00175     GtsTriangle * t = i->data;
00176     GSList * next = i->next;
00177     if (t != ((GtsTriangle *) cf)) {
00178       TRIANGLE_REPLACE_EDGE (t, e, with);
00179       i->next = with->triangles;
00180       with->triangles = i;
00181       rt = t;
00182 #ifdef DYNAMIC_SPLIT
00183       *(a++) = t;
00184 #endif
00185     }
00186     else
00187       g_slist_free_1 (i);
00188     i = next;
00189   }
00190 #ifdef DYNAMIC_SPLIT
00191   *a = NULL;
00192 #endif
00193   if (heap)
00194     HEAP_REMOVE_OBJECT (heap, e);
00195   e->triangles = NULL;
00196   gts_object_destroy (GTS_OBJECT (e));
00197 #endif /* NEW */
00198 
00199   return rt;
00200 }
00201 
00202 static CFace * cface_new (GtsFace * f,
00203                           GtsEdge * e,
00204                           GtsVertex * v1, 
00205                           GtsVertex * v2,
00206                           GtsSplit * vs,
00207                           GtsEHeap * heap,
00208                           GtsEdgeClass * klass
00209 #ifdef DYNAMIC_SPLIT
00210                           , GtsSplitCFace * scf
00211 #endif
00212                           )
00213 {
00214   CFace * cf;
00215   GtsVertex * v;
00216   GtsEdge * e1, * e2, * e3, * vvs;
00217   GSList * i;
00218   GtsTriangle * t, * t1 = NULL, * t2 = NULL;
00219   guint flags;
00220 
00221   g_return_val_if_fail (f != NULL, NULL);
00222 #ifndef NEW
00223   g_return_val_if_fail (GTS_IS_FACE (f), NULL);
00224 #endif
00225   g_return_val_if_fail (e != NULL, NULL);
00226   g_return_val_if_fail (vs != NULL, NULL);
00227 
00228   t = ((GtsTriangle *) f);
00229   if (heap)
00230     g_return_val_if_fail (!gts_triangle_is_duplicate (t), NULL);
00231 
00232 #ifdef NEW
00233   /* get CFACE_E1 and CFACE_E2 info */
00234   flags = GPOINTER_TO_UINT (GTS_OBJECT (f)->reserved);
00235 #endif
00236   GTS_OBJECT_SET_FLAGS (f, GTS_DESTROYED);
00237 
00238   i = f->surfaces;
00239   while (i) {
00240     GSList * next = i->next;
00241     gts_surface_remove_face (i->data, f);
00242     i = next;
00243   }
00244   g_slist_free (f->surfaces);
00245 
00246   e1 = t->e1; e2 = t->e2; e3 = t->e3;
00247   ROTATE_ORIENT (e, e1, e2, e3);
00248 
00249   cf = (CFace *) f;
00250 #ifndef NEW
00251   GTS_OBJECT (cf)->klass = cface_class ();
00252 #else
00253   cf->flags = flags;
00254 #endif
00255   gts_object_init (GTS_OBJECT (cf), cface_class ());
00256   cf->parent_split = vs;
00257 
00258   if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) {
00259     CFACE_ORIENTATION_DIRECT (cf); /* v1->v2->v */
00260     e3 = e1; e1 = e2; e2 = e3;
00261   }
00262   v = GTS_SEGMENT (e1)->v1 == v1 ?
00263     GTS_SEGMENT (e1)->v2 : GTS_SEGMENT (e1)->v1;
00264 #ifdef NEW
00265   if ((cf->flags & CFACE_E1) || (cf->flags & CFACE_E2)) {
00266     vvs = GTS_EDGE (gts_vertices_are_connected (vs->v, v));
00267     g_assert (vvs != NULL);
00268   } else
00269 #endif
00270   vvs = gts_edge_new (klass, v, vs->v);
00271 
00272   t1 = replace_edge_collapse (e1, vvs, cf, heap
00273 #ifdef DYNAMIC_SPLIT
00274                               , &scf->a1
00275 #endif
00276 #ifdef NEW
00277                               , CFACE_E1
00278 #endif
00279                               );
00280   t2 = replace_edge_collapse (e2, vvs, cf, heap
00281 #ifdef DYNAMIC_SPLIT
00282                               , &scf->a2
00283 #endif
00284 #ifdef NEW
00285                               , CFACE_E2
00286 #endif
00287                               );
00288   t = cf->t = t1 ? t1 : t2;
00289   g_assert (t);
00290 
00291   /* set up flags necessary to find vvs */
00292   if (t->e1 == vvs) e2 = t->e2;
00293   else if (t->e2 == vvs) e2 = t->e3;
00294   else {
00295     g_assert (t->e3 == vvs);
00296     e2 = t->e1;
00297   }
00298   if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), v))
00299     CFACE_VVS_DIRECT (cf);
00300 
00301   return cf;
00302 }
00303 
00304 static void find_vvs (GtsVertex * vs,
00305                       GtsTriangle * t,
00306                       GtsVertex ** v, GtsEdge ** vvs,
00307                       gboolean orientation)
00308 {
00309   GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3, * tmp;
00310 
00311   if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), vs)) {
00312     tmp = e1; e1 = e2; e2 = e3; e3 = tmp;
00313   }
00314   else if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e3), vs)) {
00315     tmp = e1; e1 = e3; e3 = e2; e2 = tmp;
00316   }
00317   else
00318     g_assert (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), vs));
00319   if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), vs) ||
00320       !gts_segments_touch (GTS_SEGMENT (e1), GTS_SEGMENT (e2))) {
00321     tmp = e1; e1 = e2; e2 = e3; e3 = tmp;
00322     g_assert (gts_segments_touch (GTS_SEGMENT (e1), GTS_SEGMENT (e2)));
00323   }
00324 
00325   *vvs = orientation ? e1 : e3;
00326 
00327   if (GTS_SEGMENT (*vvs)->v1 != vs) {
00328     g_assert (GTS_SEGMENT (*vvs)->v2 == vs);
00329     *v = GTS_SEGMENT (*vvs)->v1;
00330   }
00331   else
00332     *v = GTS_SEGMENT (*vvs)->v2;
00333 }
00334 
00335 static void replace_edge_expand (GtsEdge * e, 
00336                                  GtsEdge * with,
00337                                  GtsTriangle ** a,
00338                                  GtsVertex * v)
00339 {
00340   GtsTriangle ** i = a, * t;
00341 
00342   while ((t = *(i++))) {
00343 #ifdef DEBUG_EXPAND
00344     g_assert (!IS_CFACE (t));
00345     fprintf (stderr, "replacing %p->%d: e: %p->%d with: %p->%d\n",
00346              t, id (t), e, id (e), with, id (with));
00347 #endif
00348     TRIANGLE_REPLACE_EDGE (t, e, with);
00349     with->triangles = g_slist_prepend (with->triangles, t);
00350     if (GTS_OBJECT (t)->reserved) {
00351       /* apart from the triangles having e as an edge, t is the only
00352          triangle using v */
00353       g_assert (GTS_OBJECT (t)->reserved == v);
00354       GTS_OBJECT (t)->reserved = NULL;
00355     }
00356     else
00357       GTS_OBJECT (t)->reserved = v;
00358   }
00359 }
00360 
00361 static void cface_expand (CFace * cf,
00362                           GtsTriangle ** a1,
00363                           GtsTriangle ** a2,
00364                           GtsEdge * e,
00365                           GtsVertex * v1, 
00366                           GtsVertex * v2,
00367                           GtsVertex * vs,
00368                           GtsEdgeClass * klass)
00369 {
00370   GtsVertex * v;
00371   GtsEdge * e1, * e2, * vvs;
00372   gboolean orientation;
00373   guint flags;
00374 
00375   g_return_if_fail (cf != NULL);
00376   g_return_if_fail (IS_CFACE (cf));
00377   g_return_if_fail (e != NULL);
00378   g_return_if_fail (vs != NULL);
00379 
00380   flags = cf->flags;
00381   orientation = CFACE_ORIENTATION (cf);
00382 
00383   find_vvs (vs, cf->t, &v, &vvs, CFACE_VVS (cf));
00384 
00385 #ifdef NEW
00386   if (flags & CFACE_E1)
00387     e1 = GTS_EDGE (gts_vertices_are_connected (v1, v));
00388   else
00389     e1 = gts_edge_new (klass, v, v1);
00390   if (flags & CFACE_E2)
00391     e2 = GTS_EDGE (gts_vertices_are_connected (v2, v));
00392   else
00393     e2 = gts_edge_new (klass, v, v2);
00394 #else
00395   e1 = gts_edge_new (v, v1);
00396   e2 = gts_edge_new (v, v2);
00397 #endif
00398 
00399   replace_edge_expand (vvs, e1, a1, v1);
00400   replace_edge_expand (vvs, e2, a2, v2);
00401 
00402 #ifdef NEW
00403   if (!(flags & CFACE_KEEP_VVS)) {
00404     g_slist_free (vvs->triangles);
00405     vvs->triangles = NULL;
00406     gts_object_destroy (GTS_OBJECT (vvs));
00407   }
00408 #else
00409   g_slist_free (vvs->triangles);
00410   vvs->triangles = NULL;
00411   gts_object_destroy (GTS_OBJECT (vvs));
00412 #endif
00413 
00414   /* gts_face_new : because I am "creating" a face */
00415   GTS_OBJECT (cf)->klass = GTS_OBJECT_CLASS (gts_face_class ());
00416   gts_object_init (GTS_OBJECT (cf), GTS_OBJECT (cf)->klass);
00417   
00418   if (orientation)
00419     gts_triangle_set (GTS_TRIANGLE (cf), e, e2, e1);
00420   else
00421     gts_triangle_set (GTS_TRIANGLE (cf), e, e1, e2);
00422 }
00423 
00424 static void split_destroy (GtsObject * object)
00425 {
00426   GtsSplit * vs = GTS_SPLIT (object);
00427   guint i = vs->ncf;
00428   GtsSplitCFace * cf = vs->cfaces;
00429 
00430   while (i--) {
00431     if (IS_CFACE (cf->f))
00432       gts_object_destroy (GTS_OBJECT (cf->f));
00433     g_free (cf->a1);
00434     g_free (cf->a2);
00435     cf++;
00436   }
00437   g_free (vs->cfaces);
00438 
00439   if (!gts_allow_floating_vertices && vs->v && vs->v->segments == NULL)
00440     gts_object_destroy (GTS_OBJECT (vs->v));
00441 
00442   (* GTS_OBJECT_CLASS (gts_split_class ())->parent_class->destroy) (object);
00443 }
00444 
00445 static void split_class_init (GtsObjectClass * klass)
00446 {
00447   klass->destroy = split_destroy;
00448 }
00449 
00450 static void split_init (GtsSplit * split)
00451 {
00452   split->v1 = split->v2 = NULL;
00453   split->v = NULL;
00454   split->cfaces = NULL;
00455   split->ncf = 0;
00456 }
00457 
00463 GtsSplitClass * gts_split_class (void)
00464 {
00465   static GtsSplitClass * klass = NULL;
00466 
00467   if (klass == NULL) {
00468     GtsObjectClassInfo split_info = {
00469       "GtsSplit",
00470       sizeof (GtsSplit),
00471       sizeof (GtsSplitClass),
00472       (GtsObjectClassInitFunc) split_class_init,
00473       (GtsObjectInitFunc) split_init,
00474       (GtsArgSetFunc) NULL,
00475       (GtsArgGetFunc) NULL
00476     };
00477     klass = gts_object_class_new (gts_object_class (), 
00478                                   &split_info);
00479   }
00480 
00481   return klass;
00482 }
00483 
00484 #ifdef DEBUG
00485 static gboolean edge_collapse_is_valid (GtsEdge * e)
00486 {
00487   GSList * i;
00488 
00489   g_return_val_if_fail (e != NULL, FALSE);
00490   
00491   if (gts_segment_is_duplicate (GTS_SEGMENT (e))) {
00492     g_warning ("collapsing duplicate edge");
00493     return FALSE;
00494   }
00495     
00496   i = GTS_SEGMENT (e)->v1->segments;
00497   while (i) {
00498     GtsEdge * e1 = i->data;
00499     if (e1 != e && GTS_IS_EDGE (e1)) {
00500       GtsEdge * e2 = NULL;
00501       GSList * j = GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v1 ? 
00502         GTS_SEGMENT (e1)->v2->segments : GTS_SEGMENT (e1)->v1->segments;
00503       while (j && !e2) {
00504         GtsEdge * e1 = j->data;
00505         if (GTS_IS_EDGE (e1) && 
00506             (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v2 || 
00507              GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e)->v2))
00508           e2 = e1;
00509         j = j->next;
00510       }
00511       if (e2 && !gts_triangle_use_edges (e, e1, e2)) {
00512         g_warning ("collapsing empty triangle");
00513         return FALSE;
00514       }
00515     }
00516     i = i->next;
00517   }
00518 
00519   if (gts_edge_is_boundary (e, NULL)) {
00520     GtsTriangle * t = e->triangles->data;
00521     if (gts_edge_is_boundary (t->e1, NULL) &&
00522         gts_edge_is_boundary (t->e2, NULL) &&
00523         gts_edge_is_boundary (t->e3, NULL)) {
00524       g_warning ("collapsing single triangle");
00525       return FALSE;
00526     }
00527   }
00528   else {
00529     if (gts_vertex_is_boundary (GTS_SEGMENT (e)->v1, NULL) &&
00530         gts_vertex_is_boundary (GTS_SEGMENT (e)->v2, NULL)) {
00531       g_warning ("collapsing two sides of a strip");
00532       return FALSE;    
00533     }
00534     if (gts_edge_belongs_to_tetrahedron (e)) {
00535       g_warning ("collapsing tetrahedron");
00536       return FALSE;
00537     }
00538   }
00539 
00540   return TRUE;
00541 }
00542 #endif /* DEBUG */
00543 
00554 void gts_split_collapse (GtsSplit * vs, 
00555                          GtsEdgeClass * klass,
00556                          GtsEHeap * heap)
00557 {
00558   GtsEdge * e;
00559   GtsVertex * v, * v1, * v2;
00560   GSList * i, * end;
00561 #ifdef DYNAMIC_SPLIT
00562   GtsSplitCFace * cf;
00563   guint j;
00564 #endif
00565 #ifdef DEBUG
00566   gboolean invalid = FALSE;
00567   static guint ninvalid = 0;
00568 #endif
00569 
00570   g_return_if_fail (vs != NULL);
00571   g_return_if_fail (klass != NULL);
00572 
00573   v = vs->v;
00574 
00575   g_return_if_fail (v->segments == NULL);
00576   
00577   /* we don't want to destroy vertices */
00578   gts_allow_floating_vertices = TRUE;
00579 
00580   v1 = GTS_SPLIT_V1 (vs);
00581   v2 = GTS_SPLIT_V2 (vs);
00582   e = GTS_EDGE (gts_vertices_are_connected (v1, v2));
00583   g_assert (e != NULL);
00584 
00585 #ifdef DEBUG
00586   fprintf (stderr, "collapsing %p: v1: %p v2: %p v: %p\n", vs, v1, v2, v);
00587   if (!edge_collapse_is_valid (e)) {
00588     char fname[80];
00589     FILE * fptr;
00590     GSList * triangles, * i;
00591 
00592     g_warning ("invalid edge collapse");
00593     invalid = TRUE;
00594     sprintf (fname, "invalid.%d", ninvalid);
00595     fptr = fopen (fname, "wt");
00596     gts_write_segment (GTS_SEGMENT (e), GTS_POINT (v), fptr);
00597     triangles = gts_vertex_triangles (v1, NULL);
00598     triangles = gts_vertex_triangles (v2, triangles);
00599     i = triangles;
00600     while (i) {
00601       gts_write_triangle (i->data, GTS_POINT (v), fptr);
00602       i = i->next;
00603     }
00604     g_slist_free (triangles);
00605     fclose (fptr);
00606   }
00607 #endif
00608 
00609   i = e->triangles;
00610 #ifdef DYNAMIC_SPLIT
00611   cf = vs->cfaces;
00612   j = vs->ncf;
00613   while (j--) {
00614     g_free (cf->a1);
00615     g_free (cf->a2);
00616     cf++;
00617   }
00618   g_free (vs->cfaces);
00619 
00620   vs->ncf = g_slist_length (i);
00621   g_assert (vs->ncf > 0);
00622   cf = vs->cfaces = g_malloc (vs->ncf*sizeof (GtsSplitCFace));
00623 #endif /* DYNAMIC_SPLIT */
00624 #ifdef NEW
00625   while (i) {
00626     cf->f = i->data;
00627     g_assert (GTS_IS_FACE (cf->f));
00628     GTS_OBJECT (cf->f)->klass = GTS_OBJECT_CLASS (cface_class ());
00629     cf++;
00630     i = i->next;
00631   }
00632   i = e->triangles;
00633   cf = vs->cfaces;
00634   while (i) {
00635     cface_new (i->data, e, v1, v2, vs, heap, klass, cf);
00636 #ifdef DEBUG
00637     fprintf (stderr, "cface: %p->%d t: %p->%d a1: ", 
00638              cf->f, id (cf->f), CFACE (cf->f)->t, id (CFACE (cf->f)->t));
00639     {
00640       GtsTriangle * t, ** a;
00641       a = cf->a1;
00642       while ((t = *(a++)))
00643         fprintf (stderr, "%p->%d ", t, id (t));
00644       fprintf (stderr, "a2: ");
00645       a = cf->a2;
00646       while ((t = *(a++)))
00647         fprintf (stderr, "%p->%d ", t, id (t));
00648       fprintf (stderr, "\n");
00649     }
00650 #endif
00651     cf++;
00652     i = i->next;
00653   }
00654 #else /* not NEW */
00655   while (i) {
00656     cface_new (i->data, e, v1, v2, vs, heap
00657 #ifdef DYNAMIC_SPLIT
00658                , cf
00659 #endif /* DYNAMIC_SPLIT */
00660                );
00661 #ifdef DYNAMIC_SPLIT
00662     cf->f = i->data;
00663     cf++;
00664 #endif /* DYNAMIC_SPLIT */
00665     i = i->next;
00666   }
00667 #endif /* NEW */
00668   g_slist_free (e->triangles);
00669   e->triangles = NULL;
00670   gts_object_destroy (GTS_OBJECT (e));
00671 
00672   gts_allow_floating_vertices = FALSE;
00673 
00674   end = NULL;
00675   i = v1->segments;
00676   while (i) {
00677     GtsSegment * s = i->data;
00678     if (s->v1 == v1)
00679       s->v1 = v;
00680     else
00681       s->v2 = v;
00682     end = i;
00683     i = i->next;
00684   }
00685   if (end) {
00686     end->next = v->segments;
00687     v->segments = v1->segments;
00688     v1->segments = NULL;
00689   }
00690 
00691   end = NULL;
00692   i = v2->segments;
00693   while (i) {
00694     GtsSegment * s = i->data;
00695     if (s->v1 == v2)
00696       s->v1 = v;
00697     else
00698       s->v2 = v;
00699     end = i;
00700     i = i->next;
00701   }
00702   if (end) {
00703     end->next = v->segments;
00704     v->segments = v2->segments;
00705     v2->segments = NULL;
00706   }
00707 
00708 #ifdef DEBUG
00709   if (invalid) {
00710     char fname[80];
00711     FILE * fptr;
00712     GSList * triangles, * i;
00713     
00714     sprintf (fname, "invalid_after.%d", ninvalid);
00715     fptr = fopen (fname, "wt");
00716     triangles = gts_vertex_triangles (v, NULL);
00717     i = triangles;
00718     while (i) {
00719       GtsTriangle * t = i->data;
00720       fprintf (stderr, "checking %p->%d\n", t, id (t));
00721       g_assert (GTS_IS_FACE (t));
00722       gts_write_triangle (t, GTS_POINT (v), fptr);
00723       if (gts_triangle_is_duplicate (t))
00724         fprintf (stderr, "%p->%d is duplicate\n", t, id (t));
00725       if (gts_segment_is_duplicate (GTS_SEGMENT (t->e1)))
00726         fprintf (stderr, "e1 of %p->%d is duplicate\n", t, id (t));
00727       if (gts_segment_is_duplicate (GTS_SEGMENT (t->e2)))
00728         fprintf (stderr, "e2 of %p->%d is duplicate\n", t, id (t));
00729       if (gts_segment_is_duplicate (GTS_SEGMENT (t->e3)))
00730         fprintf (stderr, "e3 of %p->%d is duplicate\n", t, id (t));
00731       i = i->next;
00732     }
00733     fclose (fptr);
00734     g_slist_free (triangles);
00735 #if 0
00736     gts_split_expand (vs, surface);
00737 
00738     sprintf (fname, "invalid_after_after.%d", ninvalid);
00739     fptr = fopen (fname, "wt");
00740     triangles = gts_vertex_triangles (v1, NULL);
00741     triangles = gts_vertex_triangles (v2, triangles);
00742     i = triangles;
00743     while (i) {
00744       GtsTriangle * t = i->data;
00745       gts_write_triangle (t, GTS_POINT (v), fptr);
00746       surface = GTS_FACE (t)->surfaces->data;
00747       if (gts_triangle_is_duplicate (t))
00748         fprintf (stderr, "%p->%d is duplicate\n", t, id (t));
00749       if (gts_segment_is_duplicate (GTS_SEGMENT (t->e1)))
00750         fprintf (stderr, "e1 of %p->%d is duplicate\n", t, id (t));
00751       if (gts_segment_is_duplicate (GTS_SEGMENT (t->e2)))
00752         fprintf (stderr, "e2 of %p->%d is duplicate\n", t, id (t));
00753       if (gts_segment_is_duplicate (GTS_SEGMENT (t->e3)))
00754         fprintf (stderr, "e3 of %p->%d is duplicate\n", t, id (t));
00755       i = i->next;
00756     }
00757     fclose (fptr);
00758     g_slist_free (triangles);
00759 
00760     exit (1);
00761 #endif
00762     ninvalid++;
00763   }
00764 #endif
00765 }
00766 
00776 void gts_split_expand (GtsSplit * vs, 
00777                        GtsSurface * s,
00778                        GtsEdgeClass * klass)
00779 {
00780   GSList * i;
00781   GtsEdge * e;
00782   GtsVertex * v, * v1, * v2;  
00783   gboolean changed = FALSE;
00784   GtsSplitCFace * cf;
00785   guint j;
00786   
00787   g_return_if_fail (vs != NULL);
00788   g_return_if_fail (s != NULL);
00789   g_return_if_fail (klass != NULL);
00790 
00791   /* we don't want to destroy vertices */
00792   gts_allow_floating_vertices = TRUE;
00793 
00794   v1 = GTS_SPLIT_V1 (vs);
00795   v2 = GTS_SPLIT_V2 (vs);
00796   v = vs->v;
00797 #ifdef DEBUG_EXPAND
00798   fprintf (stderr, "expanding %p->%d: v1: %p->%d v2: %p->%d v: %p->%d\n",
00799            vs, id (vs), v1, id (v1), v2, id (v2), v, id (v));
00800 #endif
00801   e = gts_edge_new (klass, v1, v2);
00802   cf = vs->cfaces;
00803   j = vs->ncf;
00804   while (j--) {
00805     cface_expand (CFACE (cf->f), cf->a1, cf->a2, e, v1, v2, v, klass);
00806     gts_surface_add_face (s, cf->f);
00807     cf++;
00808   }
00809 
00810   gts_allow_floating_vertices = FALSE;
00811 
00812   /* this part is described by figure "expand.fig" */
00813   i = v->segments;
00814   while (i) {
00815     GtsEdge * e1 = i->data;
00816     GtsVertex * with = NULL;
00817     GSList * j = e1->triangles, * next = i->next;
00818     // fprintf (stderr, "e1: %p->%d\n", e1, id (e1));
00819     while (j && !with) {
00820       with = GTS_OBJECT (j->data)->reserved;
00821       j = j->next;
00822     }
00823     if (with) {
00824       j = e1->triangles;
00825       while (j) {
00826         GtsTriangle * t = j->data;
00827         if (GTS_OBJECT (t)->reserved) {
00828           g_assert (GTS_OBJECT (t)->reserved == with);
00829           GTS_OBJECT (t)->reserved = NULL;
00830         }
00831         else
00832           GTS_OBJECT (t)->reserved = with;
00833         j = j->next;
00834       }
00835       if (GTS_SEGMENT (e1)->v1 == v)
00836         GTS_SEGMENT (e1)->v1 = with;
00837       else
00838         GTS_SEGMENT (e1)->v2 = with;
00839 
00840       v->segments = g_slist_remove_link (v->segments, i);
00841       i->next = with->segments;
00842       with->segments = i;
00843       changed = TRUE;
00844     }
00845     if (next)
00846       i = next;
00847     else {
00848       /* check for infinite loop (the crossed out case in 
00849          figure "expand.fig") */
00850       g_assert (changed);
00851       changed = FALSE;
00852       i = v->segments;
00853     }
00854   }
00855 }
00856 
00857 #ifndef DYNAMIC_SPLIT
00858 static void cface_neighbors (GtsSplitCFace * cf,
00859                              GtsEdge * e,
00860                              GtsVertex * v1,
00861                              GtsVertex * v2)
00862 {
00863   GtsTriangle * t = GTS_TRIANGLE (cf->f), ** a;
00864   GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3;
00865   GSList * i;
00866   guint size;
00867 
00868   ROTATE_ORIENT (e, e1, e2, e3);
00869   if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) {
00870     e3 = e1; e1 = e2; e2 = e3;
00871   }
00872   
00873   i = e1->triangles;
00874   size = g_slist_length (i)*sizeof (GtsTriangle *);
00875   a = cf->a1 = g_malloc (size > 0 ? size : sizeof (GtsTriangle *));
00876   while (i) {
00877     if (i->data != t)
00878       *(a++) = i->data;
00879     i = i->next;
00880   }
00881   *a = NULL;
00882 
00883   i = e2->triangles;
00884   size = g_slist_length (i)*sizeof (GtsTriangle *);
00885   a = cf->a2 = g_malloc (size > 0 ? size : sizeof (GtsTriangle *));
00886   while (i) {
00887     if (i->data != t)
00888       *(a++) = i->data;
00889     i = i->next;
00890   }
00891   *a = NULL;
00892 }
00893 #endif /*ifndef DYNAMIC_SPLIT */
00894 
00907 GtsSplit * gts_split_new (GtsSplitClass * klass,
00908                           GtsVertex * v,
00909                           GtsObject * o1,
00910                           GtsObject * o2)
00911 {
00912   GtsSplit * vs;
00913 #ifndef DYNAMIC_SPLIT
00914   GtsVertex * v1, * v2;
00915   GtsEdge * e;
00916   GSList * i;
00917   GtsSplitCFace * cf;
00918 #endif
00919 
00920   g_return_val_if_fail (klass != NULL, NULL);
00921   g_return_val_if_fail (v != NULL, NULL);
00922   g_return_val_if_fail (GTS_IS_SPLIT (o1) || GTS_IS_VERTEX (o1), NULL);
00923   g_return_val_if_fail (GTS_IS_SPLIT (o2) || GTS_IS_VERTEX (o2), NULL);
00924 
00925   vs = GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass)));
00926   vs->v = v;
00927   vs->v1 = o1;
00928   vs->v2 = o2;
00929 #ifdef DYNAMIC_SPLIT
00930   vs->ncf = 0;
00931   vs->cfaces = NULL;
00932 #else
00933   v1 = GTS_SPLIT_V1 (vs);
00934   v2 = GTS_SPLIT_V2 (vs);
00935   e = GTS_EDGE (gts_vertices_are_connected (v1, v2));
00936   g_assert (e != NULL);
00937   i = e->triangles;
00938   vs->ncf = g_slist_length (i);
00939   g_assert (vs->ncf > 0);
00940   cf = vs->cfaces = g_malloc (vs->ncf*sizeof (GtsSplitCFace));
00941   while (i) {
00942     cf->f = i->data;
00943     cface_neighbors (cf, e, v1, v2);
00944     i = i->next;
00945     cf++;
00946   }
00947 #endif
00948   
00949   return vs;
00950 }
00951 
00952 static gboolean 
00953 split_traverse_pre_order (GtsSplit *           vs,
00954                           GtsSplitTraverseFunc func,
00955                           gpointer             data)
00956 {
00957   if (func (vs, data))
00958     return TRUE;
00959   if (GTS_IS_SPLIT (vs->v1) &&
00960       split_traverse_pre_order (GTS_SPLIT (vs->v1), func, data))
00961     return TRUE;
00962   if (GTS_IS_SPLIT (vs->v2) &&
00963       split_traverse_pre_order (GTS_SPLIT (vs->v2), func, data))
00964     return TRUE;
00965   return FALSE;
00966 }
00967 
00968 static gboolean 
00969 split_depth_traverse_pre_order (GtsSplit *             vs,
00970                                 guint                  depth,
00971                                 GtsSplitTraverseFunc   func,
00972                                 gpointer               data)
00973 {
00974   if (func (vs, data))
00975       return TRUE;
00976     
00977   depth--;
00978   if (!depth)
00979     return FALSE;
00980 
00981   if (GTS_IS_SPLIT (vs->v1) &&
00982       split_depth_traverse_pre_order (GTS_SPLIT (vs->v1), depth, func, data))
00983     return TRUE;
00984   if (GTS_IS_SPLIT (vs->v2) &&
00985       split_depth_traverse_pre_order (GTS_SPLIT (vs->v2), depth, func, data))
00986     return TRUE;
00987   return FALSE;
00988 }
00989 
00990 static gboolean 
00991 split_traverse_post_order (GtsSplit *           vs,
00992                            GtsSplitTraverseFunc func,
00993                            gpointer             data)
00994 {
00995   if (GTS_IS_SPLIT (vs->v1) &&
00996       split_traverse_post_order (GTS_SPLIT (vs->v1), func, data))
00997     return TRUE;
00998   if (GTS_IS_SPLIT (vs->v2) &&
00999       split_traverse_post_order (GTS_SPLIT (vs->v2), func, data))
01000     return TRUE;
01001   if (func (vs, data))
01002     return TRUE;
01003   return FALSE;
01004 }
01005 
01006 static gboolean
01007 split_depth_traverse_post_order (GtsSplit *           vs,
01008                                  guint                depth,
01009                                  GtsSplitTraverseFunc func,
01010                                  gpointer             data)
01011 {
01012   depth--;
01013   if (depth) {
01014     if (GTS_IS_SPLIT (vs->v1) &&
01015         split_depth_traverse_post_order (GTS_SPLIT (vs->v1), 
01016                                          depth, func, data))
01017       return TRUE;
01018     if (GTS_IS_SPLIT (vs->v2) &&
01019         split_depth_traverse_post_order (GTS_SPLIT (vs->v2),
01020                                          depth, func, data))
01021       return TRUE;
01022   }
01023   if (func (vs, data))
01024     return TRUE;
01025   return FALSE;
01026 }
01027 
01045 void gts_split_traverse (GtsSplit *           root,
01046                          GTraverseType        order,
01047                          gint                 depth,
01048                          GtsSplitTraverseFunc func,
01049                          gpointer             data)
01050 {
01051   g_return_if_fail (root != NULL);
01052   g_return_if_fail (func != NULL);
01053   g_return_if_fail (order < G_LEVEL_ORDER);
01054   g_return_if_fail (depth == -1 || depth > 0);
01055 
01056   switch (order) {
01057   case G_PRE_ORDER:
01058     if (depth < 0)
01059       split_traverse_pre_order (root, func, data);
01060     else
01061       split_depth_traverse_pre_order (root, depth, func, data);
01062     break;
01063   case G_POST_ORDER:
01064     if (depth < 0)
01065       split_traverse_post_order (root, func, data);
01066     else
01067       split_depth_traverse_post_order (root, depth, func, data);
01068     break;
01069   default:
01070     g_assert_not_reached ();
01071   }
01072 }
01073 
01080 guint gts_split_height (GtsSplit * root)
01081 {
01082   guint height = 0, tmp_height;
01083 
01084   g_return_val_if_fail (root != NULL, 0);
01085 
01086   if (GTS_IS_SPLIT (root->v1)) {
01087     tmp_height = gts_split_height (GTS_SPLIT (root->v1));
01088     if (tmp_height > height)
01089       height = tmp_height;
01090   }
01091   if (GTS_IS_SPLIT (root->v2)) {
01092     tmp_height = gts_split_height (GTS_SPLIT (root->v2));
01093     if (tmp_height > height)
01094       height = tmp_height;
01095   }
01096 
01097   return height + 1;
01098 }
01099 
01100 #ifndef DYNAMIC_SPLIT
01101 static gboolean list_array_are_identical (GSList * list, 
01102                                           gpointer * array,
01103                                           gpointer excluded)
01104 {
01105   while (list) {
01106     gpointer data = list->data;
01107     if (data != excluded) {
01108       gboolean found = FALSE;
01109       gpointer * a = array;
01110       
01111       while (!found && *a)
01112         if (*(a++) == data)
01113           found = TRUE;
01114       if (!found)
01115         return FALSE;
01116     }
01117     list = list->next;
01118   }
01119   return TRUE;
01120 }
01121 #endif /* ifndef DYNAMIC_SPLIT */
01122 
01123 #ifndef NEW
01124 gboolean gts_split_is_collapsable (GtsSplit * vs)
01125 {
01126   guint i;
01127   GtsSplitCFace * cf;
01128   GtsVertex * v1, * v2;
01129   GtsEdge * e;
01130 
01131   g_return_val_if_fail (vs != NULL, FALSE);
01132 
01133   v1 = GTS_SPLIT_V1 (vs);
01134   v2 = GTS_SPLIT_V2 (vs);
01135   g_return_val_if_fail ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2))),
01136                         FALSE);
01137 
01138 #ifdef DYNAMIC_SPLIT
01139   if (!gts_edge_collapse_is_valid (e))
01140     return FALSE;
01141 #else 
01142   i = vs->ncf;
01143   cf = vs->cfaces;
01144   while (i--) {
01145     GtsTriangle * t = GTS_TRIANGLE (cf->f);
01146     GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3;
01147 
01148     ROTATE_ORIENT (e, e1, e2, e3);
01149     if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) {
01150       e3 = e1; e1 = e2; e2 = e3;
01151     }
01152 
01153     if (!list_array_are_identical (e1->triangles, (gpointer *) cf->a1, t))
01154       return FALSE;
01155     if (!list_array_are_identical (e2->triangles, (gpointer *) cf->a2, t))
01156       return FALSE;
01157     
01158     cf++;
01159   }
01160 #endif
01161   return TRUE;
01162 }
01163 #endif /* not NEW */
01164 
01165 #ifdef DEBUG_HEXPAND
01166 static guint expand_level = 0;
01167 
01168 static void expand_indent (FILE * fptr)
01169 {
01170   guint i = expand_level;
01171   while (i--)
01172     fputc (' ', fptr);
01173 }
01174 #endif
01175 
01184 void gts_hsplit_force_expand (GtsHSplit * hs,
01185                               GtsHSurface * hsurface)
01186 {
01187   guint i;
01188   GtsSplitCFace * cf;
01189 
01190   g_return_if_fail (hs != NULL);
01191   g_return_if_fail (hsurface != NULL);
01192   g_return_if_fail (hs->nchild == 0);
01193 
01194 #ifdef DEBUG_HEXPAND
01195   expand_level += 2;
01196 #endif
01197 
01198   if (hs->parent && hs->parent->nchild == 0) {
01199 #ifdef DEBUG_HEXPAND
01200     expand_indent (stderr); 
01201     fprintf (stderr, "expand parent %p\n", hs->parent);
01202 #endif
01203     gts_hsplit_force_expand (hs->parent, hsurface);
01204   }
01205 
01206   i = GTS_SPLIT (hs)->ncf;
01207   cf = GTS_SPLIT (hs)->cfaces;
01208   while (i--) {
01209     GtsTriangle ** j, * t;
01210 
01211     j = cf->a1;
01212     while ((t = *(j++)))
01213       if (IS_CFACE (t)) {
01214 #ifdef DEBUG_HEXPAND
01215         expand_indent (stderr); 
01216         fprintf (stderr, "expand a1: cf->f: %p t: %p parent_split: %p\n", 
01217                  cf->f,
01218                  t,
01219                  GTS_HSPLIT (CFACE (t)->parent_split));
01220 #endif
01221         gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t)->parent_split),
01222                                  hsurface);
01223 #ifdef DEBUG_HEXPAND
01224         g_assert (!IS_CFACE (t));
01225 #endif
01226       }
01227     j = cf->a2;
01228     while ((t = *(j++)))
01229       if (IS_CFACE (t)) {
01230 #ifdef DEBUG_HEXPAND
01231         expand_indent (stderr); 
01232         fprintf (stderr, "expand a2: cf->f: %p t: %p parent_split: %p\n", 
01233                  cf->f,
01234                  t,
01235                  GTS_HSPLIT (CFACE (t)->parent_split));
01236 #endif
01237         gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t)->parent_split),
01238                                  hsurface);
01239       }
01240     cf++;
01241   }
01242 
01243   gts_hsplit_expand (hs, hsurface);
01244 
01245 #ifdef DEBUG_HEXPAND
01246   expand_level -= 2; 
01247   expand_indent (stderr); 
01248   fprintf (stderr, "%p expanded\n", hs);
01249 #endif
01250 }
01251 
01252 static void index_object (GtsObject * o, guint * n)
01253 {
01254   o->reserved = GUINT_TO_POINTER ((*n)++);
01255 }
01256 
01257 static void index_face (GtsFace * f, gpointer * data)
01258 {
01259   guint * nf = data[1];
01260 
01261   g_hash_table_insert (data[0], f, GUINT_TO_POINTER ((*nf)++));
01262 }
01263 
01271 void gts_psurface_write (GtsPSurface * ps, FILE * fptr)
01272 {
01273   guint nv = 1;
01274   guint nf = 1;
01275   GHashTable * hash;
01276   gpointer data[2];
01277 
01278   g_return_if_fail (ps != NULL);
01279   g_return_if_fail (fptr != NULL);
01280   g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps));
01281 
01282   while (gts_psurface_remove_vertex (ps))
01283     ;
01284 
01285   GTS_POINT_CLASS (ps->s->vertex_class)->binary = FALSE;
01286   gts_surface_write (ps->s, fptr);
01287   
01288   gts_surface_foreach_vertex (ps->s, (GtsFunc) index_object, &nv);
01289   hash = g_hash_table_new (NULL, NULL);
01290   data[0] = hash;
01291   data[1] = &nf;
01292   gts_surface_foreach_face (ps->s, (GtsFunc) index_face, data);
01293 
01294   fprintf (fptr, "%u\n", ps->split->len);
01295   while (ps->pos) {
01296     GtsSplit * vs = g_ptr_array_index (ps->split, --ps->pos);
01297     GtsSplitCFace * scf = vs->cfaces;
01298     GtsVertex * v1, * v2;
01299     guint i = vs->ncf;
01300 
01301     fprintf (fptr, "%u %u",
01302              GPOINTER_TO_UINT (GTS_OBJECT (vs->v)->reserved),
01303              vs->ncf);
01304     if (GTS_OBJECT (vs)->klass->write)
01305       (*GTS_OBJECT (vs)->klass->write) (GTS_OBJECT (vs), fptr);
01306     fputc ('\n', fptr);
01307 
01308     v1 = GTS_IS_SPLIT (vs->v1) ? GTS_SPLIT (vs->v1)->v : GTS_VERTEX (vs->v1);
01309     GTS_OBJECT (v1)->reserved = GUINT_TO_POINTER (nv++);
01310     v2 = GTS_IS_SPLIT (vs->v2) ? GTS_SPLIT (vs->v2)->v : GTS_VERTEX (vs->v2);
01311     GTS_OBJECT (v2)->reserved = GUINT_TO_POINTER (nv++);
01312 
01313     (*GTS_OBJECT (v1)->klass->write) (GTS_OBJECT (v1), fptr);
01314     fputc ('\n', fptr);
01315 
01316     (*GTS_OBJECT (v2)->klass->write) (GTS_OBJECT (v2), fptr);
01317     fputc ('\n', fptr);
01318     
01319     while (i--) {
01320       CFace * cf = CFACE (scf->f);
01321       GtsTriangle ** a, * t;
01322 
01323       fprintf (fptr, "%u %u",
01324                GPOINTER_TO_UINT (g_hash_table_lookup (hash, cf->t)),
01325                cf->flags);
01326       if (GTS_OBJECT_CLASS (ps->s->face_class)->write)
01327         (*GTS_OBJECT_CLASS (ps->s->face_class)->write) (GTS_OBJECT (cf), fptr);
01328       fputc ('\n', fptr);
01329 
01330       a = scf->a1;
01331       while ((t = *(a++)))
01332         fprintf (fptr, "%u ",
01333                  GPOINTER_TO_UINT (g_hash_table_lookup (hash, t)));
01334       fprintf (fptr, "\n");
01335 
01336       a = scf->a2;
01337       while ((t = *(a++)))
01338         fprintf (fptr, "%u ",
01339                  GPOINTER_TO_UINT (g_hash_table_lookup (hash, t)));
01340       fprintf (fptr, "\n");
01341 
01342       g_hash_table_insert (hash, cf, GUINT_TO_POINTER (nf++));
01343 
01344       scf++;
01345     }
01346 
01347     gts_split_expand (vs, ps->s, ps->s->edge_class);
01348   }
01349 
01350   gts_surface_foreach_vertex (ps->s, 
01351                               (GtsFunc) gts_object_reset_reserved, NULL);
01352   g_hash_table_destroy (hash);
01353 }
01354 
01355 static guint surface_read (GtsSurface * surface, 
01356                            GtsFile * f,
01357                            GPtrArray * vertices,
01358                            GPtrArray * faces)
01359 {
01360   GtsEdge ** edges;
01361   guint n, nv, ne, nf;
01362 
01363   g_return_val_if_fail (surface != NULL, 1);
01364   g_return_val_if_fail (f != NULL, 1);
01365   
01366   if (f->type != GTS_INT) {
01367     gts_file_error (f, "expecting an integer (number of vertices)");
01368     return f->line;
01369   }
01370   nv = atoi (f->token->str);
01371 
01372   gts_file_next_token (f);
01373   if (f->type != GTS_INT) {
01374     gts_file_error (f, "expecting an integer (number of edges)");
01375     return f->line;
01376   }
01377   ne = atoi (f->token->str);
01378 
01379   gts_file_next_token (f);
01380   if (f->type != GTS_INT) {
01381     gts_file_error (f, "expecting an integer (number of faces)");
01382     return f->line;
01383   }
01384   nf = atoi (f->token->str);
01385 
01386   gts_file_next_token (f);
01387   if (f->type == GTS_STRING) {
01388     if (f->type != GTS_STRING) {
01389       gts_file_error (f, "expecting a string (GtsSurfaceClass)");
01390       return f->line;
01391     }
01392     gts_file_next_token (f);
01393     if (f->type != GTS_STRING) {
01394       gts_file_error (f, "expecting a string (GtsFaceClass)");
01395       return f->line;
01396     }
01397     gts_file_next_token (f);
01398     if (f->type != GTS_STRING) {
01399       gts_file_error (f, "expecting a string (GtsEdgeClass)");
01400       return f->line;
01401     }
01402     gts_file_next_token (f);
01403     if (f->type != GTS_STRING) {
01404       gts_file_error (f, "expecting a string (GtsVertexClass)");
01405       return f->line;
01406     }
01407     if (!strcmp (f->token->str, "GtsVertexBinary"))
01408       GTS_POINT_CLASS (surface->vertex_class)->binary = TRUE;
01409     else
01410       gts_file_first_token_after (f, '\n');
01411   }
01412   else
01413     gts_file_first_token_after (f, '\n');
01414 
01415   g_ptr_array_set_size (vertices, nv);
01416   g_ptr_array_set_size (faces, nf);
01417   /* allocate nv + 1 just in case nv == 0 */
01418   edges = g_malloc ((ne + 1)*sizeof (GtsEdge *));
01419   
01420   n = 0;
01421   while (n < nv && f->type != GTS_ERROR) {
01422     GtsObject * new_vertex =
01423       gts_object_new (GTS_OBJECT_CLASS (surface->vertex_class));
01424 
01425     (* GTS_OBJECT_CLASS (surface->vertex_class)->read) (&new_vertex, f);
01426     if (f->type != GTS_ERROR) {
01427       if (!GTS_POINT_CLASS (surface->vertex_class)->binary)
01428         gts_file_first_token_after (f, '\n');
01429       g_ptr_array_index (vertices, n++) = new_vertex;
01430     }
01431     else
01432       gts_object_destroy (new_vertex);
01433   }
01434   if (f->type == GTS_ERROR)
01435     nv = n;
01436   if (GTS_POINT_CLASS (surface->vertex_class)->binary)
01437     gts_file_first_token_after (f, '\n');
01438 
01439   n = 0;
01440   while (n < ne && f->type != GTS_ERROR) {
01441     guint p1, p2;
01442 
01443     if (f->type != GTS_INT)
01444       gts_file_error (f, "expecting an integer (first vertex index)");
01445     else {
01446       p1 = atoi (f->token->str);
01447       if (p1 == 0 || p1 > nv)
01448         gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", 
01449                         p1, nv);
01450       else {
01451         gts_file_next_token (f);
01452         if (f->type != GTS_INT)
01453           gts_file_error (f, "expecting an integer (second vertex index)");
01454         else {
01455           p2 = atoi (f->token->str);
01456           if (p2 == 0 || p2 > nv)
01457             gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", 
01458                             p2, nv);
01459           else {
01460             GtsEdge * new_edge =
01461               gts_edge_new (surface->edge_class,
01462                             g_ptr_array_index (vertices, p1 - 1),
01463                             g_ptr_array_index (vertices, p2 - 1));
01464 
01465             gts_file_next_token (f);
01466             if (f->type != '\n')
01467               if (GTS_OBJECT_CLASS (surface->edge_class)->read)
01468                 (*GTS_OBJECT_CLASS (surface->edge_class)->read)
01469                   ((GtsObject **) &new_edge, f);
01470             gts_file_first_token_after (f, '\n');
01471             edges[n++] = new_edge;
01472           }
01473         }
01474       }
01475     }
01476   }
01477   if (f->type == GTS_ERROR)
01478     ne = n;
01479 
01480   n = 0;
01481   while (n < nf && f->type != GTS_ERROR) {
01482     guint s1, s2, s3;
01483 
01484     if (f->type != GTS_INT)
01485       gts_file_error (f, "expecting an integer (first edge index)");
01486     else {
01487       s1 = atoi (f->token->str);
01488       if (s1 == 0 || s1 > ne)
01489         gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
01490                         s1, ne);
01491       else {
01492         gts_file_next_token (f);
01493         if (f->type != GTS_INT)
01494           gts_file_error (f, "expecting an integer (second edge index)");
01495         else {
01496           s2 = atoi (f->token->str);
01497           if (s2 == 0 || s2 > ne)
01498             gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
01499                             s2, ne);
01500           else {
01501             gts_file_next_token (f);
01502             if (f->type != GTS_INT)
01503               gts_file_error (f, "expecting an integer (third edge index)");
01504             else {
01505               s3 = atoi (f->token->str);
01506               if (s3 == 0 || s3 > ne)
01507                 gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
01508                                 s3, ne);
01509               else {
01510                 GtsFace * new_face = gts_face_new (surface->face_class,
01511                                                    edges[s1 - 1],
01512                                                    edges[s2 - 1],
01513                                                    edges[s3 - 1]);
01514 
01515                 gts_file_next_token (f);
01516                 if (f->type != '\n')
01517                   if (GTS_OBJECT_CLASS (surface->face_class)->read)
01518                     (*GTS_OBJECT_CLASS (surface->face_class)->read)
01519                       ((GtsObject **) &new_face, f);
01520                 gts_file_first_token_after (f, '\n');
01521                 gts_surface_add_face (surface, new_face);
01522                 g_ptr_array_index (faces, n++) = new_face;
01523               }
01524             }
01525           }
01526         }
01527       }
01528     }
01529   }
01530 
01531   g_free (edges);
01532 
01533   if (f->type == GTS_ERROR) {
01534     gts_allow_floating_vertices = TRUE;
01535     while (nv)
01536       gts_object_destroy (GTS_OBJECT (g_ptr_array_index (vertices, nv-- - 1)));
01537     gts_allow_floating_vertices = FALSE;    
01538     return f->line;
01539   }
01540 
01541   return 0;
01542 }
01543 
01563 GtsPSurface * gts_psurface_open (GtsPSurfaceClass * klass,
01564                                  GtsSurface * s,
01565                                  GtsSplitClass * split_class,
01566                                  GtsFile * f)
01567 {
01568   GtsPSurface * ps;
01569 
01570   g_return_val_if_fail (klass != NULL, NULL);
01571   g_return_val_if_fail (s != NULL, NULL);
01572   g_return_val_if_fail (split_class != NULL, NULL);
01573   g_return_val_if_fail (f != NULL, NULL);
01574 
01575   ps = GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
01576   ps->s = s;
01577   ps->split_class = split_class;
01578 
01579   ps->vertices = g_ptr_array_new ();
01580   ps->faces = g_ptr_array_new ();
01581 
01582   if (surface_read (s, f, ps->vertices, ps->faces)) {
01583     ps->s = NULL;
01584     gts_object_destroy (GTS_OBJECT (ps));
01585     return NULL;
01586   }
01587 
01588   ps->min = gts_surface_vertex_number (ps->s);
01589   ps->pos = 0;
01590 
01591   if (f->type == GTS_INT) {
01592     gint ns = atoi (f->token->str);
01593     
01594     if (ns > 0) {
01595       g_ptr_array_set_size (ps->split, ns);
01596       gts_file_first_token_after (f, '\n');
01597     }
01598   }
01599 
01600   return ps;
01601 }
01602 
01615 GtsSplit * gts_psurface_read_vertex (GtsPSurface * ps, GtsFile * fp)
01616 {
01617   guint nv, ncf;
01618   GtsSplit * vs, * parent;
01619   GtsSplitCFace * scf;
01620 
01621   g_return_val_if_fail (ps != NULL, NULL);
01622   g_return_val_if_fail (fp != NULL, NULL);
01623   g_return_val_if_fail (!GTS_PSURFACE_IS_CLOSED (ps), NULL);
01624   
01625   if (ps->pos >= ps->split->len)
01626     return NULL;
01627 
01628   if (fp->type == GTS_NONE)
01629     return NULL;
01630   if (fp->type != GTS_INT) {
01631     gts_file_error (fp, "expecting an integer (vertex index)");
01632     return NULL;
01633   }
01634   nv = atoi (fp->token->str);
01635   if (nv == 0 || nv > ps->vertices->len) {
01636     gts_file_error (fp, "vertex index `%d' is out of range `[1,%d]'",
01637                     nv, ps->vertices->len);
01638     return NULL;
01639   }
01640 
01641   gts_file_next_token (fp);
01642   if (fp->type != GTS_INT) {
01643     gts_file_error (fp, "expecting an integer (ncf)");
01644     return NULL;
01645   }
01646   ncf = atoi (fp->token->str);
01647   
01648   vs = GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (ps->split_class)));
01649 
01650   vs->v = g_ptr_array_index (ps->vertices, nv - 1);
01651   vs->v1 = vs->v2 = NULL;
01652   vs->cfaces = NULL;
01653   vs->ncf = 0;
01654 
01655   gts_file_next_token (fp);
01656   if (fp->type != '\n')
01657     if (GTS_OBJECT (vs)->klass->read)
01658       (* GTS_OBJECT (vs)->klass->read) ((GtsObject **) &vs, fp);
01659   gts_file_first_token_after (fp, '\n');
01660 
01661   if (fp->type != GTS_ERROR) {
01662     vs->v1 = gts_object_new (GTS_OBJECT_CLASS (ps->s->vertex_class));
01663     (* GTS_OBJECT_CLASS (ps->s->vertex_class)->read) (&(vs->v1), fp);
01664     if (fp->type != GTS_ERROR) {
01665       vs->v1->reserved = vs;
01666       g_ptr_array_add (ps->vertices, vs->v1);
01667 
01668       gts_file_first_token_after (fp, '\n');
01669       
01670       vs->v2 = gts_object_new (GTS_OBJECT_CLASS (ps->s->vertex_class));
01671       (*GTS_OBJECT_CLASS (ps->s->vertex_class)->read) (&(vs->v2), fp);
01672       if (fp->type != GTS_ERROR) {
01673         vs->v2->reserved = vs;
01674         g_ptr_array_add (ps->vertices, vs->v2);
01675         gts_file_first_token_after (fp, '\n');
01676       }
01677     }
01678   }
01679 
01680   if (fp->type != GTS_ERROR) {
01681     scf = vs->cfaces = g_malloc (sizeof (GtsSplitCFace)*ncf);
01682     while (fp->type != GTS_ERROR && ncf--) {
01683       guint it, flags;
01684       GtsFace * f;
01685       CFace * cf;
01686       GPtrArray * a;
01687 
01688       if (fp->type != GTS_INT)
01689         gts_file_error (fp, "expecting an integer (face index)");
01690       else {
01691         it = atoi (fp->token->str);
01692         if (it == 0 || it > ps->faces->len)
01693           gts_file_error (fp, "face index `%d' is out of range `[1,%d]'",
01694                           it, ps->faces->len);
01695         else {
01696           gts_file_next_token (fp);
01697           if (fp->type != GTS_INT)
01698             gts_file_error (fp, "expecting an integer (flags)");
01699           else {
01700             flags = atoi (fp->token->str);
01701             f = 
01702               GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (ps->s->face_class)));
01703 
01704             gts_file_next_token (fp);
01705             if (fp->type != '\n')
01706               if (GTS_OBJECT (f)->klass->read)
01707                 (*GTS_OBJECT (f)->klass->read) ((GtsObject **) &f, fp);
01708             gts_file_first_token_after (fp, '\n');
01709             if (fp->type != GTS_ERROR) {
01710               scf->f = f;
01711 
01712               cf = (CFace *) f;
01713               GTS_OBJECT (cf)->klass = GTS_OBJECT_CLASS (cface_class ());
01714               cf->parent_split = vs;
01715               cf->t = g_ptr_array_index (ps->faces, it - 1);
01716               cf->flags = flags;
01717           
01718               a = g_ptr_array_new ();
01719               do {
01720                 if (fp->type != GTS_INT)
01721                   gts_file_error (fp, "expecting an integer (face index)");
01722                 else {
01723                   it = atoi (fp->token->str);
01724                   if (it > ps->faces->len)
01725                     gts_file_error (fp, 
01726                                     "face index `%d' is out of range `[1,%d]'",
01727                                     it, ps->faces->len);
01728                   else {
01729                     g_ptr_array_add (a, g_ptr_array_index (ps->faces, 
01730                                                            it - 1));
01731                     gts_file_next_token (fp);
01732                   }
01733                 }
01734               } while (fp->type != GTS_ERROR && fp->type != '\n');
01735               gts_file_first_token_after (fp, '\n');
01736               g_ptr_array_add (a, NULL);
01737               scf->a1 = (GtsTriangle **) a->pdata;
01738               g_ptr_array_free (a, FALSE);
01739 
01740               if (fp->type != GTS_ERROR) {
01741                 a = g_ptr_array_new ();
01742                 do {
01743                   if (fp->type != GTS_INT)
01744                     gts_file_error (fp, "expecting an integer (face index)");
01745                   else {
01746                     it = atoi (fp->token->str);
01747                     if (it > ps->faces->len)
01748                       gts_file_error (fp, 
01749                                    "face index `%d' is out of range `[1,%d]'",
01750                                       it, ps->faces->len);
01751                     else {
01752                       g_ptr_array_add (a, g_ptr_array_index (ps->faces, 
01753                                                              it - 1));
01754                       gts_file_next_token (fp);
01755                     }
01756                   }
01757                 } while (fp->type != GTS_ERROR && fp->type != '\n');
01758                 gts_file_first_token_after (fp, '\n');
01759                 g_ptr_array_add (a, NULL);
01760                 scf->a2 = (GtsTriangle **) a->pdata;
01761                 g_ptr_array_free (a, FALSE);
01762                 
01763                 g_ptr_array_add (ps->faces, f);
01764               
01765                 vs->ncf++;
01766                 scf++;
01767               }
01768             }
01769           }
01770         }
01771       }
01772     }
01773   }
01774 
01775   if (fp->type != GTS_ERROR) {
01776     if ((parent = GTS_OBJECT (vs->v)->reserved)) {
01777       GTS_OBJECT (vs->v)->reserved = NULL;
01778       if (parent->v1 == GTS_OBJECT (vs->v))
01779         parent->v1 = GTS_OBJECT (vs);
01780       else {
01781         g_assert (parent->v2 == GTS_OBJECT (vs->v));
01782         parent->v2 = GTS_OBJECT (vs);
01783       }
01784     }
01785     g_ptr_array_index (ps->split, ps->pos++) = vs;
01786     gts_split_expand (vs, ps->s, ps->s->edge_class);
01787 
01788     return vs;
01789   }
01790 
01791   if (vs->v1) gts_object_destroy (vs->v1);
01792   if (vs->v2) gts_object_destroy (vs->v2);
01793   gts_object_destroy (GTS_OBJECT (vs));
01794   
01795   return NULL;
01796 }
01797 
01804 void gts_psurface_close (GtsPSurface * ps)
01805 {
01806   g_return_if_fail (ps != NULL);
01807   g_return_if_fail (!GTS_PSURFACE_IS_CLOSED (ps));
01808 
01809   g_ptr_array_free (ps->vertices, TRUE);
01810   g_ptr_array_free (ps->faces, TRUE);
01811   ps->faces = ps->vertices = NULL;
01812   
01813   gts_surface_foreach_vertex (ps->s, 
01814                               (GtsFunc) gts_object_reset_reserved, NULL);
01815   if (ps->pos > 0)
01816     g_ptr_array_set_size (ps->split, ps->pos);
01817   if (ps->split->len > 1) {
01818     guint i, half = ps->split->len/2, n = ps->split->len - 1;
01819     
01820     for (i = 0; i < half; i++) {
01821       gpointer p1 = g_ptr_array_index (ps->split, i);
01822       gpointer p2 = g_ptr_array_index (ps->split, n - i);
01823       g_ptr_array_index (ps->split, n - i) = p1;
01824       g_ptr_array_index (ps->split, i) = p2;
01825     }
01826   }
01827   ps->pos = 0;
01828 }