Skip to content

Commit

Permalink
Resolve: use distance_along_curve, not CurveProjection
Browse files Browse the repository at this point in the history
  • Loading branch information
Tristramg committed Jul 10, 2024
1 parent f736209 commit 952d107
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 56 deletions.
56 changes: 18 additions & 38 deletions src/curves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ pub trait Curve {
fn project(&self, point: Point) -> Result<CurveProjection, CurveError>;

/// Returns the geographical position of a [`Point`] on the [`Curve`].
/// Will return an error if the [`CurveProjection`] is not on this [`Curve`].
fn resolve(&self, projection: CurveProjection) -> Result<Point, CurveError>;
/// Will return an error if the [`distance_along_curve`] is not on this [`Curve`].
fn resolve(&self, distance_along_curve: f64) -> Result<Point, CurveError>;

/// Bounding box of the [`Curve`] with a buffer of `max_extent`.
fn bbox(&self) -> Rect;
Expand Down Expand Up @@ -150,14 +150,15 @@ impl Curve for PlanarLineStringCurve {
Ok(CurveProjection {
distance_along_curve,
offset,
projected_coords,
})
}
None => Err(CurveError::NotFiniteCoordinates),
}
}

fn resolve(&self, projection: CurveProjection) -> Result<Point, CurveError> {
let fraction = (projection.distance_along_curve - self.start_offset) / self.length;
fn resolve(&self, distance_along_curve: f64) -> Result<Point, CurveError> {
let fraction = (distance_along_curve - self.start_offset) / self.length;
if !(0. ..=1.).contains(&fraction) || fraction.is_nan() {
Err(CurveError::NotOnTheCurve)
} else {
Expand Down Expand Up @@ -197,10 +198,7 @@ impl Curve for PlanarLineStringCurve {

fn get_normal(&self, offset: f64) -> Result<(f64, f64), CurveError> {
// We find the Point where the normal is computed
let point = self.resolve(CurveProjection {
distance_along_curve: offset,
offset: 0.,
})?;
let point = self.resolve(offset)?;

let line = self
.geom
Expand Down Expand Up @@ -369,7 +367,7 @@ impl Curve for SphericalLineStringCurve {
match self.line_locate_point(&point) {
Some(location) => {
let distance_along_curve = location * self.length() + self.start_offset;
let closest_point = self.geom.line_interpolate_point(location).unwrap();
let projected_coords = self.geom.line_interpolate_point(location).unwrap();

let begin = self.geom.coords().next().unwrap();
let end = self.geom.coords().next_back().unwrap();
Expand All @@ -378,19 +376,20 @@ impl Curve for SphericalLineStringCurve {
Orientation::Clockwise => 1.,
_ => -1.,
};
let offset = closest_point.geodesic_distance(&point) * sign;
let offset = projected_coords.geodesic_distance(&point) * sign;

Ok(CurveProjection {
distance_along_curve,
offset,
projected_coords,
})
}
None => Err(CurveError::NotFiniteCoordinates),
}
}

fn resolve(&self, projection: CurveProjection) -> Result<Point, CurveError> {
let fraction = (projection.distance_along_curve - self.start_offset) / self.length;
fn resolve(&self, distance_along_curve: f64) -> Result<Point, CurveError> {
let fraction = (distance_along_curve - self.start_offset) / self.length;
if !(0. ..=1.).contains(&fraction) || fraction.is_nan() {
return Err(CurveError::NotOnTheCurve);
}
Expand Down Expand Up @@ -605,16 +604,12 @@ mod tests {
fn planar_resolve() {
let mut c = PlanarLineStringCurve::new(line_string![(x: 0., y: 0.), (x: 2., y: 0.)], 1.);

let projection = CurveProjection {
distance_along_curve: 1.,
offset: 0.,
};
let p = c.resolve(projection).unwrap();
let p = c.resolve(1.).unwrap();
assert_eq!(p.x(), 1.);
assert_eq!(p.y(), 0.);

c.start_offset = 1.;
let p = c.resolve(projection).unwrap();
let p = c.resolve(1.).unwrap();
assert_eq!(p.x(), 0.);
}

Expand Down Expand Up @@ -764,41 +759,26 @@ mod tests {
let mut paris_to_new_york =
SphericalLineStringCurve::new(line_string![PARIS, NEW_YORK], 1.);

let mut projection = CurveProjection {
distance_along_curve: 1000000.,
offset: 0.,
};
let paris_to_new_york_projection = paris_to_new_york.resolve(projection).unwrap();
let paris_to_new_york_projection = paris_to_new_york.resolve(1000000.).unwrap();
assert_eq!(-11.073026969801687, paris_to_new_york_projection.x());
assert_eq!(51.452453982109404, paris_to_new_york_projection.y());

paris_to_new_york.start_offset = 300000.;
let paris_to_new_york_projection = paris_to_new_york.resolve(projection).unwrap();
let paris_to_new_york_projection = paris_to_new_york.resolve(1000000.).unwrap();
assert_eq!(-6.8972570655588346, paris_to_new_york_projection.x());
assert_eq!(50.83999834131466, paris_to_new_york_projection.y());

projection.distance_along_curve = 8000000.;
assert!(paris_to_new_york.resolve(projection).is_err());
assert!(paris_to_new_york.resolve(8000000.).is_err());

// Test on a linestring where only the longitude changes (latitude remains almost the same)
let lille_to_perpignan = SphericalLineStringCurve::new(line_string![LILLE, PERPIGNAN], 1.);

let projection = CurveProjection {
distance_along_curve: 500000.,
offset: 0.,
};
let lille_to_perpignan_p = lille_to_perpignan.resolve(projection).unwrap();
let lille_to_perpignan_p = lille_to_perpignan.resolve(500000.).unwrap();
assert_eq!(2.961644856565597, lille_to_perpignan_p.x());
assert_eq!(46.13408148827718, lille_to_perpignan_p.y());

// Test on a linestring where only the latitude changes (longitude remains almost the same)
let brest_to_nancy = SphericalLineStringCurve::new(line_string![BREST, NANCY], 1.);

let projection = CurveProjection {
distance_along_curve: 500000.,
offset: 0.,
};
let brest_to_nancy_p = brest_to_nancy.resolve(projection).unwrap();
let brest_to_nancy_p = brest_to_nancy.resolve(500000.).unwrap();
assert_eq!(2.268067652986713, brest_to_nancy_p.x());
assert_eq!(48.695256847531994, brest_to_nancy_p.y());
}
Expand Down
16 changes: 2 additions & 14 deletions src/lrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,6 @@ pub struct TraversalPosition {
pub traversal: TraversalHandle,
}

impl From<TraversalPosition> for CurveProjection {
fn from(val: TraversalPosition) -> Self {
CurveProjection {
distance_along_curve: val.distance_from_start,
offset: 0.,
}
}
}

/// Describes an interval (= range) on a [`Traversal`].
/// The borders are [`CurvePosition`]s.
/// It can be used to identify a speed limit zone for instance.
Expand Down Expand Up @@ -443,7 +434,7 @@ impl<CurveImpl: Curve> LrsBase for Lrs<CurveImpl> {
fn locate_traversal(&self, position: TraversalPosition) -> Result<Point, LrsError> {
Ok(self
.get_curve(position.traversal)?
.resolve(position.into())?)
.resolve(position.distance_from_start)?)
}

fn get_lrm_applicable_traversals(&self, lrm: LrmHandle) -> &[TraversalHandle] {
Expand Down Expand Up @@ -585,10 +576,7 @@ impl<CurveImpl: Curve> Lrs<CurveImpl> {
let from_curve = self.get_curve(handle)?;
let normal = from_curve.get_normal(from_start)?;

let position = from_curve.resolve(CurveProjection {
distance_along_curve: from_start,
offset: 0.,
})?;
let position = from_curve.resolve(from_start)?;
let start = geo::coord! {
x: position.x() + normal.0 * from_curve.max_extent(),
y: position.y() + normal.1 * from_curve.max_extent()
Expand Down
5 changes: 1 addition & 4 deletions src/lrs_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,7 @@ fn make_anchor(
anchor: &crate::lrm_scale::Anchor,
) -> Result<PositionnedAnchor, CurveError> {
let position = curve
.resolve(crate::curves::CurveProjection {
distance_along_curve: anchor.curve_position,
offset: 0.,
})
.resolve(anchor.curve_position)
.map(|point| point.into())?;
Ok(PositionnedAnchor::new(anchor, position))
}

0 comments on commit 952d107

Please sign in to comment.