pcb 4.1.1
An interactive printed circuit board layout editor.

triangle.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 "gts.h"
00022 
00023 static void triangle_destroy (GtsObject * object)
00024 {
00025   GtsTriangle * triangle = GTS_TRIANGLE (object);
00026   GtsEdge * e1 = triangle->e1;
00027   GtsEdge * e2 = triangle->e2;
00028   GtsEdge * e3 = triangle->e3;
00029 
00030   e1->triangles = g_slist_remove (e1->triangles, triangle);
00031   if (!GTS_OBJECT_DESTROYED (e1) &&
00032       !gts_allow_floating_edges && e1->triangles == NULL)
00033     gts_object_destroy (GTS_OBJECT (e1));
00034   
00035   e2->triangles = g_slist_remove (e2->triangles, triangle);
00036   if (!GTS_OBJECT_DESTROYED (e2) &&
00037       !gts_allow_floating_edges && e2->triangles == NULL)
00038     gts_object_destroy (GTS_OBJECT (e2));
00039   
00040   e3->triangles = g_slist_remove (e3->triangles, triangle);
00041   if (!GTS_OBJECT_DESTROYED (e3) &&
00042       !gts_allow_floating_edges && e3->triangles == NULL)
00043     gts_object_destroy (GTS_OBJECT (e3));
00044 
00045   (* GTS_OBJECT_CLASS (gts_triangle_class ())->parent_class->destroy) (object);
00046 }
00047 
00048 static void triangle_class_init (GtsObjectClass * klass)
00049 {
00050   klass->destroy = triangle_destroy;
00051 }
00052 
00053 static void triangle_init (GtsTriangle * triangle)
00054 {
00055   triangle->e1 = triangle->e2 = triangle->e3 = NULL;
00056 }
00057 
00063 GtsTriangleClass * gts_triangle_class (void)
00064 {
00065   static GtsTriangleClass * klass = NULL;
00066 
00067   if (klass == NULL) {
00068     GtsObjectClassInfo triangle_info = {
00069       "GtsTriangle",
00070       sizeof (GtsTriangle),
00071       sizeof (GtsTriangleClass),
00072       (GtsObjectClassInitFunc) triangle_class_init,
00073       (GtsObjectInitFunc) triangle_init,
00074       (GtsArgSetFunc) NULL,
00075       (GtsArgGetFunc) NULL
00076     };
00077     klass = gts_object_class_new (gts_object_class (), 
00078                                   &triangle_info);
00079   }
00080 
00081   return klass;
00082 }
00083 
00094 void gts_triangle_set (GtsTriangle * triangle, 
00095                        GtsEdge * e1, 
00096                        GtsEdge * e2,
00097                        GtsEdge * e3)
00098 {
00099   g_return_if_fail (e1 != NULL);
00100   g_return_if_fail (e2 != NULL);
00101   g_return_if_fail (e3 != NULL);
00102   g_return_if_fail (e1 != e2 && e1 != e3 && e2 != e3);
00103 
00104   triangle->e1 = e1;
00105   triangle->e2 = e2;
00106   triangle->e3 = e3;
00107 
00108   if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1)
00109     g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), 
00110                                            GTS_SEGMENT (e1)->v2, 
00111                                            GTS_SEGMENT (e2)->v2));
00112   else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1)
00113     g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), 
00114                                            GTS_SEGMENT (e1)->v1, 
00115                                            GTS_SEGMENT (e2)->v2));
00116   else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2)
00117     g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), 
00118                                            GTS_SEGMENT (e1)->v1, 
00119                                            GTS_SEGMENT (e2)->v1));
00120   else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2)
00121     g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), 
00122                                            GTS_SEGMENT (e1)->v2, 
00123                                            GTS_SEGMENT (e2)->v1));
00124   else
00125     g_assert_not_reached ();
00126 
00127   e1->triangles = g_slist_prepend (e1->triangles, triangle);
00128   e2->triangles = g_slist_prepend (e2->triangles, triangle);
00129   e3->triangles = g_slist_prepend (e3->triangles, triangle);
00130 }
00131 
00141 GtsTriangle * gts_triangle_new (GtsTriangleClass * klass,
00142                                 GtsEdge * e1,
00143                                 GtsEdge * e2,
00144                                 GtsEdge * e3)
00145 {
00146   GtsTriangle * t;
00147 
00148   t = GTS_TRIANGLE (gts_object_new (GTS_OBJECT_CLASS (klass)));
00149   gts_triangle_set (t, e1, e2, e3);
00150   
00151   return t;
00152 }
00153 
00163 GtsVertex * gts_triangle_vertex_opposite (GtsTriangle * t, GtsEdge * e)
00164 {
00165   g_return_val_if_fail (t != NULL, NULL);
00166   g_return_val_if_fail (e != NULL, NULL);
00167 
00168   if (t->e1 == e) {
00169     GtsVertex * v = GTS_SEGMENT (t->e2)->v1;
00170     if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2)
00171       return v;
00172     return GTS_SEGMENT (t->e2)->v2;
00173   }
00174   if (t->e2 == e) {
00175     GtsVertex * v = GTS_SEGMENT (t->e1)->v1;
00176     if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2)
00177       return v;
00178     return GTS_SEGMENT (t->e1)->v2;
00179   }
00180   if (t->e3 == e) {
00181     GtsVertex * v = GTS_SEGMENT (t->e2)->v1;
00182     if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2)
00183       return v;
00184     return GTS_SEGMENT (t->e2)->v2;
00185   }
00186   g_assert_not_reached ();
00187   return NULL;
00188 }
00189 
00197 GtsEdge * gts_triangle_edge_opposite (GtsTriangle * t, GtsVertex * v)
00198 {
00199   GtsSegment * s1, * s2, * s3;
00200 
00201   g_return_val_if_fail (t != NULL, NULL);
00202   g_return_val_if_fail (v != NULL, NULL);
00203 
00204   s1 = GTS_SEGMENT (t->e1);
00205   s2 = GTS_SEGMENT (t->e2);
00206 
00207   if (s1->v1 != v && s1->v2 != v) {
00208     if (s2->v1 != v && s2->v2 != v)
00209       return NULL;
00210     return t->e1;
00211   }
00212   if (s2->v1 != v && s2->v2 != v)
00213     return t->e2;
00214   s3 = GTS_SEGMENT (t->e3);
00215   g_assert (s3->v1 != v && s3->v2 != v);
00216   return t->e3;
00217 }
00218 
00226 gdouble gts_triangles_angle (GtsTriangle * t1,
00227                              GtsTriangle * t2)
00228 {
00229   gdouble nx1, ny1, nz1, nx2, ny2, nz2;
00230   gdouble pvx, pvy, pvz;
00231   gdouble theta;
00232 
00233   g_return_val_if_fail (t1 != NULL && t2 != NULL, 0.0);
00234 
00235   gts_triangle_normal (t1, &nx1, &ny1, &nz1);
00236   gts_triangle_normal (t2, &nx2, &ny2, &nz2);
00237 
00238   pvx = ny1*nz2 - nz1*ny2;
00239   pvy = nz1*nx2 - nx1*nz2;
00240   pvz = nx1*ny2 - ny1*nx2;
00241 
00242   theta = atan2 (sqrt (pvx*pvx + pvy*pvy + pvz*pvz), 
00243                  nx1*nx2 + ny1*ny2 + nz1*nz2) - M_PI;
00244   return theta < - M_PI ? theta + 2.*M_PI : theta;
00245 }
00246 
00259 gboolean gts_triangles_are_compatible (GtsTriangle * t1, 
00260                                        GtsTriangle * t2,
00261                                        GtsEdge * e)
00262 {
00263   GtsEdge * e1 = NULL, * e2 = NULL;
00264 
00265   g_return_val_if_fail (t1 != NULL, FALSE);
00266   g_return_val_if_fail (t2 != NULL, FALSE);
00267   g_return_val_if_fail (e != NULL, FALSE);
00268 
00269   if (t1->e1 == e) e1 = t1->e2;
00270   else if (t1->e2 == e) e1 = t1->e3;
00271   else if (t1->e3 == e) e1 = t1->e1;
00272   else
00273     g_assert_not_reached ();
00274   if (t2->e1 == e) e2 = t2->e2;
00275   else if (t2->e2 == e) e2 = t2->e3;
00276   else if (t2->e3 == e) e2 = t2->e1;
00277   else
00278     g_assert_not_reached ();
00279   if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1 || 
00280       GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2 || 
00281       GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1 || 
00282       GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2)
00283     return FALSE;
00284   return TRUE;
00285 }
00286 
00293 gdouble gts_triangle_area (GtsTriangle * t)
00294 {
00295   gdouble x, y, z;
00296   
00297   g_return_val_if_fail (t != NULL, 0.0);
00298   
00299   gts_triangle_normal (t, &x, &y, &z);
00300   
00301   return sqrt (x*x + y*y + z*z)/2.;
00302 }
00303 
00310 gdouble gts_triangle_perimeter (GtsTriangle * t)
00311 {
00312   GtsVertex * v;
00313 
00314   g_return_val_if_fail (t != NULL, 0.0);
00315 
00316   v = gts_triangle_vertex (t);
00317   return 
00318     gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), 
00319                         GTS_POINT (GTS_SEGMENT (t->e1)->v2)) +
00320     gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), 
00321                         GTS_POINT (v)) +
00322     gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v2), 
00323                         GTS_POINT (v));
00324 }
00325 
00326 /* perimeter of the equilateral triangle of area unity */
00327 #define GOLDEN_PERIMETER 4.5590141139 
00328 
00341 gdouble gts_triangle_quality (GtsTriangle * t)
00342 {
00343   gdouble perimeter;
00344 
00345   g_return_val_if_fail (t != NULL, 0.0);
00346 
00347   perimeter = gts_triangle_perimeter (t);
00348   return perimeter > 0.0 ?
00349     GOLDEN_PERIMETER*sqrt (gts_triangle_area (t))/perimeter :
00350     0.0;
00351 }
00352 
00365 void gts_triangle_normal (GtsTriangle * t, 
00366                           gdouble * x, 
00367                           gdouble * y, 
00368                           gdouble * z)
00369 {
00370   GtsVertex * v1, * v2 = NULL, * v3 = NULL;
00371   GtsPoint * p1, * p2, * p3;
00372   gdouble x1, y1, z1, x2, y2, z2;
00373 
00374   g_return_if_fail (t != NULL);
00375 
00376   v1 = GTS_SEGMENT (t->e1)->v1;
00377   if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) {
00378     v2 = GTS_SEGMENT (t->e2)->v2;
00379     v3 = GTS_SEGMENT (t->e1)->v2;
00380   }
00381   else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) {
00382     v2 = GTS_SEGMENT (t->e1)->v2;
00383     v3 = GTS_SEGMENT (t->e2)->v1;
00384   }
00385   else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) {
00386     v2 = GTS_SEGMENT (t->e2)->v1;
00387     v3 = GTS_SEGMENT (t->e1)->v2;
00388   }
00389   else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) {
00390     v2 = GTS_SEGMENT (t->e1)->v2;
00391     v3 = GTS_SEGMENT (t->e2)->v2;
00392   }
00393   else {
00394     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",
00395          t, t->e1, t->e2, 
00396          t->e3, GTS_SEGMENT (t->e1)->v1, GTS_SEGMENT (t->e1)->v2, 
00397          GTS_SEGMENT (t->e2)->v1, GTS_SEGMENT (t->e2)->v2, 
00398          GTS_SEGMENT (t->e3)->v1, GTS_SEGMENT (t->e3)->v2);
00399     g_assert_not_reached ();
00400   }
00401 
00402   p1 = GTS_POINT (v1);
00403   p2 = GTS_POINT (v2);
00404   p3 = GTS_POINT (v3);
00405 
00406   x1 = p2->x - p1->x;
00407   y1 = p2->y - p1->y;
00408   z1 = p2->z - p1->z;
00409 
00410   x2 = p3->x - p1->x;
00411   y2 = p3->y - p1->y;
00412   z2 = p3->z - p1->z;
00413 
00414   *x = y1*z2 - z1*y2;
00415   *y = z1*x2 - x1*z2;
00416   *z = x1*y2 - y1*x2;
00417 }
00418 
00429 gdouble gts_triangle_orientation (GtsTriangle * t)
00430 {
00431   GtsVertex * v1, * v2 = NULL, * v3 = NULL;
00432 
00433   g_return_val_if_fail (t != NULL, 0.0);
00434 
00435   v1 = GTS_SEGMENT (t->e1)->v1;
00436   if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) {
00437     v2 = GTS_SEGMENT (t->e2)->v2;
00438     v3 = GTS_SEGMENT (t->e1)->v2;
00439   }
00440   else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) {
00441     v2 = GTS_SEGMENT (t->e1)->v2;
00442     v3 = GTS_SEGMENT (t->e2)->v1;
00443   }
00444   else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) {
00445     v2 = GTS_SEGMENT (t->e2)->v1;
00446     v3 = GTS_SEGMENT (t->e1)->v2;
00447   }
00448   else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) {
00449     v2 = GTS_SEGMENT (t->e1)->v2;
00450     v3 = GTS_SEGMENT (t->e2)->v2;
00451   }
00452   else
00453     g_assert_not_reached ();
00454   return gts_point_orientation (GTS_POINT (v1), 
00455                                 GTS_POINT (v2), 
00456                                 GTS_POINT (v3));
00457 }
00458 
00465 void gts_triangle_revert (GtsTriangle * t)
00466 {
00467   GtsEdge * e;
00468 
00469   g_return_if_fail (t != NULL);
00470 
00471   e = t->e1;
00472   t->e1 = t->e2;
00473   t->e2 = e;
00474 }
00475 
00484 GSList * gts_triangles_from_edges (GSList * edges)
00485 {
00486   GHashTable * hash;
00487   GSList * triangles = NULL, * i;
00488 
00489   hash = g_hash_table_new (NULL, NULL);
00490   i = edges;
00491   while (i) {
00492     GSList * j = GTS_EDGE (i->data)->triangles;
00493     while (j) {
00494       GtsTriangle * t = j->data;
00495       if (g_hash_table_lookup (hash, t) == NULL) {
00496         triangles = g_slist_prepend (triangles, t);
00497         g_hash_table_insert (hash, t, i);
00498       }
00499       j = j->next;
00500     }
00501     i = i->next;
00502   }
00503   g_hash_table_destroy (hash);
00504 
00505   return triangles;
00506 }
00507 
00525 void gts_triangle_vertices_edges (GtsTriangle * t, 
00526                                   GtsEdge * e,
00527                                   GtsVertex ** v1, 
00528                                   GtsVertex ** v2, 
00529                                   GtsVertex ** v3,
00530                                   GtsEdge ** e1,
00531                                   GtsEdge ** e2,
00532                                   GtsEdge ** e3)
00533 {
00534   GtsEdge * ee1, * ee2;
00535 
00536   g_return_if_fail (t != NULL);
00537   
00538   if (e == t->e1 || e == NULL) {
00539     *e1 = ee1 = t->e1; *e2 = ee2 = t->e2; *e3 = t->e3;    
00540   }
00541   else if (e == t->e2) {
00542     *e1 = ee1 = e; *e2 = ee2 = t->e3; *e3 = t->e1;
00543   }
00544   else if (e == t->e3) {
00545     *e1 = ee1 = e; *e2 = ee2 = t->e1; *e3 = t->e2;
00546   }
00547   else {
00548     g_assert_not_reached ();
00549     ee1 = ee2 = NULL; /* to avoid complaints from the compiler */
00550   }
00551   if (GTS_SEGMENT (ee1)->v2 == GTS_SEGMENT (ee2)->v1) {
00552     *v1 = GTS_SEGMENT (ee1)->v1; 
00553     *v2 = GTS_SEGMENT (ee1)->v2; 
00554     *v3 = GTS_SEGMENT (ee2)->v2;
00555   }
00556   else if (GTS_SEGMENT (ee1)->v2 == GTS_SEGMENT (ee2)->v2) {
00557     *v1 = GTS_SEGMENT (ee1)->v1; 
00558     *v2 = GTS_SEGMENT (ee1)->v2; 
00559     *v3 = GTS_SEGMENT (ee2)->v1;
00560   }
00561   else if (GTS_SEGMENT (ee1)->v1 == GTS_SEGMENT (ee2)->v1) {
00562     *v1 = GTS_SEGMENT (ee1)->v2; 
00563     *v2 = GTS_SEGMENT (ee1)->v1; 
00564     *v3 = GTS_SEGMENT (ee2)->v2;
00565   }
00566   else if (GTS_SEGMENT (ee1)->v1 == GTS_SEGMENT (ee2)->v2) {
00567     *v1 = GTS_SEGMENT (ee1)->v2; 
00568     *v2 = GTS_SEGMENT (ee1)->v1; 
00569     *v3 = GTS_SEGMENT (ee2)->v1;
00570   }
00571   else
00572     g_assert_not_reached ();
00573 }
00574 
00575 /* sqrt(3) */
00576 #define SQRT3 1.73205080757
00577 
00593 GtsTriangle * gts_triangle_enclosing (GtsTriangleClass * klass,
00594                                       GSList * points, gdouble scale)
00595 {
00596   gdouble xmax, xmin, ymax, ymin;
00597   gdouble xo, yo, r;
00598   GtsVertex * v1, * v2, * v3;
00599   GtsEdge * e1, * e2, * e3;
00600 
00601   if (points == NULL)
00602     return NULL;
00603   
00604   xmax = xmin = GTS_POINT (points->data)->x;
00605   ymax = ymin = GTS_POINT (points->data)->y;
00606   points = points->next;
00607   while (points) {
00608     GtsPoint * p = points->data;
00609     if (p->x > xmax) xmax = p->x;
00610     else if (p->x < xmin) xmin = p->x;
00611     if (p->y > ymax) ymax = p->y;
00612     else if (p->y < ymin) ymin = p->y;    
00613     points = points->next;
00614   }
00615   xo = (xmax + xmin)/2.;
00616   yo = (ymax + ymin)/2.;
00617   r = scale*sqrt((xmax - xo)*(xmax - xo) + (ymax - yo)*(ymax - yo));
00618   if (r == 0.0) r = scale;
00619   v1 = gts_vertex_new (gts_vertex_class (),
00620                        xo + r*SQRT3, yo - r, 0.0);
00621   v2 = gts_vertex_new (gts_vertex_class (),
00622                        xo, yo + 2.*r, 0.0);
00623   v3 = gts_vertex_new (gts_vertex_class (),
00624                        xo - r*SQRT3, yo - r, 0.0);
00625   e1 = gts_edge_new (gts_edge_class (), v1, v2);
00626   e2 = gts_edge_new (gts_edge_class (), v2, v3);
00627   e3 = gts_edge_new (gts_edge_class (), v3, v1);
00628   return gts_triangle_new (gts_triangle_class (), e1, e2, e3);
00629 }
00630 
00637 guint gts_triangle_neighbor_number (GtsTriangle * t)
00638 {
00639   GSList * i;
00640   guint nn = 0;
00641   GtsEdge * ee[4], ** e = ee;
00642   
00643   g_return_val_if_fail (t != NULL, 0);
00644 
00645   ee[0] = t->e1; ee[1] = t->e2; ee[2] = t->e3; ee[3] = NULL;
00646   while (*e) {
00647     i = (*e++)->triangles;
00648     while (i) {
00649       GtsTriangle * t1 = i->data;
00650       if (t1 != t)
00651         nn++;
00652       i = i->next;
00653     }
00654   }
00655   return nn;
00656 }
00657 
00664 GSList * gts_triangle_neighbors (GtsTriangle * t)
00665 {
00666   GSList * i, * list = NULL;
00667   GtsEdge * ee[4], ** e = ee;
00668   
00669   g_return_val_if_fail (t != NULL, NULL);
00670 
00671   ee[0] = t->e1; ee[1] = t->e2; ee[2] = t->e3; ee[3] = NULL;
00672   while (*e) {
00673     i = (*e++)->triangles;
00674     while (i) {
00675       GtsTriangle * t1 = i->data;
00676       if (t1 != t)
00677         list = g_slist_prepend (list, t1);
00678       i = i->next;
00679     }
00680   }
00681   return list;
00682 }
00683 
00692 GtsEdge * gts_triangles_common_edge (GtsTriangle * t1,
00693                                      GtsTriangle * t2)
00694 {
00695   g_return_val_if_fail (t1 != NULL, NULL);
00696   g_return_val_if_fail (t2 != NULL, NULL);
00697 
00698   if (t1->e1 == t2->e1 || t1->e1 == t2->e2 || t1->e1 == t2->e3)
00699     return t1->e1;
00700   if (t1->e2 == t2->e1 || t1->e2 == t2->e2 || t1->e2 == t2->e3)
00701     return t1->e2;
00702   if (t1->e3 == t2->e1 || t1->e3 == t2->e2 || t1->e3 == t2->e3)
00703     return t1->e3;
00704   return NULL;
00705 }
00706 
00714 GtsTriangle * gts_triangle_is_duplicate (GtsTriangle * t)
00715 {
00716   GSList * i;
00717   GtsEdge * e2, * e3;
00718 
00719   g_return_val_if_fail (t != NULL, NULL);
00720 
00721   e2 = t->e2;
00722   e3 = t->e3;
00723   i = t->e1->triangles;
00724   while (i) {
00725     GtsTriangle * t1 = i->data;
00726     if (t1 != t && 
00727         (t1->e1 == e2 || t1->e2 == e2 || t1->e3 == e2) &&
00728         (t1->e1 == e3 || t1->e2 == e3 || t1->e3 == e3))
00729       return t1;
00730     i = i->next;
00731   }
00732   
00733   return NULL;
00734 }
00735 
00745 GtsTriangle * gts_triangle_use_edges (GtsEdge * e1,
00746                                       GtsEdge * e2,
00747                                       GtsEdge * e3)
00748 {
00749   GSList * i;
00750   
00751   g_return_val_if_fail (e1 != NULL, NULL);
00752   g_return_val_if_fail (e2 != NULL, NULL);
00753   g_return_val_if_fail (e3 != NULL, NULL);
00754 
00755   i = e1->triangles;
00756   while (i) {
00757     GtsTriangle * t = i->data;
00758     if ((t->e1 == e2 && (t->e2 == e3 || t->e3 == e3)) ||
00759         (t->e2 == e2 && (t->e1 == e3 || t->e3 == e3)) ||
00760         (t->e3 == e2 && (t->e1 == e3 || t->e2 == e3)))
00761       return t;
00762     i = i->next;
00763   }
00764   
00765   return NULL;
00766 }
00767 
00775 gboolean gts_triangle_is_ok (GtsTriangle * t)
00776 {
00777   g_return_val_if_fail (t != NULL, FALSE);
00778   g_return_val_if_fail (t->e1 != NULL, FALSE);
00779   g_return_val_if_fail (t->e2 != NULL, FALSE);
00780   g_return_val_if_fail (t->e3 != NULL, FALSE);
00781   g_return_val_if_fail (t->e1 != t->e2 && t->e1 != t->e3 && t->e2 != t->e3, 
00782                         FALSE);
00783   g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1), 
00784                                             GTS_SEGMENT (t->e2)),
00785                         FALSE);
00786   g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1), 
00787                                             GTS_SEGMENT (t->e3)), 
00788                         FALSE);
00789   g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e2), 
00790                                             GTS_SEGMENT (t->e3)), 
00791                         FALSE);
00792   g_return_val_if_fail (GTS_SEGMENT (t->e1)->v1 != GTS_SEGMENT (t->e1)->v2, 
00793                         FALSE);
00794   g_return_val_if_fail (GTS_SEGMENT (t->e2)->v1 != GTS_SEGMENT (t->e2)->v2, 
00795                         FALSE);
00796   g_return_val_if_fail (GTS_SEGMENT (t->e3)->v1 != GTS_SEGMENT (t->e3)->v2, 
00797                         FALSE);
00798   g_return_val_if_fail (GTS_OBJECT (t)->reserved == NULL, FALSE);
00799   g_return_val_if_fail (!gts_triangle_is_duplicate (t), FALSE);
00800   return TRUE;
00801 }
00802 
00812 void gts_triangle_vertices (GtsTriangle * t,
00813                             GtsVertex ** v1, GtsVertex ** v2, GtsVertex ** v3)
00814 {
00815   GtsSegment * e1, * e2;
00816 
00817   g_return_if_fail (t != NULL);
00818   g_return_if_fail (v1 != NULL && v2 != NULL && v3 != NULL);
00819 
00820   e1 = GTS_SEGMENT (t->e1);
00821   e2 = GTS_SEGMENT (t->e2);
00822 
00823   if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) {
00824     *v1 = GTS_SEGMENT (e1)->v1; 
00825     *v2 = GTS_SEGMENT (e1)->v2; 
00826     *v3 = GTS_SEGMENT (e2)->v2;
00827   }
00828   else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) {
00829     *v1 = GTS_SEGMENT (e1)->v1; 
00830     *v2 = GTS_SEGMENT (e1)->v2; 
00831     *v3 = GTS_SEGMENT (e2)->v1;
00832   }
00833   else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) {
00834     *v1 = GTS_SEGMENT (e1)->v2; 
00835     *v2 = GTS_SEGMENT (e1)->v1; 
00836     *v3 = GTS_SEGMENT (e2)->v2;
00837   }
00838   else {
00839     *v1 = GTS_SEGMENT (e1)->v2; 
00840     *v2 = GTS_SEGMENT (e1)->v1; 
00841     *v3 = GTS_SEGMENT (e2)->v1;
00842   }
00843 }
00844 
00853 GtsPoint * gts_triangle_circumcircle_center (GtsTriangle * t,
00854                                              GtsPointClass * point_class)
00855 {
00856   GtsVertex * v1, * v2, * v3;
00857   gdouble xa, ya, xb, yb, xc, yc;
00858   gdouble xd, yd, xe, ye;
00859   gdouble xad, yad, xae, yae;
00860   gdouble det;
00861   
00862   g_return_val_if_fail (t != NULL, NULL);
00863   g_return_val_if_fail (point_class != NULL, NULL);
00864 
00865   gts_triangle_vertices (t, &v1, &v2, &v3);
00866 
00867   xa = GTS_POINT (v1)->x; ya = GTS_POINT (v1)->y;
00868   xb = GTS_POINT (v2)->x; yb = GTS_POINT (v2)->y;
00869   xc = GTS_POINT (v3)->x; yc = GTS_POINT (v3)->y;
00870   xd = (xa + xb)/2.; yd = (ya + yb)/2.;
00871   xe = (xa + xc)/2.; ye = (ya + yc)/2.;
00872   xad = xd - xa; yad = yd - ya;
00873   xae = xe - xa; yae = ye - ya;
00874   det = xad*yae - xae*yad;
00875   if (det == 0.)
00876     return NULL;
00877   return gts_point_new (point_class,
00878                         (yae*yad*(yd - ye) + xad*yae*xd - xae*yad*xe)/det,
00879                         -(xae*xad*(xd - xe) + yad*xae*yd - yae*xad*ye)/det,
00880                         0.);
00881 }
00882 
00883 /* square of the maximum area ratio admissible */
00884 #define AREA_RATIO_MAX2 1e8
00885 
00886 static gboolean points_are_folded (GtsPoint * A,
00887                                    GtsPoint * B,
00888                                    GtsPoint * C,
00889                                    GtsPoint * D,
00890                                    gdouble max)
00891 {
00892   GtsVector AB, AC, AD;
00893   GtsVector n1, n2;
00894   gdouble nn1, nn2, n1n2;
00895 
00896   gts_vector_init (AB, A, B);
00897   gts_vector_init (AC, A, C);
00898   gts_vector_init (AD, A, D);
00899   gts_vector_cross (n1, AB, AC);
00900   gts_vector_cross (n2, AD, AB);
00901 
00902   nn1 = gts_vector_scalar (n1, n1);
00903   nn2 = gts_vector_scalar (n2, n2);
00904   if (nn1 >= AREA_RATIO_MAX2*nn2 || nn2 >= AREA_RATIO_MAX2*nn1)
00905     return TRUE;
00906   n1n2 = gts_vector_scalar (n1, n2);
00907   if (n1n2 > 0.)
00908     return FALSE;
00909   if (n1n2*n1n2/(nn1*nn2) > max)
00910     return TRUE;
00911   return FALSE;
00912 }
00913 
00914 static GtsVertex * triangle_use_vertices (GtsTriangle * t,
00915                                           GtsVertex * A, 
00916                                           GtsVertex * B)
00917 {
00918   GtsVertex 
00919     * v1 = GTS_SEGMENT (t->e1)->v1, 
00920     * v2 = GTS_SEGMENT (t->e1)->v2, 
00921     * v3 = gts_triangle_vertex (t);
00922 
00923   if (v1 == A) {
00924     if (v2 == B)
00925       return v3;
00926     g_assert (v3 == B);
00927     return v2;
00928   }
00929   if (v2 == A) {
00930     if (v1 == B)
00931       return v3;
00932     g_assert (v3 == B);
00933     return v1;
00934   }
00935   if (v3 == A) {
00936     if (v1 == B)
00937       return v2;
00938     g_assert (v2 == B);
00939     return v1;
00940   }
00941   g_assert_not_reached ();
00942   return NULL;
00943 }
00944 
00960 gboolean gts_triangles_are_folded (GSList * triangles,
00961                                    GtsVertex * A, GtsVertex * B,
00962                                    gdouble max)
00963 {
00964   GSList * i;
00965 
00966   g_return_val_if_fail (A != NULL, TRUE);
00967   g_return_val_if_fail (B != NULL, TRUE);
00968 
00969   i = triangles;
00970   while (i) {
00971     GtsVertex * C = triangle_use_vertices (i->data, A, B);
00972     GSList * j = i->next;    
00973     while (j) {
00974       GtsVertex * D = triangle_use_vertices (j->data, A, B);
00975       if (points_are_folded (GTS_POINT (A), 
00976                              GTS_POINT (B), 
00977                              GTS_POINT (C), 
00978                              GTS_POINT (D), 
00979                              max))
00980         return TRUE;
00981       j = j->next;
00982     }
00983     i = i->next;
00984   }
00985   return FALSE;
00986 }
00987 
01002 GtsObject * gts_triangle_is_stabbed (GtsTriangle * t, 
01003                                      GtsPoint * p,
01004                                      gdouble * orientation)
01005 {
01006   GtsVertex * v1, * v2, * v3, * inverted = NULL;
01007   GtsEdge * e1, * e2, * e3, * tmp;
01008   gdouble o, o1, o2, o3;
01009 
01010   g_return_val_if_fail (t != NULL, NULL);
01011   g_return_val_if_fail (p != NULL, NULL);
01012 
01013   gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3);
01014   o = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3));
01015   if (o == 0.)
01016     return NULL;
01017   if (o < 0.) {
01018     inverted = v1;
01019     v1 = v2;
01020     v2 = inverted;
01021     tmp = e2;
01022     e2 = e3;
01023     e3 = tmp;
01024   }
01025   o = gts_point_orientation_3d (GTS_POINT (v1),
01026                                 GTS_POINT (v2), 
01027                                 GTS_POINT (v3), 
01028                                 p);
01029   if (o < 0.)
01030     return NULL;
01031   o1 = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p);
01032   if (o1 < 0.)
01033     return NULL;
01034   o2 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p);
01035   if (o2 < 0.)
01036     return NULL;
01037   o3 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p);
01038   if (o3 < 0.)
01039     return NULL;  
01040   if (orientation) *orientation = inverted ? -o : o;
01041   if (o1 == 0.) {
01042     if (o2 == 0.)
01043       return GTS_OBJECT (v2);
01044     if (o3 == 0.)
01045       return GTS_OBJECT (v1);
01046     return GTS_OBJECT (e1);
01047   }
01048   if (o2 == 0.) {
01049     if (o3 == 0.)
01050       return GTS_OBJECT (v3);
01051     return GTS_OBJECT (e2);
01052   }
01053   if (o3 == 0.)
01054     return GTS_OBJECT (e3);
01055   return GTS_OBJECT (t);
01056 }
01057 
01067 void gts_triangle_interpolate_height (GtsTriangle * t, GtsPoint * p)
01068 {
01069   GtsPoint * p1, * p2, * p3;
01070   gdouble x1, x2, y1, y2, det;
01071 
01072   g_return_if_fail (t != NULL);
01073   g_return_if_fail (p != NULL);
01074 
01075   p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1);
01076   p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2);
01077   p3 = GTS_POINT (gts_triangle_vertex (t));
01078 
01079   x1 = p2->x - p1->x;
01080   y1 = p2->y - p1->y;
01081   x2 = p3->x - p1->x;
01082   y2 = p3->y - p1->y;
01083   det = x1*y2 - x2*y1;
01084   if (det == 0.)
01085     p->z = (p1->z + p2->z + p3->z)/3.;
01086   else {
01087     gdouble x = p->x - p1->x;
01088     gdouble y = p->y - p1->y;
01089     gdouble a = (x*y2 - y*x2)/det;
01090     gdouble b = (y*x1 - x*y1)/det;
01091 
01092     p->z = (1. - a - b)*p1->z + a*p2->z + b*p3->z;
01093   }
01094 }