Skip to content

Geometry

momapy.geometry

Geometric primitives and transformations for momapy.

This module provides geometric classes and functions for working with points, lines, segments, curves, and transformations. It includes support for Bezier curves, elliptical arcs, and various geometric operations.

Examples:

>>> from momapy.geometry import Point, Line, Segment, Rotation, Translation
>>> # Create points
>>> p1 = Point(0, 0)
>>> p2 = Point(10, 10)
>>> # Create a line
>>> line = Line(p1, p2)
>>> line.slope()
1.0
>>> # Create a segment
>>> segment = Segment(p1, p2)
>>> segment.length()
14.14...
>>> # Apply transformations
>>> rotated = p1.transformed(Rotation(math.pi / 2, p2))

Classes:

Name Description
Bbox

Represents a bounding box.

BezierCurve

Represents a cubic Bezier curve.

EllipticalArc

Represents an elliptical arc.

GeometryObject

Abstract base class for all geometry objects.

Line

Represents an infinite line defined by two points.

MatrixTransformation

Represents a transformation as a 3x3 matrix.

Point

Represents a 2D point with x and y coordinates.

Rotation

Represents a rotation transformation.

Scaling

Represents a scaling transformation.

Segment

Represents a line segment between two points.

Transformation

Abstract base class for geometric transformations.

Translation

Represents a translation transformation.

Functions:

Name Description
are_lines_coincident

Check if two lines are coincident.

are_lines_parallel

Check if two lines are parallel.

get_angle_at_fraction_of_bezier_curve

Get angle at a fraction along a Bezier curve.

get_angle_at_fraction_of_elliptical_arc

Get angle at a fraction along an elliptical arc.

get_angle_at_fraction_of_segment

Get angle at a fraction along a segment.

get_angle_between_segments

Get angle between two segments.

get_angle_to_horizontal_of_line

Get angle of a line relative to horizontal.

get_angle_to_horizontal_of_point

Get angle from origin to point relative to horizontal.

get_center_of_elliptical_arc

Get center of an elliptical arc.

get_center_parameterization_of_elliptical_arc

Get center parameterization of an elliptical arc.

get_distance_between_line_and_point

Get perpendicular distance from a point to a line.

get_distance_between_points

Get distance between two points.

get_distance_between_segment_and_point

Get shortest distance from a point to a segment.

get_intersection_of_line_and_bezier_curve

Get intersection of a line and a Bezier curve.

get_intersection_of_line_and_elliptical_arc

Get intersection of a line and an elliptical arc.

get_intersection_of_line_and_point

Get intersection of a line and a point.

get_intersection_of_line_and_segment

Get intersection of a line and a segment.

get_intersection_of_line_and_shapely_object

Get intersection of a line with a shapely object.

get_intersection_of_lines

Get intersection of two lines.

get_normalized_angle

Normalize an angle to [0, 2*pi).

get_position_and_angle_at_fraction_of_bezier_curve

Get position and angle at a fraction along a Bezier curve.

get_position_and_angle_at_fraction_of_elliptical_arc

Get position and angle at a fraction along an elliptical arc.

get_position_and_angle_at_fraction_of_segment

Get position and angle at a fraction along a segment.

get_position_at_fraction_of_bezier_curve

Get point at a fraction along a Bezier curve.

get_position_at_fraction_of_elliptical_arc

Get point at a fraction along an elliptical arc.

get_position_at_fraction_of_segment

Get point at a fraction along a segment.

get_shapely_object_anchor_point

Get an anchor point of a shapely object.

get_shapely_object_angle

Get the border point at a given angle.

get_shapely_object_bbox

Get the bounding box of a shapely object.

get_shapely_object_border

Get the border point in a given direction.

get_transformation_for_frame

Get transformation for a frame defined by origin and axes.

invert_matrix_transformation

Invert a matrix transformation.

invert_rotation

Invert a rotation.

invert_scaling

Invert a scaling.

invert_translation

Invert a translation.

is_angle_between

Check if an angle is between two angles.

is_angle_in_sector

Check if an angle is within a sector.

line_has_point

Check if a point lies on a line.

reverse_bezier_curve

Reverse a Bezier curve.

reverse_elliptical_arc

Reverse an elliptical arc.

reverse_line

Reverse a line (swap endpoints).

reverse_point

Return a copy of the point (points are directionless).

reverse_segment

Reverse a segment (swap endpoints).

segment_has_point

Check if a point lies on a segment.

shorten_bezier_curve

Shorten a Bezier curve by a given length.

shorten_elliptical_arc

Shorten an elliptical arc by a given length.

shorten_segment

Shorten a segment by a given length.

transform_bezier_curve

Transform a Bezier curve.

transform_elliptical_arc

Transform an elliptical arc.

transform_elliptical_arc_to_bezier_curves

Convert an elliptical arc to Bezier curves.

transform_line

Transform a line.

transform_point

Transform a point.

transform_segment

Transform a segment.

Bbox dataclass

Bbox(position: Point, width: float, height: float)

Bases: object

Represents a bounding box.

Attributes:

Name Type Description
position Point

Center point.

width float

Width of the box.

height float

Height of the box.

Examples:

1
2
3
4
5
>>> bbox = Bbox(Point(5, 5), 10, 10)
>>> bbox.north_west()
Point(x=0.0, y=0.0)
>>> bbox.south_east()
Point(x=10.0, y=10.0)

Methods:

Name Description
anchor_point

Get a named anchor point.

center

Get the center point.

east

Get the east (right center) point.

east_north_east

Get the east-north-east point.

east_south_east

Get the east-south-east point.

from_bounds

Create a Bbox from shapely bounds.

isnan

Check if the position has NaN coordinates.

north

Get the north (top center) point.

north_east

Get the north-east corner.

north_north_east

Get the north-north-east point.

north_north_west

Get the north-north-west point.

north_west

Get the north-west corner.

size

Get the size as (width, height).

south

Get the south (bottom center) point.

south_east

Get the south-east corner.

south_south_east

Get the south-south-east point.

south_south_west

Get the south-south-west point.

south_west

Get the south-west corner.

west

Get the west (left center) point.

west_north_west

Get the west-north-west point.

west_south_west

Get the west-south-west point.

anchor_point

anchor_point(anchor_point: str) -> Point

Get a named anchor point.

Parameters:

Name Type Description Default
anchor_point str

Name like 'north', 'south_east', 'center', etc.

required

Returns:

Type Description
Point

The anchor point.

Source code in src/momapy/geometry.py
def anchor_point(self, anchor_point: str) -> Point:
    """Get a named anchor point.

    Args:
        anchor_point: Name like 'north', 'south_east', 'center', etc.

    Returns:
        The anchor point.
    """
    return getattr(self, anchor_point)()

center

center() -> Point

Get the center point.

Source code in src/momapy/geometry.py
def center(self) -> Point:
    """Get the center point."""
    return Point(self.x, self.y)

east

east() -> Point

Get the east (right center) point.

Source code in src/momapy/geometry.py
def east(self) -> Point:
    """Get the east (right center) point."""
    return Point(self.x + self.width / 2, self.y)

east_north_east

east_north_east() -> Point

Get the east-north-east point.

Source code in src/momapy/geometry.py
def east_north_east(self) -> Point:
    """Get the east-north-east point."""
    return Point(self.x + self.width / 2, self.y - self.height / 4)

east_south_east

east_south_east() -> Point

Get the east-south-east point.

Source code in src/momapy/geometry.py
def east_south_east(self) -> Point:
    """Get the east-south-east point."""
    return Point(self.x + self.width / 2, self.y + self.width / 4)

from_bounds classmethod

from_bounds(bounds: tuple[float, float, float, float])

Create a Bbox from shapely bounds.

Parameters:

Name Type Description Default
bounds tuple[float, float, float, float]

Tuple of (min_x, min_y, max_x, max_y).

required

Returns:

Type Description

A new Bbox.

