diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4eda9dfa8b1..82f72125b27 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,5 @@
+### 5.0 [not yet released]
+
### 4.0 [29 Sep 2021]
- faster node-based CH preparation (~20%), (#2390)
diff --git a/client-hc/pom.xml b/client-hc/pom.xml
index 1d07077fe74..4f85b8c648c 100644
--- a/client-hc/pom.xml
+++ b/client-hc/pom.xml
@@ -22,21 +22,21 @@
4.0.0directions-api-client-hc
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTjarGraphHopper Directions API hand-crafted Java Client.com.github.GIScience.graphhoppergraphhopper-parent
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-web-api
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.squareup.okhttp3
diff --git a/config-example.yml b/config-example.yml
index 0432d559945..a933e485550 100644
--- a/config-example.yml
+++ b/config-example.yml
@@ -164,9 +164,9 @@ graphhopper:
# custom_areas.directory: path/to/custom_areas
##### Country Rules #####
- # GraphHopper applies country-specific routing rules (enabled by default) during import.
- # Use this flag to disable these rules (you need to repeat the import for changes to take effect)
- # country_rules.enable: false
+ # GraphHopper applies country-specific routing rules during import (not enabled by default).
+ # You need to redo the import for changes to take effect.
+ # country_rules.enabled: true
# Dropwizard server configuration
server:
diff --git a/core/pom.xml b/core/pom.xml
index 89f60d17b18..4b6131b7293 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -5,7 +5,7 @@
graphhopper-coreGraphHopper Core
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTjar
GraphHopper is a fast and memory efficient Java road routing engine
@@ -14,7 +14,7 @@
com.github.GIScience.graphhoppergraphhopper-parent
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOT
@@ -38,7 +38,7 @@
com.github.GIScience.graphhoppergraphhopper-web-api
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTcom.carrotsearch
diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java
index 69f9efeabd5..42ba7e36cc6 100644
--- a/core/src/main/java/com/graphhopper/GraphHopper.java
+++ b/core/src/main/java/com/graphhopper/GraphHopper.java
@@ -493,10 +493,7 @@ public GraphHopper init(GraphHopperConfig ghConfig) {
graphHopperFolder = pruneFileEnd(osmFile) + "-gh";
}
- if (ghConfig.has("country_rules.enabled")) {
- boolean countryRulesEnabled = ghConfig.getBool("country_rules.enabled", false);
- countryRuleFactory = countryRulesEnabled ? new CountryRuleFactory() : null;
- }
+ countryRuleFactory = ghConfig.getBool("country_rules.enabled", false) ? new CountryRuleFactory() : null;
customAreasDirectory = ghConfig.getString("custom_areas.directory", customAreasDirectory);
// graph
diff --git a/core/src/main/java/com/graphhopper/routing/HeadingResolver.java b/core/src/main/java/com/graphhopper/routing/HeadingResolver.java
index 1548ffabba5..db22126a898 100644
--- a/core/src/main/java/com/graphhopper/routing/HeadingResolver.java
+++ b/core/src/main/java/com/graphhopper/routing/HeadingResolver.java
@@ -19,12 +19,14 @@
package com.graphhopper.routing;
import com.carrotsearch.hppc.IntArrayList;
+import com.graphhopper.routing.util.EdgeFilter;
import com.graphhopper.storage.Graph;
import com.graphhopper.util.*;
+import com.graphhopper.util.shapes.GHPoint;
public class HeadingResolver {
private final EdgeExplorer edgeExplorer;
- private double toleranceRad = deg2Rad(100);
+ private double toleranceRad = Math.toRadians(100);
public HeadingResolver(Graph graph) {
this.edgeExplorer = graph.createEdgeExplorer();
@@ -63,12 +65,7 @@ public IntArrayList getEdgesWithDifferentHeading(int baseNode, double heading) {
* Sets the tolerance for {@link #getEdgesWithDifferentHeading} in degrees.
*/
public HeadingResolver setTolerance(double tolerance) {
- this.toleranceRad = deg2Rad(tolerance);
+ this.toleranceRad = Math.toRadians(tolerance);
return this;
}
-
- private static double deg2Rad(double deg) {
- return Math.toRadians(deg);
- }
-
}
diff --git a/core/src/main/java/com/graphhopper/routing/Router.java b/core/src/main/java/com/graphhopper/routing/Router.java
index 086394e1b17..7e2c11f1d36 100644
--- a/core/src/main/java/com/graphhopper/routing/Router.java
+++ b/core/src/main/java/com/graphhopper/routing/Router.java
@@ -24,6 +24,7 @@
import com.graphhopper.ResponsePath;
import com.graphhopper.config.Profile;
import com.graphhopper.routing.ch.CHRoutingAlgorithmFactory;
+import com.graphhopper.routing.ev.BooleanEncodedValue;
import com.graphhopper.routing.ev.EncodedValueLookup;
import com.graphhopper.routing.ev.Subnetwork;
import com.graphhopper.routing.lm.LMRoutingAlgorithmFactory;
@@ -176,12 +177,12 @@ private void checkHeadings(GHRequest request) {
}
private void checkPointHints(GHRequest request) {
- if (request.getPointHints().size() > 0 && request.getPointHints().size() != request.getPoints().size())
+ if (!request.getPointHints().isEmpty() && request.getPointHints().size() != request.getPoints().size())
throw new IllegalArgumentException("If you pass " + POINT_HINT + ", you need to pass exactly one hint for every point, empty hints will be ignored");
}
private void checkCurbsides(GHRequest request) {
- if (request.getCurbsides().size() > 0 && request.getCurbsides().size() != request.getPoints().size())
+ if (!request.getCurbsides().isEmpty() && request.getCurbsides().size() != request.getPoints().size())
throw new IllegalArgumentException("If you pass " + CURBSIDE + ", you need to pass exactly one curbside for every point, empty curbsides will be ignored");
}
@@ -207,7 +208,7 @@ protected GHResponse routeRoundTrip(GHRequest request, FlexSolver solver) {
StopWatch sw = new StopWatch().start();
double startHeading = request.getHeadings().isEmpty() ? Double.NaN : request.getHeadings().get(0);
RoundTripRouting.Params params = new RoundTripRouting.Params(request.getHints(), startHeading, routerConfig.getMaxRoundTripRetries());
- List snaps = RoundTripRouting.lookup(request.getPoints(), solver.getSnapFilter(), locationIndex, params);
+ List snaps = RoundTripRouting.lookup(request.getPoints(), solver.createSnapFilter(), locationIndex, params);
ghRsp.addDebugInfo("idLookup:" + sw.stop().getSeconds() + "s");
// ORS-GH MOD START - additional code
checkMaxSearchDistances(request, ghRsp, snaps);
@@ -259,7 +260,8 @@ protected GHResponse routeAlt(GHRequest request, Solver solver) {
throw new IllegalArgumentException("Currently alternative routes work only with start and end point. You tried to use: " + request.getPoints().size() + " points");
GHResponse ghRsp = new GHResponse();
StopWatch sw = new StopWatch().start();
- List snaps = ViaRouting.lookup(encodingManager, request.getPoints(), solver.getSnapFilter(), locationIndex, request.getSnapPreventions(), request.getPointHints());
+ List snaps = ViaRouting.lookup(encodingManager, request.getPoints(), solver.createSnapFilter(), locationIndex,
+ request.getSnapPreventions(), request.getPointHints(), solver.createDirectedSnapFilter(), request.getHeadings());
ghRsp.addDebugInfo("idLookup:" + sw.stop().getSeconds() + "s");
// ORS-GH MOD START - additional code
checkMaxSearchDistances(request, ghRsp, snaps);
@@ -308,7 +310,8 @@ protected GHResponse routeAlt(GHRequest request, Solver solver) {
protected GHResponse routeVia(GHRequest request, Solver solver) {
GHResponse ghRsp = new GHResponse();
StopWatch sw = new StopWatch().start();
- List snaps = ViaRouting.lookup(encodingManager, request.getPoints(), solver.getSnapFilter(), locationIndex, request.getSnapPreventions(), request.getPointHints());
+ List snaps = ViaRouting.lookup(encodingManager, request.getPoints(), solver.createSnapFilter(), locationIndex,
+ request.getSnapPreventions(), request.getPointHints(), solver.createDirectedSnapFilter(), request.getHeadings());
ghRsp.addDebugInfo("idLookup:" + sw.stop().getSeconds() + "s");
// ORS-GH MOD START - additional code
checkMaxSearchDistances(request, ghRsp, snaps);
@@ -321,7 +324,8 @@ protected GHResponse routeVia(GHRequest request, Solver solver) {
boolean forceCurbsides = getForceCurbsides(request.getHints());
// ORS-GH MOD START: enable TD routing
long time = getTime(request.getHints());
- ViaRouting.Result result = ViaRouting.calcPaths(request.getPoints(), queryGraph, snaps, solver.weighting, pathCalculator, request.getCurbsides(), forceCurbsides, request.getHeadings(), passThrough, time);
+ ViaRouting.Result result = ViaRouting.calcPaths(request.getPoints(), queryGraph, snaps, solver.weighting,
+ pathCalculator, request.getCurbsides(), forceCurbsides, request.getHeadings(), passThrough, time);
// ORS-GH MOD END
if (request.getPoints().size() != result.paths.size() + 1)
@@ -490,10 +494,15 @@ protected void checkProfileCompatibility() {
protected abstract Weighting createWeighting();
- protected EdgeFilter getSnapFilter() {
+ protected EdgeFilter createSnapFilter() {
return new DefaultSnapFilter(weighting, lookup.getBooleanEncodedValue(Subnetwork.key(profile.getName())));
}
+ protected EdgeFilter createDirectedSnapFilter() {
+ BooleanEncodedValue inSubnetworkEnc = lookup.getBooleanEncodedValue(Subnetwork.key(profile.getName()));
+ return edgeState -> !edgeState.get(inSubnetworkEnc) && Double.isFinite(weighting.calcEdgeWeightWithAccess(edgeState, false));
+ }
+
protected abstract PathCalculator createPathCalculator(QueryGraph queryGraph);
private List getTurnCostProfiles() {
@@ -611,7 +620,7 @@ protected FlexiblePathCalculator createPathCalculator(QueryGraph queryGraph) {
// ORS-GH MOD START: pass edgeFilter
@Override
- protected EdgeFilter getSnapFilter() {
+ protected EdgeFilter createSnapFilter() {
EdgeFilter defaultSnapFilter = new DefaultSnapFilter(weighting, lookup.getBooleanEncodedValue(Subnetwork.key(profile.getName())));
if (edgeFilterFactory != null)
return edgeFilterFactory.createEdgeFilter(request.getAdditionalHints(), weighting.getFlagEncoder(), ghStorage, defaultSnapFilter);
diff --git a/core/src/main/java/com/graphhopper/routing/ViaRouting.java b/core/src/main/java/com/graphhopper/routing/ViaRouting.java
index 8f9eb474b49..66ea5751f01 100644
--- a/core/src/main/java/com/graphhopper/routing/ViaRouting.java
+++ b/core/src/main/java/com/graphhopper/routing/ViaRouting.java
@@ -24,7 +24,7 @@
import com.graphhopper.routing.ev.RoadEnvironment;
import com.graphhopper.routing.querygraph.QueryGraph;
import com.graphhopper.routing.util.EdgeFilter;
-import com.graphhopper.routing.util.FiniteWeightFilter;
+import com.graphhopper.routing.util.HeadingEdgeFilter;
import com.graphhopper.routing.util.NameSimilarityEdgeFilter;
import com.graphhopper.routing.util.SnapPreventionEdgeFilter;
import com.graphhopper.routing.weighting.Weighting;
@@ -54,27 +54,36 @@ public class ViaRouting {
/**
* @throws MultiplePointsNotFoundException in case one or more points could not be resolved
*/
- public static List lookup(EncodedValueLookup lookup, List points, EdgeFilter edgeFilter, LocationIndex locationIndex, List snapPreventions, List pointHints) {
+ public static List lookup(EncodedValueLookup lookup, List points, EdgeFilter snapFilter,
+ LocationIndex locationIndex, List snapPreventions, List pointHints,
+ EdgeFilter directedSnapFilter, List headings) {
if (points.size() < 2)
throw new IllegalArgumentException("At least 2 points have to be specified, but was:" + points.size());
final EnumEncodedValue roadClassEnc = lookup.getEnumEncodedValue(RoadClass.KEY, RoadClass.class);
final EnumEncodedValue roadEnvEnc = lookup.getEnumEncodedValue(RoadEnvironment.KEY, RoadEnvironment.class);
EdgeFilter strictEdgeFilter = snapPreventions.isEmpty()
- ? edgeFilter
- : new SnapPreventionEdgeFilter(edgeFilter, roadClassEnc, roadEnvEnc, snapPreventions);
+ ? snapFilter
+ : new SnapPreventionEdgeFilter(snapFilter, roadClassEnc, roadEnvEnc, snapPreventions);
List snaps = new ArrayList<>(points.size());
IntArrayList pointsNotFound = new IntArrayList();
for (int placeIndex = 0; placeIndex < points.size(); placeIndex++) {
GHPoint point = points.get(placeIndex);
Snap snap = null;
- if (!pointHints.isEmpty())
+ if (placeIndex < headings.size() && !Double.isNaN(headings.get(placeIndex))) {
+ if (!pointHints.isEmpty() && !Helper.isEmpty(pointHints.get(placeIndex)))
+ throw new IllegalArgumentException("Cannot specify heading and point_hint at the same time. " +
+ "Make sure you specify either an empty point_hint (String) or a NaN heading (double) for point " + placeIndex);
+ snap = locationIndex.findClosest(point.lat, point.lon, new HeadingEdgeFilter(directedSnapFilter, headings.get(placeIndex), point));
+ } else if (!pointHints.isEmpty()) {
snap = locationIndex.findClosest(point.lat, point.lon, new NameSimilarityEdgeFilter(strictEdgeFilter,
pointHints.get(placeIndex), point, 100));
- else if (!snapPreventions.isEmpty())
+ } else if (!snapPreventions.isEmpty()) {
snap = locationIndex.findClosest(point.lat, point.lon, strictEdgeFilter);
+ }
+
if (snap == null || !snap.isValid())
- snap = locationIndex.findClosest(point.lat, point.lon, edgeFilter);
+ snap = locationIndex.findClosest(point.lat, point.lon, snapFilter);
if (!snap.isValid())
pointsNotFound.add(placeIndex);
diff --git a/core/src/main/java/com/graphhopper/routing/util/HeadingEdgeFilter.java b/core/src/main/java/com/graphhopper/routing/util/HeadingEdgeFilter.java
new file mode 100644
index 00000000000..a6b986fe5ad
--- /dev/null
+++ b/core/src/main/java/com/graphhopper/routing/util/HeadingEdgeFilter.java
@@ -0,0 +1,68 @@
+package com.graphhopper.routing.util;
+
+import com.graphhopper.util.*;
+import com.graphhopper.util.shapes.GHPoint;
+
+public class HeadingEdgeFilter implements EdgeFilter {
+
+ private final double heading;
+ private final EdgeFilter directedEdgeFilter;
+ private final GHPoint pointNearHeading;
+
+ public HeadingEdgeFilter(EdgeFilter directedEdgeFilter, double heading, GHPoint pointNearHeading) {
+ this.directedEdgeFilter = directedEdgeFilter;
+ this.heading = heading;
+ this.pointNearHeading = pointNearHeading;
+ }
+
+ @Override
+ public boolean accept(EdgeIteratorState edgeState) {
+ final double tolerance = 30;
+ // we only accept edges that are not too far away. It might happen that only far away edges match the heading
+ // in which case we rather rely on the fallback snapping than return a match here.
+ final double maxDistance = 20;
+ double headingOfEdge = getHeadingOfGeometryNearPoint(edgeState, pointNearHeading, maxDistance);
+ if (Double.isNaN(headingOfEdge))
+ // this edge is too far away. we do not accept it.
+ return false;
+ // we accept the edge if either of the two directions roughly has the right heading
+ return Math.abs(headingOfEdge - heading) < tolerance && directedEdgeFilter.accept(edgeState) ||
+ Math.abs((headingOfEdge + 180) % 360 - heading) < tolerance && directedEdgeFilter.accept(edgeState.detach(true));
+ }
+
+ /**
+ * Calculates the heading (in degrees) of the given edge in fwd direction near the given point. If the point is
+ * too far away from the edge (according to the maxDistance parameter) it returns Double.NaN.
+ */
+ static double getHeadingOfGeometryNearPoint(EdgeIteratorState edgeState, GHPoint point, double maxDistance) {
+ final DistanceCalc calcDist = DistanceCalcEarth.DIST_EARTH;
+ double closestDistance = Double.POSITIVE_INFINITY;
+ PointList points = edgeState.fetchWayGeometry(FetchMode.ALL);
+ int closestPoint = -1;
+ for (int i = 1; i < points.size(); i++) {
+ double fromLat = points.getLat(i - 1), fromLon = points.getLon(i - 1);
+ double toLat = points.getLat(i), toLon = points.getLon(i);
+ // the 'distance' between the point and an edge segment is either the vertical distance to the segment or
+ // the distance to the closer one of the two endpoints. here we save one call to calcDist per segment,
+ // because each endpoint appears in two segments (except the first and last).
+ double distance = calcDist.validEdgeDistance(point.lat, point.lon, fromLat, fromLon, toLat, toLon)
+ ? calcDist.calcDenormalizedDist(calcDist.calcNormalizedEdgeDistance(point.lat, point.lon, fromLat, fromLon, toLat, toLon))
+ : calcDist.calcDist(fromLat, fromLon, point.lat, point.lon);
+ if (i == points.size() - 1)
+ distance = Math.min(distance, calcDist.calcDist(toLat, toLon, point.lat, point.lon));
+ if (distance > maxDistance)
+ continue;
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestPoint = i;
+ }
+ }
+ if (closestPoint < 0)
+ return Double.NaN;
+
+ double fromLat = points.getLat(closestPoint - 1), fromLon = points.getLon(closestPoint - 1);
+ double toLat = points.getLat(closestPoint), toLon = points.getLon(closestPoint);
+ // calcOrientation returns value relative to East, but heading is relative to North
+ return (Math.toDegrees(AngleCalc.ANGLE_CALC.calcOrientation(fromLat, fromLon, toLat, toLon)) + 90) % 360;
+ }
+}
diff --git a/core/src/main/java/com/graphhopper/storage/BaseGraph.java b/core/src/main/java/com/graphhopper/storage/BaseGraph.java
index 9658aaefe7e..5f1b3ef323b 100644
--- a/core/src/main/java/com/graphhopper/storage/BaseGraph.java
+++ b/core/src/main/java/com/graphhopper/storage/BaseGraph.java
@@ -26,7 +26,6 @@
import com.graphhopper.util.shapes.BBox;
import java.util.Collections;
-import java.util.Locale;
import static com.graphhopper.util.Helper.nf;
@@ -42,110 +41,40 @@
* loadExisting, (4) usage, (5) flush, (6) close
*/
class BaseGraph implements Graph {
- // Currently distances are stored as 4 byte integers. using a conversion factor of 1000 the minimum distance
- // that is not considered zero is 0.0005m (=0.5mm) and the maximum distance per edge is about 2.147.483m=2147km.
- // See OSMReader.addEdge and #1871.
- private static final double INT_DIST_FACTOR = 1000d;
- static double MAX_DIST = Integer.MAX_VALUE / INT_DIST_FACTOR;
-
- final DataAccess edges;
- final DataAccess nodes;
- final BBox bounds;
- final NodeAccess nodeAccess;
private final static String STRING_IDX_NAME_KEY = "name";
+ final BaseGraphNodesAndEdges store;
+ final NodeAccess nodeAccess;
final StringIndex stringIndex;
// can be null if turn costs are not supported
final TurnCostStorage turnCostStorage;
final BitUtil bitUtil;
- private final int intsForFlags;
// length | nodeA | nextNode | ... | nodeB
- // as we use integer index in 'egdes' area => 'geometry' area is limited to 4GB (we use pos&neg values!)
+ // as we use integer index in 'edges' area => 'geometry' area is limited to 4GB (we use pos&neg values!)
private final DataAccess wayGeometry;
private final Directory dir;
- /**
- * interval [0,n)
- */
- protected int edgeCount;
- // node memory layout:
- protected int N_EDGE_REF, N_LAT, N_LON, N_ELE, N_TC;
- // edge memory layout:
- int E_NODEA, E_NODEB, E_LINKA, E_LINKB, E_FLAGS, E_DIST, E_GEO, E_NAME;
- /**
- * Specifies how many entries (integers) are used per edge.
- */
- int edgeEntryBytes;
- /**
- * Specifies how many entries (integers) are used per node
- */
- int nodeEntryBytes;
private boolean initialized = false;
- /**
- * interval [0,n)
- */
- private int nodeCount;
- private int edgeEntryIndex, nodeEntryIndex;
private long maxGeoRef;
- private boolean frozen = false;
public BaseGraph(Directory dir, int intsForFlags, boolean withElevation, boolean withTurnCosts, int segmentSize) {
this.dir = dir;
- this.intsForFlags = intsForFlags;
this.bitUtil = BitUtil.LITTLE;
this.wayGeometry = dir.create("geometry", segmentSize);
this.stringIndex = new StringIndex(dir, 1000, segmentSize);
- this.nodes = dir.create("nodes", dir.getDefaultType("nodes", true), segmentSize);
- this.edges = dir.create("edges", dir.getDefaultType("edges", true), segmentSize);
- this.bounds = BBox.createInverse(withElevation);
- this.nodeAccess = new GHNodeAccess(this, withElevation);
+ this.store = new BaseGraphNodesAndEdges(dir, intsForFlags, withElevation, withTurnCosts, segmentSize);
+ this.nodeAccess = new GHNodeAccess(store);
this.turnCostStorage = withTurnCosts ? new TurnCostStorage(this, dir.create("turn_costs", dir.getDefaultType("turn_costs", true), segmentSize)) : null;
if (segmentSize >= 0) {
checkNotInitialized();
}
}
- private void setEdgeRef(int nodeId, int edgeId) {
- nodes.setInt(toNodePointer(nodeId) + N_EDGE_REF, edgeId);
- }
-
- int getEdgeRef(int nodeId) {
- return nodes.getInt(toNodePointer(nodeId) + N_EDGE_REF);
- }
-
- private int getNodeA(long edgePointer) {
- return edges.getInt(edgePointer + E_NODEA);
- }
-
- private int getNodeB(long edgePointer) {
- return edges.getInt(edgePointer + E_NODEB);
- }
-
- private int getLinkA(long edgePointer) {
- return edges.getInt(edgePointer + E_LINKA);
- }
-
- private int getLinkB(long edgePointer) {
- return edges.getInt(edgePointer + E_LINKB);
- }
-
- long toNodePointer(int node) {
- if (node < 0 || node >= nodeCount)
- throw new IllegalArgumentException("node: " + node + " out of bounds [0," + nodeCount + "[");
- return (long) node * nodeEntryBytes;
- }
-
- private long toEdgePointer(int edge) {
- if (edge < 0 || edge >= edgeCount)
- throw new IllegalArgumentException("edge: " + edge + " out of bounds [0," + edgeCount + "[");
- return (long) edge * edgeEntryBytes;
- }
-
private int getOtherNode(int nodeThis, long edgePointer) {
- int nodeA = getNodeA(edgePointer);
- return nodeThis == nodeA ? getNodeB(edgePointer) : nodeA;
+ int nodeA = store.getNodeA(edgePointer);
+ return nodeThis == nodeA ? store.getNodeB(edgePointer) : nodeA;
}
private boolean isAdjacentToNode(int node, long edgePointer) {
- return getNodeA(edgePointer) == node || getNodeB(edgePointer) == node;
+ return store.getNodeA(edgePointer) == node || store.getNodeB(edgePointer) == node;
}
private static boolean isTestingEnabled() {
@@ -165,90 +94,16 @@ void checkNotInitialized() {
+ "after calling create or loadExisting. Calling one of the methods twice is also not allowed.");
}
- void checkInitialized() {
- if (!initialized)
- throw new IllegalStateException("The graph has not yet been initialized.");
- }
-
- private void loadNodesHeader() {
- nodeEntryBytes = nodes.getHeader(0 * 4);
- nodeCount = nodes.getHeader(1 * 4);
- bounds.minLon = Helper.intToDegree(nodes.getHeader(2 * 4));
- bounds.maxLon = Helper.intToDegree(nodes.getHeader(3 * 4));
- bounds.minLat = Helper.intToDegree(nodes.getHeader(4 * 4));
- bounds.maxLat = Helper.intToDegree(nodes.getHeader(5 * 4));
-
- if (bounds.hasElevation()) {
- bounds.minEle = Helper.intToEle(nodes.getHeader(6 * 4));
- bounds.maxEle = Helper.intToEle(nodes.getHeader(7 * 4));
- }
-
- frozen = nodes.getHeader(8 * 4) == 1;
- }
-
- private void setNodesHeader() {
- nodes.setHeader(0 * 4, nodeEntryBytes);
- nodes.setHeader(1 * 4, nodeCount);
- nodes.setHeader(2 * 4, Helper.degreeToInt(bounds.minLon));
- nodes.setHeader(3 * 4, Helper.degreeToInt(bounds.maxLon));
- nodes.setHeader(4 * 4, Helper.degreeToInt(bounds.minLat));
- nodes.setHeader(5 * 4, Helper.degreeToInt(bounds.maxLat));
- if (bounds.hasElevation()) {
- nodes.setHeader(6 * 4, Helper.eleToInt(bounds.minEle));
- nodes.setHeader(7 * 4, Helper.eleToInt(bounds.maxEle));
- }
-
- nodes.setHeader(8 * 4, isFrozen() ? 1 : 0);
- }
-
- protected void loadEdgesHeader() {
- edgeEntryBytes = edges.getHeader(0 * 4);
- edgeCount = edges.getHeader(1 * 4);
- }
-
- protected void setEdgesHeader() {
- edges.setHeader(0, edgeEntryBytes);
- edges.setHeader(1 * 4, edgeCount);
- }
-
- protected int loadWayGeometryHeader() {
+ private void loadWayGeometryHeader() {
maxGeoRef = bitUtil.combineIntsToLong(wayGeometry.getHeader(0), wayGeometry.getHeader(4));
- return 1;
}
- protected int setWayGeometryHeader() {
+ private void setWayGeometryHeader() {
wayGeometry.setHeader(0, bitUtil.getIntLow(maxGeoRef));
wayGeometry.setHeader(4, bitUtil.getIntHigh(maxGeoRef));
- return 1;
}
- void initStorage() {
- edgeEntryIndex = 0;
- nodeEntryIndex = 0;
- E_NODEA = nextEdgeEntryIndex(4);
- E_NODEB = nextEdgeEntryIndex(4);
- E_LINKA = nextEdgeEntryIndex(4);
- E_LINKB = nextEdgeEntryIndex(4);
- E_FLAGS = nextEdgeEntryIndex(intsForFlags * 4);
-
- E_DIST = nextEdgeEntryIndex(4);
- E_GEO = nextEdgeEntryIndex(4);
- E_NAME = nextEdgeEntryIndex(4);
-
- N_EDGE_REF = nextNodeEntryIndex(4);
- N_LAT = nextNodeEntryIndex(4);
- N_LON = nextNodeEntryIndex(4);
- if (nodeAccess.is3D())
- N_ELE = nextNodeEntryIndex(4);
- else
- N_ELE = -1;
-
- if (supportsTurnCosts())
- N_TC = nextNodeEntryIndex(4);
- else
- N_TC = -1;
-
- initNodeAndEdgeEntrySize();
+ private void setInitialized() {
initialized = true;
}
@@ -256,64 +111,14 @@ boolean supportsTurnCosts() {
return turnCostStorage != null;
}
- /**
- * Initializes the node storage such that each node has no edge and no turn cost entry
- */
- void initNodeRefs(long oldCapacity, long newCapacity) {
- for (long pointer = oldCapacity + N_EDGE_REF; pointer < newCapacity; pointer += nodeEntryBytes) {
- nodes.setInt(pointer, EdgeIterator.NO_EDGE);
- }
- if (supportsTurnCosts()) {
- for (long pointer = oldCapacity + N_TC; pointer < newCapacity; pointer += nodeEntryBytes) {
- nodes.setInt(pointer, TurnCostStorage.NO_TURN_ENTRY);
- }
- }
- }
-
- protected final int nextEdgeEntryIndex(int sizeInBytes) {
- int tmp = edgeEntryIndex;
- edgeEntryIndex += sizeInBytes;
- return tmp;
- }
-
- protected final int nextNodeEntryIndex(int sizeInBytes) {
- int tmp = nodeEntryIndex;
- nodeEntryIndex += sizeInBytes;
- return tmp;
- }
-
- protected final void initNodeAndEdgeEntrySize() {
- nodeEntryBytes = nodeEntryIndex;
- edgeEntryBytes = edgeEntryIndex;
- }
-
- /**
- * Check if byte capacity of DataAcess nodes object is sufficient to include node index, else
- * extend byte capacity
- */
- final void ensureNodeIndex(int nodeIndex) {
- checkInitialized();
-
- if (nodeIndex < nodeCount)
- return;
-
- long oldNodes = nodeCount;
- nodeCount = nodeIndex + 1;
- boolean capacityIncreased = nodes.ensureCapacity((long) nodeCount * nodeEntryBytes);
- if (capacityIncreased) {
- long newBytesCapacity = nodes.getCapacity();
- initNodeRefs(oldNodes * nodeEntryBytes, newBytesCapacity);
- }
- }
-
@Override
public int getNodes() {
- return nodeCount;
+ return store.getNodes();
}
@Override
public int getEdges() {
- return edgeCount;
+ return store.getEdges();
}
@Override
@@ -323,23 +128,21 @@ public NodeAccess getNodeAccess() {
@Override
public BBox getBounds() {
- return bounds;
+ return store.getBounds();
}
synchronized void freeze() {
if (isFrozen())
throw new IllegalStateException("base graph already frozen");
-
- frozen = true;
+ store.setFrozen(true);
}
synchronized boolean isFrozen() {
- return frozen;
+ return store.getFrozen();
}
void create(long initSize) {
- nodes.create(initSize);
- edges.create(initSize);
+ store.create(initSize);
initSize = Math.min(initSize, 2000);
wayGeometry.create(initSize);
@@ -347,51 +150,15 @@ void create(long initSize) {
if (supportsTurnCosts()) {
turnCostStorage.create(initSize);
}
- initStorage();
+ setInitialized();
// 0 stands for no separate geoRef
maxGeoRef = 4;
-
- initNodeRefs(0, nodes.getCapacity());
}
String toDetailsString() {
- return "edges:" + nf(edgeCount) + "(" + edges.getCapacity() / Helper.MB + "MB), "
- + "nodes:" + nf(getNodes()) + "(" + nodes.getCapacity() / Helper.MB + "MB), "
+ return store.toDetailsString() + ", "
+ "name:(" + stringIndex.getCapacity() / Helper.MB + "MB), "
- + "geo:" + nf(maxGeoRef) + "(" + wayGeometry.getCapacity() / Helper.MB + "MB), "
- + "bounds:" + bounds;
- }
-
- public void debugPrint() {
- final int printMax = 100;
- System.out.println("nodes:");
- String formatNodes = "%12s | %12s | %12s | %12s \n";
- System.out.format(Locale.ROOT, formatNodes, "#", "N_EDGE_REF", "N_LAT", "N_LON");
- NodeAccess nodeAccess = getNodeAccess();
- for (int i = 0; i < Math.min(nodeCount, printMax); ++i) {
- System.out.format(Locale.ROOT, formatNodes, i, getEdgeRef(i), nodeAccess.getLat(i), nodeAccess.getLon(i));
- }
- if (nodeCount > printMax) {
- System.out.format(Locale.ROOT, " ... %d more nodes\n", nodeCount - printMax);
- }
- System.out.println("edges:");
- String formatEdges = "%12s | %12s | %12s | %12s | %12s | %12s | %12s \n";
- System.out.format(Locale.ROOT, formatEdges, "#", "E_NODEA", "E_NODEB", "E_LINKA", "E_LINKB", "E_FLAGS", "E_DIST");
- IntsRef intsRef = new IntsRef(intsForFlags);
- for (int i = 0; i < Math.min(edgeCount, printMax); ++i) {
- long edgePointer = toEdgePointer(i);
- readFlags(edgePointer, intsRef);
- System.out.format(Locale.ROOT, formatEdges, i,
- getNodeA(edgePointer),
- getNodeB(edgePointer),
- getLinkA(edgePointer),
- getLinkB(edgePointer),
- intsRef,
- getDist(edgePointer));
- }
- if (edgeCount > printMax) {
- System.out.printf(Locale.ROOT, " ... %d more edges", edgeCount - printMax);
- }
+ + "geo:" + nf(maxGeoRef) + "(" + wayGeometry.getCapacity() / Helper.MB + "MB)";
}
/**
@@ -416,10 +183,7 @@ public void flush() {
if (!stringIndex.isClosed())
stringIndex.flush();
- setNodesHeader();
- setEdgesHeader();
- edges.flush();
- nodes.flush();
+ store.flush();
if (supportsTurnCosts()) {
turnCostStorage.flush();
}
@@ -430,15 +194,14 @@ public void close() {
wayGeometry.close();
if (!stringIndex.isClosed())
stringIndex.close();
- edges.close();
- nodes.close();
+ store.close();
if (supportsTurnCosts()) {
turnCostStorage.close();
}
}
long getCapacity() {
- return edges.getCapacity() + nodes.getCapacity() + stringIndex.getCapacity()
+ return store.getCapacity() + stringIndex.getCapacity()
+ wayGeometry.getCapacity() + (supportsTurnCosts() ? turnCostStorage.getCapacity() : 0);
}
@@ -447,16 +210,13 @@ long getMaxGeoRef() {
}
void loadExisting(String dim) {
- if (!nodes.loadExisting())
- throw new IllegalStateException("Cannot load nodes. corrupt file or directory? " + dir);
+ if (!store.loadExisting())
+ throw new IllegalStateException("Cannot load edges or nodes. corrupt file or directory? " + dir);
if (!dim.equalsIgnoreCase("" + nodeAccess.getDimension()))
throw new IllegalStateException("Configured dimension (" + nodeAccess.getDimension() + ") is not equal "
+ "to dimension of loaded graph (" + dim + ")");
- if (!edges.loadExisting())
- throw new IllegalStateException("Cannot load edges. corrupt file or directory? " + dir);
-
if (!wayGeometry.loadExisting())
throw new IllegalStateException("Cannot load geometry. corrupt file or directory? " + dir);
@@ -466,12 +226,7 @@ void loadExisting(String dim) {
if (supportsTurnCosts() && !turnCostStorage.loadExisting())
throw new IllegalStateException("Cannot load turn cost storage. corrupt file or directory? " + dir);
- // first define header indices of this storage
- initStorage();
-
- // now load some properties from stored data
- loadNodesHeader();
- loadEdgesHeader();
+ setInitialized();
loadWayGeometryHeader();
}
@@ -481,8 +236,8 @@ void loadExisting(String dim) {
* @return the updated iterator the properties where copied to.
*/
EdgeIteratorState copyProperties(EdgeIteratorState from, EdgeIteratorStateImpl to) {
- long edgePointer = toEdgePointer(to.getEdge());
- writeFlags(edgePointer, from.getFlags());
+ long edgePointer = store.toEdgePointer(to.getEdge());
+ store.writeFlags(edgePointer, from.getFlags());
// copy the rest with higher level API
to.setDistance(from.getDistance()).
@@ -501,71 +256,13 @@ EdgeIteratorState copyProperties(EdgeIteratorState from, EdgeIteratorStateImpl t
public EdgeIteratorState edge(int nodeA, int nodeB) {
if (isFrozen())
throw new IllegalStateException("Cannot create edge if graph is already frozen");
-
- ensureNodeIndex(Math.max(nodeA, nodeB));
- int edgeId = internalEdgeAdd(nextEdgeId(), nodeA, nodeB);
+ int edgeId = store.edge(nodeA, nodeB);
EdgeIteratorStateImpl edge = new EdgeIteratorStateImpl(this);
boolean valid = edge.init(edgeId, nodeB);
assert valid;
return edge;
}
- /**
- * Writes a new edge to the array of edges and adds it to the linked list of edges at nodeA and nodeB
- */
- final int internalEdgeAdd(int newEdgeId, int nodeA, int nodeB) {
- writeEdge(newEdgeId, nodeA, nodeB);
- long edgePointer = toEdgePointer(newEdgeId);
-
- int edge = getEdgeRef(nodeA);
- if (edge > EdgeIterator.NO_EDGE)
- edges.setInt(E_LINKA + edgePointer, edge);
- setEdgeRef(nodeA, newEdgeId);
-
- if (nodeA != nodeB) {
- edge = getEdgeRef(nodeB);
- if (edge > EdgeIterator.NO_EDGE)
- edges.setInt(E_LINKB + edgePointer, edge);
- setEdgeRef(nodeB, newEdgeId);
- }
- return newEdgeId;
- }
-
- /**
- * Writes plain edge information to the edges index
- */
- private long writeEdge(int edgeId, int nodeA, int nodeB) {
- if (!EdgeIterator.Edge.isValid(edgeId))
- throw new IllegalStateException("Cannot write edge with illegal ID:" + edgeId + "; nodeA:" + nodeA + ", nodeB:" + nodeB);
-
- long edgePointer = toEdgePointer(edgeId);
- edges.setInt(edgePointer + E_NODEA, nodeA);
- edges.setInt(edgePointer + E_NODEB, nodeB);
- edges.setInt(edgePointer + E_LINKA, EdgeIterator.NO_EDGE);
- edges.setInt(edgePointer + E_LINKB, EdgeIterator.NO_EDGE);
- return edgePointer;
- }
-
- // for test only
- void setEdgeCount(int cnt) {
- edgeCount = cnt;
- }
-
- /**
- * Determine next free edgeId and ensure byte capacity to store edge
- *
- * @return next free edgeId
- */
- protected int nextEdgeId() {
- int nextEdge = edgeCount;
- edgeCount++;
- if (edgeCount < 0)
- throw new IllegalStateException("too many edges. new edge id would be negative. " + toString());
-
- edges.ensureCapacity(((long) edgeCount + 1) * edgeEntryBytes);
- return nextEdge;
- }
-
@Override
public EdgeIteratorState getEdgeIteratorState(int edgeId, int adjNode) {
EdgeIteratorStateImpl edge = new EdgeIteratorStateImpl(this);
@@ -582,11 +279,6 @@ public EdgeIteratorState getEdgeIteratorStateForKey(int edgeKey) {
return edge;
}
- final void checkAdjNodeBounds(int adjNode) {
- if (adjNode < 0 && adjNode != Integer.MIN_VALUE || adjNode >= nodeCount)
- throw new IllegalStateException("adjNode " + adjNode + " out of bounds [0," + nf(nodeCount) + ")");
- }
-
@Override
public EdgeExplorer createEdgeExplorer(EdgeFilter filter) {
return new EdgeIteratorImpl(this, filter);
@@ -614,64 +306,23 @@ public Weighting wrapWeighting(Weighting weighting) {
@Override
public int getOtherNode(int edge, int node) {
- long edgePointer = toEdgePointer(edge);
+ long edgePointer = store.toEdgePointer(edge);
return getOtherNode(node, edgePointer);
}
@Override
public boolean isAdjacentToNode(int edge, int node) {
- long edgePointer = toEdgePointer(edge);
+ long edgePointer = store.toEdgePointer(edge);
return isAdjacentToNode(node, edgePointer);
}
- private void readFlags(long edgePointer, IntsRef edgeFlags) {
- int size = edgeFlags.ints.length;
- for (int i = 0; i < size; i++) {
- edgeFlags.ints[i] = edges.getInt(edgePointer + E_FLAGS + i * 4);
- }
- }
-
- private void writeFlags(long edgePointer, IntsRef edgeFlags) {
- int size = edgeFlags.ints.length;
- for (int i = 0; i < size; i++) {
- edges.setInt(edgePointer + E_FLAGS + i * 4, edgeFlags.ints[i]);
- }
- }
-
- private void setDist(long edgePointer, double distance) {
- edges.setInt(edgePointer + E_DIST, distToInt(distance));
- }
-
- /**
- * Translates double distance to integer in order to save it in a DataAccess object
- */
- private int distToInt(double distance) {
- if (distance < 0)
- throw new IllegalArgumentException("Distance cannot be negative: " + distance);
- if (distance > MAX_DIST) {
- distance = MAX_DIST;
- }
- int integ = (int) Math.round(distance * INT_DIST_FACTOR);
- assert integ >= 0 : "distance out of range";
- return integ;
- }
-
- /**
- * returns distance (already translated from integer to double)
- */
- private double getDist(long pointer) {
- int val = edges.getInt(pointer + E_DIST);
- // do never return infinity even if INT MAX, see #435
- return val / INT_DIST_FACTOR;
- }
-
private void setWayGeometry_(PointList pillarNodes, long edgePointer, boolean reverse) {
if (pillarNodes != null && !pillarNodes.isEmpty()) {
if (pillarNodes.getDimension() != nodeAccess.getDimension())
throw new IllegalArgumentException("Cannot use pointlist which is " + pillarNodes.getDimension()
+ "D for graph which is " + nodeAccess.getDimension() + "D");
- long existingGeoRef = Helper.toUnsignedLong(edges.getInt(edgePointer + E_GEO));
+ long existingGeoRef = Helper.toUnsignedLong(store.getGeoRef(edgePointer));
int len = pillarNodes.size();
int dim = nodeAccess.getDimension();
@@ -686,7 +337,7 @@ private void setWayGeometry_(PointList pillarNodes, long edgePointer, boolean re
long nextGeoRef = nextGeoRef(len * dim);
setWayGeometryAtGeoRef(pillarNodes, edgePointer, reverse, nextGeoRef);
} else {
- edges.setInt(edgePointer + E_GEO, 0);
+ store.setGeoRef(edgePointer, 0);
}
}
@@ -698,7 +349,7 @@ private void setWayGeometryAtGeoRef(PointList pillarNodes, long edgePointer, boo
ensureGeometry(geoRefPosition, totalLen);
byte[] wayGeometryBytes = createWayGeometryBytes(pillarNodes, reverse);
wayGeometry.setBytes(geoRefPosition, wayGeometryBytes, wayGeometryBytes.length);
- edges.setInt(edgePointer + E_GEO, Helper.toSignedInt(geoRef));
+ store.setGeoRef(edgePointer, Helper.toSignedInt(geoRef));
}
private byte[] createWayGeometryBytes(PointList pillarNodes, boolean reverse) {
@@ -735,7 +386,7 @@ private PointList fetchWayGeometry_(long edgePointer, boolean reverse, FetchMode
pillarNodes.add(nodeAccess, adjNode);
return pillarNodes;
}
- long geoRef = Helper.toUnsignedLong(edges.getInt(edgePointer + E_GEO));
+ long geoRef = Helper.toUnsignedLong(store.getGeoRef(edgePointer));
int count = 0;
byte[] bytes = null;
if (geoRef > 0) {
@@ -799,8 +450,7 @@ private void setName(long edgePointer, String name) {
int stringIndexRef = (int) stringIndex.add(Collections.singletonMap(STRING_IDX_NAME_KEY, name));
if (stringIndexRef < 0)
throw new IllegalStateException("Too many names are stored, currently limited to int pointer");
-
- edges.setInt(edgePointer + E_NAME, stringIndexRef);
+ store.setNameRef(edgePointer, stringIndexRef);
}
private void ensureGeometry(long bytePos, int byteLength) {
@@ -816,6 +466,10 @@ private long nextGeoRef(int arrayLength) {
return tmp;
}
+ public boolean isClosed() {
+ return store.isClosed();
+ }
+
protected static class EdgeIteratorImpl extends EdgeIteratorStateImpl implements EdgeExplorer, EdgeIterator {
final EdgeFilter filter;
int nextEdgeId;
@@ -830,7 +484,7 @@ public EdgeIteratorImpl(BaseGraph baseGraph, EdgeFilter filter) {
@Override
public EdgeIterator setBaseNode(int baseNode) {
- nextEdgeId = edgeId = baseGraph.getEdgeRef(baseNode);
+ nextEdgeId = edgeId = store.getEdgeRef(store.toNodePointer(baseNode));
this.baseNode = baseNode;
return this;
}
@@ -846,16 +500,16 @@ public final boolean next() {
}
void goToNext() {
- edgePointer = baseGraph.toEdgePointer(nextEdgeId);
+ edgePointer = store.toEdgePointer(nextEdgeId);
edgeId = nextEdgeId;
- int nodeA = baseGraph.getNodeA(edgePointer);
+ int nodeA = store.getNodeA(edgePointer);
boolean baseNodeIsNodeA = baseNode == nodeA;
- adjNode = baseNodeIsNodeA ? baseGraph.getNodeB(edgePointer) : nodeA;
+ adjNode = baseNodeIsNodeA ? store.getNodeB(edgePointer) : nodeA;
reverse = !baseNodeIsNodeA;
freshFlags = false;
// position to next edge
- nextEdgeId = baseNodeIsNodeA ? baseGraph.getLinkA(edgePointer) : baseGraph.getLinkB(edgePointer);
+ nextEdgeId = baseNodeIsNodeA ? store.getLinkA(edgePointer) : store.getLinkB(edgePointer);
assert nextEdgeId != edgeId : ("endless loop detected for base node: " + baseNode + ", adj node: " + adjNode
+ ", edge pointer: " + edgePointer + ", edge: " + edgeId);
}
@@ -878,17 +532,17 @@ public AllEdgeIterator(BaseGraph baseGraph) {
@Override
public int length() {
- return baseGraph.edgeCount;
+ return store.getEdges();
}
@Override
public boolean next() {
edgeId++;
- if (edgeId >= baseGraph.edgeCount)
+ if (edgeId >= store.getEdges())
return false;
- edgePointer = baseGraph.toEdgePointer(edgeId);
- baseNode = baseGraph.getNodeA(edgePointer);
- adjNode = baseGraph.getNodeB(edgePointer);
+ edgePointer = store.toEdgePointer(edgeId);
+ baseNode = store.getNodeA(edgePointer);
+ adjNode = store.getNodeB(edgePointer);
freshFlags = false;
reverse = false;
return true;
@@ -917,6 +571,7 @@ public final EdgeIteratorState detach(boolean reverseArg) {
static class EdgeIteratorStateImpl implements EdgeIteratorState {
final BaseGraph baseGraph;
+ final BaseGraphNodesAndEdges store;
long edgePointer = -1;
int baseNode;
int adjNode;
@@ -928,19 +583,20 @@ static class EdgeIteratorStateImpl implements EdgeIteratorState {
public EdgeIteratorStateImpl(BaseGraph baseGraph) {
this.baseGraph = baseGraph;
- this.edgeFlags = new IntsRef(baseGraph.intsForFlags);
+ this.edgeFlags = new IntsRef(baseGraph.store.getIntsForFlags());
+ store = baseGraph.store;
}
/**
* @return false if the edge has not a node equal to expectedAdjNode
*/
final boolean init(int edgeId, int expectedAdjNode) {
- if (edgeId < 0 || edgeId >= baseGraph.edgeCount)
- throw new IllegalArgumentException("edge: " + edgeId + " out of bounds: [0," + baseGraph.edgeCount + "[");
+ if (edgeId < 0 || edgeId >= store.getEdges())
+ throw new IllegalArgumentException("edge: " + edgeId + " out of bounds: [0," + store.getEdges() + "[");
this.edgeId = edgeId;
- edgePointer = baseGraph.toEdgePointer(edgeId);
- baseNode = baseGraph.getNodeA(edgePointer);
- adjNode = baseGraph.getNodeB(edgePointer);
+ edgePointer = store.toEdgePointer(edgeId);
+ baseNode = store.getNodeA(edgePointer);
+ adjNode = store.getNodeB(edgePointer);
freshFlags = false;
if (expectedAdjNode == adjNode || expectedAdjNode == Integer.MIN_VALUE) {
@@ -963,9 +619,9 @@ final void init(int edgeKey) {
if (edgeKey < 0)
throw new IllegalArgumentException("edge keys must not be negative, given: " + edgeKey);
this.edgeId = GHUtility.getEdgeFromEdgeKey(edgeKey);
- edgePointer = baseGraph.toEdgePointer(edgeId);
- baseNode = baseGraph.getNodeA(edgePointer);
- adjNode = baseGraph.getNodeB(edgePointer);
+ edgePointer = store.toEdgePointer(edgeId);
+ baseNode = store.getNodeA(edgePointer);
+ adjNode = store.getNodeB(edgePointer);
freshFlags = false;
if (edgeKey % 2 == 0 || baseNode == adjNode) {
@@ -990,19 +646,19 @@ public final int getAdjNode() {
@Override
public double getDistance() {
- return baseGraph.getDist(edgePointer);
+ return store.getDist(edgePointer);
}
@Override
public EdgeIteratorState setDistance(double dist) {
- baseGraph.setDist(edgePointer, dist);
+ store.setDist(edgePointer, dist);
return this;
}
@Override
public IntsRef getFlags() {
if (!freshFlags) {
- baseGraph.readFlags(edgePointer, edgeFlags);
+ store.readFlags(edgePointer, edgeFlags);
freshFlags = true;
}
return edgeFlags;
@@ -1010,8 +666,8 @@ public IntsRef getFlags() {
@Override
public final EdgeIteratorState setFlags(IntsRef edgeFlags) {
- assert edgeId < baseGraph.edgeCount : "must be edge but was shortcut: " + edgeId + " >= " + baseGraph.edgeCount + ". Use setFlagsAndWeight";
- baseGraph.writeFlags(edgePointer, edgeFlags);
+ assert edgeId < store.getEdges() : "must be edge but was shortcut: " + edgeId + " >= " + store.getEdges() + ". Use setFlagsAndWeight";
+ store.writeFlags(edgePointer, edgeFlags);
for (int i = 0; i < edgeFlags.ints.length; i++) {
this.edgeFlags.ints[i] = edgeFlags.ints[i];
}
@@ -1027,7 +683,7 @@ public boolean get(BooleanEncodedValue property) {
@Override
public EdgeIteratorState set(BooleanEncodedValue property, boolean value) {
property.setBool(reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1039,7 +695,7 @@ public boolean getReverse(BooleanEncodedValue property) {
@Override
public EdgeIteratorState setReverse(BooleanEncodedValue property, boolean value) {
property.setBool(!reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1049,7 +705,7 @@ public EdgeIteratorState set(BooleanEncodedValue property, boolean fwd, boolean
throw new IllegalArgumentException("EncodedValue " + property.getName() + " supports only one direction");
property.setBool(reverse, getFlags(), fwd);
property.setBool(!reverse, getFlags(), bwd);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1061,7 +717,7 @@ public int get(IntEncodedValue property) {
@Override
public EdgeIteratorState set(IntEncodedValue property, int value) {
property.setInt(reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1073,7 +729,7 @@ public int getReverse(IntEncodedValue property) {
@Override
public EdgeIteratorState setReverse(IntEncodedValue property, int value) {
property.setInt(!reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1083,7 +739,7 @@ public EdgeIteratorState set(IntEncodedValue property, int fwd, int bwd) {
throw new IllegalArgumentException("EncodedValue " + property.getName() + " supports only one direction");
property.setInt(reverse, getFlags(), fwd);
property.setInt(!reverse, getFlags(), bwd);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1095,7 +751,7 @@ public double get(DecimalEncodedValue property) {
@Override
public EdgeIteratorState set(DecimalEncodedValue property, double value) {
property.setDecimal(reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1107,7 +763,7 @@ public double getReverse(DecimalEncodedValue property) {
@Override
public EdgeIteratorState setReverse(DecimalEncodedValue property, double value) {
property.setDecimal(!reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1117,7 +773,7 @@ public EdgeIteratorState set(DecimalEncodedValue property, double fwd, double bw
throw new IllegalArgumentException("EncodedValue " + property.getName() + " supports only one direction");
property.setDecimal(reverse, getFlags(), fwd);
property.setDecimal(!reverse, getFlags(), bwd);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1129,7 +785,7 @@ public > T get(EnumEncodedValue property) {
@Override
public > EdgeIteratorState set(EnumEncodedValue property, T value) {
property.setEnum(reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1141,7 +797,7 @@ public > T getReverse(EnumEncodedValue property) {
@Override
public > EdgeIteratorState setReverse(EnumEncodedValue property, T value) {
property.setEnum(!reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1151,7 +807,7 @@ public > EdgeIteratorState set(EnumEncodedValue property, T
throw new IllegalArgumentException("EncodedValue " + property.getName() + " supports only one direction");
property.setEnum(reverse, getFlags(), fwd);
property.setEnum(!reverse, getFlags(), bwd);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1163,7 +819,7 @@ public String get(StringEncodedValue property) {
@Override
public EdgeIteratorState set(StringEncodedValue property, String value) {
property.setString(reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1175,7 +831,7 @@ public String getReverse(StringEncodedValue property) {
@Override
public EdgeIteratorState setReverse(StringEncodedValue property, String value) {
property.setString(!reverse, getFlags(), value);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1185,7 +841,7 @@ public EdgeIteratorState set(StringEncodedValue property, String fwd, String bwd
throw new IllegalArgumentException("EncodedValue " + property.getName() + " supports only one direction");
property.setString(reverse, getFlags(), fwd);
property.setString(!reverse, getFlags(), bwd);
- baseGraph.writeFlags(edgePointer, getFlags());
+ store.writeFlags(edgePointer, getFlags());
return this;
}
@@ -1227,7 +883,7 @@ public int getOrigEdgeLast() {
@Override
public String getName() {
- int stringIndexRef = baseGraph.edges.getInt(edgePointer + baseGraph.E_NAME);
+ int stringIndexRef = store.getNameRef(edgePointer);
String name = baseGraph.stringIndex.get(stringIndexRef, STRING_IDX_NAME_KEY);
// preserve backward compatibility (returns null if not explicitly set)
return name == null ? "" : name;
diff --git a/core/src/main/java/com/graphhopper/storage/BaseGraphNodesAndEdges.java b/core/src/main/java/com/graphhopper/storage/BaseGraphNodesAndEdges.java
new file mode 100644
index 00000000000..77f7170a600
--- /dev/null
+++ b/core/src/main/java/com/graphhopper/storage/BaseGraphNodesAndEdges.java
@@ -0,0 +1,395 @@
+/*
+ * Licensed to GraphHopper GmbH under one or more contributor
+ * license agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * GraphHopper GmbH licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.graphhopper.storage;
+
+import com.graphhopper.util.EdgeIterator;
+import com.graphhopper.util.Helper;
+import com.graphhopper.util.shapes.BBox;
+
+import java.util.Locale;
+
+import static com.graphhopper.util.EdgeIterator.NO_EDGE;
+import static com.graphhopper.util.Helper.nf;
+
+/**
+ * Underlying storage for nodes and edges of {@link BaseGraph}. Nodes and edges are stored using two {@link DataAccess}
+ * instances. Nodes and edges are simply stored sequentially, see the memory layout in the constructor.
+ */
+class BaseGraphNodesAndEdges {
+ // Currently distances are stored as 4 byte integers. using a conversion factor of 1000 the minimum distance
+ // that is not considered zero is 0.0005m (=0.5mm) and the maximum distance per edge is about 2.147.483m=2147km.
+ // See OSMReader.addEdge and #1871.
+ private static final double INT_DIST_FACTOR = 1000d;
+ static double MAX_DIST = Integer.MAX_VALUE / INT_DIST_FACTOR;
+
+ // nodes
+ private final DataAccess nodes;
+ private final int N_EDGE_REF, N_LAT, N_LON, N_ELE, N_TC;
+ private int nodeEntryBytes;
+ private int nodeCount;
+
+ // edges
+ private final DataAccess edges;
+ private final int E_NODEA, E_NODEB, E_LINKA, E_LINKB, E_FLAGS, E_DIST, E_GEO, E_NAME;
+ private final int intsForFlags;
+ private int edgeEntryBytes;
+ private int edgeCount;
+
+ private final boolean withTurnCosts;
+ private final boolean withElevation;
+
+ // we do not write the bounding box directly to storage, but rather to this bbox object. we only write to storage
+ // when flushing. why? just because we did it like this in the past, and otherwise we run into rounding errors,
+ // because of: #2393
+ public final BBox bounds;
+ private boolean frozen;
+
+ public BaseGraphNodesAndEdges(Directory dir, int intsForFlags, boolean withElevation, boolean withTurnCosts, int segmentSize) {
+ this.nodes = dir.create("nodes", dir.getDefaultType("nodes", true), segmentSize);
+ this.edges = dir.create("edges", dir.getDefaultType("edges", true), segmentSize);
+ this.intsForFlags = intsForFlags;
+ this.withTurnCosts = withTurnCosts;
+ this.withElevation = withElevation;
+ bounds = BBox.createInverse(withElevation);
+
+ // memory layout for nodes
+ N_EDGE_REF = 0;
+ N_LAT = 4;
+ N_LON = 8;
+ N_ELE = N_LON + (withElevation ? 4 : 0);
+ N_TC = N_ELE + (withTurnCosts ? 4 : 0);
+ nodeEntryBytes = N_TC + 4;
+
+ // memory layout for edges
+ E_NODEA = 0;
+ E_NODEB = 4;
+ E_LINKA = 8;
+ E_LINKB = 12;
+ E_FLAGS = 16;
+ E_DIST = E_FLAGS + intsForFlags * 4;
+ E_GEO = E_DIST + 4;
+ E_NAME = E_GEO + 4;
+ edgeEntryBytes = E_NAME + 4;
+ }
+
+ public void create(long initSize) {
+ nodes.create(initSize);
+ edges.create(initSize);
+ }
+
+ public boolean loadExisting() {
+ if (!nodes.loadExisting() || !edges.loadExisting())
+ return false;
+
+ // now load some properties from stored data
+ nodeEntryBytes = nodes.getHeader(0 * 4);
+ nodeCount = nodes.getHeader(1 * 4);
+ bounds.minLon = Helper.intToDegree(nodes.getHeader(2 * 4));
+ bounds.maxLon = Helper.intToDegree(nodes.getHeader(3 * 4));
+ bounds.minLat = Helper.intToDegree(nodes.getHeader(4 * 4));
+ bounds.maxLat = Helper.intToDegree(nodes.getHeader(5 * 4));
+ if (withElevation) {
+ bounds.minEle = Helper.intToEle(nodes.getHeader(6 * 4));
+ bounds.maxEle = Helper.intToEle(nodes.getHeader(7 * 4));
+ }
+ frozen = nodes.getHeader(8 * 4) == 1;
+
+ edgeEntryBytes = edges.getHeader(0 * 4);
+ edgeCount = edges.getHeader(1 * 4);
+ return true;
+ }
+
+ public void flush() {
+ nodes.setHeader(0 * 4, nodeEntryBytes);
+ nodes.setHeader(1 * 4, nodeCount);
+ nodes.setHeader(2 * 4, Helper.degreeToInt(bounds.minLon));
+ nodes.setHeader(3 * 4, Helper.degreeToInt(bounds.maxLon));
+ nodes.setHeader(4 * 4, Helper.degreeToInt(bounds.minLat));
+ nodes.setHeader(5 * 4, Helper.degreeToInt(bounds.maxLat));
+ if (withElevation) {
+ nodes.setHeader(6 * 4, Helper.eleToInt(bounds.minEle));
+ nodes.setHeader(7 * 4, Helper.eleToInt(bounds.maxEle));
+ }
+ nodes.setHeader(8 * 4, frozen ? 1 : 0);
+
+ edges.setHeader(0, edgeEntryBytes);
+ edges.setHeader(1 * 4, edgeCount);
+
+ edges.flush();
+ nodes.flush();
+ }
+
+ public void close() {
+ edges.close();
+ nodes.close();
+ }
+
+ public int getNodes() {
+ return nodeCount;
+ }
+
+ public int getEdges() {
+ return edgeCount;
+ }
+
+ public int getIntsForFlags() {
+ return intsForFlags;
+ }
+
+ public boolean withElevation() {
+ return withElevation;
+ }
+
+ public boolean withTurnCosts() {
+ return withTurnCosts;
+ }
+
+ public BBox getBounds() {
+ return bounds;
+ }
+
+ public long getCapacity() {
+ return nodes.getCapacity() + edges.getCapacity();
+ }
+
+ public boolean isClosed() {
+ assert nodes.isClosed() == edges.isClosed();
+ return nodes.isClosed();
+ }
+
+ public int edge(int nodeA, int nodeB) {
+ if (edgeCount == Integer.MAX_VALUE)
+ throw new IllegalStateException("Maximum edge count exceeded: " + edgeCount);
+ ensureNodeCapacity(Math.max(nodeA, nodeB));
+ final int edge = edgeCount;
+ final long edgePointer = (long) edgeCount * edgeEntryBytes;
+ edgeCount++;
+ edges.ensureCapacity((long) edgeCount * edgeEntryBytes);
+
+ setNodeA(edgePointer, nodeA);
+ setNodeB(edgePointer, nodeB);
+ // we keep a linked list of edges at each node. here we prepend the new edge at the already existing linked
+ // list of edges.
+ long nodePointerA = toNodePointer(nodeA);
+ int edgeRefA = getEdgeRef(nodePointerA);
+ setLinkA(edgePointer, EdgeIterator.Edge.isValid(edgeRefA) ? edgeRefA : NO_EDGE);
+ setEdgeRef(nodePointerA, edge);
+
+ if (nodeA != nodeB) {
+ long nodePointerB = toNodePointer(nodeB);
+ int edgeRefB = getEdgeRef(nodePointerB);
+ setLinkB(edgePointer, EdgeIterator.Edge.isValid(edgeRefB) ? edgeRefB : NO_EDGE);
+ setEdgeRef(nodePointerB, edge);
+ }
+ return edge;
+ }
+
+ public void ensureNodeCapacity(int node) {
+ if (node < nodeCount)
+ return;
+
+ int oldNodes = nodeCount;
+ nodeCount = node + 1;
+ nodes.ensureCapacity((long) nodeCount * nodeEntryBytes);
+ for (int n = oldNodes; n < nodeCount; ++n) {
+ setEdgeRef(toNodePointer(n), NO_EDGE);
+ if (withTurnCosts)
+ setTurnCostRef(toNodePointer(n), TurnCostStorage.NO_TURN_ENTRY);
+ }
+ }
+
+ public long toNodePointer(int node) {
+ if (node < 0 || node >= nodeCount)
+ throw new IllegalArgumentException("node: " + node + " out of bounds [0," + nodeCount + "[");
+ return (long) node * nodeEntryBytes;
+ }
+
+ public long toEdgePointer(int edge) {
+ if (edge < 0 || edge >= edgeCount)
+ throw new IllegalArgumentException("edge: " + edge + " out of bounds [0," + edgeCount + "[");
+ return (long) edge * edgeEntryBytes;
+ }
+
+ public void readFlags(long edgePointer, IntsRef edgeFlags) {
+ int size = edgeFlags.ints.length;
+ for (int i = 0; i < size; ++i)
+ edgeFlags.ints[i] = edges.getInt(edgePointer + E_FLAGS + i * 4);
+ }
+
+ public void writeFlags(long edgePointer, IntsRef edgeFlags) {
+ int size = edgeFlags.ints.length;
+ for (int i = 0; i < size; ++i)
+ edges.setInt(edgePointer + E_FLAGS + i * 4, edgeFlags.ints[i]);
+ }
+
+ public void setNodeA(long edgePointer, int nodeA) {
+ edges.setInt(edgePointer + E_NODEA, nodeA);
+ }
+
+ public void setNodeB(long edgePointer, int nodeB) {
+ edges.setInt(edgePointer + E_NODEB, nodeB);
+ }
+
+ public void setLinkA(long edgePointer, int linkA) {
+ edges.setInt(edgePointer + E_LINKA, linkA);
+ }
+
+ public void setLinkB(long edgePointer, int linkB) {
+ edges.setInt(edgePointer + E_LINKB, linkB);
+ }
+
+ public void setDist(long edgePointer, double distance) {
+ edges.setInt(edgePointer + E_DIST, distToInt(distance));
+ }
+
+ public void setGeoRef(long edgePointer, int geoRef) {
+ edges.setInt(edgePointer + E_GEO, geoRef);
+ }
+
+ public void setNameRef(long edgePointer, int nameRef) {
+ edges.setInt(edgePointer + E_NAME, nameRef);
+ }
+
+ public int getNodeA(long edgePointer) {
+ return edges.getInt(edgePointer + E_NODEA);
+ }
+
+ public int getNodeB(long edgePointer) {
+ return edges.getInt(edgePointer + E_NODEB);
+ }
+
+ public int getLinkA(long edgePointer) {
+ return edges.getInt(edgePointer + E_LINKA);
+ }
+
+ public int getLinkB(long edgePointer) {
+ return edges.getInt(edgePointer + E_LINKB);
+ }
+
+ public double getDist(long pointer) {
+ int val = edges.getInt(pointer + E_DIST);
+ // do never return infinity even if INT MAX, see #435
+ return val / INT_DIST_FACTOR;
+ }
+
+ public int getGeoRef(long edgePointer) {
+ return edges.getInt(edgePointer + E_GEO);
+ }
+
+ public int getNameRef(long edgePointer) {
+ return edges.getInt(edgePointer + E_NAME);
+ }
+
+ public void setEdgeRef(long nodePointer, int edgeRef) {
+ nodes.setInt(nodePointer + N_EDGE_REF, edgeRef);
+ }
+
+ public void setLat(long nodePointer, double lat) {
+ nodes.setInt(nodePointer + N_LAT, Helper.degreeToInt(lat));
+ }
+
+ public void setLon(long nodePointer, double lon) {
+ nodes.setInt(nodePointer + N_LON, Helper.degreeToInt(lon));
+ }
+
+ public void setEle(long elePointer, double ele) {
+ nodes.setInt(elePointer + N_ELE, Helper.eleToInt(ele));
+ }
+
+ public void setTurnCostRef(long nodePointer, int tcRef) {
+ nodes.setInt(nodePointer + N_TC, tcRef);
+ }
+
+ public int getEdgeRef(long nodePointer) {
+ return nodes.getInt(nodePointer + N_EDGE_REF);
+ }
+
+ public double getLat(long nodePointer) {
+ return Helper.intToDegree(nodes.getInt(nodePointer + N_LAT));
+ }
+
+ public double getLon(long nodePointer) {
+ return Helper.intToDegree(nodes.getInt(nodePointer + N_LON));
+ }
+
+ public double getEle(long nodePointer) {
+ return Helper.intToEle(nodes.getInt(nodePointer + N_ELE));
+ }
+
+ public int getTurnCostRef(long nodePointer) {
+ return nodes.getInt(nodePointer + N_TC);
+ }
+
+ public void setFrozen(boolean frozen) {
+ this.frozen = frozen;
+ }
+
+ public boolean getFrozen() {
+ return frozen;
+ }
+
+ public void debugPrint() {
+ final int printMax = 100;
+ System.out.println("nodes:");
+ String formatNodes = "%12s | %12s | %12s | %12s \n";
+ System.out.format(Locale.ROOT, formatNodes, "#", "N_EDGE_REF", "N_LAT", "N_LON");
+ for (int i = 0; i < Math.min(nodeCount, printMax); ++i) {
+ long nodePointer = toNodePointer(i);
+ System.out.format(Locale.ROOT, formatNodes, i, getEdgeRef(nodePointer), getLat(nodePointer), getLon(nodePointer));
+ }
+ if (nodeCount > printMax) {
+ System.out.format(Locale.ROOT, " ... %d more nodes\n", nodeCount - printMax);
+ }
+ System.out.println("edges:");
+ String formatEdges = "%12s | %12s | %12s | %12s | %12s | %12s | %12s \n";
+ System.out.format(Locale.ROOT, formatEdges, "#", "E_NODEA", "E_NODEB", "E_LINKA", "E_LINKB", "E_FLAGS", "E_DIST");
+ IntsRef intsRef = new IntsRef(intsForFlags);
+ for (int i = 0; i < Math.min(edgeCount, printMax); ++i) {
+ long edgePointer = toEdgePointer(i);
+ readFlags(edgePointer, intsRef);
+ System.out.format(Locale.ROOT, formatEdges, i,
+ getNodeA(edgePointer),
+ getNodeB(edgePointer),
+ getLinkA(edgePointer),
+ getLinkB(edgePointer),
+ intsRef,
+ getDist(edgePointer));
+ }
+ if (edgeCount > printMax) {
+ System.out.printf(Locale.ROOT, " ... %d more edges", edgeCount - printMax);
+ }
+ }
+
+ private int distToInt(double distance) {
+ if (distance < 0)
+ throw new IllegalArgumentException("Distance cannot be negative: " + distance);
+ if (distance > MAX_DIST) {
+ distance = MAX_DIST;
+ }
+ int intDist = (int) Math.round(distance * INT_DIST_FACTOR);
+ assert intDist >= 0 : "distance out of range";
+ return intDist;
+ }
+
+ public String toDetailsString() {
+ return "edges: " + nf(edgeCount) + "(" + edges.getCapacity() / Helper.MB + "MB), "
+ + "nodes: " + nf(nodeCount) + "(" + nodes.getCapacity() / Helper.MB + "MB), "
+ + "bounds: " + bounds;
+ }
+}
diff --git a/core/src/main/java/com/graphhopper/storage/CHStorage.java b/core/src/main/java/com/graphhopper/storage/CHStorage.java
index 90d97205fc6..577e11e0988 100644
--- a/core/src/main/java/com/graphhopper/storage/CHStorage.java
+++ b/core/src/main/java/com/graphhopper/storage/CHStorage.java
@@ -31,7 +31,7 @@
* DataAccess-based storage for CH shortcuts. Stores shortcuts and CH levels sequentially using two DataAccess objects
* and gives read/write access to the different shortcut and node fields.
*
- * This can be seen as an extension to a base graph: We assign a CH level to each nodes and add additional edges to
+ * This can be seen as an extension to a base graph: We assign a CH level to each node and add additional edges to
* the graph ('shortcuts'). The shortcuts need to be ordered in a certain way, but this is not enforced here.
*
* @see CHStorageBuilder to build a valid storage that can be used for routing
@@ -58,7 +58,7 @@ public class CHStorage {
private int nodeCount = -1;
private boolean edgeBased;
- // some shortcuts exceed the maximum storable weight and we count them here
+ // some shortcuts exceed the maximum storable weight, and we count them here
private int numShortcutsExceedingWeight;
// use this to report shortcuts with too small weights
diff --git a/core/src/main/java/com/graphhopper/storage/GHNodeAccess.java b/core/src/main/java/com/graphhopper/storage/GHNodeAccess.java
index 6ad8cdaa3e9..9d0d396e4a0 100644
--- a/core/src/main/java/com/graphhopper/storage/GHNodeAccess.java
+++ b/core/src/main/java/com/graphhopper/storage/GHNodeAccess.java
@@ -17,8 +17,6 @@
*/
package com.graphhopper.storage;
-import com.graphhopper.util.Helper;
-
/**
* A helper class for GraphHopperStorage for its node access.
*
@@ -26,59 +24,55 @@
* @author Peter Karich
*/
class GHNodeAccess implements NodeAccess {
- private final BaseGraph baseGraph;
- private final boolean elevation;
+ private final BaseGraphNodesAndEdges store;
- public GHNodeAccess(BaseGraph baseGraph, boolean withElevation) {
- this.baseGraph = baseGraph;
- this.elevation = withElevation;
+ public GHNodeAccess(BaseGraphNodesAndEdges store) {
+ this.store = store;
}
@Override
public void ensureNode(int nodeId) {
- baseGraph.ensureNodeIndex(nodeId);
+ store.ensureNodeCapacity(nodeId);
}
@Override
public final void setNode(int nodeId, double lat, double lon, double ele) {
- baseGraph.ensureNodeIndex(nodeId);
- long tmp = baseGraph.toNodePointer(nodeId);
- baseGraph.nodes.setInt(tmp + baseGraph.N_LAT, Helper.degreeToInt(lat));
- baseGraph.nodes.setInt(tmp + baseGraph.N_LON, Helper.degreeToInt(lon));
+ store.ensureNodeCapacity(nodeId);
+ store.setLat(store.toNodePointer(nodeId), lat);
+ store.setLon(store.toNodePointer(nodeId), lon);
- if (is3D()) {
+ if (store.withElevation()) {
// meter precision is sufficient for now
- baseGraph.nodes.setInt(tmp + baseGraph.N_ELE, Helper.eleToInt(ele));
- baseGraph.bounds.update(lat, lon, ele);
-
+ store.setEle(store.toNodePointer(nodeId), ele);
+ store.bounds.update(lat, lon, ele);
} else {
- baseGraph.bounds.update(lat, lon);
+ store.bounds.update(lat, lon);
}
}
@Override
public final double getLat(int nodeId) {
- return Helper.intToDegree(baseGraph.nodes.getInt(baseGraph.toNodePointer(nodeId) + baseGraph.N_LAT));
+ return store.getLat(store.toNodePointer(nodeId));
}
@Override
public final double getLon(int nodeId) {
- return Helper.intToDegree(baseGraph.nodes.getInt(baseGraph.toNodePointer(nodeId) + baseGraph.N_LON));
+ return store.getLon(store.toNodePointer(nodeId));
}
@Override
public final double getEle(int nodeId) {
- if (!elevation)
- throw new IllegalStateException("Cannot access elevation - 3D is not enabled");
-
- return Helper.intToEle(baseGraph.nodes.getInt(baseGraph.toNodePointer(nodeId) + baseGraph.N_ELE));
+ if (!store.withElevation())
+ throw new IllegalStateException("elevation is disabled");
+ return store.getEle(store.toNodePointer(nodeId));
}
+ @Override
public final void setTurnCostIndex(int index, int turnCostIndex) {
- if (baseGraph.supportsTurnCosts()) {
- baseGraph.ensureNodeIndex(index);
- long tmp = baseGraph.toNodePointer(index);
- baseGraph.nodes.setInt(tmp + baseGraph.N_TC, turnCostIndex);
+ if (store.withTurnCosts()) {
+ // todo: remove ensure?
+ store.ensureNodeCapacity(index);
+ store.setTurnCostRef(store.toNodePointer(index), turnCostIndex);
} else {
throw new AssertionError("This graph does not support turn costs");
}
@@ -86,21 +80,19 @@ public final void setTurnCostIndex(int index, int turnCostIndex) {
@Override
public final int getTurnCostIndex(int index) {
- if (baseGraph.supportsTurnCosts())
- return baseGraph.nodes.getInt(baseGraph.toNodePointer(index) + baseGraph.N_TC);
+ if (store.withTurnCosts())
+ return store.getTurnCostRef(store.toNodePointer(index));
else
throw new AssertionError("This graph does not support turn costs");
}
@Override
public final boolean is3D() {
- return elevation;
+ return store.withElevation();
}
@Override
public int getDimension() {
- if (elevation)
- return 3;
- return 2;
+ return store.withElevation() ? 3 : 2;
}
}
diff --git a/core/src/main/java/com/graphhopper/storage/GraphHopperStorage.java b/core/src/main/java/com/graphhopper/storage/GraphHopperStorage.java
index b19452f3ae6..9171e7ff70a 100644
--- a/core/src/main/java/com/graphhopper/storage/GraphHopperStorage.java
+++ b/core/src/main/java/com/graphhopper/storage/GraphHopperStorage.java
@@ -441,7 +441,7 @@ public void close() {
}
public boolean isClosed() {
- return baseGraph.nodes.isClosed();
+ return baseGraph.isClosed();
}
public long getCapacity() {
diff --git a/core/src/main/java/com/graphhopper/storage/RoutingCHEdgeIteratorImpl.java b/core/src/main/java/com/graphhopper/storage/RoutingCHEdgeIteratorImpl.java
index 0180f96a0b8..f0245508d97 100644
--- a/core/src/main/java/com/graphhopper/storage/RoutingCHEdgeIteratorImpl.java
+++ b/core/src/main/java/com/graphhopper/storage/RoutingCHEdgeIteratorImpl.java
@@ -54,7 +54,7 @@ public RoutingCHEdgeIterator setBaseNode(int baseNode) {
assert baseGraph.isFrozen();
baseIterator.setBaseNode(baseNode);
int lastShortcut = store.getLastShortcut(store.toNodePointer(baseNode));
- nextEdgeId = edgeId = lastShortcut < 0 ? baseIterator.edgeId : baseGraph.edgeCount + lastShortcut;
+ nextEdgeId = edgeId = lastShortcut < 0 ? baseIterator.edgeId : baseGraph.getEdges() + lastShortcut;
return this;
}
@@ -63,13 +63,13 @@ public boolean next() {
// we first traverse shortcuts (in decreasing order) and when we are done we use the base iterator to traverse
// the base edges as well. shortcuts are filtered using shortcutFilter, but base edges are only filtered by
// access/finite weight.
- while (nextEdgeId >= baseGraph.edgeCount) {
- shortcutPointer = store.toShortcutPointer(nextEdgeId - baseGraph.edgeCount);
+ while (nextEdgeId >= baseGraph.getEdges()) {
+ shortcutPointer = store.toShortcutPointer(nextEdgeId - baseGraph.getEdges());
baseNode = store.getNodeA(shortcutPointer);
adjNode = store.getNodeB(shortcutPointer);
edgeId = nextEdgeId;
nextEdgeId--;
- if (nextEdgeId < baseGraph.edgeCount || store.getNodeA(store.toShortcutPointer(nextEdgeId - baseGraph.edgeCount)) != baseNode)
+ if (nextEdgeId < baseGraph.getEdges() || store.getNodeA(store.toShortcutPointer(nextEdgeId - baseGraph.getEdges())) != baseNode)
nextEdgeId = baseIterator.edgeId;
// todo: note that it would be more efficient (but cost more memory) to separate in/out edges,
// especially for edge-based where we do not use bidirectional shortcuts
diff --git a/core/src/main/java/com/graphhopper/storage/RoutingCHEdgeIteratorStateImpl.java b/core/src/main/java/com/graphhopper/storage/RoutingCHEdgeIteratorStateImpl.java
index 5d2d5801880..b89c9eae1a8 100644
--- a/core/src/main/java/com/graphhopper/storage/RoutingCHEdgeIteratorStateImpl.java
+++ b/core/src/main/java/com/graphhopper/storage/RoutingCHEdgeIteratorStateImpl.java
@@ -44,11 +44,11 @@ public RoutingCHEdgeIteratorStateImpl(CHStorage store, BaseGraph baseGraph, Base
}
boolean init(int edge, int expectedAdjNode) {
- if (edge < 0 || edge >= baseGraph.edgeCount + store.getShortcuts())
- throw new IllegalArgumentException("edge must be in bounds: [0," + (baseGraph.edgeCount + store.getShortcuts()) + "[");
+ if (edge < 0 || edge >= baseGraph.getEdges() + store.getShortcuts())
+ throw new IllegalArgumentException("edge must be in bounds: [0," + (baseGraph.getEdges() + store.getShortcuts()) + "[");
edgeId = edge;
if (isShortcut()) {
- shortcutPointer = store.toShortcutPointer(edge - baseGraph.edgeCount);
+ shortcutPointer = store.toShortcutPointer(edge - baseGraph.getEdges());
baseNode = store.getNodeA(shortcutPointer);
adjNode = store.getNodeB(shortcutPointer);
@@ -102,7 +102,7 @@ public int getAdjNode() {
@Override
public boolean isShortcut() {
- return edgeId >= baseGraph.edgeCount;
+ return edgeId >= baseGraph.getEdges();
}
@Override
diff --git a/core/src/main/java/com/graphhopper/storage/TurnCostStorage.java b/core/src/main/java/com/graphhopper/storage/TurnCostStorage.java
index 44ff63b77d9..8464898290b 100644
--- a/core/src/main/java/com/graphhopper/storage/TurnCostStorage.java
+++ b/core/src/main/java/com/graphhopper/storage/TurnCostStorage.java
@@ -239,7 +239,7 @@ public interface TurnRelationIterator {
private class Itr implements TurnRelationIterator {
private int viaNode = -1;
private int turnCostIndex = -1;
- private IntsRef intsRef = TurnCost.createFlags();
+ private final IntsRef intsRef = TurnCost.createFlags();
private long turnCostPtr() {
return (long) turnCostIndex * BYTES_PER_ENTRY;
diff --git a/core/src/test/java/com/graphhopper/GraphHopperTest.java b/core/src/test/java/com/graphhopper/GraphHopperTest.java
index 517e763bc96..6ae47f57554 100644
--- a/core/src/test/java/com/graphhopper/GraphHopperTest.java
+++ b/core/src/test/java/com/graphhopper/GraphHopperTest.java
@@ -230,7 +230,7 @@ public void testUTurn() {
request.addPoint(new GHPoint(43.743887, 7.431151));
request.addPoint(new GHPoint(43.744007, 7.431076));
//Force initial U-Turn
- request.setHeadings(Arrays.asList(200., Double.NaN));
+ request.setHeadings(Arrays.asList(200.));
request.setAlgorithm(ASTAR).setProfile(profile);
GHResponse rsp = hopper.route(request);
diff --git a/core/src/test/java/com/graphhopper/routing/HeadingRoutingTest.java b/core/src/test/java/com/graphhopper/routing/HeadingRoutingTest.java
index 37b037a10c5..23d911f108a 100644
--- a/core/src/test/java/com/graphhopper/routing/HeadingRoutingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/HeadingRoutingTest.java
@@ -155,7 +155,7 @@ public void headingTest5() {
GHPoint via = new GHPoint(0.000, 0.0015);
GHRequest req = new GHRequest().
setPoints(Arrays.asList(start, via, end)).
- setHeadings(Arrays.asList(0., 3.14 / 2, Double.NaN)).
+ setHeadings(Arrays.asList(0., 90., Double.NaN)).
setProfile("profile").
setPathDetails(Collections.singletonList("edge_key"));
req.putHint(Parameters.Routing.PASS_THROUGH, true);
@@ -164,6 +164,96 @@ public void headingTest5() {
assertArrayEquals(new int[]{5, 4, 3, 8, 7, 6, 5, 4, 3, 2}, calcNodes(graph, response.getAll().get(0)));
}
+ @Test
+ public void testHeadingWithSnapFilter() {
+ GraphHopperStorage graph = createSquareGraphWithTunnel();
+ Router router = createRouter(graph);
+ // Start at 8 (slightly north to make it independent on some edge ordering and always use 8-3 or 3-8 as fallback)
+ GHPoint start = new GHPoint(0.0011, 0.001);
+ // End at middle of edge 2-3
+ GHPoint end = new GHPoint(0.002, 0.0005);
+
+ // no heading
+ GHRequest req = new GHRequest().
+ setPoints(Arrays.asList(start, end)).
+ setProfile("profile").
+ setPathDetails(Collections.singletonList("edge_key"));
+ req.putHint(Parameters.Routing.PASS_THROUGH, true);
+ GHResponse response = router.route(req);
+ assertFalse(response.hasErrors());
+ assertArrayEquals(new int[]{8, 3, 2}, calcNodes(graph, response.getAll().get(0)));
+
+ // same start + end but heading=0, parallel to 3-8-7
+ req = new GHRequest().
+ setPoints(Arrays.asList(start, end)).
+ setHeadings(Arrays.asList(0.)).
+ setProfile("profile").
+ setPathDetails(Collections.singletonList("edge_key"));
+ req.putHint(Parameters.Routing.PASS_THROUGH, true);
+ response = router.route(req);
+ assertFalse(response.hasErrors());
+ assertArrayEquals(new int[]{8, 3, 2}, calcNodes(graph, response.getAll().get(0)));
+
+ // heading=90 parallel to 1->5
+ req = new GHRequest().
+ setPoints(Arrays.asList(start, end)).
+ setHeadings(Arrays.asList(90., Double.NaN)).
+ setProfile("profile").
+ setPathDetails(Collections.singletonList("edge_key"));
+ req.putHint(Parameters.Routing.PASS_THROUGH, true);
+ response = router.route(req);
+ assertFalse(response.hasErrors());
+ assertArrayEquals(new int[]{1, 5, 4, 3, 2}, calcNodes(graph, response.getAll().get(0)));
+
+ for (double angle = 0; angle < 360; angle += 10) {
+ // Ignore angles nearly parallel to 1->5. I.e. it should fallback to results with 8-3.. or 3-8..
+ if (angle >= 60 && angle <= 120) continue;
+
+ req = new GHRequest().
+ setPoints(Arrays.asList(start, end)).
+ setHeadings(Arrays.asList(angle, Double.NaN)).
+ setProfile("profile").
+ setPathDetails(Collections.singletonList("edge_key"));
+ req.putHint(Parameters.Routing.PASS_THROUGH, true);
+ response = router.route(req);
+ assertFalse(response.hasErrors());
+
+ int[] expectedNodes = (angle >= 130 && angle <= 250) ? new int[]{3, 8, 7, 0, 1, 2, 3} : new int[]{8, 3, 2};
+ // System.out.println(Arrays.toString(calcNodes(graph, response.getAll().get(0))) + " angle:" + angle);
+ assertArrayEquals(expectedNodes, calcNodes(graph, response.getAll().get(0)), "angle: " + angle);
+ }
+ }
+
+ @Test
+ public void testHeadingWithSnapFilter2() {
+ GraphHopperStorage graph = createSquareGraphWithTunnel();
+ Router router = createRouter(graph);
+ // Start at 8 (slightly east to snap to edge 1->5 per default)
+ GHPoint start = new GHPoint(0.001, 0.0011);
+ // End at middle of edge 2-3
+ GHPoint end = new GHPoint(0.002, 0.0005);
+
+ GHRequest req = new GHRequest().
+ setPoints(Arrays.asList(start, end)).
+ setProfile("profile").
+ setHeadings(Arrays.asList(0.)).
+ setPathDetails(Collections.singletonList("edge_key"));
+ req.putHint(Parameters.Routing.PASS_THROUGH, true);
+ GHResponse response = router.route(req);
+ assertFalse(response.hasErrors());
+ assertArrayEquals(new int[]{8, 3, 2}, calcNodes(graph, response.getAll().get(0)));
+
+ req = new GHRequest().
+ setPoints(Arrays.asList(start, end)).
+ setProfile("profile").
+ setHeadings(Arrays.asList(180.)).
+ setPathDetails(Collections.singletonList("edge_key"));
+ req.putHint(Parameters.Routing.PASS_THROUGH, true);
+ response = router.route(req);
+ assertFalse(response.hasErrors());
+ assertArrayEquals(new int[]{8, 3, 2}, calcNodes(graph, response.getAll().get(0)));
+ }
+
@Test
public void headingTest6() {
// Test if snaps at tower nodes are ignored
@@ -199,11 +289,11 @@ private GraphHopperStorage createSquareGraph() {
EncodingManager encodingManager = new EncodingManager.Builder().add(carEncoder).add(Subnetwork.create("profile")).build();
GraphHopperStorage g = new GraphBuilder(encodingManager).create();
- // 2---3---4
- // / | \
- // 1----8----5
- // / | /
- // 0----7---6
+ // 2---3---4
+ // | | |
+ // 1---8---5
+ // | | |
+ // 0---7---6
NodeAccess na = g.getNodeAccess();
na.setNode(0, 0.000, 0.000);
na.setNode(1, 0.001, 0.000);
@@ -232,6 +322,43 @@ private GraphHopperStorage createSquareGraph() {
return g;
}
+ private GraphHopperStorage createSquareGraphWithTunnel() {
+ CarFlagEncoder carEncoder = new CarFlagEncoder();
+ EncodingManager encodingManager = new EncodingManager.Builder().add(carEncoder).add(Subnetwork.create("profile")).build();
+ GraphHopperStorage g = new GraphBuilder(encodingManager).create();
+
+ // 2----3---4
+ // | | |
+ // 1->- 8 >-5 (edge 1->5 is not connected to 8)
+ // | | |
+ // 0----7---6
+ NodeAccess na = g.getNodeAccess();
+ na.setNode(0, 0.000, 0.000);
+ na.setNode(1, 0.001, 0.000);
+ na.setNode(2, 0.002, 0.000);
+ na.setNode(3, 0.002, 0.001);
+ na.setNode(4, 0.002, 0.002);
+ na.setNode(5, 0.001, 0.002);
+ na.setNode(6, 0.000, 0.002);
+ na.setNode(7, 0.000, 0.001);
+ na.setNode(8, 0.001, 0.001);
+
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(0, 1).setDistance(100));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(1, 2).setDistance(100));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(2, 3).setDistance(100));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(3, 4).setDistance(100));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(4, 5).setDistance(100));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(5, 6).setDistance(100));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(6, 7).setDistance(100));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(7, 0).setDistance(100));
+
+ GHUtility.setSpeed(60, true, false, carEncoder, g.edge(1, 5).setDistance(110));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(3, 8).setDistance(110));
+ GHUtility.setSpeed(60, true, true, carEncoder, g.edge(7, 8).setDistance(110));
+
+ return g;
+ }
+
private int[] calcNodes(Graph graph, ResponsePath responsePath) {
List edgeKeys = responsePath.getPathDetails().get("edge_key");
int[] result = new int[edgeKeys.size() + 1];
diff --git a/core/src/test/java/com/graphhopper/storage/AbstractGraphStorageTester.java b/core/src/test/java/com/graphhopper/storage/AbstractGraphStorageTester.java
index 9e0d3b9cc46..62b779eca87 100644
--- a/core/src/test/java/com/graphhopper/storage/AbstractGraphStorageTester.java
+++ b/core/src/test/java/com/graphhopper/storage/AbstractGraphStorageTester.java
@@ -26,7 +26,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import java.io.Closeable;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@@ -117,7 +116,7 @@ public void tearDown() {
public void testSetTooBigDistance_435() {
graph = createGHStorage();
- double maxDist = BaseGraph.MAX_DIST;
+ double maxDist = BaseGraphNodesAndEdges.MAX_DIST;
EdgeIteratorState edge1 = GHUtility.setSpeed(60, true, true, carEncoder, graph.edge(0, 1).setDistance(maxDist));
assertEquals(maxDist, edge1.getDistance(), 1);
diff --git a/core/src/test/java/com/graphhopper/storage/GraphHopperStorageTest.java b/core/src/test/java/com/graphhopper/storage/GraphHopperStorageTest.java
index 13956f7b8d1..fb2237557c1 100644
--- a/core/src/test/java/com/graphhopper/storage/GraphHopperStorageTest.java
+++ b/core/src/test/java/com/graphhopper/storage/GraphHopperStorageTest.java
@@ -24,6 +24,8 @@
import com.graphhopper.routing.util.EncodingManager;
import com.graphhopper.util.*;
import com.graphhopper.util.shapes.BBox;
+import org.junit.Ignore;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.File;
@@ -55,16 +57,10 @@ protected GraphHopperStorage newGHStorage(Directory dir, boolean enabled3D, int
return GraphBuilder.start(encodingManager).setDir(dir).set3D(enabled3D).setSegmentSize(segmentSize).build();
}
+ @Disabled
@Test
public void testNoCreateCalled() {
- try (GraphHopperStorage gs = GraphBuilder.start(encodingManager).build()) {
- ((BaseGraph) gs.getBaseGraph()).ensureNodeIndex(123);
- fail("IllegalStateException should be raised");
- } catch (IllegalStateException err) {
- // ok
- } catch (Exception ex) {
- fail("IllegalStateException should be raised, but was " + ex.toString());
- }
+ assertThrows(Throwable.class, () -> GraphBuilder.start(encodingManager).build().edge(0, 1));
}
@Test
@@ -160,16 +156,6 @@ protected void checkGraph(Graph g) {
assertEquals(GHUtility.asSet(0), GHUtility.getNeighbors(explorer.setBaseNode(2)));
}
- @Test
- public void testBigDataEdge() {
- Directory dir = new RAMDirectory();
- GraphHopperStorage graph = new GraphHopperStorage(dir, encodingManager, false);
- graph.create(defaultSize);
- ((BaseGraph) graph.getBaseGraph()).setEdgeCount(Integer.MAX_VALUE / 2);
- assertTrue(graph.getAllEdges().next());
- graph.close();
- }
-
@Test
public void testDoThrowExceptionIfDimDoesNotMatch() {
graph = newGHStorage(new RAMDirectory(defaultGraphLoc, true), false);
diff --git a/docs/core/profiles.md b/docs/core/profiles.md
index d5410409493..780f844dcb1 100644
--- a/docs/core/profiles.md
+++ b/docs/core/profiles.md
@@ -54,6 +54,9 @@ weightings:
- curvature (prefers routes with lots of curves for enjoyable motorcycle rides)
- custom (enables custom profiles, see the next section)
+Another important profile setting is `turn_costs: true/false`. Use this to enable turn restrictions for each profile.
+You can learn more about this setting [here](./turn-restrictions.md)
+
The profile name is used to select the profile when executing routing queries. To do this use the `profile` request
parameter, for example `/route?point=49.5,11.1&profile=car` or `/route?point=49.5,11.1&profile=some_other_profile`.
diff --git a/example/pom.xml b/example/pom.xml
index 339c8d7455b..0a904b48fe8 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -5,21 +5,21 @@
4.0.0graphhopper-example
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTjarGraphHopper Examplecom.github.GIScience.graphhoppergraphhopper-parent
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-core
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOT
diff --git a/hmm-lib/pom.xml b/hmm-lib/pom.xml
index 0958134e3c4..0d4b7dba87a 100644
--- a/hmm-lib/pom.xml
+++ b/hmm-lib/pom.xml
@@ -19,7 +19,7 @@
4.0.0hmm-lib-external
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTjarhmm-lib
@@ -29,7 +29,7 @@
com.github.GIScience.graphhoppergraphhopper-parent
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOT
diff --git a/map-matching/pom.xml b/map-matching/pom.xml
index 6a503b0c7fc..45800119d61 100644
--- a/map-matching/pom.xml
+++ b/map-matching/pom.xml
@@ -3,20 +3,21 @@
4.0.0graphhopper-map-matching
+ 5.0-SNAPSHOTjarGraphHopper Map Matchingcom.github.GIScience.graphhoppergraphhopper-parent
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-core
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTorg.slf4j
@@ -25,7 +26,7 @@
com.github.GIScience.graphhopperhmm-lib-external
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTch.qos.logback
diff --git a/navigation/pom.xml b/navigation/pom.xml
index 680097cfcfb..269aea47b1c 100644
--- a/navigation/pom.xml
+++ b/navigation/pom.xml
@@ -5,26 +5,26 @@
4.0.0graphhopper-nav
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTjarGraphHopper Navigationcom.github.GIScience.graphhoppergraphhopper-parent
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-web-api
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-core
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTio.dropwizard
diff --git a/pom.xml b/pom.xml
index e9a575d5671..b66380a1989 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,8 +5,7 @@
com.github.GIScience.graphhoppergraphhopper-parent
- GraphHopper Parent Project
- 4.12-SNAPSHOT
+ GraphHopper Parent Project5.0-SNAPSHOTpomhttps://www.graphhopper.com2012
diff --git a/reader-gtfs/pom.xml b/reader-gtfs/pom.xml
index faf0f195a52..5b4f43873ae 100644
--- a/reader-gtfs/pom.xml
+++ b/reader-gtfs/pom.xml
@@ -10,14 +10,14 @@
com.github.GIScience.graphhoppergraphhopper-parent
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-core
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTcom.google.guava
diff --git a/tools/pom.xml b/tools/pom.xml
index 72cf4613606..ec7b44dc7a6 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -10,7 +10,7 @@
com.github.GIScience.graphhoppergraphhopper-parent
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTpackage
@@ -20,12 +20,12 @@
com.github.GIScience.graphhoppergraphhopper-core
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-web-api
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOT
diff --git a/web-api/pom.xml b/web-api/pom.xml
index 4750186bb25..856e5808ee7 100644
--- a/web-api/pom.xml
+++ b/web-api/pom.xml
@@ -5,14 +5,14 @@
4.0.0graphhopper-web-apijar
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOTGraphHopper Web APIJSON Representation of the API classescom.github.GIScience.graphhoppergraphhopper-parent
- 4.12-SNAPSHOT
+ 5.0-SNAPSHOT
diff --git a/web-bundle/pom.xml b/web-bundle/pom.xml
index 4f1a585ad56..e3fa7ff36b7 100644
--- a/web-bundle/pom.xml
+++ b/web-bundle/pom.xml
@@ -5,36 +5,36 @@
4.0.0graphhopper-web-bundlejar
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTGraphHopper Dropwizard BundleUse the GraphHopper routing engine as a web-servicecom.github.GIScience.graphhoppergraphhopper-parent
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-web-api
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-core
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-reader-gtfs
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-map-matching
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOT
@@ -118,7 +118,7 @@
com.github.GIScience.graphhopperdirections-api-client-hc
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTtest
diff --git a/web-bundle/src/main/resources/com/graphhopper/maps/index.html b/web-bundle/src/main/resources/com/graphhopper/maps/index.html
index 011f6d92920..bc0519f073a 100644
--- a/web-bundle/src/main/resources/com/graphhopper/maps/index.html
+++ b/web-bundle/src/main/resources/com/graphhopper/maps/index.html
@@ -36,7 +36,7 @@
-
+
diff --git a/web/pom.xml b/web/pom.xml
index 331fd367bff..cdf33042d43 100644
--- a/web/pom.xml
+++ b/web/pom.xml
@@ -5,14 +5,14 @@
4.0.0graphhopper-webjar
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTGraphHopper WebUse the GraphHopper routing engine as a web-servicecom.github.GIScience.graphhoppergraphhopper-parent
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTpackage
@@ -30,12 +30,12 @@
com.github.GIScience.graphhoppergraphhopper-web-bundle
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTcom.github.GIScience.graphhoppergraphhopper-nav
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOT
@@ -66,7 +66,7 @@
com.github.GIScience.graphhopperdirections-api-client-hc
- 4.9-SNAPSHOT
+ 5.0-SNAPSHOTtest