Circle inversion is a mathematical technique that holds a lot of opportunities for the creative coder.
Circle inversion, or circular inversion, or geometric inversion is a method of transforming a point within a circle to a new point outside the circle or vice-versa. By transforming multiple points, you can transform entire shapes, which become warped and curved in interesting ways, as if the original shape was reflected onto a curved surface. You can even do a circle inversion chaos game with multiple random circles to create interesting fractals. We’ll dive into that after we cover the basics.
The All Important Formula
So we start with a circle centered at x0, y0
with a radius of r
. And a point x1, y1
within that circle. We want to invert that point to x2, y2
, outside of the circle. That’s the point we need to find.
To describe it a different way, we can easily get the distance from the center of the circle to point x1, y1
. We’ll call that dist0
. We want to get the distance from the center to x2, y2
, which we’ll call dist1
.
The formula is simply r^2 / dist0
. That’s if the first point is inside the circle. If you want to transform a point outside the circle to a point inside it … well, actually, it’s the exact same formula, which is nice and handy.
I’m not going to go deep into the geometry and math that you use to work out that formula, but it’s a good idea to work it out if you’re into that kind of stuff. There are plenty of pages that will show you exactly what’s going on here.
And the code that will make it happen:
function invert(cx, cy, r, x1, y1) {
const dx = x1 - cx;
const dy = y1 - cy;
const dist0 = Math.sqrt(dx * dx + dy * dy);
const dist1 = r * r / dist0;
const angle = Math.atan2(y1 - cy, x1 - cx);
return {
x: cx + Math.cos(angle) * dist1,
y: cy + Math.sin(angle) * dist1,
}
}
This takes the center x, y and radius of a circle and the x, y of another point. It calculates the distance from the point to the center using standard Pythagorean theorem, and finds dist1
using the formula I just described. It then finds the angle from the circle center to the point and uses some trig to find the new point. And here it is in action:
You can move the circle’s center, change its radius, and move point p0. Point p1 will then move in accordance. Things to note:
- As p0 gets close to the edge of the circle, p1 also moves in close to the edge of the circle.
- As p0 gets close to the center of the circle, p1 moves out to infinity.
- When p0 goes outside of the circle, p1 crosses over to the inside.
There’s a bit of an optimization you can make to this code to remove all the trig. I’ll just put it here and leave it to you to figure out how it’s working:
function invert(cx, cy, r, x1, y1) {
const dx = x1 - cx;
const dy = y1 - cy;
const dist0 = Math.sqrt(dx * dx + dy * dy);
const dist1 = r * r / dist0;
const ratio = dist1 / dist0;
return {
x: cx + dx * ratio,
y: cy + dy * ratio,
};
}
In fact, you can go even one step further. Since we’re dividing by dist0
twice, we’re actually dividing by the square of dist0
. So we can use that to get rid of the square root and both distances:
function invert(cx, cy, r, x1, y1) {
const dx = x1 - cx;
const dy = y1 - cy;
const ratio = (r * r ) / (dx * dx + dy * dy);
return {
x: cx + dx * ratio,
y: cy + dy * ratio,
};
}
Shapes
Once you can invert a single point, you can start inverting entire paths of points, meaning you can invert shapes. To give you a feel for this, here’s a little app that lets you draw on the canvas with your mouse. It will draw both the exact path you are drawing, as well as the inverted path.
There’s no clear button, so you’ll have to refresh the whole page if you want to restart a drawing. If you want to spend some more time with it, you can open up the app in a fresh page.
I’m going to stop here for now. The core takeaway is that invert
function. Play around with it and see what happens when you draw different shapes. I’ll come back later with that circle inversion chaos game concept I mentioned earlier. That’s where things get really fun.
Note on diagrams.
The drawings above were done on my Onyx Boox Note Air eInk tablet. I had talked about sketching in eInk in an earlier post. I was about to code up some graphics to show the principles, or maybe break out some kind of drawing application, then decided to give it a go just sketching on the tablet. I then exported the drawings and added them to the post. It’s also the first time I used color in sketching on eInk. Although the Note Air is not a color tablet, you can choose different colors to draw with. They render in black and white on the eInk screen, but when exported, they are indeed color drawings. Not super important to the post. It was just a fun little workflow that worked out pretty well from my viewpoint
Controls: MiniComps
Graphics: BLJS
One thought on “Circle Inversion”