Polygon trebuchets
This commit is contained in:
commit
bde120e28e
4 changed files with 150 additions and 0 deletions
19
example.py
Normal file
19
example.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
"""
|
||||||
|
Example script that uses treimage.
|
||||||
|
"""
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
from treimage.trebuchet import D
|
||||||
|
|
||||||
|
|
||||||
|
CANVAS_SIZE = (640, 640)
|
||||||
|
WHITE = (255, 255, 255)
|
||||||
|
RED = (255, 0, 0)
|
||||||
|
|
||||||
|
a = D(10, 10, 10, 0.3)
|
||||||
|
print("Size:", a.size)
|
||||||
|
print(a.points)
|
||||||
|
|
||||||
|
with Image.new('RGB', CANVAS_SIZE, WHITE) as im:
|
||||||
|
draw = ImageDraw.Draw(im)
|
||||||
|
draw.polygon(a.points, fill=RED)
|
||||||
|
im.show()
|
9
setup.py
Normal file
9
setup.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="treimage",
|
||||||
|
description="Copy an image out of trebuchets.",
|
||||||
|
version="0.1",
|
||||||
|
packages=find_packages(),
|
||||||
|
install_requires=['Pillow~=7.1.2']
|
||||||
|
)
|
7
treimage/__init__.py
Normal file
7
treimage/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
"""
|
||||||
|
treimage provides functionality to take an
|
||||||
|
image and replicate it with flexible trebuchets.
|
||||||
|
|
||||||
|
Concept was inspired by OptArt by Robert Bosch.
|
||||||
|
"""
|
||||||
|
from . import trebuchet
|
115
treimage/trebuchet.py
Normal file
115
treimage/trebuchet.py
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
"""
|
||||||
|
Creates a trebuchet out of points.
|
||||||
|
|
||||||
|
Inspired by the OptArt book by Robert Bosch.
|
||||||
|
"""
|
||||||
|
from functools import cached_property
|
||||||
|
|
||||||
|
__all__ = ['FlexibleTrebuchet', 'A', 'B', 'C', 'D']
|
||||||
|
|
||||||
|
class FlexibleTrebuchet:
|
||||||
|
"""
|
||||||
|
Flexible trebuchet is like a normal trebuchet, but
|
||||||
|
instead of a diagnal line going through the center, we move
|
||||||
|
the end point to make two different lines that connect
|
||||||
|
to the center.
|
||||||
|
"""
|
||||||
|
def __init__(self, x1: float, y1: float,
|
||||||
|
size: float, brightness: float):
|
||||||
|
"""
|
||||||
|
Parameters
|
||||||
|
==========
|
||||||
|
x1: Top left corner, horizontal pos
|
||||||
|
y1: Top left corner, vertical pos
|
||||||
|
size: Multiplicative factor for width/height
|
||||||
|
brightness: Float between 0 and 1
|
||||||
|
"""
|
||||||
|
assert size >= 1
|
||||||
|
assert 0 <= brightness <= 1
|
||||||
|
self._x1: float = x1
|
||||||
|
self._y1: float = y1
|
||||||
|
self._size: float = size
|
||||||
|
self._brightness: float = brightness
|
||||||
|
|
||||||
|
@property
|
||||||
|
def x1(self):
|
||||||
|
return self._x1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def y1(self):
|
||||||
|
return self._y1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self):
|
||||||
|
return self._size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def brightness(self):
|
||||||
|
return self._brightness
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def x2(self):
|
||||||
|
return self.x1 + (4 * self.size)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def y2(self):
|
||||||
|
return self.y1 + (4 * self.size)
|
||||||
|
|
||||||
|
def scale_position_point(self, point):
|
||||||
|
scaled_point = (self.size * point[0], self.size * point[1])
|
||||||
|
return (self.x1 + scaled_point[0], self.y1 + scaled_point[1])
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def midpoint(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def points(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class A(FlexibleTrebuchet):
|
||||||
|
"""Follows the A Trebuchet from OptArt."""
|
||||||
|
@cached_property
|
||||||
|
def midpoint(self):
|
||||||
|
normalized_point = (-2 * self.brightness + 3, 2 * self.brightness + 1)
|
||||||
|
return self.scale_position_point(normalized_point)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def points(self):
|
||||||
|
return ((self.x1, self.y1), self.midpoint, (self.x2, self.y2), (self.x1, self.y2))
|
||||||
|
|
||||||
|
|
||||||
|
class B(FlexibleTrebuchet):
|
||||||
|
"""Follows the B Trebuchet from OptArt."""
|
||||||
|
@cached_property
|
||||||
|
def midpoint(self):
|
||||||
|
normalized_point = (-2 * self.brightness + 3, -2 * self.brightness + 3)
|
||||||
|
return self.scale_position_point(normalized_point)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def points(self):
|
||||||
|
return ((self.x1, self.y1), (self.x2, self.y1), self.midpoint, (self.x1, self.y2))
|
||||||
|
|
||||||
|
class C(FlexibleTrebuchet):
|
||||||
|
"""Follows the C Trebuchet from OptArt."""
|
||||||
|
@cached_property
|
||||||
|
def midpoint(self):
|
||||||
|
normalized_point = (2 * self.brightness + 1, -2 * self.brightness + 3)
|
||||||
|
return self.scale_position_point(normalized_point)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def points(self):
|
||||||
|
return ((self.x1, self.y1), self.midpoint, (self.x2, self.y2), (self.x2, self.y1))
|
||||||
|
|
||||||
|
class D(FlexibleTrebuchet):
|
||||||
|
"""Follows the D Trebuchet from OptArt."""
|
||||||
|
@cached_property
|
||||||
|
def midpoint(self):
|
||||||
|
normalized_point = (2 * self.brightness + 1, 2 * self.brightness + 1)
|
||||||
|
return self.scale_position_point(normalized_point)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def points(self):
|
||||||
|
return ((self.x1, self.y2), (self.x2, self.y2), (self.x2, self.y1), self.midpoint)
|
Loading…
Reference in a new issue