oxihuman_export/
landxml_export.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct LandXmlSurface {
10 pub name: String,
11 pub verts: Vec<[f64; 3]>,
12 pub tris: Vec<[u32; 3]>,
13}
14
15#[derive(Debug, Clone)]
17pub struct LandXmlAlignment {
18 pub name: String,
19 pub sta_start: f64,
20 pub sta_end: f64,
21 pub points: Vec<[f64; 3]>,
22}
23
24#[derive(Debug, Clone, Default)]
26pub struct LandXmlExport {
27 pub version: String,
28 pub surfaces: Vec<LandXmlSurface>,
29 pub alignments: Vec<LandXmlAlignment>,
30}
31
32pub fn new_landxml_export(version: &str) -> LandXmlExport {
34 LandXmlExport {
35 version: version.to_string(),
36 surfaces: Vec::new(),
37 alignments: Vec::new(),
38 }
39}
40
41pub fn add_landxml_surface(
43 export: &mut LandXmlExport,
44 name: &str,
45 verts: Vec<[f64; 3]>,
46 tris: Vec<[u32; 3]>,
47) {
48 export.surfaces.push(LandXmlSurface {
49 name: name.to_string(),
50 verts,
51 tris,
52 });
53}
54
55pub fn add_landxml_alignment(
57 export: &mut LandXmlExport,
58 name: &str,
59 sta_start: f64,
60 sta_end: f64,
61 points: Vec<[f64; 3]>,
62) {
63 export.alignments.push(LandXmlAlignment {
64 name: name.to_string(),
65 sta_start,
66 sta_end,
67 points,
68 });
69}
70
71pub fn landxml_surface_count(export: &LandXmlExport) -> usize {
73 export.surfaces.len()
74}
75
76pub fn landxml_alignment_count(export: &LandXmlExport) -> usize {
78 export.alignments.len()
79}
80
81pub fn landxml_xml_header(export: &LandXmlExport) -> String {
83 format!(
84 "<LandXML version=\"{}\" xmlns=\"http://www.landxml.org/schema/LandXML-{}\">",
85 export.version, export.version
86 )
87}
88
89pub fn validate_landxml(export: &LandXmlExport) -> bool {
91 export.surfaces.iter().all(|s| {
92 let n = s.verts.len() as u32;
93 s.tris.iter().all(|t| t[0] < n && t[1] < n && t[2] < n)
94 })
95}
96
97pub fn landxml_total_tris(export: &LandXmlExport) -> usize {
99 export.surfaces.iter().map(|s| s.tris.len()).sum()
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 fn simple_tin() -> (Vec<[f64; 3]>, Vec<[u32; 3]>) {
107 let v = vec![
108 [0.0, 0.0, 0.0],
109 [1.0, 0.0, 1.0],
110 [0.0, 1.0, 0.5],
111 [1.0, 1.0, 1.5],
112 ];
113 let t = vec![[0, 1, 2], [1, 3, 2]];
114 (v, t)
115 }
116
117 #[test]
118 fn test_new_export_empty() {
119 let exp = new_landxml_export("1.2");
120 assert_eq!(landxml_surface_count(&exp), 0);
121 }
122
123 #[test]
124 fn test_add_surface() {
125 let mut exp = new_landxml_export("1.2");
126 let (v, t) = simple_tin();
127 add_landxml_surface(&mut exp, "Ground", v, t);
128 assert_eq!(landxml_surface_count(&exp), 1);
129 }
130
131 #[test]
132 fn test_add_alignment() {
133 let mut exp = new_landxml_export("1.2");
134 add_landxml_alignment(
135 &mut exp,
136 "Road1",
137 0.0,
138 100.0,
139 vec![[0.0, 0.0, 0.0], [100.0, 0.0, 0.0]],
140 );
141 assert_eq!(landxml_alignment_count(&exp), 1);
142 }
143
144 #[test]
145 fn test_header_contains_version() {
146 let exp = new_landxml_export("1.2");
147 assert!(landxml_xml_header(&exp).contains("1.2"));
148 }
149
150 #[test]
151 fn test_validate_valid() {
152 let mut exp = new_landxml_export("1.2");
153 let (v, t) = simple_tin();
154 add_landxml_surface(&mut exp, "G", v, t);
155 assert!(validate_landxml(&exp));
156 }
157
158 #[test]
159 fn test_total_tris() {
160 let mut exp = new_landxml_export("1.2");
161 let (v, t) = simple_tin();
162 add_landxml_surface(&mut exp, "G", v, t);
163 assert_eq!(landxml_total_tris(&exp), 2);
164 }
165
166 #[test]
167 fn test_validate_empty() {
168 assert!(validate_landxml(&new_landxml_export("1.2")));
169 }
170
171 #[test]
172 fn test_version_stored() {
173 let exp = new_landxml_export("2.0");
174 assert_eq!(exp.version, "2.0");
175 }
176
177 #[test]
178 fn test_alignment_stations() {
179 let mut exp = new_landxml_export("1.2");
180 add_landxml_alignment(&mut exp, "R", 100.0, 500.0, vec![]);
181 assert!((exp.alignments[0].sta_start - 100.0).abs() < 1e-9);
182 assert!((exp.alignments[0].sta_end - 500.0).abs() < 1e-9);
183 }
184}