-
-
Save jupdike/bfe5eb23d1c395d8a0a1a4ddd94882ac to your computer and use it in GitHub Desktop.
// 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]]; | |
} |
If someone need some dirty legal python expression (might also be legal in other languages) of all the intersection points, here is this (sorry):
ix1 = (-r1**2*x1 + r1**2*x2 + r2**2*x1 - r2**2*x2 + x1**3 - x1**2*x2 - x1*x2**2 + x1*y1**2 - 2*x1*y1*y2 + x1*y2**2 + x2**3 + x2*y1**2 - 2*x2*y1*y2 + x2*y2**2 + sqrt((-r1**2 + 2*r1*r2 - r2**2 + x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)*(r1**2 + 2*r1*r2 + r2**2 - x1**2 + 2*x1*x2 - x2**2 - y1**2 + 2*y1*y2 - y2**2))*(-y1 + y2))/(2*(x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)) ix2 = (-r1**2*x1 + r1**2*x2 + r2**2*x1 - r2**2*x2 + x1**3 - x1**2*x2 - x1*x2**2 + x1*y1**2 - 2*x1*y1*y2 + x1*y2**2 + x2**3 + x2*y1**2 - 2*x2*y1*y2 + x2*y2**2 + sqrt((-r1**2 + 2*r1*r2 - r2**2 + x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)*(r1**2 + 2*r1*r2 + r2**2 - x1**2 + 2*x1*x2 - x2**2 - y1**2 + 2*y1*y2 - y2**2))*(y1 - y2))/(2*(x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)) iy1 = (-r1**2 + r2**2 + y1**2 - y2**2 + (-x1 + (-r1**2*x1 + r1**2*x2 + r2**2*x1 - r2**2*x2 + x1**3 - x1**2*x2 - x1*x2**2 + x1*y1**2 - 2*x1*y1*y2 + x1*y2**2 + x2**3 + x2*y1**2 - 2*x2*y1*y2 + x2*y2**2 + sqrt((-r1**2 + 2*r1*r2 - r2**2 + x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)*(r1**2 + 2*r1*r2 + r2**2 - x1**2 + 2*x1*x2 - x2**2 - y1**2 + 2*y1*y2 - y2**2))*(-y1 + y2))/(2*(x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)))**2 - (-x2 + (-r1**2*x1 + r1**2*x2 + r2**2*x1 - r2**2*x2 + x1**3 - x1**2*x2 - x1*x2**2 + x1*y1**2 - 2*x1*y1*y2 + x1*y2**2 + x2**3 + x2*y1**2 - 2*x2*y1*y2 + x2*y2**2 + sqrt((-r1**2 + 2*r1*r2 - r2**2 + x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)*(r1**2 + 2*r1*r2 + r2**2 - x1**2 + 2*x1*x2 - x2**2 - y1**2 + 2*y1*y2 - y2**2))*(-y1 + y2))/(2*(x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)))**2)/(2*(y1 - y2)) iy2 = (-r1**2 + r2**2 + y1**2 - y2**2 + (-x1 + (-r1**2*x1 + r1**2*x2 + r2**2*x1 - r2**2*x2 + x1**3 - x1**2*x2 - x1*x2**2 + x1*y1**2 - 2*x1*y1*y2 + x1*y2**2 + x2**3 + x2*y1**2 - 2*x2*y1*y2 + x2*y2**2 + sqrt((-r1**2 + 2*r1*r2 - r2**2 + x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)*(r1**2 + 2*r1*r2 + r2**2 - x1**2 + 2*x1*x2 - x2**2 - y1**2 + 2*y1*y2 - y2**2))*(y1 - y2))/(2*(x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)))**2 - (-x2 + (-r1**2*x1 + r1**2*x2 + r2**2*x1 - r2**2*x2 + x1**3 - x1**2*x2 - x1*x2**2 + x1*y1**2 - 2*x1*y1*y2 + x1*y2**2 + x2**3 + x2*y1**2 - 2*x2*y1*y2 + x2*y2**2 + sqrt((-r1**2 + 2*r1*r2 - r2**2 + x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)*(r1**2 + 2*r1*r2 + r2**2 - x1**2 + 2*x1*x2 - x2**2 - y1**2 + 2*y1*y2 - y2**2))*(y1 - y2))/(2*(x1**2 - 2*x1*x2 + x2**2 + y1**2 - 2*y1*y2 + y2**2)))**2)/(2*(y1 - y2))
Thanks Juppy :-)
I had to convert this to VB.Net but worked sweet with only 1 minor tweak. for calculation of var c `
Private Function IntersectTwoCircles(x1%, y1%, r1%, x2%, y2%, r2%) As Integer() '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 Dim centerdx% = x1 - x2 Dim centerdy% = y1 - y2 Dim R = Math.Sqrt(centerdx * centerdx + centerdy * centerdy) If (Not (Math.Abs(r1 - r2) <= R) And (R <= r1 + r2)) Then ' no intersection Return Nothing ' empty list of results End If 'intersection(s) should exist Dim R_2 = R * R Dim R_4 = R_2 * R_2 Dim a = (r1 * r1 - r2 * r2) / (2 * R_2) Dim r2r2 = (r1 * r1 - r2 * r2) Dim c1 As Double = 2 * (r1 * r1 + r2 * r2) / R_2 ' As Double because default is Integer Dim c2 As Double = r2r2 'seperate c2 calculation avoids Integer overflow c2 = (c2 * c2) / R_4 'recycle c2 Dim c = Math.Sqrt(c1 - c2 - 1) Dim fx = (x1 + x2) / 2 + a * (x2 - x1) Dim gx = c * (y2 - y1) / 2 Dim ix1% = Int(fx + gx + 0.05) Dim ix2% = Int(fx - gx + 0.05) Dim fy = (y1 + y2) / 2 + a * (y2 - y1) Dim gy = c * (x1 - x2) / 2 Dim iy1% = Int(fy + gy + 0.05) Dim iy2% = Int(fy - gy + 0.05) '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} End Function
`
Godot script
func intersect_two_circles(x1: float, y1: float, r1: float, x2: float, y2: float, r2: float) -> Array:
var centerdx = x1 - x2
var centerdy = y1 - y2
var R = sqrt(centerdx * centerdx + centerdy * centerdy)
if not (abs(r1 - r2) <= R and R <= r1 + r2):
return [] # Tidak ada titik perpotongan
# Perhitungan titik potong
var R2 = R * R
var R4 = R2 * R2
var a = (r1 * r1 - r2 * r2) / (2 * R2)
var r2r2 = (r1 * r1 - r2 * r2)
var c = 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
# Mengembalikan titik-titik perpotongan
return [[ix1, iy1], [ix2, iy2]]
Python visual
import math
import matplotlib.pyplot as plt
def intersect_two_circles(x1, y1, r1, x2, y2, r2):
centerdx = x1 - x2
centerdy = y1 - y2
R = math.sqrt(centerdx2 + centerdy2)
if not (abs(r1 - r2) <= R <= r1 + r2):
return [] # Tidak ada titik perpotongan
R2 = R**2
R4 = R2**2
a = (r1**2 - r2**2) / (2 * R2)
r2r2 = (r1**2 - r2**2)
c = math.sqrt(2 * (r1**2 + r2**2) / R2 - (r2r2**2) / R4 - 1)
fx = (x1 + x2) / 2 + a * (x2 - x1)
gx = c * (y2 - y1) / 2
ix1, ix2 = fx + gx, fx - gx
fy = (y1 + y2) / 2 + a * (y2 - y1)
gy = c * (x1 - x2) / 2
iy1, iy2 = fy + gy, fy - gy
return [(ix1, iy1), (ix2, iy2)]
Contoh posisi dan radius lingkaran
x1, y1, r1 = 0, 0, 5
x2, y2, r2 = 4, 0, 3
Hitung titik potong
intersection_points = intersect_two_circles(x1, y1, r1, x2, y2, r2)
Visualisasi
fig, ax = plt.subplots()
circle1 = plt.Circle((x1, y1), r1, color='blue', fill=False)
circle2 = plt.Circle((x2, y2), r2, color='red', fill=False)
ax.add_patch(circle1)
ax.add_patch(circle2)
Plot titik potong
for (ix, iy) in intersection_points:
plt.plot(ix, iy, 'go', label=f'({ix:.2f}, {iy:.2f})')
Konfigurasi plot
plt.xlim(-10, 10)
plt.ylim(-10, 10)
plt.axhline(0, color='grey', linestyle='--')
plt.axvline(0, color='grey', linestyle='--')
plt.legend()
plt.gca().set_aspect('equal', adjustable='box')
plt.title('Intersection of Two Circles')
plt.show()
javascript, vercion basada en godot con vector
var Vector2 = function(x, y) {
this.x = x || 0;
this.y = y || 0;
}
function puntoMedio(v1,v2){
return new Vector2(v1.x+v2.x/2,v1.y+v2.y/2)
}
function V2Rest(v1,v2){
return new Vector2(v1.x-v2.x,v1.y-v2.y);
}
function V2By(v1,v2){
return new Vector2(v1.x*v2.x,v1.y*v2.y);
}
function V2Plus(v1,v2){
return new Vector2(v1.x+v2.x,v1.y+v2.y);
}
function V2ByOne(v1,oneNumber){
return new Vector2(v1.x*oneNumber,v1.y*oneNumber);
}
function V2DivOne(v1,oneNumber){
oneNumber = parseFloat(oneNumber);
return new Vector2(v1.x/oneNumber,v1.y/oneNumber);
}
function V2PlusOne(v1,oneNumber){
return new Vector2(v1.x+oneNumber,v1.y+oneNumber);
}
function distancia2D(Vector_a,Vector_b){
if (Vector_a.x-Vector_b.x==0){
return Math.abs(Vector_a.y-Vector_b.y) ;
}
if (Vector_a.y-Vector_b.y==0){
return Math.abs(Vector_a.x-Vector_b.x) ;
}
return teoremaPitagoras_C(Math.abs(Vector_a.x-Vector_b.x),(Vector_a.y-Vector_b.y));
}
function teoremaPitagoras_C(a,b){
return Math.sqrt (Math.pow(a,2.00)+Math.pow(b,2.00));
}
function orthogonal(vector_2){
return new Vector2(vector_2.y,vector_2.x*-1);
}
function circle_intersect_cirle(Vector_a,r1,Vector_b,r2){
var d=distancia2D(Vector_a,Vector_b);
if (d==0){
return [new Vector2(0.00,0.00),new Vector2(0.00,0.00)];
}
var ab = V2Rest(Vector_b,Vector_a);
var r1n2=Math.pow((r1/d),2);
var r2n2=Math.pow((r2/d),2);
var rx=(r1n2-r2n2+1)/2.0;
var c=V2Plus(V2ByOne(ab,rx),Vector_a);
var h2=r1n2-Math.pow(rx,2);
if (h2<0){
return [new Vector2(0.00,0.00),new Vector2(0.00,0.00)];
}
var h=Math.sqrt(h2)*d;
var perp=V2ByOne(V2DivOne(orthogonal(ab),d),h);
return [new Vector2(V2Plus(perp,c)),new Vector2(V2Plus(V2ByOne(perp,-1),c))];
}
A simple TypeScript adaptation: