From e3049df2765338bb51e166b3ae682758b64f7d08 Mon Sep 17 00:00:00 2001 From: aoles Date: Tue, 7 Apr 2020 12:15:05 +0200 Subject: [PATCH 1/3] Store time in shortcuts --- .../routing/VirtualEdgeIterator.java | 12 +++ .../routing/VirtualEdgeIteratorState.java | 10 +++ .../java/com/graphhopper/storage/CHGraph.java | 4 + .../com/graphhopper/storage/CHGraphImpl.java | 73 +++++++++++++++++++ .../graphhopper/util/CHEdgeIteratorState.java | 6 ++ .../java/com/graphhopper/util/GHUtility.java | 11 +++ 6 files changed, 116 insertions(+) diff --git a/core/src/main/java/com/graphhopper/routing/VirtualEdgeIterator.java b/core/src/main/java/com/graphhopper/routing/VirtualEdgeIterator.java index 03936965034..f0fd0ab443e 100644 --- a/core/src/main/java/com/graphhopper/routing/VirtualEdgeIterator.java +++ b/core/src/main/java/com/graphhopper/routing/VirtualEdgeIterator.java @@ -291,4 +291,16 @@ public int getOrigEdgeLast() { public int getMergeStatus(int flags) { throw new UnsupportedOperationException("Not supported."); } + + // ORS-GH MOD START: TD CALT + public CHEdgeIteratorState setTime(long time) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public long getTime() { + // will be called only from PreparationWeighting and if isShortcut is true + return ((CHEdgeIteratorState) edges.get(current)).getTime(); + } + // ORS-GH MOD END } diff --git a/core/src/main/java/com/graphhopper/routing/VirtualEdgeIteratorState.java b/core/src/main/java/com/graphhopper/routing/VirtualEdgeIteratorState.java index 8e5389e0ba9..bebed271dcf 100644 --- a/core/src/main/java/com/graphhopper/routing/VirtualEdgeIteratorState.java +++ b/core/src/main/java/com/graphhopper/routing/VirtualEdgeIteratorState.java @@ -349,4 +349,14 @@ public void setReverseEdge(EdgeIteratorState reverseEdge) { this.reverseEdge = reverseEdge; } + // ORS-GH MOD START: TD CALT + public CHEdgeIteratorState setTime(long time) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public long getTime() { + throw new UnsupportedOperationException("Not supported."); + } + // ORS-GH MOD END } diff --git a/core/src/main/java/com/graphhopper/storage/CHGraph.java b/core/src/main/java/com/graphhopper/storage/CHGraph.java index 832f01761d7..ac955823f95 100644 --- a/core/src/main/java/com/graphhopper/storage/CHGraph.java +++ b/core/src/main/java/com/graphhopper/storage/CHGraph.java @@ -63,6 +63,10 @@ public interface CHGraph extends Graph { */ int shortcutEdgeBased(int a, int b, int accessFlags, double weight, int skippedEdge1, int skippedEdge2, int origFirst, int origLast); + // ORS-GH MOD START: TD CALT + int shortcutCore(int a, int b, int accessFlags, double weight, int skippedEdge1, int skippedEdge2, long time); + // ORS-GH MOD END + @Override CHEdgeIteratorState getEdgeIteratorState(int edgeId, int endNode); diff --git a/core/src/main/java/com/graphhopper/storage/CHGraphImpl.java b/core/src/main/java/com/graphhopper/storage/CHGraphImpl.java index 838f9c2ab67..561c99f57df 100644 --- a/core/src/main/java/com/graphhopper/storage/CHGraphImpl.java +++ b/core/src/main/java/com/graphhopper/storage/CHGraphImpl.java @@ -71,7 +71,9 @@ public class CHGraphImpl implements CHGraph, Storable { // ORS-GH MOD START // CALT add member variable + private boolean isTypeCore; private int coreNodeCount = -1; + private int S_TIME; // ORS-GH MOD END CHGraphImpl(CHProfile chProfile, Directory dir, final BaseGraph baseGraph) { @@ -86,6 +88,7 @@ public class CHGraphImpl implements CHGraph, Storable { //this.shortcuts = dir.find("shortcuts_" + name, DAType.getPreferredInt(dir.getDefaultType())); this.nodesCH = dir.find("nodes_" + chProfile.getType() + "_" + name, DAType.getPreferredInt(dir.getDefaultType())); this.shortcuts = dir.find("shortcuts_" + chProfile.getType() + "_" + name, DAType.getPreferredInt(dir.getDefaultType())); + this.isTypeCore = chProfile.getType()==CHProfile.TYPE_CORE; // ORS-GH MOD END this.chEdgeAccess = new CHEdgeAccess(name); } @@ -370,6 +373,13 @@ void initStorage() { shortcutEntryBytes = S_SKIP_EDGE2 + 4; } + // ORS-GH MOD START: TD CALT + if (isTypeCore) { + S_TIME = shortcutEntryBytes; + shortcutEntryBytes = S_TIME + 4; + } + // ORS-GH MOD END + // node based data: N_LEVEL = 0; N_CH_REF = N_LEVEL + 4; @@ -499,6 +509,18 @@ public int getNumNodes() { }; } + // ORS-GH MOD START: TD CALT + @Override + public int shortcutCore(int a, int b, int accessFlags, double weight, int skippedEdge1, int skippedEdge2, long time) { + if (!isTypeCore) { + throw new IllegalStateException("Time can be added to shortcuts only for core graph"); + } + int scId = shortcut(a, b, accessFlags, weight, skippedEdge1, skippedEdge2); + chEdgeAccess.setTime(chEdgeAccess.toPointer(scId), time); + return scId; + } + // ORS-GH MOD END + class CHEdgeIteratorImpl extends EdgeIterable implements CHEdgeExplorer, CHEdgeIterator { public CHEdgeIteratorImpl(BaseGraph baseGraph, EdgeAccess edgeAccess, EdgeFilter filter) { super(baseGraph, edgeAccess, filter); @@ -675,6 +697,27 @@ public final EdgeIteratorState setWayGeometry(PointList list) { public int getMergeStatus(int flags) { return PrepareEncoder.getScMergeStatus(getShortcutFlags(), flags); } + + // ORS-GH MOD START: TD CALT + public void checkShortcutCore(String methodName) { + if (!isTypeCore) + throw new IllegalStateException("Method " + methodName + " only allowed for core graph"); + checkShortcut(true, methodName); + } + + @Override + public long getTime() { + checkShortcutCore("getTime"); + return (long) shortcuts.getInt(edgePointer + S_TIME); + } + + @Override + public CHEdgeIteratorState setTime(long time) { + checkShortcutCore("setTime"); + shortcuts.setInt(edgePointer + S_TIME, (int) time); + return this; + } + // ORS-GH MOD END } class AllCHEdgesIteratorImpl extends AllEdgeIterator implements AllCHEdgesIterator { @@ -826,6 +869,27 @@ private void checkShortcutAndEdgeBased(String method) { throw new IllegalStateException("Method " + method + " not supported when turn costs are disabled"); } } + + // ORS-GH MOD START: TD CALT + public void checkShortcutCore(String methodName) { + if (!isTypeCore) + throw new IllegalStateException("Method " + methodName + " only allowed for core graph"); + checkShortcut(true, methodName); + } + + @Override + public long getTime() { + checkShortcutCore("getTime"); + return (long) shortcuts.getInt(edgePointer + S_TIME); + }; + + @Override + public CHEdgeIteratorState setTime(long time) { + checkShortcutCore("setTime"); + shortcuts.setInt(edgePointer + S_TIME, (int) time); + return this; + } + // ORS-GH MOD END } private class CHEdgeAccess extends EdgeAccess { @@ -940,5 +1004,14 @@ final boolean isInBounds(int shortcutId) { public String toString() { return "ch edge access " + name; } + + // ORS-GH MOD START: TD CALT + public void setTime(long edgePointer, long time) { + if (!isTypeCore) { + throw new IllegalStateException("Time can be added to shortcuts only for core graph"); + } + shortcuts.setInt(edgePointer + S_TIME, (int) time); + } + // ORS-GH MOD END } } diff --git a/core/src/main/java/com/graphhopper/util/CHEdgeIteratorState.java b/core/src/main/java/com/graphhopper/util/CHEdgeIteratorState.java index 3804f3d5ccf..17fb8f7e0cf 100644 --- a/core/src/main/java/com/graphhopper/util/CHEdgeIteratorState.java +++ b/core/src/main/java/com/graphhopper/util/CHEdgeIteratorState.java @@ -70,4 +70,10 @@ public interface CHEdgeIteratorState extends EdgeIteratorState { CHEdgeIteratorState setWeight(double weight); void setFlagsAndWeight(int flags, double weight); + + // ORS-GH MOD START: TD CALT + CHEdgeIteratorState setTime(long time); + + long getTime(); + // ORS-GH MOD END } diff --git a/core/src/main/java/com/graphhopper/util/GHUtility.java b/core/src/main/java/com/graphhopper/util/GHUtility.java index fd03380960e..b3a4c649676 100644 --- a/core/src/main/java/com/graphhopper/util/GHUtility.java +++ b/core/src/main/java/com/graphhopper/util/GHUtility.java @@ -836,5 +836,16 @@ public void setFlagsAndWeight(int flags, double weight) { public int getMergeStatus(int flags) { throw new UnsupportedOperationException("Not supported. Edge is empty."); } + + // ORS-GH MOD START: TD CALT + public CHEdgeIteratorState setTime(long time) { + throw new UnsupportedOperationException("Not supported. Edge is empty."); + } + + @Override + public long getTime() { + throw new UnsupportedOperationException("Not supported. Edge is empty."); + } + // ORS-GH MOD END } } From 70bdd654df5bdee5551c91bf3c4a9d2a5e7fbf88 Mon Sep 17 00:00:00 2001 From: aoles Date: Fri, 9 Apr 2021 16:13:47 +0200 Subject: [PATCH 2/3] Make PreparationWeighting compatible with time-dependent routing --- .../routing/ch/PreparationWeighting.java | 64 ++++++++----------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/core/src/main/java/com/graphhopper/routing/ch/PreparationWeighting.java b/core/src/main/java/com/graphhopper/routing/ch/PreparationWeighting.java index d00bf5a06b5..2af84c4f23c 100644 --- a/core/src/main/java/com/graphhopper/routing/ch/PreparationWeighting.java +++ b/core/src/main/java/com/graphhopper/routing/ch/PreparationWeighting.java @@ -17,8 +17,7 @@ */ package com.graphhopper.routing.ch; -import com.graphhopper.routing.util.FlagEncoder; -import com.graphhopper.routing.util.HintsMap; +import com.graphhopper.routing.weighting.AbstractAdjustedWeighting; import com.graphhopper.routing.weighting.Weighting; import com.graphhopper.util.CHEdgeIteratorState; import com.graphhopper.util.EdgeIteratorState; @@ -30,68 +29,57 @@ * @author Peter Karich * @see PrepareContractionHierarchies */ -public class PreparationWeighting implements Weighting { - private final Weighting userWeighting; +// ORS-GH MOD START - this class has been heavily refactored an modified to accommodate for time-dependent routing +public class PreparationWeighting extends AbstractAdjustedWeighting { - public PreparationWeighting(Weighting userWeighting) { - this.userWeighting = userWeighting; + public PreparationWeighting(Weighting superWeighting) { + super(superWeighting); } @Override public final double getMinWeight(double distance) { - return userWeighting.getMinWeight(distance); + return superWeighting.getMinWeight(distance); } @Override - public double calcWeight(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) { - CHEdgeIteratorState tmp = (CHEdgeIteratorState) edgeState; - if (tmp.isShortcut()) - // if a shortcut is in both directions the weight is identical => no need for 'reverse' - return tmp.getWeight(); + public double calcWeight(EdgeIteratorState edge, boolean reverse, int prevOrNextEdgeId) { + if (isShortcut(edge)) + return ((CHEdgeIteratorState) edge).getWeight(); - return userWeighting.calcWeight(edgeState, reverse, prevOrNextEdgeId); + return superWeighting.calcWeight(edge, reverse, prevOrNextEdgeId); } @Override public double calcWeight(EdgeIteratorState edge, boolean reverse, int prevOrNextEdgeId, long edgeEnterTime) { - return calcWeight(edge, reverse, prevOrNextEdgeId); - } + if (isShortcut(edge)) + return ((CHEdgeIteratorState) edge).getWeight(); - @Override - public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) { - if (edgeState instanceof CHEdgeIteratorState && ((CHEdgeIteratorState) edgeState).isShortcut()) { - throw new IllegalStateException("calcMillis should only be called on original edges"); - } - return userWeighting.calcMillis(edgeState, reverse, prevOrNextEdgeId); + return superWeighting.calcWeight(edge, reverse, prevOrNextEdgeId, edgeEnterTime); } @Override - public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId, long edgeEnterTime) { - return calcMillis(edgeState, reverse, prevOrNextEdgeId); - } + public long calcMillis(EdgeIteratorState edge, boolean reverse, int prevOrNextEdgeId) { + if (isShortcut(edge)) + return ((CHEdgeIteratorState) edge).getTime(); - @Override - public FlagEncoder getFlagEncoder() { - return userWeighting.getFlagEncoder(); + return superWeighting.calcMillis(edge, reverse, prevOrNextEdgeId); } @Override - public boolean matches(HintsMap map) { - return getName().equals(map.getWeighting()) && userWeighting.getFlagEncoder().toString().equals(map.getVehicle()); - } + public long calcMillis(EdgeIteratorState edge, boolean reverse, int prevOrNextEdgeId, long edgeEnterTime) { + if (isShortcut(edge)) + return ((CHEdgeIteratorState) edge).getTime(); - @Override - public String getName() { - return "prepare|" + userWeighting.getName(); + return super.calcMillis(edge, reverse, prevOrNextEdgeId, edgeEnterTime); } - @Override - public String toString() { - return getName(); + boolean isShortcut(EdgeIteratorState edge) { + return (edge instanceof CHEdgeIteratorState && ((CHEdgeIteratorState) edge).isShortcut()); } @Override - public boolean isTimeDependent() { - return false; + public String getName() { + return "prepare"; } } +// ORS-GH MOD END From 73e73f5021ff907ce5500ce5ceffb32be61ca83c Mon Sep 17 00:00:00 2001 From: aoles Date: Fri, 9 Apr 2021 16:36:50 +0200 Subject: [PATCH 3/3] Path for time-dependent core routing --- .../com/graphhopper/routing/PathTDCore.java | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 core/src/main/java/com/graphhopper/routing/PathTDCore.java diff --git a/core/src/main/java/com/graphhopper/routing/PathTDCore.java b/core/src/main/java/com/graphhopper/routing/PathTDCore.java new file mode 100644 index 00000000000..d67c318e8ff --- /dev/null +++ b/core/src/main/java/com/graphhopper/routing/PathTDCore.java @@ -0,0 +1,128 @@ +/* + * 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.routing; + +import com.graphhopper.routing.weighting.Weighting; +import com.graphhopper.storage.Graph; +import com.graphhopper.storage.SPTEntry; +import com.graphhopper.storage.ShortcutUnpacker; +import com.graphhopper.util.CHEdgeIteratorState; +import com.graphhopper.util.EdgeIterator; +import com.graphhopper.util.EdgeIteratorState; + +import static com.graphhopper.util.EdgeIterator.NO_EDGE; + +/** + * Path for time-dependent core-type algorithms + *

+ * + * @author Andrzej Oles + */ +public class PathTDCore extends PathBidirRef { + private boolean switchFromAndToSPTEntry = false; + private Graph routingGraph; + + private final ShortcutUnpacker shortcutUnpacker; + + public PathTDCore(Graph routingGraph, Graph baseGraph, final Weighting weighting) { + super(baseGraph, weighting); + this.routingGraph = routingGraph; + this.shortcutUnpacker = getShortcutUnpacker(routingGraph, weighting); + } + + @Override + public PathBidirRef setSwitchToFrom(boolean b) { + switchFromAndToSPTEntry = b; + return this; + } + + @Override + public Path extract() { + if (sptEntry == null || edgeTo == null) + return this; + + if (sptEntry.adjNode != edgeTo.adjNode) + throw new IllegalStateException("Locations of the 'to'- and 'from'-Edge have to be the same. " + toString() + ", fromEntry:" + sptEntry + ", toEntry:" + edgeTo); + + extractSW.start(); + if (switchFromAndToSPTEntry) { + SPTEntry ee = sptEntry; + sptEntry = edgeTo; + edgeTo = ee; + } + extractFwdPath(); + // no need to process any turns at meeting point + extractBwdPath(); + extractSW.stop(); + return setFound(true); + } + + private void extractFwdPath() { + // we take the 'edgeFrom'/sptEntry that points at the meeting node and follow its parent pointers back to + // the source + setFromNode(extractPath(sptEntry,false)); + // since we followed the fwd path in backward direction we need to reverse the edge ids + reverseOrder(); + } + + private void extractBwdPath() { + // we take the edgeTo at the meeting node and follow its parent pointers to the target + setEndNode(extractPath(edgeTo, true)); + } + + private int extractPath(SPTEntry currEdge, boolean bwd) { + SPTEntry prevEdge = currEdge.parent; + while (EdgeIterator.Edge.isValid(currEdge.edge)) { + processEdge(currEdge, bwd); + currEdge = prevEdge; + prevEdge = currEdge.parent; + } + return currEdge.adjNode; + } + + private void processEdge(SPTEntry currEdge, boolean bwd) { + int edgeId = currEdge.edge; + int adjNode = currEdge.adjNode; + CHEdgeIteratorState iter = (CHEdgeIteratorState) routingGraph.getEdgeIteratorState(edgeId, adjNode); + + // Shortcuts do only contain valid weight so first expand before adding + // to distance and time + if (iter.isShortcut()) { + if (bwd) + shortcutUnpacker.visitOriginalEdgesBwd(edgeId, adjNode, true, currEdge.parent.edge); + else + shortcutUnpacker.visitOriginalEdgesFwd(edgeId, adjNode, true, currEdge.parent.edge); + } + else { + distance += iter.getDistance(); + addTime((bwd ? -1 : 1) * (currEdge.time - currEdge.parent.time)); + addEdge(edgeId); + } + } + + protected ShortcutUnpacker getShortcutUnpacker(Graph routingGraph, final Weighting weighting) { + return new ShortcutUnpacker(routingGraph, new ShortcutUnpacker.Visitor() { + @Override + public void visit(EdgeIteratorState edge, boolean reverse, int prevOrNextEdgeId) { + distance += edge.getDistance(); + addTime(weighting.calcMillis(edge, reverse, NO_EDGE)); + addEdge(edge.getEdge()); + } + }, false); + } +}