Module generativepy.shape2d

Expand source code
# Author:  Martin McBride
# Created: 2023-02-17
# Copyright (C) 2023, Martin McBride
# License: MIT
from generativepy.math import Matrix, Vector
import math


class Points:
    """
    Points array stores a list of `Vector` objects.

    It provides various ways to transform all the points in the list, and static methods to create new sets of points.

    It also implements pre-multiplication by a matrix. To transform all the points in list `p` by matrix `m`, use:

    `p1 = m * p`
    """

    @staticmethod
    def regular_polygon(sides, centre=(0, 0), radius=1, flat_base=True):
        """
        Create the points for a regular polygon.

        Args:
            sides: int - number of sides of the polygon.
            centre: tuple - position of polygon centre.
            radius: number - Outer radius (distance from centre to any vertex).
            flat_base: bool - ff true, the polygon will have a flat base. Otherwise, vertex 0 will be on +ve x-axis.

        Returns:
            A new `Points` item containing the vertices.
        """
        centre_angle = math.pi * 2 / sides
        angle = math.pi / 2 - centre_angle / 2 if flat_base else 0
        angles = [angle + centre_angle * i for i in range(sides)]

        return Points(((radius * math.cos(a) + centre[0], radius * math.sin(a) + centre[1]) for a in angles))

    def __init__(self, points):
        """
        Initialise a new points object.
        Args:
            points: tuple of tuples - the points to include.
        """
        self.points = tuple(Vector(p) for p in points)

    def transform(self, m):
        """
        Transform every point by the matrix.
        Args:
            m: `Matrix` - transformation matrix.

        Returns:
            New transformed `Points` object.
        """
        return m*self

    def scale(self, scale_x, scale_y=0):
        """
        Apply scale transform to every point.

        Args:
            scale_x: number - x scale factor
            scale_y: number - y scale factor

        Returns:
            New transformed `Points` object.
        """
        return Matrix.scale(scale_x, scale_y)*self

    def translate(self, x, y):
        """
        Apply translation transform to every point.

        Args:
            x: number - x translation
            y: number - y translation

        Returns:
            New transformed `Points` object.
        """

        return Matrix.translate(x, y)*self

    def rotate(self, angle):
        """
        Apply rotation transform to every point.

        Args:
            angle: number - angle to rotate, in radians.

        Returns:
            New transformed `Points` object.
        """

        return Matrix.rotate(angle)*self

    def __iter__(self):
        return iter(self.points)

    def __len__(self):
        return len(self.points)

    def __getitem__(self, index):
        return self.points[index]

    def __eq__(self, other):
        if len(self) != len(other):
            return False
        return all([a == b for a, b in zip(self, other)])

    def __rmul__(self, other):
        if isinstance(other, Matrix):
            return Points(Vector.matrix_premultiply(other, p) for p in self.points)
        return NotImplemented

    def __repr__(self):
        return "Points(" + ", ".join((str(p) for p in self.points)) + ")"

    def __str__(self):
        return repr(self)

Classes

class Points (points)

Points array stores a list of Vector objects.

It provides various ways to transform all the points in the list, and static methods to create new sets of points.

It also implements pre-multiplication by a matrix. To transform all the points in list p by matrix m, use:

p1 = m * p

Initialise a new points object.

Args

