Last active
June 11, 2021 18:43
-
-
Save Pomax/657d3e1d2dbbe231a790eaf15a0f601f to your computer and use it in GitHub Desktop.
This sketch illustrates the inner and outer tangents between two circles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int dim; | |
ArrayList<Circle> circles; | |
boolean moving = false; | |
/** | |
* simple (x,y) point class | |
*/ | |
class Point { | |
float x, y; | |
public Point(float x, float y) { | |
this.x = x; | |
this.y = y; | |
} | |
} | |
/** | |
* circle class with a center, radius, and diameter | |
*/ | |
class Circle extends Point { | |
float r, d; | |
public Circle(float x, float y, float r) { | |
super(x, y); | |
this.r = r; | |
this.d = 2 * r; | |
} | |
void draw() { | |
ellipse(x, y, d, d); | |
} | |
} | |
/** | |
* ...docs go here... | |
*/ | |
void setup() { | |
size(1500, 500); | |
dim = width/3; | |
circles = new ArrayList<Circle>(); | |
noLoop(); | |
ellipseMode(CENTER); | |
textAlign(CENTER, CENTER); | |
float f = 100; | |
circles.add(new Circle(dim/2 - f, dim/2 - f, 100)); | |
circles.add(new Circle(dim/2 + f, dim/2 + f, 20)); | |
if (circles.get(0).r < circles.get(1).r) { | |
Circle _ = circles.get(0); | |
circles.set(0, circles.get(1)); | |
circles.set(1, _); | |
} | |
} | |
/** | |
* ...docs go here... | |
*/ | |
void draw() { | |
noFill(); | |
stroke(0); | |
background(245); | |
for (Circle c : circles) { | |
c.draw(); | |
} | |
Circle c1 = circles.get(0); | |
Circle c2 = circles.get(1); | |
float dy = c2.y - c1.y; | |
float dx = c2.x - c1.x; | |
noFill(); | |
stroke(0); | |
ellipse(c1.x, c1.y, 3, 3); | |
ellipse(c2.x, c2.y, 3, 3); | |
ellipse(c1.x, c1.y, c1.d, c1.d); | |
stroke(0); | |
fill(0); | |
noFill(); | |
translate(dim, 0); | |
drawExtangents(c1, c2, dx, dy); | |
stroke(0); | |
fill(0); | |
noFill(); | |
translate(dim, 0); | |
drawIntangents(c1, c2, dx, dy); | |
} | |
/** | |
* ...docs go here... | |
*/ | |
void drawBasics(Circle c1, Circle c2, float dx, float dy) { | |
line(0, 0, 0, dim); | |
c1.draw(); | |
c2.draw(); | |
} | |
void drawPoly(Point ...pts) { | |
beginShape(); | |
for (Point p : pts) { | |
vertex(p.x, p.y); | |
ellipse(p.x, p.y, 3, 3); | |
} | |
endShape(CLOSE); | |
} | |
/** | |
* ...docs go here... | |
*/ | |
void drawExtangents(Circle c1, Circle c2, float dx, float dy) { | |
text("outer tangents", 55, 15); | |
drawBasics(c1, c2, dx, dy); | |
float A = abs(c1.r - c2.r); | |
float H = dist(c1.x, c1.y, c2.x, c2.y); | |
float p = acos(A/H); | |
float da = atan2(dy, dx); | |
// we can now calculate our r1, r2, and r3 points: | |
float phi1 = da + p; | |
Point t3 = new Point(c1.x + A * cos(phi1), c1.y + A * sin(phi1)); | |
Point t2 = new Point(c2.x + c2.r * cos(phi1), c2.y + c2.r * sin(phi1)); | |
Point t1 = new Point(c1.x + c1.r * cos(phi1), c1.y + c1.r * sin(phi1)); | |
// and our reflections: | |
float phi2 = da - p; | |
Point s2 = new Point(c2.x + c2.r * cos(phi2), c2.y + c2.r * sin(phi2)); | |
Point s1 = new Point(c1.x + c1.r * cos(phi2), c1.y + c1.r * sin(phi2)); | |
// And we're done: let's draw all this stuff! | |
stroke(0, 200, 0); | |
fill(0, 200, 0, 20); | |
drawPoly(c1, c2, t3); | |
stroke(200, 0, 0); | |
fill(200, 0, 0, 20); | |
drawPoly(c2, t3, t1, t2); | |
noFill(); | |
stroke(0); | |
arc(c1.x, c1.y, A/2, A/2, da, phi1); | |
fill(0); | |
text("φ = cos⁻¹(A/H)", c1.x-0, c1.y - 20); | |
text("A = r₁ - r₂", c1.x + 7 + (A/2) * cos(phi1), c1.y + (A/2) * sin(phi1)); | |
text("H = |c₂ - c₁|", lerp(c1.x, c2.x, 0.5) + 10, lerp(c1.y, c2.y, 0.5) - 10); | |
text("O = √(H² - A²)", lerp(t3.x, c2.x, 0.5) - 60, lerp(t3.y, c2.y, 0.5) + 20); | |
text("r₂", c2.x + 7 + (c2.r/2) * cos(phi1), c2.y + 1 + (c2.r/2) * sin(phi1 + 0.2)); | |
noStroke(); | |
fill(200, 0, 0, 10); | |
ellipse(c1.x, c1.y, 2*A, 2*A); | |
stroke(0); | |
line(s1.x, s1.y, s2.x, s2.y); | |
} | |
/** | |
* ...docs go here... | |
*/ | |
void drawIntangents(Circle c1, Circle c2, float dx, float dy) { | |
text("inner tangents", 55, 15); | |
drawBasics(c1, c2, dx, dy); | |
float A = abs(c1.r + c2.r); | |
float H = sqrt(dx*dx + dy*dy); | |
float phi = asin(A/H); | |
float da = atan2(dy, dx); | |
// we can now calculate our r1, r2, and r3 points: | |
float phi1 = da + phi - PI/2; | |
Point t1 = new Point(c1.x + c1.r * cos(phi1), c1.y + c1.r * sin(phi1)); | |
Point t2 = new Point(c2.x + c2.r * cos(phi1 + PI), c2.y + c2.r * sin(phi1 + PI)); | |
Point t3 = new Point(c2.x + A * cos(phi1 + PI), c2.y + A * sin(phi1 + PI)); | |
// and our reflections: | |
float phi2 = da - phi + PI/2; | |
Point s1 = new Point(c1.x + c1.r * cos(phi2), c1.y + c1.r * sin(phi2)); | |
Point s2 = new Point(c2.x + c2.r * cos(phi2 + PI), c2.y + c2.r * sin(phi2 + PI)); | |
stroke(0, 20); | |
noFill(); | |
ellipse(c2.x, c2.y, 2*A, 2*A); | |
stroke(0, 200, 0); | |
fill(0, 200, 0, 20); | |
drawPoly(c1, c2, t3); | |
stroke(200, 0, 0); | |
fill(200, 0, 0, 20); | |
drawPoly(c1, t3, t2, t1); | |
stroke(0); | |
arc(c1.x, c1.y, A/2, A/2, da, phi); | |
line(s1.x, s1.y, s2.x, s2.y); | |
fill(0); | |
text("φ = sin⁻¹(O/H)", c1.x-40, c1.y - 5); | |
text("r₁", lerp(c1.x, t1.x, 0.5) - 2, lerp(c1.y, t1.y, 0.5) + 10); | |
text("H = |c₂ - c₁|", lerp(c1.x, c2.x, 0.5) - 10, lerp(c1.y, c2.y, 0.5)); | |
text("A = √(H² - O²)", lerp(c1.x, t2.x, 0.5) - 90, lerp(c1.y, t2.y, 0.5) + 50); | |
text("O = r₁ + r₂", lerp(c2.x, t2.x, 0.5), lerp(c2.y, t2.y, 0.5) + 20); | |
} | |
/** | |
* ...docs go here... | |
*/ | |
void mouseClicked() { | |
moving = !moving; | |
} | |
/** | |
* ...docs go here... | |
*/ | |
void mouseMoved() { | |
if (moving) { | |
circles.get(0).x = mouseX; | |
circles.get(0).y = mouseY; | |
redraw(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment