Search code examples
pythonellipse

Ellipse construction


I would like to construct an ellipse given the major/minor axes (or radii) and two points. I would like the line between the two points to be on the major axis. This just means that I would like the two points to lie on the major axis, and then construct the ellipse around the major axis. I originally constructed the ellipse at the origin and attempted to rotate and translate the ellipse, which didn't work. The unfinished code I have is listed below. How can I go about constructing an ellipse in this manner? Ideally, this would just return a list. Any insights would be greatly appreciated, and if you have any code for this please feel free to share.

import numpy
import matplotlib.pyplot as plt
import random

import math
from math import sin, cos
# Returns theta in [-pi/2, 3pi/2]
def generate_theta(a, b):
    u = random.random() / 4.0
    theta = numpy.arctan(b/a * numpy.tan(2*numpy.pi*u))

    v = random.random()
    if v < 0.25:
        return theta
    elif v < 0.5:
        return numpy.pi - theta
    elif v < 0.75:
        return numpy.pi + theta
    else:
        return -theta

def radius(a, b, theta):
    return a * b / numpy.sqrt((b*numpy.cos(theta))**2 + (a*numpy.sin(theta))**2)


def random_point(a, b, third_point, center=(0, 0)):
    angle = None
    if a > b:
        random_theta = generate_theta(a, b)
        max_radius = radius(a, b, random_theta)
        random_radius = max_radius * numpy.sqrt(random.random())
        f = round(random_radius * numpy.cos(random_theta))
        s = round(random_radius * numpy.sin(random_theta))
        angle = math.atan2(third_point[1], third_point[0]) - math.atan2(center[1], center[0])
    
    
    else:
        random_theta = generate_theta(b, a)
        max_radius = radius(b, a, random_theta)
        random_radius = max_radius * numpy.sqrt(random.random())
        f = round(random_radius * numpy.cos(random_theta))
        s = round(random_radius * numpy.sin(random_theta))
        
        angle = math.atan2(third_point[1], third_point[0]) - math.atan2(center[1], center[0])

        
    lio = rotate(center, (f, s), angle)
    lio = (int(lio[0]), int(lio[1]))
    return numpy.array([third, ward])



def rotate(origin, point, angle):
        #Rotate a point counterclockwise by a given angle around a given origin.
        #The angle should be given in radians.
        x = origin[0] + cos(angle) * (point[0] - origin[0]) - sin(angle) * (point[1] - origin[1])
        y = origin[1] + sin(angle) * (point[0] - origin[0]) + cos(angle) * (point[1] - origin[1])
        return (x, y)

#height
a = 95
#length
b = 25
#rand_p = (-random.randint(300, 400), -random.randint(100, 300))
rand_p = (0, 0)
points = numpy.array([random_point(a, b, (100, 100), (-25, 0)) for _ in range(200)])
#rando = rotate((0, 0), right_most_point, angle)
iopoints = []
  #  t = x[0] - (int(centroid[0]) - 100)
  #  t2 = x[1] - (int(centroid[1]) - 100)
centroid = numpy.mean(points, axis=0)
print(centroid)


#plt.plot(rando[0], rando[1], 'ro')
plt.plot(rand_p[0], rand_p[1], 'ro')
plt.scatter(points[:,0], points[:,1])

plt.show()



Solution

  • class ELLIPSE:
        def __init__(self, a, b, num_points, start, end):
            self.a = a
            self.b = b
            self.num_points = num_points
            self.start = start
            self.end = end
            self.angle_gen = math.atan2(self.end[1]-self.start[1], self.end[0]-self.start[0])
        
        def generate_theta(self, a, b):
                u = random.random() / 4.0
                theta = np.arctan(self.b/self.a * np.tan(2*np.pi*u))
    
                v = random.random()
                if v < 0.25:
                    return theta
                elif v < 0.5:
                    return np.pi - theta
                elif v < 0.75:
                    return np.pi + theta
                else:
                    return -theta
    
        def radius(self, a, b, theta):
                return self.a * self.b / np.sqrt((b*np.cos(theta))**2 + (a*np.sin(theta))**2)
    
    
        def random_point(self, major_axis, minor_axis, center, qa):
                random_theta = self.generate_theta(self.a, self.b)
                max_radius = self.radius(self.a, self.b, random_theta)
                random_radius = max_radius * np.sqrt(random.random())
                f = round(random_radius * np.cos(random_theta))
                s = round(random_radius * np.sin(random_theta))
                lio = self.rotate((0, 0), (f, s), self.angle_gen)
                return (int(lio[0]+center[0]), int(lio[1]+center[1]))
    
    
        def rotate(self, origin, point, angle):
                """
                Rotate a point counterclockwise by a given angle around a given origin.
    
                The angle should be given in radians.
                """
                ox, oy = origin
                px, py = point
    
                qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy)
                qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy)
                return qx, qy
    
        def midpoint(self, p1, p2):
                return ((p1[0]+p2[0])/2, (p1[1]+p2[1])/2)
    
        def ret_list(self):
            points = [self.random_point(self.a, self.b, self.midpoint(self.start, self.end),  self.angle_gen) for _ in range(self.num_points)]
            return points