pcb 4.1.1
An interactive printed circuit board layout editor.

boolean.c

Go to the documentation of this file.
00001 /* GTS - Library for the manipulation of triangulated surfaces
00002  * Copyright (C) 1999--2002 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 <math.h>
00021 #include "gts.h"
00022 
00023 /*#define DEBUG*/
00024 /*#define DEBUG_BOOLEAN*/
00025 /*#define CHECK_ORIENTED*/
00026 
00027 #ifdef DEBUG
00028 #ifdef DEBUG_FUNCTIONS
00029 #include "gts-private.h"
00030 #else
00031 #define DEBUG_FUNCTIONS
00032 #include "gts-private.h"
00033 #undef DEBUG_FUNCTIONS
00034 #endif
00035 #endif
00036 
00037 static void surface_inter_destroy (GtsObject * object)
00038 {
00039   GtsSurfaceInter * si = GTS_SURFACE_INTER (object);
00040 
00041   gts_object_destroy (GTS_OBJECT (si->s1));
00042   gts_object_destroy (GTS_OBJECT (si->s2));
00043   g_slist_free (si->edges);
00044 
00045   (* GTS_OBJECT_CLASS (gts_surface_inter_class ())->parent_class->destroy)
00046     (object);
00047 }
00048 
00049 static void surface_inter_class_init (GtsObjectClass * klass)
00050 {
00051   klass->destroy = surface_inter_destroy;
00052 }
00053 
00054 static void surface_inter_init (GtsSurfaceInter * si)
00055 {
00056   si->s1 = si->s2 = NULL;
00057   si->edges = NULL;
00058 }
00059 
00065 GtsSurfaceInterClass * gts_surface_inter_class (void)
00066 {
00067   static GtsSurfaceInterClass * klass = NULL;
00068 
00069   if (klass == NULL) {
00070     GtsObjectClassInfo surface_inter_info = {
00071       "GtsSurfaceInter",
00072       sizeof (GtsSurfaceInter),
00073       sizeof (GtsSurfaceInterClass),
00074       (GtsObjectClassInitFunc) surface_inter_class_init,
00075       (GtsObjectInitFunc) surface_inter_init,
00076       (GtsArgSetFunc) NULL,
00077       (GtsArgGetFunc) NULL
00078     };
00079     klass = gts_object_class_new (gts_object_class (), &surface_inter_info);
00080   }
00081 
00082   return klass;
00083 }
00084 
00085 /* EdgeInter: Header */
00086 
00087 typedef struct _EdgeInter         EdgeInter;
00088 
00089 struct _EdgeInter {
00090   GtsEdge parent;
00091 
00092   GtsTriangle * t1, * t2;
00093 };
00094 
00095 #define EDGE_INTER(obj)            GTS_OBJECT_CAST (obj,\
00096                                                  EdgeInter,\
00097                                                  edge_inter_class ())
00098 #define IS_EDGE_INTER(obj)         (gts_object_is_from_class (obj,\
00099                                                  edge_inter_class ()))
00100 
00101 static GtsEdgeClass * edge_inter_class  (void);
00102 static EdgeInter * edge_inter_new    (GtsVertex * v1, GtsVertex * v2,
00103                                       GtsTriangle * t1, GtsTriangle * t2);
00104 
00105 /* EdgeInter: Object */
00106 
00107 static GtsEdgeClass * edge_inter_class (void)
00108 {
00109   static GtsEdgeClass * klass = NULL;
00110 
00111   if (klass == NULL) {
00112     GtsObjectClassInfo edge_inter_info = {
00113       "EdgeInter",
00114       sizeof (EdgeInter),
00115       sizeof (GtsEdgeClass),
00116       (GtsObjectClassInitFunc) NULL,
00117       (GtsObjectInitFunc) NULL,
00118       (GtsArgSetFunc) NULL,
00119       (GtsArgGetFunc) NULL
00120     };
00121     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_constraint_class ()),
00122                                   &edge_inter_info);
00123   }
00124 
00125   return klass;
00126 }
00127 
00128 static EdgeInter * edge_inter_new (GtsVertex * v1, GtsVertex * v2,
00129                                    GtsTriangle * t1, GtsTriangle * t2)
00130 {
00131   EdgeInter * object;
00132 
00133   object = EDGE_INTER (gts_edge_new (GTS_EDGE_CLASS (edge_inter_class ()), 
00134                                      v1, v2));
00135   object->t1 = t1;
00136   object->t2 = t2;
00137 
00138   return object;
00139 }
00140 
00141 static GtsPoint * segment_triangle_intersection (GtsSegment * s,
00142                                                  GtsTriangle * t,
00143                                                  GtsPointClass * klass)
00144 {
00145   GtsPoint * A, * B, * C, * D, * E;
00146   gint ABCE, ABCD, ADCE, ABDE, BCDE;
00147   GtsEdge * AB, * BC, * CA;
00148   gdouble a, b, c;
00149 
00150   g_return_val_if_fail (s != NULL, NULL);
00151   g_return_val_if_fail (t != NULL, NULL);
00152   g_return_val_if_fail (klass != NULL, NULL);
00153 
00154   gts_triangle_vertices_edges (t, NULL, 
00155                                (GtsVertex **) &A, 
00156                                (GtsVertex **) &B, 
00157                                (GtsVertex **) &C, 
00158                                &AB, &BC, &CA);
00159   D = GTS_POINT (s->v1);
00160   E = GTS_POINT (s->v2);
00161 
00162   ABCE = gts_point_orientation_3d_sos (A, B, C, E);
00163   ABCD = gts_point_orientation_3d_sos (A, B, C, D);
00164   if (ABCE < 0 || ABCD > 0) {
00165     GtsPoint * tmpp;
00166     gint tmp;
00167 
00168     tmpp = E; E = D; D = tmpp;
00169     tmp = ABCE; ABCE = ABCD; ABCD = tmp;
00170   }
00171   if (ABCE < 0 || ABCD > 0)
00172     return NULL;
00173   ADCE = gts_point_orientation_3d_sos (A, D, C, E);
00174   if (ADCE < 0)
00175     return NULL;
00176   ABDE = gts_point_orientation_3d_sos (A, B, D, E);
00177   if (ABDE < 0)
00178     return NULL;
00179   BCDE = gts_point_orientation_3d_sos (B, C, D, E);
00180   if (BCDE < 0)
00181     return NULL;
00182   a = gts_point_orientation_3d (A, B, C, E);
00183   b = gts_point_orientation_3d (A, B, C, D);
00184   if (a != b) {
00185     c = a/(a - b);
00186     return gts_point_new (klass,
00187                           E->x + c*(D->x - E->x),
00188                           E->y + c*(D->y - E->y),
00189                           E->z + c*(D->z - E->z));
00190   }
00191   /* D and E are contained within ABC */
00192 #ifdef DEBUG
00193   fprintf (stderr, 
00194            "segment: %p:%s triangle: %p:%s intersection\n"
00195            "D and E contained in ABC\n",
00196            s, GTS_NEDGE (s)->name, t, GTS_NFACE (t)->name);
00197 #endif /* DEBUG */  
00198   g_assert (a == 0.); 
00199   return gts_point_new (klass,
00200                         (E->x + D->x)/2.,
00201                         (E->y + D->y)/2.,
00202                         (E->z + D->z)/2.);
00203 }
00204 
00205 static gint triangle_triangle_orientation (GtsPoint * p1, 
00206                                            GtsPoint * p2, GtsPoint * p3,
00207                                            GtsPoint * p4, GtsPoint * p5,
00208                                            GtsPoint * p6)
00209 {
00210   gint o4 = 0, o5 = 0, o6 = 0;
00211 
00212   if (p4 != p1 && p4 != p2 && p4 != p3)
00213     o4 = gts_point_orientation_3d_sos (p1, p2, p3, p4);
00214   if (p5 != p1 && p5 != p2 && p5 != p3)
00215     o5 = gts_point_orientation_3d_sos (p1, p2, p3, p5);
00216   if (o4*o5 < 0)
00217     return 0;
00218   if (p6 != p1 && p6 != p2 && p6 != p3)
00219     o6 = gts_point_orientation_3d_sos (p1, p2, p3, p6);
00220   if (o4*o6 < 0 || o5*o6 < 0)
00221     return 0;
00222   if (o4) return o4;
00223   if (o5) return o5;
00224   g_assert (o6);
00225   return o6;
00226 }
00227 
00228 static gint triangle_point_orientation (GtsTriangle * t1, 
00229                                         GtsTriangle * t2,
00230                                         gint o1,
00231                                         GtsPoint * p)
00232 {
00233   GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t1->e1)->v1);
00234   GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (t1->e1)->v2);
00235   GtsPoint * p3 = GTS_POINT (gts_triangle_vertex (t1));
00236   GtsPoint * p4 = GTS_POINT (GTS_SEGMENT (t2->e1)->v1);
00237   GtsPoint * p5 = GTS_POINT (GTS_SEGMENT (t2->e1)->v2);
00238   GtsPoint * p6 = GTS_POINT (gts_triangle_vertex (t2));
00239   gint o = triangle_triangle_orientation (p1, p2, p3, p4, p5, p6);
00240 
00241   if (o != 0)
00242     return o;
00243   o = triangle_triangle_orientation (p4, p5, p6, p1, p2, p3);
00244   if (o != 0) {
00245     gint o2 = gts_point_orientation_3d_sos (p4, p5, p6, p);
00246 
00247     return - o*o1*o2;
00248   }
00249   return 0;
00250 }
00251 
00252 static void add_edge_inter (GtsEdge * e,
00253                             GtsTriangle * t,
00254                             GtsVertex * v)
00255 {
00256   GtsVertex * ev1 = GTS_SEGMENT (e)->v1, * ev2 = GTS_SEGMENT (e)->v2;
00257   GList * i = GTS_OBJECT (e)->reserved;
00258 
00259   GTS_OBJECT (v)->reserved = t;
00260   if (i == NULL) {
00261     GTS_OBJECT (e)->reserved = g_list_prepend (NULL, v);
00262 #ifdef DEBUG
00263     fprintf (stderr, "add_edge_inter: inserting %p (%p,%p)\n", v, e, t);
00264 #endif /* DEBUG */
00265   }
00266   else {
00267     GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
00268     GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
00269     GtsPoint * p3 = GTS_POINT (gts_triangle_vertex (t));
00270     gint o1, oref = gts_point_orientation_3d_sos (p1, p2, p3, GTS_POINT (ev1));
00271     
00272     o1 = oref;
00273     while (i) {
00274       gint o2 = triangle_point_orientation (t, GTS_OBJECT (i->data)->reserved,
00275                                             oref, GTS_POINT (ev1));
00276 
00277       if (o2 == 0) {
00278 #ifdef DEBUG
00279         g_warning ("add_edge_inter: safe sign evaluation failed\n");
00280 #endif /* DEBUG */
00281         o2 = gts_point_orientation_3d_sos (p1, p2, p3, i->data);
00282       }
00283 
00284       if (o1*o2 < 0)
00285         break;
00286       ev1 = i->data;
00287       o1 = o2;
00288       i = i->next;
00289     }
00290     if (i != NULL) {
00291       GList * n = g_list_prepend (NULL, v);
00292 
00293       ev2 = i->data;
00294       n->next = i;
00295       n->prev = i->prev;
00296       i->prev = n;
00297       if (n->prev == NULL)
00298         GTS_OBJECT (e)->reserved = n;
00299       else
00300         n->prev->next = n;
00301     }
00302     else {
00303       g_assert (o1*gts_point_orientation_3d_sos (p1, p2, p3, GTS_POINT (ev2))
00304                 < 0);
00305       GTS_OBJECT (e)->reserved = g_list_append (GTS_OBJECT (e)->reserved, v);
00306     }
00307 #ifdef DEBUG
00308     fprintf (stderr, 
00309              "add_edge_inter: inserting %p (%p,%p) between %p and %p\n", 
00310              v, e, t, ev1, ev2);
00311     i = GTS_OBJECT (e)->reserved;
00312     while (i) {
00313       fprintf (stderr, " %p", i->data);
00314       i = i->next;
00315     }
00316     fprintf (stderr, "\n");
00317 #endif /* DEBUG */
00318   }
00319 }
00320 
00321 static GtsVertex * intersects (GtsEdge * e,
00322                                GtsTriangle * t,
00323                                GtsSurface * s)
00324 {
00325   GList * i = GTS_OBJECT (e)->reserved;
00326   GtsVertex * v;
00327 
00328   while (i) {
00329     if (GTS_OBJECT (i->data)->reserved == t)
00330       return i->data;
00331     i = i->next;
00332   }
00333 
00334   v = GTS_VERTEX (segment_triangle_intersection (GTS_SEGMENT (e), t, 
00335                                     GTS_POINT_CLASS (s->vertex_class)));
00336   if (v != NULL) {
00337 #ifdef DEBUG
00338     if (GTS_IS_NVERTEX (v) && GTS_IS_NEDGE (e) && GTS_IS_NFACE (t) &&
00339         GTS_NVERTEX (v)->name[0] == '\0')
00340       g_snprintf (GTS_NVERTEX (v)->name, GTS_NAME_LENGTH, "%s|%s",
00341                   GTS_NEDGE (e)->name, GTS_NFACE (t)->name);
00342 #endif /* DEBUG */
00343     if (s->vertex_class->intersection_attributes)
00344       (*s->vertex_class->intersection_attributes)
00345         (v, GTS_OBJECT (e), GTS_OBJECT (t));
00346     add_edge_inter (e, t, v);
00347   }
00348   return v;
00349 }
00350 
00351 /* see figure misc/orientation.fig */
00352 static gint intersection_orientation (GtsTriangle * t1, 
00353                                       GtsEdge * e,
00354                                       GtsTriangle * t2)
00355 {
00356   GtsVertex * v1, * v2, * v3;
00357   GtsEdge * e2, * e3;
00358   GtsVertex * v4, * v5, * v6;
00359 
00360   gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e2, &e3);
00361   gts_triangle_vertices (t2, &v4, &v5, &v6);
00362 
00363   return gts_point_orientation_3d_sos (GTS_POINT (v4), 
00364                                        GTS_POINT (v5), 
00365                                        GTS_POINT (v6),
00366                                        GTS_POINT (v2));
00367 }
00368 
00369 #define UPDATE_ORIENTATION if (o > 0) { vi2 = v; /* e2 = e; */ } else { vi2 = vi1;\
00370                                                                         /* e2 = e1; */\
00371                                                                         vi1 = v;\
00372                                                                         /* e1 = e; */ }
00373 
00374 static void intersect_edges (GtsBBox * bb1, GtsBBox * bb2,
00375                              GtsSurfaceInter * si)
00376 {
00377   GtsSurface * s1 = GTS_OBJECT (si->s1)->reserved;
00378   GtsTriangle * t1 = GTS_TRIANGLE (bb1->bounded);
00379   GtsTriangle * t2 = GTS_TRIANGLE (bb2->bounded);
00380   GtsVertex * v, * vi1 = NULL, * vi2 = NULL;
00381   //GtsEdge * e1 = NULL, * e2 = NULL, * e;
00382 
00383   vi1 = intersects (t2->e1, t1, s1);
00384   //e1 = t2->e1;
00385   v = intersects (t2->e2, t1, s1);
00386   //e = t2->e2;
00387   if (!vi1) {
00388     vi1 = v;
00389     //e1 = e;
00390   }
00391   else if (v) {
00392     gint o = intersection_orientation (t2, t2->e2, t1);
00393     UPDATE_ORIENTATION;
00394   }
00395   if (!vi2) {
00396     v = intersects (t2->e3, t1, s1);
00397     //e = t2->e3;
00398     if (!vi1) {
00399       vi1 = v;
00400       //e1 = e;
00401     }
00402     else if (v) {
00403       gint o = intersection_orientation (t2, t2->e3, t1);
00404       UPDATE_ORIENTATION;
00405     }
00406   }
00407   if (!vi2) {
00408     v = intersects (t1->e1, t2, s1);
00409     //e = t1->e1;
00410     if (!vi1) {
00411       vi1 = v;
00412       //e1 = e;
00413     }
00414     else if (v) {
00415       gint o = - intersection_orientation (t1, t1->e1, t2);
00416       UPDATE_ORIENTATION;
00417     }
00418   }
00419   if (!vi2) {
00420     v = intersects (t1->e2, t2, s1);
00421     //e = t1->e2;
00422     if (!vi1) {
00423       vi1 = v;
00424       //e1 = e;
00425     }
00426     else if (v) {
00427       gint o = - intersection_orientation (t1, t1->e2, t2);
00428       UPDATE_ORIENTATION;
00429     }
00430   }
00431   if (!vi2) {
00432     v = intersects (t1->e3, t2, s1);
00433     //e = t1->e3;
00434     if (!vi1) {
00435       vi1 = v;
00436       //e1 = e;
00437     }
00438     else if (v) {
00439       gint o = - intersection_orientation (t1, t1->e3, t2);
00440       UPDATE_ORIENTATION;
00441     }
00442   }
00443 
00444   g_assert ((!vi1 && !vi2) || (vi1 && vi2));
00445   if (vi1) {
00446     GtsEdge * e = GTS_EDGE (edge_inter_new (vi1, vi2, t1, t2));
00447 
00448 #ifdef DEBUG
00449     fprintf (stderr, "creating constraint %p: %p->%p: %p/%p\n", 
00450              e, vi1, vi2, t1, t2);
00451 #endif /* DEBUG */
00452     gts_surface_add_face (si->s1, GTS_FACE (t1));
00453     gts_surface_add_face (si->s2, GTS_FACE (t2));
00454     si->edges = g_slist_prepend (si->edges, e);
00455     GTS_OBJECT (t1)->reserved = g_slist_prepend (GTS_OBJECT (t1)->reserved, e);
00456     GTS_OBJECT (t2)->reserved = g_slist_prepend (GTS_OBJECT (t2)->reserved, e);
00457   }
00458 }
00459 
00460 static GtsSurfaceInter * surface_inter_new (GtsSurfaceInterClass * klass,
00461                                             GtsSurface * s1,
00462                                             GtsSurface * s2,
00463                                             GNode * faces_tree1,
00464                                             GNode * faces_tree2)
00465 {
00466   GtsSurfaceInter * si;
00467 
00468   si = GTS_SURFACE_INTER (gts_object_new (GTS_OBJECT_CLASS (klass)));
00469   si->s1 = gts_surface_new (gts_surface_class (),
00470                             s1->face_class,
00471                             s1->edge_class,
00472                             s1->vertex_class);
00473   GTS_OBJECT (si->s1)->reserved = s1;
00474   si->s2 = gts_surface_new (gts_surface_class (),
00475                             s2->face_class,
00476                             s2->edge_class,
00477                             s2->vertex_class);
00478   GTS_OBJECT (si->s2)->reserved = s2;
00479   gts_bb_tree_traverse_overlapping (faces_tree1, faces_tree2,
00480                                     (GtsBBTreeTraverseFunc) intersect_edges, 
00481                                     si);
00482 
00483   return si;
00484 }
00485 
00486 static void free_slist (GtsObject * o)
00487 {
00488   g_slist_free (o->reserved);
00489   o->reserved = NULL;
00490 }
00491 
00492 static void free_glist (GtsObject * o)
00493 {
00494   g_list_foreach (o->reserved, (GFunc) gts_object_reset_reserved, NULL);
00495   g_list_free (o->reserved);
00496   o->reserved = NULL;
00497 }
00498 
00510 GSList * gts_surface_intersection (GtsSurface * s1,
00511                                    GtsSurface * s2,
00512                                    GNode * faces_tree1,
00513                                    GNode * faces_tree2)
00514 {
00515   GtsSurfaceInter * si;
00516   GSList * inter;
00517 
00518   g_return_val_if_fail (s1 != NULL, NULL);
00519   g_return_val_if_fail (s2 != NULL, NULL);
00520   g_return_val_if_fail (faces_tree1 != NULL, NULL);
00521   g_return_val_if_fail (faces_tree2 != NULL, NULL);
00522 
00523   si = surface_inter_new (gts_surface_inter_class (),
00524                           s1, s2, faces_tree1, faces_tree2);
00525 
00526   gts_surface_foreach_face (si->s1, (GtsFunc) free_slist, NULL);
00527   gts_surface_foreach_face (si->s2, (GtsFunc) free_slist, NULL);
00528   gts_surface_foreach_edge (si->s1, (GtsFunc) free_glist, NULL);
00529   gts_surface_foreach_edge (si->s2, (GtsFunc) free_glist, NULL);
00530   inter = si->edges;
00531   si->edges = NULL;
00532   gts_object_destroy (GTS_OBJECT (si));
00533 
00534   return inter;  
00535 }
00536 
00537 typedef enum {
00538   INTERIOR = 1 << (GTS_USER_FLAG),
00539   RELEVANT = 1 << (GTS_USER_FLAG + 1)
00540 } CurveFlag;
00541 
00542 #define IS_SET(s, f) ((GTS_OBJECT_FLAGS (s) & (f)) != 0)
00543 #define SET(s, f)   (GTS_OBJECT_FLAGS (s) |= (f))
00544 #define UNSET(s, f) (GTS_OBJECT_FLAGS (s) &= ~(f))
00545 #define NEXT(s)  (GTS_OBJECT (s)->reserved)
00546 
00547 #ifdef DEBUG
00548 static void write_nodes (GSList * i, GHashTable * hash, guint * nn,
00549                          FILE * fp)
00550 {
00551   while (i) {
00552     GtsSegment * s = i->data;
00553 
00554     if (!g_hash_table_lookup (hash, s->v1)) {
00555       fprintf (fp, "  %u [ label = \"%p\" ];\n", *nn, s->v1);
00556       g_hash_table_insert (hash, s->v1, GUINT_TO_POINTER ((*nn)++));
00557     }
00558     if (!g_hash_table_lookup (hash, s->v2)) {
00559       fprintf (fp, "  %u [ label = \"%p\" ];\n", *nn, s->v2);
00560       g_hash_table_insert (hash, s->v2, GUINT_TO_POINTER ((*nn)++));
00561     }
00562     i = i->next;
00563   }
00564 }
00565 
00566 static void write_edges (GSList * i, GHashTable * hash, 
00567                          GtsSurface * surface,
00568                          FILE * fp)
00569 {
00570   while (i) {
00571     GtsSegment * s = i->data;
00572 
00573     fprintf (fp, "  %u -> %u [ label = \"%p:%d\" ];\n",
00574              GPOINTER_TO_UINT (g_hash_table_lookup (hash, s->v1)),
00575              GPOINTER_TO_UINT (g_hash_table_lookup (hash, s->v2)),
00576              s,
00577              gts_edge_face_number (GTS_EDGE (s), surface));
00578     i = i->next;
00579   }
00580 }
00581 
00582 static void write_graph (GSList * boundary, GSList * interior,
00583                          GtsSurface * surface,
00584                          FILE * fp)
00585 {
00586   GHashTable * hash = g_hash_table_new (NULL, NULL);
00587   guint nn = 1;
00588   
00589   fprintf (fp, "digraph oriented_curve {\n");
00590   write_nodes (boundary, hash, &nn, fp);
00591   write_nodes (interior, hash, &nn, fp);
00592   write_edges (boundary, hash, surface, fp);
00593   fprintf (fp, "  edge [ color = red ];\n");
00594   write_edges (interior, hash, surface, fp);
00595   fprintf (fp, "}\n");
00596   g_hash_table_destroy (hash);
00597 }
00598 
00599 static void print_loop (GtsSegment * start, FILE * fp)
00600 {
00601   GtsSegment * s = start;
00602 
00603   do {
00604     fprintf (fp, "  %p: %p:%s -> %p:%s\n",
00605              s, 
00606              s->v1, GTS_NVERTEX (s->v1)->name, 
00607              s->v2, GTS_NVERTEX (s->v2)->name);
00608     s = NEXT (s);
00609   } while (s != start && s != NULL);
00610 }
00611 
00612 static void draw_vector (GtsPoint * p1, GtsPoint * p2, FILE * fp)
00613 {
00614   gdouble x = p2->x - p1->x;
00615   gdouble y = p2->y - p1->y;
00616   gdouble z = p2->z - p1->z;
00617 
00618   fprintf (fp, "VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n",
00619            p1->x + x - (x - y/2.)/5.,
00620            p1->y + y - (x/2. + y)/5.,
00621            p1->z + z - (x/2. + z)/5.,
00622            p1->x + x,
00623            p1->y + y,
00624            p1->z + z,
00625            p1->x + x - (x + y/2.)/5.,
00626            p1->y + y + (x/2. - y)/5.,
00627            p1->z + z + (x/2. - z)/5.);
00628   fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n",
00629            p1->x, p1->y, p1->z,
00630            p1->x + x,
00631            p1->y + y,
00632            p1->z + z);
00633 }
00634 
00635 static void draw_vector1 (GtsPoint * p1, GtsPoint * p2, GtsPoint * o,
00636                           FILE * fp)
00637 {
00638   gdouble x1 = o->x + 0.9*(p1->x - o->x);
00639   gdouble y1 = o->y + 0.9*(p1->y - o->y);
00640   gdouble z1 = o->z + 0.9*(p1->z - o->z);
00641   gdouble x2 = o->x + 0.9*(p2->x - o->x);
00642   gdouble y2 = o->y + 0.9*(p2->y - o->y);
00643   gdouble z2 = o->z + 0.9*(p2->z - o->z);
00644   gdouble x = x2 - x1;
00645   gdouble y = y2 - y1;
00646   gdouble z = z2 - z1;
00647 
00648   fprintf (fp, "VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n",
00649            x1 + x - (x - y/2.)/5.,
00650            y1 + y - (x/2. + y)/5.,
00651            z1 + z - (x/2. + z)/5.,
00652            x1 + x,
00653            y1 + y,
00654            z1 + z,
00655            x1 + x - (x + y/2.)/5.,
00656            y1 + y + (x/2. - y)/5.,
00657            z1 + z + (x/2. - z)/5.);
00658   fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n",
00659            x1, y1, z1,
00660            x1 + x,
00661            y1 + y,
00662            z1 + z);
00663 }
00664 
00665 static void write_segments (GSList * boundary, GSList * interior,
00666                             FILE * fp)
00667 {
00668   GSList * i = boundary;
00669 
00670   fprintf (fp, "LIST {\n");
00671   while (i) {
00672     GSList * inext = i->next;
00673     GtsSegment * s = i->data;
00674     GtsSegment * next = inext ? inext->data : boundary->data;
00675     GtsVertex * v1, * v2;
00676 
00677     if (s->v1 != next->v1 && s->v1 != next->v2) {
00678       v1 = s->v1;
00679       v2 = s->v2;
00680     }
00681     else {
00682       v1 = s->v2;
00683       v2 = s->v1;
00684     }
00685     draw_vector (GTS_POINT (v1), GTS_POINT (v2), fp);
00686     i = inext;
00687   }
00688   i = interior;
00689   while (i) {
00690     GtsSegment * s = i->data;
00691 
00692     draw_vector (GTS_POINT (s->v1), GTS_POINT (s->v2), fp);
00693     i = i->next;
00694   }
00695   fprintf (fp, "}\n");
00696 }
00697 
00698 static void write_loops (GSList * i, FILE * fp)
00699 {
00700   guint nl = 0;
00701 
00702   while (i) {
00703     GtsSegment * start = i->data, * s;
00704     GtsPoint os;
00705     guint n = 0;
00706 
00707     fprintf (fp, "(geometry \"loop%d\" = LIST {\n", nl++);    
00708 
00709     os.x = os.y = os.z = 0.;
00710     s = start;
00711     do {
00712       GtsSegment * next = NEXT (s);
00713       GtsPoint * p;
00714       
00715       if (s->v1 != next->v1 && s->v1 != next->v2)
00716         p = GTS_POINT (s->v1);
00717        else
00718          p = GTS_POINT (s->v2);
00719       os.x += p->x; os.y += p->y; os.z += p->z; n++;
00720       s = next;
00721      } while (s != start);
00722     os.x /= n; os.y /= n; os.z /= n;
00723     
00724     s = start;
00725     do {
00726       GtsSegment * next = NEXT (s);
00727       
00728       if (s->v1 != next->v1 && s->v1 != next->v2)
00729         draw_vector1 (GTS_POINT (s->v1), GTS_POINT (s->v2), &os, fp);
00730       else
00731          draw_vector1 (GTS_POINT (s->v2), GTS_POINT (s->v1), &os, fp);
00732       s = next;
00733     } while (s != start);
00734     
00735     fprintf (fp, "})\n");
00736 
00737     i = i->next;
00738   }
00739 }
00740 
00741 #define NAME(v) (GTS_IS_NVERTEX (v) ? GTS_NVERTEX (v)->name : "")
00742 #endif /* DEBUG */
00743 
00744 static GtsSegment * prev_flag (GtsSegment * s, CurveFlag flag)
00745 {
00746   GSList * i = s->v1->segments;
00747 
00748   while (i) {
00749     if (i->data != s && IS_SET (i->data, flag))
00750       return i->data;
00751     i = i->next;
00752   }
00753   return NULL;
00754 }
00755 
00756 static GtsSegment * next_flag (GtsSegment * s, CurveFlag flag)
00757 {
00758   GSList * i = s->v2->segments;
00759 
00760   while (i) {
00761     if (i->data != s && IS_SET (i->data, flag))
00762       return i->data;
00763     i = i->next;
00764   }
00765   return NULL;
00766 }
00767 
00768 static GtsSegment * next_interior (GtsVertex * v)
00769 {
00770   GSList * i = v->segments;
00771 
00772   while (i) {
00773     GtsSegment * s = i->data;
00774 
00775     if (s->v1 == v && IS_SET (s, INTERIOR))
00776       return s;
00777     i = i->next;
00778   }
00779   return NULL;
00780 }
00781 
00782 static GtsSegment * prev_interior (GtsVertex * v)
00783 {
00784   GSList * i = v->segments;
00785 
00786   while (i) {
00787     GtsSegment * s = i->data;
00788 
00789     if (s->v2 == v && IS_SET (s, INTERIOR))
00790       return s;
00791     i = i->next;
00792   }
00793   return NULL;
00794 }
00795 
00796 static GtsSegment * reverse (GtsSegment * start,
00797                              gboolean interior,
00798                              gboolean * isloop)
00799 {
00800   GtsSegment * s = start, * prev = NULL, * rprev = NULL;
00801   GtsSegment * rstart = NULL, * rstart1 = NULL;
00802 
00803   do {
00804     GtsSegment * rs;
00805 
00806     g_assert (IS_EDGE_INTER (s));
00807     rs = GTS_SEGMENT (edge_inter_new (s->v2, s->v1,
00808                                       EDGE_INTER (s)->t1, EDGE_INTER (s)->t2));
00809 
00810     if (rstart == NULL)
00811       rstart = rs;
00812     else if (rstart1 == NULL)
00813       rstart1 = rs;
00814     if (interior)
00815       SET (rs, INTERIOR);
00816     NEXT (rs) = rprev;
00817     rprev = rs;
00818     prev = s;
00819     s = NEXT (s);
00820   } while (s != NULL && s != start);
00821   if (s == start) {
00822     NEXT (rstart) = rprev;
00823     *isloop = TRUE;
00824   }
00825   else {
00826     NEXT (rstart) = start;
00827     NEXT (prev) = rprev;
00828     *isloop = FALSE;
00829   }    
00830   return rstart1;
00831 }
00832 
00833 static GSList * interior_loops (GSList * interior)
00834 {
00835   GSList * i = interior;
00836   GSList * loops = NULL;
00837 
00838   i = interior;
00839   while (i) {
00840     GtsSegment * s = i->data;
00841 
00842     if (IS_SET (s, RELEVANT)) {
00843       GtsSegment * start = s, * end;
00844 
00845       do {
00846         GtsSegment * next = next_flag (s, INTERIOR);
00847 
00848         UNSET (s, RELEVANT);
00849         end = s; 
00850         s = NEXT (s) = next;
00851       } while (s != NULL && s != start);
00852 
00853       if (s == start)
00854         loops = g_slist_prepend (loops, start);
00855       else {
00856         GtsSegment * next, * prev;
00857         gboolean isloop;
00858 
00859         s = prev_flag (start, INTERIOR);
00860         while (s) {
00861           UNSET (s, RELEVANT);
00862           NEXT (s) = start;
00863           start = s;
00864           s = prev_flag (s, INTERIOR);
00865         }
00866         next = next_flag (end, RELEVANT);
00867         prev = prev_flag (start, RELEVANT);
00868         if (prev != NULL)
00869           SET (start->v1, INTERIOR);
00870         if (next != NULL)
00871           SET (end->v2, INTERIOR);
00872         if (next == NULL && prev == NULL)
00873           loops = g_slist_prepend (loops, start);
00874         else
00875           reverse (start, TRUE, &isloop);
00876       }
00877     }
00878     i = i->next;
00879   }
00880   return loops;
00881 }
00882 
00883 #define ORIENTATION(p1,p2,p3,o) (gts_point_orientation_3d (p1, p2, o, p3))
00884 #define ORIENTATION_SOS(p1,p2,p3,o) (gts_point_orientation_3d_sos (p1, p2, o, p3))
00885 
00886 #define ORIENTED_VERTICES(s,next,w1,w2) {\
00887   if ((s)->v1 == (next)->v1 || (s)->v1 == (next)->v2) {\
00888     w1 = (s)->v2;\
00889     w2 = (s)->v1;\
00890   }\
00891   else {\
00892     w1 = (s)->v1;\
00893     w2 = (s)->v2;\
00894   }\
00895 }
00896 
00897 #if 0
00898 static GtsSegment * segment_intersects (GtsPoint * p1, GtsPoint * p2,
00899                                         GSList * i,
00900                                         GtsPoint * o)
00901 {
00902   while (i) {
00903     GtsSegment * s = i->data;
00904     GtsPoint * p3 = GTS_POINT (s->v1);
00905     GtsPoint * p4 = GTS_POINT (s->v2);
00906 
00907     if (p3 != p1 && p3 != p2 && p4 != p1 && p4 != p2) {
00908       gdouble o1 = ORIENTATION (p3, p4, p1, o);
00909       gdouble o2 = ORIENTATION (p3, p4, p2, o);
00910 
00911       if ((o1 < 0. && o2 > 0.) || (o1 > 0. && o2 < 0.)) {
00912         o1 = ORIENTATION (p1, p2, p3, o);
00913         o2 = ORIENTATION (p1, p2, p4, o);
00914 
00915         if ((o1 <= 0. && o2 >= 0.) || (o1 >= 0. && o2 <= 0.))
00916           return s;
00917       }
00918     }
00919     i = i->next;
00920   }
00921   return NULL;
00922 }
00923 #else
00924 static GtsSegment * segment_intersects (GtsPoint * p1, GtsPoint * p2,
00925                                         GSList * i,
00926                                         GtsPoint * o)
00927 {
00928   while (i) {
00929     GtsSegment * s = i->data;
00930     GtsPoint * p3 = GTS_POINT (s->v1);
00931     GtsPoint * p4 = GTS_POINT (s->v2);
00932 
00933     if (p3 != p1 && p3 != p2 && p4 != p1 && p4 != p2) {
00934       gint o1 = ORIENTATION_SOS (p3, p4, p1, o);
00935       gint o2 = ORIENTATION_SOS (p3, p4, p2, o);
00936 
00937       if (o1*o2 < 0) {
00938         o1 = ORIENTATION_SOS (p1, p2, p3, o);
00939         o2 = ORIENTATION_SOS (p1, p2, p4, o);
00940 
00941         if (o1*o2 < 0)
00942           return s;
00943       }
00944     }
00945     i = i->next;
00946   }
00947   return NULL;
00948 }
00949 #endif
00950 
00951 static gboolean is_inside_wedge (GtsSegment * s1, GtsSegment * s2,
00952                                  GtsPoint * p, GtsPoint * o)
00953 {
00954   GtsVertex * v1, * v2, * v3;
00955 
00956   ORIENTED_VERTICES (s1, s2, v1, v2);
00957   v3 = s2->v1 != v2 ? s2->v1 : s2->v2;
00958 
00959   if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), 
00960                    GTS_POINT (v3), o) >= 0.) {
00961     if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), p, o) <= 0. ||
00962         ORIENTATION (GTS_POINT (v2), GTS_POINT (v3), p, o) <= 0.)
00963       return FALSE;
00964   }
00965   else if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), p, o) <= 0. &&
00966            ORIENTATION (GTS_POINT (v2), GTS_POINT (v3), p, o) <= 0.)
00967     return FALSE;
00968   return TRUE;
00969 }
00970 
00971 static GtsSegment * connection (GtsPoint * p, 
00972                                 GSList * interior,
00973                                 GSList * bloops,
00974                                 GtsPoint * o)
00975 {
00976   while (bloops) {
00977     GtsSegment * start = bloops->data, * s = start;
00978 
00979     do {
00980       GtsSegment * next = NEXT (s);
00981       GtsVertex * v2 = s->v1 == next->v1 || s->v1 == next->v2 ? s->v1 : s->v2;
00982 
00983       if (is_inside_wedge (s, next, p, o) &&
00984           !segment_intersects (p, GTS_POINT (v2), interior, o))
00985         return s;
00986       s = next;
00987     } while (s != start);
00988     bloops = bloops->next;
00989   }
00990   return NULL;
00991 }
00992 
00993 static gdouble loop_orientation (GtsSegment * start,
00994                                  GtsPoint * p, GtsPoint * o)
00995 {
00996   GtsSegment * s = start;
00997   gdouble or = 0.;
00998 
00999   do {
01000     GtsSegment * next = NEXT (s);
01001     GtsVertex * v1, * v2;
01002 
01003     ORIENTED_VERTICES (s, next, v1, v2);
01004     or += ORIENTATION (p, GTS_POINT (v1), GTS_POINT (v2), o);
01005     s = next;
01006   } while (s != start);
01007 
01008 #ifdef DEBUG
01009   fprintf (stderr, "loop orientation: %g\n", or);
01010 #endif /* DEBUG */
01011 
01012   return or;
01013 }
01014 
01015 static void connect_interior_loop (GtsSegment * start,
01016                                    GSList ** interior,
01017                                    GSList ** bloops,
01018                                    GtsSurface * surface,
01019                                    GtsPoint * o)
01020 {
01021   GtsSegment * s = start, * c = NULL, * next, * s1, * rs1, * rs;
01022   GtsVertex * v, * cv;
01023   gboolean isloop;
01024 
01025   do {
01026     if (!(c = connection (GTS_POINT (s->v2), *interior, *bloops, o)))
01027       s = NEXT (s);
01028   } while (s != start && !c);
01029   g_assert (c);
01030   next = NEXT (c);
01031   v = c->v1 == next->v1 || c->v1 == next->v2 ? c->v1 : c->v2;
01032   cv = s->v2;
01033 #ifdef DEBUG
01034   fprintf (stderr, "connecting %p:%s with %p:%s\n", 
01035            cv, NAME (cv), v, NAME (v));
01036   fprintf (stderr, "  c: %p: %p:%s %p:%s\n", c, 
01037            c->v1, NAME (c->v1),
01038            c->v2, NAME (c->v2));
01039   fprintf (stderr, "  next: %p: %p:%s %p:%s\n", next,
01040            next->v1, NAME (next->v1),
01041            next->v2, NAME (next->v2));
01042 #endif /* DEBUG */
01043   rs = reverse (s, FALSE, &isloop);
01044   if (isloop) {
01045     if (loop_orientation (rs, GTS_POINT (v), o) < 0.) {
01046       GtsSegment * tmp = s;
01047       s = rs;
01048       rs = tmp;
01049     }
01050     *bloops = g_slist_prepend (*bloops, rs);
01051   }
01052   s1 = GTS_SEGMENT (gts_edge_new (surface->edge_class, v, cv));
01053   rs1 = GTS_SEGMENT (gts_edge_new (surface->edge_class, cv, v));
01054   NEXT (c) = s1;
01055   NEXT (rs1) = next;
01056   *interior = g_slist_prepend (*interior, s1);
01057   NEXT (s1) = NEXT (s);
01058   NEXT (s) = rs1;
01059 }
01060 
01061 static GSList * boundary_loops (GSList * boundary)
01062 {
01063   GSList * i = boundary;  
01064   GtsSegment * start = i->data;
01065   GSList * loops = NULL;
01066 
01067   while (i) {
01068     GtsSegment * s = i->data;
01069     GSList * inext = i->next;
01070     GtsSegment * next = inext ? inext->data : start;
01071     GtsVertex * v = s->v1 == next->v1 || s->v1 == next->v2 ? s->v1 : s->v2;
01072 
01073     if (IS_SET (v, INTERIOR)) {
01074       GtsSegment * intprev = prev_interior (v);
01075 
01076       NEXT (intprev) = next;
01077       NEXT (s) = next_interior (v);
01078       UNSET (v, INTERIOR);
01079     }
01080     else
01081       NEXT (s) = next;
01082     i = inext;
01083   }
01084 
01085   i = boundary;
01086   while (i) {
01087     start = i->data;
01088     
01089     if (IS_SET (start, RELEVANT)) {
01090       GtsSegment * s = start;
01091 
01092       do {
01093         UNSET (s, RELEVANT);
01094         UNSET (s, INTERIOR);
01095         s = NEXT (s);
01096       } while (s != start);
01097       loops = g_slist_prepend (loops, start);
01098     }
01099     i = i->next;
01100   }
01101 
01102   return loops;
01103 }
01104 
01105 typedef struct _Ear    Ear;
01106 
01107 struct _Ear {
01108   GtsVertex * v1, * v2, * v3;
01109   GtsSegment * s1, * s2, * s3;
01110 };
01111 
01112 static gboolean point_in_wedge (GtsPoint * p1, GtsPoint * p2, GtsPoint * p3,
01113                                 GtsPoint * p, gboolean closed, GtsPoint * o)
01114 {
01115   gdouble o1;
01116 
01117   if (p == p2 || p == p3)
01118     return FALSE;
01119   o1 = ORIENTATION (p1, p2, p, o);
01120   if ((closed && o1 < 0.) || (!closed && o1 <= 0.)) return FALSE;
01121   o1 = ORIENTATION (p3, p1, p, o);
01122   if ((closed && o1 < 0.) || (!closed && o1 <= 0.)) return FALSE;
01123   return TRUE;
01124 }
01125 
01126 #if 0
01127 static gboolean segment_intersects1 (GtsPoint * p1, GtsPoint * p2, 
01128                                      GtsPoint * p3, GtsPoint * p4,
01129                                      gboolean closed, GtsPoint * o)
01130 {
01131   gdouble o1 = ORIENTATION (p3, p4, p1, o);
01132   gdouble o2 = ORIENTATION (p3, p4, p2, o);
01133   gdouble o3, o4;
01134 
01135   if ((closed && ((o1 > 0. && o2 > 0.) || (o1 < 0. && o2 < 0.))) ||
01136       (!closed && ((o1 >= 0. && o2 >= 0.) || (o1 <= 0. && o2 <= 0.))))
01137     return FALSE;
01138   o3 = ORIENTATION (p1, p2, p3, o);
01139   o4 = ORIENTATION (p1, p2, p4, o);
01140   if ((o3 > 0. && o4 > 0.) || (o3 < 0. && o4 < 0.))
01141     return FALSE;
01142   if (closed) return TRUE;
01143   if ((o3 == 0. && o4 > 0.) || (o4 == 0. && o3 > 0.))
01144     return TRUE;
01145   return FALSE;
01146 }
01147 #else
01148 static gboolean segment_intersects1 (GtsPoint * p1, GtsPoint * p2, 
01149                                      GtsPoint * p3, GtsPoint * p4,
01150                                      gboolean closed, GtsPoint * o)
01151 {
01152   gint o1, o2;
01153 
01154   o1 = ORIENTATION_SOS (p3, p4, p1, o);
01155   o2 = ORIENTATION_SOS (p3, p4, p2, o);
01156   if (o1*o2 > 0)
01157     return FALSE;
01158   o1 = ORIENTATION_SOS (p1, p2, p3, o);
01159   o2 = ORIENTATION_SOS (p1, p2, p4, o);
01160   if (o1*o2 > 0)
01161     return FALSE;
01162   return TRUE;
01163 }
01164 #endif
01165 
01166 static GtsSegment * triangle_intersects_segments (GtsPoint * p1,
01167                                                   GtsPoint * p2,
01168                                                   GtsPoint * p3,
01169                                                   gboolean closed,
01170                                                   GtsSegment * start,
01171                                                   GtsPoint * o)
01172 {
01173   GtsSegment * s = start;
01174 
01175   do {
01176     GtsPoint * p4 = GTS_POINT (s->v1);
01177     GtsPoint * p5 = GTS_POINT (s->v2);
01178 
01179     if (p4 == p1) {
01180       if (point_in_wedge (p1, p2, p3, p5, closed, o))
01181         return s;
01182     }
01183     else if (p4 == p2) {
01184       if (point_in_wedge (p2, p3, p1, p5, closed, o))
01185         return s;
01186     }
01187     else if (p4 == p3) {
01188       if (point_in_wedge (p3, p1, p2, p5, closed, o))
01189         return s;
01190     }
01191     else if (p5 == p1) {
01192       if (point_in_wedge (p1, p2, p3, p4, closed, o))
01193         return s;
01194     }
01195     else if (p5 == p2) {
01196       if (point_in_wedge (p2, p3, p1, p4, closed, o))
01197         return s;
01198     }
01199     else if (p5 == p3) {
01200       if (point_in_wedge (p3, p1, p2, p4, closed, o))
01201         return s;
01202     }
01203     else if (segment_intersects1 (p1, p2, p4, p5, closed, o) ||
01204              segment_intersects1 (p2, p3, p4, p5, closed, o) ||
01205              segment_intersects1 (p3, p1, p4, p5, closed, o))
01206       return s;
01207     s = NEXT (s);
01208   } while (s != start);
01209   return NULL;
01210 }
01211 
01212 static gboolean new_ear (GtsSegment * s, 
01213                          Ear * e, 
01214                          GtsSegment * start,
01215                          guint sloppy,
01216                          GtsPoint * o)
01217 {
01218   gdouble or;
01219 
01220   e->s1 = s;
01221   e->s2 = NEXT (s);
01222 
01223   g_return_val_if_fail (e->s2, FALSE);
01224   g_return_val_if_fail (e->s2 != e->s1, FALSE);
01225 
01226   ORIENTED_VERTICES (e->s1, e->s2, e->v1, e->v2);
01227   e->v3 = e->s2->v1 != e->v2 ? e->s2->v1 : e->s2->v2;
01228   if (e->v3 == e->v1)
01229     return FALSE;
01230   e->s3 = NEXT (e->s2);
01231   if (gts_segment_connect (e->s3, e->v1, e->v3)) {
01232     if (NEXT (e->s3) != e->s1)
01233       return FALSE;
01234   }
01235   else if (gts_vertices_are_connected (e->v1, e->v3))
01236     return FALSE;
01237   else
01238     e->s3 = NULL;
01239   or = ORIENTATION (GTS_POINT (e->v1), GTS_POINT (e->v2), GTS_POINT (e->v3),o);
01240   switch (sloppy) {
01241   case 0: 
01242     if (or <= 0. ||
01243         triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2),
01244                                       GTS_POINT (e->v3), TRUE, start, o))
01245       return FALSE;
01246     break;
01247   case 1:
01248     if (or < 0. || 
01249         (or > 0. && 
01250          triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2),
01251                                        GTS_POINT (e->v3), FALSE, start, o)))
01252       return FALSE;
01253     break;
01254   case 2:
01255     if ((or > 0. && 
01256          triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2),
01257                                        GTS_POINT (e->v3), FALSE, start, o)) ||
01258         (or < 0. && 
01259          triangle_intersects_segments (GTS_POINT (e->v2), GTS_POINT (e->v1),
01260                                        GTS_POINT (e->v3), FALSE, start, o)))
01261       return FALSE;
01262     break;
01263   case 3:
01264     if (or < 0.)
01265       return FALSE;
01266     break;
01267   }
01268 #ifdef DEBUG
01269   if (or <= 0.)
01270     fprintf (stderr, "or: %g\n", or);
01271 #endif /* DEBUG */
01272   g_assert (or > -1e-6);
01273   return TRUE;
01274 }
01275 
01276 static void triangulate_loop (GtsSegment * start,
01277                               GtsSurface * surface,
01278                               GtsPoint * o)
01279 {
01280   GtsSegment * prev = start, * s;
01281   guint sloppy = 0;
01282 #ifdef DEBUG
01283   guint nt = 0;
01284 #endif /* DEBUG */
01285 
01286   s = NEXT (start);
01287   while (NEXT (s) != s) {
01288     GtsSegment * next = NEXT (s);
01289     Ear e;
01290 
01291 #ifdef DEBUG
01292     fprintf (stderr, "prev: %p s: %p next: %p\n", prev, s, next);
01293 #endif /* DEBUG */
01294   
01295     if (!new_ear (s, &e, start, sloppy, o)) {
01296       if (s == start) {
01297         sloppy++;
01298 #ifdef DEBUG
01299         fprintf (stderr, "sloppy: %u\n", sloppy);
01300 #endif /* DEBUG */
01301       }
01302       prev = s;
01303       s = next;
01304     }
01305     else {
01306       GtsFace * f;
01307 
01308       if (!GTS_IS_EDGE (e.s3))
01309         e.s3 = GTS_SEGMENT (gts_edge_new (surface->edge_class, e.v1, e.v3));
01310       f = gts_face_new (surface->face_class, 
01311                         GTS_EDGE (e.s1), GTS_EDGE (e.s2), GTS_EDGE (e.s3));
01312       gts_surface_add_face (surface, f);
01313       UNSET (e.s1, RELEVANT);
01314       UNSET (e.s1, INTERIOR);
01315       UNSET (e.s2, RELEVANT);
01316       UNSET (e.s2, INTERIOR);
01317       NEXT (prev) = e.s3;
01318       NEXT (e.s3) = NEXT (e.s2);
01319       NEXT (e.s1) = NEXT (e.s2) = NULL;
01320       start = prev;
01321       s = NEXT (prev);
01322       sloppy = 0;
01323 #ifdef DEBUG
01324       {
01325         gchar name[80];
01326         FILE * fp;
01327         
01328         fprintf (stderr, " t.%u: (%p:%s,%p:%s,%p:%s)\n",
01329                  nt, 
01330                  e.v1, NAME (e.v1),
01331                  e.v2, NAME (e.v2),
01332                  e.v3, NAME (e.v3));
01333         sprintf (name, "/tmp/t.%u", nt++);
01334         fp = fopen (name, "wt");
01335         //      gts_surface_write (surface, fp);
01336         gts_write_triangle (GTS_TRIANGLE (f), NULL, fp);
01337         //        write_graph1 (start, interior, surface, fp);
01338         fclose (fp);
01339         print_loop (start, stderr);
01340       }
01341 #endif /* DEBUG */
01342     }
01343   }
01344   UNSET (s, RELEVANT);
01345   UNSET (s, INTERIOR);
01346   NEXT (s) = NULL;
01347 }
01348 
01349 #ifdef CHECK_ORIENTED
01350 static void check_object (GtsObject * o)
01351 {
01352   g_assert (o->reserved == NULL);
01353   g_assert (o->flags == 0);  
01354 }
01355 
01356 static void check_boundary (GtsEdge * e, GtsSurface * s)
01357 {
01358   check_object (GTS_OBJECT (e));
01359   check_object (GTS_OBJECT (GTS_SEGMENT (e)->v1));
01360   check_object (GTS_OBJECT (GTS_SEGMENT (e)->v2));
01361   g_assert (gts_edge_face_number (e, s) == 1);
01362 }
01363 
01364 static void check_interior (GtsEdge * e, GtsSurface * s)
01365 {
01366   guint n;
01367   check_object (GTS_OBJECT (e));
01368   check_object (GTS_OBJECT (GTS_SEGMENT (e)->v1));
01369   check_object (GTS_OBJECT (GTS_SEGMENT (e)->v2));
01370 
01371   n = gts_edge_face_number (e, s);
01372 #ifdef DEBUG
01373   if (n != 2)
01374     gts_surface_print_stats (s, stderr);
01375 #endif /* DEBUG */
01376   g_assert (n == 2);
01377 }
01378 
01379 static void check_boundary_interior_triangulation (GSList * boundary,
01380                                                    GSList * interior,
01381                                                    GtsSurface * surface)
01382 {
01383   g_slist_foreach (boundary, (GFunc) check_boundary, surface);
01384   g_slist_foreach (interior, (GFunc) check_interior, surface);
01385 }
01386 #endif /*ifdef CHECK_ORIENTED */
01387 
01388 static void merge_duplicate (GtsEdge * e)
01389 {
01390   GtsEdge * dup = gts_edge_is_duplicate (e);
01391 
01392   g_assert (dup);
01393   gts_edge_replace (dup, e);
01394   gts_object_destroy (GTS_OBJECT (dup));
01395 }
01396 
01397 static void triangulate_boundary_interior (GSList * boundary, 
01398                                            GSList * interior,
01399                                            GtsSurface * s,
01400                                            GtsPoint * o)
01401 {
01402   GSList * iloops, * bloops, * i;
01403 
01404   i = boundary;
01405   while (i) {
01406     SET (i->data, RELEVANT);
01407     i = i->next;
01408   }
01409   i = interior;
01410   while (i) {
01411     SET (i->data, RELEVANT);
01412     SET (i->data, INTERIOR);
01413     i = i->next;
01414   }
01415 
01416   iloops = interior_loops (interior);
01417   bloops = boundary_loops (boundary);
01418 
01419   i = iloops;
01420   while (i) {
01421 #ifdef DEBUG
01422     fprintf (stderr, "--- interior loop ---\n");
01423     print_loop (i->data, stderr);
01424 #endif /* DEBUG */
01425     connect_interior_loop (i->data, &interior, &bloops, s, o);
01426     i = i->next;
01427   }
01428   
01429 #ifdef DEBUG
01430  {
01431    FILE * fp = fopen ("/tmp/bloops", "w");
01432    write_loops (bloops, fp);
01433    fclose (fp);
01434  }
01435 #endif /* DEBUG */
01436 
01437   i = bloops;
01438   while (i) {
01439 #ifdef DEBUG
01440     fprintf (stderr, "--- boundary loop ---\n");
01441     print_loop (i->data, stderr);
01442 #endif /* DEBUG */
01443     triangulate_loop (i->data, s, o);
01444     i = i->next;
01445   }
01446   
01447   g_slist_foreach (interior, (GFunc) merge_duplicate, NULL);
01448   g_slist_free (iloops);
01449   g_slist_free (bloops);
01450 
01451 #ifdef CHECK_ORIENTED
01452   check_boundary_interior_triangulation (boundary, interior, s);
01453 #endif /* CHECK_ORIENTED */
01454 }
01455 
01456 static void create_edges (GtsSegment * s, GtsSurface * surface)
01457 {
01458   if (GTS_OBJECT (s)->reserved) {
01459     GList * i = GTS_OBJECT (s)->reserved;
01460     GtsVertex * v1 = i->data;
01461 
01462     GTS_OBJECT (s)->reserved = g_list_prepend (i, 
01463                       gts_edge_new (surface->edge_class, s->v1, v1));
01464     while (i) {
01465       GList * next = i->next;
01466       GtsVertex * v2 = next ? next->data : s->v2;
01467 
01468       GTS_OBJECT (i->data)->reserved = NULL;
01469       i->data = gts_edge_new (surface->edge_class, v1, v2);
01470       v1 = v2;
01471       i = next;
01472     }
01473   }
01474 }
01475 
01476 static void add_boundary (GtsSegment * s, GtsSegment * next, 
01477                           GSList ** boundary)
01478 {
01479   if (GTS_OBJECT (s)->reserved == NULL)
01480     *boundary = g_slist_prepend (*boundary, s);
01481   else {
01482     if (s->v2 == next->v2 || s->v2 == next->v1) {
01483       GList * i = g_list_last (GTS_OBJECT (s)->reserved);
01484 
01485       while (i) {
01486         *boundary = g_slist_prepend (*boundary, i->data);
01487         i = i->prev;
01488       }
01489     }
01490     else {
01491       GList * i = GTS_OBJECT (s)->reserved;
01492 
01493       while (i) {
01494         *boundary = g_slist_prepend (*boundary, i->data);
01495         i = i->next;
01496       }
01497     }
01498   }
01499 }
01500 
01501 static void triangulate_face (GtsTriangle * t, GtsSurface * surface)
01502 {
01503   GSList * interior = GTS_OBJECT (t)->reserved;
01504   GSList * boundary = NULL;
01505   GtsSurface * s = gts_surface_new (gts_surface_class (),
01506                                     surface->face_class,
01507                                     surface->edge_class,
01508                                     surface->vertex_class);
01509   gdouble x, y, z;
01510   GtsPoint * p = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
01511   GtsPoint * o;
01512 
01513   GTS_OBJECT (t)->reserved = NULL;  
01514   gts_triangle_normal (t, &x, &y, &z);
01515   g_assert (x != 0. || y != 0. || z != 0.);
01516   o = gts_point_new (gts_point_class (), p->x + x, p->y + y, p->z + z);
01517   add_boundary (GTS_SEGMENT (t->e3), GTS_SEGMENT (t->e1), &boundary);
01518   add_boundary (GTS_SEGMENT (t->e2), GTS_SEGMENT (t->e3), &boundary);
01519   add_boundary (GTS_SEGMENT (t->e1), GTS_SEGMENT (t->e2), &boundary);
01520 #ifdef DEBUG
01521   {
01522     static guint nt = 0;
01523     char name[80];
01524     FILE * fp;
01525 
01526     fprintf (stderr, "%u: triangulating %p\n", nt, t);
01527 if (nt == 28)
01528   fprintf (stderr, "tintin!!!!\n");
01529     sprintf (name, "/tmp/oc.%u", nt++);
01530     fp = fopen (name, "wt");
01531     //    write_graph (boundary, interior, s, fp);
01532     write_segments (boundary, interior, fp);
01533     fclose (fp);
01534   }
01535 #endif /* DEBUG */
01536   triangulate_boundary_interior (boundary, interior, s, o);
01537   g_slist_free (interior);
01538   g_slist_free (boundary);
01539   if (GTS_OBJECT (t)->klass->attributes)
01540     gts_surface_foreach_face (s, (GtsFunc) gts_object_attributes, t);
01541   gts_surface_merge (surface, s);
01542   gts_object_destroy (GTS_OBJECT (s));
01543   gts_object_destroy (GTS_OBJECT (o));
01544 }
01545 
01546 static void free_edge_list (GtsObject * o)
01547 {
01548   g_list_free (o->reserved);
01549   o->reserved = NULL;
01550 }
01551 
01570 GtsSurfaceInter * gts_surface_inter_new (GtsSurfaceInterClass * klass,
01571                                          GtsSurface * s1,
01572                                          GtsSurface * s2,
01573                                          GNode * faces_tree1,
01574                                          GNode * faces_tree2,
01575                                          gboolean is_open1,
01576                                          gboolean is_open2)
01577 {
01578   GtsSurfaceInter * si;
01579   GtsSurface * s;
01580 
01581   g_return_val_if_fail (klass != NULL, NULL);
01582   g_return_val_if_fail (s1 != NULL, NULL);
01583   g_return_val_if_fail (s2 != NULL, NULL);
01584   g_return_val_if_fail (faces_tree1 != NULL, NULL);
01585   g_return_val_if_fail (faces_tree2 != NULL, NULL);
01586 
01587   si = surface_inter_new (klass, s1, s2, faces_tree1, faces_tree2);
01588 
01589   gts_surface_foreach_edge (si->s1, (GtsFunc) create_edges, si->s1);
01590   gts_surface_foreach_edge (si->s2, (GtsFunc) create_edges, si->s2);
01591 
01592 #ifdef DEBUG
01593   fprintf (stderr, "====== triangulating s1 ======\n");
01594 #endif /* DEBUG */
01595   s = gts_surface_new (gts_surface_class (),
01596                        s1->face_class,
01597                        s1->edge_class,
01598                        s1->vertex_class);
01599   gts_surface_foreach_face (si->s1, (GtsFunc) triangulate_face, s);
01600   gts_surface_foreach_edge (si->s1, (GtsFunc) free_edge_list, NULL);
01601   gts_object_destroy (GTS_OBJECT (si->s1));
01602   si->s1 = s;
01603   GTS_OBJECT (si->s1)->reserved = s1;
01604   
01605 #ifdef DEBUG
01606   fprintf (stderr, "====== triangulating s2 ======\n");
01607 #endif /* DEBUG */
01608   s = gts_surface_new (gts_surface_class (),
01609                        s2->face_class,
01610                        s2->edge_class,
01611                        s2->vertex_class);
01612   gts_surface_foreach_face (si->s2, (GtsFunc) triangulate_face, s);
01613   gts_surface_foreach_edge (si->s2, (GtsFunc) free_edge_list, NULL);
01614   gts_object_destroy (GTS_OBJECT (si->s2));
01615   si->s2 = s;
01616   GTS_OBJECT (si->s2)->reserved = s2;
01617 
01618   return si;
01619 }
01620 
01621 static void check_surface_edge (GtsEdge * e, gpointer * data)
01622 {
01623   gboolean * ok = data[0];
01624   GtsSurface * s = data[1];
01625   GtsSurface * bs = GTS_OBJECT (s)->reserved;
01626   guint nf = gts_edge_face_number (e, s);
01627 
01628   if (nf < 1 || nf > 2) {
01629     *ok = FALSE;
01630     g_return_if_fail (nf >= 1 && nf <= 2);
01631   }
01632   if (nf == 1 && gts_edge_face_number (e, bs) == 0) {
01633     *ok = FALSE;
01634     g_return_if_fail (gts_edge_face_number (e, bs) > 0);
01635   }
01636 }
01637 
01638 static void mark_edge (GtsObject * o, gpointer data)
01639 {
01640   o->reserved = data;
01641 }
01642 
01643 static gint triangle_orientation (GtsTriangle * t, GtsEdge * e)
01644 {
01645   GtsSegment * s = GTS_SEGMENT (t->e1 == e ? t->e2 
01646                                 : 
01647                                 t->e2 == e ? t->e3 
01648                                 : 
01649                                 t->e1);
01650   GtsVertex * v2 = GTS_SEGMENT (e)->v2;
01651 
01652   if (s->v1 == v2 || s->v2 == v2)
01653     return 1;
01654   return -1;
01655 }
01656 
01657 static gboolean check_orientation (GtsEdge * e, GtsSurface * s)
01658 {
01659   GtsTriangle * t1 = NULL, * t2 = NULL;
01660   GSList * i = e->triangles;
01661   gint o1 = 0, o2 = 0;
01662 
01663   while (i) {
01664     if (GTS_IS_FACE (i->data) && 
01665         gts_face_has_parent_surface (i->data, s)) {
01666       if (t1 == NULL) {
01667         t1 = i->data;
01668         o1 = triangle_orientation (t1, e);
01669       }
01670       else if (t2 == NULL) {
01671         t2 = i->data;
01672         o2 = triangle_orientation (t2, e);
01673         g_return_val_if_fail (o1*o2 < 0, FALSE);
01674       }
01675       else
01676         g_assert_not_reached ();
01677     }
01678     i = i->next;
01679   }
01680   g_return_val_if_fail (t1 && t2, FALSE);
01681   return TRUE;
01682 }
01683 
01684 static void check_edge (GtsSegment * s, gpointer * data)
01685 {
01686   gboolean * ok = data[0];
01687   GtsSurfaceInter * si = data[1];
01688   gboolean * closed = data[2];
01689   GSList * j;
01690   guint nn = 0;
01691   
01692   j = s->v1->segments;
01693   while (j && *ok) {
01694     GtsSegment * s1 = j->data;
01695     
01696     if (s1 != s && GTS_OBJECT (s1)->reserved == si) {
01697       if (s1->v2 != s->v1)
01698         *ok = FALSE;
01699       nn++;
01700     }
01701     j = j->next;
01702   }
01703   j = s->v2->segments;
01704   while (j && *ok) {
01705     GtsSegment * s1 = j->data;
01706     
01707     if (s1 != s && GTS_OBJECT (s1)->reserved == si) {
01708       if (s1->v1 != s->v2)
01709         *ok = FALSE;
01710       nn++;
01711     }
01712     j = j->next;
01713   }
01714   if (nn != 2)
01715     *closed = FALSE;
01716 
01717   if (!check_orientation (GTS_EDGE (s), si->s1))
01718     *ok = FALSE;
01719   if (!check_orientation (GTS_EDGE (s), si->s2))
01720     *ok = FALSE;
01721 }
01722 
01732 gboolean gts_surface_inter_check (GtsSurfaceInter * si,
01733                                   gboolean * closed)
01734 {
01735   gboolean ok = TRUE;
01736   gpointer data[3];
01737 
01738   g_return_val_if_fail (si != NULL, FALSE);
01739   g_return_val_if_fail (closed != NULL, FALSE);
01740 
01741   *closed = si->edges ? TRUE : FALSE;
01742 
01743   /* mark edges as used by si */
01744   g_slist_foreach (si->edges, (GFunc) mark_edge, si);
01745 
01746   data[0] = &ok;
01747   data[1] = si;
01748   data[2] = closed;
01749   g_slist_foreach (si->edges, (GFunc) check_edge, data);
01750   g_slist_foreach (si->edges, (GFunc) gts_object_reset_reserved, NULL);
01751 
01752   /* check connectivity of the faces of @si */
01753   if (*closed) {
01754     gpointer data[2];
01755 
01756     data[0] = &ok;
01757     data[1] = si->s1;
01758     gts_surface_foreach_edge (si->s1, (GtsFunc) check_surface_edge, data);
01759     data[1] = si->s2;
01760     gts_surface_foreach_edge (si->s2, (GtsFunc) check_surface_edge, data);
01761   }
01762 
01763   return ok;
01764 }
01765 
01766 /* Given @e and @f returns a #GtsFace compatible with @f and belonging to
01767    @s1 or @s2 */
01768 static GtsFace * next_compatible_face (GtsEdge * e, 
01769                                        GtsFace * f, 
01770                                        GtsSurface * s1,
01771                                        GtsSurface * s2)
01772 {
01773   GSList * i = e->triangles;
01774   GtsFace * f2 = NULL, * f3 = NULL;
01775 
01776   while (i) {
01777     GtsFace * f1 = i->data;
01778 
01779     if (f1 != f && GTS_IS_FACE (f1)) {
01780       if (gts_face_has_parent_surface (f1, s1))
01781         return f1;
01782       if (gts_face_has_parent_surface (f1, s2)) {
01783         if (f2 == NULL) f2 = f1;
01784         else if (f3 == NULL) f3 = f1;
01785         else g_assert_not_reached (); /* s2 is a non-manifold surface */
01786       }
01787     }
01788     i = i->next;
01789   }
01790   if (f3 == NULL) {
01791     if (gts_edge_is_boundary (e, s2))
01792       return NULL;
01793     return f2; 
01794   }
01795   g_assert (gts_face_has_parent_surface (f, s1));
01796   if (gts_triangles_are_compatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f2), e))
01797     return f2;
01798   return f3;
01799 }
01800 
01801 static void walk_faces (GtsEdge * e, GtsFace * f, 
01802                         GtsSurface * s1,
01803                         GtsSurface * s2,
01804                         GtsSurface * s)
01805 {
01806   GtsFifo * faces = gts_fifo_new ();
01807   GtsFifo * edges = gts_fifo_new ();
01808 
01809   gts_fifo_push (faces, f);
01810   gts_fifo_push (edges, e);
01811   while ((f = gts_fifo_pop (faces)) && (e = gts_fifo_pop (edges))) {
01812     if (!GTS_OBJECT (f)->reserved) {
01813       GtsTriangle * t = GTS_TRIANGLE (f);
01814       GtsFace * f1;
01815 
01816       gts_surface_add_face (s, f);
01817       GTS_OBJECT (f)->reserved = s;
01818       if (t->e1 != e && !GTS_OBJECT (t->e1)->reserved &&
01819           (f1 = next_compatible_face (t->e1, f, s1, s2))) {
01820         gts_fifo_push (faces, f1);
01821         gts_fifo_push (edges, t->e1);
01822       } 
01823       if (t->e2 != e && !GTS_OBJECT (t->e2)->reserved &&
01824           (f1 = next_compatible_face (t->e2, f, s1, s2))) {
01825         gts_fifo_push (faces, f1);
01826         gts_fifo_push (edges, t->e2);
01827       } 
01828       if (t->e3 != e && !GTS_OBJECT (t->e3)->reserved &&
01829           (f1 = next_compatible_face (t->e3, f, s1, s2))) {
01830         gts_fifo_push (faces, f1);
01831         gts_fifo_push (edges, t->e3);
01832       } 
01833     }
01834   }
01835   gts_fifo_destroy (faces);
01836   gts_fifo_destroy (edges);
01837 }
01838 
01847 void gts_surface_inter_boolean (GtsSurfaceInter * si,
01848                                 GtsSurface * surface,
01849                                 GtsBooleanOperation op)
01850 {
01851   GtsSurface * s = NULL;
01852   gint orient = 1;
01853   GSList * i;
01854 
01855   g_return_if_fail (si != NULL);
01856   g_return_if_fail (surface != NULL);
01857 
01858   switch (op) {
01859   case GTS_1_OUT_2: s = si->s1; orient = 1; break;
01860   case GTS_1_IN_2: s = si->s1; orient = -1; break;
01861   case GTS_2_OUT_1: s = si->s2; orient = -1; break;
01862   case GTS_2_IN_1: s = si->s2; orient = 1; break;
01863   default: g_assert_not_reached ();
01864   }
01865 
01866   /* mark edges as belonging to intersection */
01867   g_slist_foreach (si->edges, (GFunc) mark_edge, si);
01868 
01869   i = si->edges;
01870   while (i) {
01871     GtsEdge * e = i->data;
01872     GSList * j = e->triangles;
01873     
01874     while (j) {
01875       if (gts_face_has_parent_surface (j->data, s) &&
01876           orient*triangle_orientation (j->data, e) > 0) {
01877 #ifdef DEBUG_BOOLEAN
01878         GtsFace * boundary = gts_edge_is_boundary (e, surface);
01879 
01880         g_assert (!boundary || boundary == j->data);
01881 #endif /* DEBUG_BOOLEAN */
01882         walk_faces (e, j->data, s, GTS_OBJECT (s)->reserved, surface);
01883         break;
01884       }
01885       j = j->next;
01886     }
01887     i = i->next;
01888   }
01889   g_slist_foreach (si->edges, (GFunc) gts_object_reset_reserved, NULL);
01890   gts_surface_foreach_face (surface, 
01891                             (GtsFunc) gts_object_reset_reserved, NULL);
01892 }
01893 
01894 static void self_intersecting (GtsBBox * bb1, GtsBBox * bb2, 
01895                                gpointer * d)
01896 {
01897   GtsTriangle * t1 = bb1->bounded;
01898   GtsTriangle * t2 = bb2->bounded;
01899 
01900   if (t1 != t2) {
01901     GtsSegment * s1 = GTS_SEGMENT (t1->e1);
01902     GtsSegment * s2 = GTS_SEGMENT (t1->e2);
01903     GtsSegment * s3 = GTS_SEGMENT (t1->e3);
01904     GtsSegment * s4 = GTS_SEGMENT (t2->e1);
01905     GtsSegment * s5 = GTS_SEGMENT (t2->e2);
01906     GtsSegment * s6 = GTS_SEGMENT (t2->e3);
01907     GtsPoint * pi;
01908 
01909     if ((!gts_segments_touch (s4, s1) && 
01910          !gts_segments_touch (s4, s2) &&
01911          !gts_segments_touch (s4, s3) &&
01912          (pi = segment_triangle_intersection (s4, t1, gts_point_class ()))
01913          != NULL) ||
01914         (!gts_segments_touch (s5, s1) && 
01915          !gts_segments_touch (s5, s2) &&
01916          !gts_segments_touch (s5, s3) &&
01917          (pi = segment_triangle_intersection (s5, t1, gts_point_class ())) 
01918          != NULL) ||
01919         (!gts_segments_touch (s6, s1) && 
01920          !gts_segments_touch (s6, s2) &&
01921          !gts_segments_touch (s6, s3) &&
01922          (pi = segment_triangle_intersection (s6, t1, gts_point_class ())) 
01923          != NULL)) {
01924       GtsBBTreeTraverseFunc func = d[0];
01925       gpointer data = d[1];
01926       gboolean * self_inter = d[2];
01927 
01928       gts_object_destroy (GTS_OBJECT (pi));
01929       *self_inter = TRUE;
01930       (* func) (bb1, bb2, data);
01931     }
01932   }
01933 }
01934 
01945 gboolean gts_surface_foreach_intersecting_face (GtsSurface * s,
01946                                                 GtsBBTreeTraverseFunc func,
01947                                                 gpointer data)
01948 {
01949   GNode * tree;
01950   gpointer d[3];
01951   gboolean self_inter = FALSE;
01952 
01953   g_return_val_if_fail (s != NULL, FALSE);
01954   g_return_val_if_fail (func != NULL, FALSE);
01955 
01956   tree = gts_bb_tree_surface (s);
01957   d[0] = func;
01958   d[1] = data;
01959   d[2] = &self_inter;
01960   gts_bb_tree_traverse_overlapping (tree, tree, 
01961                                     (GtsBBTreeTraverseFunc) self_intersecting,
01962                                     d);
01963   gts_bb_tree_destroy (tree, TRUE);
01964 
01965   return self_inter;
01966 }
01967 
01968 static void add_intersecting (GtsBBox * bb1, GtsBBox * bb2, 
01969                               GtsSurface * intersected)
01970 {
01971   gts_surface_add_face (intersected, bb1->bounded);
01972   gts_surface_add_face (intersected, bb2->bounded);
01973 }
01974 
01982 GtsSurface * gts_surface_is_self_intersecting (GtsSurface * s)
01983 {
01984   GtsSurface * intersected;
01985 
01986   g_return_val_if_fail (s != NULL, NULL);
01987 
01988   intersected = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass),
01989                                  s->face_class,
01990                                  s->edge_class,
01991                                  s->vertex_class);
01992   if (!gts_surface_foreach_intersecting_face (s,
01993                       (GtsBBTreeTraverseFunc) add_intersecting, intersected)) {
01994     gts_object_destroy (GTS_OBJECT (intersected));
01995     intersected = NULL;
01996   }
01997   return intersected;
01998 }