mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
one key to toggle lane types
This commit is contained in:
parent
e71fa25229
commit
7363302d5d
@ -1,6 +1,6 @@
|
||||
use crate::objects::{EDIT_MAP, ID};
|
||||
use crate::plugins::{Plugin, PluginCtx};
|
||||
use map_model::{EditReason, LaneID, LaneType};
|
||||
use map_model::{EditReason, Lane, LaneID, LaneType, MapEdits, Road};
|
||||
use piston::input::Key;
|
||||
|
||||
pub struct RoadEditor {}
|
||||
@ -20,93 +20,89 @@ impl RoadEditor {
|
||||
|
||||
impl Plugin for RoadEditor {
|
||||
fn blocking_event(&mut self, ctx: &mut PluginCtx) -> bool {
|
||||
let (input, selected, map, draw_map, sim) = (
|
||||
&mut ctx.input,
|
||||
ctx.primary.current_selection,
|
||||
&mut ctx.primary.map,
|
||||
&mut ctx.primary.draw_map,
|
||||
&mut ctx.primary.sim,
|
||||
);
|
||||
let mut edits = map.get_edits().clone();
|
||||
|
||||
// TODO a bit awkward that we can't pull this info from edits easily
|
||||
let mut changed: Option<(LaneID, LaneType)> = None;
|
||||
|
||||
if input.key_pressed(Key::Return, "stop editing roads") {
|
||||
if ctx.input.key_pressed(Key::Return, "stop editing roads") {
|
||||
return false;
|
||||
} else if let Some(ID::Lane(id)) = selected {
|
||||
let lane = map.get_l(id);
|
||||
let road = map.get_r(lane.parent);
|
||||
} else if let Some(ID::Lane(id)) = ctx.primary.current_selection {
|
||||
let lane = ctx.primary.map.get_l(id);
|
||||
let road = ctx.primary.map.get_r(lane.parent);
|
||||
let reason = EditReason::BasemapWrong; // TODO be able to choose
|
||||
|
||||
if lane.lane_type != LaneType::Sidewalk {
|
||||
if lane.lane_type != LaneType::Driving
|
||||
&& input.key_pressed(Key::D, "make this a driving lane")
|
||||
if lane.lane_type == LaneType::Sidewalk {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ctx.input.key_pressed(Key::Backspace, "delete this lane") {
|
||||
let mut edits = ctx.primary.map.get_edits().clone();
|
||||
edits.delete_lane(road, lane);
|
||||
warn!("Have to reload the map from scratch to pick up this change!");
|
||||
ctx.primary.map.store_new_edits(edits);
|
||||
} else if let Some(new_type) = next_valid_type(ctx.primary.map.get_edits(), road, lane)
|
||||
{
|
||||
if ctx
|
||||
.input
|
||||
.key_pressed(Key::Space, &format!("toggle to {:?}", new_type))
|
||||
{
|
||||
if edits.change_lane_type(reason, road, lane, LaneType::Driving) {
|
||||
changed = Some((lane.id, LaneType::Driving));
|
||||
}
|
||||
}
|
||||
if lane.lane_type != LaneType::Parking
|
||||
&& input.key_pressed(Key::P, "make this a parking lane")
|
||||
{
|
||||
if edits.change_lane_type(reason, road, lane, LaneType::Parking) {
|
||||
changed = Some((lane.id, LaneType::Parking));
|
||||
}
|
||||
}
|
||||
if lane.lane_type != LaneType::Biking
|
||||
&& input.key_pressed(Key::B, "make this a bike lane")
|
||||
{
|
||||
if edits.change_lane_type(reason, road, lane, LaneType::Biking) {
|
||||
changed = Some((lane.id, LaneType::Biking));
|
||||
}
|
||||
}
|
||||
if lane.lane_type != LaneType::Bus
|
||||
&& input.key_pressed(Key::U, "make this a bus lane")
|
||||
{
|
||||
if edits.change_lane_type(reason, road, lane, LaneType::Bus) {
|
||||
changed = Some((lane.id, LaneType::Bus));
|
||||
}
|
||||
}
|
||||
if input.key_pressed(Key::Backspace, "delete this lane") {
|
||||
if edits.delete_lane(road, lane) {
|
||||
warn!("Have to reload the map from scratch to pick up this change!");
|
||||
}
|
||||
let mut edits = ctx.primary.map.get_edits().clone();
|
||||
edits.change_lane_type(reason, road, lane, new_type);
|
||||
change_lane_type(lane.id, new_type, ctx);
|
||||
ctx.primary.map.store_new_edits(edits);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some((id, new_type)) = changed {
|
||||
let intersections = map.get_l(id).intersections();
|
||||
|
||||
// TODO generally tense about having two methods to carry out this change. weird
|
||||
// intermediate states are scary. maybe pass old and new struct for intersection (aka
|
||||
// list of turns)?
|
||||
|
||||
// Remove turns
|
||||
for i in &intersections {
|
||||
for t in &map.get_i(*i).turns {
|
||||
draw_map.edit_remove_turn(*t);
|
||||
sim.edit_remove_turn(map.get_t(*t));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Pretty sure control layer needs to recalculate based on the new turns
|
||||
let old_type = map.get_l(id).lane_type;
|
||||
map.edit_lane_type(id, new_type);
|
||||
draw_map.edit_lane_type(id, map);
|
||||
sim.edit_lane_type(id, old_type, map);
|
||||
|
||||
// Add turns back
|
||||
for i in &intersections {
|
||||
for t in &map.get_i(*i).turns {
|
||||
draw_map.edit_add_turn(*t, map);
|
||||
sim.edit_add_turn(map.get_t(*t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map.store_new_edits(edits);
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn next_valid_type(edits: &MapEdits, r: &Road, lane: &Lane) -> Option<LaneType> {
|
||||
let mut new_type = next_type(lane.lane_type);
|
||||
while new_type != lane.lane_type {
|
||||
if edits.can_change_lane_type(r, lane, new_type) {
|
||||
return Some(new_type);
|
||||
}
|
||||
new_type = next_type(new_type);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn next_type(lt: LaneType) -> LaneType {
|
||||
match lt {
|
||||
LaneType::Driving => LaneType::Parking,
|
||||
LaneType::Parking => LaneType::Biking,
|
||||
LaneType::Biking => LaneType::Bus,
|
||||
LaneType::Bus => LaneType::Driving,
|
||||
|
||||
LaneType::Sidewalk => panic!("next_type(Sidewalk) undefined; can't modify sidewalks"),
|
||||
}
|
||||
}
|
||||
|
||||
fn change_lane_type(id: LaneID, new_type: LaneType, ctx: &mut PluginCtx) {
|
||||
let intersections = ctx.primary.map.get_l(id).intersections();
|
||||
|
||||
// TODO generally tense about having two methods to carry out this change. weird intermediate
|
||||
// states are scary. maybe pass old and new struct for intersection (aka list of turns)?
|
||||
|
||||
// Remove turns
|
||||
for i in &intersections {
|
||||
for t in &ctx.primary.map.get_i(*i).turns {
|
||||
ctx.primary.draw_map.edit_remove_turn(*t);
|
||||
ctx.primary.sim.edit_remove_turn(ctx.primary.map.get_t(*t));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Pretty sure control layer needs to recalculate based on the new turns
|
||||
let old_type = ctx.primary.map.get_l(id).lane_type;
|
||||
ctx.primary.map.edit_lane_type(id, new_type);
|
||||
ctx.primary.draw_map.edit_lane_type(id, &ctx.primary.map);
|
||||
ctx.primary
|
||||
.sim
|
||||
.edit_lane_type(id, old_type, &ctx.primary.map);
|
||||
|
||||
// Add turns back
|
||||
for i in &intersections {
|
||||
for t in &ctx.primary.map.get_i(*i).turns {
|
||||
ctx.primary.draw_map.edit_add_turn(*t, &ctx.primary.map);
|
||||
ctx.primary.sim.edit_add_turn(ctx.primary.map.get_t(*t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,26 +40,23 @@ impl MapEdits {
|
||||
abstutil::save_object("edits", &self.map_name, &self.edits_name, self);
|
||||
}
|
||||
|
||||
pub fn can_change_lane_type(&self, r: &Road, lane: &Lane, new_type: LaneType) -> bool {
|
||||
RoadEdit::change_lane_type(EditReason::BasemapWrong, r, lane, new_type).is_some()
|
||||
}
|
||||
|
||||
pub fn change_lane_type(
|
||||
&mut self,
|
||||
reason: EditReason,
|
||||
r: &Road,
|
||||
lane: &Lane,
|
||||
new_type: LaneType,
|
||||
) -> bool {
|
||||
if let Some(edit) = RoadEdit::change_lane_type(reason, r, lane, new_type) {
|
||||
self.roads.insert(r.id, edit);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
) {
|
||||
let edit = RoadEdit::change_lane_type(reason, r, lane, new_type).unwrap();
|
||||
self.roads.insert(r.id, edit);
|
||||
}
|
||||
|
||||
pub fn delete_lane(&mut self, r: &Road, lane: &Lane) -> bool {
|
||||
if let Some(edit) = RoadEdit::delete_lane(r, lane) {
|
||||
self.roads.insert(r.id, edit);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
pub fn delete_lane(&mut self, r: &Road, lane: &Lane) {
|
||||
self.roads.insert(r.id, RoadEdit::delete_lane(r, lane));
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +75,6 @@ pub struct RoadEdit {
|
||||
}
|
||||
|
||||
impl RoadEdit {
|
||||
// TODO return Result, so we can enforce a reason coming back!
|
||||
fn change_lane_type(
|
||||
reason: EditReason,
|
||||
r: &Road,
|
||||
@ -86,16 +82,14 @@ impl RoadEdit {
|
||||
new_type: LaneType,
|
||||
) -> Option<RoadEdit> {
|
||||
if lane.is_sidewalk() {
|
||||
error!("Sidewalks are fixed; can't change their type");
|
||||
return None;
|
||||
panic!("Sidewalks are fixed; can't change their type");
|
||||
}
|
||||
|
||||
let (mut forwards, mut backwards) = r.get_lane_types();
|
||||
let (is_fwd, idx) = r.dir_and_offset(lane.id);
|
||||
if is_fwd {
|
||||
if forwards[idx] == new_type {
|
||||
error!("{} is already {:?}", lane.id, new_type);
|
||||
return None;
|
||||
panic!("{} is already {:?}", lane.id, new_type);
|
||||
}
|
||||
forwards[idx] = new_type;
|
||||
if !are_lanes_valid(&forwards) {
|
||||
@ -103,8 +97,7 @@ impl RoadEdit {
|
||||
}
|
||||
} else {
|
||||
if backwards[idx] == new_type {
|
||||
error!("{} is already {:?}", lane.id, new_type);
|
||||
return None;
|
||||
panic!("{} is already {:?}", lane.id, new_type);
|
||||
}
|
||||
backwards[idx] = new_type;
|
||||
if !are_lanes_valid(&backwards) {
|
||||
@ -120,11 +113,9 @@ impl RoadEdit {
|
||||
})
|
||||
}
|
||||
|
||||
fn delete_lane(r: &Road, lane: &Lane) -> Option<RoadEdit> {
|
||||
// Sidewalks are fixed
|
||||
fn delete_lane(r: &Road, lane: &Lane) -> RoadEdit {
|
||||
if lane.is_sidewalk() {
|
||||
error!("Can't delete sidewalks");
|
||||
return None;
|
||||
panic!("Can't delete sidewalks");
|
||||
}
|
||||
|
||||
let (mut forwards, mut backwards) = r.get_lane_types();
|
||||
@ -135,12 +126,12 @@ impl RoadEdit {
|
||||
backwards.remove(idx);
|
||||
}
|
||||
|
||||
Some(RoadEdit {
|
||||
RoadEdit {
|
||||
road: r.id,
|
||||
forwards_lanes: forwards,
|
||||
backwards_lanes: backwards,
|
||||
reason: EditReason::BasemapWrong,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user