add gear profile
This commit is contained in:
parent
42b37369f5
commit
bb0db54ef1
|
|
@ -3,6 +3,7 @@ use std::error::Error;
|
|||
use glam::{Mat4, UVec2, Vec3, Vec4, vec3, vec4};
|
||||
|
||||
mod camera;
|
||||
mod profile;
|
||||
mod render;
|
||||
|
||||
const BACKGROUND: Vec4 = vec4(0.00, 0.39, 0.52, 1.00);
|
||||
|
|
|
|||
98
src/profile.rs
Normal file
98
src/profile.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
use std::f32::consts::PI;
|
||||
|
||||
use glam::FloatExt;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Profile {
|
||||
pub addendum: f32,
|
||||
pub dedendum: f32,
|
||||
pub pressure_angle: f32,
|
||||
}
|
||||
|
||||
impl Default for Profile {
|
||||
fn default() -> Self {
|
||||
Profile {
|
||||
addendum: 1.0,
|
||||
dedendum: 1.25,
|
||||
pressure_angle: const { 20.0f32.to_radians() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Profile {
|
||||
pub(crate) const PITCH: f32 = PI;
|
||||
|
||||
pub fn y_from_x(&self, x: f32) -> f32 {
|
||||
self.y_from_tooth(x / Self::PITCH)
|
||||
}
|
||||
|
||||
pub fn y_from_tooth(&self, t: f32) -> f32 {
|
||||
debug_assert!(self.addendum > 0.0);
|
||||
debug_assert!(self.dedendum > 0.0);
|
||||
debug_assert!(self.pressure_angle > 0.0);
|
||||
let t = t.fract_gl();
|
||||
let slope = PI * self.slope();
|
||||
let a = self.addendum / slope;
|
||||
let d = self.dedendum / slope;
|
||||
debug_assert!(2.0 * a + 2.0 * d < 1.0, "pressure angle is too high");
|
||||
if t < a {
|
||||
slope * t
|
||||
} else if t < 0.5 - a {
|
||||
self.addendum
|
||||
} else if t < 0.5 + d {
|
||||
-(t - 0.5) * slope
|
||||
} else if t < 1.0 - d {
|
||||
-self.dedendum
|
||||
} else {
|
||||
(t - 1.0) * slope
|
||||
}
|
||||
}
|
||||
|
||||
pub fn slope(&self) -> f32 {
|
||||
1.0 / self.pressure_angle.tan()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_profile() {
|
||||
let profile = Profile::default();
|
||||
let eps = 0.01;
|
||||
for (t, y) in [
|
||||
(0.0, 0.0),
|
||||
(0.25, profile.addendum),
|
||||
(0.5, 0.0),
|
||||
(0.75, -profile.dedendum),
|
||||
(1.0, 0.0),
|
||||
(1.25, profile.addendum),
|
||||
] {
|
||||
let x = Profile::PITCH * t;
|
||||
let comp_y = profile.y_from_x(x);
|
||||
assert!(
|
||||
(comp_y - y).abs() < eps,
|
||||
"At t={t} (x={x}), expected y={y}, got y={comp_y}"
|
||||
);
|
||||
}
|
||||
for (t, slope) in [
|
||||
(0.0, 1.0),
|
||||
(eps, 1.0),
|
||||
(0.25, 0.0),
|
||||
(0.5, -1.0),
|
||||
(0.75, 0.0),
|
||||
(1.0 - eps, 1.0),
|
||||
(1.0, 1.0),
|
||||
(1.0 + eps, 1.0),
|
||||
] {
|
||||
let x = Profile::PITCH * t;
|
||||
let comp_slope = (profile.y_from_x(x + eps) - profile.y_from_x(x - eps)) / (2.0 * eps);
|
||||
let exp_slope = profile.slope() * slope;
|
||||
assert!(
|
||||
(comp_slope - exp_slope).abs() < eps,
|
||||
"At t={t} (x={x}), expected slope={exp_slope}, got slope={comp_slope}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user