1use std::collections::BTreeMap;
11
12use serde::{Deserialize, Serialize};
13
14use crate::{LandXmlDiagnosticCode, LandXmlSourceId};
15
16pub type LandXmlPipeProperties = BTreeMap<String, String>;
17
18#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
20pub struct LandXmlPipeMeasure {
21 pub value: f64,
22 pub unit: String,
23 pub meters: f64,
24}
25
26#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
28pub struct LandXmlPipeUnits {
29 pub linear_unit: String,
30 pub elevation_unit: String,
31 pub diameter_unit: String,
32 pub width_unit: String,
33 pub height_unit: String,
34 pub flow_unit: Option<String>,
36 pub linear_scale_to_meters: f64,
37 pub elevation_scale_to_meters: f64,
38 pub diameter_scale_to_meters: f64,
39 pub width_scale_to_meters: f64,
40 pub height_scale_to_meters: f64,
41}
42
43#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
45pub struct LandXmlPipePosition {
46 pub northing: f64,
47 pub easting: f64,
48 pub northing_meters: f64,
49 pub easting_meters: f64,
50 pub elevation: Option<LandXmlPipeMeasure>,
51}
52
53#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
55#[serde(tag = "kind", rename_all = "snake_case")]
56pub enum LandXmlPipePart {
57 Circular {
58 properties: LandXmlPipeProperties,
59 diameter: LandXmlPipeMeasure,
60 thickness: Option<LandXmlPipeMeasure>,
61 material: Option<String>,
62 },
63 Elliptical {
64 properties: LandXmlPipeProperties,
65 span: LandXmlPipeMeasure,
66 height: LandXmlPipeMeasure,
67 thickness: Option<LandXmlPipeMeasure>,
68 material: Option<String>,
69 },
70 Egg {
71 properties: LandXmlPipeProperties,
72 span: LandXmlPipeMeasure,
73 height: LandXmlPipeMeasure,
74 thickness: Option<LandXmlPipeMeasure>,
75 material: Option<String>,
76 },
77 Rectangular {
78 properties: LandXmlPipeProperties,
79 width: LandXmlPipeMeasure,
80 height: LandXmlPipeMeasure,
81 thickness: Option<LandXmlPipeMeasure>,
82 material: Option<String>,
83 },
84}
85
86#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
88#[serde(tag = "kind", rename_all = "snake_case")]
89pub enum LandXmlStructurePart {
90 Circular {
91 properties: LandXmlPipeProperties,
92 diameter: LandXmlPipeMeasure,
93 thickness: Option<LandXmlPipeMeasure>,
94 material: Option<String>,
95 },
96 Rectangular {
97 properties: LandXmlPipeProperties,
98 length: LandXmlPipeMeasure,
99 width: LandXmlPipeMeasure,
100 thickness: Option<LandXmlPipeMeasure>,
101 material: Option<String>,
102 },
103 Inlet {
104 properties: LandXmlPipeProperties,
105 },
106 Outlet {
107 properties: LandXmlPipeProperties,
108 },
109 Connection {
110 properties: LandXmlPipeProperties,
111 },
112}
113
114#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
116pub struct LandXmlPipeInvert {
117 pub source_id: LandXmlSourceId,
118 pub source_path: String,
119 pub pipe_source_id: LandXmlSourceId,
120 pub flow_direction: String,
121 pub elevation: LandXmlPipeMeasure,
122 pub properties: LandXmlPipeProperties,
123}
124
125#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
127pub struct LandXmlPipeFlow {
128 pub source_id: LandXmlSourceId,
129 pub source_path: String,
130 pub unit: Option<String>,
131 pub flow_in: Option<f64>,
132 pub loss_in: Option<f64>,
133 pub loss_out: Option<f64>,
134 pub properties: LandXmlPipeProperties,
135}
136
137#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
139pub struct LandXmlPipeStructure {
140 pub source_id: LandXmlSourceId,
141 pub source_path: String,
142 pub name: String,
143 pub properties: LandXmlPipeProperties,
144 pub units: LandXmlPipeUnits,
146 pub center: LandXmlPipePosition,
147 pub part: LandXmlStructurePart,
148 pub rim_elevation: Option<LandXmlPipeMeasure>,
149 pub sump_elevation: Option<LandXmlPipeMeasure>,
150 pub inverts: Vec<LandXmlPipeInvert>,
151 pub flow: Option<LandXmlPipeFlow>,
152}
153
154#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
156pub struct LandXmlPipeConnectivity {
157 pub start_structure_source_id: LandXmlSourceId,
158 pub end_structure_source_id: LandXmlSourceId,
159}
160
161#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
166#[serde(tag = "kind", rename_all = "snake_case")]
167pub enum LandXmlPipeGeometry {
168 Straight,
169 PassThrough { point: LandXmlPipePosition },
170}
171
172#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
174pub struct LandXmlPipe {
175 pub source_id: LandXmlSourceId,
176 pub source_path: String,
177 pub name: String,
178 pub properties: LandXmlPipeProperties,
179 pub units: LandXmlPipeUnits,
181 pub connectivity: LandXmlPipeConnectivity,
182 pub part: LandXmlPipePart,
183 pub geometry: LandXmlPipeGeometry,
184 pub length: Option<LandXmlPipeMeasure>,
185 pub flow: Option<LandXmlPipeFlow>,
186}
187
188#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
190pub struct LandXmlPipeRefusal {
191 pub source_id: LandXmlSourceId,
192 pub source_path: String,
193 pub code: LandXmlDiagnosticCode,
194 pub message: String,
195}
196
197#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
199pub struct LandXmlPipeFeature {
200 pub source_id: LandXmlSourceId,
201 pub source_path: String,
202 pub owner_source_id: LandXmlSourceId,
203 pub properties: LandXmlPipeProperties,
204}
205
206#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
208pub struct LandXmlPipeNetworkCollection {
209 pub source_id: LandXmlSourceId,
210 pub source_path: String,
211 pub properties: LandXmlPipeProperties,
212}
213
214#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
216pub struct LandXmlPipeNetwork {
217 pub source_id: LandXmlSourceId,
218 pub source_path: String,
219 pub name: String,
220 pub pipe_network_type: String,
221 pub properties: LandXmlPipeProperties,
222 pub features: Vec<LandXmlPipeFeature>,
223 pub structure_units: Option<LandXmlPipeUnits>,
224 pub pipe_units: Option<LandXmlPipeUnits>,
225 pub structures: Vec<LandXmlPipeStructure>,
226 pub pipes: Vec<LandXmlPipe>,
227}
228
229#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
231pub struct LandXmlPipeNetworkDocument {
232 pub schema: String,
235 pub version: String,
236 pub capability_diagnostics: Vec<crate::LandXmlCapabilityDiagnostic>,
238 pub root_units: Option<LandXmlPipeUnits>,
239 pub collections: Vec<LandXmlPipeNetworkCollection>,
240 pub features: Vec<LandXmlPipeFeature>,
242 pub networks: Vec<LandXmlPipeNetwork>,
243 pub refusals: Vec<LandXmlPipeRefusal>,
244}
245
246impl LandXmlPipeNetworkDocument {
247 pub(crate) fn into_stream_parts(
249 self,
250 preflight_refusal_batches: Vec<Vec<usize>>,
251 ) -> crate::stream::metadata::PipeStreamParts {
252 crate::stream::metadata::PipeStreamParts::new(self, preflight_refusal_batches)
253 }
254}
255
256#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
262pub struct LandXmlPipeSourceBatch {
263 pub source_ids: Vec<LandXmlSourceId>,
264}
265
266impl LandXmlPipeNetworkDocument {
267 pub fn source_batches(&self, max_records: usize) -> Vec<LandXmlPipeSourceBatch> {
270 if max_records == 0 {
271 return Vec::new();
272 }
273 let source_ids = self
274 .collections
275 .iter()
276 .map(|collection| collection.source_id.clone())
277 .chain(
278 self.features
279 .iter()
280 .map(|feature| feature.source_id.clone()),
281 )
282 .chain(self.networks.iter().flat_map(|network| {
283 std::iter::once(network.source_id.clone())
284 .chain(network.structures.iter().flat_map(|structure| {
285 std::iter::once(structure.source_id.clone())
286 .chain(
287 structure
288 .inverts
289 .iter()
290 .map(|invert| invert.source_id.clone()),
291 )
292 .chain(structure.flow.iter().map(|flow| flow.source_id.clone()))
293 }))
294 .chain(network.pipes.iter().flat_map(|pipe| {
295 std::iter::once(pipe.source_id.clone())
296 .chain(pipe.flow.iter().map(|flow| flow.source_id.clone()))
297 }))
298 }));
299 let mut batches = Vec::new();
300 let mut current = Vec::new();
301 for source_id in source_ids {
302 current.push(source_id);
303 if current.len() == max_records {
304 batches.push(LandXmlPipeSourceBatch {
305 source_ids: current,
306 });
307 current = Vec::new();
308 }
309 }
310 if !current.is_empty() {
311 batches.push(LandXmlPipeSourceBatch {
312 source_ids: current,
313 });
314 }
315 batches
316 }
317}