pcb 4.1.1
An interactive printed circuit board layout editor.

point.c

Go to the documentation of this file.
00001 /* GTS - Library for the manipulation of triangulated surfaces
00002  * Copyright (C) 1999 Stéphane Popinet
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #include <math.h>
00021 #include <stdlib.h>
00022 #include "gts.h"
00023 #include "gts-private.h"
00024 #include "predicates.h"
00025 
00026 static void point_read (GtsObject ** o, GtsFile * f)
00027 {
00028   GtsPoint * p = GTS_POINT (*o);
00029 
00030   if (GTS_POINT_CLASS ((*o)->klass)->binary) {
00031     if (gts_file_read (f, &(p->x), sizeof (gdouble), 1) != 1) {
00032       gts_file_error (f, "expecting a binary number (x coordinate)");
00033       return;
00034     }
00035     if (gts_file_read (f, &(p->y), sizeof (gdouble), 1) != 1) {
00036       gts_file_error (f, "expecting a binary number (y coordinate)");
00037       return;
00038     }
00039     if (gts_file_read (f, &(p->z), sizeof (gdouble), 1) != 1) {
00040       gts_file_error (f, "expecting a binary number (z coordinate)");
00041       return;
00042     }
00043   }
00044   else {
00045     if (f->type != GTS_INT && f->type != GTS_FLOAT) {
00046       gts_file_error (f, "expecting a number (x coordinate)");
00047       return;
00048     }
00049     p->x = atof (f->token->str);
00050     
00051     gts_file_next_token (f);
00052     if (f->type != GTS_INT && f->type != GTS_FLOAT) {
00053       gts_file_error (f, "expecting a number (y coordinate)");
00054       return;
00055     }
00056     p->y = atof (f->token->str);
00057     
00058     gts_file_next_token (f);
00059     if (f->type != GTS_INT && f->type != GTS_FLOAT) {
00060       gts_file_error (f, "expecting a number (z coordinate)");
00061       return;
00062     }
00063     p->z = atof (f->token->str);
00064     
00065     gts_file_next_token (f);
00066   }
00067 }
00068 
00069 static void point_write (GtsObject * o, FILE * fptr)
00070 {
00071   GtsPoint * p = GTS_POINT (o);
00072 
00073   if (GTS_POINT_CLASS ((o)->klass)->binary) {
00074     fwrite (&(p->x), sizeof (gdouble), 1, fptr);
00075     fwrite (&(p->y), sizeof (gdouble), 1, fptr);
00076     fwrite (&(p->z), sizeof (gdouble), 1, fptr);
00077   }
00078   else
00079     fprintf (fptr, "%.10g %.10g %.10g", p->x, p->y, p->z);
00080 }
00081 
00082 static void point_class_init (GtsObjectClass * klass)
00083 {
00084   klass->read = point_read;
00085   klass->write = point_write;
00086 }
00087 
00093 GtsPointClass * gts_point_class (void)
00094 {
00095   static GtsPointClass * klass = NULL;
00096 
00097   if (klass == NULL) {
00098     GtsObjectClassInfo point_info = {
00099       "GtsPoint",
00100       sizeof (GtsPoint),
00101       sizeof (GtsPointClass),
00102       (GtsObjectClassInitFunc) point_class_init,
00103       (GtsObjectInitFunc) NULL,
00104       (GtsArgSetFunc) NULL,
00105       (GtsArgGetFunc) NULL
00106     };
00107     klass = gts_object_class_new (gts_object_class (), 
00108                                   &point_info);
00109   }
00110 
00111   return klass;
00112 }
00113 
00123 GtsPoint * gts_point_new (GtsPointClass * klass,
00124                           gdouble x, gdouble y, gdouble z)
00125 {
00126   GtsPoint * p;
00127   
00128   p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass)));
00129   p->x = x;
00130   p->y = y;
00131   p->z = z;
00132 
00133   return p;
00134 }
00135 
00145 void gts_point_set (GtsPoint * p, gdouble x, gdouble y, gdouble z)
00146 {
00147   g_return_if_fail (p != NULL);
00148 
00149   p->x = x;
00150   p->y = y;
00151   p->z = z;
00152 }
00153 
00161 gdouble gts_point_distance (GtsPoint * p1, GtsPoint * p2)
00162 {
00163   g_return_val_if_fail (p1 != NULL && p2 != NULL, 0.0);
00164   
00165   return sqrt ((p1->x - p2->x)*(p1->x - p2->x) + 
00166                (p1->y - p2->y)*(p1->y - p2->y) + 
00167                (p1->z - p2->z)*(p1->z - p2->z));
00168 }
00169 
00177 gdouble gts_point_distance2 (GtsPoint * p1, GtsPoint * p2)
00178 {
00179   g_return_val_if_fail (p1 != NULL && p2 != NULL, 0.0);
00180   
00181   return
00182     (p1->x - p2->x)*(p1->x - p2->x) +
00183     (p1->y - p2->y)*(p1->y - p2->y) + 
00184     (p1->z - p2->z)*(p1->z - p2->z);
00185 }
00186 
00205 gdouble gts_point_orientation_3d (GtsPoint * p1,
00206                                   GtsPoint * p2,
00207                                   GtsPoint * p3,
00208                                   GtsPoint * p4)
00209 {
00210   g_return_val_if_fail (p1 != NULL && p2 != NULL && 
00211                         p3 != NULL && p4 != NULL, 0.0);
00212   return orient3d ((gdouble *) &p1->x, 
00213                    (gdouble *) &p2->x, 
00214                    (gdouble *) &p3->x, 
00215                    (gdouble *) &p4->x);
00216 }
00217 
00230 GtsIntersect gts_point_is_in_triangle (GtsPoint * p, GtsTriangle * t)
00231 {
00232   GtsVertex * v1, * v2, * v3;
00233   gdouble d1, d2, d3;
00234 
00235   g_return_val_if_fail (p != NULL && t != NULL, FALSE);
00236 
00237   gts_triangle_vertices (t, &v1, &v2, &v3);
00238 
00239   d1 = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p);
00240   if (d1 < 0.0)
00241     return GTS_OUT;
00242   d2 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p);
00243   if (d2 < 0.0)
00244     return GTS_OUT;
00245   d3 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p);
00246   if (d3 < 0.0)
00247     return GTS_OUT;
00248   if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0)
00249     return GTS_ON;
00250   return GTS_IN;
00251 }
00252 
00266 gdouble gts_point_in_triangle_circle (GtsPoint * p, GtsTriangle * t)
00267 {
00268   GtsPoint * p1, * p2, * p3;
00269 
00270   g_return_val_if_fail (p != NULL && t != NULL, 0.0);
00271 
00272   gts_triangle_vertices (t, 
00273                          (GtsVertex **) &p1, 
00274                          (GtsVertex **) &p2, 
00275                          (GtsVertex **) &p3);
00276 
00277   return incircle ((gdouble *) &p1->x, 
00278                    (gdouble *) &p2->x, 
00279                    (gdouble *) &p3->x, 
00280                    (gdouble *) &p->x);
00281 }
00282 
00297 gdouble gts_point_in_circle (GtsPoint * p, 
00298                              GtsPoint * p1, GtsPoint * p2, GtsPoint * p3)
00299 {
00300   g_return_val_if_fail (p != NULL && p1 != NULL && p2 != NULL && p3 != NULL, 
00301                         0.0);
00302 
00303   return incircle ((gdouble *) &p1->x, 
00304                    (gdouble *) &p2->x, 
00305                    (gdouble *) &p3->x, 
00306                    (gdouble *) &p->x);
00307 }
00308 
00324 gdouble gts_point_in_sphere (GtsPoint * p, 
00325                              GtsPoint * p1, GtsPoint * p2, GtsPoint * p3, GtsPoint * p4)
00326 {
00327   g_return_val_if_fail (p != NULL && p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL, 
00328                         0.0);
00329 
00330   return insphere ((gdouble *) &p1->x, 
00331                    (gdouble *) &p2->x, 
00332                    (gdouble *) &p3->x, 
00333                    (gdouble *) &p4->x, 
00334                    (gdouble *) &p->x);
00335 }
00336 
00344 gdouble gts_point_segment_distance2 (GtsPoint * p, GtsSegment * s)
00345 {
00346   gdouble t, ns2, x, y, z;
00347   GtsPoint * p1, * p2;
00348 
00349   g_return_val_if_fail (p != NULL, 0.0);
00350   g_return_val_if_fail (s != NULL, 0.0);
00351 
00352   p1 = GTS_POINT (s->v1);
00353   p2 = GTS_POINT (s->v2);
00354   ns2 = gts_point_distance2 (p1, p2);
00355   if (ns2 == 0.0)
00356     return gts_point_distance2 (p, p1);
00357   t = ((p2->x - p1->x)*(p->x - p1->x) + 
00358        (p2->y - p1->y)*(p->y - p1->y) +
00359        (p2->z - p1->z)*(p->z - p1->z))/ns2;
00360   if (t > 1.0)
00361     return gts_point_distance2 (p, p2);
00362   if (t < 0.0)
00363     return gts_point_distance2 (p, p1);
00364   x = (1. - t)*p1->x + t*p2->x - p->x;
00365   y = (1. - t)*p1->y + t*p2->y - p->y;
00366   z = (1. - t)*p1->z + t*p2->z - p->z;
00367   return x*x + y*y + z*z;
00368 }
00369 
00377 gdouble gts_point_segment_distance (GtsPoint * p, GtsSegment * s)
00378 {
00379   g_return_val_if_fail (p != NULL, 0.0);
00380   g_return_val_if_fail (s != NULL, 0.0);
00381 
00382   return sqrt (gts_point_segment_distance2 (p, s));
00383 }
00384 
00394 void gts_point_segment_closest (GtsPoint * p, 
00395                                 GtsSegment * s,
00396                                 GtsPoint * closest)
00397 {
00398   gdouble t, ns2;
00399   GtsPoint * p1, * p2;
00400 
00401   g_return_if_fail (p != NULL);
00402   g_return_if_fail (s != NULL);
00403   g_return_if_fail (closest != NULL);
00404 
00405   p1 = GTS_POINT (s->v1);
00406   p2 = GTS_POINT (s->v2);
00407   ns2 = gts_point_distance2 (p1, p2);
00408 
00409   if (ns2 == 0.0) {
00410     gts_point_set (closest, p1->x, p1->y, p1->z);
00411     return;
00412   }
00413 
00414   t = ((p2->x - p1->x)*(p->x - p1->x) + 
00415        (p2->y - p1->y)*(p->y - p1->y) +
00416        (p2->z - p1->z)*(p->z - p1->z))/ns2;
00417 
00418   if (t > 1.0)
00419     gts_point_set (closest, p2->x, p2->y, p2->z);
00420   else if (t < 0.0)
00421     gts_point_set (closest, p1->x, p1->y, p1->z);
00422   else
00423     gts_point_set (closest,
00424                    (1. - t)*p1->x + t*p2->x,
00425                    (1. - t)*p1->y + t*p2->y,
00426                    (1. - t)*p1->z + t*p2->z);
00427 }
00428 
00436 gdouble gts_point_triangle_distance2 (GtsPoint * p, GtsTriangle * t)
00437 {
00438   GtsPoint * p1, * p2, * p3;
00439   GtsEdge * e1, * e2, * e3;
00440   GtsVector p1p2, p1p3, pp1;
00441   gdouble A, B, C, D, E, det;
00442   gdouble t1, t2;
00443   gdouble x, y, z;
00444 
00445   g_return_val_if_fail (p != NULL, 0.0);
00446   g_return_val_if_fail (t != NULL, 0.0);
00447 
00448   gts_triangle_vertices_edges (t, NULL, 
00449                                (GtsVertex **) &p1, 
00450                                (GtsVertex **) &p2, 
00451                                (GtsVertex **) &p3, 
00452                                &e1, &e2, &e3);
00453 
00454   gts_vector_init (p1p2, p1, p2);
00455   gts_vector_init (p1p3, p1, p3);
00456   gts_vector_init (pp1, p, p1);
00457 
00458   B = gts_vector_scalar (p1p3, p1p2);
00459   E = gts_vector_scalar (p1p2, p1p2);
00460   C = gts_vector_scalar (p1p3, p1p3);
00461   
00462   det = B*B - E*C;
00463   if (det == 0.) { /* p1p2 and p1p3 are colinear */
00464     gdouble d1 = gts_point_segment_distance2 (p, GTS_SEGMENT (e1));
00465     gdouble d2 = gts_point_segment_distance2 (p, GTS_SEGMENT (e3));
00466     if (d1 < d2)
00467       return d1;
00468     return d2;
00469   }
00470 
00471   A = gts_vector_scalar (p1p3, pp1);
00472   D = gts_vector_scalar (p1p2, pp1);
00473   
00474   t1 = (D*C - A*B)/det;
00475   t2 = (A*E - D*B)/det;
00476 
00477   if (t1 < 0.)
00478     return gts_point_segment_distance2 (p, GTS_SEGMENT (e3));
00479   if (t2 < 0.)
00480     return gts_point_segment_distance2 (p, GTS_SEGMENT (e1));
00481   if (t1 + t2 > 1.)
00482     return gts_point_segment_distance2 (p, GTS_SEGMENT (e2));
00483 
00484   x = pp1[0] + t1*p1p2[0] + t2*p1p3[0];
00485   y = pp1[1] + t1*p1p2[1] + t2*p1p3[1];
00486   z = pp1[2] + t1*p1p2[2] + t2*p1p3[2];
00487 
00488   return x*x + y*y + z*z;
00489 }
00490 
00498 gdouble gts_point_triangle_distance (GtsPoint * p, GtsTriangle * t)
00499 {
00500   g_return_val_if_fail (p != NULL, 0.0);
00501   g_return_val_if_fail (t != NULL, 0.0);
00502 
00503   return sqrt (gts_point_triangle_distance2 (p, t));
00504 }
00505 
00515 void gts_point_triangle_closest (GtsPoint * p, 
00516                                  GtsTriangle * t, 
00517                                  GtsPoint * closest)
00518 {
00519   GtsPoint * p1, * p2, * p3;
00520   GtsEdge * e1, * e2, * e3;
00521   GtsVector p1p2, p1p3, pp1;
00522   gdouble A, B, C, D, E, det;
00523   gdouble t1, t2;
00524 
00525   g_return_if_fail (p != NULL);
00526   g_return_if_fail (t != NULL);
00527   g_return_if_fail (closest != NULL);
00528 
00529   gts_triangle_vertices_edges (t, NULL, 
00530                                (GtsVertex **) &p1, 
00531                                (GtsVertex **) &p2, 
00532                                (GtsVertex **) &p3, 
00533                                &e1, &e2, &e3);
00534 
00535   gts_vector_init (p1p2, p1, p2);
00536   gts_vector_init (p1p3, p1, p3);
00537   gts_vector_init (pp1, p, p1);
00538 
00539   B = gts_vector_scalar (p1p3, p1p2);
00540   E = gts_vector_scalar (p1p2, p1p2);
00541   C = gts_vector_scalar (p1p3, p1p3);
00542   
00543   det = B*B - E*C;
00544   if (det == 0.) { /* p1p2 and p1p3 are colinear */
00545     GtsPoint * cp = 
00546       GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ())));
00547     gts_point_segment_closest (p, GTS_SEGMENT (e1), cp);
00548     gts_point_segment_closest (p, GTS_SEGMENT (e3), closest);
00549 
00550     if (gts_point_distance2 (cp, p) < gts_point_distance2 (closest, p))
00551       gts_point_set (closest, cp->x, cp->y, cp->z);
00552     gts_object_destroy (GTS_OBJECT (cp));
00553     return;
00554   }
00555 
00556   A = gts_vector_scalar (p1p3, pp1);
00557   D = gts_vector_scalar (p1p2, pp1);
00558   
00559   t1 = (D*C - A*B)/det;
00560   t2 = (A*E - D*B)/det;
00561 
00562   if (t1 < 0.)
00563     gts_point_segment_closest (p, GTS_SEGMENT (e3), closest);
00564   else if (t2 < 0.)
00565     gts_point_segment_closest (p, GTS_SEGMENT (e1), closest);
00566   else if (t1 + t2 > 1.)
00567     gts_point_segment_closest (p, GTS_SEGMENT (e2), closest);
00568   else
00569     gts_point_set (closest, 
00570                    p1->x + t1*p1p2[0] + t2*p1p3[0],
00571                    p1->y + t1*p1p2[1] + t2*p1p3[1],
00572                    p1->z + t1*p1p2[2] + t2*p1p3[2]);
00573 }
00574 
00597 GtsPoint * gts_segment_triangle_intersection (GtsSegment * s,
00598                                               GtsTriangle * t,
00599                                               gboolean boundary,
00600                                               GtsPointClass * klass)
00601 {
00602   GtsPoint * A, * B, * C, * D, * E, * I;
00603   gdouble ABCE, ABCD, ADCE, ABDE, BCDE;
00604   gdouble c;
00605 
00606   g_return_val_if_fail (s != NULL, NULL);
00607   g_return_val_if_fail (t != NULL, NULL);
00608   g_return_val_if_fail (klass != NULL, NULL);
00609 
00610   A = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
00611   B = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
00612   C = GTS_POINT (gts_triangle_vertex (t));
00613   D = GTS_POINT (s->v1); 
00614   E = GTS_POINT (s->v2);
00615 
00616   ABCE = gts_point_orientation_3d (A, B, C, E);
00617   ABCD = gts_point_orientation_3d (A, B, C, D);
00618   if (ABCE < 0.0 || ABCD > 0.0) {
00619     GtsPoint * tmpp;
00620     gdouble tmp;
00621     tmpp = E; E = D; D = tmpp;
00622     tmp = ABCE; ABCE = ABCD; ABCD = tmp;
00623   }
00624   if (ABCE < 0.0 || ABCD > 0.0)
00625     return NULL;
00626   ADCE = gts_point_orientation_3d (A, D, C, E);
00627   if ((boundary && ADCE < 0.) || (!boundary && ADCE <= 0.))
00628     return NULL;
00629   ABDE = gts_point_orientation_3d (A, B, D, E);
00630   if ((boundary && ABDE < 0.) || (!boundary && ABDE <= 0.))
00631     return NULL;
00632   BCDE = gts_point_orientation_3d (B, C, D, E);
00633   if ((boundary && BCDE < 0.) || (!boundary && BCDE <= 0.))
00634     return NULL;
00635   if (ABCE == 0.0) {
00636     if (ABCD == 0.0)
00637       /* s is contained in the plane defined by t*/
00638       return NULL;
00639     return E;
00640   }
00641   if (ABCD == 0.0)
00642     return D;
00643   if (boundary) { /* corners of @t */
00644     if (ABDE == 0.) {
00645       if (ADCE == 0.)
00646         return A;
00647       if (BCDE == 0.)
00648         return B;
00649     }
00650     else if (BCDE == 0. && ADCE == 0.)
00651       return C;
00652   }
00653   c = ABCE/(ABCE - ABCD);
00654   I = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass)));
00655   gts_point_set (I,
00656                  E->x + c*(D->x - E->x),
00657                  E->y + c*(D->y - E->y),
00658                  E->z + c*(D->z - E->z));
00659   return I;
00660 }
00661 
00670 void gts_point_transform (GtsPoint * p, GtsMatrix * m)
00671 {
00672   gdouble x, y, z;
00673   g_return_if_fail (p != NULL && m != NULL);
00674   x = m[0][0]*p->x + m[0][1]*p->y + m[0][2]*p->z + m[0][3];
00675   y = m[1][0]*p->x + m[1][1]*p->y + m[1][2]*p->z + m[1][3];
00676   z = m[2][0]*p->x + m[2][1]*p->y + m[2][2]*p->z + m[2][3];
00677   p->x = x; p->y = y; p->z = z;
00678 }
00679 
00696 gdouble gts_point_orientation (GtsPoint * p1, GtsPoint * p2, GtsPoint * p3)
00697 {
00698   g_return_val_if_fail (p1 != NULL && p2 != NULL && p3 != NULL, 0.0);
00699 
00700   return orient2d ((gdouble *) &p1->x, 
00701                    (gdouble *) &p2->x, 
00702                    (gdouble *) &p3->x);
00703 }
00704 
00705 static gboolean ray_intersects_triangle (GtsPoint * D, GtsPoint * E,
00706                                          GtsTriangle * t)
00707 {
00708   GtsPoint * A, * B, * C;
00709   gint ABCE, ABCD, ADCE, ABDE, BCDE;
00710 
00711   gts_triangle_vertices (t, (GtsVertex **) &A, 
00712                          (GtsVertex **) &B, 
00713                          (GtsVertex **) &C);
00714 
00715   ABCE = gts_point_orientation_3d_sos (A, B, C, E);
00716   ABCD = gts_point_orientation_3d_sos (A, B, C, D);
00717   if (ABCE < 0 || ABCD > 0) {
00718     GtsPoint * tmpp;
00719     gint tmp;
00720 
00721     tmpp = E; E = D; D = tmpp;
00722     tmp = ABCE; ABCE = ABCD; ABCD = tmp;
00723   }
00724   if (ABCE < 0 || ABCD > 0)
00725     return FALSE;
00726   ADCE = gts_point_orientation_3d_sos (A, D, C, E);
00727   if (ADCE < 0)
00728     return FALSE;
00729   ABDE = gts_point_orientation_3d_sos (A, B, D, E);
00730   if (ABDE < 0)
00731     return FALSE;
00732   BCDE = gts_point_orientation_3d_sos (B, C, D, E);
00733   if (BCDE < 0)
00734     return FALSE;
00735   return TRUE;
00736 }
00737 
00749 gboolean gts_point_is_inside_surface (GtsPoint * p, 
00750                                       GNode * tree,
00751                                       gboolean is_open)
00752 {
00753   GSList * list, * i;
00754   guint nc = 0;
00755   GtsPoint * p1;
00756   GtsBBox * bb;
00757 
00758   g_return_val_if_fail (p != NULL, FALSE);
00759   g_return_val_if_fail (tree != NULL, FALSE);
00760 
00761   bb = tree->data;
00762   p1 = gts_point_new (gts_point_class (), bb->x2 + fabs (bb->x2)/10., p->y, p->z);
00763   i = list = gts_bb_tree_stabbed (tree, p);
00764   while (i) {
00765     GtsTriangle * t = GTS_TRIANGLE (GTS_BBOX (i->data)->bounded);
00766 
00767     if (ray_intersects_triangle (p, p1, t))
00768       nc++;
00769     i = i->next;
00770   }
00771   g_slist_free (list);
00772   gts_object_destroy (GTS_OBJECT (p1));
00773 
00774   return is_open ? (nc % 2 == 0) : (nc % 2 != 0);
00775 }
00776 
00777 #define SIGN(x) ((x) > 0. ? 1 : -1)
00778 #define ORIENT1D(a,b) ((a) > (b) ? 1 : (a) < (b) ? -1 : 0)
00779 
00780 static gint sortp (gpointer * p, guint n)
00781 {
00782   gint sign = 1;
00783   guint i, j;
00784 
00785   for (i = 0; i < n - 1; i++)
00786     for (j = 0; j < n - 1 - i; j++)
00787       if (GPOINTER_TO_UINT (p[j+1]) < GPOINTER_TO_UINT (p[j])) {
00788         gpointer tmp = p[j];
00789 
00790         p[j] = p[j+1];
00791         p[j+1] = tmp;
00792         sign = - sign;
00793       }
00794   return sign;
00795 }
00796 
00816 gint gts_point_orientation_3d_sos (GtsPoint * p1,
00817                                    GtsPoint * p2,
00818                                    GtsPoint * p3,
00819                                    GtsPoint * p4)
00820 {
00821   gdouble o;
00822 
00823   g_return_val_if_fail (p1 != NULL && p2 != NULL && 
00824                         p3 != NULL && p4 != NULL, 0);
00825 
00826   o = orient3d ((gdouble *) &p1->x, 
00827                 (gdouble *) &p2->x, 
00828                 (gdouble *) &p3->x, 
00829                 (gdouble *) &p4->x);
00830   if (o != 0.)
00831     return SIGN (o);
00832   else {
00833     GtsPoint * p[4];
00834     gdouble a[2], b[2], c[2];
00835     gint sign;
00836 
00837     p[0] = p1; p[1] = p2; p[2] = p3; p[3] = p4;
00838     sign = sortp ((gpointer *) p, 4);
00839     
00840     /* epsilon^1/8 */
00841     a[0] = p[1]->x; a[1] = p[1]->y;
00842     b[0] = p[2]->x; b[1] = p[2]->y;
00843     c[0] = p[3]->x; c[1] = p[3]->y;
00844     o = orient2d (a, b, c);
00845     if (o != 0.)
00846       return SIGN (o)*sign;
00847     
00848     /* epsilon^1/4 */
00849     a[0] = p[1]->x; a[1] = p[1]->z;
00850     b[0] = p[2]->x; b[1] = p[2]->z;
00851     c[0] = p[3]->x; c[1] = p[3]->z;
00852     o = orient2d (a, b, c);
00853     if (o != 0.)
00854       return - SIGN (o)*sign;
00855     
00856     /* epsilon^1/2 */
00857     a[0] = p[1]->y; a[1] = p[1]->z;
00858     b[0] = p[2]->y; b[1] = p[2]->z;
00859     c[0] = p[3]->y; c[1] = p[3]->z;
00860     o = orient2d (a, b, c);
00861     if (o != 0.)
00862       return SIGN (o)*sign;
00863     
00864     /* epsilon */
00865     a[0] = p[0]->x; a[1] = p[0]->y;
00866     b[0] = p[2]->x; b[1] = p[2]->y;
00867     c[0] = p[3]->x; c[1] = p[3]->y;
00868     o = orient2d (a, b, c);
00869     if (o != 0.)
00870       return - SIGN (o)*sign;
00871     
00872     /* epsilon^5/4 */
00873     o = ORIENT1D (p[2]->x, p[3]->x);
00874     if (o != 0.)
00875       return SIGN (o)*sign;
00876     
00877     /* epsilon^3/2 */
00878     o = ORIENT1D (p[2]->y, p[3]->y);
00879     if (o != 0.)
00880       return - SIGN (o)*sign;
00881     
00882     /* epsilon^2 */
00883     a[0] = p[0]->x; a[1] = p[0]->z;
00884     b[0] = p[2]->x; b[1] = p[2]->z;
00885     c[0] = p[3]->x; c[1] = p[3]->z;
00886     o = orient2d (a, b, c);
00887     if (o != 0.)
00888       return SIGN (o)*sign;
00889 
00890     /* epsilon^5/2 */
00891     o = ORIENT1D (p[2]->z, p[3]->z);
00892     if (o != 0.)
00893       return SIGN (o)*sign;
00894     
00895     /* epsilon^4 */
00896     a[0] = p[0]->y; a[1] = p[0]->z;
00897     b[0] = p[2]->y; b[1] = p[2]->z;
00898     c[0] = p[3]->y; c[1] = p[3]->z;
00899     o = orient2d (a, b, c);
00900     if (o != 0.)
00901       return - SIGN (o)*sign;
00902 
00903     /* epsilon^8 */
00904     a[0] = p[0]->x; a[1] = p[0]->y;
00905     b[0] = p[1]->x; b[1] = p[1]->y;
00906     c[0] = p[3]->x; c[1] = p[3]->y;
00907     o = orient2d (a, b, c);
00908     if (o != 0.)
00909       return SIGN (o)*sign;
00910 
00911     /* epsilon^33/4 */
00912     o = ORIENT1D (p[1]->x, p[3]->x);
00913     if (o != 0.)
00914       return - SIGN (o)*sign;
00915     
00916     /* epsilon^17/2 */
00917     o = ORIENT1D (p[1]->y, p[3]->y);
00918     if (o != 0.)
00919       return SIGN (o)*sign;
00920     
00921     /* epsilon^10 */
00922     o = ORIENT1D (p[0]->x, p[3]->x);
00923     if (o != 0.)
00924       return SIGN (o)*sign;
00925     
00926     /* epsilon^21/2 */
00927     return sign;
00928   }
00929 }
00930 
00948 gint gts_point_orientation_sos (GtsPoint * p1,
00949                                 GtsPoint * p2,
00950                                 GtsPoint * p3)
00951 {
00952   gdouble o;
00953 
00954   g_return_val_if_fail (p1 != NULL && p2 != NULL && p3 != NULL, 0);
00955 
00956   o = orient2d ((gdouble *) &p1->x, 
00957                 (gdouble *) &p2->x, 
00958                 (gdouble *) &p3->x);
00959   if (o != 0.)
00960     return SIGN (o);
00961   else {
00962     GtsPoint * p[3];
00963     gint sign;
00964 
00965     p[0] = p1; p[1] = p2; p[2] = p3;
00966     sign = sortp ((gpointer *) p, 3);
00967     
00968     /* epsilon^1/4 */
00969     o = ORIENT1D (p[1]->x, p[2]->x);
00970     if (o != 0.)
00971       return - SIGN (o)*sign;
00972     
00973     /* epsilon^1/2 */
00974     o = ORIENT1D (p[1]->y, p[2]->y);
00975     if (o != 0.)
00976       return SIGN (o)*sign;
00977     
00978     /* epsilon */
00979     o = ORIENT1D (p[0]->x, p[2]->x);
00980     if (o != 0.)
00981       return SIGN (o)*sign;
00982     
00983     /* epsilon^3/2 */
00984     return sign;
00985   }
00986 }