pcb 4.1.1
An interactive printed circuit board layout editor.

surface.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 <math.h>
00022 #include <string.h>
00023 #include "gts.h"
00024 
00025 #include "gts-private.h"
00026 
00027 static void destroy_foreach_face (GtsFace * f, GtsSurface * s)
00028 {
00029   f->surfaces = g_slist_remove (f->surfaces, s);
00030   if (!GTS_OBJECT_DESTROYED (f) &&
00031       !gts_allow_floating_faces && f->surfaces == NULL)
00032     gts_object_destroy (GTS_OBJECT (f));
00033 }
00034 
00035 static void surface_destroy (GtsObject * object)
00036 {
00037   GtsSurface * surface = GTS_SURFACE (object);
00038   
00039   gts_surface_foreach_face (surface, (GtsFunc) destroy_foreach_face, surface);
00040 #ifdef USE_SURFACE_BTREE
00041   g_tree_destroy (surface->faces);
00042 #else /* not USE_SURFACE_BTREE */
00043   g_hash_table_destroy (surface->faces);
00044 #endif /* not USE_SURFACE_BTREE */
00045 
00046   (* GTS_OBJECT_CLASS (gts_surface_class ())->parent_class->destroy) (object);
00047 }
00048 
00049 static void surface_write (GtsObject * object, FILE * fptr)
00050 {
00051   fprintf (fptr, " %s %s %s %s", 
00052            object->klass->info.name,
00053            GTS_OBJECT_CLASS (GTS_SURFACE (object)->face_class)->info.name,
00054            GTS_OBJECT_CLASS (GTS_SURFACE (object)->edge_class)->info.name,
00055            GTS_POINT_CLASS (GTS_SURFACE (object)->vertex_class)->binary ?
00056            "GtsVertexBinary" :
00057            GTS_OBJECT_CLASS (GTS_SURFACE (object)->vertex_class)->info.name);
00058 }
00059 
00060 static void surface_class_init (GtsSurfaceClass * klass)
00061 {
00062   GTS_OBJECT_CLASS (klass)->destroy = surface_destroy;
00063   GTS_OBJECT_CLASS (klass)->write = surface_write;
00064   klass->add_face = NULL;
00065   klass->remove_face = NULL;
00066 }
00067 
00068 #ifdef USE_SURFACE_BTREE
00069 static gint compare_pointers (gconstpointer a, gconstpointer b)
00070 {
00071   if (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b))
00072     return -1;
00073   if (GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b))
00074     return 1;
00075   return 0;
00076 }
00077 #endif /* USE_SURFACE_BTREE */
00078 
00079 static void surface_init (GtsSurface * surface)
00080 {
00081 #ifdef USE_SURFACE_BTREE
00082   surface->faces = g_tree_new (compare_pointers);
00083 #else /* not USE_SURFACE_BTREE */
00084   surface->faces = g_hash_table_new (NULL, NULL);
00085 #endif /* not USE_SURFACE_BTREE */
00086   surface->vertex_class = gts_vertex_class ();
00087   surface->edge_class = gts_edge_class ();
00088   surface->face_class = gts_face_class ();
00089   surface->keep_faces = FALSE;
00090 }
00091 
00097 GtsSurfaceClass * gts_surface_class (void)
00098 {
00099   static GtsSurfaceClass * klass = NULL;
00100 
00101   if (klass == NULL) {
00102     GtsObjectClassInfo surface_info = {
00103       "GtsSurface",
00104       sizeof (GtsSurface),
00105       sizeof (GtsSurfaceClass),
00106       (GtsObjectClassInitFunc) surface_class_init,
00107       (GtsObjectInitFunc) surface_init,
00108       (GtsArgSetFunc) NULL,
00109       (GtsArgGetFunc) NULL
00110     };
00111     klass = gts_object_class_new (gts_object_class (), &surface_info);
00112   }
00113 
00114   return klass;
00115 }
00116 
00126 GtsSurface * gts_surface_new (GtsSurfaceClass * klass,
00127                               GtsFaceClass * face_class,
00128                               GtsEdgeClass * edge_class,
00129                               GtsVertexClass * vertex_class)
00130 {
00131   GtsSurface * s;
00132 
00133   s = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
00134   s->vertex_class = vertex_class;
00135   s->edge_class = edge_class;
00136   s->face_class = face_class;
00137 
00138   return s;
00139 }
00140 
00148 void gts_surface_add_face (GtsSurface * s, GtsFace * f)
00149 {
00150   g_return_if_fail (s != NULL);
00151   g_return_if_fail (f != NULL);
00152 
00153   g_assert (s->keep_faces == FALSE);
00154 
00155 #ifdef USE_SURFACE_BTREE
00156   if (!g_tree_lookup (s->faces, f)) {
00157     f->surfaces = g_slist_prepend (f->surfaces, s);
00158     g_tree_insert (s->faces, f, f);
00159   }
00160 #else /* not USE_SURFACE_BTREE */
00161   if (!g_hash_table_lookup (s->faces, f)) {
00162     f->surfaces = g_slist_prepend (f->surfaces, s);
00163     g_hash_table_insert (s->faces, f, f);
00164   }
00165 #endif /* not USE_SURFACE_BTREE */
00166 
00167   if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->add_face)
00168     (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->add_face) (s, f);
00169 }
00170 
00178 void gts_surface_remove_face (GtsSurface * s, 
00179                               GtsFace * f)
00180 {
00181   g_return_if_fail (s != NULL);
00182   g_return_if_fail (f != NULL);
00183 
00184   g_assert (s->keep_faces == FALSE);
00185 
00186 #ifdef USE_SURFACE_BTREE
00187   g_tree_remove (s->faces, f);
00188 #else /* not USE_SURFACE_BTREE */
00189   g_hash_table_remove (s->faces, f);
00190 #endif /* not USE_SURFACE_BTREE */
00191 
00192   f->surfaces = g_slist_remove (f->surfaces, s);
00193 
00194   if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face)
00195     (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f);
00196 
00197   if (!GTS_OBJECT_DESTROYED (f) &&
00198       !gts_allow_floating_faces && 
00199       f->surfaces == NULL)
00200     gts_object_destroy (GTS_OBJECT (f));
00201 }
00202 
00215 /* Update split.c/surface_read() if modifying this function */
00216 guint gts_surface_read (GtsSurface * surface, GtsFile * f)
00217 {
00218   GtsVertex ** vertices;
00219   GtsEdge ** edges;
00220   guint n, nv, ne, nf;
00221 
00222   g_return_val_if_fail (surface != NULL, 1);
00223   g_return_val_if_fail (f != NULL, 1);
00224 
00225   if (f->type != GTS_INT) {
00226     gts_file_error (f, "expecting an integer (number of vertices)");
00227     return f->line;
00228   }
00229   nv = atoi (f->token->str);
00230 
00231   gts_file_next_token (f);
00232   if (f->type != GTS_INT) {
00233     gts_file_error (f, "expecting an integer (number of edges)");
00234     return f->line;
00235   }
00236   ne = atoi (f->token->str);
00237 
00238   gts_file_next_token (f);
00239   if (f->type != GTS_INT) {
00240     gts_file_error (f, "expecting an integer (number of faces)");
00241     return f->line;
00242   }
00243   nf = atoi (f->token->str);
00244   
00245   gts_file_next_token (f);
00246   if (f->type == GTS_STRING) {
00247     if (f->type != GTS_STRING) {
00248       gts_file_error (f, "expecting a string (GtsSurfaceClass)");
00249       return f->line;
00250     }
00251     gts_file_next_token (f);
00252     if (f->type != GTS_STRING) {
00253       gts_file_error (f, "expecting a string (GtsFaceClass)");
00254       return f->line;
00255     }
00256     gts_file_next_token (f);
00257     if (f->type != GTS_STRING) {
00258       gts_file_error (f, "expecting a string (GtsEdgeClass)");
00259       return f->line;
00260     }
00261     gts_file_next_token (f);
00262     if (f->type != GTS_STRING) {
00263       gts_file_error (f, "expecting a string (GtsVertexClass)");
00264       return f->line;
00265     }
00266     if (!strcmp (f->token->str, "GtsVertexBinary"))
00267       GTS_POINT_CLASS (surface->vertex_class)->binary = TRUE;
00268     else {
00269       GTS_POINT_CLASS (surface->vertex_class)->binary = FALSE;
00270       gts_file_first_token_after (f, '\n');
00271     }
00272   }
00273   else
00274     gts_file_first_token_after (f, '\n');
00275 
00276   if (nf <= 0)
00277     return 0;
00278 
00279   /* allocate nv + 1 just in case nv == 0 */
00280   vertices = g_malloc ((nv + 1)*sizeof (GtsVertex *));
00281   edges = g_malloc ((ne + 1)*sizeof (GtsEdge *));
00282   
00283   n = 0;
00284   while (n < nv && f->type != GTS_ERROR) {
00285     GtsObject * new_vertex =
00286       gts_object_new (GTS_OBJECT_CLASS (surface->vertex_class));
00287 
00288     (* GTS_OBJECT_CLASS (surface->vertex_class)->read) (&new_vertex, f);
00289     if (f->type != GTS_ERROR) {
00290       if (!GTS_POINT_CLASS (surface->vertex_class)->binary)
00291         gts_file_first_token_after (f, '\n');
00292       vertices[n++] = GTS_VERTEX (new_vertex);
00293     }
00294     else
00295       gts_object_destroy (new_vertex);
00296   }
00297   if (f->type == GTS_ERROR)
00298     nv = n;
00299   if (GTS_POINT_CLASS (surface->vertex_class)->binary)
00300     gts_file_first_token_after (f, '\n');
00301 
00302   n = 0;
00303   while (n < ne && f->type != GTS_ERROR) {
00304     guint p1, p2;
00305 
00306     if (f->type != GTS_INT)
00307       gts_file_error (f, "expecting an integer (first vertex index)");
00308     else {
00309       p1 = atoi (f->token->str);
00310       if (p1 == 0 || p1 > nv)
00311         gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", 
00312                         p1, nv);
00313       else {
00314         gts_file_next_token (f);
00315         if (f->type != GTS_INT)
00316           gts_file_error (f, "expecting an integer (second vertex index)");
00317         else {
00318           p2 = atoi (f->token->str);
00319           if (p2 == 0 || p2 > nv)
00320             gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", 
00321                             p2, nv);
00322           else {
00323             GtsEdge * new_edge =
00324               gts_edge_new (surface->edge_class,
00325                             vertices[p1 - 1], vertices[p2 - 1]);
00326 
00327             gts_file_next_token (f);
00328             if (f->type != '\n')
00329               if (GTS_OBJECT_CLASS (surface->edge_class)->read)
00330                 (*GTS_OBJECT_CLASS (surface->edge_class)->read)
00331                   ((GtsObject **) &new_edge, f);
00332             gts_file_first_token_after (f, '\n');
00333             edges[n++] = new_edge;
00334           }
00335         }
00336       }
00337     }
00338   }
00339   if (f->type == GTS_ERROR)
00340     ne = n;
00341 
00342   n = 0;
00343   while (n < nf && f->type != GTS_ERROR) {
00344     guint s1, s2, s3;
00345 
00346     if (f->type != GTS_INT)
00347       gts_file_error (f, "expecting an integer (first edge index)");
00348     else {
00349       s1 = atoi (f->token->str);
00350       if (s1 == 0 || s1 > ne)
00351         gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
00352                         s1, ne);
00353       else {
00354         gts_file_next_token (f);
00355         if (f->type != GTS_INT)
00356           gts_file_error (f, "expecting an integer (second edge index)");
00357         else {
00358           s2 = atoi (f->token->str);
00359           if (s2 == 0 || s2 > ne)
00360             gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
00361                             s2, ne);
00362           else {
00363             gts_file_next_token (f);
00364             if (f->type != GTS_INT)
00365               gts_file_error (f, "expecting an integer (third edge index)");
00366             else {
00367               s3 = atoi (f->token->str);
00368               if (s3 == 0 || s3 > ne)
00369                 gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", 
00370                                 s3, ne);
00371               else {
00372                 GtsFace * new_face = gts_face_new (surface->face_class,
00373                                                    edges[s1 - 1],
00374                                                    edges[s2 - 1],
00375                                                    edges[s3 - 1]);
00376 
00377                 gts_file_next_token (f);
00378                 if (f->type != '\n')
00379                   if (GTS_OBJECT_CLASS (surface->face_class)->read)
00380                     (*GTS_OBJECT_CLASS (surface->face_class)->read)
00381                       ((GtsObject **) &new_face, f);
00382                 gts_file_first_token_after (f, '\n');
00383                 gts_surface_add_face (surface, new_face);
00384                 n++;
00385               }
00386             }
00387           }
00388         }
00389       }
00390     }
00391   }
00392 
00393   if (f->type == GTS_ERROR) {
00394     gts_allow_floating_vertices = TRUE;
00395     while (nv)
00396       gts_object_destroy (GTS_OBJECT (vertices[nv-- - 1]));
00397     gts_allow_floating_vertices = FALSE;
00398   }
00399 
00400   g_free (vertices);
00401   g_free (edges);
00402 
00403   if (f->type == GTS_ERROR)
00404     return f->line;
00405   return 0;
00406 }
00407 
00408 static void sum_area (GtsFace * f, gdouble * area) {
00409   *area += gts_triangle_area (GTS_TRIANGLE (f));
00410 }
00411 
00419 gdouble gts_surface_area (GtsSurface * s)
00420 {  
00421   gdouble area = 0.0;
00422   gts_surface_foreach_face (s, (GtsFunc)sum_area, &area);
00423   return area;
00424 }
00425 
00432 void gts_range_init (GtsRange * r)
00433 {
00434   g_return_if_fail (r != NULL);
00435 
00436   r->max = - G_MAXDOUBLE;
00437   r->min = G_MAXDOUBLE;
00438   r->sum = r->sum2 = 0.0;
00439   r->n = 0;
00440 }
00441 
00448 void gts_range_reset (GtsRange * r)
00449 {
00450   g_return_if_fail (r != NULL);
00451 
00452   r->max = 0.0;
00453   r->min = 0.0;
00454   r->sum = r->sum2 = 0.0;
00455   r->n = 0;
00456 }
00457 
00465 void gts_range_add_value (GtsRange * r, gdouble val)
00466 {
00467   g_return_if_fail (r != NULL);
00468 
00469   if (val < r->min) r->min = val;
00470   if (val > r->max) r->max = val;
00471   r->sum += val;
00472   r->sum2 += val*val;
00473   r->n++;
00474 }
00475 
00482 void gts_range_update (GtsRange * r)
00483 {
00484   g_return_if_fail (r != NULL);
00485 
00486   if (r->n > 0) {
00487     if (r->sum2 - r->sum*r->sum/(gdouble) r->n >= 0.)
00488       r->stddev = sqrt ((r->sum2 - r->sum*r->sum/(gdouble) r->n)
00489                         /(gdouble) r->n);
00490     else
00491       r->stddev = 0.;
00492     r->mean = r->sum/(gdouble) r->n;
00493   }
00494   else 
00495     r->min = r->max = r->mean = r->stddev = 0.;
00496 }
00497 
00505 void gts_range_print (GtsRange * r, FILE * fptr)
00506 {
00507   g_return_if_fail (r != NULL);
00508   g_return_if_fail (fptr != NULL);
00509   fprintf (fptr, "min: %g mean: %g | %g max: %g", 
00510            r->min, r->mean, r->stddev, r->max);
00511 }
00512 
00513 static void stats_foreach_vertex (GtsVertex * v, GtsSurfaceStats * stats) 
00514 {
00515   GSList * i = v->segments;
00516   guint nedges = 0;
00517 
00518   while (i) {
00519     if (GTS_IS_EDGE (i->data) && 
00520         gts_edge_has_parent_surface (i->data, stats->parent))
00521       nedges++;
00522     i = i->next;
00523   }
00524   gts_range_add_value (&stats->edges_per_vertex, nedges);
00525 }
00526 
00527 static void stats_foreach_edge (GtsEdge * e, GtsSurfaceStats * stats) 
00528 {
00529   guint nt = gts_edge_face_number (e, stats->parent);
00530 
00531   if (gts_segment_is_duplicate (GTS_SEGMENT (e)))
00532     stats->n_duplicate_edges++;
00533   if (nt == 1)
00534     stats->n_boundary_edges++;
00535   else if (nt > 2)
00536     stats->n_non_manifold_edges++;
00537   gts_range_add_value (&stats->faces_per_edge, nt);
00538 }
00539 
00540 static void stats_foreach_face (GtsTriangle * t, GtsSurfaceStats * stats)
00541 {
00542   if (!gts_face_is_compatible (GTS_FACE (t), stats->parent))
00543     stats->n_incompatible_faces++;
00544   if (gts_triangle_is_duplicate (t))
00545     stats->n_duplicate_faces++;
00546   stats->n_faces++;
00547 }
00548 
00556 void gts_surface_stats (GtsSurface * s, GtsSurfaceStats * stats)
00557 {
00558   g_return_if_fail (s != NULL);
00559   g_return_if_fail (stats != NULL);
00560 
00561   stats->parent = s;
00562   stats->n_faces = 0;
00563   stats->n_incompatible_faces = 0;
00564   stats->n_duplicate_faces = 0;
00565   stats->n_duplicate_edges = 0;
00566   stats->n_boundary_edges = 0;
00567   stats->n_non_manifold_edges = 0;
00568   gts_range_init (&stats->edges_per_vertex);
00569   gts_range_init (&stats->faces_per_edge);
00570 
00571   gts_surface_foreach_vertex (s, (GtsFunc) stats_foreach_vertex, stats);
00572   gts_surface_foreach_edge (s, (GtsFunc) stats_foreach_edge, stats);
00573   gts_surface_foreach_face (s, (GtsFunc) stats_foreach_face, stats);
00574 
00575   gts_range_update (&stats->edges_per_vertex);
00576   gts_range_update (&stats->faces_per_edge);
00577 }
00578 
00579 static void quality_foreach_edge (GtsSegment * s,
00580                                   GtsSurfaceQualityStats * stats) 
00581 {
00582   GSList * i = GTS_EDGE (s)->triangles;
00583 
00584   gts_range_add_value (&stats->edge_length, 
00585                    gts_point_distance (GTS_POINT (s->v1), 
00586                                        GTS_POINT (s->v2)));
00587   while (i) {
00588     GSList * j = i->next;
00589     while (j) {
00590       gts_range_add_value (&stats->edge_angle,
00591                            fabs (gts_triangles_angle (i->data, j->data)));
00592       j = j->next;
00593     }
00594     i = i->next;
00595   }
00596 }
00597 
00598 static void quality_foreach_face (GtsTriangle * t,
00599                                   GtsSurfaceQualityStats * stats) 
00600 {
00601   gts_range_add_value (&stats->face_quality, gts_triangle_quality (t));
00602   gts_range_add_value (&stats->face_area, gts_triangle_area (t));
00603 }
00604 
00612 void gts_surface_quality_stats (GtsSurface * s, GtsSurfaceQualityStats * stats)
00613 {
00614   g_return_if_fail (s != NULL);
00615   g_return_if_fail (stats != NULL);
00616 
00617   stats->parent = s;
00618   gts_range_init (&stats->face_quality);
00619   gts_range_init (&stats->face_area);
00620   gts_range_init (&stats->edge_length);
00621   gts_range_init (&stats->edge_angle);
00622 
00623   gts_surface_foreach_edge (s, (GtsFunc) quality_foreach_edge, stats);  
00624   gts_surface_foreach_face (s, (GtsFunc) quality_foreach_face, stats);
00625 
00626   gts_range_update (&stats->face_quality);
00627   gts_range_update (&stats->face_area);
00628   gts_range_update (&stats->edge_length);
00629   gts_range_update (&stats->edge_angle);
00630 }
00631 
00639 void gts_surface_print_stats (GtsSurface * s, FILE * fptr)
00640 {
00641   GtsSurfaceStats stats;
00642   GtsSurfaceQualityStats qstats;
00643 
00644   g_return_if_fail (s != NULL);
00645   g_return_if_fail (fptr != NULL);
00646 
00647   gts_surface_stats (s, &stats);
00648   gts_surface_quality_stats (s, &qstats);
00649 
00650   fprintf (fptr, 
00651            "# vertices: %u edges: %u faces: %u\n"
00652            "# Connectivity statistics\n"
00653            "#   incompatible faces: %u\n"
00654            "#   duplicate faces: %u\n"
00655            "#   boundary edges: %u\n"
00656            "#   duplicate edges: %u\n"
00657            "#   non-manifold edges: %u\n",
00658            stats.edges_per_vertex.n, 
00659            stats.faces_per_edge.n,
00660            stats.n_faces,
00661            stats.n_incompatible_faces,
00662            stats.n_duplicate_faces,
00663            stats.n_boundary_edges,
00664            stats.n_duplicate_edges,
00665            stats.n_non_manifold_edges);
00666   fputs ("#   edges per vertex: ", fptr); 
00667   gts_range_print (&stats.edges_per_vertex, fptr);
00668   fputs ("\n#   faces per edge: ", fptr);
00669   gts_range_print (&stats.faces_per_edge, fptr);
00670   fputs ("\n# Geometric statistics\n#   face quality: ", fptr);
00671   gts_range_print (&qstats.face_quality, fptr);
00672   fputs ("\n#   face area  : ", fptr);
00673   gts_range_print (&qstats.face_area, fptr);
00674   fputs ("\n#   edge length : ", fptr);
00675   gts_range_print (&qstats.edge_length, fptr);
00676   fputc ('\n', fptr);
00677 }
00678 
00679 static void write_vertex (GtsPoint * p, gpointer * data)
00680 {
00681   (*GTS_OBJECT (p)->klass->write) (GTS_OBJECT (p), (FILE *) data[0]);
00682   if (!GTS_POINT_CLASS (GTS_OBJECT (p)->klass)->binary)
00683     fputc ('\n', (FILE *) data[0]);
00684   g_hash_table_insert (data[2], p, 
00685                        GUINT_TO_POINTER (++(*((guint *) data[1]))));
00686 }
00687 
00688 static void write_edge (GtsSegment * s, gpointer * data) 
00689 {
00690   fprintf ((FILE *) data[0], "%u %u",
00691            GPOINTER_TO_UINT (g_hash_table_lookup (data[2], s->v1)),
00692            GPOINTER_TO_UINT (g_hash_table_lookup (data[2], s->v2)));
00693   if (GTS_OBJECT (s)->klass->write)
00694     (*GTS_OBJECT (s)->klass->write) (GTS_OBJECT (s), (FILE *) data[0]);
00695   fputc ('\n', (FILE *) data[0]);
00696   g_hash_table_insert (data[3], s, 
00697                        GUINT_TO_POINTER (++(*((guint *) data[1]))));
00698 }
00699 
00700 static void write_face (GtsTriangle * t, gpointer * data)
00701 {
00702   fprintf (data[0], "%u %u %u",
00703            GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e1)),
00704            GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e2)),
00705            GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e3)));
00706   if (GTS_OBJECT (t)->klass->write)
00707     (*GTS_OBJECT (t)->klass->write) (GTS_OBJECT (t), data[0]);
00708   fputc ('\n', data[0]);
00709 }
00710 
00738 void gts_surface_write (GtsSurface * s, FILE * fptr)
00739 {
00740   guint n;
00741   gpointer data[4];
00742   GHashTable * vindex, * eindex;
00743   GtsSurfaceStats stats;
00744 
00745   g_return_if_fail (s != NULL);
00746   g_return_if_fail (fptr != NULL);
00747 
00748   data[0] = fptr;
00749   data[1] = &n;
00750   data[2] = vindex = g_hash_table_new (NULL, NULL);
00751   data[3] = eindex = g_hash_table_new (NULL, NULL);
00752 
00753   gts_surface_stats (s, &stats);
00754   fprintf (fptr, "%u %u %u", 
00755            stats.edges_per_vertex.n, 
00756            stats.faces_per_edge.n, 
00757            stats.n_faces);
00758   if (GTS_OBJECT (s)->klass->write)
00759     (*GTS_OBJECT (s)->klass->write) (GTS_OBJECT (s), fptr);
00760   fputc ('\n', fptr);
00761   n = 0;
00762   gts_surface_foreach_vertex (s, (GtsFunc) write_vertex, data);
00763   n = 0;
00764   if (GTS_POINT_CLASS (s->vertex_class)->binary)
00765     fputc ('\n', fptr);
00766   gts_surface_foreach_edge (s, (GtsFunc) write_edge, data);
00767   gts_surface_foreach_face (s, (GtsFunc) write_face, data);
00768   g_hash_table_destroy (vindex);
00769   g_hash_table_destroy (eindex);
00770 }
00771 
00772 static void write_vertex_oogl (GtsPoint * p, gpointer * data)
00773 {
00774   FILE * fp = data[0];
00775 
00776   fprintf (fp, "%g %g %g", p->x, p->y, p->z);
00777   if (GTS_OBJECT (p)->klass->color) {
00778     GtsColor c = (* GTS_OBJECT (p)->klass->color) (GTS_OBJECT (p));
00779     fprintf (fp, " %g %g %g 1.0\n", c.r, c.g, c.b);
00780   }
00781   else
00782     fputc ('\n', fp);
00783   GTS_OBJECT (p)->reserved = GUINT_TO_POINTER ((*((guint *) data[1]))++);
00784 }
00785 
00786 static void write_face_oogl (GtsTriangle * t, FILE * fp)
00787 {
00788   GtsVertex * v1, * v2, * v3;
00789   gts_triangle_vertices (t, &v1, &v2, &v3);
00790   fprintf (fp, "3 %u %u %u",
00791            GPOINTER_TO_UINT (GTS_OBJECT (v1)->reserved),
00792            GPOINTER_TO_UINT (GTS_OBJECT (v2)->reserved),
00793            GPOINTER_TO_UINT (GTS_OBJECT (v3)->reserved));
00794   if (GTS_OBJECT (t)->klass->color) {
00795     GtsColor c = (* GTS_OBJECT (t)->klass->color) (GTS_OBJECT (t));
00796     fprintf (fp, " %g %g %g\n", c.r, c.g, c.b);
00797   }
00798   else
00799     fputc ('\n', fp);
00800 }
00801 
00809 void gts_surface_write_oogl (GtsSurface * s, FILE * fptr)
00810 {
00811   guint n = 0;
00812   gpointer data[2];
00813   GtsSurfaceStats stats;
00814 
00815   g_return_if_fail (s != NULL);
00816   g_return_if_fail (fptr != NULL);
00817 
00818   data[0] = fptr;
00819   data[1] = &n;
00820 
00821   gts_surface_stats (s, &stats);
00822   if (GTS_OBJECT_CLASS (s->vertex_class)->color)
00823     fputs ("COFF ", fptr);
00824   else
00825     fputs ("OFF ", fptr);
00826   fprintf (fptr, "%u %u %u\n", 
00827            stats.edges_per_vertex.n, 
00828            stats.n_faces,
00829            stats.faces_per_edge.n);
00830   gts_surface_foreach_vertex (s, (GtsFunc) write_vertex_oogl, data);
00831   gts_surface_foreach_face (s, (GtsFunc) write_face_oogl, fptr);
00832   gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL);
00833 }
00834 
00835 static void write_vertex_vtk (GtsPoint * p, gpointer * data)
00836 {
00837   FILE * fp = data[0];
00838 
00839   fprintf (fp, "%g %g %g\n", p->x, p->y, p->z);
00840   GTS_OBJECT (p)->reserved = GUINT_TO_POINTER ((*((guint *) data[1]))++);
00841 }
00842 
00843 static void write_face_vtk (GtsTriangle * t, FILE * fp)
00844 {
00845   GtsVertex * v1, * v2, * v3;
00846   gts_triangle_vertices (t, &v1, &v2, &v3);
00847   fprintf (fp, "3 %u %u %u\n",
00848            GPOINTER_TO_UINT (GTS_OBJECT (v1)->reserved),
00849            GPOINTER_TO_UINT (GTS_OBJECT (v2)->reserved),
00850            GPOINTER_TO_UINT (GTS_OBJECT (v3)->reserved));
00851 }
00852 
00860 void gts_surface_write_vtk (GtsSurface * s, FILE * fptr)
00861 {
00862   guint n = 0;
00863   gpointer data[2];
00864   GtsSurfaceStats stats;
00865 
00866   g_return_if_fail (s != NULL);
00867   g_return_if_fail (fptr != NULL);
00868 
00869   data[0] = fptr;
00870   data[1] = &n;
00871 
00872   gts_surface_stats (s, &stats);
00873   fprintf (fptr,
00874            "# vtk DataFile Version 2.0\n"
00875            "Generated by GTS\n"
00876            "ASCII\n"
00877            "DATASET POLYDATA\n"
00878            "POINTS %u float\n",
00879            stats.edges_per_vertex.n);
00880   gts_surface_foreach_vertex (s, (GtsFunc) write_vertex_vtk, data);
00881   fprintf (fptr,
00882            "POLYGONS %u %u\n",
00883            stats.n_faces, stats.n_faces*4);
00884   gts_surface_foreach_face (s, (GtsFunc) write_face_vtk, fptr);
00885   gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL);  
00886 }
00887 
00888 static void write_edge_oogl_boundary (GtsSegment * s, gpointer * data)
00889 {
00890   if (!gts_edge_is_boundary (GTS_EDGE (s), data[1]))
00891     return;
00892 
00893   if (GTS_OBJECT (s)->klass->color) {
00894     GtsColor c = (* GTS_OBJECT (s)->klass->color) (GTS_OBJECT (s));
00895     fprintf (data[0], "VECT 1 2 1 2 1 %g %g %g %g %g %g %g %g %g 1.\n",
00896              GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z,
00897              GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z,
00898              c.r, c.g, c.b);
00899   }
00900   else
00901     fprintf (data[0], "VECT 1 2 0 2 0 %g %g %g %g %g %g\n",
00902              GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z,
00903              GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z);
00904 }
00905 
00914 void gts_surface_write_oogl_boundary (GtsSurface * s, FILE * fptr)
00915 {
00916   gpointer data[2];
00917 
00918   g_return_if_fail (s != NULL);
00919   g_return_if_fail (fptr != NULL);
00920 
00921   data[0] = fptr;
00922   data[1] = s;
00923   fputs ("LIST {\n", fptr);
00924   gts_surface_foreach_edge (s, (GtsFunc) write_edge_oogl_boundary, data);
00925   fputs ("}\n", fptr);
00926 }
00927 
00928 #ifdef USE_SURFACE_BTREE
00929 static gint vertex_foreach_face (GtsTriangle * t,
00930                                  gpointer t_data,
00931                                  gpointer * info)
00932 #else /* not USE_SURFACE_BTREE */
00933 static void vertex_foreach_face (GtsTriangle * t,
00934                                  gpointer t_data,
00935                                  gpointer * info)
00936 #endif /* not USE_SURFACE_BTREE */
00937 {
00938   GHashTable * hash = info[0];
00939   gpointer data = info[1];
00940   GtsFunc func = (GtsFunc) info[2];
00941   GtsSegment 
00942     * s1 = GTS_SEGMENT (t->e1);
00943 
00944   if (!g_hash_table_lookup (hash, s1->v1)) {
00945     (*func) (s1->v1, data);
00946     g_hash_table_insert (hash, s1->v1, GINT_TO_POINTER (-1));
00947   }
00948   if (!g_hash_table_lookup (hash, s1->v2)) {
00949     (*func) (s1->v2, data);
00950     g_hash_table_insert (hash, s1->v2, GINT_TO_POINTER (-1));
00951   }
00952   if (!g_hash_table_lookup (hash, gts_triangle_vertex (t))) {
00953     (*func) (gts_triangle_vertex (t), data);
00954     g_hash_table_insert (hash, gts_triangle_vertex (t), 
00955                          GINT_TO_POINTER (-1));
00956   }
00957 #ifdef USE_SURFACE_BTREE
00958   return FALSE;
00959 #endif /* USE_SURFACE_BTREE */
00960 }
00961 
00970 void gts_surface_foreach_vertex (GtsSurface * s, GtsFunc func, gpointer data)
00971 {
00972   gpointer info[3];
00973 
00974   g_return_if_fail (s != NULL);
00975   g_return_if_fail (func != NULL);
00976 
00977   /* forbid removal of faces */
00978   s->keep_faces = TRUE;
00979   info[0] = g_hash_table_new (NULL, NULL);
00980   info[1] = data;
00981   info[2] = func;
00982 #ifdef USE_SURFACE_BTREE
00983   g_tree_traverse (s->faces, (GTraverseFunc) vertex_foreach_face, G_IN_ORDER,
00984                    info);
00985 #else /* not USE_SURFACE_BTREE */
00986   g_hash_table_foreach (s->faces, (GHFunc) vertex_foreach_face, info);
00987 #endif /* not USE_SURFACE_BTREE */
00988   g_hash_table_destroy (info[0]);
00989   /* allow removal of faces */
00990   s->keep_faces = FALSE;
00991 }
00992 
00993 #ifdef USE_SURFACE_BTREE
00994 static gint edge_foreach_face (GtsTriangle * t,
00995                                gpointer t_data, 
00996                                gpointer * info)
00997 #else /* not USE_SURFACE_BTREE */
00998 static void edge_foreach_face (GtsTriangle * t,
00999                                gpointer t_data, 
01000                                gpointer * info)
01001 #endif /* not USE_SURFACE_BTREE */
01002 {
01003   GHashTable * hash = info[0];
01004   gpointer data = info[1];
01005   GtsFunc func = (GtsFunc) info[2];
01006 
01007   if (!g_hash_table_lookup (hash, t->e1)) {
01008     (*func) (t->e1, data);
01009     g_hash_table_insert (hash, t->e1, GINT_TO_POINTER (-1));
01010   }
01011   if (!g_hash_table_lookup (hash, t->e2)) {
01012     (*func) (t->e2, data);
01013     g_hash_table_insert (hash, t->e2, GINT_TO_POINTER (-1));
01014   }
01015   if (!g_hash_table_lookup (hash, t->e3)) {
01016     (*func) (t->e3, data);
01017     g_hash_table_insert (hash, t->e3, GINT_TO_POINTER (-1));
01018   }
01019 #ifdef USE_SURFACE_BTREE
01020   return FALSE;
01021 #endif /* not USE_SURFACE_BTREE */
01022 }
01023 
01032 void gts_surface_foreach_edge (GtsSurface * s, GtsFunc func, gpointer data)
01033 {
01034   gpointer info[3];
01035 
01036   g_return_if_fail (s != NULL);
01037   g_return_if_fail (func != NULL);
01038   
01039   /* forbid removal of faces */
01040   s->keep_faces = TRUE;
01041   info[0] = g_hash_table_new (NULL, NULL);
01042   info[1] = data;
01043   info[2] = func;
01044 #ifdef USE_SURFACE_BTREE
01045   g_tree_traverse (s->faces, (GTraverseFunc) edge_foreach_face, G_IN_ORDER,
01046                    info);
01047 #else /* not USE_SURFACE_BTREE */
01048   g_hash_table_foreach (s->faces, (GHFunc) edge_foreach_face, info);
01049 #endif /* not USE_SURFACE_BTREE */
01050   g_hash_table_destroy (info[0]);
01051   /* allow removal of faces */
01052   s->keep_faces = FALSE;
01053 }
01054 
01055 #ifdef USE_SURFACE_BTREE
01056 static gint foreach_face (GtsFace * f, 
01057                           gpointer t_data,
01058                           gpointer * info)
01059 #else /* not USE_SURFACE_BTREE */
01060 static void foreach_face (GtsFace * f, 
01061                           gpointer t_data,
01062                           gpointer * info)
01063 #endif /* not USE_SURFACE_BTREE */
01064 {
01065   (*((GtsFunc) info[0])) (f, info[1]);
01066 #ifdef USE_SURFACE_BTREE
01067   return FALSE;
01068 #endif /* USE_SURFACE_BTREE */
01069 }
01070 
01079 void gts_surface_foreach_face (GtsSurface * s,
01080                                GtsFunc func, 
01081                                gpointer data)
01082 {
01083   gpointer info[2];
01084 
01085   g_return_if_fail (s != NULL);
01086   g_return_if_fail (func != NULL);
01087 
01088   /* forbid removal of faces */
01089   s->keep_faces = TRUE;
01090   info[0] = func;
01091   info[1] = data;
01092 #ifdef USE_SURFACE_BTREE
01093   g_tree_traverse (s->faces, (GTraverseFunc) foreach_face, G_IN_ORDER,
01094                    info);
01095 #else /* not USE_SURFACE_BTREE */
01096   g_hash_table_foreach (s->faces, (GHFunc) foreach_face, info);
01097 #endif /* not USE_SURFACE_BTREE */
01098   /* allow removal of faces */
01099   s->keep_faces = FALSE;
01100 }
01101 
01102 #ifdef USE_SURFACE_BTREE
01103 static gint foreach_face_remove (GtsFace * f,
01104                                  gpointer t_data,
01105                                  gpointer * info)
01106 {
01107   if ((*((GtsFunc) info[0])) (f, info[1])) {
01108     GtsSurface * s = info[2];
01109     guint * n = info[3];
01110 
01111     f->surfaces = g_slist_remove (f->surfaces, s);
01112     if (!GTS_OBJECT_DESTROYED (f) &&
01113         !gts_allow_floating_faces && 
01114         f->surfaces == NULL)
01115       gts_object_destroy (GTS_OBJECT (f));
01116     
01117     if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face)
01118       (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f);
01119 
01120     g_tree_remove (s->faces, f);
01121     (*n)++;
01122   }
01123   return FALSE;
01124 }
01125 #else /* not USE_SURFACE_BTREE */
01126 static gboolean foreach_face_remove (GtsFace * f,
01127                                      gpointer t_data,
01128                                      gpointer * info)
01129 {
01130   if ((*((GtsFunc) info[0])) (f, info[1])) {
01131     GtsSurface * s = info[2];
01132 
01133     f->surfaces = g_slist_remove (f->surfaces, s);
01134     if (!GTS_OBJECT_DESTROYED (f) &&
01135         !gts_allow_floating_faces && 
01136         f->surfaces == NULL)
01137       gts_object_destroy (GTS_OBJECT (f));
01138     
01139     if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face)
01140       (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f);
01141 
01142     return TRUE;
01143   }
01144   return FALSE;
01145 }
01146 #endif /* not USE_SURFACE_BTREE */
01147 
01161 guint gts_surface_foreach_face_remove (GtsSurface * s,
01162                                        GtsFunc func, 
01163                                        gpointer data)
01164 {
01165   gpointer info[4];
01166   guint n = 0;
01167 
01168   g_return_val_if_fail (s != NULL, 0);
01169   g_return_val_if_fail (func != NULL, 0);
01170 
01171   /* forbid removal of faces */
01172   s->keep_faces = TRUE;
01173   info[0] = func;
01174   info[1] = data;
01175   info[2] = s;
01176 #ifdef USE_SURFACE_BTREE
01177   info[3] = &n;
01178   g_tree_traverse (s->faces, (GTraverseFunc) foreach_face_remove, G_PRE_ORDER,
01179                    info);
01180 #else /* not USE_SURFACE_BTREE */
01181   n = g_hash_table_foreach_remove (s->faces, 
01182                                    (GHRFunc) foreach_face_remove, 
01183                                    info);
01184 #endif /* not USE_SURFACE_BTREE */
01185   /* allow removal of faces */
01186   s->keep_faces = FALSE;
01187   
01188   return n;
01189 }
01190 
01191 static void midvertex_insertion (GtsEdge * e,
01192                                  GtsSurface * surface,
01193                                  GtsEHeap * heap,
01194                                  GtsRefineFunc refine_func,
01195                                  gpointer refine_data,
01196                                  GtsVertexClass * vertex_class,
01197                                  GtsEdgeClass * edge_class)
01198 {
01199   GtsVertex * midvertex;
01200   GtsEdge * e1, * e2;
01201   GSList * i;
01202 
01203   midvertex = (*refine_func) (e, vertex_class, refine_data);
01204   e1 = gts_edge_new (edge_class, GTS_SEGMENT (e)->v1, midvertex);
01205   gts_eheap_insert (heap, e1);
01206   e2 = gts_edge_new (edge_class, GTS_SEGMENT (e)->v2, midvertex);
01207   gts_eheap_insert (heap, e2);
01208   
01209   /* creates new faces and modifies old ones */
01210   i = e->triangles;
01211   while (i) {
01212     GtsTriangle * t = i->data;
01213     GtsVertex * v1, * v2, * v3;
01214     GtsEdge * te2, * te3, * ne, * tmp;
01215 
01216     gts_triangle_vertices_edges (t, e, &v1, &v2, &v3, &e, &te2, &te3);
01217     ne = gts_edge_new (edge_class, midvertex, v3);
01218     gts_eheap_insert (heap, ne);
01219     if (GTS_SEGMENT (e1)->v1 == v2) {
01220       tmp = e1; e1 = e2; e2 = tmp;
01221     }
01222     e1->triangles = g_slist_prepend (e1->triangles, t);
01223     ne->triangles = g_slist_prepend (ne->triangles, t);
01224     te2->triangles = g_slist_remove (te2->triangles, t);
01225     t->e1 = e1; t->e2 = ne; t->e3 = te3;
01226     gts_surface_add_face (surface, 
01227                           gts_face_new (surface->face_class, e2, te2, ne));
01228     i = i->next;
01229   }
01230   /* destroys edge */
01231   g_slist_free (e->triangles);
01232   e->triangles = NULL;
01233   gts_object_destroy (GTS_OBJECT (e));
01234 }
01235 
01236 static gdouble edge_length2_inverse (GtsSegment * s)
01237 {
01238   return - gts_point_distance2 (GTS_POINT (s->v1), GTS_POINT (s->v2));
01239 }
01240 
01241 static void create_heap_refine (GtsEdge * e, GtsEHeap * heap)
01242 {
01243   gts_eheap_insert (heap, e);
01244 }
01245 
01267 void gts_surface_refine (GtsSurface * surface,
01268                          GtsKeyFunc cost_func,
01269                          gpointer cost_data,
01270                          GtsRefineFunc refine_func,
01271                          gpointer refine_data,
01272                          GtsStopFunc stop_func,
01273                          gpointer stop_data)
01274 {
01275   GtsEHeap * heap;
01276   GtsEdge * e;
01277   gdouble top_cost;
01278 
01279   g_return_if_fail (surface != NULL);
01280   g_return_if_fail (stop_func != NULL);
01281 
01282   if (cost_func == NULL)
01283     cost_func = (GtsKeyFunc) edge_length2_inverse;
01284   if (refine_func == NULL)
01285     refine_func = (GtsRefineFunc) gts_segment_midvertex;
01286 
01287   heap = gts_eheap_new (cost_func, cost_data);
01288   gts_eheap_freeze (heap);
01289   gts_surface_foreach_edge (surface, (GtsFunc) create_heap_refine, heap);
01290   gts_eheap_thaw (heap);
01291   while ((e = gts_eheap_remove_top (heap, &top_cost)) &&
01292          !(*stop_func) (top_cost,
01293                         gts_eheap_size (heap) + 
01294                         gts_edge_face_number (e, surface) + 2,
01295                         stop_data))
01296     midvertex_insertion (e, surface, heap, refine_func, refine_data,
01297                          surface->vertex_class, surface->edge_class);
01298   gts_eheap_destroy (heap);
01299 }
01300 
01301 static GSList * edge_triangles (GtsEdge * e1, GtsEdge * e)
01302 {
01303   GSList * i = e1->triangles;
01304   GSList * triangles = NULL;
01305   
01306   while (i) {
01307     GtsTriangle * t = i->data;
01308     if (t->e1 == e || t->e2 == e || t->e3 == e) {
01309       GtsEdge * e2;
01310       GSList * j;
01311       if (t->e1 == e) {
01312         if (t->e2 == e1)
01313           e2 = t->e3;
01314         else
01315           e2 = t->e2;
01316       }
01317       else if (t->e2 == e) {
01318         if (t->e3 == e1)
01319           e2 = t->e1;
01320         else
01321           e2 = t->e3;
01322       }
01323       else {
01324         if (t->e2 == e1)
01325           e2 = t->e1;
01326         else
01327           e2 = t->e2;
01328       }
01329       j = e2->triangles;
01330       while (j) {
01331         GtsTriangle * t = j->data;
01332         if (t->e1 != e && t->e2 != e && t->e3 != e)
01333           triangles = g_slist_prepend (triangles, t);
01334         j = j->next;
01335       }
01336     }
01337     else
01338       triangles = g_slist_prepend (triangles, t);
01339     i = i->next;
01340   }
01341   return triangles;
01342 }
01343 
01344 static void replace_vertex (GSList * i, GtsVertex * v1, GtsVertex * v)
01345 {
01346   while (i) {
01347     GtsSegment * s = i->data;
01348     if (s->v1 == v1)
01349       s->v1 = v;
01350     else
01351       s->v2 = v;
01352     i = i->next;
01353   }
01354 }
01355 
01367 gboolean gts_edge_collapse_creates_fold (GtsEdge * e, 
01368                                          GtsVertex * v,
01369                                          gdouble max)
01370 {
01371   GtsVertex * v1, * v2;
01372   GtsSegment * s;
01373   GSList * i;
01374   gboolean folded = FALSE;
01375 
01376   g_return_val_if_fail (e != NULL, TRUE);
01377   g_return_val_if_fail (v != NULL, TRUE);
01378 
01379   s = GTS_SEGMENT (e);
01380   v1 = s->v1;
01381   v2 = s->v2;
01382   replace_vertex (v1->segments, v1, v);
01383   replace_vertex (v2->segments, v2, v);
01384 
01385   i = v1->segments;
01386   while (i && !folded) {
01387     GtsSegment * s = i->data;
01388     if (GTS_IS_EDGE (s)) {
01389       GtsEdge * e1 = GTS_EDGE (s);
01390       if (e1 != e) {
01391         GSList * triangles = edge_triangles (e1, e);
01392         folded = gts_triangles_are_folded (triangles, s->v1, s->v2, max);
01393         g_slist_free (triangles);
01394       }
01395     }
01396     i = i->next;
01397   }
01398 
01399   i = v2->segments;
01400   while (i && !folded) {
01401     GtsSegment * s = i->data;
01402     if (GTS_IS_EDGE (s)) {
01403       GtsEdge * e1 = GTS_EDGE (s);
01404       if (e1 != e) {
01405         GSList * triangles = edge_triangles (e1, e);
01406         folded = gts_triangles_are_folded (triangles, s->v1, s->v2, max);
01407         g_slist_free (triangles);
01408       }
01409     }
01410     i = i->next;
01411   }
01412 #if 1
01413   if (!folded) {
01414     GSList * triangles = gts_vertex_triangles (v1, NULL);
01415     i = triangles = gts_vertex_triangles (v2, triangles);
01416     while (i && !folded) {
01417       GtsTriangle * t = i->data;
01418       if (t->e1 != e && t->e2 != e && t->e3 != e) {
01419         GtsEdge * e1 = gts_triangle_edge_opposite (t, v);
01420         g_assert (e1);
01421         folded = gts_triangles_are_folded (e1->triangles, 
01422                                            GTS_SEGMENT (e1)->v1,
01423                                            GTS_SEGMENT (e1)->v2,
01424                                            max);
01425       }
01426       i = i->next;
01427     }
01428     g_slist_free (triangles);
01429   }
01430 #endif
01431   replace_vertex (v1->segments, v, v1);
01432   replace_vertex (v2->segments, v, v2);
01433   return folded;
01434 }
01435 
01446 gboolean gts_edge_collapse_is_valid (GtsEdge * e)
01447 {
01448   GSList * i;
01449 
01450   g_return_val_if_fail (e != NULL, FALSE);
01451 
01452   i = GTS_SEGMENT (e)->v1->segments;
01453   while (i) {
01454     GtsEdge * e1 = i->data;
01455     if (e1 != e && GTS_IS_EDGE (e1)) {
01456       GtsEdge * e2 = NULL;
01457       GSList * j = GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v1 ? 
01458         GTS_SEGMENT (e1)->v2->segments : GTS_SEGMENT (e1)->v1->segments;
01459       while (j && !e2) {
01460         GtsEdge * e1 = j->data;
01461         if (GTS_IS_EDGE (e1) && 
01462             (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v2 || 
01463              GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e)->v2))
01464           e2 = e1;
01465         j = j->next;
01466       }
01467       if (e2 && !gts_triangle_use_edges (e, e1, e2))
01468         return FALSE;
01469     }
01470     i = i->next;
01471   }
01472 
01473   if (gts_edge_is_boundary (e, NULL)) {
01474     GtsTriangle * t = e->triangles->data;
01475     if (gts_edge_is_boundary (t->e1, NULL) &&
01476         gts_edge_is_boundary (t->e2, NULL) &&
01477         gts_edge_is_boundary (t->e3, NULL))
01478       return FALSE;
01479   }
01480   else {
01481     if (gts_vertex_is_boundary (GTS_SEGMENT (e)->v1, NULL) &&
01482         gts_vertex_is_boundary (GTS_SEGMENT (e)->v2, NULL))
01483       return FALSE;    
01484     if (gts_edge_belongs_to_tetrahedron (e))
01485       return FALSE;
01486   }
01487 
01488   return TRUE;
01489 }
01490 
01491 #define HEAP_INSERT_EDGE(h, e) (GTS_OBJECT (e)->reserved = gts_eheap_insert (h, e))
01492 #define HEAP_REMOVE_EDGE(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\
01493                                 GTS_OBJECT (e)->reserved = NULL)
01494 
01495 static GtsVertex * edge_collapse (GtsEdge * e,
01496                                   GtsEHeap * heap,
01497                                   GtsCoarsenFunc coarsen_func,
01498                                   gpointer coarsen_data,
01499                                   GtsVertexClass * klass,
01500                                   gdouble maxcosine2)
01501 {
01502   GSList * i;
01503   GtsVertex  * v1 = GTS_SEGMENT (e)->v1, * v2 = GTS_SEGMENT (e)->v2, * mid;
01504 
01505   /* if the edge is degenerate (i.e. v1 == v2), destroy and return */
01506   if (v1 == v2) {
01507     gts_object_destroy (GTS_OBJECT (e));
01508     return NULL;
01509   }
01510 
01511   if (!gts_edge_collapse_is_valid (e)) {
01512     GTS_OBJECT (e)->reserved = 
01513       gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE);
01514     return NULL;
01515   }
01516 
01517   mid = (*coarsen_func) (e, klass, coarsen_data);
01518 
01519   if (gts_edge_collapse_creates_fold (e, mid, maxcosine2)) {
01520     GTS_OBJECT (e)->reserved = 
01521       gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE);
01522     gts_object_destroy (GTS_OBJECT (mid));
01523     return NULL;
01524   }
01525 
01526   gts_object_destroy (GTS_OBJECT (e));
01527 
01528   gts_vertex_replace (v1, mid);
01529   gts_object_destroy (GTS_OBJECT (v1));
01530   gts_vertex_replace (v2, mid);
01531   gts_object_destroy (GTS_OBJECT (v2));
01532 
01533   /* destroy duplicate edges */
01534   i = mid->segments;
01535   while (i) {
01536     GtsEdge * e1 = i->data;
01537     GtsEdge * duplicate;
01538     while ((duplicate = gts_edge_is_duplicate (e1))) {
01539       gts_edge_replace (duplicate, GTS_EDGE (e1));
01540       HEAP_REMOVE_EDGE (heap, duplicate);
01541       gts_object_destroy (GTS_OBJECT (duplicate));
01542     }
01543     i = i->next;
01544     if (!e1->triangles) {
01545       /* e1 is the result of the collapse of one edge of a pair of identical
01546          faces (it should not happen unless duplicate triangles are present in
01547          the initial surface) */
01548       g_warning ("file %s: line %d (%s): probably duplicate triangle.",
01549                  __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION);
01550       HEAP_REMOVE_EDGE (heap, e1);
01551       gts_object_destroy (GTS_OBJECT (e1));
01552       if (i == NULL) /* mid has been destroyed */
01553         mid = NULL;
01554     }
01555   }
01556 
01557   return mid;
01558 }
01559 
01560 /*
01561  * I don't see where this code is ever used, but keep it for a bit 
01562  * in case it is needed for debugging
01563  */
01564 #ifdef GTS_NEED_UPDATE_CLOSEST_NEIGHBORS
01565 static void update_closest_neighbors (GtsVertex * v, GtsEHeap * heap)
01566 {
01567   GSList * i = v->segments;
01568   
01569   while (i) {
01570     GtsSegment * s = i->data;
01571     if (GTS_IS_EDGE (s)) {
01572       HEAP_REMOVE_EDGE (heap, GTS_EDGE (s));
01573       HEAP_INSERT_EDGE (heap, GTS_EDGE (s));
01574     }
01575     i = i->next;
01576   }
01577 }
01578 #endif
01579 
01580 static void update_2nd_closest_neighbors (GtsVertex * v, GtsEHeap * heap)
01581 {
01582   GSList * i = v->segments;
01583   GSList * list = NULL;
01584   
01585   while (i) {
01586     GtsSegment * s = i->data;
01587     if (GTS_IS_EDGE (s)) {
01588       GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1;
01589       GSList * j = v1->segments;
01590       while (j) {
01591         GtsSegment * s1 = j->data;
01592         if (GTS_IS_EDGE (s1) && !g_slist_find (list, s1))
01593           list = g_slist_prepend (list, s1);
01594         j = j->next;
01595       }
01596     }
01597     i = i->next;
01598   }
01599 
01600   i = list;
01601   while (i) {
01602     GtsEdge * e = i->data;
01603     HEAP_REMOVE_EDGE (heap, e);
01604     HEAP_INSERT_EDGE (heap, e);
01605     i = i->next;
01606   }
01607 
01608   g_slist_free (list);
01609 }
01610 
01611 static gdouble edge_length2 (GtsEdge * e)
01612 {
01613   return gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), 
01614                               GTS_POINT (GTS_SEGMENT (e)->v2));
01615 }
01616 
01617 static void create_heap_coarsen (GtsEdge * e, GtsEHeap * heap)
01618 {
01619   HEAP_INSERT_EDGE (heap, e);
01620 }
01621 
01646 void gts_surface_coarsen (GtsSurface * surface,
01647                           GtsKeyFunc cost_func,
01648                           gpointer cost_data,
01649                           GtsCoarsenFunc coarsen_func,
01650                           gpointer coarsen_data,
01651                           GtsStopFunc stop_func,
01652                           gpointer stop_data,
01653                           gdouble minangle)
01654 {
01655   GtsEHeap * heap;
01656   GtsEdge * e;
01657   gdouble top_cost;
01658   gdouble maxcosine2;
01659 
01660   g_return_if_fail (surface != NULL);
01661   g_return_if_fail (stop_func != NULL);
01662 
01663   if (cost_func == NULL)
01664     cost_func = (GtsKeyFunc) edge_length2;
01665   if (coarsen_func == NULL)
01666     coarsen_func = (GtsCoarsenFunc) gts_segment_midvertex;
01667 
01668   heap = gts_eheap_new (cost_func, cost_data);
01669   maxcosine2 = cos (minangle); maxcosine2 *= maxcosine2;
01670 
01671   gts_eheap_freeze (heap);
01672   gts_surface_foreach_edge (surface, (GtsFunc) create_heap_coarsen, heap);
01673   gts_eheap_thaw (heap);
01674   /* we want to control edge destruction manually */
01675   gts_allow_floating_edges = TRUE;
01676   while ((e = gts_eheap_remove_top (heap, &top_cost)) &&
01677          (top_cost < G_MAXDOUBLE) &&
01678          !(*stop_func) (top_cost, gts_eheap_size (heap) - 
01679                         gts_edge_face_number (e, surface), stop_data))
01680     {
01681       GtsVertex * v = edge_collapse (e, heap, coarsen_func, coarsen_data,
01682                                      surface->vertex_class, maxcosine2);
01683       if (v != NULL)
01684         update_2nd_closest_neighbors (v, heap);
01685     }
01686   gts_allow_floating_edges = FALSE;
01687 
01688   /* set reserved field of remaining edges back to NULL */
01689   if (e) GTS_OBJECT (e)->reserved = NULL;
01690   gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL);
01691 
01692   gts_eheap_destroy (heap);
01693 }
01694 
01708 gboolean gts_coarsen_stop_number (gdouble cost, 
01709                                   guint nedge, 
01710                                   guint * min_number)
01711 {
01712   g_return_val_if_fail (min_number != NULL, TRUE);
01713 
01714   if (nedge < *min_number)
01715     return TRUE;
01716   return FALSE;
01717 }
01718 
01731 gboolean gts_coarsen_stop_cost (gdouble cost, 
01732                                 guint nedge, 
01733                                 gdouble * max_cost)
01734 {
01735   g_return_val_if_fail (max_cost != NULL, TRUE);
01736 
01737   if (cost > *max_cost)
01738     return TRUE;
01739   return FALSE;
01740 }
01741 
01742 #define GTS_M_ICOSAHEDRON_X /* sqrt(sqrt(5)+1)/sqrt(2*sqrt(5)) */ \
01743   0.850650808352039932181540497063011072240401406
01744 #define GTS_M_ICOSAHEDRON_Y /* sqrt(2)/sqrt(5+sqrt(5))         */ \
01745   0.525731112119133606025669084847876607285497935
01746 #define GTS_M_ICOSAHEDRON_Z 0.0
01747 
01748 static guint generate_icosahedron (GtsSurface * s)
01749 {
01750   GtsVertex * v01 = gts_vertex_new (s->vertex_class,
01751       +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y);
01752   GtsVertex * v02 = gts_vertex_new (s->vertex_class,
01753       +GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z);
01754   GtsVertex * v03 = gts_vertex_new (s->vertex_class,
01755       +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X);
01756   GtsVertex * v04 = gts_vertex_new (s->vertex_class,
01757       +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X);
01758   GtsVertex * v05 = gts_vertex_new (s->vertex_class,
01759       +GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z);
01760   GtsVertex * v06 = gts_vertex_new (s->vertex_class,
01761       +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y);
01762   GtsVertex * v07 = gts_vertex_new (s->vertex_class,
01763       -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X);
01764   GtsVertex * v08 = gts_vertex_new (s->vertex_class,
01765       +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y);
01766   GtsVertex * v09 = gts_vertex_new (s->vertex_class,
01767       -GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z);
01768   GtsVertex * v10 = gts_vertex_new (s->vertex_class,
01769       -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X);
01770   GtsVertex * v11 = gts_vertex_new (s->vertex_class,
01771       -GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z);
01772   GtsVertex * v12 = gts_vertex_new (s->vertex_class,
01773       +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y);
01774 
01775   GtsEdge * e01 = gts_edge_new (s->edge_class, v01, v02);
01776   GtsEdge * e02 = gts_edge_new (s->edge_class, v03, v02);
01777   GtsEdge * e03 = gts_edge_new (s->edge_class, v01, v03);
01778   GtsEdge * e04 = gts_edge_new (s->edge_class, v04, v05);
01779   GtsEdge * e05 = gts_edge_new (s->edge_class, v02, v05);
01780   GtsEdge * e06 = gts_edge_new (s->edge_class, v04, v02);
01781   GtsEdge * e07 = gts_edge_new (s->edge_class, v06, v07);
01782   GtsEdge * e08 = gts_edge_new (s->edge_class, v04, v07);
01783   GtsEdge * e09 = gts_edge_new (s->edge_class, v06, v04);
01784   GtsEdge * e10 = gts_edge_new (s->edge_class, v08, v03);
01785   GtsEdge * e11 = gts_edge_new (s->edge_class, v03, v05);
01786   GtsEdge * e12 = gts_edge_new (s->edge_class, v08, v05);
01787   GtsEdge * e13 = gts_edge_new (s->edge_class, v06, v09);
01788   GtsEdge * e14 = gts_edge_new (s->edge_class, v07, v09);
01789   GtsEdge * e15 = gts_edge_new (s->edge_class, v08, v10);
01790   GtsEdge * e16 = gts_edge_new (s->edge_class, v03, v10);
01791   GtsEdge * e17 = gts_edge_new (s->edge_class, v06, v01);
01792   GtsEdge * e18 = gts_edge_new (s->edge_class, v01, v09);
01793   GtsEdge * e19 = gts_edge_new (s->edge_class, v08, v11);
01794   GtsEdge * e20 = gts_edge_new (s->edge_class, v10, v11);
01795   GtsEdge * e21 = gts_edge_new (s->edge_class, v06, v02);
01796   GtsEdge * e22 = gts_edge_new (s->edge_class, v12, v11);
01797   GtsEdge * e23 = gts_edge_new (s->edge_class, v12, v08);
01798   GtsEdge * e24 = gts_edge_new (s->edge_class, v12, v07);
01799   GtsEdge * e25 = gts_edge_new (s->edge_class, v07, v11);
01800   GtsEdge * e26 = gts_edge_new (s->edge_class, v12, v04);
01801   GtsEdge * e27 = gts_edge_new (s->edge_class, v09, v11);
01802   GtsEdge * e28 = gts_edge_new (s->edge_class, v10, v09);
01803   GtsEdge * e29 = gts_edge_new (s->edge_class, v12, v05);
01804   GtsEdge * e30 = gts_edge_new (s->edge_class, v01, v10);
01805   
01806   gts_surface_add_face (s, gts_face_new (s->face_class, e01, e02, e03));
01807   gts_surface_add_face (s, gts_face_new (s->face_class, e04, e05, e06));
01808   gts_surface_add_face (s, gts_face_new (s->face_class, e07, e08, e09));
01809   gts_surface_add_face (s, gts_face_new (s->face_class, e10, e11, e12));
01810   gts_surface_add_face (s, gts_face_new (s->face_class, e13, e14, e07));
01811   gts_surface_add_face (s, gts_face_new (s->face_class, e15, e16, e10));
01812   gts_surface_add_face (s, gts_face_new (s->face_class, e17, e18, e13));
01813   gts_surface_add_face (s, gts_face_new (s->face_class, e19, e20, e15));
01814   gts_surface_add_face (s, gts_face_new (s->face_class, e21, e01, e17));
01815   gts_surface_add_face (s, gts_face_new (s->face_class, e22, e19, e23));
01816   gts_surface_add_face (s, gts_face_new (s->face_class, e09, e06, e21));
01817   gts_surface_add_face (s, gts_face_new (s->face_class, e24, e25, e22));
01818   gts_surface_add_face (s, gts_face_new (s->face_class, e26, e08, e24));
01819   gts_surface_add_face (s, gts_face_new (s->face_class, e20, e27, e28));
01820   gts_surface_add_face (s, gts_face_new (s->face_class, e29, e04, e26));
01821   gts_surface_add_face (s, gts_face_new (s->face_class, e14, e27, e25));
01822   gts_surface_add_face (s, gts_face_new (s->face_class, e23, e12, e29));
01823   gts_surface_add_face (s, gts_face_new (s->face_class, e02, e05, e11));
01824   gts_surface_add_face (s, gts_face_new (s->face_class, e30, e28, e18));
01825   gts_surface_add_face (s, gts_face_new (s->face_class, e03, e16, e30));
01826 
01827   return 0;
01828 }
01829 
01830 static GtsVertex * unit_sphere_arc_midvertex (GtsSegment * s, 
01831                                               GtsVertexClass * vertex_class)
01832 {
01833   GtsPoint * p1, * p2;
01834   gdouble x, y, z, norm;
01835 
01836   p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2);
01837 
01838   x = 0.5*(p1->x + p2->x);
01839   y = 0.5*(p1->y + p2->y);
01840   z = 0.5*(p1->z + p2->z);
01841 
01842   norm = x*x + y*y + z*z;
01843   norm = sqrt (norm);
01844 
01845   x /= norm; y /= norm; z /= norm;
01846 
01847   return gts_vertex_new (vertex_class, x, y, z);
01848 }
01849 
01850 static void tessellate_face (GtsFace * f,
01851                              GtsSurface * s,
01852                              GtsRefineFunc refine_func,
01853                              gpointer refine_data,
01854                              GtsVertexClass * vertex_class,
01855                              GtsEdgeClass * edge_class)
01856 {
01857   GtsTriangle * t;
01858   GtsEdge * e1, * e2, * e3;                          /* former edges     */
01859   GtsVertex * v1, * v2, * v3;                        /* initial vertices */
01860   GtsVertex * v4, * v5, * v6;                        /* new vertices     */ 
01861   GtsEdge * e56, * e64, * e45;                       /* new inside edges */
01862   GtsEdge * e24, * e34, * e35, * e15, * e16, * e26;  /* new border edges */
01863   GSList * dum;
01864   GtsEdge * edum;
01865   
01866   t = GTS_TRIANGLE (f);
01867   e1 = t->e1; e2 = t->e2; e3 = t->e3;
01868 
01869   if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) {
01870     v1 = GTS_SEGMENT (e2)->v2;
01871     v2 = GTS_SEGMENT (e1)->v1;
01872     v3 = GTS_SEGMENT (e1)->v2;
01873   }
01874   else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) {
01875     v1 = GTS_SEGMENT (e2)->v1;
01876     v2 = GTS_SEGMENT (e1)->v1;
01877     v3 = GTS_SEGMENT (e1)->v2;
01878   }
01879   else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) {
01880     v1 = GTS_SEGMENT (e2)->v2;
01881     v2 = GTS_SEGMENT (e1)->v2;
01882     v3 = GTS_SEGMENT (e1)->v1;
01883   }
01884   else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2) {
01885     v1 = GTS_SEGMENT (e2)->v1;
01886     v2 = GTS_SEGMENT (e1)->v2;
01887     v3 = GTS_SEGMENT (e1)->v1;
01888   }
01889   else {
01890     v1 = v2 = v3 = NULL;
01891     g_assert_not_reached ();
01892   }
01893 
01894   e1->triangles = g_slist_remove (e1->triangles, t);
01895   e2->triangles = g_slist_remove (e2->triangles, t);
01896   e3->triangles = g_slist_remove (e3->triangles, t);
01897   
01898   if (GTS_OBJECT (e1)->reserved) {
01899     dum = (GTS_OBJECT (e1)->reserved);
01900     e24 = dum->data;
01901     e34 = dum->next->data;
01902     v4 = GTS_SEGMENT (e24)->v2;
01903     if (GTS_SEGMENT (e24)->v1 == v3) {
01904       edum = e34; e34 = e24; e24 = edum;
01905     }
01906   }
01907   else {
01908     v4 = (*refine_func) (e1, vertex_class, refine_data);
01909     e24 = gts_edge_new (edge_class, v2, v4);
01910     e34 = gts_edge_new (edge_class, v3, v4);
01911     dum = g_slist_append (NULL, e24);
01912     dum = g_slist_append (dum,  e34);
01913     GTS_OBJECT (e1)->reserved = dum;
01914   }
01915   if (GTS_OBJECT (e2)->reserved) {
01916     dum = (GTS_OBJECT (e2)->reserved);
01917     e35 = dum->data;
01918     e15 = dum->next->data;
01919     v5 = GTS_SEGMENT (e35)->v2;
01920     if (GTS_SEGMENT (e35)->v1 == v1) {
01921       edum = e15; e15 = e35; e35 = edum;
01922     }
01923   }
01924   else {
01925     v5 = (*refine_func) (e2, vertex_class, refine_data);
01926     e35 = gts_edge_new (edge_class, v3, v5);
01927     e15 = gts_edge_new (edge_class, v1, v5);
01928     dum = g_slist_append (NULL, e35);
01929     dum = g_slist_append (dum,  e15);
01930     GTS_OBJECT (e2)->reserved = dum;
01931   }
01932   if (GTS_OBJECT (e3)->reserved) {
01933     dum = (GTS_OBJECT (e3)->reserved);
01934     e16 = dum->data;
01935     e26 = dum->next->data;
01936     v6 = GTS_SEGMENT (e16)->v2;
01937     if (GTS_SEGMENT (e16)->v1 == v2) {
01938       edum = e16; e16 = e26; e26 = edum;
01939     }
01940   }
01941   else {
01942     v6 = (*refine_func) (e3, vertex_class, refine_data);
01943     e16 = gts_edge_new (edge_class, v1, v6);
01944     e26 = gts_edge_new (edge_class, v2, v6);
01945     dum = g_slist_append (NULL, e16);
01946     dum = g_slist_append (dum,  e26);
01947     GTS_OBJECT (e3)->reserved = dum;
01948   }
01949   
01950   if (e1->triangles == NULL) {
01951     g_slist_free (GTS_OBJECT (e1)->reserved);
01952     GTS_OBJECT (e1)->reserved = NULL;
01953     gts_object_destroy (GTS_OBJECT (e1));
01954     e1 = NULL;
01955   }
01956   if (e2->triangles == NULL) {
01957     g_slist_free (GTS_OBJECT (e2)->reserved);
01958     GTS_OBJECT (e2)->reserved = NULL;
01959     gts_object_destroy (GTS_OBJECT (e2));
01960     e2 = NULL;
01961   }
01962   if (e3->triangles == NULL) {
01963     g_slist_free (GTS_OBJECT (e3)->reserved);
01964     GTS_OBJECT (e3)->reserved = NULL;
01965     gts_object_destroy (GTS_OBJECT (e3));
01966     e3 = NULL;
01967   }
01968 
01969   e56 = gts_edge_new (edge_class, v5, v6);
01970   e64 = gts_edge_new (edge_class, v6, v4);
01971   e45 = gts_edge_new (edge_class, v4, v5);
01972   t->e1 = e56; e56->triangles = g_slist_prepend (e56->triangles, t);
01973   t->e2 = e64; e64->triangles = g_slist_prepend (e64->triangles, t);
01974   t->e3 = e45; e45->triangles = g_slist_prepend (e45->triangles, t);
01975   
01976   gts_surface_add_face (s, gts_face_new (s->face_class, e16, e56, e15));
01977   gts_surface_add_face (s, gts_face_new (s->face_class, e26, e24, e64));
01978   gts_surface_add_face (s, gts_face_new (s->face_class, e45, e34, e35)); 
01979 }
01980 
01981 static void create_array_tessellate (GtsFace * f, GPtrArray * array)
01982 {
01983   g_ptr_array_add (array, f);
01984 }
01985 
02002 void gts_surface_tessellate (GtsSurface * s,
02003                              GtsRefineFunc refine_func,
02004                              gpointer refine_data)
02005 {
02006   GPtrArray * array;
02007   guint i;
02008 
02009   g_return_if_fail (s != NULL);
02010   
02011   if (refine_func == NULL) /* tessellate_surface == geodesate_surface */
02012     refine_func = (GtsRefineFunc) unit_sphere_arc_midvertex;
02013 
02014   array = g_ptr_array_new ();
02015   gts_surface_foreach_face (s, (GtsFunc) create_array_tessellate, array);
02016   for(i = 0; i < array->len; i++)
02017     tessellate_face (g_ptr_array_index (array, i),
02018                      s, refine_func, refine_data, 
02019                      s->vertex_class, s->edge_class);
02020   g_ptr_array_free (array, TRUE);
02021 }
02022 
02035 GtsSurface * gts_surface_generate_sphere (GtsSurface * s, 
02036                                           guint geodesation_order)
02037 {
02038   guint cgo; 
02039 
02040   g_return_val_if_fail (s != NULL, NULL);
02041   g_return_val_if_fail (geodesation_order != 0, NULL);
02042 
02043   generate_icosahedron (s);
02044 
02045   for (cgo = 1; cgo < geodesation_order; cgo++)
02046     gts_surface_tessellate (s, NULL, NULL);
02047   
02048   return s;
02049 }
02050 
02051 static void foreach_vertex_copy (GtsPoint * p, GtsVertexClass * klass)
02052 {
02053   GTS_OBJECT (p)->reserved = gts_vertex_new (klass, p->x, p->y, p->z);
02054 }
02055 
02056 static void foreach_edge_copy (GtsSegment * s, GtsEdgeClass * klass)
02057 {
02058   GTS_OBJECT (s)->reserved = gts_edge_new (klass,
02059                                            GTS_OBJECT (s->v1)->reserved, 
02060                                            GTS_OBJECT (s->v2)->reserved);
02061 }
02062 
02063 static void foreach_face_copy (GtsTriangle * t,
02064                                GtsSurface * s)
02065 {
02066   gts_surface_add_face (s, gts_face_new (s->face_class,
02067                                          GTS_OBJECT (t->e1)->reserved,
02068                                          GTS_OBJECT (t->e2)->reserved,
02069                                          GTS_OBJECT (t->e3)->reserved));
02070 }
02071 
02081 GtsSurface * gts_surface_copy (GtsSurface * s1, GtsSurface * s2)
02082 {
02083   g_return_val_if_fail (s1 != NULL, NULL);
02084   g_return_val_if_fail (s2 != NULL, NULL);
02085   
02086   gts_surface_foreach_vertex (s2, (GtsFunc) foreach_vertex_copy, 
02087                               s1->vertex_class);
02088   gts_surface_foreach_edge (s2, (GtsFunc) foreach_edge_copy, s1->edge_class);
02089   gts_surface_foreach_face (s2, (GtsFunc) foreach_face_copy, s1);
02090 
02091   gts_surface_foreach_vertex (s2, (GtsFunc) gts_object_reset_reserved, NULL);
02092   gts_surface_foreach_edge (s2, (GtsFunc) gts_object_reset_reserved, NULL);
02093   
02094   return s1;
02095 }
02096 
02097 static void merge_foreach_face (GtsFace * f, 
02098                                 GtsSurface * s)
02099 {
02100   gts_surface_add_face (s, f);
02101 }
02102 
02111 void gts_surface_merge (GtsSurface * s, GtsSurface * with)
02112 {
02113   g_return_if_fail (s != NULL);
02114   g_return_if_fail (with != NULL);
02115   
02116   gts_surface_foreach_face (with, (GtsFunc) merge_foreach_face, s);
02117 }
02118 
02119 static void manifold_foreach_edge (GtsEdge * e, gpointer * data)
02120 {
02121   gboolean * is_manifold = data[0];
02122 
02123   if (*is_manifold) {
02124     if (gts_edge_face_number (e, data[1]) > 2)
02125       *is_manifold = FALSE;
02126   }
02127 }
02128 
02135 gboolean gts_surface_is_manifold (GtsSurface * s)
02136 {
02137   gboolean is_manifold = TRUE;
02138   gpointer data[2];
02139 
02140   g_return_val_if_fail (s != NULL, FALSE);
02141 
02142   data[0] = &is_manifold;
02143   data[1] = s;
02144   gts_surface_foreach_edge (s, (GtsFunc) manifold_foreach_edge, data);
02145   return is_manifold;
02146 }
02147 
02148 static void closed_foreach_edge (GtsEdge * e, gpointer * data)
02149 {
02150   gboolean * is_closed = data[0];
02151 
02152   if (*is_closed) {
02153     if (gts_edge_face_number (e, data[1]) != 2)
02154       *is_closed = FALSE;
02155   }
02156 }
02157 
02165 gboolean gts_surface_is_closed (GtsSurface * s)
02166 {
02167   gboolean is_closed = TRUE;
02168   gpointer data[2];
02169 
02170   g_return_val_if_fail (s != NULL, FALSE);
02171 
02172   data[0] = &is_closed;
02173   data[1] = s;
02174   gts_surface_foreach_edge (s, (GtsFunc) closed_foreach_edge, data);
02175   return is_closed;
02176 }
02177 
02178 static void orientable_foreach_edge (GtsEdge * e, gpointer * data)
02179 {
02180   gboolean * is_orientable = data[0];
02181 
02182   if (*is_orientable) {
02183     GtsSurface * surface = data[1];
02184     GtsFace * f1 = NULL, * f2 = NULL;
02185     GSList * i = e->triangles;
02186     while (i && *is_orientable) {
02187       GtsFace * f = i->data;
02188       if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, surface)) {
02189         if (!f1) f1 = f;
02190         else if (!f2) f2 = f;
02191         else *is_orientable = FALSE;
02192       }
02193       i = i->next;
02194     }
02195     if (f1 && f2 && !gts_triangles_are_compatible (GTS_TRIANGLE (f1), 
02196                                                    GTS_TRIANGLE (f2), e))
02197       *is_orientable = FALSE;
02198   }
02199 }
02200 
02209 gboolean gts_surface_is_orientable (GtsSurface * s)
02210 {
02211   gboolean is_orientable = TRUE;
02212   gpointer data[2];
02213 
02214   g_return_val_if_fail (s != NULL, FALSE);
02215 
02216   data[0] = &is_orientable;
02217   data[1] = s;
02218   gts_surface_foreach_edge (s, (GtsFunc) orientable_foreach_edge, data);
02219   return is_orientable;
02220 }
02221 
02222 static void volume_foreach_face (GtsTriangle * t,
02223                                  gdouble * volume)
02224 {
02225   GtsVertex * va, * vb, * vc;
02226   GtsPoint * pa, * pb, * pc;
02227 
02228   gts_triangle_vertices (t, &va, &vb, &vc);
02229   pa = GTS_POINT (va);
02230   pb = GTS_POINT (vb);
02231   pc = GTS_POINT (vc);
02232   
02233   *volume += (pa->x * (pb->y * pc->z - pb->z * pc->y) +
02234               pb->x * (pc->y * pa->z - pc->z * pa->y) +
02235               pc->x * (pa->y * pb->z - pa->z * pb->y));
02236 }
02237 
02245 gdouble gts_surface_volume (GtsSurface * s)
02246 {
02247   gdouble volume = 0.0;
02248 
02249   g_return_val_if_fail (s != NULL, 0.0);
02250 
02251   gts_surface_foreach_face (s, (GtsFunc) volume_foreach_face, &volume);
02252 
02253   return volume/6.;
02254 }
02255 
02256 static void center_of_mass_foreach_face (GtsTriangle * t,
02257                                          gpointer * data)
02258 {
02259   GtsVertex * v1, * v2, * v3;
02260   GtsPoint * p1, * p2, * p3;
02261   gdouble x1, y1, z1, x2, y2, z2, nx, ny, nz;
02262   gdouble * volume = data[0];
02263   gdouble * cm = data[1];
02264 
02265   gts_triangle_vertices (t, &v1, &v2, &v3);
02266   p1 = GTS_POINT (v1);
02267   p2 = GTS_POINT (v2);
02268   p3 = GTS_POINT (v3);
02269 
02270   x1 = p2->x - p1->x;
02271   y1 = p2->y - p1->y;
02272   z1 = p2->z - p1->z;
02273 
02274   x2 = p3->x - p1->x;
02275   y2 = p3->y - p1->y;
02276   z2 = p3->z - p1->z;
02277   
02278   nx = y1*z2 - z1*y2;
02279   ny = z1*x2 - x1*z2;
02280   nz = x1*y2 - y1*x2;
02281 
02282   cm[0] += nx*(p1->x*p1->x + p2->x*p2->x + p3->x*p3->x + 
02283                p1->x*p2->x + p1->x*p3->x + p2->x*p3->x);
02284   cm[1] += ny*(p1->y*p1->y + p2->y*p2->y + p3->y*p3->y + 
02285                p1->y*p2->y + p1->y*p3->y + p2->y*p3->y);
02286   cm[2] += nz*(p1->z*p1->z + p2->z*p2->z + p3->z*p3->z + 
02287                p1->z*p2->z + p1->z*p3->z + p2->z*p3->z);
02288 
02289   *volume += nx*(p1->x + p2->x + p3->x);
02290 }
02291 
02292 
02302 gdouble gts_surface_center_of_mass (GtsSurface * s,
02303                                     GtsVector cm)
02304 {
02305   gdouble volume = 0.;
02306   gpointer data[2];
02307 
02308   g_return_val_if_fail (s != NULL, 0.0);
02309 
02310   data[0] = &volume;
02311   data[1] = &(cm[0]);
02312   cm[0] = cm[1] = cm[2] = 0.;
02313   gts_surface_foreach_face (s, (GtsFunc) center_of_mass_foreach_face, data);
02314   
02315   if (volume != 0.) {
02316     cm[0] /= 4.*volume;
02317     cm[1] /= 4.*volume;
02318     cm[2] /= 4.*volume;
02319   }
02320 
02321   return volume/6.;
02322 }
02323 
02324 static void center_of_area_foreach_face (GtsTriangle * t,
02325                                          gpointer * data)
02326 {
02327   GtsVertex * v1, * v2, * v3;
02328   GtsPoint * p1, * p2, * p3;
02329   gdouble a;
02330   gdouble * area = data[0];
02331   gdouble * cm = data[1];
02332 
02333   gts_triangle_vertices (t, &v1, &v2, &v3);
02334   p1 = GTS_POINT (v1);
02335   p2 = GTS_POINT (v2);
02336   p3 = GTS_POINT (v3);
02337 
02338   a = gts_triangle_area (t);
02339   cm[0] += a*(p1->x + p2->x + p3->x);
02340   cm[1] += a*(p1->y + p2->y + p3->y);
02341   cm[2] += a*(p1->z + p2->z + p3->z);
02342   *area += a;
02343 }
02344 
02345 
02355 gdouble gts_surface_center_of_area (GtsSurface * s,
02356                                     GtsVector cm)
02357 {
02358   gdouble area = 0.;
02359   gpointer data[2];
02360 
02361   g_return_val_if_fail (s != NULL, 0.0);
02362 
02363   data[0] = &area;
02364   data[1] = &(cm[0]);
02365   cm[0] = cm[1] = cm[2] = 0.;
02366   gts_surface_foreach_face (s, (GtsFunc) center_of_area_foreach_face, data);
02367   
02368   if (area != 0.) {
02369     cm[0] /= 3.*area;
02370     cm[1] /= 3.*area;
02371     cm[2] /= 3.*area;
02372   }
02373 
02374   return area;
02375 }
02376 
02377 static void number_foreach (gpointer data, guint * n)
02378 {
02379   (*n)++;
02380 }
02381 
02388 guint gts_surface_vertex_number (GtsSurface * s)
02389 {
02390   guint n = 0;
02391 
02392   g_return_val_if_fail (s != NULL, 0);
02393 
02394   gts_surface_foreach_vertex (s, (GtsFunc) number_foreach, &n);
02395 
02396   return n;
02397 }
02398 
02405 guint gts_surface_edge_number (GtsSurface * s)
02406 {
02407   guint n = 0;
02408 
02409   g_return_val_if_fail (s != NULL, 0);
02410 
02411   gts_surface_foreach_edge (s, (GtsFunc) number_foreach, &n);
02412 
02413   return n;
02414 }
02415 
02422 guint gts_surface_face_number (GtsSurface * s)
02423 {
02424   g_return_val_if_fail (s != NULL, 0);
02425 
02426 #ifdef USE_SURFACE_BTREE
02427   return g_tree_nnodes (s->faces);
02428 #else /* not USE_SURFACE_BTREE */
02429   return g_hash_table_size (s->faces);
02430 #endif /* not USE_SURFACE_BTREE */
02431 }
02432 
02433 static void build_list_face (GtsTriangle * t, GSList ** list)
02434 {
02435   *list = g_slist_prepend (*list, gts_bbox_triangle (gts_bbox_class (), t));
02436 }
02437 
02438 static void build_list_boundary (GtsEdge * e, GSList ** list)
02439 {
02440   if (gts_edge_is_boundary (e, NULL))
02441     *list = g_slist_prepend (*list, gts_bbox_segment (gts_bbox_class (),
02442                                                       GTS_SEGMENT (e)));
02443 }
02444 
02460 void gts_surface_distance (GtsSurface * s1, GtsSurface * s2, gdouble delta,
02461                            GtsRange * face_range, GtsRange * boundary_range)
02462 {
02463   GNode * face_tree, * boundary_tree;
02464   GSList * bboxes;
02465 
02466   g_return_if_fail (s1 != NULL);
02467   g_return_if_fail (s2 != NULL);
02468   g_return_if_fail (delta > 0. && delta < 1.);
02469   g_return_if_fail (face_range != NULL);
02470   g_return_if_fail (boundary_range != NULL);
02471 
02472   bboxes = NULL;
02473   gts_surface_foreach_face (s2, (GtsFunc) build_list_face, &bboxes);
02474   if (bboxes != NULL) {
02475     face_tree = gts_bb_tree_new (bboxes);
02476     g_slist_free (bboxes);
02477     
02478     gts_bb_tree_surface_distance (face_tree, s1, 
02479                                (GtsBBoxDistFunc) gts_point_triangle_distance,
02480                                   delta, face_range);
02481     gts_bb_tree_destroy (face_tree, TRUE);
02482     
02483     bboxes = NULL;
02484     gts_surface_foreach_edge (s2, (GtsFunc) build_list_boundary, &bboxes);
02485     if (bboxes != NULL) {
02486       boundary_tree = gts_bb_tree_new (bboxes);
02487       g_slist_free (bboxes);
02488 
02489       gts_bb_tree_surface_boundary_distance (boundary_tree,
02490                s1, 
02491                (GtsBBoxDistFunc) gts_point_segment_distance,
02492                delta, boundary_range);
02493       gts_bb_tree_destroy (boundary_tree, TRUE);
02494     }
02495     else
02496       gts_range_reset (boundary_range);
02497   }
02498   else {
02499     gts_range_reset (face_range);
02500     gts_range_reset (boundary_range);
02501   }
02502 }
02503 
02504 static void surface_boundary (GtsEdge * e, gpointer * data)
02505 {
02506   GSList ** list = data[0];
02507 
02508   if (gts_edge_is_boundary (e, data[1]))
02509     *list = g_slist_prepend (*list, e);
02510 }
02511 
02518 GSList * gts_surface_boundary (GtsSurface * surface)
02519 {
02520   GSList * list = NULL;
02521   gpointer data[2];
02522 
02523   g_return_val_if_fail (surface != NULL, NULL);
02524 
02525   data[0] = &list;
02526   data[1] = surface;
02527   gts_surface_foreach_edge (surface, (GtsFunc) surface_boundary, data);
02528   
02529   return list;
02530 }
02531 
02532 struct _GtsSurfaceTraverse {
02533   GtsFifo * q;
02534   GtsSurface * s;
02535 };
02536 
02545 GtsSurfaceTraverse * gts_surface_traverse_new (GtsSurface * s,
02546                                                GtsFace * f)
02547 {
02548   GtsSurfaceTraverse * t;
02549 
02550   g_return_val_if_fail (s != NULL, NULL);
02551   g_return_val_if_fail (f != NULL, NULL);
02552   g_return_val_if_fail (gts_face_has_parent_surface (f, s), NULL);
02553   
02554   t = g_malloc (sizeof (GtsSurfaceTraverse));
02555   t->q = gts_fifo_new ();
02556   t->s = s;
02557   GTS_OBJECT (f)->reserved = GUINT_TO_POINTER (1);
02558   gts_fifo_push (t->q, f);
02559   return t;
02560 }
02561 
02562 static void push_neighbor (GtsFace * v, gpointer * data)
02563 {
02564   if (!GTS_OBJECT (v)->reserved) {
02565     GTS_OBJECT (v)->reserved = 
02566       GUINT_TO_POINTER (GPOINTER_TO_UINT (GTS_OBJECT (data[1])->reserved) + 1);
02567     gts_fifo_push (data[0], v);
02568   }
02569 }
02570 
02581 GtsFace * gts_surface_traverse_next (GtsSurfaceTraverse * t,
02582                                      guint * level)
02583 {
02584   GtsFace * u;
02585 
02586   g_return_val_if_fail (t != NULL, NULL);
02587 
02588   u = gts_fifo_pop (t->q);
02589   if (u) {
02590     gpointer data[2];
02591 
02592     if (level)
02593       *level = GPOINTER_TO_UINT (GTS_OBJECT (u)->reserved);
02594     data[0] = t->q;
02595     data[1] = u;
02596     gts_face_foreach_neighbor (u, t->s, (GtsFunc) push_neighbor, data);
02597   }
02598   return u;
02599 }
02600 
02607 void gts_surface_traverse_destroy (GtsSurfaceTraverse * t)
02608 {
02609   g_return_if_fail (t != NULL);
02610 
02611   gts_surface_foreach_face (t->s, (GtsFunc) gts_object_reset_reserved, NULL);
02612   gts_fifo_destroy (t->q);
02613   g_free (t);
02614 }
02615 
02616 static void traverse_manifold (GtsTriangle * t, GtsSurface * s)
02617 {
02618   if (g_slist_length (GTS_FACE (t)->surfaces) > 1)
02619     return;
02620 
02621   gts_surface_add_face (s, GTS_FACE (t));
02622   if (g_slist_length (t->e1->triangles) == 2) {
02623     if (t->e1->triangles->data != t)
02624       traverse_manifold (t->e1->triangles->data, s);
02625     else
02626       traverse_manifold (t->e1->triangles->next->data, s);
02627   }
02628   if (g_slist_length (t->e2->triangles) == 2) {
02629     if (t->e2->triangles->data != t)
02630       traverse_manifold (t->e2->triangles->data, s);
02631     else
02632       traverse_manifold (t->e2->triangles->next->data, s);
02633   }
02634   if (g_slist_length (t->e3->triangles) == 2) {
02635     if (t->e3->triangles->data != t)
02636       traverse_manifold (t->e3->triangles->data, s);
02637     else
02638       traverse_manifold (t->e3->triangles->next->data, s);
02639   }
02640 }
02641 
02642 static void non_manifold_edges (GtsEdge * e, gpointer * data)
02643 {
02644   GtsSurface * s = data[0];
02645   GSList ** non_manifold = data[1];
02646 
02647   if (gts_edge_face_number (e, s) > 2) {
02648     GSList * i = e->triangles;
02649 
02650     while (i) {
02651       if (gts_face_has_parent_surface (i->data, s) &&
02652           !g_slist_find (*non_manifold, i->data))
02653         *non_manifold = g_slist_prepend (*non_manifold, i->data);
02654       i = i->next;
02655     }
02656   }
02657 }
02658 
02659 static void traverse_boundary (GtsEdge * e, gpointer * data)
02660 {
02661   GtsSurface * orig = data[0];
02662   GSList ** components = data[1];
02663   GtsFace * f = gts_edge_is_boundary (e, orig);
02664 
02665   if (f != NULL && g_slist_length (f->surfaces) == 1) {
02666     GtsSurface * s = 
02667       gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (orig)->klass),
02668                        orig->face_class,
02669                        orig->edge_class,
02670                        orig->vertex_class);
02671     GSList * non_manifold = NULL, * i;
02672     gpointer data[2];
02673 
02674     *components = g_slist_prepend (*components, s);
02675     data[0] = s;
02676     data[1] = &non_manifold;
02677     traverse_manifold (GTS_TRIANGLE (f), s);
02678 
02679     gts_surface_foreach_edge (s, (GtsFunc) non_manifold_edges, data);
02680     i = non_manifold;
02681     while (i) {
02682       gts_surface_remove_face (s, i->data);
02683       i = i->next;
02684     }
02685     g_slist_free (non_manifold);
02686   }
02687 }
02688 
02689 static void traverse_remaining (GtsFace * f, gpointer * data)
02690 {
02691   GtsSurface * orig = data[0];
02692   GSList ** components = data[1];
02693 
02694   if (g_slist_length (f->surfaces) == 1) {
02695     GtsSurface * s = 
02696       gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (orig)->klass),
02697                        orig->face_class,
02698                        orig->edge_class,
02699                        orig->vertex_class);
02700     GSList * non_manifold = NULL, * i;
02701     gpointer data[2];
02702 
02703     *components = g_slist_prepend (*components, s);
02704     data[0] = s;
02705     data[1] = &non_manifold;
02706     traverse_manifold (GTS_TRIANGLE (f), s);
02707 
02708     gts_surface_foreach_edge (s, (GtsFunc) non_manifold_edges, data);
02709     i = non_manifold;
02710     while (i) {
02711       gts_surface_remove_face (s, i->data);
02712       i = i->next;
02713     }
02714     g_slist_free (non_manifold);
02715   }
02716 }
02717 
02726 GSList * gts_surface_split (GtsSurface * s)
02727 {
02728   gpointer data[2];
02729   GSList * components = NULL;
02730 
02731   g_return_val_if_fail (s != NULL, NULL);
02732 
02733   data[0] = s;
02734   data[1] = &components;
02735 
02736   /* boundary components */
02737   gts_surface_foreach_edge (s, (GtsFunc) traverse_boundary, data);
02738 
02739   /* remaining components */
02740   gts_surface_foreach_face (s, (GtsFunc) traverse_remaining, data);
02741 
02742   return components;
02743 }