pcb 4.1.1
An interactive printed circuit board layout editor.

vopt.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 "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 }