Skip to main content

kaffine

codecov PyPI version Maintainer PyPI pyversions PyPI status PyPI download day

Inspiration

Kaffine is inspired by pint and affine. And aims to make the creation of unit-aware affine transformations as easy as possible.

Here is a complete, professional GitHub-style README.md for your project. I have named the library affine-3d for this document.

You can save this directly as README.md in your project root.


affine-3d

A fluent, unit-aware 3D transformation library for Python.

affine-3d simplifies constructing complex 4x4 affine transformation matrices. It replaces dense NumPy matrix math with a readable Builder Pattern, offers native integration with Pint for physical units (mixing microns, millimeters, and inches), and bridges seamlessly with Scipy for advanced usage.

Designed for Computer Vision, Microscopy, and Robotics applications where "Sample-to-Camera" or "Stage-to-World" coordinates are critical.

🚀 Features

  • Fluent Interface: Chain operations like .translate_x(10).rotate_z(90).
  • Unit Aware: Native support for Pint. Move 100 microns on X and 2 mm on Y without manual conversion.
  • Hardware Ready: Includes decompose() to extract pixel size, rotation, and stage position from a raw matrix.
  • Type Safe: Built with modern Python 3.11+ type hints (typing.Self, | unions).
  • Scipy Bridge: Cast to/from scipy.spatial.transform.Rotation for quaternions and slerp.
  • Zero-Crash Defaults: Scipy and Pint are optional dependencies. The library falls back to pure NumPy if they aren't installed.

📦 Installation

uv add rm kaffine

⚡ Quick Start

1. The Simple Math Interface

Perfect for standard graphics or geometry.

from kaffine import Affine

# Create a transform: Move 10 units X, then Rotate 45 deg Z
# (Note: Order is intuitive "Operation 1 -> Operation 2")
tf = Affine.new().translate_x(10).rotate_z(45)

# Apply to a point
point = [0, 0, 0]
result = tf * point 

print(result) 
# Output (4D homogeneous): [10.0, 0.0, 0.0, 1.0]

2. The "Hardware" Interface (with Units)

Perfect for controlling stages, cameras, or mixing scales.

from kaffine import Affine
import pint

ureg = pint.UnitRegistry()

# Define your setup's units
ureg.define("step = 0.1 um")  # Piezo stepper resolution
ureg.define("pixel = 3.45 um") # Camera sensor pixel size

# Construct a Matrix that converts Pixels to Stage Coordinates (mm)
# Scenario: 
# 1. Scale pixels to physical size
# 2. Rotate camera 90 degrees
# 3. Translate to stage position (defined in steps)
tf = Affine.new(base_unit="um", registry=ureg) \
    .scale_uniform("1 pixel") \
    .rotate_z(90) \
    .translate_x("50000 step") 

# Transform a point from Pixel Space to Millimeters
pixel_point = [100, 100, 0] # 100x100 px on image
world_point = tf.apply(pixel_point)

print(world_point)
# Output: <Quantity([5.0 -0.345 0. 1.], 'millimeter')>

📚 Advanced Usage

Matrix Decomposition (Calibration)

If you have a calibration matrix and need to know the physical properties of your setup (e.g., "What is my effective pixel size?"), use .decompose().

# Assume 'tf' is a calibrated matrix loaded from a file
info = tf.decompose()

print(f"Position:   {info.translation}") # e.g., [10.5, 2.0, 0] mm
print(f"Pixel Size: {info.scale}")       # e.g., [0.00345, 0.00345, 1.0]
print(f"Rotation:   {info.rotation}")    # e.g., [0, 0, 1.5] degree

Scipy Interoperability

Need Quaternions or Spherical Interpolation?

tf = Affine.new().rotate_x(45).rotate_y(30)

# Cast to Scipy
r_scipy = tf.to_scipy_rotation()
print(r_scipy.as_quat())

# ... do complex math ...
r_scipy_inverted = r_scipy.inv()

# Cast back
tf_inv = Affine.from_scipy(r_scipy_inverted)

🛠 API Reference

Affine.new(base_unit="mm", registry=None)

Starts a new transformation chain.

  • base_unit: The physical unit the internal matrix numbers represent.
  • registry: Your pint.UnitRegistry.

Builder Methods

All methods return a new Affine instance (immutable-style chaining).

  • .translate(x, y, z) / .translate_x(val) ...
  • .rotate(angle, axis='z') / .rotate_x(angle) ...
  • .scale(x, y, z) / .scale_uniform(s)

Application

  • tf * [x, y, z]: Returns a raw Numpy array (4D).
  • tf * other_tf: Composes two transforms.
  • tf.apply(points): Accepts/Returns Pint Quantities.

Utilities

  • tf.decompose(): Returns Decomposition(translation, scale, rotation).
  • tf.to_scipy_rotation(): Returns scipy.spatial.transform.Rotation.

🧪 Running Tests

The project includes a comprehensive pytest suite covering math accuracy, unit conversion, and edge cases.

uv run pytest tests/

📄 License

MIT License. Feel free to use this in your commercial or open-source projects.

Metadata

Release files for kaffine 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kaffine 2.1.0
File Size Uploaded Provenance
kaffine-2.1.0.tar.gz 7.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for kaffine 2.1.0
File Interpreter ABI Platform
kaffine-2.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 14.4 kB

Release files / kaffine-2.1.0.tar.gz

Download URL kaffine-2.1.0.tar.gz
Size 7.6 kB
Tags Source
SHA-256 checksum
How to use checksums
020ca1993f367dbe3e12fe46d4739498625783b212e0dbaaf15c1a7717bda8e8
BLAKE2b-256 checksum
How to use checksums
0489a26f0de047892a2360e2ac2d7d2a449428b545703fea3751bfd0adbb5a51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.3

Release files / kaffine-2.1.0-py3-none-any.whl

Download URL kaffine-2.1.0-py3-none-any.whl
Size 6.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5eaddacbc3fe2d9028b6c20e2f6fb36a11276a133e1fad1ea025aa9a3fce2066
BLAKE2b-256 checksum
How to use checksums
37f65dc32256c271abe8105b483fdf52557322fd4ae3c13d559dfc467fb2ce3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.3

Security for kaffine 2.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page