1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
3use std::fmt;
4use std::io::{Read, Write};
5
6pub mod bbox;
7pub(crate) mod io;
8pub mod macros;
9pub mod multipatch;
10pub mod multipoint;
11pub mod point;
12pub mod polygon;
13pub mod polyline;
14pub mod traits;
15
16use super::{Error, ShapeType};
17pub use bbox::{BBoxZ, GenericBBox};
18pub use multipatch::{Multipatch, Patch};
19pub use multipoint::{Multipoint, MultipointM, MultipointZ};
20pub use point::{Point, PointM, PointZ};
21pub use polygon::{Polygon, PolygonM, PolygonRing, PolygonZ};
22pub use polyline::{Polyline, PolylineM, PolylineZ};
23use traits::HasXY;
24
25#[cfg(feature = "geo-types")]
26use geo_types;
27
28pub const NO_DATA: f64 = -10e38;
30
31fn is_no_data(val: f64) -> bool {
32 val <= NO_DATA
33}
34
35pub trait HasShapeType {
37 fn shapetype() -> ShapeType;
39}
40
41pub trait ConcreteShape: Sized + HasShapeType {}
43
44pub trait ConcreteReadableShape: ConcreteShape {
45 fn read_shape_content<T: Read>(source: &mut T, record_size: i32) -> Result<Self, Error>;
48}
49
50pub trait ReadableShape: Sized {
52 fn read_from<T: Read>(source: &mut T, record_size: i32) -> Result<Self, Error>;
53}
54
55impl<S: ConcreteReadableShape> ReadableShape for S {
56 fn read_from<T: Read>(mut source: &mut T, mut record_size: i32) -> Result<S, Error> {
57 let shapetype = ShapeType::read_from(&mut source)?;
58 record_size -= std::mem::size_of::<i32>() as i32;
59 if shapetype == Self::shapetype() {
60 S::read_shape_content(&mut source, record_size)
61 } else {
62 Err(Error::MismatchShapeType {
63 requested: Self::shapetype(),
64 actual: shapetype,
65 })
66 }
67 }
68}
69
70pub trait WritableShape {
72 fn size_in_bytes(&self) -> usize;
75
76 fn write_to<T: Write>(&self, dest: &mut T) -> Result<(), Error>;
78}
79
80pub trait EsriShape: HasShapeType + WritableShape {
81 fn x_range(&self) -> [f64; 2];
82 fn y_range(&self) -> [f64; 2];
83 fn z_range(&self) -> [f64; 2] {
85 [0.0, 0.0]
86 }
87 fn m_range(&self) -> [f64; 2] {
89 [0.0, 0.0]
90 }
91}
92
93pub(crate) fn is_part_closed<PointType: PartialEq>(points: &[PointType]) -> bool {
94 if let (Some(first), Some(last)) = (points.first(), points.last()) {
95 first == last
96 } else {
97 false
98 }
99}
100
101pub(crate) fn close_points_if_not_already<PointType: PartialEq + Copy>(
102 points: &mut Vec<PointType>,
103) {
104 if !is_part_closed(points) {
105 if let Some(point) = points.first().copied() {
106 points.push(point)
107 }
108 }
109}
110
111#[derive(Eq, PartialEq, Debug)]
112pub(crate) enum RingType {
113 OuterRing,
114 InnerRing,
115}
116
117pub(crate) fn ring_type_from_points_ordering<PointType: HasXY>(points: &[PointType]) -> RingType {
134 let area = points
135 .windows(2)
136 .map(|pts| (pts[1].x() - pts[0].x()) * (pts[1].y() + pts[0].y()))
137 .sum::<f64>()
138 / 2.0f64;
139
140 if area < 0.0 {
141 RingType::InnerRing
142 } else {
143 RingType::OuterRing
144 }
145}
146
147pub enum Shape {
172 NullShape,
173 Point(Point),
174 PointM(PointM),
175 PointZ(PointZ),
176 Polyline(Polyline),
177 PolylineM(PolylineM),
178 PolylineZ(PolylineZ),
179 Polygon(Polygon),
180 PolygonM(PolygonM),
181 PolygonZ(PolygonZ),
182 Multipoint(Multipoint),
183 MultipointM(MultipointM),
184 MultipointZ(MultipointZ),
185 Multipatch(Multipatch),
186}
187
188impl HasShapeType for Shape {
189 fn shapetype() -> ShapeType {
190 ShapeType::Point
191 }
192}
193
194impl ReadableShape for Shape {
195 fn read_from<T: Read>(mut source: &mut T, mut record_size: i32) -> Result<Self, Error> {
196 let shapetype = ShapeType::read_from(&mut source)?;
197 record_size -= std::mem::size_of::<i32>() as i32;
198 let shape = match shapetype {
199 ShapeType::Polyline => {
200 Shape::Polyline(Polyline::read_shape_content(&mut source, record_size)?)
201 }
202 ShapeType::PolylineM => {
203 Shape::PolylineM(PolylineM::read_shape_content(&mut source, record_size)?)
204 }
205 ShapeType::PolylineZ => {
206 Shape::PolylineZ(PolylineZ::read_shape_content(&mut source, record_size)?)
207 }
208 ShapeType::Point => Shape::Point(Point::read_shape_content(&mut source, record_size)?),
209 ShapeType::PointM => {
210 Shape::PointM(PointM::read_shape_content(&mut source, record_size)?)
211 }
212 ShapeType::PointZ => {
213 Shape::PointZ(PointZ::read_shape_content(&mut source, record_size)?)
214 }
215 ShapeType::Polygon => {
216 Shape::Polygon(Polygon::read_shape_content(&mut source, record_size)?)
217 }
218 ShapeType::PolygonM => {
219 Shape::PolygonM(PolygonM::read_shape_content(&mut source, record_size)?)
220 }
221 ShapeType::PolygonZ => {
222 Shape::PolygonZ(PolygonZ::read_shape_content(&mut source, record_size)?)
223 }
224 ShapeType::Multipoint => {
225 Shape::Multipoint(Multipoint::read_shape_content(&mut source, record_size)?)
226 }
227 ShapeType::MultipointM => {
228 Shape::MultipointM(MultipointM::read_shape_content(&mut source, record_size)?)
229 }
230 ShapeType::MultipointZ => {
231 Shape::MultipointZ(MultipointZ::read_shape_content(&mut source, record_size)?)
232 }
233 ShapeType::Multipatch => {
234 Shape::Multipatch(Multipatch::read_shape_content(&mut source, record_size)?)
235 }
236 ShapeType::NullShape => Shape::NullShape,
237 };
238 Ok(shape)
239 }
240}
241
242impl Shape {
243 pub fn shapetype(&self) -> ShapeType {
245 match self {
246 Shape::Polyline(_) => ShapeType::Polyline,
247 Shape::PolylineM(_) => ShapeType::PolylineM,
248 Shape::PolylineZ(_) => ShapeType::PolylineZ,
249 Shape::Point(_) => ShapeType::Point,
250 Shape::PointM(_) => ShapeType::PointM,
251 Shape::PointZ(_) => ShapeType::PointZ,
252 Shape::Polygon(_) => ShapeType::Polygon,
253 Shape::PolygonM(_) => ShapeType::PolygonM,
254 Shape::PolygonZ(_) => ShapeType::PolygonZ,
255 Shape::Multipoint(_) => ShapeType::Multipoint,
256 Shape::MultipointM(_) => ShapeType::Multipoint,
257 Shape::MultipointZ(_) => ShapeType::Multipoint,
258 Shape::Multipatch(_) => ShapeType::Multipatch,
259 Shape::NullShape => ShapeType::NullShape,
260 }
261 }
262}
263
264impl fmt::Display for Shape {
265 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266 write!(f, "Shape::")?;
267 match self {
268 Shape::Polyline(shp) => write!(f, "{}", shp),
269 Shape::PolylineM(shp) => write!(f, "{}", shp),
270 Shape::PolylineZ(shp) => write!(f, "{}", shp),
271 Shape::Point(shp) => write!(f, "{}", shp),
272 Shape::PointM(shp) => write!(f, "{}", shp),
273 Shape::PointZ(shp) => write!(f, "{}", shp),
274 Shape::Polygon(shp) => write!(f, "{}", shp),
275 Shape::PolygonM(shp) => write!(f, "{}", shp),
276 Shape::PolygonZ(shp) => write!(f, "{}", shp),
277 Shape::Multipoint(shp) => write!(f, "{}", shp),
278 Shape::MultipointM(shp) => write!(f, "{}", shp),
279 Shape::MultipointZ(shp) => write!(f, "{}", shp),
280 Shape::Multipatch(shp) => write!(f, "{}", shp),
281 Shape::NullShape => write!(f, "NullShape"),
282 }
283 }
284}
285
286#[derive(Debug, Copy, Clone)]
288pub(crate) struct RecordHeader {
289 pub record_number: i32,
290 pub record_size: i32,
291}
292
293impl RecordHeader {
294 pub(crate) const SIZE: usize = 2 * std::mem::size_of::<i32>();
295
296 pub fn read_from<T: Read>(source: &mut T) -> Result<RecordHeader, Error> {
297 let record_number = source.read_i32::<BigEndian>()?;
298 let record_size = source.read_i32::<BigEndian>()?;
299 Ok(RecordHeader {
300 record_number,
301 record_size,
302 })
303 }
304
305 pub fn write_to<T: Write>(&self, dest: &mut T) -> Result<(), std::io::Error> {
306 dest.write_i32::<BigEndian>(self.record_number)?;
307 dest.write_i32::<BigEndian>(self.record_size)?;
308 Ok(())
309 }
310}
311
312pub fn convert_shapes_to_vec_of<S>(shapes: Vec<Shape>) -> Result<Vec<S>, Error>
343where
344 S: TryFrom<Shape>,
345 Error: From<<S as TryFrom<Shape>>::Error>,
346{
347 let mut concrete_shapes = Vec::<S>::with_capacity(shapes.len());
348 for shape in shapes {
349 let concrete = S::try_from(shape)?;
350 concrete_shapes.push(concrete);
351 }
352 Ok(concrete_shapes)
353}
354
355macro_rules! impl_concrete_shape_for {
358 ($ConcreteType:ident) => {
359 impl ConcreteShape for $ConcreteType {}
360 };
361}
362
363macro_rules! impl_from_concrete_shape {
366 ($ConcreteShape:ident=>Shape::$ShapeEnumVariant:ident) => {
367 impl From<$ConcreteShape> for Shape {
368 fn from(concrete: $ConcreteShape) -> Self {
369 Shape::$ShapeEnumVariant(concrete)
370 }
371 }
372 };
373}
374
375macro_rules! impl_try_from_shape {
377 (Shape::$ShapeEnumVariant:ident=>$ConcreteShape:ident) => {
378 impl TryFrom<Shape> for $ConcreteShape {
379 type Error = Error;
380 fn try_from(shape: Shape) -> Result<Self, Self::Error> {
381 match shape {
382 Shape::$ShapeEnumVariant(shp) => Ok(shp),
383 _ => Err(Error::MismatchShapeType {
384 requested: Self::shapetype(),
385 actual: shape.shapetype(),
386 }),
387 }
388 }
389 }
390 };
391}
392
393macro_rules! impl_to_way_conversion {
394 (Shape::$ShapeEnumVariant:ident<=>$ConcreteShape:ident) => {
395 impl_try_from_shape!(Shape::$ShapeEnumVariant => $ConcreteShape);
396 impl_from_concrete_shape!($ConcreteShape => Shape::$ShapeEnumVariant);
397 };
398}
399
400impl_concrete_shape_for!(Point);
401impl_concrete_shape_for!(PointM);
402impl_concrete_shape_for!(PointZ);
403impl_concrete_shape_for!(Polyline);
404impl_concrete_shape_for!(PolylineM);
405impl_concrete_shape_for!(PolylineZ);
406impl_concrete_shape_for!(Polygon);
407impl_concrete_shape_for!(PolygonM);
408impl_concrete_shape_for!(PolygonZ);
409impl_concrete_shape_for!(Multipoint);
410impl_concrete_shape_for!(MultipointM);
411impl_concrete_shape_for!(MultipointZ);
412impl_concrete_shape_for!(Multipatch);
413
414impl_to_way_conversion!(Shape::Point <=> Point);
415impl_to_way_conversion!(Shape::PointM <=> PointM);
416impl_to_way_conversion!(Shape::PointZ <=> PointZ);
417impl_to_way_conversion!(Shape::Polyline <=> Polyline);
418impl_to_way_conversion!(Shape::PolylineM <=> PolylineM);
419impl_to_way_conversion!(Shape::PolylineZ <=> PolylineZ);
420impl_to_way_conversion!(Shape::Polygon <=> Polygon);
421impl_to_way_conversion!(Shape::PolygonM <=> PolygonM);
422impl_to_way_conversion!(Shape::PolygonZ <=> PolygonZ);
423impl_to_way_conversion!(Shape::Multipoint <=> Multipoint);
424impl_to_way_conversion!(Shape::MultipointM <=> MultipointM);
425impl_to_way_conversion!(Shape::MultipointZ <=> MultipointZ);
426impl_to_way_conversion!(Shape::Multipatch <=> Multipatch);
427
428#[cfg(feature = "geo-types")]
433impl TryFrom<Shape> for geo_types::Geometry<f64> {
434 type Error = &'static str;
435
436 fn try_from(shape: Shape) -> Result<Self, Self::Error> {
437 use geo_types::Geometry;
438 match shape {
439 Shape::NullShape => Err("Cannot convert NullShape into any geo_types Geometry"),
440 Shape::Point(point) => Ok(Geometry::Point(geo_types::Point::from(point))),
441 Shape::PointM(point) => Ok(Geometry::Point(geo_types::Point::from(point))),
442 Shape::PointZ(point) => Ok(Geometry::Point(geo_types::Point::from(point))),
443 Shape::Polyline(polyline) => Ok(Geometry::MultiLineString(
444 geo_types::MultiLineString::<f64>::from(polyline),
445 )),
446 Shape::PolylineM(polyline) => Ok(Geometry::MultiLineString(
447 geo_types::MultiLineString::<f64>::from(polyline),
448 )),
449 Shape::PolylineZ(polyline) => Ok(Geometry::MultiLineString(
450 geo_types::MultiLineString::<f64>::from(polyline),
451 )),
452 Shape::Polygon(polygon) => Ok(Geometry::MultiPolygon(
453 geo_types::MultiPolygon::<f64>::from(polygon),
454 )),
455 Shape::PolygonM(polygon) => Ok(Geometry::MultiPolygon(
456 geo_types::MultiPolygon::<f64>::from(polygon),
457 )),
458 Shape::PolygonZ(polygon) => Ok(Geometry::MultiPolygon(
459 geo_types::MultiPolygon::<f64>::from(polygon),
460 )),
461 Shape::Multipoint(multipoint) => Ok(Geometry::MultiPoint(
462 geo_types::MultiPoint::<f64>::from(multipoint),
463 )),
464 Shape::MultipointM(multipoint) => Ok(Geometry::MultiPoint(
465 geo_types::MultiPoint::<f64>::from(multipoint),
466 )),
467 Shape::MultipointZ(multipoint) => Ok(Geometry::MultiPoint(
468 geo_types::MultiPoint::<f64>::from(multipoint),
469 )),
470 Shape::Multipatch(multipatch) => {
471 geo_types::MultiPolygon::<f64>::try_from(multipatch).map(Geometry::MultiPolygon)
472 }
473 }
474 }
475}
476
477#[cfg(feature = "geo-types")]
484impl TryFrom<geo_types::Geometry<f64>> for Shape {
485 type Error = &'static str;
486 fn try_from(geometry: geo_types::Geometry<f64>) -> Result<Self, Self::Error> {
487 match geometry {
488 geo_types::Geometry::Point(point) => Ok(Shape::Point(point.into())),
489 geo_types::Geometry::Line(line) => Ok(Shape::Polyline(line.into())),
490 geo_types::Geometry::LineString(polyline) => Ok(Shape::Polyline(polyline.into())),
491 geo_types::Geometry::Polygon(polygon) => Ok(Shape::Polygon(polygon.into())),
492 geo_types::Geometry::MultiPoint(multipoint) => Ok(Shape::Multipoint(multipoint.into())),
493 geo_types::Geometry::MultiLineString(multi_linestring) => {
494 Ok(Shape::Polyline(multi_linestring.into()))
495 }
496 geo_types::Geometry::MultiPolygon(multi_polygon) => {
497 Ok(Shape::Polygon(multi_polygon.into()))
498 }
499 geo_types::Geometry::GeometryCollection(_) => {
500 Err("Cannot convert geo_types::GeometryCollection into a Shape")
501 }
502 #[allow(unreachable_patterns)] _ => {
504 Err("Cannot convert unrecognized Geometry type into a Shape")
506 }
507 }
508 }
509}
510
511#[cfg(test)]
512mod tests {
513 use super::*;
514
515 #[test]
516 fn convert_to_vec_of_poly_err() {
517 let points = vec![Point::default(), Point::default()];
518 let shapes = vec![
519 Shape::Point(Point::default()),
520 Shape::Polyline(Polyline::new(points)),
521 ];
522 assert!(convert_shapes_to_vec_of::<Polyline>(shapes).is_err());
523 }
524
525 #[test]
526 fn convert_to_vec_of_point_err() {
527 let points = vec![Point::default(), Point::default()];
528 let shapes = vec![
529 Shape::Point(Point::default()),
530 Shape::Polyline(Polyline::new(points)),
531 ];
532 assert!(convert_shapes_to_vec_of::<Point>(shapes).is_err());
533 }
534
535 #[test]
536 fn convert_to_vec_of_poly_ok() {
537 let points = vec![Point::default(), Point::default()];
538
539 let shapes = vec![
540 Shape::from(Polyline::new(points.clone())),
541 Shape::from(Polyline::new(points)),
542 ];
543
544 assert!(convert_shapes_to_vec_of::<Polyline>(shapes).is_ok());
545 }
546
547 #[test]
548 fn convert_to_vec_of_point_ok() {
549 let shapes = vec![
550 Shape::Point(Point::default()),
551 Shape::Point(Point::default()),
552 ];
553 assert!(convert_shapes_to_vec_of::<Point>(shapes).is_ok());
554 }
555
556 #[test]
557 fn test_vertices_order() {
558 let mut points = vec![
559 Point::new(0.0, 0.0),
560 Point::new(1.0, 0.0),
561 Point::new(1.0, 1.0),
562 Point::new(0.0, 1.0),
563 ];
564
565 assert_eq!(ring_type_from_points_ordering(&points), RingType::InnerRing);
566 points.reverse();
567 assert_eq!(ring_type_from_points_ordering(&points), RingType::OuterRing);
568 }
569}