Skip to main content

transforms/
lib.rs

1//! A blazingly fast and efficient coordinate transform library for robotics and computer vision applications.
2//!
3//! This library provides functionality for managing coordinate transformations between different frames
4//! of reference.
5//!
6//! # Architecture
7//!
8//! The library is organized around three main components:
9//!
10//! - **Registry**: The main interface for managing transforms
11//! - **Buffer**: Internal storage for transforms between specific frames
12//! - **Transform**: The core data structure representing spatial transformations
13//!
14//! # Features
15//!
16//! - **Transform Interpolation**: Smooth interpolation between transforms at different timestamps
17//! - **Transform Chaining**: Automatic computation of transforms between indirectly connected frames
18//! - **Static Transforms**: Transforms with the static timestamp value are treated as static (`t=0` by default).
19//! - **Custom Timestamp Types**: You can use your own `Copy` timestamp type by implementing `time::TimePoint`.
20//! - **Time-based Buffer Management**: Automatic cleanup of old transforms is available with feature = "std", which is default enabled. If the library is used as ```no_std``` then manual cleanup is required. See the examples.
21//!
22//! # Non-Goals
23//!
24//! This library intentionally limits its scope to rigid body transformations (translation and rotation)
25//! commonly used in robotics and computer vision. The following transformations are explicitly not
26//! supported and will not be considered for future implementation:
27//!
28//! - Scaling transformations
29//! - Skew transformations
30//! - Perspective transformations
31//! - Non-rigid transformations
32//! - Affine transformations beyond rigid body motion
33//!
34//! This decision helps maintain the library's focus on its core purpose: providing fast and efficient
35//! rigid body transformations for robotics applications. For more general transformation needs,
36//! consider using a computer graphics or linear algebra library instead.
37//!
38//! # Examples
39//!
40//! ```rust
41//! use transforms::{
42//!     geometry::{Quaternion, Transform, Vector3},
43//!     time::Timestamp,
44//!     Registry,
45//! };
46//!
47//! # #[cfg(feature = "std")]
48//! use core::time::Duration;
49//! # #[cfg(feature = "std")]
50//! let mut registry = Registry::new(Duration::from_secs(60));
51//! # #[cfg(feature = "std")]
52//! let timestamp = Timestamp::now();
53//!
54//! # #[cfg(not(feature = "std"))]
55//! let mut registry = Registry::new();
56//! # #[cfg(not(feature = "std"))]
57//! let timestamp = Timestamp::zero();
58//!
59//! // Create a transform from frame "base" to frame "sensor"
60//! let transform = Transform {
61//!     translation: Vector3::new(1.0, 0.0, 0.0),
62//!     rotation: Quaternion::identity(),
63//!     timestamp,
64//!     parent: "base".into(),
65//!     child: "sensor".into(),
66//! };
67//!
68//! // Add the transform to the registry
69//! registry.add_transform(transform);
70//!
71//! // Retrieve the transform
72//! let result = registry.get_transform("base", "sensor", timestamp).unwrap();
73//!
74//! # #[cfg(not(feature = "std"))]
75//! // Delete old transforms
76//! # #[cfg(not(feature = "std"))]
77//! registry.delete_transforms_before(timestamp);
78//! ```
79//!
80//! # Transform and Data Transformation
81//!
82//! The library provides a `Transform` type that represents spatial transformations between different
83//! coordinate frames. Transforms follow the common robotics convention where transformations are
84//! considered from child to parent frame (e.g., from sensor frame to base frame, or from base frame
85//! to map frame).
86//!
87//! To make your data transformable between different coordinate frames, implement the `Transformable`
88//! trait. This allows you to easily transform your data using the transforms stored in the registry.
89//! ```rust
90//! use transforms::{
91//!     geometry::{Point, Quaternion, Transform, Vector3},
92//!     time::Timestamp,
93//!     Transformable,
94//! };
95//!
96//! // Create a point in the camera frame
97//! let mut point = Point {
98//!     position: Vector3::new(1.0, 0.0, 0.0),
99//!     orientation: Quaternion::identity(),
100//! # #[cfg(not(feature = "std"))]
101//!     timestamp: Timestamp::zero(),
102//! # #[cfg(feature = "std")]
103//!     timestamp: Timestamp::now(),
104//!     frame: "camera".into(),
105//! };
106//!
107//! // Define transform from camera to base frame
108//! let transform = Transform {
109//!     translation: Vector3::new(0.0, 1.0, 0.0),
110//!     rotation: Quaternion::identity(),
111//!     timestamp: point.timestamp,
112//!     parent: "base".into(),
113//!     child: "camera".into(),
114//! };
115//!
116//! // Transform the point from camera frame to base frame
117//! point.transform(&transform).unwrap();
118//! assert_eq!(point.position.x, 1.0);
119//! assert_eq!(point.position.y, 1.0);
120//! ```
121//!
122//! The transform convention follows the common robotics practice where data typically needs to be
123//! transformed from specific sensor reference frames "up" to more general frames like the robot's
124//! base frame or a global map frame.
125//!
126//! # Relationship with ROS2's tf2
127//!
128//! This library draws inspiration from ROS2's tf2 (Transform Framework 2), a widely-used
129//! transform library in the robotics community. While this crate aims to solve the same
130//! fundamental problem of transformation tracking, it does so in its own way.
131//!
132//! ## Similarities with tf2
133//!
134//! - Maintains relationships between coordinate frames in a tree structure
135//! - Buffers transforms over time
136//! - Supports transform lookups between arbitrary frames
137//! - Handles interpolation between transforms
138//!
139//! ## Key Differences
140//!
141//! This library:
142//! - Is a pure Rust implementation, not a wrapper around tf2
143//! - Makes no attempt to perfectly match the ROS2/tf2 API
144//! - Focuses on providing an ergonomic Rust-first experience
145//! - Is independent of ROS2's middleware and communication system
146//!
147//! While the core concepts and functionality align with tf2, this library prioritizes
148//! optimal usage for rust software over maintaining API compatibility with ROS2's tf2. Users
149//! familiar with tf2 will find the concepts familiar, but the implementation details
150//! and API design follow Rust idioms and best practices as best as it can.
151//!
152//! # `TimePoint` vs `Timestamp`
153//!
154//! `time::TimePoint` defines the required behavior for timestamp types.
155//! `time::Timestamp` is the default implementation.
156//! `Registry::new(...)` therefore uses `Timestamp` by default.
157//! If you need a custom clock, implement `TimePoint` and use
158//! `Registry::<CustomTimestamp>::new(...)`.
159//! With `std`, `std::time::SystemTime` is already supported via an existing
160//! `TimePoint` implementation.
161//! See `time` module docs for custom time-type guidance.
162//!
163//! # Performance Considerations
164//!
165//! - Transform lookups are optimized for O(log n) time complexity
166//! - Automatic cleanup of old transforms prevents unbounded memory growth
167//!
168//! # External Crates
169//!
170//! If you are looking for a version of this crate that is directly compatible with ROS1 & ROS2 consider
171//! [roslibrust_transforms](https://docs.rs/roslibrust_transforms/latest/roslibrust_transforms/) that wraps
172//! this crate in ROS pure-Rust ROS clients.
173//!
174//! # Safety
175//!
176//! This crate uses `#![forbid(unsafe_code)]` to ensure memory safety through pure Rust implementations.
177#![forbid(unsafe_code)]
178#![warn(clippy::pedantic)]
179#![warn(clippy::alloc_instead_of_core)]
180#![warn(clippy::std_instead_of_core)]
181#![cfg_attr(test, allow(clippy::similar_names))]
182#![cfg_attr(test, allow(clippy::too_many_lines))]
183#![cfg_attr(test, allow(clippy::duration_suboptimal_units))]
184#![cfg_attr(not(feature = "std"), no_std)]
185
186extern crate alloc;
187pub mod core;
188pub mod errors;
189pub mod geometry;
190pub mod time;
191pub use core::Registry;
192pub use geometry::{Localized, Transform, Transformable};