ifc_lite_landxml/plan/
numeric.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
5pub(super) use super::{
6    LandXmlGeometryKind, LandXmlParcel, LandXmlParcelProbe, LandXmlParcelState,
7    LandXmlPlanDocument, LandXmlPlanGeometry, LandXmlPlanPoint, LandXmlPlanPointLocation,
8    LandXmlPlanResolver,
9};
10
11mod measure;
12mod parcel_measure;
13mod parcel_probe;
14pub mod references;
15mod topology;
16use measure::same_point;
17
18const EPSILON: f64 = 1e-9;
19
20/// The parcel probe's resolution and topology passes must charge the same
21/// caller-owned work counter. The ordinary single-parcel API owns a local
22/// counter; bulk adapters provide their document-scoped resolver instead.
23pub(super) trait ParcelProbeWork {
24    fn check(&mut self) -> std::result::Result<(), crate::LandXmlError>;
25
26    fn resolve(
27        &mut self,
28        document: &LandXmlPlanDocument,
29        scope: Option<&crate::LandXmlSourceId>,
30        location: &LandXmlPlanPointLocation,
31    ) -> std::result::Result<Option<LandXmlPlanPoint>, crate::LandXmlError>;
32}
33
34impl ParcelProbeWork for LandXmlPlanResolver<'_> {
35    fn check(&mut self) -> std::result::Result<(), crate::LandXmlError> {
36        self.check_work()
37    }
38
39    fn resolve(
40        &mut self,
41        _document: &LandXmlPlanDocument,
42        scope: Option<&crate::LandXmlSourceId>,
43        location: &LandXmlPlanPointLocation,
44    ) -> std::result::Result<Option<LandXmlPlanPoint>, crate::LandXmlError> {
45        LandXmlPlanResolver::resolve(self, scope, location)
46    }
47}
48
49impl LandXmlPlanDocument {
50    /// Partition plan-source identities without coupling semantic records to a
51    /// renderer allocation or introducing a second model-load path.
52    pub fn source_batches(&self, max_records: usize) -> Vec<super::LandXmlPlanSourceBatch> {
53        if max_records == 0 {
54            return Vec::new();
55        }
56        let source_ids = self
57            .cogo_points()
58            .iter()
59            .map(|point| point.source_id.clone())
60            .chain(
61                self.monuments
62                    .iter()
63                    .map(|monument| monument.source_id.clone()),
64            )
65            .chain(self.plan_features.iter().flat_map(|feature| {
66                std::iter::once(feature.source_id.clone()).chain(
67                    feature
68                        .geometry
69                        .iter()
70                        .map(|geometry| geometry.source_id.clone()),
71                )
72            }))
73            .chain(self.parcels.iter().flat_map(|parcel| {
74                std::iter::once(parcel.source_id.clone()).chain(
75                    parcel
76                        .loops
77                        .iter()
78                        .flatten()
79                        .map(|geometry| geometry.source_id.clone()),
80                )
81            }));
82        let mut batches = Vec::new();
83        let mut current = Vec::new();
84        for source_id in source_ids {
85            current.push(source_id);
86            if current.len() == max_records {
87                batches.push(super::LandXmlPlanSourceBatch {
88                    source_ids: current,
89                });
90                current = Vec::new();
91            }
92        }
93        if !current.is_empty() {
94            batches.push(super::LandXmlPlanSourceBatch {
95                source_ids: current,
96            });
97        }
98        batches
99    }
100}