Skip to content

Commit

Permalink
Merge pull request #39 from GIScience/ors_0.13-td_calt
Browse files Browse the repository at this point in the history
Time-dependent core routing
  • Loading branch information
takb authored Apr 28, 2021
2 parents 6c6cebc + 73e73f5 commit ee6e15f
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 38 deletions.
128 changes: 128 additions & 0 deletions core/src/main/java/com/graphhopper/routing/PathTDCore.java
Original file line number Diff line number Diff line change
@@ -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
* <p>
*
* @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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
4 changes: 4 additions & 0 deletions core/src/main/java/com/graphhopper/storage/CHGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
73 changes: 73 additions & 0 deletions core/src/main/java/com/graphhopper/storage/CHGraphImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ public class CHGraphImpl implements CHGraph, Storable<CHGraph> {

// 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) {
Expand All @@ -86,6 +88,7 @@ public class CHGraphImpl implements CHGraph, Storable<CHGraph> {
//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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
}
Loading

0 comments on commit ee6e15f

Please sign in to comment.