Implement a cache for the cosine computation in CheapRuler.
This commit is contained in:
parent
665b7096e8
commit
c78b56645c
5 changed files with 107 additions and 48 deletions
|
@ -2,7 +2,7 @@ package btools.router;
|
||||||
|
|
||||||
import btools.mapaccess.OsmNode;
|
import btools.mapaccess.OsmNode;
|
||||||
import btools.mapaccess.OsmPos;
|
import btools.mapaccess.OsmPos;
|
||||||
import btools.util.CheapRuler;
|
import btools.util.CheapRulerSingleton;
|
||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
|
@ -78,7 +78,8 @@ public class OsmPathElement implements OsmPos
|
||||||
|
|
||||||
public final int calcDistance( OsmPos p )
|
public final int calcDistance( OsmPos p )
|
||||||
{
|
{
|
||||||
return (int)(CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||||
|
return (int)(cr.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
public OsmPathElement origin;
|
public OsmPathElement origin;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import btools.codec.MicroCache;
|
||||||
import btools.codec.MicroCache2;
|
import btools.codec.MicroCache2;
|
||||||
import btools.expressions.BExpressionContextWay;
|
import btools.expressions.BExpressionContextWay;
|
||||||
import btools.util.ByteArrayUnifier;
|
import btools.util.ByteArrayUnifier;
|
||||||
import btools.util.CheapRuler;
|
import btools.util.CheapRulerSingleton;
|
||||||
import btools.util.IByteArrayUnifier;
|
import btools.util.IByteArrayUnifier;
|
||||||
|
|
||||||
public class OsmNode extends OsmLink implements OsmPos
|
public class OsmNode extends OsmLink implements OsmPos
|
||||||
|
@ -103,7 +103,8 @@ public class OsmNode extends OsmLink implements OsmPos
|
||||||
|
|
||||||
public final int calcDistance( OsmPos p )
|
public final int calcDistance( OsmPos p )
|
||||||
{
|
{
|
||||||
return (int) (CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0);
|
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||||
|
return (int) (cr.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
package btools.memrouter;
|
package btools.memrouter;
|
||||||
|
|
||||||
import btools.mapaccess.OsmPos;
|
import btools.mapaccess.OsmPos;
|
||||||
import btools.util.CheapRuler;
|
import btools.util.CheapRulerSingleton;
|
||||||
|
|
||||||
public class OsmNodeP extends OsmLinkP implements Comparable<OsmNodeP>, OsmPos
|
public class OsmNodeP extends OsmLinkP implements Comparable<OsmNodeP>, OsmPos
|
||||||
{
|
{
|
||||||
|
@ -103,7 +103,8 @@ public class OsmNodeP extends OsmLinkP implements Comparable<OsmNodeP>, OsmPos
|
||||||
@Override
|
@Override
|
||||||
public int calcDistance( OsmPos p )
|
public int calcDistance( OsmPos p )
|
||||||
{
|
{
|
||||||
return (int)(CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||||
|
return (int)(cr.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
package btools.util;
|
|
||||||
|
|
||||||
public final class CheapRuler {
|
|
||||||
/**
|
|
||||||
* Cheap-Ruler Java implementation
|
|
||||||
* See
|
|
||||||
* https://blog.mapbox.com/fast-geodesic-approximations-with-cheap-ruler-106f229ad016
|
|
||||||
* for more details.
|
|
||||||
*
|
|
||||||
* Original code is at https://github.com/mapbox/cheap-ruler under ISC license.
|
|
||||||
*/
|
|
||||||
static int KILOMETERS_TO_METERS = 1000;
|
|
||||||
static double ILATLNG_TO_LATLNG = 1e-6;
|
|
||||||
static double DEG_TO_RAD = Math.PI / 180.;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param ilon1 Integer longitude for the start point. this is (longitude in degrees + 180) * 1e6.
|
|
||||||
* @param ilat1 Integer latitude for the start point, this is (latitude + 90) * 1e6.
|
|
||||||
* @param ilon2 Integer longitude for the end point, this is (longitude + 180) * 1e6.
|
|
||||||
* @param ilat2 Integer latitude for the end point, this is (latitude + 90) * 1e6.
|
|
||||||
*
|
|
||||||
* @note Integer longitude is ((longitude in degrees) + 180) * 1e6.
|
|
||||||
* Integer latitude is ((latitude in degrees) + 90) * 1e6.
|
|
||||||
*/
|
|
||||||
static public double distance(int ilon1, int ilat1, int ilon2, int ilat2) {
|
|
||||||
double lat1 = ilat1 * ILATLNG_TO_LATLNG - 90.; // Real latitude, in degrees
|
|
||||||
double cos = Math.cos(lat1 * DEG_TO_RAD);
|
|
||||||
double cos2 = 2 * cos * cos - 1;
|
|
||||||
double cos3 = 2 * cos * cos2 - cos;
|
|
||||||
double cos4 = 2 * cos * cos3 - cos2;
|
|
||||||
double cos5 = 2 * cos * cos4 - cos3;
|
|
||||||
|
|
||||||
// Multipliers for converting integer longitude and latitude into distance
|
|
||||||
// (http://1.usa.gov/1Wb1bv7)
|
|
||||||
double kx = (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5) * ILATLNG_TO_LATLNG * KILOMETERS_TO_METERS;
|
|
||||||
double ky = (111.13209 - 0.56605 * cos2 + 0.0012 * cos4) * ILATLNG_TO_LATLNG * KILOMETERS_TO_METERS;
|
|
||||||
|
|
||||||
double dlat = (ilat1 - ilat2) * ky;
|
|
||||||
double dlon = (ilon1 - ilon2) * kx;
|
|
||||||
return Math.sqrt(dlat * dlat + dlon * dlon); // in m
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
package btools.util;
|
||||||
|
|
||||||
|
public final class CheapRulerSingleton {
|
||||||
|
/**
|
||||||
|
* Cheap-Ruler Java implementation
|
||||||
|
* See
|
||||||
|
* https://blog.mapbox.com/fast-geodesic-approximations-with-cheap-ruler-106f229ad016
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* Original code is at https://github.com/mapbox/cheap-ruler under ISC license.
|
||||||
|
*
|
||||||
|
* This is implemented as a Singleton to have a unique cache for the cosine
|
||||||
|
* values across all the code.
|
||||||
|
*/
|
||||||
|
private static volatile CheapRulerSingleton instance = null;
|
||||||
|
|
||||||
|
// Conversion constants
|
||||||
|
private final static double ILATLNG_TO_LATLNG = 1e-6; // From integer to degrees
|
||||||
|
private final static int KILOMETERS_TO_METERS = 1000;
|
||||||
|
private final static double DEG_TO_RAD = Math.PI / 180.;
|
||||||
|
|
||||||
|
// Cosine cache constants
|
||||||
|
private final static int COS_CACHE_LENGTH = 8192;
|
||||||
|
private final static double COS_CACHE_MAX_DEGREES = 90.0;
|
||||||
|
// COS_CACHE_LENGTH cached values between 0 and COS_CACHE_MAX_DEGREES degrees.
|
||||||
|
double[] COS_CACHE = new double[COS_CACHE_LENGTH];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to build the cache of cosine values.
|
||||||
|
*/
|
||||||
|
private void buildCosCache() {
|
||||||
|
double increment = DEG_TO_RAD * COS_CACHE_MAX_DEGREES / COS_CACHE_LENGTH;
|
||||||
|
for (int i = 0; i < COS_CACHE_LENGTH; i++) {
|
||||||
|
COS_CACHE[i] = Math.cos(i * increment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CheapRulerSingleton() {
|
||||||
|
super();
|
||||||
|
// Build the cache of cosine values.
|
||||||
|
buildCosCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an instance of this singleton class.
|
||||||
|
*/
|
||||||
|
public final static CheapRulerSingleton getInstance() {
|
||||||
|
if (CheapRulerSingleton.instance == null) {
|
||||||
|
synchronized(CheapRulerSingleton.class) {
|
||||||
|
if (CheapRulerSingleton.instance == null) {
|
||||||
|
CheapRulerSingleton.instance = new CheapRulerSingleton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CheapRulerSingleton.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to compute the cosine of an integer latitude.
|
||||||
|
*/
|
||||||
|
private double cosLat(int ilat) {
|
||||||
|
double latDegrees = ilat * ILATLNG_TO_LATLNG;
|
||||||
|
if (ilat > 90000000) {
|
||||||
|
// Use the symmetry of the cosine.
|
||||||
|
latDegrees -= 90;
|
||||||
|
}
|
||||||
|
return COS_CACHE[(int) (latDegrees * COS_CACHE_LENGTH / COS_CACHE_MAX_DEGREES)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the distance (in meters) between two points represented by their
|
||||||
|
* (integer) latitude and longitude.
|
||||||
|
*
|
||||||
|
* @param ilon1 Integer longitude for the start point. this is (longitude in degrees + 180) * 1e6.
|
||||||
|
* @param ilat1 Integer latitude for the start point, this is (latitude + 90) * 1e6.
|
||||||
|
* @param ilon2 Integer longitude for the end point, this is (longitude + 180) * 1e6.
|
||||||
|
* @param ilat2 Integer latitude for the end point, this is (latitude + 90) * 1e6.
|
||||||
|
*
|
||||||
|
* @note Integer longitude is ((longitude in degrees) + 180) * 1e6.
|
||||||
|
* Integer latitude is ((latitude in degrees) + 90) * 1e6.
|
||||||
|
*/
|
||||||
|
public double distance(int ilon1, int ilat1, int ilon2, int ilat2) {
|
||||||
|
double cos = cosLat(ilat1);
|
||||||
|
double cos2 = 2 * cos * cos - 1;
|
||||||
|
double cos3 = 2 * cos * cos2 - cos;
|
||||||
|
double cos4 = 2 * cos * cos3 - cos2;
|
||||||
|
double cos5 = 2 * cos * cos4 - cos3;
|
||||||
|
|
||||||
|
// Multipliers for converting integer longitude and latitude into distance
|
||||||
|
// (http://1.usa.gov/1Wb1bv7)
|
||||||
|
double kx = (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5) * ILATLNG_TO_LATLNG * KILOMETERS_TO_METERS;
|
||||||
|
double ky = (111.13209 - 0.56605 * cos2 + 0.0012 * cos4) * ILATLNG_TO_LATLNG * KILOMETERS_TO_METERS;
|
||||||
|
|
||||||
|
double dlat = (ilat1 - ilat2) * ky;
|
||||||
|
double dlon = (ilon1 - ilon2) * kx;
|
||||||
|
return Math.sqrt(dlat * dlat + dlon * dlon); // in m
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue