Source code for domonic.geom.shape

"""
    domonic.geom.shape
    ====================================

"""

from domonic.geom.vec2 import vec2
from domonic.svg import *
from domonic.javascript import Math

[docs] class vertex(vec2): """ A vertex is a point in the shape. """ # def __init__(self, x=0, y=0): # self.x = x # self.y = y def move_to(self, position): x, y = position self.x = x self.y = y def move_by(self, dx, dy): self.x += dx self.y += dy
# def __str__(self): # return '{} {} {}'.format(self.x, self.y, self.color) # def __repr__(self): # return '{} {} {}'.format(self.x, self.y, self.color) Point = vertex
[docs] class Shape(Point): def __init__(self, x=0, y=0, color="red", vertices=[]): super().__init__(x, y) if isinstance(vertices, list): self.vertices = vertices self.color = color self.scale = 1 self.rotation = 0 # self.pivot = (0, 0) self.id = None self.name = None self.style = None self.locked = False self.visible = True self.selected = False self.clipMask = None self.data = None self.blendMode = None self.opacity = 1.0 self.strokeColor = None self.strokeWidth = 1 # self.strokeCap = 'butt' # self.strokeJoin = 'miter' # self.dashOffset = 0 # self.strokeScaling = 1.0 # self.dashArray = None # self.miterLimit = None # self.fillColor = None self.shadowColor = None self.shadowBlur = None self.shadowOffset = None self.shadowOpacity = None # self.vertcies = [] # self.width = None # self.height = None @property def position(self): return vec2(self.x, self.y) @position.setter def position(self, pos): self.x = pos.x self.y = pos.y @property def width(self): """determine the width of the shape""" return max(self.vertices, key=lambda v: v.x).x - min(self.vertices, key=lambda v: v.x).x @property def height(self): """determine the height of the shape""" return max(self.vertices, key=lambda v: v.y).y - min(self.vertices, key=lambda v: v.y).y
[docs] def rotate(self, angle): """rotate the shape""" self.rotation += angle
[docs] def draw(self, svg): """draw the shape""" if self.visible: svg.add( svg.polyline( self.vertices, id=self.id, class_=self.name, style=self.style, fill=self.color, stroke=self.strokeColor, stroke_width=self.strokeWidth, opacity=self.opacity, fill_opacity=self.opacity, fill_rule="evenodd", ) )
def __len__(self): return len(self.vertices) def __getitem__(self, index): return self.vertices[index] def __setitem__(self, index, value): self.vertices[index] = value def __delitem__(self, index): del self.vertices[index] def __iter__(self): return iter(self.vertices) def __reversed__(self): return reversed(self.vertices) def __contains__(self, item): return item in self.vertices def __add__(self, other): """add two shapes""" if isinstance(other, Shape): return self.vertices + other.vertices
# def matrix # def clear # def pivot # def bounds # def rasterize(self, rasterizer): # """ rasterize the shape """ # pass # def contains(self, point): # """ check if the point is inside the shape """ # pass # def isInside(self, rect): # """ check if the rect is inside the shape """ # pass # def intersects(item): # """ check if the shape intersects with another """ # pass # @property # def x(self): # return self.__x # @x.setter # def x(self, x): # self.__x = x # @property # def y(self): # return self.__y # @y.setter # def y(self, y): # self.__y = y
[docs] class Line(Shape): def __init__(self, start, end, color=None, *args): super().__init__(color) # if isinstance(p1, vec2): self.start = start self.end = end self.x = self.start[0] - self.end[0] self.y = self.start[1] - self.end[1] def __str__(self): return f"Line({self.start}, {self.end})" def __eq__(self, other): return self.start == other.start and self.end == other.end def __ne__(self, other): return self.start != other.start or self.end != other.end def __hash__(self): return hash((self.start, self.end)) def __iter__(self): return iter((self.start, self.end)) # def __len__(self): # return 2 def __getitem__(self, index): return (self.start, self.end)[index] def __setitem__(self, index, value): if index == 0: self.start = value def __delitem__(self, index): if index == 0: self.start = None def __contains__(self, item): return item in (self.start, self.end) def __add__(self, other): return Line(self.start, other.end) def __sub__(self, other): # self - other return Line(self.start, other.start) def __mul__(self, other): return Line(self.start, other.end) def __rmul__(self, other): return Line(self.start, other.end) def __neg__(self): return Line(self.start, self.end) def __pos__(self): return Line(self.start, self.end) def __abs__(self): return Line(self.start, self.end) # def __bool__(self): # return bool(self.start and self.end) # def __nonzero__(self): # return bool(self.start and self.end) # def __call__(self, p): # return Line(self.start, p) # def __getattr__(self, name): # if name == 'p1': # return self.start # elif name == 'p2': # return self.end # else: # raise AttributeError(name) # def __setattr__(self, name, value): # if name == 'p1': # self.start = value # def __delattr__(self, name): # if name == 'p1': # self.start = None # elif name == 'p2': # self.end = None # else: # raise AttributeError(name) # def __getinitargs__(self): # return (self.start, self.end) # def __setstate__(self, state): # self.start = state['p1'] # self.end = state['p2'] def __getstate__(self): return {"p1": self.start, "p2": self.end} def __reduce__(self): return (Line, (self.start, self.end)) def __reduce_ex__(self, protocol): return self.__reduce__() def __copy__(self): return Line(self.start, self.end) def __deepcopy__(self, memo): return Line(self.start, self.end) def __bool__(self): return bool(self.start and self.end) def __nonzero__(self): return bool(self.start and self.end)
class Plane: def __init__(self, normal, distance, color=None, *args): """[a plane is defined by its normal vector and a distance from the origin] Args: normal ([vec2]): [a vector representing the normal vector of the plane] distance ([type]): [a scalar representing the distance from the origin] color ([vec3], optional): [the color of the plane] """ self.normal = normal self.distance = distance self.color = color def __str__(self): return f"Plane({self.normal}, {self.distance})" def __eq__(self, other): return self.normal == other.normal and self.distance == other.distance # def bisectors(self): # return self.normal.cross(self.distance) # def with_distance(self, distance): # return Plane(self.normal, distance) # def with_normal(self, normal): # return Plane(normal, self.distance)
[docs] class Rect(Shape): def __init__(self, x=0, y=0, width=1, height=1, color=None): super().__init__(color) self.x = x self.y = y self.width = width self.height = height @property def width(self): return self._width @width.setter def width(self, w): self._width = w @property def height(self): return self._height @height.setter def height(self, w): self._height = w def get_bottom_right(self): d = self.x + self.width t = self.y + self.height return (d, t) def get_bottom_left(self): b = self.get_bottom_right() l = super().get_bottom_right() return (b[0], l[0]) def get_top_left(self): t = self.x b = super().get_bottom_right() return (t, b[1]) def get_top_right(self): t = self.x + self.width b = super().get_bottom_right() return (t, b[1]) def get_center(self): c = self.x + self.width / 2 t = self.y + self.height / 2 return (c, t) def get_center_x(self): c = self.x + self.width / 2 return c def get_center_y(self): c = self.y + self.height / 2 return c def get_left(self): return self.x def get_right(self): return self.x + self.width def get_top(self): return self.y def get_bottom(self): return self.y + self.height def get_width(self): return self.width def get_height(self): return self.height def __str__(self): return f"Rect({self.x}, {self.y}, {self.width}, {self.height})" def __eq__(self, other): return self.x == other.x and self.y == other.y and self.width == other.width and self.height == other.height def __ne__(self, other): return self.x != other.x or self.y != other.y or self.width != other.width or self.height != other.height def __hash__(self): return hash((self.x, self.y, self.width, self.height)) def __iter__(self): return iter((self.x, self.y, self.width, self.height)) def __len__(self): return 4 def __getitem__(self, index): return (self.x, self.y, self.width, self.height)[index] def __setitem__(self, index, value): if index == 0: self.x = value elif index == 1: self.y = value elif index == 2: self.width = value elif index == 3: self.height = value def __add__(self, other): return Rect( self.x + other.x, self.y + other.y, self.width + other.width, self.height + other.height, ) def __sub__(self, other): return Rect( self.x - other.x, self.y - other.y, self.width - other.width, self.height - other.height, ) def __mul__(self, other): return Rect(self.x * other, self.y * other, self.width * other, self.height * other) def __truediv__(self, other): return Rect(self.x / other, self.y / other, self.width / other, self.height / other) def __floordiv__(self, other): return Rect(self.x // other, self.y // other, self.width // other, self.height // other) def __iadd__(self, other): self.x += other.x self.y += other.y self.width += other.width self.height += other.height return self def __isub__(self, other): self.x -= other.x self.y -= other.y self.width -= other.width self.height -= other.height return self def __imul__(self, other): self.x *= other self.y *= other self.width *= other self.height *= other return self def __idiv__(self, other): self.x /= other self.y /= other self.width /= other self.height /= other return self def __ifloordiv__(self, other): self.x //= other self.y //= other self.width //= other self.height //= other return self # def __getstate__(self): # return {'x': self.x, 'y': self.y, 'width': self.width, 'height': self.height} # def __setstate__(self, state): # self.x = state['x'] # self.y = state['y'] # self.width = state['width'] # self.height = state['height'] def __reduce__(self): return (Rect, (self.x, self.y, self.width, self.height)) def __copy__(self): return Rect(self.x, self.y, self.width, self.height) def __deepcopy__(self, memo): return Rect(self.x, self.y, self.width, self.height) def __contains__(self, other): return ( self.x <= other.x and self.y <= other.y and self.x + self.width >= other.x + other.width and self.y + self.height >= other.y + other.height ) def __lt__(self, other): return self.x < other.x and self.y < other.y and self.width < other.width and self.height < other.height def __le__(self, other): return self.x <= other.x and self.y <= other.y and self.width <= other.width and self.height <= other.height def __gt__(self, other): return self.x > other.x and self.y > other.y and self.width > other.width and self.height > other.height def __ge__(self, other): return self.x >= other.x and self.y >= other.y and self.width >= other.width and self.height >= other.height
# def __eq__(self, other): # return self.x == other.x and self.y == other.y and self.width == other.width and self.height == other.height # def __ne__(self, other): # return self.x != other.x or self.y != other.y or self.width != other.width or self.height != other.height # def __hash__(self): # return hash((self.x, self.y, self.width, self.height))
[docs] class Square(Rect): def __init__(self, x=0, y=0, size=1.0, color=None): super().__init__(x, y, size, size, color) def get_size(self): return self.width def set_size(self, size): self.width = size self.height = size def __str__(self): return f"Square({self.x}, {self.y}, {self.width})" # def __getstate__(self): # return {'x': self.x, 'y': self.y, 'size': self.width, 'color': self.color} # def __setstate__(self, state): # self.x = state['x'] # self.y = state['y'] # self.width = state['size'] # self.height = state['size'] # self.color = state['color'] # def __reduce__(self): # return (Square, (self.x, self.y, self.width, self.color)) def __copy__(self): return Square(self.x, self.y, self.width, self.color) def __deepcopy__(self, memo): return Square(self.x, self.y, self.width, self.color) def __contains__(self, other): return ( self.x <= other.x and self.y <= other.y and self.x + self.width >= other.x + other.width and self.y + self.height >= other.y + other.height ) def get_vertices(self, x=None, y=None): if x is None: x = self.x if y is None: y = self.y return [ (x, y), (x + self.width, y), (x + self.width, y + self.height), (x, y + self.height), ] def get_vertices_list(self): return [ (self.x, self.y), (self.x + self.width, self.y), (self.x + self.width, self.y + self.height), (self.x, self.y + self.height), ] def svg(self, x=None, y=None): if x is None: x = self.x if y is None: y = self.y return f'<rect x="{x}" y="{y}" width="{self.width}" height="{self.height}" fill="{self.color}"/>'
# def draw_to_canvas(self, canvas): # canvas.draw_rect(self.x, self.y, self.width, self.height, self.color)
[docs] class Polygon(Shape): def __init__(self, points): super().__init__() self.points = points def get_points(self): return self.points def set_points(self, points): self.points = points def __str__(self): return f"Polygon({(self.points)})"
[docs] class Polyline(Shape): def __init__(self, points): super().__init__() self.points = points def get_points(self): return self.points def set_points(self, points): self.points = points def __str__(self): return f"Polyline({(self.points)})" def __getstate__(self): return {"points": self.points} def __setstate__(self, state): self.points = state["points"] def __reduce__(self): return (Polyline, (self.points,)) def __copy__(self): return Polyline(self.points) def __deepcopy__(self, memo): return Polyline(self.points) def __contains__(self, other): return other in self.points def __len__(self): return len(self.points) def __getitem__(self, key): return self.points[key] def __setitem__(self, key, value): self.points[key] = value def __iter__(self): return iter(self.points) def __add__(self, other): return Polyline(self.points + other.points) def __sub__(self, other): return Polyline(self.points - other.points) def __mul__(self, other): return Polyline(self.points * other) def __rmul__(self, other): return Polyline(other * self.points) def __floordiv__(self, other): return Polyline(self.points // other) def __mod__(self, other): return Polyline(self.points % other) def __divmod__(self, other): return Polyline(divmod(self.points, other)) def __pow__(self, other): return Polyline(self.points**other) def __lshift__(self, other): return Polyline(self.points << other) def __rshift__(self, other): return Polyline(self.points >> other) def __and__(self, other): return Polyline(self.points & other) def __xor__(self, other): return Polyline(self.points ^ other) def __or__(self, other): return Polyline(self.points | other) def __iadd__(self, other): self.points += other.points return self def __isub__(self, other): self.points -= other.points return self def __imul__(self, other): self.points *= other return self def __imod__(self, other): self.points %= other return self def __idivmod__(self, other): self.points //= other return self def __ipow__(self, other): self.points **= other def __ilshift__(self, other): self.points <<= other def __irshift__(self, other): self.points >>= other return self def __iand__(self, other): self.points &= other def __ixor__(self, other): self.points ^= other def __ior__(self, other): self.points |= other return self def __neg__(self): return Polyline(-self.points) def __pos__(self): return Polyline(self.points) def __abs__(self): return Polyline(abs(self.points)) def __invert__(self): return Polyline(~self.points) # def __complex__(self): # return complex(self.points) def __int__(self): return int(self.points) def __float__(self): return float(self.points) def __round__(self): return round(self.points)
# def __reversed__(self): # return Polyline(reversed(self.points)) # class Quad(Shape): # def __init__(self, left=Rect(), right=Rect(), front=Rect(), back=Rect()): # super().__init__(color='blue') # self.left, self.right, self.front, self.back = left, right, front, back # class Triangle(Shape): # def __init__(self): # super().__init__(self.color='blue') # class Wave(): # def __init__(self, color=None, *args): # self.color = color
[docs] class Circle(Shape): def __init__(self, x: float, y: float, radius: float = 1.0, color=None) -> None: """[Circle(x, y, radius=1.0, color=None)] Args: x ([float]): [the x coordinate of the center of the circle] y ([float]): [the y coordinate of the center of the circle] radius (float, optional): [description]. Defaults to 1.0. color ([type], optional): [description]. Defaults to None. """ super().__init__(color) self.radius = radius # Create an instance variable radius @property def area(self) -> float: """[area] Returns: [float]: [the area of the circle] """ return self.radius * self.radius * Math.PI @property def perimeter(self) -> float: """[perimeter] Returns: [float]: [the perimeter of the circle] """ return 2 * self.radius * Math.PI @property def average_circumference(self): return 2 * self.radius @property def center(self): x, y = self.center = [self.radius, self.radius] return x, y @center.setter def center(self, center): self._center = center def __str__(self): return f"Circle({self.center}, {self.radius}, {self.color})" def __getstate__(self): return {"center": self.center, "radius": self.radius} def __setstate__(self, state): self.center = state["center"] self.radius = state["radius"] def __copy__(self): return Circle(self.center, self.radius, self.color) def __deepcopy__(self, memo): return Circle(self.center, self.radius, self.color) def __contains__(self, other): return other in self.center def __len__(self): return len(self.center) def __getitem__(self, key): return self.center[key] def __setitem__(self, key, value): self.center[key] = value def __iter__(self): return iter(self.center) def __add__(self, other): return Circle(self.center + other.center, self.radius + other.radius) def __sub__(self, other): return Circle(self.center - other.center, self.radius - other.radius) def __mul__(self, other): return Circle(self.center * other, self.radius * other)
# def __rmul__(self, other): # return Circle(self.center * other, self.radius * other
[docs] class Oval(Circle): def __init__(self, radius=2.5, size=3): super().__init__(size, "green") self.radius = radius self.x = self.width / 2 - self.radius / 2 self.y = self.width / 2 + self.radius / 2
[docs] class Ellipse(Shape): def __init__(self, x, y, width, height, color=None): super().__init__(color) self.x = x self.y = y self.width = width self.height = height