1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 Stéphane Popinet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 gboolean gts_allow_floating_edges
= FALSE
;
24 static void edge_destroy (GtsObject
* object
)
26 GtsEdge
* edge
= GTS_EDGE (object
);
31 GSList
* next
= i
->next
;
32 gts_object_destroy (i
->data
);
35 g_assert (edge
->triangles
== NULL
);
37 (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class
->destroy
) (object
);
40 static void edge_clone (GtsObject
* clone
, GtsObject
* object
)
42 (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class
->clone
) (clone
,
44 GTS_SEGMENT (clone
)->v1
= GTS_SEGMENT (clone
)->v2
= NULL
;
45 GTS_EDGE (clone
)->triangles
= NULL
;
48 static void edge_class_init (GtsObjectClass
* klass
)
50 klass
->clone
= edge_clone
;
51 klass
->destroy
= edge_destroy
;
54 static void edge_init (GtsEdge
* edge
)
56 edge
->triangles
= NULL
;
62 * Returns: the #GtsEdgeClass.
64 GtsEdgeClass
* gts_edge_class (void)
66 static GtsEdgeClass
* klass
= NULL
;
69 GtsObjectClassInfo edge_info
= {
72 sizeof (GtsEdgeClass
),
73 (GtsObjectClassInitFunc
) edge_class_init
,
74 (GtsObjectInitFunc
) edge_init
,
78 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_segment_class ()),
87 * @klass: a #GtsEdgeClass.
91 * Returns: a new #GtsEdge linking @v1 and @v2.
93 GtsEdge
* gts_edge_new (GtsEdgeClass
* klass
,
94 GtsVertex
* v1
, GtsVertex
* v2
)
96 return GTS_EDGE (gts_segment_new (GTS_SEGMENT_CLASS (klass
), v1
, v2
));
99 void gts_edge_remove(GtsEdge
*edge
)
101 edge
->segment
.v1
->segments
= g_slist_remove(edge
->segment
.v1
->segments
, &edge
->segment
);
102 edge
->segment
.v2
->segments
= g_slist_remove(edge
->segment
.v2
->segments
, &edge
->segment
);
103 edge_destroy(GTS_OBJECT (edge
));
111 * Replaces @e with @with. For each triangle which uses @e as an
112 * edge, @e is replaced with @with. The @with->triangles list is
113 * updated appropriately and the @e->triangles list is freed and set
116 void gts_edge_replace (GtsEdge
* e
, GtsEdge
* with
)
120 g_return_if_fail (e
!= NULL
&& with
!= NULL
&& e
!= with
);
124 GtsTriangle
* t
= i
->data
;
125 if (t
->e1
== e
) t
->e1
= with
;
126 if (t
->e2
== e
) t
->e2
= with
;
127 if (t
->e3
== e
) t
->e3
= with
;
128 if (!g_slist_find (with
->triangles
, t
))
129 with
->triangles
= g_slist_prepend (with
->triangles
, t
);
132 g_slist_free (e
->triangles
);
137 * gts_edge_has_parent_surface:
139 * @surface: a #GtsSurface.
141 * Returns: a #GtsFace of @surface having @e as an edge, %NULL otherwise.
143 GtsFace
* gts_edge_has_parent_surface (GtsEdge
* e
, GtsSurface
* surface
)
147 g_return_val_if_fail (e
!= NULL
, NULL
);
151 if (GTS_IS_FACE (i
->data
) &&
152 gts_face_has_parent_surface (i
->data
, surface
))
160 * gts_edge_has_any_parent_surface:
163 * Returns: %NULL if @e is not an edge of any triangle or if all the
164 * faces having @e has an edge do not belong to any surface,
165 * a #GtsFace belonging to a surface and having @e as an edge.
167 GtsFace
* gts_edge_has_any_parent_surface (GtsEdge
* e
)
171 g_return_val_if_fail (e
!= NULL
, NULL
);
175 GtsTriangle
* t
= i
->data
;
176 if (GTS_IS_FACE (t
) && GTS_FACE (t
)->surfaces
!= NULL
)
184 * gts_edge_is_boundary:
186 * @surface: a #GtsSurface or %NULL.
188 * Returns: the unique #GtsFace (which belongs to @surface) and which
189 * has @e as an edge (i.e. @e is a boundary edge (of @surface)) or %NULL
190 * if there is more than one or no faces (belonging to @surface) and
191 * with @e as an edge.
193 GtsFace
* gts_edge_is_boundary (GtsEdge
* e
, GtsSurface
* surface
)
198 g_return_val_if_fail (e
!= NULL
, NULL
);
202 if (GTS_IS_FACE (i
->data
)) {
203 if (!surface
|| gts_face_has_parent_surface (i
->data
, surface
)) {
215 * gts_edges_from_vertices:
216 * @vertices: a list of #GtsVertex.
217 * @parent: a #GtsSurface.
219 * Returns: a list of unique #GtsEdge which have one of their vertices in
220 * @vertices and are used by a face of @parent.
222 GSList
* gts_edges_from_vertices (GSList
* vertices
, GtsSurface
* parent
)
225 GSList
* edges
= NULL
, * i
;
227 g_return_val_if_fail (parent
!= NULL
, NULL
);
229 hash
= g_hash_table_new (NULL
, NULL
);
232 GSList
* j
= GTS_VERTEX (i
->data
)->segments
;
234 GtsSegment
* s
= j
->data
;
235 if (GTS_IS_EDGE (s
) &&
236 gts_edge_has_parent_surface (GTS_EDGE (s
), parent
) &&
237 g_hash_table_lookup (hash
, s
) == NULL
) {
238 edges
= g_slist_prepend (edges
, s
);
239 g_hash_table_insert (hash
, s
, i
);
245 g_hash_table_destroy (hash
);
250 * gts_edge_face_number:
254 * Returns: the number of faces using @e and belonging to @s.
256 guint
gts_edge_face_number (GtsEdge
* e
, GtsSurface
* s
)
261 g_return_val_if_fail (e
!= NULL
, 0);
262 g_return_val_if_fail (s
!= NULL
, 0);
266 if (GTS_IS_FACE (i
->data
) &&
267 gts_face_has_parent_surface (GTS_FACE (i
->data
), s
))
275 * gts_edge_is_duplicate:
278 * Returns: the first #GtsEdge different from @e which shares the
279 * same endpoints or %NULL if there is none.
281 GtsEdge
* gts_edge_is_duplicate (GtsEdge
* e
)
286 g_return_val_if_fail (e
!= NULL
, NULL
);
288 v2
= GTS_SEGMENT (e
)->v2
;
289 i
= GTS_SEGMENT (e
)->v1
->segments
;
290 if (GTS_SEGMENT (e
)->v1
== v2
) /* e is degenerate: special treatment */
292 GtsSegment
* s
= i
->data
;
293 if (s
!= GTS_SEGMENT (e
) &&
295 s
->v1
== v2
&& s
->v2
== v2
)
299 else /* e is not degenerate */
301 GtsSegment
* s
= i
->data
;
302 if (s
!= GTS_SEGMENT (e
) &&
304 (s
->v1
== v2
|| s
->v2
== v2
))
313 * @edges: a list of #GtsEdge.
315 * For each edge in @edges check if it is duplicated (as
316 * returned by gts_edge_is_duplicate()). If it is replace it by its
317 * duplicate, destroy it and remove it from the list.
319 * Returns: the updated @edges list.
321 GList
* gts_edges_merge (GList
* edges
)
325 /* we want to control edge destruction */
326 gts_allow_floating_edges
= TRUE
;
328 GtsEdge
* e
= i
->data
;
329 GtsEdge
* de
= gts_edge_is_duplicate (e
);
331 GList
* next
= i
->next
;
332 edges
= g_list_remove_link (edges
, i
);
335 gts_edge_replace (e
, de
);
336 gts_object_destroy (GTS_OBJECT (e
));
341 gts_allow_floating_edges
= FALSE
;;
346 static void triangle_vertices_edges (GtsTriangle
* t
,
352 GtsEdge
* e1
= t
->e1
, * e2
= t
->e2
, * e3
= t
->e3
;
353 GtsVertex
* v1
= GTS_SEGMENT (e
)->v1
;
355 if (e1
== e
) e1
= e3
;
356 else if (e2
== e
) e2
= e3
;
357 else g_assert (e3
== e
);
359 if (GTS_SEGMENT (e2
)->v1
== v1
|| GTS_SEGMENT (e2
)->v2
== v1
) {
360 e3
= e1
; e1
= e2
; e2
= e3
;
362 if (GTS_SEGMENT (e1
)->v1
== v1
)
363 *v
= GTS_SEGMENT (e1
)->v2
;
365 *v
= GTS_SEGMENT (e1
)->v1
;
371 * gts_edge_belongs_to_tetrahedron:
374 * Returns: %TRUE if @e is used by faces forming a tetrahedron, %FALSE
377 gboolean
gts_edge_belongs_to_tetrahedron (GtsEdge
* e
)
381 g_return_val_if_fail (e
!= NULL
, FALSE
);
387 GSList
* j
= i
->next
;
388 triangle_vertices_edges (i
->data
, e
, &vt1
, &e1
, &e2
);
394 triangle_vertices_edges (j
->data
, e
, &vt2
, &e3
, &e4
);
395 s5
= gts_vertices_are_connected (vt1
, vt2
);
396 if (GTS_IS_EDGE (s5
) &&
397 gts_triangle_use_edges (e1
, e3
, GTS_EDGE (s5
)) &&
398 gts_triangle_use_edges (e2
, e4
, GTS_EDGE (s5
)))
408 #define edge_use_vertex(e, v) (GTS_SEGMENT(e)->v1 == v ||\
409 GTS_SEGMENT(e)->v2 == v)
411 static GtsEdge
* next_edge (GtsTriangle
* t
,
415 GtsVertex
* v1
= GTS_SEGMENT (e
)->v1
;
416 GtsVertex
* v2
= GTS_SEGMENT (e
)->v2
;
418 if (t
->e1
!= e1
&& t
->e1
!= e
&&
419 (edge_use_vertex (t
->e1
, v1
) || edge_use_vertex (t
->e1
, v2
)))
421 else if (t
->e2
!= e1
&& t
->e2
!= e
&&
422 (edge_use_vertex (t
->e2
, v1
) || edge_use_vertex (t
->e2
, v2
)))
424 else if (t
->e3
!= e1
&& t
->e3
!= e
&&
425 (edge_use_vertex (t
->e3
, v1
) || edge_use_vertex (t
->e3
, v2
)))
427 g_assert_not_reached ();
431 static void triangle_next (GtsEdge
* e1
, GtsEdge
* e
)
437 GtsTriangle
* t
= i
->data
;
438 if (GTS_OBJECT (t
)->reserved
) {
439 GTS_OBJECT (t
)->reserved
= NULL
;
440 triangle_next (next_edge (t
, e1
, e
), e
);
447 * gts_edge_is_contact:
450 * Returns: the number of sets of connected triangles sharing @e as a
453 guint
gts_edge_is_contact (GtsEdge
* e
)
455 GSList
* i
, * triangles
;
456 guint ncomponent
= 0;
458 g_return_val_if_fail (e
!= NULL
, 0);
460 triangles
= gts_vertex_triangles (GTS_SEGMENT (e
)->v1
, NULL
);
461 i
= triangles
= gts_vertex_triangles (GTS_SEGMENT (e
)->v2
, triangles
);
463 GTS_OBJECT (i
->data
)->reserved
= i
;
469 GtsTriangle
* t
= i
->data
;
470 if (GTS_OBJECT (t
)->reserved
) {
472 GTS_OBJECT (t
)->reserved
= NULL
;
473 e1
= next_edge (t
, NULL
, e
);
474 triangle_next (e1
, e
);
475 triangle_next (next_edge (t
, e1
, e
), e
);
481 g_slist_foreach (triangles
, (GFunc
) gts_object_reset_reserved
, NULL
);
482 g_slist_free (triangles
);
492 * Performs an "edge swap" on the two triangles sharing @e and
495 void gts_edge_swap (GtsEdge
* e
, GtsSurface
* s
)
497 GtsTriangle
* t1
= NULL
, * t2
= NULL
, * t
;
500 GtsVertex
* v1
, * v2
, * v3
, * v4
, * v5
, * v6
;
501 GtsEdge
* e1
, * e2
, * e3
, * e4
;
504 g_return_if_fail (e
!= NULL
);
505 g_return_if_fail (s
!= NULL
);
509 if (GTS_IS_FACE (i
->data
) && gts_face_has_parent_surface (i
->data
, s
)) {
515 g_return_if_fail (gts_edge_face_number (e
, s
) == 2);
521 gts_triangle_vertices_edges (t1
, e
, &v1
, &v2
, &v3
, &e
, &e1
, &e2
);
522 gts_triangle_vertices_edges (t2
, e
, &v4
, &v5
, &v6
, &e
, &e3
, &e4
);
523 g_assert (v2
== v4
&& v1
== v5
);
525 v3v6
= gts_vertices_are_connected (v3
, v6
);
526 if (!GTS_IS_EDGE (v3v6
))
527 v3v6
= GTS_SEGMENT (gts_edge_new (s
->edge_class
, v3
, v6
));
528 f
= gts_face_new (s
->face_class
, e1
, GTS_EDGE (v3v6
), e4
);
529 if ((t
= gts_triangle_is_duplicate (GTS_TRIANGLE (f
))) &&
531 gts_object_destroy (GTS_OBJECT (f
));
534 gts_surface_add_face (s
, f
);
536 f
= gts_face_new (s
->face_class
, GTS_EDGE (v3v6
), e2
, e3
);
537 if ((t
= gts_triangle_is_duplicate (GTS_TRIANGLE (f
))) &&
539 gts_object_destroy (GTS_OBJECT (f
));
542 gts_surface_add_face (s
, f
);
544 gts_surface_remove_face (s
, GTS_FACE (t1
));
545 gts_surface_remove_face (s
, GTS_FACE (t2
));
549 * gts_edge_manifold_faces:
552 * @f1: pointer for first face.
553 * @f2: pointer for second face.
555 * If @e is a manifold edge of surface @s, fills @f1 and @f2 with the
556 * faces belonging to @s and sharing @e.
558 * Returns: %TRUE if @e is a manifold edge, %FALSE otherwise.
560 gboolean
gts_edge_manifold_faces (GtsEdge
* e
, GtsSurface
* s
,
561 GtsFace
** f1
, GtsFace
** f2
)
565 g_return_val_if_fail (e
!= NULL
, FALSE
);
566 g_return_val_if_fail (s
!= NULL
, FALSE
);
567 g_return_val_if_fail (f1
!= NULL
, FALSE
);
568 g_return_val_if_fail (f2
!= NULL
, FALSE
);
573 if (GTS_IS_FACE (i
->data
) && gts_face_has_parent_surface (i
->data
, s
)) {
574 if (!(*f1
)) *f1
= i
->data
;
575 else if (!(*f2
)) *f2
= i
->data
;