Last active
October 17, 2024 13:10
-
-
Save jupdike/bfe5eb23d1c395d8a0a1a4ddd94882ac to your computer and use it in GitHub Desktop.
Find the intersections (two points) of two circles, if they intersect at all
This file contains 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
// based on the math here: | |
// http://math.stackexchange.com/a/1367732 | |
// x1,y1 is the center of the first circle, with radius r1 | |
// x2,y2 is the center of the second ricle, with radius r2 | |
function intersectTwoCircles(x1,y1,r1, x2,y2,r2) { | |
var centerdx = x1 - x2; | |
var centerdy = y1 - y2; | |
var R = Math.sqrt(centerdx * centerdx + centerdy * centerdy); | |
if (!(Math.abs(r1 - r2) <= R && R <= r1 + r2)) { // no intersection | |
return []; // empty list of results | |
} | |
// intersection(s) should exist | |
var R2 = R*R; | |
var R4 = R2*R2; | |
var a = (r1*r1 - r2*r2) / (2 * R2); | |
var r2r2 = (r1*r1 - r2*r2); | |
var c = Math.sqrt(2 * (r1*r1 + r2*r2) / R2 - (r2r2 * r2r2) / R4 - 1); | |
var fx = (x1+x2) / 2 + a * (x2 - x1); | |
var gx = c * (y2 - y1) / 2; | |
var ix1 = fx + gx; | |
var ix2 = fx - gx; | |
var fy = (y1+y2) / 2 + a * (y2 - y1); | |
var gy = c * (x1 - x2) / 2; | |
var iy1 = fy + gy; | |
var iy2 = fy - gy; | |
// note if gy == 0 and gx == 0 then the circles are tangent and there is only one solution | |
// but that one solution will just be duplicated as the code is currently written | |
return [[ix1, iy1], [ix2, iy2]]; | |
} |
Comparing with the math, shouldn't the denominator in line 17 be 2 * R
instead of 2 * R2
?
(I know this is an old thread, but still clarifying for those who use this as reference)
Never mind, I got confused by the similar notation of the math and the code! 2 * R2
is correct for a
Thanks for posting! Here's a compatible Rust version!
struct Point2 {
x: f64,
y: f64,
}
struct Circle2 {
center: Point2,
radius: f64,
}
pub fn circle_intersection(&self, circle_a: &Circle2, circle_b: &Circle2) -> Vec<Point2> {
let center_a = circle_a.center;
let center_b = circle_b.center;
let r_a = circle_a.radius;
let r_b = circle_b.radius;
let center_dx = center_b.x - center_a.x;
let center_dy = center_b.y - center_a.y;
let center_dist = center_dx.hypot(center_dy);
if !(center_dist <= r_a + r_b && center_dist >= r_a - r_b) {
return vec![];
}
let r_2 = center_dist * center_dist;
let r_4 = r_2 * r_2;
let a = (r_a * r_a - r_b * r_b) / (2.0 * r_2);
let r_2_r_2 = r_a * r_a - r_b * r_b;
let c = (2.0 * (r_a * r_a + r_b * r_b) / r_2 - r_2_r_2 * r_2_r_2 / r_4 - 1.0).sqrt();
let fx = (center_a.x + center_b.x) / 2.0 + a * (center_b.x - center_a.x);
let gx = c * (center_b.y - center_a.y) / 2.0;
let ix1 = fx + gx;
let ix2 = fx - gx;
let fy = (center_a.y + center_b.y) / 2.0 + a * (center_b.y - center_a.y);
let gy = c * (center_a.x - center_b.x) / 2.0;
let iy1 = fy + gy;
let iy2 = fy - gy;
vec![Point2 { x: ix1, y: iy1 }, Point2 { x: ix2, y: iy2}]
}
A simple TypeScript adaptation:
interface Point {
x: number;
y: number;
}
interface Circle {
cx: number;
cy: number;
r: number;
}
const intersectCircleCircle = (c1: Circle, c2: Circle): Point[] => {
const { cx: x1, cy: y1, r: r1 } = c1;
const { cx: x2, cy: y2, r: r2 } = c2;
const centerdx = x1 - x2;
const centerdy = y1 - y2;
const R = Math.sqrt(centerdx * centerdx + centerdy * centerdy);
if (!(Math.abs(r1 - r2) <= R && R <= r1 + r2)) {
// no intersection
return []; // empty list of results
}
// intersection(s) should exist
const R2 = R * R;
const R4 = R2 * R2;
const a = (r1 * r1 - r2 * r2) / (2 * R2);
const r2r2 = r1 * r1 - r2 * r2;
const c = Math.sqrt((2 * (r1 * r1 + r2 * r2)) / R2 - (r2r2 * r2r2) / R4 - 1);
const fx = (x1 + x2) / 2 + a * (x2 - x1);
const gx = (c * (y2 - y1)) / 2;
const ix1 = fx + gx;
const ix2 = fx - gx;
const fy = (y1 + y2) / 2 + a * (y2 - y1);
const gy = (c * (x1 - x2)) / 2;
const iy1 = fy + gy;
const iy2 = fy - gy;
// note if gy == 0 and gx == 0 then the circles are tangent and there is only one solution
// but that one solution will just be duplicated as the code is currently written
return [
{ x: ix1, y: iy1 },
{ x: ix2, y: iy2 },
];
};
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is an example using turtletoy which is based on Java Script
see: https://turtletoy.net/turtle/c60ea8510d
// Locate the intersection(s) of 2 circles
// thanks to jupdike/IntersectTwoCircles.js
// https://gist.github.com/jupdike/bfe5eb23d1c395d8a0a1a4ddd94882ac
// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(1);
const radius = 40; // min=5 max=100 step=1
const X1 = -14; // min=-100 max=100 step=1
const Y1 = -12; // min=-100 max=100 step=1
const X2 = 28; // min=-100 max=100 step=1
const Y2 = 23; // min=-100 max=100 step=1
// Global code will be evaluated once.
const turtle = new Turtle();
centeredCircle(X1, Y1, radius, 360);
centeredCircle(X2, Y2, radius, 360);
array_name = intersectTwoCircles(X1, Y1,radius, X2, Y2 ,radius)
// thanks to jupdike/IntersectTwoCircles.js
// https://gist.github.com/jupdike/bfe5eb23d1c395d8a0a1a4ddd94882ac
// based on the math here:
// http://math.stackexchange.com/a/1367732
// x1,y1 is the center of the first circle, with radius r1
// x2,y2 is the center of the second ricle, with radius r2
function intersectTwoCircles(x1,y1,r1, x2,y2,r2) {
var centerdx = x1 - x2;
var centerdy = y1 - y2;
var R = Math.sqrt(centerdx * centerdx + centerdy * centerdy);
if (!(Math.abs(r1 - r2) <= R && R <= r1 + r2)) { // no intersection
return []; // empty list of results
}
// intersection(s) should exist
var R2 = RR;
var R4 = R2R2;
var a = (r1r1 - r2r2) / (2 * R2);
var r2r2 = (r1r1 - r2r2);
var c = Math.sqrt(2 * (r1r1 + r2r2) / R2 - (r2r2 * r2r2) / R4 - 1);
var fx = (x1+x2) / 2 + a * (x2 - x1);
var gx = c * (y2 - y1) / 2;
var ix1 = fx + gx;
var ix2 = fx - gx;
var fy = (y1+y2) / 2 + a * (y2 - y1);
var gy = c * (x1 - x2) / 2;
var iy1 = fy + gy;
var iy2 = fy - gy;
centeredCircle(ix1, iy1, 2, 360); // highlight intersection point 1
centeredCircle(ix2, iy2, 2, 360); // highlight intersection point 1
// note if gy == 0 and gx == 0 then the circles are tangent and there is only one solution
// but that one solution will just be duplicated as the code is currently written
return [ix1, iy1, ix2, iy2];
}
// thanks to Reinder for this function
// Draws a circle centered a specific x,y location
// and returns the turtle to the original angle after it completes the circle.
function centeredCircle(x,y, radius, ext) {
turtle.penup();
turtle.goto(x,y);
turtle.backward(radius);
turtle.left(90);
turtle.pendown(); turtle.circle(radius, ext);
turtle.right(90); turtle.penup(); turtle.forward(radius); turtle.pendown();
}