# Source code for plugins.turtle

#
##
##  This file is part of pyFormex 1.0.7  (Mon Jun 17 12:20:39 CEST 2019)
##  pyFormex is a tool for generating, manipulating and transforming 3D
##  geometrical models by sequences of mathematical operations.
##  Project page:  http://savannah.nongnu.org/projects/pyformex/
##  Copyright 2004-2019 (C) Benedict Verhegghe (benedict.verhegghe@ugent.be)
##
##  This program is free software: you can redistribute it and/or modify
##  the Free Software Foundation, either version 3 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program.  If not, see http://www.gnu.org/licenses/.
##
"""Turtle graphics for pyFormex

This module was mainly aimed at the drawing of Lindenmayer products
(see :mod:`plugins.lima` and the Lima example).

The idea is that a turtle can be moved in 2D from one position to another,
thereby creating a line between start and endpoint or not.

The current state of the turtle is defined by

- ``pos``: the position as a 2D coordinate pair (x,y),
- ``angle``: the moving direction as an angle (in degrees) with the x-axis,
- ``step``: the speed, as a discrete step size.

The start conditions are: ``pos=(0,0), step=1., angle=0.``

The followin example turtle script creates a unit square::

fd();ro(90);fd();ro(90);fd();ro(90);fd()
"""
from __future__ import absolute_import, division, print_function

import math
deg = math.pi/180.

[docs]def sind(arg): """Return the sine of an angle in degrees.""" return math.sin(arg*deg)
[docs]def cosd(arg): """Return the cosine of an angle in degrees.""" return math.cos(arg*deg)
[docs]def reset(): """Reset the turtle graphics engine to start conditions. This resets the turtle's state to the starting conditions ``pos=(0,0), step=1., angle=0.``, removes everything from the state save stack and empties the resulting path. """ global pos, step, angle, list, save pos = [0., 0.] step = 1. angle = 0. list=[] save=[]
[docs]def push(): """Save the current state of the turtle. The turtle state includes its position, step and angle. """ global save save.append([pos, step, angle])
[docs]def pop(): """Restore the turtle state to the last saved state.""" global pos, step, angle, list, save pos, step, angle = save.pop(-1)
[docs]def fd(d=None, connect=True): """Move forward over a step `d`, with or without drawing. The direction is the current direction. If `d` is not given, the step size is the current step. By default, the new position is connected to the previous with a straight line segment. """ global pos, step, angle, list if d: step = d p = [pos[0] + step * cosd(angle), pos[1] + step * sind(angle)] if connect: list.append([pos, p]) pos = p
[docs]def mv(d=None): """Move over step `d` without drawing.""" fd(d, False)
[docs]def ro(a): """Rotate over angle `a`. The new direction is incremented with `a`""" global pos, step, angle, list angle += a
[docs]def go(p): """Go to position `p` (without drawing). While the `mv` method performs a relative move, this is an absolute move. `p` is a tuple of (x,y) values. """ global pos, step, angle, list pos = p
[docs]def st(d): """Set the step size.""" global pos, step, angle, list step = d
[docs]def an(a): """Set the angle""" global pos, step, angle, list angle = a
[docs]def play(scr, glob=None): """Play all the commands in the script `scr` The script is a string of turtle commands, where each command is ended with a semicolon (';'). If a dict `glob` is specified, it will be update with the turtle module's globals() after each turtle command. """ for line in scr.split(';'): if line: if glob: glob.update(globals()) eval(line, glob) else: eval(line) return list
reset() if __name__ == '__main__': def test(txt): l = play(txt) print("%s line segments" % len(l)) print(l) test("fd();ro(90);fd();ro(90);fd();ro(90);fd()") test("fd();ro(90);fd();ro(90);fd();ro(90);fd()") test("reset();fd();ro(90);fd();ro(90);fd();ro(90);fd()") # End