Introduce specialization technique for routing. Support avoid features and short way feature
This commit is contained in:
parent
e7c60a2a7b
commit
7a715eb931
9 changed files with 119 additions and 35 deletions
|
@ -159,7 +159,7 @@ public class RouterTestsSuite {
|
|||
System.err.println("\n\n!! Skipped test case '" + testDescription + "' because 'best_percent' attribute is not specified \n\n" );
|
||||
return;
|
||||
}
|
||||
RoutingContext ctx = new RoutingContext(config.build(vehicle, true));
|
||||
RoutingContext ctx = new RoutingContext(config.build(vehicle));
|
||||
String skip = testCase.getAttribute("skip_comment");
|
||||
if (skip != null && skip.length() > 0) {
|
||||
System.err.println("\n\n!! Skipped test case '" + testDescription + "' because '" + skip + "'\n\n" );
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -11,6 +12,9 @@ import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
|||
|
||||
public class GeneralRouter extends VehicleRouter {
|
||||
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";
|
||||
public static final String AVOID_UNPAVED = "avoid_unpaved";
|
||||
|
||||
Map<String, Double> highwaySpeed ;
|
||||
Map<String, Double> highwayPriorities ;
|
||||
|
@ -266,12 +270,27 @@ public class GeneralRouter extends VehicleRouter {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void specialize(String specializationTag, Map<String, Double> m){
|
||||
ArrayList<String> ks = new ArrayList<String>(m.keySet());
|
||||
for(String s : ks){
|
||||
if(s.startsWith(specializationTag +":")) {
|
||||
m.put(s.substring((specializationTag +":").length()), m.get(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneralRouter specialization(String specializationTag) {
|
||||
GeneralRouter gr = new GeneralRouter(this);
|
||||
gr.specialize(specializationTag, gr.highwayFuturePriorities);
|
||||
gr.specialize(specializationTag, gr.highwayPriorities);
|
||||
gr.specialize(specializationTag, gr.highwaySpeed);
|
||||
gr.specialize(specializationTag, gr.avoid);
|
||||
gr.specialize(specializationTag, gr.obstacles);
|
||||
return gr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -53,10 +53,10 @@ public class RoutingConfiguration {
|
|||
private Map<String, GeneralRouter> routers = new LinkedHashMap<String, GeneralRouter>();
|
||||
private Map<String, String> attributes = new LinkedHashMap<String, String>();
|
||||
|
||||
public RoutingConfiguration build(String router, boolean useShortestWay) {
|
||||
return build(router, useShortestWay, null);
|
||||
public RoutingConfiguration build(String router, String... specialization) {
|
||||
return build(router, null, specialization);
|
||||
}
|
||||
public RoutingConfiguration build(String router, boolean useShortestWay, Double direction) {
|
||||
public RoutingConfiguration build(String router, Double direction, String... specialization) {
|
||||
if (!routers.containsKey(router)) {
|
||||
router = defaultRouter;
|
||||
}
|
||||
|
@ -79,8 +79,10 @@ public class RoutingConfiguration {
|
|||
return i;
|
||||
}
|
||||
i.router = routers.get(router);
|
||||
if(useShortestWay) {
|
||||
i.router = i.router.specialization(GeneralRouter.USE_SHORTEST_WAY);
|
||||
if(specialization != null) {
|
||||
for(String s : specialization) {
|
||||
i.router = i.router.specialization(s);
|
||||
}
|
||||
}
|
||||
i.routerName = router;
|
||||
return i;
|
||||
|
@ -138,17 +140,20 @@ public class RoutingConfiguration {
|
|||
DefaultHandler handler = new DefaultHandler() {
|
||||
String currentSelectedRouter = null;
|
||||
GeneralRouter currentRouter = null;
|
||||
String previousKey = null;
|
||||
String previousTag = null;
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
String name = parser.isNamespaceAware() ? localName : qName;
|
||||
if("osmand_routing_config".equals(name)) {
|
||||
config.defaultRouter = attributes.getValue("defaultProfile");
|
||||
} else if("attribute".equals(name)) {
|
||||
String key = attributes.getValue("name");
|
||||
if(currentSelectedRouter != null) {
|
||||
key = currentSelectedRouter +"$"+key;
|
||||
previousKey = attributes.getValue("name");
|
||||
previousTag = name;
|
||||
if (currentSelectedRouter != null) {
|
||||
previousKey = currentSelectedRouter + "$" + previousKey;
|
||||
}
|
||||
config.attributes.put(key, attributes.getValue("value"));
|
||||
config.attributes.put(previousKey, attributes.getValue("value"));
|
||||
} else if("routingProfile".equals(name)) {
|
||||
currentSelectedRouter = attributes.getValue("name");
|
||||
Map<String, String> attrs = new LinkedHashMap<String, String>();
|
||||
|
@ -157,26 +162,55 @@ public class RoutingConfiguration {
|
|||
}
|
||||
currentRouter = new GeneralRouter(GeneralRouterProfile.valueOf(attributes.getValue("baseProfile").toUpperCase()), attrs);
|
||||
config.routers.put(currentSelectedRouter, currentRouter);
|
||||
} else if ("specialization".equals(name)) {
|
||||
String in = attributes.getValue("input");
|
||||
if (previousKey != null) {
|
||||
String k = in + ":" + previousKey;
|
||||
if (attributes.getValue("penalty") != null) {
|
||||
currentRouter.obstacles.put(k, parseSilentDouble(attributes.getValue("penalty"), 0));
|
||||
}
|
||||
if (attributes.getValue("priority") != null) {
|
||||
currentRouter.highwayPriorities.put(k, parseSilentDouble(attributes.getValue("priority"), 0));
|
||||
}
|
||||
if (attributes.getValue("dynamicPriority") != null) {
|
||||
currentRouter.highwayFuturePriorities.put(k, parseSilentDouble(attributes.getValue("dynamicPriority"), 0));
|
||||
}
|
||||
if (attributes.getValue("speed") != null) {
|
||||
currentRouter.highwaySpeed.put(k, parseSilentDouble(attributes.getValue("speed"), 0));
|
||||
}
|
||||
if ("avoid".equals(previousTag)) {
|
||||
double priority = parseSilentDouble(attributes.getValue("decreasedPriority"), 0);
|
||||
if (priority == 0) {
|
||||
currentRouter.avoid.put(k, priority);
|
||||
} else {
|
||||
currentRouter.highwayPriorities.put(k, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if("road".equals(name)) {
|
||||
String key = attributes.getValue("tag") +"$" + attributes.getValue("value");
|
||||
currentRouter.highwayPriorities.put(key, parseSilentDouble(attributes.getValue("priority"),
|
||||
previousTag = name;
|
||||
previousKey = attributes.getValue("tag") +"$" + attributes.getValue("value");
|
||||
currentRouter.highwayPriorities.put(previousKey, parseSilentDouble(attributes.getValue("priority"),
|
||||
1));
|
||||
currentRouter.highwayFuturePriorities.put(key, parseSilentDouble(attributes.getValue("dynamicPriority"),
|
||||
currentRouter.highwayFuturePriorities.put(previousKey, parseSilentDouble(attributes.getValue("dynamicPriority"),
|
||||
1));
|
||||
currentRouter.highwaySpeed.put(key, parseSilentDouble(attributes.getValue("speed"),
|
||||
currentRouter.highwaySpeed.put(previousKey, parseSilentDouble(attributes.getValue("speed"),
|
||||
10));
|
||||
} else if("obstacle".equals(name)) {
|
||||
String key = attributes.getValue("tag") + "$" + attributes.getValue("value");
|
||||
currentRouter.obstacles.put(key, parseSilentDouble(attributes.getValue("penalty"),
|
||||
previousTag = name;
|
||||
previousKey = attributes.getValue("tag") + "$" + attributes.getValue("value");
|
||||
currentRouter.obstacles.put(previousKey, parseSilentDouble(attributes.getValue("penalty"),
|
||||
0));
|
||||
} else if("avoid".equals(name)) {
|
||||
String key = attributes.getValue("tag") + "$" + attributes.getValue("value");
|
||||
previousTag = name;
|
||||
previousKey = attributes.getValue("tag") + "$" + attributes.getValue("value");
|
||||
double priority = parseSilentDouble(attributes.getValue("decreasedPriority"),
|
||||
0);
|
||||
if(priority == 0) {
|
||||
currentRouter.avoid.put(key, priority);
|
||||
currentRouter.avoid.put(previousKey, priority);
|
||||
} else {
|
||||
currentRouter.highwayPriorities.put(key, priority);
|
||||
currentRouter.highwayPriorities.put(previousKey, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,22 +59,35 @@
|
|||
<road tag="highway" value="tertiary" speed="45" priority="1" dynamicPriority="0.9"/>
|
||||
<road tag="highway" value="tertiary_link" speed="40" priority="1" dynamicPriority="0.9"/>
|
||||
<!-- lowest form of grid network, usually 90% of urban roads -->
|
||||
<road tag="highway" value="unclassified" speed="35" priority="0.7" dynamicPriority="0.7"/>
|
||||
<road tag="highway" value="unclassified" speed="35" priority="0.7" dynamicPriority="0.7">
|
||||
<specialization input="short_way" priority="1" dynamicPriority="1" speed="45"/>
|
||||
</road>
|
||||
<!-- road = no type, no review and may be not accurate -->
|
||||
<road tag="highway" value="road" speed="35" priority="0.7" dynamicPriority="0.7"/>
|
||||
<road tag="highway" value="road" speed="35" priority="0.7" dynamicPriority="0.7">
|
||||
<specialization input="short_way" priority="1" speed="45"/>
|
||||
</road>
|
||||
<!-- primarily for access to properties, small roads with 1/2 intersections -->
|
||||
<road tag="highway" value="residential" speed="35" priority="0.7" dynamicPriority="0.7"/>
|
||||
<road tag="highway" value="residential" speed="35" priority="0.7" dynamicPriority="0.7">
|
||||
<specialization input="short_way" priority="1" dynamicPriority="1" speed="45"/>
|
||||
</road>
|
||||
<!-- parking + private roads -->
|
||||
<road tag="highway" value="service" speed="30" priority="0.5" dynamicPriority="0.5"/>
|
||||
<road tag="highway" value="service" speed="30" priority="0.5" dynamicPriority="0.5">
|
||||
<specialization input="short_way" priority="1" dynamicPriority="1" speed="45"/>
|
||||
</road>
|
||||
<!-- very bad roads -->
|
||||
<road tag="highway" value="track" speed="15" priority="0.3" dynamicPriority="0.5"/>
|
||||
<road tag="highway" value="track" speed="15" priority="0.3" dynamicPriority="0.5">
|
||||
<specialization input="short_way" priority="0.7" speed="45" dynamicPriority="0.7" />
|
||||
<specialization input="avoid_unpaved" priority="0.1"/>
|
||||
</road>
|
||||
|
||||
<!-- too small for cars usually -->
|
||||
<road tag="highway" value="living_street" speed="25" priority="0.5" dynamicPriority="0.5"/>
|
||||
<road tag="highway" value="living_street" speed="25" priority="0.5" dynamicPriority="0.5">
|
||||
<specialization input="short_way" priority="1" dynamicPriority="1" speed="35"/>
|
||||
</road>
|
||||
<!-- car are able to enter in highway=pedestrian with restrictions -->
|
||||
<!-- Time actually is uknown. Currently unsupported -->
|
||||
<road tag="route" value="ferry" speed="15" priority="1.0" dynamicPriority="0.7">
|
||||
<!-- <specialization input="avoid_ferries" speed="0"/> -->
|
||||
<specialization input="avoid_ferries" speed="0"/>
|
||||
</road>
|
||||
|
||||
<obstacle tag="highway" value="traffic_signals" penalty="30"/>
|
||||
|
@ -89,7 +102,9 @@
|
|||
<avoid tag="access" value="no"/>
|
||||
<avoid tag="motorcycle" value="no"/>
|
||||
<avoid tag="motorcar" value="no"/>
|
||||
<!-- <avoid tag="toll" value="yes"/> -->
|
||||
<avoid tag="toll" value="yes" decreasedPriority="1">
|
||||
<specialization input="avoid_toll"/>
|
||||
</avoid>
|
||||
</routingProfile>
|
||||
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ public class DataExtractionSettings {
|
|||
|
||||
|
||||
public String getRouteMode(){
|
||||
return preferences.get("routeMode", "car");
|
||||
return preferences.get("routeMode", "car,short_way");
|
||||
}
|
||||
|
||||
public void setRouteMode(String mode){
|
||||
|
|
|
@ -597,8 +597,9 @@ public class MapRouterLayer implements MapPanelLayer {
|
|||
rs[it++] = new BinaryMapIndexReader(raf, false);
|
||||
}
|
||||
String m = DataExtractionSettings.getSettings().getRouteMode();
|
||||
String[] props = m.split("\\,");
|
||||
BinaryRoutePlanner router = new BinaryRoutePlanner(NativeSwingRendering.getDefaultFromSettings(), rs);
|
||||
RoutingConfiguration config = builder.build(m, true);
|
||||
RoutingConfiguration config = builder.build(props[0], props);
|
||||
RoutingContext ctx = new RoutingContext(config);
|
||||
ctx.previouslyCalculatedRoute = previousRoute;
|
||||
log.info("Use " + config.routerName + "mode for routing");
|
||||
|
|
|
@ -140,7 +140,7 @@ public class OsmExtractionPreferencesDialog extends JDialog {
|
|||
constr.gridy = gridY++;
|
||||
l.setConstraints(nativeFilesDirectory, constr);
|
||||
|
||||
label = new JLabel("Routing mode (car/bicycle/pedestrian) : ");
|
||||
label = new JLabel("Routing (car|bicycle|pedestrian,[short_way],[avoid_ferries]...) : ");
|
||||
panel.add(label);
|
||||
constr = new GridBagConstraints();
|
||||
constr.ipadx = 5;
|
||||
|
|
|
@ -37,6 +37,7 @@ import net.osmand.plus.activities.ApplicationMode;
|
|||
import net.osmand.plus.render.NativeOsmandLibrary;
|
||||
import net.osmand.router.BinaryRoutePlanner;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
||||
import net.osmand.router.GeneralRouter;
|
||||
import net.osmand.router.GeneralRouter.GeneralRouterProfile;
|
||||
import net.osmand.router.Interruptable;
|
||||
import net.osmand.router.RouteSegmentResult;
|
||||
|
@ -167,7 +168,7 @@ public class RouteProvider {
|
|||
if(previousToRecalculate != null) {
|
||||
originalRoute = previousToRecalculate.getOriginalRoute();
|
||||
}
|
||||
res = findVectorMapsRoute(start, end, mode, fast, (OsmandApplication)ctx.getApplicationContext(), originalRoute, leftSide, interruptable);
|
||||
res = findVectorMapsRoute(start, end, mode, (OsmandApplication)ctx.getApplicationContext(), originalRoute, leftSide, interruptable);
|
||||
} else {
|
||||
res = findCloudMadeRoute(start, end, mode, ctx, fast, leftSide);
|
||||
}
|
||||
|
@ -307,7 +308,7 @@ public class RouteProvider {
|
|||
return new RouteCalculationResult(res, null, start, end, null, ctx, leftSide, true);
|
||||
}
|
||||
|
||||
protected RouteCalculationResult findVectorMapsRoute(Location start, LatLon end, ApplicationMode mode, boolean fast, OsmandApplication app,
|
||||
protected RouteCalculationResult findVectorMapsRoute(Location start, LatLon end, ApplicationMode mode, OsmandApplication app,
|
||||
List<RouteSegmentResult> previousRoute,
|
||||
boolean leftSide, Interruptable interruptable) throws IOException {
|
||||
BinaryMapIndexReader[] files = app.getResourceManager().getRoutingMapFiles();
|
||||
|
@ -332,7 +333,21 @@ public class RouteProvider {
|
|||
} else {
|
||||
p = GeneralRouterProfile.CAR;
|
||||
}
|
||||
RoutingContext ctx = new RoutingContext(config.build(p.name().toLowerCase(), !fast, start.hasBearing() ? start.getBearing() / 180d * Math.PI : null));
|
||||
List<String> specs = new ArrayList<String>();
|
||||
if (!app.getSettings().FAST_ROUTE_MODE.get()) {
|
||||
specs.add(GeneralRouter.USE_SHORTEST_WAY);
|
||||
}
|
||||
if(app.getSettings().AVOID_FERRIES.get()){
|
||||
specs.add(GeneralRouter.AVOID_FERRIES);
|
||||
}
|
||||
if(app.getSettings().AVOID_TOLL_ROADS.get()){
|
||||
specs.add(GeneralRouter.AVOID_TOLL);
|
||||
}
|
||||
if(app.getSettings().AVOID_UNPAVED_ROADS.get()){
|
||||
specs.add(GeneralRouter.AVOID_UNPAVED);
|
||||
}
|
||||
String[] specialization = specs.toArray(new String[specs.size()]);
|
||||
RoutingContext ctx = new RoutingContext(config.build(p.name().toLowerCase(), start.hasBearing() ? start.getBearing() / 180d * Math.PI : null, specialization));
|
||||
ctx.interruptable = interruptable;
|
||||
ctx.previouslyCalculatedRoute = previousRoute;
|
||||
RouteSegment st= router.findRouteSegment(start.getLatitude(), start.getLongitude(), ctx);
|
||||
|
|
|
@ -539,7 +539,6 @@ public class RoutingHelper {
|
|||
private final GPXRouteParams gpxRoute;
|
||||
private final RouteCalculationResult previousRoute;
|
||||
private RouteService service;
|
||||
private boolean fastRoute;
|
||||
private boolean interrupted = false;
|
||||
|
||||
public RouteRecalculationThread(String name,
|
||||
|
@ -550,7 +549,7 @@ public class RoutingHelper {
|
|||
this.gpxRoute = gpxRoute;
|
||||
this.previousRoute = previousRoute;
|
||||
service = settings.ROUTER_SERVICE.get();
|
||||
fastRoute = settings.FAST_ROUTE_MODE.get();
|
||||
|
||||
}
|
||||
|
||||
public void stopCalculation(){
|
||||
|
@ -565,6 +564,7 @@ public class RoutingHelper {
|
|||
@Override
|
||||
public void run() {
|
||||
boolean leftSide = settings.LEFT_SIDE_NAVIGATION.get();
|
||||
boolean fastRoute = settings.FAST_ROUTE_MODE.get();
|
||||
RouteCalculationResult res = provider.calculateRouteImpl(start, end, mode, service, context, gpxRoute, previousRoute, fastRoute,
|
||||
leftSide, this);
|
||||
if (interrupted) {
|
||||
|
|
Loading…
Reference in a new issue