2020-10-01 01:35:08 +03:00
<!DOCTYPE HTML>
< html lang = "en" class = "sidebar-visible no-js light" >
< head >
<!-- Book generated using mdBook -->
< meta charset = "UTF-8" >
< title > Exporting - A/B Street< / title >
< meta content = "text/html; charset=utf-8" http-equiv = "Content-Type" >
< meta name = "description" content = "" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< meta name = "theme-color" content = "#ffffff" / >
< link rel = "shortcut icon" href = "../favicon.png" >
< link rel = "stylesheet" href = "../css/variables.css" >
< link rel = "stylesheet" href = "../css/general.css" >
< link rel = "stylesheet" href = "../css/chrome.css" >
< link rel = "stylesheet" href = "../css/print.css" media = "print" >
<!-- Fonts -->
< link rel = "stylesheet" href = "../FontAwesome/css/font-awesome.css" >
< link href = "https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel = "stylesheet" type = "text/css" >
< link href = "https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel = "stylesheet" type = "text/css" >
<!-- Highlight.js Stylesheets -->
< link rel = "stylesheet" href = "../highlight.css" >
< link rel = "stylesheet" href = "../tomorrow-night.css" >
< link rel = "stylesheet" href = "../ayu-highlight.css" >
<!-- Custom theme stylesheets -->
< / head >
< body >
<!-- Provide site root to javascript -->
< script type = "text/javascript" >
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
< / script >
<!-- Work around some values being stored in localStorage wrapped in quotes -->
< script type = "text/javascript" >
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') & & theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') & & sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
< / script >
<!-- Set the theme before any content is loaded, prevents flash -->
< script type = "text/javascript" >
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
< / script >
<!-- Hide / unhide sidebar before it is displayed -->
< script type = "text/javascript" >
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
< / script >
< nav id = "sidebar" class = "sidebar" aria-label = "Table of contents" >
< div class = "sidebar-scrollbox" >
2020-12-18 23:34:01 +03:00
< ol class = "chapter" > < li class = "chapter-item expanded " > < a href = "../index.html" > < strong aria-hidden = "true" > 1.< / strong > Overview< / a > < / li > < li class = "chapter-item expanded " > < a href = "../howto/index.html" > < strong aria-hidden = "true" > 2.< / strong > Instructions< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../howto/new_city.html" > < strong aria-hidden = "true" > 2.1.< / strong > Importing a new city< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../how_it_works.html" > < strong aria-hidden = "true" > 3.< / strong > How it works< / a > < / li > < li class = "chapter-item expanded " > < a href = "../case_studies/index.html" > < strong aria-hidden = "true" > 4.< / strong > Case studies< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../case_studies/lake_wash.html" > < strong aria-hidden = "true" > 4.1.< / strong > Lake Washington Blvd Stay Healthy Street< / a > < / li > < li class = "chapter-item expanded " > < a href = "../case_studies/west_seattle.html" > < strong aria-hidden = "true" > 4.2.< / strong > West Seattle mitigations< / a > < / li > < li class = "spacer" > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../dev/index.html" > < strong aria-hidden = "true" > 5.< / strong > Developer guide< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../dev/misc_tricks.html" > < strong aria-hidden = "true" > 5.1.< / strong > Misc developer tricks< / a > < / li > < li class = "chapter-item expanded " > < a href = "../dev/api.html" > < strong aria-hidden = "true" > 5.2.< / strong > API< / a > < / li > < li class = "chapter-item expanded " > < a href = "../dev/testing.html" > < strong aria-hidden = "true" > 5.3.< / strong > Testing< / a > < / li > < li class = "chapter-item expanded " > < a href = "../dev/mass_import.html" > < strong aria-hidden = "true" > 5.4.< / strong > Importing many maps< / a > < / li > < li class = "chapter-item expanded " > < a href = "../dev/data.html" > < strong aria-hidden = "true" > 5.5.< / strong > Data organization< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../map/index.html" > < strong aria-hidden = "true" > 6.< / strong > Map model< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../map/details.html" > < strong aria-hidden = "true" > 6.1.< / strong > Details< / a > < / li > < li class = "chapter-item expanded " > < a href = "../map/importing/index.html" > < strong aria-hidden = "true" > 6.2.< / strong > Importing< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../map/importing/convert_osm.html" > < strong aria-hidden = "true" > 6.2.1.< / strong > convert_osm< / a > < / li > < li class = "chapter-item expanded " > < a href = "../map/importing/geometry.html" > < strong aria-hidden = "true" > 6.2.2.< / strong > Road/intersection geometry< / a > < / li > < li class = "chapter-item expanded " > < a href = "../map/importing/rest.html" > < strong aria-hidden = "true" > 6.2.3.< / strong > The rest< / a > < / li > < li class = "chapter-item expanded " > < a href = "../map/importing/misc.html" > < strong aria-hidden = "true" > 6.2.4.< / strong > Misc< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../map/edits.html" > < strong aria-hidden = "true" > 6.3.< / strong > Live edits< / a > < / li > < li class = "chapter-item expanded " > < a href = "../map/platform.html" class = "active" > < strong aria-hidden = "true" > 6.4.< / strong > Exporting< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../trafficsim/index.html" > < strong aria-hidden = "true" > 7.< / strong > Traffic simulation< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../trafficsim/discrete_event.html" > < strong aria-hidden = "true" > 7.1.< / strong > Discrete event simulation< / a > < / li > < li class = "chapter-item expanded " > < a href = "../trafficsim/travel_demand.html" > < strong aria-hidden = "true" > 7.2.< / strong > Travel demand< / a > < / li > < li class = "chapter-item expanded " > < a href = "../trafficsim/gridlock.html" > < strong aria-hidden = "true" > 7.3.< / strong > Gridlock< / a > < / li > < li class = "chapter-item expanded " > < a href = "../trafficsim/trips.html" > < strong aria-hidden = "true" > 7.4.< / strong > Multi-modal trips< / a > < / li > < li class = "chapter-item expanded " > < a href = "../trafficsim/live_edits.html" > < strong aria-hidden = "true" > 7.5.< / strong > Live edits< / a > < / li > < li class = "chapter-item expanded " > < a href = "../trafficsim/parking.html" > < strong aria-hidde
2020-10-01 01:35:08 +03:00
< / div >
< div id = "sidebar-resize-handle" class = "sidebar-resize-handle" > < / div >
< / nav >
< div id = "page-wrapper" class = "page-wrapper" >
< div class = "page" >
< div id = "menu-bar-hover-placeholder" > < / div >
< div id = "menu-bar" class = "menu-bar sticky bordered" >
< div class = "left-buttons" >
< button id = "sidebar-toggle" class = "icon-button" type = "button" title = "Toggle Table of Contents" aria-label = "Toggle Table of Contents" aria-controls = "sidebar" >
< i class = "fa fa-bars" > < / i >
< / button >
< button id = "theme-toggle" class = "icon-button" type = "button" title = "Change theme" aria-label = "Change theme" aria-haspopup = "true" aria-expanded = "false" aria-controls = "theme-list" >
< i class = "fa fa-paint-brush" > < / i >
< / button >
< ul id = "theme-list" class = "theme-popup" aria-label = "Themes" role = "menu" >
< li role = "none" > < button role = "menuitem" class = "theme" id = "light" > Light (default)< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "rust" > Rust< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "coal" > Coal< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "navy" > Navy< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "ayu" > Ayu< / button > < / li >
< / ul >
< button id = "search-toggle" class = "icon-button" type = "button" title = "Search. (Shortkey: s)" aria-label = "Toggle Searchbar" aria-expanded = "false" aria-keyshortcuts = "S" aria-controls = "searchbar" >
< i class = "fa fa-search" > < / i >
< / button >
< / div >
< h1 class = "menu-title" > A/B Street< / h1 >
< div class = "right-buttons" >
< a href = "../print.html" title = "Print this book" aria-label = "Print this book" >
< i id = "print-button" class = "fa fa-print" > < / i >
< / a >
< / div >
< / div >
< div id = "search-wrapper" class = "hidden" >
< form id = "searchbar-outer" class = "searchbar-outer" >
< input type = "search" name = "search" id = "searchbar" name = "searchbar" placeholder = "Search this book ..." aria-controls = "searchresults-outer" aria-describedby = "searchresults-header" >
< / form >
< div id = "searchresults-outer" class = "searchresults-outer hidden" >
< div id = "searchresults-header" class = "searchresults-header" > < / div >
< ul id = "searchresults" >
< / ul >
< / div >
< / div >
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
< script type = "text/javascript" >
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
< / script >
< div id = "content" class = "content" >
< main >
< h1 > < a class = "header" href = "#ab-streets-map-model-as-a-platform" id = "ab-streets-map-model-as-a-platform" > A/B Street's map model as a platform< / a > < / h1 >
< p > A/B Street's representation of a city, built mostly from OSM and lots of
heuristics, is likely useful to other projects. This doc brainstorms what it
would look like to properly expose it to other users.< / p >
< p > To sum up what the map model provides: geometry + semantics.< / p >
< h2 > < a class = "header" href = "#use-cases" id = "use-cases" > Use cases< / a > < / h2 >
< ul >
< li > Different UIs (particularly 3D / VR) for exploring cities as they are or as
they could be, like Streetmix 3D and Complete Street Rule< / li >
< li > Importing slices of a city as assets into a game engine like Godot
< ul >
< li > Imagine a hackathon where people easily build games based on the real world< / li >
< li > Like < a href = "https://developers.google.com/maps/documentation/gaming/overview_musk" > https://developers.google.com/maps/documentation/gaming/overview_musk< / a >
but open< / li >
< / ul >
< / li >
2020-10-08 09:23:37 +03:00
< li > A new OSM viewer/editor, particularly focused on POIs< / li >
< li > Something focusing on 15-minute neighborhoods, with isochrones and nearby
amenities< / li >
2020-10-01 01:35:08 +03:00
< / ul >
< p > TODO: Give a quick Python example of what interacting with the end goal could
look like.< / p >
< h2 > < a class = "header" href = "#just-data-is-not-enough" id = "just-data-is-not-enough" > Just data is not enough< / a > < / h2 >
< p > At first glance, the existing < code > Map< / code > structure could be written to some format
with a nicely documented schema. This would certainly be useful, but it's not
nearly enough. Interpreting the data sometimes requires lots of code, which
already exists -- so why not expose it to users as well?< / p >
< p > Examples in OSM where I wish " standard libraries" existed to interpret the data:< / p >
< ul >
< li > The simple task of detecting intersections between ways< / li >
< li > < a href = "https://github.com/dabreegster/abstreet/blob/master/map_model/src/make/initial/lane_specs.rs" > Figuring out what lanes a road has from tags< / a > < / li >
< li > Gluing multipolygons together< / li >
< li > Inferring turns at an intersection, subject to the several types of turn
restrictions< / li >
< / ul >
< p > A/B Street solves these problems (or at least it tries to), but by itself, the
resulting data isn't always useful. So some examples of where a library would be
needed too:< / p >
< ul >
< li > Pathfinding. ABST does lots of work especially to handle " live" map edits and
cheaply regenerate contraction hierarchies. Also, pathfinding requires obeying
OSM turn restrictions that span multiple roads -- this prevents even plain old
Dijkstra's from working correctly.< / li >
< li > Getting geometry in different forms. Lanes are stored as a < code > PolyLine< / code > , but
what if a consumer wants the thickened < code > Polygon< / code > , either as points, or maybe
even pre-triangulated vertices and indices?< / li >
< / ul >
< h2 > < a class = "header" href = "#how-would-an-apilibrary-work" id = "how-would-an-apilibrary-work" > How would an API/library work?< / a > < / h2 >
< p > The traditional approach is to link against part of A/B Street as a library and
call it through language-specific bindings. The more language-agnostic option is
defining an API (maybe JSON or protobuf) and having clients run a local A/B
Street server, making HTTP requests to it. This is like the " sidecar" pattern in
microservice-land.< / p >
< h2 > < a class = "header" href = "#compatibility" id = "compatibility" > Compatibility< / a > < / h2 >
< p > Really have to think through this carefully. Some examples of big changes on the
horizon:< / p >
< ul >
< li > Additive: separate cycleways and tramways. Likely no schema change.< / li >
< li > Modify: traffic signals will get
< a href = "https://github.com/dabreegster/abstreet/issues/295" > more complex< / a > < / li >
< li > Modify: we'll likely try again to merge tiny intersections together, which
would get rid of the current guarantees that a road/intersection is associated
to one particular OSM object< / li >
< / ul >
< h2 > < a class = "header" href = "#layering" id = "layering" > Layering< / a > < / h2 >
< p > Clients should be able to opt into different data layers. For example, A/B
Street strips out OSM building tags right now to keep filesizes small. But an
OSM viewer would want to keep this (and likely discard the large contraction
hierarchies). So some pieces of the map model need to be teased apart into
optional pieces, and probably loaded in as separate files.< / p >
< h2 > < a class = "header" href = "#the-bigger-vision" id = "the-bigger-vision" > The bigger vision< / a > < / h2 >
< p > Depending what other open source projects are on board, the general idea is to
start assembling an ecosystem of libraries/tooling to make it easier to build
new things off of open GIS data.< / p >
2020-10-14 21:34:34 +03:00
< p > The end state might look like this. A few separate applications would exist, all
running both natively and in the browser:< / p >
< ul >
< li > A/B Street the game, more or less in its current form< / li >
< li > A new OpenStreetMap viewer, likely focused on visualizing roads and
points-of-interest in detail< / li >
< li > The street parking OSM editor, and other OSM editors specialized for mapping
certain things< / li >
< li > A new app focusing on 15-minute neighborhoods, using isochrones to show
amenities available nearby
< ul >
< li > Ideally, allow editing current land use / zoning, to let people explore how
new policies might get closer to a 15-minute neighborhood.< / li >
< li > Possibly < a href = "https://www.open-accessibility.org" > GOAT< / a > does all of this
already, and this new thing shouldn't be built< / li >
< / ul >
< / li >
< li > A new app for creating story maps, showing events that occur over time, with
lots of detail about the surrounding environment< / li >
< / ul >
< p > All of these would make use of some common libraries, which should be extracted
out cleanly from A/B Street today:< / p >
< ul >
< li > the map model and OSM importer< / li >
< li > the widgetry UI library< / li >
< li > some common code for specifically interacting with maps in widgetry< / li >
< li > a tool to generate a traffic demand model from OSM data, optional census data,
etc
< ul >
< li > This has been initially
< a href = "https://dabreegster.github.io/abstreet/trafficsim/travel_demand.html#proletariat-robot" > prototyped< / a > < / li >
< / ul >
< / li >
< li > the discrete-event traffic simulation that A/B Street uses today< / li >
< li > core geometry/utility libraries< / li >
< / ul >
< p > But note only the first application would use things like the simulation
library. The point of more cleanly modularizing these pieces is to make it
easier for new people to build different pieces, without having to understand
and be coupled to everything else. Also, as appropriate, these pieces should use
common data formats (like
< a href = "https://github.com/d-wasserman/shared-row/" > shared-row< / a > ) to be interoperable
with Streetmix, Complete Streets, etc.< / p >
2020-10-01 01:35:08 +03:00
< / main >
< nav class = "nav-wrapper" aria-label = "Page navigation" >
<!-- Mobile navigation buttons -->
2020-10-12 04:38:32 +03:00
< a rel = "prev" href = "../map/edits.html" class = "mobile-nav-chapters previous" title = "Previous chapter" aria-label = "Previous chapter" aria-keyshortcuts = "Left" >
2020-10-01 01:35:08 +03:00
< i class = "fa fa-angle-left" > < / i >
< / a >
< a rel = "next" href = "../trafficsim/index.html" class = "mobile-nav-chapters next" title = "Next chapter" aria-label = "Next chapter" aria-keyshortcuts = "Right" >
< i class = "fa fa-angle-right" > < / i >
< / a >
< div style = "clear: both" > < / div >
< / nav >
< / div >
< / div >
< nav class = "nav-wide-wrapper" aria-label = "Page navigation" >
2020-10-12 04:38:32 +03:00
< a rel = "prev" href = "../map/edits.html" class = "nav-chapters previous" title = "Previous chapter" aria-label = "Previous chapter" aria-keyshortcuts = "Left" >
2020-10-01 01:35:08 +03:00
< i class = "fa fa-angle-left" > < / i >
< / a >
< a rel = "next" href = "../trafficsim/index.html" class = "nav-chapters next" title = "Next chapter" aria-label = "Next chapter" aria-keyshortcuts = "Right" >
< i class = "fa fa-angle-right" > < / i >
< / a >
< / nav >
< / div >
< script type = "text/javascript" >
window.playpen_copyable = true;
< / script >
< script src = "../elasticlunr.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../mark.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../searcher.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../clipboard.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../highlight.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../book.js" type = "text/javascript" charset = "utf-8" > < / script >
<!-- Custom JS scripts -->
< / body >
< / html >