1use std::io::{Read, Write};
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4
5use super::traits::{HasM, HasMutM, HasMutXY, HasMutZ, HasXY, HasZ};
6use super::{GenericBBox, PointZ, NO_DATA};
7use super::{Point, PointM};
8
9pub(crate) fn bbox_read_xy_from<PointType: HasMutXY, R: Read>(
10 bbox: &mut GenericBBox<PointType>,
11 src: &mut R,
12) -> std::io::Result<()> {
13 *bbox.min.x_mut() = src.read_f64::<LittleEndian>()?;
14 *bbox.min.y_mut() = src.read_f64::<LittleEndian>()?;
15 *bbox.max.x_mut() = src.read_f64::<LittleEndian>()?;
16 *bbox.max.y_mut() = src.read_f64::<LittleEndian>()?;
17 Ok(())
18}
19
20pub(crate) fn bbox_write_xy_to<PointType: HasXY, W: Write>(
21 bbox: &GenericBBox<PointType>,
22 dst: &mut W,
23) -> std::io::Result<()> {
24 dst.write_f64::<LittleEndian>(bbox.min.x())?;
25 dst.write_f64::<LittleEndian>(bbox.min.y())?;
26 dst.write_f64::<LittleEndian>(bbox.max.x())?;
27 dst.write_f64::<LittleEndian>(bbox.max.y())?;
28 Ok(())
29}
30
31pub(crate) fn bbox_read_m_range_from<PointType: HasMutM, R: Read>(
32 bbox: &mut GenericBBox<PointType>,
33 src: &mut R,
34) -> std::io::Result<()> {
35 *bbox.min.m_mut() = src.read_f64::<LittleEndian>()?;
36 *bbox.max.m_mut() = src.read_f64::<LittleEndian>()?;
37 Ok(())
38}
39
40pub(crate) fn bbox_read_z_range_from<PointType: HasMutZ, R: Read>(
41 bbox: &mut GenericBBox<PointType>,
42 src: &mut R,
43) -> std::io::Result<()> {
44 *bbox.min.z_mut() = src.read_f64::<LittleEndian>()?;
45 *bbox.max.z_mut() = src.read_f64::<LittleEndian>()?;
46 Ok(())
47}
48
49pub(crate) fn bbox_write_m_range_to<PointType: HasM, W: Write>(
50 bbox: &GenericBBox<PointType>,
51 dst: &mut W,
52) -> std::io::Result<()> {
53 dst.write_f64::<LittleEndian>(bbox.min.m())?;
54 dst.write_f64::<LittleEndian>(bbox.max.m())?;
55 Ok(())
56}
57
58pub(crate) fn bbox_write_z_range_to<PointType: HasZ, W: Write>(
59 bbox: &GenericBBox<PointType>,
60 dst: &mut W,
61) -> std::io::Result<()> {
62 dst.write_f64::<LittleEndian>(bbox.min.z())?;
63 dst.write_f64::<LittleEndian>(bbox.max.z())?;
64 Ok(())
65}
66
67pub(crate) fn read_xy_in_vec_of<PointType, T>(
68 source: &mut T,
69 num_points: i32,
70) -> Result<Vec<PointType>, std::io::Error>
71where
72 PointType: HasMutXY + Default,
73 T: Read,
74{
75 let mut points = Vec::<PointType>::with_capacity(num_points as usize);
76 for _ in 0..num_points {
77 let mut p = PointType::default();
78 *p.x_mut() = source.read_f64::<LittleEndian>()?;
79 *p.y_mut() = source.read_f64::<LittleEndian>()?;
80 points.push(p);
81 }
82 Ok(points)
83}
84
85pub(crate) fn read_ms_into<T: Read, D: HasMutM>(
86 source: &mut T,
87 points: &mut [D],
88) -> Result<(), std::io::Error> {
89 for point in points {
90 *point.m_mut() = f64::max(source.read_f64::<LittleEndian>()?, NO_DATA);
91 }
92 Ok(())
93}
94
95pub(crate) fn read_zs_into<T: Read>(
96 source: &mut T,
97 points: &mut [PointZ],
98) -> Result<(), std::io::Error> {
99 for point in points {
100 point.z = source.read_f64::<LittleEndian>()?;
101 }
102 Ok(())
103}
104
105pub(crate) fn read_parts<T: Read>(
106 source: &mut T,
107 num_parts: i32,
108) -> Result<Vec<i32>, std::io::Error> {
109 let mut parts = Vec::<i32>::with_capacity(num_parts as usize);
110 for _ in 0..num_parts {
111 parts.push(source.read_i32::<LittleEndian>()?);
112 }
113 Ok(parts)
114}
115
116pub(crate) fn write_points<T: Write, PointType: HasXY>(
117 dest: &mut T,
118 points: &[PointType],
119) -> Result<(), std::io::Error> {
120 for point in points {
121 dest.write_f64::<LittleEndian>(point.x())?;
122 dest.write_f64::<LittleEndian>(point.y())?;
123 }
124 Ok(())
125}
126
127pub(crate) fn write_ms<T: Write, PointType: HasM>(
128 dest: &mut T,
129 points: &[PointType],
130) -> Result<(), std::io::Error> {
131 for point in points {
132 dest.write_f64::<LittleEndian>(point.m())?;
133 }
134 Ok(())
135}
136
137pub(crate) fn write_zs<T: Write>(dest: &mut T, points: &[PointZ]) -> Result<(), std::io::Error> {
138 for point in points {
139 dest.write_f64::<LittleEndian>(point.z)?;
140 }
141 Ok(())
142}
143
144struct PartIndexIter<'a> {
145 parts_indices: &'a Vec<i32>,
146 current_part_index: usize,
147 num_points: i32,
148}
149
150impl<'a> PartIndexIter<'a> {
151 fn new(parts_indices: &'a Vec<i32>, num_points: i32) -> Self {
152 Self {
153 parts_indices,
154 current_part_index: 0,
155 num_points,
156 }
157 }
158}
159
160impl Iterator for PartIndexIter<'_> {
161 type Item = (i32, i32);
162
163 fn next(&mut self) -> Option<Self::Item> {
164 if self.current_part_index < self.parts_indices.len() {
165 let start_of_part_index = self.parts_indices[self.current_part_index];
166 let end_of_part_index = self
167 .parts_indices
168 .get(self.current_part_index + 1)
169 .copied()
170 .unwrap_or(self.num_points);
171 self.current_part_index += 1;
172 debug_assert!(end_of_part_index >= start_of_part_index);
173 Some((start_of_part_index, end_of_part_index))
174 } else {
175 None
176 }
177 }
178
179 fn size_hint(&self) -> (usize, Option<usize>) {
180 if self.num_points < 0 {
181 (0, None)
182 } else {
183 let remaining = self.parts_indices.len() - self.current_part_index;
184 (remaining, Some(remaining))
185 }
186 }
187}
188
189pub(crate) struct MultiPartShapeReader<'a, PointType, R: Read> {
190 pub(crate) num_points: i32,
191 pub(crate) num_parts: i32,
192 pub(crate) parts: Vec<Vec<PointType>>,
193 pub(crate) bbox: GenericBBox<PointType>,
194 pub(crate) source: &'a mut R,
195 parts_array: Vec<i32>,
196}
197
198impl<'a, PointType: Default + HasMutXY, R: Read> MultiPartShapeReader<'a, PointType, R> {
199 pub(crate) fn new(source: &'a mut R) -> std::io::Result<Self> {
200 let mut bbox = GenericBBox::<PointType>::default();
201 bbox_read_xy_from(&mut bbox, source)?;
202 let num_parts = source.read_i32::<LittleEndian>()?;
203 let num_points = source.read_i32::<LittleEndian>()?;
204 let parts_array = read_parts(source, num_parts)?;
205 let parts = Vec::<Vec<PointType>>::with_capacity(num_parts as usize);
206 Ok(Self {
207 num_points,
208 num_parts,
209 parts_array,
210 parts,
211 source,
212 bbox,
213 })
214 }
215
216 pub(crate) fn read_xy(mut self) -> std::io::Result<Self> {
217 for (start_index, end_index) in PartIndexIter::new(&self.parts_array, self.num_points) {
218 let num_points_in_part = end_index - start_index;
219 self.parts
220 .push(read_xy_in_vec_of(self.source, num_points_in_part)?);
221 }
222 Ok(self)
223 }
224}
225
226impl<PointType: HasMutM, R: Read> MultiPartShapeReader<'_, PointType, R> {
227 pub(crate) fn read_ms(mut self) -> std::io::Result<Self> {
228 bbox_read_m_range_from(&mut self.bbox, &mut self.source)?;
229 for part_points in self.parts.iter_mut() {
230 read_ms_into(self.source, part_points)?;
231 }
232 Ok(self)
233 }
234
235 pub(crate) fn read_ms_if(self, condition: bool) -> std::io::Result<Self> {
236 if condition {
237 self.read_ms()
238 } else {
239 Ok(self)
240 }
241 }
242}
243
244impl<R: Read> MultiPartShapeReader<'_, PointZ, R> {
245 pub(crate) fn read_zs(mut self) -> std::io::Result<Self> {
246 bbox_read_z_range_from(&mut self.bbox, &mut self.source)?;
247 for part_points in self.parts.iter_mut() {
248 read_zs_into(self.source, part_points)?;
249 }
250 Ok(self)
251 }
252}
253
254pub(crate) struct MultiPartShapeWriter<'a, PointType, T, W>
255where
256 T: Iterator<Item = &'a [PointType]> + Clone,
257 W: Write,
258{
259 pub(crate) dst: &'a mut W,
260 parts_iter: T,
261 bbox: &'a GenericBBox<PointType>,
262}
263
264impl<'a, PointType, T, W> MultiPartShapeWriter<'a, PointType, T, W>
265where
266 T: Iterator<Item = &'a [PointType]> + Clone,
267 W: Write,
268{
269 pub(crate) fn new(bbox: &'a GenericBBox<PointType>, parts_iter: T, dst: &'a mut W) -> Self {
270 Self {
271 parts_iter,
272 bbox,
273 dst,
274 }
275 }
276
277 pub(crate) fn write_num_points(self) -> std::io::Result<Self> {
278 let point_count: usize = self.parts_iter.clone().map(|points| points.len()).sum();
279 self.dst.write_i32::<LittleEndian>(point_count as i32)?;
280 Ok(self)
281 }
282
283 pub(crate) fn write_num_parts(self) -> std::io::Result<Self> {
284 let num_parts = self.parts_iter.clone().count();
285 self.dst.write_i32::<LittleEndian>(num_parts as i32)?;
286 Ok(self)
287 }
288
289 pub(crate) fn write_parts_array(self) -> std::io::Result<Self> {
290 let mut sum = 0;
291 for i in self.parts_iter.clone().map(|points| points.len() as i32) {
292 self.dst.write_i32::<LittleEndian>(sum)?;
293 sum += i;
294 }
295 Ok(self)
296 }
297}
298
299impl<'a, PointType, T, W> MultiPartShapeWriter<'a, PointType, T, W>
300where
301 T: Iterator<Item = &'a [PointType]> + Clone,
302 W: Write,
303 PointType: HasXY,
304{
305 pub(crate) fn write_bbox_xy(self) -> std::io::Result<Self> {
306 bbox_write_xy_to(self.bbox, self.dst)?;
307 Ok(self)
308 }
309
310 pub(crate) fn write_xy(self) -> std::io::Result<Self> {
311 for points in self.parts_iter.clone() {
312 write_points(self.dst, points)?;
313 }
314 Ok(self)
315 }
316}
317
318impl<'a, PointType, T, W> MultiPartShapeWriter<'a, PointType, T, W>
319where
320 T: Iterator<Item = &'a [PointType]> + Clone,
321 W: Write,
322 PointType: HasM,
323{
324 pub(crate) fn write_bbox_m_range(self) -> std::io::Result<Self> {
325 bbox_write_m_range_to(self.bbox, self.dst)?;
326 Ok(self)
327 }
328
329 pub(crate) fn write_ms(self) -> std::io::Result<Self> {
330 for points in self.parts_iter.clone() {
331 write_ms(self.dst, points)?;
332 }
333 Ok(self)
334 }
335}
336
337impl<'a, T, W> MultiPartShapeWriter<'a, PointZ, T, W>
338where
339 T: Iterator<Item = &'a [PointZ]> + Clone,
340 W: Write,
341{
342 pub(crate) fn write_bbox_z_range(self) -> std::io::Result<Self> {
343 bbox_write_z_range_to(self.bbox, self.dst)?;
344 Ok(self)
345 }
346
347 pub(crate) fn write_zs(self) -> std::io::Result<Self> {
348 for points in self.parts_iter.clone() {
349 write_zs(self.dst, points)?;
350 }
351 Ok(self)
352 }
353}
354
355impl<'a, T, W> MultiPartShapeWriter<'a, Point, T, W>
356where
357 T: Iterator<Item = &'a [Point]> + Clone,
358 W: Write,
359{
360 pub(crate) fn write_point_shape(self) -> std::io::Result<Self> {
361 self.write_bbox_xy()
362 .and_then(|wrt| wrt.write_num_parts())
363 .and_then(|wrt| wrt.write_num_points())
364 .and_then(|wrt| wrt.write_parts_array())
365 .and_then(|wrt| wrt.write_xy())
366 }
367}
368
369impl<'a, T, W> MultiPartShapeWriter<'a, PointM, T, W>
370where
371 T: Iterator<Item = &'a [PointM]> + Clone,
372 W: Write,
373{
374 pub(crate) fn write_point_m_shape(self) -> std::io::Result<Self> {
375 self.write_bbox_xy()
376 .and_then(|wrt| wrt.write_num_parts())
377 .and_then(|wrt| wrt.write_num_points())
378 .and_then(|wrt| wrt.write_parts_array())
379 .and_then(|wrt| wrt.write_xy())
380 .and_then(|wrt| wrt.write_bbox_m_range())
381 .and_then(|wrt| wrt.write_ms())
382 }
383}
384
385impl<'a, T, W> MultiPartShapeWriter<'a, PointZ, T, W>
386where
387 T: Iterator<Item = &'a [PointZ]> + Clone,
388 W: Write,
389{
390 pub(crate) fn write_point_z_shape(self) -> std::io::Result<Self> {
391 self.write_bbox_xy()
392 .and_then(|wrt| wrt.write_num_parts())
393 .and_then(|wrt| wrt.write_num_points())
394 .and_then(|wrt| wrt.write_parts_array())
395 .and_then(|wrt| wrt.write_xy())
396 .and_then(|wrt| wrt.write_bbox_z_range())
397 .and_then(|wrt| wrt.write_zs())
398 .and_then(|wrt| wrt.write_bbox_m_range())
399 .and_then(|wrt| wrt.write_ms())
400 }
401}