This commit is contained in:
numzero 2025-09-06 03:10:35 +03:00
parent d497f3e96d
commit 9d4c61d7ec

View File

@ -4,7 +4,7 @@ use flo_draw::{
canvas::{Color::Rgba, GraphicsContext, GraphicsPrimitives}, canvas::{Color::Rgba, GraphicsContext, GraphicsPrimitives},
create_drawing_window, with_2d_graphics, create_drawing_window, with_2d_graphics,
}; };
use glam::{Mat2, Vec2, vec2}; use glam::{FloatExt, Mat2, Vec2, vec2};
const fn rad(deg: f32) -> f32 { const fn rad(deg: f32) -> f32 {
deg * (PI / 180.0) deg * (PI / 180.0)
@ -19,187 +19,114 @@ fn involute_radius_to_t(r: f32) -> f32 {
(r * r - 1.).sqrt() (r * r - 1.).sqrt()
} }
fn gear_shape(n: usize) -> Vec<Vec2> { fn gear_shape_ex(n: usize, inner: f32, outer: f32) -> Vec<Vec2> {
const A: f32 = rad(28.);
const Q: usize = 6; const Q: usize = 6;
let b = A.cos();
let offset = involute(involute_radius_to_t(1. / b)).to_angle(); const A: f32 = rad(28.);
let stop_angle = involute_radius_to_t((1.0 + 2.0 / n as f32) / b); let base = A.cos();
let halfangle = PI / n as f32;
let ma = Mat2::from_angle(offset - halfangle);
let mb = Mat2::from_diagonal(vec2(1., -1.)) * ma;
let mut ret = Vec::with_capacity(2 * n * Q); let base_to_pitch_angle = involute(involute_radius_to_t(1. / base)).to_angle();
for i in 0..n {
let m = Mat2::from_angle(i as f32 * 2. * halfangle); let tooth_angle = 2.0 * PI / n as f32;
println!("{n}: {base}, {inner}, {outer}");
let t1 = involute_radius_to_t((inner / base).max(1.));
let t2 = involute_radius_to_t(outer / base);
println!("{t1}-{t2}");
println!("{base_to_pitch_angle}, {}", tooth_angle / 4.);
let mut side = [Vec2::ZERO; Q + 2];
side[0] = vec2(inner, 0.0);
for k in 0..=Q { for k in 0..=Q {
let t = k as f32 / Q as f32; let t01 = k as f32 / Q as f32;
let p = b * m * ma * involute(stop_angle * t); let t = f32::lerp(t1, t2, t01);
ret.push(p); side[k + 1] = base * involute(t);
} }
for k in 0..=Q {
let t = 1. - k as f32 / Q as f32; let m = Mat2::from_angle(-(tooth_angle / 4.0 + base_to_pitch_angle));
let p = b * m * mb * involute(stop_angle * t); for p in &mut side {
ret.push(p); *p = m * *p;
}
if base_to_pitch_angle > tooth_angle / 4.0 {
side[0] = Mat2::from_angle(-(tooth_angle / 2.0)) * vec2(inner, 0.0);
}
let mut ret = Vec::with_capacity(2 * n * (Q + 2));
for i in 0..n {
let m = Mat2::from_angle(i as f32 * tooth_angle);
for p in side {
ret.push(m * p);
}
for p in side.iter().rev() {
ret.push(m * vec2(p.x, -p.y));
} }
} }
ret ret
} }
fn gear_shape_std(n: usize, low: f32, high: f32) -> Vec<Vec2> {
let unit = 1.0 / n as f32;
return gear_shape_ex(n, 1.0 - low * unit, 1.0 + high * unit);
}
fn gear_shape(n: usize) -> Vec<Vec2> {
return gear_shape_std(n, 2.2, 2.0);
}
fn gear_shape_outer(n: usize) -> Vec<Vec2> {
return gear_shape_std(n, 2.0, 2.2);
}
fn main() { fn main() {
let g24 = gear_shape(24); const R_SCALE: f32 = 0.5;
let g36 = gear_shape(36); const N_TEETH_SUN: usize = 36;
const N_TEETH_SAT: usize = 24;
const N_TEETH_SKY: usize = N_TEETH_SUN + 2 * N_TEETH_SAT;
const N_SAT: usize = 3;
const R_SUN: f32 = R_SCALE * N_TEETH_SUN as f32;
const R_SAT: f32 = R_SCALE * N_TEETH_SAT as f32;
const OFF_SAT: f32 = R_SUN + R_SAT;
const R_SKY: f32 = R_SCALE * N_TEETH_SKY as f32;
with_2d_graphics(|| { with_2d_graphics(|| {
let sun = gear_shape(N_TEETH_SUN);
let sat = gear_shape(N_TEETH_SAT);
let crown = gear_shape_outer(N_TEETH_SKY);
let canvas = create_drawing_window("Canvas window"); let canvas = create_drawing_window("Canvas window");
canvas.draw(|gc| { canvas.draw(|gc| {
gc.clear_canvas(Rgba(0.1, 0.1, 0.1, 1.0)); gc.clear_canvas(Rgba(0.1, 0.1, 0.1, 1.0));
gc.canvas_height(50.0); gc.canvas_height(100.0);
gc.line_width(0.5); gc.line_width(0.25);
const N1: usize = 20;
const N2: usize = 50;
const R1: f32 = 20.;
const R2: f32 = 50.;
const A: f32 = rad(28.);
let b = A.cos();
let b1 = b * R1;
let b2 = b * R2;
let offset = involute_radius_to_t(1. / b);
let offset = involute(offset).to_angle();
gc.new_path(); gc.new_path();
gc.stroke_color(Rgba(0.3, 0.3, 0.3, 1.0)); for pt in sun {
gc.circle(-R1, 0., R1); let pt = R_SUN * pt;
gc.circle(R2, 0., R2); gc.line_to(pt.x, pt.y);
gc.circle(-R2, 0., R2); }
gc.close_path();
gc.stroke_color(Rgba(0.8, 0.7, 0.1, 1.0));
gc.stroke(); gc.stroke();
for k in 0..N_SAT {
let m = Mat2::from_angle(k as f32 / N_SAT as f32 * 2. * PI);
gc.new_path(); gc.new_path();
gc.stroke_color(Rgba(0.1, 0.1, 0.8, 1.0)); for pt in &sat {
gc.circle(-R1, 0., b1); let pt = m * vec2(OFF_SAT, 0.) + R_SAT * pt;
gc.circle(R2, 0., b2); gc.line_to(pt.x, pt.y);
gc.circle(-R2, 0., b2);
gc.stroke();
// let pitch_radius = R1;
// let base_radius = b1;
// let number_of_teeth = N1;
// let addendum = 2.0 * pitch_radius / number_of_teeth as f32;
// let clearance = 0.0;
// let dedendum = addendum + clearance;
const Q: usize = 12;
let stop_angle = involute_radius_to_t((1.0 + 2.0 / N1 as f32) / b);
let halfangle = PI / N1 as f32;
let ma = Mat2::from_angle(offset - halfangle);
let mb = Mat2::from_diagonal(vec2(1., -1.)) * ma;
gc.new_path();
for i in 0..N1 {
let m = Mat2::from_angle(i as f32 / N1 as f32 * 2. * PI);
for k in 0..=Q {
let t = k as f32 / Q as f32;
let p = b1 * m * ma * involute(stop_angle * t) - vec2(R1, 0.);
gc.line_to(p.x, p.y);
}
for k in 0..=Q {
let t = 1. - k as f32 / Q as f32;
let p = b1 * m * mb * involute(stop_angle * t) - vec2(R1, 0.);
gc.line_to(p.x, p.y);
}
} }
gc.close_path(); gc.close_path();
gc.stroke_color(Rgba(0.1, 0.8, 0.1, 1.0)); gc.stroke_color(Rgba(0.1, 0.8, 0.1, 1.0));
gc.stroke(); gc.stroke();
}
let stop_angle = involute_radius_to_t((1.0 + 2.0 / N2 as f32) / b);
let halfangle = PI / N2 as f32;
let ma = Mat2::from_angle(offset - halfangle);
let mb = Mat2::from_diagonal(vec2(1., -1.)) * ma;
gc.new_path(); gc.new_path();
for i in 0..N2 { for pt in crown {
let m = Mat2::from_angle((i as f32 - 0.5) / N2 as f32 * 2. * PI); let pt = R_SKY * pt;
for k in 0..=Q { gc.line_to(pt.x, pt.y);
let t = k as f32 / Q as f32;
let p = b2 * m * ma * involute(stop_angle * t) + vec2(R2, 0.);
gc.line_to(p.x, p.y);
}
for k in 0..=Q {
let t = 1. - k as f32 / Q as f32;
let p = b2 * m * mb * involute(stop_angle * t) + vec2(R2, 0.);
gc.line_to(p.x, p.y);
}
} }
gc.close_path(); gc.close_path();
gc.stroke_color(Rgba(0.1, 0.8, 0.1, 1.0));
gc.stroke();
gc.new_path();
gc.stroke_color(Rgba(0.1, 0.4, 0.8, 1.0)); gc.stroke_color(Rgba(0.1, 0.4, 0.8, 1.0));
gc.move_to(-5., 0.);
gc.line_to(5., 0.);
gc.stroke();
return;
let m = Mat2::IDENTITY; // Mat2::from_angle(-offset);
gc.new_path();
for k in 0..=Q {
let t = k as f32 / Q as f32;
let p = vec2(R2, 0.) - b2 * m * involute(t);
gc.line_to(p.x, p.y);
}
gc.stroke_color(Rgba(0.1, 0.8, 0.1, 1.0));
gc.stroke();
gc.new_path();
for k in 0..=Q {
let t = k as f32 / Q as f32;
let m1 = Mat2::from_angle(A - t);
let m2 = Mat2::from_angle((A - t) * R1 / R2);
let p = b1 * m1 * m * involute(t) - vec2(R1, 0.);
let p = m2 * (p - vec2(R2, 0.)) + vec2(R2, 0.);
gc.line_to(p.x, p.y);
}
gc.stroke_color(Rgba(0.8, 0.8, 0.1, 1.0));
gc.stroke();
gc.new_path();
for k in 0..=Q {
let t = k as f32 / Q as f32;
let m1 = Mat2::from_angle(A - t);
let m2 = Mat2::from_angle((t - A) * R1 / R2);
let p = b1 * m1 * m * involute(t) - vec2(R1, 0.);
let p = m2 * (p + vec2(R2, 0.)) - vec2(R2, 0.);
gc.line_to(p.x, p.y);
}
gc.stroke_color(Rgba(0.8, 0.1, 0.1, 1.0));
gc.stroke();
gc.new_path();
for k in 0..=Q {
let t = k as f32 / Q as f32;
let m1 = Mat2::from_angle(A - t);
let m2 = Mat2::from_angle(t - A);
let p = b2 * m1 * m * involute(t) - vec2(R2, 0.);
let p = m2 * (p + vec2(R2, 0.)) - vec2(R2, 0.);
gc.line_to(p.x, p.y);
}
gc.stroke_color(Rgba(0.8, 0.4, 0.1, 1.0));
gc.stroke();
gc.new_path();
for k in 0..=Q {
let t = k as f32 / Q as f32;
let p = b2 * m * involute(t) - vec2(R2, 0.);
gc.line_to(p.x, p.y);
}
gc.stroke_color(Rgba(0.1, 0.8, 0.8, 0.5));
gc.stroke(); gc.stroke();
}); });
}); });