rs_math3d/scalar.rs
1//! Scalar trait definitions for generic numeric operations.
2//!
3//! This module defines traits that extend `num-traits` for use in
4//! mathematical operations throughout the library. It provides a
5//! unified interface for both integer and floating-point types.
6//!
7//! The module leverages the `num-traits` crate for basic numeric
8//! operations while adding specialized methods needed for 3D math.
9
10// Copyright 2020-Present (c) Raja Lehtihet & Wael El Oraiby
11//
12// Redistribution and use in source and binary forms, with or without
13// modification, are permitted provided that the following conditions are met:
14//
15// 1. Redistributions of source code must retain the above copyright notice,
16// this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright notice,
19// this list of conditions and the following disclaimer in the documentation
20// and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the copyright holder nor the names of its contributors
23// may be used to endorse or promote products derived from this software without
24// specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
30// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36// POSSIBILITY OF SUCH DAMAGE.
37
38use num_traits::{Num, NumAssignOps};
39use core::cmp::PartialOrd;
40use core::ops::Neg;
41
42// Re-export for convenience
43pub use num_traits::{Zero, One};
44
45/// Core scalar trait for numeric types used in the library.
46///
47/// This trait extends `num-traits` types with additional methods
48/// commonly needed in 3D mathematics. It is implemented for
49/// `i32`, `i64`, `f32`, and `f64`.
50///
51/// # Required Methods
52///
53/// Types implementing this trait must provide:
54/// - Basic arithmetic operations (via `Num` and `NumAssignOps`)
55/// - Comparison operations (via `PartialOrd`)
56/// - Additional constants and utility methods
57pub trait Scalar:
58 Num
59 + NumAssignOps
60 + Neg<Output = Self>
61 + PartialOrd
62 + Clone
63 + Copy
64 + Sized
65{
66 // Additional methods not provided by num-traits
67 fn two() -> Self;
68 fn half() -> Self;
69 fn quarter() -> Self;
70 fn l8192() -> Self;
71 fn epsilon() -> Self;
72 fn min(l: Self, r: Self) -> Self;
73 fn max(l: Self, r: Self) -> Self;
74 fn squared(self) -> Self {
75 self * self
76 }
77 fn tabs(self) -> Self;
78}
79
80/// Trait for floating-point scalars with transcendental functions.
81///
82/// Extends the base `Scalar` trait with operations specific to
83/// floating-point numbers, including trigonometric functions and
84/// square root.
85///
86/// # Implementation Note
87///
88/// These functions link to external C math libraries (libm on Unix,
89/// MSVCRT on Windows) since they're not available in no_std Rust.
90pub trait FloatScalar: Scalar {
91 fn infinity() -> Self;
92 fn tsqrt(self) -> Self;
93 fn tsin(self) -> Self;
94 fn tcos(self) -> Self;
95 fn ttan(self) -> Self;
96 fn tacos(self) -> Self;
97}
98
99// Implementation for i32
100impl Scalar for i32 {
101 fn two() -> Self { 2 }
102 fn half() -> Self { 0 } // Integer division
103 fn quarter() -> Self { 0 } // Integer division
104 fn l8192() -> Self { 8192 }
105 fn epsilon() -> Self { 0 }
106 fn min(l: Self, r: Self) -> Self {
107 if l < r { l } else { r }
108 }
109 fn max(l: Self, r: Self) -> Self {
110 if l > r { l } else { r }
111 }
112 fn tabs(self) -> Self {
113 self.abs()
114 }
115}
116
117// Implementation for i64
118impl Scalar for i64 {
119 fn two() -> Self { 2 }
120 fn half() -> Self { 0 } // Integer division
121 fn quarter() -> Self { 0 } // Integer division
122 fn l8192() -> Self { 8192 }
123 fn epsilon() -> Self { 0 }
124 fn min(l: Self, r: Self) -> Self {
125 if l < r { l } else { r }
126 }
127 fn max(l: Self, r: Self) -> Self {
128 if l > r { l } else { r }
129 }
130 fn tabs(self) -> Self {
131 self.abs()
132 }
133}
134
135// Implementation for f32
136impl Scalar for f32 {
137 fn two() -> Self { 2.0 }
138 fn half() -> Self { 0.5 }
139 fn quarter() -> Self { 0.25 }
140 fn l8192() -> Self { 8192.0 }
141 fn epsilon() -> Self {
142 1.0 / (1024.0 * 1024.0)
143 }
144 fn min(l: Self, r: Self) -> Self {
145 if l < r { l } else { r }
146 }
147 fn max(l: Self, r: Self) -> Self {
148 if l > r { l } else { r }
149 }
150 fn tabs(self) -> Self {
151 self.abs()
152 }
153}
154
155// Implementation for f64
156impl Scalar for f64 {
157 fn two() -> Self { 2.0 }
158 fn half() -> Self { 0.5 }
159 fn quarter() -> Self { 0.25 }
160 fn l8192() -> Self { 8192.0 }
161 fn epsilon() -> Self {
162 1.0 / (1024.0 * 1024.0 * 1024.0 * 1024.0)
163 }
164 fn min(l: Self, r: Self) -> Self {
165 if l < r { l } else { r }
166 }
167 fn max(l: Self, r: Self) -> Self {
168 if l > r { l } else { r }
169 }
170 fn tabs(self) -> Self {
171 self.abs()
172 }
173}
174
175// FloatScalar implementation for f32
176// Note: Without std or libm, we need to provide our own implementations
177// or link to external math libraries
178impl FloatScalar for f32 {
179 fn infinity() -> Self {
180 core::f32::INFINITY
181 }
182 fn tsqrt(self) -> Self {
183 // Use external C math function
184 extern "C" {
185 fn sqrtf(x: f32) -> f32;
186 }
187 unsafe { sqrtf(self) }
188 }
189 fn tsin(self) -> Self {
190 extern "C" {
191 fn sinf(x: f32) -> f32;
192 }
193 unsafe { sinf(self) }
194 }
195 fn tcos(self) -> Self {
196 extern "C" {
197 fn cosf(x: f32) -> f32;
198 }
199 unsafe { cosf(self) }
200 }
201 fn ttan(self) -> Self {
202 extern "C" {
203 fn tanf(x: f32) -> f32;
204 }
205 unsafe { tanf(self) }
206 }
207 fn tacos(self) -> Self {
208 extern "C" {
209 fn acosf(x: f32) -> f32;
210 }
211 unsafe { acosf(self) }
212 }
213}
214
215// FloatScalar implementation for f64
216// Note: Without std or libm, we need to provide our own implementations
217// or link to external math libraries
218impl FloatScalar for f64 {
219 fn infinity() -> Self {
220 core::f64::INFINITY
221 }
222 fn tsqrt(self) -> Self {
223 extern "C" {
224 fn sqrt(x: f64) -> f64;
225 }
226 unsafe { sqrt(self) }
227 }
228 fn tsin(self) -> Self {
229 extern "C" {
230 fn sin(x: f64) -> f64;
231 }
232 unsafe { sin(self) }
233 }
234 fn tcos(self) -> Self {
235 extern "C" {
236 fn cos(x: f64) -> f64;
237 }
238 unsafe { cos(self) }
239 }
240 fn ttan(self) -> Self {
241 extern "C" {
242 fn tan(x: f64) -> f64;
243 }
244 unsafe { tan(self) }
245 }
246 fn tacos(self) -> Self {
247 extern "C" {
248 fn acos(x: f64) -> f64;
249 }
250 unsafe { acos(self) }
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257 #[test]
258 pub fn test() {
259 let out = -1.0;
260 let f = out.tabs();
261 assert_eq!(f, 1.0);
262 }
263}