mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-09-19 06:37:15 +03:00
Update osm2streets and handle OSM tags moved off of roads
This commit is contained in:
parent
3d3062772c
commit
a77c022200
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -2952,7 +2952,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "osm2streets"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/a-b-street/osm2streets#663d5a7c1f00b8b627d953dff9fec67d4b55ae5a"
|
||||
source = "git+https://github.com/a-b-street/osm2streets#7fa918b7dc1120f70a5e47f260330c620fa6a836"
|
||||
dependencies = [
|
||||
"aabb-quadtree",
|
||||
"abstutil",
|
||||
@ -3976,7 +3976,7 @@ checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e"
|
||||
[[package]]
|
||||
name = "streets_reader"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/a-b-street/osm2streets#663d5a7c1f00b8b627d953dff9fec67d4b55ae5a"
|
||||
source = "git+https://github.com/a-b-street/osm2streets#7fa918b7dc1120f70a5e47f260330c620fa6a836"
|
||||
dependencies = [
|
||||
"abstutil",
|
||||
"anyhow",
|
||||
|
@ -9,7 +9,7 @@ use map_gui::options::OptionsPanel;
|
||||
use map_gui::render::{calculate_corners, DrawMap, DrawOptions};
|
||||
use map_gui::{AppLike, ID};
|
||||
use map_model::{
|
||||
osm, ControlTrafficSignal, IntersectionID, PathConstraints, Perimeter, Position, RoadID,
|
||||
ControlTrafficSignal, IntersectionID, PathConstraints, Perimeter, Position, RoadID,
|
||||
NORMAL_LANE_THICKNESS,
|
||||
};
|
||||
use sim::Sim;
|
||||
@ -938,10 +938,6 @@ fn find_degenerate_roads(app: &App) {
|
||||
|
||||
fn diff_tags(t1: &Tags, t2: &Tags) {
|
||||
for (k, v1, v2) in t1.diff(t2) {
|
||||
// Ignore the most common diff
|
||||
if k == osm::OSM_WAY_ID {
|
||||
continue;
|
||||
}
|
||||
println!("- {} = \"{}\" vs \"{}\"", k, v1, v2);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ use geom::{Bounds, CornerRadii, Distance, Polygon, Pt2D, UnitFmt};
|
||||
use map_gui::render::{Renderable, OUTLINE_THICKNESS};
|
||||
use map_gui::ID;
|
||||
use map_model::{
|
||||
BufferType, Direction, EditCmd, EditRoad, LaneID, LaneSpec, LaneType, MapEdits, Road, RoadID,
|
||||
osm, BufferType, Direction, EditCmd, EditRoad, LaneID, LaneSpec, LaneType, MapEdits, Road,
|
||||
RoadID,
|
||||
};
|
||||
use widgetry::tools::PopupMsg;
|
||||
use widgetry::{
|
||||
@ -18,6 +19,9 @@ use crate::common::Warping;
|
||||
use crate::edit::zones::ZoneEditor;
|
||||
use crate::edit::{apply_map_edits, can_edit_lane, speed_limit_choices};
|
||||
|
||||
// TODO Future bug alert: osm_tags.get(osm::HIGHWAY) is brittle, because it'll break for railways.
|
||||
// Plumb through road.highway instead.
|
||||
|
||||
pub struct RoadEditor {
|
||||
r: RoadID,
|
||||
selected_lane: Option<LaneID>,
|
||||
@ -290,10 +294,16 @@ impl State<App> for RoadEditor {
|
||||
} else {
|
||||
LaneType::from_short_name(lt).unwrap()
|
||||
};
|
||||
let width =
|
||||
LaneSpec::typical_lane_widths(lt, &app.primary.map.get_r(self.r).osm_tags)
|
||||
[0]
|
||||
.0;
|
||||
let width = LaneSpec::typical_lane_widths(
|
||||
lt,
|
||||
app.primary
|
||||
.map
|
||||
.get_r(self.r)
|
||||
.osm_tags
|
||||
.get(osm::HIGHWAY)
|
||||
.unwrap(),
|
||||
)[0]
|
||||
.0;
|
||||
return self.modify_current_lane(ctx, app, Some(0), |new, idx| {
|
||||
new.lanes_ltr[idx].lt = lt;
|
||||
new.lanes_ltr[idx].width = width;
|
||||
@ -324,7 +334,12 @@ impl State<App> for RoadEditor {
|
||||
let idx = LaneSpec::add_new_lane(
|
||||
&mut new.lanes_ltr,
|
||||
lt,
|
||||
&app.primary.map.get_r(self.r).osm_tags,
|
||||
app.primary
|
||||
.map
|
||||
.get_r(self.r)
|
||||
.osm_tags
|
||||
.get(osm::HIGHWAY)
|
||||
.unwrap(),
|
||||
app.primary.map.get_config().driving_side,
|
||||
);
|
||||
edits.commands.push(EditCmd::ChangeRoad {
|
||||
@ -400,10 +415,16 @@ impl State<App> for RoadEditor {
|
||||
"change to buffer" => {
|
||||
let lt = self.main_panel.persistent_split_value("change to buffer");
|
||||
app.session.buffer_lane_type = lt;
|
||||
let width =
|
||||
LaneSpec::typical_lane_widths(lt, &app.primary.map.get_r(self.r).osm_tags)
|
||||
[0]
|
||||
.0;
|
||||
let width = LaneSpec::typical_lane_widths(
|
||||
lt,
|
||||
app.primary
|
||||
.map
|
||||
.get_r(self.r)
|
||||
.osm_tags
|
||||
.get(osm::HIGHWAY)
|
||||
.unwrap(),
|
||||
)[0]
|
||||
.0;
|
||||
return self.modify_current_lane(ctx, app, Some(0), |new, idx| {
|
||||
new.lanes_ltr[idx].lt = lt;
|
||||
new.lanes_ltr[idx].width = width;
|
||||
@ -608,7 +629,9 @@ fn make_main_panel(
|
||||
.into_iter()
|
||||
.map(|buf| {
|
||||
let lt = LaneType::Buffer(buf);
|
||||
let width = LaneSpec::typical_lane_widths(lt, &road.osm_tags)[0].0;
|
||||
let width =
|
||||
LaneSpec::typical_lane_widths(lt, road.osm_tags.get(osm::HIGHWAY).unwrap())[0]
|
||||
.0;
|
||||
Choice::new(
|
||||
format!("{} ({})", lt.short_name(), width.to_string(&app.opts.units)),
|
||||
lt,
|
||||
@ -982,7 +1005,12 @@ fn width_choices(app: &App, l: LaneID) -> Vec<Choice<Distance>> {
|
||||
let lane = app.primary.map.get_l(l);
|
||||
let mut choices = LaneSpec::typical_lane_widths(
|
||||
lane.lane_type,
|
||||
&app.primary.map.get_r(lane.id.road).osm_tags,
|
||||
app.primary
|
||||
.map
|
||||
.get_r(lane.id.road)
|
||||
.osm_tags
|
||||
.get(osm::HIGHWAY)
|
||||
.unwrap(),
|
||||
);
|
||||
if !choices.iter().any(|(x, _)| *x == lane.width) {
|
||||
choices.push((lane.width, "custom"));
|
||||
|
@ -1,3 +1,4 @@
|
||||
use abstutil::Tags;
|
||||
use geom::{ArrowCap, Distance};
|
||||
use osm2streets::RoadID;
|
||||
use widgetry::{
|
||||
@ -31,8 +32,15 @@ impl EditRoad {
|
||||
);
|
||||
}
|
||||
|
||||
let tags = app
|
||||
.model
|
||||
.map
|
||||
.road_to_osm_tags(r)
|
||||
.cloned()
|
||||
.unwrap_or_else(Tags::empty);
|
||||
|
||||
let mut txt = Text::new();
|
||||
for (k, v) in road.osm_tags.inner() {
|
||||
for (k, v) in tags.inner() {
|
||||
txt.add_line(Line(format!("{} = {}", k, v)).secondary());
|
||||
}
|
||||
txt.add_line(Line(format!(
|
||||
@ -60,8 +68,7 @@ impl EditRoad {
|
||||
ctx,
|
||||
"lanes:forward",
|
||||
(1, 5),
|
||||
road.osm_tags
|
||||
.get("lanes:forward")
|
||||
tags.get("lanes:forward")
|
||||
.and_then(|x| x.parse::<usize>().ok())
|
||||
.unwrap_or(1),
|
||||
1,
|
||||
@ -73,16 +80,9 @@ impl EditRoad {
|
||||
ctx,
|
||||
"lanes:backward",
|
||||
(0, 5),
|
||||
road.osm_tags
|
||||
.get("lanes:backward")
|
||||
tags.get("lanes:backward")
|
||||
.and_then(|x| x.parse::<usize>().ok())
|
||||
.unwrap_or_else(|| {
|
||||
if road.osm_tags.is("oneway", "yes") {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}),
|
||||
.unwrap_or_else(|| if tags.is("oneway", "yes") { 0 } else { 1 }),
|
||||
1,
|
||||
),
|
||||
]),
|
||||
@ -91,13 +91,13 @@ impl EditRoad {
|
||||
Widget::dropdown(
|
||||
ctx,
|
||||
"sidewalk",
|
||||
if road.osm_tags.is("sidewalk", "both") {
|
||||
if tags.is("sidewalk", "both") {
|
||||
"both"
|
||||
} else if road.osm_tags.is("sidewalk", "none") {
|
||||
} else if tags.is("sidewalk", "none") {
|
||||
"none"
|
||||
} else if road.osm_tags.is("sidewalk", "left") {
|
||||
} else if tags.is("sidewalk", "left") {
|
||||
"left"
|
||||
} else if road.osm_tags.is("sidewalk", "right") {
|
||||
} else if tags.is("sidewalk", "right") {
|
||||
"right"
|
||||
} else {
|
||||
"both"
|
||||
@ -112,16 +112,13 @@ impl EditRoad {
|
||||
ctx,
|
||||
"parking",
|
||||
// TODO Not all possibilities represented here; very simplified.
|
||||
if road.osm_tags.is("parking:lane:both", "parallel") {
|
||||
if tags.is("parking:lane:both", "parallel") {
|
||||
"both"
|
||||
} else if road
|
||||
.osm_tags
|
||||
.is_any("parking:lane:both", vec!["no_parking", "no_stopping"])
|
||||
{
|
||||
} else if tags.is_any("parking:lane:both", vec!["no_parking", "no_stopping"]) {
|
||||
"none"
|
||||
} else if road.osm_tags.is("parking:lane:left", "parallel") {
|
||||
} else if tags.is("parking:lane:left", "parallel") {
|
||||
"left"
|
||||
} else if road.osm_tags.is("parking:lane:right", "parallel") {
|
||||
} else if tags.is("parking:lane:right", "parallel") {
|
||||
"right"
|
||||
} else {
|
||||
"none"
|
||||
@ -174,47 +171,52 @@ impl SimpleState<App> for EditRoad {
|
||||
"Apply" => {
|
||||
app.model.road_deleted(self.r);
|
||||
|
||||
let road = app.model.map.streets.roads.get_mut(&self.r).unwrap();
|
||||
let mut tags = app
|
||||
.model
|
||||
.map
|
||||
.road_to_osm_tags(self.r)
|
||||
.cloned()
|
||||
.unwrap_or_else(Tags::empty);
|
||||
|
||||
road.osm_tags.remove("lanes");
|
||||
road.osm_tags.remove("oneway");
|
||||
tags.remove("lanes");
|
||||
tags.remove("oneway");
|
||||
let fwd: usize = panel.spinner("lanes:forward");
|
||||
let back: usize = panel.spinner("lanes:backward");
|
||||
if back == 0 {
|
||||
road.osm_tags.insert("oneway", "yes");
|
||||
road.osm_tags.insert("lanes", fwd.to_string());
|
||||
tags.insert("oneway", "yes");
|
||||
tags.insert("lanes", fwd.to_string());
|
||||
} else {
|
||||
road.osm_tags.insert("lanes", (fwd + back).to_string());
|
||||
road.osm_tags.insert("lanes:forward", fwd.to_string());
|
||||
road.osm_tags.insert("lanes:backward", back.to_string());
|
||||
tags.insert("lanes", (fwd + back).to_string());
|
||||
tags.insert("lanes:forward", fwd.to_string());
|
||||
tags.insert("lanes:backward", back.to_string());
|
||||
}
|
||||
|
||||
road.osm_tags
|
||||
.insert("sidewalk", panel.dropdown_value::<String, &str>("sidewalk"));
|
||||
tags.insert("sidewalk", panel.dropdown_value::<String, &str>("sidewalk"));
|
||||
|
||||
road.osm_tags.remove("parking:lane:both");
|
||||
road.osm_tags.remove("parking:lane:left");
|
||||
road.osm_tags.remove("parking:lane:right");
|
||||
tags.remove("parking:lane:both");
|
||||
tags.remove("parking:lane:left");
|
||||
tags.remove("parking:lane:right");
|
||||
match panel.dropdown_value::<String, &str>("parking").as_ref() {
|
||||
"both" => {
|
||||
road.osm_tags.insert("parking:lane:both", "parallel");
|
||||
tags.insert("parking:lane:both", "parallel");
|
||||
}
|
||||
"none" => {
|
||||
road.osm_tags.insert("parking:lane:both", "none");
|
||||
tags.insert("parking:lane:both", "none");
|
||||
}
|
||||
"left" => {
|
||||
road.osm_tags.insert("parking:lane:left", "parallel");
|
||||
road.osm_tags.insert("parking:lane:right", "none");
|
||||
tags.insert("parking:lane:left", "parallel");
|
||||
tags.insert("parking:lane:right", "none");
|
||||
}
|
||||
"right" => {
|
||||
road.osm_tags.insert("parking:lane:left", "none");
|
||||
road.osm_tags.insert("parking:lane:right", "parallel");
|
||||
tags.insert("parking:lane:left", "none");
|
||||
tags.insert("parking:lane:right", "parallel");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let road = app.model.map.streets.roads.get_mut(&self.r).unwrap();
|
||||
road.lane_specs_ltr =
|
||||
osm2streets::get_lane_specs_ltr(&road.osm_tags, &app.model.map.streets.config);
|
||||
osm2streets::get_lane_specs_ltr(&tags, &app.model.map.streets.config);
|
||||
let scale = panel.spinner("width_scale");
|
||||
for lane in &mut road.lane_specs_ltr {
|
||||
lane.width *= scale;
|
||||
@ -235,9 +237,14 @@ impl SimpleState<App> for EditRoad {
|
||||
) -> Option<Transition<App>> {
|
||||
let scale = panel.spinner("width_scale");
|
||||
app.model.road_deleted(self.r);
|
||||
let tags = app
|
||||
.model
|
||||
.map
|
||||
.road_to_osm_tags(self.r)
|
||||
.cloned()
|
||||
.unwrap_or_else(Tags::empty);
|
||||
let road = app.model.map.streets.roads.get_mut(&self.r).unwrap();
|
||||
road.lane_specs_ltr =
|
||||
osm2streets::get_lane_specs_ltr(&road.osm_tags, &app.model.map.streets.config);
|
||||
road.lane_specs_ltr = osm2streets::get_lane_specs_ltr(&tags, &app.model.map.streets.config);
|
||||
for lane in &mut road.lane_specs_ltr {
|
||||
lane.width *= scale;
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ impl Model {
|
||||
let hitbox = center.make_polygons(total_width);
|
||||
let mut draw = GeomBatch::new();
|
||||
draw.push(
|
||||
if road.osm_tags.is("junction", "intersection") {
|
||||
if road.internal_junction_road {
|
||||
Color::PINK
|
||||
} else {
|
||||
Color::grey(0.8)
|
||||
@ -350,8 +350,6 @@ impl Model {
|
||||
osm_tags.insert("parking:both:lane", "parallel");
|
||||
osm_tags.insert("sidewalk", "both");
|
||||
osm_tags.insert("lanes", "2");
|
||||
osm_tags.insert(osm::ENDPT_FWD, "true");
|
||||
osm_tags.insert(osm::ENDPT_BACK, "true");
|
||||
// Reasonable defaults.
|
||||
osm_tags.insert("name", "Streety McStreetFace");
|
||||
osm_tags.insert("maxspeed", "25 mph");
|
||||
@ -570,11 +568,7 @@ impl Model {
|
||||
self.road_deleted(id);
|
||||
|
||||
let road = self.map.streets.roads.get_mut(&id).unwrap();
|
||||
if road.osm_tags.is("junction", "intersection") {
|
||||
road.osm_tags.remove("junction");
|
||||
} else {
|
||||
road.osm_tags.insert("junction", "intersection");
|
||||
}
|
||||
road.internal_junction_road = !road.internal_junction_road;
|
||||
|
||||
self.road_added(ctx, id);
|
||||
}
|
||||
@ -667,8 +661,9 @@ fn dump_to_osm(map: &RawMap) -> Result<(), std::io::Error> {
|
||||
pt_to_id[&pt.to_hashable()].0
|
||||
)?;
|
||||
}
|
||||
for (k, v) in r.osm_tags.inner() {
|
||||
if !k.starts_with("abst:") {
|
||||
// TODO Brittle. Instead we should effectively do lanes2osm
|
||||
if let Some(tags) = map.road_to_osm_tags(*id) {
|
||||
for (k, v) in tags.inner() {
|
||||
writeln!(f, r#" <tag k="{}" v="{}"/>"#, k, v)?;
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ use map_gui::options::OptionsPanel;
|
||||
use map_gui::render::{DrawOptions, BIG_ARROW_THICKNESS};
|
||||
use map_gui::tools::{CityPicker, Minimap, MinimapControls, Navigator, TurnExplorer};
|
||||
use map_gui::{SimpleApp, ID};
|
||||
use map_model::osm;
|
||||
use widgetry::tools::{open_browser, PopupMsg, URLManager};
|
||||
use widgetry::{
|
||||
lctrl, Color, DrawBaselayer, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key,
|
||||
@ -110,9 +109,9 @@ impl Viewer {
|
||||
continue;
|
||||
}
|
||||
if tags.contains_key("abst:parking_source")
|
||||
&& (k == osm::PARKING_RIGHT
|
||||
|| k == osm::PARKING_LEFT
|
||||
|| k == osm::PARKING_BOTH)
|
||||
&& (k == "parking:lane:right"
|
||||
|| k == "parking:lane:left"
|
||||
|| k == "parking:lane:both")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -526,29 +526,29 @@ fn generate_osmc(data: &BTreeMap<WayID, Value>, in_seattle: bool, timer: &mut Ti
|
||||
}
|
||||
|
||||
// Fill out the tags.
|
||||
osm_tags.remove(osm::PARKING_LEFT);
|
||||
osm_tags.remove(osm::PARKING_RIGHT);
|
||||
osm_tags.remove(osm::PARKING_BOTH);
|
||||
osm_tags.remove("parking:lane:left");
|
||||
osm_tags.remove("parking:lane:right");
|
||||
osm_tags.remove("parking_lane_both");
|
||||
match value {
|
||||
Value::BothSides => {
|
||||
osm_tags.insert(osm::PARKING_BOTH, "parallel");
|
||||
osm_tags.insert("parking_lane_both", "parallel");
|
||||
if in_seattle {
|
||||
osm_tags.insert("parking:condition:both:maxstay", "3 days");
|
||||
}
|
||||
}
|
||||
Value::NoStopping => {
|
||||
osm_tags.insert(osm::PARKING_BOTH, "no_stopping");
|
||||
osm_tags.insert("parking_lane_both", "no_stopping");
|
||||
}
|
||||
Value::RightOnly => {
|
||||
osm_tags.insert(osm::PARKING_RIGHT, "parallel");
|
||||
osm_tags.insert(osm::PARKING_LEFT, "no_stopping");
|
||||
osm_tags.insert("parking:lane:right", "parallel");
|
||||
osm_tags.insert("parking:lane:left", "no_stopping");
|
||||
if in_seattle {
|
||||
osm_tags.insert("parking:condition:right:maxstay", "3 days");
|
||||
}
|
||||
}
|
||||
Value::LeftOnly => {
|
||||
osm_tags.insert(osm::PARKING_LEFT, "parallel");
|
||||
osm_tags.insert(osm::PARKING_RIGHT, "no_stopping");
|
||||
osm_tags.insert("parking:lane:left", "parallel");
|
||||
osm_tags.insert("parking:lane:right", "no_stopping");
|
||||
if in_seattle {
|
||||
osm_tags.insert("parking:condition:left:maxstay", "3 days");
|
||||
}
|
||||
|
@ -15,7 +15,11 @@ pub fn extract_osm(
|
||||
clip_path: Option<String>,
|
||||
opts: &Options,
|
||||
timer: &mut Timer,
|
||||
) -> (OsmExtract, MultiMap<osm::WayID, String>) {
|
||||
) -> (
|
||||
OsmExtract,
|
||||
streets_reader::osm_reader::Document,
|
||||
MultiMap<osm::WayID, String>,
|
||||
) {
|
||||
let osm_xml = fs_err::read_to_string(osm_input_path).unwrap();
|
||||
let mut doc =
|
||||
streets_reader::osm_reader::read(&osm_xml, &map.streets.gps_bounds, timer).unwrap();
|
||||
@ -73,8 +77,6 @@ pub fn extract_osm(
|
||||
timer.next();
|
||||
let id = *id;
|
||||
|
||||
way.tags.insert(osm::OSM_WAY_ID, id.0.to_string());
|
||||
|
||||
if out.handle_way(id, &way, opts) {
|
||||
continue;
|
||||
} else if way.tags.is(osm::HIGHWAY, "service") {
|
||||
@ -132,12 +134,6 @@ pub fn extract_osm(
|
||||
|
||||
let boundary = map.streets.boundary_polygon.get_outer_ring();
|
||||
|
||||
// TODO Fill this out in a separate loop to keep a mutable borrow short. Maybe do this in
|
||||
// reader, or stop doing this entirely.
|
||||
for (id, rel) in &mut doc.relations {
|
||||
rel.tags.insert(osm::OSM_REL_ID, id.0.to_string());
|
||||
}
|
||||
|
||||
timer.start_iter("processing OSM relations", doc.relations.len());
|
||||
for (id, rel) in &doc.relations {
|
||||
timer.next();
|
||||
@ -285,7 +281,7 @@ pub fn extract_osm(
|
||||
find_parking_aisles(map, &mut out.roads);
|
||||
timer.stop("find service roads crossing parking lots");
|
||||
|
||||
(out, bus_routes_on_roads)
|
||||
(out, doc, bus_routes_on_roads)
|
||||
}
|
||||
|
||||
fn is_bldg(tags: &Tags) -> bool {
|
||||
|
@ -3,6 +3,8 @@ extern crate anyhow;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use abstio::MapName;
|
||||
@ -42,7 +44,7 @@ pub fn convert(
|
||||
map.streets.gps_bounds = gps_bounds;
|
||||
}
|
||||
|
||||
let (extract, bus_routes_on_roads) =
|
||||
let (extract, doc, bus_routes_on_roads) =
|
||||
extract::extract_osm(&mut map, &osm_input_path, clip_path, &opts, timer);
|
||||
map.bus_routes_on_roads = bus_routes_on_roads;
|
||||
let split_output = streets_reader::split_ways::split_up_roads(&mut map.streets, extract, timer);
|
||||
@ -52,6 +54,19 @@ pub fn convert(
|
||||
// doing the parking hint matching.
|
||||
map.streets.retain_roads(|r| r.src_i != r.dst_i);
|
||||
|
||||
// Remember OSM tags for all roads. Do this before apply_parking, which looks at tags
|
||||
let mut way_ids = HashSet::new();
|
||||
for r in map.streets.roads.values() {
|
||||
for id in &r.osm_ids {
|
||||
way_ids.insert(id.osm_way_id);
|
||||
}
|
||||
}
|
||||
for (id, way) in doc.ways {
|
||||
if way_ids.contains(&id) {
|
||||
map.osm_tags.insert(id, way.tags);
|
||||
}
|
||||
}
|
||||
|
||||
parking::apply_parking(&mut map, &opts, timer);
|
||||
|
||||
streets_reader::use_barrier_nodes(
|
||||
@ -92,7 +107,9 @@ pub fn convert(
|
||||
if map.name == MapName::new("gb", "bristol", "east") {
|
||||
bristol_hack(&mut map);
|
||||
}
|
||||
|
||||
timer.stop("create RawMap from input data");
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,9 @@ pub fn apply_parking(map: &mut RawMap, opts: &Options, timer: &mut Timer) {
|
||||
}
|
||||
|
||||
fn unknown_parking(tags: &Tags) -> bool {
|
||||
!tags.contains_key(osm::PARKING_LEFT)
|
||||
&& !tags.contains_key(osm::PARKING_RIGHT)
|
||||
&& !tags.contains_key(osm::PARKING_BOTH)
|
||||
!tags.contains_key("parking:lane:left")
|
||||
&& !tags.contains_key("parking:lane:right")
|
||||
&& !tags.contains_key("parking:lane:both")
|
||||
&& !tags.is_any(osm::HIGHWAY, vec!["motorway", "motorway_link", "service"])
|
||||
&& !tags.is("junction", "roundabout")
|
||||
}
|
||||
@ -42,7 +42,7 @@ fn use_parking_hints(map: &mut RawMap, path: String, timer: &mut Timer) {
|
||||
let mut closest: FindClosest<(RoadID, bool)> =
|
||||
FindClosest::new(&map.streets.gps_bounds.to_bounds());
|
||||
for (id, r) in &map.streets.roads {
|
||||
if r.is_light_rail() || r.is_footway() || r.is_service() {
|
||||
if r.is_service() || !r.is_driveable() {
|
||||
continue;
|
||||
}
|
||||
closest.add(
|
||||
@ -75,7 +75,7 @@ fn use_parking_hints(map: &mut RawMap, path: String, timer: &mut Timer) {
|
||||
continue;
|
||||
};
|
||||
if let Some(((r, fwds), _)) = closest.closest_pt(middle, DIRECTED_ROAD_THICKNESS * 5.0) {
|
||||
let tags = &mut map.streets.roads.get_mut(&r).unwrap().osm_tags;
|
||||
let mut tags = map.road_to_osm_tags(r).cloned().unwrap_or_else(Tags::empty);
|
||||
|
||||
// Skip if the road already has this mapped.
|
||||
if !unknown_parking(&tags) {
|
||||
@ -105,16 +105,16 @@ fn use_parking_hints(map: &mut RawMap, path: String, timer: &mut Timer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(both) = tags.remove(osm::PARKING_BOTH) {
|
||||
tags.insert(osm::PARKING_LEFT, both.clone());
|
||||
tags.insert(osm::PARKING_RIGHT, both);
|
||||
if let Some(both) = tags.remove("parking:lane:both") {
|
||||
tags.insert("parking:lane:left", both.clone());
|
||||
tags.insert("parking:lane:right", both);
|
||||
}
|
||||
|
||||
tags.insert(
|
||||
if fwds {
|
||||
osm::PARKING_RIGHT
|
||||
"parking:lane:right"
|
||||
} else {
|
||||
osm::PARKING_LEFT
|
||||
"parking:lane:left"
|
||||
},
|
||||
if has_parking {
|
||||
"parallel"
|
||||
@ -124,19 +124,22 @@ fn use_parking_hints(map: &mut RawMap, path: String, timer: &mut Timer) {
|
||||
);
|
||||
|
||||
// Maybe fold back into "both"
|
||||
if tags.contains_key(osm::PARKING_LEFT)
|
||||
&& tags.get(osm::PARKING_LEFT) == tags.get(osm::PARKING_RIGHT)
|
||||
if tags.contains_key("parking:lane:left")
|
||||
&& tags.get("parking:lane:left") == tags.get("parking:lane:right")
|
||||
{
|
||||
let value = tags.remove(osm::PARKING_LEFT).unwrap();
|
||||
tags.remove(osm::PARKING_RIGHT).unwrap();
|
||||
tags.insert(osm::PARKING_BOTH, value);
|
||||
let value = tags.remove("parking:lane:left").unwrap();
|
||||
tags.remove("parking:lane:right").unwrap();
|
||||
tags.insert("parking:lane:both", value);
|
||||
}
|
||||
|
||||
// Remember that this isn't OSM data
|
||||
tags.insert("abst:parking_source", "blockface");
|
||||
|
||||
let lane_specs_ltr = osm2streets::get_lane_specs_ltr(tags, &map.streets.config);
|
||||
let lane_specs_ltr = osm2streets::get_lane_specs_ltr(&tags, &map.streets.config);
|
||||
map.streets.roads.get_mut(&r).unwrap().lane_specs_ltr = lane_specs_ltr;
|
||||
|
||||
// Note the change to the tag isn't saved, so regenerating lanes from tags later would
|
||||
// lose this
|
||||
}
|
||||
}
|
||||
timer.stop("apply parking hints");
|
||||
|
@ -392,6 +392,7 @@ fn fix_lane_widths(value: &mut Value, map: &Map) -> Result<()> {
|
||||
// Before this commit, lane widths weren't modifiable, so this lookup works
|
||||
// for both "old" and "new".
|
||||
width: road.lanes[idx].width,
|
||||
turn_restrictions: Vec::new(),
|
||||
});
|
||||
}
|
||||
cmd[key]["lanes_ltr"] = serde_json::to_value(lanes_ltr).unwrap();
|
||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use abstutil::Timer;
|
||||
use geom::{Distance, HashablePt2D, Line, Speed, Time};
|
||||
use osm2streets::{get_lane_specs_ltr, InputRoad};
|
||||
use osm2streets::{get_lane_specs_ltr, osm, InputRoad};
|
||||
|
||||
pub use self::perma::PermanentMapEdits;
|
||||
use crate::make::{match_points_to_lanes, snap_driveway, trim_path};
|
||||
@ -632,7 +632,7 @@ fn recalculate_intersection_polygon(
|
||||
dst_i: osm2streets::IntersectionID(r.dst_i.0),
|
||||
center_pts: trimmed_center_pts,
|
||||
half_width,
|
||||
osm_tags: r.osm_tags.clone(),
|
||||
highway_type: r.osm_tags.get(osm::HIGHWAY).unwrap().to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,8 @@ impl Map {
|
||||
snap_nodes_with_data_to_line(&r.crossing_nodes, &r.trimmed_center_line);
|
||||
let mut road = Road {
|
||||
id: road_id,
|
||||
osm_tags: r.osm_tags.clone(),
|
||||
// Arbitrarily remember OSM tags from one of the ways
|
||||
osm_tags: raw.osm_tags[&r.osm_ids[0].osm_way_id].clone(),
|
||||
turn_restrictions: r
|
||||
.turn_restrictions
|
||||
.iter()
|
||||
@ -154,7 +155,7 @@ impl Map {
|
||||
src_i: i1,
|
||||
dst_i: i2,
|
||||
speed_limit: Speed::ZERO,
|
||||
zorder: r.get_zorder(),
|
||||
zorder: r.layer,
|
||||
access_restrictions: AccessRestrictions::new(),
|
||||
percent_incline: r.percent_incline,
|
||||
crosswalk_forward: r.crosswalk_forward,
|
||||
|
@ -6,8 +6,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use geom::{Distance, Line, PolyLine, Polygon, Pt2D};
|
||||
|
||||
use crate::{
|
||||
osm, DirectedRoadID, Direction, DrivingSide, IntersectionID, LaneType, Map, MapConfig, Road,
|
||||
RoadID, RoadSideID, SideOfRoad, TurnType,
|
||||
DirectedRoadID, Direction, DrivingSide, IntersectionID, LaneType, Map, MapConfig, Road, RoadID,
|
||||
RoadSideID, SideOfRoad, TurnType,
|
||||
};
|
||||
|
||||
/// From some manually audited cases in Seattle, the length of parallel street parking spots is a
|
||||
@ -244,11 +244,15 @@ impl Lane {
|
||||
return None;
|
||||
}
|
||||
|
||||
let all = if self.dir == Direction::Fwd && road.osm_tags.contains_key(osm::ENDPT_FWD) {
|
||||
// TODO This'll interpret turn restrictions along every segment of an OSM way. They maybe
|
||||
// only make sense for the first or last segment.
|
||||
// TODO We could plumb forward LaneSpec.turn_restrictions instead of redoing some work here
|
||||
|
||||
let all = if self.dir == Direction::Fwd {
|
||||
road.osm_tags
|
||||
.get("turn:lanes:forward")
|
||||
.or_else(|| road.osm_tags.get("turn:lanes"))?
|
||||
} else if self.dir == Direction::Back && road.osm_tags.contains_key(osm::ENDPT_BACK) {
|
||||
} else if self.dir == Direction::Back {
|
||||
road.osm_tags.get("turn:lanes:backward")?
|
||||
} else {
|
||||
return None;
|
||||
|
@ -203,6 +203,8 @@ impl Road {
|
||||
lt: l.lane_type,
|
||||
dir: l.dir,
|
||||
width: l.width,
|
||||
// TODO These get lost from osm2streets
|
||||
turn_restrictions: Vec::new(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -228,7 +230,7 @@ impl Road {
|
||||
}
|
||||
|
||||
pub(crate) fn speed_limit_from_osm(&self) -> Speed {
|
||||
if let Some(limit) = self.osm_tags.get(osm::MAXSPEED) {
|
||||
if let Some(limit) = self.osm_tags.get("maxspeed") {
|
||||
if let Ok(kmph) = limit.parse::<f64>() {
|
||||
if kmph == 0.0 {
|
||||
warn!("{} has a speed limit of 0", self.orig_id.osm_way_id);
|
||||
@ -366,7 +368,7 @@ impl Road {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(name) = self.osm_tags.get(osm::NAME) {
|
||||
if let Some(name) = self.osm_tags.get("name") {
|
||||
if name.is_empty() {
|
||||
return "???".to_string();
|
||||
} else {
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use osm2streets::{osm, StreetNetwork};
|
||||
use osm2streets::{osm, RoadID, StreetNetwork};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use abstio::{CityName, MapName};
|
||||
@ -46,6 +46,11 @@ pub struct RawMap {
|
||||
deserialize_with = "deserialize_multimap"
|
||||
)]
|
||||
pub bus_routes_on_roads: MultiMap<osm::WayID, String>,
|
||||
#[serde(
|
||||
serialize_with = "serialize_btreemap",
|
||||
deserialize_with = "deserialize_btreemap"
|
||||
)]
|
||||
pub osm_tags: BTreeMap<osm::WayID, Tags>,
|
||||
}
|
||||
|
||||
impl RawMap {
|
||||
@ -60,6 +65,7 @@ impl RawMap {
|
||||
transit_routes: Vec::new(),
|
||||
transit_stops: BTreeMap::new(),
|
||||
bus_routes_on_roads: MultiMap::new(),
|
||||
osm_tags: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,6 +76,12 @@ impl RawMap {
|
||||
pub fn get_city_name(&self) -> &CityName {
|
||||
&self.name.city
|
||||
}
|
||||
|
||||
// Only returns tags for one of the way IDs arbitrarily!
|
||||
pub fn road_to_osm_tags(&self, id: RoadID) -> Option<&Tags> {
|
||||
let way = self.streets.roads[&id].osm_ids.get(0)?.osm_way_id;
|
||||
self.osm_tags.get(&way)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
Loading…
Reference in New Issue
Block a user