use super::{
DiagramFrame, DiagramStyle, PanelKind,
fill::draw_edge,
labels::{draw_text, text_size},
layout::{PanelLayout, wheel_direction},
render::WheelConfig,
};
pub fn draw_index_wheel(
frame: &mut DiagramFrame,
layout: &PanelLayout,
gear_teeth: u32,
gear_reference_angle: f32,
color: [u8; 3],
) {
let mirrored = matches!(layout.kind, PanelKind::Pavilion);
let major_every = if gear_teeth <= 64 { 4 } else { 8 };
let inner_r = layout.wheel_radius_px * 0.94;
let minor_outer_r = layout.wheel_radius_px;
let major_outer_r = layout.wheel_radius_px * 1.08;
let label_r = layout.wheel_radius_px * 1.2;
for tooth in 0..gear_teeth {
let phi =
2.0 * std::f32::consts::PI * (tooth as f32 + gear_reference_angle) / gear_teeth as f32;
let (su, sv) = wheel_direction(phi, mirrored);
let is_major = tooth % major_every == 0;
let outer_r = if is_major {
major_outer_r
} else {
minor_outer_r
};
let from = (
su.mul_add(inner_r, layout.center_x),
sv.mul_add(-inner_r, layout.center_y),
0.0,
);
let to = (
su.mul_add(outer_r, layout.center_x),
sv.mul_add(-outer_r, layout.center_y),
0.0,
);
draw_edge(frame, from, to, color, layout.clip, 1);
let mid_r = inner_r.midpoint(outer_r);
let mid_x = su.mul_add(mid_r, layout.center_x).round() as i32;
let mid_y = sv.mul_add(-mid_r, layout.center_y).round() as i32;
tag_tooth_hit(frame, mid_x, mid_y, tooth, 4);
if is_major {
let label = tooth.to_string();
let (w, h) = text_size(&label, 1);
let lx = su.mul_add(label_r, layout.center_x) - w as f32 / 2.0;
let ly = sv.mul_add(-label_r, layout.center_y) - h as f32 / 2.0;
let lx = lx.clamp(layout.clip.0 as f32, (layout.clip.2 as f32) - w as f32);
let ly = ly.clamp(layout.clip.1 as f32, (layout.clip.3 as f32) - h as f32);
draw_text(frame, lx, ly, &label, 1, color, Some(layout.clip));
}
}
}
fn tag_tooth_hit(frame: &mut DiagramFrame, cx: i32, cy: i32, tooth: u32, radius: i32) {
for dy in -radius..=radius {
for dx in -radius..=radius {
if let Some(idx) = frame.idx(cx + dx, cy + dy) {
frame.tooth[idx] = tooth + 1;
}
}
}
}
pub fn draw_symmetry_and_mirror_lines(
frame: &mut DiagramFrame,
layout: &PanelLayout,
wheel: WheelConfig,
style: &DiagramStyle,
) {
let mirrored = matches!(layout.kind, PanelKind::Pavilion);
let line_len = layout.wheel_radius_px * 1.05;
let center = (layout.center_x, layout.center_y, 0.0);
if wheel.symmetry_order > 1 {
for k in 0..wheel.symmetry_order {
let phi = 2.0 * std::f32::consts::PI * (k as f32) / (wheel.symmetry_order as f32);
let (su, sv) = wheel_direction(phi, mirrored);
let tip = (
su.mul_add(line_len, layout.center_x),
sv.mul_add(-line_len, layout.center_y),
0.0,
);
draw_edge(
frame,
center,
tip,
style.symmetry_line_color,
layout.clip,
1,
);
}
}
if wheel.mirror {
let top = (layout.center_x, layout.center_y - line_len, 0.0);
let bottom = (layout.center_x, layout.center_y + line_len, 0.0);
draw_edge(frame, top, bottom, style.mirror_line_color, layout.clip, 2);
}
}
pub fn draw_selected_index_radials(
frame: &mut DiagramFrame,
layout: &PanelLayout,
gear_teeth: u32,
gear_reference_angle: f32,
style: &DiagramStyle,
edge_ranges: &[(usize, usize, usize)],
) {
let mirrored = matches!(layout.kind, PanelKind::Pavilion);
for &(facet_id, _start, _count) in edge_ranges {
let color = if style.selected_facet == Some(facet_id as u32) {
style.selected_facet_color
} else if style.selected.get(facet_id).copied().unwrap_or(false) {
style.selected_color
} else if style.multi_selected.contains(&(facet_id as u32)) {
style.multi_selected_color
} else {
continue;
};
let Some(&index) = style.facet_index_on_gear.get(facet_id) else {
continue;
};
let phi = 2.0 * std::f32::consts::PI * (index as f32 + gear_reference_angle)
/ gear_teeth.max(1) as f32;
let (su, sv) = wheel_direction(phi, mirrored);
let center = (layout.center_x, layout.center_y, 0.0);
let tip = (
su.mul_add(layout.wheel_radius_px, layout.center_x),
sv.mul_add(-layout.wheel_radius_px, layout.center_y),
0.0,
);
draw_edge(frame, center, tip, color, layout.clip, 2);
}
}