/*
* 2. Get the best hop from the list, given the parameters. Currently look for nearest hop,
* taking into account shape if available. If no shape are present, the computed hop and
* fraction may be a bit away from what it should be.
*/
PatternHop bestHop = null;
double minDist = Double.MAX_VALUE;
for (PatternHop hop : hops) {
LineString line = hop.getGeometry();
double dist = distanceLibrary.fastDistance(point, line);
if (dist < minDist) {
minDist = dist;
bestHop = hop;
}
}
if (minDist > 1000) LOG.warn(
"On-board depart: origin point suspiciously away from nearest trip shape ({} meters)",
minDist);
else LOG.info("On-board depart: origin point {} meters away from hop shape", minDist);
/*
* 3. Compute the fraction covered percentage of the current hop. This assume a constant
* trip speed alongside the whole hop: this should be quite precise for small hops
* (buses), a bit less for longer ones (long distance train). Shape linear distance is
* of no help here, as the unit is arbitrary (and probably usually a distance).
*/
LineString geometry = bestHop.getGeometry();
P2<LineString> geomPair = GeometryUtils.splitGeometryAtPoint(geometry, point);
geomRemaining = geomPair.second;
double total = distanceLibrary.fastLength(geometry);
double remaining = distanceLibrary.fastLength(geomRemaining);
fractionCovered = total > 0.0 ? (double) (1.0 - remaining / total) : 0.0;
nextStop = (PatternStopVertex) bestHop.getToVertex();
bestStopIndex = bestHop.getStopIndex();
/*
* 4. Compute service day based on given departure day/time relative to
* scheduled/real-time trip time for hop. This is needed as for some trips any service
* day can apply.
*/
int minDelta = Integer.MAX_VALUE;
int actDelta = 0;
for (ServiceDay serviceDay : ctx.serviceDays) {
TripPattern pattern = nextStop.getTripPattern();
Timetable timetable = pattern.getUpdatedTimetable(opt, serviceDay);
// Get the tripTimes including real-time updates for the serviceDay
TripTimes tripTimes = timetable.getTripTimes(timetable.getTripIndex(tripId));
int depTime = tripTimes.getDepartureTime(bestStopIndex);
int arrTime = tripTimes.getArrivalTime(bestStopIndex + 1);
int estTime = (int) Math.round(
depTime * fractionCovered + arrTime * (1 - fractionCovered));
int time = serviceDay.secondsSinceMidnight(opt.dateTime);
/*
* TODO Weight differently early vs late time, as the probability of any transit
* being late is higher than being early. However, this has impact if your bus is
* more than 12h late, I don't think this would happen really often.
*/
int deltaTime = Math.abs(time - estTime);
if (deltaTime < minDelta) {
minDelta = deltaTime;
actDelta = time - estTime;
bestTripTimes = tripTimes;
bestServiceDay = serviceDay;
}
}
if (minDelta > 60000) LOG.warn( // Being more than 1h late should not happen often
"On-board depart: delta between scheduled/real-time and actual time suspiciously large: {} seconds.",
actDelta);
else LOG.info(
"On-board depart: delta between scheduled/real-time and actual time is {} seconds.",
actDelta);
} else {
/* 2. Compute service day */
for (ServiceDay serviceDay : ctx.serviceDays) {
Timetable timetable = tripPattern.getUpdatedTimetable(opt, serviceDay);
// Get the tripTimes including real-time updates for the serviceDay
TripTimes tripTimes = timetable.getTripTimes(timetable.getTripIndex(tripId));
int depTime = tripTimes.getDepartureTime(0);
int arrTime = tripTimes.getArrivalTime(tripTimes.getNumStops() - 1);
int time = serviceDay.secondsSinceMidnight(opt.dateTime);
if (depTime <= time && time <= arrTime) {
bestTripTimes = tripTimes;
bestServiceDay = serviceDay;
}
}
if (bestServiceDay == null) {
throw new RuntimeException("Unable to determine on-board depart service day.");
}
int time = bestServiceDay.secondsSinceMidnight(opt.dateTime);
/*
* 3. Get the best hop from the list, given the parameters. This is done by finding the
* last hop that has not yet departed.
*/
PatternHop bestHop = null;
for (PatternHop hop : hops) {
int stopIndex = hop.getStopIndex();
int depTime = bestTripTimes.getDepartureTime(stopIndex);
int arrTime = bestTripTimes.getArrivalTime(stopIndex + 1);
if (time == arrTime) {
return ctx.graph.getVertex(hop.getEndStop().getId().toString());
} else if (depTime < time) {
bestHop = hop;
bestStopIndex = stopIndex;
} else if (time == depTime || bestTripTimes.getArrivalTime(bestStopIndex + 1) < time) {
return ctx.graph.getVertex(hop.getBeginStop().getId().toString());
} else {
break;
}
}
nextStop = (PatternStopVertex) bestHop.getToVertex();
LineString geometry = bestHop.getGeometry();
/*
* 4. Compute the fraction covered percentage of the current hop. Once again a constant
* trip speed is assumed. The linear distance of the shape is used, so the results are
* not 100% accurate. On the flip side, they are easy to compute and very well testable.