/** * gts_edge_belongs_to_tetrahedron: * @e: a #GtsEdge. * * Returns: %TRUE if @e is used by faces forming a tetrahedron, %FALSE * otherwise. */ gboolean gts_edge_belongs_to_tetrahedron (GtsEdge * e) { GSList * i; GtsVertex * v1, * v2; g_return_val_if_fail (e != NULL, FALSE); v1 = GTS_SEGMENT (e)->v1; v2 = GTS_SEGMENT (e)->v2; i = e->triangles; while (i) { GtsEdge * e1, * e2; GtsVertex * vt1; GSList * j = i->next; triangle_vertices_edges (i->data, e, &vt1, &e1, &e2); while (j) { GtsSegment * s5; GtsEdge * e3, * e4; GtsVertex * vt2; triangle_vertices_edges (j->data, e, &vt2, &e3, &e4); s5 = gts_vertices_are_connected (vt1, vt2); if (GTS_IS_EDGE (s5) && gts_triangle_use_edges (e1, e3, GTS_EDGE (s5)) && gts_triangle_use_edges (e2, e4, GTS_EDGE (s5))) return TRUE; j = j->next; } i = i->next; } return FALSE; }
/** * gts_edge_is_duplicate: * @e: a #GtsEdge. * * Returns: the first #GtsEdge different from @e which shares the * same endpoints or %NULL if there is none. */ GtsEdge * gts_edge_is_duplicate (GtsEdge * e) { GSList * i; GtsVertex * v2; g_return_val_if_fail (e != NULL, NULL); v2 = GTS_SEGMENT (e)->v2; i = GTS_SEGMENT (e)->v1->segments; if (GTS_SEGMENT (e)->v1 == v2) /* e is degenerate: special treatment */ while (i) { GtsSegment * s = i->data; if (s != GTS_SEGMENT (e) && GTS_IS_EDGE (s) && s->v1 == v2 && s->v2 == v2) return GTS_EDGE (s); i = i->next; } else /* e is not degenerate */ while (i) { GtsSegment * s = i->data; if (s != GTS_SEGMENT (e) && GTS_IS_EDGE (s) && (s->v1 == v2 || s->v2 == v2)) return GTS_EDGE (s); i = i->next; } return NULL; }
/** * gts_edge_swap: * @e: a #GtsEdge. * @s: a #GtsSurface. * * Performs an "edge swap" on the two triangles sharing @e and * belonging to @s. */ void gts_edge_swap (GtsEdge * e, GtsSurface * s) { GtsTriangle * t1 = NULL, * t2 = NULL, * t; GtsFace * f; GSList * i; GtsVertex * v1, * v2, * v3, * v4, * v5, * v6; GtsEdge * e1, * e2, * e3, * e4; GtsSegment * v3v6; g_return_if_fail (e != NULL); g_return_if_fail (s != NULL); i = e->triangles; while (i) { if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) { if (!t1) t1 = i->data; else if (!t2) t2 = i->data; else g_return_if_fail (gts_edge_face_number (e, s) == 2); } i = i->next; } g_assert (t1 && t2); gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e1, &e2); gts_triangle_vertices_edges (t2, e, &v4, &v5, &v6, &e, &e3, &e4); g_assert (v2 == v4 && v1 == v5); v3v6 = gts_vertices_are_connected (v3, v6); if (!GTS_IS_EDGE (v3v6)) v3v6 = GTS_SEGMENT (gts_edge_new (s->edge_class, v3, v6)); f = gts_face_new (s->face_class, e1, GTS_EDGE (v3v6), e4); if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) && GTS_IS_FACE (t)) { gts_object_destroy (GTS_OBJECT (f)); f = GTS_FACE (t); } gts_surface_add_face (s, f); f = gts_face_new (s->face_class, GTS_EDGE (v3v6), e2, e3); if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) && GTS_IS_FACE (t)) { gts_object_destroy (GTS_OBJECT (f)); f = GTS_FACE (t); } gts_surface_add_face (s, f); gts_surface_remove_face (s, GTS_FACE (t1)); gts_surface_remove_face (s, GTS_FACE (t2)); }
static GtsEdge * new_edge (GtsVertex * v1, GtsVertex * v2) { GtsSegment * s = gts_vertices_are_connected (v1, v2); return s == NULL ? gts_edge_new (GTS_EDGE_CLASS (gts_constraint_class ()), v1, v2) : GTS_EDGE (s); }
static void edge_clone (GtsObject * clone, GtsObject * object) { (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->clone) (clone, object); GTS_SEGMENT (clone)->v1 = GTS_SEGMENT (clone)->v2 = NULL; GTS_EDGE (clone)->triangles = NULL; }
/** * gts_edges_from_vertices: * @vertices: a list of #GtsVertex. * @parent: a #GtsSurface. * * Returns: a list of unique #GtsEdge which have one of their vertices in * @vertices and are used by a face of @parent. */ GSList * gts_edges_from_vertices (GSList * vertices, GtsSurface * parent) { GHashTable * hash; GSList * edges = NULL, * i; g_return_val_if_fail (parent != NULL, NULL); hash = g_hash_table_new (NULL, NULL); i = vertices; while (i) { GSList * j = GTS_VERTEX (i->data)->segments; while (j) { GtsSegment * s = j->data; if (GTS_IS_EDGE (s) && gts_edge_has_parent_surface (GTS_EDGE (s), parent) && g_hash_table_lookup (hash, s) == NULL) { edges = g_slist_prepend (edges, s); g_hash_table_insert (hash, s, i); } j = j->next; } i = i->next; } g_hash_table_destroy (hash); return edges; }
static void edge_destroy (GtsObject * object) { GtsEdge * edge = GTS_EDGE (object); GSList * i; i = edge->triangles; while (i) { GSList * next = i->next; gts_object_destroy (i->data); i = next; } g_assert (edge->triangles == NULL); (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->destroy) (object); }
/** * gts_triangles_from_edges: * @edges: a list of #GtsEdge. * * Builds a list of unique triangles which have one of their edges in @edges. * * Returns: the list of triangles. */ GSList * gts_triangles_from_edges (GSList * edges) { GHashTable * hash; GSList * triangles = NULL, * i; hash = g_hash_table_new (NULL, NULL); i = edges; while (i) { GSList * j = GTS_EDGE (i->data)->triangles; while (j) { GtsTriangle * t = j->data; if (g_hash_table_lookup (hash, t) == NULL) { triangles = g_slist_prepend (triangles, t); g_hash_table_insert (hash, t, i); } j = j->next; } i = i->next; } g_hash_table_destroy (hash); return triangles; }
static void gts_constraint_split (GtsConstraint * c, GtsSurface * s, GtsFifo * fifo) { GSList * i; GtsVertex * v1, * v2; GtsEdge * e; g_return_if_fail (c != NULL); g_return_if_fail (s != NULL); v1 = GTS_SEGMENT (c)->v1; v2 = GTS_SEGMENT (c)->v2; e = GTS_EDGE (c); i = e->triangles; while (i) { GtsFace * f = i->data; if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) { GtsVertex * v = gts_triangle_vertex_opposite (GTS_TRIANGLE (f), e); if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v)) == 0.) { GSList * j = e->triangles; GtsFace * f1 = NULL; GtsEdge * e1, * e2; /* replaces edges with constraints */ gts_triangle_vertices_edges (GTS_TRIANGLE (f), e, &v1, &v2, &v, &e, &e1, &e2); if (!GTS_IS_CONSTRAINT (e1)) { GtsEdge * ne1 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (c)->klass), v2, v); gts_edge_replace (e1, ne1); gts_object_destroy (GTS_OBJECT (e1)); e1 = ne1; if (fifo) gts_fifo_push (fifo, e1); } if (!GTS_IS_CONSTRAINT (e2)) { GtsEdge * ne2 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (c)->klass), v, v1); gts_edge_replace (e2, ne2); gts_object_destroy (GTS_OBJECT (e2)); e2 = ne2; if (fifo) gts_fifo_push (fifo, e2); } /* look for face opposite */ while (j && !f1) { if (GTS_IS_FACE (j->data) && gts_face_has_parent_surface (j->data, s)) f1 = j->data; j = j->next; } if (f1) { /* c is not a boundary of s */ GtsEdge * e3, * e4, * e5; GtsVertex * v3; gts_triangle_vertices_edges (GTS_TRIANGLE (f1), e, &v1, &v2, &v3, &e, &e3, &e4); e5 = gts_edge_new (s->edge_class, v, v3); gts_surface_add_face (s, gts_face_new (s->face_class, e5, e2, e3)); gts_surface_add_face (s, gts_face_new (s->face_class, e5, e4, e1)); gts_object_destroy (GTS_OBJECT (f1)); } gts_object_destroy (GTS_OBJECT (f)); return; } } i = i->next; } }
/** * gts_edge_new: * @klass: a #GtsEdgeClass. * @v1: a #GtsVertex. * @v2: a #GtsVertex. * * Returns: a new #GtsEdge linking @v1 and @v2. */ GtsEdge * gts_edge_new (GtsEdgeClass * klass, GtsVertex * v1, GtsVertex * v2) { return GTS_EDGE (gts_segment_new (GTS_SEGMENT_CLASS (klass), v1, v2)); }