mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-24 15:02:59 +03:00
Implement the two public TripEndpoint methods in synthpop, but without needing to drag in SidewalkSpot and DrivingGoal
This commit is contained in:
parent
3f8689b9ea
commit
9845d9cae1
@ -462,45 +462,15 @@ impl SidewalkSpot {
|
||||
|
||||
// Recall sidewalks are bidirectional.
|
||||
pub fn start_at_border(i: IntersectionID, map: &Map) -> Option<SidewalkSpot> {
|
||||
let lanes = map
|
||||
.get_i(i)
|
||||
.get_outgoing_lanes(map, PathConstraints::Pedestrian);
|
||||
if !lanes.is_empty() {
|
||||
return Some(SidewalkSpot {
|
||||
sidewalk_pos: Position::start(lanes[0]),
|
||||
connection: SidewalkPOI::Border(i),
|
||||
});
|
||||
}
|
||||
|
||||
map.get_i(i)
|
||||
.get_incoming_lanes(map, PathConstraints::Pedestrian)
|
||||
.get(0)
|
||||
.map(|l| SidewalkSpot {
|
||||
sidewalk_pos: Position::end(*l, map),
|
||||
connection: SidewalkPOI::Border(i),
|
||||
})
|
||||
Some(SidewalkSpot {
|
||||
sidewalk_pos: TripEndpoint::start_walking_at_border(i, map)?,
|
||||
connection: SidewalkPOI::Border(i),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn end_at_border(i: IntersectionID, map: &Map) -> Option<SidewalkSpot> {
|
||||
if let Some(l) = map
|
||||
.get_i(i)
|
||||
.get_incoming_lanes(map, PathConstraints::Pedestrian)
|
||||
.get(0)
|
||||
{
|
||||
return Some(SidewalkSpot {
|
||||
sidewalk_pos: Position::end(*l, map),
|
||||
connection: SidewalkPOI::Border(i),
|
||||
});
|
||||
}
|
||||
|
||||
let lanes = map
|
||||
.get_i(i)
|
||||
.get_outgoing_lanes(map, PathConstraints::Pedestrian);
|
||||
if lanes.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(SidewalkSpot {
|
||||
sidewalk_pos: Position::start(lanes[0]),
|
||||
sidewalk_pos: TripEndpoint::end_walking_at_border(i, map)?,
|
||||
connection: SidewalkPOI::Border(i),
|
||||
})
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ impl TripSpec {
|
||||
} else {
|
||||
PathConstraints::Bike
|
||||
};
|
||||
let goal = to.driving_goal(constraints, map)?;
|
||||
let goal = driving_goal(to, constraints, map)?;
|
||||
match from {
|
||||
TripEndpoint::Bldg(start_bldg) => {
|
||||
if mode == TripMode::Drive {
|
||||
@ -266,12 +266,12 @@ impl TripSpec {
|
||||
}
|
||||
}
|
||||
TripMode::Walk => TripSpec::JustWalking {
|
||||
start: from.start_sidewalk_spot(map)?,
|
||||
goal: to.end_sidewalk_spot(map)?,
|
||||
start: start_sidewalk_spot(from, map)?,
|
||||
goal: end_sidewalk_spot(to, map)?,
|
||||
},
|
||||
TripMode::Transit => {
|
||||
let start = from.start_sidewalk_spot(map)?;
|
||||
let goal = to.end_sidewalk_spot(map)?;
|
||||
let start = start_sidewalk_spot(from, map)?;
|
||||
let goal = end_sidewalk_spot(to, map)?;
|
||||
if let Some((stop1, maybe_stop2, route)) =
|
||||
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
|
||||
{
|
||||
@ -291,3 +291,47 @@ impl TripSpec {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn start_sidewalk_spot(endpt: TripEndpoint, map: &Map) -> Result<SidewalkSpot> {
|
||||
match endpt {
|
||||
TripEndpoint::Bldg(b) => Ok(SidewalkSpot::building(b, map)),
|
||||
TripEndpoint::Border(i) => SidewalkSpot::start_at_border(i, map)
|
||||
.ok_or_else(|| anyhow!("can't start walking from {}", i)),
|
||||
TripEndpoint::SuddenlyAppear(pos) => Ok(SidewalkSpot::suddenly_appear(pos, map)),
|
||||
}
|
||||
}
|
||||
|
||||
fn end_sidewalk_spot(endpt: TripEndpoint, map: &Map) -> Result<SidewalkSpot> {
|
||||
match endpt {
|
||||
TripEndpoint::Bldg(b) => Ok(SidewalkSpot::building(b, map)),
|
||||
TripEndpoint::Border(i) => {
|
||||
SidewalkSpot::end_at_border(i, map).ok_or_else(|| anyhow!("can't end walking at {}", i))
|
||||
}
|
||||
TripEndpoint::SuddenlyAppear(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn driving_goal(
|
||||
endpt: TripEndpoint,
|
||||
constraints: PathConstraints,
|
||||
map: &Map,
|
||||
) -> Result<DrivingGoal> {
|
||||
match endpt {
|
||||
TripEndpoint::Bldg(b) => Ok(DrivingGoal::ParkNear(b)),
|
||||
// TODO Duplicates some logic from TripEndpoint::pos
|
||||
TripEndpoint::Border(i) => map
|
||||
.get_i(i)
|
||||
.some_incoming_road(map)
|
||||
.and_then(|dr| {
|
||||
let lanes = dr.lanes(constraints, map);
|
||||
if lanes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
// TODO ideally could use any
|
||||
Some(DrivingGoal::Border(dr.dst_i(map), lanes[0]))
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| anyhow!("can't end at {} for {:?}", i, constraints)),
|
||||
TripEndpoint::SuddenlyAppear(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,18 @@
|
||||
use std::collections::{BTreeMap, HashSet, VecDeque};
|
||||
|
||||
use anyhow::Result;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use abstutil::{prettyprint_usize, Counter, Timer};
|
||||
use geom::{Distance, Pt2D, Speed};
|
||||
use map_model::{
|
||||
BuildingID, Map, OffstreetParking, PathConstraints, PathRequest, Position, RoadID,
|
||||
};
|
||||
use geom::{Distance, Speed};
|
||||
use map_model::{BuildingID, Map, OffstreetParking, RoadID};
|
||||
use synthpop::{PersonSpec, Scenario, TripEndpoint, TripMode};
|
||||
|
||||
use crate::make::fork_rng;
|
||||
use crate::{
|
||||
DrivingGoal, ParkingSpot, SidewalkSpot, Sim, StartTripArgs, TripInfo, Vehicle, VehicleSpec,
|
||||
VehicleType, BIKE_LENGTH, MAX_CAR_LENGTH, MIN_CAR_LENGTH,
|
||||
ParkingSpot, Sim, StartTripArgs, TripInfo, Vehicle, VehicleSpec, VehicleType, BIKE_LENGTH,
|
||||
MAX_CAR_LENGTH, MIN_CAR_LENGTH,
|
||||
};
|
||||
|
||||
impl Sim {
|
||||
@ -366,111 +363,3 @@ pub fn count_parked_cars_per_bldg(scenario: &Scenario) -> Counter<BuildingID> {
|
||||
}
|
||||
per_bldg
|
||||
}
|
||||
|
||||
/*impl TripEndpoint {
|
||||
/// Figure out a single PathRequest that goes between two TripEndpoints. Assume a single mode
|
||||
/// the entire time -- no walking to a car before driving, for instance. The result probably
|
||||
/// won't be exactly what would happen on a real trip between the endpoints because of this
|
||||
/// assumption.
|
||||
pub fn path_req(
|
||||
from: TripEndpoint,
|
||||
to: TripEndpoint,
|
||||
mode: TripMode,
|
||||
map: &Map,
|
||||
) -> Option<PathRequest> {
|
||||
let start = from.pos(mode, true, map)?;
|
||||
let end = to.pos(mode, false, map)?;
|
||||
Some(match mode {
|
||||
TripMode::Walk | TripMode::Transit => PathRequest::walking(start, end),
|
||||
TripMode::Bike => PathRequest::vehicle(start, end, PathConstraints::Bike),
|
||||
// Only cars leaving from a building might turn out from the driveway in a special way
|
||||
TripMode::Drive => {
|
||||
if matches!(from, TripEndpoint::Bldg(_)) {
|
||||
PathRequest::leave_from_driveway(start, end, PathConstraints::Car, map)
|
||||
} else {
|
||||
PathRequest::vehicle(start, end, PathConstraints::Car)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn start_sidewalk_spot(&self, map: &Map) -> Result<SidewalkSpot> {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => Ok(SidewalkSpot::building(*b, map)),
|
||||
TripEndpoint::Border(i) => SidewalkSpot::start_at_border(*i, map)
|
||||
.ok_or_else(|| anyhow!("can't start walking from {}", i)),
|
||||
TripEndpoint::SuddenlyAppear(pos) => Ok(SidewalkSpot::suddenly_appear(*pos, map)),
|
||||
}
|
||||
}
|
||||
|
||||
fn end_sidewalk_spot(&self, map: &Map) -> Result<SidewalkSpot> {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => Ok(SidewalkSpot::building(*b, map)),
|
||||
TripEndpoint::Border(i) => SidewalkSpot::end_at_border(*i, map)
|
||||
.ok_or_else(|| anyhow!("can't end walking at {}", i)),
|
||||
TripEndpoint::SuddenlyAppear(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn driving_goal(&self, constraints: PathConstraints, map: &Map) -> Result<DrivingGoal> {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => Ok(DrivingGoal::ParkNear(*b)),
|
||||
TripEndpoint::Border(i) => map
|
||||
.get_i(*i)
|
||||
.some_incoming_road(map)
|
||||
.and_then(|dr| {
|
||||
let lanes = dr.lanes(constraints, map);
|
||||
if lanes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
// TODO ideally could use any
|
||||
Some(DrivingGoal::Border(dr.dst_i(map), lanes[0]))
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| anyhow!("can't end at {} for {:?}", i, constraints)),
|
||||
TripEndpoint::SuddenlyAppear(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn pos(self, mode: TripMode, from: bool, map: &Map) -> Option<Position> {
|
||||
match mode {
|
||||
TripMode::Walk | TripMode::Transit => (if from {
|
||||
self.start_sidewalk_spot(map)
|
||||
} else {
|
||||
self.end_sidewalk_spot(map)
|
||||
})
|
||||
.ok()
|
||||
.map(|spot| spot.sidewalk_pos),
|
||||
TripMode::Drive | TripMode::Bike => {
|
||||
if from {
|
||||
match self {
|
||||
// Fall through and use DrivingGoal also to start.
|
||||
TripEndpoint::Bldg(_) => {}
|
||||
TripEndpoint::Border(i) => {
|
||||
return map.get_i(i).some_outgoing_road(map).and_then(|dr| {
|
||||
dr.lanes(mode.to_constraints(), map)
|
||||
.get(0)
|
||||
.map(|l| Position::start(*l))
|
||||
});
|
||||
}
|
||||
TripEndpoint::SuddenlyAppear(pos) => {
|
||||
return Some(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.driving_goal(mode.to_constraints(), map)
|
||||
.ok()
|
||||
.and_then(|goal| goal.goal_pos(mode.to_constraints(), map))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a point representing where this endpoint is.
|
||||
pub fn pt(&self, map: &Map) -> Pt2D {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => map.get_b(*b).polygon.center(),
|
||||
TripEndpoint::Border(i) => map.get_i(*i).polygon.center(),
|
||||
TripEndpoint::SuddenlyAppear(pos) => pos.pt(map),
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
154
synthpop/src/endpoint.rs
Normal file
154
synthpop/src/endpoint.rs
Normal file
@ -0,0 +1,154 @@
|
||||
use geom::Pt2D;
|
||||
use map_model::{BuildingID, IntersectionID, Map, PathConstraints, PathRequest, Position};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::TripMode;
|
||||
|
||||
/// Specifies where a trip begins or ends.
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
|
||||
pub enum TripEndpoint {
|
||||
Bldg(BuildingID),
|
||||
Border(IntersectionID),
|
||||
/// Used for interactive spawning, tests, etc. For now, only valid as a trip's start.
|
||||
SuddenlyAppear(Position),
|
||||
}
|
||||
|
||||
impl TripEndpoint {
|
||||
/// Returns a point representing where this endpoint is.
|
||||
pub fn pt(self, map: &Map) -> Pt2D {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => map.get_b(b).polygon.center(),
|
||||
TripEndpoint::Border(i) => map.get_i(i).polygon.center(),
|
||||
TripEndpoint::SuddenlyAppear(pos) => pos.pt(map),
|
||||
}
|
||||
}
|
||||
|
||||
/// Figure out a single PathRequest that goes between two TripEndpoints. Assume a single mode
|
||||
/// the entire time -- no walking to a car before driving, for instance. The result probably
|
||||
/// won't be exactly what would happen on a real trip between the endpoints because of this
|
||||
/// assumption.
|
||||
pub fn path_req(
|
||||
from: TripEndpoint,
|
||||
to: TripEndpoint,
|
||||
mode: TripMode,
|
||||
map: &Map,
|
||||
) -> Option<PathRequest> {
|
||||
let start = from.pos(mode, true, map)?;
|
||||
let end = to.pos(mode, false, map)?;
|
||||
Some(match mode {
|
||||
TripMode::Walk | TripMode::Transit => PathRequest::walking(start, end),
|
||||
TripMode::Bike => PathRequest::vehicle(start, end, PathConstraints::Bike),
|
||||
// Only cars leaving from a building might turn out from the driveway in a special way
|
||||
TripMode::Drive => {
|
||||
if matches!(from, TripEndpoint::Bldg(_)) {
|
||||
PathRequest::leave_from_driveway(start, end, PathConstraints::Car, map)
|
||||
} else {
|
||||
PathRequest::vehicle(start, end, PathConstraints::Car)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn pos(self, mode: TripMode, from: bool, map: &Map) -> Option<Position> {
|
||||
match mode {
|
||||
TripMode::Walk | TripMode::Transit => self.sidewalk_pos(map, from),
|
||||
TripMode::Drive | TripMode::Bike => {
|
||||
let constraints = mode.to_constraints();
|
||||
if from {
|
||||
match self {
|
||||
// Fall through
|
||||
TripEndpoint::Bldg(_) => {}
|
||||
TripEndpoint::Border(i) => {
|
||||
return map.get_i(i).some_outgoing_road(map).and_then(|dr| {
|
||||
dr.lanes(constraints, map)
|
||||
.get(0)
|
||||
.map(|l| Position::start(*l))
|
||||
});
|
||||
}
|
||||
TripEndpoint::SuddenlyAppear(pos) => {
|
||||
return Some(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => match constraints {
|
||||
PathConstraints::Car => {
|
||||
let driving_lane = map.find_driving_lane_near_building(b);
|
||||
let sidewalk_pos = map.get_b(b).sidewalk_pos;
|
||||
if driving_lane.road == sidewalk_pos.lane().road {
|
||||
Some(sidewalk_pos.equiv_pos(driving_lane, map))
|
||||
} else {
|
||||
Some(Position::start(driving_lane))
|
||||
}
|
||||
}
|
||||
PathConstraints::Bike => Some(map.get_b(b).biking_connection(map)?.0),
|
||||
PathConstraints::Bus
|
||||
| PathConstraints::Train
|
||||
| PathConstraints::Pedestrian => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
TripEndpoint::Border(i) => {
|
||||
map.get_i(i).some_incoming_road(map).and_then(|dr| {
|
||||
let lanes = dr.lanes(constraints, map);
|
||||
if lanes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
// TODO ideally could use any
|
||||
Some(Position::end(lanes[0], map))
|
||||
}
|
||||
})
|
||||
}
|
||||
TripEndpoint::SuddenlyAppear(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sidewalk_pos(self, map: &Map, from: bool) -> Option<Position> {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => Some(map.get_b(b).sidewalk_pos),
|
||||
TripEndpoint::Border(i) => {
|
||||
if from {
|
||||
TripEndpoint::start_walking_at_border(i, map)
|
||||
} else {
|
||||
TripEndpoint::end_walking_at_border(i, map)
|
||||
}
|
||||
}
|
||||
TripEndpoint::SuddenlyAppear(pos) => Some(pos),
|
||||
}
|
||||
}
|
||||
|
||||
// Recall sidewalks are bidirectional.
|
||||
pub fn start_walking_at_border(i: IntersectionID, map: &Map) -> Option<Position> {
|
||||
let lanes = map
|
||||
.get_i(i)
|
||||
.get_outgoing_lanes(map, PathConstraints::Pedestrian);
|
||||
if !lanes.is_empty() {
|
||||
return Some(Position::start(lanes[0]));
|
||||
}
|
||||
map.get_i(i)
|
||||
.get_incoming_lanes(map, PathConstraints::Pedestrian)
|
||||
.get(0)
|
||||
.map(|l| Position::end(*l, map))
|
||||
}
|
||||
|
||||
pub fn end_walking_at_border(i: IntersectionID, map: &Map) -> Option<Position> {
|
||||
if let Some(l) = map
|
||||
.get_i(i)
|
||||
.get_incoming_lanes(map, PathConstraints::Pedestrian)
|
||||
.get(0)
|
||||
{
|
||||
return Some(Position::end(*l, map));
|
||||
}
|
||||
|
||||
let lanes = map
|
||||
.get_i(i)
|
||||
.get_outgoing_lanes(map, PathConstraints::Pedestrian);
|
||||
if lanes.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(Position::start(lanes[0]))
|
||||
}
|
||||
}
|
@ -6,25 +6,18 @@ extern crate log;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use abstutil::{deserialize_usize, serialize_usize};
|
||||
use map_model::{BuildingID, IntersectionID, PathConstraints, Position};
|
||||
use map_model::PathConstraints;
|
||||
|
||||
pub use self::endpoint::TripEndpoint;
|
||||
pub use self::external::{ExternalPerson, ExternalTrip, ExternalTripEndpoint, MapBorders};
|
||||
pub use self::modifier::ScenarioModifier;
|
||||
pub use self::scenario::{IndividTrip, PersonSpec, Scenario, TripPurpose};
|
||||
|
||||
mod endpoint;
|
||||
mod external;
|
||||
mod modifier;
|
||||
mod scenario;
|
||||
|
||||
/// Specifies where a trip begins or ends.
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
|
||||
pub enum TripEndpoint {
|
||||
Bldg(BuildingID),
|
||||
Border(IntersectionID),
|
||||
/// Used for interactive spawning, tests, etc. For now, only valid as a trip's start.
|
||||
SuddenlyAppear(Position),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)]
|
||||
pub enum TripMode {
|
||||
Walk,
|
||||
|
Loading…
Reference in New Issue
Block a user