points
tuple of tuples - the points to include.
Expand source code
class Points:
    """
    Points array stores a list of `Vector` objects.

    It provides various ways to transform all the points in the list, and static methods to create new sets of points.

    It also implements pre-multiplication by a matrix. To transform all the points in list `p` by matrix `m`, use:

    `p1 = m * p`
    """

    @staticmethod
    def regular_polygon(sides, centre=(0, 0), radius=1, flat_base=True):
        """
        Create the points for a regular polygon.

        Args:
            sides: int - number of sides of the polygon.
            centre: tuple - position of polygon centre.
            radius: number - Outer radius (distance from centre to any vertex).
            flat_base: bool - ff true, the polygon will have a flat base. Otherwise, vertex 0 will be on +ve x-axis.

        Returns:
            A new `Points` item containing the vertices.
        """
        centre_angle = math.pi * 2 / sides
        angle = math.pi / 2 - centre_angle / 2 if flat_base else 0
        angles = [angle + centre_angle * i for i in range(sides)]

        return Points(((radius * math.cos(a) + centre[0], radius * math.sin(a) + centre[1]) for a in angles))

    def __init__(self, points):
        """
        Initialise a new points object.
        Args:
            points: tuple of tuples - the points to include.
        """
        self.points = tuple(Vector(p) for p in points)

    def transform(self, m):
        """
        Transform every point by the matrix.
        Args:
            m: `Matrix` - transformation matrix.

        Returns:
            New transformed `Points` object.
        """
        return m*self

    def scale(self, scale_x, scale_y=0):
        """
        Apply scale transform to every point.

        Args:
            scale_x: number - x scale factor
            scale_y: number - y scale factor

        Returns:
            New transformed `Points` object.
        """
        return Matrix.scale(scale_x, scale_y)*self

    def translate(self, x, y):
        """
        Apply translation transform to every point.

        Args:
            x: number - x translation
            y: number - y translation

        Returns:
            New transformed `Points` object.
        """

        return Matrix.translate(x, y)*self

    def rotate(self, angle):
        """
        Apply rotation transform to every point.

        Args:
            angle: number - angle to rotate, in radians.

        Returns:
            New transformed `Points` object.
        """

        return Matrix.rotate(angle)*self

    def __iter__(self):
        return iter(self.points)

    def __len__(self):
        return len(self.points)

    def __getitem__(self, index):
        return self.points[index]

    def __eq__(self, other):
        if len(self) != len(other):
            return False
        return all([a == b for a, b in zip(self, other)])

    def __rmul__(self, other):
        if isinstance(other, Matrix):
            return Points(Vector.matrix_premultiply(other, p) for p in self.points)
        return NotImplemented

    def __repr__(self):
        return "Points(" + ", ".join((str(p) for p in self.points)) + ")"

    def __str__(self):
        return repr(self)

Static methods

def regular_polygon(sides, centre=(0, 0), radius=1, flat_base=True)

Create the points for a regular polygon.

Args

sides
int - number of sides of the polygon.
centre
tuple - position of polygon centre.
radius
number - Outer radius (distance from centre to any vertex).
flat_base
bool - ff true, the polygon will have a flat base. Otherwise, vertex 0 will be on +ve x-axis.

Returns

A new Points item containing the vertices.

Expand source code
@staticmethod
def regular_polygon(sides, centre=(0, 0), radius=1, flat_base=True):
    """
    Create the points for a regular polygon.

    Args:
        sides: int - number of sides of the polygon.
        centre: tuple - position of polygon centre.
        radius: number - Outer radius (distance from centre to any vertex).
        flat_base: bool - ff true, the polygon will have a flat base. Otherwise, vertex 0 will be on +ve x-axis.

    Returns:
        A new `Points` item containing the vertices.
    """
    centre_angle = math.pi * 2 / sides
    angle = math.pi / 2 - centre_angle / 2 if flat_base else 0
    angles = [angle + centre_angle * i for i in range(sides)]

    return Points(((radius * math.cos(a) + centre[0], radius * math.sin(a) + centre[1]) for a in angles))

Methods

def rotate(self, angle)

Apply rotation transform to every point.

Args

angle
number - angle to rotate, in radians.

Returns

New transformed Points object.

Expand source code
def rotate(self, angle):
    """
    Apply rotation transform to every point.

    Args:
        angle: number - angle to rotate, in radians.

    Returns:
        New transformed `Points` object.
    """

    return Matrix.rotate(angle)*self
def scale(self, scale_x, scale_y=0)

Apply scale transform to every point.

Args

scale_x
number - x scale factor
scale_y
number - y scale factor

Returns

New transformed Points object.

Expand source code
def scale(self, scale_x, scale_y=0):
    """
    Apply scale transform to every point.

    Args:
        scale_x: number - x scale factor
        scale_y: number - y scale factor

    Returns:
        New transformed `Points` object.
    """
    return Matrix.scale(scale_x, scale_y)*self
def transform(self, m)

Transform every point by the matrix.

Args

m
Matrix - transformation matrix.

Returns

New transformed Points object.

Expand source code
def transform(self, m):
    """
    Transform every point by the matrix.
    Args:
        m: `Matrix` - transformation matrix.

    Returns:
        New transformed `Points` object.
    """
    return m*self
def translate(self, x, y)

Apply translation transform to every point.

Args

x
number - x translation
y
number - y translation

Returns

New transformed Points object.

Expand source code
def translate(self, x, y):
    """
    Apply translation transform to every point.

    Args:
        x: number - x translation
        y: number - y translation

    Returns:
        New transformed `Points` object.
    """

    return Matrix.translate(x, y)*self