|
|
|
@ -30,12 +30,21 @@
|
|
|
|
|
#include "order_base.h"
|
|
|
|
|
#include "settings_type.h"
|
|
|
|
|
#include "core/smallvec_type.hpp"
|
|
|
|
|
#include "core/sort_func.hpp"
|
|
|
|
|
#include "date_type.h"
|
|
|
|
|
#include "company_type.h"
|
|
|
|
|
#include "cargo_type.h"
|
|
|
|
|
#include "departures_func.h"
|
|
|
|
|
#include "departures_type.h"
|
|
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <set>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
/* A cache of used departure time for scheduled dispatch in departure time calculation */
|
|
|
|
|
typedef std::map<uint32, std::set<DateTicksScaled>> schdispatch_cache_t;
|
|
|
|
|
|
|
|
|
|
/** A scheduled order. */
|
|
|
|
|
typedef struct OrderDate
|
|
|
|
|
{
|
|
|
|
@ -44,6 +53,7 @@ typedef struct OrderDate
|
|
|
|
|
DateTicks expected_date;///< The date on which the order is expected to complete
|
|
|
|
|
Ticks lateness; ///< How late this order is expected to finish
|
|
|
|
|
DepartureStatus status; ///< Whether the vehicle has arrived to carry out the order yet
|
|
|
|
|
uint scheduled_waiting_time; ///< Scheduled waiting time if scheduled dispatch is used
|
|
|
|
|
} OrderDate;
|
|
|
|
|
|
|
|
|
|
static bool IsDeparture(const Order *order, StationID station) {
|
|
|
|
@ -70,6 +80,119 @@ static bool IsArrival(const Order *order, StationID station) {
|
|
|
|
|
order->GetWaitTime() != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool VehicleSetNextDepartureTime(DateTicks *previous_departure, uint *waiting_time, const DateTicksScaled date_only_scaled, const Vehicle *v, const Order *order, bool arrived_at_timing_point, schdispatch_cache_t &dept_schedule_last)
|
|
|
|
|
{
|
|
|
|
|
if (HasBit(v->vehicle_flags, VF_SCHEDULED_DISPATCH)) {
|
|
|
|
|
/* Loop over all order to find the first waiting order */
|
|
|
|
|
for (int j = 0; j < v->orders.list->GetNumOrders(); ++j) {
|
|
|
|
|
Order* iterating_order = v->orders.list->GetOrderAt(j);
|
|
|
|
|
|
|
|
|
|
if (iterating_order->IsWaitTimetabled() && !iterating_order->IsType(OT_IMPLICIT)) {
|
|
|
|
|
/* This condition means that we want departure time for the first order */
|
|
|
|
|
/* but not if the vehicle has arrived at the first order because the timetable is already shifted */
|
|
|
|
|
if (iterating_order == order && !(arrived_at_timing_point && v->cur_implicit_order_index == j)) {
|
|
|
|
|
DateTicksScaled actual_departure = -1;
|
|
|
|
|
const DateTicksScaled begin_time = v->orders.list->GetScheduledDispatchStartTick();
|
|
|
|
|
const uint32 dispatch_duration = v->orders.list->GetScheduledDispatchDuration();
|
|
|
|
|
const int32 max_delay = v->orders.list->GetScheduledDispatchDelay();
|
|
|
|
|
|
|
|
|
|
/* Earliest possible departure according to schedue */
|
|
|
|
|
DateTicksScaled earliest_departure = begin_time + v->orders.list->GetScheduledDispatchLastDispatch();
|
|
|
|
|
|
|
|
|
|
/* Earliest possible departure according to vehicle current timetable */
|
|
|
|
|
if (earliest_departure + max_delay < date_only_scaled + *previous_departure + order->GetTravelTime()) {
|
|
|
|
|
earliest_departure = date_only_scaled + *previous_departure + order->GetTravelTime() - max_delay - 1;
|
|
|
|
|
/* -1 because this number is actually a moment before actual departure */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find next available slots */
|
|
|
|
|
for (auto current_offset : v->orders.list->GetScheduledDispatch()) {
|
|
|
|
|
DateTicksScaled current_departure = begin_time + current_offset;
|
|
|
|
|
while (current_departure <= earliest_departure) {
|
|
|
|
|
current_departure += dispatch_duration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure the slots has not already been used previously in this departure board calculation */
|
|
|
|
|
while (dept_schedule_last[v->orders.list->index].count(current_departure) > 0) {
|
|
|
|
|
current_departure += dispatch_duration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (actual_departure == -1 || actual_departure > current_departure) {
|
|
|
|
|
actual_departure = current_departure;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*waiting_time = order->GetWaitTime() + actual_departure - date_only_scaled - *previous_departure - order->GetTravelTime();
|
|
|
|
|
*previous_departure = actual_departure - date_only_scaled + order->GetWaitTime();
|
|
|
|
|
dept_schedule_last[v->orders.list->index].insert(actual_departure);
|
|
|
|
|
|
|
|
|
|
/* Return true means that vehicle lateness should be clear from this point onward */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is special case for proper calculation of arrival time. */
|
|
|
|
|
if (arrived_at_timing_point && v->cur_implicit_order_index == j) {
|
|
|
|
|
*previous_departure += order->GetTravelTime() + order->GetWaitTime();
|
|
|
|
|
*waiting_time = -v->lateness_counter + order->GetWaitTime();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
} /* if it is first waiting order */
|
|
|
|
|
} /* for in order list */
|
|
|
|
|
} /* if vehicle is on scheduled dispatch */
|
|
|
|
|
|
|
|
|
|
/* Not using schedule for this departure time */
|
|
|
|
|
*previous_departure += order->GetTravelTime() + order->GetWaitTime();
|
|
|
|
|
*waiting_time = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ScheduledDispatchDepartureLocalFix(DepartureList *departure_list)
|
|
|
|
|
{
|
|
|
|
|
/* Seperate departure by each shared order group */
|
|
|
|
|
std::map<uint32, std::vector<Departure*>> separated_departure;
|
|
|
|
|
for (Departure** departure = departure_list->Begin(); departure != departure_list->End(); departure++) {
|
|
|
|
|
separated_departure[(*departure)->vehicle->orders.list->index].push_back(*departure);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& pair : separated_departure) {
|
|
|
|
|
auto d_list = pair.second;
|
|
|
|
|
|
|
|
|
|
/* If the group is scheduled dispatch, then */
|
|
|
|
|
if (HasBit(d_list[0]->vehicle->vehicle_flags, VF_SCHEDULED_DISPATCH)) {
|
|
|
|
|
/* Separate departure time and sort them ascendently */
|
|
|
|
|
std::vector<DateTicksScaled> departure_time_list;
|
|
|
|
|
for (const auto& d : d_list) {
|
|
|
|
|
departure_time_list.push_back(d->scheduled_date);
|
|
|
|
|
}
|
|
|
|
|
std::sort(departure_time_list.begin(), departure_time_list.end());
|
|
|
|
|
|
|
|
|
|
/* Sort the departure list by arrival time */
|
|
|
|
|
std::sort(d_list.begin(), d_list.end(), [](const Departure * const &a, const Departure * const &b) -> bool {
|
|
|
|
|
DateTicksScaled arr_a = a->scheduled_date - (a->scheduled_waiting_time > 0 ? a->scheduled_waiting_time : a->order->GetWaitTime());
|
|
|
|
|
DateTicksScaled arr_b = b->scheduled_date - (b->scheduled_waiting_time > 0 ? b->scheduled_waiting_time : b->order->GetWaitTime());
|
|
|
|
|
return arr_a < arr_b;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* Re-assign them sequentially */
|
|
|
|
|
for (size_t i = 0; i < d_list.size(); i++) {
|
|
|
|
|
const DateTicksScaled arrival = d_list[i]->scheduled_date - (d_list[i]->scheduled_waiting_time > 0 ? d_list[i]->scheduled_waiting_time : d_list[i]->order->GetWaitTime());
|
|
|
|
|
d_list[i]->scheduled_waiting_time = departure_time_list[i] - arrival;
|
|
|
|
|
d_list[i]->scheduled_date = departure_time_list[i];
|
|
|
|
|
|
|
|
|
|
if (d_list[i]->scheduled_waiting_time == d_list[i]->order->GetWaitTime()) {
|
|
|
|
|
d_list[i]->scheduled_waiting_time = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Re-sort the departure list */
|
|
|
|
|
QSortT<Departure*>(departure_list->Begin(), departure_list->Length(), [](Departure * const *a, Departure * const *b) -> int {
|
|
|
|
|
return (*a)->scheduled_date - (*b)->scheduled_date;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Compute an up-to-date list of departures for a station.
|
|
|
|
|
* @param station the station to compute the departures of
|
|
|
|
@ -102,6 +225,9 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
/* The scheduled order in next_orders with the earliest expected_date field. */
|
|
|
|
|
OrderDate *least_order = NULL;
|
|
|
|
|
|
|
|
|
|
/* Cache for scheduled departure time */
|
|
|
|
|
schdispatch_cache_t schdispatch_last_planned_dispatch;
|
|
|
|
|
|
|
|
|
|
/* Get all the vehicles stopping at this station. */
|
|
|
|
|
/* We do this to get the order which is the first time they will stop at this station. */
|
|
|
|
|
/* This order is stored along with some more information. */
|
|
|
|
@ -141,8 +267,10 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Order *order = (*v)->GetOrder((*v)->cur_implicit_order_index % (*v)->GetNumOrders());
|
|
|
|
|
DateTicksScaled start_date = date_fract_scaled - (*v)->current_order_time;
|
|
|
|
|
DateTicks start_date = date_fract_scaled - (*v)->current_order_time;
|
|
|
|
|
DepartureStatus status = D_TRAVELLING;
|
|
|
|
|
bool should_reset_lateness = false;
|
|
|
|
|
uint waiting_time = 0;
|
|
|
|
|
|
|
|
|
|
/* If the vehicle is stopped in a depot, ignore it. */
|
|
|
|
|
if ((*v)->IsStoppedInDepot()) {
|
|
|
|
@ -163,7 +291,9 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
/* Loop through the vehicle's orders until we've found a suitable order or we've determined that no such order exists. */
|
|
|
|
|
/* We only need to consider each order at most once. */
|
|
|
|
|
for (int i = (*v)->GetNumOrders(); i > 0; --i) {
|
|
|
|
|
start_date += order->GetTravelTime() + order->GetWaitTime();
|
|
|
|
|
if (VehicleSetNextDepartureTime(&start_date, &waiting_time, date_only_scaled, *v, order, status == D_ARRIVED, schdispatch_last_planned_dispatch)) {
|
|
|
|
|
should_reset_lateness = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the scheduled departure date is too far in the future, stop. */
|
|
|
|
|
if (start_date - (*v)->lateness_counter > max_date) {
|
|
|
|
@ -230,16 +360,23 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
od->expected_date = start_date;
|
|
|
|
|
od->lateness = (*v)->lateness_counter > 0 ? (*v)->lateness_counter : 0;
|
|
|
|
|
od->status = status;
|
|
|
|
|
od->scheduled_waiting_time = waiting_time;
|
|
|
|
|
|
|
|
|
|
/* Reset lateness if timing is from scheduled dispatch */
|
|
|
|
|
if (should_reset_lateness) {
|
|
|
|
|
od->lateness = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we are early, use the scheduled date as the expected date. We also take lateness to be zero. */
|
|
|
|
|
if ((*v)->lateness_counter < 0 && !(*v)->current_order.IsType(OT_LOADING)) {
|
|
|
|
|
if (!should_reset_lateness && (*v)->lateness_counter < 0 && !(*v)->current_order.IsType(OT_LOADING)) {
|
|
|
|
|
od->expected_date -= (*v)->lateness_counter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update least_order if this is the current least order. */
|
|
|
|
|
if (least_order == NULL) {
|
|
|
|
|
least_order = od;
|
|
|
|
|
} else if (least_order->expected_date - least_order->lateness - (type == D_ARRIVAL ? least_order->order->GetWaitTime() : 0) > od->expected_date - od->lateness - (type == D_ARRIVAL ? od->order->GetWaitTime() : 0)) {
|
|
|
|
|
} else if (int(least_order->expected_date - least_order->lateness - (type == D_ARRIVAL ? (least_order->scheduled_waiting_time > 0 ? least_order->scheduled_waiting_time : least_order->order->GetWaitTime()) : 0)) > int(od->expected_date - od->lateness - (type == D_ARRIVAL ? (od->scheduled_waiting_time > 0 ? od->scheduled_waiting_time : od->order->GetWaitTime()) : 0))) {
|
|
|
|
|
/* Somehow my compiler perform an unsigned comparition above so integer cast is required */
|
|
|
|
|
least_order = od;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -289,6 +426,7 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
d->vehicle = least_order->v;
|
|
|
|
|
d->type = type;
|
|
|
|
|
d->order = least_order->order;
|
|
|
|
|
d->scheduled_waiting_time = least_order->scheduled_waiting_time;
|
|
|
|
|
|
|
|
|
|
/* We'll be going through the order list later, so we need a separate variable for it. */
|
|
|
|
|
const Order *order = least_order->order;
|
|
|
|
@ -366,7 +504,7 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c.scheduled_date != 0 && (order->GetTravelTime() != 0 || order->IsTravelTimetabled())) {
|
|
|
|
|
c.scheduled_date += order->GetTravelTime();
|
|
|
|
|
c.scheduled_date += order->GetTravelTime(); /* TODO smart terminal may not work correctly */
|
|
|
|
|
} else {
|
|
|
|
|
c.scheduled_date = 0;
|
|
|
|
|
}
|
|
|
|
@ -467,7 +605,7 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
/* Again, we define a station as being called at if the vehicle loads from it. */
|
|
|
|
|
|
|
|
|
|
/* However, the very first thing we do is use the arrival time as the scheduled time instead of the departure time. */
|
|
|
|
|
d->scheduled_date -= order->GetWaitTime();
|
|
|
|
|
d->scheduled_date -= d->scheduled_waiting_time > 0 ? d->scheduled_waiting_time : order->GetWaitTime();
|
|
|
|
|
|
|
|
|
|
const Order *candidate_origin = (order->next == NULL) ? least_order->v->GetFirstOrder() : order->next;
|
|
|
|
|
bool found_origin = false;
|
|
|
|
@ -549,7 +687,9 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
|
|
|
|
|
/* Go to the next order so we don't add the current order again. */
|
|
|
|
|
order = (order->next == NULL) ? least_order->v->GetFirstOrder() : order->next;
|
|
|
|
|
least_order->expected_date += order->GetTravelTime() + order->GetWaitTime();
|
|
|
|
|
if (VehicleSetNextDepartureTime(&least_order->expected_date, &least_order->scheduled_waiting_time, date_only_scaled, least_order->v, order, false, schdispatch_last_planned_dispatch)) {
|
|
|
|
|
least_order->lateness = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Go through the order list to find the next candidate departure. */
|
|
|
|
|
/* We only need to consider each order at most once. */
|
|
|
|
@ -569,14 +709,18 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
least_order->expected_date += order->GetWaitTime();
|
|
|
|
|
if (VehicleSetNextDepartureTime(&least_order->expected_date, &least_order->scheduled_waiting_time, date_only_scaled, least_order->v, order, false, schdispatch_last_planned_dispatch)) {
|
|
|
|
|
least_order->lateness = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
case 2: {
|
|
|
|
|
/* Do not take the branch */
|
|
|
|
|
order = (order->next == NULL) ? least_order->v->GetFirstOrder() : order->next;
|
|
|
|
|
least_order->expected_date += order->GetTravelTime() + order->GetWaitTime();
|
|
|
|
|
if (VehicleSetNextDepartureTime(&least_order->expected_date, &least_order->scheduled_waiting_time, date_only_scaled, least_order->v, order, false, schdispatch_last_planned_dispatch)) {
|
|
|
|
|
least_order->lateness = 0;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -608,7 +752,9 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
order = (order->next == NULL) ? least_order->v->GetFirstOrder() : order->next;
|
|
|
|
|
least_order->expected_date += order->GetTravelTime() + order->GetWaitTime();
|
|
|
|
|
if (VehicleSetNextDepartureTime(&least_order->expected_date, &least_order->scheduled_waiting_time, date_only_scaled, least_order->v, order, false, schdispatch_last_planned_dispatch)) {
|
|
|
|
|
least_order->lateness = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we didn't find a suitable order for being a departure, then we can ignore this vehicle from now on. */
|
|
|
|
@ -632,8 +778,8 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
DateTicks odd = od->expected_date - od->lateness;
|
|
|
|
|
|
|
|
|
|
if (type == D_ARRIVAL) {
|
|
|
|
|
lod -= least_order->order->GetWaitTime();
|
|
|
|
|
odd -= od->order->GetWaitTime();
|
|
|
|
|
lod -= least_order->scheduled_waiting_time > 0 ? least_order->scheduled_waiting_time : least_order->order->GetWaitTime();
|
|
|
|
|
odd -= od->scheduled_waiting_time > 0 ? od->scheduled_waiting_time : od->order->GetWaitTime();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lod > odd && od->expected_date - od->lateness < max_date) {
|
|
|
|
@ -648,6 +794,8 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
|
|
|
|
|
delete od;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type == D_DEPARTURE) ScheduledDispatchDepartureLocalFix(result);
|
|
|
|
|
|
|
|
|
|
/* Done. Phew! */
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|