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.
23 static void triangle_destroy (GtsObject
* object
)
25 GtsTriangle
* triangle
= GTS_TRIANGLE (object
);
26 GtsEdge
* e1
= triangle
->e1
;
27 GtsEdge
* e2
= triangle
->e2
;
28 GtsEdge
* e3
= triangle
->e3
;
30 e1
->triangles
= g_slist_remove (e1
->triangles
, triangle
);
31 if (!GTS_OBJECT_DESTROYED (e1
) &&
32 !gts_allow_floating_edges
&& e1
->triangles
== NULL
)
33 gts_object_destroy (GTS_OBJECT (e1
));
35 e2
->triangles
= g_slist_remove (e2
->triangles
, triangle
);
36 if (!GTS_OBJECT_DESTROYED (e2
) &&
37 !gts_allow_floating_edges
&& e2
->triangles
== NULL
)
38 gts_object_destroy (GTS_OBJECT (e2
));
40 e3
->triangles
= g_slist_remove (e3
->triangles
, triangle
);
41 if (!GTS_OBJECT_DESTROYED (e3
) &&
42 !gts_allow_floating_edges
&& e3
->triangles
== NULL
)
43 gts_object_destroy (GTS_OBJECT (e3
));
45 (* GTS_OBJECT_CLASS (gts_triangle_class ())->parent_class
->destroy
) (object
);
48 static void triangle_class_init (GtsObjectClass
* klass
)
50 klass
->destroy
= triangle_destroy
;
53 static void triangle_init (GtsTriangle
* triangle
)
55 triangle
->e1
= triangle
->e2
= triangle
->e3
= NULL
;
61 * Returns: the #GtsTriangleClass.
63 GtsTriangleClass
* gts_triangle_class (void)
65 static GtsTriangleClass
* klass
= NULL
;
68 GtsObjectClassInfo triangle_info
= {
71 sizeof (GtsTriangleClass
),
72 (GtsObjectClassInitFunc
) triangle_class_init
,
73 (GtsObjectInitFunc
) triangle_init
,
77 klass
= gts_object_class_new (gts_object_class (),
86 * @triangle: a #GtsTriangle.
88 * @e2: another #GtsEdge touching @e1.
89 * @e3: another #GtsEdge touching both @e1 and @e2.
91 * Sets the edge of @triangle to @e1, @e2 and @e3 while checking that they
92 * define a valid triangle.
94 void gts_triangle_set (GtsTriangle
* triangle
,
99 g_return_if_fail (e1
!= NULL
);
100 g_return_if_fail (e2
!= NULL
);
101 g_return_if_fail (e3
!= NULL
);
102 g_return_if_fail (e1
!= e2
&& e1
!= e3
&& e2
!= e3
);
108 if (GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e2
)->v1
)
109 g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3
),
110 GTS_SEGMENT (e1
)->v2
,
111 GTS_SEGMENT (e2
)->v2
));
112 else if (GTS_SEGMENT (e1
)->v2
== GTS_SEGMENT (e2
)->v1
)
113 g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3
),
114 GTS_SEGMENT (e1
)->v1
,
115 GTS_SEGMENT (e2
)->v2
));
116 else if (GTS_SEGMENT (e1
)->v2
== GTS_SEGMENT (e2
)->v2
)
117 g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3
),
118 GTS_SEGMENT (e1
)->v1
,
119 GTS_SEGMENT (e2
)->v1
));
120 else if (GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e2
)->v2
)
121 g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3
),
122 GTS_SEGMENT (e1
)->v2
,
123 GTS_SEGMENT (e2
)->v1
));
125 g_assert_not_reached ();
127 e1
->triangles
= g_slist_prepend (e1
->triangles
, triangle
);
128 e2
->triangles
= g_slist_prepend (e2
->triangles
, triangle
);
129 e3
->triangles
= g_slist_prepend (e3
->triangles
, triangle
);
134 * @klass: a #GtsTriangleClass.
136 * @e2: another #GtsEdge touching @e1.
137 * @e3: another #GtsEdge touching both @e1 and @e2.
139 * Returns: a new #GtsTriangle having @e1, @e2 and @e3 as edges.
141 GtsTriangle
* gts_triangle_new (GtsTriangleClass
* klass
,
148 t
= GTS_TRIANGLE (gts_object_new (GTS_OBJECT_CLASS (klass
)));
149 gts_triangle_set (t
, e1
, e2
, e3
);
155 * gts_triangle_vertex_opposite:
156 * @t: a #GtsTriangle.
157 * @e: a #GtsEdge used by @t.
159 * This function fails if @e is not an edge of @t.
161 * Returns: a #GtsVertex, vertex of @t which does not belong to @e.
163 GtsVertex
* gts_triangle_vertex_opposite (GtsTriangle
* t
, GtsEdge
* e
)
165 g_return_val_if_fail (t
!= NULL
, NULL
);
166 g_return_val_if_fail (e
!= NULL
, NULL
);
169 GtsVertex
* v
= GTS_SEGMENT (t
->e2
)->v1
;
170 if (v
!= GTS_SEGMENT (e
)->v1
&& v
!= GTS_SEGMENT (e
)->v2
)
172 return GTS_SEGMENT (t
->e2
)->v2
;
175 GtsVertex
* v
= GTS_SEGMENT (t
->e1
)->v1
;
176 if (v
!= GTS_SEGMENT (e
)->v1
&& v
!= GTS_SEGMENT (e
)->v2
)
178 return GTS_SEGMENT (t
->e1
)->v2
;
181 GtsVertex
* v
= GTS_SEGMENT (t
->e2
)->v1
;
182 if (v
!= GTS_SEGMENT (e
)->v1
&& v
!= GTS_SEGMENT (e
)->v2
)
184 return GTS_SEGMENT (t
->e2
)->v2
;
186 g_assert_not_reached ();
191 * gts_triangle_edge_opposite:
192 * @t: a #GtsTriangle.
193 * @v: a #GtsVertex of @t.
195 * Returns: the edge of @t opposite @v or %NULL if @v is not a vertice of @t.
197 GtsEdge
* gts_triangle_edge_opposite (GtsTriangle
* t
, GtsVertex
* v
)
199 GtsSegment
* s1
, * s2
, * s3
;
201 g_return_val_if_fail (t
!= NULL
, NULL
);
202 g_return_val_if_fail (v
!= NULL
, NULL
);
204 s1
= GTS_SEGMENT (t
->e1
);
205 s2
= GTS_SEGMENT (t
->e2
);
207 if (s1
->v1
!= v
&& s1
->v2
!= v
) {
208 if (s2
->v1
!= v
&& s2
->v2
!= v
)
212 if (s2
->v1
!= v
&& s2
->v2
!= v
)
214 s3
= GTS_SEGMENT (t
->e3
);
215 g_assert (s3
->v1
!= v
&& s3
->v2
!= v
);
220 * gts_triangles_angle:
221 * @t1: a #GtsTriangle.
222 * @t2: a #GtsTriangle.
224 * Returns: the value (in radians) of the angle between @t1 and @t2.
226 gdouble
gts_triangles_angle (GtsTriangle
* t1
,
229 gdouble nx1
, ny1
, nz1
, nx2
, ny2
, nz2
;
230 gdouble pvx
, pvy
, pvz
;
233 g_return_val_if_fail (t1
!= NULL
&& t2
!= NULL
, 0.0);
235 gts_triangle_normal (t1
, &nx1
, &ny1
, &nz1
);
236 gts_triangle_normal (t2
, &nx2
, &ny2
, &nz2
);
238 pvx
= ny1
*nz2
- nz1
*ny2
;
239 pvy
= nz1
*nx2
- nx1
*nz2
;
240 pvz
= nx1
*ny2
- ny1
*nx2
;
242 theta
= atan2 (sqrt (pvx
*pvx
+ pvy
*pvy
+ pvz
*pvz
),
243 nx1
*nx2
+ ny1
*ny2
+ nz1
*nz2
) - M_PI
;
244 return theta
< - M_PI
? theta
+ 2.*M_PI
: theta
;
248 * gts_triangles_are_compatible:
249 * @t1: a #GtsTriangle.
250 * @t2: a #GtsTriangle.
251 * @e: a #GtsEdge used by both @t1 and @t2.
253 * Checks if @t1 and @t2 have compatible orientations i.e. if @t1 and
254 * @t2 can be part of the same surface without conflict in the surface
255 * normal orientation.
257 * Returns: %TRUE if @t1 and @t2 are compatible, %FALSE otherwise.
259 gboolean
gts_triangles_are_compatible (GtsTriangle
* t1
,
263 GtsEdge
* e1
= NULL
, * e2
= NULL
;
265 g_return_val_if_fail (t1
!= NULL
, FALSE
);
266 g_return_val_if_fail (t2
!= NULL
, FALSE
);
267 g_return_val_if_fail (e
!= NULL
, FALSE
);
269 if (t1
->e1
== e
) e1
= t1
->e2
;
270 else if (t1
->e2
== e
) e1
= t1
->e3
;
271 else if (t1
->e3
== e
) e1
= t1
->e1
;
273 g_assert_not_reached ();
274 if (t2
->e1
== e
) e2
= t2
->e2
;
275 else if (t2
->e2
== e
) e2
= t2
->e3
;
276 else if (t2
->e3
== e
) e2
= t2
->e1
;
278 g_assert_not_reached ();
279 if (GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e2
)->v1
||
280 GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e2
)->v2
||
281 GTS_SEGMENT (e1
)->v2
== GTS_SEGMENT (e2
)->v1
||
282 GTS_SEGMENT (e1
)->v2
== GTS_SEGMENT (e2
)->v2
)
289 * @t: a #GtsTriangle.
291 * Returns: the area of the triangle @t.
293 gdouble
gts_triangle_area (GtsTriangle
* t
)
297 g_return_val_if_fail (t
!= NULL
, 0.0);
299 gts_triangle_normal (t
, &x
, &y
, &z
);
301 return sqrt (x
*x
+ y
*y
+ z
*z
)/2.;
305 * gts_triangle_perimeter:
306 * @t: a #GtsTriangle.
308 * Returns: the perimeter of the triangle @t.
310 gdouble
gts_triangle_perimeter (GtsTriangle
* t
)
314 g_return_val_if_fail (t
!= NULL
, 0.0);
316 v
= gts_triangle_vertex (t
);
318 gts_point_distance (GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
),
319 GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
)) +
320 gts_point_distance (GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
),
322 gts_point_distance (GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
),
326 /* perimeter of the equilateral triangle of area unity */
327 #define GOLDEN_PERIMETER 4.5590141139
330 * gts_triangle_quality:
331 * @t: a #GtsTriangle.
333 * The quality of a triangle is defined as the ratio of the square
334 * root of its surface area to its perimeter relative to this same
335 * ratio for an equilateral triangle with the same area. The quality
336 * is then one for an equilateral triangle and tends to zero for a
337 * very stretched triangle.
339 * Returns: the quality of the triangle @t.
341 gdouble
gts_triangle_quality (GtsTriangle
* t
)
345 g_return_val_if_fail (t
!= NULL
, 0.0);
347 perimeter
= gts_triangle_perimeter (t
);
348 return perimeter
> 0.0 ?
349 GOLDEN_PERIMETER
*sqrt (gts_triangle_area (t
))/perimeter
:
354 * gts_triangle_normal:
355 * @t: a #GtsTriangle.
356 * @x: the x coordinate of the normal.
357 * @y: the y coordinate of the normal.
358 * @z: the z coordinate of the normal.
360 * Computes the coordinates of the oriented normal of @t as the
361 * cross-product of two edges, using the left-hand rule. The normal is
362 * not normalized. If this triangle is part of a closed and oriented
363 * surface, the normal points to the outside of the surface.
365 void gts_triangle_normal (GtsTriangle
* t
,
370 GtsVertex
* v1
, * v2
= NULL
, * v3
= NULL
;
371 GtsPoint
* p1
, * p2
, * p3
;
372 gdouble x1
, y1
, z1
, x2
, y2
, z2
;
374 g_return_if_fail (t
!= NULL
);
376 v1
= GTS_SEGMENT (t
->e1
)->v1
;
377 if (GTS_SEGMENT (t
->e1
)->v1
== GTS_SEGMENT (t
->e2
)->v1
) {
378 v2
= GTS_SEGMENT (t
->e2
)->v2
;
379 v3
= GTS_SEGMENT (t
->e1
)->v2
;
381 else if (GTS_SEGMENT (t
->e1
)->v2
== GTS_SEGMENT (t
->e2
)->v2
) {
382 v2
= GTS_SEGMENT (t
->e1
)->v2
;
383 v3
= GTS_SEGMENT (t
->e2
)->v1
;
385 else if (GTS_SEGMENT (t
->e1
)->v1
== GTS_SEGMENT (t
->e2
)->v2
) {
386 v2
= GTS_SEGMENT (t
->e2
)->v1
;
387 v3
= GTS_SEGMENT (t
->e1
)->v2
;
389 else if (GTS_SEGMENT (t
->e1
)->v2
== GTS_SEGMENT (t
->e2
)->v1
) {
390 v2
= GTS_SEGMENT (t
->e1
)->v2
;
391 v3
= GTS_SEGMENT (t
->e2
)->v2
;
394 fprintf (stderr
, "t: %p t->e1: %p t->e2: %p t->e3: %p t->e1->v1: %p t->e1->v2: %p t->e2->v1: %p t->e2->v2: %p t->e3->v1: %p t->e3->v2: %p\n",
396 t
->e3
, GTS_SEGMENT (t
->e1
)->v1
, GTS_SEGMENT (t
->e1
)->v2
,
397 GTS_SEGMENT (t
->e2
)->v1
, GTS_SEGMENT (t
->e2
)->v2
,
398 GTS_SEGMENT (t
->e3
)->v1
, GTS_SEGMENT (t
->e3
)->v2
);
399 g_assert_not_reached ();
420 * gts_triangle_orientation:
421 * @t: a #GtsTriangle.
423 * Checks for the orientation of the plane (x,y) projection of a
424 * triangle. See gts_point_orientation() for details. This function
425 * is geometrically robust.
427 * Returns: a number depending on the orientation of the vertices of @t.
429 gdouble
gts_triangle_orientation (GtsTriangle
* t
)
431 GtsVertex
* v1
, * v2
= NULL
, * v3
= NULL
;
433 g_return_val_if_fail (t
!= NULL
, 0.0);
435 v1
= GTS_SEGMENT (t
->e1
)->v1
;
436 if (GTS_SEGMENT (t
->e1
)->v1
== GTS_SEGMENT (t
->e2
)->v1
) {
437 v2
= GTS_SEGMENT (t
->e2
)->v2
;
438 v3
= GTS_SEGMENT (t
->e1
)->v2
;
440 else if (GTS_SEGMENT (t
->e1
)->v2
== GTS_SEGMENT (t
->e2
)->v2
) {
441 v2
= GTS_SEGMENT (t
->e1
)->v2
;
442 v3
= GTS_SEGMENT (t
->e2
)->v1
;
444 else if (GTS_SEGMENT (t
->e1
)->v1
== GTS_SEGMENT (t
->e2
)->v2
) {
445 v2
= GTS_SEGMENT (t
->e2
)->v1
;
446 v3
= GTS_SEGMENT (t
->e1
)->v2
;
448 else if (GTS_SEGMENT (t
->e1
)->v2
== GTS_SEGMENT (t
->e2
)->v1
) {
449 v2
= GTS_SEGMENT (t
->e1
)->v2
;
450 v3
= GTS_SEGMENT (t
->e2
)->v2
;
453 g_assert_not_reached ();
454 return gts_point_orientation (GTS_POINT (v1
),
460 * gts_triangle_revert:
461 * @t: a #GtsTriangle.
463 * Changes the orientation of triangle @t, turning it inside out.
465 void gts_triangle_revert (GtsTriangle
* t
)
469 g_return_if_fail (t
!= NULL
);
477 * gts_triangles_from_edges:
478 * @edges: a list of #GtsEdge.
480 * Builds a list of unique triangles which have one of their edges in @edges.
482 * Returns: the list of triangles.
484 GSList
* gts_triangles_from_edges (GSList
* edges
)
487 GSList
* triangles
= NULL
, * i
;
489 hash
= g_hash_table_new (NULL
, NULL
);
492 GSList
* j
= GTS_EDGE (i
->data
)->triangles
;
494 GtsTriangle
* t
= j
->data
;
495 if (g_hash_table_lookup (hash
, t
) == NULL
) {
496 triangles
= g_slist_prepend (triangles
, t
);
497 g_hash_table_insert (hash
, t
, i
);
503 g_hash_table_destroy (hash
);
509 * gts_triangle_vertices_edges:
510 * @t: a #GtsTriangle.
511 * @e: a #GtsEdge belonging to the edges of @t or %NULL.
512 * @v1: a #GtsVertex used by @t.
513 * @v2: a #GtsVertex used by @t.
514 * @v3: a #GtsVertex used by @t.
515 * @e1: a #GtsEdge used by @t.
516 * @e2: a #GtsEdge used by @t.
517 * @e3: a #GtsEdge used by @t.
519 * Given @t and @e, returns @v1, @v2, @v3, @e1, @e2 and @e3. @e1
520 * has @v1 and @v2 as vertices, @e2 has @v2 and @v3 as vertices
521 * and @e3 has @v3 and @v1 as vertices. @v1, @v2 and @v3 respects
522 * the orientation of @t. If @e is not NULL, @e1 and @e are
525 void gts_triangle_vertices_edges (GtsTriangle
* t
,
534 GtsEdge
* ee1
, * ee2
;
536 g_return_if_fail (t
!= NULL
);
538 if (e
== t
->e1
|| e
== NULL
) {
539 *e1
= ee1
= t
->e1
; *e2
= ee2
= t
->e2
; *e3
= t
->e3
;
541 else if (e
== t
->e2
) {
542 *e1
= ee1
= e
; *e2
= ee2
= t
->e3
; *e3
= t
->e1
;
544 else if (e
== t
->e3
) {
545 *e1
= ee1
= e
; *e2
= ee2
= t
->e1
; *e3
= t
->e2
;
548 g_assert_not_reached ();
549 ee1
= ee2
= NULL
; /* to avoid complaints from the compiler */
551 if (GTS_SEGMENT (ee1
)->v2
== GTS_SEGMENT (ee2
)->v1
) {
552 *v1
= GTS_SEGMENT (ee1
)->v1
;
553 *v2
= GTS_SEGMENT (ee1
)->v2
;
554 *v3
= GTS_SEGMENT (ee2
)->v2
;
556 else if (GTS_SEGMENT (ee1
)->v2
== GTS_SEGMENT (ee2
)->v2
) {
557 *v1
= GTS_SEGMENT (ee1
)->v1
;
558 *v2
= GTS_SEGMENT (ee1
)->v2
;
559 *v3
= GTS_SEGMENT (ee2
)->v1
;
561 else if (GTS_SEGMENT (ee1
)->v1
== GTS_SEGMENT (ee2
)->v1
) {
562 *v1
= GTS_SEGMENT (ee1
)->v2
;
563 *v2
= GTS_SEGMENT (ee1
)->v1
;
564 *v3
= GTS_SEGMENT (ee2
)->v2
;
566 else if (GTS_SEGMENT (ee1
)->v1
== GTS_SEGMENT (ee2
)->v2
) {
567 *v1
= GTS_SEGMENT (ee1
)->v2
;
568 *v2
= GTS_SEGMENT (ee1
)->v1
;
569 *v3
= GTS_SEGMENT (ee2
)->v1
;
572 g_assert_not_reached ();
576 #define SQRT3 1.73205080757
579 * gts_triangle_enclosing:
580 * @klass: the class of the new triangle.
581 * @points: a list of #GtsPoint.
582 * @scale: a scaling factor (must be larger than one).
584 * Builds a new triangle (including new vertices and edges) enclosing
585 * the plane projection of all the points in @points. This triangle is
586 * equilateral and encloses a rectangle defined by the maximum and
587 * minimum x and y coordinates of the points. @scale is an homothetic
588 * scaling factor. If equal to one, the triangle encloses exactly the
589 * enclosing rectangle.
591 * Returns: a new #GtsTriangle.
593 GtsTriangle
* gts_triangle_enclosing (GtsTriangleClass
* klass
,
594 GSList
* points
, gdouble scale
)
596 gdouble xmax
, xmin
, ymax
, ymin
;
598 GtsVertex
* v1
, * v2
, * v3
;
599 GtsEdge
* e1
, * e2
, * e3
;
604 xmax
= xmin
= GTS_POINT (points
->data
)->x
;
605 ymax
= ymin
= GTS_POINT (points
->data
)->y
;
606 points
= points
->next
;
608 GtsPoint
* p
= points
->data
;
609 if (p
->x
> xmax
) xmax
= p
->x
;
610 else if (p
->x
< xmin
) xmin
= p
->x
;
611 if (p
->y
> ymax
) ymax
= p
->y
;
612 else if (p
->y
< ymin
) ymin
= p
->y
;
613 points
= points
->next
;
615 xo
= (xmax
+ xmin
)/2.;
616 yo
= (ymax
+ ymin
)/2.;
617 r
= scale
*sqrt((xmax
- xo
)*(xmax
- xo
) + (ymax
- yo
)*(ymax
- yo
));
618 if (r
== 0.0) r
= scale
;
619 v1
= gts_vertex_new (gts_vertex_class (),
620 xo
+ r
*SQRT3
, yo
- r
, 0.0);
621 v2
= gts_vertex_new (gts_vertex_class (),
623 v3
= gts_vertex_new (gts_vertex_class (),
624 xo
- r
*SQRT3
, yo
- r
, 0.0);
625 e1
= gts_edge_new (gts_edge_class (), v1
, v2
);
626 e2
= gts_edge_new (gts_edge_class (), v2
, v3
);
627 e3
= gts_edge_new (gts_edge_class (), v3
, v1
);
628 return gts_triangle_new (gts_triangle_class (), e1
, e2
, e3
);
632 * gts_triangle_neighbor_number:
633 * @t: a #GtsTriangle.
635 * Returns: the number of triangles neighbors of @t.
637 guint
gts_triangle_neighbor_number (GtsTriangle
* t
)
641 GtsEdge
* ee
[4], ** e
= ee
;
643 g_return_val_if_fail (t
!= NULL
, 0);
645 ee
[0] = t
->e1
; ee
[1] = t
->e2
; ee
[2] = t
->e3
; ee
[3] = NULL
;
647 i
= (*e
++)->triangles
;
649 GtsTriangle
* t1
= i
->data
;
659 * gts_triangle_neighbors:
660 * @t: a #GtsTriangle.
662 * Returns: a list of #GtsTriangle neighbors of @t.
664 GSList
* gts_triangle_neighbors (GtsTriangle
* t
)
666 GSList
* i
, * list
= NULL
;
667 GtsEdge
* ee
[4], ** e
= ee
;
669 g_return_val_if_fail (t
!= NULL
, NULL
);
671 ee
[0] = t
->e1
; ee
[1] = t
->e2
; ee
[2] = t
->e3
; ee
[3] = NULL
;
673 i
= (*e
++)->triangles
;
675 GtsTriangle
* t1
= i
->data
;
677 list
= g_slist_prepend (list
, t1
);
685 * gts_triangles_common_edge:
686 * @t1: a #GtsTriangle.
687 * @t2: a #GtsTriangle.
689 * Returns: a #GtsEdge common to both @t1 and @t2 or %NULL if @t1 and @t2
690 * do not share any edge.
692 GtsEdge
* gts_triangles_common_edge (GtsTriangle
* t1
,
695 g_return_val_if_fail (t1
!= NULL
, NULL
);
696 g_return_val_if_fail (t2
!= NULL
, NULL
);
698 if (t1
->e1
== t2
->e1
|| t1
->e1
== t2
->e2
|| t1
->e1
== t2
->e3
)
700 if (t1
->e2
== t2
->e1
|| t1
->e2
== t2
->e2
|| t1
->e2
== t2
->e3
)
702 if (t1
->e3
== t2
->e1
|| t1
->e3
== t2
->e2
|| t1
->e3
== t2
->e3
)
708 * gts_triangle_is_duplicate:
709 * @t: a #GtsTriangle.
711 * Returns: a #GtsTriangle different from @t but sharing all its edges
712 * with @t or %NULL if there is none.
714 GtsTriangle
* gts_triangle_is_duplicate (GtsTriangle
* t
)
719 g_return_val_if_fail (t
!= NULL
, NULL
);
723 i
= t
->e1
->triangles
;
725 GtsTriangle
* t1
= i
->data
;
727 (t1
->e1
== e2
|| t1
->e2
== e2
|| t1
->e3
== e2
) &&
728 (t1
->e1
== e3
|| t1
->e2
== e3
|| t1
->e3
== e3
))
737 * gts_triangle_use_edges:
742 * Returns: a #GtsTriangle having @e1, @e2 and @e3 as edges or %NULL if @e1,
743 * @e2 and @e3 are not part of any triangle.
745 GtsTriangle
* gts_triangle_use_edges (GtsEdge
* e1
,
751 g_return_val_if_fail (e1
!= NULL
, NULL
);
752 g_return_val_if_fail (e2
!= NULL
, NULL
);
753 g_return_val_if_fail (e3
!= NULL
, NULL
);
757 GtsTriangle
* t
= i
->data
;
758 if ((t
->e1
== e2
&& (t
->e2
== e3
|| t
->e3
== e3
)) ||
759 (t
->e2
== e2
&& (t
->e1
== e3
|| t
->e3
== e3
)) ||
760 (t
->e3
== e2
&& (t
->e1
== e3
|| t
->e2
== e3
)))
769 * gts_triangle_is_ok:
770 * @t: a #GtsTriangle.
772 * Returns: %TRUE if @t is a non-degenerate, non-duplicate triangle,
775 gboolean
gts_triangle_is_ok (GtsTriangle
* t
)
777 g_return_val_if_fail (t
!= NULL
, FALSE
);
778 g_return_val_if_fail (t
->e1
!= NULL
, FALSE
);
779 g_return_val_if_fail (t
->e2
!= NULL
, FALSE
);
780 g_return_val_if_fail (t
->e3
!= NULL
, FALSE
);
781 g_return_val_if_fail (t
->e1
!= t
->e2
&& t
->e1
!= t
->e3
&& t
->e2
!= t
->e3
,
783 g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t
->e1
),
784 GTS_SEGMENT (t
->e2
)),
786 g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t
->e1
),
787 GTS_SEGMENT (t
->e3
)),
789 g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t
->e2
),
790 GTS_SEGMENT (t
->e3
)),
792 g_return_val_if_fail (GTS_SEGMENT (t
->e1
)->v1
!= GTS_SEGMENT (t
->e1
)->v2
,
794 g_return_val_if_fail (GTS_SEGMENT (t
->e2
)->v1
!= GTS_SEGMENT (t
->e2
)->v2
,
796 g_return_val_if_fail (GTS_SEGMENT (t
->e3
)->v1
!= GTS_SEGMENT (t
->e3
)->v2
,
798 g_return_val_if_fail (GTS_OBJECT (t
)->reserved
== NULL
, FALSE
);
799 g_return_val_if_fail (!gts_triangle_is_duplicate (t
), FALSE
);
804 * gts_triangle_vertices:
805 * @t: a #GtsTriangle.
806 * @v1: a pointer on a #GtsVertex.
807 * @v2: a pointer on a #GtsVertex.
808 * @v3: a pointer on a #GtsVertex.
810 * Fills @v1, @v2 and @v3 with the oriented set of vertices, summits of @t.
812 void gts_triangle_vertices (GtsTriangle
* t
,
813 GtsVertex
** v1
, GtsVertex
** v2
, GtsVertex
** v3
)
815 GtsSegment
* e1
, * e2
;
817 g_return_if_fail (t
!= NULL
);
818 g_return_if_fail (v1
!= NULL
&& v2
!= NULL
&& v3
!= NULL
);
820 e1
= GTS_SEGMENT (t
->e1
);
821 e2
= GTS_SEGMENT (t
->e2
);
823 if (GTS_SEGMENT (e1
)->v2
== GTS_SEGMENT (e2
)->v1
) {
824 *v1
= GTS_SEGMENT (e1
)->v1
;
825 *v2
= GTS_SEGMENT (e1
)->v2
;
826 *v3
= GTS_SEGMENT (e2
)->v2
;
828 else if (GTS_SEGMENT (e1
)->v2
== GTS_SEGMENT (e2
)->v2
) {
829 *v1
= GTS_SEGMENT (e1
)->v1
;
830 *v2
= GTS_SEGMENT (e1
)->v2
;
831 *v3
= GTS_SEGMENT (e2
)->v1
;
833 else if (GTS_SEGMENT (e1
)->v1
== GTS_SEGMENT (e2
)->v1
) {
834 *v1
= GTS_SEGMENT (e1
)->v2
;
835 *v2
= GTS_SEGMENT (e1
)->v1
;
836 *v3
= GTS_SEGMENT (e2
)->v2
;
839 *v1
= GTS_SEGMENT (e1
)->v2
;
840 *v2
= GTS_SEGMENT (e1
)->v1
;
841 *v3
= GTS_SEGMENT (e2
)->v1
;
846 * gts_triangle_circumcircle_center:
847 * @t: a #GtsTriangle.
848 * @point_class: a #GtsPointClass.
850 * Returns: a new #GtsPoint, center of the circumscribing circle of @t or
851 * %NULL if the circumscribing circle is not defined.
853 GtsPoint
* gts_triangle_circumcircle_center (GtsTriangle
* t
,
854 GtsPointClass
* point_class
)
856 GtsVertex
* v1
, * v2
, * v3
;
857 gdouble xa
, ya
, xb
, yb
, xc
, yc
;
858 gdouble xd
, yd
, xe
, ye
;
859 gdouble xad
, yad
, xae
, yae
;
862 g_return_val_if_fail (t
!= NULL
, NULL
);
863 g_return_val_if_fail (point_class
!= NULL
, NULL
);
865 gts_triangle_vertices (t
, &v1
, &v2
, &v3
);
867 xa
= GTS_POINT (v1
)->x
; ya
= GTS_POINT (v1
)->y
;
868 xb
= GTS_POINT (v2
)->x
; yb
= GTS_POINT (v2
)->y
;
869 xc
= GTS_POINT (v3
)->x
; yc
= GTS_POINT (v3
)->y
;
870 xd
= (xa
+ xb
)/2.; yd
= (ya
+ yb
)/2.;
871 xe
= (xa
+ xc
)/2.; ye
= (ya
+ yc
)/2.;
872 xad
= xd
- xa
; yad
= yd
- ya
;
873 xae
= xe
- xa
; yae
= ye
- ya
;
874 det
= xad
*yae
- xae
*yad
;
877 return gts_point_new (point_class
,
878 (yae
*yad
*(yd
- ye
) + xad
*yae
*xd
- xae
*yad
*xe
)/det
,
879 -(xae
*xad
*(xd
- xe
) + yad
*xae
*yd
- yae
*xad
*ye
)/det
,
883 /* square of the maximum area ratio admissible */
884 #define AREA_RATIO_MAX2 1e8
886 static gboolean
points_are_folded (GtsPoint
* A
,
892 GtsVector AB
, AC
, AD
;
894 gdouble nn1
, nn2
, n1n2
;
896 gts_vector_init (AB
, A
, B
);
897 gts_vector_init (AC
, A
, C
);
898 gts_vector_init (AD
, A
, D
);
899 gts_vector_cross (n1
, AB
, AC
);
900 gts_vector_cross (n2
, AD
, AB
);
902 nn1
= gts_vector_scalar (n1
, n1
);
903 nn2
= gts_vector_scalar (n2
, n2
);
904 if (nn1
>= AREA_RATIO_MAX2
*nn2
|| nn2
>= AREA_RATIO_MAX2
*nn1
)
906 n1n2
= gts_vector_scalar (n1
, n2
);
909 if (n1n2
*n1n2
/(nn1
*nn2
) > max
)
914 static GtsVertex
* triangle_use_vertices (GtsTriangle
* t
,
919 * v1
= GTS_SEGMENT (t
->e1
)->v1
,
920 * v2
= GTS_SEGMENT (t
->e1
)->v2
,
921 * v3
= gts_triangle_vertex (t
);
941 g_assert_not_reached ();
946 * gts_triangles_are_folded:
947 * @triangles: a list of #GtsTriangle.
949 * @B: another #GtsVertex.
950 * @max: the maximum value of the square of the cosine of the angle between
953 * Given a list of triangles sharing @A and @B as vertices, checks if any
954 * two triangles in the list make an angle larger than a given value defined
957 * Returns: %TRUE if any pair of triangles in @triangles makes an angle larger
958 * than the maximum value, %FALSE otherwise.
960 gboolean
gts_triangles_are_folded (GSList
* triangles
,
961 GtsVertex
* A
, GtsVertex
* B
,
966 g_return_val_if_fail (A
!= NULL
, TRUE
);
967 g_return_val_if_fail (B
!= NULL
, TRUE
);
971 GtsVertex
* C
= triangle_use_vertices (i
->data
, A
, B
);
972 GSList
* j
= i
->next
;
974 GtsVertex
* D
= triangle_use_vertices (j
->data
, A
, B
);
975 if (points_are_folded (GTS_POINT (A
),
989 * gts_triangle_is_stabbed:
990 * @t: a #GtsTriangle.
992 * @orientation: a pointer or %NULL.
994 * Returns: one of the vertices of @t, one of the edges of @t or @t if
995 * any of these are stabbed by the ray starting at @p (included) and
996 * ending at (@p->x, @p->y, +infty), %NULL otherwise. If the ray is
997 * contained in the plane of the triangle %NULL is also returned. If
998 * @orientation is not %NULL, it is set to the value of the
999 * orientation of @p relative to @t (as given by
1000 * gts_point_orientation_3d()).
1002 GtsObject
* gts_triangle_is_stabbed (GtsTriangle
* t
,
1004 gdouble
* orientation
)
1006 GtsVertex
* v1
, * v2
, * v3
, * inverted
= NULL
;
1007 GtsEdge
* e1
, * e2
, * e3
, * tmp
;
1008 gdouble o
, o1
, o2
, o3
;
1010 g_return_val_if_fail (t
!= NULL
, NULL
);
1011 g_return_val_if_fail (p
!= NULL
, NULL
);
1013 gts_triangle_vertices_edges (t
, NULL
, &v1
, &v2
, &v3
, &e1
, &e2
, &e3
);
1014 o
= gts_point_orientation (GTS_POINT (v1
), GTS_POINT (v2
), GTS_POINT (v3
));
1025 o
= gts_point_orientation_3d (GTS_POINT (v1
),
1031 o1
= gts_point_orientation (GTS_POINT (v1
), GTS_POINT (v2
), p
);
1034 o2
= gts_point_orientation (GTS_POINT (v2
), GTS_POINT (v3
), p
);
1037 o3
= gts_point_orientation (GTS_POINT (v3
), GTS_POINT (v1
), p
);
1040 if (orientation
) *orientation
= inverted
? -o
: o
;
1043 return GTS_OBJECT (v2
);
1045 return GTS_OBJECT (v1
);
1046 return GTS_OBJECT (e1
);
1050 return GTS_OBJECT (v3
);
1051 return GTS_OBJECT (e2
);
1054 return GTS_OBJECT (e3
);
1055 return GTS_OBJECT (t
);
1059 * gts_triangle_interpolate_height:
1060 * @t: a #GtsTriangle.
1063 * Fills the z-coordinate of point @p belonging to the plane
1064 * projection of triangle @t with the linearly interpolated value of
1065 * the z-coordinates of the vertices of @t.
1067 void gts_triangle_interpolate_height (GtsTriangle
* t
, GtsPoint
* p
)
1069 GtsPoint
* p1
, * p2
, * p3
;
1070 gdouble x1
, x2
, y1
, y2
, det
;
1072 g_return_if_fail (t
!= NULL
);
1073 g_return_if_fail (p
!= NULL
);
1075 p1
= GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
);
1076 p2
= GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
);
1077 p3
= GTS_POINT (gts_triangle_vertex (t
));
1083 det
= x1
*y2
- x2
*y1
;
1085 p
->z
= (p1
->z
+ p2
->z
+ p3
->z
)/3.;
1087 gdouble x
= p
->x
- p1
->x
;
1088 gdouble y
= p
->y
- p1
->y
;
1089 gdouble a
= (x
*y2
- y
*x2
)/det
;
1090 gdouble b
= (y
*x1
- x
*y1
)/det
;
1092 p
->z
= (1. - a
- b
)*p1
->z
+ a
*p2
->z
+ b
*p3
->z
;