Drawing an ellipse at an angle between two points in Python
Question:
I’m trying to draw an ellipse between two points. So far, I have it mostly working:
The issue comes with setting the ellipse height (ellipse_h
below).
x = center_x + radius*np.cos(theta+deg)
y = center_y - ellipse_h * radius*np.sin(theta+deg)
In this example, it’s set to -0.5:
Can anyone please help me rotate the ellipse height with the ellipse? Thank you!
import numpy as np
import matplotlib.pyplot as plt
def distance(x1, y1, x2, y2):
return np.sqrt(np.power(x2 - x1, 2) + np.power(y2 - y1, 2) * 1.0)
def midpoint(x1, y1, x2, y2):
return [(x1 + x2) / 2,(y1 + y2) / 2]
def angle(x1, y1, x2, y2):
#radians
return np.arctan2(y2 - y1, x2 - x1)
x1 = 100
y1 = 150
x2 = 200
y2 = 190
ellipse_h = -1
x_coords = []
y_coords = []
mid = midpoint(x1, y1, x2, y2)
center_x = mid[0]
center_y = mid[1]
ellipse_resolution = 40
step = 2*np.pi/ellipse_resolution
radius = distance(x1, y1, x2, y2) * 0.5
deg = angle(x1, y1, x2, y2)
cos = np.cos(deg * np.pi /180)
sin = np.sin(deg * np.pi /180)
for theta in np.arange(0, np.pi+step, step):
x = center_x + radius*np.cos(theta+deg)
y = center_y - ellipse_h * radius*np.sin(theta+deg)
x_coords.append(x)
y_coords.append(y)
plt.xlabel("X")
plt.ylabel("Y")
plt.title("Arc between 2 Points")
plt.plot(x_coords,y_coords)
plt.scatter([x1,x2],[y1,y2])
plt.axis('equal')
plt.show()
Answers:
A simple solution is to describe the ellipse by its standard parametric equation, as you effectively did. However, under the assumption that it is centered on the origin of the coordinate system, it becomes straightforward to then apply a rotation to its points using a 2d rotation matrix and finally apply a translation to position it on its true center. This gives the following:
import numpy as np
import matplotlib.pyplot as plt
# extreme points along the major axis
x1, y1 = 100, 150
x2, y2 = 200, 190
# along minor axis
height = 15
# number of points
n = 100
# center
x_c, y_c = (x1 + x2)/2, (y1 + y2)/2
# width (major axis) and height (minor) of the ellipse halved
a, b = np.sqrt((x2 - x1)**2 + (y2 - y1)**2)/2, height/2
# rotation angle
angle = np.arctan2(y2 - y1, x2 - x1)
# standard parametric equation of an ellipse
t = np.linspace(0, 2*np.pi, n)
ellipse = np.array([a*np.cos(t), b*np.sin(t)])
# 2d rotation matrix
R = np.array([[np.cos(angle), -np.sin(angle)],
[np.sin(angle), np.cos(angle)]])
# apply the rotation to the ellipse
ellipse_rot = R @ ellipse
plt.plot(x_c + ellipse_rot[0], y_c + ellipse_rot[1], 'r' )
plt.scatter([x1, x2], [y1, y2], color='k')
plt.axis('equal')
plt.show()
See the output for different heights:
Following your comment, for the limiting case of the circle, you need to specify height = np.sqrt((x2 - x1)**2 + (y2 - y1)**2)
, so that a = b
.
Hope this helps !
I’m trying to draw an ellipse between two points. So far, I have it mostly working:
The issue comes with setting the ellipse height (ellipse_h
below).
x = center_x + radius*np.cos(theta+deg)
y = center_y - ellipse_h * radius*np.sin(theta+deg)
In this example, it’s set to -0.5:
Can anyone please help me rotate the ellipse height with the ellipse? Thank you!
import numpy as np
import matplotlib.pyplot as plt
def distance(x1, y1, x2, y2):
return np.sqrt(np.power(x2 - x1, 2) + np.power(y2 - y1, 2) * 1.0)
def midpoint(x1, y1, x2, y2):
return [(x1 + x2) / 2,(y1 + y2) / 2]
def angle(x1, y1, x2, y2):
#radians
return np.arctan2(y2 - y1, x2 - x1)
x1 = 100
y1 = 150
x2 = 200
y2 = 190
ellipse_h = -1
x_coords = []
y_coords = []
mid = midpoint(x1, y1, x2, y2)
center_x = mid[0]
center_y = mid[1]
ellipse_resolution = 40
step = 2*np.pi/ellipse_resolution
radius = distance(x1, y1, x2, y2) * 0.5
deg = angle(x1, y1, x2, y2)
cos = np.cos(deg * np.pi /180)
sin = np.sin(deg * np.pi /180)
for theta in np.arange(0, np.pi+step, step):
x = center_x + radius*np.cos(theta+deg)
y = center_y - ellipse_h * radius*np.sin(theta+deg)
x_coords.append(x)
y_coords.append(y)
plt.xlabel("X")
plt.ylabel("Y")
plt.title("Arc between 2 Points")
plt.plot(x_coords,y_coords)
plt.scatter([x1,x2],[y1,y2])
plt.axis('equal')
plt.show()
A simple solution is to describe the ellipse by its standard parametric equation, as you effectively did. However, under the assumption that it is centered on the origin of the coordinate system, it becomes straightforward to then apply a rotation to its points using a 2d rotation matrix and finally apply a translation to position it on its true center. This gives the following:
import numpy as np
import matplotlib.pyplot as plt
# extreme points along the major axis
x1, y1 = 100, 150
x2, y2 = 200, 190
# along minor axis
height = 15
# number of points
n = 100
# center
x_c, y_c = (x1 + x2)/2, (y1 + y2)/2
# width (major axis) and height (minor) of the ellipse halved
a, b = np.sqrt((x2 - x1)**2 + (y2 - y1)**2)/2, height/2
# rotation angle
angle = np.arctan2(y2 - y1, x2 - x1)
# standard parametric equation of an ellipse
t = np.linspace(0, 2*np.pi, n)
ellipse = np.array([a*np.cos(t), b*np.sin(t)])
# 2d rotation matrix
R = np.array([[np.cos(angle), -np.sin(angle)],
[np.sin(angle), np.cos(angle)]])
# apply the rotation to the ellipse
ellipse_rot = R @ ellipse
plt.plot(x_c + ellipse_rot[0], y_c + ellipse_rot[1], 'r' )
plt.scatter([x1, x2], [y1, y2], color='k')
plt.axis('equal')
plt.show()
See the output for different heights:
Following your comment, for the limiting case of the circle, you need to specify height = np.sqrt((x2 - x1)**2 + (y2 - y1)**2)
, so that a = b
.
Hope this helps !