Source code for svgen.cartesian
"""
svgen - A module for Cartesian-coordinate interfaces.
"""
# built-in
from math import isclose
from typing import NamedTuple, Tuple
# internal
from svgen.attribute import SimpleAttribute
from svgen.cartesian.mutate import Translation
from svgen.cartesian.point import DEFAULT, Point
UNITY: float = 1.0
[docs]
def distance(point_a: Point, point_b: Point = DEFAULT) -> float:
"""Compute the distance between two points."""
return point_a.distance(point_b)
[docs]
class DimensionAttrs(NamedTuple):
"""A grouping for 'width' and 'height' attributes."""
width: SimpleAttribute
height: SimpleAttribute
@property
def width_val(self) -> float:
"""Get this 'width' value for these dimensions."""
return float(self.width.value)
@property
def height_val(self) -> float:
"""Get the 'height' value for these dimensions."""
return float(self.height.value)
[docs]
class Dimensions(NamedTuple):
"""A set of dimensions describing a rectangular entity."""
width: float
height: float
def __str__(self) -> str:
"""Get this instance as a string."""
return f"width={self.width}, height={self.height})"
def __hash__(self) -> int:
"""Get a suitable hash value for this instance."""
return hash(str(self))
def __eq__(self, other: object) -> bool:
"""Determine if these dimensions are equivalent to another set."""
if not isinstance(other, Dimensions):
return NotImplemented
return isclose(self.width, other.width) and isclose(
self.height, other.height
)
@property
def dx(self) -> float:
"""An alias for width."""
return self.width
@property
def dy(self) -> float:
"""An alias for height."""
return self.height
@property
def width_attr(self) -> SimpleAttribute:
"""Get the 'width' attribute for these dimensions."""
return SimpleAttribute("width", str(self.width))
@property
def height_attr(self) -> SimpleAttribute:
"""Get the 'height' attribute for these dimensions."""
return SimpleAttribute("height", str(self.height))
@property
def attrs(self) -> DimensionAttrs:
"""Get the 'width' and 'height' attributes for these dimensions."""
return DimensionAttrs(self.width_attr, self.height_attr)
@property
def square(self) -> bool:
"""Determine if these dimensions are square."""
return isclose(self.width, self.height)
[docs]
def scale(
self, width_scale: float = UNITY, height_scale: float = UNITY
) -> "Dimensions":
"""Scale these dimensions."""
return Dimensions(self.width * width_scale, self.height * height_scale)
[docs]
def to_square(self, scale: float = UNITY) -> "Dimensions":
"""Convert these dimensions to a scaled square."""
return self.to_centered_square(scale)[0]
[docs]
def to_centered_square(
self, scale: float = UNITY
) -> Tuple["Dimensions", Translation]:
"""
Make dimensions square and determine the resulting translation that
would be needed to logically center the new object.
"""
length = min(self.width, self.height)
dimensions = Dimensions(length, length).scale(scale, scale)
# Determine how much the object needs to move if the caller wants to
# center the result.
dx = abs(self.width - dimensions.dx) / 2.0
dy = abs(self.height - dimensions.dy) / 2.0
return dimensions, Translation(dx, dy)