1use serde::{Deserialize, Serialize};
11use std::fmt;
12
13use crate::LandXmlSourceId;
14
15#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
17pub struct LandXmlAlignment {
18 pub source_id: LandXmlSourceId,
19 pub ordinal: usize,
20 pub name: String,
21 pub length: f64,
22 pub sta_start: f64,
24 pub profile_source_ids: Vec<LandXmlSourceId>,
25 pub cross_section_source_ids: Vec<LandXmlSourceId>,
26}
27
28#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
30#[serde(rename_all = "snake_case")]
31pub enum LandXmlProfileKind {
32 Design,
33 Sampled,
34}
35
36#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
38pub struct LandXmlProfile {
39 pub source_id: LandXmlSourceId,
40 pub parent_alignment_source_id: LandXmlSourceId,
41 pub ordinal: usize,
42 pub name: String,
43 pub kind: LandXmlProfileKind,
44 pub pvis: Vec<LandXmlProfilePoint>,
45 pub vertical_curves: Vec<LandXmlVerticalCurve>,
46 pub grade_lines: Vec<LandXmlGradeLine>,
49}
50
51#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
53pub struct LandXmlProfilePoint {
54 pub source_id: LandXmlSourceId,
55 pub station: f64,
56 pub elevation: Option<f64>,
58}
59
60#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
62pub struct LandXmlGradeLine {
63 pub source_id: LandXmlSourceId,
64 pub parent_profile_source_id: LandXmlSourceId,
65 pub ordinal: usize,
66 pub points: Vec<LandXmlProfilePoint>,
67}
68
69#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
71#[serde(rename_all = "snake_case")]
72pub enum LandXmlVerticalCurveKind {
73 Parabolic,
74 UnsymmetricalParabolic,
75 Circular,
76}
77
78#[derive(Clone, Debug, Eq, PartialEq)]
84pub enum LandXmlProfileEvaluationError {
85 MissingTangentPvi,
86 InvalidCurveDeclaration,
87 InconsistentCircularCurve,
88 NonFiniteEvaluation,
89}
90
91impl fmt::Display for LandXmlProfileEvaluationError {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 f.write_str(match self {
94 Self::MissingTangentPvi => "vertical curve requires finite PVIs on both tangents",
95 Self::InvalidCurveDeclaration => "vertical curve has an invalid length or radius",
96 Self::InconsistentCircularCurve => {
97 "circular curve radius, length, and tangent grades disagree"
98 }
99 Self::NonFiniteEvaluation => "vertical alignment produces a non-finite elevation",
100 })
101 }
102}
103
104impl std::error::Error for LandXmlProfileEvaluationError {}
105
106#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
108pub struct LandXmlVerticalCurve {
109 pub source_id: LandXmlSourceId,
110 pub parent_profile_source_id: LandXmlSourceId,
111 pub kind: LandXmlVerticalCurveKind,
112 pub station: f64,
113 pub elevation: Option<f64>,
114 pub length: Option<f64>,
115 pub length_in: Option<f64>,
116 pub length_out: Option<f64>,
117 pub radius: Option<f64>,
118}
119
120#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
122pub struct LandXmlCrossSection {
123 pub source_id: LandXmlSourceId,
124 pub parent_alignment_source_id: LandXmlSourceId,
125 pub ordinal: usize,
126 pub station: f64,
127 pub surface_source_ids: Vec<LandXmlSourceId>,
128}
129
130#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
132#[serde(rename_all = "snake_case")]
133pub enum LandXmlCrossSectionSurfaceKind {
134 Sampled,
135 Design,
136}
137
138#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
140pub struct LandXmlCrossSectionSurface {
141 pub source_id: LandXmlSourceId,
142 pub parent_cross_section_source_id: LandXmlSourceId,
143 pub kind: LandXmlCrossSectionSurfaceKind,
144 pub name: Option<String>,
145 pub segments: Vec<LandXmlCrossSectionSegment>,
146 pub points: Vec<LandXmlCrossSectionPoint>,
147}
148
149#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
151pub struct LandXmlCrossSectionSegment {
152 pub source_id: LandXmlSourceId,
153 pub parent_surface_source_id: LandXmlSourceId,
154 pub ordinal: usize,
155 pub points: Vec<LandXmlCrossSectionPoint>,
156}
157
158#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
160#[serde(rename_all = "snake_case")]
161pub enum LandXmlCrossSectionPointDataFormat {
162 OffsetElevation,
163 SlopeDistance,
164}
165
166#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
172pub struct LandXmlCrossSectionPoint {
173 pub source_id: LandXmlSourceId,
174 pub data_format: LandXmlCrossSectionPointDataFormat,
175 pub offset: Option<f64>,
176 pub elevation: Option<f64>,
178 pub slope: Option<f64>,
179 pub distance: Option<f64>,
180 pub pnt_ref: Option<String>,
181 pub alignment_ref: Option<String>,
182 pub align_ref_station: Option<f64>,
183 pub alignment_source_id: Option<LandXmlSourceId>,
184 pub plan_feature_ref: Option<String>,
185 pub plan_feature_ref_station: Option<f64>,
186 pub parcel_ref: Option<String>,
187 pub parcel_ref_station: Option<f64>,
188}
189
190#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
192pub struct LandXmlRoadway {
193 pub source_id: LandXmlSourceId,
194 pub ordinal: usize,
195 pub name: String,
196 pub alignment_refs: Vec<String>,
197 pub alignment_source_ids: Vec<LandXmlSourceId>,
198 pub surface_refs: Vec<String>,
199 pub surface_source_ids: Vec<LandXmlSourceId>,
200 pub grade_model_refs: Vec<String>,
201}
202
203#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
205pub struct LandXmlCapabilityDiagnostic {
206 pub code: LandXmlCapabilityDiagnosticCode,
207 pub source_id: Option<LandXmlSourceId>,
208 pub source_path: String,
209 pub message: String,
210}
211
212#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
214#[serde(rename_all = "snake_case")]
215pub enum LandXmlCapabilityDiagnosticCode {
216 SchemaVersionMismatch,
217 MissingElevation,
218 MissingReference,
219 AmbiguousReference,
220 UnsupportedGradeModelReference,
221 UnresolvedPointReference,
222 UnsupportedPlanFeatureReference,
223 UnsupportedParcelReference,
224 UnsupportedSlopeDistance,
225 SectionDiscontinuity,
226 UnsupportedCorridorExtension,
227 UnsupportedStringLineExtension,
228}
229
230#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
232pub struct LandXmlPreservedOnlyExtension {
233 pub source_id: LandXmlSourceId,
234 pub parent_source_id: Option<LandXmlSourceId>,
235 pub local_name: String,
236 pub source_path: String,
237 pub kind: LandXmlPreservedOnlyExtensionKind,
238}
239
240#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
242#[serde(rename_all = "snake_case")]
243pub enum LandXmlPreservedOnlyExtensionKind {
244 Corridor,
245 StringLine,
246}