package net.osmand.router; import java.io.IOException; import java.io.InputStream; import java.util.LinkedHashMap; import java.util.Map; import net.osmand.PlatformUtil; import net.osmand.router.GeneralRouter.GeneralRouterProfile; import net.osmand.util.Algorithms; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; public class RoutingConfiguration { public static final int DEFAULT_MEMORY_LIMIT = 30; public final float DEVIATION_RADIUS = 5000; public Map attributes = new LinkedHashMap(); // 1. parameters of routing and different tweaks // Influence on A* : f(x) + heuristicCoefficient*g(X) public float heuristicCoefficient = 1; // 1.1 tile load parameters (should not affect routing) public int ZOOM_TO_LOAD_TILES = 16; public int memoryLimitation; // 1.2 Build A* graph in backward/forward direction (can affect results) // 0 - 2 ways, 1 - direct way, -1 - reverse way public int planRoadDirection = 0; // 1.3 Router specific coefficients and restrictions public VehicleRouter router = new GeneralRouter(GeneralRouterProfile.CAR, new LinkedHashMap()); public String routerName = ""; // 1.4 Used to calculate route in movement public Double initialDirection; // 1.5 Recalculate distance help public float recalculateDistance = 10000f; public static class Builder { // Design time storage private String defaultRouter = ""; private Map routers = new LinkedHashMap(); private Map attributes = new LinkedHashMap(); public RoutingConfiguration build(String router, int memoryLimitMB) { return build(router, null, memoryLimitMB, new String[0]); } public RoutingConfiguration build(String router, int memoryLimitMB, String[] specialization) { return build(router, null, memoryLimitMB, specialization); } public RoutingConfiguration build(String router, Double direction, int memoryLimitMB, String[] specialization) { if (!routers.containsKey(router)) { router = defaultRouter; } RoutingConfiguration i = new RoutingConfiguration(); if (routers.containsKey(router)) { i.router = routers.get(router); if (specialization != null) { for (String s : specialization) { i.router = i.router.specifyParameter(s); } } i.routerName = router; } attributes.put("routerName", router); i.attributes.putAll(attributes); i.initialDirection = direction; i.recalculateDistance = parseSilentFloat(getAttribute(i.router, "recalculateDistanceHelp"), i.recalculateDistance) ; i.heuristicCoefficient = parseSilentFloat(getAttribute(i.router, "heuristicCoefficient"), i.heuristicCoefficient); i.ZOOM_TO_LOAD_TILES = parseSilentInt(getAttribute(i.router, "zoomToLoadTiles"), i.ZOOM_TO_LOAD_TILES); int desirable = parseSilentInt(getAttribute(i.router, "memoryLimitInMB"), 0); if(desirable != 0) { i.memoryLimitation = desirable * (1 << 20); } else { if(memoryLimitMB == 0) { memoryLimitMB = DEFAULT_MEMORY_LIMIT; } i.memoryLimitation = memoryLimitMB * (1 << 20); } i.planRoadDirection = parseSilentInt(getAttribute(i.router, "planRoadDirection"), i.planRoadDirection); return i; } private String getAttribute(VehicleRouter router, String propertyName) { String attr = router.getAttribute(propertyName); if (attr != null) { return attr; } return attributes.get(propertyName); } } private static int parseSilentInt(String t, int v) { if (t == null || t.length() == 0) { return v; } return Integer.parseInt(t); } private static float parseSilentFloat(String t, float v) { if (t == null || t.length() == 0) { return v; } return Float.parseFloat(t); } private static RoutingConfiguration.Builder DEFAULT; public static RoutingConfiguration.Builder getDefault() { if (DEFAULT == null) { InputStream resourceAsStream = null; try { resourceAsStream = RoutingConfiguration.class.getResourceAsStream("routing.xml"); DEFAULT = parseFromInputStream(resourceAsStream); } catch (Exception e) { throw new IllegalStateException(e); } finally { if (resourceAsStream != null) { try { resourceAsStream.close(); } catch (IOException ignore) { // } } } } return DEFAULT; } public static RoutingConfiguration.Builder parseFromInputStream(InputStream is) throws IOException, XmlPullParserException { XmlPullParser parser = PlatformUtil.newXMLPullParser(); final RoutingConfiguration.Builder config = new RoutingConfiguration.Builder(); GeneralRouter currentRouter = null; String previousKey = null; String previousTag = null; int tok; parser.setInput(is, "UTF-8"); while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) { if (tok == XmlPullParser.START_TAG) { String name = parser.getName(); if ("osmand_routing_config".equals(name)) { config.defaultRouter = parser.getAttributeValue("", "defaultProfile"); } else if ("routingProfile".equals(name)) { 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 { previousKey = parser.getAttributeValue("", "tag") + "$" + parser.getAttributeValue("", "value"); previousTag = name; if (parseCurrentRule(parser, currentRouter, previousKey, name)) { } else { } } } } 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); } return true; } else { return false; } } 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 GeneralRouter parseRoutingProfile(XmlPullParser parser, final RoutingConfiguration.Builder config) { GeneralRouter currentRouter; String currentSelectedRouter = parser.getAttributeValue("", "name"); Map attrs = new LinkedHashMap(); for(int i=0; i< parser.getAttributeCount(); i++) { attrs.put(parser.getAttributeName(i), parser.getAttributeValue(i)); } GeneralRouterProfile c = Algorithms.parseEnumValue(GeneralRouterProfile.values(), parser.getAttributeValue("", "baseProfile"), GeneralRouterProfile.CAR); currentRouter = new GeneralRouter(c, attrs); config.routers.put(currentSelectedRouter, currentRouter); return currentRouter; } private static void parseAttribute(XmlPullParser parser, final RoutingConfiguration.Builder config, GeneralRouter currentRouter) { if(currentRouter != null) { currentRouter.addAttribute(parser.getAttributeValue("", "name"), parser.getAttributeValue("", "value")); } else { config.attributes.put(parser.getAttributeValue("", "name"), parser.getAttributeValue("", "value")); } } }