use super::{
DiagramStyle, MeshCache, PanelKind, SolidStyle,
request::{PlannedFrame, RedrawRequest, panel_kind_from_index},
types::CameraPose,
};
use glam::Vec3;
use indicatrix::geometry::{meet_solver::SolvedTier, stone_metrics::SolidStatus};
pub struct DiagramMemory {
pub gear_teeth: u32,
pub gear_reference_angle: f32,
pub symmetry_order: u32,
pub mirror: bool,
pub enlarged_panel: Option<PanelKind>,
pub style: DiagramStyle,
pub hover_text: Vec<String>,
pub facet_tier: Vec<Option<usize>>,
}
impl Default for DiagramMemory {
fn default() -> Self {
Self {
gear_teeth: 96,
gear_reference_angle: 0.0,
symmetry_order: 8,
mirror: true,
enlarged_panel: None,
style: DiagramStyle::default(),
hover_text: Vec::new(),
facet_tier: Vec::new(),
}
}
}
#[derive(Default)]
pub struct WorkerMemory {
pub style: SolidStyle,
pub diagram: DiagramMemory,
pub solved_masts: Option<Vec<SolvedTier>>,
pub planes: Option<Vec<(Vec3, f32)>>,
pub camera: Option<CameraPose>,
pub size: Option<(u32, u32)>,
pub view_mode: Option<u8>,
pub generation: u64,
}
pub fn dim_style(style: SolidStyle) -> SolidStyle {
SolidStyle {
base_color: [120, 122, 128],
ambient: 0.4,
diffuse: 0.35,
..style
}
}
pub fn escaping_tier_label(
design: &indicatrix_cut_core::Design,
solved: &[SolvedTier],
plane_index: usize,
) -> String {
design
.tier_for_plane_index(solved, plane_index)
.map_or_else(
|| format!("plane {plane_index}"),
|tier_index| {
design.tiers.get(tier_index).map_or_else(
|| format!("tier {}", tier_index + 1),
|tier| {
if tier.name.is_empty() {
format!("tier {}", tier_index + 1)
} else {
format!("{} (tier {})", tier.name, tier_index + 1)
}
},
)
},
)
}
fn update_diagram_memory_from_design(
last_diagram: &mut DiagramMemory,
design: &indicatrix_cut_core::Design,
solved: Option<&[SolvedTier]>,
solid_style: &SolidStyle,
n_d: f64,
) {
let facet_map = super::FacetMap::from_design(design, solved.unwrap_or(&[]));
let facet_count = facet_map.facet_count();
let mut labels = vec![String::new(); facet_count];
let mut hover_text = vec![String::new(); facet_count];
let mut facet_tier = vec![None; facet_count];
let mut facet_index_on_gear = vec![0u32; facet_count];
for id in 0..facet_count {
labels[id] = facet_map.facet_label(id);
hover_text[id] = facet_map.hover_text(id, n_d);
facet_tier[id] = facet_map.tier_of(id);
facet_index_on_gear[id] = facet_map.index_on_gear(id);
}
last_diagram.style = DiagramStyle {
flagged: solid_style.flagged.clone(),
pending: solid_style.pending.clone(),
selected: solid_style.selected.clone(),
facet_labels: labels,
facet_index_on_gear,
meet_marker_pairs: facet_map.meeting_facet_pairs(design),
..DiagramStyle::default()
};
last_diagram.hover_text = hover_text;
last_diagram.facet_tier = facet_tier;
}
const fn apply_reproject_gear(last_diagram: &mut DiagramMemory, gear: Option<(u32, f32)>) {
if let Some((gear_teeth, gear_reference_angle)) = gear {
last_diagram.gear_teeth = gear_teeth;
last_diagram.gear_reference_angle = gear_reference_angle;
}
}
pub type RequestState = (
Vec<(Vec3, f32)>,
CameraPose,
(u32, u32),
u8,
SolidStyle,
Option<Vec<SolvedTier>>,
bool,
Option<String>,
u64,
);
pub fn resolve_request_state(
memory: &mut WorkerMemory,
mesh_cache: &mut MeshCache,
request: RedrawRequest,
) -> Option<RequestState> {
match request {
RedrawRequest::Reproject {
planes,
camera,
size,
view_mode,
gear,
} => {
apply_reproject_gear(&mut memory.diagram, gear);
if memory.planes.as_deref() != Some(planes.as_slice()) {
memory.style = SolidStyle::default();
memory.diagram = DiagramMemory::default();
}
memory.planes = Some(planes.clone());
memory.camera = Some(camera);
memory.size = Some(size);
memory.view_mode = Some(view_mode);
Some((
planes,
camera,
size,
view_mode,
memory.style.clone(),
memory.solved_masts.clone(),
false,
None,
memory.generation,
))
}
RedrawRequest::UpdateFacetOverlay(overlay) => {
memory.size?;
memory.style.hovered = overlay.hovered;
memory.style.selected_facet = overlay.selected_facet;
memory.style.multi_selected = overlay.multi_selected.clone();
memory.diagram.style.hovered = overlay.hovered;
memory.diagram.style.selected_facet = overlay.selected_facet;
memory.diagram.style.multi_selected = overlay.multi_selected;
Some((
memory.planes.clone().unwrap_or_default(),
memory.camera.unwrap_or(CameraPose {
yaw: 0.0,
pitch: 0.0,
distance: 5.0,
}),
memory.size.unwrap_or((1, 1)),
memory.view_mode.unwrap_or(0),
memory.style.clone(),
memory.solved_masts.clone(),
false,
None,
memory.generation,
))
}
RedrawRequest::Planned(frame) => Some(resolve_planned_state(memory, mesh_cache, *frame)),
}
}
fn resolve_planned_state(
memory: &mut WorkerMemory,
mesh_cache: &mut MeshCache,
frame: PlannedFrame,
) -> RequestState {
let PlannedFrame {
design,
planes,
style,
solved,
stale,
unsolvable_status,
camera,
size,
view_mode,
generation,
n_d,
enlarged_panel,
} = frame;
let closes = mesh_cache.get_or_build(&planes).is_some();
let unbounded_status = if unsolvable_status.is_none() && !closes {
match mesh_cache.status() {
Some(SolidStatus::Unbounded { escaping }) => {
let solved_ref = solved.as_deref().unwrap_or(&[]);
let names = escaping
.iter()
.map(|&plane_index| escaping_tier_label(&design, solved_ref, plane_index))
.collect::<Vec<_>>()
.join(", ");
Some(format!("Unbounded: {names} never close the solid."))
}
_ => None,
}
} else {
None
};
let holding_over = unsolvable_status.is_some() || unbounded_status.is_some();
let preview_status = unsolvable_status.or(unbounded_status);
let style = if holding_over {
dim_style(style)
} else {
style
};
memory.style = style.clone();
if solved.is_some() {
memory.solved_masts.clone_from(&solved);
}
memory.planes = Some(planes.clone());
memory.camera = Some(camera);
memory.size = Some(size);
memory.view_mode = Some(view_mode);
memory.generation = generation;
memory.diagram.gear_teeth = design.meta.gear_teeth_abs();
memory.diagram.gear_reference_angle = design.meta.gear_reference_angle as f32;
memory.diagram.symmetry_order = design.meta.symmetry_order;
memory.diagram.mirror = design.meta.mirror;
memory.diagram.enlarged_panel = panel_kind_from_index(enlarged_panel);
update_diagram_memory_from_design(&mut memory.diagram, &design, solved.as_deref(), &style, n_d);
(
planes,
camera,
size,
view_mode,
style,
solved,
stale,
preview_status,
generation,
)
}