pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 }