Rev 420 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (c) 2009, Chris Miller
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package uk.me.parabola.splitter;
/**
* Utility methods for rounding numbers and areas
*
* @author Chris Miller
*/
public class RoundingUtils
{
/**
* Rounds an integer down to the nearest multiple of {@code 2^shift}.
* Works with both positive and negative integers.
* @param val the integer to round down.
* @param shift the power of two to round down to.
* @return the rounded integer.
*/
public static int roundDown
(int val,
int shift
) {
return val
>>> shift
<< shift
;
}
/**
* Rounds an integer up to the nearest multiple of {@code 2^shift}.
* Works with both positive and negative integers.
* @param val the integer to round up.
* @param shift the power of two to round up to.
* @return the rounded integer.
*/
public static int roundUp
(int val,
int shift
) {
return (val +
(1 << shift
) -
1) >>> shift
<< shift
;
}
/**
* Rounds an integer up or down to the nearest multiple of {@code 2^shift}.
* Works with both positive and negative integers.
* @param val the integer to round.
* @param shift the power of two to round to.
* @return the rounded integer.
*/
public static int round
(int val,
int shift
) {
return (val +
(1 << (shift -
1))) >>> shift
<< shift
;
}
/**
* Rounds an area's borders to suit the supplied resolution. This
* means edges are aligned at 2 ^ (24 - resolution) boundaries
*
* @param b the area to round
* @param resolution the map resolution to align the borders at
* @return the rounded area
*/
public static Area round
(Area b,
int resolution
) {
int shift =
24 - resolution
;
int alignment =
1 << shift
;
// Avoid pathological behaviour near the poles by discarding anything
// greater than +/-85 degrees latitude.
int minLat =
Math.
max(b.
getMinLat(), Utils.
toMapUnit(-85.0d
));
int maxLat =
Math.
min(b.
getMaxLat(), Utils.
toMapUnit(85.0d
));
int roundedMinLat = roundDown
(minLat, shift
);
int roundedMaxLat = roundUp
(maxLat, shift
);
assert roundedMinLat
% alignment ==
0 :
"The area's min latitude is not aligned to a multiple of " + alignment
;
assert roundedMaxLat
% alignment ==
0 :
"The area's max latitude is not aligned to a multiple of " + alignment
;
int roundedMinLon = roundDown
(b.
getMinLong(), shift
);
int roundedMaxLon = roundUp
(b.
getMaxLong(), shift
);
// don't produce illegal values
if (roundedMinLon
< -0x800000
)
roundedMinLon = -0x800000
;
if (roundedMaxLon
> 0x800000
)
roundedMaxLon = 0x800000
;
assert roundedMinLon
% alignment ==
0 :
"The area's min longitude is not aligned to a multiple of " + alignment
;
assert roundedMaxLon
% alignment ==
0 :
"The area's max longitude is not aligned to a multiple of " + alignment
;
return new Area(roundedMinLat, roundedMinLon, roundedMaxLat, roundedMaxLon
);
}
}