static double TransSign(ContourVertex u, ContourVertex v, ContourVertex w) { /* Returns a number whose sign matches TransEval(u,v,w) but which * is cheaper to evaluate. Returns > 0, == 0 , or < 0 * as v is above, on, or below the edge uw. */ double gapL, gapR; if (!u.TransLeq(v) || !v.TransLeq(w)) { throw new Exception(); } gapL = v.y - u.y; gapR = w.y - v.y; if (gapL + gapR > 0) { return (v.x - w.x) * gapL + (v.x - u.x) * gapR; } /* vertical line */ return 0; }
static void EdgeIntersect(ContourVertex o1, ContourVertex d1, ContourVertex o2, ContourVertex d2, ref ContourVertex v) /* Given edges (o1,d1) and (o2,d2), compute their point of intersection. * The computed point is guaranteed to lie in the intersection of the * bounding rectangles defined by each edge. */ { double z1, z2; /* This is certainly not the most efficient way to find the intersection * of two line segments, but it is very numerically stable. * * Strategy: find the two middle vertices in the VertLeq ordering, * and interpolate the intersection s-value from these. Then repeat * using the TransLeq ordering to find the intersection t-value. */ if (!o1.VertLeq(d1)) { Swap(ref o1, ref d1); } if (!o2.VertLeq(d2)) { Swap(ref o2, ref d2); } if (!o1.VertLeq(o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); } if (!o2.VertLeq(d1)) { /* Technically, no intersection -- do our best */ v.x = (o2.x + d1.x) / 2; } else if (d1.VertLeq(d2)) { /* Interpolate between o2 and d1 */ z1 = ContourVertex.EdgeEval(o1, o2, d1); z2 = ContourVertex.EdgeEval(o2, d1, d2); if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; } v.x = Interpolate(z1, o2.x, z2, d1.x); } else { /* Interpolate between o2 and d2 */ z1 = ContourVertex.EdgeSign(o1, o2, d1); z2 = -ContourVertex.EdgeSign(o1, d2, d1); if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; } v.x = Interpolate(z1, o2.x, z2, d2.x); } /* Now repeat the process for t */ if (!o1.TransLeq(d1)) { Swap(ref o1, ref d1); } if (!o2.TransLeq(d2)) { Swap(ref o2, ref d2); } if (!o1.TransLeq(o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); } if (!o2.TransLeq(d1)) { /* Technically, no intersection -- do our best */ v.y = (o2.y + d1.y) / 2; } else if (d1.TransLeq(d2)) { /* Interpolate between o2 and d1 */ z1 = TransEval(o1, o2, d1); z2 = TransEval(o2, d1, d2); if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; } v.y = Interpolate(z1, o2.y, z2, d1.y); } else { /* Interpolate between o2 and d2 */ z1 = TransSign(o1, o2, d1); z2 = -TransSign(o1, d2, d1); if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; } v.y = Interpolate(z1, o2.y, z2, d2.y); } }
static double TransEval(ContourVertex u, ContourVertex v, ContourVertex w) { /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w), * evaluates the t-coord of the edge uw at the s-coord of the vertex v. * Returns v.s - (uw)(v.t), ie. the signed distance from uw to v. * If uw is vertical (and thus passes thru v), the result is zero. * * The calculation is extremely accurate and stable, even when v * is very close to u or w. In particular if we set v.s = 0 and * let r be the negated result (this evaluates (uw)(v.t)), then * r is guaranteed to satisfy MIN(u.s,w.s) <= r <= MAX(u.s,w.s). */ double gapL, gapR; if (!u.TransLeq(v) || !v.TransLeq(w)) { throw new Exception(); } gapL = v.y - u.y; gapR = w.y - v.y; if (gapL + gapR > 0) { if (gapL < gapR) { return (v.x - u.x) + (u.x - w.x) * (gapL / (gapL + gapR)); } else { return (v.x - w.x) + (w.x - u.x) * (gapR / (gapL + gapR)); } } /* vertical line */ return 0; }