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 "gts.h" 00021 00022 /* #define DEBUG_VOPT */ 00023 00024 /* compute the normal (nx, ny, nz) as the cross-product of the first two 00025 oriented edges and the norm nt = |t| as (v1xv2).v3 */ 00026 static void triangle_normal (GtsTriangle * t, 00027 gdouble * nx, 00028 gdouble * ny, 00029 gdouble * nz, 00030 gdouble * nt) 00031 { 00032 GtsPoint * p1, * p2 = NULL, * p3 = NULL; 00033 gdouble x1, y1, z1, x2, y2, z2; 00034 00035 g_return_if_fail (t != NULL); 00036 00037 p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); 00038 if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) { 00039 p2 = GTS_POINT (GTS_SEGMENT (t->e2)->v2); 00040 p3 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); 00041 } 00042 else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) { 00043 p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); 00044 p3 = GTS_POINT (GTS_SEGMENT (t->e2)->v1); 00045 } 00046 else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) { 00047 p2 = GTS_POINT (GTS_SEGMENT (t->e2)->v1); 00048 p3 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); 00049 } 00050 else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) { 00051 p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); 00052 p3 = GTS_POINT (GTS_SEGMENT (t->e2)->v2); 00053 } 00054 else 00055 g_assert_not_reached (); 00056 00057 x1 = p2->x - p1->x; 00058 y1 = p2->y - p1->y; 00059 z1 = p2->z - p1->z; 00060 00061 x2 = p3->x - p1->x; 00062 y2 = p3->y - p1->y; 00063 z2 = p3->z - p1->z; 00064 00065 *nt = ((p1->y*p2->z - p1->z*p2->y)*p3->x + 00066 (p1->z*p2->x - p1->x*p2->z)*p3->y + 00067 (p1->x*p2->y - p1->y*p2->x)*p3->z); 00068 *nx = y1*z2 - z1*y2; 00069 *ny = z1*x2 - x1*z2; 00070 *nz = x1*y2 - y1*x2; 00071 } 00072 00073 static void boundary_preservation (GtsEdge * edge, 00074 GtsFace * f, 00075 GtsVector e1, GtsVector e2, 00076 GtsMatrix * H, GtsVector c) 00077 { 00078 GtsTriangle * t = GTS_TRIANGLE (f); 00079 GtsEdge * edge2; 00080 GtsVertex * v1 = GTS_SEGMENT (edge)->v1, * v2 = GTS_SEGMENT (edge)->v2; 00081 GtsPoint * p1, * p2; 00082 GtsVector e, e3; 00083 00084 /* find orientation of segment */ 00085 edge2 = edge == t->e1 ? t->e2 : edge == t->e2 ? t->e3 : t->e1; 00086 if (v2 != GTS_SEGMENT (edge2)->v1 && v2 != GTS_SEGMENT (edge2)->v2) { 00087 v2 = v1; v1 = GTS_SEGMENT (edge)->v2; 00088 } 00089 p1 = GTS_POINT (v1); 00090 p2 = GTS_POINT (v2); 00091 00092 e[0] = p2->x - p1->x; 00093 e[1] = p2->y - p1->y; 00094 e[2] = p2->z - p1->z; 00095 00096 e1[0] += e[0]; 00097 e1[1] += e[1]; 00098 e1[2] += e[2]; 00099 00100 e3[0] = p2->y*p1->z - p2->z*p1->y; 00101 e3[1] = p2->z*p1->x - p2->x*p1->z; 00102 e3[2] = p2->x*p1->y - p2->y*p1->x; 00103 00104 e2[0] += e3[0]; 00105 e2[1] += e3[1]; 00106 e2[2] += e3[2]; 00107 00108 H[0][0] += e[1]*e[1] + e[2]*e[2]; 00109 H[0][1] -= e[0]*e[1]; 00110 H[0][2] -= e[0]*e[2]; 00111 H[1][0] = H[0][1]; 00112 H[1][1] += e[0]*e[0] + e[2]*e[2]; 00113 H[1][2] -= e[1]*e[2]; 00114 H[2][0] = H[0][2]; 00115 H[2][1] = H[1][2]; 00116 H[2][2] += e[0]*e[0] + e[1]*e[1]; 00117 00118 c[0] += e[1]*e3[2] - e[2]*e3[1]; 00119 c[1] += e[2]*e3[0] - e[0]*e3[2]; 00120 c[2] += e[0]*e3[1] - e[1]*e3[0]; 00121 } 00122 00123 static gdouble boundary_cost (GtsEdge * edge, 00124 GtsFace * f, 00125 GtsVertex * v) 00126 { 00127 GtsTriangle * t = GTS_TRIANGLE (f); 00128 GtsEdge * edge2; 00129 GtsVertex * v1 = GTS_SEGMENT (edge)->v1, * v2 = GTS_SEGMENT (edge)->v2; 00130 GtsPoint * p1, * p2; 00131 GtsVector e; 00132 GtsPoint * p = GTS_POINT (v); 00133 00134 /* find orientation of segment */ 00135 edge2 = edge == t->e1 ? t->e2 : edge == t->e2 ? t->e3 : t->e1; 00136 if (v2 != GTS_SEGMENT (edge2)->v1 && v2 != GTS_SEGMENT (edge2)->v2) { 00137 v2 = v1; v1 = GTS_SEGMENT (edge)->v2; 00138 } 00139 p1 = GTS_POINT (v1); 00140 p2 = GTS_POINT (v2); 00141 00142 e[0] = (p2->y - p1->y)*(p->z - p2->z) - (p2->z - p1->z)*(p->y - p2->y); 00143 e[1] = (p2->z - p1->z)*(p->x - p2->x) - (p2->x - p1->x)*(p->z - p2->z); 00144 e[2] = (p2->x - p1->x)*(p->y - p2->y) - (p2->y - p1->y)*(p->x - p2->x); 00145 00146 return e[0]*e[0] + e[1]*e[1] + e[2]*e[2]; 00147 } 00148 00149 static gdouble edge_boundary_cost (GtsEdge * e, GtsVertex * v) 00150 { 00151 gdouble cost = 0.; 00152 GSList * i; 00153 00154 i = GTS_SEGMENT (e)->v1->segments; 00155 while (i) { 00156 GtsFace * f; 00157 if (GTS_IS_EDGE (i->data) && 00158 (f = gts_edge_is_boundary (i->data, NULL))) 00159 cost += boundary_cost (i->data, f, v); 00160 i = i->next; 00161 } 00162 i = GTS_SEGMENT (e)->v2->segments; 00163 while (i) { 00164 GtsFace * f; 00165 if (i->data != e && 00166 GTS_IS_EDGE (i->data) && 00167 (f = gts_edge_is_boundary (i->data, NULL))) 00168 cost += boundary_cost (i->data, f, v); 00169 i = i->next; 00170 } 00171 00172 return cost/4.; 00173 } 00174 00175 static gdouble edge_volume_cost (GtsEdge * e, GtsVertex * v) 00176 { 00177 GSList * i, * triangles; 00178 gdouble n1, n2, n3, nt; 00179 gdouble cost = 0.0, a; 00180 00181 triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL); 00182 triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles); 00183 00184 i = triangles; 00185 while (i) { 00186 if (GTS_IS_FACE (i->data)) { 00187 triangle_normal (i->data, &n1, &n2, &n3, &nt); 00188 a = GTS_POINT (v)->x*n1 + 00189 GTS_POINT (v)->y*n2 + 00190 GTS_POINT (v)->z*n3 - nt; 00191 cost += a*a; 00192 } 00193 i = i->next; 00194 } 00195 g_slist_free (triangles); 00196 00197 return cost/36.; 00198 } 00199 00200 static gdouble edge_shape_cost (GtsEdge * e, GtsVertex * v) 00201 { 00202 GSList * list, * i; 00203 GtsVertex 00204 * v1 = GTS_SEGMENT (e)->v1, 00205 * v2 = GTS_SEGMENT (e)->v2; 00206 gdouble cost = 0.; 00207 00208 list = gts_vertex_neighbors (v1, NULL, NULL); 00209 list = gts_vertex_neighbors (v2, list, NULL); 00210 i = list; 00211 while (i) { 00212 GtsPoint * p = i->data; 00213 if (p != GTS_POINT (v1) && p != GTS_POINT (v2)) 00214 cost += gts_point_distance2 (p, GTS_POINT (v)); 00215 i = i->next; 00216 } 00217 g_slist_free (list); 00218 00219 return cost; 00220 } 00221 00236 GtsVertex * gts_volume_optimized_vertex (GtsEdge * edge, 00237 GtsVertexClass * klass, 00238 GtsVolumeOptimizedParams * params) 00239 { 00240 GSList * triangles, * i; 00241 gdouble sn1 = 0., sn2 = 0., sn3 = 0.; 00242 gdouble sn11 = 0., sn22 = 0., sn33 = 0.; 00243 gdouble sn12 = 0., sn13 = 0., sn23 = 0.; 00244 gdouble st = 0., stn1 = 0., stn2 = 0., stn3 = 0.; 00245 gdouble n1, n2, n3, nt; 00246 GtsMatrix * A, * Ai; 00247 GtsVector A1, b; 00248 GtsVector e1 = {0., 0., 0.}, e2 = {0., 0., 0.}; 00249 GtsMatrix * Hb; 00250 GtsVector cb = {0., 0., 0.}; 00251 GtsVertex * v; 00252 GtsVertex * v1, * v2; 00253 guint n = 0, nb = 0; 00254 #ifdef DEBUG_VOPT 00255 guint nold = 0; 00256 #endif 00257 00258 g_return_val_if_fail (edge != NULL, NULL); 00259 g_return_val_if_fail (klass != NULL, NULL); 00260 g_return_val_if_fail (params != NULL, NULL); 00261 00262 A = gts_matrix_zero (NULL); 00263 Hb = gts_matrix_zero (NULL); 00264 v1 = GTS_SEGMENT (edge)->v1; 00265 v2 = GTS_SEGMENT (edge)->v2; 00266 00267 /* boundary preservation */ 00268 i = v1->segments; 00269 while (i) { 00270 GtsEdge * edge1 = i->data; 00271 GtsFace * f; 00272 if (GTS_IS_EDGE (edge1) && 00273 (f = gts_edge_is_boundary (edge1, NULL))) { 00274 boundary_preservation (edge1, f, e1, e2, Hb, cb); 00275 nb++; 00276 } 00277 i = i->next; 00278 } 00279 i = v2->segments; 00280 while (i) { 00281 GtsEdge * edge1 = i->data; 00282 GtsFace * f; 00283 if (edge1 != edge && 00284 GTS_IS_EDGE (edge1) && 00285 (f = gts_edge_is_boundary (edge1, NULL))) { 00286 boundary_preservation (edge1, f, e1, e2, Hb, cb); 00287 nb++; 00288 } 00289 i = i->next; 00290 } 00291 if (nb > 0) { 00292 GtsMatrix * H = gts_matrix_new ( 00293 e1[2]*e1[2] + e1[1]*e1[1], - e1[0]*e1[1], - e1[0]*e1[2], 0., 00294 - e1[0]*e1[1], e1[2]*e1[2] + e1[0]*e1[0], - e1[1]*e1[2], 0., 00295 - e1[0]*e1[2], - e1[1]*e1[2], e1[1]*e1[1] + e1[0]*e1[0], 0., 00296 0., 0., 0., 0.); 00297 GtsVector c; 00298 00299 c[0] = e1[1]*e2[2] - e1[2]*e2[1]; 00300 c[1] = e1[2]*e2[0] - e1[0]*e2[2]; 00301 c[2] = e1[0]*e2[1] - e1[1]*e2[0]; 00302 n = gts_matrix_quadratic_optimization (A, b, n, H, c); 00303 gts_matrix_destroy (H); 00304 } 00305 00306 g_assert (n <= 2); 00307 00308 #ifdef DEBUG_VOPT 00309 if (n != nold) { 00310 fprintf (stderr, "--- boundary preservation ---\n"); 00311 gts_matrix_print (A, stderr); 00312 gts_vector_print (b, stderr); 00313 nold = n; 00314 } 00315 #endif 00316 00317 /* volume preservation */ 00318 triangles = gts_vertex_triangles (v1, NULL); 00319 triangles = gts_vertex_triangles (v2, triangles); 00320 00321 i = triangles; 00322 while (i) { 00323 if (GTS_IS_FACE (i->data)) { 00324 triangle_normal (i->data, &n1, &n2, &n3, &nt); 00325 sn1 += n1; sn2 += n2; sn3 += n3; 00326 sn11 += n1*n1; sn22 += n2*n2; sn33 += n3*n3; 00327 sn12 += n1*n2; sn13 += n1*n3; sn23 += n2*n3; 00328 st += nt; stn1 += nt*n1; stn2 += nt*n2; stn3 += nt*n3; 00329 } 00330 i = i->next; 00331 } 00332 g_slist_free (triangles); 00333 00334 A1[0] = sn1; A1[1] = sn2; A1[2] = sn3; 00335 n = gts_matrix_compatible_row (A, b, n, A1, st); 00336 00337 #ifdef DEBUG_VOPT 00338 if (n != nold) { 00339 fprintf (stderr, "--- volume preservation ---\n"); 00340 gts_matrix_print (A, stderr); 00341 gts_vector_print (b, stderr); 00342 nold = n; 00343 } 00344 #endif 00345 00346 #if 1 /* Weighted average of volume and boundary optimization */ 00347 if (n < 3) { 00348 /* volume optimization and boundary optimization */ 00349 GtsMatrix * H = gts_matrix_new (sn11, sn12, sn13, 0., 00350 sn12, sn22, sn23, 0., 00351 sn13, sn23, sn33, 0., 00352 0., 0., 0., 0.); 00353 GtsVector c; 00354 gdouble le = 9.*params->boundary_weight* 00355 gts_point_distance2 (GTS_POINT (v1), 00356 GTS_POINT (v2)); 00357 guint i, j; 00358 00359 c[0] = - stn1; c[1] = - stn2; c[2] = - stn3; 00360 if (nb > 0) 00361 for (i = 0; i < 3; i++) { 00362 for (j = 0; j < 3; j++) 00363 H[i][j] = params->volume_weight*H[i][j] + le*Hb[i][j]; 00364 c[i] = params->volume_weight*c[i] + le*cb[i]; 00365 } 00366 n = gts_matrix_quadratic_optimization (A, b, n, H, c); 00367 gts_matrix_destroy (H); 00368 } 00369 00370 #ifdef DEBUG_VOPT 00371 if (n != nold) { 00372 fprintf (stderr, "--- volume and boundary optimization ---\n"); 00373 gts_matrix_print (A, stderr); 00374 gts_vector_print (b, stderr); 00375 nold = n; 00376 } 00377 #endif 00378 00379 if (n < 3) { 00380 /* triangle shape optimization */ 00381 gdouble nv = 0.0; 00382 GtsMatrix * H; 00383 GtsVector c = {0., 0., 0.}; 00384 GSList * list, * i; 00385 00386 list = gts_vertex_neighbors (v1, NULL, NULL); 00387 list = gts_vertex_neighbors (v2, list, NULL); 00388 00389 i = list; 00390 while (i) { 00391 GtsPoint * p1 = i->data; 00392 if (p1 != GTS_POINT (v1) && p1 != GTS_POINT (v2)) { 00393 nv += 1.0; 00394 c[0] -= p1->x; 00395 c[1] -= p1->y; 00396 c[2] -= p1->z; 00397 } 00398 i = i->next; 00399 } 00400 g_slist_free (list); 00401 00402 H = gts_matrix_new (nv, 0., 0., 0., 00403 0., nv, 0., 0., 00404 0., 0., nv, 0., 00405 0., 0., 0., 0.); 00406 n = gts_matrix_quadratic_optimization (A, b, n, H, c); 00407 gts_matrix_destroy (H); 00408 } 00409 00410 #ifdef DEBUG_VOPT 00411 if (n != nold) { 00412 fprintf (stderr, "--- triangle shape optimization ---\n"); 00413 gts_matrix_print (A, stderr); 00414 gts_vector_print (b, stderr); 00415 nold = n; 00416 } 00417 #endif 00418 #else /* Weighted average of volume, boundary and shape optimization */ 00419 if (n < 3) { 00420 /* volume optimization, boundary and shape optimization */ 00421 GtsMatrix * H; 00422 GtsVector c; 00423 gdouble l2 = gts_point_distance2 (GTS_POINT (v1), 00424 GTS_POINT (v2)); 00425 gdouble wv = params->volume_weight/32.; 00426 gdouble wb = params->boundary_weight/4.*l2; 00427 gdouble ws = params->shape_weight*l2*l2; 00428 00429 gdouble nv = 0.0; 00430 GtsVector cs = {0., 0., 0.}; 00431 GSList * list, * i; 00432 00433 list = gts_vertex_neighbors (v1, NULL, NULL); 00434 list = gts_vertex_neighbors (v2, list, NULL); 00435 00436 i = list; 00437 while (i) { 00438 GtsPoint * p1 = i->data; 00439 if (p1 != GTS_POINT (v1) && p1 != GTS_POINT (v2)) { 00440 nv += 1.0; 00441 cs[0] -= p1->x; 00442 cs[1] -= p1->y; 00443 cs[2] -= p1->z; 00444 } 00445 i = i->next; 00446 } 00447 g_slist_free (list); 00448 00449 H = gts_matrix_new (wv*sn11 + wb*Hb[0][0] + ws*nv, 00450 wv*sn12 + wb*Hb[0][1], 00451 wv*sn13 + wb*Hb[0][2], 00452 wv*sn12 + wb*Hb[1][0], 00453 wv*sn22 + wb*Hb[1][1] + ws*nv, 00454 wv*sn23 + wb*Hb[1][2], 00455 wv*sn13 + wb*Hb[2][0], 00456 wv*sn23 + wb*Hb[2][1], 00457 wv*sn33 + wb*Hb[2][2] + ws*nv); 00458 00459 c[0] = - wv*stn1 + wb*cb[0] + ws*cs[0]; 00460 c[1] = - wv*stn2 + wb*cb[1] + ws*cs[1]; 00461 c[2] = - wv*stn3 + wb*cb[2] + ws*cs[2]; 00462 00463 n = gts_matrix_quadratic_optimization (A, b, n, H, c); 00464 gts_matrix_destroy (H); 00465 } 00466 00467 #ifdef DEBUG_VOPT 00468 if (n != nold) { 00469 fprintf (stderr, "--- volume, boundary and shape optimization ---\n"); 00470 gts_matrix_print (A, stderr); 00471 gts_vector_print (b, stderr); 00472 nold = n; 00473 } 00474 #endif 00475 #endif /* Weighted average of volume, boundary and shape optimization */ 00476 00477 g_assert (n == 3); 00478 Ai = gts_matrix3_inverse (A); 00479 g_assert (Ai != NULL); 00480 00481 v = gts_vertex_new (klass, 00482 Ai[0][0]*b[0] + Ai[0][1]*b[1] + Ai[0][2]*b[2], 00483 Ai[1][0]*b[0] + Ai[1][1]*b[1] + Ai[1][2]*b[2], 00484 Ai[2][0]*b[0] + Ai[2][1]*b[1] + Ai[2][2]*b[2]); 00485 00486 gts_matrix_destroy (A); 00487 gts_matrix_destroy (Ai); 00488 gts_matrix_destroy (Hb); 00489 00490 return v; 00491 } 00492 00501 gdouble gts_volume_optimized_cost (GtsEdge * e, 00502 GtsVolumeOptimizedParams * params) 00503 { 00504 GtsVertex * v; 00505 gdouble cost; 00506 gdouble length2; 00507 00508 g_return_val_if_fail (e != NULL, G_MAXDOUBLE); 00509 g_return_val_if_fail (params != NULL, G_MAXDOUBLE); 00510 00511 v = gts_volume_optimized_vertex (e, gts_vertex_class (), params); 00512 00513 length2 = gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), 00514 GTS_POINT (GTS_SEGMENT (e)->v2)); 00515 cost = 00516 params->volume_weight*edge_volume_cost (e, v) + 00517 params->boundary_weight*length2*edge_boundary_cost (e, v) + 00518 params->shape_weight*length2*length2*edge_shape_cost (e, v); 00519 gts_object_destroy (GTS_OBJECT (v)); 00520 00521 return cost; 00522 }