@@ -119,6 +119,9 @@ macro_rules! gen_key_points_comp {
119
119
120
120
let mut scale = ( 10f64 ) . powf( ( range. 1 - range. 0 ) . log( 10.0 ) . floor( ) ) ;
121
121
// The value granularity controls how we round the values.
122
+ // To avoid generating key points like 1.00000000001, we round to the nearest multiple of the
123
+ // value granularity.
124
+ // By default, we make the granularity as the 1/10 of the scale.
122
125
let mut value_granularity = scale / 10.0 ;
123
126
fn rem_euclid( a: f64 , b: f64 ) -> f64 {
124
127
if b > 0.0 {
@@ -154,15 +157,21 @@ macro_rules! gen_key_points_comp {
154
157
}
155
158
156
159
let mut ret = vec![ ] ;
157
- let mut left = range. 0 + scale - rem_euclid( range. 0 , scale) ;
160
+ // In some extreme cases, left might be too big, so that (left + scale) - left == 0 due to
161
+ // floating point error.
162
+ // In this case, we may loop forever. To avoid this, we need to use two variables to store
163
+ // the current left value. So we need keep a left_base and a left_relative.
164
+ let left = range. 0 + scale - rem_euclid( range. 0 , scale) ;
165
+ let left_base = ( left / value_granularity) . floor( ) * value_granularity;
166
+ let mut left_relative = left - left_base;
158
167
let right = range. 1 - rem_euclid( range. 1 , scale) ;
159
- while left <= right {
160
- let new_left = ( left / value_granularity) . round( ) * value_granularity;
161
- if new_left < range . 0 {
162
- left = new_left + value_granularity;
168
+ while left_relative <= right - left_base {
169
+ let new_left_relative = ( left_relative / value_granularity) . round( ) * value_granularity;
170
+ if new_left_relative < 0 .0 {
171
+ left_relative += value_granularity;
163
172
}
164
- ret. push( left as $type) ;
165
- left += scale;
173
+ ret. push( ( left_relative + left_base ) as $type) ;
174
+ left_relative += scale;
166
175
}
167
176
return ret;
168
177
}
@@ -388,4 +397,11 @@ mod test {
388
397
let points = coord. key_points ( 500 ) ;
389
398
assert ! ( points. len( ) <= 500 ) ;
390
399
}
400
+
401
+ #[ test]
402
+ fn regression_test_issue_358_key_points_no_hang_2 ( ) {
403
+ let coord: RangedCoordf64 = ( 10000000000001f64 ..10000000000002f64 ) . into ( ) ;
404
+ let points = coord. key_points ( 500 ) ;
405
+ assert ! ( points. len( ) <= 500 ) ;
406
+ }
391
407
}
0 commit comments