ifc_lite_processing/
analytic_export.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Optional analytic descriptions of authored geometry, keyed by product occurrence.
6//! This walks the same body-representation selection as the mesh router, but does
7//! not produce meshes. Source operands of booleans are identified as such.
8
9use std::collections::{BTreeMap, HashSet};
10use ifc_lite_geometry::analytic::{AnalyticCurveSegment, AnalyticStatus};
11
12mod transform;
13mod metrics;
14pub use metrics::{DirectrixMetrics, DirectrixSegmentMetrics};
15mod checks;
16pub use checks::{check_swept_disk, SweptDiskCheckError, SweptDiskCheckFinding,
17    SweptDiskCheckOptions, SweptDiskCheckReport, SweptDiskFindingCode};
18mod quantities;
19pub use quantities::{extrusion_nominal_quantities, ExtrusionNominalQuantities, SweptDiskNominalQuantities};
20mod occurrence;
21mod operands;
22mod placement;
23mod mapped;
24mod walk;
25mod definitions;
26pub use definitions::{AnalyticSourceContext, AnalyticSourceKey, SweptDiskDefinition,
27    SweptDiskDefinitions, SweptDiskInstance, SweptDiskSourceKey, SweptDiskSourceContext};
28mod extrusion_definitions;
29pub use extrusion_definitions::{ExtrusionDefinition, ExtrusionDefinitions, ExtrusionInstance};
30use serde::Serialize;
31
32const MAX_VISITED_ITEMS: usize = 100_000;
33const MAX_ITEM_DEPTH: usize = 128;
34
35/// One authored `IfcSweptDiskSolid` in an occurrence's body representation.
36#[derive(Debug, Clone)]
37pub struct SweptDiskOccurrence {
38    pub solid_id: u32,
39    pub directrix_id: u32,
40    pub mapping_path: Vec<u32>,
41    /// True when this solid is an operand of an enclosing CSG construction.
42    pub source_modified: bool,
43    /// Effective world radius for a complete description; source radius in
44    /// metres when status is unsupported (no world circular radius is implied).
45    pub radius: f64,
46    pub inner_radius: Option<f64>,
47    pub directrix: Vec<AnalyticCurveSegment>,
48    pub status: AnalyticStatus,
49}
50
51/// Analytic swept disks in IFC Z-up, absolute-world metres.
52#[derive(Debug, Clone, Serialize)]
53pub struct SweptDiskDescriptions {
54    pub up_axis: &'static str,
55    pub units: &'static str,
56    pub coordinate_space: &'static str,
57    pub elements: BTreeMap<u32, Vec<SweptDiskOccurrence>>,
58    pub diagnostics: Vec<String>,
59}
60
61impl Default for SweptDiskDescriptions {
62    fn default() -> Self {
63        Self {
64            up_axis: "Z",
65            units: "m",
66            coordinate_space: "absolute_ifc_world",
67            elements: BTreeMap::new(),
68            diagnostics: Vec::new(),
69        }
70    }
71}
72
73/// Three analytic source views from one bounded representation walk. This is
74/// useful for quantity joins that need exact swept-disk world directrices and
75/// reusable disk/extrusion definitions with matching occurrence ordinals.
76#[derive(Debug, Clone)]
77pub struct AnalyticQuantitySources {
78    pub swept_disk_descriptions: SweptDiskDescriptions,
79    pub swept_disk_definitions: SweptDiskDefinitions,
80    pub extrusion_definitions: ExtrusionDefinitions,
81}
82
83/// Extract all quantity source views in one canonical walk. Existing individual
84/// APIs keep their output and budget contracts unchanged.
85pub fn extract_analytic_quantity_sources(
86    content: &[u8], ids: Option<&HashSet<u32>>,
87) -> AnalyticQuantitySources {
88    let result = walk::extract(content, ids, true, true, true);
89    AnalyticQuantitySources {
90        swept_disk_descriptions: result.descriptions,
91        swept_disk_definitions: result.definitions.expect("definition collection requested"),
92        extrusion_definitions: result.extrusions.expect("extrusion collection requested"),
93    }
94}
95
96/// Extract exact swept-disk definitions for product occurrences, optionally
97/// restricted to a set of product STEP IDs. An empty set returns no products.
98/// Unsupported directrices are reported in each record's `status`; malformed
99/// representation walks are reported in `diagnostics` and omitted atomically
100/// for the affected product.
101pub fn extract_swept_disk_descriptions(
102    content: &[u8], ids: Option<&HashSet<u32>>,
103) -> SweptDiskDescriptions {
104    walk::extract(content, ids, false, true, false).descriptions
105}
106
107/// Opt-in source/instance view. Definitions stay in raw IFC file units;
108/// occurrence matrices map those raw coordinates into absolute IFC Z-up metres.
109pub fn extract_swept_disk_definitions(
110    content: &[u8], ids: Option<&HashSet<u32>>,
111) -> SweptDiskDefinitions {
112    walk::extract(content, ids, true, false, false).definitions.expect("definition collection requested")
113}
114
115/// Opt-in exact source/instance view of `IfcExtrudedAreaSolid` occurrences.
116/// Source profiles and depths retain IFC file units; each f64 occurrence
117/// matrix maps solid-local source coordinates to absolute IFC Z-up metres.
118pub fn extract_extrusion_definitions(
119    content: &[u8], ids: Option<&HashSet<u32>>,
120) -> ExtrusionDefinitions {
121    walk::extract(content, ids, false, false, true)
122        .extrusions.expect("extrusion collection requested")
123}
124
125/// Return both world descriptions and reusable raw source definitions in one
126/// bounded representation walk. Both views share the same decoded source cache.
127pub fn extract_swept_disk_views(
128    content: &[u8], ids: Option<&HashSet<u32>>,
129) -> (SweptDiskDescriptions, SweptDiskDefinitions) {
130    let result = walk::extract(content, ids, true, true, false);
131    (result.descriptions, result.definitions.expect("definition collection requested"))
132}