+import cmath
+from math import atan, cos, sin, pi
+
+from PIL import Image, ImageDraw
+
+"""
+A lib to draw fractals on pillow image.
+
+>>> img = Image.new('RGB', (5000, 5000), (0, 0, 0))
+>>> figures = Figures(im=img)
+>>> figures.von_koch_curve_flake((2500, 2500), 2000,6)
+>>> img.save("test.bmp")
+"""
+
+
+[docs]class State:
+
"""State of Lsystem"""
+
width: int
+
color: tuple
+
angle: int
+
y: int
+
x: int
+
+
def __init__(self):
+
"""Initialisation of state
+
+
>>> State().x
+
0
+
>>> State().y
+
0
+
>>> State().angle
+
0
+
>>> State().color
+
(255, 255, 255)
+
>>> State().width
+
0"""
+
self.x = 0
+
self.y = 0
+
self.angle = 0
+
self.color = (255, 255, 255)
+
self.width = 0
+
+
+[docs]class Lsystem(ImageDraw.ImageDraw):
+
"""Draw a L system"""
+
state: State
+
states: list
+
+
def __init__(self, *args, **kwargs):
+
"""Initialisation
+
+
Parameters are the same than ImageDraw.__init__"""
+
super().__init__(*args, **kwargs)
+
self.states = []
+
self.state = State()
+
+
[docs] def _right(self, angle):
+
"""Turn pen to right of angle
+
+
:param angle: Angle to rotate
+
:type angle: float
+
"""
+
self.state.angle -= angle
+
+
[docs] def _left(self, angle):
+
"""Turn pen to left of angle
+
+
:param angle: Angle to rotate
+
:type angle: float
+
"""
+
self.state.angle += angle
+
+
[docs] def _forward(self, distance):
+
"""Forward pen of distance
+
+
:param distance: Distance to forward
+
:type distance: float
+
"""
+
x_2: float = (distance * cos(self.state.angle)) + self.state.x
+
y_2: float = (distance * sin(self.state.angle)) + self.state.y
+
self.line(((self.state.x, self.state.y), (x_2, y_2)), self.state.color, self.state.width)
+
self.state.x, self.state.y = x_2, y_2
+
+
[docs] def _backward(self, distance):
+
"""Backward pen of distance
+
+
:param distance: Distance to backward
+
:type distance: float
+
"""
+
self._forward(-distance)
+
+
[docs] def _save(self):
+
"""Save state of pen"""
+
self.states.append(self.state)
+
+
[docs] def _restore(self):
+
"""Restore last pen state"""
+
self.state = self.states[-1]
+
del self.states[-1]
+
+
[docs] def draw_l(self, start, replacement, constants, nb_recursive, color=(255, 255, 255), width=0):
+
"""Draw a L system
+
+
:param start: Axiome
+
:param replacement: Dictionary which contain replacement values (F->F+F-F-F+F)
+
:param constants: Dictionary which contain all elements with there function
+
:param nb_recursive: Number of recursion
+
:param color: Color to use for the drawing
+
:param width: The line width, in pixels
+
:type start: str
+
:type replacement: dict
+
:type constants: dict
+
:type nb_recursive: int
+
:type color: tuple
+
:type width: int
+
"""
+
self.state.color = color
+
self.state.width = width
+
for i in range(nb_recursive):
+
for key, value in replacement.items():
+
start = start.replace(key, value)
+
for item in start:
+
constants[item]()
+
+
[docs] def right(self, angle):
+
"""Return a lambda function which make pen turning of angle radians to right
+
+
:param angle: Angle to build function
+
:type angle: float
+
+
:return: lambda function to make pen turning right
+
:rtype: lambda"""
+
return lambda: self._right(angle)
+
+
[docs] def left(self, angle):
+
"""Return a lambda function which make pen turning of angle radians to left
+
+
:param angle: Angle to build function
+
:type angle: float
+
+
:return: lambda function to make pen turning left
+
:rtype: lambda"""
+
return lambda: self._left(angle)
+
+
[docs] def forward(self, distance):
+
"""Return a lambda function which make pen forward of distance
+
+
:param distance: Distance to build function
+
:type distance: float
+
+
:return: lambda function to make pen forward
+
:rtype: lambda"""
+
return lambda: self._forward(distance)
+
+
[docs] def backward(self, distance):
+
"""Return a lambda function which make pen backward of distance
+
+
:param distance: Distance to build function
+
:type distance: float
+
+
:return: lambda function to make pen backward
+
:rtype: lambda"""
+
return lambda: self._backward(distance)
+
+
[docs] def save(self):
+
"""Return a lambda function which save state of pen
+
+
:return: lambda function to save pen state
+
:rtype: lambda"""
+
return lambda: self._save()
+
+
[docs] def restore(self):
+
"""Return a lambda function which restore state of pen
+
+
:return: lambda function to restore pen state
+
:rtype: lambda"""
+
return lambda: self._restore()
+
+
+
+
+
+if __name__ == "__main__":
+ img = Image.new('RGB', (5000, 5000), (255, 255, 255))
+ """figures = Figures(im=img)
+ figures.blanc_manger((2000, 2000), (3000, 3000), 7, color=(0, 0, 0), width=2)"""
+ figures = Lsystem(im=img)
+ figures.state.x, figures.state.y = 4000, 4000
+
+ figures.draw_l("F", {"F": "F+F-F", },
+
+ {"+": figures.left(pi * 2 / 3), '-': figures.right(pi * 2 / 3),
+ "F": figures.forward(50), }, 7,
+
+ (255, 0, 0), 2)
+
+ figures._left(2 * pi / 3)
+
+ figures.draw_l("F", {"F": "F+F-F", },
+
+ {"+": figures.left(pi * 2 / 3), '-': figures.right(pi * 2 / 3),
+ "F": figures.forward(50), }, 7,
+
+ (0, 255, 0, 2))
+
+ figures._left(2 * pi / 3)
+
+ figures.draw_l("F", {"F": "F+F-F", },
+
+ {"+": figures.left(pi * 2 / 3), '-': figures.right(pi * 2 / 3),
+ "F": figures.forward(50), }, 7,
+
+ (0, 0, 255), 2)
+ img.save("D:\\Users\\louis chauvet\\Documents\\GitHub\\fractale\\test.bmp")
+