use std::io::{Read, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use record::io::*;
use record::{BBox, EsriShape, HasShapeType, MultipartShape, MultipointShape, WritableShape};
use record::{Point, PointM, PointZ};
use {Error, ShapeType};
use record::is_parts_array_valid;
use record::ConcreteReadableShape;
use std::fmt;
use std::mem::size_of;
use std::slice::SliceIndex;
pub struct GenericPolyline<PointType> {
pub bbox: BBox,
points: Vec<PointType>,
parts: Vec<i32>,
}
impl<PointType: HasXY> GenericPolyline<PointType> {
pub fn new(points: Vec<PointType>, parts: Vec<i32>) -> Self {
let bbox = BBox::from_points(&points);
Self {
bbox,
points,
parts,
}
}
}
impl<PointType> From<GenericPolygon<PointType>> for GenericPolyline<PointType> {
fn from(p: GenericPolygon<PointType>) -> Self {
Self {
bbox: p.bbox,
points: p.points,
parts: p.parts,
}
}
}
impl<PointType> From<GenericPolyline<PointType>> for GenericPolygon<PointType> {
fn from(p: GenericPolyline<PointType>) -> Self {
Self {
bbox: p.bbox,
points: p.points,
parts: p.parts,
}
}
}
impl<PointType> MultipointShape<PointType> for GenericPolyline<PointType> {
fn point<I: SliceIndex<[PointType]>>(&self, index: I) -> Option<&<I as SliceIndex<[PointType]>>::Output> {
self.points.get(index)
}
fn points(&self) -> &[PointType] {
&self.points
}
}
impl<PointType> MultipartShape<PointType> for GenericPolyline<PointType> {
fn parts_indices(&self) -> &[i32] {
&self.parts
}
}
pub type Polyline = GenericPolyline<Point>;
impl Polyline {
pub(crate) fn size_of_record(num_points: i32, num_parts: i32) -> usize {
let mut size = 0usize;
size += 4 * size_of::<f64>();
size += size_of::<i32>();
size += size_of::<i32>();
size += size_of::<i32>() * num_parts as usize;
size += size_of::<Point>() * num_points as usize;
size
}
}
impl fmt::Display for Polyline {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Polyline({} points, {} parts)",
self.points.len(),
self.parts.len()
)
}
}
impl HasShapeType for Polyline {
fn shapetype() -> ShapeType {
ShapeType::Polyline
}
}
impl ConcreteReadableShape for Polyline {
fn read_shape_content<T: Read>(mut source: &mut T, record_size: i32) -> Result<Self::ActualShape, Error> {
let bbox = BBox::read_from(&mut source)?;
let num_parts = source.read_i32::<LittleEndian>()?;
let num_points = source.read_i32::<LittleEndian>()?;
if record_size != Self::size_of_record(num_points, num_parts) as i32 {
Err(Error::InvalidShapeRecordSize)
}
else {
let parts = read_parts(&mut source, num_parts)?;
let points = read_xys_into_point_vec(&mut source, num_points)?;
Ok(Self {
bbox,
parts,
points,
})
}
}
}
impl WritableShape for Polyline {
fn size_in_bytes(&self) -> usize {
let mut size = 0usize;
size += 4 * size_of::<f64>();
size += size_of::<i32>();
size += size_of::<i32>();
size += size_of::<i32>() * self.parts.len();
size += 2 * size_of::<f64>() * self.points.len();
size
}
fn write_to<T: Write>(self, mut dest: &mut T) -> Result<(), Error> {
if !is_parts_array_valid(&self) {
return Err(Error::MalformedShape);
}
self.bbox.write_to(&mut dest)?;
dest.write_i32::<LittleEndian>(self.parts.len() as i32)?;
dest.write_i32::<LittleEndian>(self.points.len() as i32)?;
write_parts(&mut dest, &self.parts)?;
write_points(&mut dest, &self.points)?;
Ok(())
}
}
impl EsriShape for Polyline {
fn bbox(&self) -> BBox {
self.bbox
}
}
pub type PolylineM = GenericPolyline<PointM>;
impl PolylineM {
pub(crate) fn size_of_record(num_points: i32, num_parts: i32, is_m_used: bool) -> usize {
let mut size = Polyline::size_of_record(num_points, num_parts);
if is_m_used {
size += 2 * size_of::<f64>();
size += num_points as usize * size_of::<f64>();
}
size
}
}
impl fmt::Display for PolylineM {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PolylineM({} points, {} parts)",
self.points.len(),
self.parts.len()
)
}
}
impl HasShapeType for PolylineM {
fn shapetype() -> ShapeType {
ShapeType::PolylineM
}
}
impl ConcreteReadableShape for PolylineM {
fn read_shape_content<T: Read>(mut source: &mut T, record_size: i32) -> Result<Self::ActualShape, Error> {
let bbox = BBox::read_from(&mut source)?;
let num_parts = source.read_i32::<LittleEndian>()?;
let num_points = source.read_i32::<LittleEndian>()?;
let parts = read_parts(&mut source, num_parts)?;
let record_size_with_m = Self::size_of_record(num_points, num_parts, true) as i32;
let record_size_without_m = Self::size_of_record(num_points, num_parts, false) as i32;
if (record_size != record_size_with_m) & (record_size != record_size_without_m) {
return Err(Error::InvalidShapeRecordSize)
}
else {
let is_m_used = record_size == record_size_with_m;
let mut points = read_xys_into_pointm_vec(&mut source, num_points)?;
if is_m_used {
let _m_range = read_range(&mut source)?;
read_ms_into(&mut source, &mut points)?;
}
Ok(Self {
bbox,
parts,
points,
})
}
}
}
impl WritableShape for PolylineM {
fn size_in_bytes(&self) -> usize {
let mut size = 0 as usize;
size += size_of::<f64>() * 4;
size += size_of::<i32>();
size += size_of::<i32>();
size += size_of::<i32>() * self.parts.len();
size += 3 * size_of::<f64>() * self.points.len();
size += 2 * size_of::<f64>();
size
}
fn write_to<T: Write>(self, mut dest: &mut T) -> Result<(), Error> {
if !is_parts_array_valid(&self) {
return Err(Error::MalformedShape);
}
self.bbox.write_to(&mut dest)?;
dest.write_i32::<LittleEndian>(self.parts.len() as i32)?;
dest.write_i32::<LittleEndian>(self.points.len() as i32)?;
write_parts(&mut dest, &self.parts)?;
write_points(&mut dest, &self.points)?;
write_range(&mut dest, self.m_range())?;
write_ms(&mut dest, &self.points)?;
Ok(())
}
}
impl EsriShape for PolylineM {
fn bbox(&self) -> BBox {
self.bbox
}
fn m_range(&self) -> [f64; 2] {
calc_m_range(&self.points)
}
}
pub type PolylineZ = GenericPolyline<PointZ>;
impl PolylineZ {
pub(crate) fn size_of_record(num_points: i32, num_parts: i32, is_m_used: bool) -> usize {
let mut size = Polyline::size_of_record(num_points, num_parts);
size += 2 * size_of::<f64>();
size += num_points as usize * size_of::<f64>();
if is_m_used {
size += 2 * size_of::<f64>();
size += num_points as usize * size_of::<f64>();
}
size
}
}
impl fmt::Display for PolylineZ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PolylineZ({} points, {} parts)",
self.points.len(),
self.parts.len()
)
}
}
impl HasShapeType for PolylineZ {
fn shapetype() -> ShapeType {
ShapeType::PolylineZ
}
}
impl ConcreteReadableShape for PolylineZ {
fn read_shape_content<T: Read>(mut source: &mut T, record_size: i32) -> Result<Self::ActualShape, Error> {
let bbox = BBox::read_from(&mut source)?;
let num_parts = source.read_i32::<LittleEndian>()?;
let num_points = source.read_i32::<LittleEndian>()?;
let record_size_with_m = Self::size_of_record(num_points, num_parts, true) as i32;
let record_size_without_m = Self::size_of_record(num_points, num_parts, false) as i32;
if (record_size != record_size_with_m) & (record_size != record_size_without_m) {
return Err(Error::InvalidShapeRecordSize)
}
else {
let is_m_used = record_size == record_size_with_m;
let parts = read_parts(&mut source, num_parts)?;
let mut points = read_xys_into_pointz_vec(&mut source, num_points)?;
let _z_range = read_range(&mut source)?;
read_zs_into(&mut source, &mut points)?;
if is_m_used {
let _m_range = read_range(&mut source)?;
read_ms_into(&mut source, &mut points)?;
}
else {
println!("\nRCSDF: {}, withm: {} withoutm: {}", record_size, record_size_with_m, record_size_without_m);
}
Ok(Self {
bbox,
parts,
points,
})
}
}
}
impl WritableShape for PolylineZ {
fn size_in_bytes(&self) -> usize {
let mut size = 0 as usize;
size += size_of::<f64>() * 4;
size += size_of::<i32>();
size += size_of::<i32>();
size += size_of::<i32>() * self.parts.len();
size += 4 * size_of::<f64>() * self.points.len();
size += 2 * size_of::<f64>();
size += 2 * size_of::<f64>();
size
}
fn write_to<T: Write>(self, mut dest: &mut T) -> Result<(), Error> {
if !is_parts_array_valid(&self) {
return Err(Error::MalformedShape);
}
self.bbox.write_to(&mut dest)?;
dest.write_i32::<LittleEndian>(self.parts.len() as i32)?;
dest.write_i32::<LittleEndian>(self.points.len() as i32)?;
write_parts(&mut dest, &self.parts)?;
write_points(&mut dest, &self.points)?;
write_range(&mut dest, self.z_range())?;
write_zs(&mut dest, &self.points)?;
write_range(&mut dest, self.m_range())?;
write_ms(&mut dest, &self.points)?;
Ok(())
}
}
impl EsriShape for PolylineZ {
fn bbox(&self) -> BBox {
self.bbox
}
fn z_range(&self) -> [f64; 2] {
calc_z_range(&self.points)
}
fn m_range(&self) -> [f64; 2] {
calc_m_range(&self.points)
}
}
pub struct GenericPolygon<PointType> {
pub bbox: BBox,
points: Vec<PointType>,
parts: Vec<i32>,
}
impl<PointType: HasXY> GenericPolygon<PointType> {
pub fn new(points: Vec<PointType>, parts: Vec<i32>) -> Self {
Self::from(GenericPolyline::<PointType>::new(points, parts))
}
}
impl<PointType> MultipointShape<PointType> for GenericPolygon<PointType> {
fn point<I: SliceIndex<[PointType]>>(&self, index: I) -> Option<&<I as SliceIndex<[PointType]>>::Output> {
self.points.get(index)
}
fn points(&self) -> &[PointType] {
&self.points
}
}
impl<PointType> MultipartShape<PointType> for GenericPolygon<PointType> {
fn parts_indices(&self) -> &[i32] {
&self.parts
}
}
pub type Polygon = GenericPolygon<Point>;
impl fmt::Display for Polygon {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Polygon({} points, {} parts)",
self.points.len(),
self.parts.len()
)
}
}
impl HasShapeType for Polygon {
fn shapetype() -> ShapeType {
ShapeType::Polygon
}
}
impl ConcreteReadableShape for Polygon {
fn read_shape_content<T: Read>(mut source: &mut T, record_size: i32) -> Result<Self::ActualShape, Error> {
let poly = Polyline::read_shape_content(&mut source, record_size)?;
Ok(poly.into())
}
}
impl WritableShape for Polygon {
fn size_in_bytes(&self) -> usize {
let mut size = 0 as usize;
size += size_of::<f64>() * 4;
size += size_of::<i32>();
size += size_of::<i32>();
size += size_of::<i32>() * self.parts.len();
size += 2 * size_of::<f64>() * self.points.len();
size
}
fn write_to<T: Write>(self, mut dest: &mut T) -> Result<(), Error> {
let poly: Polyline = self.into();
poly.write_to(&mut dest)
}
}
impl EsriShape for Polygon {
fn bbox(&self) -> BBox {
self.bbox
}
}
pub type PolygonM = GenericPolygon<PointM>;
impl fmt::Display for PolygonM {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PolygonM({} points, {} parts)",
self.points.len(),
self.parts.len()
)
}
}
impl HasShapeType for PolygonM {
fn shapetype() -> ShapeType {
ShapeType::PolygonM
}
}
impl ConcreteReadableShape for PolygonM {
fn read_shape_content<T: Read>(mut source: &mut T, record_size: i32) -> Result<Self::ActualShape, Error> {
let poly = PolylineM::read_shape_content(&mut source, record_size)?;
Ok(Self::from(poly))
}
}
impl WritableShape for PolygonM {
fn size_in_bytes(&self) -> usize {
let mut size = 0 as usize;
size += size_of::<f64>() * 4;
size += size_of::<i32>();
size += size_of::<i32>();
size += size_of::<i32>() * self.parts.len();
size += 3 * size_of::<f64>() * self.points.len();
size += 2 * size_of::<f64>();
size
}
fn write_to<T: Write>(self, mut dest: &mut T) -> Result<(), Error> {
PolylineM::from(self).write_to(&mut dest)
}
}
impl EsriShape for PolygonM {
fn bbox(&self) -> BBox {
self.bbox
}
fn m_range(&self) -> [f64; 2] {
calc_m_range(&self.points)
}
}
pub type PolygonZ = GenericPolygon<PointZ>;
impl fmt::Display for PolygonZ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PolygonZ({} points, {} parts)",
self.points.len(),
self.parts.len()
)
}
}
impl HasShapeType for PolygonZ {
fn shapetype() -> ShapeType {
ShapeType::PolygonZ
}
}
impl ConcreteReadableShape for PolygonZ {
fn read_shape_content<T: Read>(mut source: &mut T, record_size: i32) -> Result<Self::ActualShape, Error> {
let poly = PolylineZ::read_shape_content(&mut source, record_size)?;
Ok(poly.into())
}
}
impl WritableShape for PolygonZ {
fn size_in_bytes(&self) -> usize {
let mut size = 0 as usize;
size += size_of::<f64>() * 4;
size += size_of::<i32>();
size += size_of::<i32>();
size += size_of::<i32>() * self.parts.len();
size += 4 * size_of::<f64>() * self.points.len();
size += 2 * size_of::<f64>();
size += 2 * size_of::<f64>();
size
}
fn write_to<T: Write>(self, mut dest: &mut T) -> Result<(), Error> {
PolylineZ::from(self).write_to(&mut dest)
}
}
impl EsriShape for PolygonZ {
fn bbox(&self) -> BBox {
self.bbox
}
fn z_range(&self) -> [f64; 2] {
calc_z_range(&self.points)
}
fn m_range(&self) -> [f64; 2] {
calc_m_range(&self.points)
}
}