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
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
//! Bus stops and routes.
// TODO Rename public transit -- these also cover light rail now.

use std::fmt;

use serde::{Deserialize, Serialize};

use abstutil::{deserialize_usize, serialize_usize};
use geom::Time;

use crate::{osm, LaneID, Map, PathConstraints, PathRequest, Position};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct BusStopID {
    pub sidewalk: LaneID,
    /// As long as this is unique per lane, this value is otherwise meaningless. Not contiguous or
    /// ordered in any way.
    pub(crate) idx: usize,
}

impl fmt::Display for BusStopID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BusStopID({0}, {1})", self.sidewalk, self.idx)
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct BusRouteID(
    #[serde(
        serialize_with = "serialize_usize",
        deserialize_with = "deserialize_usize"
    )]
    pub usize,
);

impl fmt::Display for BusRouteID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BusRoute #{}", self.0)
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct BusStop {
    pub id: BusStopID,
    pub name: String,
    /// These may be on different roads entirely, like for light rail platforms.
    pub driving_pos: Position,
    pub sidewalk_pos: Position,
    /// If it's both, train overrides bus
    pub is_train_stop: bool,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct BusRoute {
    pub id: BusRouteID,
    pub full_name: String,
    pub short_name: String,
    pub gtfs_trip_marker: Option<String>,
    pub osm_rel_id: osm::RelationID,
    pub stops: Vec<BusStopID>,
    /// May be a border or not. If not, is long enough for buses to spawn fully.
    pub start: LaneID,
    pub end_border: Option<LaneID>,
    pub route_type: PathConstraints,
    /// Non-empty, times in order for one day when a vehicle should begin at start.
    pub spawn_times: Vec<Time>,
    /// Explicitly store whatever the original was, since this can't be reconstructed without side
    /// input.
    pub orig_spawn_times: Vec<Time>,
}

impl BusRoute {
    pub fn all_steps(&self, map: &Map) -> Vec<PathRequest> {
        let mut steps = vec![PathRequest::vehicle(
            Position::start(self.start),
            map.get_bs(self.stops[0]).driving_pos,
            self.route_type,
        )];
        for pair in self.stops.windows(2) {
            steps.push(PathRequest::vehicle(
                map.get_bs(pair[0]).driving_pos,
                map.get_bs(pair[1]).driving_pos,
                self.route_type,
            ));
        }
        if let Some(end) = self.end_border {
            steps.push(PathRequest::vehicle(
                map.get_bs(*self.stops.last().unwrap()).driving_pos,
                Position::end(end, map),
                self.route_type,
            ));
        }
        steps
    }

    pub fn plural_noun(&self) -> &'static str {
        if self.route_type == PathConstraints::Bus {
            "buses"
        } else {
            "trains"
        }
    }
}