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 #include "gts-private.h"
24 #include "predicates.h"
26 static void point_read (GtsObject
** o
, GtsFile
* f
)
28 GtsPoint
* p
= GTS_POINT (*o
);
30 if (GTS_POINT_CLASS ((*o
)->klass
)->binary
) {
31 if (gts_file_read (f
, &(p
->x
), sizeof (gdouble
), 1) != 1) {
32 gts_file_error (f
, "expecting a binary number (x coordinate)");
35 if (gts_file_read (f
, &(p
->y
), sizeof (gdouble
), 1) != 1) {
36 gts_file_error (f
, "expecting a binary number (y coordinate)");
39 if (gts_file_read (f
, &(p
->z
), sizeof (gdouble
), 1) != 1) {
40 gts_file_error (f
, "expecting a binary number (z coordinate)");
45 if (f
->type
!= GTS_INT
&& f
->type
!= GTS_FLOAT
) {
46 gts_file_error (f
, "expecting a number (x coordinate)");
49 p
->x
= atof (f
->token
->str
);
51 gts_file_next_token (f
);
52 if (f
->type
!= GTS_INT
&& f
->type
!= GTS_FLOAT
) {
53 gts_file_error (f
, "expecting a number (y coordinate)");
56 p
->y
= atof (f
->token
->str
);
58 gts_file_next_token (f
);
59 if (f
->type
!= GTS_INT
&& f
->type
!= GTS_FLOAT
) {
60 gts_file_error (f
, "expecting a number (z coordinate)");
63 p
->z
= atof (f
->token
->str
);
65 gts_file_next_token (f
);
69 static void point_write (GtsObject
* o
, FILE * fptr
)
71 GtsPoint
* p
= GTS_POINT (o
);
73 if (GTS_POINT_CLASS ((o
)->klass
)->binary
) {
74 fwrite (&(p
->x
), sizeof (gdouble
), 1, fptr
);
75 fwrite (&(p
->y
), sizeof (gdouble
), 1, fptr
);
76 fwrite (&(p
->z
), sizeof (gdouble
), 1, fptr
);
79 fprintf (fptr
, "%.10g %.10g %.10g", p
->x
, p
->y
, p
->z
);
82 static void point_class_init (GtsObjectClass
* klass
)
84 klass
->read
= point_read
;
85 klass
->write
= point_write
;
91 * Returns: the #GtsPointClass.
93 GtsPointClass
* gts_point_class (void)
95 static GtsPointClass
* klass
= NULL
;
98 GtsObjectClassInfo point_info
= {
101 sizeof (GtsPointClass
),
102 (GtsObjectClassInitFunc
) point_class_init
,
103 (GtsObjectInitFunc
) NULL
,
104 (GtsArgSetFunc
) NULL
,
107 klass
= gts_object_class_new (gts_object_class (),
116 * @klass: a #GtsPointClass.
117 * @x: the x-coordinate.
118 * @y: the y-coordinate.
119 * @z: the z-coordinate.
121 * Returns: a new #GtsPoint.
123 GtsPoint
* gts_point_new (GtsPointClass
* klass
,
124 gdouble x
, gdouble y
, gdouble z
)
128 p
= GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass
)));
139 * @x: the x-coordinate.
140 * @y: the y-coordinate.
141 * @z: the z-coordinate.
143 * Sets the coordinates of @p.
145 void gts_point_set (GtsPoint
* p
, gdouble x
, gdouble y
, gdouble z
)
147 g_return_if_fail (p
!= NULL
);
155 * gts_point_distance:
157 * @p2: another #GtsPoint.
159 * Returns: the Euclidean distance between @p1 and @p2.
161 gdouble
gts_point_distance (GtsPoint
* p1
, GtsPoint
* p2
)
163 g_return_val_if_fail (p1
!= NULL
&& p2
!= NULL
, 0.0);
165 return sqrt ((p1
->x
- p2
->x
)*(p1
->x
- p2
->x
) +
166 (p1
->y
- p2
->y
)*(p1
->y
- p2
->y
) +
167 (p1
->z
- p2
->z
)*(p1
->z
- p2
->z
));
171 * gts_point_distance2:
173 * @p2: another #GtsPoint.
175 * Returns: the square of the Euclidean distance between @p1 and @p2.
177 gdouble
gts_point_distance2 (GtsPoint
* p1
, GtsPoint
* p2
)
179 g_return_val_if_fail (p1
!= NULL
&& p2
!= NULL
, 0.0);
182 (p1
->x
- p2
->x
)*(p1
->x
- p2
->x
) +
183 (p1
->y
- p2
->y
)*(p1
->y
- p2
->y
) +
184 (p1
->z
- p2
->z
)*(p1
->z
- p2
->z
);
188 * gts_point_orientation_3d:
194 * Checks if @p4 lies above, below or on the plane passing through the
195 * points @p1, @p2 and @p3. Below is defined so that @p1, @p2 and @p3
196 * appear in counterclockwise order when viewed from above the
197 * plane. The returned value is an approximation of six times the
198 * signed volume of the tetrahedron defined by the four points. This
199 * function uses adaptive floating point arithmetic and is
200 * consequently geometrically robust.
202 * Returns: a positive value if @p4 lies below, a negative value if
203 * @p4 lies above the plane, zero if the four points are coplanar.
205 gdouble
gts_point_orientation_3d (GtsPoint
* p1
,
210 g_return_val_if_fail (p1
!= NULL
&& p2
!= NULL
&&
211 p3
!= NULL
&& p4
!= NULL
, 0.0);
212 return orient3d ((gdouble
*) &p1
->x
,
219 * gts_point_is_in_triangle:
221 * @t: a #GtsTriangle.
223 * Tests if the planar projection (x, y) of @p is inside, outside or
224 * on the boundary of the planar projection of @t. This function is
225 * geometrically robust.
227 * Returns: %GTS_IN if @p is inside @t, %GTS_ON if @p is on the boundary of
228 * @t, %GTS_OUT otherwise.
230 GtsIntersect
gts_point_is_in_triangle (GtsPoint
* p
, GtsTriangle
* t
)
232 GtsVertex
* v1
, * v2
, * v3
;
235 g_return_val_if_fail (p
!= NULL
&& t
!= NULL
, FALSE
);
237 gts_triangle_vertices (t
, &v1
, &v2
, &v3
);
239 d1
= gts_point_orientation (GTS_POINT (v1
), GTS_POINT (v2
), p
);
242 d2
= gts_point_orientation (GTS_POINT (v2
), GTS_POINT (v3
), p
);
245 d3
= gts_point_orientation (GTS_POINT (v3
), GTS_POINT (v1
), p
);
248 if (d1
== 0.0 || d2
== 0.0 || d3
== 0.0)
254 * gts_point_in_triangle_circle:
256 * @t: a #GtsTriangle.
258 * Tests if the planar projection (x, y) of @p is inside or outside
259 * the circumcircle of the planar projection of @t. This function is
260 * geometrically robust.
262 * Returns: a positive number if @p lies inside,
263 * a negative number if @p lies outside and zero if @p lies on
264 * the circumcircle of @t.
266 gdouble
gts_point_in_triangle_circle (GtsPoint
* p
, GtsTriangle
* t
)
268 GtsPoint
* p1
, * p2
, * p3
;
270 g_return_val_if_fail (p
!= NULL
&& t
!= NULL
, 0.0);
272 gts_triangle_vertices (t
,
277 return incircle ((gdouble
*) &p1
->x
,
284 * gts_point_in_circle:
290 * Tests if the planar projection (x, y) of @p is inside or outside the
291 * circle defined by the planar projection of @p1, @p2 and @p3.
293 * Returns: a positive number if @p lies inside,
294 * a negative number if @p lies outside and zero if @p lies on
297 gdouble
gts_point_in_circle (GtsPoint
* p
,
298 GtsPoint
* p1
, GtsPoint
* p2
, GtsPoint
* p3
)
300 g_return_val_if_fail (p
!= NULL
&& p1
!= NULL
&& p2
!= NULL
&& p3
!= NULL
,
303 return incircle ((gdouble
*) &p1
->x
,
310 * gts_point_in_sphere:
317 * Tests if @p is inside or outside the sphere defined by @p1, @p2,
320 * Returns: a positive number if @p lies inside,
321 * a negative number if @p lies outside and zero if @p lies on
324 gdouble
gts_point_in_sphere (GtsPoint
* p
,
325 GtsPoint
* p1
, GtsPoint
* p2
, GtsPoint
* p3
, GtsPoint
* p4
)
327 g_return_val_if_fail (p
!= NULL
&& p1
!= NULL
&& p2
!= NULL
&& p3
!= NULL
&& p4
!= NULL
,
330 return insphere ((gdouble
*) &p1
->x
,
338 * gts_point_segment_distance2:
342 * Returns: the square of the minimun Euclidean distance between @p and @s.
344 gdouble
gts_point_segment_distance2 (GtsPoint
* p
, GtsSegment
* s
)
346 gdouble t
, ns2
, x
, y
, z
;
349 g_return_val_if_fail (p
!= NULL
, 0.0);
350 g_return_val_if_fail (s
!= NULL
, 0.0);
352 p1
= GTS_POINT (s
->v1
);
353 p2
= GTS_POINT (s
->v2
);
354 ns2
= gts_point_distance2 (p1
, p2
);
356 return gts_point_distance2 (p
, p1
);
357 t
= ((p2
->x
- p1
->x
)*(p
->x
- p1
->x
) +
358 (p2
->y
- p1
->y
)*(p
->y
- p1
->y
) +
359 (p2
->z
- p1
->z
)*(p
->z
- p1
->z
))/ns2
;
361 return gts_point_distance2 (p
, p2
);
363 return gts_point_distance2 (p
, p1
);
364 x
= (1. - t
)*p1
->x
+ t
*p2
->x
- p
->x
;
365 y
= (1. - t
)*p1
->y
+ t
*p2
->y
- p
->y
;
366 z
= (1. - t
)*p1
->z
+ t
*p2
->z
- p
->z
;
367 return x
*x
+ y
*y
+ z
*z
;
371 * gts_point_segment_distance:
375 * Returns: the minimun Euclidean distance between @p and @s.
377 gdouble
gts_point_segment_distance (GtsPoint
* p
, GtsSegment
* s
)
379 g_return_val_if_fail (p
!= NULL
, 0.0);
380 g_return_val_if_fail (s
!= NULL
, 0.0);
382 return sqrt (gts_point_segment_distance2 (p
, s
));
386 * gts_point_segment_closest:
389 * @closest: a #GtsPoint.
391 * Set the coordinates of @closest to the coordinates of the point belonging
392 * to @s closest to @p.
394 void gts_point_segment_closest (GtsPoint
* p
,
401 g_return_if_fail (p
!= NULL
);
402 g_return_if_fail (s
!= NULL
);
403 g_return_if_fail (closest
!= NULL
);
405 p1
= GTS_POINT (s
->v1
);
406 p2
= GTS_POINT (s
->v2
);
407 ns2
= gts_point_distance2 (p1
, p2
);
410 gts_point_set (closest
, p1
->x
, p1
->y
, p1
->z
);
414 t
= ((p2
->x
- p1
->x
)*(p
->x
- p1
->x
) +
415 (p2
->y
- p1
->y
)*(p
->y
- p1
->y
) +
416 (p2
->z
- p1
->z
)*(p
->z
- p1
->z
))/ns2
;
419 gts_point_set (closest
, p2
->x
, p2
->y
, p2
->z
);
421 gts_point_set (closest
, p1
->x
, p1
->y
, p1
->z
);
423 gts_point_set (closest
,
424 (1. - t
)*p1
->x
+ t
*p2
->x
,
425 (1. - t
)*p1
->y
+ t
*p2
->y
,
426 (1. - t
)*p1
->z
+ t
*p2
->z
);
430 * gts_point_triangle_distance2:
432 * @t: a #GtsTriangle.
434 * Returns: the square of the minimun Euclidean distance between @p and @t.
436 gdouble
gts_point_triangle_distance2 (GtsPoint
* p
, GtsTriangle
* t
)
438 GtsPoint
* p1
, * p2
, * p3
;
439 GtsEdge
* e1
, * e2
, * e3
;
440 GtsVector p1p2
, p1p3
, pp1
;
441 gdouble A
, B
, C
, D
, E
, det
;
445 g_return_val_if_fail (p
!= NULL
, 0.0);
446 g_return_val_if_fail (t
!= NULL
, 0.0);
448 gts_triangle_vertices_edges (t
, NULL
,
454 gts_vector_init (p1p2
, p1
, p2
);
455 gts_vector_init (p1p3
, p1
, p3
);
456 gts_vector_init (pp1
, p
, p1
);
458 B
= gts_vector_scalar (p1p3
, p1p2
);
459 E
= gts_vector_scalar (p1p2
, p1p2
);
460 C
= gts_vector_scalar (p1p3
, p1p3
);
463 if (det
== 0.) { /* p1p2 and p1p3 are colinear */
464 gdouble d1
= gts_point_segment_distance2 (p
, GTS_SEGMENT (e1
));
465 gdouble d2
= gts_point_segment_distance2 (p
, GTS_SEGMENT (e3
));
471 A
= gts_vector_scalar (p1p3
, pp1
);
472 D
= gts_vector_scalar (p1p2
, pp1
);
474 t1
= (D
*C
- A
*B
)/det
;
475 t2
= (A
*E
- D
*B
)/det
;
478 return gts_point_segment_distance2 (p
, GTS_SEGMENT (e3
));
480 return gts_point_segment_distance2 (p
, GTS_SEGMENT (e1
));
482 return gts_point_segment_distance2 (p
, GTS_SEGMENT (e2
));
484 x
= pp1
[0] + t1
*p1p2
[0] + t2
*p1p3
[0];
485 y
= pp1
[1] + t1
*p1p2
[1] + t2
*p1p3
[1];
486 z
= pp1
[2] + t1
*p1p2
[2] + t2
*p1p3
[2];
488 return x
*x
+ y
*y
+ z
*z
;
492 * gts_point_triangle_distance:
494 * @t: a #GtsTriangle.
496 * Returns: the minimun Euclidean distance between @p and @t.
498 gdouble
gts_point_triangle_distance (GtsPoint
* p
, GtsTriangle
* t
)
500 g_return_val_if_fail (p
!= NULL
, 0.0);
501 g_return_val_if_fail (t
!= NULL
, 0.0);
503 return sqrt (gts_point_triangle_distance2 (p
, t
));
507 * gts_point_triangle_closest:
509 * @t: a #GtsTriangle.
510 * @closest: a #GtsPoint.
512 * Set the coordinates of @closest to those of the point belonging to @t and
515 void gts_point_triangle_closest (GtsPoint
* p
,
519 GtsPoint
* p1
, * p2
, * p3
;
520 GtsEdge
* e1
, * e2
, * e3
;
521 GtsVector p1p2
, p1p3
, pp1
;
522 gdouble A
, B
, C
, D
, E
, det
;
525 g_return_if_fail (p
!= NULL
);
526 g_return_if_fail (t
!= NULL
);
527 g_return_if_fail (closest
!= NULL
);
529 gts_triangle_vertices_edges (t
, NULL
,
535 gts_vector_init (p1p2
, p1
, p2
);
536 gts_vector_init (p1p3
, p1
, p3
);
537 gts_vector_init (pp1
, p
, p1
);
539 B
= gts_vector_scalar (p1p3
, p1p2
);
540 E
= gts_vector_scalar (p1p2
, p1p2
);
541 C
= gts_vector_scalar (p1p3
, p1p3
);
544 if (det
== 0.) { /* p1p2 and p1p3 are colinear */
546 GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ())));
547 gts_point_segment_closest (p
, GTS_SEGMENT (e1
), cp
);
548 gts_point_segment_closest (p
, GTS_SEGMENT (e3
), closest
);
550 if (gts_point_distance2 (cp
, p
) < gts_point_distance2 (closest
, p
))
551 gts_point_set (closest
, cp
->x
, cp
->y
, cp
->z
);
552 gts_object_destroy (GTS_OBJECT (cp
));
556 A
= gts_vector_scalar (p1p3
, pp1
);
557 D
= gts_vector_scalar (p1p2
, pp1
);
559 t1
= (D
*C
- A
*B
)/det
;
560 t2
= (A
*E
- D
*B
)/det
;
563 gts_point_segment_closest (p
, GTS_SEGMENT (e3
), closest
);
565 gts_point_segment_closest (p
, GTS_SEGMENT (e1
), closest
);
566 else if (t1
+ t2
> 1.)
567 gts_point_segment_closest (p
, GTS_SEGMENT (e2
), closest
);
569 gts_point_set (closest
,
570 p1
->x
+ t1
*p1p2
[0] + t2
*p1p3
[0],
571 p1
->y
+ t1
*p1p2
[1] + t2
*p1p3
[1],
572 p1
->z
+ t1
*p1p2
[2] + t2
*p1p3
[2]);
576 * gts_segment_triangle_intersection:
578 * @t: a #GtsTriangle.
579 * @boundary: if %TRUE, the boundary of @t is taken into account.
580 * @klass: a #GtsPointClass to be used for the new point.
582 * Checks if @s intersects @t. If this is the case, creates a new
583 * point pi intersection of @s with @t.
585 * This function is geometrically robust in the sense that it will not
586 * return a point if @s and @t do not intersect and will return a
587 * point if @s and @t do intersect. However, the point coordinates are
588 * subject to round-off errors.
590 * Note that this function will not return any point if @s is contained in
591 * the plane defined by @t.
593 * Returns: a summit of @t (if @boundary is set to %TRUE), one of the endpoints
594 * of @s or a new #GtsPoint, intersection of @s with @t or %NULL if @s
595 * and @t don't intersect.
597 GtsPoint
* gts_segment_triangle_intersection (GtsSegment
* s
,
600 GtsPointClass
* klass
)
602 GtsPoint
* A
, * B
, * C
, * D
, * E
, * I
;
603 gdouble ABCE
, ABCD
, ADCE
, ABDE
, BCDE
;
606 g_return_val_if_fail (s
!= NULL
, NULL
);
607 g_return_val_if_fail (t
!= NULL
, NULL
);
608 g_return_val_if_fail (klass
!= NULL
, NULL
);
610 A
= GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
);
611 B
= GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
);
612 C
= GTS_POINT (gts_triangle_vertex (t
));
613 D
= GTS_POINT (s
->v1
);
614 E
= GTS_POINT (s
->v2
);
616 ABCE
= gts_point_orientation_3d (A
, B
, C
, E
);
617 ABCD
= gts_point_orientation_3d (A
, B
, C
, D
);
618 if (ABCE
< 0.0 || ABCD
> 0.0) {
621 tmpp
= E
; E
= D
; D
= tmpp
;
622 tmp
= ABCE
; ABCE
= ABCD
; ABCD
= tmp
;
624 if (ABCE
< 0.0 || ABCD
> 0.0)
626 ADCE
= gts_point_orientation_3d (A
, D
, C
, E
);
627 if ((boundary
&& ADCE
< 0.) || (!boundary
&& ADCE
<= 0.))
629 ABDE
= gts_point_orientation_3d (A
, B
, D
, E
);
630 if ((boundary
&& ABDE
< 0.) || (!boundary
&& ABDE
<= 0.))
632 BCDE
= gts_point_orientation_3d (B
, C
, D
, E
);
633 if ((boundary
&& BCDE
< 0.) || (!boundary
&& BCDE
<= 0.))
637 /* s is contained in the plane defined by t*/
643 if (boundary
) { /* corners of @t */
650 else if (BCDE
== 0. && ADCE
== 0.)
653 c
= ABCE
/(ABCE
- ABCD
);
654 I
= GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass
)));
656 E
->x
+ c
*(D
->x
- E
->x
),
657 E
->y
+ c
*(D
->y
- E
->y
),
658 E
->z
+ c
*(D
->z
- E
->z
));
663 * gts_point_transform:
665 * @m: the #GtsMatrix representing the transformation to
666 * apply to the coordinates of @p.
668 * Transform the coordinates of @p according to @m. (p[] becomes m[][].p[]).
670 void gts_point_transform (GtsPoint
* p
, GtsMatrix
* m
)
673 g_return_if_fail (p
!= NULL
&& m
!= NULL
);
674 x
= m
[0][0]*p
->x
+ m
[0][1]*p
->y
+ m
[0][2]*p
->z
+ m
[0][3];
675 y
= m
[1][0]*p
->x
+ m
[1][1]*p
->y
+ m
[1][2]*p
->z
+ m
[1][3];
676 z
= m
[2][0]*p
->x
+ m
[2][1]*p
->y
+ m
[2][2]*p
->z
+ m
[2][3];
677 p
->x
= x
; p
->y
= y
; p
->z
= z
;
681 * gts_point_orientation:
686 * Checks for orientation of the projection of three points on the
687 * (x,y) plane. The result is also an approximation of twice the
688 * signed area of the triangle defined by the three points. This
689 * function uses adaptive floating point arithmetic and is
690 * consequently geometrically robust.
692 * Returns: a positive value if @p1, @p2 and @p3 appear in
693 * counterclockwise order, a negative value if they appear in
694 * clockwise order and zero if they are colinear.
696 gdouble
gts_point_orientation (GtsPoint
* p1
, GtsPoint
* p2
, GtsPoint
* p3
)
698 g_return_val_if_fail (p1
!= NULL
&& p2
!= NULL
&& p3
!= NULL
, 0.0);
700 return orient2d ((gdouble
*) &p1
->x
,
705 static gboolean
ray_intersects_triangle (GtsPoint
* D
, GtsPoint
* E
,
708 GtsPoint
* A
, * B
, * C
;
709 gint ABCE
, ABCD
, ADCE
, ABDE
, BCDE
;
711 gts_triangle_vertices (t
, (GtsVertex
**) &A
,
715 ABCE
= gts_point_orientation_3d_sos (A
, B
, C
, E
);
716 ABCD
= gts_point_orientation_3d_sos (A
, B
, C
, D
);
717 if (ABCE
< 0 || ABCD
> 0) {
721 tmpp
= E
; E
= D
; D
= tmpp
;
722 tmp
= ABCE
; ABCE
= ABCD
; ABCD
= tmp
;
724 if (ABCE
< 0 || ABCD
> 0)
726 ADCE
= gts_point_orientation_3d_sos (A
, D
, C
, E
);
729 ABDE
= gts_point_orientation_3d_sos (A
, B
, D
, E
);
732 BCDE
= gts_point_orientation_3d_sos (B
, C
, D
, E
);
739 * gts_point_is_inside_surface:
741 * @tree: a bounding box tree of the faces of a closed, orientable
742 * surface (see gts_bb_tree_surface()).
743 * @is_open: %TRUE if the surface defined by @tree is "open" i.e. its volume
744 * is negative, %FALSE otherwise.
746 * Returns: %TRUE if @p is inside the surface defined by @tree, %FALSE
749 gboolean
gts_point_is_inside_surface (GtsPoint
* p
,
758 g_return_val_if_fail (p
!= NULL
, FALSE
);
759 g_return_val_if_fail (tree
!= NULL
, FALSE
);
762 p1
= gts_point_new (gts_point_class (), bb
->x2
+ fabs (bb
->x2
)/10., p
->y
, p
->z
);
763 i
= list
= gts_bb_tree_stabbed (tree
, p
);
765 GtsTriangle
* t
= GTS_TRIANGLE (GTS_BBOX (i
->data
)->bounded
);
767 if (ray_intersects_triangle (p
, p1
, t
))
772 gts_object_destroy (GTS_OBJECT (p1
));
774 return is_open
? (nc
% 2 == 0) : (nc
% 2 != 0);
777 #define SIGN(x) ((x) > 0. ? 1 : -1)
778 #define ORIENT1D(a,b) ((a) > (b) ? 1 : (a) < (b) ? -1 : 0)
780 static gint
sortp (gpointer
* p
, guint n
)
785 for (i
= 0; i
< n
- 1; i
++)
786 for (j
= 0; j
< n
- 1 - i
; j
++)
787 if (GPOINTER_TO_UINT (p
[j
+1]) < GPOINTER_TO_UINT (p
[j
])) {
798 * gts_point_orientation_3d_sos:
804 * Checks if @p4 lies above or below the plane passing through the
805 * points @p1, @p2 and @p3. Below is defined so that @p1, @p2 and @p3
806 * appear in counterclockwise order when viewed from above the
807 * plane. This function uses adaptive floating point arithmetic and is
808 * consequently geometrically robust.
810 * Simulation of Simplicity (SoS) is used to break ties when the
811 * orientation is degenerate (i.e. @p4 lies on the plane defined by
814 * Returns: +1 if @p4 lies below, -1 if @p4 lies above the plane.
816 gint
gts_point_orientation_3d_sos (GtsPoint
* p1
,
823 g_return_val_if_fail (p1
!= NULL
&& p2
!= NULL
&&
824 p3
!= NULL
&& p4
!= NULL
, 0);
826 o
= orient3d ((gdouble
*) &p1
->x
,
834 gdouble a
[2], b
[2], c
[2];
837 p
[0] = p1
; p
[1] = p2
; p
[2] = p3
; p
[3] = p4
;
838 sign
= sortp ((gpointer
*) p
, 4);
841 a
[0] = p
[1]->x
; a
[1] = p
[1]->y
;
842 b
[0] = p
[2]->x
; b
[1] = p
[2]->y
;
843 c
[0] = p
[3]->x
; c
[1] = p
[3]->y
;
844 o
= orient2d (a
, b
, c
);
846 return SIGN (o
)*sign
;
849 a
[0] = p
[1]->x
; a
[1] = p
[1]->z
;
850 b
[0] = p
[2]->x
; b
[1] = p
[2]->z
;
851 c
[0] = p
[3]->x
; c
[1] = p
[3]->z
;
852 o
= orient2d (a
, b
, c
);
854 return - SIGN (o
)*sign
;
857 a
[0] = p
[1]->y
; a
[1] = p
[1]->z
;
858 b
[0] = p
[2]->y
; b
[1] = p
[2]->z
;
859 c
[0] = p
[3]->y
; c
[1] = p
[3]->z
;
860 o
= orient2d (a
, b
, c
);
862 return SIGN (o
)*sign
;
865 a
[0] = p
[0]->x
; a
[1] = p
[0]->y
;
866 b
[0] = p
[2]->x
; b
[1] = p
[2]->y
;
867 c
[0] = p
[3]->x
; c
[1] = p
[3]->y
;
868 o
= orient2d (a
, b
, c
);
870 return - SIGN (o
)*sign
;
873 o
= ORIENT1D (p
[2]->x
, p
[3]->x
);
875 return SIGN (o
)*sign
;
878 o
= ORIENT1D (p
[2]->y
, p
[3]->y
);
880 return - SIGN (o
)*sign
;
883 a
[0] = p
[0]->x
; a
[1] = p
[0]->z
;
884 b
[0] = p
[2]->x
; b
[1] = p
[2]->z
;
885 c
[0] = p
[3]->x
; c
[1] = p
[3]->z
;
886 o
= orient2d (a
, b
, c
);
888 return SIGN (o
)*sign
;
891 o
= ORIENT1D (p
[2]->z
, p
[3]->z
);
893 return SIGN (o
)*sign
;
896 a
[0] = p
[0]->y
; a
[1] = p
[0]->z
;
897 b
[0] = p
[2]->y
; b
[1] = p
[2]->z
;
898 c
[0] = p
[3]->y
; c
[1] = p
[3]->z
;
899 o
= orient2d (a
, b
, c
);
901 return - SIGN (o
)*sign
;
904 a
[0] = p
[0]->x
; a
[1] = p
[0]->y
;
905 b
[0] = p
[1]->x
; b
[1] = p
[1]->y
;
906 c
[0] = p
[3]->x
; c
[1] = p
[3]->y
;
907 o
= orient2d (a
, b
, c
);
909 return SIGN (o
)*sign
;
912 o
= ORIENT1D (p
[1]->x
, p
[3]->x
);
914 return - SIGN (o
)*sign
;
917 o
= ORIENT1D (p
[1]->y
, p
[3]->y
);
919 return SIGN (o
)*sign
;
922 o
= ORIENT1D (p
[0]->x
, p
[3]->x
);
924 return SIGN (o
)*sign
;
932 * gts_point_orientation_sos:
937 * Checks for orientation of the projection of three points on the
940 * Simulation of Simplicity (SoS) is used to break ties when the
941 * orientation is degenerate (i.e. @p3 lies on the line defined by
944 * Returns: a positive value if @p1, @p2 and @p3 appear in
945 * counterclockwise order or a negative value if they appear in
948 gint
gts_point_orientation_sos (GtsPoint
* p1
,
954 g_return_val_if_fail (p1
!= NULL
&& p2
!= NULL
&& p3
!= NULL
, 0);
956 o
= orient2d ((gdouble
*) &p1
->x
,
965 p
[0] = p1
; p
[1] = p2
; p
[2] = p3
;
966 sign
= sortp ((gpointer
*) p
, 3);
969 o
= ORIENT1D (p
[1]->x
, p
[2]->x
);
971 return - SIGN (o
)*sign
;
974 o
= ORIENT1D (p
[1]->y
, p
[2]->y
);
976 return SIGN (o
)*sign
;
979 o
= ORIENT1D (p
[0]->x
, p
[2]->x
);
981 return SIGN (o
)*sign
;