1use std::collections::{BTreeMap, HashMap, HashSet};
8
9use ifc_lite_core::{
10 attribute_names_for_schema, keyword_eq, EntityDecoder, EntityScanner, ProjectUnits,
11};
12use ifc_lite_processing::{
13 check_swept_disk, extract_swept_disk_views, DirectrixMetrics, SweptDiskCheckError,
14 SweptDiskCheckOptions, SweptDiskCheckReport, SweptDiskInstance, SweptDiskSourceKey,
15};
16use serde::Serialize;
17
18use crate::rebar_attributes::{attribute, FIELDS};
19use crate::schema_detect::detect_schema;
20use crate::rebar_preflight::{assess_sweep, RebarPreflightLimits, RebarPreflightReport, RebarSchedulePreflightError};
21use crate::rebar_fabrication::{assess_fabrication, AuthoredDiameterContext, RebarFabricationPolicy, RebarFabricationReport,
22 RebarScheduleFabricationError};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
26#[serde(rename_all = "snake_case")]
27#[non_exhaustive]
28pub enum RebarSource {
29 Occurrence,
30 Type,
31}
32
33#[derive(Debug, Clone, PartialEq, Serialize)]
35#[serde(tag = "kind", rename_all = "snake_case")]
36#[non_exhaustive]
37pub enum AuthoredRebarValue {
38 Text {
39 value: String,
40 },
41 Measure {
42 value_file_units: f64,
43 value_si: f64,
44 si_unit: &'static str,
45 },
46}
47
48#[derive(Debug, Clone, PartialEq, Serialize)]
50#[non_exhaustive]
51pub struct AuthoredRebarAttribute {
52 pub source: RebarSource,
53 pub source_id: u32,
54 pub value: AuthoredRebarValue,
55}
56
57#[derive(Debug, Clone, Serialize)]
59#[non_exhaustive]
60pub struct RebarSweep {
61 pub occurrence_index: usize,
62 pub source: Option<SweptDiskSourceKey>,
65 pub solid_id: u32,
66 pub directrix_id: u32,
67 pub mapping_path: Vec<u32>,
68 pub source_modified: bool,
69 pub status: ifc_lite_geometry::analytic::AnalyticStatus,
70 pub radius_m: f64,
72 pub inner_radius_m: Option<f64>,
74 pub directrix_metrics: Option<DirectrixMetrics>,
75 pub checks: SweptDiskCheckReport,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub preflight: Option<RebarPreflightReport>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub fabrication_precheck: Option<RebarFabricationReport>,
82}
83
84#[derive(Debug, Clone, Serialize)]
86#[non_exhaustive]
87#[allow(non_snake_case)] pub struct RebarScheduleRow {
89 pub GlobalId: Option<String>,
91 pub Name: Option<String>,
93 pub type_id: Option<u32>,
94 pub authored: BTreeMap<String, AuthoredRebarAttribute>,
95 pub sweeps: Vec<RebarSweep>,
96 pub geometry_unavailable_reason: Option<String>,
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub preflight_skipped_reason: Option<String>,
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub fabrication_precheck_skipped_reason: Option<String>,
103 pub diagnostics: Vec<String>,
104}
105
106#[derive(Debug, Clone, Serialize)]
109#[non_exhaustive]
110pub struct RebarSchedule {
111 pub units: &'static str,
112 pub coordinate_space: &'static str,
113 pub length_unit_scale: f64,
114 pub bar_entity_count: usize,
115 pub represented_sweep_count: usize,
116 pub rows: BTreeMap<u32, RebarScheduleRow>,
117 pub diagnostics: Vec<String>,
118}
119
120const MAX_TYPE_RELATION_REFERENCES: usize = 100_000;
121
122#[path = "rebar_schedule_links.rs"]
123mod links;
124
125pub fn build_rebar_schedule(
129 content: &[u8],
130 ids: Option<&HashSet<u32>>,
131 options: &SweptDiskCheckOptions,
132) -> Result<RebarSchedule, SweptDiskCheckError> {
133 build_rebar_schedule_impl(content, ids, options, None, None)
134}
135
136pub fn build_rebar_schedule_with_preflight(
139 content: &[u8],
140 ids: Option<&HashSet<u32>>,
141 options: &SweptDiskCheckOptions,
142 limits: &RebarPreflightLimits,
143) -> Result<RebarSchedule, RebarSchedulePreflightError> {
144 limits.validate().map_err(RebarSchedulePreflightError::Limits)?;
145 build_rebar_schedule_impl(content, ids, options, Some(limits), None)
146 .map_err(RebarSchedulePreflightError::SweepChecks)
147}
148
149pub fn build_rebar_schedule_with_fabrication_precheck(
152 content: &[u8],
153 ids: Option<&HashSet<u32>>,
154 options: &SweptDiskCheckOptions,
155 policy: &RebarFabricationPolicy,
156) -> Result<RebarSchedule, RebarScheduleFabricationError> {
157 policy.validate().map_err(RebarScheduleFabricationError::Policy)?;
158 build_rebar_schedule_impl(content, ids, options, None, Some(policy))
159 .map_err(RebarScheduleFabricationError::SweepChecks)
160}
161
162#[path = "rebar_schedule_build.rs"]
163mod build;
164use build::build_rebar_schedule_impl;
165
166#[cfg(test)]
167#[path = "rebar_schedule_tests.rs"]
168mod tests;