public void render(Color c, int stroke, int markType) { if (c == null) c = Color.RED; V.pushColor(c); if (defined()) { seg.render(c, stroke, markType); } else { for (int i = 0; i < 2; i++) { if (i == 1 && discA == discB) continue; EdObject obj = object(i); if (obj instanceof EdDisc) { EdDisc d = (EdDisc) obj; stroke = STRK_RUBBERBAND; V.pushStroke(stroke); double r = Math.max(d.getRadius() - 4, 2.0); V.drawCircle(d.getOrigin(), r); V.popStroke(); } else { Tools.unimp("rendering undefined bitangents of polygons"); } } } V.popColor(); }
public BiTangent(FPoint2 pt1, String lbl1, FPoint2 pt2, String lbl2) { EdDisc d1 = new EdDisc(pt1, 0); d1.setLabel(lbl1); EdDisc d2 = new EdDisc(pt2, 0); d2.setLabel(lbl2); construct(d1, d2); }
private void construct(EdDisc a, EdDisc b) { this.discA = a; this.discB = b; if (EdDisc.partiallyDisjoint(a, b)) { // if (!UHullMain.oldBitanMethod()) { final boolean db = false; if (a.getRadius() == b.getRadius()) { FPoint2 oa = a.getOrigin(), ob = b.getOrigin(); FPoint2 n = new FPoint2(-(ob.y - oa.y), ob.x - oa.x); n.normalize(); n.x *= a.getRadius(); n.y *= a.getRadius(); seg = new DirSeg(FPoint2.add(oa, n, null), FPoint2.add(ob, n, null)); return; } boolean swap = a.getRadius() > b.getRadius(); if (swap) { b = (EdDisc) discA; a = (EdDisc) discB; } if (db && T.update()) T.msg( "BiTangent construct, arad=" + Tools.f(a.getRadius()) + " brad=" + Tools.f(b.getRadius()) + " swap=" + swap + " origin.a=" + T.show(a.getOrigin())); FPoint2 oa = a.getOrigin(); FPoint2 ob = b.getOrigin(); double U = ob.x, V = ob.y; double A = oa.x - U, B = oa.y - V; double R1 = a.getRadius(); double R2 = b.getRadius(); double S = R2 - R1; double x1, y1, x2, y2; x1 = A; y1 = B; boolean secondRoot; boolean altSlope = Math.abs(B) < Math.abs(A); if (!altSlope) { double C1 = S * S / B, C2 = -A / B; double qA = 1 + C2 * C2, qB = 2 * C1 * C2, qC = C1 * C1 - S * S; double root = Math.sqrt(qB * qB - 4 * qA * qC); x2 = (-qB - root) / (2 * qA); y2 = C1 + C2 * x2; secondRoot = MyMath.sideOfLine(x2, y2, A, B, 0, 0) < 0; if (swap ^ secondRoot) { x2 = (-qB + root) / (2 * qA); y2 = C1 + C2 * x2; } } else { double C1 = S * S / A, C2 = -B / A; double qA = 1 + C2 * C2, qB = 2 * C1 * C2, qC = C1 * C1 - S * S; double root = Math.sqrt(qB * qB - 4 * qA * qC); y2 = (-qB - root) / (2 * qA); x2 = C1 + C2 * y2; secondRoot = MyMath.sideOfLine(x2, y2, A, B, 0, 0) < 0; if (swap ^ secondRoot) { y2 = (-qB + root) / (2 * qA); x2 = C1 + C2 * y2; } } // now grow both discs back to r1, r2 double tx = U; double ty = V; // if (S == 0) { // FPoint2 unit = new FPoint2(-A, -B); // if (swap) { // unit.x = -unit.x; // unit.y = -unit.y; // } // unit.normalize(); // tx += -unit.y * R1; // ty += unit.x * R1; // } else { double F = R1 / S; tx += x2 * F; ty += y2 * F; } if (db && T.update()) T.msg("adding offset to both points: " + tx + ", " + ty + T.show(new FPoint2(tx, ty))); x1 += tx; y1 += ty; x2 += tx; y2 += ty; FPoint2 p1 = new FPoint2(x1, y1); FPoint2 p2 = new FPoint2(x2, y2); if (swap) { FPoint2 tmp = p1; p1 = p2; p2 = tmp; } seg = new DirSeg(p1, p2); if (db && T.update()) T.msg( "swap=" + swap + " altSlope=" + altSlope + " secondRoot=" + secondRoot + " dirseg=" + EdSegment.showDirected(p1, p2)); } // else { // // double th = calcTheta(a, b); // LineEqn eqn = new LineEqn(a.polarPoint(th + Math.PI / 2), th); // double ta = eqn.parameterFor(a.getOrigin()); // double tb = eqn.parameterFor(b.getOrigin()); // seg = new DirSeg(eqn.pt(ta), eqn.pt(tb)); // // } } }