Skip to content

Commit 3163ea1

Browse files
committed
update LineStringCurve occurrences in PlanarLineStringCurve
1 parent 66c052d commit 3163ea1

File tree

2 files changed

+162
-65
lines changed

2 files changed

+162
-65
lines changed

src/curves.rs

+158-61
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,15 @@ impl Curve for PlanarLineStringCurve {
185185
fn intersect_segment(&self, segment: Line) -> Option<Point> {
186186
self.geom
187187
.lines()
188-
.flat_map(|curve_line| match geo::line_intersection::line_intersection(segment, curve_line) {
189-
Some(LineIntersection::SinglePoint {
190-
intersection,
191-
is_proper: _,
192-
}) => Some(intersection.into()),
193-
Some(LineIntersection::Collinear { intersection: _ }) => None,
194-
None => None,
188+
.flat_map(|curve_line| {
189+
match geo::line_intersection::line_intersection(segment, curve_line) {
190+
Some(LineIntersection::SinglePoint {
191+
intersection,
192+
is_proper: _,
193+
}) => Some(intersection.into()),
194+
Some(LineIntersection::Collinear { intersection: _ }) => None,
195+
None => None,
196+
}
195197
})
196198
.next()
197199
}
@@ -210,7 +212,10 @@ impl Curve for PlanarLineStringCurve {
210212
.ok_or(CurveError::NotFiniteCoordinates)?;
211213

212214
// translate to (0, 0) and normalize by the length of the curve to get unit vector of tangent
213-
let tangent = ((line.end.x - line.start.x) / self.length, (line.end.y - line.start.y) / self.length);
215+
let tangent = (
216+
(line.end.x - line.start.x) / self.length,
217+
(line.end.y - line.start.y) / self.length,
218+
);
214219

215220
// 90° clockwise rotation
216221
let normal = (-tangent.1, tangent.0);
@@ -293,7 +298,9 @@ impl Curve for SphericalLineStringCurve {
293298
}
294299

295300
fn is_valid(&self) -> bool {
296-
if !(self.geom.coords_count() >= 2 && (self.geom.coords_count() > 2 || !self.geom.is_closed())) {
301+
if !(self.geom.coords_count() >= 2
302+
&& (self.geom.coords_count() > 2 || !self.geom.is_closed()))
303+
{
297304
return false;
298305
}
299306
for coord in self.geom.coords() {
@@ -311,7 +318,9 @@ impl Curve for SphericalLineStringCurve {
311318

312319
match self.geom.haversine_closest_point(&point) {
313320
geo::Closest::SinglePoint(closest_point) => {
314-
let distance_along_curve = closest_point.haversine_distance(&self.geom.points().next().unwrap()) + self.start_offset;
321+
let distance_along_curve = closest_point
322+
.haversine_distance(&self.geom.points().next().unwrap())
323+
+ self.start_offset;
315324

316325
let begin = self.geom.coords().next().unwrap();
317326
let end = self.geom.coords().next_back().unwrap();
@@ -324,11 +333,11 @@ impl Curve for SphericalLineStringCurve {
324333

325334
Ok(CurveProjection {
326335
distance_along_curve,
327-
offset
336+
offset,
328337
})
329338
}
330339
geo::Closest::Intersection(_) => Err(CurveError::InvalidGeometry),
331-
geo::Closest::Indeterminate => Err(CurveError::NotFiniteCoordinates)
340+
geo::Closest::Indeterminate => Err(CurveError::NotFiniteCoordinates),
332341
}
333342
}
334343

@@ -381,17 +390,15 @@ impl Curve for SphericalLineStringCurve {
381390
self.geom
382391
.densify_haversine(self.densify_by)
383392
.lines()
384-
.flat_map(|curve_line| match geo::line_intersection::line_intersection(segment, curve_line) {
385-
Some(LineIntersection::SinglePoint {
386-
intersection,
387-
is_proper: _,
388-
}) => {
389-
Some(intersection.into())
390-
},
391-
Some(LineIntersection::Collinear { intersection: _ }) => {
392-
None
393-
},
394-
None => None,
393+
.flat_map(|curve_line| {
394+
match geo::line_intersection::line_intersection(segment, curve_line) {
395+
Some(LineIntersection::SinglePoint {
396+
intersection,
397+
is_proper: _,
398+
}) => Some(intersection.into()),
399+
Some(LineIntersection::Collinear { intersection: _ }) => None,
400+
None => None,
401+
}
395402
})
396403
.next()
397404
}
@@ -467,7 +474,11 @@ mod tests {
467474
#[test]
468475
fn planar_fragmented() {
469476
let framentation_max_length = 1.;
470-
let c = PlanarLineStringCurve::new_fragmented(line_string![(x: 0., y: 0.), (x: 2., y: 0.)], framentation_max_length, 1.);
477+
let c = PlanarLineStringCurve::new_fragmented(
478+
line_string![(x: 0., y: 0.), (x: 2., y: 0.)],
479+
framentation_max_length,
480+
1.,
481+
);
471482
assert_eq!(2, c.len());
472483
assert_eq!(framentation_max_length, c[0].length());
473484
}
@@ -571,22 +582,39 @@ mod tests {
571582
#[test]
572583
fn spherical_fragmented() {
573584
let framentation_max_length = 1.;
574-
let paris_to_new_york = SphericalLineStringCurve::new_fragmented(line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)], framentation_max_length, 1.);
585+
let paris_to_new_york = SphericalLineStringCurve::new_fragmented(
586+
line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)],
587+
framentation_max_length,
588+
1.,
589+
);
575590

576591
assert_eq!(5837284, paris_to_new_york.len());
577-
assert_relative_eq!(framentation_max_length, paris_to_new_york[0].length(), epsilon = 1e-7);
592+
assert_relative_eq!(
593+
framentation_max_length,
594+
paris_to_new_york[0].length(),
595+
epsilon = 1e-7
596+
);
578597
// 1e-7 means we lose 0.1 micrometer per segment
579598
}
580599

581600
#[test]
582601
fn spherical_length() {
583-
let paris_to_new_york = SphericalLineStringCurve::new(line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)], 1.);
602+
let paris_to_new_york = SphericalLineStringCurve::new(
603+
line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)],
604+
1.,
605+
);
584606
assert_relative_eq!(5837283.441678336, paris_to_new_york.length()); // 5837283.441678336 using [`HaversineLength`] and 5852969.839293494 using [`GeodesicLength`]
585607

586-
let lille_to_perpignan = SphericalLineStringCurve::new(line_string![(x: LILLE_LON, y: LILLE_LAT), (x: PERPIGNAN_LON, y: PERPIGNAN_LAT)], 1.);
608+
let lille_to_perpignan = SphericalLineStringCurve::new(
609+
line_string![(x: LILLE_LON, y: LILLE_LAT), (x: PERPIGNAN_LON, y: PERPIGNAN_LAT)],
610+
1.,
611+
);
587612
assert_relative_eq!(883505.2931188548, lille_to_perpignan.length()); // 883505.2931188548 using [`HaversineLength`] and 883260.051153502 using [`GeodesicLength`]
588613

589-
let brest_to_nancy = SphericalLineStringCurve::new(line_string![(x: BREST_LON, y: BREST_LAT), (x: NANCY_LON, y: NANCY_LAT)], 1.);
614+
let brest_to_nancy = SphericalLineStringCurve::new(
615+
line_string![(x: BREST_LON, y: BREST_LAT), (x: NANCY_LON, y: NANCY_LAT)],
616+
1.,
617+
);
590618
assert_relative_eq!(785636.8730262491, brest_to_nancy.length()); // 785636.8730262491 using [`HaversineLength`] and 787994.4363866252 using [`GeodesicLength`]
591619
}
592620

@@ -605,66 +633,90 @@ mod tests {
605633
assert!(!curve.is_valid());
606634

607635
// Invalid curve: longitude > 180.
608-
let curve = SphericalLineStringCurve::new(line_string![(x: 180.1, y: 0.), (x: 0., y: 0.)], 1.);
636+
let curve =
637+
SphericalLineStringCurve::new(line_string![(x: 180.1, y: 0.), (x: 0., y: 0.)], 1.);
609638
assert!(!curve.is_valid());
610639

611640
// Invalid curve: longitude < -180.
612-
let curve = SphericalLineStringCurve::new(line_string![(x: -180.1, y: 0.), (x: 0., y: 0.)], 1.);
641+
let curve =
642+
SphericalLineStringCurve::new(line_string![(x: -180.1, y: 0.), (x: 0., y: 0.)], 1.);
613643
assert!(!curve.is_valid());
614644

615645
// Invalid curve: latitude > 90.
616-
let curve = SphericalLineStringCurve::new(line_string![(x: 0., y: 90.1), (x: 0., y: 0.)], 1.);
646+
let curve =
647+
SphericalLineStringCurve::new(line_string![(x: 0., y: 90.1), (x: 0., y: 0.)], 1.);
617648
assert!(!curve.is_valid());
618649

619650
// Invalid curve: latitude > 180.
620-
let curve = SphericalLineStringCurve::new(line_string![(x: 0., y: -90.1), (x: 0., y: 0.)], 1.);
651+
let curve =
652+
SphericalLineStringCurve::new(line_string![(x: 0., y: -90.1), (x: 0., y: 0.)], 1.);
621653
assert!(!curve.is_valid());
622654
}
623655

624656
#[test]
625657
fn spherical_projection() {
626-
let mut paris_to_new_york = SphericalLineStringCurve::new(line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)], 1.);
658+
let mut paris_to_new_york = SphericalLineStringCurve::new(
659+
line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)],
660+
1.,
661+
);
627662

628663
// Point is located on the right (north) of the curve
629-
let projected = paris_to_new_york.project(point! {x: -6.705403880820967, y: 51.42135181702875}).unwrap();
664+
let projected = paris_to_new_york
665+
.project(point! {x: -6.705403880820967, y: 51.42135181702875})
666+
.unwrap();
630667
assert_eq!(701924.3809693493, projected.distance_along_curve);
631668
assert_eq!(-67157.93913531031, projected.offset);
632669

633670
// Point is located on the left (south) of the curve
634-
let projected = paris_to_new_york.project(point! {x: -12.250890759346419, y: 45.857650969554356}).unwrap();
671+
let projected = paris_to_new_york
672+
.project(point! {x: -12.250890759346419, y: 45.857650969554356})
673+
.unwrap();
635674
assert_eq!(963365.3768036617, projected.distance_along_curve);
636675
assert_eq!(625592.3211438804, projected.offset);
637676

638677
// Same point, but with an offset from the curve
639678
paris_to_new_york.start_offset = 1000000.;
640-
let projected = paris_to_new_york.project(point! {x: -12.250890759346419, y: 45.857650969554356}).unwrap();
679+
let projected = paris_to_new_york
680+
.project(point! {x: -12.250890759346419, y: 45.857650969554356})
681+
.unwrap();
641682
assert_eq!(1963365.3768036617, projected.distance_along_curve);
642683
assert_eq!(625592.3211438804, projected.offset);
643684

644685
// ################################################################################
645-
let mut new_york_to_paris = SphericalLineStringCurve::new(line_string![(x: NEW_YORK_LON, y: NEW_YORK_LAT), (x: PARIS_LON, y: PARIS_LAT)], 1.);
686+
let mut new_york_to_paris = SphericalLineStringCurve::new(
687+
line_string![(x: NEW_YORK_LON, y: NEW_YORK_LAT), (x: PARIS_LON, y: PARIS_LAT)],
688+
1.,
689+
);
646690

647691
// Point is located on the left (north) of the curve
648-
let projected = new_york_to_paris.project(point! {x: -6.705403880820967, y: 51.42135181702875}).unwrap();
692+
let projected = new_york_to_paris
693+
.project(point! {x: -6.705403880820967, y: 51.42135181702875})
694+
.unwrap();
649695
assert_eq!(5135359.060708988, projected.distance_along_curve);
650696
assert_eq!(67157.93913531031, projected.offset);
651697

652698
// Point is located on the right (south) of the curve
653-
let projected = new_york_to_paris.project(point! {x: -12.250890759346419, y: 45.857650969554356}).unwrap();
699+
let projected = new_york_to_paris
700+
.project(point! {x: -12.250890759346419, y: 45.857650969554356})
701+
.unwrap();
654702
assert_eq!(4873918.064874676, projected.distance_along_curve);
655703
assert_eq!(-625592.3211438811, projected.offset); // Note: result is weird -> distance should remain the same than the other way curve, difference is 0.7mm
656704

657-
658705
// Same point, but with an offset from the curve
659706
new_york_to_paris.start_offset = 1000000.;
660-
let projected = new_york_to_paris.project(point! {x: -12.250890759346419, y: 45.857650969554356}).unwrap();
707+
let projected = new_york_to_paris
708+
.project(point! {x: -12.250890759346419, y: 45.857650969554356})
709+
.unwrap();
661710
assert_eq!(5873918.064874676, projected.distance_along_curve);
662711
assert_eq!(-625592.3211438811, projected.offset); // Note: same, difference is 0.7mm
663712
}
664713

