Skip to content

Commit b3c8ff0

Browse files
committed
get more of traits.rs wired up to mixed-num
1 parent 6d2b8e2 commit b3c8ff0

File tree

4 files changed

+45
-37
lines changed

4 files changed

+45
-37
lines changed

src/errors.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
type Real = f64;
21
use crate::math_ndsp::Point3;
32

43
/// All the possible validation issues we might encounter,

src/math_ndsp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl<T> Scalar for T where
4747
}
4848

4949
// Integer power (avoid `.powi()` calls)
50-
#[inline] pub fn powi<T: Scalar>(mut x: T, mut e: i32) -> T {
50+
#[inline] pub fn powi<T: Scalar>(x: T, mut e: i32) -> T {
5151
if e == 0 { return one() }
5252
let mut base = x;
5353
let mut acc = one();

src/tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::errors::ValidationError;
2-
use crate::math_ndsp::consts::{FRAC_PI_2, PI};
2+
use crate::math_ndsp::consts::{FRAC_PI_2};
33
use crate::mesh::Mesh;
44
use crate::mesh::bsp::Node;
55
use crate::mesh::plane::Plane;
@@ -2159,7 +2159,7 @@ fn test_mesh_quality_analysis() {
21592159
);
21602160
assert!(quality.area > 0.0, "Triangle area should be positive");
21612161
assert!(quality.min_angle > 0.0, "Minimum angle should be positive");
2162-
assert!(quality.max_angle < PI, "Maximum angle should be less than π");
2162+
assert!(quality.max_angle < T::mixed_pi(), "Maximum angle should be less than π");
21632163
}
21642164

21652165
// Compute overall mesh quality metrics
@@ -2296,7 +2296,7 @@ fn test_vertex_distance_operations() {
22962296
// Test normal angle
22972297
let angle = v1.normal_angle_to(&v2);
22982298
assert!(
2299-
(angle - PI / 2.0).abs() < 1e-10,
2299+
(angle - T::mixed_pi() / 2.0).abs() < 1e-10,
23002300
"Angle between x and y normals should be π/2"
23012301
);
23022302
}

src/traits.rs

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,41 @@
11
use crate::aabb::Aabb;
22
use crate::mesh::plane::Plane;
3+
use mixed_num::{MixedAbs, MixedPi, MixedZero};
34
use crate::math_ndsp::{Matrix3, Matrix4, Rotation3, Translation3, Vector3, Scalar, eps};
45

