Better distance computation (revisited)
This commit is contained in:
parent
e7afb236a6
commit
ab2f5e3ae0
12 changed files with 101 additions and 543 deletions
|
@ -75,8 +75,6 @@ public class OsmNogoPolygon extends OsmNodeNamed
|
|||
*/
|
||||
public void calcBoundingCircle()
|
||||
{
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
|
||||
int cxmin, cxmax, cymin, cymax;
|
||||
cxmin = cymin = Integer.MAX_VALUE;
|
||||
cxmax = cymax = Integer.MIN_VALUE;
|
||||
|
@ -103,9 +101,13 @@ public class OsmNogoPolygon extends OsmNodeNamed
|
|||
}
|
||||
}
|
||||
|
||||
double cx = (cxmax+cxmin) / 2.0; // center of circle
|
||||
double cy = (cymax+cymin) / 2.0;
|
||||
double ccoslat = cr.cosIlat((int) cy); // cosin at latitude of center
|
||||
int cx = (cxmax+cxmin) / 2; // center of circle
|
||||
int cy = (cymax+cymin) / 2;
|
||||
|
||||
double[] lonlat2m = CheapRulerSingleton.getLonLatToMeterScales( cy );
|
||||
double dlon2m = lonlat2m[0];
|
||||
double dlat2m = lonlat2m[1];
|
||||
|
||||
double rad = 0; // radius
|
||||
double rad2 = 0; // radius squared;
|
||||
|
||||
|
@ -119,8 +121,8 @@ public class OsmNogoPolygon extends OsmNodeNamed
|
|||
for (int i = 0; i < points.size();i++)
|
||||
{
|
||||
final Point p = points.get(i);
|
||||
final double dpix = (p.x - cx) * ccoslat;
|
||||
final double dpiy = p.y-cy;
|
||||
final double dpix = (p.x - cx) * dlon2m;
|
||||
final double dpiy = (p.y - cy) * dlat2m;
|
||||
final double dist2 = dpix * dpix + dpiy * dpiy;
|
||||
if (dist2 <= rad2)
|
||||
{
|
||||
|
@ -129,8 +131,8 @@ public class OsmNogoPolygon extends OsmNodeNamed
|
|||
if (dist2 > dmax2)
|
||||
{
|
||||
dmax2 = dist2; // new maximum distance found
|
||||
dpx = dpix;
|
||||
dpy = dpiy;
|
||||
dpx = dpix / dlon2m;
|
||||
dpy = dpiy / dlat2m;
|
||||
i_max = i;
|
||||
}
|
||||
}
|
||||
|
@ -141,25 +143,21 @@ public class OsmNogoPolygon extends OsmNodeNamed
|
|||
final double dist = Math.sqrt(dmax2);
|
||||
final double dd = 0.5 * (dist - rad) / dist;
|
||||
|
||||
cx = cx + dd * dpx; // shift center toward point
|
||||
cy = cy + dd * dpy;
|
||||
ccoslat = cr.cosIlat((int) cy);
|
||||
cx += (int)(dd * dpx + 0.5); // shift center toward point
|
||||
cy += (int)(dd * dpy + 0.5);
|
||||
|
||||
final Point p = points.get(i_max); // calculate new radius to just include this point
|
||||
final double dpix = (p.x - cx) * ccoslat;
|
||||
final double dpiy = p.y-cy;
|
||||
final double dpix = (p.x - cx) * dlon2m;
|
||||
final double dpiy = (p.y - cy) * dlat2m;
|
||||
dmax2 = rad2 = dpix * dpix + dpiy * dpiy;
|
||||
rad = Math.sqrt(rad2);
|
||||
i_max = -1;
|
||||
}
|
||||
while (true);
|
||||
|
||||
ilon = (int) Math.round(cx);
|
||||
ilat = (int) Math.round(cy);
|
||||
dpx = cx - ilon; // rounding error
|
||||
dpy = cy - ilat;
|
||||
// compensate rounding error of center-point
|
||||
radius = (rad + Math.sqrt(dpx * dpx + dpy * dpy)) * cr.ILATLNG_TO_LATLNG;
|
||||
ilon = cx;
|
||||
ilat = cy;
|
||||
radius = rad;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package btools.router;
|
||||
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmPos;
|
||||
import btools.util.CheapRulerSingleton;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmPos;
|
||||
import btools.util.CheapRulerSingleton;
|
||||
|
||||
/**
|
||||
* Container for link between two Osm nodes
|
||||
*
|
||||
|
@ -78,8 +78,7 @@ public class OsmPathElement implements OsmPos
|
|||
|
||||
public final int calcDistance( OsmPos p )
|
||||
{
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
return (int)(cr.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
||||
return (int)(CheapRulerSingleton.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
||||
}
|
||||
|
||||
public OsmPathElement origin;
|
||||
|
|
|
@ -288,8 +288,7 @@ public final class RoutingContext
|
|||
OsmNodeNamed nogo = nogopoints.get(i);
|
||||
cs[0] += nogo.ilon;
|
||||
cs[1] += nogo.ilat;
|
||||
// TODO[Phyks]
|
||||
cs[2] += (long) ( nogo.radius*111894.*10.);
|
||||
cs[2] += (long) ( nogo.radius*10.);
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
|
@ -311,13 +310,11 @@ public final class RoutingContext
|
|||
|
||||
public int calcDistance( int lon1, int lat1, int lon2, int lat2 )
|
||||
{
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
|
||||
coslat = cr.cosIlat(lat2);
|
||||
double coslat6 = coslat*cr.ILATLNG_TO_LATLNG;
|
||||
|
||||
double dx = (lon2 - lon1 ) * coslat6;
|
||||
double dy = (lat2 - lat1 ) * cr.ILATLNG_TO_LATLNG;
|
||||
double[] lonlat2m = CheapRulerSingleton.getLonLatToMeterScales( (lat1+lat2) >> 1 );
|
||||
double dlon2m = lonlat2m[0];
|
||||
double dlat2m = lonlat2m[1];
|
||||
double dx = (lon2 - lon1 ) * dlon2m;
|
||||
double dy = (lat2 - lat1 ) * dlat2m;
|
||||
double d = Math.sqrt( dy*dy + dx*dx );
|
||||
|
||||
shortestmatch = false;
|
||||
|
@ -327,10 +324,10 @@ public final class RoutingContext
|
|||
for( int ngidx = 0; ngidx < nogopoints.size(); ngidx++ )
|
||||
{
|
||||
OsmNodeNamed nogo = nogopoints.get(ngidx);
|
||||
double x1 = (lon1 - nogo.ilon) * coslat6;
|
||||
double y1 = (lat1 - nogo.ilat) * cr.ILATLNG_TO_LATLNG;
|
||||
double x2 = (lon2 - nogo.ilon) * coslat6;
|
||||
double y2 = (lat2 - nogo.ilat) * cr.ILATLNG_TO_LATLNG;
|
||||
double x1 = (lon1 - nogo.ilon) * dlon2m;
|
||||
double y1 = (lat1 - nogo.ilat) * dlat2m;
|
||||
double x2 = (lon2 - nogo.ilon) * dlon2m;
|
||||
double y2 = (lat2 - nogo.ilat) * dlat2m;
|
||||
double r12 = x1*x1 + y1*y1;
|
||||
double r22 = x2*x2 + y2*y2;
|
||||
double radius = Math.abs( r12 < r22 ? y1*dx - x1*dy : y2*dx - x2*dy ) / d;
|
||||
|
@ -365,8 +362,8 @@ public final class RoutingContext
|
|||
wayfraction = -s2 / (d*d);
|
||||
double xm = x2 - wayfraction*dx;
|
||||
double ym = y2 - wayfraction*dy;
|
||||
ilonshortest = (int)(xm / coslat6 + nogo.ilon);
|
||||
ilatshortest = (int)(ym / cr.ILATLNG_TO_LATLNG + nogo.ilat);
|
||||
ilonshortest = (int)(xm / dlon2m + nogo.ilon);
|
||||
ilatshortest = (int)(ym / dlat2m + nogo.ilat);
|
||||
}
|
||||
else if ( s1 > s2 )
|
||||
{
|
||||
|
@ -397,14 +394,14 @@ public final class RoutingContext
|
|||
lon1 = ilonshortest;
|
||||
lat1 = ilatshortest;
|
||||
}
|
||||
dx = (lon2 - lon1 ) * coslat6;
|
||||
dy = (lat2 - lat1 ) * cr.ILATLNG_TO_LATLNG;
|
||||
dx = (lon2 - lon1 ) * dlon2m;
|
||||
dy = (lat2 - lat1 ) * dlat2m;
|
||||
d = Math.sqrt( dy*dy + dx*dx );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (int)(cr.distance(lon1, lat1, lon2, lat2) + 1.0 );
|
||||
return (int)(d + 1.0 );
|
||||
}
|
||||
|
||||
// assumes that calcDistance/calcCosAngle called in sequence, so coslat valid
|
||||
|
|
|
@ -742,7 +742,7 @@ public class RoutingEngine extends Thread
|
|||
OsmPath startPath = routingContext.createPath( startLink );
|
||||
startLink.addLinkHolder( startPath, null );
|
||||
|
||||
if ( wp != null ) wp.radius = 1e-5;
|
||||
if ( wp != null ) wp.radius = 0.1;
|
||||
|
||||
return routingContext.createPath( startPath, link, null, guideTrack != null );
|
||||
}
|
||||
|
@ -1064,7 +1064,7 @@ public class RoutingEngine extends Thread
|
|||
{
|
||||
if ( isFinalLink )
|
||||
{
|
||||
endPos.radius = 1e-5;
|
||||
endPos.radius = 0.1;
|
||||
routingContext.setWaypoint( endPos, true );
|
||||
}
|
||||
OsmPath testPath = routingContext.createPath( otherPath, link, refTrack, guideTrack != null );
|
||||
|
|
|
@ -181,407 +181,6 @@ final class StdPath extends OsmPath
|
|||
}
|
||||
|
||||
|
||||
// @Override
|
||||
protected void xxxaddAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
|
||||
{
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
|
||||
byte[] description = link.descriptionBitmap;
|
||||
if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
|
||||
|
||||
boolean recordTransferNodes = detailMode || rc.countTraffic;
|
||||
boolean recordMessageData = detailMode;
|
||||
|
||||
rc.nogomatch = false;
|
||||
|
||||
// extract the 3 positions of the first section
|
||||
int lon0 = origin.originLon;
|
||||
int lat0 = origin.originLat;
|
||||
|
||||
OsmNode p1 = sourceNode;
|
||||
int lon1 = p1.getILon();
|
||||
int lat1 = p1.getILat();
|
||||
short ele1 = origin.selev;
|
||||
|
||||
int linkdisttotal = 0;
|
||||
|
||||
MessageData msgData = recordMessageData ? new MessageData() : null;
|
||||
|
||||
boolean isReverse = link.isReverse( sourceNode );
|
||||
|
||||
// evaluate the way tags
|
||||
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
|
||||
|
||||
// calculate the costfactor inputs
|
||||
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
|
||||
float turncostbase = rc.expctxWay.getTurncost();
|
||||
float cfup = rc.expctxWay.getUphillCostfactor();
|
||||
float cfdown = rc.expctxWay.getDownhillCostfactor();
|
||||
float cf = rc.expctxWay.getCostfactor();
|
||||
cfup = cfup == 0.f ? cf : cfup;
|
||||
cfdown = cfdown == 0.f ? cf : cfdown;
|
||||
|
||||
// *** add initial cost if the classifier changed
|
||||
float newClassifier = rc.expctxWay.getInitialClassifier();
|
||||
if ( newClassifier == 0. )
|
||||
{
|
||||
newClassifier = (cfup + cfdown + cf)/3;
|
||||
}
|
||||
float classifierDiff = newClassifier - lastClassifier;
|
||||
if ( classifierDiff > 0.0005 || classifierDiff < -0.0005 )
|
||||
{
|
||||
lastClassifier = newClassifier;
|
||||
float initialcost = rc.expctxWay.getInitialcost();
|
||||
int iicost = (int)initialcost;
|
||||
if ( recordMessageData )
|
||||
{
|
||||
msgData.linkinitcost += iicost;
|
||||
}
|
||||
cost += iicost;
|
||||
}
|
||||
|
||||
OsmTransferNode transferNode = link.geometry == null ? null
|
||||
: rc.geometryDecoder.decodeGeometry( link.geometry, p1, targetNode, isReverse );
|
||||
|
||||
boolean isFirstSection = true;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
originLon = lon1;
|
||||
originLat = lat1;
|
||||
|
||||
int lon2;
|
||||
int lat2;
|
||||
short ele2;
|
||||
|
||||
if ( transferNode == null )
|
||||
{
|
||||
lon2 = targetNode.ilon;
|
||||
lat2 = targetNode.ilat;
|
||||
ele2 = targetNode.selev;
|
||||
}
|
||||
else
|
||||
{
|
||||
lon2 = transferNode.ilon;
|
||||
lat2 = transferNode.ilat;
|
||||
ele2 = transferNode.selev;
|
||||
}
|
||||
|
||||
// check turn restrictions: do we have one with that origin?
|
||||
boolean checkTRs = false;
|
||||
if ( isFirstSection )
|
||||
{
|
||||
isFirstSection = false;
|
||||
|
||||
// TODO: TRs for inverse routing would need inverse TR logic,
|
||||
// inverse routing for now just for target island check, so don't care (?)
|
||||
// in detail mode (=final pass) no TR to not mess up voice hints
|
||||
checkTRs = rc.considerTurnRestrictions && !rc.inverseDirection && !detailMode;
|
||||
}
|
||||
|
||||
if ( checkTRs )
|
||||
{
|
||||
boolean hasAnyPositive = false;
|
||||
boolean hasPositive = false;
|
||||
boolean hasNegative = false;
|
||||
TurnRestriction tr = sourceNode.firstRestriction;
|
||||
while( tr != null )
|
||||
{
|
||||
boolean trValid = ! (tr.exceptBikes() && rc.bikeMode);
|
||||
if ( trValid && tr.fromLon == lon0 && tr.fromLat == lat0 )
|
||||
{
|
||||
if ( tr.isPositive )
|
||||
{
|
||||
hasAnyPositive = true;
|
||||
}
|
||||
if ( tr.toLon == lon2 && tr.toLat == lat2 )
|
||||
{
|
||||
if ( tr.isPositive )
|
||||
{
|
||||
hasPositive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasNegative = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
tr = tr.next;
|
||||
}
|
||||
if ( !hasPositive && ( hasAnyPositive || hasNegative ) )
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if recording, new MessageData for each section (needed for turn-instructions)
|
||||
if ( recordMessageData && msgData.wayKeyValues != null )
|
||||
{
|
||||
originElement.message = msgData;
|
||||
msgData = new MessageData();
|
||||
}
|
||||
|
||||
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
|
||||
boolean stopAtEndpoint = false;
|
||||
if ( rc.shortestmatch )
|
||||
{
|
||||
if ( rc.isEndpoint )
|
||||
{
|
||||
stopAtEndpoint = true;
|
||||
ele2 = interpolateEle( ele1, ele2, rc.wayfraction );
|
||||
}
|
||||
else
|
||||
{
|
||||
// we just start here, reset cost
|
||||
cost = 0;
|
||||
ehbd = 0;
|
||||
ehbu = 0;
|
||||
lon0 = -1; // reset turncost-pipe
|
||||
lat0 = -1;
|
||||
|
||||
if ( recordTransferNodes )
|
||||
{
|
||||
if ( rc.wayfraction > 0. )
|
||||
{
|
||||
ele1 = interpolateEle( ele1, ele2, 1. - rc.wayfraction );
|
||||
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic );
|
||||
}
|
||||
else
|
||||
{
|
||||
originElement = null; // prevent duplicate point
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( recordMessageData )
|
||||
{
|
||||
msgData.linkdist += dist;
|
||||
}
|
||||
linkdisttotal += dist;
|
||||
|
||||
// apply a start-direction if appropriate (by faking the origin position)
|
||||
if ( lon0 == -1 && lat0 == -1 )
|
||||
{
|
||||
double coslat = cr.cosIlat(lat1);
|
||||
if ( rc.startDirectionValid && coslat > 0. )
|
||||
{
|
||||
double dir = rc.startDirection.intValue() * 180. / Math.PI;
|
||||
lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / coslat );
|
||||
lat0 = lat1 - (int) ( 1000. * Math.cos( dir ) );
|
||||
}
|
||||
}
|
||||
|
||||
// *** penalty for turning angles
|
||||
if ( !isTrafficBackbone && lon0 != -1 && lat0 != -1 )
|
||||
{
|
||||
// penalty proportional to direction change
|
||||
double angle = rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
|
||||
double cos = 1. - rc.getCosAngle();
|
||||
int actualturncost = (int)(cos * turncostbase + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
|
||||
cost += actualturncost;
|
||||
if ( recordMessageData )
|
||||
{
|
||||
msgData.linkturncost += actualturncost;
|
||||
msgData.turnangle = (float)rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
|
||||
}
|
||||
}
|
||||
|
||||
// *** penalty for elevation (penalty is for descend! in a way that slow descends give no penalty)
|
||||
// only the part of the descend that does not fit into the elevation-hysteresis-buffer
|
||||
// leads to an immediate penalty
|
||||
|
||||
int elefactor = 250000;
|
||||
if ( ele2 == Short.MIN_VALUE ) ele2 = ele1;
|
||||
if ( ele1 != Short.MIN_VALUE )
|
||||
{
|
||||
ehbd += (ele1 - ele2)*elefactor - dist * rc.downhillcutoff;
|
||||
ehbu += (ele2 - ele1)*elefactor - dist * rc.uphillcutoff;
|
||||
}
|
||||
|
||||
float downweight = 0.f;
|
||||
if ( ehbd > rc.elevationpenaltybuffer )
|
||||
{
|
||||
downweight = 1.f;
|
||||
|
||||
int excess = ehbd - rc.elevationpenaltybuffer;
|
||||
int reduce = dist * rc.elevationbufferreduce;
|
||||
if ( reduce > excess )
|
||||
{
|
||||
downweight = ((float)excess)/reduce;
|
||||
reduce = excess;
|
||||
}
|
||||
excess = ehbd - rc.elevationmaxbuffer;
|
||||
if ( reduce < excess )
|
||||
{
|
||||
reduce = excess;
|
||||
}
|
||||
ehbd -= reduce;
|
||||
if ( rc.downhillcostdiv > 0 )
|
||||
{
|
||||
int elevationCost = reduce/rc.downhillcostdiv;
|
||||
cost += elevationCost;
|
||||
if ( recordMessageData )
|
||||
{
|
||||
msgData.linkelevationcost += elevationCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( ehbd < 0 )
|
||||
{
|
||||
ehbd = 0;
|
||||
}
|
||||
|
||||
float upweight = 0.f;
|
||||
if ( ehbu > rc.elevationpenaltybuffer )
|
||||
{
|
||||
upweight = 1.f;
|
||||
|
||||
int excess = ehbu - rc.elevationpenaltybuffer;
|
||||
int reduce = dist * rc.elevationbufferreduce;
|
||||
if ( reduce > excess )
|
||||
{
|
||||
upweight = ((float)excess)/reduce;
|
||||
reduce = excess;
|
||||
}
|
||||
excess = ehbu - rc.elevationmaxbuffer;
|
||||
if ( reduce < excess )
|
||||
{
|
||||
reduce = excess;
|
||||
}
|
||||
ehbu -= reduce;
|
||||
if ( rc.uphillcostdiv > 0 )
|
||||
{
|
||||
int elevationCost = reduce/rc.uphillcostdiv;
|
||||
cost += elevationCost;
|
||||
if ( recordMessageData )
|
||||
{
|
||||
msgData.linkelevationcost += elevationCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( ehbu < 0 )
|
||||
{
|
||||
ehbu = 0;
|
||||
}
|
||||
|
||||
// get the effective costfactor (slope dependent)
|
||||
float costfactor = cfup*upweight + cf*(1.f - upweight - downweight) + cfdown*downweight;
|
||||
if ( isTrafficBackbone )
|
||||
{
|
||||
costfactor = 0.f;
|
||||
}
|
||||
|
||||
float fcost = dist * costfactor + 0.5f;
|
||||
if ( ( costfactor > 9998. && !detailMode ) || fcost + cost >= 2000000000. )
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
int waycost = (int)(fcost);
|
||||
cost += waycost;
|
||||
|
||||
// calculate traffic
|
||||
if ( rc.countTraffic )
|
||||
{
|
||||
int minDist = (int)rc.trafficSourceMinDist;
|
||||
int cost2 = cost < minDist ? minDist : cost;
|
||||
traffic += dist*rc.expctxWay.getTrafficSourceDensity()*Math.pow(cost2/10000.f,rc.trafficSourceExponent);
|
||||
}
|
||||
|
||||
if ( recordMessageData )
|
||||
{
|
||||
msgData.costfactor = costfactor;
|
||||
msgData.priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
|
||||
msgData.classifiermask = (int)rc.expctxWay.getClassifierMask();
|
||||
msgData.lon = lon2;
|
||||
msgData.lat = lat2;
|
||||
msgData.ele = ele2;
|
||||
msgData.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description );
|
||||
}
|
||||
|
||||
if ( stopAtEndpoint )
|
||||
{
|
||||
if ( recordTransferNodes )
|
||||
{
|
||||
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic );
|
||||
originElement.cost = cost;
|
||||
if ( recordMessageData )
|
||||
{
|
||||
originElement.message = msgData;
|
||||
}
|
||||
}
|
||||
if ( rc.nogomatch )
|
||||
{
|
||||
cost = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( transferNode == null )
|
||||
{
|
||||
// *** penalty for being part of the reference track
|
||||
if ( refTrack != null && refTrack.containsNode( targetNode ) && refTrack.containsNode( sourceNode ) )
|
||||
{
|
||||
int reftrackcost = linkdisttotal;
|
||||
cost += reftrackcost;
|
||||
}
|
||||
selev = ele2;
|
||||
break;
|
||||
}
|
||||
transferNode = transferNode.next;
|
||||
|
||||
if ( recordTransferNodes )
|
||||
{
|
||||
originElement = OsmPathElement.create( lon2, lat2, ele2, originElement, rc.countTraffic );
|
||||
originElement.cost = cost;
|
||||
originElement.addTraffic( traffic );
|
||||
traffic = 0;
|
||||
}
|
||||
lon0 = lon1;
|
||||
lat0 = lat1;
|
||||
lon1 = lon2;
|
||||
lat1 = lat2;
|
||||
ele1 = ele2;
|
||||
|
||||
}
|
||||
|
||||
// check for nogo-matches (after the *actual* start of segment)
|
||||
if ( rc.nogomatch )
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// finally add node-costs for target node
|
||||
if ( targetNode.nodeDescription != null )
|
||||
{
|
||||
boolean nodeAccessGranted = rc.expctxWay.getNodeAccessGranted() != 0.;
|
||||
rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription );
|
||||
float initialcost = rc.expctxNode.getInitialcost();
|
||||
if ( initialcost >= 1000000. )
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
int iicost = (int)initialcost;
|
||||
|
||||
cost += iicost;
|
||||
|
||||
if ( recordMessageData )
|
||||
{
|
||||
msgData.linknodecost += iicost;
|
||||
msgData.nodeKeyValues = rc.expctxNode.getKeyValueDescription( nodeAccessGranted, targetNode.nodeDescription );
|
||||
}
|
||||
}
|
||||
if ( recordMessageData )
|
||||
{
|
||||
message = msgData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int elevationCorrection( RoutingContext rc )
|
||||
{
|
||||
|
|
|
@ -42,12 +42,12 @@ public final class WaypointMatcherImpl implements WaypointMatcher
|
|||
{
|
||||
// todo: bounding-box pre-filter
|
||||
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
double coslat = cr.cosIlat(lat2);
|
||||
double coslat6 = coslat * cr.ILATLNG_TO_LATLNG;
|
||||
double[] lonlat2m = CheapRulerSingleton.getLonLatToMeterScales( (lat1+lat2) >> 1 );
|
||||
double dlon2m = lonlat2m[0];
|
||||
double dlat2m = lonlat2m[1];
|
||||
|
||||
double dx = ( lon2 - lon1 ) * coslat6;
|
||||
double dy = ( lat2 - lat1 ) * cr.ILATLNG_TO_LATLNG;
|
||||
double dx = ( lon2 - lon1 ) * dlon2m;
|
||||
double dy = ( lat2 - lat1 ) * dlat2m;
|
||||
double d = Math.sqrt( dy * dy + dx * dx );
|
||||
if ( d == 0. )
|
||||
return;
|
||||
|
@ -56,10 +56,10 @@ public final class WaypointMatcherImpl implements WaypointMatcher
|
|||
{
|
||||
OsmNodeNamed wp = mwp.waypoint;
|
||||
|
||||
double x1 = ( lon1 - wp.ilon ) * coslat6;
|
||||
double y1 = ( lat1 - wp.ilat ) * cr.ILATLNG_TO_LATLNG;
|
||||
double x2 = ( lon2 - wp.ilon ) * coslat6;
|
||||
double y2 = ( lat2 - wp.ilat ) * cr.ILATLNG_TO_LATLNG;
|
||||
double x1 = ( lon1 - wp.ilon ) * dlon2m;
|
||||
double y1 = ( lat1 - wp.ilat ) * dlat2m;
|
||||
double x2 = ( lon2 - wp.ilon ) * dlon2m;
|
||||
double y2 = ( lat2 - wp.ilat ) * dlat2m;
|
||||
double r12 = x1 * x1 + y1 * y1;
|
||||
double r22 = x2 * x2 + y2 * y2;
|
||||
double radius = Math.abs( r12 < r22 ? y1 * dx - x1 * dy : y2 * dx - x2 * dy ) / d;
|
||||
|
@ -92,8 +92,8 @@ public final class WaypointMatcherImpl implements WaypointMatcher
|
|||
double wayfraction = -s2 / ( d * d );
|
||||
double xm = x2 - wayfraction * dx;
|
||||
double ym = y2 - wayfraction * dy;
|
||||
mwp.crosspoint.ilon = (int) ( xm / coslat6 + wp.ilon );
|
||||
mwp.crosspoint.ilat = (int) ( ym / cr.ILATLNG_TO_LATLNG + wp.ilat );
|
||||
mwp.crosspoint.ilon = (int) ( xm / dlon2m + wp.ilon );
|
||||
mwp.crosspoint.ilat = (int) ( ym / dlat2m + wp.ilat );
|
||||
}
|
||||
else if ( s1 > s2 )
|
||||
{
|
||||
|
|
|
@ -65,25 +65,25 @@ public class OsmNogoPolygonTest {
|
|||
|
||||
@Test
|
||||
public void testCalcBoundingCircle() {
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
double[] lonlat2m = CheapRulerSingleton.getLonLatToMeterScales( polygon.ilat );
|
||||
double dlon2m = lonlat2m[0];
|
||||
double dlat2m = lonlat2m[1];
|
||||
|
||||
polygon.calcBoundingCircle();
|
||||
double r = polygon.radius;
|
||||
for (int i=0; i<lons.length; i++) {
|
||||
double py = toOsmLat(lats[i]);
|
||||
double dpx = (toOsmLon(lons[i]) - polygon.ilon) * cr.cosIlat(polygon.ilat);
|
||||
double dpy = py - polygon.ilat;
|
||||
double r1 = Math.sqrt(dpx * dpx + dpy * dpy) * cr.ILATLNG_TO_LATLNG;
|
||||
double dpx = (toOsmLon(lons[i]) - polygon.ilon) * dlon2m;
|
||||
double dpy = (toOsmLon(lats[i]) - polygon.ilon) * dlat2m;
|
||||
double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
|
||||
double diff = r-r1;
|
||||
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
|
||||
}
|
||||
polyline.calcBoundingCircle();
|
||||
r = polyline.radius;
|
||||
for (int i=0; i<lons.length; i++) {
|
||||
double py = toOsmLat(lats[i]);
|
||||
double dpx = (toOsmLon(lons[i]) - polyline.ilon) * cr.cosIlat(polyline.ilat);
|
||||
double dpy = py - polyline.ilat;
|
||||
double r1 = Math.sqrt(dpx * dpx + dpy * dpy) * cr.ILATLNG_TO_LATLNG;
|
||||
double dpx = (toOsmLon(lons[i]) - polyline.ilon) * dlon2m;
|
||||
double dpy = (toOsmLon(lats[i]) - polyline.ilon) * dlat2m;
|
||||
double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
|
||||
double diff = r-r1;
|
||||
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
import btools.util.CheapRulerSingleton;
|
||||
import btools.util.ReducedMedianFilter;
|
||||
|
||||
/**
|
||||
|
@ -229,8 +228,7 @@ public class SrtmRaster
|
|||
|
||||
private static Weights[][] calcWeights( int latIndex )
|
||||
{
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
double coslat = cr.cosLat(latIndex * 5.);
|
||||
double coslat = Math.cos( latIndex * 5. / 57.3 );
|
||||
|
||||
// radius in pixel units
|
||||
double ry = filterDiscRadius;
|
||||
|
|
|
@ -7,7 +7,6 @@ package btools.mapaccess;
|
|||
|
||||
import btools.codec.MicroCache;
|
||||
import btools.codec.MicroCache2;
|
||||
import btools.expressions.BExpressionContextWay;
|
||||
import btools.util.ByteArrayUnifier;
|
||||
import btools.util.CheapRulerSingleton;
|
||||
import btools.util.IByteArrayUnifier;
|
||||
|
@ -103,8 +102,7 @@ public class OsmNode extends OsmLink implements OsmPos
|
|||
|
||||
public final int calcDistance( OsmPos p )
|
||||
{
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
return (int) (cr.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0);
|
||||
return (int)(CheapRulerSingleton.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
|
|
|
@ -103,8 +103,7 @@ public class OsmNodeP extends OsmLinkP implements Comparable<OsmNodeP>, OsmPos
|
|||
@Override
|
||||
public int calcDistance( OsmPos p )
|
||||
{
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
return (int)(cr.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
||||
return (int)(CheapRulerSingleton.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -509,17 +509,17 @@ public class BRouterView extends View
|
|||
centerLon = ( maxlon + minlon ) / 2;
|
||||
centerLat = ( maxlat + minlat ) / 2;
|
||||
|
||||
CheapRulerSingleton cr = CheapRulerSingleton.getInstance();
|
||||
double coslat = cr.cosIlat(centerLat);
|
||||
double difflon = maxlon - minlon;
|
||||
double difflat = maxlat - minlat;
|
||||
double[] lonlat2m = CheapRulerSingleton.getLonLatToMeterScales( centerLat );
|
||||
double dlon2m = lonlat2m[0];
|
||||
double dlat2m = lonlat2m[1];
|
||||
double difflon = (maxlon - minlon)*dlon2m;
|
||||
double difflat = (maxlat - minlat)*dlat2m;
|
||||
|
||||
scaleLon = imgw / ( difflon * 1.5 );
|
||||
scaleLat = imgh / ( difflat * 1.5 );
|
||||
if ( scaleLon < scaleLat * coslat )
|
||||
scaleLat = scaleLon / coslat;
|
||||
else
|
||||
scaleLon = scaleLat * coslat;
|
||||
double scaleMin = scaleLon < scaleLat ? scaleLon : scaleLat;
|
||||
scaleLat *= dlon2m;
|
||||
scaleLon *= dlat2m;
|
||||
|
||||
startTime = System.currentTimeMillis();
|
||||
RoutingContext.prepareNogoPoints( nogoList );
|
||||
|
|
|
@ -12,69 +12,49 @@ public final class CheapRulerSingleton {
|
|||
* 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
|
||||
public final static double ILATLNG_TO_LATLNG = 1e-6; // From integer to degrees
|
||||
public final static int KILOMETERS_TO_METERS = 1000;
|
||||
public 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;
|
||||
private final static int SCALE_CACHE_LENGTH = 1800;
|
||||
private final static int SCALE_CACHE_INCREMENT = 100000;
|
||||
// COS_CACHE_LENGTH cached values between 0 and COS_CACHE_MAX_DEGREES degrees.
|
||||
double[] COS_CACHE = new double[COS_CACHE_LENGTH];
|
||||
private final static double[][] SCALE_CACHE = new double[SCALE_CACHE_LENGTH][];
|
||||
|
||||
/**
|
||||
* Helper to build the cache of cosine values.
|
||||
* 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);
|
||||
static {
|
||||
for (int i = 0; i < SCALE_CACHE_LENGTH; i++) {
|
||||
SCALE_CACHE[i] = calcKxKyFromILat( i*SCALE_CACHE_INCREMENT + SCALE_CACHE_INCREMENT/2 );
|
||||
}
|
||||
}
|
||||
|
||||
private CheapRulerSingleton() {
|
||||
super();
|
||||
// Build the cache of cosine values.
|
||||
buildCosCache();
|
||||
private static double[] calcKxKyFromILat(int ilat) {
|
||||
double lat = DEG_TO_RAD*(ilat-90000000)/1000000.;
|
||||
double cos = Math.cos(lat);
|
||||
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[] kxky = new double[2];
|
||||
kxky[0] = (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5) * ILATLNG_TO_LATLNG * KILOMETERS_TO_METERS;
|
||||
kxky[1] = (111.13209 - 0.56605 * cos2 + 0.0012 * cos4) * ILATLNG_TO_LATLNG * KILOMETERS_TO_METERS;
|
||||
return kxky;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of this singleton class.
|
||||
* Calculate the degree->meter scale for given latitude
|
||||
*
|
||||
* @result [lon->meter,lat->meter]
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public double cosIlat(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)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to compute the cosine of a latitude (in degrees).
|
||||
*/
|
||||
public double cosLat(double lat) {
|
||||
if (lat < 0) {
|
||||
lat += 90.;
|
||||
}
|
||||
return COS_CACHE[(int) (lat * COS_CACHE_LENGTH / COS_CACHE_MAX_DEGREES)];
|
||||
public static double[] getLonLatToMeterScales( int ilat ) {
|
||||
return SCALE_CACHE[ ilat / SCALE_CACHE_INCREMENT ];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,20 +69,10 @@ public final class CheapRulerSingleton {
|
|||
* @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 = cosIlat(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;
|
||||
public static double distance(int ilon1, int ilat1, int ilon2, int ilat2) {
|
||||
double[] kxky = getLonLatToMeterScales( ( ilat1 + ilat2 ) >> 1 );
|
||||
double dlon = (ilon1 - ilon2) * kxky[0];
|
||||
double dlat = (ilat1 - ilat2) * kxky[1];
|
||||
return Math.sqrt(dlat * dlat + dlon * dlon); // in m
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue