cut a bevel gear
This commit is contained in:
parent
e46b68003d
commit
5603fea44b
145
src/main.rs
145
src/main.rs
|
|
@ -4,7 +4,7 @@ use flo_draw::{
|
|||
canvas::{Color::Rgba, GraphicsContext},
|
||||
create_drawing_window_with_events, with_2d_graphics,
|
||||
};
|
||||
use glam::{FloatExt, Vec2, vec2};
|
||||
use glam::{FloatExt, Vec2, mat3, vec2, vec3};
|
||||
|
||||
const fn rad(deg: f32) -> f32 {
|
||||
deg * (PI / 180.0)
|
||||
|
|
@ -53,14 +53,32 @@ fn main() {
|
|||
let (canvas, mut events) = create_drawing_window_with_events(title);
|
||||
let mut t = 0.0;
|
||||
|
||||
let n_rack_teeth = 10;
|
||||
let n_rack_teeth = 6;
|
||||
let n_crown_teeth = 3;
|
||||
|
||||
let r_crown = 18.0;
|
||||
|
||||
let n_teeth = 36;
|
||||
let n_teeth = 24;
|
||||
let n_teeth_sample = n_teeth;
|
||||
let r_pitch = 0.5 * n_teeth as f32;
|
||||
|
||||
let n_other = 16;
|
||||
let r_other = 0.5 * n_other as f32;
|
||||
let shaft_angle = 0.5 * PI;
|
||||
|
||||
let r_crown = {
|
||||
let (s, c) = shaft_angle.sin_cos();
|
||||
let pt = vec2(r_other * s, r_pitch + r_other * c);
|
||||
let x = pt.x + pt.y * (c / s);
|
||||
let y = r_pitch;
|
||||
vec2(x, y).length()
|
||||
};
|
||||
|
||||
let crown_angle = (r_pitch / r_crown).asin();
|
||||
dbg!(r_pitch, r_crown, crown_angle * 180.0 / PI);
|
||||
let crown_rot = {
|
||||
let (s, c) = crown_angle.sin_cos();
|
||||
mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, c, s), vec3(0.0, -s, c))
|
||||
};
|
||||
|
||||
let gear_profile = Profile {
|
||||
addemdum: ADDENDUM,
|
||||
dedendum: DEDENDUM,
|
||||
|
|
@ -74,7 +92,12 @@ fn main() {
|
|||
|
||||
let n_points_per_tooth = 100;
|
||||
let n_points = n_points_per_tooth * n_teeth_sample;
|
||||
let mut shape = vec![r_pitch + ADDENDUM; n_points];
|
||||
let mut inv_shape = vec![r_pitch + ADDENDUM; n_points];
|
||||
let mut bevel_shape = vec![r_pitch + ADDENDUM; n_points];
|
||||
let show_crown_gear = false;
|
||||
let show_crown_cutter = true;
|
||||
let show_rack_gear = false;
|
||||
let show_rack_cutter = true;
|
||||
'main: loop {
|
||||
while let Poll::Ready(event) =
|
||||
events.poll_next_unpin(&mut Context::from_waker(Waker::noop()))
|
||||
|
|
@ -97,12 +120,55 @@ fn main() {
|
|||
let gear_offset = t * TPS - (n_teeth_sample as f32 + 5.0);
|
||||
let rack_offset = (t * TPS).fract_gl();
|
||||
|
||||
let rack_y_at_x = |x, profile| {
|
||||
let angle = f32::atan2(x, r_crown);
|
||||
let vx = angle * r_crown;
|
||||
rack_shape(vx - rack_offset * PI, profile)
|
||||
let make_crown = |profile| {
|
||||
let mut crown_project = Vec::new();
|
||||
for tooth in -n_crown_teeth..=n_crown_teeth {
|
||||
for k in 0..n_points_per_tooth {
|
||||
let tooth_frac = k as f32 / n_points_per_tooth as f32;
|
||||
let normal_height_at_r =
|
||||
rack_shape((tooth_frac - rack_offset) * PI, profile);
|
||||
let angle = PI * (tooth as f32 + tooth_frac) / r_crown;
|
||||
let (s, c) = angle.sin_cos();
|
||||
let pos_rel_to_crown =
|
||||
vec3(r_crown * s, normal_height_at_r, r_crown * c);
|
||||
let pos_rel_to_crown_center = crown_rot * pos_rel_to_crown;
|
||||
let pos_rel_to_center = r_crown
|
||||
* crown_angle.cos() * vec2(
|
||||
pos_rel_to_crown_center.x,
|
||||
pos_rel_to_crown_center.y,
|
||||
) / pos_rel_to_crown_center.z;
|
||||
let pos = vec2(pos_rel_to_center.x, pos_rel_to_center.y + r_pitch);
|
||||
crown_project.push(pos);
|
||||
}
|
||||
}
|
||||
crown_project
|
||||
};
|
||||
let crown_gear = make_crown(&gear_profile);
|
||||
let crown_cutter = make_crown(&cutter_profile);
|
||||
|
||||
let rack_y_at_x = |x, profile| rack_shape(x - rack_offset * PI, profile);
|
||||
let inv_cutter_y_at_x = |x| rack_y_at_x(x, &cutter_profile);
|
||||
let bevel_cutter_y_at_x = |x| {
|
||||
if x < crown_cutter.first().unwrap().x || x > crown_cutter.last().unwrap().x {
|
||||
return -cutter_profile.dedendum;
|
||||
}
|
||||
let mut i1 = 0;
|
||||
let mut i2 = crown_cutter.len() - 1;
|
||||
while i2 - i1 > 1 {
|
||||
let i3 = (i1 + i2) / 2;
|
||||
if x < crown_cutter[i3].x {
|
||||
i2 = i3;
|
||||
} else {
|
||||
i1 = i3;
|
||||
}
|
||||
}
|
||||
let a = crown_cutter[i1];
|
||||
let b = crown_cutter[i2];
|
||||
assert!(a.x <= x);
|
||||
assert!(x <= b.x);
|
||||
let delta = (x - a.x) / (b.x - a.x);
|
||||
a.y + delta * (b.y - a.y)
|
||||
};
|
||||
let cutter_y_at_x = |x| rack_y_at_x(x, &cutter_profile);
|
||||
|
||||
let kr_to_xy = |k, r: f32| {
|
||||
let u = k as f32 / n_points_per_tooth as f32;
|
||||
|
|
@ -111,10 +177,10 @@ fn main() {
|
|||
vec2(s * r, r_pitch - c * r)
|
||||
};
|
||||
|
||||
for (k, r) in shape.iter_mut().enumerate() {
|
||||
for (k, r) in inv_shape.iter_mut().enumerate() {
|
||||
loop {
|
||||
let xy = kr_to_xy(k, *r);
|
||||
let cut_y = cutter_y_at_x(xy.x);
|
||||
let cut_y = inv_cutter_y_at_x(xy.x);
|
||||
if cut_y < xy.y {
|
||||
break;
|
||||
}
|
||||
|
|
@ -122,7 +188,29 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
line(gc, shape.iter().enumerate().map(|(k, r)| kr_to_xy(k, *r)));
|
||||
for (k, r) in bevel_shape.iter_mut().enumerate() {
|
||||
loop {
|
||||
let xy = kr_to_xy(k, *r);
|
||||
let cut_y = bevel_cutter_y_at_x(xy.x);
|
||||
if cut_y < xy.y {
|
||||
break;
|
||||
}
|
||||
*r -= 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
line(
|
||||
gc,
|
||||
inv_shape.iter().enumerate().map(|(k, r)| kr_to_xy(k, *r)),
|
||||
);
|
||||
gc.close_path();
|
||||
gc.stroke_color(Rgba(0.3, 0.3, 0.3, 0.4));
|
||||
gc.stroke();
|
||||
|
||||
line(
|
||||
gc,
|
||||
bevel_shape.iter().enumerate().map(|(k, r)| kr_to_xy(k, *r)),
|
||||
);
|
||||
gc.close_path();
|
||||
gc.stroke_color(Rgba(0.1, 0.6, 1.0, 0.4));
|
||||
gc.stroke();
|
||||
|
|
@ -134,17 +222,30 @@ fn main() {
|
|||
let x = (tooth as f32 + k as f32 / n_points_per_tooth as f32 + rack_offset)
|
||||
* PI;
|
||||
pts_rack.push(vec2(x, rack_y_at_x(x, &gear_profile)));
|
||||
pts_cutter.push(vec2(x, cutter_y_at_x(x)));
|
||||
pts_cutter.push(vec2(x, inv_cutter_y_at_x(x)));
|
||||
}
|
||||
}
|
||||
|
||||
line(gc, pts_cutter);
|
||||
gc.stroke_color(Rgba(1.0, 0.1, 0.1, 0.4));
|
||||
gc.stroke();
|
||||
|
||||
line(gc, pts_rack);
|
||||
gc.stroke_color(Rgba(0.1, 1.0, 0.1, 0.4));
|
||||
gc.stroke();
|
||||
if show_crown_cutter {
|
||||
line(gc, crown_cutter);
|
||||
gc.stroke_color(Rgba(1.0, 1.0, 0.1, 0.4));
|
||||
gc.stroke();
|
||||
}
|
||||
if show_crown_gear {
|
||||
line(gc, crown_gear);
|
||||
gc.stroke_color(Rgba(0.1, 1.0, 0.1, 0.4));
|
||||
gc.stroke();
|
||||
}
|
||||
if show_rack_cutter {
|
||||
line(gc, pts_cutter);
|
||||
gc.stroke_color(Rgba(1.0, 0.1, 0.1, 0.4));
|
||||
gc.stroke();
|
||||
}
|
||||
if show_rack_gear {
|
||||
line(gc, pts_rack);
|
||||
gc.stroke_color(Rgba(0.1, 1.0, 0.1, 0.4));
|
||||
gc.stroke();
|
||||
}
|
||||
});
|
||||
|
||||
std::thread::sleep(Duration::from_secs_f32(1.0 / FPS));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user