1use std::collections::BTreeMap;
2
3use anyhow::Result;
4use serde::Deserialize;
5use serde_json::Value;
6
7use abstio::{CityName, MapName};
8use geom::Speed;
9
10use crate::{
11 osm, AccessRestrictions, Direction, EditCmd, EditRoad, LaneSpec, LaneType, Map, OriginalRoad,
12 PermanentMapEdits, RoadID,
13};
14
15pub fn upgrade(mut value: Value, map: &Map) -> Result<PermanentMapEdits> {
23 if value.get("version").is_none() {
26 fix_offset(&mut value);
29 fix_intersection_ids(&mut value);
30
31 value
32 .as_object_mut()
33 .unwrap()
34 .insert("version".to_string(), Value::Number(0.into()));
35 }
36 if value["version"] == Value::Number(0.into()) {
37 fix_road_direction(&mut value);
38 value
39 .as_object_mut()
40 .unwrap()
41 .insert("version".to_string(), Value::Number(1.into()));
42 }
43 if value["version"] == Value::Number(1.into()) {
44 fix_old_lane_cmds(&mut value, map)?;
45 value
46 .as_object_mut()
47 .unwrap()
48 .insert("version".to_string(), Value::Number(2.into()));
49 }
50 if value["version"] == Value::Number(2.into()) {
51 fix_merge_zones(&mut value);
52 value
53 .as_object_mut()
54 .unwrap()
55 .insert("version".to_string(), Value::Number(3.into()));
56 }
57 if value["version"] == Value::Number(3.into()) {
58 fix_map_name(&mut value);
59 value
60 .as_object_mut()
61 .unwrap()
62 .insert("version".to_string(), Value::Number(4.into()));
63 }
64 if value["version"] == Value::Number(4.into()) {
65 fix_phase_to_stage(&mut value);
66 value
67 .as_object_mut()
68 .unwrap()
69 .insert("version".to_string(), Value::Number(5.into()));
70 }
71 if value["version"] == Value::Number(5.into()) {
72 fix_adaptive_stages(&mut value);
73 value
74 .as_object_mut()
75 .unwrap()
76 .insert("version".to_string(), Value::Number(6.into()));
77 }
78 if value["version"] == Value::Number(6.into()) {
79 fix_plans(&mut value);
80 value
81 .as_object_mut()
82 .unwrap()
83 .insert("version".to_string(), Value::Number(7.into()));
84 }
85 if value["version"] == Value::Number(7.into()) {
86 fix_city_name(&mut value);
87 value
88 .as_object_mut()
89 .unwrap()
90 .insert("version".to_string(), Value::Number(8.into()));
91 }
92 if value["version"] == Value::Number(8.into()) {
93 fix_lane_widths(&mut value, map)?;
94 value
95 .as_object_mut()
96 .unwrap()
97 .insert("version".to_string(), Value::Number(9.into()));
98 }
99 if value["version"] == Value::Number(9.into()) {
100 fix_f64s(&mut value);
101 value
102 .as_object_mut()
103 .unwrap()
104 .insert("version".to_string(), Value::Number(10.into()));
105 }
106 if value["version"] == Value::Number(10.into()) {
107 remove_vehicle_caps(&mut value);
108 value
109 .as_object_mut()
110 .unwrap()
111 .insert("version".to_string(), Value::Number(11.into()));
112 }
113 if value["version"] == Value::Number(11.into()) {
114 fix_turn_restrictions(&mut value);
115 value
116 .as_object_mut()
117 .unwrap()
118 .insert("version".to_string(), Value::Number(12.into()));
119 }
120 if value["version"] == Value::Number(12.into()) {
121 bail!("Breaking changes happened to map edits between v12 and v13. Recreate your edits from scratch; sorry.");
122 }
123
124 abstutil::from_json(&value.to_string().into_bytes())
125}
126
127fn walk<F: Fn(&mut serde_json::Map<String, Value>) -> bool>(value: &mut Value, transform: &F) {
130 match value {
131 Value::Array(list) => {
132 for x in list {
133 walk(x, transform);
134 }
135 }
136 Value::Object(map) => {
137 if !(transform)(map) {
138 for x in map.values_mut() {
139 walk(x, transform);
140 }
141 }
142 }
143 _ => {}
144 }
145}
146
147fn fix_offset(value: &mut Value) {
149 walk(value, &|map| {
150 if map.len() == 1 && map.contains_key("TrafficSignal") {
151 let ts = map
152 .get_mut("TrafficSignal")
153 .unwrap()
154 .as_object_mut()
155 .unwrap();
156 if ts.get("offset_seconds").is_none() {
157 ts.insert("offset_seconds".to_string(), Value::Number(0.into()));
158 }
159 true
160 } else {
161 false
162 }
163 })
164}
165
166fn fix_intersection_ids(value: &mut Value) {
168 match value {
169 Value::Array(list) => {
170 for x in list {
171 fix_intersection_ids(x);
172 }
173 }
174 Value::Object(map) => {
175 if map.len() == 1 && map.contains_key("osm_node_id") {
176 *value = Value::Number(map["osm_node_id"].as_i64().unwrap().into());
177 } else {
178 for x in map.values_mut() {
179 fix_intersection_ids(x);
180 }
181 }
182 }
183 _ => {}
184 }
185}
186
187fn fix_road_direction(value: &mut Value) {
189 walk(value, &|map| {
190 if map.contains_key("num_fwd") {
191 map.insert(
192 "dir".to_string(),
193 if map["fwd"].as_bool().unwrap() {
194 "Fwd".into()
195 } else {
196 "Back".into()
197 },
198 );
199 true
200 } else {
201 false
202 }
203 });
204}
205
206fn fix_old_lane_cmds(value: &mut Value, map: &Map) -> Result<()> {
209 let mut modified: BTreeMap<RoadID, EditRoad> = BTreeMap::new();
213 let mut commands = Vec::new();
214 for mut orig in value.as_object_mut().unwrap()["commands"]
215 .as_array_mut()
216 .unwrap()
217 .drain(..)
218 {
219 let cmd = orig.as_object_mut().unwrap();
220 if let Some(obj) = cmd.remove("ChangeLaneType") {
221 let obj: ChangeLaneType = serde_json::from_value(obj).unwrap();
222 let (r, idx) = obj.id.lookup(map)?;
223 let road = modified.entry(r).or_insert_with(|| map.get_r_edit(r));
224 if road.lanes_ltr[idx].lt != obj.orig_lt {
225 bail!("{:?} lane type has changed", obj);
226 }
227 road.lanes_ltr[idx].lt = obj.lt;
228 } else if let Some(obj) = cmd.remove("ReverseLane") {
229 let obj: ReverseLane = serde_json::from_value(obj).unwrap();
230 let (r, idx) = obj.l.lookup(map)?;
231 let dst_i = map.find_i_by_osm_id(obj.dst_i)?;
232 let road = modified.entry(r).or_insert_with(|| map.get_r_edit(r));
233 let edits_dir = if dst_i == map.get_r(r).dst_i {
234 Direction::Fwd
235 } else if dst_i == map.get_r(r).src_i {
236 Direction::Back
237 } else {
238 bail!("{:?}'s road doesn't point to dst_i at all", obj);
239 };
240 if road.lanes_ltr[idx].dir == edits_dir {
241 bail!("{:?}'s road already points to dst_i", obj);
242 }
243 road.lanes_ltr[idx].dir = edits_dir;
244 } else if let Some(obj) = cmd.remove("ChangeSpeedLimit") {
245 let obj: ChangeSpeedLimit = serde_json::from_value(obj).unwrap();
246 let r = map.find_r_by_osm_id(obj.id)?;
247 let road = modified.entry(r).or_insert_with(|| map.get_r_edit(r));
248 if road.speed_limit != obj.old {
249 bail!("{:?} speed limit has changed", obj);
250 }
251 road.speed_limit = obj.new;
252 } else if let Some(obj) = cmd.remove("ChangeAccessRestrictions") {
253 let obj: ChangeAccessRestrictions = serde_json::from_value(obj).unwrap();
254 let r = map.find_r_by_osm_id(obj.id)?;
255 let road = modified.entry(r).or_insert_with(|| map.get_r_edit(r));
256 if road.access_restrictions != obj.old {
257 bail!("{:?} access restrictions have changed", obj);
258 }
259 road.access_restrictions = obj.new.clone();
260 } else {
261 commands.push(orig);
262 }
263 }
264
265 for (r, new) in modified {
266 let old = map.get_r_edit(r);
267 commands
268 .push(serde_json::to_value(EditCmd::ChangeRoad { r, old, new }.to_perma(map)).unwrap());
269 }
270 value.as_object_mut().unwrap()["commands"] = Value::Array(commands);
271 Ok(())
272}
273
274fn fix_merge_zones(value: &mut Value) {
276 let obj = value.as_object_mut().unwrap();
277 if !obj.contains_key("merge_zones") {
278 obj.insert("merge_zones".to_string(), Value::Bool(true));
279 }
280}
281
282fn fix_map_name(value: &mut Value) {
284 let root = value.as_object_mut().unwrap();
285 if let Value::String(ref name) = root["map_name"].clone() {
286 root.insert(
289 "map_name".to_string(),
290 serde_json::to_value(MapName::seattle(name)).unwrap(),
291 );
292 }
293}
294
295fn fix_phase_to_stage(value: &mut Value) {
297 walk(value, &|map| {
298 if let Some(list) = map.remove("phases") {
299 map.insert("stages".to_string(), list);
300 }
301 if let Some(obj) = map.remove("phase_type") {
302 map.insert("stage_type".to_string(), obj);
303 }
304 false
305 });
306}
307
308fn fix_adaptive_stages(value: &mut Value) {
310 walk(value, &|map| {
311 if let Some(seconds) = map.remove("Adaptive") {
312 let minimum = seconds.clone();
317 let delay = Value::Number(1.into());
318 let additional = seconds;
319 map.insert(
320 "Variable".to_string(),
321 Value::Array(vec![minimum, delay, additional]),
322 );
323 }
324 false
325 });
326}
327
328fn fix_plans(value: &mut Value) {
330 walk(value, &|map| {
331 if map.len() == 1 && map.contains_key("TrafficSignal") {
332 let ts = map
333 .get_mut("TrafficSignal")
334 .unwrap()
335 .as_object_mut()
336 .unwrap();
337 let mut plan = serde_json::Map::new();
338 plan.insert("start_time_seconds".to_string(), Value::Number(0.into()));
339 plan.insert("stages".to_string(), ts.remove("stages").unwrap());
340 plan.insert(
341 "offset_seconds".to_string(),
342 ts.remove("offset_seconds").unwrap(),
343 );
344 ts.insert("plans".to_string(), Value::Array(vec![Value::Object(plan)]));
345 true
346 } else {
347 false
348 }
349 })
350}
351
352fn fix_city_name(value: &mut Value) {
354 let root = value.as_object_mut().unwrap();
355 let map_name = root["map_name"].as_object_mut().unwrap();
356 if let Value::String(ref name) = map_name["city"].clone() {
357 let country = match name.as_ref() {
360 "salzburg" => "at",
361 "montreal" => "ca",
362 "berlin" => "de",
363 "paris" => "fr",
364 "leeds" | "london" => "gb",
365 "tel_aviv" => "il",
366 "krakow" | "warsaw" => "pl",
367 _ => "us",
368 };
369 map_name.insert(
370 "city".to_string(),
371 serde_json::to_value(CityName::new(country, name)).unwrap(),
372 );
373 }
374}
375
376fn fix_lane_widths(value: &mut Value, map: &Map) -> Result<()> {
378 for orig in value.as_object_mut().unwrap()["commands"]
379 .as_array_mut()
380 .unwrap()
381 {
382 let cmd = orig.as_object_mut().unwrap();
383 if let Some(cmd) = cmd.get_mut("ChangeRoad") {
384 let road_id: OriginalRoad = serde_json::from_value(cmd["r"].clone()).unwrap();
385 let road = map.get_r(map.find_r_by_osm_id(road_id)?);
386 let cmd = cmd.as_object_mut().unwrap();
387
388 for key in ["old", "new"] {
389 let mut lanes_ltr = Vec::new();
390 for (idx, mut pair) in cmd[key]["lanes_ltr"]
391 .as_array_mut()
392 .unwrap()
393 .drain(..)
394 .enumerate()
395 {
396 let pair = pair.as_array_mut().unwrap();
397 let lt: LaneType = serde_json::from_value(pair[0].clone()).unwrap();
398 let dir: Direction = serde_json::from_value(pair[1].clone()).unwrap();
399 lanes_ltr.push(LaneSpec {
400 lt,
401 dir,
402 width: road.lanes[idx].width,
405 allowed_turns: Default::default(),
406 });
407 }
408 cmd[key]["lanes_ltr"] = serde_json::to_value(lanes_ltr).unwrap();
409 }
410 }
411 }
412 Ok(())
413}
414
415fn fix_f64s(value: &mut Value) {
417 walk(value, &|map| {
418 for key in ["width", "speed_limit"] {
420 if let Some(value) = map.get_mut(key) {
421 if let Value::Number(num) = value {
422 if num.is_f64() {
423 let encoded = (num.as_f64().unwrap() * 10_000.0) as i32;
424 *value = Value::Number(encoded.into());
425 }
426 }
427 }
428 }
429 if map.contains_key("osm_rel_id") {
431 for key in ["old", "new"] {
432 for value in map.get_mut(key).unwrap().as_array_mut().unwrap() {
433 if let Value::Number(num) = value {
434 if num.is_f64() {
435 let encoded = (num.as_f64().unwrap() * 10_000.0) as i32;
436 *value = Value::Number(encoded.into());
437 }
438 }
439 }
440 }
441 }
442
443 false
444 })
445}
446
447fn remove_vehicle_caps(value: &mut Value) {
449 walk(value, &|map| {
450 map.remove("cap_vehicles_per_hour");
451 false
452 });
453}
454
455fn fix_turn_restrictions(value: &mut Value) {
458 for orig in value.as_object_mut().unwrap()["commands"]
459 .as_array_mut()
460 .unwrap()
461 {
462 let cmd = orig.as_object_mut().unwrap();
463 if let Some(cmd) = cmd.get_mut("ChangeRoad") {
464 let cmd = cmd.as_object_mut().unwrap();
465 for key in ["old", "new"] {
466 for spec in cmd[key]["lanes_ltr"].as_array_mut().unwrap() {
467 spec.as_object_mut()
470 .unwrap()
471 .insert("turn_restrictions".to_string(), Value::Array(Vec::new()));
472 }
473 }
474 }
475 }
476}
477
478#[derive(Debug, Deserialize)]
480struct OriginalLane {
481 parent: OriginalRoad,
482 num_fwd: usize,
483 num_back: usize,
484 dir: Direction,
485 idx: usize,
486}
487#[derive(Debug, Deserialize)]
488struct ChangeLaneType {
489 id: OriginalLane,
490 lt: LaneType,
491 orig_lt: LaneType,
492}
493#[derive(Debug, Deserialize)]
494struct ReverseLane {
495 l: OriginalLane,
496 dst_i: osm::NodeID,
498}
499#[derive(Debug, Deserialize)]
500struct ChangeSpeedLimit {
501 id: OriginalRoad,
502 new: Speed,
503 old: Speed,
504}
505#[derive(Debug, Deserialize)]
506struct ChangeAccessRestrictions {
507 id: OriginalRoad,
508 new: AccessRestrictions,
509 old: AccessRestrictions,
510}
511
512impl OriginalLane {
513 fn lookup(&self, map: &Map) -> Result<(RoadID, usize)> {
514 let r = map.get_r(map.find_r_by_osm_id(self.parent)?);
515 let current_fwd = r.children_forwards();
516 let current_back = r.children_backwards();
517 if current_fwd.len() != self.num_fwd || current_back.len() != self.num_back {
518 bail!(
519 "number of lanes in {} is ({} fwd, {} back) now, but ({}, {}) in the edits",
520 r.orig_id,
521 current_fwd.len(),
522 current_back.len(),
523 self.num_fwd,
524 self.num_back
525 );
526 }
527 let l = if self.dir == Direction::Fwd {
528 current_fwd[self.idx].0
529 } else {
530 current_back[self.idx].0
531 };
532 Ok((r.id, l.offset))
533 }
534}