Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support generic numeric type for geometries #30

Merged
merged 16 commits into from
Jul 17, 2016
Prev Previous commit
Next Next commit
Move from num::Num to num::Float
  • Loading branch information
Zambelli Pietro committed May 19, 2016
commit ae6ce89078a4a4e861eed852fa8eff1d8f10d8b6
62 changes: 28 additions & 34 deletions src/algorithm/centroid.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use num::{Num, ToPrimitive};
use num::{Float, ToPrimitive};

use types::{Point, LineString, Polygon};

/// Calculation of the centroid.

pub trait Centroid<T: Num + Copy> {
pub trait Centroid<T: Float> {
/// Calculation the centroid, see: https://en.wikipedia.org/wiki/Centroid
///
/// ```
Expand All @@ -22,71 +22,65 @@ pub trait Centroid<T: Num + Copy> {
fn centroid(&self) -> Option<Point<T>>;
}

impl<T> Centroid<f64> for LineString<T>
where T: Num + Copy + ToPrimitive
impl<T> Centroid<T> for LineString<T>
where T: Float + ToPrimitive
{
///
/// Centroid on a LineString is the mean of the middle of the segment
/// weighted by the length of the segments.
///
fn centroid(&self) -> Option<Point<f64>> {
fn centroid(&self) -> Option<Point<T>> {
let vect = &self.0;
if vect.is_empty() {
return None;
}
if vect.len() == 1 {
Some(Point::new(vect[0].x().to_f64().unwrap(),
vect[0].y().to_f64().unwrap()))
Some(Point::new(vect[0].x(),
vect[0].y()))
} else {
let mut sum_x : f64 = 0.;
let mut sum_y : f64 = 0.;
let mut total_length : f64 = 0.;
let mut sum_x = T::zero();
let mut sum_y = T::zero();
let mut total_length = T::zero();
for (p1, p2) in vect.iter().zip(vect[1..].iter()) {
let segment_len : f64 = p1.distance_to(&p2);
let x1 : f64 = p1.x().to_f64().unwrap();
let x2 : f64 = p2.x().to_f64().unwrap();
let y1 : f64 = p1.y().to_f64().unwrap();
let y2 : f64 = p2.y().to_f64().unwrap();
total_length += segment_len;
sum_x += segment_len * ((x1 + x2) / 2.);
sum_y += segment_len * ((y1 + y2) / 2.);
let segment_len = p1.distance_to(&p2);
let (x1, y1, x2, y2) = (p1.x(), p1.y(), p2.x(), p2.y());
total_length = total_length + segment_len;
sum_x = sum_x + segment_len * ((x1 + x2) / 2.);
sum_y = sum_y + segment_len * ((y1 + y2) / 2.);
}
Some(Point::new(sum_x / total_length, sum_y / total_length))
}
}
}

impl<T> Centroid<f64> for Polygon<T>
where T: Num + Copy + ToPrimitive
impl<T> Centroid<T> for Polygon<T>
where T: Float + ToPrimitive
{
///
/// Centroid on a Polygon.
/// See: https://en.wikipedia.org/wiki/Centroid
///
fn centroid(&self) -> Option<Point<f64>> {
fn centroid(&self) -> Option<Point<T>> {
// TODO: consideration of inner polygons;
let linestring = &self.0;
let vect = &linestring.0;
if vect.is_empty() {
return None;
}
if vect.len() == 1 {
Some(Point::new(vect[0].x().to_f64().unwrap(), vect[0].y().to_f64().unwrap()))
Some(Point::new(vect[0].x(), vect[0].y()))
} else {
let mut area : f64 = 0.;
let mut sum_x : f64 = 0.;
let mut sum_y : f64 = 0.;
let mut area = T::zero();
let mut sum_x = T::zero();
let mut sum_y = T::zero();
for (p1, p2) in vect.iter().zip(vect[1..].iter()) {
let x1 : f64 = p1.x().to_f64().unwrap();
let x2 : f64 = p2.x().to_f64().unwrap();
let y1 : f64 = p1.y().to_f64().unwrap();
let y2 : f64 = p2.y().to_f64().unwrap();
let tmp : f64 = x1 * y2 - x2 * y1;
area += tmp;
sum_x += (x1 + x2) * tmp;
sum_y += (y2 + y1) * tmp;
let (x1, y1, x2, y2) = (p1.x(), p1.y(), p2.x(), p2.y());
let tmp = x1 * y2 - x2 * y1;
area = area + tmp;
sum_x = sum_x + (x1 + x2) * tmp;
sum_y = sum_y + (y2 + y1) * tmp;
}
area /= 2.;
area = area / 2.;
Some(Point::new(sum_x / (6. * area), (sum_y / (6. * area))))
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pub use ::Geometry;

use num::Num;
use num::Float;

pub trait ToGeo<T: Num + Copy>
pub trait ToGeo<T: Float>
{
fn to_geo(&self) -> Geometry<T>;
}
35 changes: 17 additions & 18 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ use std::ops::Add;
use std::ops::Neg;
use std::ops::Sub;

use num::{Num, ToPrimitive};
use num::{Float, ToPrimitive};

#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Coordinate<T>
where T: Num + Copy
where T: Float
{
pub x: T,
pub y: T,
}

#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Point<T> (pub Coordinate<T>) where T: Num + Copy;
pub struct Point<T> (pub Coordinate<T>) where T: Float;

impl<T> Point<T>
where T: Num + Copy + ToPrimitive
where T: Float + ToPrimitive
{
/// Creates a new point.
///
Expand Down Expand Up @@ -169,15 +169,14 @@ impl<T> Point<T>
///
/// assert!(dist < 1e-1)
/// ```
pub fn distance_to(&self, point: &Point<T>) -> f64 {
let dx : f64 = self.x().to_f64().unwrap() - point.x().to_f64().unwrap();
let dy : f64 = self.y().to_f64().unwrap() - point.y().to_f64().unwrap();
(dx * dx + dy * dy).sqrt()
pub fn distance_to(&self, point: &Point<T>) -> T {
let (dx, dy) = (self.x() - point.x(), self.y() - point.y());
Float::sqrt(dx * dx + dy * dy)
}
}

impl<T> Neg for Point<T>
where T: Num + Neg<Output = T> + Copy + ToPrimitive
where T: Float + Neg<Output = T> + ToPrimitive
{
type Output = Point<T>;

Expand All @@ -197,7 +196,7 @@ impl<T> Neg for Point<T>
}

impl<T> Add for Point<T>
where T: Num + Copy + ToPrimitive
where T: Float + ToPrimitive
{
type Output = Point<T>;

Expand All @@ -217,7 +216,7 @@ impl<T> Add for Point<T>
}

impl<T> Sub for Point<T>
where T: Num + Copy + ToPrimitive
where T: Float + ToPrimitive
{
type Output = Point<T>;

Expand All @@ -237,26 +236,26 @@ impl<T> Sub for Point<T>
}

#[derive(PartialEq, Clone, Debug)]
pub struct MultiPoint<T>(pub Vec<Point<T>>) where T: Num + Copy;
pub struct MultiPoint<T>(pub Vec<Point<T>>) where T: Float;

#[derive(PartialEq, Clone, Debug)]
pub struct LineString<T>(pub Vec<Point<T>>) where T: Num + Copy;
pub struct LineString<T>(pub Vec<Point<T>>) where T: Float;

#[derive(PartialEq, Clone, Debug)]
pub struct MultiLineString<T>(pub Vec<LineString<T>>) where T: Num + Copy;
pub struct MultiLineString<T>(pub Vec<LineString<T>>) where T: Float;

#[derive(PartialEq, Clone, Debug)]
pub struct Polygon<T>(pub LineString<T>, pub Vec<LineString<T>>) where T: Num + Copy;
pub struct Polygon<T>(pub LineString<T>, pub Vec<LineString<T>>) where T: Float;

#[derive(PartialEq, Clone, Debug)]
pub struct MultiPolygon<T>(pub Vec<Polygon<T>>) where T: Num + Copy;
pub struct MultiPolygon<T>(pub Vec<Polygon<T>>) where T: Float;

#[derive(PartialEq, Clone, Debug)]
pub struct GeometryCollection<T>(pub Vec<Geometry<T>>) where T: Num + Copy;
pub struct GeometryCollection<T>(pub Vec<Geometry<T>>) where T: Float;

#[derive(PartialEq, Clone, Debug)]
pub enum Geometry<T>
where T: Num + Copy
where T: Float
{
Point(Point<T>),
LineString(LineString<T>),
Expand Down