pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 /* GTS - Library for the manipulation of triangulated surfaces 00002 * Copyright (C) 1999 Stéphane Popinet 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Library General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Library General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Library General Public 00015 * License along with this library; if not, write to the 00016 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 * Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <math.h> 00022 #include "gts.h" 00023 00024 #define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\ 00025 gts_eheap_insert (h, e)) 00026 #define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\ 00027 GTS_OBJECT (e)->reserved = NULL) 00028 00029 static void psurface_destroy (GtsObject * object) 00030 { 00031 GtsPSurface * ps = GTS_PSURFACE (object); 00032 guint i; 00033 00034 if (!GTS_PSURFACE_IS_CLOSED (ps)) 00035 gts_psurface_close (ps); 00036 00037 for (i = 0; i < ps->split->len; i++) 00038 if (g_ptr_array_index (ps->split, i)) 00039 gts_object_destroy (GTS_OBJECT (g_ptr_array_index (ps->split, i))); 00040 g_ptr_array_free (ps->split, TRUE); 00041 00042 (* GTS_OBJECT_CLASS (gts_psurface_class ())->parent_class->destroy) (object); 00043 } 00044 00045 static void psurface_class_init (GtsObjectClass * klass) 00046 { 00047 klass->destroy = psurface_destroy; 00048 } 00049 00050 static void psurface_init (GtsPSurface * psurface) 00051 { 00052 psurface->s = NULL; 00053 psurface->split = g_ptr_array_new (); 00054 psurface->split_class = gts_split_class (); 00055 psurface->pos = psurface->min = 0; 00056 psurface->vertices = psurface->faces = NULL; 00057 } 00058 00064 GtsPSurfaceClass * gts_psurface_class (void) 00065 { 00066 static GtsPSurfaceClass * klass = NULL; 00067 00068 if (klass == NULL) { 00069 GtsObjectClassInfo psurface_info = { 00070 "GtsPSurface", 00071 sizeof (GtsPSurface), 00072 sizeof (GtsPSurfaceClass), 00073 (GtsObjectClassInitFunc) psurface_class_init, 00074 (GtsObjectInitFunc) psurface_init, 00075 (GtsArgSetFunc) NULL, 00076 (GtsArgGetFunc) NULL 00077 }; 00078 klass = gts_object_class_new (gts_object_class (), 00079 &psurface_info); 00080 } 00081 00082 return klass; 00083 } 00084 00085 static GtsVertex * edge_collapse (GtsPSurface * ps, 00086 GtsEdge * e, 00087 GtsEHeap * heap, 00088 GtsCoarsenFunc coarsen_func, 00089 gpointer coarsen_data, 00090 gdouble maxcosine2) 00091 { 00092 GtsVertex * v1 = GTS_SEGMENT (e)->v1, * v2 = GTS_SEGMENT (e)->v2, * mid; 00093 GtsSplit * vs; 00094 GtsObject * o1, * o2; 00095 00096 /* if the edge is degenerate (i.e. v1 == v2), destroy and return */ 00097 if (v1 == v2) { 00098 gts_object_destroy (GTS_OBJECT (e)); 00099 return NULL; 00100 } 00101 00102 if (!gts_edge_collapse_is_valid (e) || 00103 /* check that a non-manifold edge is not a contact edge */ 00104 (g_slist_length (e->triangles) > 2 && gts_edge_is_contact (e) > 1)) { 00105 GTS_OBJECT (e)->reserved = 00106 gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); 00107 return NULL; 00108 } 00109 00110 mid = (*coarsen_func) (e, ps->s->vertex_class, coarsen_data); 00111 00112 if (gts_edge_collapse_creates_fold (e, mid, maxcosine2)) { 00113 GTS_OBJECT (e)->reserved = 00114 gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); 00115 gts_object_destroy (GTS_OBJECT (mid)); 00116 return NULL; 00117 } 00118 00119 if (GTS_OBJECT (v1)->reserved) 00120 o1 = GTS_OBJECT (v1)->reserved; 00121 else 00122 o1 = GTS_OBJECT (v1); 00123 if (GTS_OBJECT (v2)->reserved) 00124 o2 = GTS_OBJECT (v2)->reserved; 00125 else 00126 o2 = GTS_OBJECT (v2); 00127 vs = gts_split_new (ps->split_class, mid, o1, o2); 00128 gts_split_collapse (vs, ps->s->edge_class, heap); 00129 GTS_OBJECT (vs->v)->reserved = vs; 00130 g_ptr_array_add (ps->split, vs); 00131 00132 return mid; 00133 } 00134 00135 static void update_2nd_closest_neighbors (GtsVertex * v, GtsEHeap * heap) 00136 { 00137 GSList * i = v->segments; 00138 GSList * list = NULL; 00139 00140 while (i) { 00141 GtsSegment * s = i->data; 00142 if (GTS_IS_EDGE (s)) { 00143 GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1; 00144 GSList * j = v1->segments; 00145 while (j) { 00146 GtsSegment * s1 = j->data; 00147 if (GTS_IS_EDGE (s1) && !g_slist_find (list, s1)) 00148 list = g_slist_prepend (list, s1); 00149 j = j->next; 00150 } 00151 } 00152 i = i->next; 00153 } 00154 00155 i = list; 00156 while (i) { 00157 GtsEdge * e = i->data; 00158 if (GTS_OBJECT (e)->reserved) 00159 HEAP_REMOVE_OBJECT (heap, e); 00160 HEAP_INSERT_OBJECT (heap, e); 00161 i = i->next; 00162 } 00163 00164 g_slist_free (list); 00165 } 00166 00167 static gdouble edge_length2 (GtsEdge * e) 00168 { 00169 return gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), 00170 GTS_POINT (GTS_SEGMENT (e)->v2)); 00171 } 00172 00173 static void create_heap_coarsen (GtsEdge * e, GtsEHeap * heap) 00174 { 00175 HEAP_INSERT_OBJECT (heap, e); 00176 } 00177 00178 /* #define DEBUG_FOLD */ 00179 /* #define DEBUG_CONTACT_VERTEX */ 00180 00181 #ifdef DEBUG_FOLD 00182 static void check_fold (GtsTriangle * t, gdouble * maxcosine2) 00183 { 00184 GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; 00185 00186 00187 if (gts_triangles_are_folded (e1->triangles, 00188 GTS_SEGMENT (e1)->v1, 00189 GTS_SEGMENT (e1)->v2, 00190 *maxcosine2) || 00191 gts_triangles_are_folded (e2->triangles, 00192 GTS_SEGMENT (e2)->v1, 00193 GTS_SEGMENT (e2)->v2, 00194 *maxcosine2) || 00195 gts_triangles_are_folded (e3->triangles, 00196 GTS_SEGMENT (e3)->v1, 00197 GTS_SEGMENT (e3)->v2, 00198 *maxcosine2)) { 00199 fprintf (stderr, "triangle %p:(%p,%p,%p) is folded\n", t, e1, e2, e3); 00200 g_assert_not_reached (); 00201 } 00202 } 00203 #endif 00204 00228 GtsPSurface * gts_psurface_new (GtsPSurfaceClass * klass, 00229 GtsSurface * surface, 00230 GtsSplitClass * split_class, 00231 GtsKeyFunc cost_func, 00232 gpointer cost_data, 00233 GtsCoarsenFunc coarsen_func, 00234 gpointer coarsen_data, 00235 GtsStopFunc stop_func, 00236 gpointer stop_data, 00237 gdouble minangle) 00238 { 00239 GtsPSurface * psurface; 00240 GtsEHeap * heap; 00241 GtsEdge * e; 00242 gdouble top_cost, maxcosine2; 00243 guint i; 00244 00245 g_return_val_if_fail (klass != NULL, NULL); 00246 g_return_val_if_fail (surface != NULL, NULL); 00247 g_return_val_if_fail (split_class != NULL, NULL); 00248 g_return_val_if_fail (stop_func != NULL, NULL); 00249 00250 psurface = GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); 00251 psurface->s = surface; 00252 psurface->split_class = split_class; 00253 00254 if (cost_func == NULL) 00255 cost_func = (GtsKeyFunc) edge_length2; 00256 if (coarsen_func == NULL) 00257 coarsen_func = (GtsCoarsenFunc) gts_segment_midvertex; 00258 00259 heap = gts_eheap_new (cost_func, cost_data); 00260 maxcosine2 = cos (minangle); maxcosine2 *= maxcosine2; 00261 00262 gts_eheap_freeze (heap); 00263 gts_surface_foreach_edge (surface, (GtsFunc) create_heap_coarsen, heap); 00264 gts_eheap_thaw (heap); 00265 /* we want to control edge destruction manually */ 00266 gts_allow_floating_edges = TRUE; 00267 while ((e = gts_eheap_remove_top (heap, &top_cost)) && 00268 (top_cost < G_MAXDOUBLE) && 00269 !(*stop_func) (top_cost, gts_eheap_size (heap) - 00270 gts_edge_face_number (e, surface), stop_data)) { 00271 GtsVertex * v = edge_collapse (psurface, e, heap, 00272 coarsen_func, coarsen_data, maxcosine2); 00273 if (v != NULL) { 00274 update_2nd_closest_neighbors (v, heap); 00275 #ifdef DEBUG_FOLD 00276 { 00277 GSList * triangles = gts_vertex_triangles (v, NULL), * i; 00278 fprintf (stderr, "\n---- Check for folds ----\n%p: ", v); 00279 i = triangles; 00280 while (i) { 00281 GtsTriangle * t = i->data; 00282 fprintf (stderr, "%p:(%p,%p,%p) ", t, t->e1, t->e2, t->e3); 00283 i = i->next; 00284 } 00285 fprintf (stderr, "\n"); 00286 g_slist_free (triangles); 00287 gts_surface_foreach_face (surface, (GtsFunc) check_fold, &maxcosine2); 00288 } 00289 #endif 00290 #ifdef DEBUG_CONTACT_VERTEX 00291 if (gts_vertex_is_contact (v, FALSE) != 1) { 00292 FILE * fptr = fopen ("after", "wt"); 00293 GSList * triangles = gts_vertex_triangles (v, NULL), * i; 00294 00295 fprintf (stderr, "collapse of %p created a contact vertex\n", e); 00296 00297 fprintf (fptr, 00298 "(geometry \"sphere\" { = SPHERE 0.1 0. 0. 0. })\n" 00299 "(normalization \"sphere\" none)\n"); 00300 i = triangles; 00301 while (i) { 00302 gts_write_triangle (i->data, GTS_POINT (v), fptr); 00303 i = i->next; 00304 } 00305 g_assert_not_reached (); 00306 } 00307 #endif 00308 } 00309 } 00310 gts_allow_floating_edges = FALSE; 00311 00312 /* set reserved field of remaining edges back to NULL */ 00313 if (e) GTS_OBJECT (e)->reserved = NULL; 00314 gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); 00315 00316 gts_eheap_destroy (heap); 00317 00318 psurface->pos = psurface->split->len; 00319 psurface->min = gts_surface_vertex_number (psurface->s); 00320 00321 /* set reserved field of vertices (used to build the hierarchy) 00322 back to NULL */ 00323 for (i = 0; i < psurface->split->len; i++) { 00324 GtsSplit * vs = g_ptr_array_index (psurface->split, i); 00325 gts_object_reset_reserved (GTS_OBJECT (vs->v)); 00326 } 00327 00328 return psurface; 00329 } 00330 00341 GtsSplit * gts_psurface_add_vertex (GtsPSurface * ps) 00342 { 00343 GtsSplit * vs; 00344 00345 g_return_val_if_fail (ps != NULL, NULL); 00346 g_return_val_if_fail (GTS_PSURFACE_IS_CLOSED (ps), NULL); 00347 00348 if (ps->pos == 0) 00349 return NULL; 00350 00351 vs = g_ptr_array_index (ps->split, --ps->pos); 00352 gts_split_expand (vs, ps->s, ps->s->edge_class); 00353 00354 return vs; 00355 } 00356 00367 GtsSplit * gts_psurface_remove_vertex (GtsPSurface * ps) 00368 { 00369 GtsSplit * vs; 00370 00371 g_return_val_if_fail (ps != NULL, NULL); 00372 g_return_val_if_fail (GTS_PSURFACE_IS_CLOSED (ps), NULL); 00373 00374 if (ps->pos == ps->split->len) 00375 return NULL; 00376 00377 vs = g_ptr_array_index (ps->split, ps->pos++); 00378 gts_split_collapse (vs, ps->s->edge_class, NULL); 00379 00380 return vs; 00381 } 00382 00390 guint gts_psurface_max_vertex_number (GtsPSurface * ps) 00391 { 00392 g_return_val_if_fail (ps != NULL, 0); 00393 00394 return ps->min + ps->split->len; 00395 } 00396 00404 guint gts_psurface_min_vertex_number (GtsPSurface * ps) 00405 { 00406 g_return_val_if_fail (ps != NULL, 0); 00407 00408 return ps->min; 00409 } 00410 00419 void gts_psurface_set_vertex_number (GtsPSurface * ps, guint n) 00420 { 00421 g_return_if_fail (ps != NULL); 00422 g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps)); 00423 00424 n = ps->min + ps->split->len - n; 00425 while (ps->pos > n && gts_psurface_add_vertex (ps)) 00426 ; 00427 while (ps->pos < n && gts_psurface_remove_vertex (ps)) 00428 ; 00429 } 00430 00437 guint gts_psurface_get_vertex_number (GtsPSurface * ps) 00438 { 00439 g_return_val_if_fail (ps != NULL, 0); 00440 00441 if (!GTS_PSURFACE_IS_CLOSED (ps)) 00442 return ps->min + ps->pos; 00443 else 00444 return ps->min + ps->split->len - ps->pos; 00445 } 00446 00457 void gts_psurface_foreach_vertex (GtsPSurface * ps, 00458 GtsFunc func, 00459 gpointer data) 00460 { 00461 guint i; 00462 00463 g_return_if_fail (ps != NULL); 00464 g_return_if_fail (func != NULL); 00465 g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps)); 00466 00467 for (i = 0; i < ps->split->len; i++) { 00468 GtsSplit * vs = g_ptr_array_index (ps->split, i); 00469 (*func) (vs->v, data); 00470 } 00471 }