Introduce New routing config

This commit is contained in:
vshcherb 2014-02-02 14:06:09 +01:00
parent 311ec40157
commit db06f5ee00
12 changed files with 836 additions and 740 deletions

View file

@ -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);

View file

@ -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 {

View file

@ -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] ;
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}
}

View file

@ -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;

View file

@ -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 {

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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.
*/