diff --git a/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java b/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java index b6dc2f2176..ae54564cb5 100644 --- a/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java +++ b/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java @@ -1117,4 +1117,15 @@ public class RouteDataObject { } restrictionsVia[k] = viaWay; } + + public void setPointTypes(int pntInd, int[] array) { + if (pointTypes == null || pointTypes.length < pntInd) { + int[][] npointTypes = new int[pntInd + 1][]; + for (int k = 0; pointTypes != null && k < pointTypes.length; k++) { + npointTypes[k] = pointTypes[k]; + } + pointTypes = npointTypes; + } + pointTypes[pntInd] = array; + } } diff --git a/OsmAnd-java/src/main/java/net/osmand/router/GeneralRouter.java b/OsmAnd-java/src/main/java/net/osmand/router/GeneralRouter.java index be5bba2f5f..07be280c53 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/GeneralRouter.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/GeneralRouter.java @@ -1,8 +1,10 @@ package net.osmand.router; +import net.osmand.GPXUtilities.WptPt; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule; import net.osmand.binary.RouteDataObject; +import net.osmand.data.QuadTree; import net.osmand.router.BinaryRoutePlanner.RouteSegment; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; @@ -76,6 +78,7 @@ public class GeneralRouter implements VehicleRouter { private float maxVehicleSpeed; private TLongHashSet impassableRoads; + private GeneralRouterProfile profile; Map>[] evalCache; @@ -268,11 +271,11 @@ public class GeneralRouter implements VehicleRouter { @Override public boolean acceptLine(RouteDataObject way) { Float res = getCache(RouteDataObjectAttribute.ACCESS, way); - if(res == null) { + if (res == null) { res = (float) getObjContext(RouteDataObjectAttribute.ACCESS).evaluateInt(way, 0); putCache(RouteDataObjectAttribute.ACCESS, way, res); } - if(impassableRoads != null && impassableRoads.contains(way.id)) { + if (impassableRoads != null && impassableRoads.contains(way.id)) { return false; } return res >= 0; diff --git a/OsmAnd-java/src/main/java/net/osmand/router/RoutingConfiguration.java b/OsmAnd-java/src/main/java/net/osmand/router/RoutingConfiguration.java index 232b971f9f..65ea507434 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RoutingConfiguration.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RoutingConfiguration.java @@ -1,14 +1,5 @@ package net.osmand.router; -import net.osmand.PlatformUtil; -import net.osmand.router.GeneralRouter.GeneralRouterProfile; -import net.osmand.router.GeneralRouter.RouteAttributeContext; -import net.osmand.router.GeneralRouter.RouteDataObjectAttribute; -import net.osmand.util.Algorithms; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import java.io.IOException; import java.io.InputStream; import java.util.HashSet; @@ -17,6 +8,17 @@ import java.util.Map; import java.util.Set; import java.util.Stack; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import net.osmand.GPXUtilities.WptPt; +import net.osmand.PlatformUtil; +import net.osmand.data.QuadTree; +import net.osmand.router.GeneralRouter.GeneralRouterProfile; +import net.osmand.router.GeneralRouter.RouteAttributeContext; +import net.osmand.router.GeneralRouter.RouteDataObjectAttribute; +import net.osmand.util.Algorithms; + public class RoutingConfiguration { public static final int DEFAULT_MEMORY_LIMIT = 30; @@ -49,6 +51,11 @@ public class RoutingConfiguration { // 1.6 Time to calculate all access restrictions based on conditions public long routeCalculationTime = 0; + + // extra points to be inserted in ways (quad tree is based on 31 coords) + public QuadTree directionPoints; + public int directionPointsRadius = 30; // 30 m + public static class Builder { // Design time storage private String defaultRouter = ""; diff --git a/OsmAnd-java/src/main/java/net/osmand/router/RoutingContext.java b/OsmAnd-java/src/main/java/net/osmand/router/RoutingContext.java index 584be83bb3..265a0a07c3 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RoutingContext.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RoutingContext.java @@ -11,14 +11,17 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.apache.commons.logging.Log; import gnu.trove.iterator.TIntObjectIterator; import gnu.trove.iterator.TLongIterator; +import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.TLongObjectMap; import gnu.trove.map.hash.TLongObjectHashMap; import gnu.trove.set.hash.TLongHashSet; +import net.osmand.GPXUtilities.WptPt; import net.osmand.NativeLibrary; import net.osmand.NativeLibrary.NativeRouteSearchResult; import net.osmand.PlatformUtil; @@ -28,10 +31,12 @@ 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.data.QuadRect; import net.osmand.router.BinaryRoutePlanner.FinalRouteSegment; import net.osmand.router.BinaryRoutePlanner.RouteSegment; import net.osmand.router.BinaryRoutePlanner.RouteSegmentVisitor; import net.osmand.router.RoutePlannerFrontEnd.RouteCalculationMode; +import net.osmand.util.MapUtils; public class RoutingContext { @@ -277,22 +282,22 @@ public class RoutingContext { ts.setLoadedNonNative(); List res = reader.loadRouteIndexData(ts.subregion); - if(toLoad != null) { + if (toLoad != null) { toLoad.addAll(res); } else { - for(RouteDataObject ro : res){ - if(ro != null) { - if(config.routeCalculationTime != 0) { + for (RouteDataObject ro : res) { + if (ro != null) { + if (config.routeCalculationTime != 0) { ro.processConditionalTags(config.routeCalculationTime); } - if(config.router.acceptLine(ro)) { - if(excludeNotAllowed != null && !excludeNotAllowed.contains(ro.getId())) { + if (config.router.acceptLine(ro)) { + if (excludeNotAllowed != null && !excludeNotAllowed.contains(ro.getId())) { ts.add(ro); } } - if(excludeNotAllowed != null && ro.getId() > 0){ + if (excludeNotAllowed != null && ro.getId() > 0) { excludeNotAllowed.add(ro.getId()); - if(ts.excludedIds == null ){ + if (ts.excludedIds == null) { ts.excludedIds = new TLongHashSet(); } ts.excludedIds.add(ro.getId()); @@ -451,8 +456,9 @@ public class RoutingContext { @SuppressWarnings("unused") private long getRoutingTile(int x31, int y31, long memoryLimit) { // long now = System.nanoTime(); - long xloc = x31 >> (31 - config.ZOOM_TO_LOAD_TILES); - long yloc = y31 >> (31 - config.ZOOM_TO_LOAD_TILES); + int zmShift = 31 - config.ZOOM_TO_LOAD_TILES; + long xloc = x31 >> zmShift; + long yloc = y31 >> zmShift; long tileId = (xloc << config.ZOOM_TO_LOAD_TILES) + yloc; if (memoryLimit == 0) { memoryLimit = config.memoryLimitation; @@ -505,6 +511,11 @@ public class RoutingContext { excludeIds.addAll(ts.excludedIds); } } + // connect direction points + if(config.directionPoints != null) { + connectDirectionPoints(ts, (int) (xloc << zmShift), (int) (yloc << zmShift), + (int) ((xloc + 1) << zmShift), (int) ((yloc + 1) << zmShift)); + } } } } @@ -513,7 +524,67 @@ public class RoutingContext { } - + private static final String ATTACHED_ID = "AID"; + private void connectDirectionPoints(RoutingSubregionTile ts, int minx, int miny, int maxx, int maxy) { + List points = config.directionPoints.queryInBox(new QuadRect(minx, miny, maxx, maxy), new ArrayList<>()); + for (WptPt connectPoint : points) { + TIntArrayList types = new TIntArrayList(); + for (Entry e : connectPoint.getExtensionsToRead().entrySet()) { + if(e.getKey().equals(ATTACHED_ID)) { + types.clear(); + break; + } + int type = ts.subregion.routeReg.searchRouteEncodingRule(e.getKey(), e.getValue()); + if(type != -1) { + types.add(type); + } + } + // don't attach empty points + if(types.size() == 0) { + continue; + } + int y = MapUtils.get31TileNumberY(connectPoint.lat); + int x = MapUtils.get31TileNumberX(connectPoint.lon); + double closest = Integer.MAX_VALUE; + int xc = 0, yc = 0; + long[] keys = ts.routes.keys(); + for (long k : keys) { + // long k = (((long) x31) << 31) + (long) y31; + int xp = (int) (k >> 31); + int yp = (int) (k - (xp << 31)); + double dist = MapUtils.squareRootDist31(x, y, xp, yp); + if (dist < closest) { + xc = xp; + yc = yp; + closest = dist; + } + } + // config.directionPointsRadius + if (closest < config.directionPointsRadius) { + long k = (((long) xc) << 31) + (long) yc; + RouteSegment segment = ts.routes.get(k); + int pntInd = -1; + for(int i = 0; i < segment.getRoad().getPointsLength() - 1; i ++) { + if(xc == segment.getRoad().getPoint31XTile(i) && yc == segment.getRoad().getPoint31YTile(i)) { + pntInd = i; + } + } + if (pntInd != -1) { + System.out.println( + "INSERT INTO " + segment.getRoad() + " " + connectPoint.getLatitude() + " " + connectPoint.getLongitude()); + segment.getRoad().insert(pntInd, x, y); + connectPoint.getExtensionsToWrite().put(ATTACHED_ID, segment.getRoad().getId() +""); + if (types.size() > 0) { + System.out.println(" >>> INSERT INTO " + segment.getRoad() + " " + connectPoint.getLatitude() + " " + + connectPoint.getLongitude()); + segment.getRoad().setPointTypes(pntInd, types.toArray()); + } + } + + } + } + } + public boolean checkIfMemoryLimitCritical(long memoryLimit) { return getCurrentEstimatedSize() > 0.9 * memoryLimit; }