pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 }