Skip to content

Instantly share code, notes, and snippets.

@jupdike
Last active October 17, 2024 13:10
Show Gist options
  • Save jupdike/bfe5eb23d1c395d8a0a1a4ddd94882ac to your computer and use it in GitHub Desktop.
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
// 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]];
}
@rupertrussell
Copy link

rupertrussell commented Jul 8, 2023

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 = R2
R2;
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();
}

@Abhirikshma
Copy link

Abhirikshma commented Aug 17, 2023

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

@MattFerraro
Copy link

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}]
}

@samestep
Copy link

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