简体   繁体   English

如何使用python从3个点中找到一个椭圆方程

[英]How to find the equation for an ellipse from 3 points using python

I am bulding a game and I need to creat a map for it. 我正在开发游戏,因此需要为其创建地图。 in order to do it i have to use two kinds of elipse: one that is found using 2 points and one that found using 3 points (and go through them). 为了做到这一点,我必须使用两种椭圆:一种是使用2点找到的,另一种是使用3点找到的(通过它们)。 I have found a way to find the equation with 2 points but now I have not found a way to do with 3 point. 我找到了一种方法来找到2点的方程,但现在我还没有找到一种方法来解决3点。 So I am looking to find the equation for an ellipse given 3 point. 因此,我正在寻找给定3点的椭圆方程。 that is how i have done 2 points (it is not elegant but it does the job great): 这就是我完成2分的方式(虽然不雅致,但效果很好):

import turtle
import sympy as sp
import random
SCREEN = turtle.Screen()
t = turtle.Turtle()
t.up()
t.ht()
t.speed(0)
tt = turtle.Turtle()
tt.up()
tt.ht()
tt.speed(0)
press = 1
def get_mouse_click_coor(x, y):
    turtle.onscreenclick(None)
    print(x, y)
    draw(x,y)

def draw(mou_x,mou_y):
    SCREEN.tracer(0)
    global press
    global x_press1, y_press1

    if press%2 != 0:
        t.goto(mou_x,mou_y)
        x_press1, y_press1 = mou_x, mou_y
        tt.color('blue')
        tt.goto(mou_x,mou_y)
        tt.dot(7)

    if press%2 == 0:
        if mou_x == x_press1 and mou_y == y_press1:
            press = press - 1
        else:
            tt.color('red')
            tt.goto(mou_x,mou_y)
            tt.dot(7)

            if mou_x > x_press1 and mou_y > y_press1:
                turn = 1
            if mou_x > x_press1 and mou_y < y_press1:
                turn = 2
            if mou_x < x_press1 and mou_y < y_press1:
                turn = 3
            if mou_x < x_press1 and mou_y > y_press1:
                turn = 4

      #   if turn <= 2:
            x0 = -mou_x+x_press1
            if turn >= 3:
                x0 = -x_press1+mou_x
            y0 = mou_y - y_press1

            for x in range(int(x0), 1, 1):
                y = y0 - y0*sp.root(1.0-(float((x-x0)**2)/(x0**2)),2)
                if turn >= 3:
                    x = -x
                t.goto(x+mou_x, y+y_press1)
                t.down()

    t.up()      
    press = press + 1
    SCREEN.tracer(1)

while True:
    t.color('black')
    turtle.onscreenclick(get_mouse_click_coor)

turtle.mainloop()

Sounds like a fun problem! 听起来是个有趣的问题! If your 3 click points are in the same quadrant then one of the angles of the triangle defined by those points must be obtuse. 如果您的3个点击点在同一象限中,则这些点所定义的三角形角度之一必须是钝角。 Call that B and the other two vertices A and C. The general equation for an xy oriented ellipse has 4 parameters in it. 称为B以及其他两个顶点A和C。面向xy的椭圆的一般方程式中有4个参数。 Substituting the x and y coordinates of A, B and C into the ellipse equation will give you three equations. 将A,B和C的x和y坐标代入椭圆方程,将得到三个方程。 You need to come up with a 4th. 您需要拿出第四名。 You have the freedom to pick that 4th point in some way that makes sense in the context of your game. 您可以根据自己的游戏环境自由选择第4点。 Here's a SymPy code snippet that assigns an x value to the center of the ellipse based on A, B and C and a parameter 'f'. 这是一个SymPy代码段,该代码段基于A,B和C以及参数“ f”将x值分配给椭圆的中心。

def e3(p1, p2, p3, f):
    t = Triangle(p1, p2, p3)
    a = t.angles
    for p in a:
        if a[p] > pi/2:
            break
    else:
        return
    while p != p2:
        p1, p2, p3 = p2, p3, p1
    pts = A, B, C = p1, p2, p3
    # perpendicular line to AB passing through A
    perp = Segment(A, B).perpendicular_line(A)
    # intersection between that and the perpendicular to that
    # which passes through C
    m = perp.perpendicular_line(C).intersection(perp)[0]
    delta = m - A
    c = A + delta*f
    x, y, h, r, y0 = symbols('x y h r y0', cls=Dummy)
    eq = Ellipse((c.x, y0), h, r).equation(x, y)
    s = solve([
        eq.xreplace(dict(zip((x, y), p))) for p in pts], dict=True)[0]
    return eq.subs(s)  # for desmos graphing: str(eq.subs(s)).replace('**','^').replace('_','')+'=0'

Some of the results for f = .125, .25, .5, 1, 2 are shown at desmos . f = .125,.25, .5、1、2的一些结果显示在desmos处 通过3点省略

