Hierarchical coordinate frames - crystal clear transforms
Project description
hazy-frames
Hierarchical coordinate frames - crystal clear transforms
A Python library for managing hierarchical reference frames and frame-aware geometric primitives with efficient transformation caching, inspired by optiland.
Features
- Hierarchical Frame System: Build complex frame hierarchies with parent-child relationships
- Frame-Aware Primitives:
PointandVectorclasses that carry frame information - Automatic Transformations: Transform primitives between any frames in the hierarchy
- Efficient Caching: Transformation matrices are cached for performance
- Proper Geometric Semantics: Type-safe arithmetic operations (e.g., Point - Point = Vector)
- Flexible Transformations: Support for rotation (Euler angles, matrices), translation, and scaling
- Global Reference Frame: Singleton global frame for world coordinates
Installation
Install directly from GitHub:
pip install git+https://github.com/Littie28/hazy-frames.git
Or download the wheel from releases:
pip install hazy_frames-0.1.0-py3-none-any.whl
For development:
# Clone the repository
git clone https://github.com/Littie28/hazy-frames.git
cd hazy-frames
# Install with development dependencies
uv sync --group dev
Quick Start
from hazy import Frame, Point, Vector
# Create a frame hierarchy
world = Frame.get_global()
robot = Frame(parent=world, name="robot")
robot.translate(x=5, y=0, z=0).rotate_euler(z=90, degrees=True)
camera = robot.make_child(name="camera") # different initialization methods
camera.translate(x=0, y=0, z=1)
# Create frame-aware primitives
point_in_camera = Point(1, 0, 0, frame=camera)
# Transform between frames
point_in_world = point_in_camera.to_frame(world)
point_in_robot = point_in_camera.to_frame(robot)
print(f"Camera: {point_in_camera}")
print(f"World: {point_in_world}")
print(f"Robot: {point_in_robot}")
Core Concepts
Frames
Frames represent coordinate systems and can be organized hierarchically:
# Create frames
root = Frame.make_root(name="root")
parent = root.make_child("parent")
child = Frame(parent=parent, name="child")
# Apply transformations (chainable)
child.translate(x=10, y=5, z=0)
child.rotate_euler(x=45, y=0, z=90, degrees=True)
child.scale(2.0) # uniform scaling
child.scale((1.0, 2.0, 1.5)) # non-uniform scaling
# Freeze frames to prevent modifications
child.freeze()
Transformations are applied in S->R->T order (Scale, Rotation, Translation) when converting from local to parent coordinates.
Points and Vectors
Points represent positions, vectors represent directions/displacements:
# Create primitives
origin = Point(0, 0, 0, frame=child)
direction = Vector(1, 0, 0, frame=child)
# Proper geometric arithmetic
point_a = Point(1, 2, 3, frame=child)
point_b = Point(4, 5, 6, frame=child)
displacement = point_b - point_a # Returns Vector
new_point = point_a + displacement # Returns Point
# Vectors support additional operations
vec = Vector(1, 0, 0, frame=child)
vec.normalize() # Normalize in-place
magnitude = vec.magnitude
# Cross product
vec1 = Vector(1, 0, 0, frame=child)
vec2 = Vector(0, 1, 0, frame=child)
perpendicular = vec1.cross(vec2) # Vector(0, 0, 1)
Frame Transformations
# Get transformation matrices
T_to_parent = frame.transform_to_parent # 4x4 matrix
T_from_parent = frame.transform_from_parent # Inverse
T_to_global = frame.transform_to_global # To world frame
T_to_target = frame.transform_to(target_frame) # To any frame
# Transform primitives
point_global = point_local.to_global()
point_target = point_local.to_frame(target_frame)
# Batch transformations for efficiency
points_array = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
transformed = frame.batch_transform_points_global(points_array)
Unit Vectors and Origin
Frames provide convenient accessors for unit vectors and origin:
# Unit vectors in frame's local coordinates
x_axis = frame.x_axis
y_axis = frame.y_axis
z_axis = frame.z_axis
# Unit vectors in global coordinates
x_global = frame.x_axis_global
y_global = frame.y_axis_global
z_global = frame.z_axis_global
# Frame origin
origin_local = frame.origin # Point(0, 0, 0) in frame
origin_global = frame.origin_global # Origin in global coords
API Overview
Frame Class
| Method/Property | Description |
|---|---|
translate(x, y, z) |
Add translation to frame |
rotate_euler(x, y, z, seq, degrees) |
Add Euler angle rotation |
rotate(matrix) |
Add rotation from 3x3 matrix |
scale(factor) |
Add scaling (uniform or non-uniform) |
freeze()/unfreeze() |
Prevent/allow modifications |
transform_to_parent |
4x4 transformation matrix to parent |
transform_to_global |
4x4 transformation matrix to global |
transform_to(target) |
4x4 transformation matrix to target frame |
point(x, y, z) |
Create Point in this frame |
vector(x, y, z) |
Create Vector in this frame |
Point Class
| Method/Property | Description |
|---|---|
to_frame(target) |
Transform to target frame |
to_global() |
Transform to global frame |
x, y, z |
Coordinate components |
Point + Vector |
Returns Point (displacement) |
Point - Point |
Returns Vector (difference) |
Point - Vector |
Returns Point (reverse displacement) |
Vector Class
| Method/Property | Description |
|---|---|
to_frame(target) |
Transform to target frame |
to_global() |
Transform to global frame |
x, y, z |
Vector components |
magnitude |
Vector length |
normalize() |
Normalize to unit length (in-place) |
cross(other) |
Cross product with another vector |
Vector + Vector |
Returns Vector (sum) |
Vector - Vector |
Returns Vector (difference) |
Vector + Point |
Returns Point (displacement) |
Development
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=src/hazy --cov-report=html
# Run specific test markers
pytest -m unit
pytest -m integration
# Watch mode for development
pytest-watcher
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hazy_frames-0.1.0.tar.gz.
File metadata
- Download URL: hazy_frames-0.1.0.tar.gz
- Upload date:
- Size: 131.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.05","id":"yarara","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f90386365677706feb69b08048a60435b79f0fea8410911e2a6c4298652bd13
|
|
| MD5 |
f3461eab57c13f5edef62b648ed8f92d
|
|
| BLAKE2b-256 |
1151a8d8fa9c671e976b91657d11c47d533e9086bcda317a2b2d7216722d6fba
|
File details
Details for the file hazy_frames-0.1.0-py3-none-any.whl.
File metadata
- Download URL: hazy_frames-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.05","id":"yarara","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f947502a31ae9d57c9669eeef82eb7b7fce235aab5881898f1ce312337f6636d
|
|
| MD5 |
7ed44da574a1c9b357d1d982bbc408c5
|
|
| BLAKE2b-256 |
9089d8aac90941c32de9a97821db9920f6d72d0009ad0bfc793034c3596952cc
|