use std::ops::Add;
use std::ops::AddAssign;
use std::ops::Neg;
use std::ops::Sub;
use std::fmt::Debug;
use std::iter::{self, FromIterator, Iterator};
use spade::SpadeNum;
use spade::{PointN, TwoDimensional};
use num_traits::{Float, Num, NumCast, ToPrimitive};
pub trait CoordinateType: Num + Copy + NumCast + PartialOrd {}
impl<T: Num + Copy + NumCast + PartialOrd> CoordinateType for T {}
pub static COORD_PRECISION: f32 = 1e-1;
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Coordinate<T>
where
T: CoordinateType,
{
pub x: T,
pub y: T,
}
impl<T: CoordinateType> From<(T, T)> for Coordinate<T> {
fn from(coords: (T, T)) -> Self {
Coordinate {
x: coords.0,
y: coords.1,
}
}
}
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Bbox<T>
where
T: CoordinateType,
{
pub xmin: T,
pub xmax: T,
pub ymin: T,
pub ymax: T,
}
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Extremes {
pub ymin: usize,
pub xmax: usize,
pub ymax: usize,
pub xmin: usize,
}
impl From<Vec<usize>> for Extremes {
fn from(original: Vec<usize>) -> Extremes {
Extremes {
ymin: original[0],
xmax: original[1],
ymax: original[2],
xmin: original[3],
}
}
}
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ExtremePoint<T>
where
T: CoordinateType,
{
pub ymin: Point<T>,
pub xmax: Point<T>,
pub ymax: Point<T>,
pub xmin: Point<T>,
}
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Point<T>(pub Coordinate<T>)
where
T: CoordinateType;
impl<T: CoordinateType> From<Coordinate<T>> for Point<T> {
fn from(x: Coordinate<T>) -> Point<T> {
Point(x)
}
}
impl<T: CoordinateType> From<(T, T)> for Point<T> {
fn from(coords: (T, T)) -> Point<T> {
Point::new(coords.0, coords.1)
}
}
impl<T> Point<T>
where
T: CoordinateType + ToPrimitive,
{
pub fn new(x: T, y: T) -> Point<T> {
Point(Coordinate { x: x, y: y })
}
pub fn x(&self) -> T {
self.0.x
}
pub fn set_x(&mut self, x: T) -> &mut Point<T> {
self.0.x = x;
self
}
pub fn y(&self) -> T {
self.0.y
}
pub fn set_y(&mut self, y: T) -> &mut Point<T> {
self.0.y = y;
self
}
pub fn lng(&self) -> T {
self.x()
}
pub fn set_lng(&mut self, lng: T) -> &mut Point<T> {
self.set_x(lng)
}
pub fn lat(&self) -> T {
self.y()
}
pub fn set_lat(&mut self, lat: T) -> &mut Point<T> {
self.set_y(lat)
}
pub fn dot(&self, point: &Point<T>) -> T {
self.x() * point.x() + self.y() * point.y()
}
pub fn cross_prod(&self, point_b: &Point<T>, point_c: &Point<T>) -> T
where
T: Float,
{
(point_b.x() - self.x()) * (point_c.y() - self.y()) -
(point_b.y() - self.y()) * (point_c.x() - self.x())
}
pub(crate) fn coords(&self) -> (T, T) {
(self.x(), self.y())
}
}
impl<T> Neg for Point<T>
where
T: CoordinateType + Neg<Output = T> + ToPrimitive,
{
type Output = Point<T>;
fn neg(self) -> Point<T> {
Point::new(-self.x(), -self.y())
}
}
impl<T> Add for Point<T>
where
T: CoordinateType + ToPrimitive,
{
type Output = Point<T>;
fn add(self, rhs: Point<T>) -> Point<T> {
Point::new(self.x() + rhs.x(), self.y() + rhs.y())
}
}
impl<T> Sub for Point<T>
where
T: CoordinateType + ToPrimitive,
{
type Output = Point<T>;
fn sub(self, rhs: Point<T>) -> Point<T> {
Point::new(self.x() - rhs.x(), self.y() - rhs.y())
}
}
impl<T> PointN for Point<T>
where
T: Float + SpadeNum + Debug,
{
type Scalar = T;
fn dimensions() -> usize {
2
}
fn from_value(value: Self::Scalar) -> Self {
Point::new(value, value)
}
fn nth(&self, index: usize) -> &Self::Scalar {
match index {
0 => &self.0.x,
1 => &self.0.y,
_ => unreachable!(),
}
}
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
match index {
0 => &mut self.0.x,
1 => &mut self.0.y,
_ => unreachable!(),
}
}
}
impl<T> TwoDimensional for Point<T>
where
T: Float + SpadeNum + Debug,
{
}
impl<T> Add for Bbox<T>
where
T: CoordinateType + ToPrimitive,
{
type Output = Bbox<T>;
fn add(self, rhs: Bbox<T>) -> Bbox<T> {
Bbox {
xmin: if self.xmin <= rhs.xmin {
self.xmin
} else {
rhs.xmin
},
xmax: if self.xmax >= rhs.xmax {
self.xmax
} else {
rhs.xmax
},
ymin: if self.ymin <= rhs.ymin {
self.ymin
} else {
rhs.ymin
},
ymax: if self.ymax >= rhs.ymax {
self.ymax
} else {
rhs.ymax
},
}
}
}
impl<T> AddAssign for Bbox<T>
where
T: CoordinateType + ToPrimitive,
{
fn add_assign(&mut self, rhs: Bbox<T>) {
self.xmin = if self.xmin <= rhs.xmin {
self.xmin
} else {
rhs.xmin
};
self.xmax = if self.xmax >= rhs.xmax {
self.xmax
} else {
rhs.xmax
};
self.ymin = if self.ymin <= rhs.ymin {
self.ymin
} else {
rhs.ymin
};
self.ymax = if self.ymax >= rhs.ymax {
self.ymax
} else {
rhs.ymax
};
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub struct MultiPoint<T>(pub Vec<Point<T>>)
where
T: CoordinateType;
impl<T: CoordinateType, IP: Into<Point<T>>> From<IP> for MultiPoint<T> {
fn from(x: IP) -> MultiPoint<T> {
MultiPoint(vec![x.into()])
}
}
impl<T: CoordinateType, IP: Into<Point<T>>> From<Vec<IP>> for MultiPoint<T> {
fn from(v: Vec<IP>) -> MultiPoint<T> {
MultiPoint(v.into_iter().map(|p| p.into()).collect())
}
}
impl<T: CoordinateType, IP: Into<Point<T>>> FromIterator<IP> for MultiPoint<T> {
fn from_iter<I: IntoIterator<Item = IP>>(iter: I) -> Self {
MultiPoint(iter.into_iter().map(|p| p.into()).collect())
}
}
impl<T: CoordinateType> IntoIterator for MultiPoint<T> {
type Item = Point<T>;
type IntoIter = ::std::vec::IntoIter<Point<T>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Line<T>
where
T: CoordinateType,
{
pub start: Point<T>,
pub end: Point<T>,
}
impl<T> Line<T>
where
T: CoordinateType,
{
pub fn new(start: Point<T>, end: Point<T>) -> Line<T> {
Line {
start: start,
end: end,
}
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub struct LineString<T>(pub Vec<Point<T>>)
where
T: CoordinateType;
impl<T: CoordinateType> LineString<T> {
pub fn lines<'a>(&'a self) -> Box<Iterator<Item = Line<T>> + 'a> {
if self.0.len() < 2 {
return Box::new(iter::empty());
}
Box::new(self.0.windows(2).map(|w| unsafe {
Line::new(*w.get_unchecked(0), *w.get_unchecked(1))
}))
}
}
impl<T: CoordinateType, IP: Into<Point<T>>> From<Vec<IP>> for LineString<T> {
fn from(v: Vec<IP>) -> Self {
LineString(v.into_iter().map(|p| p.into()).collect())
}
}
impl<T: CoordinateType, IP: Into<Point<T>>> FromIterator<IP> for LineString<T> {
fn from_iter<I: IntoIterator<Item = IP>>(iter: I) -> Self {
LineString(iter.into_iter().map(|p| p.into()).collect())
}
}
impl<T: CoordinateType> IntoIterator for LineString<T> {
type Item = Point<T>;
type IntoIter = ::std::vec::IntoIter<Point<T>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub struct MultiLineString<T>(pub Vec<LineString<T>>)
where
T: CoordinateType;
impl<T: CoordinateType, ILS: Into<LineString<T>>> From<ILS> for MultiLineString<T> {
fn from(ls: ILS) -> Self {
MultiLineString(vec![ls.into()])
}
}
impl<T: CoordinateType, ILS: Into<LineString<T>>> FromIterator<ILS> for MultiLineString<T> {
fn from_iter<I: IntoIterator<Item = ILS>>(iter: I) -> Self {
MultiLineString(iter.into_iter().map(|ls| ls.into()).collect())
}
}
impl<T: CoordinateType> IntoIterator for MultiLineString<T> {
type Item = LineString<T>;
type IntoIter = ::std::vec::IntoIter<LineString<T>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub struct Polygon<T>
where
T: CoordinateType,
{
pub exterior: LineString<T>,
pub interiors: Vec<LineString<T>>,
}
impl<T> Polygon<T>
where
T: CoordinateType,
{
pub fn new(exterior: LineString<T>, interiors: Vec<LineString<T>>) -> Polygon<T> {
Polygon {
exterior: exterior,
interiors: interiors,
}
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub struct MultiPolygon<T>(pub Vec<Polygon<T>>)
where
T: CoordinateType;
impl<T: CoordinateType, IP: Into<Polygon<T>>> From<IP> for MultiPolygon<T> {
fn from(x: IP) -> Self {
MultiPolygon(vec![x.into()])
}
}
impl<T: CoordinateType, IP: Into<Polygon<T>>> FromIterator<IP> for MultiPolygon<T> {
fn from_iter<I: IntoIterator<Item = IP>>(iter: I) -> Self {
MultiPolygon(iter.into_iter().map(|p| p.into()).collect())
}
}
impl<T: CoordinateType> IntoIterator for MultiPolygon<T> {
type Item = Polygon<T>;
type IntoIter = ::std::vec::IntoIter<Polygon<T>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct GeometryCollection<T>(pub Vec<Geometry<T>>)
where
T: CoordinateType;
impl<T: CoordinateType, IG: Into<Geometry<T>>> From<IG> for GeometryCollection<T> {
fn from(x: IG) -> Self {
GeometryCollection(vec![x.into()])
}
}
impl<T: CoordinateType, IG: Into<Geometry<T>>> FromIterator<IG> for GeometryCollection<T> {
fn from_iter<I: IntoIterator<Item = IG>>(iter: I) -> Self {
GeometryCollection(iter.into_iter().map(|g| g.into()).collect())
}
}
impl<T: CoordinateType> IntoIterator for GeometryCollection<T> {
type Item = Geometry<T>;
type IntoIter = ::std::vec::IntoIter<Geometry<T>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(PartialEq, Clone, Debug)]
pub enum Geometry<T>
where
T: CoordinateType,
{
Point(Point<T>),
Line(Line<T>),
LineString(LineString<T>),
Polygon(Polygon<T>),
MultiPoint(MultiPoint<T>),
MultiLineString(MultiLineString<T>),
MultiPolygon(MultiPolygon<T>),
GeometryCollection(GeometryCollection<T>),
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum Closest<F: Float> {
Intersection(Point<F>),
SinglePoint(Point<F>),
Indeterminate,
}
impl<F: Float> Closest<F> {
pub fn best_of_two(&self, other: &Self, p: &Point<F>) -> Self {
use algorithm::distance::Distance;
let left = match *self {
Closest::Indeterminate => return *other,
Closest::Intersection(_) => return *self,
Closest::SinglePoint(l) => l,
};
let right = match *other {
Closest::Indeterminate => return *self,
Closest::Intersection(_) => return *other,
Closest::SinglePoint(r) => r,
};
if left.distance(p) <= right.distance(p) {
*self
} else {
*other
}
}
}
impl<T: CoordinateType> From<Point<T>> for Geometry<T> {
fn from(x: Point<T>) -> Geometry<T> {
Geometry::Point(x)
}
}
impl<T: CoordinateType> From<LineString<T>> for Geometry<T> {
fn from(x: LineString<T>) -> Geometry<T> {
Geometry::LineString(x)
}
}
impl<T: CoordinateType> From<Polygon<T>> for Geometry<T> {
fn from(x: Polygon<T>) -> Geometry<T> {
Geometry::Polygon(x)
}
}
impl<T: CoordinateType> From<MultiPoint<T>> for Geometry<T> {
fn from(x: MultiPoint<T>) -> Geometry<T> {
Geometry::MultiPoint(x)
}
}
impl<T: CoordinateType> From<MultiLineString<T>> for Geometry<T> {
fn from(x: MultiLineString<T>) -> Geometry<T> {
Geometry::MultiLineString(x)
}
}
impl<T: CoordinateType> From<MultiPolygon<T>> for Geometry<T> {
fn from(x: MultiPolygon<T>) -> Geometry<T> {
Geometry::MultiPolygon(x)
}
}
impl<T: CoordinateType> Geometry<T> {
pub fn as_point(self) -> Option<Point<T>> {
if let Geometry::Point(x) = self {
Some(x)
} else {
None
}
}
pub fn as_linestring(self) -> Option<LineString<T>> {
if let Geometry::LineString(x) = self {
Some(x)
} else {
None
}
}
pub fn as_line(self) -> Option<Line<T>> {
if let Geometry::Line(x) = self {
Some(x)
} else {
None
}
}
pub fn as_polygon(self) -> Option<Polygon<T>> {
if let Geometry::Polygon(x) = self {
Some(x)
} else {
None
}
}
pub fn as_multipoint(self) -> Option<MultiPoint<T>> {
if let Geometry::MultiPoint(x) = self {
Some(x)
} else {
None
}
}
pub fn as_multilinestring(self) -> Option<MultiLineString<T>> {
if let Geometry::MultiLineString(x) = self {
Some(x)
} else {
None
}
}
pub fn as_multipolygon(self) -> Option<MultiPolygon<T>> {
if let Geometry::MultiPolygon(x) = self {
Some(x)
} else {
None
}
}
}
#[cfg(test)]
mod test {
use types::*;
#[test]
fn type_test() {
let c = Coordinate {
x: 40.02f64,
y: 116.34,
};
let p = Point(c);
let Point(c2) = p;
assert_eq!(c, c2);
assert_eq!(c.x, c2.x);
assert_eq!(c.y, c2.y);
let p: Point<f32> = (0f32, 1f32).into();
assert_eq!(p.x(), 0.);
assert_eq!(p.y(), 1.);
}
#[test]
fn convert_types() {
let p: Point<f32> = Point::new(0., 0.);
let p1 = p.clone();
let g: Geometry<f32> = p.into();
let p2 = g.as_point().unwrap();
assert_eq!(p1, p2);
}
#[test]
fn polygon_new_test() {
let exterior = LineString(vec![
Point::new(0., 0.),
Point::new(1., 1.),
Point::new(1., 0.),
Point::new(0., 0.),
]);
let interiors = vec![
LineString(vec![
Point::new(0.1, 0.1),
Point::new(0.9, 0.9),
Point::new(0.9, 0.1),
Point::new(0.1, 0.1),
]),
];
let p = Polygon::new(exterior.clone(), interiors.clone());
assert_eq!(p.exterior, exterior);
assert_eq!(p.interiors, interiors);
}
#[test]
fn iters() {
let _: MultiPoint<_> = vec![(0., 0.), (1., 2.)].into();
let _: MultiPoint<_> = vec![(0., 0.), (1., 2.)].into_iter().collect();
let _: LineString<_> = vec![(0., 0.), (1., 2.)].into();
let _: LineString<_> = vec![(0., 0.), (1., 2.)].into_iter().collect();
}
#[test]
fn test_coordinate_types() {
let p: Point<u8> = Point::new(0, 0);
assert_eq!(p.x(), 0u8);
let p: Point<i64> = Point::new(1_000_000, 0);
assert_eq!(p.x(), 1_000_000i64);
}
}