trackball/
lib.rs

1//! Virtual Trackball Orbiting via the Exponential Map
2//!
3//! This is an alternative trackball technique using exponential map and parallel transport to
4//! preserve distances and angles for inducing coherent and intuitive trackball rotations. For
5//! instance, displacements on straight radial lines through the screen's center are carried to arcs
6//! of the same length on great circles of the trackball. This is in contrast to state-of-the-art
7//! techniques using orthogonal projection which distorts radial distances further away from the
8//! screen's center.[^1]
9//!
10//! [^1]: G. Stantchev, “Virtual Trackball Modeling and the Exponential Map”, [S2CID 44199608 (2004)
11//! ](https://api.semanticscholar.org/CorpusID:44199608), [Archived PDF
12//! ](https://web.archive.org/web/2/http://www.math.umd.edu:80/~gogo/Papers/trackballExp.pdf)
13//!
14//! # Features
15//!
16//!   * Common trackball operations split into several operation handlers.
17//!   * Coherent and intuitive orbiting via the exponential map, see [`Orbit`] operation handler.
18//!   * Identical C11 implementation for [`Orbit`] operation handler behind `cc` feature gate.
19//!   * Coherent [`First`] person view aka free look or mouse look wrt [`Orbit`] operation handler.
20//!   * Observer [`Frame`] with [`Frame::slide()`], [`Frame::orbit()`], [`Frame::scale()`]
21//!     operations in world space and their local complements in camera space and with orbit and
22//!     slide operations around arbitrary points in either world or camera space.
23//!   * Gliding [`Clamp`] operation handler trait ensuring boundary conditions of observer
24//!     [`Frame`]. When [`Delta`] between initial and final [`Frame`] is not orthogonal to a
25//!     boundary [`Plane`], [`Delta`] is changed in such a way that the clamped movement glides
26//!     along the plane.
27//!   * [`Bound`] implementing [`Clamp`] providing customizable orthogonal boundary conditions.
28//!   * Object inspection mode scaling clip plane distances by measuring from target instead of eye.
29//!   * Scale-preserving transitioning between orthographic and perspective projection mode.
30//!   * Converting between [`Fixed`] quantities wrt to field of view, see [`Scope::set_fov()`].
31//!   * Time-free [`Touch`] gesture recognition for slide, orbit, scale, and focus operations.
32//!
33//! # Optional Features
34//!
35//! Following features are disabled unless their corresponding feature gate is enabled:
36//!
37//!   * `glam` for converting between `nalgebra` and `glam` types.
38//!   * `serde` for `serde` support of various structures of this crate and its dependencies.
39//!   * `rkyv` for `rkyv` support of various structures of this crate and its dependencies.
40//!   * `cc` for testing the behaviorally identical C implementation of the exponential map.
41//!
42//! # Example
43//!
44//! A trackball camera mode implementation can be as easy as this by delegating events of your 3D
45//! graphics library of choice to the [`Orbit`] operation handler along with other handlers.
46//!
47//! ```
48//! use trackball::{
49//! 	nalgebra::{Point2, Vector3},
50//! 	Frame, Image, Orbit,
51//! };
52//!
53//! /// Trackball camera mode.
54//! pub struct Trackball {
55//! 	// Frame wrt camera eye and target.
56//! 	frame: Frame<f32>,
57//! 	// Image as projection of `Scope` wrt `Frame`.
58//! 	image: Image<f32>,
59//! 	// Orbit induced by displacement on screen.
60//! 	orbit: Orbit<f32>,
61//! }
62//!
63//! impl Trackball {
64//! 	// Usually, a cursor position event with left mouse button being pressed.
65//! 	fn handle_left_button_displacement(&mut self, pos: &Point2<f32>) {
66//! 		// Maximum position as screen's width and height.
67//! 		let max = self.image.max();
68//! 		// Induced rotation in camera space.
69//! 		let rot = self.orbit.compute(&pos, max).unwrap_or_default();
70//! 		// Apply induced rotation to local observer frame.
71//! 		self.frame.local_orbit(&rot);
72//! 	}
73//! 	// Event when left mouse button is released again.
74//! 	fn handle_left_button_release(&mut self) {
75//! 		// Can also or instead be invoked on `Self::handle_left_button_press()`.
76//! 		self.orbit.discard();
77//! 	}
78//! }
79//! ```
80
81#![cfg_attr(any(feature = "rkyv", feature = "cc"), deny(unsafe_code))]
82#![cfg_attr(not(any(feature = "rkyv", feature = "cc")), forbid(unsafe_code))]
83#![no_std]
84
85pub use approx;
86pub use nalgebra;
87
88mod bound;
89mod clamp;
90mod delta;
91mod first;
92mod fixed;
93mod frame;
94mod image;
95mod orbit;
96mod plane;
97mod scale;
98mod scope;
99mod slide;
100mod touch;
101
102pub use bound::*;
103pub use clamp::*;
104pub use delta::*;
105pub use first::*;
106pub use fixed::*;
107pub use frame::*;
108pub use image::*;
109pub use orbit::*;
110pub use plane::*;
111pub use scale::*;
112pub use scope::*;
113pub use slide::*;
114pub use touch::*;