Skip to main content

A 2D/3D geometry library for CAD/CAM applications.

Project description

raygeo

PyPI CI

A high-performance 2D/3D geometry library for Python, built in Rust with PyO3.

raygeo provides vector path construction, polygon boolean operations, curve fitting, path transformations, and geometric queries — all backed by a native Rust extension.

Installation

pip install raygeo

Requires Python 3.10+ and a compatible platform (Linux, Windows, macOS Intel, or macOS Apple Silicon). Pre-compiled wheels are available on PyPI.

Quick Start

Building Paths

The Geometry class is the core abstraction. It stores a vector path as a sequence of move, line, arc, and cubic Bezier commands. All mutating methods return self for chaining:

from raygeo.geo import Geometry

# Create a 10x10 square
g = Geometry()
g.move_to(0, 0)
g.line_to(10, 0)
g.line_to(10, 10)
g.line_to(0, 10)
g.close_path()

print(g.area())    # 100.0
print(g.rect())    # (0.0, 0.0, 10.0, 10.0)
print(g.is_closed())  # True

Builder methods can be chained:

g = Geometry()
g.move_to(0, 0).line_to(10, 0).line_to(10, 10).line_to(0, 10).close_path()

You can also create paths from point lists:

triangle = Geometry.from_points([(0, 0), (10, 0), (5, 8.66)])

Arcs and Bezier Curves

g = Geometry()
g.move_to(0, 0)
g.arc_to(10, 0, i=5, j=0, clockwise=False)  # semicircular arc
g.close_path()

# Bezier curves
g2 = Geometry()
g2.move_to(0, 0)
g2.bezier_to(10, 0, c1x=3, c1y=5, c2x=7, c2y=5)

# Convert arcs to Bezier curves (for non-uniform scaling)
g3 = Geometry()
g3.move_to(0, 0)
g3.arc_to_as_bezier(10, 0, i=5, j=0)
g3.upgrade_to_scalable()

Path Analysis

print(g.distance())       # total path length
print(g.area())           # signed enclosed area
print(g.rect())           # bounding box (x_min, y_min, x_max, y_max)
print(g.is_closed())      # path closure check
print(g.segments())       # split into sub-paths

# Find closest point on path
result = g.find_closest_point(5, 5)  # (segment_index, t, (x, y))

# Point and tangent at parameter t on a segment
point = g.get_point_at(segment_index=0, t=0.5)
tangent = g.get_tangent_at(segment_index=0, t=0.5)

Transformations

All transformation methods mutate the geometry in place and return self, allowing chaining. Use .copy() first if you need to preserve the original:

import numpy as np
from raygeo.geo import Geometry

g = Geometry.from_points([(0, 0), (10, 0), (10, 10), (0, 10)])

# Offset (grow/shrink) — mutates in place
g.grow(2.0)   # offset outward by 2 units
print(g.area())  # 144.0

# Use .copy() to preserve the original
original = Geometry.from_points([(0, 0), (10, 0), (10, 10), (0, 10)])
shrunk = original.copy()
shrunk.grow(-1.0)  # offset inward by 1 unit

# Affine transform (4x4 matrix) — mutates in place
matrix = [
    [1, 0, 0, 5],  # translate x by 5
    [0, 1, 0, 3],  # translate y by 3
    [0, 0, 1, 0],
    [0, 0, 0, 1],
]
g.transform(matrix)

# Map geometry into a frame — mutates in place
g.map_to_frame(
    origin=(0, 0),
    p_width=(100, 0),
    p_height=(0, 100),
)

g.flip_x()  # negate all x coordinates
g.flip_y()  # negate all y coordinates

# Chaining is possible since all methods return self
g2 = Geometry.from_points([(0, 0), (10, 0), (10, 10), (0, 10)])
g2.transform(matrix).flip_x().grow(1.0)

Contour Operations

All contour methods mutate the geometry in place and return self:

# Split into separate closed contours (returns list, does not mutate)
contours = g.split_into_contours()

# Split into disconnected components (returns list, does not mutate)
components = g.split_into_components()

# Separate holes from solids (returns tuple, does not mutate)
inner, outer = g.split_inner_and_outer_contours()

# Normalize winding orders — mutates in place
g.normalize_winding_orders()

# Filter to only external contours — mutates in place
g.filter_to_external_contours()

# Remove shared edges between sub-paths — mutates in place
g.remove_inner_edges()

Polygon Operations

The geo.shape.polygon submodule provides polygon-specific operations powered by Clipper2:

from raygeo.geo import Geometry
from raygeo.geo.shape.polygon import (
    get_polygon_area,
    get_polygon_bounds,
    offset_polygon,
    get_polygons_union,
    get_polygons_intersection,
    get_polygons_difference,
    is_point_inside_polygon,
    polygons_intersect,
    get_polygon_convex_hull,
)

square = [(0, 0), (10, 0), (10, 10), (0, 10)]
circle_approx = [(5 + 5 * math.cos(a), 5 + 5 * math.sin(a))
                 for a in [i * math.pi / 20 for i in range(40)]]

get_polygon_area(square)                # 100.0
get_polygon_bounds(square)              # (0.0, 0.0, 10.0, 10.0)
is_point_inside_polygon((5, 5), square) # True

# Boolean operations
union = get_polygons_union([square, circle_approx])
intersection = get_polygons_intersection([square, circle_approx])
difference = get_polygons_difference([square], [circle_approx])

# Offset
inflated = offset_polygon(square, 2.0)

# NumPy variants are also available (suffixed with _numpy)
import numpy as np
sq_np = np.array(square)
get_polygon_area(sq_np)  # also works with numpy arrays