Source code in src/momapy/geometry.py
@classmethod
def from_bounds(cls, bounds: tuple[float, float, float, float]):
    """Create a Bbox from shapely bounds.

    Args:
        bounds: Tuple of (min_x, min_y, max_x, max_y).

    Returns:
        A new Bbox.
    """
    return cls(
        Point((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2),
        bounds[2] - bounds[0],
        bounds[3] - bounds[1],
    )

isnan

isnan() -> bool

Check if the position has NaN coordinates.

Returns:

Type Description
bool

True if position has NaN.

Source code in src/momapy/geometry.py
def isnan(self) -> bool:
    """Check if the position has NaN coordinates.

    Returns:
        True if position has NaN.
    """
    return self.position.isnan()

north

north() -> Point

Get the north (top center) point.

Source code in src/momapy/geometry.py
def north(self) -> Point:
    """Get the north (top center) point."""
    return Point(self.x, self.y - self.height / 2)

north_east

north_east() -> Point

Get the north-east corner.

Source code in src/momapy/geometry.py
def north_east(self) -> Point:
    """Get the north-east corner."""
    return Point(self.x + self.width / 2, self.y - self.height / 2)

north_north_east

north_north_east() -> Point

Get the north-north-east point.

Source code in src/momapy/geometry.py
def north_north_east(self) -> Point:
    """Get the north-north-east point."""
    return Point(self.x + self.width / 4, self.y - self.height / 2)

north_north_west

north_north_west() -> Point

Get the north-north-west point.

Source code in src/momapy/geometry.py
def north_north_west(self) -> Point:
    """Get the north-north-west point."""
    return Point(self.x - self.width / 4, self.y - self.height / 2)

north_west

north_west() -> Point

Get the north-west corner.

Source code in src/momapy/geometry.py
def north_west(self) -> Point:
    """Get the north-west corner."""
    return Point(self.x - self.width / 2, self.y - self.height / 2)

size

size() -> tuple[float, float]

Get the size as (width, height).

Returns:

Type Description
tuple[float, float]

Tuple of (width, height).

Source code in src/momapy/geometry.py
def size(self) -> tuple[float, float]:
    """Get the size as (width, height).

    Returns:
        Tuple of (width, height).
    """
    return (self.width, self.height)

south

south() -> Point

Get the south (bottom center) point.

Source code in src/momapy/geometry.py
def south(self) -> Point:
    """Get the south (bottom center) point."""
    return Point(self.x, self.y + self.height / 2)

south_east

south_east() -> Point

Get the south-east corner.

Source code in src/momapy/geometry.py
def south_east(self) -> Point:
    """Get the south-east corner."""
    return Point(self.x + self.width / 2, self.y + self.height / 2)

south_south_east

south_south_east() -> Point

Get the south-south-east point.

Source code in src/momapy/geometry.py
def south_south_east(self) -> Point:
    """Get the south-south-east point."""
    return Point(self.x + self.width / 4, self.y + self.height / 2)

south_south_west

south_south_west() -> Point

Get the south-south-west point.

Source code in src/momapy/geometry.py
def south_south_west(self) -> Point:
    """Get the south-south-west point."""
    return Point(self.x - self.width / 4, self.y + self.height / 2)

south_west

south_west() -> Point

Get the south-west corner.

Source code in src/momapy/geometry.py
def south_west(self) -> Point:
    """Get the south-west corner."""
    return Point(self.x - self.width / 2, self.y + self.height / 2)

west

west() -> Point

Get the west (left center) point.

Source code in src/momapy/geometry.py
def west(self) -> Point:
    """Get the west (left center) point."""
    return Point(self.x - self.width / 2, self.y)

west_north_west

west_north_west() -> Point

Get the west-north-west point.

Source code in src/momapy/geometry.py
def west_north_west(self) -> Point:
    """Get the west-north-west point."""
    return Point(self.x - self.width / 2, self.y - self.height / 4)

west_south_west

west_south_west() -> Point

Get the west-south-west point.

Source code in src/momapy/geometry.py
def west_south_west(self) -> Point:
    """Get the west-south-west point."""
    return Point(self.x - self.width / 2, self.y + self.height / 4)

x property

x: float

The x coordinate of the center.

y property

y: float

The y coordinate of the center.

BezierCurve dataclass

BezierCurve(p1: Point, p2: Point, control_points: tuple[Point, ...] = tuple())

Bases: GeometryObject

Represents a cubic Bezier curve.

Attributes:

Name Type Description
p1 Point

Start point.

p2 Point

End point.

control_points tuple[Point, ...]

Tuple of control points (1 for quadratic, 2 for cubic).

Examples:

1
2
3
4
5
6
7
>>> curve = BezierCurve(
...     Point(0, 0),
...     Point(10, 0),
...     (Point(3, 5), Point(7, 5))
... )
>>> curve.length()
11.77...

Methods:

Name Description
bbox

Get the bounding box of the curve.

evaluate

Evaluate the curve at parameter s.

evaluate_multi

Evaluate the curve at multiple parameters.

get_angle_at_fraction

Get angle at a fraction along the curve.

get_intersection_with_line

Get intersection with a line.

get_position_and_angle_at_fraction

Get both position and angle at a fraction.

get_position_at_fraction

Get point at a fraction along the curve.

length

Calculate the length of the curve.

reversed

Return a reversed copy of the curve.

shortened

Return a shortened copy of the curve.

to_shapely

Convert to a shapely LineString.

transformed

Apply a transformation to this curve.

bbox

bbox()

Get the bounding box of the curve.

Returns:

Type Description

A Bbox enclosing the curve.

Source code in src/momapy/geometry.py
def bbox(self):
    """Get the bounding box of the curve.

    Returns:
        A Bbox enclosing the curve.
    """
    return Bbox.from_bounds(self.to_shapely().bounds)

evaluate

evaluate(s: float) -> Point

Evaluate the curve at parameter s.

Parameters:

Name Type Description Default
s float

Parameter value from 0 to 1.

required

Returns:

Type Description
Point

The point at parameter s.

Source code in src/momapy/geometry.py
def evaluate(self, s: float) -> Point:
    """Evaluate the curve at parameter s.

    Args:
        s: Parameter value from 0 to 1.

    Returns:
        The point at parameter s.
    """
    evaluation = self._to_bezier().evaluate(s)
    return Point.from_fortranarray(evaluation)

evaluate_multi

evaluate_multi(s: ndarray) -> list[Point]

Evaluate the curve at multiple parameters.

Parameters:

Name Type Description Default
s ndarray

Array of parameter values.

required

Returns:

Type Description
list[Point]

List of points.

Source code in src/momapy/geometry.py
def evaluate_multi(self, s: numpy.ndarray) -> list[Point]:
    """Evaluate the curve at multiple parameters.

    Args:
        s: Array of parameter values.

    Returns:
        List of points.
    """
    evaluation = self._to_bezier().evaluate_multi(s)
    return [Point(e[0], e[1]) for e in evaluation.T]

get_angle_at_fraction

get_angle_at_fraction(fraction: float)

Get angle at a fraction along the curve.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_at_fraction(self, fraction: float):
    """Get angle at a fraction along the curve.

    Args:
        fraction: Fraction from 0 to 1.

    Returns:
        Angle in radians.
    """
    return get_angle_at_fraction_of_bezier_curve(self, fraction)

get_intersection_with_line

get_intersection_with_line(line: Line) -> list[Point] | list[Segment]

Get intersection with a line.

Parameters:

Name Type Description Default
line Line

The line to intersect with.

required

Returns:

Type Description
list[Point] | list[Segment]

List of intersection points or segments.

Source code in src/momapy/geometry.py
def get_intersection_with_line(self, line: Line) -> list[Point] | list[Segment]:
    """Get intersection with a line.

    Args:
        line: The line to intersect with.

    Returns:
        List of intersection points or segments.
    """
    return get_intersection_of_line_and_bezier_curve(line, self)

get_position_and_angle_at_fraction

get_position_and_angle_at_fraction(fraction: float)

Get both position and angle at a fraction.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description

Tuple of (point, angle).

Source code in src/momapy/geometry.py
def get_position_and_angle_at_fraction(self, fraction: float):
    """Get both position and angle at a fraction.

    Args:
        fraction: Fraction from 0 to 1.

    Returns:
        Tuple of (point, angle).
    """
    return get_position_and_angle_at_fraction_of_bezier_curve(self, fraction)

get_position_at_fraction

get_position_at_fraction(fraction: float)

Get point at a fraction along the curve.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description

The point at that fraction.

Source code in src/momapy/geometry.py
def get_position_at_fraction(self, fraction: float):
    """Get point at a fraction along the curve.

    Args:
        fraction: Fraction from 0 to 1.

    Returns:
        The point at that fraction.
    """
    return get_position_at_fraction_of_bezier_curve(self, fraction)

length

length() -> float

Calculate the length of the curve.

Returns:

Type Description
float

The arc length.

Source code in src/momapy/geometry.py
def length(self) -> float:
    """Calculate the length of the curve.

    Returns:
        The arc length.
    """
    return self._to_bezier().length

reversed

reversed()

Return a reversed copy of the curve.

Returns:

Type Description

A new BezierCurve going in reverse direction.

Source code in src/momapy/geometry.py
def reversed(self):
    """Return a reversed copy of the curve.

    Returns:
        A new BezierCurve going in reverse direction.
    """
    return reverse_bezier_curve(self)

shortened

shortened(length: float, start_or_end: Literal['start', 'end'] = 'end') -> BezierCurve

Return a shortened copy of the curve.

Parameters:

Name Type Description Default
length float

Amount to shorten by.

required
start_or_end Literal['start', 'end']

Which end to shorten from.

'end'

Returns:

Type Description
BezierCurve

A new shortened BezierCurve.

Source code in src/momapy/geometry.py
def shortened(
    self, length: float, start_or_end: typing.Literal["start", "end"] = "end"
) -> "BezierCurve":
    """Return a shortened copy of the curve.

    Args:
        length: Amount to shorten by.
        start_or_end: Which end to shorten from.

    Returns:
        A new shortened BezierCurve.
    """
    return shorten_bezier_curve(self, length, start_or_end)

to_shapely

to_shapely(n_segs=50)

Convert to a shapely LineString.

Parameters:

Name Type Description Default
n_segs

Number of segments to approximate with.

50

Returns:

Type Description

A shapely LineString.

Source code in src/momapy/geometry.py
def to_shapely(self, n_segs=50):
    """Convert to a shapely LineString.

    Args:
        n_segs: Number of segments to approximate with.

    Returns:
        A shapely LineString.
    """
    points = self.evaluate_multi(
        numpy.arange(0, 1 + 1 / n_segs, 1 / n_segs, dtype="double")
    )
    return shapely.LineString([point.to_tuple() for point in points])

transformed

transformed(transformation)

Apply a transformation to this curve.

Parameters:

Name Type Description Default
transformation

The transformation to apply.

required

Returns:

Type Description

A new transformed BezierCurve.

Source code in src/momapy/geometry.py
def transformed(self, transformation):
    """Apply a transformation to this curve.

    Args:
        transformation: The transformation to apply.

    Returns:
        A new transformed BezierCurve.
    """
    return transform_bezier_curve(self, transformation)

EllipticalArc dataclass

EllipticalArc(p1: Point, p2: Point, rx: float, ry: float, x_axis_rotation: float, arc_flag: int, sweep_flag: int)

Bases: GeometryObject

Represents an elliptical arc.

Attributes:

Name Type Description
p1 Point

Start point.

p2 Point

End point.

rx float

X-radius of the ellipse.

ry float

Y-radius of the ellipse.

x_axis_rotation float

Rotation of the x-axis in radians.

arc_flag int

Large arc flag (0 or 1).

sweep_flag int

Sweep flag (0 or 1).

Examples:

1
2
3
>>> arc = EllipticalArc(
...     Point(0, 0), Point(10, 0), 5, 5, 0, 0, 1
... )

Methods:

Name Description
bbox

Get the bounding box of the arc.

get_angle_at_fraction

Get angle at a fraction along the arc.

get_center

Get the center point of the ellipse.

get_center_parameterization

Get the center parameterization of the arc.

get_intersection_with_line

Get intersection with a line.

get_position_and_angle_at_fraction

Get both position and angle at a fraction.

get_position_at_fraction

Get point at a fraction along the arc.

length

Calculate the length of the arc.

reversed

Return a reversed copy of the arc.

shortened

Return a shortened copy of the arc.

to_bezier_curves

Convert to Bezier curves.

to_shapely

Convert to a shapely LineString.

transformed

Apply a transformation to this arc.

bbox

bbox() -> Bbox

Get the bounding box of the arc.

Returns:

Type Description
Bbox

A Bbox enclosing the arc.

Source code in src/momapy/geometry.py
def bbox(self) -> "Bbox":
    """Get the bounding box of the arc.

    Returns:
        A Bbox enclosing the arc.
    """
    return Bbox.from_bounds(self.to_shapely().bounds)

get_angle_at_fraction

get_angle_at_fraction(fraction: float) -> float

Get angle at a fraction along the arc.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_at_fraction(self, fraction: float) -> float:
    """Get angle at a fraction along the arc.

    Args:
        fraction: Fraction from 0 to 1.

    Returns:
        Angle in radians.
    """
    return get_angle_at_fraction_of_elliptical_arc(self, fraction)

get_center

get_center() -> Point

Get the center point of the ellipse.

Returns:

Type Description
Point

The center point.

Source code in src/momapy/geometry.py
def get_center(self) -> Point:
    """Get the center point of the ellipse.

    Returns:
        The center point.
    """
    return get_center_of_elliptical_arc(self)

get_center_parameterization

get_center_parameterization() -> tuple[float, float, float, float, float, float, float, float]

Get the center parameterization of the arc.

Returns:

Type Description
tuple[float, float, float, float, float, float, float, float]

Tuple of (cx, cy, rx, ry, sigma, theta1, theta2, delta_theta).

Source code in src/momapy/geometry.py
def get_center_parameterization(
    self,
) -> tuple[float, float, float, float, float, float, float, float]:
    """Get the center parameterization of the arc.

    Returns:
        Tuple of (cx, cy, rx, ry, sigma, theta1, theta2, delta_theta).
    """
    return get_center_parameterization_of_elliptical_arc(self)

get_intersection_with_line

get_intersection_with_line(line: Line) -> list[Point]

Get intersection with a line.

Parameters:

Name Type Description Default
line Line

The line to intersect with.

required

Returns:

Type Description
list[Point]

List of intersection points.

Source code in src/momapy/geometry.py
def get_intersection_with_line(self, line: Line) -> list[Point]:
    """Get intersection with a line.

    Args:
        line: The line to intersect with.

    Returns:
        List of intersection points.
    """
    return get_intersection_of_line_and_elliptical_arc(line, self)

get_position_and_angle_at_fraction

get_position_and_angle_at_fraction(fraction: float) -> tuple[Point, float]

Get both position and angle at a fraction.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
tuple[Point, float]

Tuple of (point, angle).

Source code in src/momapy/geometry.py
def get_position_and_angle_at_fraction(
    self, fraction: float
) -> tuple[Point, float]:
    """Get both position and angle at a fraction.

    Args:
        fraction: Fraction from 0 to 1.

    Returns:
        Tuple of (point, angle).
    """
    return get_position_and_angle_at_fraction_of_elliptical_arc(self, fraction)

get_position_at_fraction

get_position_at_fraction(fraction: float) -> Point

Get point at a fraction along the arc.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
Point

The point at that fraction.

Source code in src/momapy/geometry.py
def get_position_at_fraction(self, fraction: float) -> Point:
    """Get point at a fraction along the arc.

    Args:
        fraction: Fraction from 0 to 1.

    Returns:
        The point at that fraction.
    """
    return get_position_at_fraction_of_elliptical_arc(self, fraction)

length

length() -> float

Calculate the length of the arc.

Returns:

Type Description
float

The arc length.

Source code in src/momapy/geometry.py
def length(self) -> float:
    """Calculate the length of the arc.

    Returns:
        The arc length.
    """
    return self.to_shapely().length

reversed

reversed() -> EllipticalArc

Return a reversed copy of the arc.

Returns:

Type Description
EllipticalArc

A new EllipticalArc going in reverse direction.

Source code in src/momapy/geometry.py
def reversed(self) -> "EllipticalArc":
    """Return a reversed copy of the arc.

    Returns:
        A new EllipticalArc going in reverse direction.
    """
    return reverse_elliptical_arc(self)

shortened

shortened(length: float, start_or_end: Literal['start', 'end'] = 'end') -> EllipticalArc

Return a shortened copy of the arc.

Parameters:

Name Type Description Default
length float

Amount to shorten by.

required
start_or_end Literal['start', 'end']

Which end to shorten from.

'end'

Returns:

Type Description
EllipticalArc

A new shortened EllipticalArc.

Source code in src/momapy/geometry.py
def shortened(
    self,
    length: float,
    start_or_end: typing.Literal["start", "end"] = "end",
) -> "EllipticalArc":
    """Return a shortened copy of the arc.

    Args:
        length: Amount to shorten by.
        start_or_end: Which end to shorten from.

    Returns:
        A new shortened EllipticalArc.
    """
    return shorten_elliptical_arc(self, length, start_or_end)

to_bezier_curves

to_bezier_curves() -> BezierCurve

Convert to Bezier curves.

Returns:

Type Description
BezierCurve

BezierCurve(s) approximating the arc.

Source code in src/momapy/geometry.py
def to_bezier_curves(self) -> BezierCurve:
    """Convert to Bezier curves.

    Returns:
        BezierCurve(s) approximating the arc.
    """
    return transform_elliptical_arc_to_bezier_curves(self)

to_shapely

to_shapely()

Convert to a shapely LineString.

Returns:

Type Description

A shapely LineString approximating the arc.

Source code in src/momapy/geometry.py
def to_shapely(self):
    """Convert to a shapely LineString.

    Returns:
        A shapely LineString approximating the arc.
    """
    def _split_line_string(
        line_string: shapely.LineString,
        point: Point,
    ):
        segment = Segment(
            Point.from_tuple(line_string.coords[0]),
            Point.from_tuple(line_string.coords[1]),
        )
        min_distance = segment.get_distance_to_point(point)
        min_i = 0
        for i, current_coord in enumerate(line_string.coords[2:]):
            previous_coord = line_string.coords[i + 1]
            segment = Segment(
                Point.from_tuple(previous_coord),
                Point.from_tuple(current_coord),
            )
            distance = segment.get_distance_to_point(point)
            if distance <= min_distance:
                min_distance = distance
                min_i = i
        left_coords = line_string.coords[0 : min_i + 1] + [point.to_shapely()]
        right_coords = [point.to_shapely()] + line_string.coords[min_i + 1 :]
        left_line_string = shapely.LineString(left_coords)
        right_line_string = shapely.LineString(right_coords)
        return [left_line_string, right_line_string]

    origin = shapely.Point(0, 0)
    circle = origin.buffer(1.0).boundary
    ellipse = shapely.affinity.scale(circle, self.rx, self.ry)
    ellipse = shapely.affinity.rotate(ellipse, self.x_axis_rotation)
    center = self.get_center()
    ellipse = shapely.affinity.translate(ellipse, center.x, center.y)
    line1 = Line(center, Point.from_tuple(ellipse.coords[0]))
    angle1 = get_angle_to_horizontal_of_line(line1)
    line2 = Line(center, Point.from_tuple(ellipse.coords[-2]))
    angle2 = get_angle_to_horizontal_of_line(line2)
    angle = angle1 - angle2
    if angle >= 0:
        sweep = 1
    else:
        sweep = 0
    if sweep != self.sweep_flag:
        ellipse = shapely.LineString(ellipse.coords[::-1])
    if ellipse.coords[0] == self.p1.to_tuple():
        ellipse = shapely.LineString(ellipse.coords[1:] + [ellipse.coords[0]])
    first_split = _split_line_string(ellipse, self.p1)
    multi_line = shapely.MultiLineString([first_split[1], first_split[0]])
    line_string = shapely.ops.linemerge(multi_line)
    second_split = _split_line_string(line_string, self.p2)
    shapely_arc = second_split[0]
    return shapely_arc

transformed

transformed(transformation: Transformation) -> EllipticalArc

Apply a transformation to this arc.

Parameters:

Name Type Description Default
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
EllipticalArc

A new transformed EllipticalArc.

Source code in src/momapy/geometry.py
def transformed(self, transformation: "Transformation") -> "EllipticalArc":
    """Apply a transformation to this arc.

    Args:
        transformation: The transformation to apply.

    Returns:
        A new transformed EllipticalArc.
    """
    return transform_elliptical_arc(self, transformation)

GeometryObject dataclass

GeometryObject()

Bases: ABC

Abstract base class for all geometry objects.

Methods:

Name Description
to_shapely

Convert to a shapely geometry object.

to_shapely abstractmethod

to_shapely() -> Geometry

Convert to a shapely geometry object.

Returns:

Type Description
Geometry

A shapely geometry representing this object.

Source code in src/momapy/geometry.py
@abc.abstractmethod
def to_shapely(self) -> shapely.Geometry:
    """Convert to a shapely geometry object.

    Returns:
        A shapely geometry representing this object.
    """
    pass

Line dataclass

Line(p1: Point, p2: Point)

Bases: GeometryObject

Represents an infinite line defined by two points.

Attributes:

Name Type Description
p1 Point

First point on the line.

p2 Point

Second point on the line.

Examples:

1
2
3
4
5
>>> line = Line(Point(0, 0), Point(10, 10))
>>> line.slope()
1.0
>>> line.intercept()
0.0

Methods:

Name Description
get_angle_to_horizontal

Get the angle of the line relative to horizontal.

get_distance_to_point

Get perpendicular distance from a point to this line.

get_intersection_with_line

Get intersection with another line.

has_point

Check if a point lies on this line.

intercept

Calculate the y-intercept of the line.

is_coincident_to_line

Check if this line is coincident with another.

is_parallel_to_line

Check if this line is parallel to another.

reversed

Return a reversed copy of the line.

slope

Calculate the slope of the line.

to_shapely

Convert to a shapely LineString.

transformed

Apply a transformation to this line.

get_angle_to_horizontal

get_angle_to_horizontal() -> float

Get the angle of the line relative to horizontal.

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_to_horizontal(self) -> float:
    """Get the angle of the line relative to horizontal.

    Returns:
        Angle in radians.
    """
    return get_angle_to_horizontal_of_line(self)

get_distance_to_point

get_distance_to_point(point: Point) -> float

Get perpendicular distance from a point to this line.

Parameters:

Name Type Description Default
point Point

The point to measure from.

required

Returns:

Type Description
float

The perpendicular distance.

Source code in src/momapy/geometry.py
def get_distance_to_point(self, point: Point) -> float:
    """Get perpendicular distance from a point to this line.

    Args:
        point: The point to measure from.

    Returns:
        The perpendicular distance.
    """
    return get_distance_between_line_and_point(self, point)

get_intersection_with_line

get_intersection_with_line(line: Line) -> list[Line] | list[Point]

Get intersection with another line.

Parameters:

Name Type Description Default
line Line

The other line.

required

Returns:

Type Description
list[Line] | list[Point]

List containing intersection point(s) or the coincident line.

Source code in src/momapy/geometry.py
def get_intersection_with_line(self, line: "Line") -> list["Line"] | list["Point"]:
    """Get intersection with another line.

    Args:
        line: The other line.

    Returns:
        List containing intersection point(s) or the coincident line.
    """
    return get_intersection_of_lines(self, line)

has_point

has_point(point: Point, max_distance: float = 0.01) -> bool

Check if a point lies on this line.

Parameters:

Name Type Description Default
point Point

The point to check.

required
max_distance float

Maximum allowed distance from line.

0.01

Returns:

Type Description
bool

True if point is on the line within tolerance.

Source code in src/momapy/geometry.py
def has_point(self, point: Point, max_distance: float = 0.01) -> bool:
    """Check if a point lies on this line.

    Args:
        point: The point to check.
        max_distance: Maximum allowed distance from line.

    Returns:
        True if point is on the line within tolerance.
    """
    return line_has_point(self, point, max_distance)

intercept

intercept() -> float

Calculate the y-intercept of the line.

Returns:

Type Description
float

The y-intercept, or NaN if vertical.

Source code in src/momapy/geometry.py
def intercept(self) -> float:
    """Calculate the y-intercept of the line.

    Returns:
        The y-intercept, or NaN if vertical.
    """
    slope = self.slope()
    if not math.isnan(slope):
        return self.p1.y - slope * self.p1.x
    else:
        return float("NAN")

is_coincident_to_line

is_coincident_to_line(line: Line) -> bool

Check if this line is coincident with another.

Parameters:

Name Type Description Default
line Line

The other line.

required

Returns:

Type Description
bool

True if coincident (same infinite line).

Source code in src/momapy/geometry.py
def is_coincident_to_line(self, line: "Line") -> bool:
    """Check if this line is coincident with another.

    Args:
        line: The other line.

    Returns:
        True if coincident (same infinite line).
    """
    return are_lines_coincident(self, line)

is_parallel_to_line

is_parallel_to_line(line: Line) -> bool

Check if this line is parallel to another.

Parameters:

Name Type Description Default
line Line

The other line.

required

Returns:

Type Description
bool

True if parallel.

Source code in src/momapy/geometry.py
def is_parallel_to_line(self, line: "Line") -> bool:
    """Check if this line is parallel to another.

    Args:
        line: The other line.

    Returns:
        True if parallel.
    """
    return are_lines_parallel(self, line)

reversed

reversed() -> Line

Return a reversed copy of the line.

Returns:

Type Description
Line

A new Line with p1 and p2 swapped.

Source code in src/momapy/geometry.py
def reversed(self) -> "Line":
    """Return a reversed copy of the line.

    Returns:
        A new Line with p1 and p2 swapped.
    """
    return reverse_line(self)

slope

slope() -> float

Calculate the slope of the line.

Returns:

Type Description
float

The slope, or NaN if vertical.

Source code in src/momapy/geometry.py
def slope(self) -> float:
    """Calculate the slope of the line.

    Returns:
        The slope, or NaN if vertical.
    """
    if self.p1.x != self.p2.x:
        return round((self.p2.y - self.p1.y) / (self.p2.x - self.p1.x), ROUNDING)
    return float("NAN")

to_shapely

to_shapely() -> LineString

Convert to a shapely LineString.

Returns:

Type Description
LineString

A shapely LineString.

Source code in src/momapy/geometry.py
def to_shapely(self) -> shapely.LineString:
    """Convert to a shapely LineString.

    Returns:
        A shapely LineString.
    """
    return shapely.LineString(
        [
            self.p1.to_tuple(),
            self.p2.to_tuple(),
        ]
    )

transformed

transformed(transformation: Transformation) -> Line

Apply a transformation to this line.

Parameters:

Name Type Description Default
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
Line

A new transformed Line.

Source code in src/momapy/geometry.py
def transformed(self, transformation: "Transformation") -> "Line":
    """Apply a transformation to this line.

    Args:
        transformation: The transformation to apply.

    Returns:
        A new transformed Line.
    """
    return transform_line(self, transformation)

MatrixTransformation dataclass

MatrixTransformation(m: NDArray)

Bases: Transformation

Represents a transformation as a 3x3 matrix.

Attributes:

Name Type Description
m NDArray

The 3x3 transformation matrix.

Methods:

Name Description
inverted

Get the inverse transformation.

to_matrix

Get the matrix representation.

inverted

inverted() -> Transformation

Get the inverse transformation.

Returns:

Type Description
Transformation

The inverse matrix transformation.

Source code in src/momapy/geometry.py
def inverted(self) -> Transformation:
    """Get the inverse transformation.

    Returns:
        The inverse matrix transformation.
    """
    return invert_matrix_transformation(self)

to_matrix

to_matrix() -> NDArray

Get the matrix representation.

Returns:

Type Description
NDArray

The 3x3 matrix.

Source code in src/momapy/geometry.py
def to_matrix(self) -> numpy.typing.NDArray:
    """Get the matrix representation.

    Returns:
        The 3x3 matrix.
    """
    return self.m

Point dataclass

Point(x: float, y: float)

Bases: GeometryObject

Represents a 2D point with x and y coordinates.

Attributes:

Name Type Description
x float

The x-coordinate.

y float

The y-coordinate.

Examples:

1
2
3
4
5
>>> p = Point(10, 20)
>>> p.x
10
>>> p + (5, 5)
Point(x=15, y=25)

Methods:

Name Description
bbox

Get the bounding box of this point.

from_fortranarray

Create a Point from a numpy Fortran array.

from_shapely

Create a Point from a shapely Point.

from_tuple

Create a Point from a tuple.

get_angle_to_horizontal

Get the angle from origin to this point relative to horizontal.

get_intersection_with_line

Get intersection points with a line.

isnan

Check if either coordinate is NaN.

reversed

Return a reversed copy (identity for points).

round

Round coordinates to specified digits.

to_fortranarray

Convert to a numpy Fortran array.

to_matrix

Convert to a 3x1 numpy matrix for transformation operations.

to_shapely

Convert to a shapely Point.

to_tuple

Convert to a tuple.

transformed

Apply a transformation to this point.

bbox

bbox() -> Bbox

Get the bounding box of this point.

Returns:

Type Description
Bbox

A Bbox with zero width and height.

Source code in src/momapy/geometry.py
def bbox(self) -> "Bbox":
    """Get the bounding box of this point.

    Returns:
        A Bbox with zero width and height.
    """
    return Bbox(copy.deepcopy(self), 0, 0)

from_fortranarray classmethod

from_fortranarray(fortranarray: Any) -> Self

Create a Point from a numpy Fortran array.

Parameters:

Name Type Description Default
fortranarray Any

A 2x1 array [[x], [y]].

required

Returns:

Type Description
Self

A new Point.

Source code in src/momapy/geometry.py
@classmethod
def from_fortranarray(cls, fortranarray: typing.Any) -> typing_extensions.Self:
    """Create a Point from a numpy Fortran array.

    Args:
        fortranarray: A 2x1 array [[x], [y]].

    Returns:
        A new Point.
    """
    return cls(fortranarray[0][0], fortranarray[1][1])

from_shapely classmethod

from_shapely(point: Point) -> Self

Create a Point from a shapely Point.

Parameters:

Name Type Description Default
point Point

A shapely Point.

required

Returns:

Type Description
Self

A new Point.

Source code in src/momapy/geometry.py
@classmethod
def from_shapely(cls, point: shapely.Point) -> typing_extensions.Self:
    """Create a Point from a shapely Point.

    Args:
        point: A shapely Point.

    Returns:
        A new Point.
    """
    return cls(float(point.x), float(point.y))

from_tuple classmethod

from_tuple(t: tuple[float, float]) -> Self

Create a Point from a tuple.

Parameters:

Name Type Description Default
t tuple[float, float]

Tuple (x, y).

required

Returns:

Type Description
Self

A new Point.

Source code in src/momapy/geometry.py
@classmethod
def from_tuple(cls, t: tuple[float, float]) -> typing_extensions.Self:
    """Create a Point from a tuple.

    Args:
        t: Tuple (x, y).

    Returns:
        A new Point.
    """
    return cls(t[0], t[1])

get_angle_to_horizontal

get_angle_to_horizontal() -> float

Get the angle from origin to this point relative to horizontal.

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_to_horizontal(self) -> float:
    """Get the angle from origin to this point relative to horizontal.

    Returns:
        Angle in radians.
    """
    return get_angle_to_horizontal_of_point(self)

get_intersection_with_line

get_intersection_with_line(line: Line) -> list[Point]

Get intersection points with a line.

Parameters:

Name Type Description Default
line Line

The line to intersect with.

required

Returns:

Type Description
list[Point]

List of intersection points (empty if no intersection).

Source code in src/momapy/geometry.py
def get_intersection_with_line(self, line: "Line") -> list["Point"]:
    """Get intersection points with a line.

    Args:
        line: The line to intersect with.

    Returns:
        List of intersection points (empty if no intersection).
    """
    return get_intersection_of_line_and_point(line, self)

isnan

isnan() -> bool

Check if either coordinate is NaN.

Returns:

Type Description
bool

True if x or y is NaN.

Source code in src/momapy/geometry.py
def isnan(self) -> bool:
    """Check if either coordinate is NaN.

    Returns:
        True if x or y is NaN.
    """
    return math.isnan(self.x) or math.isnan(self.y)

reversed

reversed() -> Point

Return a reversed copy (identity for points).

Returns:

Type Description
Point

A copy of the point.

Source code in src/momapy/geometry.py
def reversed(self) -> "Point":
    """Return a reversed copy (identity for points).

    Returns:
        A copy of the point.
    """
    return reverse_point(self)

round

round(ndigits=None)

Round coordinates to specified digits.

Parameters:

Name Type Description Default
ndigits

Number of decimal places.

None

Returns:

Type Description

A new Point with rounded coordinates.

Source code in src/momapy/geometry.py
def round(self, ndigits=None):
    """Round coordinates to specified digits.

    Args:
        ndigits: Number of decimal places.

    Returns:
        A new Point with rounded coordinates.
    """
    return Point(round(self.x, ndigits), round(self.y, ndigits))

to_fortranarray

to_fortranarray() -> Any

Convert to a numpy Fortran array.

Returns:

Type Description
Any

A 2x1 Fortran array [[x], [y]].

Source code in src/momapy/geometry.py
def to_fortranarray(self) -> typing.Any:
    """Convert to a numpy Fortran array.

    Returns:
        A 2x1 Fortran array [[x], [y]].
    """
    return numpy.asfortranarray([[self.x], [self.y]])

to_matrix

to_matrix() -> ndarray

Convert to a 3x1 numpy matrix for transformation operations.

Returns:

Type Description
ndarray

A numpy array [[x], [y], [1]].

Source code in src/momapy/geometry.py
def to_matrix(self) -> numpy.ndarray:
    """Convert to a 3x1 numpy matrix for transformation operations.

    Returns:
        A numpy array [[x], [y], [1]].
    """
    m = numpy.array([[self.x], [self.y], [1]], dtype=float)
    return m

to_shapely

to_shapely() -> Point

Convert to a shapely Point.

Returns:

Type Description
Point

A shapely Point.

Source code in src/momapy/geometry.py
def to_shapely(self) -> shapely.Point:
    """Convert to a shapely Point.

    Returns:
        A shapely Point.
    """
    return shapely.Point(self.x, self.y)

to_tuple

to_tuple() -> tuple[float, float]

Convert to a tuple.

Returns:

Type Description
tuple[float, float]

Tuple (x, y).

Source code in src/momapy/geometry.py
def to_tuple(self) -> tuple[float, float]:
    """Convert to a tuple.

    Returns:
        Tuple (x, y).
    """
    return (
        self.x,
        self.y,
    )

transformed

transformed(transformation: Transformation) -> Point

Apply a transformation to this point.

Parameters:

Name Type Description Default
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
Point

A new transformed Point.

Source code in src/momapy/geometry.py
def transformed(self, transformation: "Transformation") -> "Point":
    """Apply a transformation to this point.

    Args:
        transformation: The transformation to apply.

    Returns:
        A new transformed Point.
    """
    return transform_point(self, transformation)

Rotation dataclass

Rotation(angle: float, point: Point | None = None)

Bases: Transformation

Represents a rotation transformation.

Attributes:

Name Type Description
angle float

Rotation angle in radians.

point Point | None

Optional center of rotation (defaults to origin).

Examples:

>>> rot = Rotation(math.pi / 2, Point(5, 5))

Methods:

Name Description
inverted

Get the inverse rotation.

to_matrix

Convert to a rotation matrix.

inverted

inverted() -> Transformation

Get the inverse rotation.

Returns:

Type Description
Transformation

A rotation by the negative angle.

Source code in src/momapy/geometry.py
def inverted(self) -> Transformation:
    """Get the inverse rotation.

    Returns:
        A rotation by the negative angle.
    """
    return invert_rotation(self)

to_matrix

to_matrix() -> NDArray

Convert to a rotation matrix.

Returns:

Type Description
NDArray

A 3x3 rotation matrix.

Source code in src/momapy/geometry.py
def to_matrix(self) -> numpy.typing.NDArray:
    """Convert to a rotation matrix.

    Returns:
        A 3x3 rotation matrix.
    """
    m = numpy.array(
        [
            [math.cos(self.angle), -math.sin(self.angle), 0],
            [math.sin(self.angle), math.cos(self.angle), 0],
            [0, 0, 1],
        ],
        dtype=float,
    )
    if self.point is not None:
        translation = Translation(self.point.x, self.point.y)
        m = numpy.matmul(
            numpy.matmul(translation.to_matrix(), m),
            translation.inverted().to_matrix(),
        )
    return m

Scaling dataclass

Scaling(sx: float, sy: float)

Bases: Transformation

Represents a scaling transformation.

Attributes:

Name Type Description
sx float

Scale factor in x direction.

sy float

Scale factor in y direction.

Examples:

>>> scale = Scaling(2, 2)  # Double size

Methods:

Name Description
inverted

Get the inverse scaling.

to_matrix

Convert to a scaling matrix.

inverted

inverted() -> Transformation

Get the inverse scaling.

Returns:

Type Description
Transformation

Scaling by (1/sx, 1/sy).

Source code in src/momapy/geometry.py
def inverted(self) -> Transformation:
    """Get the inverse scaling.

    Returns:
        Scaling by (1/sx, 1/sy).
    """
    return invert_scaling(self)

to_matrix

to_matrix() -> NDArray

Convert to a scaling matrix.

Returns:

Type Description
NDArray

A 3x3 scaling matrix.

Source code in src/momapy/geometry.py
def to_matrix(self) -> numpy.typing.NDArray:
    """Convert to a scaling matrix.

    Returns:
        A 3x3 scaling matrix.
    """
    m = numpy.array(
        [
            [self.sx, 0, 0],
            [0, self.sy, 0],
            [0, 0, 1],
        ],
        dtype=float,
    )
    return m

Segment dataclass

Segment(p1: Point, p2: Point)

Bases: GeometryObject

Represents a line segment between two points.

Attributes:

Name Type Description
p1 Point

Start point.

p2 Point

End point.

Examples:

1
2
3
4
5
>>> seg = Segment(Point(0, 0), Point(10, 10))
>>> seg.length()
14.14...
>>> seg.get_position_at_fraction(0.5)
Point(x=5.0, y=5.0)

Methods:

Name Description
bbox

Get the bounding box of the segment.

from_shapely

Create a Segment from a shapely LineString.

get_angle_at_fraction

Get angle at a fraction along the segment.

get_angle_to_horizontal

Get the angle of the segment relative to horizontal.

get_distance_to_point

Get shortest distance from a point to this segment.

get_intersection_with_line

Get intersection with a line.

get_position_and_angle_at_fraction

Get both position and angle at a fraction.

get_position_at_fraction

Get point at a fraction along the segment.

has_point

Check if a point lies on this segment.

length

Calculate the length of the segment.

reversed

Return a reversed copy of the segment.

shortened

Return a shortened copy of the segment.

to_shapely

Convert to a shapely LineString.

transformed

Apply a transformation to this segment.

bbox

bbox() -> Bbox

Get the bounding box of the segment.

Returns:

Type Description
Bbox

A Bbox enclosing the segment.

Source code in src/momapy/geometry.py
def bbox(self) -> "Bbox":
    """Get the bounding box of the segment.

    Returns:
        A Bbox enclosing the segment.
    """
    return Bbox.from_bounds(self.to_shapely().bounds)

from_shapely classmethod

from_shapely(line_string: LineString) -> Self

Create a Segment from a shapely LineString.

Parameters:

Name Type Description Default
line_string LineString

A 2-point LineString.

required

Returns:

Type Description
Self

A new Segment.

Source code in src/momapy/geometry.py
@classmethod
def from_shapely(cls, line_string: shapely.LineString) -> typing_extensions.Self:
    """Create a Segment from a shapely LineString.

    Args:
        line_string: A 2-point LineString.

    Returns:
        A new Segment.
    """
    shapely_points = line_string.boundary.geoms
    return cls(
        Point.from_shapely(shapely_points[0]),
        Point.from_shapely(shapely_points[1]),
    )

get_angle_at_fraction

get_angle_at_fraction(fraction: float) -> float

Get angle at a fraction along the segment.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_at_fraction(self, fraction: float) -> float:
    """Get angle at a fraction along the segment.

    Args:
        fraction: Fraction from 0 to 1.

    Returns:
        Angle in radians.
    """
    return get_angle_at_fraction_of_segment(self, fraction)

get_angle_to_horizontal

get_angle_to_horizontal() -> float

Get the angle of the segment relative to horizontal.

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_to_horizontal(self) -> float:
    """Get the angle of the segment relative to horizontal.

    Returns:
        Angle in radians.
    """
    return get_angle_to_horizontal_of_line(self)

get_distance_to_point

get_distance_to_point(point: Point) -> float

Get shortest distance from a point to this segment.

Parameters:

Name Type Description Default
point Point

The point to measure from.

required

Returns:

Type Description
float

The shortest distance.

Source code in src/momapy/geometry.py
def get_distance_to_point(self, point: Point) -> float:
    """Get shortest distance from a point to this segment.

    Args:
        point: The point to measure from.

    Returns:
        The shortest distance.
    """
    return get_distance_between_segment_and_point(self, point)

get_intersection_with_line

get_intersection_with_line(line: Line) -> list[Point] | list[Segment]

Get intersection with a line.

Parameters:

Name Type Description Default
line Line

The line to intersect with.

required

Returns:

Type Description
list[Point] | list[Segment]

List of intersection points or segment if coincident.

Source code in src/momapy/geometry.py
def get_intersection_with_line(self, line: Line) -> list[Point] | list["Segment"]:
    """Get intersection with a line.

    Args:
        line: The line to intersect with.

    Returns:
        List of intersection points or segment if coincident.
    """
    return get_intersection_of_line_and_segment(line, self)

get_position_and_angle_at_fraction

get_position_and_angle_at_fraction(fraction: float) -> tuple[Point, float]

Get both position and angle at a fraction.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
tuple[Point, float]

Tuple of (point, angle in radians).

Source code in src/momapy/geometry.py
def get_position_and_angle_at_fraction(
    self, fraction: float
) -> tuple[Point, float]:
    """Get both position and angle at a fraction.

    Args:
        fraction: Fraction from 0 to 1.

    Returns:
        Tuple of (point, angle in radians).
    """
    return get_position_and_angle_at_fraction_of_segment(self, fraction)

get_position_at_fraction

get_position_at_fraction(fraction: float) -> Point

Get point at a fraction along the segment.

Parameters:

Name Type Description Default
fraction float

Fraction from 0 to 1 (0 = start, 1 = end).

required

Returns:

Type Description
Point

The point at that fraction.

Source code in src/momapy/geometry.py
def get_position_at_fraction(self, fraction: float) -> Point:
    """Get point at a fraction along the segment.

    Args:
        fraction: Fraction from 0 to 1 (0 = start, 1 = end).

    Returns:
        The point at that fraction.
    """
    return get_position_at_fraction_of_segment(self, fraction)

has_point

has_point(point: Point, max_distance: float = 0.01) -> bool

Check if a point lies on this segment.

Parameters:

Name Type Description Default
point Point

The point to check.

required
max_distance float

Maximum allowed distance.

0.01

Returns:

Type Description
bool

True if point is on the segment within tolerance.

Source code in src/momapy/geometry.py
def has_point(self, point: Point, max_distance: float = 0.01) -> bool:
    """Check if a point lies on this segment.

    Args:
        point: The point to check.
        max_distance: Maximum allowed distance.

    Returns:
        True if point is on the segment within tolerance.
    """
    return segment_has_point(self, point, max_distance)

length

length() -> float

Calculate the length of the segment.

Returns:

Type Description
float

The Euclidean length.

Source code in src/momapy/geometry.py
def length(self) -> float:
    """Calculate the length of the segment.

    Returns:
        The Euclidean length.
    """
    return math.sqrt((self.p2.x - self.p1.x) ** 2 + (self.p2.y - self.p1.y) ** 2)

reversed

reversed() -> Segment

Return a reversed copy of the segment.

Returns:

Type Description
Segment

A new Segment with p1 and p2 swapped.

Source code in src/momapy/geometry.py
def reversed(self) -> "Segment":
    """Return a reversed copy of the segment.

    Returns:
        A new Segment with p1 and p2 swapped.
    """
    return reverse_segment(self)

shortened

shortened(length: float, start_or_end: Literal['start', 'end'] = 'end') -> Segment

Return a shortened copy of the segment.

Parameters:

Name Type Description Default
length float

Amount to shorten by.

required
start_or_end Literal['start', 'end']

Which end to shorten from.

'end'

Returns:

Type Description
Segment

A new shortened Segment.

Source code in src/momapy/geometry.py
def shortened(
    self,
    length: float,
    start_or_end: typing.Literal["start", "end"] = "end",
) -> "Segment":
    """Return a shortened copy of the segment.

    Args:
        length: Amount to shorten by.
        start_or_end: Which end to shorten from.

    Returns:
        A new shortened Segment.
    """
    return shorten_segment(self, length, start_or_end)

to_shapely

to_shapely() -> LineString

Convert to a shapely LineString.

Returns:

Type Description
LineString

A shapely LineString.

Source code in src/momapy/geometry.py
def to_shapely(self) -> shapely.LineString:
    """Convert to a shapely LineString.

    Returns:
        A shapely LineString.
    """
    return shapely.LineString(
        [
            self.p1.to_tuple(),
            self.p2.to_tuple(),
        ]
    )

transformed

transformed(transformation: Transformation) -> Segment

Apply a transformation to this segment.

Parameters:

Name Type Description Default
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
Segment

A new transformed Segment.

Source code in src/momapy/geometry.py
def transformed(self, transformation: "Transformation") -> "Segment":
    """Apply a transformation to this segment.

    Args:
        transformation: The transformation to apply.

    Returns:
        A new transformed Segment.
    """
    return transform_segment(self, transformation)

Transformation dataclass

Transformation()

Bases: ABC

Abstract base class for geometric transformations.

Methods:

Name Description
inverted

Get the inverse transformation.

to_matrix

Convert to a 3x3 transformation matrix.

inverted abstractmethod

inverted() -> Transformation

Get the inverse transformation.

Returns:

Type Description
Transformation

The inverse transformation.

Source code in src/momapy/geometry.py
@abc.abstractmethod
def inverted(self) -> "Transformation":
    """Get the inverse transformation.

    Returns:
        The inverse transformation.
    """
    pass

to_matrix abstractmethod

to_matrix() -> NDArray

Convert to a 3x3 transformation matrix.

Returns:

Type Description
NDArray

A 3x3 numpy array.

Source code in src/momapy/geometry.py
@abc.abstractmethod
def to_matrix(self) -> numpy.typing.NDArray:
    """Convert to a 3x3 transformation matrix.

    Returns:
        A 3x3 numpy array.
    """
    pass

Translation dataclass

Translation(tx: float, ty: float)

Bases: Transformation

Represents a translation transformation.

Attributes:

Name Type Description
tx float

Translation in x direction.

ty float

Translation in y direction.

Examples:

>>> trans = Translation(10, 20)

Methods:

Name Description
inverted

Get the inverse translation.

to_matrix

Convert to a translation matrix.

inverted

inverted() -> Transformation

Get the inverse translation.

Returns:

Type Description
Transformation

A translation by (-tx, -ty).

Source code in src/momapy/geometry.py
def inverted(self) -> Transformation:
    """Get the inverse translation.

    Returns:
        A translation by (-tx, -ty).
    """
    return invert_translation(self)

to_matrix

to_matrix() -> NDArray

Convert to a translation matrix.

Returns:

Type Description
NDArray

A 3x3 translation matrix.

Source code in src/momapy/geometry.py
def to_matrix(self) -> numpy.typing.NDArray:
    """Convert to a translation matrix.

    Returns:
        A 3x3 translation matrix.
    """
    m = numpy.array([[1, 0, self.tx], [0, 1, self.ty], [0, 0, 1]], dtype=float)
    return m

are_lines_coincident

are_lines_coincident(line1: Line, line2: Line) -> bool

Check if two lines are coincident.

Parameters:

Name Type Description Default
line1 Line

First line.

required
line2 Line

Second line.

required

Returns:

Type Description
bool

True if coincident.

Source code in src/momapy/geometry.py
def are_lines_coincident(line1: Line, line2: Line) -> bool:
    """Check if two lines are coincident.

    Args:
        line1: First line.
        line2: Second line.

    Returns:
        True if coincident.
    """
    slope1 = line1.slope()
    intercept1 = line1.intercept()
    slope2 = line2.slope()
    intercept2 = line2.intercept()
    return (
        math.isnan(slope1)
        and math.isnan(slope2)
        and line1.p1.x == line2.p1.x
        or slope1 == slope2
        and intercept1 == intercept2
    )

are_lines_parallel

are_lines_parallel(line1: Line, line2: Line) -> bool

Check if two lines are parallel.

Parameters:

Name Type Description Default
line1 Line

First line.

required
line2 Line

Second line.

required

Returns:

Type Description
bool

True if parallel.

Source code in src/momapy/geometry.py
def are_lines_parallel(line1: Line, line2: Line) -> bool:
    """Check if two lines are parallel.

    Args:
        line1: First line.
        line2: Second line.

    Returns:
        True if parallel.
    """
    slope1 = line1.slope()
    slope2 = line2.slope()
    if math.isnan(slope1) and math.isnan(slope2):
        return True
    return slope1 == slope2

get_angle_at_fraction_of_bezier_curve

get_angle_at_fraction_of_bezier_curve(bezier_curve: BezierCurve, fraction: float) -> float

Get angle at a fraction along a Bezier curve.

Parameters:

Name Type Description Default
bezier_curve BezierCurve

The curve.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_at_fraction_of_bezier_curve(
    bezier_curve: BezierCurve,
    fraction: float,
) -> float:
    """Get angle at a fraction along a Bezier curve.

    Args:
        bezier_curve: The curve.
        fraction: Fraction from 0 to 1.

    Returns:
        Angle in radians.
    """
    return _get_angle_at_fraction(bezier_curve, fraction)

get_angle_at_fraction_of_elliptical_arc

get_angle_at_fraction_of_elliptical_arc(elliptical_arc: EllipticalArc, fraction: float) -> float

Get angle at a fraction along an elliptical arc.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_at_fraction_of_elliptical_arc(
    elliptical_arc: EllipticalArc,
    fraction: float,
) -> float:
    """Get angle at a fraction along an elliptical arc.

    Args:
        elliptical_arc: The arc.
        fraction: Fraction from 0 to 1.

    Returns:
        Angle in radians.
    """
    return _get_angle_at_fraction(elliptical_arc, fraction)

get_angle_at_fraction_of_segment

get_angle_at_fraction_of_segment(segment: Segment, fraction: float) -> float

Get angle at a fraction along a segment.

Parameters:

Name Type Description Default
segment Segment

The segment.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_at_fraction_of_segment(
    segment: Segment,
    fraction: float,
) -> float:
    """Get angle at a fraction along a segment.

    Args:
        segment: The segment.
        fraction: Fraction from 0 to 1.

    Returns:
        Angle in radians.
    """
    return _get_angle_at_fraction(segment, fraction)

get_angle_between_segments

get_angle_between_segments(segment1: Segment, segment2: Segment) -> float

Get angle between two segments.

Parameters:

Name Type Description Default
segment1 Segment

First segment.

required
segment2 Segment

Second segment.

required

Returns:

Type Description
float

Angle in radians (range -pi to pi).

Source code in src/momapy/geometry.py
def get_angle_between_segments(segment1: Segment, segment2: Segment) -> float:
    """Get angle between two segments.

    Args:
        segment1: First segment.
        segment2: Second segment.

    Returns:
        Angle in radians (range -pi to pi).
    """
    p1 = segment1.p2 - segment1.p1
    p2 = segment2.p2 - segment2.p1
    scalar_prod = p1.x * p2.x + p1.y * p2.y
    angle = math.acos(
        round(scalar_prod / (segment1.length() * segment2.length()), ROUNDING)
    )
    sign = p1.x * p2.y - p1.y * p2.x
    if sign < 0:
        angle = -angle
    return angle

get_angle_to_horizontal_of_line

get_angle_to_horizontal_of_line(line: Line | Segment) -> float

Get angle of a line relative to horizontal.

Parameters:

Name Type Description Default
line Line | Segment

A Line or Segment.

required

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_to_horizontal_of_line(line: Line | Segment) -> float:
    """Get angle of a line relative to horizontal.

    Args:
        line: A Line or Segment.

    Returns:
        Angle in radians.
    """
    x1 = line.p1.x
    y1 = line.p1.y
    x2 = line.p2.x
    y2 = line.p2.y
    angle = math.atan2(y2 - y1, x2 - x1)
    return get_normalized_angle(angle)

get_angle_to_horizontal_of_point

get_angle_to_horizontal_of_point(point: Point) -> float

Get angle from origin to point relative to horizontal.

Parameters:

Name Type Description Default
point Point

The point.

required

Returns:

Type Description
float

Angle in radians.

Source code in src/momapy/geometry.py
def get_angle_to_horizontal_of_point(point: Point) -> float:
    """Get angle from origin to point relative to horizontal.

    Args:
        point: The point.

    Returns:
        Angle in radians.
    """
    line = Line(Point(0, 0), point)
    return line.get_angle_to_horizontal()

get_center_of_elliptical_arc

get_center_of_elliptical_arc(elliptical_arc: EllipticalArc) -> Point

Get center of an elliptical arc.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc.

required

Returns:

Type Description
Point

The center point.

Source code in src/momapy/geometry.py
def get_center_of_elliptical_arc(elliptical_arc: EllipticalArc) -> Point:
    """Get center of an elliptical arc.

    Args:
        elliptical_arc: The arc.

    Returns:
        The center point.
    """
    cx, cy, *_ = get_center_parameterization_of_elliptical_arc(elliptical_arc)
    return Point(cx, cy)

get_center_parameterization_of_elliptical_arc

get_center_parameterization_of_elliptical_arc(elliptical_arc: EllipticalArc) -> tuple[float, float, float, float, float, float, float, float]

Get center parameterization of an elliptical arc.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc.

required

Returns:

Type Description
tuple[float, float, float, float, float, float, float, float]

Tuple of (cx, cy, rx, ry, sigma, theta1, theta2, delta_theta).

Source code in src/momapy/geometry.py
def get_center_parameterization_of_elliptical_arc(
    elliptical_arc: EllipticalArc,
) -> tuple[float, float, float, float, float, float, float, float]:
    """Get center parameterization of an elliptical arc.

    Args:
        elliptical_arc: The arc.

    Returns:
        Tuple of (cx, cy, rx, ry, sigma, theta1, theta2, delta_theta).
    """
    x1, y1 = elliptical_arc.p1.x, elliptical_arc.p1.y
    sigma = elliptical_arc.x_axis_rotation
    x2, y2 = elliptical_arc.p2.x, elliptical_arc.p2.y
    rx = elliptical_arc.rx
    ry = elliptical_arc.ry
    fa = elliptical_arc.arc_flag
    fs = elliptical_arc.sweep_flag
    x1p = math.cos(sigma) * ((x1 - x2) / 2) + math.sin(sigma) * ((y1 - y2) / 2)
    y1p = -math.sin(sigma) * ((x1 - x2) / 2) + math.cos(sigma) * ((y1 - y2) / 2)
    l = x1p**2 / rx**2 + y1p**2 / ry**2
    if l > 1:
        rx = math.sqrt(l) * rx
        ry = math.sqrt(l) * ry
    r = rx**2 * ry**2 - rx**2 * y1p**2 - ry**2 * x1p**2
    if r < 0:
        r = 0
    a = math.sqrt(r / (rx**2 * y1p**2 + ry**2 * x1p**2))
    if fa == fs:
        a = -a
    cxp = a * rx * y1p / ry
    cyp = -a * ry * x1p / rx
    cx = math.cos(sigma) * cxp - math.sin(sigma) * cyp + (x1 + x2) / 2
    cy = math.sin(sigma) * cxp + math.cos(sigma) * cyp + (y1 + y2) / 2
    theta1 = get_angle_between_segments(
        Segment(Point(0, 0), Point(1, 0)),
        Segment(Point(0, 0), Point((x1p - cxp) / rx, (y1p - cyp) / ry)),
    )
    delta_theta = get_angle_between_segments(
        Segment(Point(0, 0), Point((x1p - cxp) / rx, (y1p - cyp) / ry)),
        Segment(Point(0, 0), Point(-(x1p + cxp) / rx, -(y1p + cyp) / ry)),
    )
    if fs == 0 and delta_theta > 0:
        delta_theta -= 2 * math.pi
    elif fs == 1 and delta_theta < 0:
        delta_theta += 2 * math.pi
    theta2 = theta1 + delta_theta
    return cx, cy, rx, ry, sigma, theta1, theta2, delta_theta

get_distance_between_line_and_point

get_distance_between_line_and_point(line: Line, point: Point) -> float

Get perpendicular distance from a point to a line.

Parameters:

Name Type Description Default
line Line

The line.

required
point Point

The point.

required

Returns:

Type Description
float

The perpendicular distance.

Source code in src/momapy/geometry.py
def get_distance_between_line_and_point(line: Line, point: Point) -> float:
    """Get perpendicular distance from a point to a line.

    Args:
        line: The line.
        point: The point.

    Returns:
        The perpendicular distance.
    """
    distance = abs(
        (line.p2.x - line.p1.x) * (line.p1.y - point.y)
        - (line.p1.x - point.x) * (line.p2.y - line.p1.y)
    ) / math.sqrt((line.p2.x - line.p1.x) ** 2 + (line.p2.y - line.p1.y) ** 2)
    return distance

get_distance_between_points

get_distance_between_points(p1: Point, p2: Point) -> float

Get distance between two points.

Parameters:

Name Type Description Default
p1 Point

First point.

required
p2 Point

Second point.

required

Returns:

Type Description
float

The Euclidean distance.

Source code in src/momapy/geometry.py
def get_distance_between_points(p1: Point, p2: Point) -> float:
    """Get distance between two points.

    Args:
        p1: First point.
        p2: Second point.

    Returns:
        The Euclidean distance.
    """
    return Segment(p1, p2).length()

get_distance_between_segment_and_point

get_distance_between_segment_and_point(segment: Segment, point: Point) -> float

Get shortest distance from a point to a segment.

Parameters:

Name Type Description Default
segment Segment

The segment.

required
point Point

The point.

required

Returns:

Type Description
float

The shortest distance.

Source code in src/momapy/geometry.py
def get_distance_between_segment_and_point(segment: Segment, point: Point) -> float:
    """Get shortest distance from a point to a segment.

    Args:
        segment: The segment.
        point: The point.

    Returns:
        The shortest distance.
    """
    a = point.x - segment.p1.x
    b = point.y - segment.p1.y
    c = segment.p2.x - segment.p1.x
    d = segment.p2.y - segment.p1.y
    dot = a * c + b * d
    len_sq = c**2 + d**2
    if len_sq != 0:
        param = dot / len_sq
    else:
        param = -1
    if param < 0:
        xx = segment.p1.x
        yy = segment.p1.y
    elif param > 1:
        xx = segment.p2.x
        yy = segment.p2.y
    else:
        xx = segment.p1.x + param * c
        yy = segment.p1.y + param * d
    dx = point.x - xx
    dy = point.y - yy
    distance = math.sqrt(dx**2 + dy**2)
    return distance

get_intersection_of_line_and_bezier_curve

get_intersection_of_line_and_bezier_curve(line: Line, bezier_curve: BezierCurve) -> list[Point] | list[Segment]

Get intersection of a line and a Bezier curve.

Parameters:

Name Type Description Default
line Line

The line.

required
bezier_curve BezierCurve

The Bezier curve.

required

Returns:

Type Description
list[Point] | list[Segment]

List of intersection points or segments.

Source code in src/momapy/geometry.py
def get_intersection_of_line_and_bezier_curve(
    line: Line, bezier_curve: BezierCurve
) -> list[Point] | list[Segment]:
    """Get intersection of a line and a Bezier curve.

    Args:
        line: The line.
        bezier_curve: The Bezier curve.

    Returns:
        List of intersection points or segments.
    """
    shapely_object = bezier_curve.to_shapely()
    return get_intersection_of_line_and_shapely_object(line, shapely_object)

get_intersection_of_line_and_elliptical_arc

get_intersection_of_line_and_elliptical_arc(line: Line, elliptical_arc: EllipticalArc) -> list[Point] | list[Segment]

Get intersection of a line and an elliptical arc.

Parameters:

Name Type Description Default
line Line

The line.

required
elliptical_arc EllipticalArc

The elliptical arc.

required

Returns:

Type Description
list[Point] | list[Segment]

List of intersection points or segments.

Source code in src/momapy/geometry.py
def get_intersection_of_line_and_elliptical_arc(
    line: Line, elliptical_arc: EllipticalArc
) -> list[Point] | list[Segment]:
    """Get intersection of a line and an elliptical arc.

    Args:
        line: The line.
        elliptical_arc: The elliptical arc.

    Returns:
        List of intersection points or segments.
    """
    shapely_object = elliptical_arc.to_shapely()
    return get_intersection_of_line_and_shapely_object(line, shapely_object)

get_intersection_of_line_and_point

get_intersection_of_line_and_point(line: Line, point: Point) -> list[Point]

Get intersection of a line and a point.

Parameters:

Name Type Description Default
line Line

The line.

required
point Point

The point.

required

Returns:

Type Description
list[Point]

List containing the point if it lies on the line, empty otherwise.

Source code in src/momapy/geometry.py
def get_intersection_of_line_and_point(line: Line, point: Point) -> list[Point]:
    """Get intersection of a line and a point.

    Args:
        line: The line.
        point: The point.

    Returns:
        List containing the point if it lies on the line, empty otherwise.
    """
    if line.has_point(point):
        return [point]
    return []

get_intersection_of_line_and_segment

get_intersection_of_line_and_segment(line: Line, segment: Segment) -> list[Point] | list[Segment] | list[Line]

Get intersection of a line and a segment.

Parameters:

Name Type Description Default
line Line

The line.

required
segment Segment

The segment.

required

Returns:

Type Description
list[Point] | list[Segment] | list[Line]

List of intersection points, segment if coincident, or empty.

Source code in src/momapy/geometry.py
def get_intersection_of_line_and_segment(
    line: Line, segment: Segment
) -> list[Point] | list[Segment] | list[Line]:
    """Get intersection of a line and a segment.

    Args:
        line: The line.
        segment: The segment.

    Returns:
        List of intersection points, segment if coincident, or empty.
    """
    line2 = Line(segment.p1, segment.p2)
    intersection = line.get_intersection_with_line(line2)
    if len(intersection) > 0 and isinstance(intersection[0], Point):
        sorted_xs = sorted([segment.p1.x, segment.p2.x])
        sorted_ys = sorted([segment.p1.y, segment.p2.y])
        if not (
            intersection[0].x >= sorted_xs[0]
            and intersection[0].x <= sorted_xs[-1]
            and intersection[0].y >= sorted_ys[0]
            and intersection[0].y <= sorted_ys[-1]
        ):
            intersection = []
    elif len(intersection) > 0:
        intersection = [segment]
    return intersection

get_intersection_of_line_and_shapely_object

get_intersection_of_line_and_shapely_object(line: Line, shapely_object: Geometry) -> list[Point] | list[Segment]

Get intersection of a line with a shapely object.

Parameters:

Name Type Description Default
line Line

The line.

required
shapely_object Geometry

A shapely geometry.

required

Returns:

Type Description
list[Point] | list[Segment]

List of intersection points or segments.

Source code in src/momapy/geometry.py
def get_intersection_of_line_and_shapely_object(
    line: Line, shapely_object: shapely.Geometry
) -> list[Point] | list[Segment]:
    """Get intersection of a line with a shapely object.

    Args:
        line: The line.
        shapely_object: A shapely geometry.

    Returns:
        List of intersection points or segments.
    """
    intersection = []
    for shapely_geom in shapely_object.geoms:
        bbox = Bbox.from_bounds(shapely_object.bounds)
        slope = line.slope()
        north_west = bbox.north_west()
        south_east = bbox.south_east()
        offset = 100.0
        if not math.isnan(slope):
            intercept = line.intercept()
            left_x = north_west.x - offset
            left_y = slope * left_x + intercept
            right_x = south_east.x + offset
            right_y = slope * right_x + intercept
        else:
            left_x = line.p1.x
            left_y = north_west.y - offset
            right_x = line.p1.x
            right_y = south_east.y + offset
        left_point = Point(left_x, left_y)
        right_point = Point(right_x, right_y)
        line_string = shapely.LineString(
            [left_point.to_shapely(), right_point.to_shapely()]
        )
        shapely_intersection = line_string.intersection(shapely_geom)
        if not hasattr(shapely_intersection, "geoms"):
            shapely_intersection = [shapely_intersection]
        else:
            shapely_intersection = shapely_intersection.geoms
        for shapely_obj in shapely_intersection:
            if not shapely.is_empty(shapely_obj):
                if isinstance(shapely_obj, shapely.Point):
                    intersection_obj = Point.from_shapely(shapely_obj)
                elif isinstance(shapely_obj, shapely.LineString):
                    intersection_obj = Segment.from_shapely(shapely_obj)
                intersection.append(intersection_obj)
    return intersection

get_intersection_of_lines

get_intersection_of_lines(line1: Line, line2: Line) -> list[Line] | list[Point]

Get intersection of two lines.

Parameters:

Name Type Description Default
line1 Line

First line.

required
line2 Line

Second line.

required

Returns:

Type Description
list[Line] | list[Point]

List containing intersection point(s) or coincident line.

Source code in src/momapy/geometry.py
def get_intersection_of_lines(line1: Line, line2: Line) -> list[Line] | list[Point]:
    """Get intersection of two lines.

    Args:
        line1: First line.
        line2: Second line.

    Returns:
        List containing intersection point(s) or coincident line.
    """
    slope1 = line1.slope()
    intercept1 = line1.intercept()
    slope2 = line2.slope()
    intercept2 = line2.intercept()
    if line1.is_coincident_to_line(line2):
        intersection = [copy.deepcopy(line1)]
    elif line1.is_parallel_to_line(line2):
        intersection = []
    elif math.isnan(slope1):
        intersection = [Point(line1.p1.x, slope2 * line1.p1.x + intercept2)]
    elif math.isnan(slope2):
        intersection = [Point(line2.p1.x, slope1 * line2.p1.x + intercept1)]
    else:
        d = (line1.p1.x - line1.p2.x) * (line2.p1.y - line2.p2.y) - (
            line1.p1.y - line1.p2.y
        ) * (line2.p1.x - line2.p2.x)
        px = (
            (line1.p1.x * line1.p2.y - line1.p1.y * line1.p2.x)
            * (line2.p1.x - line2.p2.x)
            - (line1.p1.x - line1.p2.x)
            * (line2.p1.x * line2.p2.y - line2.p1.y * line2.p2.x)
        ) / d
        py = (
            (line1.p1.x * line1.p2.y - line1.p1.y * line1.p2.x)
            * (line2.p1.y - line2.p2.y)
            - (line1.p1.y - line1.p2.y)
            * (line2.p1.x * line2.p2.y - line2.p1.y * line2.p2.x)
        ) / d
        intersection = [Point(px, py)]
    return intersection

get_normalized_angle

get_normalized_angle(angle: float) -> float

Normalize an angle to [0, 2*pi).

Parameters:

Name Type Description Default
angle float

Angle in radians.

required

Returns:

Type Description
float

Normalized angle.

Source code in src/momapy/geometry.py
def get_normalized_angle(angle: float) -> float:
    """Normalize an angle to [0, 2*pi).

    Args:
        angle: Angle in radians.

    Returns:
        Normalized angle.
    """
    return angle - (angle // (2 * math.pi) * (2 * math.pi))

get_position_and_angle_at_fraction_of_bezier_curve

get_position_and_angle_at_fraction_of_bezier_curve(bezier_curve: BezierCurve, fraction: float) -> tuple[Point, float]

Get position and angle at a fraction along a Bezier curve.

Parameters:

Name Type Description Default
bezier_curve BezierCurve

The curve.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
tuple[Point, float]

Tuple of (point, angle).

Source code in src/momapy/geometry.py
def get_position_and_angle_at_fraction_of_bezier_curve(
    bezier_curve: BezierCurve,
    fraction: float,
) -> tuple[Point, float]:
    """Get position and angle at a fraction along a Bezier curve.

    Args:
        bezier_curve: The curve.
        fraction: Fraction from 0 to 1.

    Returns:
        Tuple of (point, angle).
    """
    return _get_position_and_angle_at_fraction(bezier_curve, fraction)

get_position_and_angle_at_fraction_of_elliptical_arc

get_position_and_angle_at_fraction_of_elliptical_arc(elliptical_arc: EllipticalArc, fraction: float) -> tuple[Point, float]

Get position and angle at a fraction along an elliptical arc.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
tuple[Point, float]

Tuple of (point, angle).

Source code in src/momapy/geometry.py
def get_position_and_angle_at_fraction_of_elliptical_arc(
    elliptical_arc: EllipticalArc,
    fraction: float,
) -> tuple[Point, float]:
    """Get position and angle at a fraction along an elliptical arc.

    Args:
        elliptical_arc: The arc.
        fraction: Fraction from 0 to 1.

    Returns:
        Tuple of (point, angle).
    """
    return _get_position_and_angle_at_fraction(elliptical_arc, fraction)

get_position_and_angle_at_fraction_of_segment

get_position_and_angle_at_fraction_of_segment(segment: Segment, fraction: float) -> tuple[Point, float]

Get position and angle at a fraction along a segment.

Parameters:

Name Type Description Default
segment Segment

The segment.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
tuple[Point, float]

Tuple of (point, angle).

Source code in src/momapy/geometry.py
def get_position_and_angle_at_fraction_of_segment(
    segment: Segment,
    fraction: float,
) -> tuple[Point, float]:
    """Get position and angle at a fraction along a segment.

    Args:
        segment: The segment.
        fraction: Fraction from 0 to 1.

    Returns:
        Tuple of (point, angle).
    """
    return _get_position_and_angle_at_fraction(segment, fraction)

get_position_at_fraction_of_bezier_curve

get_position_at_fraction_of_bezier_curve(bezier_curve: BezierCurve, fraction: float) -> Point

Get point at a fraction along a Bezier curve.

Parameters:

Name Type Description Default
bezier_curve BezierCurve

The curve.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
Point

The point at that fraction.

Source code in src/momapy/geometry.py
def get_position_at_fraction_of_bezier_curve(
    bezier_curve: BezierCurve,
    fraction: float,
) -> Point:
    """Get point at a fraction along a Bezier curve.

    Args:
        bezier_curve: The curve.
        fraction: Fraction from 0 to 1.

    Returns:
        The point at that fraction.
    """
    return _get_position_at_fraction(bezier_curve, fraction)

get_position_at_fraction_of_elliptical_arc

get_position_at_fraction_of_elliptical_arc(elliptical_arc: EllipticalArc, fraction: float) -> Point

Get point at a fraction along an elliptical arc.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
Point

The point at that fraction.

Source code in src/momapy/geometry.py
def get_position_at_fraction_of_elliptical_arc(
    elliptical_arc: EllipticalArc,
    fraction: float,
) -> Point:
    """Get point at a fraction along an elliptical arc.

    Args:
        elliptical_arc: The arc.
        fraction: Fraction from 0 to 1.

    Returns:
        The point at that fraction.
    """
    return _get_position_at_fraction(elliptical_arc, fraction)

get_position_at_fraction_of_segment

get_position_at_fraction_of_segment(segment: Segment, fraction: float) -> Point

Get point at a fraction along a segment.

Parameters:

Name Type Description Default
segment Segment

The segment.

required
fraction float

Fraction from 0 to 1.

required

Returns:

Type Description
Point

The point at that fraction.

Source code in src/momapy/geometry.py
def get_position_at_fraction_of_segment(
    segment: Segment,
    fraction: float,
) -> Point:
    """Get point at a fraction along a segment.

    Args:
        segment: The segment.
        fraction: Fraction from 0 to 1.

    Returns:
        The point at that fraction.
    """
    return _get_position_at_fraction(segment, fraction)

get_shapely_object_anchor_point

get_shapely_object_anchor_point(shapely_object: Geometry, anchor_point: str, center: Point | None = None) -> Point

Get an anchor point of a shapely object.

Parameters:

Name Type Description Default
shapely_object Geometry

A shapely geometry.

required
anchor_point str

Name of anchor point.

required
center Point | None

Optional center point.

None

Returns:

Type Description
Point

The anchor point.

Source code in src/momapy/geometry.py
def get_shapely_object_anchor_point(
    shapely_object: shapely.Geometry,
    anchor_point: str,
    center: Point | None = None,
) -> Point:
    """Get an anchor point of a shapely object.

    Args:
        shapely_object: A shapely geometry.
        anchor_point: Name of anchor point.
        center: Optional center point.

    Returns:
        The anchor point.
    """
    bbox = get_shapely_object_bbox(shapely_object)
    if center is None:
        center = bbox.center()
    if center.isnan():
        return Point(float("nan"), float("nan"))
    point = bbox.anchor_point(anchor_point)
    return get_shapely_object_border(shapely_object, point, center)

get_shapely_object_angle

get_shapely_object_angle(shapely_object: Geometry, angle: float, unit: Literal['degrees', 'radians'] = 'degrees', center: Point | None = None) -> Point | None

Get the border point at a given angle.

Parameters:

Name Type Description Default
shapely_object Geometry

A shapely geometry.

required
angle float

The angle.

required
unit Literal['degrees', 'radians']

Unit of angle ('degrees' or 'radians').

'degrees'
center Point | None

Optional center point.

None

Returns:

Type Description
Point | None

The border point or None.

Source code in src/momapy/geometry.py
def get_shapely_object_angle(
    shapely_object: shapely.Geometry,
    angle: float,
    unit: typing.Literal["degrees", "radians"] = "degrees",
    center: Point | None = None,
) -> Point | None:
    """Get the border point at a given angle.

    Args:
        shapely_object: A shapely geometry.
        angle: The angle.
        unit: Unit of angle ('degrees' or 'radians').
        center: Optional center point.

    Returns:
        The border point or None.
    """
    if unit == "degrees":
        angle = math.radians(angle)
    angle = -angle
    d = 100
    if center is None:
        bbox = get_shapely_object_bbox(shapely_object)
        center = bbox.center()
        if center.isnan():
            return Point(float("nan"), float("nan"))
    point = center + (d * math.cos(angle), d * math.sin(angle))
    return get_shapely_object_border(shapely_object, point, center)

get_shapely_object_bbox

get_shapely_object_bbox(shapely_object: Geometry) -> Bbox

Get the bounding box of a shapely object.

Parameters:

Name Type Description Default
shapely_object Geometry

A shapely geometry.

required

Returns:

Type Description
Bbox

The bounding box.

Source code in src/momapy/geometry.py
def get_shapely_object_bbox(shapely_object: shapely.Geometry) -> Bbox:
    """Get the bounding box of a shapely object.

    Args:
        shapely_object: A shapely geometry.

    Returns:
        The bounding box.
    """
    return Bbox.from_bounds(shapely_object.bounds)

get_shapely_object_border

get_shapely_object_border(shapely_object: Geometry, point: Point, center: Point | None = None) -> Point | None

Get the border point in a given direction.

Parameters:

Name Type Description Default
shapely_object Geometry

A shapely geometry.

required
point Point

Direction point.

required
center Point | None

Optional center point.

None

Returns:

Type Description
Point | None

The border point or None.

Source code in src/momapy/geometry.py
def get_shapely_object_border(
    shapely_object: shapely.Geometry, point: Point, center: Point | None = None
) -> Point | None:
    """Get the border point in a given direction.

    Args:
        shapely_object: A shapely geometry.
        point: Direction point.
        center: Optional center point.

    Returns:
        The border point or None.
    """
    if center is None:
        bbox = get_shapely_object_bbox(shapely_object)
        center = bbox.center()
    if center.isnan():
        return Point(float("nan"), float("nan"))
    line = Line(center, point)
    intersection = get_intersection_of_line_and_shapely_object(line, shapely_object)
    candidate_points = []
    for intersection_obj in intersection:
        if isinstance(intersection_obj, Segment):
            candidate_points.append(intersection_obj.p1)
            candidate_points.append(intersection_obj.p2)
        elif isinstance(intersection_obj, Point):
            candidate_points.append(intersection_obj)
    intersection_point = None
    max_d = -1
    ok_direction_exists = False
    d1 = get_distance_between_points(point, center)
    for candidate_point in candidate_points:
        d2 = get_distance_between_points(candidate_point, point)
        d3 = get_distance_between_points(candidate_point, center)
        candidate_ok_direction = not d2 > d1 or d2 < d3
        if candidate_ok_direction or not ok_direction_exists:
            if candidate_ok_direction and not ok_direction_exists:
                ok_direction_exists = True
                max_d = -1
            if d3 > max_d:
                max_d = d3
                intersection_point = candidate_point
    return intersection_point

get_transformation_for_frame

get_transformation_for_frame(origin: Point, unit_x: Point, unit_y: Point) -> MatrixTransformation

Get transformation for a frame defined by origin and axes.

Given a frame F defined by its origin, unit x axis vector, and unit y axis vector, returns the transformation that converts points from F coordinates to reference frame coordinates.

Parameters:

Name Type Description Default
origin Point

Origin of the frame.

required
unit_x Point

Unit x-axis vector.

required
unit_y Point

Unit y-axis vector.

required

Returns:

Type Description
MatrixTransformation

The transformation matrix.

Source code in src/momapy/geometry.py
def get_transformation_for_frame(
    origin: Point, unit_x: Point, unit_y: Point
) -> MatrixTransformation:
    """Get transformation for a frame defined by origin and axes.

    Given a frame F defined by its origin, unit x axis vector, and unit y axis
    vector, returns the transformation that converts points from F coordinates
    to reference frame coordinates.

    Args:
        origin: Origin of the frame.
        unit_x: Unit x-axis vector.
        unit_y: Unit y-axis vector.

    Returns:
        The transformation matrix.
    """
    m = numpy.array(
        [
            [
                unit_x.x - origin.x,
                unit_y.x - origin.x,
                origin.x,
            ],
            [
                unit_x.y - origin.y,
                unit_y.y - origin.y,
                origin.y,
            ],
            [0, 0, 1],
        ],
        dtype=float,
    )
    return MatrixTransformation(m)

invert_matrix_transformation

invert_matrix_transformation(matrix_transformation: MatrixTransformation) -> MatrixTransformation

Invert a matrix transformation.

Parameters:

Name Type Description Default
matrix_transformation MatrixTransformation

The transformation to invert.

required

Returns:

Type Description
MatrixTransformation

The inverse transformation.

Source code in src/momapy/geometry.py
def invert_matrix_transformation(
    matrix_transformation: MatrixTransformation,
) -> MatrixTransformation:
    """Invert a matrix transformation.

    Args:
        matrix_transformation: The transformation to invert.

    Returns:
        The inverse transformation.
    """
    return MatrixTransformation(numpy.linalg.inv(matrix_transformation.m))

invert_rotation

invert_rotation(rotation: Rotation) -> Rotation

Invert a rotation.

Parameters:

Name Type Description Default
rotation Rotation

The rotation to invert.

required

Returns:

Type Description
Rotation

A rotation by the negative angle.

Source code in src/momapy/geometry.py
def invert_rotation(rotation: Rotation) -> Rotation:
    """Invert a rotation.

    Args:
        rotation: The rotation to invert.

    Returns:
        A rotation by the negative angle.
    """
    return Rotation(-rotation.angle, rotation.point)

invert_scaling

invert_scaling(scaling: Scaling) -> Scaling

Invert a scaling.

Parameters:

Name Type Description Default
scaling Scaling

The scaling to invert.

required

Returns:

Type Description
Scaling

Scaling by the reciprocal factors.

Source code in src/momapy/geometry.py
def invert_scaling(scaling: Scaling) -> Scaling:
    """Invert a scaling.

    Args:
        scaling: The scaling to invert.

    Returns:
        Scaling by the reciprocal factors.
    """
    return Scaling(-scaling.sx, -scaling.sy)

invert_translation

invert_translation(translation: Translation) -> Translation

Invert a translation.

Parameters:

Name Type Description Default
translation Translation

The translation to invert.

required

Returns:

Type Description
Translation

A translation by (-tx, -ty).

Source code in src/momapy/geometry.py
def invert_translation(translation: Translation) -> Translation:
    """Invert a translation.

    Args:
        translation: The translation to invert.

    Returns:
        A translation by (-tx, -ty).
    """
    return Translation(-translation.tx, -translation.ty)

is_angle_between

is_angle_between(angle: float, start_angle: float, end_angle: float) -> bool

Check if an angle is between two angles.

Parameters:

Name Type Description Default
angle float

The angle to check (radians).

required
start_angle float

Start angle (radians).

required
end_angle float

End angle (radians).

required

Returns:

Type Description
bool

True if angle is between start and end.

Source code in src/momapy/geometry.py
def is_angle_between(angle: float, start_angle: float, end_angle: float) -> bool:
    """Check if an angle is between two angles.

    Args:
        angle: The angle to check (radians).
        start_angle: Start angle (radians).
        end_angle: End angle (radians).

    Returns:
        True if angle is between start and end.
    """
    angle = get_normalized_angle(angle)
    start_angle = get_normalized_angle(start_angle)
    end_angle = get_normalized_angle(end_angle)
    if start_angle < end_angle:
        if angle >= start_angle and angle <= end_angle:
            return True
    else:
        if start_angle <= angle <= 2 * math.pi or angle >= 0 and angle <= end_angle:
            return True
    return False

is_angle_in_sector

is_angle_in_sector(angle: float, center: Point, point1: Point, point2: Point) -> bool

Check if an angle is within a sector.

Parameters:

Name Type Description Default
angle float

The angle to check (radians).

required
center Point

Center of sector.

required
point1 Point

First sector boundary.

required
point2 Point

Second sector boundary.

required

Returns:

Type Description
bool

True if angle is in sector.

Source code in src/momapy/geometry.py
def is_angle_in_sector(
    angle: float, center: Point, point1: Point, point2: Point
) -> bool:
    """Check if an angle is within a sector.

    Args:
        angle: The angle to check (radians).
        center: Center of sector.
        point1: First sector boundary.
        point2: Second sector boundary.

    Returns:
        True if angle is in sector.
    """
    angle1 = get_angle_to_horizontal_of_line(Line(center, point1))
    angle2 = get_angle_to_horizontal_of_line(Line(center, point2))
    return is_angle_between(angle, angle1, angle2)

line_has_point

line_has_point(line: Line, point: Point, max_distance: float = 0.01) -> bool

Check if a point lies on a line.

Parameters:

Name Type Description Default
line Line

The line.

required
point Point

The point.

required
max_distance float

Maximum allowed distance.

0.01

Returns:

Type Description
bool

True if point is on the line within tolerance.

Source code in src/momapy/geometry.py
def line_has_point(line: Line, point: Point, max_distance: float = 0.01) -> bool:
    """Check if a point lies on a line.

    Args:
        line: The line.
        point: The point.
        max_distance: Maximum allowed distance.

    Returns:
        True if point is on the line within tolerance.
    """
    d = line.get_distance_to_point(point)
    if d <= max_distance:
        return True
    return False

reverse_bezier_curve

reverse_bezier_curve(bezier_curve: BezierCurve) -> BezierCurve

Reverse a Bezier curve.

Parameters:

Name Type Description Default
bezier_curve BezierCurve

The curve to reverse.

required

Returns:

Type Description
BezierCurve

A new BezierCurve going in reverse direction.

Source code in src/momapy/geometry.py
def reverse_bezier_curve(bezier_curve: BezierCurve) -> BezierCurve:
    """Reverse a Bezier curve.

    Args:
        bezier_curve: The curve to reverse.

    Returns:
        A new BezierCurve going in reverse direction.
    """
    return BezierCurve(
        bezier_curve.p2, bezier_curve.p1, bezier_curve.control_points[::-1]
    )

reverse_elliptical_arc

reverse_elliptical_arc(elliptical_arc: EllipticalArc) -> EllipticalArc

Reverse an elliptical arc.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc to reverse.

required

Returns:

Type Description
EllipticalArc

A new EllipticalArc going in reverse direction.

Source code in src/momapy/geometry.py
def reverse_elliptical_arc(elliptical_arc: EllipticalArc) -> EllipticalArc:
    """Reverse an elliptical arc.

    Args:
        elliptical_arc: The arc to reverse.

    Returns:
        A new EllipticalArc going in reverse direction.
    """
    return EllipticalArc(
        elliptical_arc.p2,
        elliptical_arc.p1,
        elliptical_arc.rx,
        elliptical_arc.ry,
        elliptical_arc.x_axis_rotation,
        elliptical_arc.arc_flag,
        abs(elliptical_arc.sweep_flag - 1),
    )

reverse_line

reverse_line(line: Line) -> Line

Reverse a line (swap endpoints).

Parameters:

Name Type Description Default
line Line

The line to reverse.

required

Returns:

Type Description
Line

A new Line with p1 and p2 swapped.

Source code in src/momapy/geometry.py
def reverse_line(line: Line) -> Line:
    """Reverse a line (swap endpoints).

    Args:
        line: The line to reverse.

    Returns:
        A new Line with p1 and p2 swapped.
    """
    return Line(line.p2, line.p1)

reverse_point

reverse_point(point: Point) -> Point

Return a copy of the point (points are directionless).

Parameters:

Name Type Description Default
point Point

The point.

required

Returns:

Type Description
Point

A copy of the point.

Source code in src/momapy/geometry.py
def reverse_point(point: Point) -> Point:
    """Return a copy of the point (points are directionless).

    Args:
        point: The point.

    Returns:
        A copy of the point.
    """
    return Point(point.x, point.y)

reverse_segment

reverse_segment(segment)

Reverse a segment (swap endpoints).

Parameters:

Name Type Description Default
segment

The segment to reverse.

required

Returns:

Type Description

A new Segment with p1 and p2 swapped.

Source code in src/momapy/geometry.py
def reverse_segment(segment):
    """Reverse a segment (swap endpoints).

    Args:
        segment: The segment to reverse.

    Returns:
        A new Segment with p1 and p2 swapped.
    """
    return Segment(segment.p2, segment.p1)

segment_has_point

segment_has_point(segment: Segment, point: Point, max_distance: float = 0.01) -> bool

Check if a point lies on a segment.

Parameters:

Name Type Description Default
segment Segment

The segment.

required
point Point

The point.

required
max_distance float

Maximum allowed distance.

0.01

Returns:

Type Description
bool

True if point is on the segment within tolerance.

Source code in src/momapy/geometry.py
def segment_has_point(
    segment: Segment, point: Point, max_distance: float = 0.01
) -> bool:
    """Check if a point lies on a segment.

    Args:
        segment: The segment.
        point: The point.
        max_distance: Maximum allowed distance.

    Returns:
        True if point is on the segment within tolerance.
    """
    d = segment.get_distance_to_point(point)
    if d <= max_distance:
        return True
    return False

shorten_bezier_curve

shorten_bezier_curve(bezier_curve: BezierCurve, length: float, start_or_end: Literal['start', 'end'] = 'end') -> BezierCurve

Shorten a Bezier curve by a given length.

Parameters:

Name Type Description Default
bezier_curve BezierCurve

The curve to shorten.

required
length float

Amount to shorten by.

required
start_or_end Literal['start', 'end']

Which end to shorten from.

'end'

Returns:

Type Description
BezierCurve

A new shortened BezierCurve.

Source code in src/momapy/geometry.py
def shorten_bezier_curve(
    bezier_curve: BezierCurve,
    length: float,
    start_or_end: typing.Literal["start", "end"] = "end",
) -> BezierCurve:
    """Shorten a Bezier curve by a given length.

    Args:
        bezier_curve: The curve to shorten.
        length: Amount to shorten by.
        start_or_end: Which end to shorten from.

    Returns:
        A new shortened BezierCurve.
    """
    if length == 0 or bezier_curve.length() == 0:
        shortened_bezier_curve = copy.deepcopy(bezier_curve)
    else:
        if start_or_end == "start":
            shortened_bezier_curve = (
                bezier_curve.reversed().shortened(length).reversed()
            )
        else:
            lib_bezier_curve = bezier_curve._to_bezier()
            total_length = lib_bezier_curve.length
            if length > total_length:
                length = total_length
            fraction = 1 - length / total_length
            point = bezier_curve.get_position_at_fraction(fraction)
            horizontal_line = BezierCurve(point - (5, 0), point + (5, 0))._to_bezier()
            s = lib_bezier_curve.intersect(horizontal_line)[0][0]
            lib_shortened_bezier_curve = lib_bezier_curve.specialize(0, s)
            shortened_bezier_curve = BezierCurve._from_bezier(
                lib_shortened_bezier_curve
            )
    return shortened_bezier_curve

shorten_elliptical_arc

shorten_elliptical_arc(elliptical_arc: EllipticalArc, length: float, start_or_end: Literal['start', 'end'] = 'end')

Shorten an elliptical arc by a given length.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc to shorten.

required
length float

Amount to shorten by.

required
start_or_end Literal['start', 'end']

Which end to shorten from.

'end'

Returns:

Type Description

A new shortened EllipticalArc.

Source code in src/momapy/geometry.py
def shorten_elliptical_arc(
    elliptical_arc: EllipticalArc,
    length: float,
    start_or_end: typing.Literal["start", "end"] = "end",
):
    """Shorten an elliptical arc by a given length.

    Args:
        elliptical_arc: The arc to shorten.
        length: Amount to shorten by.
        start_or_end: Which end to shorten from.

    Returns:
        A new shortened EllipticalArc.
    """
    if length == 0 or elliptical_arc.length() == 0:
        shortened_elliptical_arc = copy.deepcopy(elliptical_arc)
    else:
        if start_or_end == "start":
            shortened_elliptical_arc = (
                elliptical_arc.reversed().shortened(length).reversed()
            )
        else:
            fraction = 1 - length / elliptical_arc.length()
            point = elliptical_arc.get_position_at_fraction(fraction)
            shortened_elliptical_arc = dataclasses.replace(elliptical_arc, p2=point)
    return shortened_elliptical_arc

shorten_segment

shorten_segment(segment: Segment, length: float, start_or_end: Literal['start', 'end'] = 'end') -> Segment

Shorten a segment by a given length.

Parameters:

Name Type Description Default
segment Segment

The segment to shorten.

required
length float

Amount to shorten by.

required
start_or_end Literal['start', 'end']

Which end to shorten from.

'end'

Returns:

Type Description
Segment

A new shortened Segment.

Source code in src/momapy/geometry.py
def shorten_segment(
    segment: Segment,
    length: float,
    start_or_end: typing.Literal["start", "end"] = "end",
) -> Segment:
    """Shorten a segment by a given length.

    Args:
        segment: The segment to shorten.
        length: Amount to shorten by.
        start_or_end: Which end to shorten from.

    Returns:
        A new shortened Segment.
    """
    if length == 0 or segment.length() == 0:
        shortened_segment = copy.deepcopy(segment)
    else:
        if start_or_end == "start":
            shortened_segment = segment.reversed().shortened(length).reversed()
        else:
            fraction = 1 - length / segment.length()
            point = segment.get_position_at_fraction(fraction)
            shortened_segment = Segment(segment.p1, point)
    return shortened_segment

transform_bezier_curve

transform_bezier_curve(bezier_curve: BezierCurve, transformation: Transformation) -> BezierCurve

Transform a Bezier curve.

Parameters:

Name Type Description Default
bezier_curve BezierCurve

The curve to transform.

required
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
BezierCurve

The transformed BezierCurve.

Source code in src/momapy/geometry.py
def transform_bezier_curve(
    bezier_curve: BezierCurve, transformation: Transformation
) -> BezierCurve:
    """Transform a Bezier curve.

    Args:
        bezier_curve: The curve to transform.
        transformation: The transformation to apply.

    Returns:
        The transformed BezierCurve.
    """
    return BezierCurve(
        transform_point(bezier_curve.p1, transformation),
        transform_point(bezier_curve.p2, transformation),
        tuple(
            [
                transform_point(point, transformation)
                for point in bezier_curve.control_points
            ]
        ),
    )

transform_elliptical_arc

transform_elliptical_arc(elliptical_arc: EllipticalArc, transformation: Transformation) -> EllipticalArc

Transform an elliptical arc.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc to transform.

required
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
EllipticalArc

The transformed EllipticalArc.

Source code in src/momapy/geometry.py
def transform_elliptical_arc(
    elliptical_arc: EllipticalArc, transformation: Transformation
) -> EllipticalArc:
    """Transform an elliptical arc.

    Args:
        elliptical_arc: The arc to transform.
        transformation: The transformation to apply.

    Returns:
        The transformed EllipticalArc.
    """
    east = Point(
        math.cos(elliptical_arc.x_axis_rotation) * elliptical_arc.rx,
        math.sin(elliptical_arc.x_axis_rotation) * elliptical_arc.rx,
    )
    north = Point(
        math.cos(elliptical_arc.x_axis_rotation) * elliptical_arc.ry,
        math.sin(elliptical_arc.x_axis_rotation) * elliptical_arc.ry,
    )
    new_center = transform_point(Point(0, 0), transformation)
    new_east = transform_point(east, transformation)
    new_north = transform_point(north, transformation)
    new_rx = Segment(new_center, new_east).length()
    new_ry = Segment(new_center, new_north).length()
    new_start_point = transform_point(elliptical_arc.p1, transformation)
    new_end_point = transform_point(elliptical_arc.p2, transformation)
    new_x_axis_rotation = math.degrees(
        get_angle_to_horizontal_of_line(Line(new_center, new_east))
    )
    return EllipticalArc(
        p1=new_start_point,
        p2=new_end_point,
        rx=new_rx,
        ry=new_ry,
        x_axis_rotation=new_x_axis_rotation,
        arc_flag=elliptical_arc.arc_flag,
        sweep_flag=elliptical_arc.sweep_flag,
    )

transform_elliptical_arc_to_bezier_curves

transform_elliptical_arc_to_bezier_curves(elliptical_arc: EllipticalArc) -> list[BezierCurve]

Convert an elliptical arc to Bezier curves.

Parameters:

Name Type Description Default
elliptical_arc EllipticalArc

The arc to convert.

required

Returns:

Type Description
list[BezierCurve]

List of BezierCurve approximating the arc.

Source code in src/momapy/geometry.py
def transform_elliptical_arc_to_bezier_curves(
    elliptical_arc: EllipticalArc,
) -> list[BezierCurve]:
    """Convert an elliptical arc to Bezier curves.

    Args:
        elliptical_arc: The arc to convert.

    Returns:
        List of BezierCurve approximating the arc.
    """
    def _make_angles(angles):
        new_angles = [angles[0]]
        for theta1, theta2 in zip(angles, angles[1:]):
            delta_theta = theta2 - theta1
            if delta_theta > math.pi / 2:
                new_angles.append(theta1 + delta_theta / 2)
            new_angles.append(theta2)
        if len(new_angles) != len(angles):
            new_angles = _make_angles(new_angles)
        return new_angles

    bezier_curves = []
    (
        cx,
        cy,
        rx,
        ry,
        sigma,
        theta1,
        theta2,
        delta_theta,
    ) = get_center_parameterization_of_elliptical_arc(elliptical_arc)
    translation = Translation(cx, cy)
    scaling = Scaling(rx, ry)
    rotation = Rotation(sigma)
    transformation = translation * rotation * scaling
    angles = _make_angles([theta1, theta2])
    for theta1, theta2 in zip(angles, angles[1:]):
        x1 = math.cos(theta1)
        y1 = math.sin(theta1)
        x2 = math.cos(theta2)
        y2 = math.sin(theta2)
        ax = x1
        ay = y1
        bx = x2
        by = y2
        q1 = ax * ax + ay * ay
        q2 = q1 + ax * bx + ay * by
        k2 = (4 / 3) * (math.sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx)
        cp1x = ax - k2 * ay
        cp1y = ay + k2 * ax
        cp2x = bx + k2 * by
        cp2y = by - k2 * bx
        p1 = Point(x1, y1)
        p2 = Point(x2, y2)
        control_point1 = Point(cp1x, cp1y)
        control_point2 = Point(cp2x, cp2y)
        bezier_curve = BezierCurve(
            p1=p1, p2=p2, control_points=tuple([control_point1, control_point2])
        ).transformed(transformation)
        bezier_curves.append(bezier_curve)
    return bezier_curves

transform_line

transform_line(line: Line, transformation: Transformation) -> Line

Transform a line.

Parameters:

Name Type Description Default
line Line

The line to transform.

required
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
Line

The transformed line.

Source code in src/momapy/geometry.py
def transform_line(line: Line, transformation: Transformation) -> Line:
    """Transform a line.

    Args:
        line: The line to transform.
        transformation: The transformation to apply.

    Returns:
        The transformed line.
    """
    return Line(
        transform_point(line.p1, transformation),
        transform_point(line.p2, transformation),
    )

transform_point

transform_point(point: Point, transformation: Transformation) -> Point

Transform a point.

Parameters:

Name Type Description Default
point Point

The point to transform.

required
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
Point

The transformed point.

Source code in src/momapy/geometry.py
def transform_point(point: Point, transformation: Transformation) -> Point:
    """Transform a point.

    Args:
        point: The point to transform.
        transformation: The transformation to apply.

    Returns:
        The transformed point.
    """
    m = numpy.matmul(transformation.to_matrix(), point.to_matrix())
    return Point(m[0][0], m[1][0])

transform_segment

transform_segment(segment: Segment, transformation: Transformation) -> Segment

Transform a segment.

Parameters:

Name Type Description Default
segment Segment

The segment to transform.

required
transformation Transformation

The transformation to apply.

required

Returns:

Type Description
Segment

The transformed segment.

Source code in src/momapy/geometry.py
def transform_segment(segment: Segment, transformation: Transformation) -> Segment:
    """Transform a segment.

    Args:
        segment: The segment to transform.
        transformation: The transformation to apply.

    Returns:
        The transformed segment.
    """
    return Segment(
        transform_point(segment.p1, transformation),
        transform_point(segment.p2, transformation),
    )