Skip to content

Instantly share code, notes, and snippets.

@Pomax
Last active June 11, 2021 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pomax/657d3e1d2dbbe231a790eaf15a0f601f to your computer and use it in GitHub Desktop.
Save Pomax/657d3e1d2dbbe231a790eaf15a0f601f to your computer and use it in GitHub Desktop.
This sketch illustrates the inner and outer tangents between two circles
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