diff --git a/src/bevel_gear.rs b/src/bevel_gear.rs index cb5fefe..c8173f8 100644 --- a/src/bevel_gear.rs +++ b/src/bevel_gear.rs @@ -1,6 +1,6 @@ -use std::f32::consts::{FRAC_PI_2, PI}; +use std::f32::consts::PI; -use glam::{Affine3A, FloatExt, Quat, Vec2, Vec3, Vec3Swizzles, vec3}; +use glam::{Affine3A, Vec2, Vec3, Vec3Swizzles, vec3}; use crate::{crown_gear::CrownGearDesc, profile::Profile, render::mesh::MeshIndexed}; @@ -55,34 +55,29 @@ impl BevelGearShape { .map(move |(k, r)| Vec2::from_angle(k as f32 * angle) * r) } - pub fn cut(&mut self, offset_teeth: f32) { + pub fn cut(&mut self, cutter_tfm: Affine3A) { let cutter = self.desc.cutter(); - let crown_skip_teeth = cutter.pitch_radius.floor(); - let crown_turns = (offset_teeth.fract_gl() + crown_skip_teeth) / (2. * cutter.pitch_radius); - let cutter_tfm = Affine3A::from_rotation_translation( - Quat::from_rotation_y(FRAC_PI_2 + self.desc.cone_halfangle) - * Quat::from_rotation_z(2. * PI * crown_turns), - vec3(0., 0., self.desc.pitch_distance()), - ); let z_proj = self.desc.pitch_distance(); - let cutting_line = cutter.to_shape(0.375..0.725, 200); + let cutting_line = cutter.to_shape(0.375..0.625, 200); let cutting_line: Vec<_> = cutting_line .into_iter() .map(|pt| { let pt_3d = cutter_tfm.transform_point3(pt); - let pt_2d = -pt_3d.xy() * (z_proj / (z_proj - pt_3d.z)); + let pt_2d = pt_3d.xy() * (z_proj / (z_proj - pt_3d.z)); pt_2d }) .collect(); - let len = self.points.len(); + let angle = 2.0 * PI / self.points.len() as f32; for (k, pt) in self.points.iter_mut().enumerate() { - let dir = Vec2::from_angle( - 2.0 * PI * (k as f32 / len as f32 - offset_teeth / self.desc.teeth as f32), - ); + let dir = Vec2::from_angle(k as f32 * angle); for line in cutting_line.iter().zip(&cutting_line[1..]) { - if line.0.dot(dir.perp()) >= 0. && line.1.dot(dir.perp()) <= 0. { - *pt = pt.min(f32::min(line.0.length(), line.1.length())); + if line.0.dot(dir) <= 0. || line.1.dot(dir) <= 0. { + continue; } + if line.0.dot(dir.perp()) < 0. || line.1.dot(dir.perp()) > 0. { + continue; + } + *pt = pt.min(f32::min(line.0.length(), line.1.length())); } } } diff --git a/src/crown_gear.rs b/src/crown_gear.rs index 40d3169..0918aed 100644 --- a/src/crown_gear.rs +++ b/src/crown_gear.rs @@ -21,6 +21,10 @@ pub struct CrownGearVisual { } impl CrownGearDesc { + pub fn teeth(&self) -> f32 { + 2. * self.pitch_radius + } + pub fn to_shape(&self, part: Range, sides: usize) -> Vec { let teeth = 2.0 * self.pitch_radius; let mut ret = Vec::new(); diff --git a/src/lib.rs b/src/lib.rs index 280ee13..ef6b81f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ use std::{ f32::consts::{FRAC_PI_2, PI}, }; -use glam::{FloatExt, Mat4, Quat, UVec2, Vec3, Vec4, vec3, vec4}; +use glam::{Affine3A, FloatExt, Mat4, Quat, UVec2, Vec3, Vec4, vec3, vec4}; use crate::render::mesh::GpuParams; @@ -156,6 +156,21 @@ impl Core { } } + fn gear_tfm(&self) -> Affine3A { + let turns = -self.t / self.bevel_gear_desc.teeth as f32; + Affine3A::from_rotation_translation(Quat::from_rotation_z(2. * PI * turns), Vec3::ZERO) + } + + fn cutter_tfm(&self) -> Affine3A { + let skip_teeth = self.crown_gear_desc.pitch_radius.floor(); + let turns = (self.t.fract_gl() + skip_teeth) / self.crown_gear_desc.teeth(); + Affine3A::from_rotation_translation( + Quat::from_rotation_y(FRAC_PI_2 + self.bevel_gear_desc.cone_halfangle) + * Quat::from_rotation_z(2. * PI * turns), + vec3(0., 0., self.bevel_gear_desc.pitch_distance()), + ) + } + fn render(&self, output: &wgpu::Texture, args: &RedrawArgs) { let y_frac = { let size = output.size(); @@ -184,30 +199,17 @@ impl Core { }, ); - let turn_teeth = self.t; - let bevel_turns = 0.5 - turn_teeth / self.bevel_gear_desc.teeth as f32; - let crown_skip_teeth = self.crown_gear_desc.pitch_radius.floor(); - let crown_turns = - (turn_teeth.fract_gl() + crown_skip_teeth) / (2. * self.crown_gear_desc.pitch_radius); - self.params_gear.set( &self.queue, render::mesh::ObjectParams { - transform: Mat4::from_rotation_translation( - Quat::from_rotation_z(2. * PI * bevel_turns), - Vec3::ZERO, - ), + transform: self.gear_tfm().into(), color: srgba_to_linear(vec4(0.2, 0.8, 0.1, 1.0)), }, ); self.params_cutter.set( &self.queue, render::mesh::ObjectParams { - transform: Mat4::from_rotation_translation( - Quat::from_rotation_y(FRAC_PI_2 + self.bevel_gear_desc.cone_halfangle) - * Quat::from_rotation_z(2. * PI * crown_turns), - vec3(0., 0., self.bevel_gear_desc.pitch_distance()), - ), + transform: self.cutter_tfm().into(), color: srgba_to_linear(vec4(0.8, 0.2, 0.1, 1.0)), }, ); @@ -302,7 +304,8 @@ impl Core { /// /// [`Self::configure`] must be called at least once before this. pub fn redraw(&mut self, args: &RedrawArgs) { - self.bevel_gear_shape.cut(self.t); + self.bevel_gear_shape + .cut(self.gear_tfm().inverse() * self.cutter_tfm()); let output = self.surface.get_current_texture().unwrap(); self.render(&output.texture, args); output.present();