Paul Wicks
Paul Wicks

Reputation: 65610

Given 2 points on a circle and the angle between, how to find the center (in python)?

I have 2 points on a circle and the angle between them and I would like to find the center of the circle that is thus defined (well, both centers preferably). enter image description here

def find_center(p1,p2,angle):
  # magic happens... What to do here?
  return (center_x, center_y)

Upvotes: -2

Views: 5251

Answers (6)

Daniel H.
Daniel H.

Reputation: 1

@Dhara's answer needs to divide the angle by two as @Panos pointed out. Unfortunately, I couldn't post a comment due to my low reputation. Here is the code (also adapted to use matplotlib and numpy). There are two possible centers, the other one can be obtained by providing the negative value of the angle as an argument.

import matplotlib.pyplot as plt
import numpy as np

def find_center(p1, p2, angle):

    angle = angle/2
    # End points of the chord
    x1, y1 = p1 
    x2, y2 = p2 

    # Slope of the line through the chord
    slope = (y1-y2)/(x1-x2)

    # Slope of a line perpendicular to the chord
    new_slope = -1/slope

    # Point on the line perpendicular to the chord
    # Note that this line also passes through the center of the circle
    xm, ym = (x1+x2)/2, (y1+y2)/2

    # Distance between p1 and p2
    d_chord = ((x1-x2)**2 + (y1-y2)**2)**0.5

    # Distance between xm, ym and center of the circle (xc, yc)
    d_perp = d_chord/(2*np.tan(angle))

    # Equation of line perpendicular to the chord: y-ym = new_slope(x-xm)
    # Distance between xm,ym and xc, yc: (yc-ym)^2 + (xc-xm)^2 = d_perp^2
    # Substituting from 1st to 2nd equation for y,
    #   we get: (new_slope^2+1)(xc-xm)^2 = d^2

    # Solve for xc:
    xc = (d_perp)/(new_slope**2+1)**0.5 + xm

    # Solve for yc:
    yc = (new_slope)*(xc-xm) + ym

    return xc, yc


def find_two_centers(p1, p2, angle):

    return find_center(p1, p2, angle), find_center(p1, p2, -angle)


plt.figure()

p1 = [1., 2.]
p2 = [-3, 4.]
angle = np.pi/2
xc, yc = find_center(p1, p2, angle)
# Calculate the radius and draw a circle
r = ((xc-p1[0])**2 + (yc-p1[1])**2)**0.5
cir = plt.Circle((xc,yc), radius=r,  fc='y')
plt.gca().add_patch(cir)

# mark p1 and p2 and the center of the circle
plt.plot(p1[0], p1[1], 'ro')
plt.plot(p2[0], p2[1], 'ro')
plt.plot(xc, yc, 'go')

plt.axis('equal')

xc, yc = find_center(p1, p2, -angle)
# Calculate the radius and draw a circle
r = ((xc-p1[0])**2 + (yc-p1[1])**2)**0.5
cir = plt.Circle((xc,yc), radius=r,  fc='y')
plt.gca().add_patch(cir)

# mark p1 and p2 and the center of the circle
plt.plot(p1[0], p1[1], 'ro')
plt.plot(p2[0], p2[1], 'ro')
plt.plot(xc, yc, 'go')

plt.axis('equal')

plt.show()

Upvotes: 0

Panos
Panos

Reputation: 1

Only it seems like it should be: d_perp = d_chord/(2*tan(angle/2)).

# Distance between xm, ym and center of the circle (xc, yc)
d_perp = d_chord/(2*tan(angle))

Upvotes: 0

Dhara
Dhara

Reputation: 6767

Here is my solution with the test code

from pylab import *
from numpy import *

def find_center(p1, p2, angle):
    # End points of the chord
    x1, y1 = p1 
    x2, y2 = p2 

    # Slope of the line through the chord
    slope = (y1-y2)/(x1-x2)

    # Slope of a line perpendicular to the chord
    new_slope = -1/slope

    # Point on the line perpendicular to the chord
    # Note that this line also passes through the center of the circle
    xm, ym = (x1+x2)/2, (y1+y2)/2

    # Distance between p1 and p2
    d_chord = sqrt((x1-x2)**2 + (y1-y2)**2)

    # Distance between xm, ym and center of the circle (xc, yc)
    d_perp = d_chord/(2*tan(angle))

    # Equation of line perpendicular to the chord: y-ym = new_slope(x-xm)
    # Distance between xm,ym and xc, yc: (yc-ym)^2 + (xc-xm)^2 = d_perp^2
    # Substituting from 1st to 2nd equation for y,
    #   we get: (new_slope^2+1)(xc-xm)^2 = d^2

    # Solve for xc:
    xc = (d_perp)/sqrt(new_slope**2+1) + xm

    # Solve for yc:
    yc = (new_slope)*(xc-xm) + ym

    return xc, yc

if __name__=='__main__':
    p1 = [1., 2.]
    p2 = [-3, 4.]
    angle = pi/6
    xc, yc = find_center(p1, p2,angle)

    # Calculate the radius and draw a circle
    r = sqrt((xc-p1[0])**2 + (yc-p1[1])**2)
    cir = Circle((xc,yc), radius=r,  fc='y')
    gca().add_patch(cir)

    # mark p1 and p2 and the center of the circle
    plot(p1[0], p1[1], 'ro')
    plot(p2[0], p2[1], 'ro')
    plot(xc, yc, 'go')

    show()

Upvotes: 6

Mike McP
Mike McP

Reputation: 21

# Solve for xc:
xc = (d_perp)/sqrt(new_slope**2+1) +xm # looks like +xm got omitted!)

# Solve for yc:
yc = (new_slope)*(xc-xm)+ym

you also need to check for x1=x2

# Slope of the line through the chord
if x1==x2
    slope = 999999
else
    slope = (y1-y2)/(x1-x2)

Upvotes: 2

Erwin J.
Erwin J.

Reputation: 617

you have to solve the triangle p1 p2 c. You have one angle. The other two angles are (180-angle)/2 Calculate side p1 p2 (distance) Then calculate the side p1 c this gives you the radius r of the circle. The solutions are the two points that are the intersection of the circles with center p1 and center p2 and radius r.

Upvotes: 1

Nathaniel Ford
Nathaniel Ford

Reputation: 21249

I'm really rusty on this stuff, so this might be a bit off, but it should get you started. Also, I don't know python, so this is just the pseudocode:

//check to ensure...
  //The two points aren't the same
  //The angle isn't zero
  //Other edge cases

//Get the distance between the points
x_dist = x2 - x1;
y_dist = y2 - y1;

//Find the length of the 'opposite' side of the right triangle
dist_opp = (sqrt((x_dist)^2 + (y_dist)^2)));
x_midpoint = (x1 - (x_dist / 2);
y_midpoint = (y1 - (y_dist / 2);
theta = the_angle / 2; //the right triangle's angle is half the starting angle
dist_adj = cotangent(theta) * dist_opp;//find the right triangle's length

epsilon = sqrt((-y_dist)^2 + x_dist^2);
segments = epsilon / dist_adj;

x_center = x_midpoint + (x_dist * segments);
y_center = y_midpoint + (y_dist * segments);

Upvotes: 1

Related Questions