1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
3
4use std::fmt;
5use std::io::{Read, Seek, SeekFrom, Write};
6use std::mem::size_of;
7
8use super::io::*;
9use super::ConcreteReadableShape;
10use super::{close_points_if_not_already, GenericBBox};
11use super::{Error, ShapeType};
12use super::{EsriShape, HasShapeType, Point, PointZ, WritableShape};
13
14#[cfg(feature = "geo-types")]
15use geo_types;
16#[cfg(feature = "geo-types")]
17use std::convert::TryFrom;
18
19#[derive(Debug, Copy, Clone, PartialEq)]
20enum PatchType {
21 TriangleStrip,
22 TriangleFan,
23 OuterRing,
24 InnerRing,
25 FirstRing,
26 Ring,
27}
28
29impl PatchType {
30 pub fn read_from<T: Read>(source: &mut T) -> Result<PatchType, Error> {
31 let code = source.read_i32::<LittleEndian>()?;
32 Self::from(code).ok_or(Error::InvalidPatchType(code))
33 }
34
35 pub fn from(code: i32) -> Option<PatchType> {
36 match code {
37 0 => Some(PatchType::TriangleStrip),
38 1 => Some(PatchType::TriangleFan),
39 2 => Some(PatchType::OuterRing),
40 3 => Some(PatchType::InnerRing),
41 4 => Some(PatchType::FirstRing),
42 5 => Some(PatchType::Ring),
43 _ => None,
44 }
45 }
46}
47
48#[derive(Debug, Clone, PartialEq)]
49pub enum Patch {
50 TriangleStrip(Vec<PointZ>),
56 TriangleFan(Vec<PointZ>),
63 OuterRing(Vec<PointZ>),
65 InnerRing(Vec<PointZ>),
67 FirstRing(Vec<PointZ>),
69 Ring(Vec<PointZ>),
71}
72
73impl Patch {
74 #[inline]
76 pub fn points(&self) -> &[PointZ] {
77 match self {
78 Patch::TriangleStrip(points) => points,
79 Patch::TriangleFan(points) => points,
80 Patch::OuterRing(points) => points,
81 Patch::InnerRing(points) => points,
82 Patch::FirstRing(points) => points,
83 Patch::Ring(points) => points,
84 }
85 }
86}
87
88impl AsRef<[PointZ]> for Patch {
89 fn as_ref(&self) -> &[PointZ] {
90 self.points()
91 }
92}
93
94#[derive(Debug, PartialEq, Clone)]
107pub struct Multipatch {
108 bbox: GenericBBox<PointZ>,
109 patches: Vec<Patch>,
110}
111
112impl Multipatch {
113 pub fn new(patch: Patch) -> Self {
130 Self::with_parts(vec![patch])
131 }
132
133 pub fn with_parts(mut patches: Vec<Patch>) -> Self {
157 for patch in patches.iter_mut() {
158 match patch {
159 Patch::TriangleStrip(_) => {}
160 Patch::TriangleFan(_) => {}
161 Patch::OuterRing(points) => close_points_if_not_already(points),
162 Patch::InnerRing(points) => close_points_if_not_already(points),
163 Patch::FirstRing(points) => close_points_if_not_already(points),
164 Patch::Ring(points) => close_points_if_not_already(points),
165 }
166 }
167 let mut bbox = GenericBBox::<PointZ>::from_points(patches[0].points());
168 for patch in &patches[1..] {
169 bbox.grow_from_points(patch.points());
170 }
171
172 Self { bbox, patches }
173 }
174
175 #[inline]
177 pub fn bbox(&self) -> &GenericBBox<PointZ> {
178 &self.bbox
179 }
180
181 #[inline]
183 pub fn patches(&self) -> &Vec<Patch> {
184 &self.patches
185 }
186
187 #[inline]
189 pub fn patch(&self, index: usize) -> Option<&Patch> {
190 self.patches.get(index)
191 }
192
193 #[inline]
195 pub fn into_inner(self) -> Vec<Patch> {
196 self.patches
197 }
198
199 #[inline]
200 pub fn total_point_count(&self) -> usize {
201 self.patches.iter().map(|patch| patch.points().len()).sum()
202 }
203
204 pub(crate) fn size_of_record(num_points: i32, num_parts: i32, is_m_used: bool) -> usize {
205 let mut size = 0usize;
206 size += 4 * size_of::<f64>(); size += size_of::<i32>(); size += size_of::<i32>(); size += size_of::<i32>() * num_parts as usize; size += size_of::<i32>() * num_parts as usize; size += size_of::<Point>() * num_points as usize;
212 size += 2 * size_of::<f64>(); size += size_of::<f64>() * num_points as usize; if is_m_used {
216 size += 2 * size_of::<f64>(); size += size_of::<f64>() * num_points as usize; }
219 size
220 }
221}
222
223impl fmt::Display for Multipatch {
224 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225 write!(f, "Multipatch({} patches)", self.patches.len())
226 }
227}
228
229impl HasShapeType for Multipatch {
230 fn shapetype() -> ShapeType {
231 ShapeType::Multipatch
232 }
233}
234
235impl ConcreteReadableShape for Multipatch {
236 fn read_shape_content<T: Read + Seek>(source: &mut T, record_size: i32) -> Result<Self, Error> {
237 let reader = MultiPartShapeReader::<PointZ, T>::new(source)?;
238
239 let record_size_with_m =
240 Self::size_of_record(reader.num_points, reader.num_parts, true) as i32;
241 let record_size_without_m =
242 Self::size_of_record(reader.num_points, reader.num_parts, false) as i32;
243
244 let size_read = if record_size >= record_size_with_m {
245 record_size_with_m
246 } else {
247 record_size_without_m
248 };
249
250 let diff = record_size - size_read;
251 if diff < 0 {
252 return Err(Error::InvalidShapeRecordSize);
253 }
254
255 let mut patch_types = vec![PatchType::Ring; reader.num_parts as usize];
256 let mut patches = Vec::<Patch>::with_capacity(reader.num_parts as usize);
257 for i in 0..reader.num_parts {
258 patch_types[i as usize] = PatchType::read_from(reader.source)?;
259 }
260 let (bbox, patches_points) = reader
261 .read_xy()
262 .and_then(|rdr| rdr.read_zs())
263 .and_then(|rdr| rdr.read_ms_if(record_size >= record_size_with_m))
264 .map_err(Error::IoError)
265 .map(|rdr| (rdr.bbox, rdr.parts))?;
266
267 for (patch_type, points) in patch_types.iter().zip(patches_points) {
268 let patch = match patch_type {
269 PatchType::TriangleStrip => Patch::TriangleStrip(points),
270 PatchType::TriangleFan => Patch::TriangleFan(points),
271 PatchType::OuterRing => Patch::OuterRing(points),
272 PatchType::InnerRing => Patch::InnerRing(points),
273 PatchType::FirstRing => Patch::FirstRing(points),
274 PatchType::Ring => Patch::Ring(points),
275 };
276 patches.push(patch);
277 }
278
279 if diff > 0 {
280 source.seek(SeekFrom::Current(i64::from(diff)))?;
281 }
282 Ok(Self { bbox, patches })
283 }
284}
285
286impl WritableShape for Multipatch {
287 fn size_in_bytes(&self) -> usize {
288 let mut size = 0usize;
289 size += 4 * size_of::<f64>();
290 size += size_of::<i32>();
291 size += size_of::<i32>();
292 size += size_of::<i32>() * self.patches.len();
293 size += size_of::<i32>() * self.patches.len();
294 size += 4 * size_of::<f64>() * self.total_point_count();
295 size += 2 * size_of::<f64>();
296 size += 2 * size_of::<f64>();
297 size
298 }
299
300 fn write_to<T: Write>(&self, dest: &mut T) -> Result<(), Error> {
301 let parts_iter = self.patches.iter().map(|patch| patch.points());
302 let writer = MultiPartShapeWriter::new(&self.bbox, parts_iter, dest);
303 writer
304 .write_bbox_xy()
305 .and_then(|wrt| wrt.write_num_parts())
306 .and_then(|wrt| wrt.write_num_points())
307 .and_then(|wrt| wrt.write_parts_array())
308 .and_then(|wrt| {
309 for patch in self.patches.iter() {
310 match patch {
311 Patch::TriangleStrip(_) => wrt.dst.write_i32::<LittleEndian>(0)?,
312 Patch::TriangleFan(_) => wrt.dst.write_i32::<LittleEndian>(1)?,
313 Patch::OuterRing(_) => wrt.dst.write_i32::<LittleEndian>(2)?,
314 Patch::InnerRing(_) => wrt.dst.write_i32::<LittleEndian>(3)?,
315 Patch::FirstRing(_) => wrt.dst.write_i32::<LittleEndian>(4)?,
316 Patch::Ring(_) => wrt.dst.write_i32::<LittleEndian>(5)?,
317 }
318 }
319 Ok(wrt)
320 })
321 .and_then(|wrt| wrt.write_xy())
322 .and_then(|wrt| wrt.write_bbox_z_range())
323 .and_then(|wrt| wrt.write_zs())
324 .and_then(|wrt| wrt.write_bbox_m_range())
325 .and_then(|wrt| wrt.write_ms())
326 .map_err(Error::IoError)
327 .map(|_wrt| {})
328 }
329}
330
331impl EsriShape for Multipatch {
332 fn x_range(&self) -> [f64; 2] {
333 self.bbox.x_range()
334 }
335
336 fn y_range(&self) -> [f64; 2] {
337 self.bbox.y_range()
338 }
339
340 fn z_range(&self) -> [f64; 2] {
341 self.bbox.z_range()
342 }
343
344 fn m_range(&self) -> [f64; 2] {
345 self.bbox.m_range()
346 }
347}
348#[cfg(feature = "geo-types")]
359impl TryFrom<Multipatch> for geo_types::MultiPolygon<f64> {
360 type Error = Error;
361
362 fn try_from(mp: Multipatch) -> Result<Self, Self::Error> {
363 use geo_types::{Coord, LineString};
364
365 let mut polygons = Vec::<geo_types::Polygon<f64>>::new();
366 let mut last_poly = None;
367 for patch in mp.patches {
368 match patch {
369 Patch::TriangleStrip(_) => return Err(Error::UnsupportedConversion),
370 Patch::TriangleFan(_) => return Err(Error::UnsupportedConversion),
371 Patch::OuterRing(points) | Patch::FirstRing(points) => {
372 let exterior = points
373 .into_iter()
374 .map(Coord::<f64>::from)
375 .collect::<Vec<Coord<f64>>>();
376
377 if let Some(poly) = last_poly.take() {
378 polygons.push(poly);
379 }
380 last_poly = Some(geo_types::Polygon::new(LineString::from(exterior), vec![]))
381 }
382 Patch::InnerRing(points) | Patch::Ring(points) => {
383 let interior = points
384 .into_iter()
385 .map(Coord::<f64>::from)
386 .collect::<Vec<Coord<f64>>>();
387
388 if let Some(poly) = last_poly.as_mut() {
389 poly.interiors_push(interior);
390 } else {
391 return Err(Error::OrphanedInnerRing);
392 }
393 }
394 }
395 }
396
397 if let Some(poly) = last_poly {
398 polygons.push(poly);
399 }
400 Ok(polygons.into())
401 }
402}