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)
 | 
			
		||||
		Reference in a new issue