add a bevel gear blank

This commit is contained in:
numzero 2026-10-18 04:01:12 +03:00
parent cfbd5a41c3
commit f35ca37cae
2 changed files with 131 additions and 1 deletions

110
src/bevel_gear.rs Normal file
View File

@ -0,0 +1,110 @@
use std::f32::consts::PI;
use glam::{Mat3A, Vec2, Vec3, vec3};
use crate::{profile::Profile, render::mesh::MeshIndexed};
#[derive(Debug, Clone, Copy)]
pub struct BevelGearDesc {
pub profile: Profile,
pub teeth: u32,
pub cone_halfangle: f32,
}
impl BevelGearDesc {
pub fn cutter(&self) -> crate::crown_gear::CrownGearDesc {
crate::crown_gear::CrownGearDesc {
profile: Profile {
addendum: self.profile.dedendum,
dedendum: self.profile.addendum,
pressure_angle: self.profile.pressure_angle,
},
pitch_radius: self.pitch_radius() / self.cone_halfangle.sin(),
}
}
fn pitch_radius(&self) -> f32 {
0.5 * self.teeth as f32
}
fn pitch_distance(&self) -> f32 {
self.pitch_radius() / self.cone_halfangle.tan()
}
}
#[derive(Debug, Clone)]
pub struct BevelGearShape {
points: Vec<f32>,
}
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)
}
pub fn to_points(&self) -> impl Iterator<Item = Vec2> {
let angle = 2.0 * PI / self.points.len() as f32;
self.points
.iter()
.enumerate()
.map(move |(k, r)| Vec2::from_angle(k as f32 * angle) * r)
}
}
#[derive(Debug, Clone, Copy)]
pub enum BevelGearCap {
Flat,
Conical,
Spherical,
}
#[derive(Debug, Clone, Copy)]
pub struct BevelGearVisual {
pub inner_distance: f32,
pub outer_distance: f32,
}
pub fn make_mesh(
desc: &BevelGearDesc,
visual: &BevelGearVisual,
shape: &BevelGearShape,
) -> MeshIndexed<Vec3> {
let inner_scale = visual.inner_distance / desc.pitch_distance();
let outer_scale = visual.outer_distance / desc.pitch_distance();
let sides = shape.points.len();
let mut mesh = MeshIndexed::new();
mesh.vertices.reserve_exact(2 * sides + 2);
mesh.faces.reserve_exact(4 * sides);
for pt in shape.to_points() {
let pt = vec3(pt.x, pt.y, desc.pitch_distance());
mesh.vertices.extend([inner_scale * pt, outer_scale * pt]);
}
let caps = mesh.vertices.len();
mesh.vertices.extend([
vec3(0., 0., visual.inner_distance),
vec3(0., 0., visual.outer_distance),
]);
for k in 0..sides {
let base1 = 2 * k;
let base2 = 2 * ((k + 1) % sides);
mesh.faces.extend(
[
[base1, caps, base2],
[base1, base2, base1 + 1],
[base2 + 1, base1 + 1, base2],
[base2 + 1, caps + 1, base1 + 1],
]
.map(|face| face.map(|index| u16::try_from(index).unwrap())),
);
}
mesh
}

View File

@ -2,6 +2,7 @@ use std::error::Error;
use glam::{Mat4, UVec2, Vec3, Vec4, vec3, vec4};
mod bevel_gear;
mod camera;
mod crown_gear;
mod profile;
@ -80,6 +81,7 @@ impl Core {
let depth = Self::create_depth_buffer(&device, pixel_size);
let mesh_pipeline = render::mesh::Pipeline::new(&device);
let crown_gear_mesh = crown_gear::make_mesh_simple(
&crown_gear::CrownGearDesc {
profile: Default::default(),
@ -95,7 +97,25 @@ impl Core {
.to_mesh()
.to_standard_mesh(vec3(0.5, 0.5, 0.5))
.into_indexed();
let mesh_gray = render::mesh::GpuMeshIndexed::new(&device, &crown_gear_mesh);
let bevel_gear_desc = bevel_gear::BevelGearDesc {
profile: Default::default(),
teeth: 24,
cone_halfangle: 0.5,
};
let bevel_gear_mesh = bevel_gear::make_mesh(
&bevel_gear_desc,
&bevel_gear::BevelGearVisual {
inner_distance: 8.0,
outer_distance: 12.0,
},
&bevel_gear::BevelGearShape::new_blank(&bevel_gear_desc, 60),
)
.to_mesh()
.to_standard_mesh(vec3(0.5, 0.5, 0.5))
.into_indexed();
let mesh_gray = render::mesh::GpuMeshIndexed::new(&device, &bevel_gear_mesh);
Self::configure_surface(&surface, &device, pixel_size);