chiark / gitweb /
b3af3faae50a8c705c0d2a7295b73e03b6648845
[moebius2.git] / energy.c
1 /*
2  * We try to find an optimal triangle grid
3  */
4
5 #include "common.h"
6 #include "minimise.h"
7 #include "mgraph.h"
8 #include "parallel.h"
9
10 double vertex_areas[N], vertex_mean_edge_lengths[N], edge_lengths[N][V6];
11
12 static double best_energy= DBL_MAX;
13
14 static void addcost(double *energy, double tweight, double tcost, int pr);
15
16 /*---------- main energy computation, weights, etc. ----------*/
17
18 typedef double CostComputation(const Vertices vertices, int section);
19 typedef void PreComputation(const Vertices vertices, int section);
20
21 typedef struct {
22   double weight;
23   CostComputation *fn;
24 } CostContribution;
25
26 #define NPRECOMPS ((sizeof(precomps)/sizeof(precomps[0])))
27 #define NCOSTS ((sizeof(costs)/sizeof(costs[0])))
28 #define COST(weight, compute) { (weight),(compute) },
29
30 static PreComputation *const precomps[]= {
31   compute_edge_lengths,
32   compute_vertex_areas
33 };
34
35 static const CostContribution costs[]= {
36
37 #if XBITS==3
38 #define STOP_EPSILON 1e-6
39     COST(  3e3,   vertex_displacement_cost)
40     COST( 0.4e3,  rim_proximity_cost)
41     COST(  1e7,   edge_angle_cost)
42                   #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.2/1.7)
43     COST(  1e2,   small_triangles_cost)
44     COST(  1e12,   noncircular_rim_cost)
45 #endif
46
47 #if XBITS==4
48 #define STOP_EPSILON 1.2e-3
49     COST(  3e3,   vertex_displacement_cost)
50     COST(  3e3,   vertex_edgewise_displ_cost)
51     COST( 0.2e3,  rim_proximity_cost)
52     COST( 1e6,  rim_twist_cost)
53     COST(  1e12,   noncircular_rim_cost)
54     COST(  10e1,   nonequilateral_triangles_cost)
55 //    COST(  1e1,   small_triangles_cost)
56 //    COST(  1e6,   edge_angle_cost)
57                   #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.7)
58 #endif
59
60 #if XBITS==5
61 #define STOP_EPSILON 1.2e-4
62     COST(  3e3,   vertex_displacement_cost)
63     COST(  3e3,   vertex_edgewise_displ_cost)
64     COST(  2e-1,  rim_proximity_cost)
65     COST(  1e12,   noncircular_rim_cost)
66     COST(  10e1,   nonequilateral_triangles_cost)
67 //    COST(  1e1,   small_triangles_cost)
68 //    COST(  1e6,   edge_angle_cost)
69                   #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.7)
70 #endif
71
72 #if XBITS==6
73 #define STOP_EPSILON 1.2e-4
74     COST(  3e3,   vertex_displacement_cost)
75     COST(  3e3,   vertex_edgewise_displ_cost)
76     COST( 0.02e0,  rim_proximity_cost)
77     COST(  1e12,   noncircular_rim_cost)
78     COST(  10e1,   nonequilateral_triangles_cost)
79 //    COST(  1e1,   small_triangles_cost)
80 //    COST(  1e6,   edge_angle_cost)
81                   #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.7)
82 #endif
83
84 #if XBITS>=7 /* nonsense follows but never mind */
85 #define STOP_EPSILON 1e-6
86     COST(  3e5,   line_bending_cost)
87     COST( 10e2,   edge_length_variation_cost)
88     COST( 9.0e1,  rim_proximity_cost) // 5e1 is too much
89                                       // 2.5e1 is too little
90     // 0.2e1 grows compared to previous ?
91     // 0.6e0 shrinks compared to previous ?
92
93     COST(  1e12,   edge_angle_cost)
94                   #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.3)
95     COST(  1e18,   noncircular_rim_cost)
96 #endif
97
98 };
99
100 const double edge_angle_cost_circcircrat= EDGE_ANGLE_COST_CIRCCIRCRAT;
101
102 void energy_init(void) {
103   stop_epsilon= STOP_EPSILON;
104 }
105
106 /*---------- energy computation machinery ----------*/
107
108 void compute_energy_separately(const struct Vertices *vs,
109                          int section, void *energies_v, void *totals_v) {
110   double *energies= energies_v;
111   int ci;
112   
113   for (ci=0; ci<NPRECOMPS; ci++) {
114     precomps[ci](vs->a, section);
115     inparallel_barrier();
116   }
117   for (ci=0; ci<NCOSTS; ci++)
118     energies[ci]= costs[ci].fn(vs->a, section);
119 }
120
121 void compute_energy_combine(const struct Vertices *vertices,
122                          int section, void *energies_v, void *totals_v) {
123   int ci;
124   double *energies= energies_v;
125   double *totals= totals_v;
126
127   for (ci=0; ci<NCOSTS; ci++)
128     totals[ci] += energies[ci];
129 }
130
131 double compute_energy(const struct Vertices *vs) {
132   static int bests_unprinted;
133
134   double totals[NCOSTS], energy;
135   int ci, printing;
136
137   printing= printing_check(pr_cost,0);
138
139   if (printing) printf("%15lld c>e |", evaluations);
140
141   for (ci=0; ci<NCOSTS; ci++)
142     totals[ci]= 0;
143
144   inparallel(vs,
145              compute_energy_separately,
146              compute_energy_combine,
147              sizeof(totals) /* really, size of energies */,
148              totals);
149
150   energy= 0;
151   for (ci=0; ci<NCOSTS; ci++)
152     addcost(&energy, costs[ci].weight, totals[ci], printing);
153
154   if (printing) printf("| total %# e |", energy);
155
156   if (energy < best_energy) {
157     FILE *best_f;
158     int r;
159
160     if (printing) {
161       printf(" BEST");
162       if (bests_unprinted) printf(" [%4d]",bests_unprinted);
163       bests_unprinted= 0;
164     } else {
165       bests_unprinted++;
166     }
167
168     best_f= fopen(best_file_tmp,"wb");  if (!best_f) diee("fopen new out");
169     r= fwrite(vs->a,sizeof(vs->a),1,best_f); if (r!=1) diee("fwrite");
170     if (fclose(best_f)) diee("fclose new best");
171     if (rename(best_file_tmp,best_file)) diee("rename install new best");
172
173     best_energy= energy;
174   }
175   if (printing) {
176     putchar('\n');
177     flushoutput();
178   }
179
180   evaluations++;
181   return energy;
182 }
183
184 static void addcost(double *energy, double tweight, double tcost, int pr) {
185   double tenergy= tweight * tcost;
186   if (pr) printf(" %# e > %# e* |", tcost, tenergy);
187   *energy += tenergy;
188 }
189
190 /*---------- Precomputations ----------*/
191
192 void compute_edge_lengths(const Vertices vertices, int section) {
193   int v1,e,v2;
194
195   FOR_EDGE(v1,e,v2, OUTER)
196     edge_lengths[v1][e]= hypotD(vertices[v1],vertices[v2]);
197 }
198
199 void compute_vertex_areas(const Vertices vertices, int section) {
200   int v0,v1,v2, e1,e2;
201 //  int k;
202
203   FOR_VERTEX(v0, OUTER) {
204     double total= 0.0, edges_total=0;
205     int count= 0;
206
207     FOR_VEDGE(v0,e1,v1) {
208       e2= (e1+1) % V6;
209       v2= EDGE_END2(v0,e2);
210       if (v2<0) continue;
211
212       edges_total += edge_lengths[v0][e1];
213
214 //      double e1v[D3], e2v[D3], av[D3];
215 //      K {
216 //      e1v[k]= vertices[v1][k] - vertices[v0][k];
217 //      e2v[k]= vertices[v2][k] - vertices[v0][k];
218 //      }
219 //      xprod(av, e1v, e2v);
220 //      total += magnD(av);
221
222       count++;
223     }
224     vertex_areas[v0]= total / count;
225     vertex_mean_edge_lengths[v0]= edges_total / count;
226   }
227 }
228
229 /*---------- displacement of vertices across a midpoint ----------*/
230
231   /*
232    * Subroutine used where we have
233    *
234    *        R - - - - - - - M . -  -  -  -  R'
235    *                            ` .
236    *                                ` .
237    *                                    S
238    *
239    * and wish to say that the vector RM should be similar to MS
240    * or to put it another way S = M + RM
241    *
242    * NB this is not symmetric wrt R and S since it divides by
243    * |SM| but not |RM| so you probably want to call it twice.
244    *
245    * Details:
246    *
247    *   Let  R' = M + SM
248    *        D  = R' - R
249    *
250    * Then the (1/delta)th power of the cost is
251    *      proportional to |D|, and
252    *      inversely proportional to |SM|
253    * except that |D| is measured in a wierd way which counts
254    * distance in the same direction as SM 1/lambda times as much
255    * ie the equipotential surfaces are ellipsoids around R',
256    * lengthened by lambda in the direction of RM.
257    *
258    * So
259    *                                                               delta
260    *                [       -1                                    ]
261    *   cost      =  [ lambda  . ( D . SM/|SM| ) + | D x SM/|SM| | ]
262    *       R,S,M    [ ------------------------------------------- ]
263    *                [                      |SM|                   ]
264    *
265    */
266
267 static double vertex_one_displ_cost(const double r[D3], const double s[D3],
268                                     const double midpoint[D3],
269                                     double delta, double inv_lambda) {
270   const double smlen2_epsilon= 1e-12;
271   double sm[D3], d[D3], ddot, dcross[D3];
272   int k;
273
274   K sm[k]= -s[k] + midpoint[k];
275   K d[k]= midpoint[k] + sm[k] - r[k];
276   ddot= dotprod(d,sm);
277   xprod(dcross, d,sm);
278   double smlen2= magnD2(sm);
279   double cost_basis= inv_lambda * ddot + magnD(dcross);
280   double cost= pow(cost_basis / (smlen2 + smlen2_epsilon), delta);
281
282   return cost;
283 }
284
285 /*---------- displacement of vertices opposite at a vertex ----------*/
286
287   /*
288    *   At vertex Q considering edge direction e to R
289    *   and corresponding opposite edge to S.
290    *
291    *   This is vertex displacement as above with M=Q
292    */
293
294 double vertex_displacement_cost(const Vertices vertices, int section) {
295   const double inv_lambda= 1.0/1; //2;
296   const double delta= 4;
297
298   int si,e,qi,ri;
299   double total_cost= 0;
300
301   FOR_EDGE(qi,e,ri, OUTER) {
302     si= EDGE_END2(qi,(e+3)%V6); if (si<0) continue;
303
304     total_cost += vertex_one_displ_cost(vertices[ri], vertices[si], vertices[qi],
305                                         delta, inv_lambda);
306   }
307   return total_cost;
308 }
309
310 /*---------- displacement of vertices opposite at an edge ----------*/
311
312   /*
313    *   At edge PQ considering vertices R and S (see diagram
314    *   below for overly sharp edge cost).
315    *
316    *   Let  M  = midpoint of PQ
317    */
318
319 double vertex_edgewise_displ_cost(const Vertices vertices, int section) {
320   const double inv_lambda= 1.0/1; //2;
321   const double delta= 4;
322
323   int pi,e,qi,ri,si, k;
324   double m[D3];
325   double total_cost= 0;
326
327   FOR_EDGE(pi,e,qi, OUTER) {
328     si= EDGE_END2(pi,(e+V6-1)%V6);  if (si<0) continue;
329     ri= EDGE_END2(pi,(e   +1)%V6);  if (ri<0) continue;
330
331     K m[k]= 0.5 * (vertices[pi][k] + vertices[qi][k]);
332     
333     total_cost += vertex_one_displ_cost(vertices[ri], vertices[si], m,
334                                         delta, inv_lambda);
335   }
336   return total_cost;
337 }
338
339
340 /*---------- at-vertex edge angles ----------*/
341
342   /*
343    * Definition:
344    *
345    *    At each vertex Q, in each direction e:
346    *
347    *                                  e
348    *                           Q ----->----- R
349    *                      _,-'\__/
350    *                  _,-'       delta
351    *               P '
352    *
353    *                      r
354    *       cost    = delta          (we use r=3)
355    *           Q,e
356    *
357    *
358    * Calculation:
359    *
360    *      Let vector A = PQ
361    *                 B = QR
362    *
363    *                   -1   A . B
364    *      delta =  tan     -------
365    *                      | A x B |
366    *
367    *      which is always in the range 0..pi because the denominator
368    *      is nonnegative.  We add epsilon to |AxB| to avoid division
369    *      by zero.
370    *
371    *                     r
372    *      cost    = delta
373    *          Q,e
374    */
375
376 double line_bending_cost(const Vertices vertices, int section) {
377   static const double axb_epsilon= 1e-6;
378   static const double exponent_r= 4;
379
380   int pi,e,qi,ri, k;
381   double  a[D3], b[D3], axb[D3];
382   double total_cost= 0;
383
384   FOR_EDGE(qi,e,ri, OUTER) {
385     pi= EDGE_END2(qi,(e+3)%V6); if (pi<0) continue;
386
387 //if (!(qi&XMASK)) fprintf(stderr,"%02x-%02x-%02x (%d)\n",pi,qi,ri,e);
388
389     K a[k]= -vertices[pi][k] + vertices[qi][k];
390     K b[k]= -vertices[qi][k] + vertices[ri][k];
391
392     xprod(axb,a,b);
393
394     double delta= atan2(magnD(axb) + axb_epsilon, dotprod(a,b));
395     double cost= pow(delta,exponent_r);
396
397     total_cost += cost;
398   }
399   return total_cost;
400 }
401
402 /*---------- edge length variation ----------*/
403
404   /*
405    * Definition:
406    *
407    *    See the diagram above.
408    *                                r
409    *       cost    = ( |PQ| - |QR| )
410    *           Q,e
411    */
412
413 double edge_length_variation_cost(const Vertices vertices, int section) {
414   double diff, cost= 0, exponent_r= 2;
415   int q, e,r, eback;
416
417   FOR_EDGE(q,e,r, OUTER) {
418     eback= edge_reverse(q,e);
419     diff= edge_lengths[q][e] - edge_lengths[q][eback];
420     cost += pow(diff,exponent_r);
421   }
422   return cost;
423 }
424
425 /*---------- proportional edge length variation ----------*/
426
427   /*
428    * Definition:
429    *
430    *    See the diagram above.
431    *                                r
432    *       cost    = ( |PQ| - |QR| )
433    *           Q,e
434    */
435
436 double prop_edge_length_variation_cost(const Vertices vertices, int section) {
437   const double num_epsilon= 1e-6;
438
439   double cost= 0, exponent_r= 2;
440   int q, e,r, eback;
441
442   FOR_EDGE(q,e,r, OUTER) {
443     eback= edge_reverse(q,e);
444     double le= edge_lengths[q][e];
445     double leback= edge_lengths[q][eback];
446     double diff= le - leback;
447     double num= MIN(le, leback);
448     cost += pow(diff / (num + num_epsilon), exponent_r);
449   }
450   return cost;
451 }
452
453 /*---------- rim proximity cost ----------*/
454
455 static void find_nearest_oncircle(double oncircle[D3], const double p[D3]) {
456   /* By symmetry, nearest point on circle is the one with
457    * the same angle subtended at the z axis. */
458   oncircle[0]= p[0];
459   oncircle[1]= p[1];
460   oncircle[2]= 0;
461   double mult= 1.0/ magnD(oncircle);
462   oncircle[0] *= mult;
463   oncircle[1] *= mult;
464 }
465
466 double rim_proximity_cost(const Vertices vertices, int section) {
467   double oncircle[3], cost=0;
468   int v;
469
470   FOR_VERTEX(v, OUTER) {
471     int y= v >> YSHIFT;
472     int nominal_edge_distance= y <= Y/2 ? y : Y-1-y;
473     if (nominal_edge_distance==0) continue;
474
475     find_nearest_oncircle(oncircle, vertices[v]);
476
477     cost +=
478       vertex_mean_edge_lengths[v] *
479       (nominal_edge_distance*nominal_edge_distance) /
480       (hypotD2(vertices[v], oncircle) + 1e-6);
481   }
482   return cost;
483 }
484
485 /*---------- noncircular rim cost ----------*/
486
487 double noncircular_rim_cost(const Vertices vertices, int section) {
488   int vy,vx,v;
489   double cost= 0.0;
490   double oncircle[3];
491
492   FOR_RIM_VERTEX(vy,vx,v, OUTER) {
493     find_nearest_oncircle(oncircle, vertices[v]);
494
495     double d2= hypotD2(vertices[v], oncircle);
496     cost += d2*d2;
497   }
498   return cost;
499 }
500
501 /*---------- rim contact angle rotation ----------*/
502
503 /*
504  *
505  *               vq ---- vs
506  *              /       /
507  *           e0/       /e1
508  *           vp 0--- vr
509  *
510  */
511
512 double rim_twist_cost(const Vertices vertices, int section) {
513   const double our_epsilon=1e-6;
514   int vpy,vpx,vpi, vqi,vri,vsi, e0,e1, k;
515   double total_cost= 0.0;
516   double pq[D3], rs[D3], pq_x_rs[D3];
517
518   FOR_RIM_VERTEX(vpy,vpx,vpi, INNER) {
519     FOR_VPEDGE(e0) {
520       if (e0==0 || e0==3) continue;
521       vqi= EDGE_END2(vpi,e0);  if (vqi<0) continue;
522       vri= EDGE_END2(vpi,0);  assert(vri>=0);
523       e1= !vertices_span_join_p(vpi,vri) ? e0 : V6 - e0;
524       vsi= EDGE_END2(vri,e1);  assert(vsi>=0);
525
526       K pq[k]= -vertices[vpi][k] + vertices[vqi][k];
527       K rs[k]= -vertices[vri][k] + vertices[vsi][k];
528
529       xprod(pq_x_rs, pq,rs);
530       double magndiv= edge_lengths[vpi][e0] * edge_lengths[vri][e1];
531
532       double cost= magnD2(pq_x_rs) / (magndiv*magndiv + our_epsilon);
533
534 //fprintf(stderr,"rimtwist P=%03x Q=%03x R=%03x S=%03x e0=%d e1=%d %f\n",
535 //      vpi,vqi,vri,vsi,e0,e1, cost);
536
537       total_cost += cost;
538     }
539   }
540
541   return total_cost;
542 }
543
544 /*---------- overly sharp edge cost ----------*/
545
546   /*
547    *
548    *                Q `-_
549    *              / |    `-_                           P'Q' ------ S'
550    *             /  |       `-.                      _,' `.       .
551    *            /   |           S                 _,'     :      .
552    *           /    |      _,-'                _,'        :r    .r
553    *          /     |  _,-'                R' '           `.   .
554    *         /    , P '                        ` .   r     :  .
555    *        /  ,-'                                  `  .   : 
556    *       /,-'                                          ` C'
557    *      /'
558    *     R
559    *
560    *
561    *
562    *  Let delta =  angle between two triangles' normals
563    *
564    *  Giving energy contribution:
565    *
566    *                                   2
567    *    E             =  F   .  delta
568    *     vd, edge PQ      vd
569    */
570
571 double edge_angle_cost(const Vertices vertices, int section) {
572   double pq1[D3], rp[D3], ps[D3], rp_2d[D3], ps_2d[D3], rs_2d[D3];
573   double a,b,c,s,r;
574   const double minradius_base= 0.2;
575
576   int pi,e,qi,ri,si, k;
577 //  double our_epsilon=1e-6;
578   double total_cost= 0;
579
580   FOR_EDGE(pi,e,qi, OUTER) {
581 //    if (!(RIM_VERTEX_P(pi) || RIM_VERTEX_P(qi))) continue;
582
583     si= EDGE_END2(pi,(e+V6-1)%V6);  if (si<0) continue;
584     ri= EDGE_END2(pi,(e   +1)%V6);  if (ri<0) continue;
585
586     K {
587       pq1[k]= -vertices[pi][k] + vertices[qi][k];
588       rp[k]=  -vertices[ri][k] + vertices[pi][k];
589       ps[k]=  -vertices[pi][k] + vertices[si][k];
590     }
591
592     normalise(pq1,1,1e-6);
593     xprod(rp_2d, rp,pq1); /* projects RP into plane normal to PQ */
594     xprod(ps_2d, ps,pq1); /* likewise PS */
595     K rs_2d[k]= rp_2d[k] + ps_2d[k];
596     /* radius of circumcircle of R'P'S' from Wikipedia
597      * `Circumscribed circle' */
598     a= magnD(rp_2d);
599     b= magnD(ps_2d);
600     c= magnD(rs_2d);
601     s= 0.5*(a+b+c);
602     r= a*b*c / sqrt((a+b+c)*(a-b+c)*(b-c+a)*(c-a+b) + 1e-6);
603
604     double minradius= minradius_base + edge_angle_cost_circcircrat*(a+b);
605     double deficit= minradius - r;
606     if (deficit < 0) continue;
607     double cost= deficit*deficit;
608
609     total_cost += cost;
610   }
611
612   return total_cost;
613 }
614
615 /*---------- small triangles cost ----------*/
616
617   /*
618    * Consider a triangle PQS
619    *
620    * Cost is 1/( area^2 )
621    */
622
623 double small_triangles_cost(const Vertices vertices, int section) {
624   double pq[D3], ps[D3];
625   double x[D3];
626   int pi,e,qi,si, k;
627 //  double our_epsilon=1e-6;
628   double total_cost= 0;
629
630   FOR_EDGE(pi,e,qi, OUTER) {
631 //    if (!(RIM_VERTEX_P(pi) || RIM_VERTEX_P(qi))) continue;
632
633     si= EDGE_END2(pi,(e+V6-1)%V6);  if (si<0) continue;
634
635     K {
636       pq[k]= vertices[qi][k] - vertices[pi][k];
637       ps[k]= vertices[si][k] - vertices[pi][k];
638     }
639     xprod(x, pq,ps);
640
641     double cost= 1/(magnD2(x) + 0.01);
642
643 //double cost= pow(magnD(spqxpqr), 3);
644 //assert(dot>=-1 && dot <=1);
645 //double cost= 1-dot;
646     total_cost += cost;
647   }
648
649   return total_cost;
650 }
651
652 /*---------- nonequilateral triangles cost ----------*/
653
654   /*
655    * Consider a triangle PQR
656    *
657    * let edge lengths a=|PQ| b=|QR| c=|RP|
658    *
659    * predicted edge length p = 1/3 * (a+b+c)
660    *
661    * compute cost for each x in {a,b,c}
662    *
663    *
664    *      cost      = (x-p)^2 / p^2
665    *          PQR,x
666    */
667
668 double nonequilateral_triangles_cost(const Vertices vertices, int section) {
669   double pr[D3], abc[3];
670   int pi,e0,e1,qi,ri, k,i;
671   double our_epsilon=1e-6;
672   double total_cost= 0;
673
674   FOR_EDGE(pi,e0,qi, OUTER) {
675     e1= (e0+V6-1)%V6;
676     ri= EDGE_END2(pi,e1);  if (ri<0) continue;
677
678     K pr[k]= -vertices[pi][k] + vertices[ri][k];
679
680     abc[0]= edge_lengths[pi][e0]; /* PQ */
681     abc[1]= edge_lengths[qi][e1]; /* QR */
682     abc[2]= magnD(pr);
683
684     double p= (1/3.0) * (abc[0]+abc[1]+abc[2]);
685     double p_inv2= 1/(p*p + our_epsilon);
686
687     for (i=0; i<3; i++) {
688       double diff= (abc[i] - p);
689       double cost= diff*diff * p_inv2;
690       total_cost += cost;
691     }
692   }
693
694   return total_cost;
695 }