#!/usr/bin/python # -*- coding: iso-8859-2 -*- ######################################################################## # Turtle drawer # # Copyright (C) 2006 Gergõ ÉRDI # http://cactus.rulez.org/ # # Published under the terms of the GNU General Public License 2.0 # $Id: turtle.py 188 2006-03-12 11:59:46Z cactus $ ######################################################################## import libxml2; ######################################################################## # Infrastructure ######################################################################## class Point: def __init__ (self, x, y): self.x = x self.y = y def __add__ (p1, p2): return Point(p1.x + p2.x, p1.y + p2.y) def __sub__ (p1, p2): return Point(p1.x - p2.x, p1.y - p2.y) def __div__ (p, q): return Point(p.x / q, p.y / q) def __mul__ (p, q): return Point(p.x * q, p.y * q) class Turtle: def __init__ (self): self.p = Point (0.0, 0.0) self.heading = Point (1.0, 0.0) class Canvas: def __init__ (self): self.turtle = Turtle() self.segments = [] def draw (self, path): map (lambda i: i(self), path); def draw_line (self, p1, p2): self.segments.append ((p1, p2)) def render_to_svg (self, svg_root, p0, size): svg = svg_root.newChild(None, "svg", None); ns = svg.newNs ("http://www.w3.org/2000/svg", None); svg.setNs(ns) for (p1, p2) in self.segments: p1_ = (p1 * size + p0) p2_ = (p2 * size + p0) line_node = svg.newChild(ns, "line", None) line_node.setProp("style", "stroke:rgb(99,99,99);stroke-width:2") line_node.setProp("x1", "%f" % p1_.x) line_node.setProp("y1", "%f" % p1_.y) line_node.setProp("x2", "%f" % p2_.x) line_node.setProp("y2", "%f" % p2_.y) def create_svg (filename, shrink, path): canvas = Canvas () canvas.draw (path) doc = libxml2.newDoc("1.0") canvas.render_to_svg (doc, Point(100.0, 100.0), 100.0 / shrink) doc.saveFile(filename) doc.freeDoc() ######################################################################## # Drawing alphabet ######################################################################## def f (canvas): canvas.turtle.p += canvas.turtle.heading def F (canvas): p1 = canvas.turtle.p f (canvas) p2 = canvas.turtle.p canvas.draw_line (p1, p2) def l (canvas): heading = canvas.turtle.heading; (heading.x, heading.y) = (-heading.y, heading.x) def r (canvas): heading = canvas.turtle.heading; (heading.x, heading.y) = (heading.y, -heading.x) ######################################################################## # Sequence transformation ######################################################################## def map_concat(func, l): ret = [] for i in l: ret += func(i) return ret def draw_iterate(l, func, factor, n): name = func.__name__ shrink = 1 create_svg("%s-0.svg" % name, shrink, l) for i in range(1, n + 1): shrink = shrink * factor l = map_concat (func, l) create_svg("%s-%d.svg" % (name, i), shrink, l) ######################################################################## # Test sequences ######################################################################## def Koch(): square = [F, l, F, l, F, l, F, l] def koch(x): if x == F: return [F, l, F, r, F, r, F, F, l, F, l, F, r, F] return [x] draw_iterate(square, koch, 4, 4) def Unnamed(): line = [F, F, F, F] def unnamed(x): if x == F: return [F, r, f, l, F, F, r, F, r, F, F, r, F, f, r, F, F, l, f, r, F, F, l, F, l, F, F, l, F, f, F, F, F] if x == f: return [f, f, f, f, f, f] return [x] draw_iterate(line, unnamed, 3, 2) Koch() #Unnamed()