diff --git a/brouter-core/src/main/java/btools/router/AreaReader.java b/brouter-core/src/main/java/btools/router/AreaReader.java new file mode 100644 index 0000000..b302eb2 --- /dev/null +++ b/brouter-core/src/main/java/btools/router/AreaReader.java @@ -0,0 +1,161 @@ +package btools.router; + +import java.io.File; +import java.util.List; + +import btools.codec.DataBuffers; +import btools.codec.MicroCache; +import btools.expressions.BExpressionContextWay; +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 ais) { + this.segmentFolder = folder; + + int cellsize = 1000000 / 32; + int scale = maxscale; + int count = 0; + int used = 0; + for (int idxLat = -scale; idxLat <= scale; idxLat++) { + for (int idxLon = -scale; idxLon <= scale; idxLon++) { + int tmplon = wp.ilon + cellsize * idxLon; + int tmplat = wp.ilat + cellsize * idxLat; + if (getDirectData(tmplon, tmplat, rc, expctxWay, searchRect, ais)) used++; + count++; + } + } + + } + + public boolean getDirectData(int inlon, int inlat, RoutingContext rc, BExpressionContextWay expctxWay, OsmNogoPolygon searchRect, List ais) { + int lonDegree = inlon / 1000000; + int latDegree = inlat / 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; + lon = 180000000 + (int) (lon * 1000000 + 0.5); + lat = 90000000 + (int) (lat * 1000000 + 0.5); + + String filenameBase = slon + "_" + slat; + + File file = new File(segmentFolder, filenameBase + ".rd5"); + PhysicalFile pf = null; + + long maxmem = rc.memoryclass * 1024L * 1024L; // in MB + NodesCache nodesCache = new NodesCache(segmentFolder, expctxWay, rc.forceSecondaryData, maxmem, null, false); + + OsmNodesMap nodesMap = new OsmNodesMap(); + + try { + + DataBuffers dataBuffers = new DataBuffers(); + pf = new PhysicalFile(file, dataBuffers, -1, -1); + int div = pf.divisor; + + OsmFile osmf = new OsmFile(pf, lonDegree, latDegree, dataBuffers); + if (osmf.hasData()) { + int cellsize = 1000000 / div; + int tmplon = inlon; // + cellsize * idxLon; + int tmplat = inlat; // + cellsize * idxLat; + 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 = 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) { + return false; + } + + MicroCache segment = osmf.createMicroCache(lonIdx, latIdx, dataBuffers, expctxWay, null, true, null); + + if (segment != null /*&& segment.getDataSize()>0*/) { + 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) { + e.printStackTrace(); + } finally { + if (pf != null) + try { + pf.close(); + } catch (Exception ee) { + } + nodesCache.close(); + nodesCache = null; + } + return false; + } + + /* + 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); + } +} diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java index 4dbee89..1996488 100644 --- a/brouter-core/src/main/java/btools/router/RoutingEngine.java +++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java @@ -485,15 +485,13 @@ public class RoutingEngine extends Thread { public void doRoundTrip() { try { long startTime = System.currentTimeMillis(); - MatchedWaypoint wpt1 = new MatchedWaypoint(); - wpt1.waypoint = waypoints.get(0); - wpt1.name = "roundtrip"; 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 = getRandomDirectionByRouting(waypoints.get(0), searchRadius); + 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 = getRandomDirectionFromRouting(waypoints.get(0), searchRadius); + 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); @@ -565,7 +563,141 @@ public class RoutingEngine extends Thread { waypoints.add(onn); } - int getRandomDirectionByRouting(OsmNodeNamed wp, double searchRadius) { + 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 = "start_info"; + List listStart = new ArrayList<>(); + listStart.add(wpt1); + + List wpliststart = new ArrayList<>(); + wpliststart.add(wp); + + List 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(); + rc.localFunction = "dummy"; + + 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(); + + List ais = new ArrayList<>(); + 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); + + new AreaReader().getDirectAllData(segmentDir, rc, wp, maxscale, rc.expctxWay, searchRect, ais); + + 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); + } + + rc.ai = null; + + int angle = ais.get(0).direction; + return angle - 45 + (int) (Math.random()*90); + } + + int getRandomDirectionFromRouting(OsmNodeNamed wp, double searchRadius) { long start = System.currentTimeMillis(); @@ -698,6 +830,8 @@ public class RoutingEngine extends Thread { return angle - 45 + (int) (Math.random()*90); } + + private void postElevationCheck(OsmTrack track) { OsmPathElement lastPt = null; OsmPathElement startPt = null; diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java index 9b5724b..2df3844 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java @@ -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; diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/PhysicalFile.java b/brouter-mapaccess/src/main/java/btools/mapaccess/PhysicalFile.java index e61f469..0ea3af7 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/PhysicalFile.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/PhysicalFile.java @@ -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) { + } + } + } + }