Merge pull request #759 from afischerdev/roundtrip
New Roundtrip function
This commit is contained in:
commit
063efcc3e1
71
brouter-core/src/main/java/btools/router/AreaInfo.java
Normal file
71
brouter-core/src/main/java/btools/router/AreaInfo.java
Normal file
@ -0,0 +1,71 @@
|
||||
package btools.router;
|
||||
|
||||
import btools.expressions.BExpressionContext;
|
||||
|
||||
public class AreaInfo {
|
||||
final static int RESULT_TYPE_NONE = 0;
|
||||
final static int RESULT_TYPE_ELEV50 = 1;
|
||||
final static int RESULT_TYPE_GREEN = 4;
|
||||
final static int RESULT_TYPE_RIVER = 5;
|
||||
|
||||
public int direction;
|
||||
public int numForest = -1;
|
||||
public int numRiver = -1;
|
||||
|
||||
public OsmNogoPolygon polygon;
|
||||
|
||||
public int ways = 0;
|
||||
public int greenWays = 0;
|
||||
public int riverWays = 0;
|
||||
public double elevStart = 0;
|
||||
public int elev50 = 0;
|
||||
|
||||
public AreaInfo(int dir) {
|
||||
direction = dir;
|
||||
}
|
||||
|
||||
void checkAreaInfo(BExpressionContext expctxWay, double elev, byte[] ab) {
|
||||
ways++;
|
||||
|
||||
double test = elevStart - elev;
|
||||
if (Math.abs(test) < 50) elev50++;
|
||||
|
||||
int[] ld2 = expctxWay.createNewLookupData();
|
||||
expctxWay.decode(ld2, false, ab);
|
||||
|
||||
if (numForest != -1 && ld2[numForest] > 1) {
|
||||
greenWays++;
|
||||
}
|
||||
|
||||
if (numRiver != -1 && ld2[numRiver] > 1) {
|
||||
riverWays++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getElev50Weight() {
|
||||
if (ways == 0) return 0;
|
||||
return (int) (elev50 * 100. / ways);
|
||||
}
|
||||
|
||||
public int getGreen() {
|
||||
if (ways == 0) return 0;
|
||||
return (int) (greenWays * 100. / ways);
|
||||
}
|
||||
|
||||
public int getRiver() {
|
||||
if (ways == 0) return 0;
|
||||
return (int) (riverWays * 100. / ways);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Area ").append(direction).append(" ").append(elevStart).append("m ways ").append(ways);
|
||||
if (ways > 0) {
|
||||
sb.append("\nArea ways <50m ").append(elev50).append(" ").append(getElev50Weight()).append("%");
|
||||
sb.append("\nArea ways green ").append(greenWays).append(" ").append(getGreen()).append("%");
|
||||
sb.append("\nArea ways river ").append(riverWays).append(" ").append(getRiver()).append("%");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
270
brouter-core/src/main/java/btools/router/AreaReader.java
Normal file
270
brouter-core/src/main/java/btools/router/AreaReader.java
Normal file
@ -0,0 +1,270 @@
|
||||
package btools.router;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import btools.codec.DataBuffers;
|
||||
import btools.codec.MicroCache;
|
||||
import btools.expressions.BExpressionContextWay;
|
||||
import btools.mapaccess.MatchedWaypoint;
|
||||
import btools.mapaccess.NodesCache;
|
||||
import btools.mapaccess.OsmFile;
|
||||
import btools.mapaccess.OsmLink;
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmNodesMap;
|
||||
import btools.mapaccess.PhysicalFile;
|
||||
|
||||
public class AreaReader {
|
||||
|
||||
File segmentFolder;
|
||||
|
||||
public void getDirectAllData(File folder, RoutingContext rc, OsmNodeNamed wp, int maxscale, BExpressionContextWay expctxWay, OsmNogoPolygon searchRect, List<AreaInfo> ais) {
|
||||
this.segmentFolder = folder;
|
||||
|
||||
int div = 32;
|
||||
int cellsize = 1000000 / div;
|
||||
int scale = maxscale;
|
||||
int count = 0;
|
||||
int used = 0;
|
||||
boolean checkBorder = maxscale > 7;
|
||||
|
||||
Map<Long, String> tiles = new TreeMap<>();
|
||||
for (int idxLat = -scale; idxLat <= scale; idxLat++) {
|
||||
for (int idxLon = -scale; idxLon <= scale; idxLon++) {
|
||||
if (ignoreCenter(maxscale, idxLon, idxLat)) continue;
|
||||
int tmplon = wp.ilon + cellsize * idxLon;
|
||||
int tmplat = wp.ilat + cellsize * idxLat;
|
||||
int lonDegree = tmplon / 1000000;
|
||||
int latDegree = tmplat / 1000000;
|
||||
int lonMod5 = (int) lonDegree % 5;
|
||||
int latMod5 = (int) latDegree % 5;
|
||||
|
||||
int lon = (int) lonDegree - 180 - lonMod5;
|
||||
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
|
||||
int lat = (int) latDegree - 90 - latMod5;
|
||||
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
|
||||
String filenameBase = slon + "_" + slat;
|
||||
|
||||
int lonIdx = tmplon / cellsize;
|
||||
int latIdx = tmplat / cellsize;
|
||||
int subIdx = (latIdx - div * latDegree) * div + (lonIdx - div * lonDegree);
|
||||
|
||||
int subLonIdx = (lonIdx - div * lonDegree);
|
||||
int subLatIdx = (latIdx - div * latDegree);
|
||||
|
||||
OsmNogoPolygon dataRect = new OsmNogoPolygon(true);
|
||||
lon = lonDegree * 1000000;
|
||||
lat = latDegree * 1000000;
|
||||
int tmplon2 = lon + cellsize * (subLonIdx);
|
||||
int tmplat2 = lat + cellsize * (subLatIdx);
|
||||
dataRect.addVertex(tmplon2, tmplat2);
|
||||
|
||||
tmplon2 = lon + cellsize * (subLonIdx + 1);
|
||||
tmplat2 = lat + cellsize * (subLatIdx);
|
||||
dataRect.addVertex(tmplon2, tmplat2);
|
||||
|
||||
tmplon2 = lon + cellsize * (subLonIdx + 1);
|
||||
tmplat2 = lat + cellsize * (subLatIdx + 1);
|
||||
dataRect.addVertex(tmplon2, tmplat2);
|
||||
|
||||
tmplon2 = lon + cellsize * (subLonIdx);
|
||||
tmplat2 = lat + cellsize * (subLatIdx + 1);
|
||||
dataRect.addVertex(tmplon2, tmplat2);
|
||||
|
||||
boolean intersects = checkBorder && dataRect.intersects(searchRect.points.get(0).x, searchRect.points.get(0).y, searchRect.points.get(2).x, searchRect.points.get(2).y);
|
||||
if (!intersects && checkBorder)
|
||||
intersects = dataRect.intersects(searchRect.points.get(1).x, searchRect.points.get(1).y, searchRect.points.get(2).x, searchRect.points.get(3).y);
|
||||
if (intersects) {
|
||||
continue;
|
||||
}
|
||||
|
||||
intersects = searchRect.intersects(dataRect.points.get(0).x, dataRect.points.get(0).y, dataRect.points.get(2).x, dataRect.points.get(2).y);
|
||||
if (!intersects)
|
||||
intersects = searchRect.intersects(dataRect.points.get(1).x, dataRect.points.get(1).y, dataRect.points.get(3).x, dataRect.points.get(3).y);
|
||||
if (!intersects)
|
||||
intersects = containsRect(searchRect, dataRect.points.get(0).x, dataRect.points.get(0).y, dataRect.points.get(2).x, dataRect.points.get(2).y);
|
||||
|
||||
if (!intersects) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tiles.put(((long) tmplon) << 32 | tmplat, filenameBase);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
List<Map.Entry<Long, String>> list = new ArrayList<>(tiles.entrySet());
|
||||
Collections.sort(list, new Comparator<>() {
|
||||
@Override
|
||||
public int compare(Map.Entry<Long, String> e1, Map.Entry<Long, String> e2) {
|
||||
return e1.getValue().compareTo(e2.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
long maxmem = rc.memoryclass * 1024L * 1024L; // in MB
|
||||
NodesCache nodesCache = new NodesCache(segmentFolder, expctxWay, rc.forceSecondaryData, maxmem, null, false);
|
||||
PhysicalFile pf = null;
|
||||
String lastFilenameBase = "";
|
||||
DataBuffers dataBuffers = null;
|
||||
try {
|
||||
for (Map.Entry<Long, String> entry : list) {
|
||||
OsmNode n = new OsmNode(entry.getKey());
|
||||
// System.out.println("areareader set " + n.getILon() + "_" + n.getILat() + " " + entry.getValue());
|
||||
String filenameBase = entry.getValue();
|
||||
if (!filenameBase.equals(lastFilenameBase)) {
|
||||
if (pf != null) pf.close();
|
||||
lastFilenameBase = filenameBase;
|
||||
File file = new File(segmentFolder, filenameBase + ".rd5");
|
||||
dataBuffers = new DataBuffers();
|
||||
|
||||
pf = new PhysicalFile(file, dataBuffers, -1, -1);
|
||||
}
|
||||
if (getDirectData(pf, dataBuffers, n.getILon(), n.getILat(), rc, expctxWay, ais))
|
||||
used++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("AreaReader: after " + used + "/" + count + " " + e.getMessage());
|
||||
ais.clear();
|
||||
} finally {
|
||||
if (pf != null)
|
||||
try {
|
||||
pf.close();
|
||||
} catch (Exception ee) {
|
||||
}
|
||||
nodesCache.close();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getDirectData(PhysicalFile pf, DataBuffers dataBuffers, int inlon, int inlat, RoutingContext rc, BExpressionContextWay expctxWay, List<AreaInfo> ais) {
|
||||
|
||||
int lonDegree = inlon / 1000000;
|
||||
int latDegree = inlat / 1000000;
|
||||
|
||||
OsmNodesMap nodesMap = new OsmNodesMap();
|
||||
|
||||
try {
|
||||
int div = pf.divisor;
|
||||
|
||||
OsmFile osmf = new OsmFile(pf, lonDegree, latDegree, dataBuffers);
|
||||
if (osmf.hasData()) {
|
||||
int cellsize = 1000000 / div;
|
||||
int tmplon = inlon;
|
||||
int tmplat = inlat;
|
||||
int lonIdx = tmplon / cellsize;
|
||||
int latIdx = tmplat / cellsize;
|
||||
|
||||
MicroCache segment = osmf.createMicroCache(lonIdx, latIdx, dataBuffers, expctxWay, null, true, null);
|
||||
|
||||
if (segment != null) {
|
||||
int size = segment.getSize();
|
||||
for (int i = 0; i < size; i++) {
|
||||
long id = segment.getIdForIndex(i);
|
||||
OsmNode node = new OsmNode(id);
|
||||
if (segment.getAndClear(id)) {
|
||||
node.parseNodeBody(segment, nodesMap, expctxWay);
|
||||
if (node.firstlink instanceof OsmLink) {
|
||||
for (OsmLink link = node.firstlink; link != null; link = link.getNext(node)) {
|
||||
OsmNode nextNode = link.getTarget(node);
|
||||
if (nextNode.firstlink == null)
|
||||
continue; // don't care about dead ends
|
||||
if (nextNode.firstlink.descriptionBitmap == null)
|
||||
continue;
|
||||
|
||||
for (AreaInfo ai : ais) {
|
||||
if (ai.polygon.isWithin(node.ilon, node.ilat)) {
|
||||
ai.checkAreaInfo(expctxWay, node.getElev(), nextNode.firstlink.descriptionBitmap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("AreaReader: " + e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean ignoreCenter(int maxscale, int idxLon, int idxLat) {
|
||||
int centerScale = (int) Math.round(maxscale * .2) - 1;
|
||||
if (centerScale < 0) return false;
|
||||
return idxLon >= -centerScale && idxLon <= centerScale &&
|
||||
idxLat >= -centerScale && idxLat <= centerScale;
|
||||
}
|
||||
|
||||
/*
|
||||
in this case the polygon is 'only' a rectangle
|
||||
*/
|
||||
boolean containsRect(OsmNogoPolygon searchRect, int p1x, int p1y, int p2x, int p2y) {
|
||||
return searchRect.isWithin((long) p1x, (long) p1y) &&
|
||||
searchRect.isWithin(p2x, p2y);
|
||||
}
|
||||
|
||||
public void writeAreaInfo(String filename, MatchedWaypoint wp, List<AreaInfo> ais) throws Exception {
|
||||
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(filename)));
|
||||
|
||||
wp.writeToStream(dos);
|
||||
for (AreaInfo ai : ais) {
|
||||
dos.writeInt(ai.direction);
|
||||
dos.writeDouble(ai.elevStart);
|
||||
dos.writeInt(ai.ways);
|
||||
dos.writeInt(ai.greenWays);
|
||||
dos.writeInt(ai.riverWays);
|
||||
dos.writeInt(ai.elev50);
|
||||
}
|
||||
dos.close();
|
||||
}
|
||||
|
||||
public void readAreaInfo(File fai, MatchedWaypoint wp, List<AreaInfo> ais) {
|
||||
DataInputStream dis = null;
|
||||
MatchedWaypoint ep = null;
|
||||
try {
|
||||
dis = new DataInputStream(new BufferedInputStream(new FileInputStream(fai)));
|
||||
ep = MatchedWaypoint.readFromStream(dis);
|
||||
if (Math.abs(ep.waypoint.ilon - wp.waypoint.ilon) > 500 &&
|
||||
Math.abs(ep.waypoint.ilat - wp.waypoint.ilat) > 500) {
|
||||
return;
|
||||
}
|
||||
if (Math.abs(ep.radius - wp.radius) > 500) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int direction = dis.readInt();
|
||||
AreaInfo ai = new AreaInfo(direction);
|
||||
ai.elevStart = dis.readDouble();
|
||||
ai.ways = dis.readInt();
|
||||
ai.greenWays = dis.readInt();
|
||||
ai.riverWays = dis.readInt();
|
||||
ai.elev50 = dis.readInt();
|
||||
ais.add(ai);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ais.clear();
|
||||
} finally {
|
||||
if (dis != null) {
|
||||
try {
|
||||
dis.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -141,6 +141,10 @@ abstract class OsmPath implements OsmLinkHolder {
|
||||
// evaluate the way tags
|
||||
rc.expctxWay.evaluate(rc.inverseDirection ^ isReverse, description);
|
||||
|
||||
// and check if is useful
|
||||
if (rc.ai != null && rc.ai.polygon.isWithin(lon1, lat1)) {
|
||||
rc.ai.checkAreaInfo(rc.expctxWay, ele1/4., description);
|
||||
}
|
||||
|
||||
// calculate the costfactor inputs
|
||||
float costfactor = rc.expctxWay.getCostfactor();
|
||||
|
||||
@ -36,6 +36,7 @@ public final class RoutingContext {
|
||||
public Map<String, String> keyValues;
|
||||
|
||||
public String rawTrackPath;
|
||||
public String rawAreaPath;
|
||||
|
||||
public String getProfileName() {
|
||||
String name = localFunction == null ? "unknown" : localFunction;
|
||||
@ -79,6 +80,8 @@ public final class RoutingContext {
|
||||
public boolean useDynamicDistance;
|
||||
public boolean buildBeelineOnRange;
|
||||
|
||||
public AreaInfo ai;
|
||||
|
||||
private void setModel(String className) {
|
||||
if (className == null) {
|
||||
pm = new StdModel();
|
||||
@ -193,6 +196,10 @@ public final class RoutingContext {
|
||||
public Integer startDirection;
|
||||
public boolean startDirectionValid;
|
||||
public boolean forceUseStartDirection;
|
||||
public Integer roundTripDistance;
|
||||
public Integer roundTripDirectionAdd;
|
||||
public Integer roundTripPoints;
|
||||
public boolean allowSamewayback;
|
||||
|
||||
public CheapAngleMeter anglemeter = new CheapAngleMeter();
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -21,6 +23,7 @@ import btools.mapaccess.OsmLinkHolder;
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmNodePairSet;
|
||||
import btools.mapaccess.OsmPos;
|
||||
import btools.util.CheapRuler;
|
||||
import btools.util.CompactLongMap;
|
||||
import btools.util.SortedHeap;
|
||||
import btools.util.StackSampler;
|
||||
@ -31,6 +34,7 @@ public class RoutingEngine extends Thread {
|
||||
public final static int BROUTER_ENGINEMODE_SEED = 1;
|
||||
public final static int BROUTER_ENGINEMODE_GETELEV = 2;
|
||||
public final static int BROUTER_ENGINEMODE_GETINFO = 3;
|
||||
public final static int BROUTER_ENGINEMODE_ROUNDTRIP = 4;
|
||||
|
||||
private NodesCache nodesCache;
|
||||
private SortedHeap<OsmPath> openSet = new SortedHeap<>();
|
||||
@ -48,7 +52,9 @@ public class RoutingEngine extends Thread {
|
||||
|
||||
private int engineMode = 0;
|
||||
|
||||
private int MAX_STEPS_CHECK = 10;
|
||||
private int MAX_STEPS_CHECK = 500;
|
||||
|
||||
private int ROUNDTRIP_DEFAULT_DIRECTIONADD = 45;
|
||||
|
||||
private int MAX_DYNAMIC_RANGE = 60000;
|
||||
|
||||
@ -178,6 +184,11 @@ public class RoutingEngine extends Thread {
|
||||
}
|
||||
doGetInfo();
|
||||
break;
|
||||
case BROUTER_ENGINEMODE_ROUNDTRIP:
|
||||
if (waypoints.size() < 1)
|
||||
throw new IllegalArgumentException("we need one lat/lon point at least!");
|
||||
doRoundTrip();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("not a valid engine mode");
|
||||
}
|
||||
@ -189,6 +200,26 @@ public class RoutingEngine extends Thread {
|
||||
startTime = System.currentTimeMillis();
|
||||
long startTime0 = startTime;
|
||||
this.maxRunningTime = maxRunningTime;
|
||||
|
||||
if (routingContext.allowSamewayback) {
|
||||
if (waypoints.size() == 2) {
|
||||
OsmNodeNamed onn = new OsmNodeNamed(new OsmNode(waypoints.get(0).ilon, waypoints.get(0).ilat));
|
||||
onn.name = "to";
|
||||
waypoints.add(onn);
|
||||
} else {
|
||||
waypoints.get(waypoints.size() - 1).name = "via" + (waypoints.size() - 1) + "_center";
|
||||
List<OsmNodeNamed> newpoints = new ArrayList<>();
|
||||
for (int i = waypoints.size() - 2; i >= 0; i--) {
|
||||
// System.out.println("back " + waypoints.get(i));
|
||||
OsmNodeNamed onn = new OsmNodeNamed(new OsmNode(waypoints.get(i).ilon, waypoints.get(i).ilat));
|
||||
onn.name = "via";
|
||||
newpoints.add(onn);
|
||||
}
|
||||
newpoints.get(newpoints.size() - 1).name = "to";
|
||||
waypoints.addAll(newpoints);
|
||||
}
|
||||
}
|
||||
|
||||
int nsections = waypoints.size() - 1;
|
||||
OsmTrack[] refTracks = new OsmTrack[nsections]; // used ways for alternatives
|
||||
OsmTrack[] lastTracks = new OsmTrack[nsections];
|
||||
@ -196,6 +227,10 @@ public class RoutingEngine extends Thread {
|
||||
List<String> messageList = new ArrayList<>();
|
||||
for (int i = 0; ; i++) {
|
||||
track = findTrack(refTracks, lastTracks);
|
||||
|
||||
// we are only looking for info
|
||||
if (routingContext.ai != null) return;
|
||||
|
||||
track.message = "track-length = " + track.distance + " filtered ascend = " + track.ascend
|
||||
+ " plain-ascend = " + track.plainAscend + " cost=" + track.cost;
|
||||
if (track.energy != 0) {
|
||||
@ -376,24 +411,24 @@ public class RoutingEngine extends Thread {
|
||||
}
|
||||
}
|
||||
int otherIdx = 0;
|
||||
if (minIdx == t.nodes.size()-1) {
|
||||
otherIdx = minIdx-1;
|
||||
if (minIdx == t.nodes.size() - 1) {
|
||||
otherIdx = minIdx - 1;
|
||||
} else {
|
||||
otherIdx = minIdx+1;
|
||||
otherIdx = minIdx + 1;
|
||||
}
|
||||
int otherdist = t.nodes.get(otherIdx).calcDistance(listOne.get(0).crosspoint);
|
||||
int minSElev = t.nodes.get(minIdx).getSElev();
|
||||
int otherSElev = t.nodes.get(otherIdx).getSElev();
|
||||
int diffSElev = 0;
|
||||
diffSElev = otherSElev - minSElev;
|
||||
double diff = (double) mindist/(mindist + otherdist) * diffSElev;
|
||||
double diff = (double) mindist / (mindist + otherdist) * diffSElev;
|
||||
|
||||
|
||||
OsmNodeNamed n = new OsmNodeNamed(listOne.get(0).crosspoint);
|
||||
n.name = wpt1.name;
|
||||
n.selev = minIdx != -1 ? (short) (minSElev + (int) diff) : Short.MIN_VALUE;
|
||||
if (engineMode == BROUTER_ENGINEMODE_GETINFO) {
|
||||
n.nodeDescription = (start1 != null && start1.firstlink!=null ? start1.firstlink.descriptionBitmap : null);
|
||||
n.nodeDescription = (start1 != null && start1.firstlink != null ? start1.firstlink.descriptionBitmap : null);
|
||||
t.pois.add(n);
|
||||
//t.message = "get_info";
|
||||
//t.messageList.add(t.message);
|
||||
@ -447,6 +482,215 @@ public class RoutingEngine extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
public void doRoundTrip() {
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
routingContext.useDynamicDistance = true;
|
||||
double searchRadius = (routingContext.roundTripDistance == null ? 1500 :routingContext.roundTripDistance);
|
||||
double direction = (routingContext.startDirection == null ? -1 :routingContext.startDirection);
|
||||
double directionAdd = (routingContext.roundTripDirectionAdd == null ? ROUNDTRIP_DEFAULT_DIRECTIONADD :routingContext.roundTripDirectionAdd);
|
||||
if (direction == -1) direction = getRandomDirectionFromData(waypoints.get(0), searchRadius);
|
||||
|
||||
if (routingContext.allowSamewayback) {
|
||||
int[] pos = CheapRuler.destination(waypoints.get(0).ilon, waypoints.get(0).ilat, searchRadius, direction);
|
||||
MatchedWaypoint wpt2 = new MatchedWaypoint();
|
||||
wpt2.waypoint = new OsmNode(pos[0], pos[1]);
|
||||
wpt2.name = "rt1_" + direction;
|
||||
|
||||
OsmNodeNamed onn = new OsmNodeNamed(new OsmNode(pos[0], pos[1]));
|
||||
onn.name = "rt1";
|
||||
waypoints.add(onn);
|
||||
} else {
|
||||
buildPointsFromCircle(waypoints, direction, searchRadius, routingContext.roundTripPoints == null ? 5 : routingContext.roundTripPoints);
|
||||
}
|
||||
|
||||
routingContext.waypointCatchingRange = 250;
|
||||
|
||||
doRouting(0);
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
logInfo("round trip execution time = " + (endTime - startTime) / 1000. + " seconds");
|
||||
} catch (Exception e) {
|
||||
e.getStackTrace();
|
||||
logException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void buildPointsFromCircle(List<OsmNodeNamed> waypoints, double startAngle, double searchRadius, int points) {
|
||||
//startAngle -= 90;
|
||||
for (int i = 1; i < points; i++) {
|
||||
double anAngle = 90 - (180.0 * i / points);
|
||||
int[] pos = CheapRuler.destination(waypoints.get(0).ilon, waypoints.get(0).ilat, searchRadius, startAngle - anAngle);
|
||||
OsmNodeNamed onn = new OsmNodeNamed(new OsmNode(pos[0], pos[1]));
|
||||
onn.name = "rt" + i;
|
||||
waypoints.add(onn);
|
||||
}
|
||||
|
||||
OsmNodeNamed onn = new OsmNodeNamed(waypoints.get(0));
|
||||
onn.name = "to_rt";
|
||||
waypoints.add(onn);
|
||||
}
|
||||
|
||||
int getRandomDirectionFromData(OsmNodeNamed wp, double searchRadius) {
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
int preferredRandomType = 0;
|
||||
boolean consider_elevation = routingContext.expctxWay.getVariableValue("consider_elevation", 0f) == 1f;
|
||||
boolean consider_forest = routingContext.expctxWay.getVariableValue("consider_forest", 0f) == 1f;
|
||||
boolean consider_river = routingContext.expctxWay.getVariableValue("consider_river", 0f) == 1f;
|
||||
if (consider_elevation) {
|
||||
preferredRandomType = AreaInfo.RESULT_TYPE_ELEV50;
|
||||
} else if (consider_forest) {
|
||||
preferredRandomType = AreaInfo.RESULT_TYPE_GREEN;
|
||||
} else if (consider_river) {
|
||||
preferredRandomType = AreaInfo.RESULT_TYPE_RIVER;
|
||||
} else {
|
||||
return (int) (Math.random()*360);
|
||||
}
|
||||
|
||||
MatchedWaypoint wpt1 = new MatchedWaypoint();
|
||||
wpt1.waypoint = wp;
|
||||
wpt1.name = "info";
|
||||
wpt1.radius = searchRadius * 1.5;
|
||||
|
||||
List<AreaInfo> ais = new ArrayList<>();
|
||||
AreaReader areareader = new AreaReader();
|
||||
if (routingContext.rawAreaPath != null) {
|
||||
File fai = new File(routingContext.rawAreaPath);
|
||||
if (fai.exists()) {
|
||||
areareader.readAreaInfo(fai, wpt1, ais);
|
||||
}
|
||||
}
|
||||
|
||||
if (ais.isEmpty()) {
|
||||
List<MatchedWaypoint> listStart = new ArrayList<>();
|
||||
listStart.add(wpt1);
|
||||
|
||||
List<OsmNodeNamed> wpliststart = new ArrayList<>();
|
||||
wpliststart.add(wp);
|
||||
|
||||
List<OsmNodeNamed> listOne = new ArrayList<>();
|
||||
|
||||
for (int a = 45; a < 360; a += 90) {
|
||||
int[] pos = CheapRuler.destination(wp.ilon, wp.ilat, searchRadius * 1.5, a);
|
||||
OsmNodeNamed onn = new OsmNodeNamed(new OsmNode(pos[0], pos[1]));
|
||||
onn.name = "via" + a;
|
||||
listOne.add(onn);
|
||||
|
||||
MatchedWaypoint wpt = new MatchedWaypoint();
|
||||
wpt.waypoint = onn;
|
||||
wpt.name = onn.name;
|
||||
listStart.add(wpt);
|
||||
}
|
||||
|
||||
RoutingEngine re = null;
|
||||
RoutingContext rc = new RoutingContext();
|
||||
String name = routingContext.localFunction;
|
||||
int idx = name.lastIndexOf(File.separator);
|
||||
rc.localFunction = idx == -1 ? "dummy" : name.substring(0, idx + 1) + "dummy.brf";
|
||||
|
||||
re = new RoutingEngine(null, null, segmentDir, wpliststart, rc, BROUTER_ENGINEMODE_ROUNDTRIP);
|
||||
rc.useDynamicDistance = true;
|
||||
re.matchWaypointsToNodes(listStart);
|
||||
re.resetCache(true);
|
||||
|
||||
int numForest = rc.expctxWay.getLookupKey("estimated_forest_class");
|
||||
int numRiver = rc.expctxWay.getLookupKey("estimated_river_class");
|
||||
|
||||
OsmNode start1 = re.nodesCache.getStartNode(listStart.get(0).node1.getIdFromPos());
|
||||
|
||||
double elev = (start1 == null ? 0 : start1.getElev()); // listOne.get(0).crosspoint.getElev();
|
||||
|
||||
int maxlon = Integer.MIN_VALUE;
|
||||
int minlon = Integer.MAX_VALUE;
|
||||
int maxlat = Integer.MIN_VALUE;
|
||||
int minlat = Integer.MAX_VALUE;
|
||||
for (OsmNodeNamed on : listOne) {
|
||||
maxlon = Math.max(on.ilon, maxlon);
|
||||
minlon = Math.min(on.ilon, minlon);
|
||||
maxlat = Math.max(on.ilat, maxlat);
|
||||
minlat = Math.min(on.ilat, minlat);
|
||||
}
|
||||
OsmNogoPolygon searchRect = new OsmNogoPolygon(true);
|
||||
searchRect.addVertex(maxlon, maxlat);
|
||||
searchRect.addVertex(maxlon, minlat);
|
||||
searchRect.addVertex(minlon, minlat);
|
||||
searchRect.addVertex(minlon, maxlat);
|
||||
|
||||
for (int a = 0; a < 4; a++) {
|
||||
rc.ai = new AreaInfo(a * 90 + 90);
|
||||
rc.ai.elevStart = elev;
|
||||
rc.ai.numForest = numForest;
|
||||
rc.ai.numRiver = numRiver;
|
||||
|
||||
rc.ai.polygon = new OsmNogoPolygon(true);
|
||||
rc.ai.polygon.addVertex(wp.ilon, wp.ilat);
|
||||
rc.ai.polygon.addVertex(listOne.get(a).ilon, listOne.get(a).ilat);
|
||||
if (a == 3)
|
||||
rc.ai.polygon.addVertex(listOne.get(0).ilon, listOne.get(0).ilat);
|
||||
else
|
||||
rc.ai.polygon.addVertex(listOne.get(a + 1).ilon, listOne.get(a + 1).ilat);
|
||||
|
||||
ais.add(rc.ai);
|
||||
}
|
||||
|
||||
int maxscale = Math.abs(searchRect.points.get(2).x - searchRect.points.get(0).x);
|
||||
maxscale = Math.max(1, Math.round(maxscale / 31250f / 2) + 1);
|
||||
|
||||
areareader.getDirectAllData(segmentDir, rc, wp, maxscale, rc.expctxWay, searchRect, ais);
|
||||
|
||||
if (routingContext.rawAreaPath != null) {
|
||||
try {
|
||||
wpt1.radius = searchRadius * 1.5;
|
||||
areareader.writeAreaInfo(routingContext.rawAreaPath, wpt1, ais);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
rc.ai = null;
|
||||
|
||||
}
|
||||
|
||||
logInfo("round trip execution time = " + (System.currentTimeMillis() - start) / 1000. + " seconds");
|
||||
|
||||
// for (AreaInfo ai: ais) {
|
||||
// System.out.println("\n" + ai.toString());
|
||||
//}
|
||||
|
||||
switch (preferredRandomType) {
|
||||
case AreaInfo.RESULT_TYPE_ELEV50:
|
||||
Collections.sort(ais, new Comparator<>() {
|
||||
public int compare(AreaInfo o1, AreaInfo o2) {
|
||||
return o2.getElev50Weight() - o1.getElev50Weight();
|
||||
}
|
||||
});
|
||||
break;
|
||||
case AreaInfo.RESULT_TYPE_GREEN:
|
||||
Collections.sort(ais, new Comparator<>() {
|
||||
public int compare(AreaInfo o1, AreaInfo o2) {
|
||||
return o2.getGreen() - o1.getGreen();
|
||||
}
|
||||
});
|
||||
break;
|
||||
case AreaInfo.RESULT_TYPE_RIVER:
|
||||
Collections.sort(ais, new Comparator<>() {
|
||||
public int compare(AreaInfo o1, AreaInfo o2) {
|
||||
return o2.getRiver() - o1.getRiver();
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return (int) (Math.random()*360);
|
||||
}
|
||||
|
||||
int angle = ais.get(0).direction;
|
||||
return angle - 30 + (int) (Math.random() * 60);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void postElevationCheck(OsmTrack track) {
|
||||
OsmPathElement lastPt = null;
|
||||
OsmPathElement startPt = null;
|
||||
@ -639,21 +883,21 @@ public class RoutingEngine extends Thread {
|
||||
// add extra waypoints from the last broken round
|
||||
for (OsmNodeNamed wp : extraWaypoints) {
|
||||
if (wp.direct) hasDirectRouting = true;
|
||||
if (wp.name.startsWith("from")) {
|
||||
if (wp.name.startsWith("from")) {
|
||||
waypoints.add(1, wp);
|
||||
waypoints.get(0).direct = true;
|
||||
nUnmatched++;
|
||||
} else {
|
||||
waypoints.add(waypoints.size()-1, wp);
|
||||
waypoints.get(waypoints.size()-2).direct = true;
|
||||
waypoints.add(waypoints.size() - 1, wp);
|
||||
waypoints.get(waypoints.size() - 2).direct = true;
|
||||
nUnmatched++;
|
||||
}
|
||||
}
|
||||
extraWaypoints = null;
|
||||
}
|
||||
if (lastTracks.length < waypoints.size()-1) {
|
||||
refTracks = new OsmTrack[waypoints.size()-1]; // used ways for alternatives
|
||||
lastTracks = new OsmTrack[waypoints.size()-1];
|
||||
if (lastTracks.length < waypoints.size() - 1) {
|
||||
refTracks = new OsmTrack[waypoints.size() - 1]; // used ways for alternatives
|
||||
lastTracks = new OsmTrack[waypoints.size() - 1];
|
||||
hasDirectRouting = true;
|
||||
}
|
||||
for (OsmNodeNamed wp : waypoints) {
|
||||
@ -688,13 +932,14 @@ public class RoutingEngine extends Thread {
|
||||
int startSize = matchedWaypoints.size();
|
||||
matchWaypointsToNodes(matchedWaypoints);
|
||||
if (startSize < matchedWaypoints.size()) {
|
||||
refTracks = new OsmTrack[matchedWaypoints.size()-1]; // used ways for alternatives
|
||||
lastTracks = new OsmTrack[matchedWaypoints.size()-1];
|
||||
refTracks = new OsmTrack[matchedWaypoints.size() - 1]; // used ways for alternatives
|
||||
lastTracks = new OsmTrack[matchedWaypoints.size() - 1];
|
||||
hasDirectRouting = true;
|
||||
}
|
||||
|
||||
for (MatchedWaypoint mwp : matchedWaypoints) {
|
||||
if (hasInfo() && matchedWaypoints.size() != nUnmatched) logInfo("new wp=" + mwp.waypoint + " " + mwp.crosspoint + (mwp.direct ? " direct" : ""));
|
||||
if (hasInfo() && matchedWaypoints.size() != nUnmatched)
|
||||
logInfo("new wp=" + mwp.waypoint + " " + mwp.crosspoint + (mwp.direct ? " direct" : ""));
|
||||
}
|
||||
|
||||
routingContext.checkMatchedWaypointAgainstNogos(matchedWaypoints);
|
||||
@ -724,9 +969,9 @@ public class RoutingEngine extends Thread {
|
||||
matchedWaypoints.add(nearbyTrack.endPoint);
|
||||
}
|
||||
} else {
|
||||
if (lastTracks.length < matchedWaypoints.size()-1) {
|
||||
refTracks = new OsmTrack[matchedWaypoints.size()-1]; // used ways for alternatives
|
||||
lastTracks = new OsmTrack[matchedWaypoints.size()-1];
|
||||
if (lastTracks.length < matchedWaypoints.size() - 1) {
|
||||
refTracks = new OsmTrack[matchedWaypoints.size() - 1]; // used ways for alternatives
|
||||
lastTracks = new OsmTrack[matchedWaypoints.size() - 1];
|
||||
hasDirectRouting = true;
|
||||
}
|
||||
}
|
||||
@ -750,12 +995,26 @@ public class RoutingEngine extends Thread {
|
||||
} else {
|
||||
seg = searchTrack(matchedWaypoints.get(i), matchedWaypoints.get(i + 1), i == matchedWaypoints.size() - 2 ? nearbyTrack : null, refTracks[i]);
|
||||
wptIndex = i;
|
||||
if (engineMode == BROUTER_ENGINEMODE_ROUNDTRIP) {
|
||||
if (i < matchedWaypoints.size() - 2) {
|
||||
OsmNode lastPoint = seg.containsNode(matchedWaypoints.get(i+1).node1) ? matchedWaypoints.get(i+1).node1 : matchedWaypoints.get(i+1).node2;
|
||||
OsmNodeNamed nogo = new OsmNodeNamed(lastPoint);
|
||||
nogo.radius = 5;
|
||||
nogo.name = "nogo" + (i+1);
|
||||
nogo.nogoWeight = 9999.;
|
||||
nogo.isNogo = true;
|
||||
if (routingContext.nogopoints == null) routingContext.nogopoints = new ArrayList<>();
|
||||
routingContext.nogopoints.add(nogo);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (seg == null)
|
||||
return null;
|
||||
|
||||
if (routingContext.ai != null) return null;
|
||||
|
||||
boolean changed = false;
|
||||
if (routingContext.correctMisplacedViaPoints && !matchedWaypoints.get(i).direct) {
|
||||
if (routingContext.correctMisplacedViaPoints && !matchedWaypoints.get(i).direct && !routingContext.allowSamewayback) {
|
||||
changed = snappPathConnection(totaltrack, seg, routingContext.inverseRouting ? matchedWaypoints.get(i + 1) : matchedWaypoints.get(i));
|
||||
}
|
||||
if (wptIndex > 0)
|
||||
@ -785,7 +1044,7 @@ public class RoutingEngine extends Thread {
|
||||
|
||||
// check for way back on way point
|
||||
private boolean snappPathConnection(OsmTrack tt, OsmTrack t, MatchedWaypoint startWp) {
|
||||
if (!startWp.name.startsWith("via"))
|
||||
if (!startWp.name.startsWith("via") && !startWp.name.startsWith("rt"))
|
||||
return false;
|
||||
|
||||
int ourSize = tt.nodes.size();
|
||||
@ -876,15 +1135,11 @@ public class RoutingEngine extends Thread {
|
||||
}
|
||||
indexback--;
|
||||
indexfore++;
|
||||
|
||||
if (routingContext.correctMisplacedViaPointsDistance > 0 &&
|
||||
wayDistance > routingContext.correctMisplacedViaPointsDistance) break;
|
||||
}
|
||||
|
||||
if (routingContext.correctMisplacedViaPointsDistance > 0 &&
|
||||
wayDistance > routingContext.correctMisplacedViaPointsDistance) {
|
||||
removeVoiceHintList.clear();
|
||||
removeBackList.clear();
|
||||
removeForeList.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// time hold
|
||||
float atime = 0;
|
||||
@ -1111,6 +1366,7 @@ public class RoutingEngine extends Thread {
|
||||
for (int i = 0; i < unmatchedWaypoints.size(); i++) {
|
||||
MatchedWaypoint wp = unmatchedWaypoints.get(i);
|
||||
if (wp.waypoint.calcDistance(wp.crosspoint) > routingContext.waypointCatchingRange) {
|
||||
|
||||
MatchedWaypoint nmw = new MatchedWaypoint();
|
||||
if (i == 0) {
|
||||
OsmNodeNamed onn = new OsmNodeNamed(wp.waypoint);
|
||||
@ -1153,7 +1409,6 @@ public class RoutingEngine extends Thread {
|
||||
}
|
||||
wp.crosspoint = new OsmNode(wp.waypoint.ilon, wp.waypoint.ilat);
|
||||
}
|
||||
|
||||
} else {
|
||||
waypoints.add(wp);
|
||||
}
|
||||
@ -1161,6 +1416,7 @@ public class RoutingEngine extends Thread {
|
||||
unmatchedWaypoints.clear();
|
||||
unmatchedWaypoints.addAll(waypoints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private OsmTrack searchTrack(MatchedWaypoint startWp, MatchedWaypoint endWp, OsmTrack nearbyTrack, OsmTrack refTrack) {
|
||||
@ -1222,6 +1478,7 @@ public class RoutingEngine extends Thread {
|
||||
OsmTrack t;
|
||||
try {
|
||||
t = findTrack(cfi == 0 ? "pass0" : "pass1", startWp, endWp, track, refTrack, false);
|
||||
if (routingContext.ai != null) return t;
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if (!terminated && matchPath != null) { // timeout, but eventually prepare a dirty ref track
|
||||
logInfo("supplying dirty reference track after timeout");
|
||||
|
||||
@ -202,6 +202,17 @@ public class RoutingParamCollector {
|
||||
rctx.forceUseStartDirection = true;
|
||||
} else if (key.equals("direction")) {
|
||||
rctx.startDirection = Integer.valueOf(value);
|
||||
} else if (key.equals("roundTripDistance")) {
|
||||
rctx.roundTripDistance = Integer.valueOf(value);
|
||||
} else if (key.equals("roundTripDirectionAdd")) {
|
||||
rctx.roundTripDirectionAdd = Integer.valueOf(value);
|
||||
} else if (key.equals("roundTripPoints")) {
|
||||
rctx.roundTripPoints = Integer.valueOf(value);
|
||||
if (rctx.roundTripPoints == null || rctx.roundTripPoints < 3 || rctx.roundTripPoints > 20) {
|
||||
rctx.roundTripPoints = 5;
|
||||
}
|
||||
} else if (key.equals("allowSamewayback")) {
|
||||
rctx.allowSamewayback = Integer.parseInt(value)==1;
|
||||
} else if (key.equals("alternativeidx")) {
|
||||
rctx.setAlternativeIdx(Integer.parseInt(value));
|
||||
} else if (key.equals("turnInstructionMode")) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package btools.router;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@ -110,4 +111,22 @@ public class OsmNodeNamedTest {
|
||||
0.1 * 5
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestination() {
|
||||
// Segment ends
|
||||
int lon1, lat1, lon2, lat2;
|
||||
// Circle definition
|
||||
OsmNodeNamed node = new OsmNodeNamed();
|
||||
// Center
|
||||
node.ilon = toOsmLon(0);
|
||||
node.ilat = toOsmLat(0);
|
||||
double startDist = 1000;
|
||||
|
||||
for (int i = 0; i <= 360; i += 45) {
|
||||
int[] pos = CheapRuler.destination(node.ilon, node.ilat, startDist, i);
|
||||
double dist = CheapRuler.distance(node.ilon, node.ilat, pos[0], pos[1]);
|
||||
assertTrue("pos " + pos[0] + " " + pos[1] + " distance (" + dist + ") should be around (" + startDist + ")", dist -1 < startDist && dist +1 > startDist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import btools.codec.WaypointMatcher;
|
||||
import btools.util.ByteDataReader;
|
||||
import btools.util.Crc32;
|
||||
|
||||
final class OsmFile {
|
||||
final public class OsmFile {
|
||||
private RandomAccessFile is = null;
|
||||
private long fileOffset;
|
||||
|
||||
|
||||
@ -143,4 +143,14 @@ final public class PhysicalFile {
|
||||
elevationType = dis.readByte();
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
public void close(){
|
||||
if (ra != null) {
|
||||
try {
|
||||
ra.close();
|
||||
} catch (Exception ee) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -64,7 +64,8 @@ public class BRouterService extends Service {
|
||||
worker.segmentDir = new File(baseDir, "brouter/segments4");
|
||||
String errMsg = null;
|
||||
|
||||
if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING) {
|
||||
if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING ||
|
||||
engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUNDTRIP) {
|
||||
String remoteProfile = params.getString("remoteProfile", null);
|
||||
|
||||
if (remoteProfile == null) {
|
||||
|
||||
@ -46,6 +46,7 @@ public class BRouterWorker {
|
||||
|
||||
RoutingContext rc = new RoutingContext();
|
||||
rc.rawTrackPath = rawTrackPath;
|
||||
rc.rawAreaPath = (rawTrackPath != null ? rawTrackPath.substring(0, rawTrackPath.lastIndexOf(File.separator)+1) + "rawAreaInfo.dat" : null);
|
||||
rc.localFunction = profilePath;
|
||||
|
||||
RoutingParamCollector routingParamCollector = new RoutingParamCollector();
|
||||
@ -136,7 +137,8 @@ public class BRouterWorker {
|
||||
cr.quite = true;
|
||||
cr.doRun(maxRunningTime);
|
||||
|
||||
if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING) {
|
||||
if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING ||
|
||||
engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUNDTRIP) {
|
||||
// store new reference track if any
|
||||
// (can exist for timed-out search)
|
||||
if (cr.getFoundRawTrack() != null) {
|
||||
|
||||
@ -222,7 +222,8 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
||||
}
|
||||
String headers = encodings == null || encodings.indexOf("gzip") < 0 ? null : "Content-Encoding: gzip\n";
|
||||
writeHttpHeader(bw, handler.getMimeType(), handler.getFileName(), headers, HTTP_STATUS_OK);
|
||||
if (engineMode == 0) {
|
||||
if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUTING ||
|
||||
engineMode == RoutingEngine.BROUTER_ENGINEMODE_ROUNDTRIP) {
|
||||
if (track != null) {
|
||||
if (headers != null) { // compressed
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
@ -235,7 +236,8 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
||||
bw.write(handler.formatTrack(track));
|
||||
}
|
||||
}
|
||||
} else if (engineMode == 2) {
|
||||
} else if (engineMode == RoutingEngine.BROUTER_ENGINEMODE_GETELEV ||
|
||||
engineMode == RoutingEngine.BROUTER_ENGINEMODE_GETINFO) {
|
||||
String s = cr.getFoundInfo();
|
||||
if (s != null) {
|
||||
bw.write(s);
|
||||
|
||||
@ -77,4 +77,21 @@ public final class CheapRuler {
|
||||
double dlat = (ilat1 - ilat2) * kxky[1];
|
||||
return Math.sqrt(dlat * dlat + dlon * dlon); // in m
|
||||
}
|
||||
|
||||
public static int[] destination(int lon1, int lat1, double distance, double angle) {
|
||||
|
||||
double[] lonlat2m = getLonLatToMeterScales(lat1);
|
||||
double lon2m = lonlat2m[0];
|
||||
double lat2m = lonlat2m[1];
|
||||
angle = 90. - angle;
|
||||
double st = Math.sin(angle * Math.PI / 180.);
|
||||
double ct = Math.cos(angle * Math.PI / 180.);
|
||||
|
||||
int lon2 = (int) (0.5 + lon1 + ct * distance / lon2m);
|
||||
int lat2 = (int) (0.5 + lat1 + st * distance / lat2m);
|
||||
int[] ret = new int[2];
|
||||
ret[0] = lon2;
|
||||
ret[1] = lat2;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user