+static void addcost(double *energy, double tweight, double tcost, int pr);
+
+/*---------- main energy computation, weights, etc. ----------*/
+
+typedef double CostComputation(const Vertices vertices, int section);
+typedef void PreComputation(const Vertices vertices, int section);
+
+typedef struct {
+ double weight;
+ CostComputation *fn;
+} CostContribution;
+
+#define NPRECOMPS ((sizeof(precomps)/sizeof(precomps[0])))
+#define NCOSTS ((sizeof(costs)/sizeof(costs[0])))
+#define COST(weight, compute) { (weight),(compute) },
+
+static PreComputation *const precomps[]= {
+ compute_edge_lengths,
+ compute_vertex_areas,
+ compute_rim_twist_angles
+};
+
+static const CostContribution costs[]= {
+
+#if XBITS==3
+#define STOP_EPSILON 1e-6
+ COST( 3e3, vertex_displacement_cost)
+ COST( 0.4e3, rim_proximity_cost)
+ COST( 1e7, edge_angle_cost)
+ #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.2/1.7)
+ COST( 1e2, small_triangles_cost)
+ COST( 1e12, noncircular_rim_cost)
+#endif
+
+#if XBITS==4
+#define STOP_EPSILON 5e-3
+ COST( 3e4, vertex_displacement_cost) // NB this is probably wrong now
+ COST( 3e4, vertex_edgewise_displ_cost) // we have changed the power
+ COST( 0.2e3, rim_proximity_cost)
+ COST( 1e4, rim_twist_cost)
+ COST( 1e12, noncircular_rim_cost)
+ COST( 10e1, nonequilateral_triangles_cost)
+// COST( 1e1, small_triangles_cost)
+// COST( 1e6, edge_angle_cost)
+ #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.7)
+#endif
+
+#if XBITS==5
+#define STOP_EPSILON 1e-5
+ COST( 3e4, vertex_displacement_cost)
+ COST( 3e4, vertex_edgewise_displ_cost)
+ COST( 2e-1, rim_proximity_cost)
+ COST( 3e3, rim_twist_cost)
+ COST( 1e12, noncircular_rim_cost)
+ COST( 3e2, nonequilateral_triangles_cost)
+// COST( 1e1, small_triangles_cost)
+// COST( 1e6, edge_angle_cost)
+ #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.7)
+#endif
+
+#if XBITS==6
+#define STOP_EPSILON 1e-4
+ COST( 3e5, vertex_displacement_cost)
+ COST( 3e5, vertex_edgewise_displ_cost)
+ COST( 3e-2, rim_proximity_cost)
+ COST( 1e4, rim_twist_cost)
+ COST( 1e12, noncircular_rim_cost)
+ COST( 10e1, nonequilateral_triangles_cost)
+// COST( 1e1, small_triangles_cost)
+// COST( 1e6, edge_angle_cost)
+ #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.7)
+#endif
+
+#if XBITS>=7 /* nonsense follows but never mind */
+#define STOP_EPSILON 1e-6
+ COST( 3e5, line_bending_cost)
+ COST( 10e2, edge_length_variation_cost)
+ COST( 9.0e1, rim_proximity_cost) // 5e1 is too much
+ // 2.5e1 is too little
+ // 0.2e1 grows compared to previous ?
+ // 0.6e0 shrinks compared to previous ?
+
+ COST( 1e12, edge_angle_cost)
+ #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.3)
+ COST( 1e18, noncircular_rim_cost)
+#endif
+
+};
+
+const double edge_angle_cost_circcircrat= EDGE_ANGLE_COST_CIRCCIRCRAT;
+
+void energy_init(void) {
+ stop_epsilon= STOP_EPSILON;
+}
+
+/*---------- energy computation machinery ----------*/
+
+void compute_energy_separately(const struct Vertices *vs,
+ int section, void *energies_v, void *totals_v) {
+ double *energies= energies_v;
+ int ci;
+
+ for (ci=0; ci<NPRECOMPS; ci++) {
+ precomps[ci](vs->a, section);
+ inparallel_barrier();
+ }
+ for (ci=0; ci<NCOSTS; ci++)
+ energies[ci]= costs[ci].fn(vs->a, section);
+}
+
+void compute_energy_combine(const struct Vertices *vertices,
+ int section, void *energies_v, void *totals_v) {
+ int ci;
+ double *energies= energies_v;
+ double *totals= totals_v;
+
+ for (ci=0; ci<NCOSTS; ci++)
+ totals[ci] += energies[ci];
+}
+
+double compute_energy(const struct Vertices *vs) {
+ static int bests_unprinted;