You can see that they all go through the points that you gave as an example. 您可以看到它们都经历了您作为示例给出的要点。 The red circle provides an interesting point of reference. 红色圆圈提供了一个有趣的参考点。 You might want to pick an f so the resulting width of the ellipse is some fraction of the diameter of the circle that would have gone through the points. 您可能希望选择一个f,这样椭圆的结果宽度将是通过点的圆直径的一部分。

The points that the ellipses are going through do not lay in the same quadrant of each ellipse, however. 但是,椭圆经过的点并不位于每个椭圆的相同象限中。 To meet that criteria, you have to consider an "off axis" ellipse. 为了满足该条件,您必须考虑“离轴”椭圆。 It may also be helpful to use the equation of the arbitrary ellipse that I posted here to guide you in making a selection for variables to control when defining your ellipse. 使用我在此处发布的任意椭圆方程式也可能会有所帮助,以指导您选择定义椭圆时要控制的变量。

To make the equation as simple as possible to solve and deterministic, you can make make the axis go through the 2nd click point if that angle creates an acute angle else go through the 1st and 3rd point. 为了使方程式尽可能简单地求解和确定,可以使该轴经过第二点击点(如果该角度产生锐角),否则使其经过第一和第三点。 Here is code demonstrating that: 下面的代码演示了这一点:

def e3(A, B, C, n=7):
    '''Return centered at the midpoint of A and C with the axis going through B if the angle at B is acute, else going through A and C.
    '''
    from sympy import Line
    xc, yc = ctr = (A + C)/2
    AC = A.distance(C)
    smalls = True
    if AC >= B.distance(A) and AC >= B.distance(C):
        s = Line(A, C).slope
        M2 = ctr.distance(A)**2
        b = B
        if abs(s) <= 1:
            m2 = -M2*(s*(b.x - xc) - b.y + yc)**2/(
                -M2*(s**2 + 1) + (s*(b.y - yc) + b.x - xc)**2)
        else:
            s = 1/s
            m2 = M2*(s*(b.y - yc) - b.x + xc)**2/(
                M2*(s**2 + 1) - (s*(b.x - xc) + b.y - yc)**2)
            smalls = False
    else:
        s = Line(B, ctr).slope
        M2 = ctr.distance(B)**2
        p = A # or C
        if abs(s) <= 1:
            m2 = -M2*(s*(p.x - xc) - p.y + yc)**2/(
                -M2*(s**2 + 1) + (s*(p.y - yc) + p.x - xc)**2)
        else:
            s = 1/s
            m2 = M2*(s*(p.y - yc) - p.x + xc)**2/(
                M2*(s**2 + 1) - (s*(p.x - xc) + p.y - yc)**2)
            smalls = False
    if smalls:
        el = -1 + (-s*(x - xc) + y - yc)**2/(m2*(s**2 + 1)) + (
            s*(y - yc) + x - xc)**2/(M2*(s**2 + 1))
    else:
        el = (M2*(s**2 + 1)*(-m2*(s**2 + 1) + (s*(y - yc) - x + xc)**2
            ) + m2*(s**2 + 1)*(s*(x - xc) + y - yc)**2)/(
            M2*m2*(s**2 + 1)**2)
    return el.expand().n(n=n)

from sympy import Point
a,b,c = Point(7/5, 12/5), Point(3/2, 5/2), Point(19/10, 3/2)
e3(a,b,c)
e3(b,c,a)
e3(c,a,b)

Depending on the 2nd click point, then, you will get 1 or 3 ellipses: 然后,根据第二个点击点,您将获得1或3个椭圆:

基于第二点击点角度的椭圆

Not sure if I get your point as it is actually a math question. 不知道我是否明白你的意思,因为这实际上是一个数学问题。 For me it seems like your looking for something like a function that requires 3 input parameters to draw an ellipse. 对我来说,似乎您正在寻找类似需要3个输入参数绘制椭圆的函数。 This would be then following code, where width is the major axis and height the minor axis. 然后是下面的代码,其中宽度是长轴,高度是短轴。 xy is the center point of the ellipse. xy是椭圆的中心点。

 import matplotlib.pyplot as plt
 import numpy as np
 from matplotlib.patches import Ellipse

 # These are 3 xy points 
 xpoints=(1.5,1.4,1.9)
 ypoints=(2.5,2.4,1.5)

 # calculate the center 
 mean_x=np.mean(xpoints)
 mean_y=np.mean(ypoints)

 # set the size of the ellipse 
 w=np.max(xpoints)+0.1
 h=np.max(ypoints)+0.1

 # buid the ellipse around it
 ells = Ellipse((mean_x,mean_y), width=w, height=h,facecolor='None') 

 # plot it 
 fig = plt.figure(0)
 ax = fig.add_subplot(111, aspect='equal')
 ax.add_artist(ells)
 ax.scatter(xpoints,ypoints, color='r')

ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
plt.show()

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM