【问题标题】:Draw an arc between two points on a tkinter canvas在 tkinter 画布上的两点之间画一条弧线
【发布时间】:2016-08-25 19:14:02
【问题描述】:

我的问题很简单:我有两个椭圆,中心分别是 (x0, y0) 和 (x1, y1)。 如果我想在它们之间画一条线,我会做 create_line(x0, y0, x1, y1)。

但我想在它们之间画一条弧线。我在这里为数学而苦苦挣扎。情况如下:

  • 我有这两个中心:它们必须是椭圆的一部分
  • 有无数个椭圆经过这两点,但使用 tkinter,我们只能绘制水平椭圆。 (对吧?)

我需要:

  • 包含椭圆的矩形的左上角和右下角坐标
  • 弧的起始角度和范围

我也在想也许画一条弧线是错误的方法?我可以用一条线做一些等效的事情,为此我在该弧上指定了很多点(即使它不是实际的弧)

编辑回答盲人:

使用 tkinter,您可以像这样定义弧: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/create_oval.html 我们不定义椭圆本身,而只定义包含椭圆的矩形的左上角和右下角坐标。

这两个椭圆如何相互关联:它们没有关联。你只是在画布上的一个随机位置有两个椭圆,你想要它们之间的弧线。 我想要连接这些椭圆的两个中心的弧线。

最后,这是我想要的一个想法,以防两个椭圆具有相同的 y 坐标:

我想要的正是这个,对于任何职位。

还有 tkinter 代码:

import tkinter as tk

class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.canvas = tk.Canvas(width=400, height=400)
        self.canvas.pack(fill="both", expand=True)

        self._create_token((100, 100), "white")
        self._create_token((200, 100), "pink")

        self.canvas.create_arc(100, 100 + 10, 200, 100 - 10, extent=180, style=tk.ARC)

    def _create_token(self, coord, color):
        '''Create a token at the given coordinate in the given color'''
        (x,y) = coord
        self.canvas.create_oval(x-5, y-5, x+5, y+5, 
                                outline=color, fill=color, tags="token")

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

【问题讨论】:

  • 我开始研究解决方案,但未知数太多。我从来没有使用过 python,所以我不知道他们使用什么类型的椭圆/椭圆。也没有迹象表明这两个椭圆是如何相互关联的,以及您希望线/曲线/弧/连接物在哪里连接两者,答案的可能性太多了。您能否提供问题的草图,并详细说明您使用什么来定义这两个椭圆。
  • 我更新了帖子,希望现在更清楚
  • 当弧的起点和终点具有相同的 x(或 y)坐标时,您可以使用矩形,其中起点和终点是矩形相对边的中点,弧的范围 = 180。只需就像在您的示例代码中一样。当弧的起点和终点具有不同的 x 和 y 坐标时,您可以使用矩形,其中起点和终点是矩形相邻边的中点,弧的范围为 90。
  • 在我的示例代码中,我使用矩形的对角而不是对边的中点。话虽如此,我不明白您对不同 x/y 坐标的概括是如何工作的。可以发展一下吗?

标签: python canvas tkinter tkinter-canvas


【解决方案1】:

有一个start 选项用于创建弧线,它定义了在给定角度时从哪里开始绘制。使用这个和一些数学,您可以使用create_arc-方法为任何位置绘制弧线:

import Tkinter as tk


class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.canvas = tk.Canvas(width=400, height=400)
        self.canvas.pack(fill="both", expand=True)

        self._create_token((100, 100), "white")
        self._create_token((200, 300), "pink")
        self._create_arc((100,100), (200, 300))

    def _create_token(self, coord, color):
        '''Create a token at the given coordinate in the given color'''
        (x,y) = coord
        self.canvas.create_oval(x-5, y-5, x+5, y+5, 
                                outline=color, fill=color, tags="token")

    def _create_arc(self, p0, p1):
        extend_x = (self._distance(p0,p1) -(p1[0]-p0[0]))/2 # extend x boundary 
        extend_y = (self._distance(p0,p1) -(p1[1]-p0[1]))/2 # extend y boundary
        startAngle = math.atan2(p0[0] - p1[0], p0[1] - p1[1]) *180 / math.pi # calculate starting angle  
        self.canvas.create_arc(p0[0]-extend_x, p0[1]-extend_y , 
                               p1[0]+extend_x, p1[1]+extend_y, 
                               extent=180, start=90+startAngle, style=tk.ARC)

        '''use this rectangle for visualisation'''
        #self.canvas.create_rectangle(p0[0]-extend_x, p0[1]-extend_y, 
        #                                p1[0]+extend_x, p1[1]+extend_y)       

    def _distance(self, p0, p1):
        '''calculate distance between 2 points'''
        return sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)   

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

【讨论】:

  • 有没有一种简单的方法可以调整它以获得不同的角度?例如,一条非常接近直线的圆弧?如我所见,当角度太小时,用于定义椭圆的矩形的角恰好是两个椭圆的中心。
  • 实际上,我想我可以简单地在两个椭圆之间的直线的平分线上取一个点,然后计算那个新圆的角。
【解决方案2】:

实际上,我会回答我自己的问题,因为我找到了更好的方法。 VRage 的答案很好,但如果您希望弧线更靠近两点之间的线,则很难适应。 正确的做法是在线段的垂直平分线上使用带有第三个点的线,并结合“平滑”选项。

这是我想要的一个例子:

import tkinter as tk
import math

class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.canvas = tk.Canvas(width=400, height=400)
        self.canvas.pack(fill="both", expand=True)

    def _create_token(self, coord, color):
        '''Create a token at the given coordinate in the given color'''
        (x,y) = coord
        self.canvas.create_oval(x-5, y-5, x+5, y+5, 
                                outline=color, fill=color, tags="token")

    def create(self, xA, yA, xB, yB, d=10):
        self._create_token((xA, yA), "white")
        self._create_token((xB, yB), "pink")

        t = math.atan2(yB - yA, xB - xA)
        xC = (xA + xB)/2 + d * math.sin(t)
        yC = (yA + yB)/2 - d * math.cos(t)
        xD = (xA + xB)/2 - d * math.sin(t)
        yD = (yA + yB)/2 + d * math.cos(t)

        self.canvas.create_line((xA, yA), (xC, yC), (xB, yB), smooth=True)
        self.canvas.create_line((xA, yA), (xD, yD), (xB, yB), smooth=True, fill="red")

   if __name__ == "__main__":
        app = SampleApp()
        app.create(100, 100, 300, 250)
        app.mainloop()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-02
    • 1970-01-01
    • 1970-01-01
    • 2023-02-16
    • 2012-11-07
    • 1970-01-01
    相关资源
    最近更新 更多