diff --git a/editor/src/plugins/sim/even_simpler_model.rs b/editor/src/plugins/sim/even_simpler_model.rs index 9dbb106ec0..4379ae2e9f 100644 --- a/editor/src/plugins/sim/even_simpler_model.rs +++ b/editor/src/plugins/sim/even_simpler_model.rs @@ -4,7 +4,9 @@ use crate::plugins::{BlockingPlugin, PluginCtx}; use crate::render::MIN_ZOOM_FOR_DETAIL; use ezgui::{EventLoopMode, GfxCtx, Key}; use geom::{Distance, Duration, Speed}; -use map_model::{BuildingID, LaneID, LaneType, Map, Traversable}; +use map_model::{ + BuildingID, LaneID, LaneType, Map, PathRequest, Pathfinder, Position, Traversable, +}; use rand::seq::SliceRandom; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -132,7 +134,8 @@ fn populate_sim(start: LaneID, map: &Map) -> new_des_model::Sim { } } - let mut counter = 0; + let mut car_counter = 0; + let mut ped_counter = 0; let mut rng = XorShiftRng::from_seed([42; 16]); for source in sources { let len = map.get_l(source).length(); @@ -142,12 +145,14 @@ fn populate_sim(start: LaneID, map: &Map) -> new_des_model::Sim { } for _ in 0..10 { - if spawn_car(&mut sim, &mut rng, map, counter, source) { - counter += 1; + if spawn_car(&mut sim, &mut rng, map, car_counter, source) { + car_counter += 1; } } - seed_parked_cars_near(source, &mut rng, &mut sim, map, &mut counter); + seed_parked_cars_near(source, &mut rng, &mut sim, map, &mut car_counter); + + random_ped_near(source, &mut sim, map, &mut rng, &mut ped_counter); } sim @@ -156,17 +161,20 @@ fn populate_sim(start: LaneID, map: &Map) -> new_des_model::Sim { fn densely_populate_sim(map: &Map) -> new_des_model::Sim { let mut sim = new_des_model::Sim::new(map); let mut rng = XorShiftRng::from_seed([42; 16]); - let mut counter = 0; + let mut car_counter = 0; + let mut ped_counter = 0; for l in map.all_lanes() { let len = l.length(); if l.is_driving() && len >= new_des_model::MAX_VEHICLE_LENGTH { for _ in 0..rng.gen_range(0, 5) { - if spawn_car(&mut sim, &mut rng, map, counter, l.id) { - counter += 1; + if spawn_car(&mut sim, &mut rng, map, car_counter, l.id) { + car_counter += 1; } } - seed_parked_cars_near(l.id, &mut rng, &mut sim, map, &mut counter); + seed_parked_cars_near(l.id, &mut rng, &mut sim, map, &mut car_counter); + + random_ped_near(l.id, &mut sim, map, &mut rng, &mut ped_counter); } } @@ -290,3 +298,47 @@ fn rand_vehicle(rng: &mut XorShiftRng, id: usize) -> new_des_model::Vehicle { max_speed, } } + +fn random_ped_near( + start_near: LaneID, + sim: &mut new_des_model::Sim, + map: &Map, + rng: &mut XorShiftRng, + counter: &mut usize, +) { + let end_near = random_path(start_near, rng, map).last().unwrap().as_lane(); + let (start, end) = match ( + map.find_closest_lane(start_near, vec![LaneType::Sidewalk]), + map.find_closest_lane(end_near, vec![LaneType::Sidewalk]), + ) { + (Ok(l1), Ok(l2)) => (l1, l2), + _ => { + return; + } + }; + + let pos1 = Position::new(start, map.get_l(start).length() / 2.0); + let pos2 = Position::new(end, map.get_l(end).length() / 2.0); + let path = match Pathfinder::shortest_distance( + map, + PathRequest { + start: pos1, + end: pos2, + can_use_bike_lanes: false, + can_use_bus_lanes: false, + }, + ) { + Some(p) => p, + None => { + return; + } + }; + + sim.spawn_ped( + PedestrianID::tmp_new(*counter), + new_des_model::SidewalkSpot::bike_rack(pos1, map), + new_des_model::SidewalkSpot::bike_rack(pos2, map), + path, + ); + *counter += 1 +} diff --git a/editor/src/plugins/sim/new_des_model/car.rs b/editor/src/plugins/sim/new_des_model/car.rs index e56c47d879..33f0e587fd 100644 --- a/editor/src/plugins/sim/new_des_model/car.rs +++ b/editor/src/plugins/sim/new_des_model/car.rs @@ -1,4 +1,6 @@ -use crate::plugins::sim::new_des_model::{ParkingSpot, Router, Vehicle}; +use crate::plugins::sim::new_des_model::{ + DistanceInterval, ParkingSpot, Router, TimeInterval, Vehicle, +}; use geom::{Distance, Duration, PolyLine}; use map_model::{Map, Traversable, LANE_THICKNESS}; use sim::DrawCarInput; @@ -135,52 +137,3 @@ pub enum CarState { Unparking(Distance, TimeInterval), Parking(Distance, ParkingSpot, TimeInterval), } - -// TODO Walking will use these too -- lift up - -#[derive(Debug)] -pub struct TimeInterval { - // TODO Private fields - pub start: Duration, - pub end: Duration, -} - -impl TimeInterval { - pub fn new(start: Duration, end: Duration) -> TimeInterval { - if end < start { - panic!("Bad TimeInterval {} .. {}", start, end); - } - TimeInterval { start, end } - } - - pub fn percent(&self, t: Duration) -> f64 { - if self.start == self.end { - return 1.0; - } - - let x = (t - self.start) / (self.end - self.start); - assert!(x >= 0.0 && x <= 1.0); - x - } -} - -#[derive(Debug)] -pub struct DistanceInterval { - // TODO Private fields - pub start: Distance, - pub end: Distance, -} - -impl DistanceInterval { - fn new(start: Distance, end: Distance) -> DistanceInterval { - if end < start { - panic!("Bad DistanceInterval {} .. {}", start, end); - } - DistanceInterval { start, end } - } - - pub fn lerp(&self, x: f64) -> Distance { - assert!(x >= 0.0 && x <= 1.0); - self.start + x * (self.end - self.start) - } -} diff --git a/editor/src/plugins/sim/new_des_model/mod.rs b/editor/src/plugins/sim/new_des_model/mod.rs index 8456e476b7..dd32454209 100644 --- a/editor/src/plugins/sim/new_des_model/mod.rs +++ b/editor/src/plugins/sim/new_des_model/mod.rs @@ -6,7 +6,7 @@ mod queue; mod router; mod sim; -pub use self::car::{Car, CarState, TimeInterval}; +pub use self::car::{Car, CarState}; pub use self::driving::DrivingSimState; pub use self::intersection::IntersectionController; pub use self::parking::ParkingSimState; @@ -14,8 +14,8 @@ pub use self::queue::Queue; pub use self::router::{ActionAtEnd, Router}; pub use self::sim::Sim; use ::sim::{CarID, VehicleType}; -use geom::{Distance, Speed}; -use map_model::{BuildingID, LaneID}; +use geom::{Distance, Duration, Speed}; +use map_model::{BuildingID, BusStopID, IntersectionID, LaneID, LaneType, Map, Position}; use serde_derive::{Deserialize, Serialize}; pub const MIN_VEHICLE_LENGTH: Distance = Distance::const_meters(2.0); @@ -60,3 +60,134 @@ impl ParkedCar { } } } + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +pub struct SidewalkSpot { + connection: SidewalkPOI, + pub sidewalk_pos: Position, +} + +impl SidewalkSpot { + #[allow(dead_code)] + pub fn parking_spot( + spot: ParkingSpot, + map: &Map, + parking_sim: &ParkingSimState, + ) -> SidewalkSpot { + let sidewalk = map + .find_closest_lane(spot.lane, vec![LaneType::Sidewalk]) + .unwrap(); + SidewalkSpot { + connection: SidewalkPOI::ParkingSpot(spot), + sidewalk_pos: parking_sim.spot_to_sidewalk_pos(spot, sidewalk, map), + } + } + + #[allow(dead_code)] + pub fn building(bldg: BuildingID, map: &Map) -> SidewalkSpot { + let front_path = &map.get_b(bldg).front_path; + SidewalkSpot { + connection: SidewalkPOI::Building(bldg), + sidewalk_pos: front_path.sidewalk, + } + } + + pub fn bike_rack(sidewalk_pos: Position, map: &Map) -> SidewalkSpot { + assert!(map.get_l(sidewalk_pos.lane()).is_sidewalk()); + SidewalkSpot { + connection: SidewalkPOI::BikeRack, + sidewalk_pos, + } + } + + #[allow(dead_code)] + pub fn bus_stop(stop: BusStopID, map: &Map) -> SidewalkSpot { + SidewalkSpot { + sidewalk_pos: map.get_bs(stop).sidewalk_pos, + connection: SidewalkPOI::BusStop(stop), + } + } + + #[allow(dead_code)] + pub fn start_at_border(i: IntersectionID, map: &Map) -> Option { + let lanes = map.get_i(i).get_outgoing_lanes(map, LaneType::Sidewalk); + if lanes.is_empty() { + None + } else { + Some(SidewalkSpot { + sidewalk_pos: Position::new(lanes[0], Distance::ZERO), + connection: SidewalkPOI::Border(i), + }) + } + } + + #[allow(dead_code)] + pub fn end_at_border(i: IntersectionID, map: &Map) -> Option { + let lanes = map.get_i(i).get_incoming_lanes(map, LaneType::Sidewalk); + if lanes.is_empty() { + None + } else { + Some(SidewalkSpot { + sidewalk_pos: Position::new(lanes[0], map.get_l(lanes[0]).length()), + connection: SidewalkPOI::Border(i), + }) + } + } +} + +// Point of interest, that is +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +enum SidewalkPOI { + ParkingSpot(ParkingSpot), + Building(BuildingID), + BusStop(BusStopID), + Border(IntersectionID), + BikeRack, +} + +#[derive(Debug)] +pub struct TimeInterval { + // TODO Private fields + pub start: Duration, + pub end: Duration, +} + +impl TimeInterval { + pub fn new(start: Duration, end: Duration) -> TimeInterval { + if end < start { + panic!("Bad TimeInterval {} .. {}", start, end); + } + TimeInterval { start, end } + } + + pub fn percent(&self, t: Duration) -> f64 { + if self.start == self.end { + return 1.0; + } + + let x = (t - self.start) / (self.end - self.start); + assert!(x >= 0.0 && x <= 1.0); + x + } +} + +#[derive(Debug)] +pub struct DistanceInterval { + // TODO Private fields + pub start: Distance, + pub end: Distance, +} + +impl DistanceInterval { + fn new(start: Distance, end: Distance) -> DistanceInterval { + if end < start { + panic!("Bad DistanceInterval {} .. {}", start, end); + } + DistanceInterval { start, end } + } + + pub fn lerp(&self, x: f64) -> Distance { + assert!(x >= 0.0 && x <= 1.0); + self.start + x * (self.end - self.start) + } +} diff --git a/editor/src/plugins/sim/new_des_model/parking.rs b/editor/src/plugins/sim/new_des_model/parking.rs index 7726333c75..5eca49e823 100644 --- a/editor/src/plugins/sim/new_des_model/parking.rs +++ b/editor/src/plugins/sim/new_des_model/parking.rs @@ -162,9 +162,9 @@ impl ParkingSimState { .equiv_pos(driving_lane, map) } - /*pub fn spot_to_sidewalk_pos(&self, spot: ParkingSpot, sidewalk: LaneID, map: &Map) -> Position { + pub fn spot_to_sidewalk_pos(&self, spot: ParkingSpot, sidewalk: LaneID, map: &Map) -> Position { Position::new(spot.lane, self.get_spot(spot).dist_along_for_ped()).equiv_pos(sidewalk, map) - }*/ + } fn get_spot(&self, spot: ParkingSpot) -> &ParkingSpotGeometry { &self.lanes[spot.lane.0].spots[spot.idx] @@ -264,10 +264,10 @@ struct ParkingSpotGeometry { } impl ParkingSpotGeometry { - /*fn dist_along_for_ped(&self) -> Distance { + fn dist_along_for_ped(&self) -> Distance { // Always centered in the entire parking spot self.dist_along - (map_model::PARKING_SPOT_LENGTH / 2.0) - }*/ + } fn dist_along_for_car(&self, vehicle: &Vehicle) -> Distance { // Find the offset to center this particular car in the parking spot diff --git a/editor/src/plugins/sim/new_des_model/sim.rs b/editor/src/plugins/sim/new_des_model/sim.rs index 7b8e12a479..4c2635ec99 100644 --- a/editor/src/plugins/sim/new_des_model/sim.rs +++ b/editor/src/plugins/sim/new_des_model/sim.rs @@ -1,10 +1,10 @@ use crate::plugins::sim::new_des_model::{ - DrivingSimState, ParkedCar, ParkingSimState, Router, Vehicle, + DrivingSimState, ParkedCar, ParkingSimState, Router, SidewalkSpot, Vehicle, }; use ezgui::GfxCtx; use geom::{Distance, Duration}; -use map_model::{Map, Traversable}; -use sim::DrawCarInput; +use map_model::{Map, Path, Traversable}; +use sim::{DrawCarInput, PedestrianID}; pub struct Sim { driving: DrivingSimState, @@ -64,6 +64,16 @@ impl Sim { ); } + pub fn spawn_ped( + &mut self, + id: PedestrianID, + start: SidewalkSpot, + goal: SidewalkSpot, + path: Path, + ) { + // TODO Assert valid + } + pub fn step_if_needed(&mut self, time: Duration, map: &Map) { self.driving.step_if_needed(time, map, &mut self.parking); } diff --git a/sim/src/lib.rs b/sim/src/lib.rs index a7076f3588..96f7b26465 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -65,6 +65,12 @@ impl fmt::Display for CarID { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct PedestrianID(pub usize); +impl PedestrianID { + pub fn tmp_new(idx: usize) -> PedestrianID { + PedestrianID(idx) + } +} + impl fmt::Display for PedestrianID { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "PedestrianID({0})", self.0)