rs_math3d/basis.rs
1// Copyright 2020-Present (c) Raja Lehtihet & Wael El Oraiby
2//
3// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are met:
5//
6// 1. Redistributions of source code must retain the above copyright notice,
7// this list of conditions and the following disclaimer.
8//
9// 2. Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12//
13// 3. Neither the name of the copyright holder nor the names of its contributors
14// may be used to endorse or promote products derived from this software without
15// specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27// POSSIBILITY OF SUCH DAMAGE.
28//! Coordinate basis and reference frame utilities.
29//!
30//! This module provides types and functions for working with coordinate systems
31//! and reference frames in 3D space. A basis represents a local coordinate system
32//! with its own origin and axis orientations.
33//!
34//! # Examples
35//!
36//! ```
37//! use rs_math3d::basis::{Basis, BasisPlane};
38//! use rs_math3d::vector::Vector3;
39//!
40//! // Create a basis at origin with default axes
41//! let basis = Basis::<f32>::default();
42//!
43//! // Create a basis with custom center
44//! let center = Vector3::new(10.0, 5.0, 0.0);
45//! let basis = Basis::default_with_center(¢er);
46//! ```
47
48use crate::matrix::*;
49use crate::scalar::*;
50use crate::vector::*;
51use num_traits::{Zero, One};
52
53/// Represents one of the three coordinate planes.
54#[derive(Debug, Clone, Copy)]
55pub enum BasisPlane {
56 YZ,
57 ZX,
58 XY,
59}
60
61impl BasisPlane {
62 /// Converts the plane to a numeric ID (0=YZ, 1=ZX, 2=XY).
63 pub fn to_id(&self) -> usize {
64 match self {
65 BasisPlane::YZ => 0,
66 BasisPlane::ZX => 1,
67 BasisPlane::XY => 2,
68 }
69 }
70
71 /// Creates a plane from a numeric ID.
72 ///
73 /// # Panics
74 /// Panics if id is not 0, 1, or 2.
75 pub fn of_id(id: usize) -> Self {
76 match id {
77 0 => BasisPlane::YZ,
78 1 => BasisPlane::ZX,
79 2 => BasisPlane::XY,
80 _ => panic!("invalid id"),
81 }
82 }
83}
84
85/// A 3D coordinate basis (reference frame).
86///
87/// Represents a local coordinate system with three orthogonal axes
88/// and an origin point. This is useful for transformations between
89/// different coordinate spaces.
90#[derive(Debug, Clone, Copy)]
91#[repr(C)]
92pub struct Basis<T: Scalar> {
93 pub x_axis: Vector3<T>,
94 pub y_axis: Vector3<T>,
95 pub z_axis: Vector3<T>,
96 pub center: Vector3<T>,
97}
98
99impl<T: Scalar> Basis<T> {
100 /// Returns the center (origin) of the basis.
101 pub fn center(&self) -> &Vector3<T> {
102 &self.center
103 }
104
105 /// Returns a mutable reference to the center.
106 pub fn center_mut(&mut self) -> &mut Vector3<T> {
107 &mut self.center
108 }
109
110 /// Converts the basis to a 4x4 transformation matrix.
111 ///
112 /// The resulting matrix transforms from local basis space to world space:
113 /// - Columns 0-2: The basis axes (rotation/scale)
114 /// - Column 3: The center point (translation)
115 pub fn to_mat4(&self) -> Matrix4<T> {
116 Matrix4::new(
117 self.x_axis.x,
118 self.x_axis.y,
119 self.x_axis.z,
120 <T as Zero>::zero(),
121 self.y_axis.x,
122 self.y_axis.y,
123 self.y_axis.z,
124 <T as Zero>::zero(),
125 self.z_axis.x,
126 self.z_axis.y,
127 self.z_axis.z,
128 <T as Zero>::zero(),
129 self.center.x,
130 self.center.y,
131 self.center.z,
132 <T as One>::one(),
133 )
134 }
135
136 /// Creates a basis from a 4x4 transformation matrix.
137 ///
138 /// Extracts the axes from columns 0-2 and center from column 3.
139 pub fn of_mat4(mat: &Matrix4<T>) -> Self {
140 let col0 = mat.col[0];
141 let col1 = mat.col[1];
142 let col2 = mat.col[2];
143 let col3 = mat.col[3];
144 Self {
145 center: col3.xyz(),
146 x_axis: col0.xyz(),
147 y_axis: col1.xyz(),
148 z_axis: col2.xyz(),
149 }
150 }
151
152 pub fn default() -> Self {
153 Self {
154 center: Vector3::new(<T as Zero>::zero(), <T as Zero>::zero(), <T as Zero>::zero()),
155 x_axis: Vector3::new(<T as One>::one(), <T as Zero>::zero(), <T as Zero>::zero()),
156 y_axis: Vector3::new(<T as Zero>::zero(), <T as One>::one(), <T as Zero>::zero()),
157 z_axis: Vector3::new(<T as Zero>::zero(), <T as Zero>::zero(), <T as One>::one()),
158 }
159 }
160
161 pub fn default_with_center(center: &Vector3<T>) -> Self {
162 Self {
163 center: *center,
164 x_axis: Vector3::new(<T as One>::one(), <T as Zero>::zero(), <T as Zero>::zero()),
165 y_axis: Vector3::new(<T as Zero>::zero(), <T as One>::one(), <T as Zero>::zero()),
166 z_axis: Vector3::new(<T as Zero>::zero(), <T as Zero>::zero(), <T as One>::one()),
167 }
168 }
169
170 pub fn plane_axis(&self, plane: BasisPlane) -> (&Vector3<T>, &Vector3<T>) {
171 match plane {
172 BasisPlane::YZ => (&self.y_axis, &self.z_axis),
173 BasisPlane::ZX => (&self.z_axis, &self.x_axis),
174 BasisPlane::XY => (&self.x_axis, &self.y_axis),
175 }
176 }
177
178 pub fn plane_axis_mut(&mut self, plane: BasisPlane) -> (&mut Vector3<T>, &mut Vector3<T>) {
179 match plane {
180 BasisPlane::YZ => (&mut self.y_axis, &mut self.z_axis),
181 BasisPlane::ZX => (&mut self.z_axis, &mut self.x_axis),
182 BasisPlane::XY => (&mut self.x_axis, &mut self.y_axis),
183 }
184 }
185
186 /// Converts the basis axes to a 3x3 rotation matrix.
187 ///
188 /// The matrix contains only the rotation part, without translation.
189 pub fn to_mat3(&self) -> Matrix3<T> {
190 Matrix3::new(
191 self.x_axis.x,
192 self.x_axis.y,
193 self.x_axis.z,
194 self.y_axis.x,
195 self.y_axis.y,
196 self.y_axis.z,
197 self.z_axis.x,
198 self.z_axis.y,
199 self.z_axis.z,
200 )
201 }
202
203 /// Creates a basis from a center point and a 3x3 rotation matrix.
204 ///
205 /// The matrix columns become the basis axes.
206 pub fn of_center_mat3(center: &Vector3<T>, m: Matrix3<T>) -> Self {
207 Self {
208 center: *center,
209 x_axis: m.col[0],
210 y_axis: m.col[1],
211 z_axis: m.col[2],
212 }
213 }
214}