132 lines
3.8 KiB
Python
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)
|