Skip to content

Commit

Permalink
Distance and Contains for Triangle, Point
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelkirk committed Jul 4, 2018
1 parent 25f1ef2 commit b3944ca
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 3 deletions.
69 changes: 67 additions & 2 deletions geo/src/algorithm/contains.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use num_traits::{Float, ToPrimitive};

use algorithm::intersects::Intersects;
use {CoordinateType, Line, LineString, MultiPolygon, Point, Polygon, Rect};
use {
Coordinate, CoordinateType, Line, LineString, MultiPolygon, Point, Polygon, Rect, Triangle,
};

/// Checks if the geometry A is completely inside the B geometry
pub trait Contains<Rhs = Self> {
Expand Down Expand Up @@ -249,10 +251,31 @@ where
}
}

impl<T> Contains<Point<T>> for Triangle<T>
where
T: CoordinateType,
{
fn contains(&self, point: &Point<T>) -> bool {
let sign_1 = sign(&point.0, &self.0, &self.1);
let sign_2 = sign(&point.0, &self.1, &self.2);
let sign_3 = sign(&point.0, &self.2, &self.0);

((sign_1 == sign_2) && (sign_2 == sign_3))
}
}

fn sign<T>(point_1: &Coordinate<T>, point_2: &Coordinate<T>, point_3: &Coordinate<T>) -> bool
where
T: CoordinateType,
{
(point_1.x - point_3.x) * (point_2.y - point_3.y)
- (point_2.x - point_3.x) * (point_1.y - point_3.y) < T::zero()
}

#[cfg(test)]
mod test {
use algorithm::contains::Contains;
use {Coordinate, Line, LineString, MultiPolygon, Point, Polygon, Rect};
use {Coordinate, Line, LineString, MultiPolygon, Point, Polygon, Rect, Triangle};
#[test]
// V doesn't contain rect because two of its edges intersect with V's exterior boundary
fn polygon_does_not_contain_polygon() {
Expand Down Expand Up @@ -591,4 +614,46 @@ mod test {
};
assert!(bounding_rect.contains(&smaller_bounding_rect));
}

#[test]
fn triangle_contains_point_on_edge() {
let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let p = Point::new(1.0, 0.0);
assert!(t.contains(&p));
}

#[test]
fn triangle_contains_point_on_vertex() {
let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let p = Point::new(2.0, 0.0);
assert!(t.contains(&p));
}

#[test]
fn triangle_contains_point_inside() {
let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let p = Point::new(1.0, 0.5);
assert!(t.contains(&p));
}

#[test]
fn triangle_not_contains_point_above() {
let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let p = Point::new(1.0, 1.5);
assert!(!t.contains(&p));
}

#[test]
fn triangle_not_contains_point_below() {
let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let p = Point::new(-1.0, 0.5);
assert!(!t.contains(&p));
}

#[test]
fn triangle_contains_neg_point() {
let t = Triangle::from([(0.0, 0.0), (-2.0, 0.0), (-2.0, -2.0)]);
let p = Point::new(-1.0, -0.5);
assert!(t.contains(&p));
}
}
51 changes: 50 additions & 1 deletion geo/src/algorithm/euclidean_distance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use algorithm::intersects::Intersects;
use algorithm::polygon_distance_fast_path::*;
use num_traits::float::FloatConst;
use num_traits::{Float, Signed};
use {Line, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon};
use {Line, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon, Triangle};

use spade::rtree::RTree;
use spade::SpadeFloat;
Expand Down Expand Up @@ -437,6 +437,22 @@ where
}
}

impl<T> EuclideanDistance<T, Point<T>> for Triangle<T>
where
T: Float,
{
fn euclidean_distance(&self, point: &Point<T>) -> T {
if self.contains(point) {
return T::zero();
}

[(self.0, self.1), (self.1, self.2), (self.2, self.0)]
.into_iter()
.map(|edge|
::geo_types::private_utils::line_segment_distance(*point, edge.0.into(), edge.1.into()))
.fold(T::max_value(), |accum, val| accum.min(val))
}
}
/// Uses an R* tree and nearest-neighbour lookups to calculate minimum distances
// This is somewhat slow and memory-inefficient, but certainly better than quadratic time
pub fn nearest_neighbour_distance<T>(geom1: &LineString<T>, geom2: &LineString<T>) -> T
Expand Down Expand Up @@ -945,4 +961,37 @@ mod test {
let ls: LineString<_> = vec![(3.0, 0.0), (1.0, 1.0), (3.0, 2.0)].into();
assert_eq!(ls.euclidean_distance(&line), 1.0);
}

#[test]
// Triangle-Point test: point on vertex
fn test_triangle_point_on_vertex_distance() {
let triangle = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let point = Point::new(0.0, 0.0);
assert_eq!(triangle.euclidean_distance(&point), 0.0);
}

#[test]
// Triangle-Point test: point on edge
fn test_triangle_point_on_edge_distance() {
let triangle = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let point = Point::new(1.5, 0.0);
assert_eq!(triangle.euclidean_distance(&point), 0.0);
}

#[test]
// Triangle-Point test
fn test_triangle_point_distance() {
let triangle = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let point = Point::new(2.0, 3.0);
assert_eq!(triangle.euclidean_distance(&point), 1.0);
}

#[test]
// Triangle-Point test: point within triangle
fn test_triangle_point_inside_distance() {
let triangle = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
let point = Point::new(1.0, 0.5);
assert_eq!(triangle.euclidean_distance(&point), 0.0);
}

}

0 comments on commit b3944ca

Please sign in to comment.