diff --git a/src/bevel_gear.rs b/src/bevel_gear.rs index f3a8d53..cb5fefe 100644 --- a/src/bevel_gear.rs +++ b/src/bevel_gear.rs @@ -1,8 +1,8 @@ -use std::f32::consts::PI; +use std::f32::consts::{FRAC_PI_2, PI}; -use glam::{Mat3A, Vec2, Vec3, vec3}; +use glam::{Affine3A, FloatExt, Quat, Vec2, Vec3, Vec3Swizzles, vec3}; -use crate::{profile::Profile, render::mesh::MeshIndexed}; +use crate::{crown_gear::CrownGearDesc, profile::Profile, render::mesh::MeshIndexed}; #[derive(Debug, Clone, Copy)] pub struct BevelGearDesc { @@ -12,8 +12,8 @@ pub struct BevelGearDesc { } impl BevelGearDesc { - pub fn cutter(&self) -> crate::crown_gear::CrownGearDesc { - crate::crown_gear::CrownGearDesc { + pub fn cutter(&self) -> CrownGearDesc { + CrownGearDesc { profile: Profile { addendum: self.profile.dedendum, dedendum: self.profile.addendum, @@ -34,19 +34,17 @@ impl BevelGearDesc { #[derive(Debug, Clone)] pub struct BevelGearShape { + desc: BevelGearDesc, points: Vec, } impl BevelGearShape { - fn new_raw(r: f32, n_points: usize) -> Self { - BevelGearShape { - points: vec![r; n_points], - } - } - pub fn new_blank(desc: &BevelGearDesc, n_points: usize) -> Self { let r = 0.5 * desc.teeth as f32 + desc.profile.addendum + 0.1; - Self::new_raw(r, n_points) + BevelGearShape { + desc: *desc, + points: vec![r; n_points], + } } pub fn to_points(&self) -> impl Iterator { @@ -56,6 +54,38 @@ impl BevelGearShape { .enumerate() .map(move |(k, r)| Vec2::from_angle(k as f32 * angle) * r) } + + pub fn cut(&mut self, offset_teeth: f32) { + 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: 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)); + pt_2d + }) + .collect(); + let len = self.points.len(); + 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), + ); + 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())); + } + } + } + } } #[derive(Debug, Clone, Copy)] diff --git a/src/lib.rs b/src/lib.rs index f443750..280ee13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,6 @@ pub struct Core { mesh_pipeline: render::mesh::Pipeline, - mesh_gear: render::mesh::GpuMeshIndexed, mesh_cutter: render::mesh::GpuMeshIndexed, params_gear: render::mesh::GpuParams, @@ -118,18 +117,7 @@ impl Core { teeth: args.tooth, cone_halfangle: args.cone_halfangle, }; - let bevel_gear_shape = bevel_gear::BevelGearShape::new_blank(&bevel_gear_desc, 60); - let bevel_gear_mesh = bevel_gear::make_mesh( - &bevel_gear_desc, - &bevel_gear::BevelGearVisual { - pad_in: 4., - pad_out: 0., - }, - &bevel_gear_shape, - ) - .to_mesh() - .to_standard_mesh() - .into_indexed(); + let bevel_gear_shape = bevel_gear::BevelGearShape::new_blank(&bevel_gear_desc, 600); let crown_gear_desc = bevel_gear_desc.cutter(); let crown_gear_mesh = crown_gear::make_mesh_simple( @@ -146,7 +134,6 @@ impl Core { .into_indexed(); let mesh_cutter = render::mesh::GpuMeshIndexed::new(&device, &crown_gear_mesh); - let mesh_gear = render::mesh::GpuMeshIndexed::new(&device, &bevel_gear_mesh); let params_gear = GpuParams::new(&device, &mesh_pipeline); let params_cutter = GpuParams::new(&device, &mesh_pipeline); @@ -159,7 +146,6 @@ impl Core { surface, depth, mesh_pipeline, - mesh_gear, mesh_cutter, params_gear, params_cutter, @@ -199,7 +185,7 @@ impl Core { ); let turn_teeth = self.t; - let bevel_turns = -turn_teeth / self.bevel_gear_desc.teeth as f32; + 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); @@ -226,6 +212,19 @@ impl Core { }, ); + let bevel_gear_mesh = bevel_gear::make_mesh( + &self.bevel_gear_desc, + &bevel_gear::BevelGearVisual { + pad_in: 4., + pad_out: 0., + }, + &self.bevel_gear_shape, + ) + .to_mesh() + .to_standard_mesh() + .into_indexed(); + let mesh_gear = render::mesh::GpuMeshIndexed::new(&self.device, &bevel_gear_mesh); + let view = output.create_view(&wgpu::TextureViewDescriptor::default()); let depth_view = self .depth @@ -255,8 +254,7 @@ impl Core { }); self.mesh_cutter .render(&mut pass, &self.mesh_pipeline, &self.params_cutter); - self.mesh_gear - .render(&mut pass, &self.mesh_pipeline, &self.params_gear); + mesh_gear.render(&mut pass, &self.mesh_pipeline, &self.params_gear); drop(pass); self.queue.submit(std::iter::once(encoder.finish())); } @@ -304,6 +302,7 @@ 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); let output = self.surface.get_current_texture().unwrap(); self.render(&output.texture, args); output.present();