Circle-circle intersection points

AlgorithmMathGeometryIntersection

Algorithm Problem Overview


How do I calculate the intersection points of two circles. I would expect there to be either two, one or no intersection points in all cases.

I have the x and y coordinates of the centre-point, and the radius for each circle.

An answer in python would be preferred, but any working algorithm would be acceptable.

Algorithm Solutions


Solution 1 - Algorithm

Intersection of two circles

Written by Paul Bourke

> The following note describes how to find the intersection point(s) > between two circles on a plane, the following notation is used. The > aim is to find the two points P3 = (x3, > y3) if they exist.

> > Intersection of 2 circles > >

First calculate the distance d between the center > of the circles. d = ||P1 - P0||.

    >
  • If d > r0 + r1 then there are no solutions, > the circles are separate.

  • If d < |r0 - > r1| then there are no solutions because one circle is > contained within the other.

  • If d = 0 and r0 = > r1 then the circles are coincident and there are an > infinite number of solutions.

> > Considering the two triangles P0P2P3 > and P1P2P3 we can write

> a2 + h2 = r02 and > b2 + h2 = r12
>

Using d = a + b we can solve for a,

a = > (r02 - r12 + > d2 ) / (2 d)

> >

It can be readily shown that this reduces to > r0 when the two circles touch at one point, ie: d = > r0 + r1

> >

Solve for h by substituting a into the first > equation, h2 = r02 - a2 >

> > So

P2 = P0 + a ( P1 - > P0 ) / d

And finally, P3 = > (x3,y3) in terms of P0 = > (x0,y0), P1 = > (x1,y1) and P2 = > (x2,y2), is

x3 = > x2 +- h ( y1 - y0 ) / d

> y3 = y2 -+ h ( x1 - x0 ) / > d

Source: http://paulbourke.net/geometry/circlesphere/

Solution 2 - Algorithm

Here is my C++ implementation based on Paul Bourke's article. It only works if there are two intersections, otherwise it probably returns NaN NAN NAN NAN.

class Point{
	public:
		float x, y;
		Point(float px, float py) {
			x = px;
			y = py;
		}
		Point sub(Point p2) {
			return Point(x - p2.x, y - p2.y);
		}
		Point add(Point p2) {
			return Point(x + p2.x, y + p2.y);
		}
		float distance(Point p2) {
			return sqrt((x - p2.x)*(x - p2.x) + (y - p2.y)*(y - p2.y));
		}
		Point normal() {
			float length = sqrt(x*x + y*y);
			return Point(x/length, y/length);
		}
		Point scale(float s) {
			return Point(x*s, y*s);
		}
};

class Circle {
	public:
		float x, y, r, left;
		Circle(float cx, float cy, float cr) {
			x = cx;
			y = cy;
			r = cr;
			left = x - r;
		}
		pair<Point, Point> intersections(Circle c) {
			Point P0(x, y);
			Point P1(c.x, c.y);
			float d, a, h;
			d = P0.distance(P1);
			a = (r*r - c.r*c.r + d*d)/(2*d);
			h = sqrt(r*r - a*a);
			Point P2 = P1.sub(P0).scale(a/d).add(P0);
			float x3, y3, x4, y4;
			x3 = P2.x + h*(P1.y - P0.y)/d;
			y3 = P2.y - h*(P1.x - P0.x)/d;
			x4 = P2.x - h*(P1.y - P0.y)/d;
			y4 = P2.y + h*(P1.x - P0.x)/d;
						
			return pair<Point, Point>(Point(x3, y3), Point(x4, y4));
		}
		
};

Solution 3 - Algorithm

Why not just use 7 lines of your favorite procedural language (or programmable calculator!) as below.

Assuming you are given P0 coords (x0,y0), P1 coords (x1,y1), r0 and r1 and you want to find P3 coords (x3,y3):

d=sqr((x1-x0)^2 + (y1-y0)^2)
a=(r0^2-r1^2+d^2)/(2*d)
h=sqr(r0^2-a^2)
x2=x0+a*(x1-x0)/d	
y2=y0+a*(y1-y0)/d	
x3=x2+h*(y1-y0)/d		// also x3=x2-h*(y1-y0)/d
y3=y2-h*(x1-x0)/d		// also y3=y2+h*(x1-x0)/d

Solution 4 - Algorithm

Here's an implementation in Javascript using vectors. The code is well documented, you should be able to follow it. Here's the original source

See live demo here: enter image description here

