+
+/*---------- rim contact angle rotation ----------*/
+
+void compute_rim_twist_angles(const Vertices vertices, int section) {
+ double oncircle[D3], distance[D3];
+ int vpy,vpx,v,k;
+
+ FOR_NEAR_RIM_VERTEX(vpy,vpx,v, 1,OUTER) {
+ find_nearest_oncircle(oncircle, vertices[v]);
+ /* we are interested in the angle subtended at the rim, from the
+ * rim's point of view. */
+ K distance[k]= vertices[v][k] - oncircle[k];
+ double distance_positive_z= distance[3];
+ double distance_radial_outwards= dotprod(distance, oncircle);
+ rim_vertex_angles[v]= atan2(distance_positive_z, distance_radial_outwards);
+ }
+}
+
+double rim_twist_cost(const Vertices vertices, int section) {
+ double total_cost= 0;
+ int vpy,vpx,v0,v1;
+
+ FOR_NEAR_RIM_VERTEX(vpy,vpx,v0, 1,OUTER) {
+ v1= EDGE_END2(v0,0); assert(v1!=0);
+ double delta= rim_vertex_angles[v0] - rim_vertex_angles[v1];
+ if (delta < M_PI) delta += 2*M_PI;
+ if (delta > M_PI) delta -= 2*M_PI;
+
+ double cost= pow(delta, 4);
+ total_cost += cost;
+ }
+
+ return total_cost;
+}
+
+/*---------- overly sharp edge cost ----------*/
+
+ /*
+ *
+ * Q `-_
+ * / | `-_ P'Q' ------ S'
+ * / | `-. _,' `. .
+ * / | S _,' : .
+ * / | _,-' _,' :r .r
+ * / | _,-' R' ' `. .
+ * / , P ' ` . r : .
+ * / ,-' ` . :
+ * /,-' ` C'
+ * /'
+ * R
+ *
+ *
+ *
+ * Let delta = angle between two triangles' normals
+ *
+ * Giving energy contribution:
+ *
+ * 2
+ * E = F . delta
+ * vd, edge PQ vd
+ */
+
+double edge_angle_cost(const Vertices vertices, int section) {
+ double pq1[D3], rp[D3], ps[D3], rp_2d[D3], ps_2d[D3], rs_2d[D3];
+ double a,b,c,s,r;
+ const double minradius_base= 0.2;
+
+ int pi,e,qi,ri,si, k;
+// double our_epsilon=1e-6;
+ double total_cost= 0;
+
+ FOR_EDGE(pi,e,qi, OUTER) {
+// if (!(RIM_VERTEX_P(pi) || RIM_VERTEX_P(qi))) continue;
+
+ si= EDGE_END2(pi,(e+V6-1)%V6); if (si<0) continue;
+ ri= EDGE_END2(pi,(e +1)%V6); if (ri<0) continue;
+
+ K {
+ pq1[k]= -vertices[pi][k] + vertices[qi][k];
+ rp[k]= -vertices[ri][k] + vertices[pi][k];
+ ps[k]= -vertices[pi][k] + vertices[si][k];
+ }
+
+ normalise(pq1,1,1e-6);
+ xprod(rp_2d, rp,pq1); /* projects RP into plane normal to PQ */
+ xprod(ps_2d, ps,pq1); /* likewise PS */
+ K rs_2d[k]= rp_2d[k] + ps_2d[k];
+ /* radius of circumcircle of R'P'S' from Wikipedia
+ * `Circumscribed circle' */
+ a= magnD(rp_2d);
+ b= magnD(ps_2d);
+ c= magnD(rs_2d);
+ s= 0.5*(a+b+c);
+ r= a*b*c / sqrt((a+b+c)*(a-b+c)*(b-c+a)*(c-a+b) + 1e-6);
+
+ double minradius= minradius_base + edge_angle_cost_circcircrat*(a+b);
+ double deficit= minradius - r;
+ if (deficit < 0) continue;
+ double cost= deficit*deficit;
+
+ total_cost += cost;
+ }
+
+ return total_cost;
+}
+
+/*---------- small triangles cost ----------*/
+
+ /*
+ * Consider a triangle PQS
+ *
+ * Cost is 1/( area^2 )
+ */
+
+double small_triangles_cost(const Vertices vertices, int section) {
+ double pq[D3], ps[D3];
+ double x[D3];
+ int pi,e,qi,si, k;
+// double our_epsilon=1e-6;
+ double total_cost= 0;
+
+ FOR_EDGE(pi,e,qi, OUTER) {
+// if (!(RIM_VERTEX_P(pi) || RIM_VERTEX_P(qi))) continue;
+
+ si= EDGE_END2(pi,(e+V6-1)%V6); if (si<0) continue;
+
+ K {
+ pq[k]= vertices[qi][k] - vertices[pi][k];
+ ps[k]= vertices[si][k] - vertices[pi][k];
+ }
+ xprod(x, pq,ps);
+
+ double cost= 1/(magnD2(x) + 0.01);
+
+//double cost= pow(magnD(spqxpqr), 3);
+//assert(dot>=-1 && dot <=1);
+//double cost= 1-dot;
+ total_cost += cost;
+ }
+
+ return total_cost;
+}
+
+/*---------- nonequilateral triangles cost ----------*/
+
+ /*
+ * Consider a triangle PQR
+ *
+ * let edge lengths a=|PQ| b=|QR| c=|RP|
+ *
+ * predicted edge length p = 1/3 * (a+b+c)
+ *
+ * compute cost for each x in {a,b,c}
+ *
+ *
+ * cost = (x-p)^2 / p^2
+ * PQR,x
+ */
+
+double nonequilateral_triangles_cost(const Vertices vertices, int section) {
+ double pr[D3], abc[3];
+ int pi,e0,e1,qi,ri, k,i;
+ double our_epsilon=1e-6;
+ double total_cost= 0;
+
+ FOR_EDGE(pi,e0,qi, OUTER) {
+ e1= (e0+V6-1)%V6;
+ ri= EDGE_END2(pi,e1); if (ri<0) continue;
+
+ K pr[k]= -vertices[pi][k] + vertices[ri][k];
+
+ abc[0]= edge_lengths[pi][e0]; /* PQ */
+ abc[1]= edge_lengths[qi][e1]; /* QR */
+ abc[2]= magnD(pr);
+
+ double p= (1/3.0) * (abc[0]+abc[1]+abc[2]);
+ double p_inv2= 1/(p*p + our_epsilon);
+
+ for (i=0; i<3; i++) {
+ double diff= (abc[i] - p);
+ double cost= diff*diff * p_inv2;
+ total_cost += cost;
+ }
+ }
+
+ return total_cost;
+}