Skip to content

Commit

Permalink
Merge georust#503
Browse files Browse the repository at this point in the history
503: cargo fmt r=michaelkirk a=michaelkirk

only ran `cargo fmt`... forgot to do it before merging georust#416 

Co-authored-by: Michael Kirk <michael.code@endoftheworl.de>
  • Loading branch information
bors[bot] and michaelkirk committed Aug 25, 2020
2 parents f6a5b0a + c97dd51 commit 9d8a1c3
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 110 deletions.
1 change: 0 additions & 1 deletion geo/src/algorithm/contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,6 @@ mod test {
use crate::line_string;
use crate::{Coordinate, Line, LineString, MultiPolygon, Point, Polygon, Rect, Triangle};


#[test]
// see https://github.com/georust/geo/issues/452
fn linestring_contains_point() {
Expand Down
110 changes: 44 additions & 66 deletions geo/src/algorithm/line_interpolate_point.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
use std::{
ops::AddAssign,
};
use num_traits::{
Float,
Zero,
One,
};
use num_traits::{Float, One, Zero};
use std::ops::AddAssign;

use crate::{
Line,
LineString,
Coordinate,
algorithm::euclidean_length::EuclideanLength, Coordinate, CoordinateType, Line, LineString,
Point,
CoordinateType,
algorithm::{
euclidean_length::EuclideanLength
},
};

/// Returns the point that lies a given fraction along the line.
///
/// If the given fraction is
/// If the given fraction is
/// * less than zero: returns the starting point
/// * greater than one: returns the end point
///
Expand Down Expand Up @@ -55,8 +43,12 @@ where
type Output = Point<T>;

fn line_interpolate_point(&self, fraction: &T) -> Self::Output {
if fraction < &T::zero() { return self.start.into() };
if fraction > &T::one() { return self.end.into() };
if fraction < &T::zero() {
return self.start.into();
};
if fraction > &T::one() {
return self.end.into();
};
let s = [self.start.x, self.start.y];
let v = [self.end.x - self.start.x, self.end.y - self.start.y];
let r = [*fraction * v[0] + s[0], *fraction * v[1] + s[1]];
Expand All @@ -68,9 +60,9 @@ impl<T> LineInterpolatePoint<T> for LineString<T>
where
T: CoordinateType + Float + Zero + AddAssign + One,
Line<T>: EuclideanLength<T>,
LineString<T>: EuclideanLength<T>
LineString<T>: EuclideanLength<T>,
{
type Output = Point<T>;
type Output = Point<T>;

fn line_interpolate_point(&self, fraction: &T) -> Self::Output {
let total_length = self.euclidean_length();
Expand All @@ -79,45 +71,37 @@ where
let mut queue = Vec::new();
for line in self.lines() {
let length = line.euclidean_length();
queue.push(
(
cum_length.clone(),
cum_length.clone() + length.clone(),
length.clone(),
line.clone()
)
);
queue.push((
cum_length.clone(),
cum_length.clone() + length.clone(),
length.clone(),
line.clone(),
));
cum_length += length;
}
match queue.iter()
.find(|x| x.1 >= fractional_length) {
Some(x) => {
let line_frac = (fractional_length - x.0) / x.2;
(x.3).line_interpolate_point(&line_frac)
},
None => {
self.points_iter().last().unwrap()
}
match queue.iter().find(|x| x.1 >= fractional_length) {
Some(x) => {
let line_frac = (fractional_length - x.0) / x.2;
(x.3).line_interpolate_point(&line_frac)
}
None => self.points_iter().last().unwrap(),
}
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::{
algorithm::{
line_locate_point::LineLocatePoint,
closest_point::ClosestPoint
},
algorithm::{closest_point::ClosestPoint, line_locate_point::LineLocatePoint},
point,
};

#[test]
fn test_line_interpolate_point_line() {
let line = Line::new(
Coordinate {x: -1.0, y: 0.0 },
Coordinate {x: 1.0, y: 0.0 }
Coordinate { x: -1.0, y: 0.0 },
Coordinate { x: 1.0, y: 0.0 },
);
assert_eq!(line.line_interpolate_point(&-1.0), point!(x: -1.0, y: 0.0));
assert_eq!(line.line_interpolate_point(&0.5), point!(x: 0.0, y: 0.0));
Expand All @@ -126,46 +110,40 @@ mod test {
assert_eq!(line.line_interpolate_point(&1.0), point!(x: 1.0, y: 0.0));
assert_eq!(line.line_interpolate_point(&2.0), point!(x: 1.0, y: 0.0));

let line = Line::new(
Coordinate {x: 0.0, y: 0.0 },
Coordinate {x: 1.0, y: 1.0 }
);
let line = Line::new(Coordinate { x: 0.0, y: 0.0 }, Coordinate { x: 1.0, y: 1.0 });
assert_eq!(line.line_interpolate_point(&0.5), point!(x: 0.5, y: 0.5));
}

#[test]
fn test_line_interpolate_point_linestring() {
let linestring: LineString<f64> = vec![
[-1.0, 0.0],
[0.0, 0.0],
[1.0, 0.0]
].into();
assert_eq!(linestring.line_interpolate_point(&0.5), point!(x: 0.0, y: 0.0));
assert_eq!(linestring.line_interpolate_point(&1.0), point!(x: 1.0, y: 0.0));
let linestring: LineString<f64> = vec![[-1.0, 0.0], [0.0, 0.0], [1.0, 0.0]].into();
assert_eq!(
linestring.line_interpolate_point(&0.5),
point!(x: 0.0, y: 0.0)
);
assert_eq!(
linestring.line_interpolate_point(&1.0),
point!(x: 1.0, y: 0.0)
);

let linestring: LineString<f64> = vec![
[-1.0, 0.0],
[0.0, 0.0],
[0.0, 1.0]
].into();
assert_eq!(linestring.line_interpolate_point(&1.5), point!(x: 0.0, y: 1.0));
let linestring: LineString<f64> = vec![[-1.0, 0.0], [0.0, 0.0], [0.0, 1.0]].into();
assert_eq!(
linestring.line_interpolate_point(&1.5),
point!(x: 0.0, y: 1.0)
);
}

#[test]
fn test_matches_closest_point() {
let linestring: LineString<f64> = vec![
[-1.0, 0.0],
[0.5, 1.0],
[1.0, 2.0]
].into();
let linestring: LineString<f64> = vec![[-1.0, 0.0], [0.5, 1.0], [1.0, 2.0]].into();
let pt = point!(x: 0.7, y: 0.7);
let frac = linestring.line_locate_point(&pt);
println!("{:?}", &frac);
let interpolated_point = linestring.line_interpolate_point(&frac);
let closest_point = linestring.closest_point(&pt);
match closest_point {
crate::Closest::SinglePoint(p) => assert_eq!(interpolated_point, p),
_ => panic!("The closest point should be a SinglePoint")
_ => panic!("The closest point should be a SinglePoint"),
};
}
}
72 changes: 33 additions & 39 deletions geo/src/algorithm/line_locate_point.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
use std::{
ops::AddAssign,
};
use crate::{
Point,
Line,
LineString,
CoordinateType,
algorithm::{
euclidean_distance::EuclideanDistance,
euclidean_length::EuclideanLength
},
algorithm::{euclidean_distance::EuclideanDistance, euclidean_length::EuclideanLength},
CoordinateType, Line, LineString, Point,
};
use num_traits::{
identities::{One, Zero},
Float,
identities::{Zero, One},
};
use std::ops::AddAssign;

/// Returns a fraction of the line's total length
/// representing the location
/// representing the location
/// of the closest point on the line to the given point.
///
/// # Examples
Expand All @@ -38,17 +30,16 @@ use num_traits::{
/// assert_eq!(linestring.line_locate_point(&point!(x: 0.0, y: 0.5)), 0.75);
/// assert_eq!(linestring.line_locate_point(&point!(x: 0.0, y: 1.0)), 1.0);
/// ```
pub trait LineLocatePoint<T, Rhs>
{
pub trait LineLocatePoint<T, Rhs> {
type Output;
type Rhs;

fn line_locate_point(&self, p: &Rhs) -> Self::Output;
}

impl<T> LineLocatePoint<T, Point<T>> for Line<T>
where
T: CoordinateType + Float + Zero + One
impl<T> LineLocatePoint<T, Point<T>> for Line<T>
where
T: CoordinateType + Float + Zero + One,
{
type Output = T;
type Rhs = Point<T>;
Expand All @@ -57,7 +48,8 @@ where
let sp = [p.x() - self.start.x, p.y() - self.start.y];
let v = [self.end.x - self.start.x, self.end.y - self.start.y];
let v_sq = v[0] * v[0] + v[1] * v[1];
if v_sq == T::zero() { // The line has zero length, return zero
if v_sq == T::zero() {
// The line has zero length, return zero
return T::zero();
} else {
let v_dot_sp = v[0] * sp[0] + v[1] * sp[1];
Expand All @@ -74,7 +66,7 @@ where
impl<T> LineLocatePoint<T, Point<T>> for LineString<T>
where
T: CoordinateType + Float + Zero + One + PartialOrd + AddAssign,
Line<T>: EuclideanDistance<T, Point<T>> + EuclideanLength<T>
Line<T>: EuclideanDistance<T, Point<T>> + EuclideanLength<T>,
{
type Output = T;
type Rhs = Point<T>;
Expand All @@ -85,17 +77,16 @@ where
for line in self.lines() {
let length = line.euclidean_length();
let distance_to_point = line.euclidean_distance(p);
queue.push(
(
total_length.clone(),
length.clone(),
distance_to_point.clone(),
line.clone()
)
);
queue.push((
total_length.clone(),
length.clone(),
distance_to_point.clone(),
line.clone(),
));
total_length += length;
}
let l = queue.iter()
let l = queue
.iter()
.min_by(|x, y| (x.2).partial_cmp(&y.2).unwrap())
.unwrap();

Expand All @@ -106,16 +97,13 @@ where
#[cfg(test)]
mod test {
use super::*;
use crate::{
Coordinate,
point
};
use crate::{point, Coordinate};

#[test]
fn test_line_locate_point_line() {
let line = Line::new(
Coordinate {x: -1.0, y: 0.0 },
Coordinate {x: 1.0, y: 0.0 }
Coordinate { x: -1.0, y: 0.0 },
Coordinate { x: 1.0, y: 0.0 },
);
let point = Point::new(0.0, 1.0);
assert_eq!(line.line_locate_point(&point), 0.5);
Expand All @@ -133,15 +121,21 @@ mod test {
assert_eq!(line.line_locate_point(&point), 0.0);

let line = Line::new(
Coordinate {x: 0.0, y: 0.0},
Coordinate {x: Float::infinity(), y:0.0}
Coordinate { x: 0.0, y: 0.0 },
Coordinate {
x: Float::infinity(),
y: 0.0,
},
);
let point = Point::new(1000.0, 1000.0);
assert_eq!(line.line_locate_point(&point), 0.0);

let line = Line::new(
Coordinate {x: 0.0, y: 0.0},
Coordinate {x: Float::nan(), y:0.0}
Coordinate { x: 0.0, y: 0.0 },
Coordinate {
x: Float::nan(),
y: 0.0,
},
);
let point = Point::new(1000.0, 1000.0);
assert!(line.line_locate_point(&point).is_nan());
Expand Down
8 changes: 4 additions & 4 deletions geo/src/algorithm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ pub mod haversine_intermediate;
pub mod haversine_length;
/// Determine whether `Geometry` `A` intersects `Geometry` `B`.
pub mod intersects;
/// Interpolate a point along a `Line` or `LineString`.
pub mod line_interpolate_point;
/// Locate a point along a `Line` or `LineString`.
pub mod line_locate_point;
/// Apply a function to all `Coordinates` of a `Geometry`.
pub mod map_coords;
/// Orient a `Polygon`'s exterior and interior rings.
Expand All @@ -59,7 +63,3 @@ pub mod vincenty_distance;
pub mod vincenty_length;
/// Calculate and work with the winding order of `Linestring`s.
pub mod winding_order;
/// Locate a point along a `Line` or `LineString`.
pub mod line_locate_point;
/// Interpolate a point along a `Line` or `LineString`.
pub mod line_interpolate_point;

0 comments on commit 9d8a1c3

Please sign in to comment.