use super::diagnostics::{count_attributed_products, UNATTRIBUTED_PRODUCT_ID};
use super::GeometryRouter;
use crate::BoolFailure;
use rustc_hash::FxHashMap;
#[derive(Debug, Default, Clone, Copy)]
pub struct ClassificationStats {
pub rectangular: usize,
pub diagonal: usize,
pub non_rectangular: usize,
}
#[derive(Debug, Clone, Default)]
pub struct HostOpeningDiagnostic {
pub host_type: String,
pub openings: Vec<OpeningDiagnostic>,
pub csg_failure_count: usize,
pub first_failure_label: Option<String>,
pub tris_before: Option<usize>,
pub tris_after: Option<usize>,
pub rect_boxes_processed: usize,
pub host_bounds: Option<((f32, f32, f32), (f32, f32, f32))>,
}
#[derive(Debug, Clone)]
pub struct OpeningDiagnostic {
pub opening_id: u32,
pub kind: OpeningKindDiag,
pub vertex_count: usize,
}
const _: () = {
#[allow(dead_code)]
fn field_list_is_pinned(d: OpeningDiagnostic) {
let OpeningDiagnostic {
opening_id: _,
kind,
vertex_count: _,
} = d;
match kind {
OpeningKindDiag::Rectangular
| OpeningKindDiag::Diagonal
| OpeningKindDiag::NonRectangular => {}
}
}
};
const _: () = {
#[allow(dead_code)]
fn host_opening_diagnostic_field_list_is_pinned(d: HostOpeningDiagnostic) {
let HostOpeningDiagnostic {
host_type: _,
openings: _,
csg_failure_count: _,
first_failure_label: _,
tris_before: _,
tris_after: _,
rect_boxes_processed: _,
host_bounds: _,
} = d;
}
};
const _: () = {
#[allow(dead_code)]
fn classification_stats_field_list_is_pinned(d: ClassificationStats) {
let ClassificationStats {
rectangular: _,
diagonal: _,
non_rectangular: _,
} = d;
}
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpeningKindDiag {
Rectangular,
Diagonal,
NonRectangular,
}
impl OpeningKindDiag {
pub fn as_str(self) -> &'static str {
match self {
OpeningKindDiag::Rectangular => "Rectangular",
OpeningKindDiag::Diagonal => "Diagonal",
OpeningKindDiag::NonRectangular => "NonRectangular",
}
}
}
impl GeometryRouter {
pub fn take_csg_failures(&self) -> FxHashMap<u32, Vec<BoolFailure>> {
self.drain_processor_failures();
let pending = crate::diagnostics::take_pending_mapped_bool_failures();
if !pending.is_empty() {
self.csg_failures
.borrow_mut()
.entry(UNATTRIBUTED_PRODUCT_ID)
.or_default()
.extend(pending);
}
std::mem::take(&mut *self.csg_failures.borrow_mut())
}
pub(crate) fn push_layer_slice_diag(&self, element_id: u32, reason: &'static str) {
self.layer_slice_diag.borrow_mut().push((element_id, reason));
}
pub fn take_layer_slice_diag(&self) -> Vec<(u32, &'static str)> {
std::mem::take(&mut *self.layer_slice_diag.borrow_mut())
}
pub fn csg_failure_product_count(&self) -> usize {
count_attributed_products(&self.csg_failures.borrow()) as usize
}
pub fn csg_failure_total(&self) -> usize {
self.csg_failures.borrow().values().map(|v| v.len()).sum()
}
pub(crate) fn record_void_consumed_host(&self, product_id: u32) {
self.voids_consumed_hosts.borrow_mut().insert(product_id);
}
pub fn host_consumed_by_void(&self, product_id: u32) -> bool {
self.voids_consumed_hosts.borrow().contains(&product_id)
}
pub(crate) fn record_csg_failures(&self, product_id: u32, failures: Vec<BoolFailure>) {
if failures.is_empty() {
return;
}
let attributed: Vec<BoolFailure> = failures
.into_iter()
.map(|f| f.with_product_id(product_id))
.collect();
self.csg_failures
.borrow_mut()
.entry(product_id)
.or_default()
.extend(attributed);
}
pub fn take_classification_stats(&self) -> ClassificationStats {
std::mem::take(&mut *self.classification_stats.borrow_mut())
}
pub fn take_host_opening_diagnostics(&self) -> FxHashMap<u32, HostOpeningDiagnostic> {
std::mem::take(&mut *self.host_opening_diagnostics.borrow_mut())
}
pub(crate) fn record_rect_fast(&self, s: &crate::rect_fast::RectFastStats) {
let mut acc = self.rect_fast_stats.borrow_mut();
acc.fired += s.fired;
acc.openings_cut += s.openings_cut;
acc.defer_host_not_box += s.defer_host_not_box;
acc.defer_not_through += s.defer_not_through;
acc.defer_off_face += s.defer_off_face;
acc.defer_near_edge += s.defer_near_edge;
acc.defer_no_openings += s.defer_no_openings;
acc.defer_too_many_openings += s.defer_too_many_openings;
}
pub fn take_rect_fast_stats(&self) -> crate::rect_fast::RectFastStats {
std::mem::take(&mut *self.rect_fast_stats.borrow_mut())
}
pub fn host_opening_diagnostic_count(&self) -> usize {
self.host_opening_diagnostics.borrow().len()
}
pub(crate) fn bump_classification(&self, kind: ClassificationKind) {
let mut s = self.classification_stats.borrow_mut();
match kind {
ClassificationKind::Rectangular => s.rectangular += 1,
ClassificationKind::Diagonal => s.diagonal += 1,
ClassificationKind::NonRectangular => s.non_rectangular += 1,
}
}
pub(crate) fn record_host_opening_diagnostic(
&self,
host_id: u32,
host_type: &str,
openings: Vec<OpeningDiagnostic>,
) {
let mut log = self.host_opening_diagnostics.borrow_mut();
let entry = log.entry(host_id).or_default();
if entry.host_type.is_empty() {
entry.host_type = host_type.to_string();
}
entry.openings.extend(openings);
}
pub(crate) fn record_host_cut_effect(
&self,
host_id: u32,
tris_before: usize,
tris_after: usize,
rect_boxes_processed: usize,
host_bounds: ((f32, f32, f32), (f32, f32, f32)),
) {
let mut log = self.host_opening_diagnostics.borrow_mut();
let entry = log.entry(host_id).or_default();
entry.tris_before = Some(tris_before);
entry.tris_after = Some(tris_after);
entry.rect_boxes_processed = rect_boxes_processed;
entry.host_bounds = Some(host_bounds);
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum ClassificationKind {
Rectangular,
Diagonal,
NonRectangular,
}