pcb 4.1.1
An interactive printed circuit board layout editor.

edge.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 "gts.h"
00021 
00022 gboolean gts_allow_floating_edges = FALSE;
00023 
00024 static void edge_destroy (GtsObject * object)
00025 {
00026   GtsEdge * edge = GTS_EDGE (object);
00027   GSList * i;
00028 
00029   i = edge->triangles;
00030   while (i) {
00031     GSList * next = i->next;
00032     gts_object_destroy (i->data);
00033     i = next;
00034   }
00035   g_assert (edge->triangles == NULL);
00036 
00037   (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->destroy) (object);
00038 }
00039 
00040 static void edge_clone (GtsObject * clone, GtsObject * object)
00041 {
00042   (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->clone) (clone,
00043                                                                  object);
00044   GTS_SEGMENT (clone)->v1 = GTS_SEGMENT (clone)->v2 = NULL;
00045   GTS_EDGE (clone)->triangles = NULL;
00046 }
00047 
00048 static void edge_class_init (GtsObjectClass * klass)
00049 {
00050   klass->clone = edge_clone;
00051   klass->destroy = edge_destroy;
00052 }
00053 
00054 static void edge_init (GtsEdge * edge)
00055 {
00056   edge->triangles = NULL;
00057 }
00058 
00064 GtsEdgeClass * gts_edge_class (void)
00065 {
00066   static GtsEdgeClass * klass = NULL;
00067 
00068   if (klass == NULL) {
00069     GtsObjectClassInfo edge_info = {
00070       "GtsEdge",
00071       sizeof (GtsEdge),
00072       sizeof (GtsEdgeClass),
00073       (GtsObjectClassInitFunc) edge_class_init,
00074       (GtsObjectInitFunc) edge_init,
00075       (GtsArgSetFunc) NULL,
00076       (GtsArgGetFunc) NULL
00077     };
00078     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_segment_class ()), 
00079                                   &edge_info);
00080   }
00081 
00082   return klass;
00083 }
00084 
00093 GtsEdge * gts_edge_new (GtsEdgeClass * klass,
00094                         GtsVertex * v1, GtsVertex * v2)
00095 {
00096   return GTS_EDGE (gts_segment_new (GTS_SEGMENT_CLASS (klass), v1, v2));
00097 }
00098 
00099 void gts_edge_remove(GtsEdge *edge) 
00100 {
00101   edge->segment.v1->segments = g_slist_remove(edge->segment.v1->segments, &edge->segment);
00102   edge->segment.v2->segments = g_slist_remove(edge->segment.v2->segments, &edge->segment);
00103   edge_destroy(GTS_OBJECT (edge));
00104 }
00105 
00116 void gts_edge_replace (GtsEdge * e, GtsEdge * with)
00117 {
00118   GSList * i;
00119 
00120   g_return_if_fail (e != NULL && with != NULL && e != with);
00121 
00122   i = e->triangles;
00123   while (i) {
00124     GtsTriangle * t = i->data;
00125     if (t->e1 == e) t->e1 = with;
00126     if (t->e2 == e) t->e2 = with;
00127     if (t->e3 == e) t->e3 = with;
00128     if (!g_slist_find (with->triangles, t))
00129       with->triangles = g_slist_prepend (with->triangles, t);
00130     i = i->next;
00131   }
00132   g_slist_free (e->triangles);
00133   e->triangles = NULL;
00134 }
00135 
00143 GtsFace * gts_edge_has_parent_surface (GtsEdge * e, GtsSurface * surface)
00144 {
00145   GSList * i;
00146 
00147   g_return_val_if_fail (e != NULL, NULL);
00148 
00149   i = e->triangles;
00150   while (i) {
00151     if (GTS_IS_FACE (i->data) && 
00152         gts_face_has_parent_surface (i->data, surface))
00153       return i->data;
00154     i = i->next;
00155   }
00156   return NULL;
00157 }
00158 
00167 GtsFace * gts_edge_has_any_parent_surface (GtsEdge * e)
00168 {
00169   GSList * i;
00170 
00171   g_return_val_if_fail (e != NULL, NULL);
00172 
00173   i = e->triangles;
00174   while (i) {
00175     GtsTriangle * t = i->data;
00176     if (GTS_IS_FACE (t) && GTS_FACE (t)->surfaces != NULL)
00177       return GTS_FACE (t);
00178     i = i->next;
00179   }
00180   return NULL;
00181 }
00182 
00193 GtsFace * gts_edge_is_boundary (GtsEdge * e, GtsSurface * surface)
00194 {
00195   GSList * i;
00196   GtsFace * f = NULL;
00197   
00198   g_return_val_if_fail (e != NULL, NULL);
00199   
00200   i = e->triangles;
00201   while (i) {
00202     if (GTS_IS_FACE (i->data)) {
00203       if (!surface || gts_face_has_parent_surface (i->data, surface)) {
00204         if (f != NULL)
00205           return NULL;
00206         f = i->data;
00207       }
00208     }
00209     i = i->next;    
00210   }
00211   return f;
00212 }
00213 
00222 GSList * gts_edges_from_vertices (GSList * vertices, GtsSurface * parent)
00223 {
00224   GHashTable * hash;
00225   GSList * edges = NULL, * i;
00226 
00227   g_return_val_if_fail (parent != NULL, NULL);
00228   
00229   hash = g_hash_table_new (NULL, NULL);
00230   i = vertices;
00231   while (i) {
00232     GSList * j = GTS_VERTEX (i->data)->segments;
00233     while (j) {
00234       GtsSegment * s = j->data;
00235       if (GTS_IS_EDGE (s) &&
00236           gts_edge_has_parent_surface (GTS_EDGE (s), parent) && 
00237           g_hash_table_lookup (hash, s) == NULL) {
00238         edges = g_slist_prepend (edges, s);
00239         g_hash_table_insert (hash, s, i);
00240       }
00241       j = j->next;
00242     }
00243     i = i->next;
00244   }
00245   g_hash_table_destroy (hash);
00246   return edges;
00247 }
00248 
00256 guint gts_edge_face_number (GtsEdge * e, GtsSurface * s)
00257 {
00258   GSList * i;
00259   guint nt = 0;
00260 
00261   g_return_val_if_fail (e != NULL, 0);
00262   g_return_val_if_fail (s != NULL, 0);
00263 
00264   i = e->triangles;
00265   while (i) {
00266     if (GTS_IS_FACE (i->data) && 
00267         gts_face_has_parent_surface (GTS_FACE (i->data), s))
00268       nt++;
00269     i = i->next;
00270   }
00271   return nt;
00272 }
00273 
00281 GtsEdge * gts_edge_is_duplicate (GtsEdge * e)
00282 {
00283   GSList * i;
00284   GtsVertex * v2;
00285 
00286   g_return_val_if_fail (e != NULL, NULL);
00287 
00288   v2 = GTS_SEGMENT (e)->v2;
00289   i = GTS_SEGMENT (e)->v1->segments;
00290   if (GTS_SEGMENT (e)->v1 == v2) /* e is degenerate: special treatment */
00291     while (i) {
00292       GtsSegment * s = i->data;
00293       if (s != GTS_SEGMENT (e) &&
00294           GTS_IS_EDGE (s) && 
00295           s->v1 == v2 && s->v2 == v2)
00296         return GTS_EDGE (s);
00297       i = i->next;
00298     }
00299   else /* e is not degenerate */
00300     while (i) {
00301       GtsSegment * s = i->data;
00302       if (s != GTS_SEGMENT (e) &&
00303           GTS_IS_EDGE (s) && 
00304           (s->v1 == v2 || s->v2 == v2))
00305         return GTS_EDGE (s);
00306       i = i->next;
00307     }
00308   return NULL;
00309 }
00310 
00321 GList * gts_edges_merge (GList * edges)
00322 {
00323   GList * i = edges;
00324 
00325   /* we want to control edge destruction */
00326   gts_allow_floating_edges = TRUE;
00327   while (i) {
00328     GtsEdge * e = i->data;
00329     GtsEdge * de = gts_edge_is_duplicate (e);
00330     if (de) {
00331       GList * next = i->next;
00332       edges = g_list_remove_link (edges, i);
00333       g_list_free_1 (i);
00334       i = next;
00335       gts_edge_replace (e, de);
00336       gts_object_destroy (GTS_OBJECT (e));
00337     }
00338     else
00339       i = i->next;
00340   }
00341   gts_allow_floating_edges = FALSE;;
00342 
00343   return edges;
00344 }
00345 
00346 static void triangle_vertices_edges (GtsTriangle * t, 
00347                                      GtsEdge * e,
00348                                      GtsVertex ** v,
00349                                      GtsEdge ** ee1,
00350                                      GtsEdge ** ee2)
00351 {
00352   GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3;
00353   GtsVertex * v1 = GTS_SEGMENT (e)->v1;
00354 
00355   if (e1 == e)        e1 = e3;
00356   else if (e2 == e)   e2 = e3;
00357   else                g_assert (e3 == e);
00358 
00359   if (GTS_SEGMENT (e2)->v1 == v1 || GTS_SEGMENT (e2)->v2 == v1) {
00360     e3 = e1; e1 = e2; e2 = e3;
00361   }
00362   if (GTS_SEGMENT (e1)->v1 == v1)
00363     *v = GTS_SEGMENT (e1)->v2;
00364   else
00365     *v = GTS_SEGMENT (e1)->v1;
00366   *ee1 = e1;
00367   *ee2 = e2;
00368 }
00369 
00377 gboolean gts_edge_belongs_to_tetrahedron (GtsEdge * e)
00378 {
00379   GSList * i;
00380 
00381   g_return_val_if_fail (e != NULL, FALSE);
00382 
00383   i = e->triangles;
00384   while (i) {
00385     GtsEdge * e1, * e2;
00386     GtsVertex * vt1;
00387     GSList * j = i->next;
00388     triangle_vertices_edges (i->data, e, &vt1, &e1, &e2);
00389     while (j) {      
00390       GtsSegment * s5;
00391       GtsEdge * e3, * e4;
00392       GtsVertex * vt2;
00393 
00394       triangle_vertices_edges (j->data, e, &vt2, &e3, &e4);
00395       s5 = gts_vertices_are_connected (vt1, vt2);
00396       if (GTS_IS_EDGE (s5) &&
00397           gts_triangle_use_edges (e1, e3, GTS_EDGE (s5)) &&
00398           gts_triangle_use_edges (e2, e4, GTS_EDGE (s5)))
00399         return TRUE;
00400       j = j->next;
00401     }
00402     i = i->next;
00403   }
00404 
00405   return FALSE;
00406 }
00407 
00408 #define edge_use_vertex(e, v) (GTS_SEGMENT(e)->v1 == v ||\
00409                                GTS_SEGMENT(e)->v2 == v)
00410 
00411 static GtsEdge * next_edge (GtsTriangle * t,
00412                             GtsEdge * e1,
00413                             GtsEdge * e)
00414 {
00415   GtsVertex * v1 = GTS_SEGMENT (e)->v1;
00416   GtsVertex * v2 = GTS_SEGMENT (e)->v2;
00417   
00418   if (t->e1 != e1 && t->e1 != e && 
00419       (edge_use_vertex (t->e1, v1) || edge_use_vertex (t->e1, v2)))
00420     return t->e1;
00421   else if (t->e2 != e1 && t->e2 != e && 
00422            (edge_use_vertex (t->e2, v1) || edge_use_vertex (t->e2, v2)))
00423     return t->e2;
00424   else if (t->e3 != e1 && t->e3 != e && 
00425            (edge_use_vertex (t->e3, v1) || edge_use_vertex (t->e3, v2)))
00426     return t->e3;
00427   g_assert_not_reached ();
00428   return NULL;
00429 }
00430 
00431 static void triangle_next (GtsEdge * e1, GtsEdge * e)
00432 {
00433   GSList * i;
00434 
00435   i = e1->triangles;
00436   while (i) {
00437     GtsTriangle * t = i->data;
00438     if (GTS_OBJECT (t)->reserved) {
00439       GTS_OBJECT (t)->reserved = NULL;
00440       triangle_next (next_edge (t, e1, e), e);
00441     }
00442     i = i->next;
00443   }
00444 }
00445 
00453 guint gts_edge_is_contact (GtsEdge * e)
00454 {
00455   GSList * i, * triangles;
00456   guint ncomponent = 0;
00457 
00458   g_return_val_if_fail (e != NULL, 0);
00459 
00460   triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL);
00461   i = triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles);
00462   while (i) {
00463     GTS_OBJECT (i->data)->reserved = i;
00464     i = i->next;
00465   }
00466 
00467   i = e->triangles;
00468   while (i) {
00469     GtsTriangle * t = i->data;
00470     if (GTS_OBJECT (t)->reserved) {
00471       GtsEdge * e1;
00472       GTS_OBJECT (t)->reserved = NULL;
00473       e1 = next_edge (t, NULL, e);
00474       triangle_next (e1, e);
00475       triangle_next (next_edge (t, e1, e), e);
00476       ncomponent++;
00477     }
00478     i = i->next;
00479   }
00480    
00481   g_slist_foreach (triangles, (GFunc) gts_object_reset_reserved, NULL);
00482   g_slist_free (triangles);
00483 
00484   return ncomponent;
00485 }
00486 
00495 void gts_edge_swap (GtsEdge * e, GtsSurface * s)
00496 {
00497   GtsTriangle * t1 = NULL, * t2 = NULL, * t;
00498   GtsFace * f;
00499   GSList * i;
00500   GtsVertex * v1, * v2, * v3, * v4, * v5, * v6;
00501   GtsEdge * e1, * e2, * e3, * e4;
00502   GtsSegment * v3v6;
00503 
00504   g_return_if_fail (e != NULL);
00505   g_return_if_fail (s != NULL);
00506 
00507   i = e->triangles;
00508   while (i) {
00509     if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) {
00510       if (!t1)
00511         t1 = i->data;
00512       else if (!t2)
00513         t2 = i->data;
00514       else
00515         g_return_if_fail (gts_edge_face_number (e, s) == 2);
00516     }
00517     i = i->next;
00518   }
00519   g_assert (t1 && t2);
00520 
00521   gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e1, &e2);
00522   gts_triangle_vertices_edges (t2, e, &v4, &v5, &v6, &e, &e3, &e4);
00523   g_assert (v2 == v4 && v1 == v5);
00524 
00525   v3v6 = gts_vertices_are_connected (v3, v6);
00526   if (!GTS_IS_EDGE (v3v6))
00527     v3v6 = GTS_SEGMENT (gts_edge_new (s->edge_class, v3, v6));
00528   f = gts_face_new (s->face_class, e1, GTS_EDGE (v3v6), e4);
00529   if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) &&
00530       GTS_IS_FACE (t)) {
00531     gts_object_destroy (GTS_OBJECT (f));
00532     f = GTS_FACE (t);
00533   }
00534   gts_surface_add_face (s, f);
00535 
00536   f = gts_face_new (s->face_class, GTS_EDGE (v3v6), e2, e3);
00537   if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) &&
00538       GTS_IS_FACE (t)) {
00539     gts_object_destroy (GTS_OBJECT (f));
00540     f = GTS_FACE (t);
00541   }
00542   gts_surface_add_face (s, f);
00543 
00544   gts_surface_remove_face (s, GTS_FACE (t1));
00545   gts_surface_remove_face (s, GTS_FACE (t2));
00546 }
00547 
00560 gboolean gts_edge_manifold_faces (GtsEdge * e, GtsSurface * s,
00561                                   GtsFace ** f1, GtsFace ** f2)
00562 {
00563   GSList * i;
00564 
00565   g_return_val_if_fail (e != NULL, FALSE);
00566   g_return_val_if_fail (s != NULL, FALSE);
00567   g_return_val_if_fail (f1 != NULL, FALSE);
00568   g_return_val_if_fail (f2 != NULL, FALSE);
00569 
00570   *f1 = *f2 = NULL;
00571   i = e->triangles;
00572   while (i) {
00573     if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) {
00574       if (!(*f1)) *f1 = i->data;
00575       else if (!(*f2)) *f2 = i->data;
00576       else return FALSE;
00577     }
00578     i = i->next;
00579   }
00580 
00581   return (*f1 && *f2);
00582 }