Hello! I need to store an array of speeds at some edge for a given flag encoder. Each item in this array indicate speed for a week day:
0 - Monday - 5km/h
1 - Tuesday - 10km/h
2 - Wednesday - 12km/h
etc…
I need this because the traffic jam in our city is not the same everyday, it depends only on weekday. I have seen @karussell example:
Looks fantastic! But it stores only one speed.
I have an idea to extend CarFlagEncoder by seven other classes:
MondayCarFlagEncoder, TuesdayCarFlagEncoder, Wed… etc and store speed for each weekday in the appropriate flag encoder.
But the solution looks weird. Do you have any idea? Or some better solution?
Thank you!
I have a new idea:
What if I save EncodedValues for each day? Like it was done in MotorcycleFlagEncoder:
mondayWayEncoder = new EncodedValue(“Monday”);
tuesdayWayEncoder = new EncodedValue(“Tuesday”)
You could do it this way but this will probably not scale for more values. For some internal projects we use a SpeedArray class that stores the speeds in a DataAccess
object and the set+get methods look like
public double getSpeed(int edgeId, boolean reverse, int timeSliceIndex) {
if (edgeId > maxEdgeId)
throw new IllegalStateException("too big edgeId " + edgeId + ", maxEdgeId: " + maxEdgeId);
if (timeSliceIndex >= numSpeedValues)
throw new IllegalArgumentException("Cannot access time slice " + timeSliceIndex + ". Maximum time slices of " + numSpeedValues + " allowed.");
int offset = reverse ? 1 : 0;
return speeds.getInt(4L * (2L * edgeId * numSpeedValues + 2 * timeSliceIndex + offset)) / factor;
}
public void setSpeed(int edgeId, boolean reverse, int timeSliceIndex, double value) {
if (timeSliceIndex >= numSpeedValues)
throw new IllegalArgumentException("Cannot access time slice " + timeSliceIndex + ". Maximum time slices of " + numSpeedValues + " allowed.");
ensureCapacity(edgeId);
int offset = reverse ? 1 : 0;
speeds.setInt(4L * (2L * edgeId * numSpeedValues + 2 * timeSliceIndex + offset), (int) Math.round(value * factor));
}
This is easy for speed values that are independent of the direction but is a bit more tricky if you need direction dependent values. For this case we do inside the encoder:
boolean reverse = directedBit.getValue(edge.getFlags()) == 0;
and the directedBit needs this handling in the encoder:
@Override
public long reverseFlags(long flags) {
// swap access
flags = super.reverseFlags(flags);
// swap speeds
long val = directedBit.getValue(flags);
return directedBit.setValue(flags, val == 0 ? 1 : 0);
}
Another edge case are virtual edges (edges at query locations) those currently need ugly special handling:
if (edgeId > speedArray.getMaxEdgeId()) {
EdgeIteratorState edgeState = edge.detach(false);
if (edgeState instanceof VirtualEdgeIteratorState)
edgeId = GHUtility.getEdgeFromEdgeKey(((VirtualEdgeIteratorState) edgeState).getOriginalTraversalKey());
}
Of course this is all a bit too complicated and so we work on a much simpler API.
Thank you very much! This looks easier than 7 encoded values. I will try the solution with DataAccess. As I complete traffic jams with multiple speeds, I am going to share source code in github with graphhopper’s amazing community.
Hi…Did it work? Is there any link for your code in Github?