/* GTS - Library for the manipulation of triangulated surfaces * Copyright (C) 1999 Stéphane Popinet * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "gts.h" gboolean gts_allow_floating_faces = FALSE; static void face_destroy (GtsObject * object) { GtsFace * face = GTS_FACE (object); GSList * i; i = face->surfaces; while (i) { GSList * next = i->next; gts_surface_remove_face (i->data, face); i = next; } g_assert (face->surfaces == NULL); (* GTS_OBJECT_CLASS (gts_face_class ())->parent_class->destroy) (object); } static void face_clone (GtsObject * clone, GtsObject * object) { (* GTS_OBJECT_CLASS (gts_face_class ())->parent_class->clone) (clone, object); GTS_FACE (clone)->surfaces = NULL; } static void face_class_init (GtsFaceClass * klass) { GTS_OBJECT_CLASS (klass)->clone = face_clone; GTS_OBJECT_CLASS (klass)->destroy = face_destroy; } static void face_init (GtsFace * face) { face->surfaces = NULL; } /** * gts_face_class: * * Returns: the #GtsFaceClass. */ GtsFaceClass * gts_face_class (void) { static GtsFaceClass * klass = NULL; if (klass == NULL) { GtsObjectClassInfo face_info = { "GtsFace", sizeof (GtsFace), sizeof (GtsFaceClass), (GtsObjectClassInitFunc) face_class_init, (GtsObjectInitFunc) face_init, (GtsArgSetFunc) NULL, (GtsArgGetFunc) NULL }; klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_triangle_class ()), &face_info); } return klass; } /** * gts_face_new: * @klass: a #GtsFaceClass. * @e1: a #GtsEdge. * @e2: a #GtsEdge. * @e3: a #GtsEdge. * * Returns: a new #GtsFace using @e1, @e2 and @e3 as edges. */ GtsFace * gts_face_new (GtsFaceClass * klass, GtsEdge * e1, GtsEdge * e2, GtsEdge * e3) { GtsFace * f; f = GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (klass))); gts_triangle_set (GTS_TRIANGLE (f), e1, e2, e3); return f; } /** * gts_face_has_parent_surface: * @f: a #GtsFace. * @s: a #GtsSurface. * * Returns: %TRUE if @f belongs to @s, %FALSE otherwise. */ gboolean gts_face_has_parent_surface (GtsFace * f, GtsSurface * s) { GSList * i; g_return_val_if_fail (f != NULL, FALSE); i = f->surfaces; while (i) { if (i->data == s) return TRUE; i = i->next; } return FALSE; } /** * gts_faces_from_edges: * @edges: a list of #GtsEdge. * @s: a #GtsSurface or %NULL. * * Builds a list of unique faces which belong to @s and have * one of their edges in @edges. * * Returns: the list of faces. */ GSList * gts_faces_from_edges (GSList * edges, GtsSurface * s) { GHashTable * hash; GSList * faces = 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 (GTS_IS_FACE (t) && (!s || gts_face_has_parent_surface (GTS_FACE (t), s)) && g_hash_table_lookup (hash, t) == NULL) { faces = g_slist_prepend (faces, t); g_hash_table_insert (hash, t, i); } j = j->next; } i = i->next; } g_hash_table_destroy (hash); return faces; } /** * gts_face_neighbor_number: * @f: a #GtsFace. * @s: a #GtsSurface or %NULL. * * Returns: the number of faces neighbors of @f and belonging to @s. */ guint gts_face_neighbor_number (GtsFace * f, GtsSurface * s) { GSList * i; guint nn = 0; GtsEdge * e[4], ** e1 = e; g_return_val_if_fail (f != NULL, 0); e[0] = GTS_TRIANGLE (f)->e1; e[1] = GTS_TRIANGLE (f)->e2; e[2] = GTS_TRIANGLE (f)->e3; e[3] = NULL; while (*e1) { i = (*e1++)->triangles; while (i) { GtsTriangle * t = i->data; if (GTS_FACE (t) != f && GTS_IS_FACE (t) && (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) nn++; i = i->next; } } return nn; } /** * gts_face_neighbors: * @f: a #GtsFace. * @s: a #GtsSurface or %NULL. * * Returns: a list of unique #GtsFace neighbors of @f and belonging to @s. */ GSList * gts_face_neighbors (GtsFace * f, GtsSurface * s) { GSList * i, * list = NULL; GtsEdge * e[4], ** e1 = e; g_return_val_if_fail (f != NULL, NULL); e[0] = GTS_TRIANGLE (f)->e1; e[1] = GTS_TRIANGLE (f)->e2; e[2] = GTS_TRIANGLE (f)->e3; e[3] = NULL; while (*e1) { i = (*e1++)->triangles; while (i) { GtsTriangle * t = i->data; if (GTS_FACE (t) != f && GTS_IS_FACE (t) && (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) list = g_slist_prepend (list, t); i = i->next; } } return list; } /** * gts_face_foreach_neighbor: * @f: a #GtsFace. * @s: a #GtsSurface or %NULL. * @func: a #GtsFunc. * @data: user data to pass to @func. * * Calls @func for each neighbor of @f belonging to @s (if not %NULL). */ void gts_face_foreach_neighbor (GtsFace * f, GtsSurface * s, GtsFunc func, gpointer data) { GSList * i; GtsEdge * e[4], ** e1 = e; g_return_if_fail (f != NULL); g_return_if_fail (func != NULL); e[0] = GTS_TRIANGLE (f)->e1; e[1] = GTS_TRIANGLE (f)->e2; e[2] = GTS_TRIANGLE (f)->e3; e[3] = NULL; while (*e1) { i = (*e1++)->triangles; while (i) { GtsTriangle * t = i->data; if (GTS_FACE (t) != f && GTS_IS_FACE (t) && (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) (* func) (t, data); i = i->next; } } } static gboolean triangle_is_incompatible (GtsTriangle * t, GtsEdge * e, GtsSurface * s) { GSList * i = e->triangles; while (i) { if (i->data != t && GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s) && !gts_triangles_are_compatible (t, i->data, e)) return TRUE; i = i->next; } return FALSE; } /** * gts_face_is_compatible: * @f: a #GtsFace. * @s: a #GtsSurface. * * Returns: %TRUE if @f is compatible with all its neighbors belonging * to @s, %FALSE otherwise. */ gboolean gts_face_is_compatible (GtsFace * f, GtsSurface * s) { g_return_val_if_fail (f != NULL, FALSE); g_return_val_if_fail (s != NULL, FALSE); return !(triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e1, s) || triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e2, s) || triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e3, s)); }