Curve Fitting

All fitting methods mutate the geometry in place and return self:

from raygeo.geo import Geometry

# Simplify a path
g.simplify(tolerance=0.1)

# Convert curves to line segments
g.linearize(tolerance=0.01)

# Fit arcs and beziers to linear data
g.fit_arcs(tolerance=0.5)
g.fit_curves(tolerance=0.5, beziers=True, arcs=True)

# Convert geometry to polygons (returns list, does not mutate)
polygons = g.to_polygons(tolerance=0.01)

Self-Intersection Detection

g.has_self_intersections()          # check for self-intersections
g.intersects_with(other_geometry)   # check intersection with another geometry
g.encloses(other_geometry)          # check if this fully encloses another

Serialization

# Dump to dict (JSON-safe)
data = g.dump()

# Load from dict
g2 = Geometry.load(data)

# Pickle support (via __reduce_ex__)
import pickle
g3 = pickle.loads(pickle.dumps(g))

Documentation

Full API documentation is generated from the source type stubs and published with the RayForge Developer Docs.

Development

Prerequisites

  • Rust toolchain (latest stable)
  • Python 3.10+
  • maturin (pip install maturin)
  • Node.js (only needed for make lint-python, which runs pyright via npx)

Quick Start

# Create and activate a virtual environment (Unix)
python -m venv .venv
source .venv/bin/activate   # on Windows: .venv\Scripts\activate

# Install build tool and build the extension
pip install maturin pytest
make dev                   # builds Rust extension and installs into venv

# Run tests
make test

# Full check (lint + test)
make check

Available Make Targets

Target Description
make dev Build and install into the active venv
make build Build release wheel to dist/
make test Run pytest
make lint Lint Rust + Python (including pyright)
make format Auto-format Rust + Python
make check Lint + test
make stubs Regenerate .pyi type stubs
make visual Launch Streamlit visual test playground

Visual Testing

The make visual target launches an interactive Streamlit app for exploring geometry operations visually. Install the optional deps first:

pip install -e ".[visual]"
make visual

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

raygeo-0.7.0.tar.gz (345.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

raygeo-0.7.0-cp311-abi3-win_amd64.whl (1.3 MB view details)

Uploaded CPython 3.11+Windows x86-64

raygeo-0.7.0-cp311-abi3-manylinux_2_35_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.35+ x86-64

raygeo-0.7.0-cp311-abi3-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

raygeo-0.7.0-cp311-abi3-macosx_10_12_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

Details for the file raygeo-0.7.0.tar.gz.

File metadata

  • Download URL: raygeo-0.7.0.tar.gz
  • Upload date:
  • Size: 345.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for raygeo-0.7.0.tar.gz
Algorithm Hash digest
SHA256 b27665483508ada85057df5a6d9a9b133b8b96f60976c709c217141b5ea617a5
MD5 a9e715423f7dfff762cabf958e1d2f48
BLAKE2b-256 63419340e5e5a7c53e3ebc839141cb9f7fcbb824b7111282209f36378a5d9584

See more details on using hashes here.

Provenance

The following attestation bundles were made for raygeo-0.7.0.tar.gz:

Publisher: release.yml on barebaric/raygeo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file raygeo-0.7.0-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: raygeo-0.7.0-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 1.3 MB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for raygeo-0.7.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 b55033c1144a2cb6f15f68621b462f04fc7a1b39c515182efb76d9218a5e7fd8
MD5 71ed80c41bd0fcd183f0801962d1a416
BLAKE2b-256 73e2c28a903ef18c9e6f33b8586bcae3aee634bfe2a240f895f658b9e2f576c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for raygeo-0.7.0-cp311-abi3-win_amd64.whl:

Publisher: release.yml on barebaric/raygeo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file raygeo-0.7.0-cp311-abi3-manylinux_2_35_x86_64.whl.

File metadata

File hashes

Hashes for raygeo-0.7.0-cp311-abi3-manylinux_2_35_x86_64.whl
Algorithm Hash digest
SHA256 671dc4673d93fc69950644c38f923a3e3b28f3e2dd2eb37c1827a79ba9a40694
MD5 6d3d0b9fc4ab34ffe3916170efb01337
BLAKE2b-256 c5efb0a76638b497eebba0b1c989942470d9a6dc288220c24ecd9d03fee01473

See more details on using hashes here.

Provenance

The following attestation bundles were made for raygeo-0.7.0-cp311-abi3-manylinux_2_35_x86_64.whl:

Publisher: release.yml on barebaric/raygeo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file raygeo-0.7.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for raygeo-0.7.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c774ab3d0b47b8b3b54b4c5c6c98ed4094e872aa414a5baa962fee8dda468d06
MD5 ac3c09867b11783626d4b9837561a266
BLAKE2b-256 ae2ced253efe6fb1c37f79cf7fd8da1031d3a60eb3b9bb3a8ca85af9aa9aec02

See more details on using hashes here.

Provenance

The following attestation bundles were made for raygeo-0.7.0-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on barebaric/raygeo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file raygeo-0.7.0-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for raygeo-0.7.0-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 a81aa7d7f0f9005711f576dd2bbe3ed80811558b18df07211be6afbcc2203590
MD5 e47496cb3f9f683ad948829571343168
BLAKE2b-256 e936122c61f3741415016b503d4c6844ef1c4419bfe3d1ea092ca2db652f9f07

See more details on using hashes here.

Provenance

The following attestation bundles were made for raygeo-0.7.0-cp311-abi3-macosx_10_12_x86_64.whl:

Publisher: release.yml on barebaric/raygeo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page