mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
starting a new crate with a JSON schema for traffic signals. exporting
to it.
This commit is contained in:
parent
0f5ab2f410
commit
d44303de5c
@ -15,6 +15,7 @@ members = [
|
|||||||
"precompute",
|
"precompute",
|
||||||
"sim",
|
"sim",
|
||||||
"tests",
|
"tests",
|
||||||
|
"traffic_signals",
|
||||||
]
|
]
|
||||||
|
|
||||||
# See https://doc.rust-lang.org/cargo/reference/profiles.html#overrides. This
|
# See https://doc.rust-lang.org/cargo/reference/profiles.html#overrides. This
|
||||||
|
@ -48,7 +48,7 @@ impl TrafficSignalEditor {
|
|||||||
i: id,
|
i: id,
|
||||||
current_phase: 0,
|
current_phase: 0,
|
||||||
composite: make_diagram(id, 0, app, ctx),
|
composite: make_diagram(id, 0, app, ctx),
|
||||||
top_panel: make_top_panel(false, false, ctx),
|
top_panel: make_top_panel(ctx, app, false, false),
|
||||||
groups: DrawTurnGroup::for_i(id, &app.primary.map),
|
groups: DrawTurnGroup::for_i(id, &app.primary.map),
|
||||||
group_selected: None,
|
group_selected: None,
|
||||||
suspended_sim,
|
suspended_sim,
|
||||||
@ -158,7 +158,7 @@ impl State for TrafficSignalEditor {
|
|||||||
phase.edit_group(&orig_signal.turn_groups[&id], pri);
|
phase.edit_group(&orig_signal.turn_groups[&id], pri);
|
||||||
self.command_stack.push(orig_signal.clone());
|
self.command_stack.push(orig_signal.clone());
|
||||||
self.redo_stack.clear();
|
self.redo_stack.clear();
|
||||||
self.top_panel = make_top_panel(true, false, ctx);
|
self.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
self.change_phase(self.current_phase, app, ctx);
|
self.change_phase(self.current_phase, app, ctx);
|
||||||
return Transition::Keep;
|
return Transition::Keep;
|
||||||
@ -176,6 +176,9 @@ impl State for TrafficSignalEditor {
|
|||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
"Export" => {
|
||||||
|
orig_signal.export(&app.primary.map);
|
||||||
|
}
|
||||||
"Preview" => {
|
"Preview" => {
|
||||||
// Might have to do this first!
|
// Might have to do this first!
|
||||||
app.primary
|
app.primary
|
||||||
@ -192,14 +195,14 @@ impl State for TrafficSignalEditor {
|
|||||||
"undo" => {
|
"undo" => {
|
||||||
self.redo_stack.push(orig_signal.clone());
|
self.redo_stack.push(orig_signal.clone());
|
||||||
change_traffic_signal(self.command_stack.pop().unwrap(), app, ctx);
|
change_traffic_signal(self.command_stack.pop().unwrap(), app, ctx);
|
||||||
self.top_panel = make_top_panel(!self.command_stack.is_empty(), true, ctx);
|
self.top_panel = make_top_panel(ctx, app, !self.command_stack.is_empty(), true);
|
||||||
self.change_phase(0, app, ctx);
|
self.change_phase(0, app, ctx);
|
||||||
return Transition::Keep;
|
return Transition::Keep;
|
||||||
}
|
}
|
||||||
"redo" => {
|
"redo" => {
|
||||||
self.command_stack.push(orig_signal.clone());
|
self.command_stack.push(orig_signal.clone());
|
||||||
change_traffic_signal(self.redo_stack.pop().unwrap(), app, ctx);
|
change_traffic_signal(self.redo_stack.pop().unwrap(), app, ctx);
|
||||||
self.top_panel = make_top_panel(true, !self.redo_stack.is_empty(), ctx);
|
self.top_panel = make_top_panel(ctx, app, true, !self.redo_stack.is_empty());
|
||||||
self.change_phase(0, app, ctx);
|
self.change_phase(0, app, ctx);
|
||||||
return Transition::Keep;
|
return Transition::Keep;
|
||||||
}
|
}
|
||||||
@ -289,8 +292,9 @@ impl State for TrafficSignalEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_top_panel(can_undo: bool, can_redo: bool, ctx: &mut EventCtx) -> Composite {
|
fn make_top_panel(ctx: &mut EventCtx, app: &App, can_undo: bool, can_redo: bool) -> Composite {
|
||||||
let row = vec![
|
let mut row = vec![
|
||||||
|
WrappedComposite::text_button(ctx, "Finish", hotkey(Key::Escape)),
|
||||||
WrappedComposite::text_button(ctx, "Finish", hotkey(Key::Escape)),
|
WrappedComposite::text_button(ctx, "Finish", hotkey(Key::Escape)),
|
||||||
WrappedComposite::text_button(ctx, "Preview", lctrl(Key::P)),
|
WrappedComposite::text_button(ctx, "Preview", lctrl(Key::P)),
|
||||||
(if can_undo {
|
(if can_undo {
|
||||||
@ -325,6 +329,9 @@ fn make_top_panel(can_undo: bool, can_redo: bool, ctx: &mut EventCtx) -> Composi
|
|||||||
})
|
})
|
||||||
.margin(15),
|
.margin(15),
|
||||||
];
|
];
|
||||||
|
if app.opts.dev {
|
||||||
|
row.push(WrappedComposite::text_button(ctx, "Export", None));
|
||||||
|
}
|
||||||
Composite::new(ManagedWidget::row(row).bg(colors::PANEL_BG))
|
Composite::new(ManagedWidget::row(row).bg(colors::PANEL_BG))
|
||||||
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
|
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
|
||||||
.build(ctx)
|
.build(ctx)
|
||||||
@ -521,7 +528,7 @@ fn edit_entire_signal(app: &App, i: IntersectionID, suspended_sim: Sim) -> Box<d
|
|||||||
.command_stack
|
.command_stack
|
||||||
.push(app.primary.map.get_traffic_signal(editor.i).clone());
|
.push(app.primary.map.get_traffic_signal(editor.i).clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
editor.change_phase(0, app, ctx);
|
editor.change_phase(0, app, ctx);
|
||||||
})))
|
})))
|
||||||
@ -534,7 +541,7 @@ fn edit_entire_signal(app: &App, i: IntersectionID, suspended_sim: Sim) -> Box<d
|
|||||||
if new_signal.convert_to_ped_scramble() {
|
if new_signal.convert_to_ped_scramble() {
|
||||||
editor.command_stack.push(orig_signal.clone());
|
editor.command_stack.push(orig_signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
editor.change_phase(0, app, ctx);
|
editor.change_phase(0, app, ctx);
|
||||||
}
|
}
|
||||||
@ -566,7 +573,7 @@ fn edit_entire_signal(app: &App, i: IntersectionID, suspended_sim: Sim) -> Box<d
|
|||||||
let mut signal = app.primary.map.get_traffic_signal(editor.i).clone();
|
let mut signal = app.primary.map.get_traffic_signal(editor.i).clone();
|
||||||
editor.command_stack.push(signal.clone());
|
editor.command_stack.push(signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
signal.offset = Duration::seconds(new_duration as f64);
|
signal.offset = Duration::seconds(new_duration as f64);
|
||||||
change_traffic_signal(signal, app, ctx);
|
change_traffic_signal(signal, app, ctx);
|
||||||
editor.change_phase(editor.current_phase, app, ctx);
|
editor.change_phase(editor.current_phase, app, ctx);
|
||||||
@ -582,7 +589,7 @@ fn edit_entire_signal(app: &App, i: IntersectionID, suspended_sim: Sim) -> Box<d
|
|||||||
.1;
|
.1;
|
||||||
editor.command_stack.push(orig_signal.clone());
|
editor.command_stack.push(orig_signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
// Don't use change_phase; it tries to preserve scroll
|
// Don't use change_phase; it tries to preserve scroll
|
||||||
editor.current_phase = 0;
|
editor.current_phase = 0;
|
||||||
@ -639,7 +646,7 @@ fn edit_phase(app: &App, i: IntersectionID, idx: usize) -> Box<dyn State> {
|
|||||||
new_signal.phases[idx].duration = Duration::seconds(new_duration as f64);
|
new_signal.phases[idx].duration = Duration::seconds(new_duration as f64);
|
||||||
editor.command_stack.push(orig_signal.clone());
|
editor.command_stack.push(orig_signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
editor.change_phase(idx, app, ctx);
|
editor.change_phase(idx, app, ctx);
|
||||||
})))
|
})))
|
||||||
@ -653,7 +660,7 @@ fn edit_phase(app: &App, i: IntersectionID, idx: usize) -> Box<dyn State> {
|
|||||||
new_signal.phases.insert(idx, Phase::new());
|
new_signal.phases.insert(idx, Phase::new());
|
||||||
editor.command_stack.push(orig_signal.clone());
|
editor.command_stack.push(orig_signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
editor.change_phase(idx, app, ctx);
|
editor.change_phase(idx, app, ctx);
|
||||||
})))
|
})))
|
||||||
@ -667,7 +674,7 @@ fn edit_phase(app: &App, i: IntersectionID, idx: usize) -> Box<dyn State> {
|
|||||||
new_signal.phases.insert(idx + 1, Phase::new());
|
new_signal.phases.insert(idx + 1, Phase::new());
|
||||||
editor.command_stack.push(orig_signal.clone());
|
editor.command_stack.push(orig_signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
editor.change_phase(idx + 1, app, ctx);
|
editor.change_phase(idx + 1, app, ctx);
|
||||||
})))
|
})))
|
||||||
@ -680,7 +687,7 @@ fn edit_phase(app: &App, i: IntersectionID, idx: usize) -> Box<dyn State> {
|
|||||||
new_signal.phases.swap(idx, idx - 1);
|
new_signal.phases.swap(idx, idx - 1);
|
||||||
editor.command_stack.push(orig_signal.clone());
|
editor.command_stack.push(orig_signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
editor.change_phase(idx - 1, app, ctx);
|
editor.change_phase(idx - 1, app, ctx);
|
||||||
}))),
|
}))),
|
||||||
@ -693,7 +700,7 @@ fn edit_phase(app: &App, i: IntersectionID, idx: usize) -> Box<dyn State> {
|
|||||||
new_signal.phases.swap(idx, idx + 1);
|
new_signal.phases.swap(idx, idx + 1);
|
||||||
editor.command_stack.push(orig_signal.clone());
|
editor.command_stack.push(orig_signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
editor.change_phase(idx + 1, app, ctx);
|
editor.change_phase(idx + 1, app, ctx);
|
||||||
})))
|
})))
|
||||||
@ -708,7 +715,7 @@ fn edit_phase(app: &App, i: IntersectionID, idx: usize) -> Box<dyn State> {
|
|||||||
let num_phases = new_signal.phases.len();
|
let num_phases = new_signal.phases.len();
|
||||||
editor.command_stack.push(orig_signal.clone());
|
editor.command_stack.push(orig_signal.clone());
|
||||||
editor.redo_stack.clear();
|
editor.redo_stack.clear();
|
||||||
editor.top_panel = make_top_panel(true, false, ctx);
|
editor.top_panel = make_top_panel(ctx, app, true, false);
|
||||||
change_traffic_signal(new_signal, app, ctx);
|
change_traffic_signal(new_signal, app, ctx);
|
||||||
// Don't use change_phase; it tries to preserve scroll
|
// Don't use change_phase; it tries to preserve scroll
|
||||||
editor.current_phase = if idx == num_phases { idx - 1 } else { idx };
|
editor.current_phase = if idx == num_phases { idx - 1 } else { idx };
|
||||||
|
@ -15,3 +15,4 @@ petgraph = "0.4.13"
|
|||||||
serde = "1.0.89"
|
serde = "1.0.89"
|
||||||
serde_derive = "1.0.98"
|
serde_derive = "1.0.98"
|
||||||
thread_local = "0.3.6"
|
thread_local = "0.3.6"
|
||||||
|
traffic_signals = { path = "../traffic_signals" }
|
||||||
|
@ -616,3 +616,56 @@ fn make_phases(
|
|||||||
|
|
||||||
phases
|
phases
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ControlTrafficSignal {
|
||||||
|
pub fn export(&self, map: &Map) {
|
||||||
|
let ts = traffic_signals::TrafficSignal {
|
||||||
|
intersection_osm_node_id: map.get_i(self.id).orig_id.osm_node_id,
|
||||||
|
phases: self
|
||||||
|
.phases
|
||||||
|
.iter()
|
||||||
|
.map(|p| traffic_signals::Phase {
|
||||||
|
protected_turns: p
|
||||||
|
.protected_groups
|
||||||
|
.iter()
|
||||||
|
.map(|t| export_turn_group(t, map))
|
||||||
|
.collect(),
|
||||||
|
permitted_turns: p
|
||||||
|
.yield_groups
|
||||||
|
.iter()
|
||||||
|
.map(|t| export_turn_group(t, map))
|
||||||
|
.collect(),
|
||||||
|
duration_seconds: p.duration.inner_seconds() as usize,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
offset_seconds: self.offset.inner_seconds() as usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
abstutil::write_json(
|
||||||
|
format!("traffic_signal_data/{}.json", ts.intersection_osm_node_id),
|
||||||
|
&ts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn export_turn_group(id: &TurnGroupID, map: &Map) -> traffic_signals::Turn {
|
||||||
|
let from = map.get_r(id.from.id).orig_id;
|
||||||
|
let to = map.get_r(id.to.id).orig_id;
|
||||||
|
|
||||||
|
traffic_signals::Turn {
|
||||||
|
from: traffic_signals::DirectedRoad {
|
||||||
|
osm_way_id: from.osm_way_id,
|
||||||
|
osm_node1: from.i1.osm_node_id,
|
||||||
|
osm_node2: from.i2.osm_node_id,
|
||||||
|
is_forwards: id.from.forwards,
|
||||||
|
},
|
||||||
|
to: traffic_signals::DirectedRoad {
|
||||||
|
osm_way_id: to.osm_way_id,
|
||||||
|
osm_node1: to.i1.osm_node_id,
|
||||||
|
osm_node2: to.i2.osm_node_id,
|
||||||
|
is_forwards: id.to.forwards,
|
||||||
|
},
|
||||||
|
intersection_osm_node_id: map.get_i(id.parent).orig_id.osm_node_id,
|
||||||
|
is_crosswalk: id.crosswalk,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
11
traffic_signals/Cargo.toml
Normal file
11
traffic_signals/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "traffic_signals"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Dustin Carlino <dabreegster@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
include_dir = "0.5.0"
|
||||||
|
serde = "1.0.89"
|
||||||
|
serde_derive = "1.0.98"
|
||||||
|
serde_json = "1.0.40"
|
11
traffic_signals/README.md
Normal file
11
traffic_signals/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Traffic signal mapping
|
||||||
|
|
||||||
|
## Using the data
|
||||||
|
|
||||||
|
You can conveniently import in Rust by depending on the crate.
|
||||||
|
|
||||||
|
Or...
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The minimal code in this repository are Apache licensed. The data collected are [ODbL](https://www.openstreetmap.org/copyright), the same as OpenStreetMap.
|
404
traffic_signals/data/53219808.json
Normal file
404
traffic_signals/data/53219808.json
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
{
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"phases": [
|
||||||
|
{
|
||||||
|
"protected_turns": [
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"permitted_turns": [
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration_seconds": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"protected_turns": [
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"permitted_turns": [
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 53084814,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53219808,
|
||||||
|
"osm_node2": 1709143541,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": {
|
||||||
|
"osm_way_id": 149669465,
|
||||||
|
"osm_node1": 53231631,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": true
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"osm_way_id": 6470476,
|
||||||
|
"osm_node1": 53128048,
|
||||||
|
"osm_node2": 53219808,
|
||||||
|
"is_forwards": false
|
||||||
|
},
|
||||||
|
"intersection_osm_node_id": 53219808,
|
||||||
|
"is_crosswalk": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration_seconds": 15
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"offset_seconds": 0
|
||||||
|
}
|
73
traffic_signals/src/lib.rs
Normal file
73
traffic_signals/src/lib.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct TrafficSignal {
|
||||||
|
/// The ID of the OSM node representing the intersection with the traffic signal. This node
|
||||||
|
/// should be tagged `highway = traffic_signals` in OSM.
|
||||||
|
pub intersection_osm_node_id: i64,
|
||||||
|
/// The traffic signal repeatedly cycles through these phases. During each phase, only some
|
||||||
|
/// turns are protected and permitted through the intersection.
|
||||||
|
pub phases: Vec<Phase>,
|
||||||
|
// TODO What should this be relative to?
|
||||||
|
pub offset_seconds: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Phase {
|
||||||
|
/// During this phase, these turns can be performed with the highest priority, protected by a
|
||||||
|
/// green light. No two protected turns in the same phase should cross; that would be a
|
||||||
|
/// conflict.
|
||||||
|
pub protected_turns: BTreeSet<Turn>,
|
||||||
|
/// During this phase, these turns can be performed after yielding. For example, an unprotected
|
||||||
|
/// left turn after yielding to oncoming traffic, or a right turn on red after yielding to
|
||||||
|
/// oncoming traffic and crosswalks.
|
||||||
|
pub permitted_turns: BTreeSet<Turn>,
|
||||||
|
/// The phase lasts this long before moving to the next one.
|
||||||
|
pub duration_seconds: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A movement through an intersection.
|
||||||
|
///
|
||||||
|
/// TODO Diagram of the 4 crosswalk cases.
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Turn {
|
||||||
|
/// The movement begins at the end of this road segment.
|
||||||
|
pub from: DirectedRoad,
|
||||||
|
/// The movement ends at the beginning of this road segment.
|
||||||
|
pub to: DirectedRoad,
|
||||||
|
/// The ID of the OSM node representing the intersection. This is redundant for turns performed
|
||||||
|
/// by vehicles, but is necessary for disambiguating the 4 cases of crosswalks.
|
||||||
|
pub intersection_osm_node_id: i64,
|
||||||
|
/// True iff the movement is along a crosswalk. Note that moving over a crosswalk has a
|
||||||
|
/// different `Turn` for each direction.
|
||||||
|
pub is_crosswalk: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A road segment connecting two intersections, and a direction along the segment.
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct DirectedRoad {
|
||||||
|
/// The ID of the OSM way representing the road.
|
||||||
|
pub osm_way_id: i64,
|
||||||
|
/// The ID of the OSM node at the start of this road segment.
|
||||||
|
pub osm_node1: i64,
|
||||||
|
/// The ID of the OSM node at the end of this road segment.
|
||||||
|
pub osm_node2: i64,
|
||||||
|
/// The direction along the road segment. See
|
||||||
|
/// https://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right for details.
|
||||||
|
pub is_forwards: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
static DATA: include_dir::Dir = include_dir::include_dir!("data");
|
||||||
|
|
||||||
|
/// Returns all traffic signal data compiled into this build, keyed by OSM node ID.
|
||||||
|
pub fn load_all_data() -> Result<BTreeMap<i64, TrafficSignal>, std::io::Error> {
|
||||||
|
let mut results = BTreeMap::new();
|
||||||
|
if let Some(dir) = DATA.get_dir("data") {
|
||||||
|
for f in dir.files() {
|
||||||
|
let ts: TrafficSignal = serde_json::from_slice(&f.contents())?;
|
||||||
|
results.insert(ts.intersection_osm_node_id, ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(results)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user