#main_script
import fme
import fmeobjects
import random
from fmeobjects import FMELine, FMEGeometryTools
import numpy as np
import matplotlib.pyplot as plt
def gen2(repeat= 2):
# recursive function
initiator2 = "A"
generator2 = [ "F-[[A]+A]+F[+FA]-A" , "F[+A]F[-A]A" , "F[+[FA[-A]F]][-A]FA" ]
generator_way2 = []
for i in range(repeat):
_com = []
for k in initiator2:
if k == "F":
_com.append("FF")
elif k == "A":
_com.append(random.choice(generator2))
else:
_com.append(k)
initiator2 = "".join(_com)
return initiator2
generator_rand = {"A":gen2(2)}
generators = [
{"F": "FB", "A": "F-[[A]+A]+F[+FA]-A", "B":"+F[+FA]-A"},
{"F": "FF", "A": "F-[[A]+A]+F[+FA]-A"},
{"A": "F+[[B]-B]-F[-FB]+B)", "F": "F[+F]-F[+F[-F]+F]"},
{"A":" F+[[B]-B]-F[-FB]+B)", "F":"-F[+F+F]-F"},
{"F": "FF", "A": "F[+A]F[-A]A"}
]
# global variables goes here
state = [[4, 1], np.pi / 2] # Initial starting point and initial direction(in radians) of turtle
initiator = "A"
initiator = "+F[+F]F"
initiator = "+F[+A]F"
initiator = "A"
com = initiator
generator = random.choice(generators)
generator = generators[-1]
generator= generator_rand
angle = 22.5 / 180 * np.pi # Rotation angle degrees - radians
drawcolor = 'green'
repeat = 4
distance = 2 * (1 / 2) ** repeat # Length of one step. Change according to the object
# call stack is used to store the state of the turtle when encountering the `[` command
# and to restore it when encountering the `]` command in order to
# to remember its position and direction at certain points, enabling it to return to
# those points later.
stack = []
datastructure = []
# Move pointer froward without drawing
# and memorize the state
def move_pointer(state):
th = state[1]
x = state[0][0] + distance * np.cos(th)
y = state[0][1] + distance * np.sin(th)
return [[x, y], th]
# Move forward by distance and draw
def forward(state):
th = state[1]
x1 = state[0][0]
y1 = state[0][1]
x2 = x1 + distance * np.cos(th)
y2 = y1 + distance * np.sin(th)
datastructure.append([[x1, y1], [x2, y2]])
return [[x2, y2], th]
# Change direction coef 1/0 left/right
def rotate(coef, state):
th = state[1]
th = th + coef * angle
return [state[0], th]
def turtle(command, state):
# Move the turtle according to the command L, R do nothing, return the state of the turtle
# When the turtle encounters `[`, it saves the current state (position and direction) onto the stack.
# When the turtle encounters `]`, it pops the last saved state from the stack and restores it.
# This mechanism is essential for generating branching structures in L-systems, where the turtle needs to backtrack to previous positions to create branches.
if command == "A" or command == "B" or command == "F":
state = forward(state)
if command == "f":
state = move_pointer(state)
if command == "+":
state = rotate(1, state)
if command == "-":
state = rotate(-1, state)
if command == "[":
stack.append(state)
if command == "]":
state = stack.pop()
return state
def _main():
""" main calls
str.maketrans(generator)
com.translate(...)
for command in com:
turtle(command, state) where for each command you call:
forward(state)|
move_pointer(state)|
rotate(coef, state)|
stack.append(state)|
stack.pop()
This sequence ensures that the turtle graphics are generated according to the L
system rules defined by the generator
"""
global state, com, datastructure
for i in range(repeat):
com = com.translate(str.maketrans(generator))
for command in com:
state = turtle(command, state)
return datastructure
class FeatureProcessor(object):
def __init__(self):
pass
def input(self, feature: fmeobjects.FMEFeature):
# svg_body = create_svg_no_deps(datastructure,'foo')
_lines = _main()
for i in _lines:
# i being [[4, 1], [4.0, 1.125]]
# i can make a fme line
coords = [tuple(sublist) for sublist in i]
feature.setAttribute('i', 'yo')
line = FMELine(coords)
feature.setGeometry(line)
self.pyoutput(feature)
def close(self):
pass