665714
#[test]
666715
fn spherical_resolve() {
667-
let mut paris_to_new_york = SphericalLineStringCurve::new(line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)], 1.);
716+
let mut paris_to_new_york = SphericalLineStringCurve::new(
717+
line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)],
718+
1.,
719+
);
668720

669721
let mut projection = CurveProjection {
670722
distance_along_curve: 1000000.,
@@ -683,7 +735,10 @@ mod tests {
683735
assert!(paris_to_new_york.resolve(projection).is_err());
684736

685737
// ################################################################################
686-
let lille_to_perpignan = SphericalLineStringCurve::new(line_string![(x: LILLE_LON, y: LILLE_LAT), (x: PERPIGNAN_LON, y: PERPIGNAN_LAT)], 1.);
738+
let lille_to_perpignan = SphericalLineStringCurve::new(
739+
line_string![(x: LILLE_LON, y: LILLE_LAT), (x: PERPIGNAN_LON, y: PERPIGNAN_LAT)],
740+
1.,
741+
);
687742

688743
let projection = CurveProjection {
689744
distance_along_curve: 500000.,
@@ -694,7 +749,10 @@ mod tests {
694749
assert_eq!(lille_to_perpignan_p.y(), 46.13725407237963);
695750

696751
// ################################################################################
697-
let brest_to_nancy = SphericalLineStringCurve::new(line_string![(x: BREST_LON, y: BREST_LAT), (x: NANCY_LON, y: NANCY_LAT)], 1.);
752+
let brest_to_nancy = SphericalLineStringCurve::new(
753+
line_string![(x: BREST_LON, y: BREST_LAT), (x: NANCY_LON, y: NANCY_LAT)],
754+
1.,
755+
);
698756

699757
let projection = CurveProjection {
700758
distance_along_curve: 500000.,
@@ -707,37 +765,66 @@ mod tests {
707765

708766
#[test]
709767
fn spherical_bbox() {
710-
let paris_to_new_york = SphericalLineStringCurve::new(line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)], 1.);
768+
let paris_to_new_york = SphericalLineStringCurve::new(
769+
line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)],
770+
1.,
771+
);
711772
let bbox = paris_to_new_york.bbox();
712773

713-
assert_eq!(bbox.min(), coord! {x: -75.00599134051316, y: 39.71274961837565});
714-
assert_eq!(bbox.max(), coord! {x: 3.352565660016694, y: 49.85643268390663});
774+
assert_eq!(
775+
bbox.min(),
776+
coord! {x: -75.00599134051316, y: 39.71274961837565}
777+
);
778+
assert_eq!(
779+
bbox.max(),
780+
coord! {x: 3.352565660016694, y: 49.85643268390663}
781+
);
715782
}
716783

717784
#[test]
718785
fn spherical_intersect_segment() {
719786
// Note: following tests have been computed with a maximum length of curve of 100m, otherwise the curve is densified.
720-
787+
721788
// Intersection
722-
let paris_to_new_york = SphericalLineStringCurve::new(line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)], 1.);
723-
let segment = Line::new(coord! {x: -36.76627263796084, y: 69.72980545457074}, coord! {x: -53.52127629098692, y: 15.34337895024332});
724-
assert_eq!(paris_to_new_york.intersect_segment(segment), Some(point! {x: -42.500669938830555, y: 51.11605974559634}));
789+
let paris_to_new_york = SphericalLineStringCurve::new(
790+
line_string![(x: PARIS_LON, y: PARIS_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)],
791+
1.,
792+
);
793+
let segment = Line::new(
794+
coord! {x: -36.76627263796084, y: 69.72980545457074},
795+
coord! {x: -53.52127629098692, y: 15.34337895024332},
796+
);
797+
assert_eq!(
798+
paris_to_new_york.intersect_segment(segment),
799+
Some(point! {x: -42.500669938830555, y: 51.11605974559634})
800+
);
725801

726802
// No intersection
727-
let segment = Line::new(coord! {x: -88.45243862592235, y: 20.758717928501483}, coord! {x:19.035989490700018, y: 41.32134615429521});
803+
let segment = Line::new(
804+
coord! {x: -88.45243862592235, y: 20.758717928501483},
805+
coord! {x:19.035989490700018, y: 41.32134615429521},
806+
);
728807
assert!(paris_to_new_york.intersect_segment(segment).is_none());
729808

730809
// TODO: Collinear
731-
// Notes:
810+
// Notes:
732811
// - because of the haversine densification, the geometry is slightly different and includes more points
733812
// than before, thus creating intersection(s) point(s).
734813
// - is very rare in reality
735814

736815
// Multiple intersection
737-
let paris_to_reykjavik_to_new_york = SphericalLineStringCurve::new(line_string![(x: PARIS_LON, y: PARIS_LAT), (x: REYKJAVIK_LON, y: REYKJAVIK_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)], 1.);
816+
let paris_to_reykjavik_to_new_york = SphericalLineStringCurve::new(
817+
line_string![(x: PARIS_LON, y: PARIS_LAT), (x: REYKJAVIK_LON, y: REYKJAVIK_LAT), (x: NEW_YORK_LON, y: NEW_YORK_LAT)],
818+
1.,
819+
);
738820

739-
let segment = Line::new(coord! {x: -70.77775907909825, y: 47.835409180411006}, coord! {x: 9.293636086504506, y: 54.83039737996501});
740-
assert!(paris_to_reykjavik_to_new_york.intersect_segment(segment).is_some());
821+
let segment = Line::new(
822+
coord! {x: -70.77775907909825, y: 47.835409180411006},
823+
coord! {x: 9.293636086504506, y: 54.83039737996501},
824+
);
825+
assert!(paris_to_reykjavik_to_new_york
826+
.intersect_segment(segment)
827+
.is_some());
741828
}
742829

