Skip to content

Commit

Permalink
implement contains for point and linestring
Browse files Browse the repository at this point in the history
  • Loading branch information
frewsxcv committed Jan 24, 2017
1 parent 72a6d85 commit e20e29c
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 44 deletions.
2 changes: 1 addition & 1 deletion src/algorithm/centroid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> Option<Point<T>>
let mut sum_y = T::zero();
let mut total_length = T::zero();
for ps in vect.windows(2) {
let segment_len = ps[0].distance_to_point(&ps[1]);
let segment_len = ps[0].distance_to_point(ps[1]);
let (x1, y1, x2, y2) = (ps[0].x(), ps[0].y(), ps[1].x(), ps[1].y());
total_length = total_length + segment_len;
sum_x = sum_x + segment_len * ((x1 + x2) / (T::one() + T::one()));
Expand Down
79 changes: 44 additions & 35 deletions src/algorithm/contains.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use num_traits::{Float, ToPrimitive};
use num_traits::{Float, FromPrimitive};

use types::{COORD_PRECISION, Point, LineString, Polygon, MultiPolygon, Bbox};
use algorithm::intersects::Intersects;
use traits::PointTrait;
use traits::{PointTrait, LineStringTrait};

/// Checks if the geometry A is completely inside the B geometry.
pub trait Contains<Rhs = Self> {
/// Checks if the geometry A is completely inside the B geometry.
///
/// ```
/// /*
/// use geo::{Coordinate, Point, LineString, Polygon};
/// use geo::algorithm::contains::Contains;
///
Expand All @@ -26,50 +27,57 @@ pub trait Contains<Rhs = Self> {
///
/// //Point in Polygon
/// assert!(poly.contains(&p(1., 1.)));
/// */
///
/// ```
///
fn contains(&self, rhs: &Rhs) -> bool;
}

impl<T> Contains<Point<T>> for Point<T>
where T: Float + ToPrimitive + ::num_traits::FromPrimitive
pub fn point_contains_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> bool
where T: 'a + Float + FromPrimitive,
P1: 'a + PointTrait<T> + ?Sized,
P2: 'a + PointTrait<T> + ?Sized,
{
fn contains(&self, p: &Point<T>) -> bool {
self.distance_to_point(p).to_f32().unwrap() < COORD_PRECISION
}
point1.distance_to_point(point2).to_f32().unwrap() < COORD_PRECISION
}

impl<T> Contains<Point<T>> for LineString<T>
where T: Float + ::num_traits::FromPrimitive
pub fn line_string_contains_point<'a, L, P, T>(line_string: &'a L, point: &'a P) -> bool
where T: 'a + Float + FromPrimitive,
L: 'a + LineStringTrait<'a, T> + ?Sized,
P: 'a + PointTrait<T> + ?Sized,
{
fn contains(&self, p: &Point<T>) -> bool {
let vect = &self.0;
// LineString without points
if vect.is_empty() {
return false;
}
// LineString with one point equal p
if vect.len() == 1 {
return vect[0].contains(p);
}
// check if point is a vertex
if vect.contains(p) {
// FIXME: remove collect
let vect = line_string.points().collect::<Vec<_>>();

// LineString without points
if vect.is_empty() {
return false;
}
// LineString with one point equal p
if vect.len() == 1 {
return vect[0].contains_point(point);
}
// check if point is a vertex
for p in &vect {
if p.has_same_coordinates_as_point(point) {
return true;
}
for ps in vect.windows(2) {
if ((ps[0].y() == ps[1].y()) && (ps[0].y() == p.y()) &&
(p.x() > ps[0].x().min(ps[1].x())) &&
(p.x() < ps[0].x().max(ps[1].x()))) ||
((ps[0].x() == ps[1].x()) && (ps[0].x() == p.x()) &&
(p.y() > ps[0].y().min(ps[1].y())) &&
(p.y() < ps[0].y().max(ps[1].y()))) {
return true;
}
}

for ps in vect.windows(2) {
if ((ps[0].y() == ps[1].y()) && (ps[0].y() == point.y()) &&
(point.x() > ps[0].x().min(ps[1].x())) &&
(point.x() < ps[0].x().max(ps[1].x()))) ||
((ps[0].x() == ps[1].x()) && (ps[0].x() == point.x()) &&
(point.y() > ps[0].y().min(ps[1].y())) &&
(point.y() < ps[0].y().max(ps[1].y()))) {
return true;
}
false
}
false
}

#[derive(PartialEq, Clone, Debug)]
enum PositionPoint {
OnBoundary,
Expand All @@ -91,7 +99,7 @@ fn get_position<T>(p: &Point<T>, linestring: &LineString<T>) -> PositionPoint
return PositionPoint::Outside;
}
// Point is on linestring
if linestring.contains(p) {
if linestring.contains_point(p) {
return PositionPoint::OnBoundary;
}

Expand Down Expand Up @@ -166,23 +174,24 @@ impl<T> Contains<Bbox<T>> for Bbox<T>
mod test {
use types::{Coordinate, Point, LineString, Polygon, MultiPolygon, Bbox};
use algorithm::contains::Contains;
use traits::LineStringTrait;
/// Tests: Point in LineString
#[test]
fn empty_linestring_test() {
let linestring = LineString(Vec::new());
assert!(!linestring.contains(&Point::new(2., 1.)));
assert!(!linestring.contains_point(&Point::new(2., 1.)));
}
#[test]
fn linestring_point_is_vertex_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.)]);
assert!(linestring.contains(&p(2., 2.)));
assert!(linestring.contains_point(&p(2., 2.)));
}
#[test]
fn linestring_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let linestring = LineString(vec![p(0., 0.), p(2., 0.), p(2., 2.)]);
assert!(linestring.contains(&p(1., 0.)));
assert!(linestring.contains_point(&p(1., 0.)));
}
/// Tests: Point in Polygon
#[test]
Expand Down
11 changes: 6 additions & 5 deletions src/algorithm/distance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::cmp::Ordering;
use std::collections::BinaryHeap;
use num_traits::{Float, ToPrimitive, FromPrimitive};
use types::{Point, LineString, Polygon};
use traits::PointTrait;
use traits::{PointTrait, LineStringTrait};
use algorithm::contains::Contains;
use num_traits::pow::pow;

Expand Down Expand Up @@ -66,11 +66,12 @@ pub trait Distance<T, Rhs = Self> {
fn distance(&self, rhs: &Rhs) -> T;
}

pub fn point_to_point<'a, G, T>(p1: &'a G, p2: &'a G) -> T
pub fn point_to_point<'a, P1, P2, T>(point1: &'a P1, point2: &'a P2) -> T
where T: 'a + Float + FromPrimitive,
G: 'a + PointTrait<T> + ?Sized
P1: 'a + PointTrait<T> + ?Sized,
P2: 'a + PointTrait<T> + ?Sized,
{
let (dx, dy) = (p1.x() - p2.x(), p1.y() - p2.y());
let (dx, dy) = (point1.x() - point2.x(), point1.y() - point2.y());
dx.hypot(dy)
}

Expand Down Expand Up @@ -159,7 +160,7 @@ impl<T> Distance<T, LineString<T>> for Point<T>
{
fn distance(&self, linestring: &LineString<T>) -> T {
// No need to continue if the point is on the LineString, or it's empty
if linestring.contains(self) || linestring.0.len() == 0 {
if linestring.contains_point(self) || linestring.0.len() == 0 {
return T::zero();
}
// minimum priority queue
Expand Down
2 changes: 1 addition & 1 deletion src/algorithm/length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn line_string<'a, G, T>(line_string: &'a G) -> T
// FIXME: don't collect
let v = line_string.points().collect::<Vec<_>>();
v.windows(2)
.fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(&p[1]))
.fold(T::zero(), |total_length, p| total_length + p[0].distance_to_point(p[1]))
}

pub fn multi_line_string<'a, G, T>(multi_line_string: &'a G) -> T
Expand Down
17 changes: 15 additions & 2 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,22 @@ pub trait ToGeo<T: Float + FromPrimitive>
// FIXME: find good names for these traits, don't use XyzTrait naming scheme
// FIXME: remove FromPrimitive trait

pub trait PointTrait<T: Float + FromPrimitive> {
pub trait PointTrait<T: Float + FromPrimitive>: Sized {
fn x(&self) -> T;
fn y(&self) -> T;

fn distance_to_point(&self, other: &Self) -> T {
// TODO: keep this?
fn has_same_coordinates_as_point<P: PointTrait<T>>(&self, other: &P) -> bool {
self.x() == other.x() && self.y() == other.y()
}

fn distance_to_point<P: PointTrait<T>>(&self, other: &P) -> T {
::algorithm::distance::point_to_point(self, other)
}

fn contains_point<P: PointTrait<T>>(&self, other: &P) -> bool {
::algorithm::contains::point_contains_point(self, other)
}
}

pub trait LineStringTrait<'a, T>
Expand All @@ -37,6 +46,10 @@ pub trait LineStringTrait<'a, T>
fn centroid(&'a self) -> Option<::Point<T>> {
::algorithm::centroid::line_string(self)
}

fn contains_point<P: PointTrait<T>>(&'a self, other: &'a P) -> bool {
::algorithm::contains::line_string_contains_point(self, other)
}
}

pub trait PolygonTrait<'a, T>
Expand Down

0 comments on commit e20e29c

Please sign in to comment.