1use serde::{Deserialize, Serialize};
6use std::{collections::BTreeMap, fmt};
7
8pub type LandXmlProperties = BTreeMap<String, String>;
9
10#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
12pub enum LandXmlDiagnosticCode {
13 InputTooLarge,
14 DtdForbidden,
15 EntityForbidden,
16 LimitExceeded,
17 Cancelled,
18 InvalidXml,
19 UnsupportedNamespace,
20 UnsupportedVersion,
21 InvalidSemantic,
22}
23
24impl LandXmlDiagnosticCode {
25 pub const fn as_str(self) -> &'static str {
26 match self {
27 Self::InputTooLarge => "LXML001",
28 Self::DtdForbidden => "LXML002",
29 Self::EntityForbidden => "LXML003",
30 Self::LimitExceeded => "LXML004",
31 Self::Cancelled => "LXML005",
32 Self::InvalidXml => "LXML006",
33 Self::UnsupportedNamespace => "LXML007",
34 Self::UnsupportedVersion => "LXML008",
35 Self::InvalidSemantic => "LXML009",
36 }
37 }
38}
39
40#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
42pub struct LandXmlError {
43 pub code: LandXmlDiagnosticCode,
44 pub message: String,
45}
46
47impl LandXmlError {
48 pub fn new(code: LandXmlDiagnosticCode, message: impl Into<String>) -> Self {
49 Self {
50 code,
51 message: message.into(),
52 }
53 }
54}
55
56impl fmt::Display for LandXmlError {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 write!(f, "{}: {}", self.code.as_str(), self.message)
59 }
60}
61
62impl std::error::Error for LandXmlError {}
63
64#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
70#[serde(rename_all = "snake_case")]
71pub enum LandXmlVersionCapability {
72 NotLandXml,
73 LandXml10Unsupported,
75 LandXml11Unsupported,
77 LandXml10Tin,
78 LandXml11Tin,
79 LandXml12Tin,
80 LandXml10VersionMismatch,
81 LandXml11VersionMismatch,
82 LandXml12VersionMismatch,
83 LandXml12Unsupported,
85}
86
87impl LandXmlVersionCapability {
88 pub const fn supports_tin_ingestion(self) -> bool {
89 matches!(
90 self,
91 Self::LandXml10Tin
92 | Self::LandXml11Tin
93 | Self::LandXml12Tin
94 | Self::LandXml10VersionMismatch
95 | Self::LandXml11VersionMismatch
96 | Self::LandXml12VersionMismatch
97 )
98 }
99
100 pub const fn schema(self) -> Option<&'static str> {
101 match self {
102 Self::LandXml10Tin | Self::LandXml10VersionMismatch => Some("LandXML-1.0"),
103 Self::LandXml11Tin | Self::LandXml11VersionMismatch => Some("LandXML-1.1"),
104 Self::LandXml12Tin | Self::LandXml12VersionMismatch => Some("LandXML-1.2"),
105 Self::NotLandXml
106 | Self::LandXml10Unsupported
107 | Self::LandXml11Unsupported
108 | Self::LandXml12Unsupported => None,
109 }
110 }
111
112 pub const fn has_compatibility_version_mismatch(self) -> bool {
113 matches!(
114 self,
115 Self::LandXml10VersionMismatch
116 | Self::LandXml11VersionMismatch
117 | Self::LandXml12VersionMismatch
118 )
119 }
120}
121
122#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
124#[serde(transparent)]
125pub struct LandXmlSourceId(pub String);
126
127#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
128pub struct LandXmlPoint {
129 pub source_id: LandXmlSourceId,
131 pub id: String,
132 pub northing: f64,
133 pub easting: f64,
134 pub elevation: f64,
135}
136
137#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
144pub struct LandXmlCanonicalVertex {
145 pub id: String,
146 pub northing: f64,
147 pub easting: f64,
148 pub elevation: f64,
149 pub contributor_source_ids: Vec<LandXmlSourceId>,
150}
151
152#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
154pub struct LandXmlSourcePoint {
155 pub source_id: LandXmlSourceId,
156 pub ordinal: usize,
157 pub source_path: String,
158 pub coordinate_dimension: u8,
159 pub coordinates: Vec<f64>,
160}
161
162#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
168#[serde(rename_all = "snake_case")]
169pub enum LandXmlSurfaceKind {
170 Tin,
171 Grid,
172 Volume,
173 Other,
174}
175
176#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
178#[serde(rename_all = "snake_case")]
179pub enum LandXmlRenderState {
180 Rendered,
182 PreservedOnly,
184 Unsupported,
186}
187
188#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
190#[serde(rename_all = "snake_case")]
191pub enum LandXmlTopologyOrigin {
192 AuthoredFaces,
193 ConstrainedTriangulation,
194 PreservedOnly,
195}
196
197#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
199#[serde(rename_all = "snake_case")]
200pub enum LandXmlTerrainDiagnosticCode {
201 MissingOuterBoundary,
202 UnsupportedBoundarySemantics,
203 UnsupportedBreaklineSemantics,
204 MissingElevation,
205 ConflictingElevation,
206 IntersectingConstraints,
207 DegenerateConstraints,
208 WorkLimitExceeded,
209 Cancelled,
210}
211
212impl LandXmlTerrainDiagnosticCode {
213 pub const fn as_str(self) -> &'static str {
214 match self {
215 Self::MissingOuterBoundary => "LXMLT001",
216 Self::UnsupportedBoundarySemantics => "LXMLT002",
217 Self::UnsupportedBreaklineSemantics => "LXMLT003",
218 Self::MissingElevation => "LXMLT004",
219 Self::ConflictingElevation => "LXMLT005",
220 Self::IntersectingConstraints => "LXMLT006",
221 Self::DegenerateConstraints => "LXMLT007",
222 Self::WorkLimitExceeded => "LXMLT008",
223 Self::Cancelled => "LXMLT009",
224 }
225 }
226}
227
228#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
230pub struct LandXmlTerrainDiagnostic {
231 pub code: LandXmlTerrainDiagnosticCode,
232 pub message: String,
233}
234
235#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
237pub struct LandXmlPolyline {
238 pub source_id: LandXmlSourceId,
239 pub ordinal: usize,
241 pub name: Option<String>,
242 pub kind: Option<String>,
244 pub source_path: String,
245 pub properties: LandXmlProperties,
246 pub coordinate_dimension: u8,
248 pub points: Vec<Vec<f64>>,
249 pub point_source_ids: Vec<LandXmlSourceId>,
253}
254
255#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
257pub struct LandXmlExtension {
258 pub namespace: String,
259 pub local_name: String,
260 pub path: String,
261}
262
263#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
264pub struct LandXmlSurface {
265 pub source_id: LandXmlSourceId,
266 pub ordinal: usize,
268 pub source_path: String,
269 pub properties: LandXmlProperties,
270 pub definition_properties: LandXmlProperties,
271 pub name: String,
272 pub kind: LandXmlSurfaceKind,
273 pub render_state: LandXmlRenderState,
274 pub topology_origin: LandXmlTopologyOrigin,
275 pub terrain_diagnostic: Option<LandXmlTerrainDiagnostic>,
278 pub points: Vec<LandXmlPoint>,
279 pub canonical_vertices: Vec<LandXmlCanonicalVertex>,
282 pub source_data_points: Vec<LandXmlSourcePoint>,
283 pub faces: Vec<[String; 3]>,
284 pub face_source_ids: Vec<LandXmlSourceId>,
287 pub face_visibility: Vec<bool>,
290 pub hidden_face_count: usize,
291 pub boundaries: Vec<LandXmlPolyline>,
292 pub breaklines: Vec<LandXmlPolyline>,
293 pub contours: Vec<LandXmlPolyline>,
294}
295
296#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
297pub struct LandXmlUnits {
298 pub linear_unit: String,
299 pub elevation_unit: String,
300 pub linear_scale_to_meters: f64,
301 pub elevation_scale_to_meters: f64,
302 pub assumed: bool,
309}
310
311#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
318#[non_exhaustive]
319pub struct LandXmlCoordinateSystem {
320 pub horizontal_datum: Option<String>,
321 pub vertical_datum: Option<String>,
322 #[serde(default)]
327 pub epsg_code: Option<String>,
328 #[serde(default)]
334 pub name: Option<String>,
335}
336
337#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
338pub struct LandXmlTinDocument {
339 pub format: String,
340 pub schema: String,
341 pub capabilities: LandXmlCapabilities,
342 pub version: String,
343 pub units: Option<LandXmlUnits>,
347 pub coordinate_system: Option<LandXmlCoordinateSystem>,
348 pub surfaces: Vec<LandXmlSurface>,
349 pub extensions: Vec<LandXmlExtension>,
350 pub warnings: Vec<String>,
351 pub alignments: Vec<crate::LandXmlAlignment>,
353 pub profiles: Vec<crate::LandXmlProfile>,
355 pub cross_sections: Vec<crate::LandXmlCrossSection>,
356 pub cross_section_surfaces: Vec<crate::LandXmlCrossSectionSurface>,
357 pub roadways: Vec<crate::LandXmlRoadway>,
358 pub capability_diagnostics: Vec<crate::LandXmlCapabilityDiagnostic>,
359 pub preserved_only_extensions: Vec<crate::LandXmlPreservedOnlyExtension>,
360 pub pipe_networks: Option<crate::LandXmlPipeNetworkDocument>,
363}
364
365impl LandXmlTinDocument {
366 pub(crate) fn into_stream_parts(self) -> crate::stream::metadata::TerrainStreamParts {
368 crate::stream::metadata::TerrainStreamParts::new(self)
369 }
370}
371
372#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
373pub struct LandXmlCapabilities {
374 pub renderable_tin: bool,
375 pub preserved_only_surfaces: usize,
376 pub unknown_extensions: usize,
377}