Unnecessarily slow turtle rotations
還沒有人認領這個 Issue。
- 主要語言
- Python
- 星號
- 77.2k
- 分支
- 36k
- PR 合併指標
- PR 指標待擷取
描述
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 ?
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
研究方向
從 turtle.py 中的 RawTurtle._rotate() 開始,然後在啟用動畫並隱藏 turtle 的情況下執行隨附的 star7 範例,以重現不成比例的延遲。比較大角度和正規化角度的情況;當隱藏 turtle 的等效旋轉不再產生令人困惑的不同繪製時間時,即表示完成。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- python
- 領域
- computer-graphics
- Issue 類型
- 缺陷
- 難度
- 2/5
- 預估耗時
- 1-3 小時
- 活躍度
- 停滯
- 描述清晰度
- 描述清楚
- 新手友好度
- 45/100