Fast route calculation
This commit is contained in:
parent
cc2f1b1a7d
commit
fdd80c9fb7
11 changed files with 451 additions and 253 deletions
|
@ -26,10 +26,39 @@ public class NativeLibrary {
|
|||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
deleteNativeResult();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void deleteNativeResult() {
|
||||
if (nativeHandler != 0) {
|
||||
super.finalize();
|
||||
deleteSearchResult(nativeHandler);
|
||||
nativeHandler = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class NativeRouteSearchResult {
|
||||
|
||||
public long nativeHandler;
|
||||
public RouteDataObject[] objects;
|
||||
public RouteRegion region;
|
||||
public NativeRouteSearchResult(long nativeHandler, RouteDataObject[] objects) {
|
||||
this.nativeHandler = nativeHandler;
|
||||
this.objects = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
deleteNativeResult();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void deleteNativeResult() {
|
||||
if (nativeHandler != 0) {
|
||||
deleteRouteSearchResult(nativeHandler);
|
||||
nativeHandler = 0;
|
||||
}
|
||||
deleteSearchResult(nativeHandler);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,13 +71,14 @@ public class NativeLibrary {
|
|||
return new NativeSearchResult(searchNativeObjectsForRendering(sleft, sright, stop, sbottom, zoom, request, skipDuplicates,
|
||||
objectWithInterruptedField, msgIfNothingFound));
|
||||
}
|
||||
|
||||
public void deleteSearchResult(NativeSearchResult searchResultHandler) {
|
||||
if (searchResultHandler.nativeHandler != 0) {
|
||||
deleteSearchResult(searchResultHandler.nativeHandler);
|
||||
searchResultHandler.nativeHandler = 0;
|
||||
|
||||
public RouteDataObject[] getDataObjects(NativeRouteSearchResult rs, int x31, int y31) {
|
||||
if(rs.nativeHandler == 0) {
|
||||
throw new IllegalStateException("Native route handler is 0");
|
||||
}
|
||||
return getRouteDataObjects(rs.region, rs.nativeHandler, x31, y31);
|
||||
}
|
||||
|
||||
|
||||
public boolean initMapFile(String filePath) {
|
||||
return initBinaryMapFile(filePath);
|
||||
|
@ -58,13 +88,24 @@ public class NativeLibrary {
|
|||
return closeBinaryMapFile(filePath);
|
||||
}
|
||||
|
||||
public RouteDataObject[] loadRouteRegion(RouteRegion reg, int left, int right, int top, int bottom) {
|
||||
return loadRoutingData(reg, reg.getName(), reg.getFilePointer(), left, right, top, bottom);
|
||||
|
||||
|
||||
public NativeRouteSearchResult loadRouteRegion(RouteRegion reg, int left, int right, int top, int bottom, boolean loadObjects) {
|
||||
NativeRouteSearchResult lr = loadRoutingData(reg, reg.getName(), reg.getFilePointer(), left, right, top, bottom, loadObjects);
|
||||
if(lr != null && lr.nativeHandler != 0){
|
||||
lr.region = reg;
|
||||
}
|
||||
return lr;
|
||||
}
|
||||
|
||||
|
||||
protected static native RouteDataObject[] loadRoutingData(RouteRegion reg, String regName, int fpointer, int left, int right, int top, int bottom);
|
||||
|
||||
protected static native NativeRouteSearchResult loadRoutingData(RouteRegion reg, String regName, int fpointer, int left, int right, int top, int bottom,
|
||||
boolean loadObjects);
|
||||
|
||||
protected static native void deleteRouteSearchResult(long searchResultHandle);
|
||||
|
||||
protected static native RouteDataObject[] getRouteDataObjects(RouteRegion reg, long rs, int x31, int y31);
|
||||
|
||||
protected static native void deleteSearchResult(long searchResultHandle);
|
||||
|
||||
protected static native boolean initBinaryMapFile(String filePath);
|
||||
|
|
|
@ -14,16 +14,13 @@ import java.util.Iterator;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import net.osmand.LogUtil;
|
||||
import net.osmand.NativeLibrary;
|
||||
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;
|
||||
|
@ -48,6 +45,9 @@ public class BinaryRoutePlanner {
|
|||
|
||||
public BinaryRoutePlanner(NativeLibrary nativeLib, BinaryMapIndexReader... map) {
|
||||
this.nativeLib = nativeLib;
|
||||
if(nativeLib != null) {
|
||||
RoutingConfiguration.DEFAULT_DESIRABLE_TILES_IN_MEMORY = 25;
|
||||
}
|
||||
for (BinaryMapIndexReader mr : map) {
|
||||
List<RouteRegion> rr = mr.getRoutingIndexes();
|
||||
List<RouteSubregion> subregions = new ArrayList<BinaryMapRouteReaderAdapter.RouteSubregion>();
|
||||
|
@ -119,7 +119,7 @@ public class BinaryRoutePlanner {
|
|||
List<RouteDataObject> dataObjects = new ArrayList<RouteDataObject>();
|
||||
Iterator<RoutingTile> it = ts.valueCollection().iterator();
|
||||
while(it.hasNext()){
|
||||
loadTileData(ctx, it.next(), dataObjects);
|
||||
ctx.loadTileData(it.next(), dataObjects, nativeLib, map);
|
||||
}
|
||||
RouteSegment road = null;
|
||||
double sdist = 0;
|
||||
|
@ -158,7 +158,7 @@ public class BinaryRoutePlanner {
|
|||
}
|
||||
if(road != null) {
|
||||
// re-register the best road because one more point was inserted
|
||||
registerRouteDataObject(ctx, road.getRoad(), ctx.getRoutingTile(foundProjX, foundProjY));
|
||||
ctx.registerRouteDataObject(road.getRoad(), ctx.getRoutingTile(foundProjX, foundProjY));
|
||||
}
|
||||
return road;
|
||||
}
|
||||
|
@ -297,11 +297,16 @@ public class BinaryRoutePlanner {
|
|||
relaxNotNeededSegments(ctx, graphReverseSegments, false);
|
||||
}
|
||||
}
|
||||
printDebugMemoryInformation(ctx, graphDirectSegments, graphReverseSegments, visitedDirectSegments, visitedOppositeSegments);
|
||||
println("Result is found");
|
||||
|
||||
// 4. Route is found : collect all segments and prepare result
|
||||
return prepareResult(ctx, start, end, leftSideNavigation);
|
||||
|
||||
List<RouteSegmentResult> resultPrepared = prepareResult(ctx, start, end, leftSideNavigation);
|
||||
printDebugMemoryInformation(ctx, graphDirectSegments, graphReverseSegments, visitedDirectSegments, visitedOppositeSegments);
|
||||
Object[] vls = ctx.tiles.values();
|
||||
for(Object tl : vls) {
|
||||
ctx.unloadTile((RoutingTile) tl, false);
|
||||
}
|
||||
return resultPrepared;
|
||||
}
|
||||
|
||||
private void unloadUnusedTiles(RoutingContext ctx, int desirableSize) {
|
||||
|
@ -334,11 +339,13 @@ public class BinaryRoutePlanner {
|
|||
return v1 < v2 ? -1 : (v1 == v2 ? 0 : 1);
|
||||
}
|
||||
});
|
||||
int toUnload = Math.max(loaded / 5, loaded - desirableSize);
|
||||
for (int i = 0; i < loaded; i++) {
|
||||
list.get(i).access = 0;
|
||||
if (i < toUnload) {
|
||||
ctx.unloadTile(list.get(i), true);
|
||||
if (loaded >= 0.9f * desirableSize) {
|
||||
int toUnload = Math.max(loaded / 5, loaded - desirableSize);
|
||||
for (int i = 0; i < loaded; i++) {
|
||||
list.get(i).access = 0;
|
||||
if (i < toUnload) {
|
||||
ctx.unloadTile(list.get(i), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,54 +402,7 @@ public class BinaryRoutePlanner {
|
|||
return result;
|
||||
}
|
||||
|
||||
private void registerRouteDataObject(final RoutingContext ctx, RouteDataObject o, RoutingTile suggestedTile ) {
|
||||
if(!ctx.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.routes.get(l);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void println(String logMsg) {
|
||||
// log.info(logMsg);
|
||||
|
@ -453,8 +413,8 @@ public class BinaryRoutePlanner {
|
|||
TLongObjectHashMap<RouteSegment> visitedDirectSegments,TLongObjectHashMap<RouteSegment> visitedOppositeSegments) {
|
||||
println("Time to calculate : " + (System.nanoTime() - ctx.timeToCalculate) / 1e6 + ", time to load : " + ctx.timeToLoad / 1e6);
|
||||
println("Current loaded tiles : " + ctx.getCurrentlyLoadedTiles() + ", maximum loaded tiles " + ctx.maxLoadedTiles);
|
||||
println("Loaded tiles : " + ctx.loadedTiles + ", unloaded tiles " + ctx.unloadedTiles +
|
||||
" (distinct " + ctx.distinctUnloadedTiles.size()+") "+ ", loaded \"unloaded\" tiles "
|
||||
println("Loaded tiles " + ctx.loadedTiles + " (distinct "+ctx.distinctLoadedTiles+ "), unloaded tiles " + ctx.unloadedTiles +
|
||||
" (distinct " + ctx.distinctUnloadedTiles.size()+") "+ ", loaded more than once same tiles "
|
||||
+ ctx.loadedPrevUnloadedTiles );
|
||||
println("Visited roads, " + ctx.visitedSegments + ", relaxed roads " + ctx.relaxedSegments);
|
||||
if (graphDirectSegments != null && graphReverseSegments != null) {
|
||||
|
@ -468,88 +428,15 @@ public class BinaryRoutePlanner {
|
|||
|
||||
public RoutingTile loadRoutes(final RoutingContext ctx, int tile31X, int tile31Y) {
|
||||
final RoutingTile tile = ctx.getRoutingTile(tile31X, tile31Y);
|
||||
loadTileData(ctx, tile, null);
|
||||
if (tile.isLoaded()) {
|
||||
tile.access++;
|
||||
return tile;
|
||||
}
|
||||
ctx.loadTileData(tile, null, nativeLib, map);
|
||||
return tile;
|
||||
}
|
||||
|
||||
|
||||
private void loadTileData(final RoutingContext ctx, final RoutingTile tile, final List<RouteDataObject> toFillIn) {
|
||||
if (tile.isLoaded()) {
|
||||
tile.access++;
|
||||
if(toFillIn != null){
|
||||
for(RouteDataObject ro : tile.idObjects.valueCollection()){
|
||||
toFillIn.add(ro);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
long now = System.nanoTime();
|
||||
ResultMatcher<RouteDataObject> matcher = new ResultMatcher<RouteDataObject>() {
|
||||
@Override
|
||||
public boolean publish(RouteDataObject o) {
|
||||
if (toFillIn != null) {
|
||||
if (ctx.getRouter().acceptLine(o)) {
|
||||
toFillIn.add(o);
|
||||
}
|
||||
}
|
||||
registerRouteDataObject(ctx, o, tile);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
int zoomToLoad = 31 - tile.getZoom();
|
||||
int tileX = tile.getTileX();
|
||||
int tileY = tile.getTileY();
|
||||
SearchRequest<RouteDataObject> request = BinaryMapIndexReader.buildSearchRouteRequest(tileX << zoomToLoad,
|
||||
(tileX + 1) << zoomToLoad, tileY << zoomToLoad, (tileY + 1) << zoomToLoad, matcher);
|
||||
for (Entry<BinaryMapIndexReader, List<RouteSubregion>> r : map.entrySet()) {
|
||||
if(nativeLib != null) {
|
||||
for(RouteRegion reg : r.getKey().getRoutingIndexes()) {
|
||||
nativeLoadRegion(request, reg);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
r.getKey().searchRouteIndex(request, r.getValue());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Loading data exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.loadedTiles++;
|
||||
if (tile.isUnloaded()) {
|
||||
ctx.loadedPrevUnloadedTiles++;
|
||||
}
|
||||
tile.setLoaded();
|
||||
ctx.timeToLoad += (System.nanoTime() - now);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void nativeLoadRegion(SearchRequest<RouteDataObject> request, RouteRegion reg) {
|
||||
boolean intersects = false;
|
||||
for(RouteSubregion sub : reg.getSubregions()) {
|
||||
if(request.intersects(sub.left, sub.top, sub.right, sub.bottom)) {
|
||||
intersects = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(intersects) {
|
||||
RouteDataObject[] res = nativeLib.loadRouteRegion(reg, request.getLeft(), request.getRight(), request.getTop(), request.getBottom());
|
||||
if(res != null){
|
||||
for(RouteDataObject ro : res) {
|
||||
if(ro != null) {
|
||||
request.publish(ro);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean processRouteSegment(final RoutingContext ctx, boolean reverseWaySearch,
|
||||
PriorityQueue<RouteSegment> graphSegments, TLongObjectHashMap<RouteSegment> visitedSegments, int targetEndX, int targetEndY,
|
||||
|
@ -649,7 +536,7 @@ public class BinaryRoutePlanner {
|
|||
|
||||
|
||||
long l = (((long) x) << 31) + (long) y;
|
||||
RouteSegment next = tile.routes.get(l);
|
||||
RouteSegment next = tile.getSegment(l);
|
||||
// 3. get intersected ways
|
||||
if (next != null) {
|
||||
// TO-DO U-Turn
|
||||
|
@ -875,6 +762,9 @@ public class BinaryRoutePlanner {
|
|||
|
||||
// calculate time
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
if(ctx.runTilesGC()) {
|
||||
unloadUnusedTiles(ctx, ctx.config.NUMBER_OF_DESIRABLE_TILES_IN_MEMORY);
|
||||
}
|
||||
RouteSegmentResult rr = result.get(i);
|
||||
RouteDataObject road = rr.getObject();
|
||||
double distOnRoadToPass = 0;
|
||||
|
@ -1190,7 +1080,7 @@ public class BinaryRoutePlanner {
|
|||
}
|
||||
}
|
||||
}
|
||||
RouteSegment routeSegment = tl.getLoadedRoutes().get(l);
|
||||
RouteSegment routeSegment = tl.getSegment(l);
|
||||
// try to attach all segments except with current id
|
||||
while (routeSegment != null) {
|
||||
if (routeSegment.road.getId() != road.getId() && routeSegment.road.getId() != previousRoadId) {
|
||||
|
|
|
@ -23,7 +23,8 @@ public class RoutingConfiguration {
|
|||
// 1.1 tile load parameters (should not affect routing)
|
||||
public int ZOOM_TO_LOAD_TILES = 13; // 12?, 14?
|
||||
public int ITERATIONS_TO_RUN_GC = 100;
|
||||
public int NUMBER_OF_DESIRABLE_TILES_IN_MEMORY = 25;
|
||||
public static int DEFAULT_DESIRABLE_TILES_IN_MEMORY = 100;
|
||||
public int NUMBER_OF_DESIRABLE_TILES_IN_MEMORY = DEFAULT_DESIRABLE_TILES_IN_MEMORY;
|
||||
|
||||
// 1.2 Dynamic road prioritizing (heuristic)
|
||||
public boolean useDynamicRoadPrioritising = true;
|
||||
|
@ -92,21 +93,21 @@ public class RoutingConfiguration {
|
|||
}
|
||||
|
||||
private static int parseSilentInt(String t, int v) {
|
||||
if (t == null) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Integer.parseInt(t);
|
||||
}
|
||||
|
||||
private static boolean parseSilentBoolean(String t, boolean v) {
|
||||
if (t == null) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Boolean.parseBoolean(t);
|
||||
}
|
||||
|
||||
private static double parseSilentDouble(String t, double v) {
|
||||
if (t == null) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Double.parseDouble(t);
|
||||
|
|
|
@ -7,10 +7,20 @@ 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.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
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.RouteRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
|
||||
import net.osmand.binary.RouteDataObject;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegmentVisitor;
|
||||
|
@ -49,6 +59,7 @@ public class RoutingContext {
|
|||
long timeToLoad = 0;
|
||||
long timeToCalculate = 0;
|
||||
public int loadedTiles = 0;
|
||||
int distinctLoadedTiles = 0;
|
||||
int maxLoadedTiles = 0;
|
||||
int loadedPrevUnloadedTiles = 0;
|
||||
int unloadedTiles = 0;
|
||||
|
@ -180,6 +191,145 @@ public class RoutingContext {
|
|||
distinctUnloadedTiles.add(l);
|
||||
}
|
||||
|
||||
|
||||
public void loadTileData(final RoutingTile tile, final List<RouteDataObject> toFillIn, NativeLibrary nativeLib,
|
||||
Map<BinaryMapIndexReader, List<RouteSubregion>> map) {
|
||||
|
||||
long now = System.nanoTime();
|
||||
ResultMatcher<RouteDataObject> matcher = new ResultMatcher<RouteDataObject>() {
|
||||
@Override
|
||||
public boolean publish(RouteDataObject o) {
|
||||
if (toFillIn != null) {
|
||||
if (getRouter().acceptLine(o)) {
|
||||
toFillIn.add(o);
|
||||
}
|
||||
}
|
||||
registerRouteDataObject(o, tile);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
int zoomToLoad = 31 - tile.getZoom();
|
||||
int tileX = tile.getTileX();
|
||||
int tileY = tile.getTileY();
|
||||
boolean loadData = toFillIn != null;
|
||||
List<NativeRouteSearchResult> nativeRouteSearchResults = new ArrayList<NativeRouteSearchResult>();
|
||||
SearchRequest<RouteDataObject> request = BinaryMapIndexReader.buildSearchRouteRequest(tileX << zoomToLoad,
|
||||
(tileX + 1) << zoomToLoad, tileY << zoomToLoad, (tileY + 1) << zoomToLoad, matcher);
|
||||
for (Entry<BinaryMapIndexReader, List<RouteSubregion>> r : map.entrySet()) {
|
||||
if(nativeLib != null) {
|
||||
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 {
|
||||
r.getKey().searchRouteIndex(request, r.getValue());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Loading data exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
loadedTiles++;
|
||||
if (tile.isUnloaded()) {
|
||||
loadedPrevUnloadedTiles++;
|
||||
} else {
|
||||
distinctLoadedTiles++;
|
||||
}
|
||||
tile.setLoaded();
|
||||
if(nativeRouteSearchResults.size() > 0) {
|
||||
tile.nativeLib = nativeLib;
|
||||
tile.nativeResults = nativeRouteSearchResults;
|
||||
|
||||
}
|
||||
timeToLoad += (System.nanoTime() - now);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private NativeRouteSearchResult nativeLoadRegion(SearchRequest<RouteDataObject> 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);
|
||||
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 static class RoutingTile {
|
||||
private int tileX;
|
||||
private int tileY;
|
||||
|
@ -188,8 +338,53 @@ public class RoutingContext {
|
|||
// make it without get/set for fast access
|
||||
public int access;
|
||||
|
||||
TLongObjectMap<RouteSegment> routes = new TLongObjectHashMap<RouteSegment>();
|
||||
TLongObjectHashMap<RouteDataObject> idObjects = new TLongObjectHashMap<RouteDataObject>();
|
||||
private NativeLibrary nativeLib;
|
||||
// null if it doesn't work with native results
|
||||
private List<NativeRouteSearchResult> nativeResults;
|
||||
private TLongHashSet excludeDuplications = new TLongHashSet();
|
||||
|
||||
private TLongObjectMap<RouteSegment> routes = new TLongObjectHashMap<RouteSegment>();
|
||||
private TLongObjectHashMap<RouteDataObject> idObjects = new TLongObjectHashMap<RouteDataObject>();
|
||||
|
||||
public RouteSegment getSegment(long id) {
|
||||
if(nativeResults != null) {
|
||||
RouteSegment original = loadNativeRouteSegment(id);
|
||||
return original;
|
||||
}
|
||||
return routes.get(id);
|
||||
}
|
||||
|
||||
private RouteSegment loadNativeRouteSegment(long id) {
|
||||
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) {
|
||||
if (ro != null && !excludeDuplications.contains(ro.id)) {
|
||||
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;
|
||||
|
@ -231,6 +426,11 @@ public class RoutingContext {
|
|||
} else {
|
||||
isLoaded = -Math.abs(isLoaded);
|
||||
}
|
||||
if(nativeResults != null) {
|
||||
for(NativeRouteSearchResult rs : nativeResults) {
|
||||
rs.deleteNativeResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoaded() {
|
||||
|
@ -242,8 +442,5 @@ public class RoutingContext {
|
|||
return tileX == (x31 >> (31 - zoom)) && tileY == (y31 >> (31 - zoom));
|
||||
}
|
||||
|
||||
public TLongObjectMap<RouteSegment> getLoadedRoutes() {
|
||||
return routes;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,8 @@
|
|||
<!-- 1.1 tile load parameters (should not affect routing) -->
|
||||
<attribute name="zoomToLoadTiles" value="13" />
|
||||
<attribute name="iterationsToRunGC" value="125" />
|
||||
<attribute name="desirableTilesInMemory" value="25" />
|
||||
<!-- by default it is 25 -->
|
||||
<attribute name="desirableTilesInMemory" value="" />
|
||||
|
||||
<!-- 1.2 Dynamic road prioritizing (heuristic) -->
|
||||
<attribute name="useDynamicRoadPrioritising" value="true" />
|
||||
|
@ -78,7 +79,7 @@
|
|||
<obstacle tag="railway" value="crossing" penalty="25"/>
|
||||
<obstacle tag="railway" value="level_crossing" penalty="25"/>
|
||||
<obstacle tag="motorcar" value="no" penalty="-1"/>
|
||||
<obstacle tag="barrier" value="lift_gate" penalty="-1"/>
|
||||
<obstacle tag="barrier" value="lift_gate" penalty="100"/>
|
||||
<obstacle tag="barrier" value="gate" penalty="-1"/>
|
||||
<obstacle tag="barrier" value="bollard" penalty="-1"/>
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import net.osmand.binary.BinaryMapIndexReader;
|
|||
import net.osmand.router.BinaryRoutePlanner;
|
||||
import net.osmand.router.RoutingConfiguration;
|
||||
import net.osmand.swing.DataExtractionSettings;
|
||||
import net.osmand.swing.NativeSwingRendering;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -22,11 +23,13 @@ import org.xml.sax.SAXException;
|
|||
public class JUnitRouteTest {
|
||||
|
||||
static BinaryMapIndexReader[] rs;
|
||||
private NativeSwingRendering lib;
|
||||
@Before
|
||||
public void setupFiles() throws IOException {
|
||||
if(rs != null){
|
||||
return;
|
||||
}
|
||||
lib = NativeSwingRendering.getDefaultFromSettings();
|
||||
BinaryRoutePlanner.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = false;
|
||||
String obfdir = System.getenv("OBF_DIR");
|
||||
if(Algoritms.isEmpty(obfdir)){
|
||||
|
@ -50,12 +53,12 @@ public class JUnitRouteTest {
|
|||
|
||||
@Test
|
||||
public void runNL() throws SAXException, IOException, ParserConfigurationException {
|
||||
RouterTestsSuite.test(getClass().getResourceAsStream("nl.test.xml"), rs, RoutingConfiguration.getDefault());
|
||||
RouterTestsSuite.test(lib, getClass().getResourceAsStream("nl.test.xml"), rs, RoutingConfiguration.getDefault());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runNL2() throws SAXException, IOException, ParserConfigurationException {
|
||||
RouterTestsSuite.test(getClass().getResourceAsStream("nl2.test.xml"), rs, RoutingConfiguration.getDefault());
|
||||
RouterTestsSuite.test(lib, getClass().getResourceAsStream("nl2.test.xml"), rs, RoutingConfiguration.getDefault());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import net.osmand.NativeLibrary;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
import net.osmand.router.BinaryRoutePlanner;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
||||
|
@ -101,7 +102,7 @@ public class RouterTestsSuite {
|
|||
boolean allSuccess = true;
|
||||
|
||||
for(File f : params.tests) {
|
||||
allSuccess &= test(new FileInputStream(f), rs, params.configBuilder);
|
||||
allSuccess &= test(null, new FileInputStream(f), rs, params.configBuilder);
|
||||
}
|
||||
if (allSuccess) {
|
||||
System.out.println("All is successfull");
|
||||
|
@ -115,13 +116,13 @@ public class RouterTestsSuite {
|
|||
}
|
||||
|
||||
|
||||
public static boolean test(InputStream resource, BinaryMapIndexReader[] rs, RoutingConfiguration.Builder config) throws SAXException, IOException, ParserConfigurationException {
|
||||
public static boolean test(NativeLibrary lib, InputStream resource, BinaryMapIndexReader[] rs, RoutingConfiguration.Builder config) throws SAXException, IOException, ParserConfigurationException {
|
||||
Document testSuite = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(resource));
|
||||
NodeList tests = testSuite.getElementsByTagName("test");
|
||||
|
||||
for (int i = 0; i < tests.getLength(); i++) {
|
||||
Element e = (Element) tests.item(i);
|
||||
BinaryRoutePlanner router = new BinaryRoutePlanner(null, rs);
|
||||
BinaryRoutePlanner router = new BinaryRoutePlanner(lib, rs);
|
||||
testRoute(e, router, config);
|
||||
}
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ public class MapClusterLayer implements MapPanelLayer {
|
|||
long lstart = (((long) startRoad.getPoint31XTile(st.getSegmentStart())) << 31) +
|
||||
(long) startRoad.getPoint31YTile(st.getSegmentStart());
|
||||
RouteSegment next = ctx.getRoutingTile((int)lstart>>31, (int) (lstart- (lstart>>31)<<31)).
|
||||
getLoadedRoutes().get(lstart);
|
||||
getSegment(lstart);
|
||||
while (next != null) {
|
||||
if(next.getRoad().getId() != st.getRoad().getId()){
|
||||
queue.add(next);
|
||||
|
@ -281,7 +281,7 @@ public class MapClusterLayer implements MapPanelLayer {
|
|||
|
||||
router.loadRoutes(ctx, x, y);
|
||||
long l = (((long) x) << 31) + (long) y;
|
||||
next = ctx.getRoutingTile(x, y).getLoadedRoutes().get(l);
|
||||
next = ctx.getRoutingTile(x, y).getSegment(l);
|
||||
boolean addToQueue = true;;
|
||||
while (next != null) {
|
||||
String h = getHighway(next.getRoad());
|
||||
|
@ -298,7 +298,7 @@ public class MapClusterLayer implements MapPanelLayer {
|
|||
}
|
||||
|
||||
if (addToQueue) {
|
||||
next = ctx.getRoutingTile(x, y).getLoadedRoutes().get(l);
|
||||
next = ctx.getRoutingTile(x, y).getSegment(l);
|
||||
while (next != null) {
|
||||
if (!visitedIds.contains(calculateId(next, next.getSegmentStart()))) {
|
||||
queue.add(next);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* Parking plugin
|
||||
* Enable/disable monitoring widget
|
||||
</string>
|
||||
<string name="use_compass_navigation_descr">Use compass in navigation when diretion is not detected</string>
|
||||
<string name="use_compass_navigation_descr">Use compass when direction is not detected</string>
|
||||
<string name="use_compass_navigation">Use compass</string>
|
||||
<string name="select_animate_speedup">Select animate route acceleration</string>
|
||||
<string name="monitoring_info_control">Show logging button</string>
|
||||
|
|
|
@ -283,11 +283,11 @@ public class MapRenderRepositories {
|
|||
NativeSearchResult resultHandler = library.searchObjectsForRendering(leftX, rightX, topY, bottomY, zoom, renderingReq,
|
||||
PerformanceFlags.checkForDuplicateObjectIds, this, context.getString(R.string.switch_to_raster_map_to_see));
|
||||
if (checkWhetherInterrupted()) {
|
||||
library.deleteSearchResult(resultHandler);
|
||||
resultHandler.deleteNativeResult();
|
||||
return false;
|
||||
}
|
||||
if(cNativeObjects != null) {
|
||||
library.deleteSearchResult(cNativeObjects);
|
||||
cNativeObjects.deleteNativeResult();
|
||||
}
|
||||
cNativeObjects = resultHandler;
|
||||
cObjectsBox = dataBox;
|
||||
|
|
|
@ -380,6 +380,9 @@ jfieldID jfield_RouteDataObject_pointTypes = NULL;
|
|||
jfieldID jfield_RouteDataObject_id = NULL;
|
||||
jmethodID jmethod_RouteDataObject_init = NULL;
|
||||
|
||||
jclass jclass_NativeRouteSearchResult = NULL;
|
||||
jmethodID jmethod_NativeRouteSearchResult_init = NULL;
|
||||
|
||||
void loadJniRenderingContext(JNIEnv* env)
|
||||
{
|
||||
jclass_RenderingContext = findClass(env, "net/osmand/RenderingContext");
|
||||
|
@ -409,6 +412,8 @@ void loadJniRenderingContext(JNIEnv* env)
|
|||
jmethod_JUnidecode_unidecode = env->GetStaticMethodID(jclass_JUnidecode, "unidecode", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
|
||||
jclass_RouteDataObject = findClass(env, "net/osmand/binary/RouteDataObject");
|
||||
jclass_NativeRouteSearchResult = findClass(env, "net/osmand/NativeLibrary$NativeRouteSearchResult");
|
||||
jmethod_NativeRouteSearchResult_init = env->GetMethodID(jclass_NativeRouteSearchResult, "<init>", "(J[Lnet/osmand/binary/RouteDataObject;)V");
|
||||
|
||||
jfield_RouteDataObject_types = getFid(env, jclass_RouteDataObject, "types", "[I" );
|
||||
jfield_RouteDataObject_pointsX = getFid(env, jclass_RouteDataObject, "pointsX", "[I" );
|
||||
|
@ -439,97 +444,156 @@ void pullFromJavaRenderingContext(JNIEnv* env, jobject jrc, JNIRenderingContext*
|
|||
|
||||
// ElapsedTimer routingTimer;
|
||||
|
||||
//RouteDataObject[] loadRoutingData(RouteRegion reg, int left, int right, int top, int bottom)
|
||||
extern "C" JNIEXPORT jobjectArray JNICALL Java_net_osmand_NativeLibrary_loadRoutingData(JNIEnv* ienv,
|
||||
jobject obj, jobject reg, jstring regName, jint filepointer, jint left, jint right, jint top, jint bottom) {
|
||||
jobject convertRouteDataObjectToJava(JNIEnv* ienv, RouteDataObject* route, jobject reg) {
|
||||
jintArray nameInts = ienv->NewIntArray(route->names.size());
|
||||
jobjectArray nameStrings = ienv->NewObjectArray(route->names.size(), jclassString, NULL);
|
||||
jint ar[route->names.size()];
|
||||
UNORDERED(map)<int, std::string >::iterator itNames = route->names.begin();
|
||||
jsize sz = 0;
|
||||
for (; itNames != route->names.end(); itNames++, sz++) {
|
||||
std::string name = itNames->second;
|
||||
jstring js = ienv->NewStringUTF(name.c_str());
|
||||
ienv->SetObjectArrayElement(nameStrings, sz, js);
|
||||
ienv->DeleteLocalRef(js);
|
||||
ar[sz] = itNames->first;
|
||||
}
|
||||
ienv->SetIntArrayRegion(nameInts, 0, route->names.size(), ar);
|
||||
jobject robj = ienv->NewObject(jclass_RouteDataObject, jmethod_RouteDataObject_init, reg, nameInts, nameStrings);
|
||||
ienv->DeleteLocalRef(nameInts);
|
||||
ienv->DeleteLocalRef(nameStrings);
|
||||
|
||||
ienv->SetLongField(robj, jfield_RouteDataObject_id, route->id);
|
||||
|
||||
jintArray types = ienv->NewIntArray(route->types.size());
|
||||
if (route->types.size() > 0) {
|
||||
ienv->SetIntArrayRegion(types, 0, route->types.size(), (jint*) &route->types[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_types, types);
|
||||
ienv->DeleteLocalRef(types);
|
||||
|
||||
jintArray pointsX = ienv->NewIntArray(route->pointsX.size());
|
||||
if (route->pointsX.size() > 0) {
|
||||
ienv->SetIntArrayRegion(pointsX, 0, route->pointsX.size(), (jint*) &route->pointsX[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointsX, pointsX);
|
||||
ienv->DeleteLocalRef(pointsX);
|
||||
|
||||
jintArray pointsY = ienv->NewIntArray(route->pointsY.size());
|
||||
if (route->pointsY.size() > 0) {
|
||||
ienv->SetIntArrayRegion(pointsY, 0, route->pointsY.size(), (jint*) &route->pointsY[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointsY, pointsY);
|
||||
ienv->DeleteLocalRef(pointsY);
|
||||
|
||||
jlongArray restrictions = ienv->NewLongArray(route->restrictions.size());
|
||||
if (route->restrictions.size() > 0) {
|
||||
ienv->SetLongArrayRegion(restrictions, 0, route->restrictions.size(), (jlong*) &route->restrictions[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_restrictions, restrictions);
|
||||
ienv->DeleteLocalRef(restrictions);
|
||||
|
||||
jobjectArray pointTypes = ienv->NewObjectArray(route->pointTypes.size(), jclassIntArray, NULL);
|
||||
for (jint k = 0; k < route->pointTypes.size(); k++) {
|
||||
std::vector<uint32_t> ts = route->pointTypes[k];
|
||||
if (ts.size() > 0) {
|
||||
jintArray tos = ienv->NewIntArray(ts.size());
|
||||
ienv->SetIntArrayRegion(tos, 0, ts.size(), (jint*) &ts[0]);
|
||||
ienv->SetObjectArrayElement(pointTypes, k, tos);
|
||||
ienv->DeleteLocalRef(tos);
|
||||
}
|
||||
}
|
||||
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointTypes, pointTypes);
|
||||
ienv->DeleteLocalRef(pointTypes);
|
||||
return robj;
|
||||
}
|
||||
|
||||
class NativeRoutingTile {
|
||||
public:
|
||||
std::vector<RouteDataObject*> result;
|
||||
UNORDERED(map)<uint64_t, std::vector<RouteDataObject*> > cachedByLocations;
|
||||
};
|
||||
|
||||
|
||||
// protected static native void deleteRouteSearchResult(long searchResultHandle!);
|
||||
extern "C" JNIEXPORT void JNICALL Java_net_osmand_NativeLibrary_deleteRouteSearchResult(JNIEnv* ienv,
|
||||
jobject obj, jlong ref) {
|
||||
NativeRoutingTile* t = (NativeRoutingTile*) ref;
|
||||
for (unsigned int i = 0; i < t->result.size(); i++) {
|
||||
delete t->result[i];
|
||||
t->result[i] = NULL;
|
||||
}
|
||||
delete t;
|
||||
}
|
||||
|
||||
|
||||
// protected static native RouteDataObject[] getRouteDataObjects(NativeRouteSearchResult rs, int x31, int y31!);
|
||||
extern "C" JNIEXPORT jobjectArray JNICALL Java_net_osmand_NativeLibrary_getRouteDataObjects(JNIEnv* ienv,
|
||||
jobject obj, jobject reg, jlong ref, jint x31, jint y31) {
|
||||
|
||||
NativeRoutingTile* t = (NativeRoutingTile*) ref;
|
||||
uint64_t lr = ((uint64_t) x31 << 31) + y31;
|
||||
std::vector<RouteDataObject*> collected = t->cachedByLocations[lr];
|
||||
jobjectArray res = ienv->NewObjectArray(collected.size(), jclass_RouteDataObject, NULL);
|
||||
for (jint i = 0; i < collected.size(); i++) {
|
||||
jobject robj = convertRouteDataObjectToJava(ienv, collected[i], reg);
|
||||
ienv->SetObjectArrayElement(res, i, robj);
|
||||
ienv->DeleteLocalRef(robj);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//protected static native NativeRouteSearchResult loadRoutingData(RouteRegion reg, String regName, int fpointer, int left, int right, int top, int bottom,
|
||||
// boolean loadObjects!);
|
||||
extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_NativeLibrary_loadRoutingData(JNIEnv* ienv,
|
||||
jobject obj, jobject reg, jstring regName, jint filepointer, jint left, jint right, jint top, jint bottom, jboolean loadObjects) {
|
||||
RoutingIndex ind;
|
||||
ind.filePointer = filepointer;
|
||||
ind.name = getString(ienv, regName);
|
||||
|
||||
|
||||
std::vector<RouteDataObject*> result;
|
||||
SearchQuery q(left, right, top, bottom);
|
||||
searchRouteRegion(&q, result, &ind);
|
||||
|
||||
jobjectArray res = ienv->NewObjectArray(result.size(), jclass_RouteDataObject, NULL );
|
||||
for (jint i = 0; i < result.size(); i++) {
|
||||
if (result[i] != NULL) {
|
||||
jintArray nameInts = ienv->NewIntArray(result[i]->names.size());
|
||||
jobjectArray nameStrings = ienv->NewObjectArray(result[i]->names.size(),
|
||||
jclassString, NULL);
|
||||
jint ar[result[i]->names.size()];
|
||||
UNORDERED(map)<int, std::string >::iterator itNames = result[i]->names.begin();
|
||||
jsize sz = 0;
|
||||
for(;itNames != result[i]->names.end(); itNames++, sz++) {
|
||||
std::string name = itNames->second;
|
||||
jstring js = ienv->NewStringUTF(name.c_str());
|
||||
ienv->SetObjectArrayElement(nameStrings, sz, js);
|
||||
ienv->DeleteLocalRef(js);
|
||||
ar[sz] = itNames->first;
|
||||
|
||||
if (loadObjects) {
|
||||
jobjectArray res = ienv->NewObjectArray(result.size(), jclass_RouteDataObject, NULL);
|
||||
for (jint i = 0; i < result.size(); i++) {
|
||||
if (result[i] != NULL) {
|
||||
jobject robj = convertRouteDataObjectToJava(ienv, result[i], reg);
|
||||
ienv->SetObjectArrayElement(res, i, robj);
|
||||
ienv->DeleteLocalRef(robj);
|
||||
}
|
||||
ienv->SetIntArrayRegion(nameInts, 0, result[i]->names.size(),ar);
|
||||
jobject robj = ienv->NewObject(jclass_RouteDataObject, jmethod_RouteDataObject_init, reg,
|
||||
nameInts, nameStrings);
|
||||
ienv->DeleteLocalRef(nameInts);
|
||||
ienv->DeleteLocalRef(nameStrings);
|
||||
|
||||
ienv->SetLongField(robj, jfield_RouteDataObject_id, result[i]->id);
|
||||
|
||||
jintArray types = ienv->NewIntArray(result[i]->types.size());
|
||||
if(result[i]->types.size() > 0) {
|
||||
ienv->SetIntArrayRegion(types, 0, result[i]->types.size(), (jint*) &result[i]->types[0]);
|
||||
}
|
||||
for (unsigned int i = 0; i < result.size(); i++) {
|
||||
if (result[i] != NULL) {
|
||||
delete result[i];
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_types, types);
|
||||
ienv->DeleteLocalRef(types);
|
||||
|
||||
jintArray pointsX = ienv->NewIntArray(result[i]->pointsX.size());
|
||||
if (result[i]->pointsX.size() > 0) {
|
||||
ienv->SetIntArrayRegion(pointsX, 0, result[i]->pointsX.size(), (jint*) &result[i]->pointsX[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointsX, pointsX);
|
||||
ienv->DeleteLocalRef(pointsX);
|
||||
|
||||
jintArray pointsY = ienv->NewIntArray(result[i]->pointsY.size());
|
||||
if (result[i]->pointsY.size() > 0) {
|
||||
ienv->SetIntArrayRegion(pointsY, 0, result[i]->pointsY.size(), (jint*) &result[i]->pointsY[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointsY, pointsY);
|
||||
ienv->DeleteLocalRef(pointsY);
|
||||
|
||||
jlongArray restrictions = ienv->NewLongArray(result[i]->restrictions.size());
|
||||
if (result[i]->restrictions.size() > 0) {
|
||||
ienv->SetLongArrayRegion(restrictions, 0, result[i]->restrictions.size(),
|
||||
(jlong*) &result[i]->restrictions[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_restrictions, restrictions);
|
||||
ienv->DeleteLocalRef(restrictions);
|
||||
|
||||
|
||||
jobjectArray pointTypes = ienv->NewObjectArray(result[i]->pointTypes.size(), jclassIntArray, NULL);
|
||||
for(jint k = 0; k < result[i]->pointTypes.size(); k++ ) {
|
||||
std::vector<uint32_t> ts = result[i]->pointTypes[k];
|
||||
if (ts.size() > 0) {
|
||||
jintArray tos = ienv->NewIntArray(ts.size());
|
||||
ienv->SetIntArrayRegion(tos, 0, ts.size(), (jint*) &ts[0]);
|
||||
ienv->SetObjectArrayElement(pointTypes, k, tos);
|
||||
ienv->DeleteLocalRef(tos);
|
||||
result[i] = NULL;
|
||||
}
|
||||
return ienv->NewObject(jclass_NativeRouteSearchResult, jmethod_NativeRouteSearchResult_init, ((jlong) 0), res);
|
||||
} else {
|
||||
NativeRoutingTile* r = new NativeRoutingTile();
|
||||
for (jint i = 0; i < result.size(); i++) {
|
||||
if (result[i] != NULL) {
|
||||
r->result.push_back(result[i]);
|
||||
for (jint j = 0; j < result[i]->pointsX.size(); j++) {
|
||||
jint x = result[i]->pointsX[j];
|
||||
jint y = result[i]->pointsY[j];
|
||||
uint64_t lr = ((uint64_t) x << 31) + y;
|
||||
r->cachedByLocations[lr].push_back(result[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointTypes, pointTypes);
|
||||
ienv->DeleteLocalRef(pointTypes);
|
||||
|
||||
|
||||
|
||||
ienv->SetObjectArrayElement(res, i, robj);
|
||||
ienv->DeleteLocalRef(robj);
|
||||
}
|
||||
jlong ref = (jlong) r;
|
||||
if(r->result.size() == 0) {
|
||||
ref = 0;
|
||||
delete r;
|
||||
}
|
||||
|
||||
return ienv->NewObject(jclass_NativeRouteSearchResult, jmethod_NativeRouteSearchResult_init, ref, NULL);
|
||||
}
|
||||
for (unsigned int i = 0; i < result.size(); i++) {
|
||||
delete result[i];
|
||||
result[i] = NULL;
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue