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};
|
use glam::{Mat4, UVec2, Vec3, Vec4, vec3, vec4};
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
|
mod profile;
|
||||||
mod render;
|
mod render;
|
||||||
|
|
||||||
const BACKGROUND: Vec4 = vec4(0.00, 0.39, 0.52, 1.00);
|
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