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

问题描述 投票:0回答:2

我正在建造一个游戏,我需要为它创建一个地图。为了做到这一点,我必须使用两种椭圆:一种是使用2点找到的,一种是使用3点找到的(并通过它们)。我找到了一种方法来找到2分的方程,但现在我还没有找到一个方法来处理3分。所以我希望找到给出3点椭圆的方程。这就是我如何做到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()
python python-2.7 numpy sympy turtle-graphics
2个回答
4
投票

听起来很有趣!如果您的3个点击点位于同一象限中,则由这些点定义的三角形的一个角度必须是钝角。调用B和其他两个顶点A和C. x-y定向椭圆的一般方程中有4个参数。将A,B和C的x和y坐标代入椭圆方程将给出三个方程。你需要拿出第4个。您可以自由选择在游戏环境中有意义的第四点。这是一个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'

f = .125,.25,.5,1,2的一些结果显示在desmosellipses through 3 points

您可以看到他们都通过您提供的要点作为示例。红色圆圈提供了一个有趣的参考点。您可能想要选择一个f,因此椭圆的最终宽度是圆的直径的一小部分,它将通过这些点。

然而,椭圆经过的点不在每个椭圆的相同象限中。要满足该标准,您必须考虑“离轴”椭圆。使用here发布的任意椭圆方程可能也会有所帮助,以指导您在定义椭圆时选择要控制的变量。

为了使方程尽可能简单地求解和确定,如果该角度产生锐角,则可以使轴穿过第二个点击点,否则通过第1和第3点。这是代码证明:

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)

根据第二个单击点,您将获得1或3个省略号:

ellipse based on angle at 2nd click point


1
投票

不确定我是否得到你的观点,因为它实际上是一个数学问题。对我来说,似乎你正在寻找类似于需要3个输入参数来绘制椭圆的函数。接下来是代码,其中width是长轴,高度是短轴。 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()

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.