From 7068dd3b61918a8a75392567a66f5f4595d2513c Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Mon, 5 Nov 2012 01:38:24 +0100 Subject: [PATCH] Native routing --- .../src/net/osmand/NativeLibrary.java | 9 +- .../binary/BinaryMapRouteReaderAdapter.java | 2 +- .../net/osmand/binary/RouteDataObject.java | 3 +- .../data/preparation/IndexRouteCreator.java | 1 + .../net/osmand/router/BinaryRoutePlanner.java | 48 +++--- .../osmand/router/BinaryRoutePlannerOld.java | 81 ++++------ .../osmand/router/RouteResultPreparation.java | 49 ++++-- .../net/osmand/router/RouteSegmentResult.java | 16 ++ .../osmand/router/RoutingConfiguration.java | 6 +- .../src/net/osmand/router/RoutingContext.java | 40 +---- .../src/net/osmand/router/routing.xml | 151 +++++++++--------- .../src/net/osmand/swing/MapRouterLayer.java | 14 +- Osmand-kernel/osmand/src/binaryRead.h | 57 ++++++- .../osmand/src/binaryRoutePlanner.cpp | 87 +++++++--- Osmand-kernel/osmand/src/binaryRoutePlanner.h | 39 +++-- Osmand-kernel/osmand/src/common.cpp | 11 ++ Osmand-kernel/osmand/src/common.h | 1 + Osmand-kernel/osmand/src/java_wrap.cpp | 72 +++++++-- 18 files changed, 437 insertions(+), 250 deletions(-) diff --git a/DataExtractionOSM/src/net/osmand/NativeLibrary.java b/DataExtractionOSM/src/net/osmand/NativeLibrary.java index 3f0de5ea30..12603e3830 100644 --- a/DataExtractionOSM/src/net/osmand/NativeLibrary.java +++ b/DataExtractionOSM/src/net/osmand/NativeLibrary.java @@ -109,7 +109,8 @@ public class NativeLibrary { return closeBinaryMapFile(filePath); } - public RouteSegmentResult[] runNativeRouting(int sx31, int sy31, int ex31, int ey31, RoutingConfiguration config) { + public RouteSegmentResult[] runNativeRouting(int sx31, int sy31, int ex31, int ey31, RoutingConfiguration config, + RouteRegion[] regions) { TIntArrayList state = new TIntArrayList(); List keys = new ArrayList(); List values = new ArrayList(); @@ -124,7 +125,8 @@ public class NativeLibrary { fillObjects(state, keys, values, 5, attrs); return nativeRouting(new int[]{sx31, sy31, ex31, ey31}, state.toArray(), keys.toArray(new String[keys.size()]), - values.toArray(new String[values.size()])); + values.toArray(new String[values.size()]), config.initialDirection == null ? -360 : config.initialDirection.floatValue(), + regions); } public void fillObjects(TIntArrayList state, List keys, List values, int s, Map map) { @@ -156,7 +158,8 @@ public class NativeLibrary { protected static native RouteDataObject[] getRouteDataObjects(RouteRegion reg, long rs, int x31, int y31); - protected static native RouteSegmentResult[] nativeRouting(int[] coordinates, int[] state, String[] keyConfig, String[] valueConfig); + protected static native RouteSegmentResult[] nativeRouting(int[] coordinates, int[] state, String[] keyConfig, String[] valueConfig, + float initDirection, RouteRegion[] regions); protected static native void deleteSearchResult(long searchResultHandle); diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java index 5f337b7037..a2f4a4e5c6 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java @@ -845,7 +845,7 @@ public class BinaryMapRouteReaderAdapter { RouteBorderLine ln = readBorderLine(); if(ln.hasTox() && req.intersects(ln.getX(), ln.getY(), ln.getTox(), ln.getY())) { blocksToRead.add(ln.getShiftToPointsBlock() + fp); - // FIXME + // FIXME borders approach // } else if(ln.hasToy() && req.intersects(ln.getX(), ln.getY(), ln.getX(), ln.getToy())) { // blocksToRead.add(ln.getShiftToPointsBlock() + fp); } diff --git a/DataExtractionOSM/src/net/osmand/binary/RouteDataObject.java b/DataExtractionOSM/src/net/osmand/binary/RouteDataObject.java index 62c2c02646..efe7b4af85 100644 --- a/DataExtractionOSM/src/net/osmand/binary/RouteDataObject.java +++ b/DataExtractionOSM/src/net/osmand/binary/RouteDataObject.java @@ -11,7 +11,7 @@ public class RouteDataObject { public final RouteRegion region; // all these arrays supposed to be immutable! - // These feilds accessible from C++ + // These fields accessible from C++ public int[] types; public int[] pointsX; public int[] pointsY; @@ -213,6 +213,7 @@ public class RouteDataObject { } public double directionRoute(int startPoint, boolean plus) { + // same goes to C++ // Victor : the problem to put more than 5 meters that BinaryRoutePlanner will treat // 2 consequent Turn Right as UT and here 2 points will have same turn angle // So it should be fix in both places diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexRouteCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexRouteCreator.java index 5ed9e7493e..a209c56e4f 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexRouteCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexRouteCreator.java @@ -422,6 +422,7 @@ public class IndexRouteCreator extends AbstractIndexPartCreator { routeTree, false); TLongObjectHashMap base = writeBinaryRouteIndexHeader(writer, baserouteTree, true); + // FIXME borders should not be committed in master branch // writeBorderBox(writer, routeBorders); // writeBorderBox(writer, baseRouteBorders); diff --git a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java index 15c57f852b..fd247fc485 100644 --- a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java +++ b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java @@ -43,9 +43,9 @@ public class BinaryRoutePlanner { int px = MapUtils.get31TileNumberX(lon); int py = MapUtils.get31TileNumberY(lat); ArrayList dataObjects = new ArrayList(); - ctx.loadTileData(px, py, 16, dataObjects); + ctx.loadTileData(px, py, 17, dataObjects); if (dataObjects.isEmpty()) { - ctx.loadTileData(px, py, 14, dataObjects); + ctx.loadTileData(px, py, 15, dataObjects); } RouteSegment road = null; double sdist = 0; @@ -334,10 +334,6 @@ public class BinaryRoutePlanner { graphSegments = graphDirectSegments; } - if(ctx.runRelaxingStrategy() ) { - relaxNotNeededSegments(ctx, graphDirectSegments, true); - relaxNotNeededSegments(ctx, graphReverseSegments, false); - } // check if interrupted if(ctx.interruptable != null && ctx.interruptable.isCancelled()) { throw new InterruptedException("Route calculation interrupted"); @@ -349,12 +345,12 @@ public class BinaryRoutePlanner { private RouteSegment smartRecalculationEnabled(final RoutingContext ctx, TLongObjectHashMap visitedOppositeSegments) { - boolean runRecalculation = ctx.previouslyCalculatedRoute != null && ctx.previouslyCalculatedRoute.size() > 0; + boolean runRecalculation = ctx.previouslyCalculatedRoute != null && ctx.previouslyCalculatedRoute.size() > 0 + && ctx.config.recalculateDistance != 0; if (runRecalculation) { RouteSegment previous = null; List rlist = new ArrayList(); - // always recalculate first 7 km - int distanceThreshold = 7000; + float distanceThreshold = ctx.config.recalculateDistance; float threshold = 0; for(RouteSegmentResult rr : ctx.previouslyCalculatedRoute) { threshold += rr.getDistance(); @@ -489,16 +485,6 @@ public class BinaryRoutePlanner { } double result = distToFinalPoint / ctx.getRouter().getMaxDefaultSpeed(); - if(ctx.isUseDynamicRoadPrioritising() && next != null){ - double priority = ctx.getRouter().getFutureRoadPriority(next.road); - result /= priority; - int dist = ctx.getDynamicRoadPriorityDistance(); - // only first N km-s count by dynamic priority - if(distToFinalPoint > dist && dist != 0){ - result = (distToFinalPoint - dist) / ctx.getRouter().getMaxDefaultSpeed() + - dist / (ctx.getRouter().getMaxDefaultSpeed() * priority); - } - } return (float) result; } @@ -984,6 +970,30 @@ public class BinaryRoutePlanner { return String.format("s%.2f e%.2f", ((float)distanceFromStart), ((float)distanceToEnd)); } + + public Iterator getIterator() { + return new Iterator() { + RouteSegment next = RouteSegment.this; + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public RouteSegment next() { + RouteSegment c = next; + if(next != null) { + next = next.next; + } + return c; + } + + @Override + public boolean hasNext() { + return next != null; + } + }; + } } static class FinalRouteSegment extends RouteSegment { diff --git a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlannerOld.java b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlannerOld.java index 50c2063471..17c0d44a9d 100644 --- a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlannerOld.java +++ b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlannerOld.java @@ -5,12 +5,15 @@ import gnu.trove.map.hash.TLongObjectHashMap; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.PriorityQueue; import net.osmand.LogUtil; +import net.osmand.binary.BinaryMapRouteReaderAdapter; +import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion; import net.osmand.binary.RouteDataObject; import net.osmand.osm.MapRenderingTypes; import net.osmand.osm.MapUtils; @@ -73,9 +76,9 @@ public class BinaryRoutePlannerOld { int px = MapUtils.get31TileNumberX(lon); int py = MapUtils.get31TileNumberY(lat); ArrayList dataObjects = new ArrayList(); - ctx.loadTileData(px, py, 16, dataObjects); + ctx.loadTileData(px, py, 17, dataObjects); if (dataObjects.isEmpty()) { - ctx.loadTileData(px, py, 14, dataObjects); + ctx.loadTileData(px, py, 15, dataObjects); } RouteSegment road = null; double sdist = 0; @@ -201,17 +204,31 @@ public class BinaryRoutePlannerOld { private List searchRouteInternalPrepare(final RoutingContext ctx, RouteSegment start, RouteSegment end, boolean leftSideNavigation) throws IOException, InterruptedException { - // Split into 2 methods to let GC work in between - searchRouteInternal(ctx, start, end, leftSideNavigation); - // 4. Route is found : collect all segments and prepare result - return new RouteResultPreparation().prepareResult(ctx, ctx.finalRouteSegment, leftSideNavigation); + if (ctx.nativeLib != null) { + int ex31 = end.getRoad().getPoint31XTile(end.getSegmentStart()); + int ey31 = end.getRoad().getPoint31YTile(end.getSegmentStart()); + int sx31 = start.getRoad().getPoint31XTile(start.getSegmentStart()); + int sy31 = start.getRoad().getPoint31YTile(start.getSegmentStart()); + RouteRegion[] regions = ctx.reverseMap.keySet().toArray(new BinaryMapRouteReaderAdapter.RouteRegion[ctx.reverseMap.size()]); + RouteSegmentResult[] res = ctx.nativeLib.runNativeRouting(sx31, sy31, ex31, ey31, ctx.config, regions); + ArrayList result = new ArrayList(Arrays.asList(res)); + + return new RouteResultPreparation().prepareResult(ctx, leftSideNavigation, result); + } else { + // Split into 2 methods to let GC work in between + searchRouteInternal(ctx, start, end); + // 4. Route is found : collect all segments and prepare result + return new RouteResultPreparation().prepareResult(ctx, ctx.finalRouteSegment, leftSideNavigation); + } + + } /** * Calculate route between start.segmentEnd and end.segmentStart (using A* algorithm) * return list of segments */ - private void searchRouteInternal(final RoutingContext ctx, RouteSegment start, RouteSegment end, boolean leftSideNavigation) throws IOException, InterruptedException { + private void searchRouteInternal(final RoutingContext ctx, RouteSegment start, RouteSegment end) throws IOException, InterruptedException { // measure time ctx.timeToLoad = 0; ctx.visitedSegments = 0; @@ -250,12 +267,12 @@ public class BinaryRoutePlannerOld { TLongObjectHashMap visitedDirectSegments = new TLongObjectHashMap(); TLongObjectHashMap visitedOppositeSegments = new TLongObjectHashMap(); - boolean runRecalculation = ctx.previouslyCalculatedRoute != null && ctx.previouslyCalculatedRoute.size() > 0; + boolean runRecalculation = ctx.previouslyCalculatedRoute != null && ctx.previouslyCalculatedRoute.size() > 0 + && ctx.config.recalculateDistance != 0; if (runRecalculation) { RouteSegment previous = null; List rlist = new ArrayList(); - // always recalculate first 7 km - int distanceThreshold = 7000; + float distanceThreshold = ctx.config.recalculateDistance; float threshold = 0; for(RouteSegmentResult rr : ctx.previouslyCalculatedRoute) { threshold += rr.getDistance(); @@ -340,11 +357,6 @@ public class BinaryRoutePlannerOld { } else { graphSegments = graphDirectSegments; } - - if(ctx.runRelaxingStrategy() ) { - relaxNotNeededSegments(ctx, graphDirectSegments, true); - relaxNotNeededSegments(ctx, graphReverseSegments, false); - } // check if interrupted if(ctx.interruptable != null && ctx.interruptable.isCancelled()) { throw new InterruptedException("Route calculation interrupted"); @@ -356,35 +368,6 @@ public class BinaryRoutePlannerOld { - private void relaxNotNeededSegments(RoutingContext ctx, PriorityQueue graphSegments, boolean inverse) { - RouteSegment next = graphSegments.peek(); - double mine = next.distanceToEnd; -// int before = graphSegments.size(); -// SegmentStat statStart = new SegmentStat("Distance from start (" + inverse + ") "); -// SegmentStat statEnd = new SegmentStat("Distance to end (" + inverse + ") "); - Iterator iterator = graphSegments.iterator(); - while (iterator.hasNext()) { - RouteSegment s = iterator.next(); -// statStart.addNumber((float) s.distanceFromStart); -// statEnd.addNumber((float) s.distanceToEnd); - if (s.distanceToEnd < mine) { - mine = s.distanceToEnd; - } - } - double d = mine * ctx.config.RELAX_NODES_IF_START_DIST_COEF; - iterator = graphSegments.iterator(); - while (iterator.hasNext()) { - RouteSegment s = iterator.next(); - if (s.distanceToEnd > d) { - ctx.relaxedSegments++; - iterator.remove(); - } - } -// int after = graphSegments.size(); -// println(statStart.toString()); -// println(statEnd.toString()); -// println("Relaxing : before " + before + " after " + after + " minend " + ((float) mine)); - } private double h(final RoutingContext ctx, int targetEndX, int targetEndY, int startX, int startY) { @@ -394,16 +377,6 @@ public class BinaryRoutePlannerOld { protected static double h(RoutingContext ctx, double distToFinalPoint, RouteSegment next) { double result = distToFinalPoint / ctx.getRouter().getMaxDefaultSpeed(); - if(ctx.isUseDynamicRoadPrioritising() && next != null){ - double priority = ctx.getRouter().getFutureRoadPriority(next.road); - result /= priority; - int dist = ctx.getDynamicRoadPriorityDistance(); - // only first N km-s count by dynamic priority - if(distToFinalPoint > dist && dist != 0){ - result = (distToFinalPoint - dist) / ctx.getRouter().getMaxDefaultSpeed() + - dist / (ctx.getRouter().getMaxDefaultSpeed() * priority); - } - } return result; } diff --git a/DataExtractionOSM/src/net/osmand/router/RouteResultPreparation.java b/DataExtractionOSM/src/net/osmand/router/RouteResultPreparation.java index ee597d3807..28d462915d 100644 --- a/DataExtractionOSM/src/net/osmand/router/RouteResultPreparation.java +++ b/DataExtractionOSM/src/net/osmand/router/RouteResultPreparation.java @@ -4,6 +4,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.List; import net.osmand.binary.RouteDataObject; @@ -20,9 +21,12 @@ public class RouteResultPreparation { */ List prepareResult(RoutingContext ctx, FinalRouteSegment finalSegment,boolean leftside) { List result = convertFinalSegmentToResults(ctx, finalSegment); + prepareResult(ctx, leftside, result); + return result; + } + List prepareResult(RoutingContext ctx, boolean leftside, List result) { validateAllPointsConnected(result); - // calculate time calculateTimeSpeedAndAttachRoadSegments(ctx, result); @@ -47,12 +51,12 @@ public class RouteResultPreparation { double distance = 0; for (int j = rr.getStartPointIndex(); j != rr.getEndPointIndex(); j = next) { next = plus ? j + 1 : j - 1; - if(j == rr.getStartPointIndex()) { - attachRoadSegments(ctx, result, i, j, plus); - } - if(next != rr.getEndPointIndex()) { - attachRoadSegments(ctx, result, i, next, plus); - } + if (j == rr.getStartPointIndex()) { + attachRoadSegments(ctx, result, i, j, plus); + } + if (next != rr.getEndPointIndex()) { + attachRoadSegments(ctx, result, i, next, plus); + } double d = measuredDist(road.getPoint31XTile(j), road.getPoint31YTile(j), road.getPoint31XTile(next), road.getPoint31YTile(next)); @@ -81,6 +85,7 @@ public class RouteResultPreparation { if (isSplit) { int endPointIndex = rr.getEndPointIndex(); RouteSegmentResult split = new RouteSegmentResult(rr.getObject(), next, endPointIndex); + split.copyPreattachedRoutes(rr, Math.abs(next - rr.getStartPointIndex())); rr.setSegmentTime((float) distOnRoadToPass); rr.setSegmentSpeed((float) speed); rr.setDistance((float) distance); @@ -496,12 +501,35 @@ public class RouteResultPreparation { } } } - RouteSegment routeSegment = ctx.loadRouteSegment(road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd), ctx.config.memoryLimitation); + Iterator it; + if(rr.getPreAttachedRoutes(pointInd) != null) { + final RouteSegmentResult[] list = rr.getPreAttachedRoutes(pointInd); + it = new Iterator() { + int i = 0; + @Override + public boolean hasNext() { + return i < list.length; + } + + @Override + public RouteSegment next() { + RouteSegmentResult r = list[i++]; + return new RouteSegment(r.getObject(), r.getStartPointIndex()); + } + + @Override + public void remove() { + } + }; + } else { + RouteSegment rt = ctx.loadRouteSegment(road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd), ctx.config.memoryLimitation); + it = rt.getIterator(); + } // try to attach all segments except with current id - while (routeSegment != null) { + while (it.hasNext()) { + RouteSegment routeSegment = it.next(); if (routeSegment.road.getId() != road.getId() && routeSegment.road.getId() != previousRoadId) { RouteDataObject addRoad = routeSegment.road; - // TODO restrictions can be considered as well int oneWay = ctx.getRouter().isOneWay(addRoad); if (oneWay >= 0 && routeSegment.getSegmentStart() < addRoad.getPointsLength() - 1) { @@ -519,7 +547,6 @@ public class RouteResultPreparation { } } } - routeSegment = routeSegment.next; } } diff --git a/DataExtractionOSM/src/net/osmand/router/RouteSegmentResult.java b/DataExtractionOSM/src/net/osmand/router/RouteSegmentResult.java index 723701022a..9f035b7b0b 100644 --- a/DataExtractionOSM/src/net/osmand/router/RouteSegmentResult.java +++ b/DataExtractionOSM/src/net/osmand/router/RouteSegmentResult.java @@ -14,6 +14,7 @@ public class RouteSegmentResult { private int startPointIndex; private int endPointIndex; private List[] attachedRoutes; + private RouteSegmentResult[][] preAttachedRoutes; private float segmentTime; private float speed; private float distance; @@ -28,6 +29,7 @@ public class RouteSegmentResult { this.endPointIndex = endPointIndex; updateCapacity(); } + @SuppressWarnings("unchecked") private void updateCapacity() { @@ -43,6 +45,20 @@ public class RouteSegmentResult { attachedRoutes[st].add(r); } + public void copyPreattachedRoutes(RouteSegmentResult toCopy, int shift) { + int l = toCopy.preAttachedRoutes.length - shift; + preAttachedRoutes = new RouteSegmentResult[l][]; + System.arraycopy(toCopy.preAttachedRoutes, shift, preAttachedRoutes, 0, l); + } + + public RouteSegmentResult[] getPreAttachedRoutes(int routeInd) { + int st = Math.abs(routeInd - startPointIndex); + if(st < preAttachedRoutes.length) { + return preAttachedRoutes[st]; + } + return null; + } + public List getAttachedRoutes(int routeInd) { int st = Math.abs(routeInd - startPointIndex); List list = attachedRoutes[st]; diff --git a/DataExtractionOSM/src/net/osmand/router/RoutingConfiguration.java b/DataExtractionOSM/src/net/osmand/router/RoutingConfiguration.java index 8e83f48151..f21aaa3d40 100644 --- a/DataExtractionOSM/src/net/osmand/router/RoutingConfiguration.java +++ b/DataExtractionOSM/src/net/osmand/router/RoutingConfiguration.java @@ -39,6 +39,9 @@ public class RoutingConfiguration { // 1.4 Used to calculate route in movement public Double initialDirection; + // 1.5 Recalculate distance help + public float recalculateDistance = 10000f; + public static class Builder { @@ -67,6 +70,7 @@ public class RoutingConfiguration { attributes.put("routerName", router); i.attributes.putAll(attributes); i.initialDirection = direction; + i.recalculateDistance = parseSilentFloat(getAttribute(i.router, "recalculateDistanceHelp"), i.recalculateDistance) ; i.heuristicCoefficient = parseSilentFloat(getAttribute(i.router, "heuristicCoefficient"), i.heuristicCoefficient); i.ZOOM_TO_LOAD_TILES = parseSilentInt(getAttribute(i.router, "zoomToLoadTiles"), i.ZOOM_TO_LOAD_TILES); int desirable = parseSilentInt(getAttribute(i.router, "memoryLimitInMB"), 0); @@ -78,7 +82,7 @@ public class RoutingConfiguration { } i.memoryLimitation = memoryLimitMB * (1 << 20); } - i.planRoadDirection = parseSilentInt(getAttribute(router, "planRoadDirection"), i.planRoadDirection); + i.planRoadDirection = parseSilentInt(getAttribute(i.router, "planRoadDirection"), i.planRoadDirection); return i; diff --git a/DataExtractionOSM/src/net/osmand/router/RoutingContext.java b/DataExtractionOSM/src/net/osmand/router/RoutingContext.java index 684c51842b..491ed7ba9a 100644 --- a/DataExtractionOSM/src/net/osmand/router/RoutingContext.java +++ b/DataExtractionOSM/src/net/osmand/router/RoutingContext.java @@ -54,7 +54,6 @@ public class RoutingContext { public final Map reverseMap = new LinkedHashMap(); // 1. Initial variables - private int relaxingIteration = 0; public long firstRoadId = 0; public int firstRoadDirection = 0; @@ -179,42 +178,11 @@ public class RoutingContext { return global.size; } - public boolean runRelaxingStrategy(){ - if(!isUseRelaxingStrategy()){ - return false; - } - relaxingIteration++; - if(relaxingIteration > config.ITERATIONS_TO_RELAX_NODES){ - relaxingIteration = 0; - return true; - } - return false; - } public void setVisitor(RouteSegmentVisitor visitor) { this.visitor = visitor; } - public boolean isUseDynamicRoadPrioritising() { - return config.useDynamicRoadPrioritising; - } - - public int getDynamicRoadPriorityDistance() { - return config.dynamicRoadPriorityDistance; - } - - public boolean isUseRelaxingStrategy() { - return config.useRelaxingStrategy; - } - - public void setUseRelaxingStrategy(boolean useRelaxingStrategy) { - config.useRelaxingStrategy = useRelaxingStrategy; - } - - public void setUseDynamicRoadPrioritising(boolean useDynamicRoadPrioritising) { - config.useDynamicRoadPrioritising = useDynamicRoadPrioritising; - } - public void setRouter(VehicleRouter router) { config.router = router; } @@ -350,7 +318,7 @@ public class RoutingContext { borderLineCoordinates = new int[borderLines.length]; for(int i=0; i 0 && borderLineCoordinates[i - 1] >> 17 == borderLineCoordinates[i] >> 17) { throw new IllegalStateException(); @@ -517,13 +485,15 @@ public class RoutingContext { } public void loadTileData(int x31, int y31, int zoomAround, final List toFillIn) { - int t = zoomAround - config.ZOOM_TO_LOAD_TILES; + int t = config.ZOOM_TO_LOAD_TILES - zoomAround; + int coordinatesShift = (1 << (31 - config.ZOOM_TO_LOAD_TILES)); if(t <= 0) { t = 1; + coordinatesShift = (1 << (31 - zoomAround)); } else { t = 1 << t; } - int coordinatesShift = (1 << (31 - config.ZOOM_TO_LOAD_TILES)); + TLongHashSet ts = new TLongHashSet(); long now = System.nanoTime(); for(int i = -t; i <= t; i++) { diff --git a/DataExtractionOSM/src/net/osmand/router/routing.xml b/DataExtractionOSM/src/net/osmand/router/routing.xml index 9822e1b61a..9b86e94d9e 100644 --- a/DataExtractionOSM/src/net/osmand/router/routing.xml +++ b/DataExtractionOSM/src/net/osmand/router/routing.xml @@ -12,23 +12,24 @@ (don't specify here ! it is device dependent) --> - + + + + + - - + - - @@ -36,55 +37,55 @@ --> - + - + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - + @@ -121,36 +122,36 @@ leftTurn="0" rightTurn="0" followSpeedLimitations="false" onewayAware="true"> - + - + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + @@ -171,36 +172,36 @@ - + - + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java b/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java index f2299b2bd6..bcaf0919ce 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java @@ -716,14 +716,11 @@ public class MapRouterLayer implements MapPanelLayer { }); - int ex31 = e.getRoad().getPoint31XTile(e.getSegmentStart()); - int ey31 = e.getRoad().getPoint31YTile(e.getSegmentStart()); - int sx31 = st.getRoad().getPoint31XTile(st.getSegmentStart()); - int sy31 = st.getRoad().getPoint31YTile(st.getSegmentStart()); -// FIXME - RouteSegmentResult[] searchRoute = ctx.nativeLib.runNativeRouting(sx31, sy31, ex31, ey31, ctx.config); -// /*List searchRoute = */router.searchRoute(ctx, st, e, inters, false); -// this.previousRoute = searchRoute; + + // Choose native or not native + long nt = System.nanoTime(); + List searchRoute = router.searchRoute(ctx, st, e, inters, false); + System.out.println("External native time " + (System.nanoTime() - nt) / 1e9f); if (animateRoutingCalculation) { playPauseButton.setVisible(false); nextTurn.setText("FINISH"); @@ -742,7 +739,6 @@ public class MapRouterLayer implements MapPanelLayer { // String name = String.format("beg %.2f end %.2f ", s.getBearingBegin(), s.getBearingEnd()); way.putTag(OSMTagKey.NAME.getValue(),name); boolean plus = s.getStartPointIndex() < s.getEndPointIndex(); - System.out.println("Segment " + s.getObject().id + " "+s.getStartPointIndex() + " -> " + s.getEndPointIndex()); int i = s.getStartPointIndex(); while (true) { LatLon l = s.getPoint(i); diff --git a/Osmand-kernel/osmand/src/binaryRead.h b/Osmand-kernel/osmand/src/binaryRead.h index fe5f64b1a0..26de60afca 100644 --- a/Osmand-kernel/osmand/src/binaryRead.h +++ b/Osmand-kernel/osmand/src/binaryRead.h @@ -10,8 +10,6 @@ #include #include #include - - #include "mapObjects.h" #include "multipolygons.h" #include "common.h" @@ -108,6 +106,61 @@ struct RouteDataObject { UNORDERED(map) names; vector > namesIds; + + string getName() { + if(names.size() > 0) { + return names.begin()->second; + } + return ""; + } + + int getSize() { + int s = sizeof(this); + s += pointsX.capacity()*sizeof(uint32_t); + s += pointsY.capacity()*sizeof(uint32_t); + s += types.capacity()*sizeof(uint32_t); + s += restrictions.capacity()*sizeof(uint64_t); + std::vector >::iterator t = pointTypes.begin(); + for(;t!=pointTypes.end(); t++) { + s+= (*t).capacity() * sizeof(uint32_t); + } + s += namesIds.capacity()*sizeof(pair); + s += names.size()*sizeof(pair)*10; + return s; + } + + double directionRoute(int startPoint, bool plus){ + // look at comment JAVA + return directionRoute(startPoint, plus, 5); + } + + // Gives route direction of EAST degrees from NORTH ]-PI, PI] + double directionRoute(int startPoint, bool plus, float dist) { + int x = pointsX[startPoint]; + int y = pointsY[startPoint]; + int nx = startPoint; + int px = x; + int py = y; + double total = 0; + do { + if (plus) { + nx++; + if (nx >= pointsX.size()) { + break; + } + } else { + nx--; + if (nx < 0) { + break; + } + } + px = pointsX[nx]; + py = pointsY[nx]; + // translate into meters + total += abs(px - x) * 0.011 + abs(py - y) * 0.01863; + } while (total < dist); + return -atan2( (float)x - px, (float) y - py ) + M_PI/2; + } }; diff --git a/Osmand-kernel/osmand/src/binaryRoutePlanner.cpp b/Osmand-kernel/osmand/src/binaryRoutePlanner.cpp index 0733a6300b..28d4a68109 100644 --- a/Osmand-kernel/osmand/src/binaryRoutePlanner.cpp +++ b/Osmand-kernel/osmand/src/binaryRoutePlanner.cpp @@ -7,7 +7,6 @@ static bool PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true; static const int REVERSE_WAY_RESTRICTION_ONLY = 1024; -static const int STANDARD_ROAD_IN_QUEUE_OVERHEAD = 900; static const int ROUTE_POINTS = 11; static const float TURN_DEGREE_MIN = 45; @@ -18,6 +17,7 @@ static const short RESTRICTION_NO_STRAIGHT_ON = 4; static const short RESTRICTION_ONLY_RIGHT_TURN = 5; static const short RESTRICTION_ONLY_LEFT_TURN = 6; static const short RESTRICTION_ONLY_STRAIGHT_ON = 7; +static const bool TRACE_ROUTING = false; inline int roadPriorityComparator(float o1DistanceFromStart, float o1DistanceToEnd, float o2DistanceFromStart, float o2DistanceToEnd, float heuristicCoefficient) { @@ -66,8 +66,9 @@ struct SegmentsComparator : public std::binary_function } bool operator()(const SHARED_PTR lhs, const SHARED_PTR rhs) const { - return roadPriorityComparator(lhs.get()->distanceFromStart, lhs.get()->distanceToEnd, rhs.get()->distanceFromStart, - rhs.get()->distanceToEnd, ctx->getHeuristicCoefficient()) > 0; + int cmp = roadPriorityComparator(lhs.get()->distanceFromStart, lhs.get()->distanceToEnd, rhs.get()->distanceFromStart, + rhs.get()->distanceToEnd, ctx->getHeuristicCoefficient()); + return cmp > 0; } }; struct NonHeuristicSegmentsComparator : public std::binary_function, SHARED_PTR, bool> @@ -89,26 +90,36 @@ bool processIntersections(RoutingContext* ctx, SEGMENTS_QUEUE& graphSegments, SHARED_PTR segment, int segmentEnd, SHARED_PTR inputNext, bool reverseWay); + +int calculateSizeOfSearchMaps(SEGMENTS_QUEUE graphDirectSegments, + SEGMENTS_QUEUE graphReverseSegments, VISITED_MAP visitedDirectSegments, + VISITED_MAP visitedOppositeSegments){ + int sz = visitedDirectSegments.size()*sizeof(pair > ); + sz += visitedOppositeSegments.size()*sizeof(pair >); + sz += graphDirectSegments.size()*sizeof(SHARED_PTR); + sz += graphReverseSegments.size()*sizeof(SHARED_PTR); + return sz; +} /** * Calculate route between start.segmentEnd and end.segmentStart (using A* algorithm) * return list of segments */ void searchRouteInternal(RoutingContext* ctx, SHARED_PTR start, SHARED_PTR end, bool leftSideNavigation) { + // FIXME intermediate points // measure time ctx->visitedSegments = 0; ctx->timeToCalculate.start(); - // FIXME initial direction -// if(ctx.config.initialDirection != null) { -// ctx.firstRoadId = (start->road->id << ROUTE_POINTS) + start.getSegmentStart(); -// double plusDir = start->road->directionRoute(start.segmentStart, true); -// double diff = plusDir - ctx.config.initialDirection; -// if(Math.abs(MapUtils.alignAngleDifference(diff)) <= Math.PI / 3) { -// ctx.firstRoadDirection = 1; -// } else if(Math.abs(MapUtils.alignAngleDifference(diff - Math.PI)) <= Math.PI / 3) { -// ctx.firstRoadDirection = -1; -// } -// -// } + if(ctx->config.initialDirection != -360) { + ctx->firstRoadId = (start->road->id << ROUTE_POINTS) + start->getSegmentStart(); + double plusDir = start->road->directionRoute(start->getSegmentStart(), true); + double diff = plusDir - ctx->config.initialDirection; + if(abs(alignAngleDifference(diff)) <= M_PI / 3) { + ctx->firstRoadDirection = 1; + } else if(abs(alignAngleDifference(diff - M_PI )) <= M_PI / 3) { + ctx->firstRoadDirection = -1; + } + + } SegmentsComparator sgmCmp(ctx); SEGMENTS_QUEUE graphDirectSegments(sgmCmp); @@ -189,7 +200,14 @@ void searchRouteInternal(RoutingContext* ctx, SHARED_PTR start, SH osmand_log_print(LOG_WARN, "[Native] Result visited (visited roads %d, visited segments %d / %d , queue sizes %d / %d ) ", ctx-> visitedSegments, visitedDirectSegments.size(), visitedOppositeSegments.size(), graphDirectSegments.size(),graphReverseSegments.size()); + osmand_log_print(LOG_WARN, "[Native] Result timing (time to load %d, time to calc %d, loaded tiles %d) ", ctx->timeToLoad.getElapsedTime() + , ctx->timeToCalculate.getElapsedTime(), ctx->loadedTiles); + int sz = calculateSizeOfSearchMaps(graphDirectSegments, graphReverseSegments, visitedDirectSegments, visitedOppositeSegments); + osmand_log_print(LOG_WARN, "[Native] Memory occupied (Routing context %d Kb, search %d Kb)", ctx->getSize()/ 1024, sz/1024); } + + + bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch, SEGMENTS_QUEUE& graphSegments, VISITED_MAP& visitedSegments, int targetEndX, int targetEndY, SHARED_PTR segment, VISITED_MAP& oppositeSegments) { @@ -206,6 +224,10 @@ bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch, if(visitedSegments.find(nt) != visitedSegments.end()) { return false; } + if(TRACE_ROUTING) { + osmand_log_print(LOG_DEBUG, "Process segment id=%lld name=%s dist=%f", road->id, road->getName().c_str(), segment->distanceFromStart); + } + ctx->visitedSegments++; // avoid empty segments to connect but mark the point as visited visitedSegments[nt] = SHARED_PTR(); @@ -303,7 +325,6 @@ bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch, // throw new OutOfMemoryError("There is no enough memory " + ctx.config.memoryLimitation/(1<<20) + " Mb"); // } SHARED_PTR next = ctx->loadRouteSegment(x, y); - // 3. get intersected ways if (next.get() != NULL) { if((next.get() == segment.get() || next->road->id == road->id) && next->next.get() == NULL) { @@ -447,6 +468,7 @@ bool processIntersections(RoutingContext* ctx, SEGMENTS_QUEUE& graphSegments, return true; } } + // road.id could be equal on roundabout, but we should accept them bool alreadyVisited = visitedSegments.find(nts) != visitedSegments.end(); if (!alreadyVisited) { @@ -463,6 +485,9 @@ bool processIntersections(RoutingContext* ctx, SEGMENTS_QUEUE& graphSegments, // put additional information to recover whole route after next->parentRoute = segment; next->parentSegmentEnd = segmentEnd; + if(TRACE_ROUTING) { + osmand_log_print(LOG_DEBUG, ">> next segment id=%lld name=%s dist=%f", next->road->id, next->road->getName().c_str(), next->distanceFromStart); + } graphSegments.push(next); } } else { @@ -490,9 +515,9 @@ bool processIntersections(RoutingContext* ctx, SEGMENTS_QUEUE& graphSegments, SHARED_PTR findRouteSegment(int px, int py, RoutingContext* ctx) { vector > dataObjects; - ctx->loadTileData(px, py, 16, dataObjects); + ctx->loadTileData(px, py, 17, dataObjects); if (dataObjects.size() == 0) { - ctx->loadTileData(px, py, 14, dataObjects); + ctx->loadTileData(px, py, 15, dataObjects); } SHARED_PTR road; double sdist = 0; @@ -566,6 +591,26 @@ void addRouteSegmentToResult(vector& result, RouteSegmentRes } } +void attachConnectedRoads(RoutingContext* ctx, vector& res ) { + vector::iterator it = res.begin(); + for(; it != res.end(); it++){ + bool plus = it->startPointIndex < it->endPointIndex; + int j = it->startPointIndex; + do { + SHARED_PTR s = ctx->loadRouteSegment(it->object->pointsX[j], it->object->pointsY[j]); + vector r; + while(s.get() != NULL) { + RouteSegmentResult res(s->road, s->getSegmentStart(), s->getSegmentStart()); + r.push_back(res); + s = s->next; + } + it->attachedRoutes.push_back(r); + j = plus ? j + 1 : j - 1; + } while(j != it->endPointIndex); + } + +} + vector convertFinalSegmentToResults(RoutingContext* ctx) { vector result; if (ctx->finalRouteSegment.get() != NULL) { @@ -620,9 +665,9 @@ vector searchRouteInternal(RoutingContext* ctx, bool leftSid osmand_log_print(LOG_WARN, "End point was found %lld [Native]", end->road->id); } searchRouteInternal(ctx, start, end, leftSideNavigation); - osmand_log_print(LOG_WARN, "[Native] Result timing (time to load %d, time to calc %d, loaded tiles %d) ", ctx->timeToLoad.getElapsedTime() - , ctx->timeToCalculate.getElapsedTime(), ctx->loadedTiles); - return convertFinalSegmentToResults(ctx); + vector res = convertFinalSegmentToResults(ctx); + attachConnectedRoads(ctx, res); + return res; } diff --git a/Osmand-kernel/osmand/src/binaryRoutePlanner.h b/Osmand-kernel/osmand/src/binaryRoutePlanner.h index a530c049b1..32f8c8dfba 100644 --- a/Osmand-kernel/osmand/src/binaryRoutePlanner.h +++ b/Osmand-kernel/osmand/src/binaryRoutePlanner.h @@ -42,6 +42,7 @@ struct RouteSegmentResult { SHARED_PTR object; int startPointIndex; int endPointIndex; + vector > attachedRoutes; RouteSegmentResult(SHARED_PTR object, int startPointIndex, int endPointIndex) : object(object), startPointIndex(startPointIndex), endPointIndex (endPointIndex) { @@ -62,10 +63,11 @@ struct RoutingSubregionTile { // make it without get/set for fast access int access; int loaded; + int size ; UNORDERED(map) > routes; RoutingSubregionTile(RouteSubregion& sub) : access(0), loaded(0), subregion(sub) { - + size = sizeof(RoutingSubregionTile); } ~RoutingSubregionTile(){ } @@ -77,7 +79,12 @@ struct RoutingSubregionTile { loaded++; } + int getSize(){ + return size + routes.size() * sizeof(std::pair >); + } + void add(SHARED_PTR o) { + size += o->getSize() + sizeof(RouteSegment)* o->pointsX.size(); for (int i = 0; i < o->pointsX.size(); i++) { uint64_t x31 = o->pointsX[i]; uint64_t y31 = o->pointsY[i]; @@ -98,7 +105,7 @@ struct RoutingSubregionTile { } }; static int64_t calcRouteId(SHARED_PTR o, int ind) { - return (o->id << 10) + ind; + return ((int64_t) o->id << 10) + ind; } typedef std::pair > ROUTE_TRIPLE; @@ -127,6 +134,7 @@ struct RoutingConfiguration { int planRoadDirection; string routerName; float initialDirection; + float distanceRecalculate; string routerProfile; float roundaboutTurn; float leftTurn; @@ -166,9 +174,10 @@ struct RoutingConfiguration { zoomToLoad = (int)parseFloat("zoomToLoadTiles", 16); routerName = parseString("name", "default"); routerProfile = parseString("baseProfile", "car"); + distanceRecalculate = parseFloat("recalculateDistanceHelp", 10000) ; } - RoutingConfiguration(vector& config, int memLimit = 30, float initDirection = 0) : + RoutingConfiguration(vector& config, float initDirection = -360, int memLimit = 30) : memoryLimitation(memLimit), initialDirection(initDirection) { for(int j = 0; j > MAP_SUBREGION_TILES; + int visitedSegments; int loadedTiles; ElapsedTimer timeToLoad; @@ -358,7 +369,7 @@ struct RoutingContext { vector > segmentsToVisitPrescripted; SHARED_PTR finalRouteSegment; - UNORDERED(map) > subregionTiles; + MAP_SUBREGION_TILES subregionTiles; UNORDERED(map) > > indexedSubregions; RoutingContext(RoutingConfiguration& config) : finalRouteSegment(), firstRoadDirection(0), loadedTiles(0), visitedSegments(0), @@ -369,6 +380,16 @@ struct RoutingContext { return config.acceptLine(r); } + int getSize() { + // multiply 2 for to maps + int sz = subregionTiles.size() * sizeof(pair< int64_t, SHARED_PTR >) * 2; + MAP_SUBREGION_TILES::iterator it = subregionTiles.begin(); + for(;it != subregionTiles.end(); it++) { + sz += it->second->getSize(); + } + return sz; + } + void loadHeaderObjects(int64_t tileId) { vector > subregions = indexedSubregions[tileId]; for(int j = 0; j > collection; for(int i=0; i(new RoutingSubregionTile(rs)); } collection.push_back(subregionTiles[key]); } - //osmand_log_print(LOG_INFO, "Native load %d %d (%d)", xloc, yloc, tempResult.size()); indexedSubregions[tileId] = collection; } loadHeaderObjects(tileId); timeToLoad.pause(); } - void loadTileData(int x31, int y31, int zoomAround, vector >& dataObjects ){ - int t = zoomAround - config.zoomToLoad; + void loadTileData(int x31, int y31, int zoomAround, vector >& dataObjects ) { + int t = config.zoomToLoad - zoomAround; + int coordinatesShift = (1 << (31 - config.zoomToLoad)); if(t <= 0) { t = 1; + coordinatesShift = (1 << (31 - zoomAround)); } else { t = 1 << t; } - int coordinatesShift = (1 << (31 - config.zoomToLoad)); UNORDERED(set) ids; int z = config.zoomToLoad; for(int i = -t; i <= t; i++) { diff --git a/Osmand-kernel/osmand/src/common.cpp b/Osmand-kernel/osmand/src/common.cpp index 10947ceceb..4685bfbac8 100644 --- a/Osmand-kernel/osmand/src/common.cpp +++ b/Osmand-kernel/osmand/src/common.cpp @@ -300,3 +300,14 @@ double getDistance(double lat1, double lon1, double lat2, double lon2) { double c = 2 * atan2(sqrt(a), sqrt(1 - a)); return R * c * 1000; } + +double alignAngleDifference(double diff) { + while (diff > M_PI) { + diff -= 2 * M_PI; + } + while (diff <= -M_PI) { + diff += 2 * M_PI; + } + return diff; + +} diff --git a/Osmand-kernel/osmand/src/common.h b/Osmand-kernel/osmand/src/common.h index c9f180ff81..ff23861462 100644 --- a/Osmand-kernel/osmand/src/common.h +++ b/Osmand-kernel/osmand/src/common.h @@ -322,6 +322,7 @@ double calculateProjection31TileMetric(int xA, int yA, int xB, int yB, int xC, i double squareDist31TileMetric(int x1, int y1, int x2, int y2) ; double convert31YToMeters(int y1, int y2); double convert31XToMeters(int y1, int y2); +double alignAngleDifference(double diff); #endif /*_OSMAND_COMMON_H*/ diff --git a/Osmand-kernel/osmand/src/java_wrap.cpp b/Osmand-kernel/osmand/src/java_wrap.cpp index ef45e9d2ea..a2ccca530b 100644 --- a/Osmand-kernel/osmand/src/java_wrap.cpp +++ b/Osmand-kernel/osmand/src/java_wrap.cpp @@ -410,17 +410,25 @@ jfieldID jfield_RouteSubregion_top = NULL; jfieldID jfield_RouteSubregion_bottom = NULL; jfieldID jfield_RouteSubregion_shiftToData = NULL; +jclass jclass_RouteRegion = NULL; +jfieldID jfield_RouteRegion_length = NULL; +jfieldID jfield_RouteRegion_filePointer= NULL; jclass jclass_RouteSegmentResult = NULL; +jclass jclass_RouteSegmentResultAr = NULL; jmethodID jmethod_RouteSegmentResult_ctor = NULL; +jfieldID jfield_RouteSegmentResult_preAttachedRoutes = NULL; void loadJniRenderingContext(JNIEnv* env) { jclass_RouteSegmentResult = findClass(env, "net/osmand/router/RouteSegmentResult"); + jclass_RouteSegmentResultAr = findClass(env, "[Lnet/osmand/router/RouteSegmentResult;"); jmethod_RouteSegmentResult_ctor = env->GetMethodID(jclass_RouteSegmentResult, "", "(Lnet/osmand/binary/RouteDataObject;II)V"); + jfield_RouteSegmentResult_preAttachedRoutes = getFid(env, jclass_RouteSegmentResult, "preAttachedRoutes", + "[[Lnet/osmand/router/RouteSegmentResult;"); jclass_RenderingContext = findClass(env, "net/osmand/RenderingContext"); jfield_RenderingContext_interrupted = getFid(env, jclass_RenderingContext, "interrupted", "Z"); @@ -467,6 +475,10 @@ void loadJniRenderingContext(JNIEnv* env) jmethod_RouteDataObject_init = env->GetMethodID(jclass_RouteDataObject, "", "(Lnet/osmand/binary/BinaryMapRouteReaderAdapter$RouteRegion;[I[Ljava/lang/String;)V"); + jclass_RouteRegion = findClass(env, "net/osmand/binary/BinaryMapRouteReaderAdapter$RouteRegion"); + jfield_RouteRegion_length= getFid(env, jclass_RouteRegion, "length", "I" ); + jfield_RouteRegion_filePointer= getFid(env, jclass_RouteRegion, "filePointer", "I" ); + jclass_RouteSubregion = findClass(env, "net/osmand/binary/BinaryMapRouteReaderAdapter$RouteSubregion"); jfield_RouteSubregion_length= getFid(env, jclass_RouteSubregion, "length", "I" ); jfield_RouteSubregion_filePointer= getFid(env, jclass_RouteSubregion, "filePointer", "I" ); @@ -563,6 +575,38 @@ jobject convertRouteDataObjectToJava(JNIEnv* ienv, RouteDataObject* route, jobje return robj; } +jobject convertRouteSegmentResultToJava(JNIEnv* ienv, RouteSegmentResult& r, UNORDERED(map)& indexes, + jobjectArray regions) { + RouteDataObject* rdo = r.object.get(); + jobject reg = NULL; + int64_t fp = rdo->region->filePointer; + int64_t ln = rdo->region->length; + if(indexes.find((fp <<31) + ln) != indexes.end()) { + reg = ienv->GetObjectArrayElement(regions, indexes[(fp <<31) + ln]); + } + jobjectArray ar = ienv->NewObjectArray(r.attachedRoutes.size(), jclass_RouteSegmentResultAr, NULL); + for(jsize k = 0; k < r.attachedRoutes.size(); k++) { + jobjectArray art = ienv->NewObjectArray(r.attachedRoutes[k].size(), jclass_RouteSegmentResult, NULL); + for(jsize kj = 0; kj < r.attachedRoutes[k].size(); kj++) { + jobject jo = convertRouteSegmentResultToJava(ienv, r.attachedRoutes[k][kj], indexes, regions); + ienv->SetObjectArrayElement(art, kj, jo); + ienv->DeleteLocalRef(jo); + } + ienv->SetObjectArrayElement(ar, k, art); + ienv->DeleteLocalRef(art); + } + jobject robj = convertRouteDataObjectToJava(ienv, rdo, reg); + jobject resobj = ienv->NewObject(jclass_RouteSegmentResult, jmethod_RouteSegmentResult_ctor, robj, + r.startPointIndex, r.endPointIndex); + ienv->SetObjectField(resobj, jfield_RouteSegmentResult_preAttachedRoutes, ar); + if(reg != NULL) { + ienv->DeleteLocalRef(reg); + } + ienv->DeleteLocalRef(robj); + ienv->DeleteLocalRef(ar); + return resobj; +} + class NativeRoutingTile { public: std::vector result; @@ -583,20 +627,25 @@ extern "C" JNIEXPORT void JNICALL Java_net_osmand_NativeLibrary_deleteRouteSearc //p RouteSegmentResult[] nativeRouting(int[] coordinates, int[] state, String[] keyConfig, String[] valueConfig); extern "C" JNIEXPORT jobjectArray JNICALL Java_net_osmand_NativeLibrary_nativeRouting(JNIEnv* ienv, jobject obj, jintArray coordinates, - jintArray stateConfig, jobjectArray keyConfig, jobjectArray valueConfig) { + jintArray stateConfig, jobjectArray keyConfig, jobjectArray valueConfig, jfloat initDirection, + jobjectArray regions) { vector cfg; int* data = ienv->GetIntArrayElements(stateConfig, NULL); for(int k = 0; k < ienv->GetArrayLength(stateConfig); k++) { + jstring kl = (jstring)ienv->GetObjectArrayElement(keyConfig, k); + jstring vl = (jstring)ienv->GetObjectArrayElement(valueConfig, k); ROUTE_TRIPLE t = ROUTE_TRIPLE (data[k], std::pair( - getString(ienv, (jstring) ienv->GetObjectArrayElement(keyConfig, k)), - getString(ienv, (jstring) ienv->GetObjectArrayElement(valueConfig, k))) + getString(ienv, kl), + getString(ienv, vl)) ); + ienv->DeleteLocalRef(kl); + ienv->DeleteLocalRef(vl); cfg.push_back(t); } ienv->ReleaseIntArrayElements(stateConfig, data, 0); - RoutingConfiguration config(cfg); + RoutingConfiguration config(cfg, initDirection); RoutingContext c(config); data = ienv->GetIntArrayElements(coordinates, NULL); c.startX = data[0]; @@ -606,16 +655,21 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_net_osmand_NativeLibrary_nativeRo ienv->ReleaseIntArrayElements(coordinates, data, 0); vector r = searchRouteInternal(&c, false); + UNORDERED(map) indexes; + for (int t = 0; t< ienv->GetArrayLength(regions); t++) { + jobject oreg = ienv->GetObjectArrayElement(regions, t); + int64_t fp = ienv->GetIntField(oreg, jfield_RouteRegion_filePointer); + int64_t ln = ienv->GetIntField(oreg, jfield_RouteRegion_length); + ienv->DeleteLocalRef(oreg); + indexes[(fp <<31) + ln] = t; + } + // convert results jobjectArray res = ienv->NewObjectArray(r.size(), jclass_RouteSegmentResult, NULL); for (int i = 0; i < r.size(); i++) { - jobject robj = convertRouteDataObjectToJava(ienv, r[i].object.get(), NULL); - jobject resobj = ienv->NewObject(jclass_RouteSegmentResult, jmethod_RouteSegmentResult_ctor, robj, - r[i].startPointIndex, r[i].endPointIndex); + jobject resobj = convertRouteSegmentResultToJava(ienv, r[i], indexes, regions); ienv->SetObjectArrayElement(res, i, resobj); - ienv->DeleteLocalRef(robj); ienv->DeleteLocalRef(resobj); - } if (r.size() == 0) { osmand_log_print(LOG_INFO, "No route found");