Files
lindenmayer/lindenmayer/drawer.py
2022-01-05 23:15:12 +01:00

132 lines
3.8 KiB
Python

import turtle
from dataclasses import dataclass
import lSystems
@dataclass
class State:
heading: float
position: turtle.Vec2D
@dataclass
class DrawingInfo:
lSystem: lSystems.LSytem
position: turtle.Vec2D
rotation: float
color: any
scale: float
recursionDepth: int
@dataclass
class Drawing:
info: DrawingInfo
turtle: turtle.Turtle
drawings = []
class Drawer():
def __init__(self, drawing):
self.startWord = drawing.info.lSystem.startWord
self.recursionDepth = drawing.info.recursionDepth
self.productionRules = drawing.info.lSystem.productionRules
self.angel = drawing.info.lSystem.angel
self.forwardDistance = drawing.info.scale
self.turtle = drawing.turtle
self.turtle.penup()
self.turtle.setposition(drawing.info.position)
self.turtle.setheading(drawing.info.rotation)
self.pendown()
self.turtle.pencolor(drawing.info.color)
def storeEdges(self):
pass
def pendown(self):
self.turtle.pendown()
def draw(self, word = None, n = None):
if n == None:
n = self.recursionDepth
if word == None:
word = self.startWord
turtleStates = []
if n == 0:
self.turtle.screen.update()
return
for character in word:
match character:
case "F":
self.turtle.forward(self.forwardDistance)
self.storeEdges()
case "+":
self.turtle.left(self.angel)
case "-":
self.turtle.right(self.angel)
case "[":
turtleStates.append(State(self.turtle.heading(), self.turtle.position()))
case "]":
self.turtle.penup()
state = turtleStates.pop()
self.turtle.setposition(state.position)
self.turtle.setheading(state.heading)
self.pendown()
if character in self.productionRules:
self.draw(self.productionRules[character], n - 1)
class Edges:
def __init__(self):
self.min = [0, 0]
self.max = [0, 0]
def minVec(self):
return turtle.Vec2D(self.min[0], self.min[1])
def maxVec(self):
return turtle.Vec2D(self.max[0], self.max[1])
class DrawerSimulation(Drawer):
def __init__(self, drawing):
super(DrawerSimulation, self).__init__(drawing)
self.edges = Edges()
def storeEdges(self):
for i, koord in enumerate(self.turtle.position()):
if koord < self.edges.min[i]:
self.edges.min[i] = koord
elif koord > self.edges.max[i]:
self.edges.max[i] = koord
def pendown(self):
pass
def draw(lSystem, recursionDepth, middle, rotation, size, color):
drawingInfo = DrawingInfo(lSystem, turtle.Vec2D(0, 0), rotation, color, 1, recursionDepth)
turtleObject = newTurtle()
drawing = Drawing(drawingInfo, turtleObject)
simulatedDraw = DrawerSimulation(drawing)
simulatedDraw.draw()
maxVec = simulatedDraw.edges.maxVec()
minVec = simulatedDraw.edges.minVec()
distance = maxVec - minVec
xScale = size[0] / distance[0]
yScale = size[1] / distance[1]
scale = yScale if xScale > yScale else xScale
pos = middle + (-minVec - distance * (1/2)) * scale
drawing.info.position = pos
drawing.info.scale = scale
drawScaled(drawing)
def newTurtle():
turtleObject = turtle.Turtle()
turtleObject.hideturtle()
turtleObject._tracer(0, 0)
return turtleObject
def delete(i):
drawings[i].turtle.clear()
del drawings[i]
def drawScaled(drawing):
actualDrawer = Drawer(drawing)
actualDrawer.draw()
drawings.append(drawing)