diff --git a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java index 881aeb6..2b6c72a 100644 --- a/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java +++ b/brouter-core/src/main/java/btools/router/OsmNogoPolygon.java @@ -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; } diff --git a/brouter-core/src/main/java/btools/router/OsmPathElement.java b/brouter-core/src/main/java/btools/router/OsmPathElement.java index 8e54a4c..f24ae64 100644 --- a/brouter-core/src/main/java/btools/router/OsmPathElement.java +++ b/brouter-core/src/main/java/btools/router/OsmPathElement.java @@ -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; diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java index 51927bd..9adbffa 100644 --- a/brouter-core/src/main/java/btools/router/RoutingContext.java +++ b/brouter-core/src/main/java/btools/router/RoutingContext.java @@ -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 diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java index 4193842..81b5e1c 100644 --- a/brouter-core/src/main/java/btools/router/RoutingEngine.java +++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java @@ -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 ); diff --git a/brouter-core/src/main/java/btools/router/StdPath.java b/brouter-core/src/main/java/btools/router/StdPath.java index bdfe5e9..c299f04 100644 --- a/brouter-core/src/main/java/btools/router/StdPath.java +++ b/brouter-core/src/main/java/btools/router/StdPath.java @@ -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 ) { diff --git a/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java b/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java index e1ceb19..82000f9 100644 --- a/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java +++ b/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java @@ -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 ) { diff --git a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java index 9497640..7eae51f 100644 --- a/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java +++ b/brouter-core/src/test/java/btools/router/OsmNogoPolygonTest.java @@ -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= r1("+r1+")", diff >= 0); } polyline.calcBoundingCircle(); r = polyline.radius; for (int i=0; i= r1("+r1+")", diff >= 0); } diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/SrtmRaster.java b/brouter-map-creator/src/main/java/btools/mapcreator/SrtmRaster.java index 3c5d3d1..1fb0d6b 100644 --- a/brouter-map-creator/src/main/java/btools/mapcreator/SrtmRaster.java +++ b/brouter-map-creator/src/main/java/btools/mapcreator/SrtmRaster.java @@ -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; diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java index 9825a96..279147f 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java @@ -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() diff --git a/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java b/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java index 3b8241c..abe8568 100644 --- a/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java +++ b/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java @@ -103,8 +103,7 @@ public class OsmNodeP extends OsmLinkP implements Comparable, 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 diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java index f4f97a6..33d2672 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java @@ -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 ); diff --git a/brouter-util/src/main/java/btools/util/CheapRulerSingleton.java b/brouter-util/src/main/java/btools/util/CheapRulerSingleton.java index 8749664..3935282 100644 --- a/brouter-util/src/main/java/btools/util/CheapRulerSingleton.java +++ b/brouter-util/src/main/java/btools/util/CheapRulerSingleton.java @@ -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 } }