TrafficSpeedCalculator.java
package org.heigit.ors.routing.traffic;
import com.graphhopper.routing.querygraph.VirtualEdgeIteratorState;
import com.graphhopper.routing.util.AbstractAdjustedSpeedCalculator;
import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.routing.util.SpeedCalculator;
import com.graphhopper.storage.GraphHopperStorage;
import com.graphhopper.util.EdgeIteratorState;
import com.graphhopper.util.GHUtility;
import org.heigit.ors.routing.graphhopper.extensions.flagencoders.HeavyVehicleFlagEncoder;
import org.heigit.ors.routing.graphhopper.extensions.flagencoders.VehicleFlagEncoder;
import org.heigit.ors.routing.graphhopper.extensions.storages.GraphStorageUtils;
import org.heigit.ors.routing.graphhopper.extensions.storages.TrafficGraphStorage;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class TrafficSpeedCalculator extends AbstractAdjustedSpeedCalculator {
// time-dependent stuff
protected TrafficGraphStorage trafficGraphStorage;
protected int timeZoneOffset;
private VehicleFlagEncoder vehicleFlagEncoder;
private boolean isVehicle = false;
private boolean isHGV = false;
private final double HGVTrafficSpeedLimit = 80.0;
public TrafficSpeedCalculator(SpeedCalculator superSpeedCalculator) {
super(superSpeedCalculator);
}
public void init(GraphHopperStorage graphHopperStorage, FlagEncoder flagEncoder) {
if (flagEncoder instanceof VehicleFlagEncoder vehicleFE)
setVehicleFlagEncoder(vehicleFE);
if (flagEncoder instanceof HeavyVehicleFlagEncoder)
isHGV = true;
setTrafficGraphStorage(GraphStorageUtils.getGraphExtension(graphHopperStorage, TrafficGraphStorage.class));
}
@Override
public double getSpeed(EdgeIteratorState edge, boolean reverse, long time) {
double speed = superSpeedCalculator.getSpeed(edge, reverse, time);
int edgeKey = getEdgeKey(edge, reverse);
double trafficSpeed;
if (time == -1)
trafficSpeed = trafficGraphStorage.getMaxSpeedValue(edgeKey);
else
trafficSpeed = trafficGraphStorage.getSpeedValue(edgeKey, time, timeZoneOffset);
if (trafficSpeed > 0) {
//TODO: This is a heuristic to provide expected results given traffic data and ORS internal speed calculations.
if (isVehicle) {
trafficSpeed = vehicleFlagEncoder.adjustSpeedForAcceleration(edge.getDistance(), trafficSpeed);
// For heavy vehicles, consider the traffic speeds only up to a predefined speeds
if (!isHGV || (isHGV && trafficSpeed <= HGVTrafficSpeedLimit)) {
speed = trafficSpeed;
}
} else {
if (speed >= 45.0 && !(trafficSpeed > 1.1 * speed) || trafficSpeed < speed) {
speed = trafficSpeed;
}
}
}
return speed;
}
protected int getEdgeKey(EdgeIteratorState edge, boolean reverse) {
int edgeKey;
if (edge instanceof VirtualEdgeIteratorState iteratorState) {
edgeKey = iteratorState.getOriginalEdgeKey();
} else {
edgeKey = edge.getEdgeKey();
}
if (reverse)
edgeKey = GHUtility.reverseEdgeKey(edgeKey);
return edgeKey;
}
public void setVehicleFlagEncoder(VehicleFlagEncoder flagEncoder) {
this.vehicleFlagEncoder = flagEncoder;
isVehicle = true;
}
public void setTrafficGraphStorage(TrafficGraphStorage trafficGraphStorage) {
this.trafficGraphStorage = trafficGraphStorage;
}
public void setZonedDateTime(ZonedDateTime zdt) {
this.timeZoneOffset = zdt.getOffset().getTotalSeconds() / 3600;
}
public ZoneId getZoneId() {
return trafficGraphStorage.getZoneId();
}
@Override
public boolean isTimeDependent() {
return true;
}
}