@@ -12,6 +12,9 @@ pub trait RhumbDestination<T: CoordFloat> {
12
12
/// Returns the destination Point having travelled the given distance along a [rhumb line]
13
13
/// from the origin Point with the given bearing
14
14
///
15
+ /// A rhumb line has a finite length, so if the path distance exceeds the location of the pole,
16
+ /// the result is None.
17
+ ///
15
18
/// # Units
16
19
///
17
20
/// - `bearing`: degrees, zero degrees is north
@@ -24,18 +27,18 @@ pub trait RhumbDestination<T: CoordFloat> {
24
27
/// use geo::Point;
25
28
///
26
29
/// let p_1 = Point::new(9.177789688110352, 48.776781529534965);
27
- /// let p_2 = p_1.rhumb_destination(45., 10000.);
30
+ /// let p_2 = p_1.rhumb_destination(45., 10000.).unwrap() ;
28
31
/// assert_eq!(p_2, Point::new(9.274348757829898, 48.84037308229984))
29
32
/// ```
30
33
/// [rhumb line]: https://en.wikipedia.org/wiki/Rhumb_line
31
- fn rhumb_destination ( & self , bearing : T , distance : T ) -> Point < T > ;
34
+ fn rhumb_destination ( & self , bearing : T , distance : T ) -> Option < Point < T > > ;
32
35
}
33
36
34
37
impl < T > RhumbDestination < T > for Point < T >
35
38
where
36
39
T : CoordFloat + FromPrimitive ,
37
40
{
38
- fn rhumb_destination ( & self , bearing : T , distance : T ) -> Point < T > {
41
+ fn rhumb_destination ( & self , bearing : T , distance : T ) -> Option < Point < T > > {
39
42
let delta = distance / T :: from ( MEAN_EARTH_RADIUS ) . unwrap ( ) ; // angular distance in radians
40
43
let lambda1 = self . x ( ) . to_radians ( ) ;
41
44
let phi1 = self . y ( ) . to_radians ( ) ;
@@ -49,32 +52,38 @@ where
49
52
mod test {
50
53
use super :: * ;
51
54
use crate :: RhumbDistance ;
52
- use num_traits:: pow;
53
55
54
56
#[ test]
55
57
fn returns_a_new_point ( ) {
56
58
let p_1 = Point :: new ( 9.177789688110352 , 48.776781529534965 ) ;
57
- let p_2 = p_1. rhumb_destination ( 45. , 10000. ) ;
59
+ let p_2 = p_1. rhumb_destination ( 45. , 10000. ) . unwrap ( ) ;
58
60
assert_eq ! ( p_2, Point :: new( 9.274348757829898 , 48.84037308229984 ) ) ;
59
61
let distance = p_1. rhumb_distance ( & p_2) ;
60
- assert_relative_eq ! ( distance, 10000. , epsilon = 1.0e-6 )
62
+ assert_relative_eq ! ( distance, 10000. , epsilon = 1.0e-6 ) ;
61
63
}
62
64
63
65
#[ test]
64
66
fn direct_and_indirect_destinations_are_close ( ) {
65
67
let p_1 = Point :: new ( 9.177789688110352 , 48.776781529534965 ) ;
66
- let p_2 = p_1. rhumb_destination ( 45. , 10000. ) ;
67
- let square_edge = { pow ( 10000. , 2 ) / 2f64 } . sqrt ( ) ;
68
- let p_3 = p_1. rhumb_destination ( 0. , square_edge) ;
69
- let p_4 = p_3. rhumb_destination ( 90. , square_edge) ;
68
+ let p_2 = p_1. rhumb_destination ( 45. , 10000. ) . unwrap ( ) ;
69
+ let square_edge = 10000.0 * 0.5f64 . sqrt ( ) ;
70
+ let p_3 = p_1. rhumb_destination ( 0. , square_edge) . unwrap ( ) ;
71
+ let p_4 = p_3. rhumb_destination ( 90. , square_edge) . unwrap ( ) ;
70
72
assert_relative_eq ! ( p_4, p_2, epsilon = 1.0e-3 ) ;
71
73
}
72
74
73
75
#[ test]
74
76
fn bearing_zero_is_north ( ) {
75
77
let p_1 = Point :: new ( 9.177789688110352 , 48.776781529534965 ) ;
76
- let p_2 = p_1. rhumb_destination ( 0. , 1000. ) ;
78
+ let p_2 = p_1. rhumb_destination ( 0. , 1000. ) . unwrap ( ) ;
77
79
assert_relative_eq ! ( p_1. x( ) , p_2. x( ) , epsilon = 1.0e-6 ) ;
78
- assert ! ( p_2. y( ) > p_1. y( ) )
80
+ assert ! ( p_2. y( ) > p_1. y( ) ) ;
81
+ }
82
+
83
+ #[ test]
84
+ fn past_the_pole ( ) {
85
+ let p = Point :: new ( 9.177789688110352 , 48.776781529534965 ) ;
86
+ let result = p. rhumb_destination ( 0. , 1e8 ) ;
87
+ assert ! ( result. is_none( ) ) ;
79
88
}
80
89
}
0 commit comments