在Python的乌龟中控制形状重叠?

时间:2016-05-31 21:16:30

标签: python python-3.x turtle-graphics

我正在编写一个程序,它接受用户输入(1)要绘制的形状的边数,(2)绘制它的大小,(3)绘制的数量,以及(4)多少种颜色使用。然后乌龟将许多围绕圆圈形状的空间隔开,所有这些都在圆圈的中心共享一个顶点。

困扰我的是,如果形状在最后重叠,最后的形状将在所有东西之上,而我希望它们像其他形状一样藏在它们前面的形状后面。

我设法确定错误重叠的形状数量取决于形状的边数 - 例如,对于三角形,与1-6个形状没有重叠。对于7-12,一个形状重叠不正确。对于13-18,两个形状重叠不正确。等等。

到目前为止,我已经为它写了第一组和最后一组形状作为他们自己的东西,poly1和poly2,并开始我至少希望能够告诉它在poly1后面绘制poly2。

主要的事情:龟甚至可能吗?然后,如果是这样,我该怎么办呢? (使用3.5)

编辑:我认为这可能是不可能的。我听到的一切都是乌龟只能在现有的形状上绘制。但也有人建议我加一个截图,以防它增加清晰度;这里是乌龟绘制的图像(当被告知用3种不同颜色绘制9个三角形时)。

enter image description here

我的目标是在十二点钟的时候把那个完整的三角形藏在一个三角形下面,但仍然在它之前,就像它最初绘制的那样。

1 个答案:

答案 0 :(得分:1)

  

我认为这可能是不可能的。

你低估了海龟的意外情况。这是我的初始示例,展示了您希望修复的非对称问题:

import math
from itertools import cycle
from turtle import Turtle, Screen

COLORS = cycle(['red', 'green', 'blue', 'yellow'])

def rotate_polygon(polygon, angle):

    theta = math.radians(angle)
    sin, cos = math.sin(theta), math.cos(theta)

    return [(x * cos - y * sin, x * sin + y * cos) for x, y in polygon]

def fill_polygon(turtle, polygon, color):

    turtle.color(color)

    for vertex in polygon:
        turtle.goto(vertex)

        if not turtle.filling():
            turtle.begin_fill()

    turtle.end_fill()

# triangle cursor 5x in size and X translated 50 pixels
polygon = ((100, -28.85), (50, 57.75), (0, -28.85))

screen = Screen()

yertle = Turtle(visible=False)
yertle.penup()

for angle in range(0, 360, 30):
    rotated_polygon = rotate_polygon(polygon, angle)
    color = next(COLORS)
    fill_polygon(yertle, rotated_polygon, color)

screen.exitonclick()

<强>输出

enter image description here

我们真的希望最后的黄色三角形整齐地隐藏在最初的红色三角形之下,就像一个不断上升的埃舍尔楼梯。我选择了这个插图,因为它有多个重叠,理论上最后的黄色三角形不仅应该是红色的下面,而是红色后面的绿色和蓝色。同样地,最终黄色之前的蓝色和绿色应该是红色的。等

enter image description here

上面的代码比绘制这个特定插图所需的更复杂,但需要额外的结构来支持以下增强:

一种方法是计算交点,而不是绘制最新三角形的那一部分。另一种方法是绘制新的三角形,但在应该重叠的三角交叉处重新着色。后面的方法是我在下面实现的,使用现有的Python函数通过Sutherland-Hodgman多边形裁剪算法获得交集:

import math
from itertools import cycle
from turtle import Turtle, Screen

COLORS = cycle(['red', 'green', 'blue', 'yellow'])

def clip(subjectPolygon, clipPolygon):

    # obtain this code from:
    # https://rosettacode.org/wiki/Sutherland-Hodgman_polygon_clipping#Python

    return outputList

def rotate_polygon(polygon, angle):

    theta = math.radians(angle)
    sin, cos = math.sin(theta), math.cos(theta)

    return [(x * cos - y * sin, x * sin + y * cos) for x, y in polygon]

def fill_polygon(turtle, polygon, color):

    turtle.color(color)

    for vertex in polygon:
        turtle.goto(vertex)

        if not turtle.filling():
            turtle.begin_fill()

    turtle.end_fill()

# triangle cursor 5x in size and X translated 50 pixels
polygon = ((100, -28.85), (50, 57.75), (0, -28.85))

screen = Screen()

yertle = Turtle(visible=False)
yertle.speed('slowest')  # slowly so we can see redrawing
yertle.penup()

polygons = []
POLYGON, COLOR = 0, 1

for angle in range(0, 360, 30):
    rotated_polygon = rotate_polygon(polygon, angle)
    color = next(COLORS)
    fill_polygon(yertle, rotated_polygon, color)
    polygons.append((rotated_polygon, color))

    # The -3 here is empirical and really should be calculated, an exercise for the reader
    for forward, backward in enumerate(range(-3, 1 - len(polygons), -1)):
        if polygons[forward] != polygons[backward]:
            try:
                intersection_polygon = clip(rotated_polygon, polygons[forward][POLYGON])
            except (IndexError, ZeroDivisionError):
                break  # because clip() can throw an error when no intersection

            if intersection_polygon:
                fill_polygon(yertle, intersection_polygon, polygons[forward][COLOR])
            else:
                break  # if no intersection, don't look any further
        else:
            break  # avoid testing against polygons clockwise from this one (needs work)

screen.exitonclick()

输出

enter image description here