743830
#[test]
@@ -746,14 +833,24 @@ mod tests {
746833
let earth_circumference = 6371008.8 * std::f64::consts::PI * 2.; // = 40030228.88407185 m
747834
let normalized_translation_on_earth = 360. / earth_circumference;
748835

749-
let longitudinal_curve = SphericalLineStringCurve::new(line_string![(x: 0., y: 0.), (x: 1., y: 0.)], 1.);
836+
let longitudinal_curve =
837+
SphericalLineStringCurve::new(line_string![(x: 0., y: 0.), (x: 1., y: 0.)], 1.);
750838
let longitudinal_normal = longitudinal_curve.get_normal(0.).unwrap();
751839
assert_relative_eq!(longitudinal_normal.0, 0., epsilon = 1e-7);
752-
assert_relative_eq!(longitudinal_normal.1, normalized_translation_on_earth, epsilon = 1e-4);
840+
assert_relative_eq!(
841+
longitudinal_normal.1,
842+
normalized_translation_on_earth,
843+
epsilon = 1e-4
844+
);
753845

754-
let latitudinal_curve = SphericalLineStringCurve::new(line_string![(x: 0., y: 0.), (x: 0., y: 1.)], 1.);
846+
let latitudinal_curve =
847+
SphericalLineStringCurve::new(line_string![(x: 0., y: 0.), (x: 0., y: 1.)], 1.);
755848
let latitudinal_normal = latitudinal_curve.get_normal(0.).unwrap();
756-
assert_relative_eq!(latitudinal_normal.0, normalized_translation_on_earth, epsilon = 1e-8);
849+
assert_relative_eq!(
850+
latitudinal_normal.0,
851+
normalized_translation_on_earth,
852+
epsilon = 1e-8
853+
);
757854
assert_relative_eq!(latitudinal_normal.1, 0., epsilon = 1e-7);
758855
}
759856
}

0 commit comments

Comments
 (0)