be able to start and end bike trips on bike lanes. use driving

blackholes for now.
This commit is contained in:
Dustin Carlino 2019-11-19 13:52:36 -08:00
parent ade23dac5f
commit ba2206d02a
10 changed files with 95 additions and 22 deletions

View File

@ -33,9 +33,11 @@ will eventually shift mode or take different trips altogether. Not attempting
any of that yet -- just using PSRC trips. I don't understand the demand modeling
process well at all yet.
## Bikes using bus lanes
## Bike/bus lane connectivity
This should be pretty easy to allow.
Bikes and buses can make crazy left turns from the rightmost protected lane.
Alternatively, stop generating those turns and start generating turns between
protected and general lanes.
## Parking

View File

@ -37,6 +37,7 @@
- https://www.the74million.org/article/building-a-smarter-and-cheaper-school-bus-system-how-a-boston-mit-partnership-led-to-new-routes-that-are-20-more-efficient-use-400-fewer-buses-save-5-million/
- https://www.citylab.com/perspective/2019/10/micromobility-urban-design-car-free-infrastruture-futurama/600163/
- https://www.sanjorn.com/
- https://ui.kpf.com/
## Similar projects

View File

@ -96,7 +96,8 @@ impl AgentSpawner {
maybe_goal: None,
}));
}
// TODO First lane might be a bike lane! Need to pass PathConstraints.
}
if let Some(pos) = Position::bldg_via_biking(id, map) {
if ctx
.input
.contextual_action(Key::F7, "spawn a bike starting here")
@ -198,8 +199,7 @@ impl State for AgentSpawner {
if constraints == PathConstraints::Pedestrian {
Position::bldg_via_walking(to, map)
} else {
// TODO Specify biking maybe
DrivingGoal::ParkNear(to).goal_pos(map)
DrivingGoal::ParkNear(to).goal_pos(constraints, map)
}
}
Goal::Border(to) => {
@ -208,7 +208,7 @@ impl State for AgentSpawner {
constraints,
map,
) {
g.goal_pos(map)
g.goal_pos(constraints, map)
} else {
self.maybe_goal = None;
return Transition::Keep;

View File

@ -404,7 +404,7 @@ fn calculate_bike_network(ctx: &EventCtx, ui: &UI) -> RoadColorer {
fn calculate_bus_network(ctx: &EventCtx, ui: &UI) -> RoadColorer {
let mut colorer = RoadColorerBuilder::new(
Text::prompt("bus networks"),
vec![("bike lanes", Color::GREEN)],
vec![("bus lanes", Color::GREEN)],
);
for l in ui.primary.map.all_lanes() {
if l.is_bus() {

View File

@ -531,6 +531,56 @@ impl Map {
}
}
// TODO Refactor and also use a different blackhole measure
pub fn find_biking_lane_near_building(&self, b: BuildingID) -> LaneID {
if let Ok(l) = self.find_closest_lane(self.get_b(b).sidewalk(), vec![LaneType::Biking]) {
return self.get_l(l).parking_blackhole.unwrap_or(l);
}
if let Ok(l) = self.find_closest_lane(self.get_b(b).sidewalk(), vec![LaneType::Driving]) {
return self.get_l(l).parking_blackhole.unwrap_or(l);
}
let mut roads_queue: VecDeque<RoadID> = VecDeque::new();
let mut visited: HashSet<RoadID> = HashSet::new();
{
let start = self.building_to_road(b).id;
roads_queue.push_back(start);
visited.insert(start);
}
loop {
if roads_queue.is_empty() {
panic!(
"Giving up looking for a biking or driving lane near {}, searched {} roads: {:?}",
b,
visited.len(),
visited
);
}
let r = self.get_r(roads_queue.pop_front().unwrap());
for (lane, lane_type) in r
.children_forwards
.iter()
.chain(r.children_backwards.iter())
{
if *lane_type == LaneType::Biking {
return self.get_l(*lane).parking_blackhole.unwrap_or(*lane);
}
if *lane_type == LaneType::Driving {
return self.get_l(*lane).parking_blackhole.unwrap_or(*lane);
}
}
for next_r in self.get_next_roads(r.id).into_iter() {
if !visited.contains(&next_r) {
roads_queue.push_back(next_r);
visited.insert(next_r);
}
}
}
}
pub fn get_boundary_polygon(&self) -> &Polygon {
&self.boundary_polygon
}

View File

@ -79,7 +79,8 @@ impl VehiclePathfinder {
req.end.dist_along(),
Distance::centimeters(raw_path.get_weight()),
);
if self.constraints == PathConstraints::Bike {
// Disabled, because this looks stable now.
if false && self.constraints == PathConstraints::Bike {
check_bike_route(&path, map);
}
Some(path)
@ -176,7 +177,6 @@ pub fn cost(lane: &Lane, turn: &Turn, constraints: PathConstraints, map: &Map) -
}
}
// TODO Temporary, while I'm figuring out why bike lanes aren't always used.
fn check_bike_route(path: &Path, map: &Map) {
let steps: Vec<PathStep> = path.get_steps().iter().cloned().collect();
for pair in steps.windows(2) {

View File

@ -72,6 +72,19 @@ impl Position {
.equiv_pos(driving_lane, Distance::ZERO, map),
)
}
pub fn bldg_via_biking(b: BuildingID, map: &Map) -> Option<Position> {
let bldg = map.get_b(b);
let driving_lane = map
.find_closest_lane(bldg.sidewalk(), vec![LaneType::Biking])
.or_else(|_| map.find_closest_lane(bldg.sidewalk(), vec![LaneType::Driving]))
.ok()?;
Some(
bldg.front_path
.sidewalk
.equiv_pos(driving_lane, Distance::ZERO, map),
)
}
}
// TODO also building paths?

View File

@ -183,6 +183,8 @@ pub struct ParkedCar {
pub spot: ParkingSpot,
}
// It'd be nice to inline the goal_pos like SidewalkSpot does, but DrivingGoal is persisted in
// Scenarios, so this wouldn't survive map edits.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum DrivingGoal {
ParkNear(BuildingID),
@ -204,17 +206,19 @@ impl DrivingGoal {
}
}
// TODO Stick this in the DrivingGoal directly, like SidewalkSpot. Find it upon construction.
pub fn goal_pos(&self, map: &Map) -> Position {
pub fn goal_pos(&self, constraints: PathConstraints, map: &Map) -> Position {
let lane = match self {
// TODO Biking option.
DrivingGoal::ParkNear(b) => map.find_driving_lane_near_building(*b),
DrivingGoal::ParkNear(b) => match constraints {
PathConstraints::Car => map.find_driving_lane_near_building(*b),
PathConstraints::Bike => map.find_biking_lane_near_building(*b),
PathConstraints::Bus | PathConstraints::Pedestrian => unreachable!(),
},
DrivingGoal::Border(_, l) => *l,
};
Position::new(lane, map.get_l(lane).length())
}
pub fn make_router(&self, path: Path, map: &Map, vt: VehicleType) -> Router {
pub(crate) fn make_router(&self, path: Path, map: &Map, vt: VehicleType) -> Router {
match self {
DrivingGoal::ParkNear(b) => {
if vt == VehicleType::Bike {

View File

@ -135,7 +135,7 @@ impl TripSpawner {
return;
}
if let DrivingGoal::ParkNear(_) = goal {
let last_lane = goal.goal_pos(map).lane();
let last_lane = goal.goal_pos(PathConstraints::Bike, map).lane();
// If bike_to_sidewalk works, then SidewalkSpot::bike_rack should too.
if map
.get_parent(last_lane)
@ -475,11 +475,14 @@ impl TripSpec {
vehicle_spec,
goal,
..
} => PathRequest {
} => {
let constraints = vehicle_spec.vehicle_type.to_constraints();
PathRequest {
start: *start_pos,
end: goal.goal_pos(map),
constraints: vehicle_spec.vehicle_type.to_constraints(),
},
end: goal.goal_pos(constraints, map),
constraints,
}
}
TripSpec::UsingParkedCar { start, spot, .. } => PathRequest {
start: start.sidewalk_pos,
end: SidewalkSpot::parking_spot(*spot, map, parking).sidewalk_pos,

View File

@ -191,7 +191,7 @@ impl TripManager {
// Actually, to unpark, the car's front should be where it'll wind up at the end.
start = Position::new(start.lane(), start.dist_along() + parked_car.vehicle.length);
}
let end = drive_to.goal_pos(map);
let end = drive_to.goal_pos(PathConstraints::Car, map);
let path = if let Some(p) = map.pathfind(PathRequest {
start,
end,
@ -243,7 +243,7 @@ impl TripManager {
_ => unreachable!(),
};
let end = drive_to.goal_pos(map);
let end = drive_to.goal_pos(PathConstraints::Bike, map);
let path = if let Some(p) = map.pathfind(PathRequest {
start: driving_pos,
end,