56
/// Boolean operations + transformations
67
pub trait CSG: Sized + Clone {
8+
type Scalar: Scalar;
9+
710
fn new() -> Self;
811
fn union(&self, other: &Self) -> Self;
912
fn difference(&self, other: &Self) -> Self;
1013
fn intersection(&self, other: &Self) -> Self;
1114
fn xor(&self, other: &Self) -> Self;
12-
fn transform(&self, matrix: &Matrix4<Real>) -> Self;
15+
fn transform(&self, matrix: &Matrix4<Self::Scalar>) -> Self;
1316
fn inverse(&self) -> Self;
14-
fn bounding_box(&self) -> Aabb<T>;
17+
fn bounding_box(&self) -> Aabb<Self::Scalar>;
1518
fn invalidate_bounding_box(&mut self);
1619

1720
/// Returns a new Self translated by vector.
18-
fn translate_vector(&self, vector: Vector3<Real>) -> Self {
21+
fn translate_vector(&self, vector: Vector3<Self::Scalar>) -> Self {
1922
self.transform(&Translation3::from(vector).to_homogeneous())
2023
}
2124

2225
/// Returns a new Self translated by x, y, and z.
23-
fn translate(&self, x: Real, y: Real, z: Real) -> Self {
26+
fn translate(&self, x: Self::Scalar, y: Self::Scalar, z: Self::Scalar) -> Self {
2427
self.translate_vector(Vector3::new(x, y, z))
2528
}
2629

2730
/// Returns a new Self translated so that its bounding-box center is at the origin (0,0,0).
2831
fn center(&self) -> Self {
2932
let aabb = self.bounding_box();
33+
let c2 = self::Scalar::mixed_from(0.5);
3034

3135
// Compute the AABB center
32-
let center_x = (aabb.mins.x + aabb.maxs.x) * 0.5;
33-
let center_y = (aabb.mins.y + aabb.maxs.y) * 0.5;
34-
let center_z = (aabb.mins.z + aabb.maxs.z) * 0.5;
36+
let center_x = (aabb.mins.x + aabb.maxs.x) * c2;
37+
let center_y = (aabb.mins.y + aabb.maxs.y) * c2;
38+
let center_z = (aabb.mins.z + aabb.maxs.z) * c2;
3539

3640
// Translate so that the bounding-box center goes to the origin
3741
self.translate(-center_x, -center_y, -center_z)
@@ -52,22 +56,23 @@ pub trait CSG: Sized + Clone {
5256
fn float(&self) -> Self {
5357
let aabb = self.bounding_box();
5458
let min_z = aabb.mins.z;
55-
self.translate(0.0, 0.0, -min_z)
59+
self.translate(Self::Scalar::mixed_zero(), Self::Scalar::mixed_zero(), -min_z)
5660
}
5761

5862
/// Rotates Self by x_degrees, y_degrees, z_degrees
59-
fn rotate(&self, x_deg: Real, y_deg: Real, z_deg: Real) -> Self {
60-
let rx = Rotation3::from_axis_angle(&Vector3::x_axis(), x_deg.to_radians());
61-
let ry = Rotation3::from_axis_angle(&Vector3::y_axis(), y_deg.to_radians());
62-
let rz = Rotation3::from_axis_angle(&Vector3::z_axis(), z_deg.to_radians());
63+
fn rotate(&self, x_deg: Self::Scalar, y_deg: Self::Scalar, z_deg: Self::Scalar) -> Self {
64+
let deg2rad = Self::Scalar::mixed_pi() / Self::Scalar::mixed_from(180.0);
65+
let rx = Rotation3::from_axis_angle(&Vector3::x_axis(), x_deg * deg2rad);
66+
let ry = Rotation3::from_axis_angle(&Vector3::y_axis(), y_deg * deg2rad);
67+
let rz = Rotation3::from_axis_angle(&Vector3::z_axis(), z_deg * deg2rad);
6368

6469
// Compose them in the desired order
6570
let rot = rz * ry * rx;
6671
self.transform(&rot.to_homogeneous())
6772
}
6873

6974
/// Scales Self by scale_x, scale_y, scale_z
70-
fn scale(&self, sx: Real, sy: Real, sz: Real) -> Self {
75+
fn scale(&self, sx: Self::Scalar, sy: Self::Scalar, sz: Self::Scalar) -> Self {
7176
let mat4 = Matrix4::scaling(sx, sy, sz);
7277
self.transform(&mat4)
7378
}
@@ -116,10 +121,10 @@ pub trait CSG: Sized + Clone {
116121
/// the orientation of polygons, affecting inside/outside semantics in CSG.
117122
///
118123
/// Returns a new Self whose geometry is mirrored accordingly.
119-
fn mirror(&self, plane: Plane<T>) -> Self {
124+
fn mirror(&self, plane: Plane<Self::Scalar>) -> Self {
120125
// Normal might not be unit, so compute its length:
121126
let len = plane.normal().norm();
122-
if len.abs() < eps::<T>() {
127+
if len.mixed_abs() <= eps::<Self::Scalar>() {
123128
// Degenerate plane? Just return clone (no transform)
124129
return self.clone();
125130
}
@@ -139,7 +144,7 @@ pub trait CSG: Sized + Clone {
139144
//let mut reflect_4 = Matrix4::identity();
140145
//let reflect_3 = Matrix3::identity() - 2.0 * n * n.transpose();
141146
let reflect_3 = Matrix3::reflection_about_unit_normal(n);
142-
let r4 = Matrix4::from_matrix3_and_translation(reflect_3, Vector3::zeros());
147+
let r4 = Matrix4::from_matrix3_and_translation(reflect_3, Vector3::mixed_zeroes());
143148
//reflect_4.fixed_view_mut::<3, 3>(0, 0).copy_from(&reflect_3);
144149

145150
// Translate back
@@ -158,23 +163,25 @@ pub trait CSG: Sized + Clone {
158163
fn distribute_arc(
159164
&self,
160165
count: usize,
161-
radius: Real,
162-
start_angle_deg: Real,
163-
end_angle_deg: Real,
166+
radius: Self::Scalar,
167+
start_angle_deg: Self::Scalar,
168+
end_angle_deg: Self::Scalar,
164169
) -> Self {
165170
if count < 1 {
166171
return self.clone();
167172
}
168-
let start_rad = start_angle_deg.to_radians();
169-
let end_rad = end_angle_deg.to_radians();
173+
let deg2rad = Self::Scalar::mixed_pi() / Self::Scalar::mixed_from(180.0);
174+
let start_rad = start_angle_deg * deg2rad;
175+
let end_rad = end_angle_deg * deg2rad;
170176
let sweep = end_rad - start_rad;
171177

172178
(0..count)
173179
.map(|i| {
174180
let t = if count == 1 {
175-
0.5
181+
Self::Scalar::mixed_from(0.5)
176182
} else {
177-
i as Real / ((count - 1) as Real)
183+
Self::Scalar::mixed_from(i)
184+
/ Self::Scalar::mixed_from((count - 1))
178185
};
179186

180187
let angle = start_rad + t * sweep;
@@ -183,7 +190,7 @@ pub trait CSG: Sized + Clone {
183190
.to_homogeneous();
184191

185192
// translate out to radius in x
186-
let trans = Translation3::new(radius, 0.0, 0.0).to_homogeneous();
193+
let trans = Translation3::new(radius, Self::Scalar::mixed_zero(), Self::Scalar::mixed_zero()).to_homogeneous();
187194
let mat = rot * trans;
188195
self.transform(&mat)
189196
})
@@ -198,8 +205,8 @@ pub trait CSG: Sized + Clone {
198205
fn distribute_linear(
199206
&self,
200207
count: usize,
201-
dir: Vector3<Real>,
202-
spacing: Real,
208+
dir: Vector3<Self::Scalar>,
209+
spacing: Self::Scalar,
203210
) -> Self {
204211
if count < 1 {
205212
return self.clone();
@@ -208,8 +215,8 @@ pub trait CSG: Sized + Clone {
208215

209216
(0..count)
210217
.map(|i| {
211-
let offset = step * (i as Real);
212-
let trans = Translation3::from(offset).to_homogeneous();
218+
let offset = Self::Scalar::mixed_from(i);
219+
let trans = Translation3::from(offset * step).to_homogeneous();
213220
self.transform(&trans)
214221
})
215222
.reduce(|acc, csg| acc.union(&csg))
@@ -218,17 +225,19 @@ pub trait CSG: Sized + Clone {
218225

219226
/// Distribute Self in a grid of `rows x cols`, with spacing dx, dy in XY plane.
220227
/// top-left or bottom-left depends on your usage of row/col iteration.
221-
fn distribute_grid(&self, rows: usize, cols: usize, dx: Real, dy: Real) -> Self {
228+
fn distribute_grid(&self, rows: usize, cols: usize, dx: Self::Scalar, dy: Self::Scalar) -> Self {
222229
if rows < 1 || cols < 1 {
223230
return self.clone();
224231
}
225-
let step_x = Vector3::new(dx, 0.0, 0.0);
226-
let step_y = Vector3::new(0.0, dy, 0.0);
232+
let step_x = Vector3::new(dx, Self::Scalar::mixed_zero(), Self::Scalar::mixed_zero());
233+
let step_y = Vector3::new(Self::Scalar::mixed_zero(), dy, Self::Scalar::mixed_zero());
227234

228235
(0..rows)
229236
.flat_map(|r| {
230237
(0..cols).map(move |c| {
231-
let offset = step_x * (c as Real) + step_y * (r as Real);
238+
let rx = Self::Scalar::mixed_from(c);
239+
let ry = Self::Scalar::mixed_from(r);
240+
let offset = step_x * rx + step_y * ry;
232241
let trans = Translation3::from(offset).to_homogeneous();
233242
self.transform(&trans)
234243
})

0 commit comments

Comments
 (0)