Update native routing

This commit is contained in:
Victor Shcherb 2012-11-04 01:53:33 +01:00
parent efaf4e25c4
commit 0a2edd2afc
10 changed files with 428 additions and 314 deletions

View file

@ -1,13 +1,23 @@
package net.osmand;
import gnu.trove.list.array.TIntArrayList;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
import net.osmand.binary.RouteDataObject;
import net.osmand.render.RenderingRuleSearchRequest;
import net.osmand.render.RenderingRulesStorage;
import net.osmand.router.GeneralRouter;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.RoutingConfiguration;
public class NativeLibrary {
@ -99,8 +109,32 @@ public class NativeLibrary {
return closeBinaryMapFile(filePath);
}
public RouteSegmentResult[] testRoutingInternal(int sx31, int sy31, int ex31, int ey31) {
return testRouting(sx31, sy31, ex31, ey31);
public RouteSegmentResult[] runNativeRouting(int sx31, int sy31, int ex31, int ey31, RoutingConfiguration config) {
TIntArrayList state = new TIntArrayList();
List<String> keys = new ArrayList<String>();
List<String> values = new ArrayList<String>();
GeneralRouter r = (GeneralRouter) config.router;
fillObjects(state, keys, values, 0, r.highwaySpeed);
fillObjects(state, keys, values, 1, r.highwayPriorities);
fillObjects(state, keys, values, 2, r.avoid);
fillObjects(state, keys, values, 3, r.obstacles);
fillObjects(state, keys, values, 4, r.routingObstacles);
LinkedHashMap<String, String> attrs = new LinkedHashMap<String, String>(config.attributes);
attrs.putAll(r.attributes);
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()]));
}
public <T> void fillObjects(TIntArrayList state, List<String> keys, List<String> values, int s, Map<String, T> map) {
Iterator<Entry<String, T>> it = map.entrySet().iterator();
while(it.hasNext()) {
Entry<String, T> n = it.next();
state.add(s);
keys.add(n.getKey());
values.add(n.getValue()+"");
}
}
@ -122,7 +156,7 @@ public class NativeLibrary {
protected static native RouteDataObject[] getRouteDataObjects(RouteRegion reg, long rs, int x31, int y31);
protected static native RouteSegmentResult[] testRouting(int sx31, int sy31, int ex31, int ey31);
protected static native RouteSegmentResult[] nativeRouting(int[] coordinates, int[] state, String[] keyConfig, String[] valueConfig);
protected static native void deleteSearchResult(long searchResultHandle);

View file

@ -1,8 +1,10 @@
package net.osmand.router;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import net.osmand.binary.RouteDataObject;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
@ -17,26 +19,25 @@ public class GeneralRouter extends VehicleRouter {
public static final String AVOID_MOTORWAY = "avoid_motorway";
public static final String AVOID_UNPAVED = "avoid_unpaved";
Map<String, Float> highwaySpeed ;
Map<String, Float> highwayPriorities ;
Map<String, Float> highwayFuturePriorities ;
Map<String, Float> avoid ;
Map<String, Float> obstacles;
Map<String, Float> routingObstacles;
Map<String, String> attributes;
public Map<String, Float> highwaySpeed ;
public Map<String, Float> highwayPriorities ;
public Map<String, Float> avoid ;
public Map<String, Float> obstacles;
public Map<String, Float> routingObstacles;
public Map<String, String> attributes;
private GeneralRouterProfile profile;
// cached values
private Boolean restrictionsAware;
private Float leftTurn;
private Float roundaboutTurn;
private Float rightTurn;
private Boolean onewayAware;
private Boolean followSpeedLimitations;
private Float minDefaultSpeed;
private Float maxDefaultSpeed;
private boolean restrictionsAware = true;
private float leftTurn;
private float roundaboutTurn;
private float rightTurn;
private boolean onewayAware = true;
private boolean followSpeedLimitations = true;
private float minDefaultSpeed = 10;
private float maxDefaultSpeed = 10;
public enum GeneralRouterProfile {
CAR,
@ -49,21 +50,51 @@ public class GeneralRouter extends VehicleRouter {
this.profile = profile;
highwaySpeed = new LinkedHashMap<String, Float>();
highwayPriorities = new LinkedHashMap<String, Float>();
highwayFuturePriorities = new LinkedHashMap<String, Float>();
avoid = new LinkedHashMap<String, Float>();
obstacles = new LinkedHashMap<String, Float>();
routingObstacles = new LinkedHashMap<String, Float>();
Iterator<Entry<String, String>> e = attributes.entrySet().iterator();
while(e.hasNext()){
Entry<String, String> next = e.next();
addAttribute(next.getKey(), next.getValue());
}
}
public GeneralRouter(GeneralRouter pr) {
this.highwaySpeed = new LinkedHashMap<String, Float>(pr.highwaySpeed);
this.highwayPriorities = new LinkedHashMap<String, Float>(pr.highwayPriorities);
this.highwayFuturePriorities = new LinkedHashMap<String, Float>(pr.highwayFuturePriorities);
this.avoid = new LinkedHashMap<String, Float>(pr.avoid);
this.obstacles = new LinkedHashMap<String, Float>(pr.obstacles);
this.routingObstacles = new LinkedHashMap<String, Float>(pr.routingObstacles);
this.attributes = new LinkedHashMap<String, String>(pr.attributes);
this.profile = pr.profile;
Iterator<Entry<String, String>> e = pr.attributes.entrySet().iterator();
while(e.hasNext()){
Entry<String, String> next = e.next();
addAttribute(next.getKey(), next.getValue());
}
}
public void addAttribute(String k, String v) {
attributes.put(k, v);
if(k.equals("restrictionsAware")) {
restrictionsAware = parseSilentBoolean(v, restrictionsAware);
} else if(k.equals("onewayAware")) {
onewayAware = parseSilentBoolean(v, onewayAware);
} else if(k.equals("followSpeedLimitations")) {
followSpeedLimitations = parseSilentBoolean(v, followSpeedLimitations);
} else if(k.equals("leftTurn")) {
leftTurn = parseSilentFloat(v, leftTurn);
} else if(k.equals("rightTurn")) {
rightTurn = parseSilentFloat(v, rightTurn);
} else if(k.equals("roundaboutTurn")) {
roundaboutTurn = parseSilentFloat(v, roundaboutTurn);
} else if(k.equals("minDefaultSpeed")) {
minDefaultSpeed = parseSilentFloat(v, minDefaultSpeed * 3.6f) / 3.6f;
} else if(k.equals("maxDefaultSpeed")) {
maxDefaultSpeed = parseSilentFloat(v, maxDefaultSpeed * 3.6f) / 3.6f;
}
}
@Override
@ -105,9 +136,6 @@ public class GeneralRouter extends VehicleRouter {
@Override
public boolean restrictionsAware() {
if(restrictionsAware == null) {
restrictionsAware = parseSilentBoolean(attributes.get("restrictionsAware"), true);
}
return restrictionsAware;
}
@ -156,9 +184,6 @@ public class GeneralRouter extends VehicleRouter {
}
public boolean isOnewayAware() {
if(onewayAware == null) {
onewayAware = parseSilentBoolean(attributes.get("onewayAware"), true);
}
return onewayAware;
}
@ -170,23 +195,9 @@ public class GeneralRouter extends VehicleRouter {
return super.isOneWay(road);
}
@Override
public float getFutureRoadPriority(RouteDataObject road) {
float priority = 1;
for (int i = 0; i < road.types.length; i++) {
RouteTypeRule r = road.region.quickGetEncodingRule(road.types[i]);
if(highwayFuturePriorities.containsKey(r.getTag()+"$"+r.getValue())){
priority = highwayFuturePriorities.get(r.getTag()+"$"+r.getValue());
break;
}
}
return priority;
}
public boolean isFollowSpeedLimitations(){
if(followSpeedLimitations == null){
followSpeedLimitations = parseSilentBoolean(attributes.get("followSpeedLimitations"), true);
}
return followSpeedLimitations;
}
@ -241,38 +252,23 @@ public class GeneralRouter extends VehicleRouter {
@Override
public float getMinDefaultSpeed() {
if(minDefaultSpeed == null ){
minDefaultSpeed = parseSilentFloat(attributes.get("minDefaultSpeed"), 10);
}
return minDefaultSpeed / 3.6f;
return minDefaultSpeed;
}
@Override
public float getMaxDefaultSpeed() {
if(maxDefaultSpeed == null ){
maxDefaultSpeed = parseSilentFloat(attributes.get("maxDefaultSpeed"), 10);
}
return maxDefaultSpeed / 3.6f;
return maxDefaultSpeed ;
}
public double getLeftTurn() {
if(leftTurn == null) {
leftTurn = parseSilentFloat(attributes.get("leftTurn"), 0);
}
return leftTurn;
}
public double getRightTurn() {
if(rightTurn == null) {
rightTurn = parseSilentFloat(attributes.get("rightTurn"), 0);
}
return rightTurn;
}
public double getRoundaboutTurn() {
if(roundaboutTurn == null) {
roundaboutTurn = parseSilentFloat(attributes.get("roundaboutTurn"), 0);
}
return roundaboutTurn;
}
@Override
@ -307,7 +303,7 @@ public class GeneralRouter extends VehicleRouter {
return 0;
}
private void specialize(String specializationTag, Map<String, Float> m){
private <T> void specialize(String specializationTag, Map<String, T> m){
ArrayList<String> ks = new ArrayList<String>(m.keySet());
for(String s : ks){
if(s.startsWith(specializationTag +":")) {
@ -319,15 +315,25 @@ public class GeneralRouter extends VehicleRouter {
@Override
public GeneralRouter specialization(String specializationTag) {
GeneralRouter gr = new GeneralRouter(this);
gr.specialize(specializationTag, gr.highwayFuturePriorities);
gr.specialize(specializationTag, gr.highwayPriorities);
gr.specialize(specializationTag, gr.highwaySpeed);
gr.specialize(specializationTag, gr.avoid);
gr.specialize(specializationTag, gr.obstacles);
gr.specialize(specializationTag, gr.routingObstacles);
gr.specialize(specializationTag, gr.attributes);
return gr;
}
@Override
public boolean containsAttribute(String attribute) {
return attributes.containsKey(attribute);
}
@Override
public String getAttribute(String attribute) {
return attributes.get(attribute);
}
}

View file

@ -16,38 +16,31 @@ import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class RoutingConfiguration {
public static final int DEFAULT_MEMORY_LIMIT = 30;
public Map<String, String> attributes = new LinkedHashMap<String, String>();
// 1. parameters of routing and different tweaks
// Influence on A* : f(x) + heuristicCoefficient*g(X)
public float heuristicCoefficient = 1;
public static final int DEFAULT_MEMORY_LIMIT = 30;
// 1.1 tile load parameters (should not affect routing)
public int ZOOM_TO_LOAD_TILES = 16;
public int memoryLimitation;
// 1.2 Dynamic road prioritizing (heuristic)
public boolean useDynamicRoadPrioritising = true;
public int dynamicRoadPriorityDistance = 0;
// 1.3 Relaxing strategy
public boolean useRelaxingStrategy = true;
public int ITERATIONS_TO_RELAX_NODES = 100;
public float RELAX_NODES_IF_START_DIST_COEF = 3;
// 1.4 Build A* graph in backward/forward direction (can affect results)
// 1.2 Build A* graph in backward/forward direction (can affect results)
// 0 - 2 ways, 1 - direct way, -1 - reverse way
public int planRoadDirection = 0;
// 1.5 Router specific coefficients and restrictions
// 1.3 Router specific coefficients and restrictions
public VehicleRouter router = new GeneralRouter(GeneralRouterProfile.CAR, new LinkedHashMap<String, String>());
public String routerName = "";
// 1.6 Used to calculate route in movement
// 1.4 Used to calculate route in movement
public Double initialDirection;
public static class Builder {
// Design time storage
private String defaultRouter = "";
@ -62,10 +55,21 @@ public class RoutingConfiguration {
router = defaultRouter;
}
RoutingConfiguration i = new RoutingConfiguration();
if (routers.containsKey(router)) {
i.router = routers.get(router);
if (specialization != null) {
for (String s : specialization) {
i.router = i.router.specialization(s);
}
}
i.routerName = router;
}
attributes.put("routerName", router);
i.attributes.putAll(attributes);
i.initialDirection = direction;
i.heuristicCoefficient = parseSilentFloat(getAttribute(router, "heuristicCoefficient"), i.heuristicCoefficient);
i.ZOOM_TO_LOAD_TILES = parseSilentInt(getAttribute(router, "zoomToLoadTiles"), i.ZOOM_TO_LOAD_TILES);
int desirable = parseSilentInt(getAttribute(router, "memoryLimitInMB"), 0);
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);
if(desirable != 0) {
i.memoryLimitation = desirable * (1 << 20);
} else {
@ -74,29 +78,15 @@ public class RoutingConfiguration {
}
i.memoryLimitation = memoryLimitMB * (1 << 20);
}
i.useDynamicRoadPrioritising = parseSilentBoolean(getAttribute(router, "useDynamicRoadPrioritising"), i.useDynamicRoadPrioritising);
i.useRelaxingStrategy = parseSilentBoolean(getAttribute(router, "useRelaxingStrategy"), i.useRelaxingStrategy);
i.dynamicRoadPriorityDistance = parseSilentInt(getAttribute(router, "dynamicRoadPriorityDistance"), i.dynamicRoadPriorityDistance);
i.ITERATIONS_TO_RELAX_NODES = parseSilentInt(getAttribute(router, "iterationsToRelaxRoutes"), i.ITERATIONS_TO_RELAX_NODES);
i.RELAX_NODES_IF_START_DIST_COEF = parseSilentFloat(getAttribute(router, "relaxNodesIfStartDistSmallCoeff"), i.RELAX_NODES_IF_START_DIST_COEF);
i.planRoadDirection = parseSilentInt(getAttribute(router, "planRoadDirection"), i.planRoadDirection);
if (!routers.containsKey(router)) {
return i;
}
i.router = routers.get(router);
if(specialization != null) {
for(String s : specialization) {
i.router = i.router.specialization(s);
}
}
i.routerName = router;
return i;
}
private String getAttribute(String router, String propertyName) {
if (attributes.containsKey(router + "$" + propertyName)) {
return attributes.get(router + "$" + propertyName);
private String getAttribute(VehicleRouter router, String propertyName) {
if (router.containsAttribute(propertyName)) {
return router.getAttribute(propertyName);
}
return attributes.get(propertyName);
}
@ -151,15 +141,15 @@ public class RoutingConfiguration {
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
String name = parser.isNamespaceAware() ? localName : qName;
previousTag = name;
if("osmand_routing_config".equals(name)) {
config.defaultRouter = attributes.getValue("defaultProfile");
} else if("attribute".equals(name)) {
previousKey = attributes.getValue("name");
previousTag = name;
if (currentSelectedRouter != null) {
previousKey = currentSelectedRouter + "$" + previousKey;
if(currentRouter != null) {
currentRouter.addAttribute(attributes.getValue("name"), attributes.getValue("value"));
} else {
config.attributes.put(attributes.getValue("name"), attributes.getValue("value"));
}
config.attributes.put(previousKey, attributes.getValue("value"));
} else if("routingProfile".equals(name)) {
currentSelectedRouter = attributes.getValue("name");
Map<String, String> attrs = new LinkedHashMap<String, String>();
@ -181,12 +171,12 @@ public class RoutingConfiguration {
if (attributes.getValue("priority") != null) {
currentRouter.highwayPriorities.put(k, parseSilentFloat(attributes.getValue("priority"), 0));
}
if (attributes.getValue("dynamicPriority") != null) {
currentRouter.highwayFuturePriorities.put(k, parseSilentFloat(attributes.getValue("dynamicPriority"), 0));
}
if (attributes.getValue("speed") != null) {
currentRouter.highwaySpeed.put(k, parseSilentFloat(attributes.getValue("speed"), 0));
}
if ("attribute".equals(previousTag)) {
currentRouter.attributes.put(k, attributes.getValue("value"));
}
if ("avoid".equals(previousTag)) {
float priority = parseSilentFloat(attributes.getValue("decreasedPriority"), 0);
if (priority == 0) {
@ -198,23 +188,18 @@ public class RoutingConfiguration {
}
} else if("road".equals(name)) {
previousTag = name;
previousKey = attributes.getValue("tag") +"$" + attributes.getValue("value");
currentRouter.highwayPriorities.put(previousKey, parseSilentFloat(attributes.getValue("priority"),
1));
currentRouter.highwayFuturePriorities.put(previousKey, parseSilentFloat(attributes.getValue("dynamicPriority"),
1));
currentRouter.highwaySpeed.put(previousKey, parseSilentFloat(attributes.getValue("speed"),
10));
} else if("obstacle".equals(name)) {
previousTag = name;
previousKey = attributes.getValue("tag") + "$" + attributes.getValue("value");
float penalty = parseSilentFloat(attributes.getValue("penalty"), 0);
currentRouter.obstacles.put(previousKey, penalty);
float routingPenalty = parseSilentFloat(attributes.getValue("routingPenalty"), penalty );
currentRouter.routingObstacles.put(previousKey, routingPenalty);
} else if("avoid".equals(name)) {
previousTag = name;
previousKey = attributes.getValue("tag") + "$" + attributes.getValue("value");
float priority = parseSilentFloat(attributes.getValue("decreasedPriority"),
0);

View file

@ -27,11 +27,11 @@ public abstract class VehicleRouter {
return road.getHighway();
}
public abstract boolean containsAttribute(String attribute);
public abstract String getAttribute(String attribute);
/**
* Used for algorithm to multiply h(x) part A* based on current road
*/
public abstract float getFutureRoadPriority(RouteDataObject road);
/**
* return delay in seconds

View file

@ -12,18 +12,6 @@
(don't specify here ! it is device dependent) -->
<attribute name="memoryLimitInMB" value="155" />
<!-- 1.2 Dynamic road prioritizing (heuristic) -->
<attribute name="useDynamicRoadPrioritising" value="false" />
<!-- for first N meters speed multiplied by priority, 0 special number - all rest distance -->
<attribute name="dynamicRoadPriorityDistance" value="30000" />
<!-- 1.3 Relaxing strategy -->
<!-- If the furthest routing branch passed distance 3 times more than small branches, small will be relaxed-->
<!-- Coefficient is configurable -->
<attribute name="useRelaxingStrategy" value="false" />
<attribute name="iterationsToRelaxRoutes" value="100" />
<attribute name="relaxNodesIfStartDistSmallCoeff" value="5"/>
<!-- 1.4 Build A* graph in backward/forward direction (can affect results) -->
<!-- 0 - 2 ways, 1 - direct way, -1 - reverse way -->
<attribute name="planRoadDirection" value="0" />

View file

@ -721,7 +721,7 @@ public class MapRouterLayer implements MapPanelLayer {
int sx31 = st.getRoad().getPoint31XTile(st.getSegmentStart());
int sy31 = st.getRoad().getPoint31YTile(st.getSegmentStart());
// FIXME
RouteSegmentResult[] searchRoute = ctx.nativeLib.testRoutingInternal(sx31, sy31, ex31, ey31);
RouteSegmentResult[] searchRoute = ctx.nativeLib.runNativeRouting(sx31, sy31, ex31, ey31, ctx.config);
/*List<RouteSegmentResult> searchRoute = */router.searchRoute(ctx, st, e, inters, false);
// this.previousRoute = searchRoute;
if (animateRoutingCalculation) {

View file

@ -58,13 +58,13 @@ static double squareDist(int x1, int y1, int x2, int y2) {
}
static double h(RoutingContext* ctx, float distanceToFinalPoint, SHARED_PTR<RouteSegment> next) {
return distanceToFinalPoint / ctx->getMaxDefaultSpeed();
return distanceToFinalPoint / ctx->config.getMaxDefaultSpeed();
}
static double h(RoutingContext* ctx, int targetEndX, int targetEndY,
int startX, int startY) {
double distance = squareRootDist(startX, startY, targetEndX, targetEndY);
return distance / ctx->getMaxDefaultSpeed();
return distance / ctx->config.getMaxDefaultSpeed();
}
@ -220,7 +220,7 @@ bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch,
// avoid empty segments to connect but mark the point as visited
visitedSegments[nt] = SHARED_PTR<RouteSegment>();
int oneway = ctx->isOneWay(road);
int oneway = ctx->config.isOneWay(road);
bool minusAllowed;
bool plusAllowed;
if(ctx->firstRoadId == nt) {
@ -238,11 +238,11 @@ bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch,
int d = plusAllowed ? 1 : -1;
if(segment->parentRoute.get() != NULL) {
if(plusAllowed && middle < segment->road->pointsX.size() - 1) {
obstaclePlusTime = ctx->calculateTurnTime(segment, segment->road->pointsX.size() - 1,
obstaclePlusTime = ctx->config.calculateTurnTime(segment, segment->road->pointsX.size() - 1,
segment->parentRoute, segment->parentSegmentEnd);
}
if(minusAllowed && middle > 0) {
obstacleMinusTime = ctx->calculateTurnTime(segment, 0,
obstacleMinusTime = ctx->config.calculateTurnTime(segment, 0,
segment->parentRoute, segment->parentSegmentEnd);
}
}
@ -291,14 +291,14 @@ bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch,
// 2.1 calculate possible obstacle plus time
if(positive) {
double obstacle = ctx->defineRoutingObstacle(road, segmentEnd);
double obstacle = ctx->config.defineRoutingObstacle(road, segmentEnd);
if (obstacle < 0) {
plusAllowed = false;
continue;
}
obstaclePlusTime += obstacle;
} else {
double obstacle = ctx->defineRoutingObstacle(road, segmentEnd);
double obstacle = ctx->config.defineRoutingObstacle(road, segmentEnd);
if (obstacle < 0) {
minusAllowed = false;
continue;
@ -324,10 +324,10 @@ bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch,
// Using A* routing algorithm
// g(x) - calculate distance to that point and calculate time
double priority = ctx->defineSpeedPriority(road);
double speed = ctx->defineSpeed(road) * priority;
double priority = ctx->config.defineSpeedPriority(road);
double speed = ctx->config.defineSpeed(road) * priority;
if (speed == 0) {
speed = ctx->getMinDefaultSpeed() * priority;
speed = ctx->config.getMinDefaultSpeed() * priority;
}
double distOnRoadToPass = positive? posSegmentDist : negSegmentDist;
double distStartObstacles = segment->distanceFromStart + ( positive ? obstaclePlusTime : obstacleMinusTime) + distOnRoadToPass / speed;
@ -353,7 +353,7 @@ bool proccessRestrictions(RoutingContext* ctx, SHARED_PTR<RouteDataObject> road,
if (!reverseWay && road->restrictions.size() == 0) {
return false;
}
if(!ctx->restrictionsAware()) {
if(!ctx->config.restrictionsAware()) {
return false;
}
while (next.get() != NULL) {
@ -497,7 +497,7 @@ bool processIntersections(RoutingContext* ctx, SEGMENTS_QUEUE& graphSegments,
return false;
}
// FIXME
// FIXME replace with adequate method
SHARED_PTR<RouteSegment> findRouteSegment(int px, int py, RoutingContext* ctx) {
return ctx->loadSegmentAround(px, py);
}

View file

@ -3,6 +3,9 @@
#include "common.h"
#include "binaryRead.h"
typedef UNORDERED(map)<string, float> MAP_STR_FLOAT;
typedef UNORDERED(map)<string, string> MAP_STR_STR;
static double measuredDist(int x1, int y1, int x2, int y2) {
return getDistance(get31LatitudeY(y1), get31LongitudeX(x1), get31LatitudeY(y2),
get31LongitudeX(x2));
@ -54,7 +57,6 @@ struct FinalRouteSegment {
const static int ZOOM_TO_LOAD_TILES = 16;
struct RoutingSubregionTile {
RouteSubregion subregion;
// make it without get/set for fast access
@ -99,9 +101,245 @@ static int64_t calcRouteId(SHARED_PTR<RouteDataObject> o, int ind) {
return (o->id << 10) + ind;
}
typedef std::pair<int, std::pair<string, string> > ROUTE_TRIPLE;
struct RoutingConfiguration {
// 0 index in triple
MAP_STR_FLOAT highwaySpeed ;
// 1 index in triple
MAP_STR_FLOAT highwayPriorities ;
// 2 index in triple
MAP_STR_FLOAT avoid ;
// 3 index in triple
MAP_STR_FLOAT obstacles;
// 4 index in triple
MAP_STR_FLOAT routingObstacles;
// 5 index in triple
MAP_STR_STR attributes;
int zoomToLoad;
float heurCoefficient;
float maxDefaultSpeed;
float minDefaultSpeed;
bool restrictions;
bool onewayAware;
bool followLimitations;
int memoryLimitation;
int planRoadDirection;
string routerName;
float initialDirection;
string routerProfile;
float roundaboutTurn;
float leftTurn;
float rightTurn;
float parseFloat(string key, float def) {
if(attributes.find(key) != attributes.end() && attributes[key] != "") {
return atof(attributes[key].c_str());
}
return def;
}
bool parseBool(string key, bool def) {
if (attributes.find(key) != attributes.end() && attributes[key] != "") {
return attributes[key] == "true";
}
return def;
}
string parseString(string key, string def) {
if (attributes.find(key) != attributes.end() && attributes[key] != "") {
return attributes[key];
}
return def;
}
void defaultParams() {
planRoadDirection = (int) parseFloat("planRoadDirection", 0);
restrictions = parseBool("restrictionsAware", true);
followLimitations = parseBool("followSpeedLimitations", true);
onewayAware = parseBool("onewayAware", true);
roundaboutTurn = parseFloat("roundaboutTurn", 0);
leftTurn = parseFloat("leftTurn", 0);
rightTurn = parseFloat("rightTurn", 0);
minDefaultSpeed = parseFloat("minDefaultSpeed", 45) / 3.6;
maxDefaultSpeed = parseFloat("maxDefaultSpeed", 130) / 3.6;
heurCoefficient = parseFloat("heuristicCoefficient", 1);
memoryLimitation = (int)parseFloat("memoryLimitInMB", memoryLimitation);
zoomToLoad = (int)parseFloat("zoomToLoadTiles", 16);
routerName = parseString("name", "default");
routerProfile = parseString("baseProfile", "car");
}
RoutingConfiguration(vector<ROUTE_TRIPLE>& config, int memLimit = 30, float initDirection = 0) :
memoryLimitation(memLimit), initialDirection(initDirection) {
for(int j = 0; j<config.size(); j++) {
ROUTE_TRIPLE r = config[j];
if(r.first == 0) {
highwaySpeed[r.second.first] = atof(r.second.second.c_str());
} else if(r.first == 1) {
highwayPriorities[r.second.first] = atof(r.second.second.c_str());
} else if(r.first == 2) {
avoid[r.second.first] = atof(r.second.second.c_str());
} else if(r.first == 3) {
obstacles[r.second.first] = atof(r.second.second.c_str());
} else if(r.first == 4) {
routingObstacles[r.second.first] = atof(r.second.second.c_str());
} else if(r.first == 5) {
string v = r.second.second;
attributes[r.second.first] = v;
}
}
defaultParams();
}
bool acceptLine(SHARED_PTR<RouteDataObject> r) {
std::vector<uint32_t>::iterator t = r->types.begin();
bool accepted = false;
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(type.first=="highway" && highwaySpeed[type.second] > 0) {
accepted = true;
break;
} else if(highwaySpeed[type.first + '$' + type.second] > 0) {
accepted = true;
break;
}
}
if(!accepted) {
return false;
}
t = r->types.begin();
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(avoid.find(type.first + '$' + type.second) != avoid.end()) {
return false;
}
}
return true;
}
string getHighway(SHARED_PTR<RouteDataObject> r) {
std::vector<uint32_t>::iterator t = r->types.begin();
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(type.first=="highway") {
return type.second;
}
}
return "";
}
float defineSpeedPriority(SHARED_PTR<RouteDataObject> r) {
float priority = 1;
std::vector<uint32_t>::iterator t = r->types.begin();
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(highwayPriorities.find(type.first+"$"+type.second) != highwaySpeed.end()) {
priority *= highwayPriorities[type.first+"$"+type.second];
}
}
return priority;
}
float getMinDefaultSpeed() {
return minDefaultSpeed;
}
float getMaxDefaultSpeed() {
return maxDefaultSpeed;
}
int isOneWay(SHARED_PTR<RouteDataObject> r) {
if(!onewayAware){
return 0;
}
std::vector<uint32_t>::iterator t = r->types.begin();
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(type.first == "oneway") {
string v = type.second;
if("-1" ==v || "reverse" == v) {
return -1;
} else if("1" == v || "yes" == v) {
return 1;
}
}
}
return 0;
}
// TODO
float calculateTurnTime(SHARED_PTR<RouteSegment> segment, int index, SHARED_PTR<RouteSegment> next, int nextIndex) {
return 0;
}
float defineRoutingObstacle(SHARED_PTR<RouteDataObject> road, int segmentEnd) {
if(road->pointTypes.size() <= segmentEnd) {
return 0;
}
std::vector<uint32_t> pointTypes = road->pointTypes[segmentEnd];
std::vector<uint32_t>::iterator t = pointTypes.begin();
for(; t != pointTypes.end(); t++) {
tag_value type = road->region->decodingRules[*t];
if(routingObstacles.find(type.first + "$" + type.second) != routingObstacles.end()) {
return routingObstacles[type.first + "$" + type.second];
}
}
t = pointTypes.begin();
for(; t != pointTypes.end(); t++) {
tag_value type = road->region->decodingRules[*t];
if(routingObstacles.find(type.first + "$" ) != routingObstacles.end()) {
return routingObstacles[type.first + "$" ];
}
}
return 0;
}
bool restrictionsAware() {
return restrictions;
}
float maxSpeed(SHARED_PTR<RouteDataObject> r) {
std::vector<uint32_t>::iterator t = r->types.begin();
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(type.first=="maxspeed") {
std::string v = type.second;
int i = 0;
while(i < v.length() && v[i] >= '0' && v[i] <= '9') {
i++;
}
if(i > 0) {
float f = atoi(v.substr(0, i).c_str());
f = f / 3.6;
if(v.find("mph") != std::string::npos ) {
f *= 1.6;
}
return f;
}
return 0;
}
}
return 0;
}
float defineSpeed(SHARED_PTR<RouteDataObject> r) {
if (followLimitations) {
float m = maxSpeed(r);
if(m > 0) {
return m;
}
}
std::vector<uint32_t>::iterator t = r->types.begin();
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(highwaySpeed.find(type.first+"$"+type.second) != highwaySpeed.end()) {
return highwaySpeed[type.first+"$"+type.second] / 3.6;
}
}
return getMinDefaultSpeed();
}
};
// FIXME configuration methods
struct RoutingContext {
int visitedSegments;
int loadedTiles;
@ -109,6 +347,7 @@ struct RoutingContext {
ElapsedTimer timeToCalculate;
int firstRoadDirection;
int64_t firstRoadId;
RoutingConfiguration config;
int startX;
int startY;
@ -122,25 +361,12 @@ struct RoutingContext {
UNORDERED(map)<int64_t, SHARED_PTR<RoutingSubregionTile> > subregionTiles;
UNORDERED(map)<int64_t, std::vector<SHARED_PTR<RoutingSubregionTile> > > indexedSubregions;
RoutingContext() : finalRouteSegment(), firstRoadDirection(0), loadedTiles(0), visitedSegments(0){
}
bool acceptLine(SHARED_PTR<RouteDataObject> r) {
string v = getHighway(r);
if(v != "" && v != "cycleway" && v != "footway" && v != "steps"){
return true;
}
return false;
RoutingContext(RoutingConfiguration& config) : finalRouteSegment(), firstRoadDirection(0), loadedTiles(0), visitedSegments(0),
config(config){
}
string getHighway(SHARED_PTR<RouteDataObject> r) {
std::vector<uint32_t>::iterator t = r->types.begin();
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(type.first=="highway") {
return type.second;
}
}
return "";
bool acceptLine(SHARED_PTR<RouteDataObject> r) {
return config.acceptLine(r);
}
void loadHeaderObjects(int64_t tileId) {
@ -167,7 +393,7 @@ struct RoutingContext {
void loadHeaders(uint32_t xloc, uint32_t yloc) {
timeToLoad.start();
int z = ZOOM_TO_LOAD_TILES;
int z = config.zoomToLoad;
int tz = 31 - z;
int64_t tileId = (xloc << z) + yloc;
if (indexedSubregions.find(tileId) == indexedSubregions.end()) {
@ -192,12 +418,12 @@ struct RoutingContext {
}
// FIXME
// FIXME replace with adequate method
SHARED_PTR<RouteSegment> loadSegmentAround(int x31, int y31) {
timeToLoad.start();
SHARED_PTR<RouteSegment> r;
float dist = -1;
int z = ZOOM_TO_LOAD_TILES;
int z = config.zoomToLoad;
uint32_t xloc = x31 >> (31 - z);
uint32_t yloc = y31 >> (31 - z);
uint64_t l = (((uint64_t) x31) << 31) + (uint64_t) y31;
@ -227,7 +453,7 @@ struct RoutingContext {
// void searchRouteRegion(SearchQuery* q, std::vector<RouteDataObject*>& list, RoutingIndex* rs, RouteSubregion* sub)
SHARED_PTR<RouteSegment> loadRouteSegment(int x31, int y31) {
int z = ZOOM_TO_LOAD_TILES;
int z = config.zoomToLoad;
int64_t xloc = x31 >> (31 - z);
int64_t yloc = y31 >> (31 - z);
uint64_t l = (((uint64_t) x31) << 31) + (uint64_t) y31;
@ -262,157 +488,16 @@ struct RoutingContext {
return false;
}
float getHeuristicCoefficient(){
return 1;
return config.heurCoefficient;
}
bool planRouteIn2Directions() {
return getPlanRoadDirection() == 0;
}
int getPlanRoadDirection() {
return 1;
return config.planRoadDirection;
}
float defineSpeedPriority(SHARED_PTR<RouteDataObject> r) {
string v = getHighway(r);
if(v == "") {
return 1;
} else if(v == "motorway") {
return 1.2;
} else if(v == "motorway_link") {
return 1.2;
} else if(v == "trunk") {
return 1.2;
} else if(v == "trunk_link") {
return 1.2;
} else if(v == "primary") {
return 1.1;
} else if(v == "primary_link") {
return 1.1;
} else if(v == "secondary") {
return 1.05;
} else if(v == "secondary_link") {
return 1.05;
} else if(v == "tertiary") {
return 1;
} else if(v == "tertiary_link") {
return 1;
} else if(v == "unclassified") {
return 0.7;
} else if(v == "road") {
return 0.7;
} else if(v == "service") {
return 0.5;
} else if(v == "track") {
return 0.3;
} else if(v == "residential") {
return 0.5;
} else if(v == "living_street") {
return 0.5;
}
return 1;
}
float maxSpeed(SHARED_PTR<RouteDataObject> r) {
std::vector<uint32_t>::iterator t = r->types.begin();
for(; t != r->types.end(); t++) {
tag_value type = r->region->decodingRules[*t];
if(type.first=="maxspeed") {
std::string v = type.second;
int i = 0;
while(i < v.length() && v[i] >= '0' && v[i] <= '9') {
i++;
}
if(i > 0) {
float f = atoi(v.substr(0, i).c_str());
f /= 3.6; // km/h -> m/s
if(v.find("mph") != std::string::npos ) {
f *= 1.6;
}
return f;
}
return 0;
}
}
return 0;
}
float defineSpeed(SHARED_PTR<RouteDataObject> r) {
float speed = maxSpeed(r);
if(speed > 0) {
return speed;
}
string v = getHighway(r);
if(v == "") {
} else if(v == "motorway") {
speed = 110;
} else if(v == "motorway_link") {
speed = 80;
} else if(v == "trunk") {
speed = 100;
} else if(v == "trunk_link") {
speed = 75;
} else if(v == "primary") {
speed = 65;
} else if(v == "primary_link") {
speed = 50;
} else if(v == "secondary") {
speed = 60;
} else if(v == "secondary_link") {
speed = 50;
} else if(v == "tertiary") {
speed = 45;
} else if(v == "tertiary_link") {
speed = 40;
} else if(v == "unclassified") {
speed = 35;
} else if(v == "road") {
speed = 35;
} else if(v == "service") {
speed = 30;
} else if(v == "track") {
speed = 15;
} else if(v == "residential") {
speed = 35;
} else if(v == "living_street") {
speed = 25;
}
return speed / 3.;
}
float getMinDefaultSpeed(){
return 40 / 3.6;
}
float getMaxDefaultSpeed(){
return 130 / 3.6;
}
int isOneWay(SHARED_PTR<RouteDataObject> r) {
std::vector<uint32_t>::iterator t = r->types.begin();
for(; t != r->types.end(); t++){
tag_value type = r->region->decodingRules[*t];
if(type.first == "oneway") {
string v = type.second;
if("-1" ==v || "reverse" == v) {
return -1;
} else if("1" == v || "yes" == v) {
return 1;
}
}
}
return 0;
}
float calculateTurnTime(SHARED_PTR<RouteSegment> segment, int index, SHARED_PTR<RouteSegment> next, int nextIndex){
return 0;
}
float defineRoutingObstacle(SHARED_PTR<RouteDataObject> road, int segmentEnd) {
return 0;
}
bool restrictionsAware(){
return true;
}
};

View file

@ -580,15 +580,33 @@ extern "C" JNIEXPORT void JNICALL Java_net_osmand_NativeLibrary_deleteRouteSearc
}
delete t;
}
extern "C" JNIEXPORT jobjectArray JNICALL Java_net_osmand_NativeLibrary_testRouting(JNIEnv* ienv,
jobject obj, jint sx31,
jint sy31, jint ex31, jint ey31) {
RoutingContext c;
c.startX = sx31;
c.startY = sy31;
c.endX = ex31;
c.endY = ey31;
//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) {
vector<ROUTE_TRIPLE> cfg;
int* data = ienv->GetIntArrayElements(stateConfig, NULL);
for(int k = 0; k < ienv->GetArrayLength(stateConfig); k++) {
ROUTE_TRIPLE t = ROUTE_TRIPLE (data[k], std::pair<string, string>(
getString(ienv, (jstring) ienv->GetObjectArrayElement(keyConfig, k)),
getString(ienv, (jstring) ienv->GetObjectArrayElement(valueConfig, k)))
);
cfg.push_back(t);
}
ienv->ReleaseIntArrayElements(stateConfig, data, 0);
RoutingConfiguration config(cfg);
RoutingContext c(config);
data = ienv->GetIntArrayElements(coordinates, NULL);
c.startX = data[0];
c.startY = data[1];
c.endX = data[2];
c.endY = data[3];
ienv->ReleaseIntArrayElements(coordinates, data, 0);
vector<RouteSegmentResult> r = searchRouteInternal(&c, false);
// 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);

View file

@ -160,11 +160,9 @@ void printFileInformation(const char* fileName, VerboseInfo* verbose) {
i, j++, rt->minZoom, rt->maxZoom, rt->length, ch);
}
if ((verbose != NULL && verbose->vmap)) {
// FIXME
//printMapDetailInfo(verbose, index);
}
} else if (it->type == TRANSPORT_INDEX) {
// FIXME
// TransportIndex ti = ((TransportIndex) p);
// int sh = (31 - BinaryMapIndexReader.TRANSPORT_STOP_ZOOM);
// println(