Introduce New routing config
This commit is contained in:
parent
311ec40157
commit
db06f5ee00
12 changed files with 836 additions and 740 deletions
|
@ -136,11 +136,12 @@ public class NativeLibrary {
|
|||
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);
|
||||
// TODO
|
||||
// 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);
|
||||
|
|
|
@ -156,7 +156,7 @@ public class BinaryMapRouteReaderAdapter {
|
|||
int ch = c.indexOf('@');
|
||||
if (ch > 0) {
|
||||
RouteTypeCondition cond = new RouteTypeCondition();
|
||||
cond.floatValue = parseMaxSpeed(c.substring(0, ch));
|
||||
cond.floatValue = RouteDataObject.parseSpeed(c.substring(0, ch), 0);
|
||||
cond.condition = c.substring(ch + 1).trim();
|
||||
if (cond.condition.startsWith("(") && cond.condition.endsWith(")")) {
|
||||
cond.condition = cond.condition.substring(1, cond.condition.length() - 1).trim();
|
||||
|
@ -168,7 +168,7 @@ public class BinaryMapRouteReaderAdapter {
|
|||
type = MAXSPEED;
|
||||
} else if(t.equalsIgnoreCase("maxspeed") && v != null){
|
||||
type = MAXSPEED;
|
||||
floatValue = parseMaxSpeed(v);
|
||||
floatValue = RouteDataObject.parseSpeed(v, 0);
|
||||
} else if (t.equalsIgnoreCase("lanes") && v != null) {
|
||||
intValue = -1;
|
||||
int i = 0;
|
||||
|
@ -183,25 +183,7 @@ public class BinaryMapRouteReaderAdapter {
|
|||
|
||||
}
|
||||
|
||||
private float parseMaxSpeed(String v) {
|
||||
float floatValue = -1;
|
||||
if (v.equals("none")) {
|
||||
floatValue = RouteDataObject.NONE_MAX_SPEED;
|
||||
} else {
|
||||
int i = 0;
|
||||
while (i < v.length() && Character.isDigit(v.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
if (i > 0) {
|
||||
floatValue = Integer.parseInt(v.substring(0, i));
|
||||
floatValue /= 3.6; // km/h -> m/s
|
||||
if (v.contains("mph")) {
|
||||
floatValue *= 1.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
return floatValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class RouteRegion extends BinaryIndexPart {
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.text.MessageFormat;
|
|||
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
|
||||
import net.osmand.util.MapUtils;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
public class RouteDataObject {
|
||||
/*private */static final int RESTRICTION_SHIFT = 3;
|
||||
|
@ -160,6 +160,51 @@ public class RouteDataObject {
|
|||
return maxSpeed ;
|
||||
}
|
||||
|
||||
|
||||
public static float parseSpeed(String v, float def) {
|
||||
if(v.equals("none")) {
|
||||
return RouteDataObject.NONE_MAX_SPEED;
|
||||
} else {
|
||||
int i = Algorithms.findFirstNumberEndIndex(v);
|
||||
if (i > 0) {
|
||||
float f = Float.parseFloat(v.substring(0, i));
|
||||
f /= 3.6; // km/h -> m/s
|
||||
if (v.contains("mph")) {
|
||||
f *= 1.6;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public static float parseLength(String v, float def) {
|
||||
// 14"10' not supported
|
||||
int i = Algorithms.findFirstNumberEndIndex(v);
|
||||
if (i > 0) {
|
||||
float f = Float.parseFloat(v.substring(0, i));
|
||||
if (v.contains("\"") || v.contains("ft")) {
|
||||
// foot to meters
|
||||
f *= 0.3048;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public static float parseWeightInTon(String v, float def) {
|
||||
int i = Algorithms.findFirstNumberEndIndex(v);
|
||||
if (i > 0) {
|
||||
float f = Float.parseFloat(v.substring(0, i));
|
||||
if (v.contains("\"") || v.contains("lbs")) {
|
||||
// lbs -> kg -> ton
|
||||
f = (f * 0.4535f) / 1000f;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public boolean loop(){
|
||||
return pointsX[0] == pointsX[pointsX.length - 1] && pointsY[0] == pointsY[pointsY.length - 1] ;
|
||||
}
|
||||
|
|
|
@ -223,12 +223,16 @@ public class BinaryRoutePlanner {
|
|||
ctx.calculationProgress.reverseSegmentQueueSize = graphReverseSegments.size();
|
||||
ctx.calculationProgress.directSegmentQueueSize = graphDirectSegments.size();
|
||||
if(graphDirectSegments.size() > 0) {
|
||||
ctx.calculationProgress.distanceFromBegin =
|
||||
Math.max(graphDirectSegments.peek().distanceFromStart, ctx.calculationProgress.distanceFromBegin);
|
||||
RouteSegment peek = graphDirectSegments.peek();
|
||||
ctx.calculationProgress.distanceFromBegin = Math.max(peek.distanceFromStart,
|
||||
ctx.calculationProgress.distanceFromBegin);
|
||||
ctx.calculationProgress.directDistance = peek.distanceFromStart + peek.distanceToEnd;
|
||||
}
|
||||
if(graphReverseSegments.size() > 0) {
|
||||
ctx.calculationProgress.distanceFromEnd =
|
||||
Math.max(graphReverseSegments.peek().distanceFromStart, ctx.calculationProgress.distanceFromEnd);
|
||||
RouteSegment peek = graphReverseSegments.peek();
|
||||
ctx.calculationProgress.distanceFromEnd = Math.max(peek.distanceFromStart + peek.distanceToEnd,
|
||||
ctx.calculationProgress.distanceFromEnd);
|
||||
ctx.calculationProgress.reverseDistance = peek.distanceFromStart + peek.distanceToEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +443,7 @@ public class BinaryRoutePlanner {
|
|||
|
||||
private float calculateTimeWithObstacles(RoutingContext ctx, RouteDataObject road, float distOnRoadToPass, float obstaclesTime) {
|
||||
float priority = ctx.getRouter().defineSpeedPriority(road);
|
||||
float speed = (ctx.getRouter().defineSpeed(road) * priority);
|
||||
float speed = (ctx.getRouter().defineRoutingSpeed(road) * priority);
|
||||
if (speed == 0) {
|
||||
speed = (ctx.getRouter().getMinDefaultSpeed() * priority);
|
||||
}
|
||||
|
|
|
@ -378,7 +378,7 @@ public class BinaryRoutePlannerOld {
|
|||
// g(x) - calculate distance to that point and calculate time
|
||||
|
||||
float priority = ctx.getRouter().defineSpeedPriority(road);
|
||||
float speed = ctx.getRouter().defineSpeed(road) * priority;
|
||||
float speed = ctx.getRouter().defineRoutingSpeed(road) * priority;
|
||||
if (speed == 0) {
|
||||
speed = ctx.getRouter().getMinDefaultSpeed() * priority;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
|
||||
import net.osmand.binary.RouteDataObject;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
public class GeneralRouter extends VehicleRouter {
|
||||
public class GeneralRouter implements VehicleRouter {
|
||||
|
||||
private static final float CAR_SHORTEST_DEFAULT_SPEED = 45/3.6f;
|
||||
public static final String USE_SHORTEST_WAY = "short_way";
|
||||
public static final String AVOID_FERRIES = "avoid_ferries";
|
||||
public static final String AVOID_TOLL = "avoid_toll";
|
||||
|
@ -21,71 +29,109 @@ public class GeneralRouter extends VehicleRouter {
|
|||
public static final String AVOID_UNPAVED = "avoid_unpaved";
|
||||
public static final String PREFER_MOTORWAYS = "prefer_motorway";
|
||||
|
||||
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 final RouteAttributeContext[] objectAttributes;
|
||||
public final Map<String, String> attributes;
|
||||
private final Map<String, RoutingParameter> parameters;
|
||||
private final Map<String, Integer> universalRules;
|
||||
private final List<String> universalRulesById;
|
||||
private final Map<String, BitSet> tagRuleMask;
|
||||
private final ArrayList<Object> ruleToValue;
|
||||
private boolean shortestRoute;
|
||||
|
||||
private Map<RouteRegion, Map<Integer, Integer>> regionConvert = new LinkedHashMap<RouteRegion, Map<Integer,Integer>>();
|
||||
|
||||
private GeneralRouterProfile profile;
|
||||
|
||||
// cached values
|
||||
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 RouteDataObjectAttribute {
|
||||
ROAD_SPEED("speed"),
|
||||
ROAD_PRIORITIES("priority"),
|
||||
ACCESS("access"),
|
||||
OBSTACLES("obstacle_time"),
|
||||
ROUTING_OBSTACLES("obstacle"),
|
||||
ONEWAY("oneway");
|
||||
public final String nm;
|
||||
RouteDataObjectAttribute(String name) {
|
||||
nm = name;
|
||||
}
|
||||
|
||||
public static RouteDataObjectAttribute getValueOf(String s){
|
||||
for(RouteDataObjectAttribute a : RouteDataObjectAttribute.values()){
|
||||
if(a.nm.equals(s)){
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum GeneralRouterProfile {
|
||||
CAR,
|
||||
PEDESTRIAN,
|
||||
BICYCLE
|
||||
}
|
||||
|
||||
|
||||
public enum RoutingParameterType {
|
||||
NUMERIC,
|
||||
BOOLEAN,
|
||||
SYMBOLIC
|
||||
}
|
||||
|
||||
public GeneralRouter(GeneralRouterProfile profile, Map<String, String> attributes) {
|
||||
this.attributes = new LinkedHashMap<String, String>(attributes);
|
||||
this.profile = profile;
|
||||
highwaySpeed = new LinkedHashMap<String, Float>();
|
||||
highwayPriorities = new LinkedHashMap<String, Float>();
|
||||
avoid = new LinkedHashMap<String, Float>();
|
||||
obstacles = new LinkedHashMap<String, Float>();
|
||||
routingObstacles = new LinkedHashMap<String, Float>();
|
||||
this.attributes = new LinkedHashMap<String, String>();
|
||||
Iterator<Entry<String, String>> e = attributes.entrySet().iterator();
|
||||
while(e.hasNext()){
|
||||
Entry<String, String> next = e.next();
|
||||
addAttribute(next.getKey(), next.getValue());
|
||||
}
|
||||
objectAttributes = new RouteAttributeContext[RouteDataObjectAttribute.values().length];
|
||||
for (int i = 0; i < objectAttributes.length; i++) {
|
||||
objectAttributes[i] = new RouteAttributeContext();
|
||||
}
|
||||
universalRules = new LinkedHashMap<String, Integer>();
|
||||
universalRulesById = new ArrayList<String>();
|
||||
tagRuleMask = new LinkedHashMap<String, BitSet>();
|
||||
ruleToValue = new ArrayList<Object>();
|
||||
parameters = new LinkedHashMap<String, GeneralRouter.RoutingParameter>();
|
||||
}
|
||||
|
||||
public GeneralRouter(GeneralRouter pr, Map<String, String> attributes) {
|
||||
this.highwaySpeed = new LinkedHashMap<String, Float>(pr.highwaySpeed);
|
||||
this.highwayPriorities = new LinkedHashMap<String, Float>(pr.highwayPriorities);
|
||||
this.avoid = new LinkedHashMap<String, Float>(pr.avoid);
|
||||
this.obstacles = new LinkedHashMap<String, Float>(pr.obstacles);
|
||||
this.routingObstacles = new LinkedHashMap<String, Float>(pr.routingObstacles);
|
||||
public GeneralRouter(GeneralRouter parent, Map<String, String> params) {
|
||||
this.attributes = new LinkedHashMap<String, String>();
|
||||
this.profile = pr.profile;
|
||||
Iterator<Entry<String, String>> e = attributes.entrySet().iterator();
|
||||
while(e.hasNext()){
|
||||
Iterator<Entry<String, String>> e = parent.attributes.entrySet().iterator();
|
||||
while (e.hasNext()) {
|
||||
Entry<String, String> next = e.next();
|
||||
addAttribute(next.getKey(), next.getValue());
|
||||
}
|
||||
// do not copy, keep linked
|
||||
universalRules = parent.universalRules;
|
||||
universalRulesById = parent.universalRulesById;
|
||||
tagRuleMask = parent.tagRuleMask;
|
||||
ruleToValue = parent.ruleToValue;
|
||||
parameters = parent.parameters;
|
||||
|
||||
objectAttributes = new RouteAttributeContext[RouteDataObjectAttribute.values().length];
|
||||
for (int i = 0; i < objectAttributes.length; i++) {
|
||||
objectAttributes[i] = new RouteAttributeContext(parent.objectAttributes[i], params);
|
||||
}
|
||||
shortestRoute = params.containsKey(USE_SHORTEST_WAY) && parseSilentBoolean(params.get(USE_SHORTEST_WAY), false);
|
||||
if(shortestRoute) {
|
||||
maxDefaultSpeed = Math.min(CAR_SHORTEST_DEFAULT_SPEED, maxDefaultSpeed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
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")) {
|
||||
|
@ -98,43 +144,102 @@ public class GeneralRouter extends VehicleRouter {
|
|||
maxDefaultSpeed = parseSilentFloat(v, maxDefaultSpeed * 3.6f) / 3.6f;
|
||||
}
|
||||
}
|
||||
|
||||
public RouteAttributeContext getObjContext(RouteDataObjectAttribute a) {
|
||||
return objectAttributes[a.ordinal()];
|
||||
}
|
||||
|
||||
|
||||
public void registerBooleanParameter(String id, String name, String description) {
|
||||
RoutingParameter rp = new RoutingParameter();
|
||||
rp.name = name;
|
||||
rp.description = description;
|
||||
rp.id = id;
|
||||
rp.type = RoutingParameterType.BOOLEAN;
|
||||
parameters.put(rp.id, rp);
|
||||
|
||||
}
|
||||
|
||||
public void registerNumericParameter(String id, String name, String description, Double[] vls, String[] vlsDescriptions) {
|
||||
RoutingParameter rp = new RoutingParameter();
|
||||
rp.name = name;
|
||||
rp.description = description;
|
||||
rp.id = id;
|
||||
rp.possibleValues = vls;
|
||||
rp.possibleValueDescriptions = vlsDescriptions;
|
||||
rp.type = RoutingParameterType.NUMERIC;
|
||||
parameters.put(rp.id, rp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptLine(RouteDataObject way) {
|
||||
int[] types = way.getTypes();
|
||||
RouteRegion reg = way.region;
|
||||
return acceptLine(types, reg);
|
||||
int res = getObjContext(RouteDataObjectAttribute.ACCESS).evaluateInt(way, 0);
|
||||
return res >= 0;
|
||||
}
|
||||
|
||||
public boolean acceptLine(int[] types, RouteRegion reg) {
|
||||
if(!highwaySpeed.containsKey(RouteDataObject.getHighway(types, reg))) {
|
||||
boolean accepted = false;
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
RouteTypeRule r = reg.quickGetEncodingRule(types[i]);
|
||||
Float sp = highwaySpeed.get(r.getTag()+"$"+r.getValue());
|
||||
if(sp != null){
|
||||
if(sp > 0) {
|
||||
accepted = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!accepted) {
|
||||
return false;
|
||||
}
|
||||
private int registerTagValueAttribute(String tag, String value) {
|
||||
String key = tag +"$"+value;
|
||||
if(universalRules.containsKey(key)) {
|
||||
return universalRules.get(key);
|
||||
}
|
||||
|
||||
|
||||
for(int i=0; i<types.length; i++) {
|
||||
RouteTypeRule r = reg.quickGetEncodingRule(types[i]);
|
||||
String k = r.getTag() + "$" + r.getValue();
|
||||
if(avoid.containsKey(k)) {
|
||||
return false;
|
||||
}
|
||||
int id = universalRules.size();
|
||||
universalRulesById.add(key);
|
||||
universalRules.put(key, id);
|
||||
if(!tagRuleMask.containsKey(tag)) {
|
||||
tagRuleMask.put(tag, new BitSet());
|
||||
}
|
||||
return true;
|
||||
tagRuleMask.get(tag).set(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
private Object parseValue(String value, String type) {
|
||||
float vl = -1;
|
||||
value = value.trim();
|
||||
if("speed".equals(type)) {
|
||||
vl = RouteDataObject.parseSpeed(value, vl);
|
||||
} else if("weight".equals(type)) {
|
||||
vl = RouteDataObject.parseWeightInTon(value, vl);
|
||||
} else if("length".equals(type)) {
|
||||
vl = RouteDataObject.parseLength(value, vl);
|
||||
} else {
|
||||
int i = Algorithms.findFirstNumberEndIndex(value);
|
||||
if (i > 0) {
|
||||
// could be negative
|
||||
return Float.parseFloat(value.substring(0, i));
|
||||
}
|
||||
}
|
||||
if(vl == -1) {
|
||||
return null;
|
||||
}
|
||||
return vl;
|
||||
}
|
||||
|
||||
private Object parseValueFromTag(int id, String type) {
|
||||
while (ruleToValue.size() <= id) {
|
||||
ruleToValue.add(null);
|
||||
}
|
||||
Object res = ruleToValue.get(id);
|
||||
if (res == null) {
|
||||
String v = universalRulesById.get(id);
|
||||
String value = v.substring(v.indexOf('$') + 1);
|
||||
res = parseValue(value, type);
|
||||
if (res == null) {
|
||||
res = "";
|
||||
}
|
||||
ruleToValue.set(id, res);
|
||||
}
|
||||
if ("".equals(res)) {
|
||||
return null;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VehicleRouter build(Map<String, String> params) {
|
||||
return new GeneralRouter(this, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restrictionsAware() {
|
||||
return restrictionsAware;
|
||||
|
@ -143,21 +248,8 @@ public class GeneralRouter extends VehicleRouter {
|
|||
@Override
|
||||
public float defineObstacle(RouteDataObject road, int point) {
|
||||
int[] pointTypes = road.getPointTypes(point);
|
||||
if(pointTypes == null) {
|
||||
return 0;
|
||||
}
|
||||
RouteRegion reg = road.region;
|
||||
int sz = pointTypes.length;
|
||||
for(int i=0; i<sz; i++) {
|
||||
RouteTypeRule r = reg.quickGetEncodingRule(pointTypes[i]);
|
||||
Float v = obstacles.get(r.getTag() + "$" + r.getValue());
|
||||
if(v != null ){
|
||||
return v;
|
||||
}
|
||||
v = obstacles.get(r.getTag() + "$");
|
||||
if(v != null ){
|
||||
return v;
|
||||
}
|
||||
if(pointTypes != null) {
|
||||
return getObjContext(RouteDataObjectAttribute.OBSTACLES).evaluateFloat(road.region, pointTypes, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -165,90 +257,30 @@ public class GeneralRouter extends VehicleRouter {
|
|||
@Override
|
||||
public float defineRoutingObstacle(RouteDataObject road, int point) {
|
||||
int[] pointTypes = road.getPointTypes(point);
|
||||
if(pointTypes == null) {
|
||||
return 0;
|
||||
}
|
||||
RouteRegion reg = road.region;
|
||||
int sz = pointTypes.length;
|
||||
for(int i=0; i<sz; i++) {
|
||||
RouteTypeRule r = reg.quickGetEncodingRule(pointTypes[i]);
|
||||
Float v = routingObstacles.get(r.getTag() + "$" + r.getValue());
|
||||
if(v != null ){
|
||||
return v;
|
||||
}
|
||||
v = routingObstacles.get(r.getTag() + "$");
|
||||
if(v != null ){
|
||||
return v;
|
||||
}
|
||||
if(pointTypes != null){
|
||||
return getObjContext(RouteDataObjectAttribute.ROUTING_OBSTACLES).evaluateFloat(road.region, pointTypes, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isOnewayAware() {
|
||||
return onewayAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isOneWay(RouteDataObject road) {
|
||||
if (!isOnewayAware()) {
|
||||
return 0;
|
||||
}
|
||||
return road.getOneway();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean isFollowSpeedLimitations(){
|
||||
return followSpeedLimitations;
|
||||
}
|
||||
|
||||
private static boolean parseSilentBoolean(String t, boolean v) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Boolean.parseBoolean(t);
|
||||
}
|
||||
|
||||
private static float parseSilentFloat(String t, float v) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Float.parseFloat(t);
|
||||
return getObjContext(RouteDataObjectAttribute.ONEWAY).evaluateInt(road, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float defineSpeed(RouteDataObject road) {
|
||||
if (isFollowSpeedLimitations()) {
|
||||
float m = road.getMaximumSpeed();
|
||||
if(m > 0) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
Float value = null;
|
||||
for (int i = 0; i < road.types.length; i++) {
|
||||
RouteTypeRule r = road.region.quickGetEncodingRule(road.types[i]);
|
||||
if(highwaySpeed.containsKey(r.getTag()+"$"+r.getValue())){
|
||||
value = highwaySpeed.get(r.getTag()+"$"+r.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value == null) {
|
||||
return getMinDefaultSpeed();
|
||||
}
|
||||
return value / 3.6f;
|
||||
public float defineRoutingSpeed(RouteDataObject road) {
|
||||
return Math.min(defineVehicleSpeed(road), maxDefaultSpeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float defineVehicleSpeed(RouteDataObject road) {
|
||||
return getObjContext(RouteDataObjectAttribute.ROAD_SPEED) .evaluateFloat(road, getMinDefaultSpeed() * 3.6f) / 3.6f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float defineSpeedPriority(RouteDataObject road) {
|
||||
float priority = 1;
|
||||
for (int i = 0; i < road.types.length; i++) {
|
||||
RouteTypeRule r = road.region.quickGetEncodingRule(road.types[i]);
|
||||
if(highwayPriorities.containsKey(r.getTag()+"$"+r.getValue())){
|
||||
priority *= highwayPriorities.get(r.getTag()+"$"+r.getValue());
|
||||
}
|
||||
}
|
||||
return priority;
|
||||
return getObjContext(RouteDataObjectAttribute.ROAD_PRIORITIES).evaluateFloat(road, 1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -258,7 +290,7 @@ public class GeneralRouter extends VehicleRouter {
|
|||
|
||||
@Override
|
||||
public float getMaxDefaultSpeed() {
|
||||
return maxDefaultSpeed ;
|
||||
return maxDefaultSpeed;
|
||||
}
|
||||
|
||||
|
||||
|
@ -304,36 +336,7 @@ public class GeneralRouter extends VehicleRouter {
|
|||
return 0;
|
||||
}
|
||||
|
||||
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 +":")) {
|
||||
String tagName = s.substring((specializationTag +":").length());
|
||||
m.put(tagName, m.get(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneralRouter specifyParameter(String specializationTag) {
|
||||
Map<String, String> attrs = new LinkedHashMap<String, String>(attributes);
|
||||
for(String s : attributes.keySet()){
|
||||
if(s.startsWith(specializationTag +":")) {
|
||||
String tagName = s.substring((specializationTag +":").length());
|
||||
attrs.put(tagName, attributes.get(s));
|
||||
}
|
||||
}
|
||||
GeneralRouter gr = new GeneralRouter(this, attrs);
|
||||
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);
|
||||
|
@ -344,6 +347,431 @@ public class GeneralRouter extends VehicleRouter {
|
|||
return attributes.get(attribute);
|
||||
}
|
||||
|
||||
private static boolean parseSilentBoolean(String t, boolean v) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Boolean.parseBoolean(t);
|
||||
}
|
||||
|
||||
private static float parseSilentFloat(String t, float v) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Float.parseFloat(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class RoutingParameter {
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private RoutingParameterType type;
|
||||
private Object[] possibleValues;
|
||||
private String[] possibleValueDescriptions;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public RoutingParameterType getType() {
|
||||
return type;
|
||||
}
|
||||
public String[] getPossibleValueDescriptions() {
|
||||
return possibleValueDescriptions;
|
||||
}
|
||||
|
||||
public Object[] getPossibleValues() {
|
||||
return possibleValues;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class ParameterContext {
|
||||
private Map<String, String> vars;
|
||||
}
|
||||
|
||||
public class RouteAttributeContext {
|
||||
List<RouteAttributeEvalRule> rules = new ArrayList<RouteAttributeEvalRule>();
|
||||
ParameterContext paramContext = null;
|
||||
|
||||
public RouteAttributeContext(){
|
||||
}
|
||||
public RouteAttributeContext(RouteAttributeContext original, Map<String, String> params){
|
||||
if (params != null) {
|
||||
paramContext = new ParameterContext();
|
||||
paramContext.vars = params;
|
||||
}
|
||||
for(RouteAttributeEvalRule rt : original.rules){
|
||||
if(checkParameter(rt)){
|
||||
rules.add(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object evaluate(RouteDataObject ro) {
|
||||
return evaluate(convert(ro.region, ro.types));
|
||||
}
|
||||
|
||||
public void printRules(PrintStream out) {
|
||||
for(RouteAttributeEvalRule r : rules) {
|
||||
r.printRule(out);
|
||||
}
|
||||
}
|
||||
|
||||
public RouteAttributeEvalRule registerNewRule(String selectValue, String selectType) {
|
||||
RouteAttributeEvalRule ev = new RouteAttributeEvalRule();
|
||||
ev.registerSelectValue(selectValue, selectType);
|
||||
rules.add(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
public RouteAttributeEvalRule getLastRule() {
|
||||
return rules.get(rules.size() - 1);
|
||||
}
|
||||
|
||||
private Object evaluate(BitSet types) {
|
||||
for (int k = 0; k < rules.size(); k++) {
|
||||
RouteAttributeEvalRule r = rules.get(k);
|
||||
Object o = r.eval(types, paramContext);
|
||||
if (o != null) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean checkParameter(RouteAttributeEvalRule r) {
|
||||
if (paramContext != null && r.parameters.size() > 0) {
|
||||
for (String p : r.parameters) {
|
||||
boolean not = false;
|
||||
if (p.startsWith("-")) {
|
||||
not = true;
|
||||
p = p.substring(1);
|
||||
}
|
||||
boolean val = paramContext.vars.containsKey(p);
|
||||
if (not && val) {
|
||||
return false;
|
||||
} else if (!not && !val) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int evaluateInt(RouteDataObject ro, int defValue) {
|
||||
Object o = evaluate(ro);
|
||||
if(!(o instanceof Number)) {
|
||||
return defValue;
|
||||
}
|
||||
return ((Number)o).intValue();
|
||||
}
|
||||
|
||||
public int evaluateInt(RouteRegion region, int[] types, int defValue) {
|
||||
Object o = evaluate(convert(region, types));
|
||||
if(!(o instanceof Number)){
|
||||
return defValue;
|
||||
}
|
||||
return ((Number)o).intValue();
|
||||
}
|
||||
|
||||
public float evaluateFloat(RouteDataObject ro, float defValue) {
|
||||
Object o = evaluate(ro);
|
||||
if(!(o instanceof Number)) {
|
||||
return defValue;
|
||||
}
|
||||
return ((Number)o).floatValue();
|
||||
}
|
||||
|
||||
public float evaluateFloat(RouteRegion region, int[] types, float defValue) {
|
||||
Object o = evaluate(convert(region, types));
|
||||
if(!(o instanceof Number)) {
|
||||
return defValue;
|
||||
}
|
||||
return ((Number)o).floatValue();
|
||||
}
|
||||
|
||||
private BitSet convert(RouteRegion reg, int[] types) {
|
||||
BitSet b = new BitSet(universalRules.size());
|
||||
Map<Integer, Integer> map = regionConvert.get(reg);
|
||||
if(map == null){
|
||||
map = new HashMap<Integer, Integer>();
|
||||
regionConvert.put(reg, map);
|
||||
}
|
||||
for(int k = 0; k < types.length; k++) {
|
||||
Integer nid = map.get(types[k]);
|
||||
if(nid == null){
|
||||
RouteTypeRule r = reg.quickGetEncodingRule(types[k]);
|
||||
nid = registerTagValueAttribute(r.getTag(), r.getValue());
|
||||
map.put(types[k], nid);
|
||||
}
|
||||
b.set(nid);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
public class RouteAttributeExpression {
|
||||
public static final int LESS_EXPRESSION = 1;
|
||||
public static final int GREAT_EXPRESSION = 2;
|
||||
|
||||
public RouteAttributeExpression(String[] vs, String valueType, int expressionId) {
|
||||
this.expressionType = expressionId;
|
||||
this.values = vs;
|
||||
if (vs.length < 2) {
|
||||
throw new IllegalStateException("Expression should have at least 2 arguments");
|
||||
}
|
||||
this.cacheValues = new Number[vs.length];
|
||||
this.valueType = valueType;
|
||||
for (int i = 0; i < vs.length; i++) {
|
||||
if(!vs[i].startsWith("$") && !vs[i].startsWith(":")) {
|
||||
Object o = parseValue(vs[i], valueType);
|
||||
if (o instanceof Number) {
|
||||
cacheValues[i] = (Number) o;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String[] values;
|
||||
private int expressionType;
|
||||
private String valueType;
|
||||
private Number[] cacheValues;
|
||||
|
||||
public boolean matches(BitSet types, ParameterContext paramContext) {
|
||||
double f1 = calculateExprValue(0, types, paramContext);
|
||||
double f2 = calculateExprValue(1, types, paramContext);
|
||||
if(Double.isNaN(f1) ||Double.isNaN(f2)) {
|
||||
return false;
|
||||
}
|
||||
if (expressionType == LESS_EXPRESSION) {
|
||||
return f1 <= f2;
|
||||
} else if (expressionType == GREAT_EXPRESSION) {
|
||||
return f1 >= f2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private double calculateExprValue(int id, BitSet types, ParameterContext paramContext) {
|
||||
String value = values[id];
|
||||
Number cacheValue = cacheValues[id];
|
||||
if(cacheValue != null) {
|
||||
return cacheValue.doubleValue();
|
||||
}
|
||||
Object o = null;
|
||||
if (value instanceof String && value.toString().startsWith("$")) {
|
||||
BitSet mask = tagRuleMask.get(value.toString().substring(1));
|
||||
if (mask != null && mask.intersects(types)) {
|
||||
BitSet findBit = new BitSet(mask.size());
|
||||
findBit.or(mask);
|
||||
findBit.and(types);
|
||||
int v = findBit.nextSetBit(0);
|
||||
o = parseValueFromTag(v, valueType);
|
||||
}
|
||||
} else if (value instanceof String && value.toString().startsWith(":")) {
|
||||
String p = ((String) value).substring(1);
|
||||
if (paramContext != null && paramContext.vars.containsKey(p)) {
|
||||
o = parseValue(paramContext.vars.get(p), value);
|
||||
}
|
||||
}
|
||||
|
||||
if(o instanceof Number) {
|
||||
return ((Number)o).doubleValue();
|
||||
}
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class RouteAttributeEvalRule {
|
||||
protected List<String> parameters = new ArrayList<String>() ;
|
||||
protected Object selectValue = null;
|
||||
protected String selectType = null;
|
||||
protected BitSet filterTypes = new BitSet();
|
||||
protected BitSet filterNotTypes = new BitSet();
|
||||
protected BitSet evalFilterTypes = new BitSet();
|
||||
|
||||
protected Set<String> onlyTags = new LinkedHashSet<String>();
|
||||
protected Set<String> onlyNotTags = new LinkedHashSet<String>();
|
||||
protected List<RouteAttributeExpression> expressions = new ArrayList<RouteAttributeExpression>();
|
||||
|
||||
public void registerSelectValue(String value, String type) {
|
||||
if(value.startsWith(":") || value.startsWith("$")) {
|
||||
selectValue = value;
|
||||
} else {
|
||||
selectValue = parseValue(value, type);
|
||||
if(selectValue == null) {
|
||||
System.err.println("Routing.xml select value '" + value+"' was not registered");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void printRule(PrintStream out) {
|
||||
out.print(" Select " + selectValue + " if ");
|
||||
for(int k = 0; k < filterTypes.size(); k++) {
|
||||
if(filterTypes.get(k)) {
|
||||
String key = universalRulesById.get(k);
|
||||
out.print(key + " ");
|
||||
}
|
||||
}
|
||||
if(filterNotTypes.size() > 0) {
|
||||
out.print(" ifnot ");
|
||||
}
|
||||
for(int k = 0; k < filterNotTypes.size(); k++) {
|
||||
if(filterNotTypes.get(k)) {
|
||||
String key = universalRulesById.get(k);
|
||||
out.print(key + " ");
|
||||
}
|
||||
}
|
||||
for(int k = 0; k < parameters.size(); k++) {
|
||||
out.print(" param="+parameters.get(k));
|
||||
}
|
||||
if(onlyTags.size() > 0) {
|
||||
out.print(" match tag = " + onlyTags);
|
||||
}
|
||||
if(onlyNotTags.size() > 0) {
|
||||
out.print(" not match tag = " + onlyNotTags);
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
|
||||
public void registerAndTagValueCondition(String tag, String value, boolean not) {
|
||||
if(value == null) {
|
||||
if (not) {
|
||||
onlyNotTags.add(tag);
|
||||
} else {
|
||||
onlyTags.add(tag);
|
||||
}
|
||||
} else {
|
||||
int vtype = registerTagValueAttribute(tag, value);
|
||||
if(not) {
|
||||
filterNotTypes.set(vtype);
|
||||
} else {
|
||||
filterTypes.set(vtype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerLessCondition(String value1, String value2, String valueType) {
|
||||
expressions.add(new RouteAttributeExpression(new String[] { value1, value2 }, valueType,
|
||||
RouteAttributeExpression.LESS_EXPRESSION));
|
||||
}
|
||||
|
||||
public void registerGreatCondition(String value1, String value2, String valueType) {
|
||||
expressions.add(new RouteAttributeExpression(new String[] { value1, value2 }, valueType,
|
||||
RouteAttributeExpression.GREAT_EXPRESSION));
|
||||
}
|
||||
|
||||
public void registerAndParamCondition(String param, boolean not) {
|
||||
param = not ? "-" + param : param;
|
||||
parameters.add(param);
|
||||
}
|
||||
|
||||
public Object eval(BitSet types, ParameterContext paramContext) {
|
||||
if (matches(types, paramContext)) {
|
||||
return calcSelectValue(types, paramContext);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected Object calcSelectValue(BitSet types, ParameterContext paramContext) {
|
||||
if (selectValue instanceof String && selectValue.toString().startsWith("$")) {
|
||||
BitSet mask = tagRuleMask.get(selectValue.toString().substring(1));
|
||||
if (mask != null && mask.intersects(types)) {
|
||||
BitSet findBit = new BitSet(mask.size());
|
||||
findBit.or(mask);
|
||||
findBit.and(types);
|
||||
int value = findBit.nextSetBit(0);
|
||||
return parseValueFromTag(value, selectType);
|
||||
}
|
||||
} else if (selectValue instanceof String && selectValue.toString().startsWith(":")) {
|
||||
String p = ((String) selectValue).substring(1);
|
||||
if (paramContext != null && paramContext.vars.containsKey(p)) {
|
||||
selectValue = parseValue(paramContext.vars.get(p), selectType);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return selectValue;
|
||||
}
|
||||
|
||||
public boolean matches(BitSet types, ParameterContext paramContext) {
|
||||
if(!checkAllTypesShouldBePresent(types)) {
|
||||
return false;
|
||||
}
|
||||
if(!checkAllTypesShouldNotBePresent(types)) {
|
||||
return false;
|
||||
}
|
||||
if(!checkFreeTags(types)) {
|
||||
return false;
|
||||
}
|
||||
if(!checkNotFreeTags(types)) {
|
||||
return false;
|
||||
}
|
||||
if(!checkExpressions(types, paramContext)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkExpressions(BitSet types, ParameterContext paramContext) {
|
||||
for(RouteAttributeExpression e : expressions){
|
||||
if(!e.matches(types, paramContext)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkFreeTags(BitSet types) {
|
||||
for (String ts : onlyTags) {
|
||||
BitSet b = tagRuleMask.get(ts);
|
||||
if (b == null || !b.intersects(types)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkNotFreeTags(BitSet types) {
|
||||
for (String ts : onlyNotTags) {
|
||||
BitSet b = tagRuleMask.get(ts);
|
||||
if (b != null && b.intersects(types)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkAllTypesShouldNotBePresent(BitSet types) {
|
||||
if(filterNotTypes.intersects(types)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkAllTypesShouldBePresent(BitSet types) {
|
||||
// Bitset method subset is missing "filterTypes.isSubset(types)"
|
||||
// reset previous evaluation
|
||||
evalFilterTypes.or(filterTypes);
|
||||
// evaluate bit intersection and check if filterTypes contained as set in types
|
||||
evalFilterTypes.and(types);
|
||||
if(!evalFilterTypes.equals(filterTypes)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,414 +0,0 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import gnu.trove.list.array.TByteArrayList;
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
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.RouteTypeRule;
|
||||
import net.osmand.binary.RouteDataObject;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
public class NewGeneralRouter extends VehicleRouter {
|
||||
|
||||
public RouteAttributeContext roadSpeed ;
|
||||
public RouteAttributeContext roadPriorities ;
|
||||
public RouteAttributeContext access ;
|
||||
public RouteAttributeContext obstacles;
|
||||
public RouteAttributeContext routingObstacles;
|
||||
public RouteAttributeContext oneway;
|
||||
public Map<String, String> attributes;
|
||||
|
||||
private Map<String, RoutingParameter> parameters = new LinkedHashMap<String, RoutingParameter>();
|
||||
private Map<String, Integer> universalRules = new LinkedHashMap<String, Integer>();
|
||||
private Map<String, List<RouteEvaluationRule>> freeTagRules = new HashMap<String, List<RouteEvaluationRule>>();
|
||||
private Map<RouteRegion, Map<Integer, Integer>> regionConvert = new LinkedHashMap<RouteRegion, Map<Integer,Integer>>();
|
||||
|
||||
|
||||
private GeneralRouterProfile profile;
|
||||
|
||||
// cached values
|
||||
private boolean restrictionsAware = true;
|
||||
private float leftTurn;
|
||||
private float roundaboutTurn;
|
||||
private float rightTurn;
|
||||
private float minDefaultSpeed = 10;
|
||||
private float maxDefaultSpeed = 10;
|
||||
|
||||
public enum RoutingParameterType {
|
||||
NUMERIC,
|
||||
BOOLEAN,
|
||||
SYMBOLIC
|
||||
}
|
||||
public enum GeneralRouterProfile {
|
||||
CAR,
|
||||
PEDESTRIAN,
|
||||
BICYCLE
|
||||
}
|
||||
|
||||
public NewGeneralRouter(GeneralRouterProfile profile, Map<String, String> attributes) {
|
||||
this.attributes = new LinkedHashMap<String, String>();
|
||||
this.profile = profile;
|
||||
Iterator<Entry<String, String>> e = 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("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
|
||||
public boolean acceptLine(RouteDataObject way) {
|
||||
int[] utypes = convert(way.region, way.getTypes());
|
||||
int res = access.evaluateInt(utypes, 0);
|
||||
return res >= 0;
|
||||
}
|
||||
|
||||
private int[] convert(RouteRegion reg, int[] types) {
|
||||
int[] utypes = new int[types.length];
|
||||
Map<Integer, Integer> map = regionConvert.get(reg);
|
||||
if(map == null){
|
||||
map = new HashMap<Integer, Integer>();
|
||||
regionConvert.put(reg, map);
|
||||
}
|
||||
for(int k = 0; k < types.length; k++) {
|
||||
Integer nid = map.get(types[k]);
|
||||
if(nid == null){
|
||||
RouteTypeRule r = reg.quickGetEncodingRule(types[k]);
|
||||
nid = registerRule(r.getTag(), r.getValue());
|
||||
map.put(types[k], nid);
|
||||
}
|
||||
utypes[k] = nid;
|
||||
}
|
||||
Arrays.sort(utypes);
|
||||
return utypes;
|
||||
}
|
||||
|
||||
public int registerRule(String tag, String value) {
|
||||
String key = tag +"$"+value;
|
||||
if(universalRules.containsKey(key)) {
|
||||
return universalRules.get(key);
|
||||
}
|
||||
universalRules.put(key, universalRules.size());
|
||||
return universalRules.size() - 1;
|
||||
}
|
||||
|
||||
public void build(){
|
||||
freeTagRules.clear();
|
||||
|
||||
roadSpeed.newEvaluationContext();
|
||||
roadPriorities.newEvaluationContext();
|
||||
access.newEvaluationContext();
|
||||
obstacles.newEvaluationContext();
|
||||
routingObstacles.newEvaluationContext();
|
||||
oneway.newEvaluationContext();
|
||||
}
|
||||
|
||||
public void registerFreeTagRule(RouteEvaluationRule r, String tag) {
|
||||
if(!freeTagRules.containsKey(tag)) {
|
||||
freeTagRules.put(tag, new ArrayList<NewGeneralRouter.RouteEvaluationRule>());
|
||||
}
|
||||
freeTagRules.get(tag).add(r);
|
||||
Iterator<Entry<String, Integer>> it = universalRules.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<String, Integer> e = it.next();
|
||||
String key = e.getKey();
|
||||
if (key.startsWith(tag + "$")) {
|
||||
r.insertType(e.getValue(), false);
|
||||
}
|
||||
if (tag.startsWith("-") && universalRules.containsKey(tag.substring(1) + "$")) {
|
||||
r.insertType(e.getValue(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFreeTagRules() {
|
||||
|
||||
}
|
||||
|
||||
private void updateFreeTagRules(List<RouteEvaluationRule> flist, int value, boolean not) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restrictionsAware() {
|
||||
return restrictionsAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float defineObstacle(RouteDataObject road, int point) {
|
||||
int[] ts = road.getPointTypes(point);
|
||||
if(ts != null) {
|
||||
|
||||
}
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float defineRoutingObstacle(RouteDataObject road, int point) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isOneWay(RouteDataObject road) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
private static boolean parseSilentBoolean(String t, boolean v) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Boolean.parseBoolean(t);
|
||||
}
|
||||
|
||||
private static float parseSilentFloat(String t, float v) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Float.parseFloat(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float defineSpeed(RouteDataObject road) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float defineSpeedPriority(RouteDataObject road) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinDefaultSpeed() {
|
||||
return minDefaultSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxDefaultSpeed() {
|
||||
return maxDefaultSpeed ;
|
||||
}
|
||||
|
||||
|
||||
public double getLeftTurn() {
|
||||
return leftTurn;
|
||||
}
|
||||
|
||||
public double getRightTurn() {
|
||||
return rightTurn;
|
||||
}
|
||||
public double getRoundaboutTurn() {
|
||||
return roundaboutTurn;
|
||||
}
|
||||
@Override
|
||||
public double calculateTurnTime(RouteSegment segment, int segmentEnd, RouteSegment prev, int prevSegmentEnd) {
|
||||
int[] pt = prev.getRoad().getPointTypes(prevSegmentEnd);
|
||||
if(pt != null) {
|
||||
RouteRegion reg = prev.getRoad().region;
|
||||
for(int i=0; i<pt.length; i++) {
|
||||
RouteTypeRule r = reg.quickGetEncodingRule(pt[i]);
|
||||
if("highway".equals(r.getTag()) && "traffic_signals".equals(r.getValue())) {
|
||||
// traffic signals don't add turn info
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
double rt = getRoundaboutTurn();
|
||||
if(rt > 0 && !prev.getRoad().roundabout() && segment.getRoad().roundabout()) {
|
||||
return rt;
|
||||
}
|
||||
if (getLeftTurn() > 0 || getRightTurn() > 0) {
|
||||
double a1 = segment.getRoad().directionRoute(segment.getSegmentStart(), segment.getSegmentStart() < segmentEnd);
|
||||
double a2 = prev.getRoad().directionRoute(prevSegmentEnd, prevSegmentEnd < prev.getSegmentStart());
|
||||
double diff = Math.abs(MapUtils.alignAngleDifference(a1 - a2 - Math.PI));
|
||||
// more like UT
|
||||
if (diff > 2 * Math.PI / 3) {
|
||||
return getLeftTurn();
|
||||
} else if (diff > Math.PI / 2) {
|
||||
return getRightTurn();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NewGeneralRouter specifyParameter(String parameter) {
|
||||
// TODO
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAttribute(String attribute) {
|
||||
return attributes.containsKey(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttribute(String attribute) {
|
||||
return attributes.get(attribute);
|
||||
}
|
||||
|
||||
|
||||
public static class RoutingParameter {
|
||||
public String id;
|
||||
public String name;
|
||||
public String description;
|
||||
public RoutingParameterType type;
|
||||
public String[] possibleValues;
|
||||
public String[] possibleValueDescriptions;
|
||||
public Object value;
|
||||
}
|
||||
|
||||
private class RouteEvaluationRule {
|
||||
|
||||
private List<String> tag = new ArrayList<String>();
|
||||
private List<String> values = new ArrayList<String>();
|
||||
private List<String> parameters = new ArrayList<String>() ;
|
||||
|
||||
//// evaluation variables
|
||||
private boolean parameterValue = true;
|
||||
private TByteArrayList notType = new TByteArrayList();
|
||||
private TIntArrayList sortedTypeArrays = new TIntArrayList();
|
||||
|
||||
public void newEvaluationContext(){
|
||||
evaluateParameterExpr();
|
||||
sortedTypeArrays.clear();
|
||||
notType.clear();
|
||||
for(int i = 0; i<tag.size(); i++) {
|
||||
if(values.get(i) == null) {
|
||||
registerFreeTagRule(this, tag.get(i));
|
||||
} else {
|
||||
registerRule(tag.get(i), values.get(i));
|
||||
}
|
||||
}
|
||||
//FIXME check parameters!
|
||||
}
|
||||
|
||||
public void insertType(int t, boolean b) {
|
||||
int i = sortedTypeArrays.binarySearch(t);
|
||||
if (i < 0) {
|
||||
sortedTypeArrays.insert(-(i + 1), t);
|
||||
notType.insert(-(i + 1), (byte) (b ? 1 : -1));
|
||||
}
|
||||
}
|
||||
|
||||
private void evaluateParameterExpr() {
|
||||
parameterValue = true;
|
||||
Map<String, RoutingParameter> defParams = NewGeneralRouter.this.parameters;
|
||||
for(String p : parameters) {
|
||||
boolean not = false;
|
||||
if(p.startsWith("-")) {
|
||||
not = true;
|
||||
p = p.substring(1);
|
||||
}
|
||||
boolean val = false;
|
||||
if(defParams.containsKey(p)) {
|
||||
RoutingParameter t = defParams.get(p);
|
||||
val = t.type == RoutingParameterType.BOOLEAN && t.value != null && (Boolean) t.value;
|
||||
}
|
||||
if(not && val){
|
||||
parameterValue = false;
|
||||
break;
|
||||
} else if(!not && !val){
|
||||
parameterValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAlwaysFalse() {
|
||||
return !parameterValue;
|
||||
}
|
||||
|
||||
public boolean isAlwaysTrue() {
|
||||
return parameterValue && isConst();
|
||||
}
|
||||
|
||||
public boolean isConst(){
|
||||
return tag == null;
|
||||
}
|
||||
|
||||
public boolean matches(int[] types) {
|
||||
if(isAlwaysFalse()){
|
||||
return false;
|
||||
}
|
||||
// TODO <gt value1=":weight" value2="$maxweight"/>
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class RouteAttributeContext {
|
||||
List<RouteEvaluationRule> rules = new ArrayList<RouteEvaluationRule>();
|
||||
List<Object> values = new ArrayList<Object>();
|
||||
|
||||
public void newEvaluationContext(){
|
||||
for (int k = 0; k < rules.size(); k++) {
|
||||
rules.get(k).newEvaluationContext();
|
||||
}
|
||||
}
|
||||
|
||||
public Object evaluate(int[] types) {
|
||||
for (int k = 0; k < rules.size(); k++) {
|
||||
if(rules.get(k).matches(types)){
|
||||
return values.get(k);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int evaluateInt(int[] types, int defValue) {
|
||||
Object o = evaluate(types);
|
||||
if(o == null) {
|
||||
return defValue;
|
||||
}
|
||||
return ((Number)o).intValue();
|
||||
}
|
||||
|
||||
public float evaluateFloat(int[] types, float defValue) {
|
||||
Object o = evaluate(types);
|
||||
if(o == null) {
|
||||
return defValue;
|
||||
}
|
||||
return ((Float)o).intValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -4,9 +4,11 @@ public class RouteCalculationProgress {
|
|||
|
||||
public int segmentNotFound = -1;
|
||||
public float distanceFromBegin;
|
||||
public float directDistance;
|
||||
public int directSegmentQueueSize;
|
||||
public float distanceFromEnd;
|
||||
public int reverseSegmentQueueSize;
|
||||
public float reverseDistance;
|
||||
public float totalEstimatedDistance = 0;
|
||||
|
||||
public float routingCalculatedTime = 0;
|
||||
|
|
|
@ -44,7 +44,7 @@ public class RouteResultPreparation {
|
|||
RouteSegmentResult rr = result.get(i);
|
||||
RouteDataObject road = rr.getObject();
|
||||
double distOnRoadToPass = 0;
|
||||
double speed = ctx.getRouter().defineSpeed(road);
|
||||
double speed = ctx.getRouter().defineVehicleSpeed(road);
|
||||
if (speed == 0) {
|
||||
speed = ctx.getRouter().getMinDefaultSpeed();
|
||||
} else {
|
||||
|
|
|
@ -4,9 +4,12 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
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;
|
||||
|
@ -45,7 +48,7 @@ public class RoutingConfiguration {
|
|||
public static class Builder {
|
||||
// Design time storage
|
||||
private String defaultRouter = "";
|
||||
private Map<String, GeneralRouter> routers = new LinkedHashMap<String, GeneralRouter>();
|
||||
private Map<String, VehicleRouter> routers = new LinkedHashMap<String, VehicleRouter>();
|
||||
private Map<String, String> attributes = new LinkedHashMap<String, String>();
|
||||
|
||||
public RoutingConfiguration build(String router, int memoryLimitMB) {
|
||||
|
@ -63,9 +66,11 @@ public class RoutingConfiguration {
|
|||
if (routers.containsKey(router)) {
|
||||
i.router = routers.get(router);
|
||||
if (specialization != null) {
|
||||
Map<String, String> params = new LinkedHashMap<String, String>();
|
||||
for (String s : specialization) {
|
||||
i.router = i.router.specifyParameter(s);
|
||||
params.put(s, "true");
|
||||
}
|
||||
i.router = i.router.build(params);
|
||||
}
|
||||
i.routerName = router;
|
||||
}
|
||||
|
@ -90,9 +95,8 @@ public class RoutingConfiguration {
|
|||
}
|
||||
|
||||
private String getAttribute(VehicleRouter router, String propertyName) {
|
||||
String attr = router.getAttribute(propertyName);
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
if (router.containsAttribute(propertyName)) {
|
||||
return router.getAttribute(propertyName);
|
||||
}
|
||||
return attributes.get(propertyName);
|
||||
}
|
||||
|
@ -119,21 +123,11 @@ public class RoutingConfiguration {
|
|||
|
||||
public static RoutingConfiguration.Builder getDefault() {
|
||||
if (DEFAULT == null) {
|
||||
InputStream resourceAsStream = null;
|
||||
try {
|
||||
resourceAsStream = RoutingConfiguration.class.getResourceAsStream("routing.xml");
|
||||
DEFAULT = parseFromInputStream(resourceAsStream);
|
||||
DEFAULT = parseFromInputStream(RoutingConfiguration.class.getResourceAsStream("routing.xml"));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
} finally {
|
||||
if (resourceAsStream != null) {
|
||||
try {
|
||||
resourceAsStream.close();
|
||||
} catch (IOException ignore) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return DEFAULT;
|
||||
}
|
||||
|
@ -142,10 +136,10 @@ public class RoutingConfiguration {
|
|||
XmlPullParser parser = PlatformUtil.newXMLPullParser();
|
||||
final RoutingConfiguration.Builder config = new RoutingConfiguration.Builder();
|
||||
GeneralRouter currentRouter = null;
|
||||
String previousKey = null;
|
||||
String previousTag = null;
|
||||
int tok;
|
||||
RouteDataObjectAttribute currentAttribute = null;
|
||||
Stack<RoutingRule> rulesStck = new Stack<RoutingConfiguration.RoutingRule>();
|
||||
parser.setInput(is, "UTF-8");
|
||||
int tok;
|
||||
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
if (tok == XmlPullParser.START_TAG) {
|
||||
String name = parser.getName();
|
||||
|
@ -155,80 +149,111 @@ public class RoutingConfiguration {
|
|||
currentRouter = parseRoutingProfile(parser, config);
|
||||
} else if ("attribute".equals(name)) {
|
||||
parseAttribute(parser, config, currentRouter);
|
||||
previousKey = parser.getAttributeValue("", "name");
|
||||
previousTag = name;
|
||||
} else if ("specialization".equals(name)) {
|
||||
parseSpecialization(parser, currentRouter, previousKey, previousTag);
|
||||
} else if ("parameter".equals(name)) {
|
||||
parseRoutingParameter(parser, currentRouter);
|
||||
} else if ("point".equals(name) || "way".equals(name)) {
|
||||
String attribute = parser.getAttributeValue("", "attribute");
|
||||
currentAttribute = RouteDataObjectAttribute.getValueOf(attribute);
|
||||
} else {
|
||||
previousKey = parser.getAttributeValue("", "tag") + "$" + parser.getAttributeValue("", "value");
|
||||
previousTag = name;
|
||||
if (parseCurrentRule(parser, currentRouter, previousKey, name)) {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
parseRoutingRule(parser, currentRouter, currentAttribute, rulesStck);
|
||||
}
|
||||
} else if (tok == XmlPullParser.END_TAG) {
|
||||
String pname = parser.getName();
|
||||
if (checkTag(pname)) {
|
||||
rulesStck.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
private static boolean parseCurrentRule(XmlPullParser parser, GeneralRouter currentRouter, String key, String name) {
|
||||
if ("road".equals(name)) {
|
||||
currentRouter.highwayPriorities.put(key, parseSilentFloat(parser.getAttributeValue("", "priority"), 1));
|
||||
currentRouter.highwaySpeed.put(key, parseSilentFloat(parser.getAttributeValue("", "speed"), 10));
|
||||
return true;
|
||||
} else if ("obstacle".equals(name)) {
|
||||
float penalty = parseSilentFloat(parser.getAttributeValue("", "penalty"), 0);
|
||||
currentRouter.obstacles.put(key, penalty);
|
||||
float routingPenalty = parseSilentFloat(parser.getAttributeValue("", "routingPenalty"), penalty);
|
||||
currentRouter.routingObstacles.put(key, routingPenalty);
|
||||
return true;
|
||||
} else if ("avoid".equals(name)) {
|
||||
float priority = parseSilentFloat(parser.getAttributeValue("", "decreasedPriority"), 0);
|
||||
if (priority == 0) {
|
||||
currentRouter.avoid.put(key, priority);
|
||||
} else {
|
||||
currentRouter.highwayPriorities.put(key, priority);
|
||||
private static void parseRoutingParameter(XmlPullParser parser, GeneralRouter currentRouter) {
|
||||
String description = parser.getAttributeValue("", "description");
|
||||
String name = parser.getAttributeValue("", "name");
|
||||
String id = parser.getAttributeValue("", "id");
|
||||
String type = parser.getAttributeValue("", "type");
|
||||
if(type.equalsIgnoreCase("boolean")) {
|
||||
currentRouter.registerBooleanParameter(id, name, description);
|
||||
} else if(type.equalsIgnoreCase("numeric")) {
|
||||
String values = parser.getAttributeValue("", "values");
|
||||
String valueDescriptions = parser.getAttributeValue("", "valueDescriptions");
|
||||
String[] strValues = values.split(",");
|
||||
Double[] vls = new Double[strValues.length];
|
||||
for(int i =0; i< vls.length; i++) {
|
||||
vls[i] =Double.parseDouble(strValues[i].trim());
|
||||
}
|
||||
return true;
|
||||
currentRouter.registerNumericParameter(id, name, description, vls ,
|
||||
valueDescriptions.split(","));
|
||||
} else {
|
||||
return false;
|
||||
throw new UnsupportedOperationException("Unsupported routing parameter type - " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RoutingRule {
|
||||
String tagName;
|
||||
String t;
|
||||
String v;
|
||||
String param;
|
||||
String value1;
|
||||
String value2;
|
||||
String type;
|
||||
}
|
||||
|
||||
private static void parseRoutingRule(XmlPullParser parser, GeneralRouter currentRouter, RouteDataObjectAttribute attr,
|
||||
Stack<RoutingRule> stack) {
|
||||
String pname = parser.getName();
|
||||
if (checkTag(pname)) {
|
||||
if(attr == null){
|
||||
throw new NullPointerException("Select tag filter outside road attribute < " + pname + " > : "+parser.getLineNumber());
|
||||
}
|
||||
RoutingRule rr = new RoutingRule();
|
||||
rr.tagName = pname;
|
||||
rr.t = parser.getAttributeValue("", "t");
|
||||
rr.v = parser.getAttributeValue("", "v");
|
||||
rr.param = parser.getAttributeValue("", "param");
|
||||
rr.value1 = parser.getAttributeValue("", "value1");
|
||||
rr.value2 = parser.getAttributeValue("", "value2");
|
||||
rr.type = parser.getAttributeValue("", "type");
|
||||
|
||||
RouteAttributeContext ctx = currentRouter.getObjContext(attr);
|
||||
if("select".equals(rr.tagName)) {
|
||||
String val = parser.getAttributeValue("", "value");
|
||||
String type = parser.getAttributeValue("", "type");
|
||||
ctx.registerNewRule(val, type);
|
||||
addSubclause(rr, ctx);
|
||||
for (int i = 0; i < stack.size(); i++) {
|
||||
addSubclause(stack.get(i), ctx);
|
||||
}
|
||||
} else if(stack.size() > 0 && stack.peek().tagName.equals("select")) {
|
||||
addSubclause(rr, ctx);
|
||||
}
|
||||
stack.push(rr);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseSpecialization(XmlPullParser parser, GeneralRouter currentRouter, String previousKey, String previousTag) {
|
||||
String in = parser.getAttributeValue("","input");
|
||||
if (previousKey != null) {
|
||||
String k = in + ":" + previousKey;
|
||||
if (parser.getAttributeValue("","penalty") != null) {
|
||||
float penalty = parseSilentFloat(parser.getAttributeValue("","penalty"), 0);
|
||||
currentRouter.obstacles.put(k, penalty);
|
||||
float routingPenalty = parseSilentFloat(parser.getAttributeValue("","routingPenalty"), penalty );
|
||||
currentRouter.routingObstacles.put(k, routingPenalty);
|
||||
}
|
||||
if (parser.getAttributeValue("","priority") != null) {
|
||||
currentRouter.highwayPriorities.put(k, parseSilentFloat(parser.getAttributeValue("","priority"), 0));
|
||||
}
|
||||
if (parser.getAttributeValue("","speed") != null) {
|
||||
currentRouter.highwaySpeed.put(k, parseSilentFloat(parser.getAttributeValue("","speed"), 0));
|
||||
}
|
||||
if ("attribute".equals(previousTag)) {
|
||||
currentRouter.attributes.put(k, parser.getAttributeValue("","value"));
|
||||
}
|
||||
if ("avoid".equals(previousTag)) {
|
||||
float priority = parseSilentFloat(parser.getAttributeValue("","decreasedPriority"), 0);
|
||||
if (priority == 0) {
|
||||
currentRouter.avoid.put(k, priority);
|
||||
} else {
|
||||
currentRouter.highwayPriorities.put(k, priority);
|
||||
}
|
||||
}
|
||||
private static boolean checkTag(String pname) {
|
||||
return "select".equals(pname) || "if".equals(pname) || "ifnot".equals(pname)
|
||||
|| "ge".equals(pname) || "le".equals(pname);
|
||||
}
|
||||
|
||||
private static void addSubclause(RoutingRule rr, RouteAttributeContext ctx) {
|
||||
boolean not = "ifnot".equals(rr.tagName);
|
||||
if(!Algorithms.isEmpty(rr.param)) {
|
||||
ctx.getLastRule().registerAndParamCondition(rr.param, not);
|
||||
}
|
||||
if (!Algorithms.isEmpty(rr.t)) {
|
||||
ctx.getLastRule().registerAndTagValueCondition(rr.t, Algorithms.isEmpty(rr.v) ? null : rr.v, not);
|
||||
}
|
||||
if (rr.tagName.equals("ge")) {
|
||||
ctx.getLastRule().registerGreatCondition(rr.value1, rr.value2, rr.type);
|
||||
} else if (rr.tagName.equals("le")) {
|
||||
ctx.getLastRule().registerLessCondition(rr.value1, rr.value2, rr.type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static GeneralRouter parseRoutingProfile(XmlPullParser parser, final RoutingConfiguration.Builder config) {
|
||||
GeneralRouter currentRouter;
|
||||
String currentSelectedRouter = parser.getAttributeValue("", "name");
|
||||
Map<String, String> attrs = new LinkedHashMap<String, String>();
|
||||
for(int i=0; i< parser.getAttributeCount(); i++) {
|
||||
|
@ -236,7 +261,7 @@ public class RoutingConfiguration {
|
|||
}
|
||||
GeneralRouterProfile c = Algorithms.parseEnumValue(GeneralRouterProfile.values(),
|
||||
parser.getAttributeValue("", "baseProfile"), GeneralRouterProfile.CAR);
|
||||
currentRouter = new GeneralRouter(c, attrs);
|
||||
GeneralRouter currentRouter = new GeneralRouter(c, attrs);
|
||||
config.routers.put(currentSelectedRouter, currentRouter);
|
||||
return currentRouter;
|
||||
}
|
||||
|
|
|
@ -1,68 +1,77 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.osmand.binary.RouteDataObject;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
||||
|
||||
public abstract class VehicleRouter {
|
||||
public interface VehicleRouter {
|
||||
|
||||
/**
|
||||
* Accepts line to use it for routing
|
||||
*
|
||||
* @param way
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean acceptLine(RouteDataObject way);
|
||||
|
||||
public abstract boolean restrictionsAware();
|
||||
|
||||
public abstract int isOneWay(RouteDataObject road);
|
||||
|
||||
public abstract boolean containsAttribute(String attribute);
|
||||
|
||||
public abstract String getAttribute(String attribute);
|
||||
public boolean containsAttribute(String attribute);
|
||||
|
||||
public String getAttribute(String attribute);
|
||||
|
||||
/**
|
||||
* return delay in seconds
|
||||
* return if the road is accepted for routing
|
||||
*/
|
||||
public float defineObstacle(RouteDataObject road, int point) {
|
||||
// no obstacles
|
||||
return 0;
|
||||
}
|
||||
public boolean acceptLine(RouteDataObject way);
|
||||
|
||||
public float defineRoutingObstacle(RouteDataObject road, int point) {
|
||||
// no obstacles
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* return oneway +/- 1 if it is oneway and 0 if both ways
|
||||
*/
|
||||
public int isOneWay(RouteDataObject road);
|
||||
|
||||
/**
|
||||
* return delay in seconds (0 no obstacles)
|
||||
*/
|
||||
public float defineObstacle(RouteDataObject road, int point);
|
||||
|
||||
/**
|
||||
* return delay in seconds (0 no obstacles)
|
||||
*/
|
||||
public float defineRoutingObstacle(RouteDataObject road, int point);
|
||||
|
||||
/**
|
||||
* return speed in m/s for vehicle for specified road
|
||||
* return routing speed in m/s for vehicle for specified road
|
||||
*/
|
||||
public abstract float defineSpeed(RouteDataObject road);
|
||||
public float defineRoutingSpeed(RouteDataObject road);
|
||||
|
||||
/**
|
||||
* return real speed in m/s for vehicle for specified road
|
||||
*/
|
||||
public float defineVehicleSpeed(RouteDataObject road);
|
||||
|
||||
/**
|
||||
* define priority to multiply the speed for g(x) A*
|
||||
*/
|
||||
public abstract float defineSpeedPriority(RouteDataObject road);
|
||||
public float defineSpeedPriority(RouteDataObject road);
|
||||
|
||||
/**
|
||||
* Used for A* routing to calculate g(x)
|
||||
*
|
||||
* @return minimal speed at road in m/s
|
||||
*/
|
||||
public abstract float getMinDefaultSpeed();
|
||||
public float getMinDefaultSpeed();
|
||||
|
||||
/**
|
||||
* Used for A* routing to predict h(x) : it should be great any g(x)
|
||||
*
|
||||
* @return maximum speed to calculate shortest distance
|
||||
*/
|
||||
public abstract float getMaxDefaultSpeed();
|
||||
public float getMaxDefaultSpeed();
|
||||
|
||||
/**
|
||||
* aware of road restrictions
|
||||
*/
|
||||
public boolean restrictionsAware();
|
||||
|
||||
public abstract VehicleRouter specifyParameter(String tag);
|
||||
|
||||
/**
|
||||
* Calculate turn time
|
||||
*/
|
||||
public abstract double calculateTurnTime(RouteSegment segment, int segmentEnd, RouteSegment prev, int prevSegmentEnd) ;
|
||||
public double calculateTurnTime(RouteSegment segment, int segmentEnd, RouteSegment prev, int prevSegmentEnd);
|
||||
|
||||
|
||||
public VehicleRouter build(Map<String, String> params);
|
||||
|
||||
}
|
|
@ -8,9 +8,6 @@ import java.io.FileInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
|
||||
|
@ -28,6 +25,23 @@ public class Algorithms {
|
|||
return s == null || s.length() == 0;
|
||||
}
|
||||
|
||||
public static int findFirstNumberEndIndex(String value) {
|
||||
int i = 0;
|
||||
boolean valid = false;
|
||||
if (value.length() > 0 && value.charAt(0) == '-') {
|
||||
i++;
|
||||
}
|
||||
while (i < value.length() && (Character.isDigit(value.charAt(i)) || value.charAt(i) == '.')) {
|
||||
i++;
|
||||
valid = true;
|
||||
}
|
||||
if (valid) {
|
||||
return i;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a file is a ZIP File.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue