Skip to content

Commit fd1e1b1

Browse files
committed
Introduce crossing=no and crossing=informal for QA
- `is_crossing` now includes all `crossing=*`, including "informal" - `is_explicit_crossing_no` (new) handles `crossing=no` - on the QA map, `crossing=no` are purple circles - …they are part of the count of crossings on a junction - A junction is "green" when the sum of crossings and `crossing=no` are the same as edges - The UI shows the crossings and `crossing=no` in the sentence
1 parent 3a78604 commit fd1e1b1

File tree

5 files changed

+74
-11
lines changed

5 files changed

+74
-11
lines changed

backend/src/audit.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,28 @@ impl Speedwalk {
2626
let edge = &graph.edges[&e];
2727
debug_arms.push(self.mercator.to_wgs84_gj(&edge.linestring));
2828
}
29+
let crossing_count = junction.crossings.len();
30+
let explicit_non_crossing_count = junction.explicit_non_crossings.len();
2931
let mut debug_crossings = Vec::new();
30-
for n in junction.crossings {
32+
for n in &junction.crossings {
3133
debug_crossings.push(
3234
self.mercator
33-
.to_wgs84_gj(&Point::from(self.derived_nodes[&n].pt)),
35+
.to_wgs84_gj(&Point::from(self.derived_nodes[n].pt)),
3436
);
3537
}
36-
f.set_property("complete", debug_arms.len() == debug_crossings.len());
38+
let mut debug_explicit_non_crossings = Vec::new();
39+
for n in &junction.explicit_non_crossings {
40+
debug_explicit_non_crossings.push(
41+
self.mercator
42+
.to_wgs84_gj(&Point::from(self.derived_nodes[n].pt)),
43+
);
44+
}
45+
f.set_property("complete", debug_arms.len() == crossing_count + explicit_non_crossing_count);
3746
f.set_property("arms", GeoJson::from(debug_arms));
3847
f.set_property("crossings", GeoJson::from(debug_crossings));
48+
f.set_property("explicit_non_crossings", GeoJson::from(debug_explicit_non_crossings));
49+
f.set_property("crossing_count", crossing_count);
50+
f.set_property("explicit_non_crossing_count", explicit_non_crossing_count);
3951

4052
features.push(f);
4153
}
@@ -57,6 +69,7 @@ impl Speedwalk {
5769
let mut any_severances = false;
5870
let mut arms = Vec::new();
5971
let mut crossings = BTreeSet::new();
72+
let mut explicit_non_crossings = BTreeSet::new();
6073
for e in &intersection.edges {
6174
let edge = &graph.edges[e];
6275
let way = &self.derived_ways[&edge.osm_way];
@@ -68,10 +81,26 @@ impl Speedwalk {
6881
}
6982
arms.push(*e);
7083

71-
// TODO Simple definition of "nearby crossings", with both false positives and
72-
// negatives
73-
for n in &edge.node_ids {
74-
if self.derived_nodes[n].is_crossing() {
84+
// Iterate along the edge away from the intersection, stopping at crossing=no
85+
let node_iter: Box<dyn Iterator<Item = &NodeID>> = if edge.src == *i {
86+
// Iterate forward from src to dst
87+
Box::new(edge.node_ids.iter().skip(1))
88+
} else if edge.dst == *i {
89+
// Iterate backward from dst to src
90+
Box::new(edge.node_ids.iter().rev().skip(1))
91+
} else {
92+
// Shouldn't happen, but fallback to all nodes
93+
Box::new(edge.node_ids.iter())
94+
};
95+
96+
for n in node_iter {
97+
let node = &self.derived_nodes[n];
98+
if node.is_explicit_crossing_no() {
99+
explicit_non_crossings.insert(*n);
100+
// Stop iterating along this edge when we hit crossing=no
101+
break;
102+
}
103+
if node.is_crossing() {
75104
crossings.insert(*n);
76105
}
77106
}
@@ -82,6 +111,7 @@ impl Speedwalk {
82111
i: *i,
83112
arms,
84113
crossings,
114+
explicit_non_crossings,
85115
});
86116
}
87117
}
@@ -93,4 +123,5 @@ struct Junction {
93123
i: IntersectionID,
94124
arms: Vec<EdgeID>,
95125
crossings: BTreeSet<NodeID>,
126+
explicit_non_crossings: BTreeSet<NodeID>,
96127
}

backend/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,18 @@ pub struct Way {
8787

8888
impl Node {
8989
pub fn is_crossing(&self) -> bool {
90+
// Include any node with a crossing tag value != "no" (informal, traffic_signals, yes, etc.)
91+
if let Some(value) = self.tags.get("crossing") {
92+
return value != "no";
93+
}
9094
self.tags.is("highway", "crossing")
9195
|| (self.tags.is("highway", "traffic_signals")
9296
&& self.tags.is("crossing", "traffic_signals"))
9397
}
98+
99+
pub fn is_explicit_crossing_no(&self) -> bool {
100+
self.tags.is("crossing", "no")
101+
}
94102
}
95103

96104
impl Way {

backend/src/wasm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl Speedwalk {
5757
f.set_property("tags", serde_json::to_value(&node.tags).map_err(err_to_js)?);
5858
}
5959
f.set_property("is_crossing", node.is_crossing());
60+
f.set_property("is_explicit_crossing_no", node.is_explicit_crossing_no());
6061
f.set_property("modified", node.modified);
6162
f.set_property(
6263
"way_ids",

web/src/crossings/AuditCrossingsMode.svelte

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@
2828
$: debugCrossings = hovered
2929
? JSON.parse(hovered.properties!.crossings)
3030
: emptyGeojson();
31+
$: debugExplicitNonCrossings = hovered
32+
? JSON.parse(hovered.properties!.explicit_non_crossings)
33+
: emptyGeojson();
34+
$: crossingCount = hovered?.properties?.crossing_count ?? 0;
35+
$: explicitNonCrossingCount = hovered?.properties?.explicit_non_crossing_count ?? 0;
3136
3237
let crossingNodes = JSON.parse($backend!.getNodes()) as FeatureCollection;
3338
crossingNodes.features = crossingNodes.features.filter(
34-
(f) => f.properties!.is_crossing,
39+
(f) => f.properties!.is_crossing || f.properties!.is_explicit_crossing_no,
3540
);
3641
</script>
3742

@@ -48,8 +53,9 @@
4853

4954
{#if hovered}
5055
<p class="mt-5">
51-
Junction has {debugArms.features.length} arms, {debugCrossings.features
52-
.length} crossings
56+
Junction has {debugArms.features.length} arms,
57+
{crossingCount} crossing{#if crossingCount !== 1}s{/if}
58+
{#if explicitNonCrossingCount > 0}, {explicitNonCrossingCount} explicit non-crossing{#if explicitNonCrossingCount !== 1}s{/if}{/if}
5359
</p>
5460
{/if}
5561
</div>
@@ -78,7 +84,12 @@
7884
manageHoverState
7985
paint={{
8086
"circle-radius": 7,
81-
"circle-color": "yellow",
87+
"circle-color": [
88+
"case",
89+
["get", "is_explicit_crossing_no"],
90+
"purple",
91+
"yellow",
92+
],
8293
"circle-opacity": hoverStateFilter(0.3, 1.0),
8394
"circle-stroke-color": "black",
8495
"circle-stroke-width": 1,
@@ -111,5 +122,16 @@
111122
}}
112123
/>
113124
</GeoJSON>
125+
126+
<GeoJSON data={debugExplicitNonCrossings}>
127+
<CircleLayer
128+
paint={{
129+
"circle-radius": 10,
130+
"circle-opacity": 0,
131+
"circle-stroke-color": "purple",
132+
"circle-stroke-width": 3,
133+
}}
134+
/>
135+
</GeoJSON>
114136
</div>
115137
</SplitComponent>

web/src/sidewalks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface NodeProps {
66
id: number;
77
tags?: Record<string, string>;
88
is_crossing: boolean;
9+
is_explicit_crossing_no?: boolean;
910
modified: boolean;
1011
way_ids: number[];
1112
problems: Problem[];

0 commit comments

Comments
 (0)