1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
3
4use std::fmt;
5use std::io::{Read, 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>(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 if (record_size != record_size_with_m) & (record_size != record_size_without_m) {
245 Err(Error::InvalidShapeRecordSize)
246 } else {
247 let mut patch_types = vec![PatchType::Ring; reader.num_parts as usize];
248 let mut patches = Vec::<Patch>::with_capacity(reader.num_parts as usize);
249 for i in 0..reader.num_parts {
250 patch_types[i as usize] = PatchType::read_from(reader.source)?;
251 }
252 let (bbox, patches_points) = reader
253 .read_xy()
254 .and_then(|rdr| rdr.read_zs())
255 .and_then(|rdr| rdr.read_ms_if(record_size == record_size_with_m))
256 .map_err(Error::IoError)
257 .map(|rdr| (rdr.bbox, rdr.parts))?;
258
259 for (patch_type, points) in patch_types.iter().zip(patches_points) {
260 let patch = match patch_type {
261 PatchType::TriangleStrip => Patch::TriangleStrip(points),
262 PatchType::TriangleFan => Patch::TriangleFan(points),
263 PatchType::OuterRing => Patch::OuterRing(points),
264 PatchType::InnerRing => Patch::InnerRing(points),
265 PatchType::FirstRing => Patch::FirstRing(points),
266 PatchType::Ring => Patch::Ring(points),
267 };
268 patches.push(patch);
269 }
270 Ok(Self { bbox, patches })
271 }
272 }
273}
274
275impl WritableShape for Multipatch {
276 fn size_in_bytes(&self) -> usize {
277 let mut size = 0usize;
278 size += 4 * size_of::<f64>();
279 size += size_of::<i32>();
280 size += size_of::<i32>();
281 size += size_of::<i32>() * self.patches.len();
282 size += size_of::<i32>() * self.patches.len();
283 size += 4 * size_of::<f64>() * self.total_point_count();
284 size += 2 * size_of::<f64>();
285 size += 2 * size_of::<f64>();
286 size
287 }
288
289 fn write_to<T: Write>(&self, dest: &mut T) -> Result<(), Error> {
290 let parts_iter = self.patches.iter().map(|patch| patch.points());
291 let writer = MultiPartShapeWriter::new(&self.bbox, parts_iter, dest);
292 writer
293 .write_bbox_xy()
294 .and_then(|wrt| wrt.write_num_parts())
295 .and_then(|wrt| wrt.write_num_points())
296 .and_then(|wrt| wrt.write_parts_array())
297 .and_then(|wrt| {
298 for patch in self.patches.iter() {
299 match patch {
300 Patch::TriangleStrip(_) => wrt.dst.write_i32::<LittleEndian>(0)?,
301 Patch::TriangleFan(_) => wrt.dst.write_i32::<LittleEndian>(1)?,
302 Patch::OuterRing(_) => wrt.dst.write_i32::<LittleEndian>(2)?,
303 Patch::InnerRing(_) => wrt.dst.write_i32::<LittleEndian>(3)?,
304 Patch::FirstRing(_) => wrt.dst.write_i32::<LittleEndian>(4)?,
305 Patch::Ring(_) => wrt.dst.write_i32::<LittleEndian>(5)?,
306 }
307 }
308 Ok(wrt)
309 })
310 .and_then(|wrt| wrt.write_xy())
311 .and_then(|wrt| wrt.write_bbox_z_range())
312 .and_then(|wrt| wrt.write_zs())
313 .and_then(|wrt| wrt.write_bbox_m_range())
314 .and_then(|wrt| wrt.write_ms())
315 .map_err(Error::IoError)
316 .map(|_wrt| {})
317 }
318}
319
320impl EsriShape for Multipatch {
321 fn x_range(&self) -> [f64; 2] {
322 self.bbox.x_range()
323 }
324
325 fn y_range(&self) -> [f64; 2] {
326 self.bbox.y_range()
327 }
328
329 fn z_range(&self) -> [f64; 2] {
330 self.bbox.z_range()
331 }
332
333 fn m_range(&self) -> [f64; 2] {
334 self.bbox.m_range()
335 }
336}
337#[cfg(feature = "geo-types")]
348impl TryFrom<Multipatch> for geo_types::MultiPolygon<f64> {
349 type Error = &'static str;
350
351 fn try_from(mp: Multipatch) -> Result<Self, Self::Error> {
352 use geo_types::{Coord, LineString};
353
354 let mut polygons = Vec::<geo_types::Polygon<f64>>::new();
355 let mut last_poly = None;
356 for patch in mp.patches {
357 match patch {
358 Patch::TriangleStrip(_) => {
359 return Err("Cannot convert Multipatch::TriangleStrip to Multipolygon")
360 }
361 Patch::TriangleFan(_) => {
362 return Err("Cannot convert Multipatch::TriangleFan to Multipolygon")
363 }
364 Patch::OuterRing(points) | Patch::FirstRing(points) => {
365 let exterior = points
366 .into_iter()
367 .map(Coord::<f64>::from)
368 .collect::<Vec<Coord<f64>>>();
369
370 if let Some(poly) = last_poly.take() {
371 polygons.push(poly);
372 }
373 last_poly = Some(geo_types::Polygon::new(LineString::from(exterior), vec![]))
374 }
375 Patch::InnerRing(points) | Patch::Ring(points) => {
376 let interior = points
377 .into_iter()
378 .map(Coord::<f64>::from)
379 .collect::<Vec<Coord<f64>>>();
380
381 if let Some(poly) = last_poly.as_mut() {
382 poly.interiors_push(interior);
383 } else {
384 polygons.push(geo_types::Polygon::<f64>::new(
386 LineString::<f64>::from(Vec::<Coord<f64>>::new()),
387 vec![LineString::from(interior)],
388 ));
389 }
390 }
391 }
392 }
393
394 if let Some(poly) = last_poly {
395 polygons.push(poly);
396 }
397 Ok(polygons.into())
398 }
399}