diff --git a/NOTICE-THIRD-PARTY.md b/NOTICE-THIRD-PARTY.md
index 923aab731..1a927766b 100644
--- a/NOTICE-THIRD-PARTY.md
+++ b/NOTICE-THIRD-PARTY.md
@@ -93,22 +93,22 @@ FindBugs-jsr305 (3.0.2)
* Source: https://code.google.com/p/jsr-305/
-GraphHopper API (0.13.0)
-
- * License: Apache License, Version 2.0
- * Maven artifact: `com.graphhopper:graphhopper-api:0.13.0`
- * Project: https://www.graphhopper.com/graphhopper-api
- * Source: https://github.com/graphhopper/graphhopper/graphhopper-api
-
-
-GraphHopper Core (0.13.0)
+GraphHopper Core (8.0)
* License: The Apache Software License, Version 2.0
- * Maven artifact: `com.graphhopper:graphhopper-core:0.13.0`
+ * Maven artifact: `com.graphhopper:graphhopper-core:8.0`
* Project: https://www.graphhopper.com/graphhopper-core
* Source: https://github.com/graphhopper/graphhopper/graphhopper-core
+GraphHopper Web API (8.0)
+
+ * License: Apache License, Version 2.0
+ * Maven artifact: `com.graphhopper:graphhopper-web-api:8.0`
+ * Project: https://www.graphhopper.com/graphhopper-web-api
+ * Source: https://github.com/graphhopper/graphhopper/graphhopper-web-api
+
+
Gson (2.10.1)
* License: Apache-2.0
@@ -133,46 +133,46 @@ HPPC Collections (0.8.1)
* Source: https://github.com/carrotsearch/hppc/hppc
-Jackson module: JAXB Annotations (2.9.9)
+Jackson-annotations (2.15.0)
* License: The Apache Software License, Version 2.0
- * Maven artifact: `com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.9.9`
- * Project: https://github.com/FasterXML/jackson-modules-base
- * Source: https://github.com/FasterXML/jackson-modules-base/jackson-module-jaxb-annotations
-
-
-Jackson-annotations (2.9.0)
-
- * License: The Apache Software License, Version 2.0
- * Maven artifact: `com.fasterxml.jackson.core:jackson-annotations:2.9.0`
- * Project: http://github.com/FasterXML/jackson
+ * Maven artifact: `com.fasterxml.jackson.core:jackson-annotations:2.15.0`
+ * Project: https://github.com/FasterXML/jackson
* Source: https://github.com/FasterXML/jackson-annotations
-Jackson-core (2.9.9)
+Jackson-core (2.15.0)
* License: The Apache Software License, Version 2.0
- * Maven artifact: `com.fasterxml.jackson.core:jackson-core:2.9.9`
+ * Maven artifact: `com.fasterxml.jackson.core:jackson-core:2.15.0`
* Project: https://github.com/FasterXML/jackson-core
* Source: https://github.com/FasterXML/jackson-core
-jackson-databind (2.9.9)
+jackson-databind (2.15.0)
* License: The Apache Software License, Version 2.0
- * Maven artifact: `com.fasterxml.jackson.core:jackson-databind:2.9.9`
- * Project: http://github.com/FasterXML/jackson
+ * Maven artifact: `com.fasterxml.jackson.core:jackson-databind:2.15.0`
+ * Project: https://github.com/FasterXML/jackson
* Source: https://github.com/FasterXML/jackson-databind
-Jackson-dataformat-XML (2.9.9)
+Jackson-dataformat-XML (2.15.0)
* License: The Apache Software License, Version 2.0
- * Maven artifact: `com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.9`
- * Project: http://wiki.fasterxml.com/JacksonExtensionXmlDataBinding
+ * Maven artifact: `com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.0`
+ * Project: https://github.com/FasterXML/jackson-dataformat-xml
* Source: https://github.com/FasterXML/jackson-dataformat-xml
+Jackson-datatype-jts (2.14)
+
+ * License: The Apache Software License, Version 2.0
+ * Maven artifact: `com.graphhopper.external:jackson-datatype-jts:2.14`
+ * Project: https://github.com/bedatadriven/jackson-datatype-jts/
+ * Source: scm:git:https://github.com/bedatadriven/jackson-datatype-jts
+
+
Janino (2.7.5)
* License: New BSD License
@@ -237,6 +237,14 @@ org.leadpony.justify (1.1.0)
* Source: https://github.com/leadpony/justify
+org.locationtech.jts:jts-core (1.19.0)
+
+ * License: Eclipse Distribution License - v 1.0, Eclipse Public License, Version 2.0
+ * Maven artifact: `org.locationtech.jts:jts-core:1.19.0`
+ * Project: https://www.locationtech.org/projects/technology.jts/jts-modules/jts-core
+ * Source: https://github.com/locationtech/jts/jts-modules/jts-core
+
+
Protocol Buffers [Core] (3.8.0)
* License: 3-Clause BSD License
@@ -269,10 +277,10 @@ Stax2 API (4.2.1)
* Source: https://github.com/FasterXML/stax2-api
-Woodstox (5.1.0)
+Woodstox (6.5.1)
* License: The Apache License, Version 2.0
- * Maven artifact: `com.fasterxml.woodstox:woodstox-core:5.1.0`
+ * Maven artifact: `com.fasterxml.woodstox:woodstox-core:6.5.1`
* Project: https://github.com/FasterXML/woodstox
* Source: https://github.com/FasterXML/woodstox
diff --git a/bundle/src/assembly/mosaic-bundle.xml b/bundle/src/assembly/mosaic-bundle.xml
index 7dd9da292..6fcba6a40 100644
--- a/bundle/src/assembly/mosaic-bundle.xml
+++ b/bundle/src/assembly/mosaic-bundle.xml
@@ -154,9 +154,11 @@
- com.graphhopper:graphhopper-api
+ com.graphhopper:graphhopper-web-api
com.graphhopper:graphhopper-core
+ com.graphhopper.external:jackson-datatype-jts
com.carrotsearch:hppc
+ org.locationtech.jts:jts-core
com.jcraft:jsch
diff --git a/lib/mosaic-routing/pom.xml b/lib/mosaic-routing/pom.xml
index a53dccb1e..67b165199 100644
--- a/lib/mosaic-routing/pom.xml
+++ b/lib/mosaic-routing/pom.xml
@@ -32,16 +32,6 @@
com.graphhopper
graphhopper-core
-
-
- org.locationtech.jts
- jts-core
-
-
- org.apache.xmlgraphics
- xmlgraphics-commons
-
-
com.google.guava
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/CandidateRoute.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/CandidateRoute.java
index f8e2a6e7e..58c13d383 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/CandidateRoute.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/CandidateRoute.java
@@ -23,25 +23,94 @@
*/
public class CandidateRoute {
+ /**
+ * The list of connections forming this route.
+ */
private final List connectionIds;
+
+ /**
+ * The length in meters of this route.
+ */
private final double length;
+
+ /**
+ * The approximated driving time in seconds on this route.
+ */
private final double time;
+ /**
+ * The distance in meters from the start node of the first connection in the connectionIds list, to
+ * the point the source query was issued.
+ */
+ private final double offsetFromSource;
+
+ /**
+ * The distance in meters from the point the target query was issued, until the end node of the
+ * final connection in the connectionIds list.
+ */
+ private final double offsetToTarget;
+
+ /**
+ * @param connectionIds the list of connection id this route persists of.
+ * @param length the length in m of this route.
+ * @param time the approximate travel time in seconds of this route.
+ */
public CandidateRoute(List connectionIds, double length, double time) {
+ this(connectionIds, length, time, 0, 0);
+ }
+
+ /**
+ *
+ * @param connectionIds the list of connection id this route persists of.
+ * @param length the length in m of this route.
+ * @param time the approximate travel time in seconds of this route.
+ * @param offsetFromSource the distance in meters from the start node of the first connection in the connectionIds list, to
+ * the point the source query was issued.
+ * @param offsetToTarget the distance in meters from the point the target query was issued, until the end node of the
+ * final connection in the connectionIds list.
+ */
+ public CandidateRoute(List connectionIds, double length, double time, double offsetFromSource, double offsetToTarget) {
this.connectionIds = connectionIds;
this.length = length;
this.time = time;
+ this.offsetFromSource = offsetFromSource;
+ this.offsetToTarget = offsetToTarget;
}
+ /**
+ * @return the list of connection ids forming this route.
+ */
public List getConnectionIds() {
return connectionIds;
}
+ /**
+ * @return the length in meters of this route.
+ */
public double getLength() {
return length;
}
+ /**
+ * @return the approximated driving time in seconds on this route.
+ */
public double getTime() {
return time;
}
+
+ /**
+ * @return the distance in meters from the start node of the first connection in the connectionIds list, to
+ * the point the source query was issued.
+ */
+ public double getOffsetFromSource() {
+ return offsetFromSource;
+ }
+
+ /**
+ * @return the distance in meters from the point the target query was issued, until
+ * the end node of the final connection in the connectionIds list.
+ */
+ public double getOffsetToTarget() {
+ return offsetToTarget;
+ }
}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/database/DatabaseRouting.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/database/DatabaseRouting.java
index e9d91d634..4b9e8409f 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/database/DatabaseRouting.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/database/DatabaseRouting.java
@@ -86,8 +86,7 @@ public void initialize(final CRouting configuration, final File baseDirectory) t
}
//creates an implementation of IRoutingGraph according to the configuration
- this.routing = new GraphHopperRouting()
- .loadGraphFromDatabase(scenarioDatabase);
+ this.routing = new GraphHopperRouting(scenarioDatabase);
this.routeManager = new RouteManager(this.scenarioDatabase);
}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperEdgeProperties.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperEdgeProperties.java
index a735837d5..048030d1e 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperEdgeProperties.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperEdgeProperties.java
@@ -20,10 +20,12 @@
import org.eclipse.mosaic.lib.routing.EdgeProperties;
import org.eclipse.mosaic.lib.routing.RoutingCostFunction;
import org.eclipse.mosaic.lib.routing.graphhopper.util.GraphhopperToDatabaseMapper;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.VehicleEncoding;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.WayTypeEncoder;
import com.google.common.collect.Iterables;
-import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.util.EdgeIteratorState;
+import com.graphhopper.util.FetchMode;
import org.apache.commons.lang3.Validate;
import java.util.Optional;
@@ -32,16 +34,18 @@
* Provides properties from the current {@link EdgeIteratorState} or
* its belonging {@link Connection} to be used by an {@link RoutingCostFunction}.
*/
-class GraphHopperEdgeProperties implements EdgeProperties {
+public class GraphHopperEdgeProperties implements EdgeProperties {
- private final FlagEncoder flagEncoder;
+ private final VehicleEncoding encoding;
+ private final WayTypeEncoder wayTypeEncoder;
private final GraphhopperToDatabaseMapper graphMapper;
private EdgeIteratorState currentEdgeIterator;
private boolean reverseRequests;
- GraphHopperEdgeProperties(FlagEncoder encoder, GraphhopperToDatabaseMapper graphMapper) {
- this.flagEncoder = encoder;
+ GraphHopperEdgeProperties(VehicleEncoding encoding, WayTypeEncoder wayTypeEncoder, GraphhopperToDatabaseMapper graphMapper) {
+ this.encoding = encoding;
+ this.wayTypeEncoder = wayTypeEncoder;
this.graphMapper = graphMapper;
}
@@ -54,9 +58,9 @@ void setCurrentEdgeIterator(EdgeIteratorState currentEdgeIterator, boolean rever
@Override
public double getSpeed() {
Validate.notNull(currentEdgeIterator, "Edge iterator is null");
- return (reverseRequests
- ? currentEdgeIterator.getReverse(flagEncoder.getAverageSpeedEnc())
- : currentEdgeIterator.get(flagEncoder.getAverageSpeedEnc())) / 3.6d;
+ return reverseRequests
+ ? currentEdgeIterator.getReverse(encoding.speed()) / 3.6
+ : currentEdgeIterator.get(encoding.speed()) / 3.6;
}
@Override
@@ -69,8 +73,8 @@ public double getLength() {
public Iterable getGeometry() {
Validate.notNull(currentEdgeIterator, "Edge iterator is null");
return Iterables.transform(
- currentEdgeIterator.fetchWayGeometry(3), // 3 = fetch all pillar nodes inclusive the base and adjacent tower node
- ghPoint3D -> GeoPoint.latLon(ghPoint3D.getLat(), ghPoint3D.getLon(), ghPoint3D.getElevation())
+ currentEdgeIterator.fetchWayGeometry(FetchMode.ALL), // fetches all pillar nodes inclusive the base and adjacent tower node
+ ghPoint3D -> GeoPoint.latLon(ghPoint3D.getLat(), ghPoint3D.getLon(), ghPoint3D.getEle())
);
}
@@ -81,7 +85,11 @@ public String getConnectionId() {
@Override
public String getWayType() {
- return getConnection().map(con -> con.getWay().getType()).orElse(null);
+ return WayTypeEncoder.decode(getWayTypeEncoded());
+ }
+
+ public int getWayTypeEncoded() {
+ return currentEdgeIterator.get(wayTypeEncoder);
}
private Optional getConnection() {
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperRouting.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperRouting.java
index be567a702..bbc81632e 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperRouting.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperRouting.java
@@ -28,42 +28,92 @@
import org.eclipse.mosaic.lib.routing.RoutingCostFunction;
import org.eclipse.mosaic.lib.routing.RoutingPosition;
import org.eclipse.mosaic.lib.routing.RoutingRequest;
-import org.eclipse.mosaic.lib.routing.graphhopper.algorithm.AlternativeRoutesRoutingAlgorithm;
-import org.eclipse.mosaic.lib.routing.graphhopper.algorithm.DijkstraCamvitChoiceRouting;
-import org.eclipse.mosaic.lib.routing.graphhopper.extended.ExtendedGraphHopper;
+import org.eclipse.mosaic.lib.routing.graphhopper.algorithm.RoutingAlgorithmFactory;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.DatabaseGraphLoader;
import org.eclipse.mosaic.lib.routing.graphhopper.util.GraphhopperToDatabaseMapper;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.OptionalTurnCostProvider;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.VehicleEncoding;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.VehicleEncodingManager;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
-import com.graphhopper.GraphHopper;
+import com.graphhopper.config.Profile;
import com.graphhopper.routing.Path;
-import com.graphhopper.routing.QueryGraph;
-import com.graphhopper.routing.util.BikeFlagEncoder;
-import com.graphhopper.routing.util.CarFlagEncoder;
-import com.graphhopper.routing.util.DefaultEdgeFilter;
+import com.graphhopper.routing.RoutingAlgorithm;
+import com.graphhopper.routing.ev.BooleanEncodedValue;
+import com.graphhopper.routing.querygraph.QueryGraph;
+import com.graphhopper.routing.querygraph.VirtualEdgeIteratorState;
+import com.graphhopper.routing.subnetwork.PrepareRoutingSubnetworks;
+import com.graphhopper.routing.util.AccessFilter;
import com.graphhopper.routing.util.EdgeFilter;
-import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.routing.weighting.TurnWeighting;
-import com.graphhopper.storage.TurnCostExtension;
-import com.graphhopper.storage.index.QueryResult;
+import com.graphhopper.routing.weighting.Weighting;
+import com.graphhopper.storage.BaseGraph;
+import com.graphhopper.storage.Graph;
+import com.graphhopper.storage.NodeAccess;
+import com.graphhopper.storage.RAMDirectory;
+import com.graphhopper.storage.index.LocationIndex;
+import com.graphhopper.storage.index.LocationIndexTree;
+import com.graphhopper.storage.index.Snap;
import com.graphhopper.util.DistanceCalc;
import com.graphhopper.util.DistancePlaneProjection;
import com.graphhopper.util.EdgeIteratorState;
+import com.graphhopper.util.PMap;
+import com.graphhopper.util.Parameters;
import com.graphhopper.util.PointList;
import com.graphhopper.util.shapes.GHPoint;
+import edu.umd.cs.findbugs.annotations.SuppressWarnings;
+import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+@SuppressWarnings(value = "MS_SHOULD_BE_FINAL", justification = "Static fields kept public and adjustable for user customization")
public class GraphHopperRouting {
+ private static final Logger LOG = LoggerFactory.getLogger(GraphHopperRouting.class);
+
+ public static final Profile PROFILE_CAR = new Profile("car").setVehicle("car").setTurnCosts(true);
+
+ public static final Profile PROFILE_BIKE = new Profile("bike").setVehicle("bike").setTurnCosts(false);
+
+ public static final List PROFILES = Collections.unmodifiableList(Lists.newArrayList(
+ PROFILE_CAR, PROFILE_BIKE
+ ));
+
+ /**
+ * The minimum number of alternatives to calculate when alternative routes have been requested.
+ * GraphHopper often returns equal routes, and by calculating more than required we can
+ * reduce the result to match the requested number of alternatives.
+ */
+ private static final int NUM_ALTERNATIVE_PATHS = 5;
+
+ /**
+ * Alternative routes may share a maximum of 70% of roads of the best route.
+ */
+ public static double ALTERNATIVE_ROUTES_MAX_SHARE = 0.7;
+
+ /**
+ * Alternative routes may cost a maximum of 40% more than the best route.
+ */
+ public static double ALTERNATIVE_ROUTES_MAX_WEIGHT = 1.4;
+
+ /**
+ * Increases the changes to find more alternatives.
+ */
+ public static double ALTERNATIVE_ROUTES_EXPLORATION_FACTOR = 1.3;
+
+ /**
+ * Specifies the minimum plateau portion of every alternative path that is required.
+ */
+ public static double ALTERNATIVE_ROUTES_PLATEAU_FACTOR = 0.1;
+
/**
* If the distance of the query position to the closest node is lower than this
* value, then the closest node is used definitely as the source or target of the route.
@@ -76,7 +126,7 @@ public class GraphHopperRouting {
* the found route, another connection is added on which the target
* point is matched on.
*/
- public static double TARGET_REQUEST_CONNECTION_THRESHOLD = 5d;
+ public static final double TARGET_REQUEST_CONNECTION_THRESHOLD = 5d;
/**
* Sometimes edges are dead ends. In these cases routing fails and invalid
@@ -85,151 +135,189 @@ public class GraphHopperRouting {
*/
private static final double MAX_DISTANCE_TO_TARGET = 500d;
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- private GraphHopper ghApi;
private final DistanceCalc distanceCalculation = new DistancePlaneProjection();
- private GraphhopperToDatabaseMapper graphMapper;
- private Database db;
+ private final GraphhopperToDatabaseMapper graphMapper;
+ private final Database db;
+ private final VehicleEncodingManager encoding;
+ private final BaseGraph graph;
+ private final LocationIndex locationIndex;
- public GraphHopperRouting loadGraphFromDatabase(Database db) {
+ public GraphHopperRouting(Database db) {
this.db = db;
- //initialize reader and mapper for database import into graphhopper
- GraphLoader reader = new DatabaseGraphLoader(db);
graphMapper = new GraphhopperToDatabaseMapper();
+ encoding = new VehicleEncodingManager(PROFILES);
- ghApi = new ExtendedGraphHopper(reader, graphMapper).forDesktop();
- //we only need a encoder for speed,flag and turn costs for cars
- ghApi.setEncodingManager(EncodingManager.create(
- new CarFlagEncoder(5, 5, 127),
- new BikeFlagEncoder(4, 2, 0)
- ));
+ graph = createGraphFromDatabase(db);
+ locationIndex = createLocationIndex();
+ cleanUpGraph();
- //load graph from database
- ghApi.importOrLoad();
+ graph.flush();
+ }
+
+ private BaseGraph createGraphFromDatabase(Database db) {
+ final BaseGraph graph = new BaseGraph
+ .Builder(encoding.getEncodingManager())
+ .setDir(new RAMDirectory())
+ .set3D(true)
+ .withTurnCosts(encoding.getEncodingManager().needsTurnCostsSupport())
+ .setSegmentSize(-1)
+ .build();
+
+ final DatabaseGraphLoader reader = new DatabaseGraphLoader(db);
+ reader.initialize(graph, encoding, graphMapper);
+ reader.loadGraph();
+ LOG.info("nodes: {}, edges: {}", graph.getNodes(), graph.getEdges());
+ return graph;
+ }
+
+ private LocationIndex createLocationIndex() {
+ return new LocationIndexTree(graph, graph.getDirectory())
+ .setMinResolutionInMeter(300)
+ .setMaxRegionSearch(4)
+ .prepareIndex();
+ }
+
+ protected void cleanUpGraph() {
+ new PrepareRoutingSubnetworks(graph, buildSubnetworkRemovalJobs())
+ .setMinNetworkSize(200)
+ .setThreads(1)
+ .doWork();
+ }
- return this;
+ private List buildSubnetworkRemovalJobs() {
+ List jobs = new ArrayList<>();
+ for (Profile profile : encoding.getAllProfiles()) {
+ Weighting weighting = createWeighting(profile, RoutingCostFunction.Fastest, false);
+ jobs.add(new PrepareRoutingSubnetworks.PrepareJob(encoding.getVehicleEncoding(profile.getVehicle()).subnetwork(), weighting));
+ }
+ return jobs;
}
public List findRoutes(RoutingRequest routingRequest) {
- if (ghApi == null) {
+ if (graph == null) {
throw new IllegalStateException("Load database at first");
}
- final FlagEncoder flagEncoder;
+ final Profile profile;
if (routingRequest.getRoutingParameters().getVehicleClass() == VehicleClass.Bicycle) {
- flagEncoder = ghApi.getEncodingManager().getEncoder("bike");
- } else {
- flagEncoder = ghApi.getEncodingManager().getEncoder("car");
- }
-
- final GraphHopperWeighting graphhopperWeighting = new GraphHopperWeighting(flagEncoder, graphMapper);
-
- // if there is no cost function given (initial routes), use the default
- if (routingRequest.getRoutingParameters().getRoutingCostFunction() == null) {
- graphhopperWeighting.setRoutingCostFunction(RoutingCostFunction.Default);
+ profile = PROFILE_BIKE;
} else {
- graphhopperWeighting.setRoutingCostFunction(routingRequest.getRoutingParameters().getRoutingCostFunction());
+ profile = PROFILE_CAR;
}
+ final VehicleEncoding vehicleEncoding = encoding.getVehicleEncoding(profile.getVehicle());
final RoutingPosition source = routingRequest.getSource();
final RoutingPosition target = routingRequest.getTarget();
- final QueryResult querySource = createQueryForSource(source, flagEncoder);
- final QueryResult queryTarget = createQueryForTarget(target, flagEncoder);
+ final Snap snapSource = createQueryForSource(source, vehicleEncoding.access());
+ final Snap snapTarget = createQueryForTarget(target, vehicleEncoding.access());
- if (querySource.getClosestEdge() == null || queryTarget.getClosestEdge() == null) {
- log.warn("Could not find a route from {} to {}", routingRequest.getSource(), routingRequest.getTarget());
+ if (snapSource.getClosestEdge() == null || snapTarget.getClosestEdge() == null) {
+ LOG.warn("Could not find a route from {} to {}", routingRequest.getSource(), routingRequest.getTarget());
return Lists.newArrayList();
}
- final QueryGraph queryGraph = new QueryGraph(ghApi.getGraphHopperStorage());
- queryGraph.lookup(querySource, queryTarget);
+ final QueryGraph queryGraph = QueryGraph.create(graph, snapSource, snapTarget);
- final TurnWeighting weighting = new TurnWeightingOptional(
- graphhopperWeighting, (TurnCostExtension) queryGraph.getExtension(),
- routingRequest.getRoutingParameters().isConsiderTurnCosts(),
- routingRequest.getRoutingParameters().getRestrictionCosts()
- );
-
- // create algorithm
- final AlternativeRoutesRoutingAlgorithm algo = new DijkstraCamvitChoiceRouting(queryGraph, weighting);
- algo.setRequestAlternatives(routingRequest.getRoutingParameters().getNumAlternativeRoutes());
+ final int numberOfAlternatives = routingRequest.getRoutingParameters().getNumAlternativeRoutes();
+ final PMap algoHints = new PMap();
+ if (numberOfAlternatives > 0) {
+ // We calculate more alternative routes than required, since GraphHopper often seem to return equal alternatives
+ algoHints.putObject(Parameters.Algorithms.AltRoute.MAX_PATHS, Math.max(numberOfAlternatives, NUM_ALTERNATIVE_PATHS) + 1);
+ }
- final List paths = new ArrayList<>();
+ final Weighting weighting = createWeighting(profile,
+ routingRequest.getRoutingParameters().getRoutingCostFunction(),
+ routingRequest.getRoutingParameters().isConsiderTurnCosts()
+ );
- // Calculates all paths and returns the best one
- paths.add(algo.calcPath(querySource.getClosestNode(), queryTarget.getClosestNode()));
+ final RoutingAlgorithm algo = RoutingAlgorithmFactory.DEFAULT.createAlgorithm(
+ queryGraph, queryGraph.wrapWeighting(weighting), algoHints
+ );
- //add alternative paths to path set
- paths.addAll(algo.getAlternativePaths());
+ final List paths = algo.calcPaths(snapSource.getClosestNode(), snapTarget.getClosestNode());
final Set duplicateSet = new HashSet<>();
final List result = new ArrayList<>();
// convert paths to routes
for (final Path path : paths) {
- final CandidateRoute route = convertPath(path, queryGraph, querySource, queryTarget, source, target);
+ if (result.size() > numberOfAlternatives) {
+ break;
+ }
+ final CandidateRoute route = convertPath(queryGraph, path, source, target);
if (route != null
&& !route.getConnectionIds().isEmpty()
&& checkRouteOnRequiredSourceConnection(route, source)
- && checkForDuplicate(route, duplicateSet)) {
+ && checkForDuplicate(route, duplicateSet)
+ ) {
result.add(route);
- } else if (route != null && log.isDebugEnabled()) {
- log.debug("Path is invalid and will be ignored [" + StringUtils.join(route.getConnectionIds(), ",") + "]");
+ } else if (route != null && LOG.isDebugEnabled()) {
+ LOG.debug("Path is invalid and will be ignored [" + StringUtils.join(route.getConnectionIds(), ",") + "]");
}
}
return result;
}
- private QueryResult createQueryForTarget(RoutingPosition target, FlagEncoder flagEncoder) {
- final EdgeFilter toEdgeFilter = createEdgeFilterForRoutingPosition(target, flagEncoder);
- QueryResult queryTarget = ghApi.getLocationIndex().findClosest(target.getPosition().getLatitude(), target.getPosition().getLongitude(), toEdgeFilter);
+ private Weighting createWeighting(Profile profile, RoutingCostFunction costFunction, boolean withTurnCosts) {
+ final VehicleEncoding vehicleEncoding = encoding.getVehicleEncoding(profile.getVehicle());
+ final OptionalTurnCostProvider turnCostProvider = new OptionalTurnCostProvider(vehicleEncoding, graph.getTurnCostStorage());
+ if (!withTurnCosts) {
+ turnCostProvider.disableTurnCosts();
+ }
+ return new GraphHopperWeighting(vehicleEncoding, encoding.wayType(), turnCostProvider, graphMapper)
+ .setRoutingCostFunction(ObjectUtils.defaultIfNull(costFunction, RoutingCostFunction.Default));
+ }
+
+ private Snap createQueryForTarget(RoutingPosition target, BooleanEncodedValue accessEnc) {
+ final EdgeFilter toEdgeFilter = createEdgeFilterForRoutingPosition(target, accessEnc);
+ Snap queryTarget = locationIndex.findClosest(target.getPosition().getLatitude(), target.getPosition().getLongitude(), toEdgeFilter);
if (target.getConnectionId() != null) {
- return fixQueryResultIfNoClosestEdgeFound(queryTarget, target, flagEncoder);
+ return fixQueryResultIfNoClosestEdgeFound(queryTarget, target, accessEnc);
} else {
return fixQueryResultIfSnappedPointIsCloseToTowerNode(queryTarget, target);
}
}
- private QueryResult createQueryForSource(RoutingPosition source, FlagEncoder flagEncoder) {
- final EdgeFilter fromEdgeFilter = createEdgeFilterForRoutingPosition(source, flagEncoder);
- QueryResult querySource = ghApi.getLocationIndex().findClosest(source.getPosition().getLatitude(), source.getPosition().getLongitude(), fromEdgeFilter);
+ private Snap createQueryForSource(RoutingPosition source, BooleanEncodedValue accessEnc) {
+ final EdgeFilter fromEdgeFilter = createEdgeFilterForRoutingPosition(source, accessEnc);
+ Snap querySource = locationIndex.findClosest(source.getPosition().getLatitude(), source.getPosition().getLongitude(), fromEdgeFilter);
if (source.getConnectionId() != null) {
querySource = fixQueryResultIfSnappedPointIsTowerNode(querySource, source, fromEdgeFilter);
- return fixQueryResultIfNoClosestEdgeFound(querySource, source, flagEncoder);
+ return fixQueryResultIfNoClosestEdgeFound(querySource, source, accessEnc);
} else {
return fixQueryResultIfSnappedPointIsCloseToTowerNode(querySource, source);
}
}
- private QueryResult fixQueryResultIfSnappedPointIsCloseToTowerNode(QueryResult queryResult, RoutingPosition target) {
- if (queryResult.getSnappedPosition() == QueryResult.Position.TOWER || target.getConnectionId() != null) {
+ private Snap fixQueryResultIfSnappedPointIsCloseToTowerNode(Snap queryResult, RoutingPosition target) {
+ if (queryResult.getSnappedPosition() == Snap.Position.TOWER || target.getConnectionId() != null) {
return queryResult;
}
Node closestNode = graphMapper.toNode(queryResult.getClosestNode());
/* If the query result is snapped to an edge, but the matched node is very close to the query, than we use the actual closest node
* as the target of the route.*/
if (closestNode != null && target.getPosition().distanceTo(closestNode.getPosition()) < TARGET_NODE_QUERY_DISTANCE) {
- queryResult.setSnappedPosition(QueryResult.Position.TOWER);
+ queryResult.setSnappedPosition(Snap.Position.TOWER);
}
return queryResult;
}
- private QueryResult fixQueryResultIfNoClosestEdgeFound(QueryResult queryResult, RoutingPosition routingPosition, FlagEncoder flagEncoder) {
+ private Snap fixQueryResultIfNoClosestEdgeFound(Snap queryResult, RoutingPosition routingPosition, BooleanEncodedValue accessEnc) {
if (queryResult.getClosestEdge() == null) {
- log.warn("Wrong routing request: The from-connection {} does not fit with the given position {}", routingPosition.getConnectionId(), routingPosition.getPosition());
- return ghApi.getLocationIndex().findClosest(
- routingPosition.getPosition().getLatitude(), routingPosition.getPosition().getLongitude(), DefaultEdgeFilter.allEdges(flagEncoder)
+ LOG.warn("Wrong routing request: The from-connection {} does not fit with the given position {}", routingPosition.getConnectionId(), routingPosition.getPosition());
+
+ return locationIndex.findClosest(
+ routingPosition.getPosition().getLatitude(), routingPosition.getPosition().getLongitude(), AccessFilter.allEdges(accessEnc)
);
}
return queryResult;
}
- private QueryResult fixQueryResultIfSnappedPointIsTowerNode(QueryResult queryResult, RoutingPosition routingPosition, EdgeFilter fromEdgeFilter) {
- if (queryResult.getSnappedPosition() != QueryResult.Position.TOWER) {
+ private Snap fixQueryResultIfSnappedPointIsTowerNode(Snap queryResult, RoutingPosition routingPosition, EdgeFilter fromEdgeFilter) {
+ if (queryResult.getSnappedPosition() != Snap.Position.TOWER) {
return queryResult;
}
/* If the requested position is in front or behind the edge it is mapped either on the start or end of the edge (one of the tower nodes).
@@ -244,7 +332,7 @@ private QueryResult fixQueryResultIfSnappedPointIsTowerNode(QueryResult queryRes
queryConnection.getFrom().getPosition(), queryConnection.getTo().getPosition()
);
}
- return ghApi.getLocationIndex().findClosest(
+ return locationIndex.findClosest(
alternativeQueryPosition.getLatitude(), alternativeQueryPosition.getLongitude(), fromEdgeFilter
);
}
@@ -261,18 +349,25 @@ private boolean checkForDuplicate(CandidateRoute route, Set duplicateSet
return duplicateSet.add(nodeIdList);
}
- private EdgeFilter createEdgeFilterForRoutingPosition(final RoutingPosition position, final FlagEncoder flagEncoder) {
+ private boolean checkRouteOnRequiredSourceConnection(CandidateRoute route, RoutingPosition source) {
+ if (source.getConnectionId() != null) {
+ return source.getConnectionId().equals(route.getConnectionIds().get(0));
+ }
+ return true;
+ }
+
+ private EdgeFilter createEdgeFilterForRoutingPosition(final RoutingPosition position, final BooleanEncodedValue accessEnc) {
if (position.getConnectionId() == null) {
- return DefaultEdgeFilter.allEdges(flagEncoder);
+ return AccessFilter.allEdges(accessEnc);
}
final int forcedEdge = graphMapper.fromConnection(db.getConnection(position.getConnectionId()));
if (forcedEdge < 0) {
- return DefaultEdgeFilter.allEdges(flagEncoder);
+ return AccessFilter.allEdges(accessEnc);
}
return edgeState -> edgeState.getEdge() == forcedEdge;
}
- private CandidateRoute convertPath(Path newPath, QueryGraph queryGraph, QueryResult source, QueryResult target, RoutingPosition sourcePosition, RoutingPosition targetPosition) {
+ private CandidateRoute convertPath(Graph graph, Path newPath, RoutingPosition sourcePosition, RoutingPosition targetPosition) {
PointList pointList = newPath.calcPoints();
if (pointList.isEmpty()) {
return null;
@@ -290,26 +385,25 @@ private CandidateRoute convertPath(Path newPath, QueryGraph queryGraph, QueryRes
List pathConnections = new ArrayList<>();
+ double offsetFromSource = 0;
+ int lastNode = -1;
+ Connection lastConnection = null;
+ NodeAccess nodes = graph.getNodeAccess();
+
while (edgesIt.hasNext()) {
- EdgeIteratorState ghEdge = edgesIt.next();
+ EdgeIteratorState origEdge = edgesIt.next();
+ EdgeIteratorState currEdge = origEdge;
/*
* If the requested source or target point is in the middle of the road, an artificial node
* (and artificial edges) is created in the QueryGraph. As a consequence, the first
- * and/or last edge of the route might be such virtual edge. We use the queried source
- * and target to extract the original edge where the requested points have been matched on.
+ * and/or last edge of the route might be such virtual edge, which must be converted to its original edge.
*/
- if (queryGraph.isVirtualEdge(ghEdge.getEdge())) {
- if (pathConnections.isEmpty() && queryGraph.isVirtualNode(source.getClosestNode())) {
- ghEdge = queryGraph.getOriginalEdgeFromVirtNode(source.getClosestNode());
- } else if (!edgesIt.hasNext() && queryGraph.isVirtualNode(target.getClosestNode())) {
- ghEdge = queryGraph.getOriginalEdgeFromVirtNode(target.getClosestNode());
- } else {
- continue;
- }
+ if (currEdge instanceof VirtualEdgeIteratorState) {
+ currEdge = graph.getEdgeIteratorStateForKey(((VirtualEdgeIteratorState) origEdge).getOriginalEdgeKey());
}
- Connection con = graphMapper.toConnection(ghEdge.getEdge());
+ Connection con = graphMapper.toConnection(currEdge.getEdge());
if (con != null) {
/*
* In some cases, virtual edges are created at the target even though they are only some
@@ -323,20 +417,56 @@ private CandidateRoute convertPath(Path newPath, QueryGraph queryGraph, QueryRes
continue;
}
+ if (pathConnections.isEmpty()) {
+ offsetFromSource = calcOffset(con, origEdge.getBaseNode(), nodes);
+ }
+
pathConnections.add(con.getId());
+ lastNode = origEdge.getAdjNode();
+ lastConnection = con;
if (Double.isInfinite(newPath.getWeight())) {
- log.warn(
+ LOG.warn(
"Something went wrong during path search: The found route has infinite weight. Maybe there's a turn restriction or unconnected "
+ "sub-graphs in the network. Route will be ignored.");
return null;
}
} else {
- log.debug(String.format("A connection could be resolved by internal ID %d.", ghEdge.getEdge()));
+ LOG.debug(String.format("A connection could be resolved by internal ID %d.", origEdge.getEdge()));
}
}
+
+ double offsetToTarget = 0;
+ if (lastConnection != null) {
+ offsetToTarget = lastConnection.getLength() - calcOffset(lastConnection, lastNode, nodes);
+ }
+
fixFirstConnectionOfPathIfNotAsQueried(sourcePosition, pathConnections);
- return new CandidateRoute(pathConnections, newPath.getDistance(), newPath.getTime() / (double) 1000);
+ return new CandidateRoute(
+ pathConnections,
+ newPath.getDistance(),
+ newPath.getTime() / 1000.0,
+ offsetFromSource,
+ offsetToTarget
+ );
+ }
+
+ private double calcOffset(Connection con, int node, NodeAccess nodes) {
+ GeoPoint onConnection = GeoPoint.latLon(nodes.getLat(node), nodes.getLon(node));
+ double offset = 0;
+ Node prev = null;
+ for (Node curr : con.getNodes()) {
+ if (prev != null) {
+ double distancePrevToCurr = prev.getPosition().distanceTo(curr.getPosition());
+ double distancePrevToNode = prev.getPosition().distanceTo(onConnection);
+ if (distancePrevToNode < distancePrevToCurr) {
+ return Math.max(con.getLength(), offset + distancePrevToNode);
+ }
+ offset += distancePrevToCurr;
+ }
+ prev = curr;
+ }
+ return con.getLength();
}
/**
@@ -356,12 +486,4 @@ private void fixFirstConnectionOfPathIfNotAsQueried(RoutingPosition sourcePositi
}
}
}
-
- private boolean checkRouteOnRequiredSourceConnection(CandidateRoute route, RoutingPosition source) {
- if (source.getConnectionId() != null) {
- return source.getConnectionId().equals(route.getConnectionIds().get(0));
- }
- return true;
- }
-
}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperWeighting.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperWeighting.java
index 2aae49a79..778ae9753 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperWeighting.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperWeighting.java
@@ -17,9 +17,11 @@
import org.eclipse.mosaic.lib.routing.RoutingCostFunction;
import org.eclipse.mosaic.lib.routing.graphhopper.util.GraphhopperToDatabaseMapper;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.VehicleEncoding;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.WayTypeEncoder;
-import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.routing.weighting.AbstractWeighting;
+import com.graphhopper.routing.weighting.TurnCostProvider;
import com.graphhopper.util.EdgeIteratorState;
/**
@@ -35,10 +37,15 @@ public class GraphHopperWeighting extends AbstractWeighting {
private RoutingCostFunction routingCostFunction;
- public GraphHopperWeighting(FlagEncoder encoder, GraphhopperToDatabaseMapper graphMapper) {
- super(encoder);
- this.edgePropertiesState = new GraphHopperEdgeProperties(encoder, graphMapper);
- this.maxSpeed = encoder.getMaxSpeed() / 3.6; // getMaxSpeed returns the speed in km/h
+ public GraphHopperWeighting(VehicleEncoding vehicleEncoding, WayTypeEncoder wayTypeEncoder, TurnCostProvider turnCostProvider, GraphhopperToDatabaseMapper graphMapper) {
+ super(vehicleEncoding.access(), vehicleEncoding.speed(), turnCostProvider);
+ this.edgePropertiesState = new GraphHopperEdgeProperties(vehicleEncoding, wayTypeEncoder, graphMapper);
+ this.maxSpeed = speedEnc.getMaxOrMaxStorableDecimal() / 3.6; // getMaxOrMaxStorableDecimal returns the speed in km/h
+ }
+
+ public GraphHopperWeighting setRoutingCostFunction(RoutingCostFunction routingCostFunction) {
+ this.routingCostFunction = routingCostFunction;
+ return this;
}
@Override
@@ -47,7 +54,15 @@ public double getMinWeight(double distance) {
}
@Override
- public double calcWeight(EdgeIteratorState edge, boolean reverse, int prevOrNextEdgeId) {
+ public double calcTurnWeight(int inEdge, int viaNode, int outEdge) {
+ return super.calcTurnWeight(inEdge, viaNode, outEdge);
+ }
+
+ @Override
+ public double calcEdgeWeight(EdgeIteratorState edge, boolean reverse) {
+ if (reverse ? !edge.getReverse(accessEnc) : !edge.get(accessEnc)) {
+ return Double.POSITIVE_INFINITY;
+ }
synchronized (edgePropertiesState) {
edgePropertiesState.setCurrentEdgeIterator(edge, reverse);
if (routingCostFunction == null) {
@@ -60,14 +75,10 @@ public double calcWeight(EdgeIteratorState edge, boolean reverse, int prevOrNext
public String getName() {
if (routingCostFunction == null) {
- return "null|" + flagEncoder;
+ return "fastest";
} else {
- return routingCostFunction.getCostFunctionName().toLowerCase() + "|" + flagEncoder;
+ return routingCostFunction.getCostFunctionName().toLowerCase();
}
}
- public void setRoutingCostFunction(RoutingCostFunction routingCostFunction) {
- this.routingCostFunction = routingCostFunction;
- }
-
}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphLoader.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphLoader.java
deleted file mode 100644
index 90dc388c5..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphLoader.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper;
-
-import org.eclipse.mosaic.lib.routing.graphhopper.util.GraphhopperToDatabaseMapper;
-
-import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.storage.GraphHopperStorage;
-
-/**
- * Encapsulates the import procedure of a MOSAIC scenario database into a GraphHopper readable GraphStorage.
- */
-public interface GraphLoader {
-
- /**
- * Initializes the import process.
- *
- */
- void initialize(GraphHopperStorage graph, EncodingManager encodingManager, GraphhopperToDatabaseMapper mapper);
-
- /**
- * Creates a graph.
- */
- void loadGraph();
-
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/TurnWeightingOptional.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/TurnWeightingOptional.java
deleted file mode 100644
index 939037a67..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/TurnWeightingOptional.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper;
-
-import com.graphhopper.routing.weighting.TurnWeighting;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.TurnCostExtension;
-
-/**
- * Extension of TurnWeighting which allows to disable
- * the consideration of turn costs while still considering turn restrictions.
- */
-class TurnWeightingOptional extends TurnWeighting {
-
- private final boolean enableTurnCosts;
- private final TurnCostExtension tcExt;
- private final double restrictedCosts;
-
- /**
- * Creates a {@link TurnWeighting} extension which disables or enables the consideration of turn costs, but always
- * considers turn restrictions.
- *
- * @param superWeighting the basic weighting implementation for road weighting
- * @param turnCostExt the turn cost extension of the graph
- * @param enableTurnCosts if true
, turn costs and restrictions are considered,
- * if false
, only turn restrictions are considered
- * @param restrictedCosts the costs to apply if a turn is restricted (use Double.POSITIVE_INFINITY to forbid turn)
- */
- public TurnWeightingOptional(Weighting superWeighting, TurnCostExtension turnCostExt, boolean enableTurnCosts, double restrictedCosts) {
- super(superWeighting, turnCostExt);
- this.tcExt = turnCostExt;
- this.restrictedCosts = restrictedCosts;
- this.enableTurnCosts = enableTurnCosts;
- }
-
- @Override
- public double calcTurnWeight(int edgeFrom, int nodeVia, int edgeTo) {
- long turnFlags = tcExt.getTurnCostFlags(edgeFrom, nodeVia, edgeTo);
- if (getFlagEncoder().isTurnRestricted(turnFlags)) {
- return restrictedCosts;
- }
-
- if (enableTurnCosts) {
- return getFlagEncoder().getTurnCost(turnFlags);
- }
- return 0;
- }
-
-}
\ No newline at end of file
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AStarCamvitChoiceRouting.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AStarCamvitChoiceRouting.java
deleted file mode 100644
index 72d44a6b9..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AStarCamvitChoiceRouting.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.algorithm;
-
-import com.carrotsearch.hppc.IntObjectMap;
-import com.graphhopper.routing.weighting.BeelineWeightApproximator;
-import com.graphhopper.routing.weighting.ConsistentWeightApproximator;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.Graph;
-import com.graphhopper.storage.SPTEntry;
-import com.graphhopper.util.EdgeExplorer;
-import com.graphhopper.util.EdgeIterator;
-import com.graphhopper.util.Helper;
-import edu.umd.cs.findbugs.annotations.SuppressWarnings;
-
-import java.util.PriorityQueue;
-
-/**
- * Calculates alternative routes next to the best route, by using bidirectional AStar as routing
- * engine and 'camvit choice routing' afterwards to determine alternative routes.
- *
- * @see AbstractCamvitChoiceRouting
- * @see
- */
-public class AStarCamvitChoiceRouting extends AbstractCamvitChoiceRouting {
-
- private final ConsistentWeightApproximator weightApprox;
-
- private int visitedToCount;
- private int visitedFromCount;
-
- /**
- * Creates a new {@link AStarCamvitChoiceRouting} object with a graph and the weighting of it.
- *
- * @param g The graph to check for suitability as alternative route.
- * @param weighting The weighting of the given graph.
- */
- public AStarCamvitChoiceRouting(Graph g, Weighting weighting) {
- super(g, weighting);
- BeelineWeightApproximator defaultApprox = new BeelineWeightApproximator(nodeAccess, weighting);
- defaultApprox.setDistanceCalc(Helper.DIST_PLANE);
- weightApprox = new ConsistentWeightApproximator(defaultApprox);
- }
-
- @Override
- public AbstractCamvitChoiceRouting initFrom(int from) {
-
- super.initFrom(from);
-
- weightApprox.setFrom(from);
-
- if (currTo != null) {
- currFrom.weight += weightApprox.approximate(currFrom.adjNode, false);
- currTo.weight += weightApprox.approximate(currTo.adjNode, true);
- }
- return this;
- }
-
- @Override
- public AbstractCamvitChoiceRouting initTo(int to) {
-
- super.initTo(to);
-
- weightApprox.setTo(to);
-
- if (currFrom != null) {
- currFrom.weight += weightApprox.approximate(currFrom.adjNode, false);
- currTo.weight += weightApprox.approximate(currTo.adjNode, true);
- }
-
- return this;
- }
-
- private void fillEdges(SPTEntry curr, PriorityQueue prioQueueOpenSet,
- IntObjectMap shortestWeightMap, EdgeExplorer explorer, boolean reverse) {
-
- int currNode = curr.adjNode;
- EdgeIterator iter = explorer.setBaseNode(currNode);
- while (iter.next()) {
- if (!accept(iter, curr)) {
- continue;
- }
-
- int traversalId = traversalMode.createTraversalId(iter, reverse);
- double alreadyVisitedWeight = weighting.calcWeight(iter, reverse, curr.edge) + curr.weight;
-
- if (Double.isInfinite(alreadyVisitedWeight)) {
- continue;
- }
-
- AStarSPTEntry de = (AStarSPTEntry) shortestWeightMap.get(traversalId);
- if (de == null || de.weight > alreadyVisitedWeight) {
-
- double currWeightToGoal = weightApprox.approximate(iter.getAdjNode(), reverse);
- double estimationFullDist = alreadyVisitedWeight + currWeightToGoal;
- if (de == null) {
- de = new AStarSPTEntry(iter.getEdge(), iter.getAdjNode(), alreadyVisitedWeight, estimationFullDist);
- shortestWeightMap.put(traversalId, de);
- } else {
- assert (de.weight > estimationFullDist) : "Inconsistent distance estimate";
- prioQueueOpenSet.remove(de);
- de.edge = iter.getEdge();
- de.weight = alreadyVisitedWeight;
- de.distanceEstimation = estimationFullDist;
- }
-
- de.parent = curr;
- prioQueueOpenSet.add(de);
- }
- }
- }
-
- /**
- * Creates the shortest path tree starting at the origin node.
- *
- * @return true
if creating the source tree has been finished, otherwise false
.
- */
- protected boolean fillEdgesFrom(IntObjectMap weights, PriorityQueue heap) {
- if (currFrom != null) {
- if (finished(currFrom, to)) {
- return true;
- }
-
- fillEdges(currFrom, heap, weights, outEdgeExplorer, false);
- visitedFromCount++;
- if (heap.isEmpty()) {
- return true;
- }
- currFrom = heap.poll();
-
- } else if (currTo == null) {
- //creating the source tree is finished when target tree has been finished as well
- return true;
- }
- return false;
- }
-
- protected boolean finished(SPTEntry currEdge, int to) {
- return currEdge.adjNode == to;
- }
-
- /**
- * Creates the shortest path tree in reverse direction starting at the target node.
- *
- * @return true
if creating the target tree has been finished, otherwise
- * false
- */
- protected boolean fillEdgesTo(IntObjectMap weights, PriorityQueue heap) {
- if (currTo != null) {
- if (finished(currTo, from)) {
- return true;
- }
- fillEdges(currTo, heap, weights, inEdgeExplorer, true);
- visitedToCount++;
- if (heap.isEmpty()) {
- return true;
- }
- currTo = heap.poll();
- } else if (currFrom == null) {
- //creating the target tree is finished when source tree has been finished as well
- return true;
- }
- return false;
- }
-
- @Override
- public int getVisitedNodes() {
- return visitedFromCount + visitedToCount;
- }
-
- @Override
- public String getName() {
- return "choiceroutingAstar";
- }
-
- @Override
- SPTEntry createEdge(int edgeId, int endNode, double distance) {
- return new AStarSPTEntry(edgeId, endNode, distance, 0);
- }
-
-
- /**
- * extension of the {@link SPTEntry} which uses
- * the distanceEstimation of AStar to sort existing
- * {@link SPTEntry}s instead of the actual weight.
- */
- @SuppressWarnings(
- value="EQ_COMPARETO_USE_OBJECT_EQUALS",
- justification = "Seems to be OK here, as extended class does not implement equals/hashCode anyhow. "
- )
- private static class AStarSPTEntry extends SPTEntry {
-
- private double distanceEstimation;
-
- private AStarSPTEntry(int edgeId, int node, double weightForHeap, double distanceEstimation) {
- super(edgeId, node, weightForHeap);
- // round makes distance smaller => heuristic should underestimate the distance!
- this.distanceEstimation = (float) distanceEstimation;
- }
-
-
- public int compareTo(SPTEntry o) {
- if (o instanceof AStarSPTEntry) {
- return Double.compare(this.distanceEstimation, ((AStarSPTEntry) o).distanceEstimation);
- } else {
- return super.compareTo(o);
- }
- }
- }
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AbstractCamvitChoiceRouting.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AbstractCamvitChoiceRouting.java
deleted file mode 100644
index b2a04bbe5..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AbstractCamvitChoiceRouting.java
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.algorithm;
-
-import com.carrotsearch.hppc.IntObjectHashMap;
-import com.carrotsearch.hppc.IntObjectMap;
-import com.carrotsearch.hppc.cursors.IntCursor;
-import com.graphhopper.routing.AbstractRoutingAlgorithm;
-import com.graphhopper.routing.Path;
-import com.graphhopper.routing.util.TraversalMode;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.Graph;
-import com.graphhopper.storage.SPTEntry;
-import com.graphhopper.util.EdgeIterator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.PriorityQueue;
-import java.util.Set;
-
-/**
- * Implementation of the 'Camvit Choice Routing' algorithm to calculate alternative routes next to
- * the best route. After building the source tree and target tree by the router on top of this
- * class, edges which are in both trees will be determined. Afterwards, all of those edges which are
- * connected to each other will be collected in a set of so called 'plateaus'. Those plateaus are
- * either good (many edges / highest weight) or bad (few edges / low weight). One plateau can be
- * used to calculate an alternative path from A to B going trough this plateau, by traversing from
- * the start of a plateau to A by using the target tree and by traversing from the end of the
- * plateau to B by using the source tree. By choosing the best plateau a good alternative route next
- * to the best route can be found.
- *
- * @see
- */
-public abstract class AbstractCamvitChoiceRouting extends AbstractRoutingAlgorithm implements AlternativeRoutesRoutingAlgorithm {
-
- private double constraintMaxShare = 0.9d;
- private double constraintMaxStretch = 0.8d;
- private double constraintMaxUniformlyBoundedStretch = 0.7d;
- private double constraintThresholdLocalOptimality = 0.3d;
- private double constraintMinLocalOptimality = 0.1d;
-
- private final Logger logger = LoggerFactory.getLogger(getClass());
-
- protected int from;
- protected int to;
-
- private IntObjectMap shortestWeightsFrom;
- private IntObjectMap shortestWeightsTo;
-
- private PriorityQueue heapFrom;
- private PriorityQueue heapTo;
-
- private boolean alreadyRun;
- SPTEntry currFrom;
- SPTEntry currTo;
-
- private PriorityQueue plateaus;
- private PriorityQueue relevantEdgesQ;
- private HashSet relevantEdgesIDs;
-
- private int requestAlternatives = 0;
-
- private List alternativePaths;
-
- AbstractCamvitChoiceRouting(Graph g, Weighting type) {
- super(g, type, TraversalMode.EDGE_BASED);
- initCollections(Math.max(20, graph.getNodes()));
- }
-
- /**
- * initializes all required collections and maps.
- *
- * @param nodes the number of nodes in the graph
- */
- private void initCollections(int nodes) {
- try {
- heapFrom = new PriorityQueue<>(nodes / 10);
- shortestWeightsFrom = new IntObjectHashMap<>(nodes / 10);
-
- heapTo = new PriorityQueue<>(nodes / 10);
- shortestWeightsTo = new IntObjectHashMap<>(nodes / 10);
- } catch (OutOfMemoryError e) {
- logger.error("Not sufficient memory", e);
- throw e;
- }
- }
-
-
-
- /**
- * Returns the identifier of an already traversed edge entry. In edge-based algorithms it is
- * usually the id of the edge, but it might be extended by a flag which signalizes the direction
- * of the edge (if algorithm is direction sensitive)-
- *
- * @return the identifier of an already traversed edge entry.
- */
- private int createTraversalIdentifier(SPTEntry iter, boolean reverse) {
- if (iter.parent != null) {
- return traversalMode.createTraversalId(iter.parent.adjNode, iter.adjNode, iter.edge, reverse);
- }
- return iter.edge;
-
- }
-
-
- /**
- * Determines, if the currently traversed edge should be continued with.
- *
- * @param edge the edge which is currently being traversed.
- * @param currEdge the preceding edge.
- * @return true
if this edge is acceptable to continue with.
- */
- protected boolean accept(EdgeIterator edge, SPTEntry currEdge) {
- return (currEdge.edge == EdgeIterator.NO_EDGE || edge.getEdge() != currEdge.edge) && super.accept(edge, currEdge.edge);
- }
-
- /**
- * Initializes the routing process by announcing the source node.
- *
- * @param from the source node
- */
- public AbstractCamvitChoiceRouting initFrom(int from) {
- this.from = from;
- currFrom = createEdge(EdgeIterator.NO_EDGE, from, 0);
- return this;
- }
-
- /**
- * Creates the first initial edge.
- *
- * @return an instance of CRAStarEdge
- */
- abstract SPTEntry createEdge(int edgeId, int endNode, double distance);
-
- /**
- * Initializes the routing process by announcing the target node.
- *
- * @param to the target node.
- */
- public AbstractCamvitChoiceRouting initTo(int to) {
- this.to = to;
- currTo = createEdge(EdgeIterator.NO_EDGE, to, 0);
- return this;
- }
-
- @Override
- public void setRequestAlternatives(int alternatives) {
- this.requestAlternatives = alternatives;
- }
-
- /**
- * Calculates the best and alternative paths between the specified nodes.
- *
- * @param from Start of the path.
- * @param to End of the path.
- * @return The calculated path.
- */
- @Override
- public Path calcPath(int from, int to) {
- if (alreadyRun) {
- throw new IllegalStateException("Create a new instance per call");
- }
- alreadyRun = true;
-
- alternativePaths = new ArrayList();
-
- logger.debug("calc " + (requestAlternatives + 1) + " paths from " + from + " to " + to);
-
- if (from == to) {
- return new Path(graph, weighting);
- }
-
- initFrom(from);
- initTo(to);
-
- boolean finished = false;
- while (!finished) {
- finished = fillEdgesFrom(shortestWeightsFrom, heapFrom) & fillEdgesTo(shortestWeightsTo,
- heapTo);
- }
-
- PlateauPath path = extractPath();
-
- if (requestAlternatives > 0) {
- // determine edges which has been traversed in both source and target
- // tree
- determineRelevantEdges(path.getWeight());
-
- // determine edges which are connected with each other
- determinePlateaus(path.getWeight());
-
- // extracts alternative paths
- calculateAlternativePaths(path);
- }
-
- return path;
- }
-
- /**
- * Returns a list of alternative paths (not including the optimal path).
- *
- * @return The alternative paths, is empty if no alternative paths have been requested.
- */
- @Override
- public List getAlternativePaths() {
- return alternativePaths;
- }
-
- public PlateauPath extractPath() {
- PlateauPath path = (PlateauPath) new PlateauPath(graph, weighting).setSPTEntry(currFrom).extract();
- path.setWeight(currFrom.weight);
- return path;
- }
-
- /**
- * Executes one step of traversal in forward direction starting at the source node.
- *
- * @return true
if creating the source tree has been finished, otherwise
- * false
- */
- abstract boolean fillEdgesFrom(IntObjectMap weights, PriorityQueue heap);
-
- /**
- * Executes one step of traversal in backward direction starting at the target node.
- *
- * @return true
if creating the target tree has been finished, otherwise
- * false
- */
- abstract boolean fillEdgesTo(IntObjectMap weights, PriorityQueue heap);
-
- /**
- * @return true
, if both path searches reached their final node.
- */
- abstract boolean finished(SPTEntry currEdge, int to);
-
- @Override
- protected boolean finished() {
- throw new UnsupportedOperationException("Not required");
- }
-
- /**
- * Collects all edges which have been traversed by both forward and backward path searches. All
- * edges receive a weighting depending on their distances towards the target and source node.
- * Furthermore, edges which are far away from the best path are ignored to speed up the search.
- *
- * @param optimalWeight the weight of the optimal path.
- */
- private void determineRelevantEdges(double optimalWeight) {
- relevantEdgesQ = new PriorityQueue<>(Math.max(1, shortestWeightsFrom.size() / 10),
- Comparator.comparingDouble(o -> o.rating)
- );
-
- relevantEdgesIDs = new HashSet<>();
-
- double maxWeight = optimalWeight * (1.0d + constraintMaxStretch);
-
- for (IntCursor key : shortestWeightsFrom.keys()) {
- SPTEntry edge = shortestWeightsFrom.get(key.value);
- if (edge.parent != null) {
- SPTEntry edgeOfTargetTree = shortestWeightsTo.get(key.value);
- if (edgeOfTargetTree != null && edgeOfTargetTree.edge == edge.edge && edge.adjNode != edgeOfTargetTree.adjNode) {
- //create a new relevant edge if it has been found in both search trees
- //the rating is composed by the distances of the edge towards source and target
-
- RelEdge relEdge = new RelEdge();
- relEdge.fwd = edge;
- relEdge.bwd = edgeOfTargetTree;
- relEdge.rating = (edgeOfTargetTree.parent != null)
- ? edge.weight + edgeOfTargetTree.parent.weight
- : edgeOfTargetTree.weight + edge.parent.weight;
-
- if (relEdge.rating < maxWeight && relEdge.fwd.weight < Double.MAX_VALUE
- && relEdge.bwd.weight < Double.MAX_VALUE) {
- relevantEdgesQ.add(relEdge);
- relevantEdgesIDs.add(key.value);
- }
- }
- }
- }
- }
-
- /**
- * The set of relevant edges is used to build plateaus. A plateau consists of a sequence of
- * relevant edges. If a plateau has been built, all its edges are removed out of the set of
- * relevant edges. The relevant edge with the lowest rating is used to build the next plateau.
- *
- * @param optimalWeight the weight of the optimal path.
- */
- private void determinePlateaus(double optimalWeight) {
- plateaus = new PriorityQueue(Math.max(1, relevantEdgesQ.size() / 10),
- new Comparator() {
- @Override
- public int compare(Plateau o1, Plateau o2) {
- // sub paths with equal rating but highest weight on top
- int r = Double.compare(o1.rating(), o2.rating());
- if (r == 0) {
- return Double.compare(o1.weight(), o2.weight());
- } else {
- return r;
- }
- }
- });
-
- double bestRating = Double.MAX_VALUE;
-
- while (!relevantEdgesQ.isEmpty()) {
- RelEdge relEdge = relevantEdgesQ.poll();
-
- bestRating = Math.min(relEdge.rating, bestRating);
-
- // if edge pointers of current relevant edge is already a member of
- // a plateau, reject this relevant edge
- if (!relevantEdgesIDs.contains(createTraversalIdentifier(relEdge.fwd, false))
- && !relevantEdgesIDs.contains(createTraversalIdentifier(relEdge.bwd, true))) {
- continue;
- }
-
- // if rating is twice expensive than best rating, then cancel search
- // for plateaus
- if (relEdge.rating > bestRating * 2) {
- relevantEdgesQ.clear();
- break;
- }
-
- // create new plateau
- Plateau plateau = new Plateau();
- plateau.start = relEdge.fwd;
- plateau.startRev = relEdge.bwd;
- plateau.targetRev = relEdge.bwd;
-
- // the distance of relevant edge from target
- double distance = plateau.startRev.weight;
-
- // traverse backward until we found the start of the plateaus, that
- // is as long the parent edge is relevant
- SPTEntry tmp = plateau.start.parent;
- while (tmp != null && tmp.parent != null
- && relevantEdgesIDs.remove(createTraversalIdentifier(tmp, false))
- ) {
- distance += tmp.weight - tmp.parent.weight;
- // build new edge entry for the backward pointer startRev
- SPTEntry entry = new SPTEntry(tmp.edge, tmp.parent.adjNode, distance);
- entry.parent = plateau.startRev;
- plateau.startRev = entry;
- plateau.start = tmp;
- tmp = tmp.parent;
- }
-
- // traverse forward until we found the end of the plateaus
- tmp = plateau.targetRev.parent;
- while (tmp != null && tmp.parent != null
- && relevantEdgesIDs.remove(createTraversalIdentifier(tmp, true))
- ) {
- plateau.targetRev = tmp;
- tmp = tmp.parent;
- }
-
- // the local optimality = weight of plateau / weight of optimal path
- plateau.localOptimality = (plateau.startRev.weight - plateau.targetRev.parent.weight) / optimalWeight;
-
- // if plateau consists of only one edge or is not locally optimal,
- // then reject it
- if (plateau.start.edge != plateau.targetRev.edge && plateau.localOptimality >= constraintMinLocalOptimality) {
- plateaus.add(plateau);
- }
-
- // mark the relevant edge as used
- relevantEdgesIDs.remove(createTraversalIdentifier(relEdge.fwd, false));
- relevantEdgesIDs.remove(createTraversalIdentifier(relEdge.bwd, true));
- }
-
- // we don't need those anymore
- relevantEdgesIDs.clear();
- }
-
- /**
- * Out of the plateaus, path are generated.
- *
- * @param optimalPath the optimal path
- */
- private void calculateAlternativePaths(PlateauPath optimalPath) {
- alternativePaths.clear();
-
- if (requestAlternatives == 0) {
- return;
- }
-
- if (plateaus != null) {
- // the first subPath is also the best path we've already found, so
- // we refuse it as an alternative
- plateaus.poll();
- }
-
- // add alternative paths as long as their weight is not greater than
- // weight of original path + drift
- PlateauPath nextPath = createPathFromPlateau(optimalPath);
- while (nextPath != null) {
-
- // logger.debug("Found next path: weight "+nextPath.getWeight()+"");
- alternativePaths.add(nextPath);
- // continue with next path, if we not yet have the desired number of
- // paths (maxPath < 0 means as many as possible)
- nextPath = (alternativePaths.size() < requestAlternatives || requestAlternatives < 0) ? createPathFromPlateau(
- optimalPath) : null;
- }
- }
-
- private PlateauPath createPathFromPlateau(PlateauPath optimalPath) {
- if (plateaus.isEmpty()) {
- return null;
- }
-
- // get plateau with highest weight (the next best sub path)
- final Plateau plateau = plateaus.poll();
-
- // weight of path
- final double pathWeight = plateau.startRev.weight + plateau.start.weight;
-
- // weight of plateau
- final double plateauWeight = plateau.startRev.weight - plateau.targetRev.parent.weight;
-
- double ubs = 0;
-
- // if local optimality is below a certain threshold, the uniformly
- // bounded stretch will be calculated (quite expensive procedure)
- if (plateau.localOptimality < constraintThresholdLocalOptimality) {
- double maxWeight = plateauWeight + (optimalPath.getWeight() - plateauWeight) / 2;
-
- while (maxWeight > plateauWeight * 1.5d) {
- ubs = Math.max(ubs, calculateUniformleyBoundedStretch(plateau, maxWeight));
- maxWeight = plateauWeight + (maxWeight - plateauWeight) / 2;
-
- //if UBS exceeds the max value, the path will be rejected
- if (ubs > constraintMaxUniformlyBoundedStretch) {
- return createPathFromPlateau(optimalPath);
- }
- }
- }
-
- final String debugInfo = String.format(Locale.ENGLISH,
- "%s, ubs: %.2f, lo: %.2f, weight_optimal: %.2f, weight_plateau: %.2f",
- createPlateauString(plateau), ubs, plateau.localOptimality, optimalPath.getWeight(),
- plateauWeight);
- final PlateauPath path = new PlateauPath(graph, weighting) {
- public String getDebugInfo() {
- return debugInfo;
- }
- };
-
- // target node
- final int to = optimalPath.getSptEntry().adjNode;
-
- // create path by traversing downwards until target node
- SPTEntry targetEdge = plateau.start;
- SPTEntry currentRevOfPlateau = plateau.startRev.parent;
- while (currentRevOfPlateau != null) {
- int endNode = (currentRevOfPlateau.parent != null) ? currentRevOfPlateau.parent.adjNode : to;
- SPTEntry newEntry = new SPTEntry(currentRevOfPlateau.edge, endNode, pathWeight - currentRevOfPlateau.weight);
- newEntry.parent = targetEdge;
- targetEdge = newEntry;
- currentRevOfPlateau = currentRevOfPlateau.parent;
- if (endNode == to) {
- break;
- }
- }
- path.setWeight(targetEdge.weight);
- path.setSPTEntry(targetEdge).extract();
-
- if (filter(optimalPath, path)) {
- return createPathFromPlateau(optimalPath);
- } else {
- return path;
- }
- }
-
- /**
- * Applies several filters on a newly generated path. If one filter returns true, the new path
- * will be rejected. Following filters are applied:-
- * Route Share
-
- * Route Stretch
-
- * Contains loop
- */
- private boolean filter(PlateauPath optimalPath, PlateauPath newPath) {
- /*
- * it is sufficient to check similarity against the best path only,
- * because plateaus derive only from the best path.
- */
- if (checkSimilarity(optimalPath, newPath) > constraintMaxShare) {
- return true;
- }
-
- // filter route, if it's more than 1+STRETCH_MAX times longer (distance)
- // than the shortest (distance) route
- if (newPath.getDistance() > optimalPath.getDistance() * (1 + constraintMaxStretch)) {
- return true;
- }
-
- if (containsLoop(newPath)) {
- return true;
- }
-
- return false;
- }
-
- /**
- * This method checks whether a loop between the new and the previous founded paths exist.
- *
- * @param newPath The new path to check for loop.
- * @return True if it contains a loop.
- */
- private boolean containsLoop(PlateauPath newPath) {
- Set visitedEdges = new HashSet<>();
-
- // first edge of already found path
- SPTEntry edge = newPath.getSptEntry();
-
- while (edge.parent.edge != EdgeIterator.NO_EDGE) {
- if (!visitedEdges.add(createTraversalIdentifier(edge, false))) {
- return true;
- }
- edge = edge.parent;
- }
-
- return false;
- }
-
- /**
- * This method checks the similarity between an existing and new path.
- *
- * @param existingPath The existing path to check for similarity with a new path.
- * @param newPath The new path to check for similarity with an existing path.
- * @return A factor, which indicating the similarity.
- */
- private double checkSimilarity(PlateauPath existingPath, PlateauPath newPath) {
-
- Set edgesOfOriginal = new HashSet();
- // first edge of already found path
- SPTEntry edge1 = existingPath.getSptEntry();
- // first edge of new path
- SPTEntry edge2 = newPath.getSptEntry();
-
- while (edge1.parent.edge != EdgeIterator.NO_EDGE) {
- edgesOfOriginal.add(edge1.edge);
- edge1 = edge1.parent;
- }
-
- double sharedWeight = 0.0d;
- while (edge2.parent.edge != EdgeIterator.NO_EDGE) {
- if (edgesOfOriginal.remove(edge2.edge)) {
- sharedWeight += Math.abs(edge2.weight - edge2.parent.weight);
- }
- edge2 = edge2.parent;
- }
-
- return sharedWeight / existingPath.getWeight();
- }
-
- /**
- * Calculates the value for uniformly bounded stretch (UBS) for a plateau. UBS describes the
- * stretch of the full detour. Since a shortest path search is required this procedure is quite
- * expensive.
- *
- * @return the stretch of the detour (0 means no stretch)
- */
- private double calculateUniformleyBoundedStretch(Plateau plateau, double maxWeight) {
-
- // the weight of the plateau
- double weightDetour = plateau.startRev.weight - plateau.targetRev.parent.weight;
-
- // the start and end edge of the plateau (pointers)
- SPTEntry start = plateau.start;
- SPTEntry end = plateau.targetRev;
-
- while (start.parent.edge != EdgeIterator.NO_EDGE || end.parent.edge != EdgeIterator.NO_EDGE) {
-
- // move the start point towards the source and add its weight
- if (start.parent.edge != EdgeIterator.NO_EDGE) {
- weightDetour += (start.weight - start.parent.weight);
- start = start.parent;
- }
-
- // move the end point towards the target and add its weight
- if (end.parent.edge != EdgeIterator.NO_EDGE) {
- weightDetour += (end.weight - end.parent.weight);
- end = end.parent;
- }
-
- if (weightDetour >= maxWeight) {
- double weightShortest = calculateWeightOfShortestSubPath(start, end);
- return weightDetour / weightShortest - 1;
- }
- }
- return 0;
- }
-
- private double calculateWeightOfShortestSubPath(SPTEntry start, SPTEntry end) {
- from = start.adjNode;
- to = end.adjNode;
- initCollections(Math.max(20, graph.getNodes()));
- initFrom(from);
- initTo(to);
- boolean finished = false;
- while (!finished) {
- finished = fillEdgesFrom(shortestWeightsFrom, heapFrom);
- }
- return currFrom.weight;
- }
-
- /**
- * Creates a {@link String} for the {@link Plateau} with start and end points.
- *
- * @param plateau The {@link Plateau} for which to create the string.
- * @return The created {@link Plateau} string.
- */
- private String createPlateauString(Plateau plateau) {
- StringBuilder plateauString = new StringBuilder();
- plateauString.append("plateau: ");
- SPTEntry tmpEdge = plateau.startRev;
- while (tmpEdge.parent.edge != EdgeIterator.NO_EDGE && tmpEdge.edge != plateau.targetRev.edge) {
- plateauString.append(tmpEdge.edge);
- plateauString.append("|");
- if (tmpEdge.parent.edge == plateau.targetRev.edge) {
- plateauString.append(tmpEdge.parent.edge);
- }
- tmpEdge = tmpEdge.parent;
- }
- return plateauString.toString();
- }
-
- /**
- * Represents a relevant edge. A relevant edge has been traversed by both path searches.
- */
- public static class RelEdge {
-
- /**
- * EdgeEntry whose parent points along the shortest path towards the source node. Its weight
- * is the distance from this edge to the source node.
- */
- SPTEntry fwd;
-
- /**
- * EdgeEntry whose parent points along the shortest path towards the target node. Its weight
- * is the distance from this edge to the target node.
- */
- SPTEntry bwd;
-
- /**
- * A rating of the relevant edge which is composed of the sum of the costs of both edge
- * entries.
- */
- double rating;
- }
-
- /**
- * A plateau represents a sequence of edges which have been traversed by both path searches.
- */
- public static class Plateau {
-
- /**
- * Marks the start of the plateau and points towards the source of the path. By following
- * its parents the shortest path from the start of the plateau towards the source node can
- * be determined.
- */
- SPTEntry start;
-
- /**
- * Marks the start of the plateau and points towards the target of the path. By following
- * its parents the path along the plateau towards the target can be determined.
- */
- SPTEntry startRev;
-
- /**
- * Marks the end of the plateau and points towards the target of the path. By following its
- * parents the shortest path from the end of the plateau towards the target node can be
- * determined.
- */
- SPTEntry targetRev;
-
- /**
- * Stores the local optimality of the plateau which has previously been calculated.
- */
- double localOptimality;
-
- /**
- * Calculates the weight of the resulting path of the plateau.
- */
- public double weight() {
- if (start.parent == null) {
- return startRev.weight;
- } else {
- return start.parent.weight + startRev.weight;
- }
- }
-
- /**
- * Calculates the rating of the plateau. The farther away from source or target the higher
- * the rating.
- */
- public double rating() {
- double costsAtStartOfPlateau = (start.parent == null) ? 0 : start.parent.weight;
- double costsAtEndOfPlateau = (targetRev.parent == null) ? 0 : targetRev.parent.weight;
-
- return costsAtStartOfPlateau + costsAtEndOfPlateau;
-
- }
- }
-
- public final void setUbsMax(double ubsMax) {
- this.constraintMaxUniformlyBoundedStretch = ubsMax;
- }
-
- public final void setRouteShareMax(double shareMax) {
- this.constraintMaxShare = shareMax;
- }
-
- public final void setRouteStretchMax(double stretchMax) {
- this.constraintMaxStretch = stretchMax;
- }
-
- public final void setLocalOptimalityMin(double loMin) {
- this.constraintMinLocalOptimality = loMin;
- }
-
- public final void setUbsThreshold(double ubsThreshold) {
- this.constraintThresholdLocalOptimality = ubsThreshold;
- }
-
-
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AlternativeRoutesRoutingAlgorithm.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AlternativeRoutesRoutingAlgorithm.java
deleted file mode 100644
index 12370853c..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AlternativeRoutesRoutingAlgorithm.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.algorithm;
-
-import com.graphhopper.routing.Path;
-import com.graphhopper.routing.RoutingAlgorithm;
-
-import java.util.List;
-
-/**
- * Mark an routing algorithm which is able to generate alternative routes.
- */
-public interface AlternativeRoutesRoutingAlgorithm extends RoutingAlgorithm {
-
- /**
- * Defines the number of additional alternative routes to calculate.
- *
- * @param alternatives the number of alternative routes.
- */
- void setRequestAlternatives(int alternatives);
-
- /**
- * Returns all alternative paths excluding the best path.
- *
- * @return all alternative paths
- */
- List getAlternativePaths();
-
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/BellmanFordRouting.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/BellmanFordRouting.java
index 229b6f3af..e3f4a3577 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/BellmanFordRouting.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/BellmanFordRouting.java
@@ -20,14 +20,16 @@
import com.carrotsearch.hppc.cursors.IntObjectCursor;
import com.graphhopper.routing.AbstractRoutingAlgorithm;
import com.graphhopper.routing.Path;
-import com.graphhopper.routing.util.DefaultEdgeFilter;
+import com.graphhopper.routing.PathExtractor;
+import com.graphhopper.routing.SPTEntry;
import com.graphhopper.routing.util.TraversalMode;
import com.graphhopper.routing.weighting.Weighting;
import com.graphhopper.storage.Graph;
-import com.graphhopper.storage.SPTEntry;
import com.graphhopper.util.EdgeExplorer;
import com.graphhopper.util.EdgeIterator;
import com.graphhopper.util.EdgeIteratorState;
+import com.graphhopper.util.GHUtility;
+import com.graphhopper.util.PMap;
/**
* Implementation of the Bellman-Ford algorithm which supports negative edge costs.
@@ -39,16 +41,13 @@ public class BellmanFordRouting extends AbstractRoutingAlgorithm {
private final IntObjectMap edgeEntries = new IntObjectHashMap<>();
private final IntObjectMap nodeEntries = new IntObjectHashMap<>();
- private SPTEntry toNode = null;
- private boolean finished = false;
-
/**
* Creates a new {@link BellmanFordRouting} object based on the {@link AbstractRoutingAlgorithm}.
*
* @param graph specifies the graph where this algorithm will run on.
* @param weighting set the used weight calculation (e.g. fastest, shortest).
*/
- public BellmanFordRouting(Graph graph, Weighting weighting) {
+ public BellmanFordRouting(Graph graph, Weighting weighting, PMap hints) {
super(graph, weighting, TraversalMode.EDGE_BASED);
}
@@ -61,12 +60,9 @@ public BellmanFordRouting(Graph graph, Weighting weighting) {
*/
@Override
public Path calcPath(int from, int to) {
- finished = false;
-
edgeEntries.clear();
nodeEntries.clear();
- toNode = null;
-
+
determineAllEdges();
createStartCondition(from);
@@ -83,9 +79,11 @@ public Path calcPath(int from, int to) {
throw new IllegalStateException("There's a cycle with negative weights.");
}
- toNode = nodeEntries.get(to);
- finished = true;
- return extractPath();
+ SPTEntry toNode = nodeEntries.get(to);
+ if (toNode != null) {
+ return PathExtractor.extractPath(graph, weighting, toNode);
+ }
+ return null;
}
/**
@@ -110,7 +108,7 @@ private boolean updateWeightsOfEdges() {
continue;
}
- tmpWeight = this.weighting.calcWeight(edgeIt, false, u.edge) + u.weight;
+ tmpWeight = GHUtility.calcWeightWithTurnWeight(weighting, edgeIt, false, u.edge) + u.weight;
if (tmpWeight < edge.weight) {
edge.weight = tmpWeight;
@@ -127,12 +125,12 @@ private boolean updateWeightsOfEdges() {
}
private void determineAllEdges() {
- final EdgeExplorer edgeExplorer = graph.createEdgeExplorer(DefaultEdgeFilter.outEdges(flagEncoder));
+ final EdgeExplorer edgeExplorer = graph.createEdgeExplorer();
for (int node = 0; node < graph.getNodes(); node++) {
EdgeIterator edgeIt = edgeExplorer.setBaseNode(node);
while (edgeIt.next()) {
- SPTEntry entry = new SPTEntry(edgeIt.getEdge(), edgeIt.getAdjNode(), Double.POSITIVE_INFINITY);
+ SPTEntry entry = new SPTEntry(edgeIt.getEdge(), edgeIt.getAdjNode(), Double.POSITIVE_INFINITY, null);
int id = traversalMode.createTraversalId(edgeIt, false);
edgeEntries.put(id, entry);
nodeEntries.put(edgeIt.getAdjNode(), entry);
@@ -141,24 +139,11 @@ private void determineAllEdges() {
}
private void createStartCondition(int from) {
- nodeEntries.put(from, new SPTEntry(EdgeIterator.NO_EDGE, from, 0));
+ nodeEntries.put(from, new SPTEntry(from, 0));
}
@Override
public int getVisitedNodes() {
return this.graph.getNodes();
}
-
- @Override
- protected boolean finished() {
- return finished;
- }
-
- @Override
- protected Path extractPath() {
- if (toNode != null) {
- return new Path(this.graph, this.weighting).setWeight(toNode.weight).setSPTEntry(toNode).extract();
- }
- return null;
- }
}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/DijkstraCamvitChoiceRouting.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/DijkstraCamvitChoiceRouting.java
deleted file mode 100644
index fdca81214..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/DijkstraCamvitChoiceRouting.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.algorithm;
-
-import com.carrotsearch.hppc.IntObjectMap;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.Graph;
-import com.graphhopper.storage.SPTEntry;
-import com.graphhopper.util.EdgeExplorer;
-import com.graphhopper.util.EdgeIterator;
-
-import java.util.PriorityQueue;
-
-/**
- * Calculates alternative routes next to the best route, by using bidirectional Dijkstra as routing
- * engine and 'camvit choice routing' afterwards to determine alternative routes.
- *
- * @see AbstractCamvitChoiceRouting
- * @see
- */
-public class DijkstraCamvitChoiceRouting extends AbstractCamvitChoiceRouting {
-
- private int visitedToCount;
- private int visitedFromCount;
-
- /**
- * Creates a new {@link DijkstraCamvitChoiceRouting} object while using Dijkstra and camvit choice routing.
- *
- * @param g Specifies the graph where this algorithm will run on.
- * @param type Set the used weight calculation.
- */
- public DijkstraCamvitChoiceRouting(Graph g, Weighting type) {
- super(g, type);
- }
-
- void fillEdges(SPTEntry curr, PriorityQueue prioQueue,
- IntObjectMap shortestWeightMap, EdgeExplorer explorer, boolean reverse) {
-
- EdgeIterator iter = explorer.setBaseNode(curr.adjNode);
- while (iter.next()) {
- if (!accept(iter, curr)) {
- continue;
- }
-
- int traversalId = traversalMode.createTraversalId(iter, reverse);//createTraversalIdentifier(iter, reverse);
- double tmpWeight = weighting.calcWeight(iter, reverse, curr.edge) + curr.weight;
-
- if (Double.isInfinite(tmpWeight)) {
- continue;
- }
-
- SPTEntry de = shortestWeightMap.get(traversalId);
- if (de == null) {
- de = new SPTEntry(iter.getEdge(), iter.getAdjNode(), tmpWeight);
- de.parent = curr;
- shortestWeightMap.put(traversalId, de);
- prioQueue.add(de);
- } else if (de.weight > tmpWeight) {
- prioQueue.remove(de);
- de.edge = iter.getEdge();
- de.weight = tmpWeight;
- de.parent = curr;
- prioQueue.add(de);
- }
- }
- }
-
- /**
- * Creates the shortest path tree starting at the source node.
- *
- * @return true
if creating the source tree has been finished, otherwise
- * false
- */
- protected boolean fillEdgesFrom(IntObjectMap weights, PriorityQueue heap) {
- if (currFrom != null) {
- if (finished(currFrom, to)) {
- return true;
- }
-
- fillEdges(currFrom, heap, weights, outEdgeExplorer, false);
- visitedFromCount++;
- if (heap.isEmpty()) {
- return true;
- }
- currFrom = heap.poll();
-
- } else if (currTo == null) {
- //creating the source tree is finished when target tree has been finished as well
- return true;
- }
- return false;
- }
-
- protected boolean finished(SPTEntry currEdge, int to) {
- return currEdge.adjNode == to;
- }
-
- /**
- * Creates the shortest path tree in reverse direction starting at the target node.
- *
- * @return true
if creating the target tree has been finished, otherwise
- * false
- */
- protected boolean fillEdgesTo(IntObjectMap weights, PriorityQueue heap) {
- if (currTo != null) {
- if (finished(currTo, from)) {
- return true;
- }
- fillEdges(currTo, heap, weights, inEdgeExplorer, true);
- visitedToCount++;
- if (heap.isEmpty()) {
- return true;
- }
- currTo = heap.poll();
- } else if (currFrom == null) {
- //creating the target tree is finished when source tree has been finished as well
- return true;
- }
- return false;
- }
-
- @Override
- public int getVisitedNodes() {
- return visitedFromCount + visitedToCount;
- }
-
- @Override
- public String getName() {
- return "choicerouting";
- }
-
- @Override
- SPTEntry createEdge(int edgeId, int endNode, double distance) {
- return new SPTEntry(edgeId, endNode, distance);
- }
-
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/PlateauPath.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/PlateauPath.java
deleted file mode 100644
index c72902500..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/PlateauPath.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.algorithm;
-
-import com.graphhopper.routing.Path;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.Graph;
-import com.graphhopper.storage.SPTEntry;
-
-/**
- * Extension of {@link Path} providing access to the shortest path tree entry ({@link SPTEntry}).
- */
-class PlateauPath extends Path {
-
- PlateauPath(Graph graph, Weighting weighting) {
- super(graph, weighting);
- }
-
- SPTEntry getSptEntry() {
- return sptEntry;
- }
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/RoutingAlgorithmFactory.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/RoutingAlgorithmFactory.java
index 9e08e9cff..e061ad6a0 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/RoutingAlgorithmFactory.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/RoutingAlgorithmFactory.java
@@ -15,16 +15,33 @@
package org.eclipse.mosaic.lib.routing.graphhopper.algorithm;
+import org.eclipse.mosaic.lib.routing.graphhopper.GraphHopperRouting;
+
+import com.graphhopper.routing.AStarBidirection;
+import com.graphhopper.routing.AlternativeRoute;
import com.graphhopper.routing.RoutingAlgorithm;
+import com.graphhopper.routing.util.TraversalMode;
import com.graphhopper.routing.weighting.Weighting;
import com.graphhopper.storage.Graph;
+import com.graphhopper.util.PMap;
+import com.graphhopper.util.Parameters;
/**
* Factory to instantiate the routing algorithm to be used.
*/
public interface RoutingAlgorithmFactory {
- RoutingAlgorithmFactory CHOICE_ROUTING_DIJKSTRA = DijkstraCamvitChoiceRouting::new;
+ RoutingAlgorithmFactory DEFAULT = (graph, weighting, hints) -> {
+ if (hints.getInt(Parameters.Algorithms.AltRoute.MAX_PATHS, 1) > 1) {
+ hints.putObject(Parameters.Algorithms.AltRoute.MAX_SHARE, GraphHopperRouting.ALTERNATIVE_ROUTES_MAX_SHARE);
+ hints.putObject(Parameters.Algorithms.AltRoute.MAX_WEIGHT, GraphHopperRouting.ALTERNATIVE_ROUTES_MAX_WEIGHT);
+ hints.putObject("alternative_route.max_exploration_factor", GraphHopperRouting.ALTERNATIVE_ROUTES_EXPLORATION_FACTOR);
+ hints.putObject("alternative_route.min_plateau_factor", GraphHopperRouting.ALTERNATIVE_ROUTES_PLATEAU_FACTOR);
+ return new AlternativeRoute(graph, weighting, TraversalMode.EDGE_BASED, hints);
+ } else {
+ return new AStarBidirection(graph, weighting, TraversalMode.EDGE_BASED);
+ }
+ };
RoutingAlgorithmFactory BELLMAN_FORD = BellmanFordRouting::new;
@@ -32,10 +49,10 @@ public interface RoutingAlgorithmFactory {
* Creates a {@link RoutingAlgorithm} instance for calculating routes based
* on the given {@link Graph} and {@link Weighting} function.
*
- * @param graph the {@link Graph} containing the network to find routes in
+ * @param graph the {@link Graph} containing the network to find routes in
* @param weighting the cost function
* @return the {@link RoutingAlgorithm}
*/
- RoutingAlgorithm createAlgorithm(Graph graph, Weighting weighting);
+ RoutingAlgorithm createAlgorithm(Graph graph, Weighting weighting, PMap hints);
}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHPoint.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHPoint.java
deleted file mode 100644
index 3b3a22125..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHPoint.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.extended;
-
-import com.graphhopper.util.NumHelper;
-import com.graphhopper.util.shapes.GHPoint;
-
-public class ExtendedGHPoint extends GHPoint {
-
- private final int edgeId;
-
- public ExtendedGHPoint(double lat, double lon, int edgeId) {
- super(lat, lon);
- this.edgeId = edgeId;
- }
-
- public int getEdgeId() {
- return edgeId;
- }
-
- @Override
- public int hashCode() {
- int hash = super.hashCode();
- hash = 83 * hash + edgeId;
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!super.equals(obj) || !(obj instanceof ExtendedGHPoint)) {
- return false;
- }
- return NumHelper.equals(edgeId, ((ExtendedGHPoint) obj).edgeId);
- }
-
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHRequest.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHRequest.java
deleted file mode 100644
index e71d6e837..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHRequest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.extended;
-
-import org.eclipse.mosaic.lib.routing.graphhopper.algorithm.RoutingAlgorithmFactory;
-
-import com.graphhopper.GHRequest;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.Graph;
-import com.graphhopper.util.shapes.GHPoint;
-
-/**
- * Extends GHRequest by providing instances of weighting and algorithms preparation instead of
- * defining string constants. Additionally the number of alternative routes can be set in this
- * request.
- *
- */
-public class ExtendedGHRequest extends GHRequest {
-
- protected WeightingFactory weightingFactory;
- protected int alternatives;
- protected RoutingAlgorithmFactory routingAlgorithmFactory;
-
- public ExtendedGHRequest(GHPoint from, GHPoint to) {
- super(from, to);
- this.routingAlgorithmFactory = RoutingAlgorithmFactory.CHOICE_ROUTING_DIJKSTRA;
- }
-
- public ExtendedGHRequest setWeightingFactory(WeightingFactory w) {
- this.weightingFactory = w;
- return this;
- }
-
- public WeightingFactory getWeightingFactory() {
- return weightingFactory;
- }
-
- public Weighting getWeightingInstance(Graph graph) {
- return weightingFactory.create(graph);
- }
-
- public int getAlternatives() {
- return alternatives;
- }
-
- public void setAlternatives(int alternatives) {
- this.alternatives = alternatives;
-
- }
-
- public RoutingAlgorithmFactory getAlgorithmFactory() {
- return routingAlgorithmFactory;
- }
-
- public void setRoutingAlgorithmFactory(RoutingAlgorithmFactory routingAlgorithmFactory) {
- this.routingAlgorithmFactory = routingAlgorithmFactory;
- }
-
- public interface WeightingFactory {
- Weighting create(Graph graph);
- }
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHResponse.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHResponse.java
deleted file mode 100644
index e73f24c2a..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGHResponse.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.extended;
-
-import com.graphhopper.GHResponse;
-import com.graphhopper.routing.Path;
-
-import java.util.List;
-import java.util.Vector;
-
-/**
- * Extends the response of a routing request by providing the calculated path and several child
- * response containing alternative routes.
- */
-public class ExtendedGHResponse extends GHResponse {
-
- private Path path;
- private List responses;
-
- public ExtendedGHResponse setPath(Path path) {
- this.path = path;
- this.responses = new Vector<>();
- return this;
- }
-
- public Path getPath() {
- return path;
- }
-
- public List getAdditionalRoutes() {
- return responses;
- }
-
- public void addRouteResponse(ExtendedGHResponse rsp) {
- this.responses.add(rsp);
- }
-
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGraphHopper.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGraphHopper.java
deleted file mode 100644
index ff96b5bd0..000000000
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/extended/ExtendedGraphHopper.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.extended;
-
-import org.eclipse.mosaic.lib.routing.graphhopper.GraphLoader;
-import org.eclipse.mosaic.lib.routing.graphhopper.algorithm.AlternativeRoutesRoutingAlgorithm;
-import org.eclipse.mosaic.lib.routing.graphhopper.util.GraphhopperToDatabaseMapper;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.graphhopper.GHRequest;
-import com.graphhopper.GHResponse;
-import com.graphhopper.GraphHopper;
-import com.graphhopper.routing.Path;
-import com.graphhopper.routing.QueryGraph;
-import com.graphhopper.routing.RoutingAlgorithm;
-import com.graphhopper.routing.util.BikeFlagEncoder;
-import com.graphhopper.routing.util.CarFlagEncoder;
-import com.graphhopper.routing.util.DefaultEdgeFilter;
-import com.graphhopper.routing.util.EdgeFilter;
-import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.routing.util.FootFlagEncoder;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.GHDirectory;
-import com.graphhopper.storage.GraphHopperStorage;
-import com.graphhopper.storage.RAMDirectory;
-import com.graphhopper.storage.TurnCostExtension;
-import com.graphhopper.storage.index.QueryResult;
-import com.graphhopper.util.StopWatch;
-import com.graphhopper.util.shapes.GHPoint;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * An extension of GraphHopper which is able to import map data from the MOSAIC scenario database.
- */
-public class ExtendedGraphHopper extends GraphHopper {
-
- private final Logger logger = LoggerFactory.getLogger(getClass());
-
- protected GraphLoader graphLoader;
- protected TurnCostExtension tcStorage;
- protected GraphhopperToDatabaseMapper mapper;
-
- public ExtendedGraphHopper(GraphLoader graphLoader, GraphhopperToDatabaseMapper mapper) {
- this.graphLoader = graphLoader;
- this.mapper = mapper;
-
- setCHEnabled(false);
- setEncodingManager(EncodingManager.create(
- new CarFlagEncoder(5, 5, 127),
- new BikeFlagEncoder(),
- new FootFlagEncoder())
- );
- }
-
- @Override
- public GraphHopper importOrLoad() {
- GHDirectory dir = new RAMDirectory();
-
- tcStorage = new TurnCostExtension() {
- // is required since we need to store the way type of edges
- public boolean isRequireEdgeField() {
- return true;
- }
-
- public int getDefaultEdgeFieldValue() {
- return 0;
- }
- };
-
- GraphHopperStorage graph = new GraphHopperStorage(dir, getEncodingManager(), true, tcStorage);
-
- setGraphHopperStorage(graph);
- graph.setSegmentSize(-1);
-
- importDB(getGraphHopperLocation());
-
- return this;
- }
-
- private void importDB(String ghLocation) {
- if (getGraphHopperStorage() == null) {
- throw new IllegalStateException("Load or init graph before import database");
- }
-
- if (mapper == null) {
- throw new IllegalStateException("A mapper is required for importing database");
- }
-
- logger.info("start creating graph from database");
-
- graphLoader.initialize(getGraphHopperStorage(), getEncodingManager(), mapper);
- graphLoader.loadGraph();
-
- postProcessing();
- try {
- cleanUp();
- } catch (Exception e) {
- logger.warn("Could not clean up routing graph, skipping. Routing might not work as expected!");
- }
- // optimize();
- flush();
- }
-
- @Override
- public GHResponse route(GHRequest request) {
- if (request instanceof ExtendedGHRequest) {
- return route((ExtendedGHRequest) request);
- }
- throw new UnsupportedOperationException("ExtendedGHRequest is required");
- }
-
- private ExtendedGHResponse route(ExtendedGHRequest request) {
- if (getGraphHopperStorage() == null) {
- throw new IllegalStateException("no graph has yet been initialized");
- }
-
- ExtendedGHResponse rsp = new ExtendedGHResponse();
-
- if (!getEncodingManager().hasEncoder(request.getVehicle())) {
- rsp.addError(
- new IllegalArgumentException("Vehicle " + request.getVehicle() + " unsupported. Supported are: " + getEncodingManager())
- );
- return rsp;
- }
-
- FlagEncoder encoder = getEncodingManager().getEncoder(request.getVehicle());
-
- GHPoint fromPoint = Iterables.getFirst(request.getPoints(), null);
- GHPoint toPoint = Iterables.getLast(request.getPoints(), null);
-
- EdgeFilter edgeFilterFrom = createEdgeFilter(fromPoint, encoder);
- EdgeFilter edgeFilterTo = createEdgeFilter(toPoint, encoder);
-
- if (fromPoint == null || toPoint == null) {
- rsp.addError(new IllegalArgumentException("Not enough points given"));
- return rsp;
- }
-
- StopWatch sw = new StopWatch().start();
-
- final QueryResult fromRes = getLocationIndex().findClosest(fromPoint.lat, fromPoint.lon, edgeFilterFrom);
- final QueryResult toRes = getLocationIndex().findClosest(toPoint.lat, toPoint.lon, edgeFilterTo);
-
- if (fromRes.getClosestNode() < 0 || toRes.getClosestNode() < 0) {
- rsp.addError(new IllegalArgumentException("Request location(s) can not be snapped to the network"));
- return rsp;
- }
-
- QueryGraph queryGraph = new QueryGraph(getGraphHopperStorage());
- queryGraph.lookup(Lists.newArrayList(fromRes, toRes));
-
- String debug = "graphLookup:" + sw.stop().getSeconds() + "s";
-
- sw = new StopWatch().start();
- Weighting weighting = request.getWeightingInstance(queryGraph);
-
- RoutingAlgorithm algorithm = request.getAlgorithmFactory().createAlgorithm(queryGraph, weighting);
-
- if (algorithm instanceof AlternativeRoutesRoutingAlgorithm && request.getAlternatives() > 0) {
- ((AlternativeRoutesRoutingAlgorithm) algorithm).setRequestAlternatives(request.getAlternatives());
- }
-
- debug += ", algoInit:" + sw.stop().getSeconds() + "s";
- sw = new StopWatch().start();
-
- Path bestPath = algorithm.calcPath(fromRes.getClosestNode(), toRes.getClosestNode());
- debug += ", " + algorithm.getName() + "-routing:" + sw.stop().getSeconds() + "s, " + bestPath.getDebugInfo();
-
- final List paths = new ArrayList();
- paths.add(bestPath);
- if (algorithm instanceof AlternativeRoutesRoutingAlgorithm) {
- paths.addAll(((AlternativeRoutesRoutingAlgorithm) algorithm).getAlternativePaths());
- }
-
- ExtendedGHResponse currentResponse = null;
- int i = 1;
- for (Path path : paths) {
- if (currentResponse == null) {
- // the first path is always the requested shortest path
- currentResponse = rsp;
- } else {
- // if more than one route returned, we add a new response
- currentResponse = new ExtendedGHResponse();
- rsp.addRouteResponse(currentResponse);
- debug = "alternative path: " + (i++) + ", " + path.getDebugInfo();
- }
- currentResponse.setPath(path).addDebugInfo(debug);
- }
- return rsp;
- }
-
-
-
- private EdgeFilter createEdgeFilter(final GHPoint point, FlagEncoder encoder) {
- if (point instanceof ExtendedGHPoint) {
- return edgeState -> edgeState.getEdge() == ((ExtendedGHPoint) point).getEdgeId();
- }
- return DefaultEdgeFilter.allEdges(encoder);
- }
-
-}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/DatabaseGraphLoader.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/DatabaseGraphLoader.java
similarity index 69%
rename from lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/DatabaseGraphLoader.java
rename to lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/DatabaseGraphLoader.java
index 9272863bb..230ae975f 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/DatabaseGraphLoader.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/DatabaseGraphLoader.java
@@ -13,24 +13,25 @@
* Contact: mosaic@fokus.fraunhofer.de
*/
-package org.eclipse.mosaic.lib.routing.graphhopper;
+package org.eclipse.mosaic.lib.routing.graphhopper.util;
import org.eclipse.mosaic.lib.database.Database;
import org.eclipse.mosaic.lib.database.DatabaseUtils;
import org.eclipse.mosaic.lib.database.road.Connection;
import org.eclipse.mosaic.lib.database.road.Node;
import org.eclipse.mosaic.lib.database.road.Way;
-import org.eclipse.mosaic.lib.routing.graphhopper.util.GraphhopperToDatabaseMapper;
-import org.eclipse.mosaic.lib.routing.graphhopper.util.TurnCostAnalyzer;
-import org.eclipse.mosaic.lib.routing.graphhopper.util.WayTypeEncoder;
+import org.eclipse.mosaic.lib.routing.graphhopper.GraphHopperRouting;
import com.graphhopper.reader.ReaderWay;
-import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.storage.GraphHopperStorage;
+import com.graphhopper.routing.ev.EdgeIntAccess;
+import com.graphhopper.routing.util.DefaultVehicleTagParserFactory;
+import com.graphhopper.routing.util.VehicleTagParsers;
+import com.graphhopper.routing.util.parsers.TagParser;
+import com.graphhopper.storage.BaseGraph;
import com.graphhopper.storage.IntsRef;
-import com.graphhopper.storage.TurnCostExtension;
+import com.graphhopper.storage.TurnCostStorage;
import com.graphhopper.util.EdgeIteratorState;
+import com.graphhopper.util.PMap;
import com.graphhopper.util.PointList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,36 +44,41 @@
/**
* Loads the content of a MOSAIC scenario database into a graphhopper graph.
*/
-public class DatabaseGraphLoader implements GraphLoader {
+public class DatabaseGraphLoader {
private static final Logger LOG = LoggerFactory.getLogger(DatabaseGraphLoader.class);
- private GraphHopperStorage graphStorage;
- private EncodingManager encodingManager;
- private FlagEncoder flagEncoder;
+ private final Database database;
+ private final List wayParsers = new ArrayList<>();
+ private BaseGraph graphStorage;
+ private VehicleEncodingManager encodingManager;
private GraphhopperToDatabaseMapper graphMapper;
- private TurnCostExtension turnCostStorage;
- private Database database;
+ private TurnCostStorage turnCostStorage;
+ private EdgeIntAccess edgeAccess;
public DatabaseGraphLoader(Database database) {
this.database = database;
}
- @Override
- public void initialize(GraphHopperStorage graph,
- EncodingManager encodingManager, GraphhopperToDatabaseMapper mapper) {
+ public void initialize(BaseGraph graph,
+ VehicleEncodingManager encodingManager,
+ GraphhopperToDatabaseMapper mapper
+ ) {
this.graphStorage = graph;
this.graphMapper = mapper;
this.encodingManager = encodingManager;
- this.flagEncoder = encodingManager.getEncoder("CAR");
- if (graph.getExtension() instanceof TurnCostExtension) {
- turnCostStorage = (TurnCostExtension) (graph).getExtension();
- } else {
- throw new IllegalStateException("Graph must store turn costs by using TurnCostStorage.");
+ this.turnCostStorage = graph.getTurnCostStorage();
+
+ wayParsers.clear();
+
+ for (String vehicle : encodingManager.getAllProfileVehicles()) {
+ VehicleTagParsers parsers = new DefaultVehicleTagParserFactory()
+ .createParsers(encodingManager.getEncodingManager(), vehicle, new PMap());
+ wayParsers.add(parsers.getAccessParser());
+ wayParsers.add(parsers.getSpeedParser());
}
}
- @Override
public void loadGraph() {
int nodeIndex = 0;
@@ -82,6 +88,9 @@ public void loadGraph() {
final Set mainGraph = searchForMainGraph();
graphStorage.create(Math.max(mainGraph.size() / 30, 100));
+ edgeAccess = graphStorage.createEdgeIntAccess();
+
+ WayTypeEncoder wayTypeEncoder = encodingManager.wayType();
// add nodes and connections
for (Connection con : database.getConnections()) {
@@ -106,24 +115,19 @@ public void loadGraph() {
nodeIndex++;
}
- IntsRef flags = createFlags(encodingManager, way);
-
- if (flags != null) {
- EdgeIteratorState edgeIt = graphStorage.edge(
- graphMapper.fromNode(from),
- graphMapper.fromNode(to)).setDistance(con.getLength()).setFlags(flags);
+ EdgeIteratorState edgeIt = graphStorage.edge(graphMapper.fromNode(from), graphMapper.fromNode(to))
+ .setDistance(con.getLength())
+ .setWayGeometry(getWayGeometry(from, to, con.getNodes()));
+ handleWayTags(edgeIt.getEdge(), way);
- graphMapper.setConnection(con, edgeIt.getEdge());
+ wayTypeEncoder.setWay(way, con.getLanes(), edgeIt.getEdge(), edgeAccess);
- edgeIt.setWayGeometry(getWayGeometry(from, to, con.getNodes()));
- edgeIt.setAdditionalField(
- WayTypeEncoder.encode(way.getType(), way.getNumberOfLanesForward(), 0));
- } else {
- LOG.warn("Connection on (way={}, type={}) is not accessible by any vehicle type"
- + " and will therefore be ignored during routing.", way.getId(), way.getType());
- }
+ graphMapper.setConnection(con, edgeIt.getEdge());
}
+ VehicleEncoding car = encodingManager.getVehicleEncoding(GraphHopperRouting.PROFILE_CAR.getVehicle());
+ VehicleEncoding bike = encodingManager.getVehicleEncoding(GraphHopperRouting.PROFILE_BIKE.getVehicle());
+
// add turn restrictions
for (Connection conFrom : database.getConnections()) {
@@ -154,21 +158,25 @@ public void loadGraph() {
// if end node is connected with an connection, which is not
// accessible from incoming connection, then add turn
// restriction
- turnCostStorage.addTurnInfo(ghConFrom, ghNodeVia, ghConTo,
- flagEncoder.getTurnFlags(true, 0));
+ turnCostStorage.set(
+ car.turnRestriction(), ghConFrom, ghNodeVia, ghConTo, true
+ );
+ turnCostStorage.set(
+ bike.turnRestriction(), ghConFrom, ghNodeVia, ghConTo, true
+ );
} else if (isUTurn) {
// avoid (high costs) u-turns on same road, that is if from and to node
- // of first connection are the same nodes as of second
- // connection
- turnCostStorage.addTurnInfo(ghConFrom, ghNodeVia, ghConTo,
- flagEncoder.getTurnFlags(false, endsAtJunction ? 120 : 90));
+ // of first connection are the same nodes as of second connection
+ // note, only for cars, bikes can easily turn
+ turnCostStorage.set(
+ car.turnCost(), ghConFrom, ghNodeVia, ghConTo, endsAtJunction ? 120 : 90
+ );
}
}
}
// analyze turn costs
- new TurnCostAnalyzer().createTurnCostsForCars(graphStorage,
- encodingManager.getEncoder("CAR"));
+ new TurnCostAnalyzer(graphStorage, wayTypeEncoder).createTurnCostsForVehicle(car);
if (graphStorage.getNodes() == 0) {
throw new IllegalStateException(
@@ -209,23 +217,17 @@ private void addNode(int nodeIndex, final Node node) {
graphMapper.setNode(node, nodeIndex);
}
- /**
- * Rebuild an OSMway to get internal edge properties as flags.
- *
- * @param encoding Encoder parameter.
- * @param way Way for which to create flags.
- */
- private IntsRef createFlags(EncodingManager encoding, Way way) {
+ private void handleWayTags(int edgeId, Way way) {
+ IntsRef relationFlags = IntsRef.EMPTY;
+
ReaderWay osmWay = new ReaderWay(0);
osmWay.setTag("highway", way.getType());
- osmWay.setTag("maxspeed", String.valueOf((int) way.getMaxSpeedInKmh()));
+ osmWay.setTag("maxspeed", String.valueOf((int) Math.round(way.getMaxSpeedInKmh())));
osmWay.setTag("oneway", "yes");
- EncodingManager.AcceptWay aw = new EncodingManager.AcceptWay();
- if (encoding.acceptWay(osmWay, aw)) {
- return encoding.handleWayTags(osmWay, aw, 0);
+ for (TagParser parser : wayParsers) {
+ parser.handleWayTags(edgeId, edgeAccess, osmWay, relationFlags);
}
- return null;
}
/**
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/OptionalTurnCostProvider.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/OptionalTurnCostProvider.java
new file mode 100644
index 000000000..843039579
--- /dev/null
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/OptionalTurnCostProvider.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2023 Fraunhofer FOKUS and others. All rights reserved.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contact: mosaic@fokus.fraunhofer.de
+ */
+
+package org.eclipse.mosaic.lib.routing.graphhopper.util;
+
+import com.graphhopper.routing.ev.BooleanEncodedValue;
+import com.graphhopper.routing.ev.DecimalEncodedValue;
+import com.graphhopper.routing.weighting.TurnCostProvider;
+import com.graphhopper.storage.TurnCostStorage;
+import com.graphhopper.util.EdgeIterator;
+
+public class OptionalTurnCostProvider implements TurnCostProvider {
+
+ private final BooleanEncodedValue turnRestrictionsEnc;
+ private final DecimalEncodedValue turnCostsEnc;
+ private final TurnCostStorage turnCostStorage;
+
+ private boolean turnCostsEnabled = true;
+
+ public OptionalTurnCostProvider(VehicleEncoding encoding, TurnCostStorage turnCostStorage) {
+ if (turnCostStorage == null) {
+ throw new IllegalArgumentException("No storage set to calculate turn weight");
+ }
+ this.turnRestrictionsEnc = encoding.turnRestriction();
+ this.turnCostsEnc = encoding.turnCost();
+ this.turnCostStorage = turnCostStorage;
+ }
+
+ /**
+ * Disables consideration of turn costs. Only turn restrictions are checked.
+ */
+ public TurnCostProvider disableTurnCosts() {
+ this.turnCostsEnabled = false;
+ return this;
+ }
+
+ @Override
+ public double calcTurnWeight(int edgeFrom, int nodeVia, int edgeTo) {
+ if (!EdgeIterator.Edge.isValid(edgeFrom) || !EdgeIterator.Edge.isValid(edgeTo)) {
+ return 0;
+ }
+ if (turnRestrictionsEnc != null) {
+ boolean restricted = turnCostStorage.get(turnRestrictionsEnc, edgeFrom, nodeVia, edgeTo);
+ if (restricted) {
+ return Double.POSITIVE_INFINITY;
+ }
+ }
+ if (turnCostsEnc != null && turnCostsEnabled) {
+ return turnCostStorage.get(turnCostsEnc, edgeFrom, nodeVia, edgeTo);
+ }
+ return 0;
+ }
+
+ @Override
+ public long calcTurnMillis(int inEdge, int viaNode, int outEdge) {
+ return (long) (1000 * calcTurnWeight(inEdge, viaNode, outEdge));
+ }
+
+ @Override
+ public String toString() {
+ return "mosaic_tcp";
+ }
+}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/TurnCostAnalyzer.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/TurnCostAnalyzer.java
index 3f0255589..976ed287a 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/TurnCostAnalyzer.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/TurnCostAnalyzer.java
@@ -18,13 +18,13 @@
import org.eclipse.mosaic.lib.geo.GeoPoint;
import org.eclipse.mosaic.lib.geo.GeoUtils;
-import com.graphhopper.routing.util.DefaultEdgeFilter;
-import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.routing.util.AccessFilter;
+import com.graphhopper.storage.BaseGraph;
import com.graphhopper.storage.Graph;
-import com.graphhopper.storage.GraphHopperStorage;
-import com.graphhopper.storage.TurnCostExtension;
+import com.graphhopper.storage.TurnCostStorage;
import com.graphhopper.util.EdgeExplorer;
import com.graphhopper.util.EdgeIterator;
+import com.graphhopper.util.FetchMode;
import com.graphhopper.util.PointList;
import com.graphhopper.util.shapes.GHPoint;
@@ -55,11 +55,15 @@ public class TurnCostAnalyzer {
* TODO make depend on road type
*/
private double minCurveRadius;
+ private final WayTypeEncoder waytypeEncoder;
+ private final BaseGraph graph;
/**
* Crates a new {@link TurnCostAnalyzer} with default calculation properties.
*/
- public TurnCostAnalyzer() {
+ public TurnCostAnalyzer(BaseGraph graph, WayTypeEncoder waytypeEncoder) {
+ this.graph = graph;
+ this.waytypeEncoder = waytypeEncoder;
/*
* Mean acceleration and deceleration for cars
* (according to [Maurya et al: "Acceleration-Deceleration Behaviour of Various Vehicle Types", 2016]).
@@ -69,21 +73,14 @@ public TurnCostAnalyzer() {
minCurveRadius = 20;
}
- public void createTurnCostsForCars(GraphHopperStorage graph, FlagEncoder flagEncoder) {
- EdgeExplorer outEdgeExplorer = graph.createEdgeExplorer(DefaultEdgeFilter.outEdges(flagEncoder));
- EdgeExplorer inEdgeExplorer = graph.createEdgeExplorer(DefaultEdgeFilter.inEdges(flagEncoder));
- final TurnCostExtension tcStorage;
- if (graph.getExtension() instanceof TurnCostExtension) {
- tcStorage = (TurnCostExtension) graph.getExtension();
- if (!tcStorage.isRequireEdgeField()) {
- throw new IllegalStateException(
- "Graph does not support storing additional edge fields");
- }
- } else {
- throw new IllegalStateException("Graph does not support storing of turn costs");
- }
+ public void createTurnCostsForVehicle(VehicleEncoding encoding) {
+
+ EdgeExplorer outEdgeExplorer = graph.createEdgeExplorer(AccessFilter.allEdges(encoding.access()));
+ EdgeExplorer inEdgeExplorer = graph.createEdgeExplorer(AccessFilter.allEdges(encoding.access()));
+
+ TurnCostStorage tcStorage = graph.getTurnCostStorage();
for (int n = 0; n < graph.getNodes(); n++) {
EdgeIterator inEdgeIt = inEdgeExplorer.setBaseNode(n);
@@ -91,14 +88,13 @@ public void createTurnCostsForCars(GraphHopperStorage graph, FlagEncoder flagEnc
EdgeIterator outEdgeIt = outEdgeExplorer.setBaseNode(n);
while (outEdgeIt.next()) {
if (inEdgeIt.getEdge() != outEdgeIt.getEdge()) {
- long existingTurnCosts = tcStorage.getTurnCostFlags(inEdgeIt.getEdge(), n,
- outEdgeIt.getEdge());
+ boolean alreadyRestricted = tcStorage.get(encoding.turnRestriction(), inEdgeIt.getEdge(), n, outEdgeIt.getEdge());
+ double existingCosts = tcStorage.get(encoding.turnCost(), inEdgeIt.getEdge(), n, outEdgeIt.getEdge());
//if turn is already restricted, than we do not need to consider turn costs
- if (!flagEncoder.isTurnRestricted(existingTurnCosts)) {
- double c = calculateTurnCosts(graph, flagEncoder, inEdgeIt, n, outEdgeIt);
+ if (!alreadyRestricted) {
+ double c = calculateTurnCosts(encoding, inEdgeIt, n, outEdgeIt) + existingCosts;
if (c > 0.00001) {
- long turnFlags = flagEncoder.getTurnFlags(false, Math.ceil(c));
- tcStorage.addTurnInfo(inEdgeIt.getEdge(), n, outEdgeIt.getEdge(), turnFlags);
+ tcStorage.set(encoding.turnCost(), inEdgeIt.getEdge(), n, outEdgeIt.getEdge(), Math.ceil(c));
}
}
}
@@ -114,29 +110,25 @@ public void createTurnCostsForCars(GraphHopperStorage graph, FlagEncoder flagEnc
* into geometric points. Further parameter for the calculating are the angle between incoming and outgoing edge,
* the length and the maximum speed of the edge.
*
- * @param graph Graph fot which to calculate the turn costs
- * @param flagEncoder Encoding the flag
* @param incomingEdge Incoming edge
* @param node ID of the node
* @param outgoingEdge Outgoing edge
* @return Calculated turn cost
*/
- private double calculateTurnCosts(GraphHopperStorage graph, FlagEncoder flagEncoder, EdgeIterator incomingEdge, int node,
- EdgeIterator outgoingEdge) {
+ private double calculateTurnCosts(VehicleEncoding encoding, EdgeIterator incomingEdge, int node, EdgeIterator outgoingEdge) {
//determining way types
- int incomingWayType = incomingEdge.getAdditionalField();
- int outgoingWayType = outgoingEdge.getAdditionalField();
+ int incomingWayType = incomingEdge.get(waytypeEncoder);
+ int outgoingWayType = outgoingEdge.get(waytypeEncoder);
//we ignore turn costs, as soon as we are on highways
if (WayTypeEncoder.isHighway(incomingWayType) && WayTypeEncoder.isHighway(outgoingWayType)) {
return 0;
}
- //use way geometry to calculate
+ //use way geometry to calculate
final GHPoint pointFrom = getSecondLastPointOfEdge(graph, incomingEdge);
- final GHPoint pointVia = new GHPoint(graph.getNodeAccess().getLatitude(node),
- graph.getNodeAccess().getLongitude(node));
+ final GHPoint pointVia = new GHPoint(graph.getNodeAccess().getLat(node), graph.getNodeAccess().getLon(node));
final GHPoint pointTo = getSecondPointOfEdge(graph, outgoingEdge);
//calculate angle between incoming/outgoing edge using bearing of from-via and via-to
@@ -148,8 +140,8 @@ private double calculateTurnCosts(GraphHopperStorage graph, FlagEncoder flagEnco
double alpha = (bearingViaTo - (bearingFromVia) + 360) % 360;
//get length and max speed of edges
- double v1 = incomingEdge.get(flagEncoder.getAverageSpeedEnc()) / 3.6;
- double v2 = outgoingEdge.get(flagEncoder.getAverageSpeedEnc()) / 3.6;
+ double v1 = incomingEdge.get(encoding.speed()) / 3.6;
+ double v2 = outgoingEdge.get(encoding.speed()) / 3.6;
double l1 = incomingEdge.getDistance();
double l2 = outgoingEdge.getDistance();
@@ -166,12 +158,12 @@ private double calculateTurnCosts(GraphHopperStorage graph, FlagEncoder flagEnco
//else, the maximum turn speed depends on the angle between incoming and outgoing edge
} else {
if (isLeftTurn || isRightTurn) {
- //when turning, the max speed on the outgoing edge also depends on its length (i.e., if the
+ //when turning, the max speed on the outgoing edge also depends on its length (i.e., if the
//outgoing edge is very short, we don't need to accelerate till max speed)
v2 = Math.min(v2, MAX_A * Math.sqrt((2 * l2) / MAX_A));
}
- //adjusting angle: tangens only gives positive values in [0,180]
+ //adjusting angle: tangens only gives positive values in [0,180]
if (alpha > 180) {
alpha = 360 - alpha;
}
@@ -209,13 +201,13 @@ private double calculateTurnCosts(GraphHopperStorage graph, FlagEncoder flagEnco
* @return the second last coordinate of an edge.
*/
private GHPoint getSecondLastPointOfEdge(Graph graph, EdgeIterator edge) {
- PointList geom = edge.fetchWayGeometry(GEOMETRY_FETCH_MODE_PILLAR_NODES_ONLY);
- if (geom.getSize() == 0) {
- return new GHPoint(graph.getNodeAccess().getLatitude(edge.getAdjNode()),
- graph.getNodeAccess().getLongitude(edge.getAdjNode()));
+ PointList geom = edge.fetchWayGeometry(FetchMode.PILLAR_ONLY);
+ if (geom.isEmpty()) {
+ return new GHPoint(graph.getNodeAccess().getLat(edge.getAdjNode()),
+ graph.getNodeAccess().getLon(edge.getAdjNode()));
}
- int index = geom.getSize() - 1;
- return new GHPoint(geom.getLatitude(index), geom.getLongitude(index));
+ int index = geom.size() - 1;
+ return new GHPoint(geom.getLat(index), geom.getLon(index));
}
/**
@@ -225,12 +217,12 @@ private GHPoint getSecondLastPointOfEdge(Graph graph, EdgeIterator edge) {
* @return the second coordinate of an edge.
*/
private GHPoint getSecondPointOfEdge(Graph graph, EdgeIterator edge) {
- PointList geom = edge.fetchWayGeometry(GEOMETRY_FETCH_MODE_PILLAR_NODES_ONLY);
- if (geom.getSize() == 0) {
- return new GHPoint(graph.getNodeAccess().getLatitude(edge.getAdjNode()),
- graph.getNodeAccess().getLongitude(edge.getAdjNode()));
+ PointList geom = edge.fetchWayGeometry(FetchMode.PILLAR_ONLY);
+ if (geom.isEmpty()) {
+ return new GHPoint(graph.getNodeAccess().getLat(edge.getAdjNode()),
+ graph.getNodeAccess().getLon(edge.getAdjNode()));
}
- return new GHPoint(geom.getLatitude(0), geom.getLongitude(0));
+ return new GHPoint(geom.getLat(0), geom.getLon(0));
}
}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/VehicleEncoding.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/VehicleEncoding.java
new file mode 100644
index 000000000..1ec7c1cf5
--- /dev/null
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/VehicleEncoding.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2023 Fraunhofer FOKUS and others. All rights reserved.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contact: mosaic@fokus.fraunhofer.de
+ */
+
+package org.eclipse.mosaic.lib.routing.graphhopper.util;
+
+import com.graphhopper.config.Profile;
+import com.graphhopper.routing.ev.BooleanEncodedValue;
+import com.graphhopper.routing.ev.DecimalEncodedValue;
+import com.graphhopper.routing.ev.Subnetwork;
+import com.graphhopper.routing.ev.TurnCost;
+import com.graphhopper.routing.ev.TurnRestriction;
+import com.graphhopper.routing.util.DefaultVehicleEncodedValuesFactory;
+import com.graphhopper.routing.util.VehicleEncodedValues;
+import com.graphhopper.util.PMap;
+
+/**
+ * Collection of all {@link com.graphhopper.routing.ev.EncodedValue} implementations
+ * required for a vehicle to function within the GraphHopper context. This includes:
+ * - "access" - If a vehicle can drive on an edge.
+ * - "speed" - The speed limit for the vehicle on the edge.
+ * - "priority" - Encode how to prioritize a road type to another.
+ * - "subnetwork" - Encode if an edge belongs to a subnetwork
+ * - "turnRestriction" / "turnCost" - encoding of costs for a turn from on edge to another.
+ * These encoders take care of storing and reading properties on edges.
+ */
+public class VehicleEncoding {
+
+ private final BooleanEncodedValue accessEnc;
+ private final DecimalEncodedValue speedEnc;
+ private final BooleanEncodedValue turnRestrictionEnc;
+ private final DecimalEncodedValue turnCostEnc;
+ private final DecimalEncodedValue priorityEnc;
+ private final BooleanEncodedValue subnetworkEnc;
+
+ VehicleEncoding(Profile profile) {
+ VehicleEncodedValues vehicle = new DefaultVehicleEncodedValuesFactory()
+ .createVehicleEncodedValues(profile.getVehicle(), new PMap());
+ this.accessEnc = vehicle.getAccessEnc();
+ this.speedEnc = vehicle.getAverageSpeedEnc();
+ this.priorityEnc = vehicle.getPriorityEnc();
+ this.turnRestrictionEnc = TurnRestriction.create(profile.getVehicle());
+ this.turnCostEnc = TurnCost.create(profile.getVehicle(), 255);
+ this.subnetworkEnc = Subnetwork.create(profile.getVehicle());
+ }
+
+ public BooleanEncodedValue access() {
+ return accessEnc;
+ }
+
+ public DecimalEncodedValue speed() {
+ return speedEnc;
+ }
+
+ public DecimalEncodedValue priority() {
+ return priorityEnc;
+ }
+
+ public BooleanEncodedValue turnRestriction() {
+ return turnRestrictionEnc;
+ }
+
+ public DecimalEncodedValue turnCost() {
+ return turnCostEnc;
+ }
+
+ public BooleanEncodedValue subnetwork() {
+ return subnetworkEnc;
+ }
+}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/VehicleEncodingManager.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/VehicleEncodingManager.java
new file mode 100644
index 000000000..80c05ea17
--- /dev/null
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/VehicleEncodingManager.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2023 Fraunhofer FOKUS and others. All rights reserved.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contact: mosaic@fokus.fraunhofer.de
+ */
+
+package org.eclipse.mosaic.lib.routing.graphhopper.util;
+
+import com.graphhopper.config.Profile;
+import com.graphhopper.routing.util.EncodingManager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * In GraphHopper, any data for edges, nodes, and turns, are stored with as low overhead
+ * as possible. To achieve this, {@link com.graphhopper.routing.ev.EncodedValue}s
+ * to encode and decode any data. This class, encapsulates the initialization and access to single
+ * {@link com.graphhopper.routing.ev.EncodedValue}s, making it easier to use them in code.
+ */
+public class VehicleEncodingManager {
+
+ private final WayTypeEncoder waytypeEncoder;
+ private final EncodingManager encodingManager;
+
+ private final Map vehicleEncodings = new HashMap<>();
+ private final List profiles;
+
+ public VehicleEncodingManager(List profiles) {
+ this.waytypeEncoder = WayTypeEncoder.create();
+ this.profiles = new ArrayList<>(profiles);
+
+ EncodingManager.Builder builder = new EncodingManager.Builder().add(waytypeEncoder);
+ for (Profile profile : this.profiles) {
+ final VehicleEncoding encoding = new VehicleEncoding(profile);
+ vehicleEncodings.put(profile.getVehicle(), encoding);
+ builder.add(encoding.access())
+ .add(encoding.speed())
+ .addTurnCostEncodedValue(encoding.turnRestriction())
+ .addTurnCostEncodedValue(encoding.turnCost())
+ .add(encoding.subnetwork());
+ if (encoding.priority() != null) {
+ builder.add(encoding.priority());
+ }
+ }
+ this.encodingManager = builder.build();
+ }
+
+ public List getAllProfiles() {
+ return Collections.unmodifiableList(profiles);
+ }
+
+ /**
+ * Returns a list of all possible transportation modes (e.g. "car", "bike").
+ */
+ public Collection getAllProfileVehicles() {
+ return Collections.unmodifiableCollection(vehicleEncodings.keySet());
+ }
+
+ /**
+ * Returns the specific wrapper of {@link com.graphhopper.routing.ev.EncodedValue}s required
+ * for the given transportation mode (e.g. "car", "bike").
+ */
+ public VehicleEncoding getVehicleEncoding(String vehicle) {
+ return vehicleEncodings.get(vehicle);
+ }
+
+ /**
+ * Returns an encoder, which is used to encode/decode precomputed flags for way types.
+ */
+ public WayTypeEncoder wayType() {
+ return waytypeEncoder;
+ }
+
+ /**
+ * Returns the actual encoding manager used in GraphHopper.
+ */
+ public EncodingManager getEncodingManager() {
+ return encodingManager;
+ }
+}
diff --git a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/WayTypeEncoder.java b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/WayTypeEncoder.java
index 09b3f4371..8b8ccd252 100644
--- a/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/WayTypeEncoder.java
+++ b/lib/mosaic-routing/src/main/java/org/eclipse/mosaic/lib/routing/graphhopper/util/WayTypeEncoder.java
@@ -15,13 +15,24 @@
package org.eclipse.mosaic.lib.routing.graphhopper.util;
+import org.eclipse.mosaic.lib.database.road.Way;
+
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
+import com.graphhopper.routing.ev.EdgeIntAccess;
+import com.graphhopper.routing.ev.IntEncodedValueImpl;
import java.util.Set;
-public class WayTypeEncoder {
+/**
+ * Stores additional properties on an edge to describe the way-type of an edge.
+ * It does so by encoding the way-type, and some boolean flags based on this
+ * way-type, within one integer field by using bit-masking.
+ */
+public class WayTypeEncoder extends IntEncodedValueImpl {
+
+ public final static String KEY = "waytype";
private static final BiMap wayTypeIntMap = HashBiMap.create();
private static final Set highwayTypes = Sets.newHashSet(
@@ -40,15 +51,20 @@ public class WayTypeEncoder {
"cycleway"
);
- private static final int HIGHWAY = 1 << 31;
- private static final int RESIDENTIAL = 1 << 30;
- private static final int TUNNEL = 1 << 29;
- private static final int TOLL = 1 << 28;
- private static final int BAD_ROAD = 1 << 27;
- private static final int ONE_LANE = 1 << 26;
- private static final int MAIN_ROAD = 1 << 25;
- private static final int CYCLEWAY = 1 << 24;
- private static final int TYPE_MASK = 0x03FFFFFF;
+ private static final int HIGHWAY = 1 << 15;
+ private static final int RESIDENTIAL = 1 << 14;
+ private static final int TUNNEL = 1 << 13;
+ private static final int TOLL = 1 << 12;
+ private static final int BAD_ROAD = 1 << 11;
+ private static final int ONE_LANE = 1 << 10;
+ private static final int MAIN_ROAD = 1 << 9;
+ private static final int CYCLEWAY = 1 << 8;
+
+ /*
+ * Store the type as integer in the first 1 byte (max value = 255)
+ * The rest of the integer bits is used to store the property flags, e.g. HIGHWAY, RESIDENTIAL.
+ */
+ private static final int TYPE_MASK = 0x00FF;
static {
// autobahn
@@ -73,6 +89,16 @@ public class WayTypeEncoder {
wayTypeIntMap.put("service", 27);
wayTypeIntMap.put("road", 26);
wayTypeIntMap.put("track", 25);
+ // any other roads
+ wayTypeIntMap.put("cycleway", 10);
+ }
+
+ private WayTypeEncoder() {
+ super(KEY, 31, false);
+ }
+
+ public static WayTypeEncoder create() {
+ return new WayTypeEncoder();
}
public static String decode(int type) {
@@ -83,26 +109,27 @@ public static String decode(int type) {
return "unknown";
}
- public static int encode(String wayType, int numberLanes, int additionalFlags) {
+ public static int encode(String wayType, int numberLanes) {
+ int flags = 0;
if (highwayTypes.contains(wayType)) {
- additionalFlags |= HIGHWAY;
+ flags |= HIGHWAY;
}
if (residentialTypes.contains(wayType)) {
- additionalFlags |= RESIDENTIAL;
+ flags |= RESIDENTIAL;
}
if (numberLanes == 1 && !oneLaneIgnoreTypes.contains(wayType)) {
- additionalFlags |= ONE_LANE;
+ flags |= ONE_LANE;
}
if (mainroadTypes.contains(wayType)) {
- additionalFlags |= MAIN_ROAD;
+ flags |= MAIN_ROAD;
}
if (cyclewayTypes.contains(wayType)) {
- additionalFlags |= CYCLEWAY;
+ flags |= CYCLEWAY;
}
Integer result = wayTypeIntMap.get(wayType);
if (result != null) {
- return result | additionalFlags;
+ return result | flags;
}
return 0;
}
@@ -145,4 +172,7 @@ public static boolean isLowerType(int a, int b) {
return typeB + 4 < typeA;
}
+ public void setWay(Way way, int lanes, int edge, EdgeIntAccess access) {
+ setInt(false, edge, access, encode(way.getType(), lanes));
+ }
}
diff --git a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/CharlottenburgRoutingTest.java b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/CharlottenburgRoutingTest.java
new file mode 100644
index 000000000..f980db71a
--- /dev/null
+++ b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/CharlottenburgRoutingTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2024 Fraunhofer FOKUS and others. All rights reserved.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contact: mosaic@fokus.fraunhofer.de
+ */
+
+package org.eclipse.mosaic.lib.routing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.eclipse.mosaic.lib.database.Database;
+import org.eclipse.mosaic.lib.database.road.Connection;
+import org.eclipse.mosaic.lib.enums.VehicleClass;
+import org.eclipse.mosaic.lib.geo.GeoPoint;
+import org.eclipse.mosaic.lib.junit.GeoProjectionRule;
+import org.eclipse.mosaic.lib.routing.graphhopper.GraphHopperRouting;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Test routing with a real world map (Charlottenburg extract from BeST scenario).
+ */
+public class CharlottenburgRoutingTest {
+
+ @Rule
+ public GeoProjectionRule transformationRule = new GeoProjectionRule(GeoPoint.latLon(52, 13));
+
+ private final static String dbFile = "/charlottenburg.db";
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ private Database database;
+ private GraphHopperRouting routing;
+
+ @Before
+ public void setUp() throws IOException {
+ final File dbFileCopy = folder.newFile("charlottenburg.db");
+
+ FileUtils.copyInputStreamToFile(getClass().getResourceAsStream(dbFile), dbFileCopy);
+
+ database = Database.loadFromFile(dbFileCopy);
+
+ routing = new GraphHopperRouting(database);
+ }
+
+ @Test
+ public void findPaths_27537749_to_252864802() {
+ List result = routing
+ .findRoutes(new RoutingRequest(
+ new RoutingPosition(GeoPoint.latLon(52.504185, 13.323964), null, "-440300111"),
+ new RoutingPosition(database.getNode("26761203").getPosition()),
+ new RoutingParameters()
+ .vehicleClass(VehicleClass.Car)
+ .alternativeRoutes(1)
+ .costFunction(RoutingCostFunction.Fastest)
+ ));
+ assertNotNull(result);
+ assertEquals(2, result.size());
+ assertValidRoute(result.get(0));
+ assertValidRoute(result.get(1));
+ assertEquals(Lists.newArrayList("-440300111", "4381160#2", "832017303", "823947542#0", "110008909#2", "547450789#0", "4402682#8", "4490390#2", "-25418285#1", "4500153"),
+ result.get(0).getConnectionIds());
+ assertEquals(Lists.newArrayList("-440300111", "4381160#2", "832017303", "823947542#0", "110008909#2", "547450789#0", "490351849#0", "490351848#0", "4492013#2", "25418287#6", "318889281#0", "4371002#2", "-4437136#0"),
+ result.get(1).getConnectionIds());
+ }
+
+ private void assertValidRoute(CandidateRoute candidateRoute) {
+ Connection currentConnection;
+ Connection previousConnection = null;
+ for (String connectionId : candidateRoute.getConnectionIds()) {
+ currentConnection = database.getConnection(connectionId);
+ if (previousConnection != null && !previousConnection.getOutgoingConnections().contains(currentConnection)) {
+ throw new AssertionError("Route is not valid, no transition existing");
+ }
+ previousConnection = currentConnection;
+ }
+ }
+
+}
diff --git a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/database/DatabaseRoutingTest.java b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/database/DatabaseRoutingTest.java
index da7cdfefd..3bf4bd85b 100644
--- a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/database/DatabaseRoutingTest.java
+++ b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/database/DatabaseRoutingTest.java
@@ -229,7 +229,7 @@ public void findRoutes() throws InternalFederateException {
//ASSERT
assertEquals(0, response.getAlternativeRoutes().size());
assertNotNull(response.getBestRoute());
- assertEquals(15.672, response.getBestRoute().getTime(), 0.1d);
+ assertEquals(15.237, response.getBestRoute().getTime(), 0.1d);
assertEquals(304.74, response.getBestRoute().getLength(), 0.1d);
assertEquals(Arrays.asList("32909782_26704482_26785753", "25185001_26785753_26704584"),
response.getBestRoute().getConnectionIds());
diff --git a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperMosaicTest.java b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperMosaicTest.java
deleted file mode 100644
index b2c00c5af..000000000
--- a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperMosaicTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import org.eclipse.mosaic.lib.routing.graphhopper.algorithm.BellmanFordRouting;
-import org.eclipse.mosaic.lib.routing.graphhopper.algorithm.DijkstraCamvitChoiceRouting;
-import org.eclipse.mosaic.lib.routing.graphhopper.algorithm.RoutingAlgorithmFactory;
-import org.eclipse.mosaic.lib.routing.graphhopper.extended.ExtendedGHRequest;
-import org.eclipse.mosaic.lib.routing.graphhopper.extended.ExtendedGHRequest.WeightingFactory;
-import org.eclipse.mosaic.lib.routing.graphhopper.extended.ExtendedGHResponse;
-import org.eclipse.mosaic.lib.routing.graphhopper.extended.ExtendedGraphHopper;
-import org.eclipse.mosaic.lib.routing.graphhopper.junit.TestGraphRule;
-import org.eclipse.mosaic.lib.routing.graphhopper.util.GHListHelper;
-import org.eclipse.mosaic.lib.routing.graphhopper.util.GraphhopperToDatabaseMapper;
-
-import com.graphhopper.GHRequest;
-import com.graphhopper.GHResponse;
-import com.graphhopper.routing.Path;
-import com.graphhopper.routing.RoutingAlgorithm;
-import com.graphhopper.routing.util.TurnCostEncoder;
-import com.graphhopper.routing.weighting.FastestWeighting;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.Graph;
-import com.graphhopper.storage.GraphExtension;
-import com.graphhopper.storage.GraphHopperStorage;
-import com.graphhopper.storage.TurnCostExtension;
-import com.graphhopper.util.shapes.GHPoint;
-import org.junit.Test;
-
-import java.util.List;
-
-public class GraphHopperMosaicTest {
-
- @Test
- public void importFromTestGraph() {
- ExtendedGraphHopper gh = new ExtendedGraphHopper(new TestGraphRule(null), new GraphhopperToDatabaseMapper());
- gh.importOrLoad();
-
- assertFalse("Contraction Hierarchies should be disabled", gh.isCHEnabled());
- assertTrue("Graph is not from instance GraphHopperStorage", gh.getGraphHopperStorage() instanceof GraphHopperStorage);
-
- assertTrue("The default CAR encoder should implement TurnCostEncoder",
- gh.getEncodingManager().getEncoder("CAR") instanceof TurnCostEncoder);
-
- GraphExtension extStorage = gh.getGraphHopperStorage().getExtension();
- assertTrue("Extended storage of graph is not from instance TurnCostStorage", extStorage instanceof TurnCostExtension);
- assertTrue("Extended storage must offer an additional edge field", extStorage.isRequireEdgeField());
-
- assertEquals("Not all nodes have been imported.", 14, gh.getGraphHopperStorage().getNodes());
-
- }
-
- @Test(expected = IllegalStateException.class)
- public void extendedGHRequestRequiredForRouting() {
- ExtendedGraphHopper gh = new ExtendedGraphHopper(null, null);
- gh.route(new GHRequest((GHPoint) null, (GHPoint) null));
- }
-
- @Test
- public void routeRequest_alternativeRoutesWithDijkstra() {
- //setup
- final ExtendedGraphHopper gh = new ExtendedGraphHopper(new TestGraphRule(null), new GraphhopperToDatabaseMapper());
- gh.importOrLoad();
-
- ExtendedGHRequest request = new ExtendedGHRequest(new GHPoint(0, 0), new GHPoint(0.03, 0.03));
- request.setWeightingFactory(new WeightingFactory() {
-
- @Override
- public Weighting create(Graph graph) {
- return new FastestWeighting(gh.getEncodingManager().getEncoder("CAR"));
- }
- });
- request.setRoutingAlgorithmFactory(new RoutingAlgorithmFactory() {
-
- @Override
- public RoutingAlgorithm createAlgorithm(Graph graph, Weighting weighting) {
- return new DijkstraCamvitChoiceRouting(graph, weighting);
- }
- });
- request.setVehicle("CAR");
- request.setAlternatives(2);
-
- //run
- GHResponse response = gh.route(request);
-
- //assert
- assertTrue("response should be from instance ExtendedGHResponse", response instanceof ExtendedGHResponse);
- assertTrue(response.getErrors().isEmpty());
-
- ExtendedGHResponse extResponse = (ExtendedGHResponse) response;
- Path p = extResponse.getPath();
- assertNotNull(p);
- assertEquals(GHListHelper.createTList(0, 1, 5, 10), p.calcNodes());
- assertEquals(5000, p.getDistance(), 0.1);
- assertEquals(300000, p.getTime());
-
- List alternatives = extResponse.getAdditionalRoutes();
- assertNotNull(alternatives);
- assertEquals(2, alternatives.size());
-
- p = alternatives.get(0).getPath();
- assertNotNull(p);
- assertEquals(GHListHelper.createTList(0, 4, 7, 9, 10), p.calcNodes());
- assertEquals(5500, p.getDistance(), 0.1);
- assertEquals(330000, p.getTime());
-
- p = alternatives.get(1).getPath();
- assertNotNull(p);
- assertEquals(GHListHelper.createTList(0, 1, 2, 6, 10), p.calcNodes());
- assertEquals(5600, p.getDistance(), 0.1);
- assertEquals(336000, p.getTime());
-
- }
-
- @Test
- public void routeRequest_fastestWithBellmanFord() {
- //setup
- final ExtendedGraphHopper gh = new ExtendedGraphHopper(new TestGraphRule(null), new GraphhopperToDatabaseMapper());
- gh.importOrLoad();
-
- ExtendedGHRequest request = new ExtendedGHRequest(new GHPoint(0, 0), new GHPoint(0.03, 0.03));
- request.setWeightingFactory((graph) -> new FastestWeighting(gh.getEncodingManager().getEncoder("CAR")));
- request.setRoutingAlgorithmFactory(BellmanFordRouting::new);
- request.setVehicle("CAR");
-
- //run
- GHResponse response = gh.route(request);
-
- //assert
- assertTrue("response should be from instance ExtendedGHResponse", response instanceof ExtendedGHResponse);
- assertTrue(response.getErrors().isEmpty());
-
- ExtendedGHResponse extResponse = (ExtendedGHResponse) response;
- Path p = extResponse.getPath();
- assertNotNull(p);
- assertEquals(GHListHelper.createTList(0, 1, 5, 10), p.calcNodes());
- assertEquals(5000, p.getDistance(), 0.1);
- assertEquals(300000, p.getTime());
- }
-
-}
diff --git a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperRoutingTest.java b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperRoutingTest.java
index 5b4ecb067..b661ca137 100644
--- a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperRoutingTest.java
+++ b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperRoutingTest.java
@@ -60,8 +60,7 @@ public void setUp() throws IOException {
database = Database.loadFromFile(dbFileCopy);
- routing = new GraphHopperRouting();
- routing.loadGraphFromDatabase(database);
+ routing = new GraphHopperRouting(database);
}
@Test
diff --git a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperWeightingTest.java b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperWeightingTest.java
new file mode 100644
index 000000000..374203e5f
--- /dev/null
+++ b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/GraphHopperWeightingTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contact: mosaic@fokus.fraunhofer.de
+ */
+
+package org.eclipse.mosaic.lib.routing.graphhopper;
+
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.mosaic.lib.routing.RoutingCostFunction;
+import org.eclipse.mosaic.lib.routing.graphhopper.junit.TestGraphRule;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.OptionalTurnCostProvider;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.VehicleEncoding;
+
+import com.graphhopper.routing.weighting.Weighting;
+import com.graphhopper.util.EdgeExplorer;
+import com.graphhopper.util.EdgeIterator;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class GraphHopperWeightingTest {
+
+ @Rule
+ public TestGraphRule testGraph = new TestGraphRule();
+
+ @Test
+ public void fastest_noTurnCosts() {
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+
+ Weighting w = new GraphHopperWeighting(enc, testGraph.getEncodingManager().wayType(), new OptionalTurnCostProvider(enc, testGraph.getGraph().getTurnCostStorage()), null)
+ .setRoutingCostFunction(RoutingCostFunction.Fastest);
+
+ EdgeExplorer expl = testGraph.getGraph().createEdgeExplorer();
+ EdgeIterator it = expl.setBaseNode(0);
+
+ double distance = it.getDistance();
+
+ double weight = w.calcEdgeWeight(it, false);
+ double turnWeight = w.calcTurnWeight(1, 0, 0);
+
+ assertEquals(distance / enc.speed().getMaxStorableDecimal() * 3.6, weight, 0.1d);
+ assertEquals(0, turnWeight, 0.1d);
+ }
+
+ @Test
+ public void shortest_noTurnCosts() {
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+
+ Weighting w = new GraphHopperWeighting(enc, testGraph.getEncodingManager().wayType(), new OptionalTurnCostProvider(enc, testGraph.getGraph().getTurnCostStorage()), null)
+ .setRoutingCostFunction(RoutingCostFunction.Shortest);
+
+ EdgeExplorer expl = testGraph.getGraph().createEdgeExplorer();
+ EdgeIterator it = expl.setBaseNode(0);
+
+ double distance = it.getDistance();
+
+ double weight = w.calcEdgeWeight(it, false);
+ double turnWeight = w.calcTurnWeight(1, 0, 0);
+
+ assertEquals(distance, weight, 0.1d);
+ assertEquals(0, turnWeight, 0.1d);
+ }
+
+
+ @Test
+ public void shortest_turnCosts() {
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+
+ testGraph.getGraph().getTurnCostStorage().set(enc.turnCost(), 1, 0, 0, 10.0);
+
+ Weighting w = new GraphHopperWeighting(enc, testGraph.getEncodingManager().wayType(), new OptionalTurnCostProvider(enc, testGraph.getGraph().getTurnCostStorage()), null)
+ .setRoutingCostFunction(RoutingCostFunction.Shortest);
+
+ EdgeExplorer expl = testGraph.getGraph().createEdgeExplorer();
+ EdgeIterator it = expl.setBaseNode(0);
+
+ double distance = it.getDistance();
+
+ double weight = w.calcEdgeWeight(it, false);
+ double turnWeight = w.calcTurnWeight(1, 0, 0);
+
+ assertEquals(distance, weight, 0.1d);
+ assertEquals(10, turnWeight, 0.1d);
+ }
+
+ @Test
+ public void fastest_turnCosts() {
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+
+ testGraph.getGraph().getTurnCostStorage().set(enc.turnCost(), 1, 0, 0, 10.0);
+
+ Weighting w = new GraphHopperWeighting(enc, testGraph.getEncodingManager().wayType(), new OptionalTurnCostProvider(enc, testGraph.getGraph().getTurnCostStorage()), null)
+ .setRoutingCostFunction(RoutingCostFunction.Fastest);
+
+ EdgeExplorer expl = testGraph.getGraph().createEdgeExplorer();
+ EdgeIterator it = expl.setBaseNode(0);
+
+ double distance = it.getDistance();
+
+ double weight = w.calcEdgeWeight(it, false);
+ double turnWeight = w.calcTurnWeight(1, 0, 0);
+
+ assertEquals(distance / enc.speed().getMaxOrMaxStorableDecimal() * 3.6, weight, 0.1d);
+ assertEquals(10, turnWeight, 0.1d);
+ }
+
+ @Test
+ public void shortest_turnRestriction() {
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+
+ testGraph.getGraph().getTurnCostStorage().set(enc.turnRestriction(), 1, 0, 0, true);
+
+ Weighting w = new GraphHopperWeighting(enc, testGraph.getEncodingManager().wayType(), new OptionalTurnCostProvider(enc, testGraph.getGraph().getTurnCostStorage()), null)
+ .setRoutingCostFunction(RoutingCostFunction.Shortest);
+
+ EdgeExplorer expl = testGraph.getGraph().createEdgeExplorer();
+ EdgeIterator it = expl.setBaseNode(0);
+
+ double distance = it.getDistance();
+
+ double weight = w.calcEdgeWeight(it, false);
+ double turnWeight = w.calcTurnWeight(1, 0, 0);
+
+ assertEquals(distance, weight, 0.1d);
+ assertEquals(Double.POSITIVE_INFINITY, turnWeight, 0.1d);
+ }
+
+ @Test
+ public void fastest_turnRestriction() {
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+
+ testGraph.getGraph().getTurnCostStorage().set(enc.turnRestriction(), 1, 0, 0, true);
+
+ Weighting w = new GraphHopperWeighting(enc, testGraph.getEncodingManager().wayType(), new OptionalTurnCostProvider(enc, testGraph.getGraph().getTurnCostStorage()), null)
+ .setRoutingCostFunction(RoutingCostFunction.Fastest);
+
+ EdgeExplorer expl = testGraph.getGraph().createEdgeExplorer();
+ EdgeIterator it = expl.setBaseNode(0);
+
+ double distance = it.getDistance();
+
+ double weight = w.calcEdgeWeight(it, false);
+ double turnWeight = w.calcTurnWeight(1, 0, 0);
+
+ assertEquals(distance / enc.speed().getMaxOrMaxStorableDecimal() * 3.6, weight, 0.1d);
+ assertEquals(Double.POSITIVE_INFINITY, turnWeight, 0.1d);
+ }
+
+}
diff --git a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AlternativeRoutesRoutingTest.java b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AlternativeRoutesRoutingTest.java
new file mode 100644
index 000000000..b70f00613
--- /dev/null
+++ b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/AlternativeRoutesRoutingTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contact: mosaic@fokus.fraunhofer.de
+ */
+
+package org.eclipse.mosaic.lib.routing.graphhopper.algorithm;
+
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.mosaic.lib.routing.graphhopper.junit.TestGraphRule;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.GHListHelper;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.OptionalTurnCostProvider;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.VehicleEncoding;
+
+import com.graphhopper.routing.Path;
+import com.graphhopper.routing.RoutingAlgorithm;
+import com.graphhopper.routing.weighting.FastestWeighting;
+import com.graphhopper.routing.weighting.Weighting;
+import com.graphhopper.storage.BaseGraph;
+import com.graphhopper.util.PMap;
+import com.graphhopper.util.Parameters;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+
+public class AlternativeRoutesRoutingTest {
+
+ @Rule
+ public TestGraphRule testGraph = new TestGraphRule();
+
+ /**
+ * Calculates two alternatives paths using the test graph
+ */
+ @Test
+ public void calculateAlternativePaths_withTurnCost() {
+ BaseGraph g = testGraph.getGraph();
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+ Weighting w = new FastestWeighting(enc.access(), enc.speed(), new OptionalTurnCostProvider(enc, g.getTurnCostStorage()));
+
+ //100 seconds turn costs for turn (0-1)->(1-2)
+ g.getTurnCostStorage().set(enc.turnCost(), 0, 1, 2, 100);
+
+ RoutingAlgorithm algo = RoutingAlgorithmFactory.DEFAULT.createAlgorithm(g, w,
+ new PMap().putObject(Parameters.Algorithms.AltRoute.MAX_PATHS, 3)
+ );
+
+ // RUN
+ List paths = algo.calcPaths(0, 10);
+
+ // ASSERT
+ assertEquals(3, paths.size());
+
+ Path p = paths.get(0);
+ assertEquals(GHListHelper.createTList(0, 1, 5, 10), p.calcNodes());
+ assertEquals(5000, p.getDistance(), 0.1);
+
+ p = paths.get(1);
+ assertEquals(GHListHelper.createTList(0, 4, 7, 9, 10), p.calcNodes());
+ assertEquals(5500, p.getDistance(), 0.1);
+
+ p = paths.get(2);
+ assertEquals(GHListHelper.createTList(0, 1, 5, 6, 10), p.calcNodes());
+ assertEquals(6000, p.getDistance(), 0.1);
+ }
+
+ /**
+ * Calculates two alternatives paths using the test graph
+ * considering turn costs
+ */
+ @Test
+ public void calculateAlternativePaths() {
+ BaseGraph g = testGraph.getGraph();
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+ Weighting w = new FastestWeighting(enc.access(), enc.speed(), new OptionalTurnCostProvider(enc, g.getTurnCostStorage()));
+
+ RoutingAlgorithm algo = RoutingAlgorithmFactory.DEFAULT.createAlgorithm(g, w,
+ new PMap().putObject(Parameters.Algorithms.AltRoute.MAX_PATHS, 3)
+ );
+
+ // RUN
+ List paths = algo.calcPaths(0, 10);
+
+ // ASSERT
+ assertEquals(3, paths.size());
+ //assert shortest
+ Path p = paths.get(0);
+ assertEquals(GHListHelper.createTList(0, 1, 5, 10), p.calcNodes());
+ assertEquals(5000, p.getDistance(), 0.1);
+
+ p = paths.get(1);
+ assertEquals(GHListHelper.createTList(0, 4, 7, 9, 10), p.calcNodes());
+ assertEquals(5500, p.getDistance(), 0.1);
+
+ p = paths.get(2);
+ assertEquals(GHListHelper.createTList(0, 1, 2, 6, 10), p.calcNodes());
+ assertEquals(5600, p.getDistance(), 0.1);
+ }
+
+ /**
+ * Calculates only the best path.
+ */
+ @Test
+ public void calculateBestPath() {
+ BaseGraph g = testGraph.getGraph();
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+ Weighting w = new FastestWeighting(enc.access(), enc.speed(), new OptionalTurnCostProvider(enc, g.getTurnCostStorage()));
+
+ RoutingAlgorithm algo = RoutingAlgorithmFactory.DEFAULT.createAlgorithm(g, w, new PMap());
+
+ Path p = algo.calcPath(0, 10);
+
+ //assert shortest
+ assertEquals(GHListHelper.createTList(0, 1, 5, 10), p.calcNodes());
+ assertEquals(5000, p.getDistance(), 0.1);
+ }
+
+}
diff --git a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/BellmanFordRoutingTest.java b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/BellmanFordRoutingTest.java
index 0986d9160..899283e2e 100644
--- a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/BellmanFordRoutingTest.java
+++ b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/BellmanFordRoutingTest.java
@@ -19,42 +19,32 @@
import org.eclipse.mosaic.lib.routing.graphhopper.junit.TestGraphRule;
import org.eclipse.mosaic.lib.routing.graphhopper.util.GHListHelper;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.OptionalTurnCostProvider;
+import org.eclipse.mosaic.lib.routing.graphhopper.util.VehicleEncoding;
import com.graphhopper.routing.Path;
-import com.graphhopper.routing.util.BikeFlagEncoder;
-import com.graphhopper.routing.util.CarFlagEncoder;
-import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.routing.util.FootFlagEncoder;
import com.graphhopper.routing.weighting.FastestWeighting;
import com.graphhopper.routing.weighting.ShortestWeighting;
-import com.graphhopper.routing.weighting.TurnWeighting;
import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.GraphHopperStorage;
-import com.graphhopper.storage.TurnCostExtension;
+import com.graphhopper.storage.BaseGraph;
+import com.graphhopper.util.PMap;
import org.junit.Rule;
import org.junit.Test;
public class BellmanFordRoutingTest {
- private EncodingManager encManager = EncodingManager.create(
- new CarFlagEncoder(5, 5, 127),
- new BikeFlagEncoder(),
- new FootFlagEncoder()
- );
@Rule
- public TestGraphRule testGraph = new TestGraphRule(encManager);
+ public TestGraphRule testGraph = new TestGraphRule();
@Test
public void calculateFastestPath() {
- GraphHopperStorage g = testGraph.getGraph();
- FlagEncoder e = encManager.getEncoder("CAR");
- Weighting w = new FastestWeighting(e);
-
+ BaseGraph g = testGraph.getGraph();
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+ Weighting w = new FastestWeighting(enc.access(), enc.speed());
//run
- Path p = new BellmanFordRouting(g, w).calcPath(0, 10);
+ Path p = new BellmanFordRouting(g, w, new PMap()).calcPath(0, 10);
//assert shortest
assertEquals(GHListHelper.createTList(0, 1, 5, 10), p.calcNodes());
@@ -63,15 +53,15 @@ public void calculateFastestPath() {
@Test
public void calculateFastestPath_turnCosts() {
- GraphHopperStorage g = testGraph.getGraph();
- FlagEncoder e = encManager.getEncoder("CAR");
- Weighting w = new TurnWeighting(new FastestWeighting(e), (TurnCostExtension) g.getExtension());
+ BaseGraph g = testGraph.getGraph();
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+ Weighting w = new FastestWeighting(enc.access(), enc.speed(), new OptionalTurnCostProvider(enc, g.getTurnCostStorage()));
//add expensive turn at (0-1)->(1,5)
- testGraph.getTurnCostStorage().addTurnInfo(0, 1, 3, e.getTurnFlags(false, 124));
+ g.getTurnCostStorage().set(enc.turnCost(), 0, 1, 3, 124);
//run
- Path p = new BellmanFordRouting(g, w).calcPath(0, 10);
+ Path p = new BellmanFordRouting(g, w, new PMap()).calcPath(0, 10);
//assert shortest
assertEquals(GHListHelper.createTList(0, 4, 7, 9, 10), p.calcNodes());
@@ -80,12 +70,12 @@ public void calculateFastestPath_turnCosts() {
@Test
public void calculateShortestPath() {
- GraphHopperStorage g = testGraph.getGraph();
- FlagEncoder e = encManager.getEncoder("CAR");
- Weighting w = new ShortestWeighting(e);
+ BaseGraph g = testGraph.getGraph();
+ VehicleEncoding enc = testGraph.getEncodingManager().getVehicleEncoding("car");
+ Weighting w = new ShortestWeighting(enc.access(), enc.speed());
//run
- Path p = new BellmanFordRouting(g, w).calcPath(0, 10);
+ Path p = new BellmanFordRouting(g, w, new PMap()).calcPath(0, 10);
//assert shortest
assertEquals(GHListHelper.createTList(0, 1, 5, 10), p.calcNodes());
diff --git a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/CamvitChoiceRoutingTest.java b/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/CamvitChoiceRoutingTest.java
deleted file mode 100644
index ac796353d..000000000
--- a/lib/mosaic-routing/src/test/java/org/eclipse/mosaic/lib/routing/graphhopper/algorithm/CamvitChoiceRoutingTest.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2020 Fraunhofer FOKUS and others. All rights reserved.
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contact: mosaic@fokus.fraunhofer.de
- */
-
-package org.eclipse.mosaic.lib.routing.graphhopper.algorithm;
-
-import static org.junit.Assert.assertEquals;
-
-import org.eclipse.mosaic.lib.routing.graphhopper.junit.TestGraphRule;
-import org.eclipse.mosaic.lib.routing.graphhopper.util.GHListHelper;
-
-import com.graphhopper.routing.Path;
-import com.graphhopper.routing.util.BikeFlagEncoder;
-import com.graphhopper.routing.util.CarFlagEncoder;
-import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.routing.util.FootFlagEncoder;
-import com.graphhopper.routing.util.TurnCostEncoder;
-import com.graphhopper.routing.weighting.FastestWeighting;
-import com.graphhopper.routing.weighting.TurnWeighting;
-import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.Graph;
-import com.graphhopper.storage.GraphHopperStorage;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-@RunWith(Parameterized.class)
-public class CamvitChoiceRoutingTest {
- /**
- * Run tests with both implementations: Djikstra and A*
- */
- @Parameters
- public static Collection
-
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${version.jackson}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${version.jackson}
+
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
- ${version.jackson-xml}
+ ${version.jackson}
@@ -318,7 +330,7 @@
com.graphhopper
- graphhopper-api
+ graphhopper-web-api
${version.graphhopper}
@@ -326,6 +338,28 @@
com.graphhopper
graphhopper-core
${version.graphhopper}
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+
+
+ org.openstreetmap.osmosis
+ osmosis-osm-binary
+
+
+ de.westnordost
+ osm-legal-default-speeds-jvm
+
+
+ org.codehaus.janino
+ janino
+
+
+ org.apache.xmlgraphics
+ xmlgraphics-commons
+
+
@@ -333,6 +367,12 @@
hppc
${version.hppc}
+
+
+ org.locationtech.jts
+ jts-core
+ ${version.jts-core}
+
org.java-websocket
diff --git a/test/mosaic-integration-tests/src/test/java/org/eclipse/mosaic/test/AbstractPerceptionModuleIT.java b/test/mosaic-integration-tests/src/test/java/org/eclipse/mosaic/test/AbstractPerceptionModuleIT.java
index 7c0b1ea7f..5ca6daf4c 100644
--- a/test/mosaic-integration-tests/src/test/java/org/eclipse/mosaic/test/AbstractPerceptionModuleIT.java
+++ b/test/mosaic-integration-tests/src/test/java/org/eclipse/mosaic/test/AbstractPerceptionModuleIT.java
@@ -55,4 +55,5 @@ public void rightAmountOfTrafficLightPhaseSwitches() throws Exception {
// perceived vehicles repeat their route 10 times resulting in 11 perceptions
LogAssert.contains(simulationRule, PERCEPTION_VEHICLE_LOG, ".*Traffic Light switched 11 times\\..*");
}
+
}