diff --git a/DataExtractionOSM/src-tests/net/osmand/router/RouterTestsSuite.java b/DataExtractionOSM/src-tests/net/osmand/router/RouterTestsSuite.java index 3bca1d2ae5..d1762cf43e 100644 --- a/DataExtractionOSM/src-tests/net/osmand/router/RouterTestsSuite.java +++ b/DataExtractionOSM/src-tests/net/osmand/router/RouterTestsSuite.java @@ -17,6 +17,7 @@ import net.osmand.router.BinaryRoutePlanner; import net.osmand.router.BinaryRoutePlanner.RouteSegment; import net.osmand.router.RouteSegmentResult; import net.osmand.router.RoutingConfiguration; +import net.osmand.router.RoutingConfiguration.Builder; import net.osmand.router.RoutingContext; import net.osmand.swing.DataExtractionSettings; @@ -122,8 +123,8 @@ public class RouterTestsSuite { for (int i = 0; i < tests.getLength(); i++) { Element e = (Element) tests.item(i); - BinaryRoutePlanner router = new BinaryRoutePlanner(lib, rs); - testRoute(e, router, config); + + testRoute(e, config, lib, rs); } return true; @@ -146,7 +147,7 @@ public class RouterTestsSuite { return false; } - private static void testRoute(Element testCase, BinaryRoutePlanner planner, RoutingConfiguration.Builder config) throws IOException, SAXException { + private static void testRoute(Element testCase, Builder config, NativeLibrary lib, BinaryMapIndexReader[] rs) throws IOException, SAXException { String vehicle = testCase.getAttribute("vehicle"); int loadedTiles = (int) parseFloat(testCase, "loadedTiles"); int visitedSegments = (int) parseFloat(testCase, "visitedSegments"); @@ -158,7 +159,9 @@ public class RouterTestsSuite { System.err.println("\n\n!! Skipped test case '" + testDescription + "' because 'best_percent' attribute is not specified \n\n" ); return; } - RoutingContext ctx = new RoutingContext(config.build(vehicle, RoutingConfiguration.DEFAULT_MEMORY_LIMIT)); + BinaryRoutePlanner router = new BinaryRoutePlanner(); + RoutingContext ctx = new RoutingContext(config.build(vehicle, RoutingConfiguration.DEFAULT_MEMORY_LIMIT), + lib, rs); String skip = testCase.getAttribute("skip_comment"); if (skip != null && skip.length() > 0) { System.err.println("\n\n!! Skipped test case '" + testDescription + "' because '" + skip + "'\n\n" ); @@ -168,17 +171,17 @@ public class RouterTestsSuite { double startLat = Double.parseDouble(testCase.getAttribute("start_lat")); double startLon = Double.parseDouble(testCase.getAttribute("start_lon")); - RouteSegment startSegment = planner.findRouteSegment(startLat, startLon, ctx); + RouteSegment startSegment = router.findRouteSegment(startLat, startLon, ctx); double endLat = Double.parseDouble(testCase.getAttribute("target_lat")); double endLon = Double.parseDouble(testCase.getAttribute("target_lon")); - RouteSegment endSegment = planner.findRouteSegment(endLat, endLon, ctx); + RouteSegment endSegment = router.findRouteSegment(endLat, endLon, ctx); if(startSegment == null){ throw new IllegalArgumentException("Start segment is not found for test : " + testDescription); } if(endSegment == null){ throw new IllegalArgumentException("End segment is not found for test : " + testDescription); } - List route = planner.searchRoute(ctx, startSegment, endSegment, false); + List route = router.searchRoute(ctx, startSegment, endSegment, false); float completeTime = 0; float completeDistance = 0; for (int i = 0; i < route.size(); i++) { diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java index 357538c433..41e477d49f 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java @@ -1981,4 +1981,11 @@ public class BinaryMapIndexReader { } } + public List loadRouteIndexData(RouteSubregion rs) throws IOException { + if(routeAdapter != null){ + return routeAdapter.loadRouteRegionData(rs); + } + return Collections.emptyList(); + } + } \ No newline at end of file diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java index 2450648ef9..d15098dfc3 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java @@ -636,6 +636,21 @@ public class BinaryMapRouteReaderAdapter { } + public List loadRouteRegionData(RouteSubregion rs) throws IOException { + TLongArrayList idMap = new TLongArrayList(); + TLongObjectHashMap restrictionMap = new TLongObjectHashMap(); + if (rs.dataObjects == null) { + codedIS.seek(rs.filePointer + rs.shiftToData); + int limit = codedIS.readRawVarint32(); + int oldLimit = codedIS.pushLimit(limit); + readRouteTreeData(rs, idMap, restrictionMap); + codedIS.popLimit(oldLimit); + } + List res = rs.dataObjects; + rs.dataObjects = null; + return res; + } + public void loadRouteRegionData(List toLoad, ResultMatcher matcher) throws IOException { Collections.sort(toLoad, new Comparator() { @Override @@ -665,9 +680,9 @@ public class BinaryMapRouteReaderAdapter { } } - public List searchRouteRegionTree(SearchRequest req, List list, List toLoad) - throws IOException { - for(RouteSubregion rs : list){ + public List searchRouteRegionTree(SearchRequest req, List list, + List toLoad) throws IOException { + for (RouteSubregion rs : list) { if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) { if (rs.subregions == null) { codedIS.seek(rs.filePointer); diff --git a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java index a207ba09bb..3101a1226d 100644 --- a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java +++ b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java @@ -1,7 +1,5 @@ package net.osmand.router; -import gnu.trove.iterator.TIntObjectIterator; -import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.map.hash.TLongObjectHashMap; import java.io.IOException; @@ -11,23 +9,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.PriorityQueue; -import java.util.Set; -import java.util.TreeSet; import net.osmand.LogUtil; -import net.osmand.NativeLibrary; -import net.osmand.binary.BinaryMapIndexReader; -import net.osmand.binary.BinaryMapRouteReaderAdapter; -import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion; -import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion; import net.osmand.binary.RouteDataObject; import net.osmand.osm.MapRenderingTypes; import net.osmand.osm.MapUtils; -import net.osmand.router.RoutingContext.RoutingTile; import org.apache.commons.logging.Log; @@ -35,29 +23,11 @@ public class BinaryRoutePlanner { public static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true; private final int REVERSE_WAY_RESTRICTION_ONLY = 1024; - private final NativeLibrary nativeLib; - private final Map> map = new LinkedHashMap>(); protected static final Log log = LogUtil.getLog(BinaryRoutePlanner.class); private static final int ROUTE_POINTS = 11; private static final float TURN_DEGREE_MIN = 45; - private static final boolean SHOW_GC_SIZE = false; - - - public BinaryRoutePlanner(NativeLibrary nativeLib, BinaryMapIndexReader... map) { - this.nativeLib = null; //nativeLib; - for (BinaryMapIndexReader mr : map) { - List rr = mr.getRoutingIndexes(); - List subregions = new ArrayList(); - for (RouteRegion r : rr) { - for (RouteSubregion rs : r.getSubregions()) { - subregions.add(new RouteSubregion(rs)); - } - } - this.map.put(mr, subregions); - } - } private static double squareRootDist(int x1, int y1, int x2, int y2) { @@ -100,49 +70,38 @@ public class BinaryRoutePlanner { public RouteSegment findRouteSegment(double lat, double lon, RoutingContext ctx) throws IOException { - int zoomAround = 15; - int coordinatesShift = (1 << (31 - zoomAround)); int px = MapUtils.get31TileNumberX(lon); int py = MapUtils.get31TileNumberY(lat); - // put in map to avoid duplicate map loading - TIntObjectHashMap ts = new TIntObjectHashMap(); - // calculate box to load neighbor tiles - RoutingTile rt = ctx.getRoutingTile(px - coordinatesShift, py - coordinatesShift); - ts.put(rt.getId(), rt); - rt = ctx.getRoutingTile(px + coordinatesShift, py - coordinatesShift); - ts.put(rt.getId(), rt); - rt = ctx.getRoutingTile(px - coordinatesShift, py + coordinatesShift); - ts.put(rt.getId(), rt); - rt = ctx.getRoutingTile(px + coordinatesShift, py + coordinatesShift); - ts.put(rt.getId(), rt); - - List dataObjects = new ArrayList(); - Iterator it = ts.valueCollection().iterator(); - while(it.hasNext()){ - ctx.loadTileData(it.next(), dataObjects, nativeLib, map); + ArrayList dataObjects = new ArrayList(); + ctx.loadTileData(px, py, 16, dataObjects); + if (dataObjects.isEmpty()) { + ctx.loadTileData(px, py, 14, dataObjects); } RouteSegment road = null; - double sdist = 0; + double sdist = 0; int foundProjX = 0; int foundProjY = 0; - - for(RouteDataObject r : dataObjects){ - if(r.getPointsLength() > 1){ + + for (RouteDataObject r : dataObjects) { + if (r.getPointsLength() > 1) { for (int j = 1; j < r.getPointsLength(); j++) { - double mDist = squareRootDist(r.getPoint31XTile(j), r.getPoint31YTile(j), r.getPoint31XTile(j - 1), r.getPoint31YTile(j - 1)); + double mDist = squareRootDist(r.getPoint31XTile(j), r.getPoint31YTile(j), r.getPoint31XTile(j - 1), + r.getPoint31YTile(j - 1)); int prx = r.getPoint31XTile(j); int pry = r.getPoint31YTile(j); - double projection = calculateProjection(r.getPoint31XTile(j - 1), r.getPoint31YTile(j - 1), r.getPoint31XTile(j), r.getPoint31YTile(j), - px, py); - if(projection < 0){ + double projection = calculateProjection(r.getPoint31XTile(j - 1), r.getPoint31YTile(j - 1), r.getPoint31XTile(j), + r.getPoint31YTile(j), px, py); + if (projection < 0) { prx = r.getPoint31XTile(j - 1); pry = r.getPoint31YTile(j - 1); - } else if(projection >= mDist * mDist){ + } else if (projection >= mDist * mDist) { prx = r.getPoint31XTile(j); pry = r.getPoint31YTile(j); } else { - prx = (int) (r.getPoint31XTile(j - 1) + (r.getPoint31XTile(j) - r.getPoint31XTile(j - 1))* (projection / (mDist *mDist))); - pry = (int) (r.getPoint31YTile(j - 1) + (r.getPoint31YTile(j) - r.getPoint31YTile(j - 1)) * (projection / (mDist *mDist))); + prx = (int) (r.getPoint31XTile(j - 1) + (r.getPoint31XTile(j) - r.getPoint31XTile(j - 1)) + * (projection / (mDist * mDist))); + pry = (int) (r.getPoint31YTile(j - 1) + (r.getPoint31YTile(j) - r.getPoint31YTile(j - 1)) + * (projection / (mDist * mDist))); } double currentsDist = squareDist(prx, pry, px, py); if (road == null || currentsDist < sdist) { @@ -156,9 +115,9 @@ public class BinaryRoutePlanner { } } } - if(road != null) { + if (road != null) { // re-register the best road because one more point was inserted - ctx.registerRouteDataObject(road.getRoad(), ctx.getRoutingTile(foundProjX, foundProjY)); + ctx.registerRouteDataObject(foundProjX, foundProjY, road.getRoad()); } return road; } @@ -185,8 +144,7 @@ public class BinaryRoutePlanner { ps.add(0, start); List results = new ArrayList(); for (int i = 0; i < ps.size() - 1; i++) { - RoutingContext local = new RoutingContext(ctx.config); - local.copyLoadedDataAndClearCaches(ctx); + RoutingContext local = new RoutingContext(ctx); if(i == 0) { local.previouslyCalculatedRoute = firstPartRecalculatedRoute; } @@ -194,34 +152,21 @@ public class BinaryRoutePlanner { List res = searchRouteInternal(local, ps.get(i), ps.get(i + 1), leftSideNavigation); results.addAll(res); ctx.distinctLoadedTiles += local.distinctLoadedTiles; - ctx.distinctUnloadedTiles.addAll(local.distinctUnloadedTiles); ctx.loadedTiles += local.loadedTiles; ctx.visitedSegments += local.visitedSegments; ctx.loadedPrevUnloadedTiles += local.loadedPrevUnloadedTiles; ctx.timeToCalculate += local.timeToCalculate; ctx.timeToLoad += local.timeToLoad; + ctx.timeToLoadHeaders += local.timeToLoadHeaders; ctx.relaxedSegments += local.relaxedSegments; - List toUnload = new ArrayList(); - for(RoutingTile t : local.tiles.valueCollection()){ - if(!ctx.tiles.contains(t.getId())) { - toUnload.add(t); - } - } - for(RoutingTile tl : toUnload) { - local.unloadTile(tl, false); - } + local.unloadAllData(ctx); if(restPartRecalculatedRoute != null) { results.addAll(restPartRecalculatedRoute); break; } } - Object[] vls = ctx.tiles.values(); - for (Object tl : vls) { - if (((RoutingTile) tl).isLoaded()) { - ctx.unloadTile((RoutingTile) tl, false); - } - } + ctx.unloadAllData(); printResults(ctx, start, end, results); return results; } @@ -233,11 +178,7 @@ public class BinaryRoutePlanner { if(result != null) { printResults(ctx, start, end, result); } - Object[] vls = ctx.tiles.values(); - for(Object tl : vls) { - ctx.unloadTile((RoutingTile) tl, false); - } - + ctx.unloadAllData(); return result; } @@ -393,62 +334,6 @@ public class BinaryRoutePlanner { return resultPrepared; } - private void unloadUnusedTiles(RoutingContext ctx) { - // now delete all - float desirableSize = ctx.config.memoryLimitation * 0.7f; - List list = new ArrayList(); - TIntObjectIterator it = ctx.tiles.iterator(); - int loaded = 0; - while(it.hasNext()) { - it.advance(); - RoutingTile t = it.value(); - if(t.isLoaded()) { - list.add(t); - loaded++; - } - - } - ctx.maxLoadedTiles = Math.max(ctx.maxLoadedTiles, ctx.getCurrentlyLoadedTiles()); - Collections.sort(list, new Comparator() { - private int pow(int base, int pw) { - int r = 1; - for (int i = 0; i < pw; i++) { - r *= base; - } - return r; - } - @Override - public int compare(RoutingTile o1, RoutingTile o2) { - int v1 = (o1.access + 1) * pow(10, o1.getUnloadCont() -1); - int v2 = (o2.access + 1) * pow(10, o2.getUnloadCont() -1); - return v1 < v2 ? -1 : (v1 == v2 ? 0 : 1); - } - }); - while(ctx.getCurrentEstimatedSize() >= desirableSize && list.size() > loaded / 5) { - RoutingTile unload = list.remove(0); -// System.out.println("Unload " + unload); - unload.access = 0; - ctx.unloadTile(unload, true); - } - } - - private static long runGCUsedMemory() { - Runtime runtime = Runtime.getRuntime(); - long usedMem1 = runtime.totalMemory() - runtime.freeMemory(); - long usedMem2 = Long.MAX_VALUE; - int cnt = 4; - while (cnt-- >= 0) { - for (int i = 0; (usedMem1 < usedMem2) && (i < 1000); ++i) { - runtime.runFinalization(); - runtime.gc(); - Thread.yield(); - - usedMem2 = usedMem1; - usedMem1 = runtime.totalMemory() - runtime.freeMemory(); - } - } - return usedMem1; - } private void relaxNotNeededSegments(RoutingContext ctx, PriorityQueue graphSegments, boolean inverse) { @@ -516,10 +401,10 @@ public class BinaryRoutePlanner { public void printDebugMemoryInformation(RoutingContext ctx, PriorityQueue graphDirectSegments, PriorityQueue graphReverseSegments, TLongObjectHashMap visitedDirectSegments,TLongObjectHashMap visitedOppositeSegments) { printInfo("Time to calculate : " + (System.nanoTime() - ctx.timeToCalculate) / 1e6 + ", time to load : " + ctx.timeToLoad / 1e6 + ", time to load headers : " + ctx.timeToLoadHeaders / 1e6); - printInfo("Loaded file tiles: " + ctx.routingSubregionLoaded + " distinct " + ctx.routingSubregionsSet.size()); - printInfo("Current loaded tiles : " + ctx.getCurrentlyLoadedTiles() + ", maximum loaded tiles " + ctx.maxLoadedTiles); + int maxLoadedTiles = Math.max(ctx.maxLoadedTiles, ctx.getCurrentlyLoadedTiles()); + printInfo("Current loaded tiles : " + ctx.getCurrentlyLoadedTiles() + ", maximum loaded tiles " + maxLoadedTiles); printInfo("Loaded tiles " + ctx.loadedTiles + " (distinct "+ctx.distinctLoadedTiles+ "), unloaded tiles " + ctx.unloadedTiles + - " (distinct " + ctx.distinctUnloadedTiles.size()+") "+ ", loaded more than once same tiles " + ", loaded more than once same tiles " + ctx.loadedPrevUnloadedTiles ); printInfo("Visited roads, " + ctx.visitedSegments + ", relaxed roads " + ctx.relaxedSegments); if (graphDirectSegments != null && graphReverseSegments != null) { @@ -531,42 +416,6 @@ public class BinaryRoutePlanner { } - @SuppressWarnings("unused") - public RoutingTile loadRoutes(final RoutingContext ctx, int tile31X, int tile31Y) { - - final RoutingTile tile = ctx.getRoutingTile(tile31X, tile31Y); - if (tile.isLoaded()) { - tile.access++; - return tile; - } - if(ctx.getCurrentEstimatedSize() > 0.95 *ctx.config.memoryLimitation) { - int sz1 = ctx.getCurrentEstimatedSize(); - long h1 = 0; - if(SHOW_GC_SIZE && sz1 > 0.7 * ctx.config.memoryLimitation ) { - runGCUsedMemory(); - h1 = runGCUsedMemory(); - } - int clt = ctx.getCurrentlyLoadedTiles(); - unloadUnusedTiles(ctx); - if (h1 != 0 && ctx.getCurrentlyLoadedTiles() != clt) { - int sz2 = ctx.getCurrentEstimatedSize(); - runGCUsedMemory(); - long h2 = runGCUsedMemory(); - float mb = (1 << 20); - log.warn("Unload tiles : estimated " + (sz1 - sz2) / mb + " ?= " + (h1 - h2) / mb+ " actual"); - log.warn("Used after " + h2 / mb + " of " + Runtime.getRuntime().totalMemory() / mb + " max " + Runtime.getRuntime().maxMemory() / mb); - } else { - float mb = (1 << 20); - int sz2 = ctx.getCurrentEstimatedSize(); - log.warn("Unload tiles : occupied before " + sz1/ mb + " Mb - now " + sz2/mb + "MB "); - log.warn("Memory free " + Runtime.getRuntime().freeMemory() / mb + " of " + Runtime.getRuntime().totalMemory() / mb + " max " + Runtime.getRuntime().maxMemory() / mb); - } - } - ctx.loadTileData(tile, null, nativeLib, map); - return tile; - } - - private boolean processRouteSegment(final RoutingContext ctx, boolean reverseWaySearch, PriorityQueue graphSegments, TLongObjectHashMap visitedSegments, int targetEndX, int targetEndY, @@ -661,7 +510,6 @@ public class BinaryRoutePlanner { // 2. calculate point and try to load neighbor ways if they are not loaded int x = road.getPoint31XTile(segmentEnd); int y = road.getPoint31YTile(segmentEnd); - RoutingTile tile = loadRoutes(ctx, x, y); if(positive) { posSegmentDist += squareRootDist(x, y, road.getPoint31XTile(segmentEnd - 1), road.getPoint31YTile(segmentEnd - 1)); @@ -687,8 +535,7 @@ public class BinaryRoutePlanner { obstacleMinusTime += obstacle; } - long l = (((long) x) << 31) + (long) y; - RouteSegment next = tile.getSegment(l, ctx); + RouteSegment next = ctx.loadRouteSegment(x, y); // 3. get intersected ways if (next != null) { // TO-DO U-Turn @@ -927,8 +774,8 @@ public class BinaryRoutePlanner { // calculate time for (int i = 0; i < result.size(); i++) { - if(ctx.getCurrentEstimatedSize() > 0.9 *ctx.config.memoryLimitation) { - unloadUnusedTiles(ctx); + if(ctx.checkIfMemoryLimitCritical()) { + ctx.unloadUnusedTiles(); } RouteSegmentResult rr = result.get(i); RouteDataObject road = rr.getObject(); @@ -1281,8 +1128,6 @@ public class BinaryRoutePlanner { private void attachRoadSegments(RoutingContext ctx, List result, int routeInd, int pointInd, boolean plus) { RouteSegmentResult rr = result.get(routeInd); RouteDataObject road = rr.getObject(); - RoutingTile tl = loadRoutes(ctx, road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd)); - long l = getPoint(road, pointInd); long nextL = pointInd < road.getPointsLength() - 1 ? getPoint(road, pointInd + 1) : 0; long prevL = pointInd > 0 ? getPoint(road, pointInd - 1) : 0; @@ -1305,7 +1150,7 @@ public class BinaryRoutePlanner { } } } - RouteSegment routeSegment = tl.getSegment(l, ctx); + RouteSegment routeSegment = ctx.loadRouteSegment(road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd)); // try to attach all segments except with current id while (routeSegment != null) { if (routeSegment.road.getId() != road.getId() && routeSegment.road.getId() != previousRoadId) { @@ -1384,45 +1229,4 @@ public class BinaryRoutePlanner { } - - public static class SegmentStat { - String name; - Set set = new TreeSet(); - - public SegmentStat(String name) { - this.name = name; - } - - void addNumber(float v) { - set.add(v); - } - - @Override - public String toString() { - int segmentation = 7; - StringBuilder sb = new StringBuilder(); - sb.append(name).append(" (").append(set.size()).append(") : "); - float s = set.size() / ((float) segmentation); - int k = 0, number = 0; - float limit = 0, value = 0; - Iterator it = set.iterator(); - while (it.hasNext()) { - k++; - number++; - value += it.next(); - if (k >= limit) { - limit += s; - sb.append(value / number).append(" "); - number = 0; - value = 0; - } - } - if(number > 0) { - sb.append(value / number).append(" "); - } - return sb.toString(); - } - - } - } diff --git a/DataExtractionOSM/src/net/osmand/router/RoutingContext.java b/DataExtractionOSM/src/net/osmand/router/RoutingContext.java index 1fc143f151..05f4eb5055 100644 --- a/DataExtractionOSM/src/net/osmand/router/RoutingContext.java +++ b/DataExtractionOSM/src/net/osmand/router/RoutingContext.java @@ -5,52 +5,62 @@ import gnu.trove.map.TLongObjectMap; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.map.hash.TLongObjectHashMap; import gnu.trove.set.TLongSet; -import gnu.trove.set.hash.TIntHashSet; import gnu.trove.set.hash.TLongHashSet; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; -import java.util.LinkedHashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; +import net.osmand.LogUtil; import net.osmand.NativeLibrary; import net.osmand.NativeLibrary.NativeRouteSearchResult; -import net.osmand.ResultMatcher; import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader.SearchRequest; +import net.osmand.binary.BinaryMapRouteReaderAdapter; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion; import net.osmand.binary.RouteDataObject; import net.osmand.router.BinaryRoutePlanner.RouteSegment; import net.osmand.router.BinaryRoutePlanner.RouteSegmentVisitor; +import org.apache.commons.logging.Log; + public class RoutingContext { + private final static Log log = LogUtil.getLog(RoutingContext.class); + // Final context variables public final RoutingConfiguration config; - // 1. Initial variables + public final NativeLibrary nativeLib; + public final Map> map = new LinkedHashMap>(); + public final Map reverseMap = new LinkedHashMap(); + // 1. Initial variables private int relaxingIteration = 0; public long firstRoadId = 0; public int firstRoadDirection = 0; public Interruptable interruptable; public List previouslyCalculatedRoute; - // 2. Routing memory cache (big objects) TIntObjectHashMap tiles = new TIntObjectHashMap(); - + // need to be array list + List subregionTiles = new ArrayList(); // 3. Warm object caches TLongSet nonRestrictedIds = new TLongHashSet(); ArrayList segmentsToVisitPrescripted = new ArrayList(5); ArrayList segmentsToVisitNotForbidden = new ArrayList(5); + TLongObjectHashMap excludeDuplications = new TLongObjectHashMap(); + // 4. Final results RouteSegment finalDirectRoute = null; @@ -62,24 +72,62 @@ public class RoutingContext { // 5. debug information (package accessor) long timeToLoad = 0; long timeToLoadHeaders = 0; + long timeToFindInitialSegments = 0; long timeToCalculate = 0; public int loadedTiles = 0; int distinctLoadedTiles = 0; int maxLoadedTiles = 0; int loadedPrevUnloadedTiles = 0; int unloadedTiles = 0; - TIntHashSet distinctUnloadedTiles = new TIntHashSet(); public int visitedSegments = 0; public int relaxedSegments = 0; // callback of processing segments RouteSegmentVisitor visitor = null; - public int routingSubregionLoaded = 0; - public Set routingSubregionsSet = new LinkedHashSet(); private TileStatistics global = new TileStatistics(); + private static final boolean SHOW_GC_SIZE = false; - public RoutingContext(RoutingConfiguration config) { + + + public RoutingContext(RoutingContext cp) { + this.config = cp.config; + this.map.putAll(cp.map); + this.reverseMap.putAll(cp.reverseMap); + this.nativeLib = cp.nativeLib; + // copy local data and clear caches + for(RoutingSubregionTile tl : subregionTiles) { + if(tl.isLoaded()) { + subregionTiles.add(tl); + for (RouteSegment rs : tl.routes.valueCollection()) { + RouteSegment s = rs; + while (s != null) { + s.parentRoute = null; + s.parentSegmentEnd = 0; + s.distanceFromStart = 0; + s.distanceToEnd = 0; + s = s.next; + } + } + } + } + } + + public RoutingContext(RoutingConfiguration config, NativeLibrary nativeLibrary, BinaryMapIndexReader[] map) { + for (BinaryMapIndexReader mr : map) { + List rr = mr.getRoutingIndexes(); + List subregions = new ArrayList(); + for (RouteRegion r : rr) { + for (RouteSubregion rs : r.getSubregions()) { + subregions.add(new RouteSubregion(rs)); + } + this.reverseMap.put(r, mr); + } + this.map.put(mr, subregions); + } this.config = config; + // FIXME not commit +// this.nativeLib = nativeLibrary; + this.nativeLib = null; } @@ -89,9 +137,8 @@ public class RoutingContext { public int getCurrentlyLoadedTiles() { int cnt = 0; - Iterator it = tiles.valueCollection().iterator(); - while (it.hasNext()) { - if (it.next().isLoaded()) { + for(RoutingSubregionTile t : this.subregionTiles){ + if(t.isLoaded()) { cnt++; } } @@ -114,7 +161,6 @@ public class RoutingContext { return false; } - public void setVisitor(RouteSegmentVisitor visitor) { this.visitor = visitor; } @@ -138,8 +184,6 @@ public class RoutingContext { public void setUseDynamicRoadPrioritising(boolean useDynamicRoadPrioritising) { config.useDynamicRoadPrioritising = useDynamicRoadPrioritising; } - - public void setRouter(VehicleRouter router) { config.router = router; @@ -170,29 +214,588 @@ public class RoutingContext { config.heuristicCoefficient); } - public RoutingTile getRoutingTile(int x31, int y31){ + public void registerRouteDataObject(int x31, int y31, RouteDataObject o ) { + if(!getRouter().acceptLine(o)){ + return; + } + getRoutingTile(x31, y31, false).registerRouteDataObject(o); + } + + public void unloadAllData() { + unloadAllData(null); + } + + public void unloadAllData(RoutingContext except) { +// List toUnload = new ArrayList(); +// for(RoutingTile t : local.tiles.valueCollection()){ +// if(!ctx.tiles.contains(t.getId())) { +// toUnload.add(t); +// } +// } +// for(RoutingTile tl : toUnload) { +// local.unloadTile(tl, false); +// } + + for (RoutingSubregionTile tl : subregionTiles) { + if (tl.isLoaded()) { + if(except == null || except.searchSubregionTile(tl.subregion) < 0){ + tl.unload(); + } + } + } + } + + private int searchSubregionTile(RouteSubregion subregion){ + RoutingSubregionTile key = new RoutingSubregionTile(subregion); + int ind = Collections.binarySearch(subregionTiles, key, new Comparator() { + @Override + public int compare(RoutingSubregionTile o1, RoutingSubregionTile o2) { + if(o1.subregion.left == o2.subregion.left) { + return 0; + } + return o1.subregion.left < o2.subregion.left ? 1 : -1; + } + }); + if (ind >= 0) { + for (int i = ind; i <= subregionTiles.size(); i++) { + if (i == subregionTiles.size() || subregionTiles.get(i).subregion.left > subregion.left) { + ind = -i - 1; + return ind; + } + if (subregionTiles.get(i).subregion == subregion) { + return i; + } + } + } + return ind; + } + + + + public RouteSegment loadRouteSegment(int x31, int y31) { + final RoutingTile tile = getRoutingTile(x31, y31, true); + return tile.getSegment(x31, y31, this); + } + + private void loadSubregionTile(final RoutingSubregionTile ts) { + boolean wasUnloaded = ts.isUnloaded(); + if (nativeLib == null) { + long now = System.nanoTime(); + try { + BinaryMapIndexReader reader = reverseMap.get(ts.subregion.routeReg); + ts.setLoadedNonNative(); + List res = reader.loadRouteIndexData(ts.subregion); + for(RouteDataObject ro : res){ + if(ro != null && config.router.acceptLine(ro)) { + ts.add(ro); + } + } + } catch (IOException e) { + throw new RuntimeException("Loading data exception", e); + } + + timeToLoad += (System.nanoTime() - now); + } else { + throw new UnsupportedOperationException(); + // try { + // r.getKey().initRouteRegionsIfNeeded(request); + // } catch (IOException e) { + // throw new RuntimeException("Loading data exception", e); + // } + // for(RouteRegion reg : r.getKey().getRoutingIndexes()) { + // NativeRouteSearchResult rs = nativeLoadRegion(request, reg, nativeLib, loadData); + // if(rs != null) { + // if(!loadData){ + // if (rs.nativeHandler != 0) { + // nativeRouteSearchResults.add(rs); + // } + // } else { + // if(rs.objects != null){ + // for(RouteDataObject ro : rs.objects) { + // if(ro != null) { + // request.publish(ro); + // } + // } + // } + // } + // } + // } + } + loadedTiles++; + if (wasUnloaded) { + loadedPrevUnloadedTiles++; + } else { + if(global != null) { + global.allRoutes += ts.tileStatistics.allRoutes; + global.coordinates += ts.tileStatistics.coordinates; + } + distinctLoadedTiles++; + } + global.size += ts.tileStatistics.size; + } + + private void loadTileHeaders(RoutingTile tile) { + final int zoomToLoad = 31 - tile.getZoom(); + final int tileX = tile.getTileX(); + final int tileY = tile.getTileY(); + + SearchRequest request = BinaryMapIndexReader.buildSearchRouteRequest(tileX << zoomToLoad, + (tileX + 1) << zoomToLoad, tileY << zoomToLoad, (tileY + 1) << zoomToLoad, null); + for (Entry> r : map.entrySet()) { + if(nativeLib == null) { + try { + if (r.getValue().size() > 0) { + long now = System.nanoTime(); +// int rg = r.getValue().get(0).routeReg.regionsRead; + List subregs = r.getKey().searchRouteIndexTree(request, r.getValue()); + for(RouteSubregion sr : subregs) { + List tiles = getRoutingTiles(sr.left, sr.top, sr.right, sr.bottom); + int ind = searchSubregionTile(sr); + RoutingSubregionTile found; + if(ind < 0){ + found = new RoutingSubregionTile(sr); + subregionTiles.add(-(ind+1), found); + } else { + found = subregionTiles.get(ind); + } + for(RoutingTile t : tiles) { + t.searchSubregionAndAdd(sr, found); + } + } + timeToLoadHeaders += (System.nanoTime() - now); + } + } catch (IOException e) { + throw new RuntimeException("Loading data exception", e); + } + + } else { + throw new UnsupportedOperationException(); + } + } + tile.setHeadersLoaded(); + + } + + public void loadTileData(int x31, int y31, int zoomAround, final List toFillIn) { + int coordinatesShift = (1 << (31 - zoomAround)); + // put in map to avoid duplicate map loading + TIntObjectHashMap ts = new TIntObjectHashMap(); + long now = System.nanoTime(); + RoutingTile rt = getRoutingTile(x31 - coordinatesShift, y31 - coordinatesShift, true); + ts.put(rt.getId(), rt); + rt = getRoutingTile(x31 + coordinatesShift, y31 - coordinatesShift, true); + ts.put(rt.getId(), rt); + rt = getRoutingTile(x31 - coordinatesShift, y31 + coordinatesShift, true); + ts.put(rt.getId(), rt); + rt = getRoutingTile(x31 + coordinatesShift, y31 + coordinatesShift, true); + ts.put(rt.getId(), rt); + + Iterator it = ts.valueCollection().iterator(); + + while (it.hasNext()) { + RoutingTile tl = it.next(); + tl.getAllObjects(toFillIn, this); + } + timeToLoadHeaders += (System.nanoTime() - now); + } + + private RoutingTile getRoutingTile(int x31, int y31, boolean load){ int xloc = x31 >> (31 - config.ZOOM_TO_LOAD_TILES); int yloc = y31 >> (31 - config.ZOOM_TO_LOAD_TILES); int l = (xloc << config.ZOOM_TO_LOAD_TILES) + yloc; - RoutingTile tl = tiles.get(l); - if(tl == null) { - tl = new RoutingTile(xloc, yloc, config.ZOOM_TO_LOAD_TILES); - tiles.put(l, tl); + RoutingTile tile = tiles.get(l); + if(tile == null) { + tile = new RoutingTile(xloc, yloc, config.ZOOM_TO_LOAD_TILES); + tiles.put(l, tile); } - return tiles.get(l); + if (load) { + if (getCurrentEstimatedSize() > 0.95 * config.memoryLimitation) { + int sz1 = getCurrentEstimatedSize(); + long h1 = 0; + if (SHOW_GC_SIZE && sz1 > 0.7 * config.memoryLimitation) { + runGCUsedMemory(); + h1 = runGCUsedMemory(); + } + int clt = getCurrentlyLoadedTiles(); + unloadUnusedTiles(); + if (h1 != 0 && getCurrentlyLoadedTiles() != clt) { + int sz2 = getCurrentEstimatedSize(); + runGCUsedMemory(); + long h2 = runGCUsedMemory(); + float mb = (1 << 20); + log.warn("Unload tiles : estimated " + (sz1 - sz2) / mb + " ?= " + (h1 - h2) / mb + " actual"); + log.warn("Used after " + h2 / mb + " of " + Runtime.getRuntime().totalMemory() / mb + " max " + + Runtime.getRuntime().maxMemory() / mb); + } else { +// float mb = (1 << 20); +// int sz2 = getCurrentEstimatedSize(); +// log.warn("Unload tiles : occupied before " + sz1 / mb + " Mb - now " + sz2 / mb + "MB "); +// log.warn("Memory free " + Runtime.getRuntime().freeMemory() / mb + " of " + Runtime.getRuntime().totalMemory() / mb +// + " max " + Runtime.getRuntime().maxMemory() / mb); + } + } + if (!tile.isHeadersLoaded()) { + loadTileHeaders(tile); + } + for (RoutingSubregionTile ts : tile.subregions) { + if (!ts.isLoaded()) { + loadSubregionTile(ts); + } + } + } + return tile; } - public void unloadTile(RoutingTile tile, boolean createEmpty){ - int l = (tile.tileX << config.ZOOM_TO_LOAD_TILES) + tile.tileY; - RoutingTile old = tiles.remove(l); - RoutingTile n = new RoutingTile(tile.tileX, tile.tileY, config.ZOOM_TO_LOAD_TILES); - n.isLoaded = old.isLoaded; + private List getRoutingTiles(int leftX, int topY, int rightX, int bottomY) { + int xl = leftX >> (31 - config.ZOOM_TO_LOAD_TILES); + int yt = topY >> (31 - config.ZOOM_TO_LOAD_TILES); + int xr = rightX >> (31 - config.ZOOM_TO_LOAD_TILES); + int yb = bottomY >> (31 - config.ZOOM_TO_LOAD_TILES); + List res = new ArrayList(); + for (int xloc = xl; xloc <= xr; xloc++) { + for (int yloc = yt; yloc <= yb; yloc++) { + int l = (xloc << config.ZOOM_TO_LOAD_TILES) + yloc; + RoutingTile tl = tiles.get(l); + if (tl == null) { + tl = new RoutingTile(xloc, yloc, config.ZOOM_TO_LOAD_TILES); + tiles.put(l, tl); + } + res.add(tiles.get(l)); + } + } + return res; + } + + public boolean checkIfMemoryLimitCritical() { + return getCurrentEstimatedSize() > 0.9 * config.memoryLimitation; + } + + public void unloadUnusedTiles() { + float desirableSize = config.memoryLimitation * 0.7f; + List list = new ArrayList(subregionTiles.size() / 2); + int loaded = 0; + for(RoutingSubregionTile t : subregionTiles) { + if(t.isLoaded()) { + list.add(t); + loaded++; + } + } + maxLoadedTiles = Math.max(maxLoadedTiles, getCurrentlyLoadedTiles()); + Collections.sort(list, new Comparator() { + private int pow(int base, int pw) { + int r = 1; + for (int i = 0; i < pw; i++) { + r *= base; + } + return r; + } + @Override + public int compare(RoutingSubregionTile o1, RoutingSubregionTile o2) { + int v1 = (o1.access + 1) * pow(10, o1.getUnloadCont() -1); + int v2 = (o2.access + 1) * pow(10, o2.getUnloadCont() -1); + return v1 < v2 ? -1 : (v1 == v2 ? 0 : 1); + } + }); + int i = 0; + while(getCurrentEstimatedSize() >= desirableSize && (list.size() - i) > loaded / 5 && i < list.size()) { + RoutingSubregionTile unload = list.get(i); + i++; +// System.out.println("Unload " + unload); + unload.unload(); + // tile could be cleaned from routing tiles and deleted from whole list + // List ts = getRoutingTiles(tile.subregion.left, tile.subregion.top, tile.subregion.right, tile.subregion.bottom); + + } + for(RoutingSubregionTile t : subregionTiles) { + t.access /= 3; + } + } + + private static long runGCUsedMemory() { + Runtime runtime = Runtime.getRuntime(); + long usedMem1 = runtime.totalMemory() - runtime.freeMemory(); + long usedMem2 = Long.MAX_VALUE; + int cnt = 4; + while (cnt-- >= 0) { + for (int i = 0; (usedMem1 < usedMem2) && (i < 1000); ++i) { + runtime.runFinalization(); + runtime.gc(); + Thread.yield(); + + usedMem2 = usedMem1; + usedMem1 = runtime.totalMemory() - runtime.freeMemory(); + } + } + return usedMem1; + } + + + + protected NativeRouteSearchResult nativeLoadRegion(SearchRequest request, RouteRegion reg, NativeLibrary nativeLib, boolean loadData) { + boolean intersects = false; + for(RouteSubregion sub : reg.getSubregions()) { + if(request.intersects(sub.left, sub.top, sub.right, sub.bottom)) { + intersects = true; + break; + } + } + if(intersects) { + return nativeLib.loadRouteRegion(reg, request.getLeft(), request.getRight(), request.getTop(), request.getBottom(), loadData); + } + return null; + } + + public static class RoutingSubregionTile { + public final RouteSubregion subregion; + // make it without get/set for fast access + public int access; + public TileStatistics tileStatistics = new TileStatistics(); - n.setUnloaded(); - tiles.put(l, n); - unloadedTiles++; - global.size -= tile.tileStatistics.size; - distinctUnloadedTiles.add(l); + private NativeRouteSearchResult searchResult = null; + private int isLoaded = 0; + private TLongObjectMap routes = null; + + public RoutingSubregionTile(RouteSubregion subregion) { + this.subregion = subregion; + } + + private void loadAllObjects(final List toFillIn, RoutingContext ctx) { + if(routes != null) { + Iterator it = routes.valueCollection().iterator(); + while(it.hasNext()){ + RouteSegment rs = it.next(); + while(rs != null){ + RouteDataObject ro = rs.road; + if (!ctx.excludeDuplications.contains(ro.id)) { + ctx.excludeDuplications.put(ro.id, ro); + toFillIn.add(ro); + } + rs = rs.next; + } + } + } else if(searchResult != null) { + throw new UnsupportedOperationException(); + } + } + + private RouteSegment loadRouteSegment(int x31, int y31, RoutingContext ctx, + TLongObjectHashMap excludeDuplications, RouteSegment original) { + if(searchResult == null && routes == null) { + return original; + } + access++; + if (searchResult == null) { + long l = (((long) x31) << 31) + (long) y31; + RouteSegment segment = routes.get(l); + while (segment != null) { + RouteDataObject ro = segment.road; + RouteDataObject toCmp = excludeDuplications.get(ro.id); + if (toCmp == null || toCmp.getPointsLength() < ro.getPointsLength()) { + excludeDuplications.put(ro.id, ro); + RouteSegment s = new RouteSegment(ro, segment.getSegmentStart()); + s.next = original; + original = s; + } + segment = segment.next; + } + return original; + } + // Native use case + RouteDataObject[] res = ctx.nativeLib.getDataObjects(searchResult, x31, y31); + if (res != null) { + for (RouteDataObject ro : res) { + RouteDataObject toCmp = excludeDuplications.get(ro.id); + boolean accept = ro != null && (toCmp == null || toCmp.getPointsLength() < ro.getPointsLength()); + if (ctx != null && accept) { + accept = ctx.getRouter().acceptLine(ro); + } + if (accept) { + excludeDuplications.put(ro.id, ro); + for (int i = 0; i < ro.pointsX.length; i++) { + if (ro.getPoint31XTile(i) == x31 && ro.getPoint31YTile(i) == y31) { + RouteSegment segment = new RouteSegment(ro, i); + segment.next = original; + original = segment; + } + } + } + } + } + return original; + } + + public boolean isLoaded() { + return isLoaded > 0; + } + + public int getUnloadCont(){ + return Math.abs(isLoaded); + } + + public boolean isUnloaded() { + return isLoaded < 0; + } + + public void unload() { + if(isLoaded == 0) { + this.isLoaded = -1; + } else { + isLoaded = -Math.abs(isLoaded); + } + if(searchResult != null) { + searchResult.deleteNativeResult(); + } + searchResult = null; + routes = null; + } + + public void setLoadedNonNative(){ + isLoaded = Math.abs(isLoaded) + 1; + routes = new TLongObjectHashMap(); + tileStatistics = new TileStatistics(); + } + + public void add(RouteDataObject ro) { + tileStatistics.addObject(ro); + for (int i = 0; i < ro.pointsX.length; i++) { + int x31 = ro.getPoint31XTile(i); + int y31 = ro.getPoint31YTile(i); + long l = (((long) x31) << 31) + (long) y31; + RouteSegment segment = new RouteSegment(ro, i); + if (!routes.containsKey(l)) { + routes.put(l, segment); + } else { + RouteSegment orig = routes.get(l); + while (orig.next != null) { + orig = orig.next; + } + orig.next = segment; + } + } + } + + public void load(NativeRouteSearchResult r) { + isLoaded = Math.abs(isLoaded) + 1; + searchResult = r; + // FIXME +// tileStatistics = new TileStatistics(); + } + } + + public static class RoutingTile { + private int tileX; + private int tileY; + private int zoom; + private int isLoaded = 0; + + private List routes = null; + + private List subregions = new ArrayList(4); + + public RoutingTile(int tileX, int tileY, int zoom) { + this.tileX = tileX; + this.tileY = tileY; + this.zoom = zoom; + } + + public boolean isHeadersLoaded(){ + return isLoaded > 0; + } + + public void setHeadersLoaded(){ + isLoaded = 1; + } + + public boolean isEmpty(){ + return (routes == null || routes.isEmpty()) && subregions.isEmpty(); + } + + + public RoutingSubregionTile searchSubregionAndAdd(RouteSubregion s, RoutingSubregionTile rt) { + for(int i=0; i toFillIn, RoutingContext ctx) { + ctx.excludeDuplications.clear(); + if (routes != null) { + for (RouteDataObject ro : routes) { + if (!ctx.excludeDuplications.contains(ro.id)) { + ctx.excludeDuplications.put(ro.id, ro); + toFillIn.add(ro); + } + } + } + for (RoutingSubregionTile rs : subregions) { + rs.loadAllObjects(toFillIn, ctx); + } + } + + public RouteSegment getSegment(int x31, int y31, RoutingContext ctx) { + ctx.excludeDuplications.clear(); + RouteSegment original = null; + if (routes != null) { + for (RouteDataObject ro : routes) { + for (int i = 0; i < ro.pointsX.length; i++) { + if (ro.getPoint31XTile(i) == x31 && ro.getPoint31YTile(i) == y31) { + ctx.excludeDuplications.put(ro.id, ro); + RouteSegment segment = new RouteSegment(ro, i); + segment.next = original; + original = segment; + } + } + } + } + for (RoutingSubregionTile rs : subregions) { + original = rs.loadRouteSegment(x31, y31, ctx, ctx.excludeDuplications, original); + } + return original; + } + + public void registerRouteDataObject(RouteDataObject r) { + if(routes == null){ + routes = new ArrayList(); + } + routes.add(r); + } + + public int getId(){ + return (tileX << zoom) + tileY; + } + + public int getZoom() { + return zoom; + } + + public int getTileX() { + return tileX; + } + + public int getTileY() { + return tileY; + } + + public boolean checkContains(int x31, int y31) { + return tileX == (x31 >> (31 - zoom)) && tileY == (y31 >> (31 - zoom)); + } + + @Override + public String toString() { + return "Tile " + tileX + "/" + tileY ; + } } private static class TileStatistics { @@ -244,337 +847,4 @@ public class RoutingContext { } } - - public void loadTileData(final RoutingTile tile, final List toFillIn, NativeLibrary nativeLib, - Map> map) { - final int zoomToLoad = 31 - tile.getZoom(); - final int tileX = tile.getTileX(); - final int tileY = tile.getTileY(); - final TileStatistics ts = new TileStatistics(); - ResultMatcher matcher = new ResultMatcher() { - @Override - public boolean publish(RouteDataObject o) { - if(o.getPointsLength() == 0) { - return false; - } - ts.allRoutes++; - - int minx, maxx, miny, maxy; - minx = maxx = o.getPoint31XTile(0); - miny = maxy = o.getPoint31YTile(0); - for (int ti = 0; ti < o.getPointsLength(); ti++) { - minx = Math.min(o.getPoint31XTile(ti), minx); - maxx = Math.max(o.getPoint31XTile(ti), maxx); - miny = Math.min(o.getPoint31YTile(ti), miny); - maxy = Math.max(o.getPoint31YTile(ti), maxy); - } - minx = minx >> zoomToLoad; - maxx = maxx >> zoomToLoad; - miny = miny >> zoomToLoad; - maxy = maxy >> zoomToLoad; - if(minx > tileX || maxx < tileX || miny > tileY || maxy < tileY) { - return false; - } - ts.addObject(o); - if (toFillIn != null) { - if (getRouter().acceptLine(o)) { - toFillIn.add(o); - } - } - registerRouteDataObject(o, tile); - return false; - } - - @Override - public String toString() { - return "Tile " + tileX + "/"+ tileY + " : " + ts; - } - - @Override - public boolean isCancelled() { - return false; - } - }; - - boolean loadData = toFillIn != null; - List nativeRouteSearchResults = new ArrayList(); - SearchRequest request = BinaryMapIndexReader.buildSearchRouteRequest(tileX << zoomToLoad, - (tileX + 1) << zoomToLoad, tileY << zoomToLoad, (tileY + 1) << zoomToLoad, matcher); - for (Entry> r : map.entrySet()) { - if(nativeLib != null) { - try { - r.getKey().initRouteRegionsIfNeeded(request); - } catch (IOException e) { - throw new RuntimeException("Loading data exception", e); - } - for(RouteRegion reg : r.getKey().getRoutingIndexes()) { - NativeRouteSearchResult rs = nativeLoadRegion(request, reg, nativeLib, loadData); - if(rs != null) { - if(!loadData){ - if (rs.nativeHandler != 0) { - nativeRouteSearchResults.add(rs); - } - } else { - if(rs.objects != null){ - for(RouteDataObject ro : rs.objects) { - if(ro != null) { - request.publish(ro); - } - } - } - } - } - } - } else { - try { - if (r.getValue().size() > 0) { - long now = System.nanoTime(); -// int rg = r.getValue().get(0).routeReg.regionsRead; - List subregs = r.getKey().searchRouteIndexTree(request, r.getValue()); - for(RouteSubregion s : subregs) { - routingSubregionLoaded ++; - routingSubregionsSet.add(s); - } - timeToLoadHeaders += (System.nanoTime() - now); - now = System.nanoTime(); - r.getKey().loadRouteIndexData(subregs, matcher); - timeToLoad += (System.nanoTime() - now); - } - } catch (IOException e) { - throw new RuntimeException("Loading data exception", e); - } - } - } - - loadedTiles++; - if (tile.isUnloaded()) { - loadedPrevUnloadedTiles++; - } else { - if(global != null) { - global.allRoutes += ts.allRoutes; - global.coordinates += ts.coordinates; - } - distinctLoadedTiles++; - } - tile.tileStatistics = ts; - global.size += ts.size; -// System.out.println("Loaded " + tile + " global " + global); - tile.setLoaded(); - if(nativeRouteSearchResults.size() > 0) { - tile.nativeLib = nativeLib; - tile.nativeResults = nativeRouteSearchResults; - - } - - } - - - - - private NativeRouteSearchResult nativeLoadRegion(SearchRequest request, RouteRegion reg, NativeLibrary nativeLib, boolean loadData) { - boolean intersects = false; - for(RouteSubregion sub : reg.getSubregions()) { - if(request.intersects(sub.left, sub.top, sub.right, sub.bottom)) { - intersects = true; - break; - } - } - if(intersects) { - return nativeLib.loadRouteRegion(reg, request.getLeft(), request.getRight(), request.getTop(), request.getBottom(), loadData); - } - return null; - } - - - /*private */void registerRouteDataObject(RouteDataObject o, RoutingTile suggestedTile ) { - if(!getRouter().acceptLine(o)){ - return; - } - RoutingTile tl = suggestedTile; - RouteDataObject old = tl.idObjects.get(o.id); - // sometimes way is present only partially in one index - if (old != null && old.getPointsLength() >= o.getPointsLength()) { - return; - }; - for (int j = 0; j < o.getPointsLength(); j++) { - int x = o.getPoint31XTile(j); - int y = o.getPoint31YTile(j); - if(!tl.checkContains(x, y)){ - // don't register in different tiles - // in order to throw out tile object easily - continue; - } - long l = (((long) x) << 31) + (long) y; - RouteSegment segment = new RouteSegment(o , j); - RouteSegment prev = tl.getSegment(l, this); - boolean i = true; - if (prev != null) { - if (old == null) { - segment.next = prev; - } else if (prev.road == old) { - segment.next = prev.next; - } else { - // segment somewhere in the middle replace element in linked list - RouteSegment rr = prev; - while (rr != null) { - if (rr.road == old) { - prev.next = segment; - segment.next = rr.next; - break; - } - prev = rr; - rr = rr.next; - } - i = false; - } - } - if (i) { - tl.routes.put(l, segment); - tl.idObjects.put(o.id, o); - } - } - } - - public void copyLoadedDataAndClearCaches(RoutingContext ctx) { - for(RoutingTile tl : ctx.tiles.valueCollection()) { - if(tl.isLoaded()) { - this.tiles.put(tl.getId(), tl); - for(RouteSegment rs : tl.routes.valueCollection()) { - RouteSegment s = rs; - while(s != null) { - s.parentRoute = null; - s.parentSegmentEnd = 0; - s.distanceFromStart = 0; - s.distanceToEnd = 0; - s = s.next; - } - } - } - } - } - - public static class RoutingTile { - private int tileX; - private int tileY; - private int zoom; - private int isLoaded; - // make it without get/set for fast access - public int access; - - private NativeLibrary nativeLib; - // null if it doesn't work with native results - private List nativeResults; - private TLongHashSet excludeDuplications = new TLongHashSet(); - - private TLongObjectMap routes = new TLongObjectHashMap(); - private TLongObjectHashMap idObjects = new TLongObjectHashMap(); - private TileStatistics tileStatistics = new TileStatistics(); - - public RouteSegment getSegment(long id, RoutingContext ctx) { - if(nativeResults != null) { - RouteSegment original = loadNativeRouteSegment(id, ctx); - return original; - } - return routes.get(id); - } - - private RouteSegment loadNativeRouteSegment(long id, RoutingContext ctx) { - int y31 = (int) (id & Integer.MAX_VALUE); - int x31 = (int) (id >> 31); - excludeDuplications.clear(); - RouteSegment original = null; - RouteSegment prev = null; - for (NativeRouteSearchResult rs : nativeResults) { - RouteDataObject[] res = nativeLib.getDataObjects(rs, x31, y31); - if (res != null) { - for (RouteDataObject ro : res) { - boolean accept = ro != null && !excludeDuplications.contains(ro.id); - if(ctx != null && accept) { - accept = ctx.getRouter().acceptLine(ro); - } - if (accept) { - excludeDuplications.add(ro.id); - for (int i = 0; i < ro.pointsX.length; i++) { - if (ro.getPoint31XTile(i) == x31 && ro.getPoint31YTile(i) == y31) { - RouteSegment segment = new RouteSegment(ro, i); - if (prev != null) { - prev.next = segment; - prev = segment; - } else { - original = segment; - prev = segment; - } - } - } - - } - } - } - } - return original; - } - - public RoutingTile(int tileX, int tileY, int zoom) { - this.tileX = tileX; - this.tileY = tileY; - this.zoom = zoom; - } - - public int getId(){ - return (tileX << zoom) + tileY; - } - - public int getZoom() { - return zoom; - } - - public int getTileX() { - return tileX; - } - - public int getTileY() { - return tileY; - } - - public boolean isLoaded() { - return isLoaded > 0; - } - - public int getUnloadCont(){ - return Math.abs(isLoaded); - } - - public boolean isUnloaded() { - return isLoaded < 0; - } - - public void setUnloaded() { - if(isLoaded == 0) { - this.isLoaded = -1; - } else { - isLoaded = -Math.abs(isLoaded); - } - if(nativeResults != null) { - for(NativeRouteSearchResult rs : nativeResults) { - rs.deleteNativeResult(); - } - } - } - - public void setLoaded() { - isLoaded = Math.abs(isLoaded) + 1; - } - - - public boolean checkContains(int x31, int y31) { - return tileX == (x31 >> (31 - zoom)) && tileY == (y31 >> (31 - zoom)); - } - - @Override - public String toString() { - return "Tile " + tileX + "/" + tileY + " : " + tileStatistics; - } - - } - } \ No newline at end of file diff --git a/DataExtractionOSM/src/net/osmand/swing/MapClusterLayer.java b/DataExtractionOSM/src/net/osmand/swing/MapClusterLayer.java index 61a6987a2e..b35b3e26c9 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapClusterLayer.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapClusterLayer.java @@ -119,11 +119,11 @@ public class MapClusterLayer implements MapPanelLayer { rs.add(new BinaryMapIndexReader(raf)); } } - BinaryRoutePlanner router = new BinaryRoutePlanner(NativeSwingRendering.getDefaultFromSettings(), - rs.toArray(new BinaryMapIndexReader[rs.size()])); + BinaryRoutePlanner router = new BinaryRoutePlanner(); Builder builder = RoutingConfiguration.getDefault(); RoutingConfiguration config = builder.build("car", RoutingConfiguration.DEFAULT_MEMORY_LIMIT * 3); - RoutingContext ctx = new RoutingContext(config); + RoutingContext ctx = new RoutingContext(config, NativeSwingRendering.getDefaultFromSettings(), + rs.toArray(new BinaryMapIndexReader[rs.size()])); // find closest way RouteSegment st = router.findRouteSegment(lat, lon, ctx); if (st != null) { @@ -173,7 +173,7 @@ public class MapClusterLayer implements MapPanelLayer { } }); - List results = searchCluster(ctx, st, router); + List results = searchCluster(ctx, st); return results; } @@ -186,7 +186,7 @@ public class MapClusterLayer implements MapPanelLayer { } - private List searchCluster(RoutingContext ctx, RouteSegment st, BinaryRoutePlanner router) throws IOException { + private List searchCluster(RoutingContext ctx, RouteSegment st) throws IOException { Queue> queue = new LinkedList>(); List result = new ArrayList(); TLongHashSet visitedIds = new TLongHashSet(); @@ -264,9 +264,7 @@ public class MapClusterLayer implements MapPanelLayer { int x = road.getPoint31XTile(segmentEnd); int y = road.getPoint31YTile(segmentEnd); - router.loadRoutes(ctx, x, y); - long l = (((long) x) << 31) + (long) y; - RouteSegment next = ctx.getRoutingTile(x, y).getSegment(l, ctx); + RouteSegment next = ctx.loadRouteSegment(x, y); RouteSegment toAdd = segment; if (!onTheMap.contains(toAdd.getRoad().getId())) { onTheMap.add(toAdd.getRoad().getId()); diff --git a/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java b/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java index dc3bfef706..6e196bd95d 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java @@ -35,16 +35,20 @@ import net.osmand.data.DataTileManager; import net.osmand.osm.Entity; import net.osmand.osm.LatLon; import net.osmand.osm.MapUtils; -import net.osmand.osm.Way; import net.osmand.osm.OSMSettings.OSMTagKey; +import net.osmand.osm.Way; import net.osmand.router.BinaryRoutePlanner; +import net.osmand.router.BinaryRoutePlanner.RouteSegment; +import net.osmand.router.BinaryRoutePlanner.RouteSegmentVisitor; import net.osmand.router.RouteSegmentResult; import net.osmand.router.RoutingConfiguration; import net.osmand.router.RoutingConfiguration.Builder; import net.osmand.router.RoutingContext; -import net.osmand.router.BinaryRoutePlanner.RouteSegment; -import net.osmand.router.BinaryRoutePlanner.RouteSegmentVisitor; +import org.apache.commons.logging.Log; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -52,11 +56,6 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import org.apache.commons.logging.Log; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; - public class MapRouterLayer implements MapPanelLayer { @@ -611,11 +610,11 @@ public class MapRouterLayer implements MapPanelLayer { } String m = DataExtractionSettings.getSettings().getRouteMode(); String[] props = m.split("\\,"); - BinaryRoutePlanner router = new BinaryRoutePlanner(NativeSwingRendering.getDefaultFromSettings(), rs); + BinaryRoutePlanner router = new BinaryRoutePlanner(); RoutingConfiguration config = builder.build(props[0], RoutingConfiguration.DEFAULT_MEMORY_LIMIT * 2, props); // config.NUMBER_OF_DESIRABLE_TILES_IN_MEMORY = 300; // config.ZOOM_TO_LOAD_TILES = 14; - RoutingContext ctx = new RoutingContext(config); + RoutingContext ctx = new RoutingContext(config, NativeSwingRendering.getDefaultFromSettings(), rs); ctx.previouslyCalculatedRoute = previousRoute; log.info("Use " + config.routerName + "mode for routing"); diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index 9b3be3a95c..6ce7a5e1db 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -314,7 +314,7 @@ public class RouteProvider { List previousRoute, boolean leftSide, Interruptable interruptable) throws IOException { BinaryMapIndexReader[] files = app.getResourceManager().getRoutingMapFiles(); - BinaryRoutePlanner router = new BinaryRoutePlanner(NativeOsmandLibrary.getLoadedLibrary(), files); + BinaryRoutePlanner router = new BinaryRoutePlanner(); File routingXml = app.getSettings().extendOsmandPath(ResourceManager.ROUTING_XML); RoutingConfiguration.Builder config ; if (routingXml.exists() && routingXml.canRead()) { @@ -356,11 +356,11 @@ public class RouteProvider { Runtime rt = Runtime.getRuntime(); // make visible int memoryLimit = (int) (0.9 * ((rt.maxMemory() - rt.totalMemory()) + rt.freeMemory()) / mb); - log.error("Use " + memoryLimit + "Free " + rt.freeMemory() / mb + " of " + rt.totalMemory() / mb + " max " + rt.maxMemory() / mb); + log.warn("Use " + memoryLimit + "Free " + rt.freeMemory() / mb + " of " + rt.totalMemory() / mb + " max " + rt.maxMemory() / mb); RoutingConfiguration cf = config.build(p.name().toLowerCase(), start.hasBearing() ? start.getBearing() / 180d * Math.PI : null, memoryLimit, specialization); - RoutingContext ctx = new RoutingContext(cf); + RoutingContext ctx = new RoutingContext(cf, NativeOsmandLibrary.getLoadedLibrary(), files); ctx.interruptable = interruptable; ctx.previouslyCalculatedRoute = previousRoute; RouteSegment st= router.findRouteSegment(start.getLatitude(), start.getLongitude(), ctx);