// Let EPS (epsilon) be a small value
var EPS = 0.0000001;

// Let a point be a pair: (x, y)
function Point(x, y) {
  this.x = x;
  this.y = y;
}

// Define a circle centered at (x,y) with radius r
function Circle(x,y,r) {
  this.x = x;
  this.y = y;
  this.r = r;
}

// Due to double rounding precision the value passed into the Math.acos
// function may be outside its domain of [-1, +1] which would return
// the value NaN which we do not want.
function acossafe(x) {
  if (x >= +1.0) return 0;
  if (x <= -1.0) return Math.PI;
  return Math.acos(x);
}

// Rotates a point about a fixed point at some angle 'a'
function rotatePoint(fp, pt, a) {
  var x = pt.x - fp.x;
  var y = pt.y - fp.y;
  var xRot = x * Math.cos(a) + y * Math.sin(a);
  var yRot = y * Math.cos(a) - x * Math.sin(a);
  return new Point(fp.x+xRot,fp.y+yRot);
}

// Given two circles this method finds the intersection
// point(s) of the two circles (if any exists)
function circleCircleIntersectionPoints(c1, c2) {
  
  var r, R, d, dx, dy, cx, cy, Cx, Cy;
  
  if (c1.r < c2.r) {
    r  = c1.r;  R = c2.r;
    cx = c1.x; cy = c1.y;
    Cx = c2.x; Cy = c2.y;
  } else {
    r  = c2.r; R  = c1.r;
    Cx = c1.x; Cy = c1.y;
    cx = c2.x; cy = c2.y;
  }
  
  // Compute the vector <dx, dy>
  dx = cx - Cx;
  dy = cy - Cy;

  // Find the distance between two points.
  d = Math.sqrt( dx*dx + dy*dy );
  
  // There are an infinite number of solutions
  // Seems appropriate to also return null
  if (d < EPS && Math.abs(R-r) < EPS) return [];
  
  // No intersection (circles centered at the 
  // same place with different size)
  else if (d < EPS) return [];
  
  var x = (dx / d) * R + Cx;
  var y = (dy / d) * R + Cy;
  var P = new Point(x, y);
  
  // Single intersection (kissing circles)
  if (Math.abs((R+r)-d) < EPS || Math.abs(R-(r+d)) < EPS) return [P];
  
  // No intersection. Either the small circle contained within 
  // big circle or circles are simply disjoint.
  if ( (d+r) < R || (R+r < d) ) return [];
  
  var C = new Point(Cx, Cy);
  var angle = acossafe((r*r-d*d-R*R)/(-2.0*d*R));
  var pt1 = rotatePoint(C, P, +angle);
  var pt2 = rotatePoint(C, P, -angle);
  return [pt1, pt2];
  
}

Solution 5 - Algorithm

