mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 07:25:47 +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",
|
||||
"sim",
|
||||
"tests",
|
||||
"traffic_signals",
|
||||
]
|
||||
|
||||
# See https://doc.rust-lang.org/cargo/reference/profiles.html#overrides. This
|
||||
|
@ -48,7 +48,7 @@ impl TrafficSignalEditor {
|
||||
i: id,
|
||||
current_phase: 0,
|
||||
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),
|
||||
group_selected: None,
|
||||
suspended_sim,
|
||||
@ -158,7 +158,7 @@ impl State for TrafficSignalEditor {
|
||||
phase.edit_group(&orig_signal.turn_groups[&id], pri);
|
||||
self.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
self.change_phase(self.current_phase, app, ctx);
|
||||
return Transition::Keep;
|
||||
@ -176,6 +176,9 @@ impl State for TrafficSignalEditor {
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
"Export" => {
|
||||
orig_signal.export(&app.primary.map);
|
||||
}
|
||||
"Preview" => {
|
||||
// Might have to do this first!
|
||||
app.primary
|
||||
@ -192,14 +195,14 @@ impl State for TrafficSignalEditor {
|
||||
"undo" => {
|
||||
self.redo_stack.push(orig_signal.clone());
|
||||
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);
|
||||
return Transition::Keep;
|
||||
}
|
||||
"redo" => {
|
||||
self.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
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 {
|
||||
let row = vec![
|
||||
fn make_top_panel(ctx: &mut EventCtx, app: &App, can_undo: bool, can_redo: bool) -> Composite {
|
||||
let mut row = vec![
|
||||
WrappedComposite::text_button(ctx, "Finish", hotkey(Key::Escape)),
|
||||
WrappedComposite::text_button(ctx, "Finish", hotkey(Key::Escape)),
|
||||
WrappedComposite::text_button(ctx, "Preview", lctrl(Key::P)),
|
||||
(if can_undo {
|
||||
@ -325,6 +329,9 @@ fn make_top_panel(can_undo: bool, can_redo: bool, ctx: &mut EventCtx) -> Composi
|
||||
})
|
||||
.margin(15),
|
||||
];
|
||||
if app.opts.dev {
|
||||
row.push(WrappedComposite::text_button(ctx, "Export", None));
|
||||
}
|
||||
Composite::new(ManagedWidget::row(row).bg(colors::PANEL_BG))
|
||||
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
|
||||
.build(ctx)
|
||||
@ -521,7 +528,7 @@ fn edit_entire_signal(app: &App, i: IntersectionID, suspended_sim: Sim) -> Box<d
|
||||
.command_stack
|
||||
.push(app.primary.map.get_traffic_signal(editor.i).clone());
|
||||
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);
|
||||
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() {
|
||||
editor.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
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();
|
||||
editor.command_stack.push(signal.clone());
|
||||
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);
|
||||
change_traffic_signal(signal, 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;
|
||||
editor.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
// Don't use change_phase; it tries to preserve scroll
|
||||
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);
|
||||
editor.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
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());
|
||||
editor.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
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());
|
||||
editor.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
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);
|
||||
editor.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
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);
|
||||
editor.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
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();
|
||||
editor.command_stack.push(orig_signal.clone());
|
||||
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);
|
||||
// Don't use change_phase; it tries to preserve scroll
|
||||
editor.current_phase = if idx == num_phases { idx - 1 } else { idx };
|
||||
|
@ -15,3 +15,4 @@ petgraph = "0.4.13"
|
||||
serde = "1.0.89"
|
||||
serde_derive = "1.0.98"
|
||||
thread_local = "0.3.6"
|
||||
traffic_signals = { path = "../traffic_signals" }
|
||||
|
@ -616,3 +616,56 @@ fn make_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