pcb 4.1.1
An interactive printed circuit board layout editor.

psurface.c

Go to the documentation of this file.
00001 /* GTS - Library for the manipulation of triangulated surfaces
00002  * Copyright (C) 1999 Stéphane Popinet
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #include <stdlib.h>
00021 #include <math.h>
00022 #include "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 }