python / python/cpython

Unnecessarily slow turtle rotations

Đang mở
#99,296 8 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

stdlib type-bug
Ngôn ngữ chính
Python
Star
77.2k
Fork
36k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

Bug report

Two similar drawings can widely differ in terms of speed, resulting in a counter-intuitive experience for the end-user. This is independent from the plateform (OS, architecture) and from python version (due to the current implementation of turtle).

Example

Consider the following script (which is a simplified version of a real demo program with animation turned on). it draws two 7-points stars. The first one is drawn normally but the second, while similar, is much slower. This is very confusing (also for the programmer trying to understand what happens).

import turtle
def star7(t, a, b, c):
    t.left(a)
    for i in range(7):
        t.forward(80)
        t.left(b)
        t.forward(80)
        t.left(c)
    t.left(-a)

t = turtle.Turtle()
t.hideturtle()
star7(t, 64.6, -77.7, 129.1)    # draw star 1 (normal speed)
star7(t, 295.4, -282.3, 590.9)  # draw star 2 (really too slow !)

Explanation

The problem comes from turtle rotation: in case of animation (by default speed > 0), the time taken by the rotation is proportional to the amplitude of the angle even if the turtle is not visible resulting in a confusing slow drawing. This can be confirmed with a visible turtle, commenting out:

# t.hideturtle()

Indeed, the second star7() invocation contains "large" angles (these values are actually computed, not written by a human). Obviously, it is possible to give smaller equal angles (here taking the opposite of angles of the first star), resulting in a fast drawing e.g.:

star7(t, -64.6, 77.7, -129.1)

Obviously, the programmer can normalize all rotation angles in case of animation but this is painfull and error-prone (the programmer can misses some). And above all, there is no justification for such delays if the turtle is not shown !

Looking at the code of function _rotate() in class RawTurtle (in turtle.py:3279):

    def _rotate(self, angle):
        """Turns pen clockwise by angle.
        """
        if self.undobuffer:
            self.undobuffer.push(("rot", angle, self._degreesPerAU))
        angle *= self._degreesPerAU                # angle is now in degrees
        neworient = self._orient.rotate(angle)
        tracing = self.screen._tracing
        if tracing == 1 and self._speed > 0:       # test: rotation animation ?
            anglevel = 3.0 * self._speed
            steps = 1 + int(abs(angle)/anglevel)   # animation: split into steps (proportionally to abs(angle))
            delta = 1.0*angle/steps
            for _ in range(steps):
                self._orient = self._orient.rotate(delta)
                self._update()
        self._orient = neworient
        self._update()

In case of animation (speed>0), the rotation is split in several steps, each invoking _update(), thus the delays.

Solutions

A first solution is to only do this if the turtle is visible. This can be achieved replacing the test by:

        if self._shown and tracing == 1 and self._speed > 0:

But maybe this results in a too fast drawing.

A second solution consists in normalizing the angle if the turtle is not visible. This can be achived with:

        if tracing == 1 and self._speed > 0:
            if not self._shown:
                angle -= math.ceil(angle / 360.0 - 0.5) * 360.0     # normalize angle in (-180;180]

This normalization ensures the angle (in degrees since the instruction angle *= self._degreesPerAU above) is now in (-180;180] and prevents too long delays. The result is nice. I'm in favor of this second solution.

What do you think ?

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu trong turtle.py tại RawTurtle._rotate(), sau đó chạy ví dụ star7 được cung cấp với animation được bật và turtle bị ẩn để tái hiện độ trễ không tương xứng. So sánh các trường hợp góc lớn và góc đã được chuẩn hóa; hoàn tất khi các phép xoay tương đương với turtle bị ẩn không còn tạo ra thời gian vẽ khác nhau một cách khó hiểu.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
computer-graphics
Loại issue
Lỗi
Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
45/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.