Try this;

    def ri(cr1,cr2,cp1,cp2):
        int1=[]
        int2=[]
        ori=0
        if cp1[0]<cp2[0] and cp1[1]!=cp2[1]:
            p1=cp1
            p2=cp2
            r1=cr1
            r2=cr2
            if cp1[1]<cp2[1]:
                ori+=1
            elif cp1[1]>cp2[1]:
                ori+=2        
        elif cp1[0]>cp2[0] and cp1[1]!=cp2[1]:
            p1=cp2
            p2=cp1
            r1=cr2
            r2=cr1
            if p1[1]<p2[1]:
                ori+=1
            elif p1[1]>p2[1]:
                ori+=2
        elif cp1[0]==cp2[0]:
            ori+=4
            if cp1[1]>cp2[1]:
                p1=cp1
                p2=cp2
                r1=cr1
                r2=cr2
            elif cp1[1]<cp2[1]:
                p1=cp2
                p2=cp1
                r1=cr2
                r2=cr1
        elif cp1[1]==cp2[1]:
            ori+=3
            if cp1[0]>cp2[0]:
                p1=cp2
                p2=cp1
                r1=cr2
                r2=cr1
            elif cp1[0]<cp2[0]:
                p1=cp1
                p2=cp2
                r1=cr1
                r2=cr2
        if ori==1:#+
            D=calc_dist(p1,p2)
            tr=r1+r2
            el=tr-D
            a=r1-el
            b=r2-el
            A=a+(el/2)
            B=b+(el/2)
            thta=math.degrees(math.acos(A/r1))
            rs=p2[1]-p1[1]
            rn=p2[0]-p1[0]
            gd=rs/rn
            yint=p1[1]-((gd)*p1[0])
            dty=calc_dist(p1,[0,yint])

            aa=p1[1]-yint
            bb=math.degrees(math.asin(aa/dty))
            d=90-bb
            e=180-d-thta
            g=(dty/math.sin(math.radians(e)))*math.sin(math.radians(thta))
            f=(g/math.sin(math.radians(thta)))*math.sin(math.radians(d))
            oty=yint+g
            h=f+r1
            i=90-e
            j=180-90-i
            l=math.sin(math.radians(i))*h
            k=math.cos(math.radians(i))*h
            iy2=oty-l
            ix2=k
            int2.append(ix2)
            int2.append(iy2)

            m=90+bb
            n=180-m-thta
            p=(dty/math.sin(math.radians(n)))*math.sin(math.radians(m))
            o=(p/math.sin(math.radians(m)))*math.sin(math.radians(thta))
            q=p+r1
            r=90-n
            s=math.sin(math.radians(r))*q
            t=math.cos(math.radians(r))*q
            otty=yint-o
            iy1=otty+s
            ix1=t
            int1.append(ix1)
            int1.append(iy1)
        elif ori==2:#-
            D=calc_dist(p1,p2)
            tr=r1+r2
            el=tr-D
            a=r1-el
            b=r2-el
            A=a+(el/2)
            B=b+(el/2)
            thta=math.degrees(math.acos(A/r1))
            rs=p2[1]-p1[1]
            rn=p2[0]-p1[0]
            gd=rs/rn
            yint=p1[1]-((gd)*p1[0])
            dty=calc_dist(p1,[0,yint])

            aa=yint-p1[1]
            bb=math.degrees(math.asin(aa/dty))
            c=180-90-bb
            d=180-c-thta
            e=180-90-d
            f=math.tan(math.radians(e))*p1[0]
            g=math.sqrt(p1[0]**2+f**2)
            h=g+r1
            i=180-90-e
            j=math.sin(math.radians(e))*h
            jj=math.cos(math.radians(i))*h
            k=math.cos(math.radians(e))*h
            kk=math.sin(math.radians(i))*h
            l=90-bb
            m=90-e
            tt=l+m+thta
            n=(dty/math.sin(math.radians(m)))*math.sin(math.radians(thta))
            nn=(g/math.sin(math.radians(l)))*math.sin(math.radians(thta))
            oty=yint-n
            iy1=oty+j
            ix1=k
            int1.append(ix1)
            int1.append(iy1)

            o=bb+90
            p=180-o-thta
            q=90-p
            r=180-90-q
            s=(dty/math.sin(math.radians(p)))*math.sin(math.radians(o))
            t=(s/math.sin(math.radians(o)))*math.sin(math.radians(thta))
            u=s+r1
            v=math.sin(math.radians(r))*u
            vv=math.cos(math.radians(q))*u
            w=math.cos(math.radians(r))*u
            ww=math.sin(math.radians(q))*u
            ix2=v
            otty=yint+t
            iy2=otty-w
            int2.append(ix2)
            int2.append(iy2)

        elif ori==3:#y
            D=calc_dist(p1,p2)
            tr=r1+r2
            el=tr-D
            a=r1-el
            b=r2-el
            A=a+(el/2)
            B=b+(el/2)
            b=math.sqrt(r1**2-A**2)
            int1.append(p1[0]+A)
            int1.append(p1[1]+b)
            int2.append(p1[0]+A)
            int2.append(p1[1]-b)
        elif ori==4:#x
            D=calc_dist(p1,p2)
            tr=r1+r2
            el=tr-D
            a=r1-el
            b=r2-el
            A=a+(el/2)
            B=b+(el/2)
            b=math.sqrt(r1**2-A**2)
            int1.append(p1[0]+b)
            int1.append(p1[1]-A)
            int2.append(p1[0]-b)
            int2.append(p1[1]-A)
        return [int1,int2]
    def calc_dist(p1,p2):
        return math.sqrt((p2[0] - p1[0]) ** 2 +
                         (p2[1] - p1[1]) ** 2)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionfmarkView Question on Stackoverflow
Solution 1 - AlgorithmJacobView Answer on Stackoverflow
Solution 2 - Algorithmrobert kingView Answer on Stackoverflow
Solution 3 - AlgorithmCuriousMarcView Answer on Stackoverflow
Solution 4 - Algorithmwill.fisetView Answer on Stackoverflow
Solution 5 - Algorithmkulprit.001View Answer on Stackoverflow