|
|
@@ -1,20 +1,27 @@ |
|
|
|
#!/usr/bin/env python3 |
|
|
|
"""svgturtle - simple library to generate SVG paths from turtle graphics style commands""" |
|
|
|
|
|
|
|
import math |
|
|
|
import sys |
|
|
|
|
|
|
|
class SvgTurtle(): |
|
|
|
def __init__(self, homex=0, homey=0): |
|
|
|
"""Create a new turtle at the given home location, facing right""" |
|
|
|
self.homex = homex |
|
|
|
self.homey = homey |
|
|
|
self.cvtangle = math.tau/360 |
|
|
|
self.reset() |
|
|
|
|
|
|
|
def penup(self): |
|
|
|
"""Subsequent movements will be invisible and only affect location and heading""" |
|
|
|
self.pen = False |
|
|
|
|
|
|
|
def pendown(self): |
|
|
|
"""Subsequent movements will be visible and drawn""" |
|
|
|
self.pen = True |
|
|
|
|
|
|
|
def forward(self, distance): |
|
|
|
"""Move forward""" |
|
|
|
if self.pen and (self.path == ''): |
|
|
|
self.path = "M %.2f,%.2f" % (self.x,self.y) |
|
|
|
dx = distance*math.cos(self.heading) |
|
|
@@ -32,15 +39,22 @@ class SvgTurtle(): |
|
|
|
self.path += " m %.2f, %.2f" % (dx, dy) |
|
|
|
|
|
|
|
def back(self, distance): |
|
|
|
"""Move backward""" |
|
|
|
self.forward(-distance) |
|
|
|
|
|
|
|
def left(self, angle): |
|
|
|
"""Turn left by angle specified in degrees""" |
|
|
|
self.right(-angle) |
|
|
|
|
|
|
|
def right(self, angle): |
|
|
|
"""Turn right by angle specified in degrees""" |
|
|
|
self.heading = (self.heading + angle*self.cvtangle) % math.tau |
|
|
|
|
|
|
|
def circle(self, radius, extent=360, steps=None): |
|
|
|
"""Draw a circle or arc spanning extent degrees around a center |
|
|
|
radius units to the left (if radius is positive) or right |
|
|
|
(if radius is negative). Use a polygon if steps is specified, |
|
|
|
otherwise a circle.""" |
|
|
|
if steps: |
|
|
|
w = 1.0*extent/steps |
|
|
|
w2 = 0.5*w |
|
|
@@ -76,9 +90,11 @@ class SvgTurtle(): |
|
|
|
|
|
|
|
|
|
|
|
def to_s(self): |
|
|
|
"""Return the generated path, suitable for the d attribute of an SVG <path> element""" |
|
|
|
return self.path |
|
|
|
|
|
|
|
def home(self): |
|
|
|
"""Reset to the initial position and heading""" |
|
|
|
self.x = self.homex |
|
|
|
self.y = self.homey |
|
|
|
self.heading = 0 |
|
|
@@ -86,6 +102,30 @@ class SvgTurtle(): |
|
|
|
self.path += " M %.2f, %.2f" % (self.x, self.y) |
|
|
|
|
|
|
|
def reset(self): |
|
|
|
"""Clear the path and return home""" |
|
|
|
self.path = '' |
|
|
|
self.pen = True |
|
|
|
self.home() |
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
turtle = SvgTurtle(50, 100) |
|
|
|
turtle.left(90) |
|
|
|
turtle.forward(50) |
|
|
|
turtle.left(30) |
|
|
|
turtle.forward(50) |
|
|
|
turtle.penup() |
|
|
|
turtle.back(50) |
|
|
|
turtle.right(60) |
|
|
|
turtle.pendown() |
|
|
|
turtle.forward(50) |
|
|
|
turtle.penup() |
|
|
|
turtle.back(50) |
|
|
|
turtle.left(30) |
|
|
|
turtle.back(50) |
|
|
|
turtle.right(90) |
|
|
|
turtle.forward(70) |
|
|
|
turtle.pendown() |
|
|
|
turtle.circle(25) |
|
|
|
print('<svg viewBox="0 0 170 110" xmlns="http://www.w3.org/2000/svg">') |
|
|
|
print('<path fill="none" stroke="blue" d="%s"/>' % turtle.to_s()) |
|
|
|
print('</svg>') |