1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use crate::construction::heuristics::{ActivityContext, RouteContext};
use crate::models::common::{Distance, Duration, Timestamp};
use crate::models::problem::{TransportCost, TravelTime};
use crate::models::solution::{Activity, Route};

/// Calculates a travel info from prev to next directly.
pub fn calculate_travel(
    route_ctx: &RouteContext,
    activity_ctx: &ActivityContext,
    transport: &(dyn TransportCost + Send + Sync),
) -> ((Distance, Distance), (Duration, Duration)) {
    let route = route_ctx.route();
    let prev = activity_ctx.prev;
    let tar = activity_ctx.target;
    let next = activity_ctx.next;

    let prev_dep = prev.schedule.departure;

    let (prev_to_tar_dis, prev_to_tar_dur) = calculate_travel_leg(route, prev, tar, prev_dep, transport);

    if let Some(next) = next {
        let tar_dep = prev_dep + prev_to_tar_dur;

        let (tar_to_next_dis, tar_to_next_dur) = calculate_travel_leg(route, tar, next, tar_dep, transport);

        ((prev_to_tar_dis, tar_to_next_dis), (prev_to_tar_dur, tar_to_next_dur))
    } else {
        ((prev_to_tar_dis, Distance::default()), (prev_to_tar_dur, Duration::default()))
    }
}

/// Calculates delta in distance and duration for target activity in given activity context.
pub fn calculate_travel_delta(
    route_ctx: &RouteContext,
    activity_ctx: &ActivityContext,
    transport: &(dyn TransportCost + Send + Sync),
) -> (Distance, Duration) {
    // NOTE accept some code duplication between methods in that module as they are called often,
    //      generalization might require some redundancy in calculations

    let route = route_ctx.route();
    let prev = activity_ctx.prev;
    let tar = activity_ctx.target;
    let next = activity_ctx.next;

    let prev_dep = prev.schedule.departure;

    let (prev_to_tar_dis, prev_to_tar_dur) = calculate_travel_leg(route, prev, tar, prev_dep, transport);

    if let Some(next) = next {
        let tar_dep = prev_dep + prev_to_tar_dur;

        let (prev_to_next_dis, prev_to_next_dur) = calculate_travel_leg(route, prev, next, prev_dep, transport);
        let (tar_to_next_dis, tar_to_next_dur) = calculate_travel_leg(route, tar, next, tar_dep, transport);

        (prev_to_tar_dis + tar_to_next_dis - prev_to_next_dis, prev_to_tar_dur + tar_to_next_dur - prev_to_next_dur)
    } else {
        (prev_to_tar_dis, prev_to_tar_dur)
    }
}

/// Calculates a travel leg info.
fn calculate_travel_leg(
    route: &Route,
    first: &Activity,
    second: &Activity,
    departure: Timestamp,
    transport: &(dyn TransportCost + Send + Sync),
) -> (Distance, Duration) {
    let first_to_second_dis =
        transport.distance(route, first.place.location, second.place.location, TravelTime::Departure(departure));
    let first_to_second_dur =
        transport.duration(route, first.place.location, second.place.location, TravelTime::Departure(departure));

    let second_arr = departure + first_to_second_dur;
    let second_wait = (second.place.time.start - second_arr).max(0.);
    let second_dep = second_arr + second_wait + second.place.duration;

    (first_to_second_dis, second_dep - departure)
}