mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
3806 lines
217 KiB
HTML
3806 lines
217 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="sidebar-visible no-js light">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title>A/B Street</title>
|
|
|
|
<meta name="robots" content="noindex" />
|
|
|
|
|
|
<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">
|
|
<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/map_parking.html"><strong aria-hidden="true">2.1.</strong> How to map on-street parking</a></li><li class="chapter-item expanded "><a href="howto/new_city.html"><strong aria-hidden="true">2.2.</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"><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-hidden="true">7.6.</strong> Parking</a></li><li class="spacer"></li></ol></li><li class="chapter-item expanded "><a href="project/index.html"><strong aria-hidden="true">8.</strong> Project</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="project/roadmap.html"><strong aria-hidden="true">8.1.</strong> Roadmap</a></li><li class="chapter-item expanded "><a href="project/motivations.html"><strong aria-hidden="true">8.2.</strong> Motivations</a></li><li class="chapter-item expanded "><a href="project/history/index.html"><strong aria-hidden="true">8.3.</strong> History</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="project/history/backstory.html"><strong aria-hidden="true">8.3.1.</strong> Backstory</a></li><li class="chapter-item expanded "><a href="project/history/year1.html"><strong aria-hidden="true">8.3.2.</strong> Year 1</a></li><li class="chapter-item expanded "><a href="project/history/year2.html"><strong aria-hidden="true">8.3.3.</strong> Year 2</a></li><li class="chapter-item expanded "><a href="project/history/year3.html"><strong aria-hidden="true">8.3.4.</strong> Year 3</a></li></ol></li><li class="chapter-item expanded "><a href="project/CHANGELOG.html"><strong aria-hidden="true">8.4.</strong> Full CHANGELOG</a></li><li class="chapter-item expanded "><a href="project/references.html"><strong aria-hidden="true">8.5.</strong> References</a></li><li class="chapter-item expanded "><a href="project/collaborations.html"><strong aria-hidden="true">8.6.</strong> Collaborations</a></li></ol></li></ol>
|
|
</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-street" id="ab-street">A/B Street</a></h1>
|
|
<p>All documentation lives here. Some chapters are only intended for a technical
|
|
audience.</p>
|
|
<h1><a class="header" href="#ab-street-instructions" id="ab-street-instructions">A/B Street Instructions</a></h1>
|
|
<p>This is an alpha-quality demo. Please email <a href="mailto:howto/dabreegster@gmail.com">dabreegster@gmail.com</a> or
|
|
<a href="https://github.com/dabreegster/abstreet/issues/">file a Github issue</a> if you
|
|
hit problems.</p>
|
|
<h2><a class="header" href="#installing-the-game" id="installing-the-game">Installing the game</a></h2>
|
|
<p>Grab a pre-built binary release -- updated every Sunday, announced at
|
|
<a href="http://old.reddit.com/r/abstreet">r/abstreet</a>:</p>
|
|
<ul>
|
|
<li><a href="https://github.com/dabreegster/abstreet/releases/download/v0.2.19/abstreet_windows_v0_2_19.zip">Windows</a>
|
|
<ul>
|
|
<li>Unzip the folder, then run <code>play_abstreet.bat</code>. You'll probably getting a
|
|
warning about running software from an unknown publisher.</li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="https://github.com/dabreegster/abstreet/releases/download/v0.2.19/abstreet_mac_v0_2_19.zip">Mac</a>
|
|
<ul>
|
|
<li>Unzip the directory, then run <code>play_abstreet.sh</code>.</li>
|
|
<li>If you get an error about the developer unverified,
|
|
<a href="https://support.apple.com/guide/mac-help/open-a-mac-app-from-an-unidentified-developer-mh40616/mac">follow this</a>.
|
|
Help needed to start
|
|
<a href="https://github.com/dabreegster/abstreet/issues/107">signing the release</a>!</li>
|
|
<li>If that just opens a text file instead of running the game, then instead
|
|
open terminal, <code>cd</code> to the directory you just unzipped. Then do:
|
|
<code>cd game; RUST_BACKTRACE=1 ./game 1> ../output.txt 2>&1</code></li>
|
|
<li><a href="https://github.com/dabreegster/abstreet/issues/77">Help needed</a> to package
|
|
this as a Mac .app, to make this process simpler</li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="https://github.com/dabreegster/abstreet/releases/download/v0.2.19/abstreet_linux_v0_2_19.zip">Linux</a>
|
|
<ul>
|
|
<li>Unzip the directory, then run <code>play_abstreet.sh</code>.</li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="https://www.freshports.org/games/abstreet/">FreeBSD</a>, thanks to
|
|
<a href="https://github.com/yurivict">Yuri</a></li>
|
|
</ul>
|
|
<p>Or you can try playing
|
|
<a href="http://abstreet.s3-website.us-east-2.amazonaws.com/dev">directly in your web browser</a>
|
|
-- still experimental for now.</p>
|
|
<p>Or you can <a href="howto/../dev/index.html">compile from source</a>.</p>
|
|
<h2><a class="header" href="#playing-the-game" id="playing-the-game">Playing the game</a></h2>
|
|
<ul>
|
|
<li>Use the <strong>tutorial</strong> to learn the controls.</li>
|
|
<li>Play the <strong>challenges</strong> for directed gameplay.</li>
|
|
<li>Try out any ideas in the <strong>sandbox</strong>.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#data-source-licensing" id="data-source-licensing">Data source licensing</a></h2>
|
|
<p>A/B Street binary releases contain pre-built maps that combine data from:</p>
|
|
<ul>
|
|
<li>OpenStreetMap (<a href="https://www.openstreetmap.org/copyright">https://www.openstreetmap.org/copyright</a>)</li>
|
|
<li>King County metro
|
|
(<a href="https://www.kingcounty.gov/depts/transportation/metro/travel-options/bus/app-center/terms-of-use.aspx">https://www.kingcounty.gov/depts/transportation/metro/travel-options/bus/app-center/terms-of-use.aspx</a>)</li>
|
|
<li>City of Seattle GIS program
|
|
(<a href="https://www.opendatacommons.org/licenses/pddl/1.0/">https://www.opendatacommons.org/licenses/pddl/1.0/</a>)</li>
|
|
<li><a href="https://github.com/seattleio/seattle-boundaries-data">https://github.com/seattleio/seattle-boundaries-data</a>
|
|
(<a href="https://creativecommons.org/publicdomain/zero/1.0/">https://creativecommons.org/publicdomain/zero/1.0/</a>)</li>
|
|
<li>Puget Sound Regional Council
|
|
(<a href="https://www.psrc.org/activity-based-travel-model-soundcast">https://www.psrc.org/activity-based-travel-model-soundcast</a>)</li>
|
|
<li>USGS SRTM</li>
|
|
</ul>
|
|
<p>Other binary data bundled in:</p>
|
|
<ul>
|
|
<li>Overpass font (<a href="https://fonts.google.com/specimen/Overpass">https://fonts.google.com/specimen/Overpass</a>, Open Font
|
|
License)</li>
|
|
<li>Bungee fonts (<a href="https://fonts.google.com/specimen/Bungee">https://fonts.google.com/specimen/Bungee</a>, Open Font License)</li>
|
|
<li>Material Design icons (<a href="https://material.io/resources/icons">https://material.io/resources/icons</a>, Apache license)</li>
|
|
<li>Some Graphics textures (<a href="https://www.kenney.nl/">https://www.kenney.nl/</a>, CC0 1.0 Universal)</li>
|
|
</ul>
|
|
<h1><a class="header" href="#help-map-out-on-street-parking" id="help-map-out-on-street-parking">Help map out on-street parking</a></h1>
|
|
<p><img src="howto/parking_mapper.gif" alt="parking_mapper" /></p>
|
|
<p>This guide assumes you've edited OSM before. Contact <a href="mailto:howto/dabreegster@gmail.com">dabreegster@gmail.com</a> if
|
|
you have any trouble. Also give me a heads up when you make some edits, so I can
|
|
regenerate the maps!</p>
|
|
<ol>
|
|
<li><a href="howto/index.html">Install A/B Street</a></li>
|
|
<li>Choose <strong>Contribute parking data</strong> on the main screen</li>
|
|
<li>Change the map if you'd like to focus somewhere in particular</li>
|
|
<li>Click a road with unknown parking</li>
|
|
<li>Select what kind of on-street parking the road has</li>
|
|
<li>Repeat</li>
|
|
<li>Click <strong>Generate OsmChange file</strong></li>
|
|
<li>Upload the diff.osc file by adding a layer in JOSM (or send it to me)</li>
|
|
</ol>
|
|
<p>Like all edits to OSM, to figure out ground-truth, you can survey in-person or
|
|
use
|
|
<a href="https://wiki.openstreetmap.org/wiki/Bing_Maps#Streetside_imagery">Bing Streetside</a>.
|
|
<strong>Do not use data from Google Maps to edit OSM.</strong></p>
|
|
<h2><a class="header" href="#faq" id="faq">FAQ</a></h2>
|
|
<h3><a class="header" href="#why" id="why">Why?</a></h3>
|
|
<p>I'm trying to build a realistic traffic simulation of Seattle using OSM data,
|
|
then use it to strengthen proposals for
|
|
<a href="howto/../case_studies/lake_wash.html">pedestrianized streets</a>,
|
|
<a href="https://www.glwstreets.org/45th-st-bridge-overview">improving the bike network</a>,
|
|
and
|
|
<a href="howto/../case_studies/west_seattle.html">mitigating the West Seattle bridge closure</a>.
|
|
A/B Street is only as good as its data, and parking is one of the biggest gaps.
|
|
Missing data means unrealistic traffic as vehicles contend for few parking
|
|
spots, and roads that look much wider than they are in reality.</p>
|
|
<h3><a class="header" href="#why-put-this-data-in-osm" id="why-put-this-data-in-osm">Why put this data in OSM?</a></h3>
|
|
<p>Why can't I just grab parking data from
|
|
<a href="http://web6.seattle.gov/SDOT/seattleparkingmap/">SDOT's map</a>, using the
|
|
<a href="http://data-seattlecitygis.opendata.arcgis.com/datasets/blockface">blockface</a>
|
|
dataset? Well, I'm trying -- when you see a parking lane in the tool, it's
|
|
coming from blockface, unless that road in OSM is tagged. But the blockface
|
|
dataset is comically wrong in many places -- for example, the Montlake bridge
|
|
apparently has unrestricted parking?! King County GIS has confirmed the dataset
|
|
isn't meant to be used for this level of detail.</p>
|
|
<p>Plus, if the data is in OSM, anybody else can make use of it.</p>
|
|
<h3><a class="header" href="#how-does-the-tool-work" id="how-does-the-tool-work">How does the tool work?</a></h3>
|
|
<p>A/B Street attempts to render individual lanes and intersections from OSM data.
|
|
This makes it useful to audit the lane tags in OSM, including
|
|
<a href="https://wiki.openstreetmap.org/wiki/Key:parking:lane">parking:lane</a>. The tool
|
|
tracks your edits and when you generate the OsmChange file, it grabs modified
|
|
ways from the OSM API to generate a diff. You can inspect the diff, load it in
|
|
JOSM, and upload.</p>
|
|
<p><strong>Your changes won't immediately be reflected in A/B Street.</strong> Let me know when
|
|
you've done some amount of mapping, and I'll regenerate the maps from fresh
|
|
data.</p>
|
|
<h3><a class="header" href="#why-use-this-tool" id="why-use-this-tool">Why use this tool?</a></h3>
|
|
<p>You don't have to; <a href="https://zlant.github.io/parking-lanes/">this tool</a> or ID or
|
|
JOSM all work. But the UI is clunky for this specific purpose. (Also, if you
|
|
find this tool clunky in any way, let me know and I'll fix it.) There's also a
|
|
proposed
|
|
<a href="https://github.com/westnordost/StreetComplete/issues/771">StreetComplete quest</a>.</p>
|
|
<h3><a class="header" href="#what-about-parking-restrictions" id="what-about-parking-restrictions">What about parking restrictions?</a></h3>
|
|
<p>There are many
|
|
<a href="https://wiki.openstreetmap.org/wiki/Key:parking:lane">parking:lane</a> tags to
|
|
indicate restricted parking zones, time restrictions, etc. Feel free to map that
|
|
in ID or JOSM, but I'm just looking to make a first pass over a wide area.</p>
|
|
<h3><a class="header" href="#what-about-off-street-parking" id="what-about-off-street-parking">What about off-street parking?</a></h3>
|
|
<p>Ideally I'd also like to know how many private parking spots are available to
|
|
residents of each building. But I don't know of an OSM schema for mapping this,
|
|
or a practical way to collect this data. Let me know if you have ideas.</p>
|
|
<h3><a class="header" href="#what-about-long-roads-where-parking-appears-and-disappears" id="what-about-long-roads-where-parking-appears-and-disappears">What about long roads where parking appears and disappears?</a></h3>
|
|
<p>The tool won't help. Use your favorite editor to split the way when the lane
|
|
configuration changes. Also feel free to just skip these areas.</p>
|
|
<h3><a class="header" href="#how-to-coordinate-with-other-mappers" id="how-to-coordinate-with-other-mappers">How to coordinate with other mappers?</a></h3>
|
|
<p>If somebody wants to set up HOT tasking, that'd be great, but I don't expect so
|
|
many people to jump on this.</p>
|
|
<h3><a class="header" href="#i-noticed-weird-roads-in-the-tool" id="i-noticed-weird-roads-in-the-tool">I noticed weird roads in the tool</a></h3>
|
|
<p>Welcome to my world. ;) If the number of lanes seems wrong, select the road and
|
|
check the OSM tags. I'm inferring lanes from that. Feel free to make manual OSM
|
|
edits to fix any problems you see. (I'd like to extend this tool to make that
|
|
easier; let me know if you have ideas how to do this.)</p>
|
|
<h3><a class="header" href="#i-want-to-map-an-area-but-theres-no-option-for-it" id="i-want-to-map-an-area-but-theres-no-option-for-it">I want to map an area, but there's no option for it</a></h3>
|
|
<p>To keep the release size small, I'm not including all maps yet. Let me know what
|
|
you'd like to see included.</p>
|
|
<p>Or if you have a <code>.osm</code> file, try the <a href="howto/new_city.html">quick start guide</a>.</p>
|
|
<h1><a class="header" href="#importing-a-new-city-into-ab-street" id="importing-a-new-city-into-ab-street">Importing a new city into A/B Street</a></h1>
|
|
<p>This process isn't easy yet. Please email <a href="mailto:howto/dabreegster@gmail.com">dabreegster@gmail.com</a> or
|
|
<a href="https://github.com/dabreegster/abstreet/issues/">file a Github issue</a> if you
|
|
hit problems. I'd really appreciate help and PRs to improve this.</p>
|
|
<h2><a class="header" href="#quick-start" id="quick-start">Quick start</a></h2>
|
|
<p>Use this if you want to import a city on your computer without making it
|
|
available to other users yet.</p>
|
|
<ul>
|
|
<li>
|
|
<p>If you're using the <strong>binary release</strong> and have a <code>.osm</code> file, just do:
|
|
<code>./importer --oneshot=map.osm</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>If you're building <strong>from source</strong>, do: <code>./import.sh --oneshot=map.osm</code>. If
|
|
you can't run <code>import.sh</code>, make sure you have all
|
|
<a href="howto/../dev/index.html#building-map-data">dependencies</a>. If you're using Windows and
|
|
the console logs appear in a new window, try running the command from
|
|
<code>import.sh</code> directly, changing the <code>$@</code> at the end to <code>--oneshot=map.osm</code> or
|
|
whatever arguments you're passing in.</p>
|
|
</li>
|
|
</ul>
|
|
<p>The oneshot importer will will generate a new file in <code>data/system/oneshot/maps</code>
|
|
that you can then load in the game. If you have an Osmosis polygon filter (see
|
|
below), you can also pass <code>--oneshot_clip=clip.poly</code> to improve the result. You
|
|
should first make sure your .osm has been clipped:
|
|
<code>osmconvert large_map.osm -B=clipping.poly --complete-ways -o=smaller_map.osm</code>.</p>
|
|
<p>By default, driving on the right is assumed. Use <code>--oneshot_drive_on_left</code> to
|
|
invert.</p>
|
|
<h3><a class="header" href="#how-to-get-osm-files" id="how-to-get-osm-files">How to get .osm files</a></h3>
|
|
<p>If the area is small enough, try the "export" tool on
|
|
<a href="https://www.openstreetmap.org">https://www.openstreetmap.org</a>. You can download larger areas from
|
|
<a href="https://download.bbbike.org/">https://download.bbbike.org/</a> or <a href="http://download.geofabrik.de/index.html">http://download.geofabrik.de/index.html</a>,
|
|
then clip them to a smaller area. Use <a href="http://geojson.io/">geojson.io</a> or
|
|
<a href="https://geoman.io/geojson-editor">geoman.io</a> to draw a boundary around the
|
|
region you want to simulate and save the GeoJSON locally. Use
|
|
<code>cargo run --bin geojson_to_osmosis < boundary.geojson</code> to convert that GeoJSON
|
|
to the
|
|
<a href="https://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format">Osmosis format</a>
|
|
required by osmconvert.</p>
|
|
<p>Note that you may hit problems if you use JOSM to download additional data to a
|
|
.osm file. Unless it updates the <code><bounds/></code> element, A/B Street will clip out
|
|
anything extra. The best approach is to explicitly specify the boundary with
|
|
<code>--oneshot_clip</code>.</p>
|
|
<h2><a class="header" href="#including-the-city-to-ab-street-more-permanently" id="including-the-city-to-ab-street-more-permanently">Including the city to A/B street more permanently</a></h2>
|
|
<p>Follow this guide to add a new city to A/B street by default so other users can
|
|
use it as well.</p>
|
|
<ol>
|
|
<li>
|
|
<p>Make sure you can run <code>import.sh</code> -- see
|
|
<a href="howto/../dev/index.html#building-map-data">the instructions</a>. You'll need Rust,
|
|
osmconvert, gdal, etc.</p>
|
|
</li>
|
|
<li>
|
|
<p>Create a new directory: <code>mkdir importer/config/your_city</code></p>
|
|
</li>
|
|
<li>
|
|
<p>Use <a href="http://geojson.io/">geojson.io</a> or
|
|
<a href="https://geoman.io/geojson-editor">geoman.io</a> to draw a boundary around the
|
|
region you want to simulate and save the geojson locally.</p>
|
|
</li>
|
|
<li>
|
|
<p>Use <code>cargo run --bin geojson_to_osmosis < boundary.geojson</code> to convert that
|
|
geojson to the
|
|
<a href="https://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format">Osmosis format</a>
|
|
required by osmconvert. This tool writes one file per feature in the input,
|
|
so you'd then
|
|
<code>mv boundary0.poly importer/config/your_city/region_name.poly</code>, repeating if
|
|
you drew multiple polygons.</p>
|
|
</li>
|
|
<li>
|
|
<p>Copy <code>importer/config/tel_aviv/cfg.json</code> to
|
|
<code>importer/config/your_city/cfg.json</code> and edit this file. See
|
|
<a href="https://github.com/dabreegster/abstreet/blob/master/importer/src/generic.rs">here</a>
|
|
for details on the different fields. The defaults are a reasonable start;
|
|
the only thing you need to change is <code>osm_url</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>Run it: <code>./import.sh --city=your_city --raw --map</code></p>
|
|
</li>
|
|
<li>
|
|
<p>Update <code>.gitignore</code>, following <code>tel_aviv</code> as an example.</p>
|
|
</li>
|
|
</ol>
|
|
<p>Send a PR with your changes! I'll generate everything and make it work with
|
|
<code>updater</code>, so most people don't have to build everything from scratch.</p>
|
|
<p>Also, you can divide the city into multiple regions, repeating step 4 and
|
|
declaring more polygon boundaries. The boundaries may overlap each other, and
|
|
they don't have to cover all of the space. Picking good boundaries may take
|
|
trial-and-error; the goal is to keep the resulting map file size small, so that
|
|
it loads quickly, while capturing all of the area needed to simulate something
|
|
interesting. This is easiest when you have some local knowledge of the area, and
|
|
at least a vague goal in mind for what you want to study.</p>
|
|
<h2><a class="header" href="#next-steps" id="next-steps">Next steps</a></h2>
|
|
<p>OpenStreetMap isn't the only data source we need. If you look at the import
|
|
pipeline for Seattle, you'll see many more sources for parking, GTFS bus
|
|
schedules, person/trip demand data for scenarios, etc. Most of these aren't
|
|
standard between cities. If you want to make your city more realistic, we'll
|
|
have to import more data. Get in touch.</p>
|
|
<p>You may notice issues with OSM data while using A/B Street. Some of these are
|
|
bugs in A/B Street itself, but others are incorrectly tagged lanes. Some
|
|
resources for fixing OSM:</p>
|
|
<ul>
|
|
<li><a href="https://learnosm.org">https://learnosm.org</a></li>
|
|
<li><a href="https://wiki.openstreetmap.org/wiki/StreetComplete">https://wiki.openstreetmap.org/wiki/StreetComplete</a></li>
|
|
<li><a href="howto/map_parking.html">Mapping parking</a></li>
|
|
</ul>
|
|
<h1><a class="header" href="#how-ab-street-works" id="how-ab-street-works">How A/B Street works</a></h1>
|
|
<p>The overview:</p>
|
|
<ol>
|
|
<li>A detailed map of Seattle is built from
|
|
<a href="https://www.openstreetmap.org/about">OpenStreetMap (OSM)</a></li>
|
|
<li>A realistic set of daily trips by car, bike, foot, and bus are simulated</li>
|
|
<li>You make small changes to roads and intersections</li>
|
|
<li>You explore how these changes affect the trips</li>
|
|
</ol>
|
|
<p>Details below. Many limitations are mentioned; improvements are ongoing. I'll
|
|
add pictures to explain better when I get time.</p>
|
|
<!--ts-->
|
|
<ul>
|
|
<li><a href="how_it_works.html#how-ab-street-works">How A/B Street works</a>
|
|
<ul>
|
|
<li><a href="how_it_works.html#driving">Driving</a></li>
|
|
<li><a href="how_it_works.html#parking">Parking</a></li>
|
|
<li><a href="how_it_works.html#biking">Biking</a></li>
|
|
<li><a href="how_it_works.html#walking">Walking</a></li>
|
|
<li><a href="how_it_works.html#transit">Transit</a></li>
|
|
<li><a href="how_it_works.html#intersections">Intersections</a></li>
|
|
<li><a href="how_it_works.html#people-and-trips">People and trips</a></li>
|
|
<li><a href="how_it_works.html#map-edits">Map edits</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<!-- Added by: dabreegster, at: Mon Jun 8 12:17:13 PDT 2020 -->
|
|
<!--te-->
|
|
<h2><a class="header" href="#driving" id="driving">Driving</a></h2>
|
|
<ul>
|
|
<li>Movement: no acceleration, go the full speed limit of the road unless there's
|
|
a slower vehicle in front</li>
|
|
<li>Lanes
|
|
<ul>
|
|
<li>No over-taking or lane-changing in the middle of a road, only at
|
|
intersections</li>
|
|
<li>Strange choice of lanes -- the least full at the time of arrival</li>
|
|
<li>Narrow two-way neighborhood roads where, in practice, only one car at a time
|
|
can go are currently full two-way roads</li>
|
|
</ul>
|
|
</li>
|
|
<li>Routing is based on fastest time assuming no traffic
|
|
<ul>
|
|
<li>No rerouting if the driver encounters a traffic jam</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#parking" id="parking">Parking</a></h2>
|
|
<ul>
|
|
<li>Types
|
|
<ul>
|
|
<li>On-street: parallel parking lanes from
|
|
<a href="http://data-seattlecitygis.opendata.arcgis.com/datasets/blockface">GeoData blockface dataset</a>
|
|
and <a href="howto/map_parking.html">manually mapped</a></li>
|
|
<li>Off-street: most buildings have at least a few parking spots in a driveway
|
|
or carport
|
|
<ul>
|
|
<li>Currently experimenting in the downtown map: set the number of available
|
|
spots based on number of cars seeded at midnight</li>
|
|
</ul>
|
|
</li>
|
|
<li>Parking lots: the number of spots is inferred</li>
|
|
</ul>
|
|
</li>
|
|
<li>Restrictions
|
|
<ul>
|
|
<li>All spots are public except for the few spots associated with each building</li>
|
|
<li>No time restrictions or modeling of payment</li>
|
|
</ul>
|
|
</li>
|
|
<li>How cars park
|
|
<ul>
|
|
<li>Drivers won't look for parking until they first reach their destination
|
|
building. Then they'll drive to the nearest open parking spot (magically
|
|
knowing what spots are open, even if they're a few blocks away). If somebody
|
|
else has taken the spot when they arrive, they'll try again.</li>
|
|
<li>Once a driver finds an open spot, they'll take 10-15 seconds to park. They
|
|
block the road behind them in the meantime. There are no conflicts between
|
|
pedestrians and cars when using a driveway. Cars won't make left turns into
|
|
or out of driveways.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Some parking along the boundary of the map is "blackholed", meaning it's
|
|
impossible to actually reach it. Nobody will use these spots.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#biking" id="biking">Biking</a></h2>
|
|
<ul>
|
|
<li>Choice of lane
|
|
<ul>
|
|
<li>Multi-use trails like the Burke Gilman and separated cycle-tracks like the
|
|
one along Broadway are currently missing</li>
|
|
<li>Cyclists won't use an empty parking lane</li>
|
|
<li>On roads without a bike lane, cyclists currently won't stick to the
|
|
rightmost lane</li>
|
|
<li>No over-taking yet, so cars can get stuck behind a bike even if there's a
|
|
passing lane</li>
|
|
</ul>
|
|
</li>
|
|
<li>Elevation change isn't factored into route choice or speed yet; pretend
|
|
everybody has an e-bike</li>
|
|
<li>Beginning or ending a cycling trip takes 30-45 seconds. Locking up at bike
|
|
racks with limited capacity isn't modeled; in practice, it's always easy in
|
|
Seattle to find a place to lock up.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#walking" id="walking">Walking</a></h2>
|
|
<ul>
|
|
<li>Not using sidewalk and crosswalk data from OSM yet</li>
|
|
<li>No jay-walking, even on empty residential streets</li>
|
|
<li>Pedestrians can't use roads without sidewalks at all
|
|
<ul>
|
|
<li>When a road only has a sidewalk on one side, driveways will cross the road</li>
|
|
</ul>
|
|
</li>
|
|
<li>Pedestrians can "ghost" through each other; crowds of people can grow to any
|
|
size</li>
|
|
</ul>
|
|
<h2><a class="header" href="#transit" id="transit">Transit</a></h2>
|
|
<ul>
|
|
<li>The modeling of buses is extremely simple and buggy; I'll work on this soon</li>
|
|
<li>No light rail yet</li>
|
|
</ul>
|
|
<h2><a class="header" href="#intersections" id="intersections">Intersections</a></h2>
|
|
<ul>
|
|
<li>Conflicting movements are coarse: a second vehicle won't start a conflicting
|
|
turn, even if the first vehicle is physically out of the way but still
|
|
partially in the intersection</li>
|
|
<li>Most of the time, vehicles won't "block the box" -- if there's no room in the
|
|
target lane, a vehicle won't start turning and risk getting stuck in the
|
|
intersection</li>
|
|
<li>Traffic signals
|
|
<ul>
|
|
<li>Only fixed timers; no actuated signals or
|
|
<a href="https://www.seattle.gov/transportation/projects-and-programs/programs/technology-program/mercer-scoot">centralized control</a>
|
|
yet</li>
|
|
<li>The timing and stages are automatically guessed, except some intersections
|
|
are
|
|
<a href="https://docs.google.com/document/d/1Od_7WvBVYsvpY4etRI0sKmYmZnwXMAXcJxVmm8Iwdcg/edit?usp=sharing">manually mapped</a></li>
|
|
<li>No pedestrian beg buttons; walk signals always come on</li>
|
|
<li>The signal doesn't change for rush hour or weekday/weekend traffic; there's
|
|
one pattern all day</li>
|
|
</ul>
|
|
</li>
|
|
<li>Turn restrictions from OSM are applied
|
|
<ul>
|
|
<li>Per lane (left turn only from leftmost lane), entire roads, multiple
|
|
intersections</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#people-and-trips" id="people-and-trips">People and trips</a></h2>
|
|
<ul>
|
|
<li>A "synthetic population" of ~700,000 people come from
|
|
<a href="https://www.psrc.org/activity-based-travel-model-soundcast">PSRC's Soundcast model</a>
|
|
<ul>
|
|
<li>Soundcast uses census, land-use, vehicle counts, and commuter surveys. The
|
|
current data is from 2014.</li>
|
|
<li>All driving trips are currently single-occupancy; no car-pooling or
|
|
ridesharing</li>
|
|
<li>Parked cars are initially placed at midnight based on the number of trips
|
|
between buildings</li>
|
|
</ul>
|
|
</li>
|
|
<li>Each person's schedule never changes
|
|
<ul>
|
|
<li>Your changes to the map won't yet convince somebody to take a bus or walk
|
|
instead of drive</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#map-edits" id="map-edits">Map edits</a></h2>
|
|
<ul>
|
|
<li>Types of edits
|
|
<ul>
|
|
<li>Change types of lanes. Sometimes this is unrealistic based on actual road
|
|
width, but data for this is unavailable.</li>
|
|
<li>Reversing direction of lanes</li>
|
|
<li>Changing stop signs</li>
|
|
<li>Changing traffic signal timing</li>
|
|
<li>Closing roads and intersections for construction, forcing rerouting</li>
|
|
</ul>
|
|
</li>
|
|
<li>Disconnecting the map
|
|
<ul>
|
|
<li>Generally you can't close sidewalks or make changes to make buildings
|
|
unreachable</li>
|
|
<li>You shouldn't be able to make bus stops unreachable, but currently this is
|
|
buggy</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h1><a class="header" href="#case-studies" id="case-studies">Case studies</a></h1>
|
|
<p>Note: Most of these still aren't started, because the baseline simulation in the
|
|
relevant area isn't working. Unknown traffic signal timing, bad guesses at the
|
|
amount of off-street parking, lanes tagged incorrectly in OpenStreetMap, and
|
|
simulation bugs cause unrealistic gridlock. It's hard to evaluate a change
|
|
without a realistic baseline.</p>
|
|
<p>In progress:</p>
|
|
<ul>
|
|
<li><a href="case_studies/lake_wash.html">Stay Healthy Streets: Lake Washington Blvd</a></li>
|
|
<li><a href="case_studies/west_seattle.html">West Seattle mitigations</a></li>
|
|
<li>Simplify where the Burke Gilman crosses Corliss and Pacific
|
|
<ul>
|
|
<li>No write-up yet, but the proposal is included in A/B Street</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p>TODO:</p>
|
|
<ul>
|
|
<li>Close Broadway and Pine to through-traffic
|
|
<ul>
|
|
<li>proposed
|
|
<a href="https://old.reddit.com/r/SeattleWA/comments/gr4dsi/its_time_for_mayor_durkan_to_bring_stay_healthy/">here</a></li>
|
|
<li>partly <a href="https://www.openstreetmap.org/way/814244753">happening already</a></li>
|
|
<li>another
|
|
<a href="https://twitter.com/pushtheneedle/status/1270757771802103809/photo/1">proposal</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>Traffic signal timing at Montlake/520 and Montlake/Pacific
|
|
<ul>
|
|
<li>Walking around here is frustrating, and pre-COVID, vehicle traffic got
|
|
fairly stuck</li>
|
|
</ul>
|
|
</li>
|
|
<li>Pedestrianizing the Ave (u-district)
|
|
<ul>
|
|
<li>I can't find the proposal anymore; maybe
|
|
<a href="http://www.udistrictmobility.com/">this</a>?</li>
|
|
</ul>
|
|
</li>
|
|
<li>Eastlake bike lanes / RapidRide J
|
|
<ul>
|
|
<li>See
|
|
<a href="https://www.seattle.gov/transportation/projects-and-programs/programs/bike-program/protected-bike-lanes/eastlake-avenue-protected-bike-lanes">here</a>
|
|
and
|
|
<a href="http://www.seattle.gov/transportation/projects-and-programs/programs/transit-program/transit-plus-multimodal-corridor-program/rapidride-roosevelt">here</a></li>
|
|
<li>Need to audit lanes in OSM along Eastlake</li>
|
|
<li>Especially with the Fairview Ave bridge out, detouring to the Cheshiahud
|
|
loop isn't as useful</li>
|
|
</ul>
|
|
</li>
|
|
<li>Madison / RapidRide G
|
|
<ul>
|
|
<li>See
|
|
<a href="http://www.seattle.gov/transportation/projects-and-programs/programs/transit-program/transit-plus-multimodal-corridor-program/madison-street-bus-rapid-transit">here</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>Bus lanes on Denny
|
|
<ul>
|
|
<li>Proposed
|
|
<a href="https://twitter.com/transitrunner/status/1175068582142599168">here</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>Bike Master Plan
|
|
<ul>
|
|
<li>Prototype the
|
|
<a href="https://www.seattle.gov/transportation/document-library/citywide-plans/modal-plans/bicycle-master-plan">planned network</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>Downtown one-way snake
|
|
<ul>
|
|
<li>An old crazy idea I've always wanted to try</li>
|
|
</ul>
|
|
</li>
|
|
<li>Unsorted ideas
|
|
<ul>
|
|
<li><a href="https://www.reddit.com/r/SeattleWA/comments/cr1r1l/why_the_fuck_does_the_right_lane_convert_to/">Parking</a></li>
|
|
<li><a href="https://seattletransitblog.com/2018/10/05/seven-places-to-add-bus-lanes-now/">Bus lanes</a></li>
|
|
<li><a href="https://old.reddit.com/r/SeattleWA/comments/83h4ri/the_intersection_at_john_and_broadway_desperately/">John and Broadway</a></li>
|
|
<li><a href="https://old.reddit.com/r/Seattle/comments/4z3ewl/what_are_seattles_worst_intersections/">Bad intersections</a></li>
|
|
<li><a href="https://old.reddit.com/r/SeattleWA/comments/5rvss5/what_changes_would_you_make_to_seattles_bus/">Bus routes</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h1><a class="header" href="#lake-washington-blvd-stay-healthy-street" id="lake-washington-blvd-stay-healthy-street">Lake Washington Blvd Stay Healthy Street</a></h1>
|
|
<p><em>Draft, updated May 7, 2020 by Dustin Carlino (<a href="mailto:case_studies/dabreegster@gmail.com">dabreegster@gmail.com</a>)</em></p>
|
|
<p>In April 2020, Seattle Department of Transportation started rolling out
|
|
<a href="https://sdotblog.seattle.gov/2020/04/16/announcing-stay-healthy-streets/">Stay Healthy Streets</a>,
|
|
restricting roads to through-traffic to give people walking and biking more
|
|
space for social distancing.
|
|
<a href="http://seattlegreenways.org/socialdistancingstreets/">Seattle Neighborhood Greenways</a>
|
|
soon proposed extending this to a
|
|
<a href="https://drive.google.com/open?id=1HQMnagRf8EbS1nouqCMLl4LZr0QE8VrC&usp=sharing">130-mile network</a>.</p>
|
|
<p>Selecting the streets requires some planning:</p>
|
|
<blockquote>
|
|
<p>These streets were selected to amplify outdoor exercise opportunities for
|
|
areas with limited open space options, low car ownership and routes connecting
|
|
people to essential services and food take out. We also ensured street
|
|
closures did not impact newly opened food pick up loading zones, parking
|
|
around hospitals for service for health care professionals, and bus routes.</p>
|
|
</blockquote>
|
|
<p>I've spent the last two years building <a href="https://abstreet.org">A/B Street</a>,
|
|
software to explore the impacts of changes like this on different modes of
|
|
transportation. So, let's try implementing part of the proposed network and see
|
|
what happens!</p>
|
|
<blockquote>
|
|
<p><strong><em>NOTE:</em></strong> You might want to read <a href="case_studies/../how_it_works.html">how A/B Street works</a>
|
|
first.</p>
|
|
</blockquote>
|
|
<h2><a class="header" href="#lake-washington-blvd" id="lake-washington-blvd">Lake Washington Blvd</a></h2>
|
|
<p>Let's start with one part of the proposal, closing Lake Washington Blvd to cars
|
|
through the Arboretum. There's already a multi-use trail alongside this stretch,
|
|
but its width makes it difficult to maintain 6 feet from people. There are some
|
|
parking lots that become inaccessible with this proposal, but they're currently
|
|
closed anyway.</p>
|
|
<p><img src="case_studies/edits.gif" alt="edits" /></p>
|
|
<h3><a class="header" href="#first-attempt" id="first-attempt">First attempt</a></h3>
|
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/PU0iT-_3-es" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
|
<p>Let's get started! If you want to follow along,
|
|
<a href="case_studies/../howto/index.html">install A/B Street</a>, open sandbox mode, and switch the map
|
|
to Lake Washington corridor. Zoom in on the southern tip of the Arboretum and
|
|
hop into edit mode. We can see Lake Washington Blvd just has one travel lane in
|
|
each direction here. Click each lane, convert it to a bike lane, and repeat
|
|
north until Foster Island Road.</p>
|
|
<p>When we leave edit mode, the traffic simulation resets to midnight. Nothing
|
|
really interesting happens until 5 or 6am, so we'll speed up time. Watching the
|
|
section of road we edited, we'll only see pedestrians and bikes use this stretch
|
|
of road. If we want, we can click an individual person and follow along their
|
|
journey.</p>
|
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/LSCHeDi5484" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
|
<p>Something's weird though. There's lots of traffic cutting northbound through the
|
|
neighborhood, along 29th, Ward, and 28th. We can open up the throughput layer to
|
|
find which roads have the most traffic. More usefully, we can select "compare
|
|
before edits" to see what roads are getting more or less traffic because of the
|
|
road we modified. As expected, there's much less traffic along Lake Wash Blvd,
|
|
but it's also clear that lots of cars are now cutting through 26th Ave E.</p>
|
|
<h3><a class="header" href="#traffic-calming" id="traffic-calming">Traffic calming</a></h3>
|
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/qAf5IAMbpcU" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
|
<p>Let's say you want to nudge traffic to use 23rd Ave, the nearest north/south
|
|
arterial, instead. (A/B Street is an unopinionated tool; if you have a different
|
|
goal in mind, try using it for that instead.) In this simulation, drivers pick
|
|
the fastest route, so we could try lowering speed limits or make some of the
|
|
residential streets connecting to Madison one-way, discouraging through-traffic.
|
|
In reality, the speed limit changes could be implemented through
|
|
<a href="https://streetsillustrated.seattle.gov/design-standards/trafficcalming/">traffic calming</a>
|
|
or cheap, temporary alternatives.</p>
|
|
<h2><a class="header" href="#next-steps-1" id="next-steps-1">Next steps</a></h2>
|
|
<p>I'm working to model "local access only" roads in A/B Street, and I'll describe
|
|
how to measure the impact on travel times. Stay tuned to see more of the
|
|
<a href="https://drive.google.com/open?id=1HQMnagRf8EbS1nouqCMLl4LZr0QE8VrC&usp=sharing">proposed network</a>
|
|
simulated, and get in touch if you'd like to help out!</p>
|
|
<h1><a class="header" href="#west-seattle-mitigations" id="west-seattle-mitigations">West Seattle mitigations</a></h1>
|
|
<p><em>Draft, updated June 23, 2020 by Dustin Carlino (<a href="mailto:case_studies/dabreegster@gmail.com">dabreegster@gmail.com</a>)</em></p>
|
|
<p>In March 2020, the West Seattle bridge was closed due to cracks forming. As of
|
|
May, COVID-19's impact on commuting means the area still hasn't seen how the
|
|
area will handle losing the main route to the rest of Seattle. A local group,
|
|
HPAC, published a list of
|
|
<a href="https://www.westsideseattle.com/robinson-papers/2020/05/04/highland-park-action-coalition-calls-seattle-officials-traffic">requests to SDOT</a>
|
|
to prepare the area for these changes.</p>
|
|
<p>This page will try to explore some of the problems and solutions from HPAC's
|
|
document using <a href="https://abstreet.org">A/B Street</a>, a traffic simulator designed
|
|
to explore the impacts of changes like this on different modes of
|
|
transportation.</p>
|
|
<blockquote>
|
|
<p><strong><em>NOTE:</em></strong> You might want to read <a href="case_studies/../how_it_works.html">how A/B Street works</a>
|
|
first.</p>
|
|
</blockquote>
|
|
<h2><a class="header" href="#16th-ave-sw-and-sw-holden-st" id="16th-ave-sw-and-sw-holden-st">16th Ave SW and SW Holden St</a></h2>
|
|
<p>HPAC has been asking for a protected left-turn stage at this intersection. I'm
|
|
unfamiliar with this intersection and currently unable to scout in-person, so
|
|
I'm blindly guessing the traffic signal currently has just two stages:</p>
|
|
<p><img src="case_studies/existing_diagram.gif" alt="existing_diagram" /></p>
|
|
<p>From watching the traffic, it seems like the east/west direction is busier, with
|
|
lots of eastbound traffic headed towards WA-509. Holden St has no turn lanes, so
|
|
a protected left turn stage makes sense. Let's make the change and see what
|
|
happens:</p>
|
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/6tooJaZLa0Q" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
|
<p>Unfortuately, we can't evaluate the change yet, because the simulation gets
|
|
stuck with unrealistic traffic jams in other parts of the map. This is mostly
|
|
due to data quality issues in OpenStreetMap and incorrectly guessed traffic
|
|
signal timings. These problems can be fixed with the help of somebody familiar
|
|
with the area.</p>
|
|
<h2><a class="header" href="#re-evaluate-arterials" id="re-evaluate-arterials">Re-evaluate arterials</a></h2>
|
|
<p>The 9th item from HPAC's list asks for measuring the amount of east-west traffic
|
|
to figure out what streets people are using as arterials. That's an easy
|
|
analysis, using the <em>throughput</em> layer.</p>
|
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/yzp9c7gHhOI" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
|
<p>By 6am, the busiest streets include Admiral Way, S Charlestown, SW Genesee, SW
|
|
Alaska, SW Holden, and SW Roxbury St. Again, it's necessary to first fix data
|
|
quality problems and run a full day before doing more analysis.</p>
|
|
<p>Once the simulation is running smoothly, A/B Street can be used to make changes
|
|
-- like lowering speed limits, adding a protected left turn stage, or converting
|
|
part of the road into a bus lane -- and evaluate the effects on individual trips
|
|
and aggregate groups.</p>
|
|
<h2><a class="header" href="#repair-the-bridge" id="repair-the-bridge">Repair the bridge</a></h2>
|
|
<p>Community proposals now includes a "repair the bridge" option, which should
|
|
restore things to how they were before March 2020. This is useful as a baseline,
|
|
to explore what traffic patterns were like before the closure.</p>
|
|
<h1><a class="header" href="#developer-guide" id="developer-guide">Developer guide</a></h1>
|
|
<h2><a class="header" href="#getting-started" id="getting-started">Getting started</a></h2>
|
|
<p>You will first need:</p>
|
|
<ul>
|
|
<li>Stable Rust, at least 1.47. <a href="https://www.rust-lang.org/tools/install">https://www.rust-lang.org/tools/install</a>.
|
|
<ul>
|
|
<li>On Windows, you may need
|
|
<a href="https://visualstudio.microsoft.com/en/downloads/">Visual Studio 2019</a>.</li>
|
|
</ul>
|
|
</li>
|
|
<li>On Linux, <code>sudo apt-get install xorg-dev libxcb-shape0-dev libxcb-xfixes0-dev</code>
|
|
or the equivalent for your distro</li>
|
|
</ul>
|
|
<p>One-time setup:</p>
|
|
<ol>
|
|
<li>
|
|
<p>Download the repository:
|
|
<code>git clone https://github.com/dabreegster/abstreet.git</code></p>
|
|
</li>
|
|
<li>
|
|
<p>Grab the minimal amount of data to get started: <code>cargo run --bin updater</code></p>
|
|
</li>
|
|
<li>
|
|
<p>Run the game: <code>RUST_BACKTRACE=1 cargo run --bin game --release</code>. On Windows,
|
|
set environment variables like this:
|
|
<code>set RUST_BACKTRACE=1 && cargo run --bin game --release</code></p>
|
|
</li>
|
|
</ol>
|
|
<h2><a class="header" href="#development-tips" id="development-tips">Development tips</a></h2>
|
|
<ul>
|
|
<li><a href="https://dabreegster.github.io/abstreet/rustdoc/map_model/index.html">Generated API documentation</a></li>
|
|
<li>Compile faster by just doing <code>cargo run</code>. The executable will have debug stack
|
|
traces and run more slowly. You can do <code>cargo run --release</code> to build in
|
|
optimized release mode; compilation will be slower, but the executable much
|
|
faster.</li>
|
|
<li>Some in-game features are turned off by default or don't have a normal menu to
|
|
access them. The list:
|
|
<ul>
|
|
<li>To toggle developer mode: press <strong>Control+S</strong> in game, or
|
|
<code>cargo run -- --dev</code></li>
|
|
<li>To warp to an object by numeric ID: press <strong>Control+j</strong></li>
|
|
<li>To enter debug mode with all sorts of goodies: press <strong>Control+D</strong></li>
|
|
</ul>
|
|
</li>
|
|
<li>You can start the game in different modes using flags:
|
|
<ul>
|
|
<li><code>cargo run --bin game -- --dev data/system/seattle/maps/downtown.bin</code> starts
|
|
on a particular map</li>
|
|
<li><code>cargo run --bin game -- data/system/seattle/scenarios/downtown/weekday.bin</code>
|
|
starts with a scenario (which is tied to a certain map)</li>
|
|
<li><code>cargo run --bin game -- --challenge=trafficsig/tut2</code> starts on a particular
|
|
challenge. See the list of aliases by passing in a bad value here.</li>
|
|
<li><code>cargo run --bin game -- data/player/saves/montlake/no_edits_unnamed/00h00m20.3s.bin</code>
|
|
restores an exact simulation state. Savestates are found in debug mode
|
|
(<strong>Control+D</strong>) -- they're probably confusing for the normal player
|
|
experience, so they're hidden for now.</li>
|
|
<li><code>cargo run --bin game -- --tutorial=12</code> starts somewhere in the tutorial</li>
|
|
<li>Adding <code>--edits='name of edits'</code> starts with edits applied to the map.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#downloading-more-cities" id="downloading-more-cities">Downloading more cities</a></h2>
|
|
<p>As data formats change over time, things in the <code>data/</code> directory not under
|
|
version control will get out of date. At any time, you can run
|
|
<code>cargo run --bin updater</code> from the main repository directory to update only the
|
|
files that have changed.</p>
|
|
<p>You can also opt into downloading updates for more cities by editing
|
|
<code>data/player/data.json</code>. In the main UI, there's a button to download more
|
|
cities that will help you manage this config file.</p>
|
|
<h2><a class="header" href="#building-map-data" id="building-map-data">Building map data</a></h2>
|
|
<p>You can skip this section if you're just touching code in <code>game</code>, <code>widgetry</code>,
|
|
and <code>sim</code>.</p>
|
|
<p>To run all pieces of the importer, you'll need some extra dependencies:</p>
|
|
<ul>
|
|
<li><code>osmconvert</code>: See <a href="https://wiki.openstreetmap.org/wiki/Osmconvert#Download">https://wiki.openstreetmap.org/wiki/Osmconvert#Download</a> or
|
|
<a href="https://github.com/interline-io/homebrew-planetutils#installation">https://github.com/interline-io/homebrew-planetutils#installation</a> for Mac</li>
|
|
<li><code>libgdal-dev</code>: See <a href="https://gdal.org">https://gdal.org</a> if your OS package manager doesn't have
|
|
this. If you keep hitting linking errors, then just remove
|
|
<code>--features scenarios</code> from <code>import.sh</code>. You won't be able to build the
|
|
Seattle scenarios.</li>
|
|
<li>Standard Unix utilities: <code>curl</code>, <code>unzip</code>, <code>gunzip</code></li>
|
|
</ul>
|
|
<p>The first stage of the importer, <code>--raw</code>, will download input files from OSM,
|
|
King County GIS, and so on. If the mirrors are slow or the files vanish, you
|
|
could fill out <code>data/config</code> and use the <code>updater</code> described above to grab the
|
|
latest input.</p>
|
|
<p>You can rerun specific stages of the importer:</p>
|
|
<ul>
|
|
<li>If you're modifying the initial OSM data -> RawMap conversion in
|
|
<code>convert_osm</code>, you need <code>./import.sh --raw --map</code>.</li>
|
|
<li>If you're modifying <code>map_model</code> but not the OSM -> RawMap conversion, then you
|
|
just need <code>./import.sh --map</code>.</li>
|
|
<li>If you're modifying the demand model for Seattle, you can add <code>--scenario</code> to
|
|
regenerate.</li>
|
|
<li>By default, all maps are regenerated. You can also specify a single map:
|
|
<code>./import.sh --map downtown</code>.</li>
|
|
<li>By default, Seattle is assumed as the city. You have to specify otherwise:
|
|
<code>./import.sh --city=los_angeles --map downtown_la</code>.</li>
|
|
</ul>
|
|
<p>You can also make the importer <a href="dev/../howto/new_city.html">import a new city</a>.</p>
|
|
<h2><a class="header" href="#understanding-stuff" id="understanding-stuff">Understanding stuff</a></h2>
|
|
<p>The docs listed at <a href="https://github.com/dabreegster/abstreet#documentation">https://github.com/dabreegster/abstreet#documentation</a>
|
|
explain things like map importing and how the traffic simulation works.</p>
|
|
<h3><a class="header" href="#code-organization" id="code-organization">Code organization</a></h3>
|
|
<p>If you're going to dig into the code, it helps to know what all the crates are.
|
|
The most interesting crates are <code>map_model</code>, <code>sim</code>, and <code>game</code>.</p>
|
|
<p>Constructing the map:</p>
|
|
<ul>
|
|
<li><code>convert_osm</code>: extract useful data from OpenStreetMap and other data sources,
|
|
emit intermediate map format</li>
|
|
<li><code>kml</code>: extract shapes from KML and CSV shapefiles</li>
|
|
<li><code>map_model</code>: the final representation of the map, also conversion from the
|
|
intermediate map format into the final format</li>
|
|
<li><code>map_editor</code>: GUI for modifying geometry of maps and creating maps from
|
|
scratch. pretty abandoned as of June 2020</li>
|
|
<li><code>importer</code>: tool to run the entire import pipeline</li>
|
|
<li><code>updater</code>: tool to download/upload large files used in the import pipeline</li>
|
|
</ul>
|
|
<p>Traffic simulation:</p>
|
|
<ul>
|
|
<li><code>sim</code>: all of the agent-based simulation logic</li>
|
|
<li><code>headless</code>: tool to run a simulation without any visualization</li>
|
|
</ul>
|
|
<p>Graphics:</p>
|
|
<ul>
|
|
<li><code>game</code>: the GUI and main gameplay</li>
|
|
<li><code>widgetry</code>: a GUI and 2D OpenGL rendering library, using glium + winit +
|
|
glutin</li>
|
|
</ul>
|
|
<p>Common utilities:</p>
|
|
<ul>
|
|
<li><code>abstutil</code>: a grab-bag of IO helpers, timing and logging utilities, etc</li>
|
|
<li><code>geom</code>: types for GPS and map-space points, lines, angles, polylines,
|
|
polygons, circles, durations, speeds</li>
|
|
</ul>
|
|
<p>Other:</p>
|
|
<ul>
|
|
<li><code>collisions</code>: an experimental data format for real-world collision data</li>
|
|
<li><code>traffic_seitan</code>: a bug-finding tool that randomly generates live map edits</li>
|
|
<li><code>tests</code>: integration tests</li>
|
|
</ul>
|
|
<h2><a class="header" href="#code-conventions" id="code-conventions">Code conventions</a></h2>
|
|
<p>All code is automatically formatted using
|
|
<a href="https://github.com/rust-lang/rustfmt">https://github.com/rust-lang/rustfmt</a>; please run <code>cargo +nightly fmt</code> before
|
|
sending a PR. (You have to install the nightly toolchain just for fmt)</p>
|
|
<p>cargo fmt can't yet organize imports, but we follow a convention to minimize
|
|
conflict with what some IDEs do. Follow existing code to group imports: std,
|
|
external crates, other crates in the project, the current crate, then finally
|
|
any module declarations.</p>
|
|
<p>The error handling is unfortunately inconsistent. The goal is to gracefully
|
|
degrade instead of crashing the game. If a crash does happen, make sure the logs
|
|
will have enough context to reproduce and debug. For example, giving up when
|
|
some geometry problem happens isn't ideal, but at least make sure to print the
|
|
road / agent IDs or whatever will help find the problem. It's fine to crash
|
|
during map importing, since the player won't deal with this, and loudly stopping
|
|
problems is useful. It's also fine to crash when initially constructing all of
|
|
the renderable map objects, because this crash will consistently happen at
|
|
startup-time and be noticed by somebody developing before a player gets to it.</p>
|
|
<p>Prefer using <code>info!</code>, <code>warn!</code>, <code>error!</code>, etc from the <code>log</code> crate. Or if a
|
|
<code>Timer</code> is available and you want to collect all notes together, <code>timer.note</code>.
|
|
There are still many places calling <code>println!</code>, but we're trying to clean these
|
|
up.</p>
|
|
<p>See the <a href="dev/testing.html">testing strategy</a> page.</p>
|
|
<h2><a class="header" href="#profiling" id="profiling">Profiling</a></h2>
|
|
<p>Use <a href="https://github.com/flamegraph-rs/flamegraph">https://github.com/flamegraph-rs/flamegraph</a>, just running it on the
|
|
binaries you build normally.</p>
|
|
<h1><a class="header" href="#development-notes" id="development-notes">Development notes</a></h1>
|
|
<p>Find packages to upgrade: <code>cargo outdated -R</code></p>
|
|
<p>Deal with compile tile: <code>cargo bloat --time</code></p>
|
|
<p>Find why two binary crates aren't sharing dependencies:
|
|
<a href="https://old.reddit.com/r/rust/comments/cqceu4/common_crates_in_cargo_workspace_recompiled/">https://old.reddit.com/r/rust/comments/cqceu4/common_crates_in_cargo_workspace_recompiled/</a></p>
|
|
<p>Where's a dependency coming from? <code>cargo tree -i -p syn</code></p>
|
|
<p>Diff screencaps: <a href="http://www.imagemagick.org/Usage/compare/#methods">http://www.imagemagick.org/Usage/compare/#methods</a></p>
|
|
<p>Debug OpenGL calls:</p>
|
|
<pre><code>apitrace trace --api gl ../target/debug/game
|
|
qapitrace game.trace
|
|
apitrace dump game.trace
|
|
</code></pre>
|
|
<p>Understand XML: just use firefox</p>
|
|
<h2><a class="header" href="#building-releases" id="building-releases">Building releases</a></h2>
|
|
<p>Cross-compilation notes: <a href="https://github.com/rust-embedded/cross">https://github.com/rust-embedded/cross</a> Or use
|
|
<a href="https://github.com/japaric/trust">https://github.com/japaric/trust</a></p>
|
|
<p>Initially have to:</p>
|
|
<pre><code class="language-shell">cargo install cross
|
|
sudo apt-get install docker.io
|
|
sudo usermod -aG docker ${USER}
|
|
</code></pre>
|
|
<p>Then:</p>
|
|
<pre><code>sudo systemctl start docker
|
|
cross build --release --target x86_64-pc-windows-gnu --bin game
|
|
wine target/x86_64-pc-windows-gnu/release/game.exe data/system/seattle/maps/montlake.bin
|
|
</code></pre>
|
|
<h2><a class="header" href="#markdown" id="markdown">Markdown</a></h2>
|
|
<p>For formatting:</p>
|
|
<pre><code>sudo apt-get install npm
|
|
cd ~; mkdir npm; cd npm
|
|
npm init --yes
|
|
npm install prettier --save-dev --save-exact
|
|
</code></pre>
|
|
<h2><a class="header" href="#videos" id="videos">Videos</a></h2>
|
|
<pre><code># Fullscreen
|
|
ffmpeg -f x11grab -r 25 -s 1920x960 -i :0.0+0,55 -vcodec huffyuv raw.avi
|
|
|
|
ffmpeg -ss 10.0 -t 5.0 -i raw.avi -f gif -filter_complex "[0:v] fps=12,scale=1024:-1,split [a][b];[a] palettegen [p];[b][p] paletteuse" screencast.gif
|
|
</code></pre>
|
|
<h2><a class="header" href="#faster-linking" id="faster-linking">Faster linking</a></h2>
|
|
<pre><code>sudo apt-get install lld
|
|
</code></pre>
|
|
<p>Stick this in ~/.cargo/config:</p>
|
|
<pre><code>[target.x86_64-unknown-linux-gnu]
|
|
rustflags = [
|
|
"-C", "link-arg=-fuse-ld=lld",
|
|
]
|
|
</code></pre>
|
|
<h2><a class="header" href="#git" id="git">git</a></h2>
|
|
<p>Keep a fork up to date:</p>
|
|
<pre><code># Once
|
|
git remote add upstream https://github.com/rust-windowing/glutin/
|
|
|
|
git fetch upstream
|
|
git merge upstream/master
|
|
git diff upstream/master
|
|
</code></pre>
|
|
<h2><a class="header" href="#refactoring" id="refactoring">Refactoring</a></h2>
|
|
<pre><code>perl -pi -e 's/WrappedComposite::text_button\(ctx, (.+?), (.+?)\)/Btn::text_fg(\1).build_def\(ctx, \2\)/' `find|grep rs|xargs`
|
|
</code></pre>
|
|
<h2><a class="header" href="#stack-overflow" id="stack-overflow">Stack overflow</a></h2>
|
|
<p>rust-gdb --args ../target/release/game --dev</p>
|
|
<h2><a class="header" href="#drawing-diagrams" id="drawing-diagrams">Drawing diagrams</a></h2>
|
|
<p>draw.io</p>
|
|
<h2><a class="header" href="#mapping" id="mapping">Mapping</a></h2>
|
|
<p>xodo on Android for annotating maps in the field</p>
|
|
<h2><a class="header" href="#osm-tools" id="osm-tools">OSM tools</a></h2>
|
|
<p>osmcha.org for recent changes</p>
|
|
<p>To upload diffs:</p>
|
|
<pre><code>java -jar ~/Downloads/josm-tested.jar ~/abstreet/map_editor/diff.osc
|
|
</code></pre>
|
|
<p>JOSM: Press (and release T), then click to pan. Download a relevant layer,
|
|
select the .osc, merge, then upload.</p>
|
|
<h2><a class="header" href="#fonts" id="fonts">Fonts</a></h2>
|
|
<p>fontdrop.info</p>
|
|
<h2><a class="header" href="#release-checklist" id="release-checklist">Release checklist</a></h2>
|
|
<p>What things are sensitive to changes in map data and simulation rules?</p>
|
|
<ul>
|
|
<li>tutorial</li>
|
|
<li>optimize commute challenges</li>
|
|
</ul>
|
|
<p>What things do I always forget to test?</p>
|
|
<ul>
|
|
<li>DPI issues, use <code>--scale_factor</code></li>
|
|
</ul>
|
|
<h1><a class="header" href="#api" id="api">API</a></h1>
|
|
<p>Suppose you're tired of manually fiddling with traffic signals, and you want to
|
|
use machine learning to do it. You can run A/B Street without graphics and
|
|
automatically control it through an API.</p>
|
|
<h2><a class="header" href="#examples" id="examples">Examples</a></h2>
|
|
<p>This
|
|
<a href="https://github.com/dabreegster/abstreet/blob/master/headless/examples/python_client.py">Python example</a>
|
|
has everything you need to get started.</p>
|
|
<p>See
|
|
<a href="https://github.com/dabreegster/abstreet/tree/master/headless/examples">all example code</a>
|
|
-- there are different experiments in Go and Python that automate running a
|
|
simulation, measuring some metric, and making a change to improve the metric.</p>
|
|
<h2><a class="header" href="#control-flow" id="control-flow">Control flow</a></h2>
|
|
<p>The <code>headless</code> API server that you run contains a single map and simulation at a
|
|
time. Even though you can theoretically have multiple clients make requests to
|
|
it simultaneously, the server will only execute one at a time. If you're trying
|
|
to do something other than use one script to make API calls in sequence, please
|
|
get in touch, so we can figure out something better suited to your use case.</p>
|
|
<p>When you start the <code>headless</code> server, it always loads the <code>montlake</code> map with
|
|
the <code>weekday</code> scenario. The only way you can change this is by calling
|
|
<code>/sim/load</code>. For example:</p>
|
|
<pre><code>curl http://localhost:1234/sim/load -d '{ "scenario": "data/system/seattle/scenarios/downtown/monday.bin", "modifiers": [], "edits": null }' -X POST`
|
|
</code></pre>
|
|
<p>You can also pass flags like <code>--infinite_parking</code> to the server to control
|
|
<a href="https://dabreegster.github.io/abstreet/rustdoc/sim/struct.SimOptions.html">SimOptions</a>.
|
|
These settings will apply for the entire lifetime of the server; you can't
|
|
change them later.</p>
|
|
<h2><a class="header" href="#api-details" id="api-details">API details</a></h2>
|
|
<blockquote>
|
|
<p><strong>Under construction</strong>: The API will keep changing. There are no backwards
|
|
compatibility guarantees yet. Please make sure I know about your project, so I
|
|
don't break your client code.</p>
|
|
</blockquote>
|
|
<p>For now, the API is JSON over HTTP. The exact format is unspecified, error codes
|
|
are missing, etc. A summary of the commands available so far:</p>
|
|
<ul>
|
|
<li><strong>/sim</strong>
|
|
<ul>
|
|
<li><strong>GET /sim/reset</strong>: Reset all temporary map edits and the simulation state.
|
|
The trips that will run don't change; they're determined by the scenario
|
|
specified by the last call to <code>/sim/load</code>. If you made live map edits using
|
|
things like <code>/traffic-signals/set</code>, they'll be reset to the <code>edits</code> from
|
|
<code>/sim/load</code>.</li>
|
|
<li><strong>POST /sim/load</strong>: Switch the scenario being simulated, and also optionally
|
|
sets the map edits.</li>
|
|
<li><strong>GET /sim/get-time</strong>: Returns the current simulation time.</li>
|
|
<li><strong>GET /sim/goto-time?t=06:30:00</strong>: Simulate until 6:30 AM. If the time you
|
|
specify is before the current time, you have to call <strong>/sim/reset</strong> first.</li>
|
|
<li><strong>POST /sim/new-person</strong>: The POST body must be an
|
|
<a href="https://dabreegster.github.io/abstreet/rustdoc/sim/struct.ExternalPerson.html">ExternalPerson</a>
|
|
in JSON format.</li>
|
|
</ul>
|
|
</li>
|
|
<li><strong>/traffic-signals</strong>
|
|
<ul>
|
|
<li><strong>GET /traffic-signals/get?id=42</strong>: Returns the traffic signal of
|
|
intersection #42 in JSON.</li>
|
|
<li><strong>POST /traffic-signals/set</strong>: The POST body must be a
|
|
<a href="https://dabreegster.github.io/abstreet/rustdoc/map_model/struct.ControlTrafficSignal.html">ControlTrafficSignal</a>
|
|
in JSON format.</li>
|
|
<li><strong>GET /traffic-signals/get-delays?id=42&t1=03:00:00&t2=03:30:00</strong>: Returns
|
|
the delay experienced by every agent passing through intersection #42 from
|
|
3am to 3:30, grouped by direction of travel.</li>
|
|
<li><strong>GET /traffic-signals/get-cumulative-thruput?id=42</strong>: Returns the number of
|
|
agents passing through intersection #42 since midnight, grouped by direction
|
|
of travel.</li>
|
|
<li><strong>GET /traffic-signals/get-all-current-state</strong>: Returns the current state of
|
|
all traffic signals, including the stage timing, waiting, and accepted
|
|
agents.</li>
|
|
</ul>
|
|
</li>
|
|
<li><strong>/data</strong>
|
|
<ul>
|
|
<li><strong>GET /data/get-finished-trips</strong>: Returns a JSON list of all finished trips.
|
|
Each tuple is (time the trip finished in seconds after midnight, trip ID,
|
|
mode, duration of trip in seconds). The mode is either a string like "Walk"
|
|
or "Drive", or null if the trip was cancelled for any reason.</li>
|
|
<li><strong>GET /data/get-agent-positions</strong>: Returns a JSON list of all active agents.
|
|
Vehicle type (or pedestrian), person ID, and position is included.</li>
|
|
<li><strong>GET /data/get-road-thruput</strong>: Returns a JSON list of (road, agent type,
|
|
hour since midnight, throughput for that one hour period).</li>
|
|
</ul>
|
|
</li>
|
|
<li><strong>/map</strong>
|
|
<ul>
|
|
<li><strong>GET /map/get-edits</strong>: Returns the current map edits in JSON. You can save
|
|
this to a file in <code>data/player/edits/city_name/map_name/</code> and later use it
|
|
in-game normally. You can also later run the <code>headless</code> server with
|
|
<code>--edits=name_of_edits</code>.</li>
|
|
<li><strong>GET /map/get-edit-road-command?id=123</strong>: Returns an object that can be
|
|
modified and then added to map edits.</li>
|
|
<li><strong>GET /map/get-intersection-geometry?id=123</strong>: Returns a GeoJSON object with
|
|
one feature for the intersection and a feature for all connecting roads. The
|
|
polygon coordinates are measured in meters, with the origin centered at the
|
|
intersection's center.</li>
|
|
<li><strong>GET /map/get-all-geometry</strong>: Returns a huge GeoJSON object with one
|
|
feature per road and intersection in the map. The coordinate space is WGS84.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#working-with-the-map-model" id="working-with-the-map-model">Working with the map model</a></h2>
|
|
<p>If you need to deeply inspect the map, you can dump it to JSON:</p>
|
|
<pre><code>cargo run --bin dump_map data/system/seattle/maps/montlake.bin > montlake.json
|
|
</code></pre>
|
|
<p>See some example code that
|
|
<a href="https://github.com/dabreegster/abstreet/blob/master/headless/examples/generate_traffic.py">reads this JSON and finds buildings</a>.</p>
|
|
<p>You could also edit the map JSON, convert it back to binary, and use it in the
|
|
simulation. This isn't recommended generally, but one possible use case could be
|
|
tuning the amount of offstreet parking per building. The map JSON has a list
|
|
called <code>buildings</code>, and each object there has a field <code>parking</code>. You coud set
|
|
this object to <code>{ "Private": [100, false] }</code> to indicate 100 parking spots, for
|
|
a building not explicitly designated in OpenStreetMap as a garage. After editing
|
|
the JSON, you have to convert it back to the binary format:</p>
|
|
<pre><code>cargo run --bin json_to_binary_map -- --input=montlake.json out=data/system/seattle/maps/montlake_modified.bin`
|
|
</code></pre>
|
|
<p>... Except this tool doesn't seem to work yet!</p>
|
|
<p>The format of the map isn't well-documented yet. See the
|
|
<a href="https://dabreegster.github.io/abstreet/rustdoc/map_model/index.html">generated API docs</a>
|
|
and <a href="dev/../map/index.html">the map model docs</a> in the meantime.</p>
|
|
<h2><a class="header" href="#working-with-individual-trips" id="working-with-individual-trips">Working with individual trips</a></h2>
|
|
<p>You can use the <strong>/sim/new-person</strong> API in the middle of a simulation, if
|
|
needed. If possible, it's simpler to create a Scenario as input.</p>
|
|
<h2><a class="header" href="#working-with-scenarios" id="working-with-scenarios">Working with Scenarios</a></h2>
|
|
<p>You can
|
|
<a href="dev/../trafficsim/travel_demand.html#custom-import">import trips from your own data</a>.</p>
|
|
<p>You can also generate different variations of one of the
|
|
<a href="dev/../trafficsim/travel_demand.html#proletariat-robot">demand models</a> by specifying
|
|
an RNG seed:</p>
|
|
<pre><code>cargo run --bin random_scenario -- --rng=123 --map=data/system/seattle/maps/montlake.bin --scenario_name=home_to_work
|
|
</code></pre>
|
|
<p>You can also dump Scenarios (the file that defines all of the people and trips)
|
|
to JSON:</p>
|
|
<pre><code>cargo run --bin dump_scenario data/system/seattle/scenarios/montlake/weekday.bin > montlake_weekday.json
|
|
</code></pre>
|
|
<p>You can modify the JSON, then put the file back in the appropriate directory and
|
|
use it in-game:</p>
|
|
<pre><code>cargo run --bin game data/system/seattle/scenarios/montlake/modified_scenario.json
|
|
</code></pre>
|
|
<p>The Scenario format is also undocumented, but see the
|
|
<a href="https://dabreegster.github.io/abstreet/rustdoc/sim/struct.Scenario.html">generated API docs</a>
|
|
anyway.</p>
|
|
<h1><a class="header" href="#testing-strategy" id="testing-strategy">Testing strategy</a></h1>
|
|
<h2><a class="header" href="#unit-tests" id="unit-tests">Unit tests</a></h2>
|
|
<p>As you've probably noticed, there aren't many. Lots of the interesting behavior
|
|
in A/B Street - UI interactions, details of the simulation, map importing --
|
|
would take lots of infrastructure to specify a setup and expected outcomes. If
|
|
you have ideas for new tests, contributions always welcome! In the meantime, one
|
|
useful test covers how
|
|
<a href="https://github.com/dabreegster/abstreet/blob/master/map_model/src/make/initial/lane_specs.rs">OSM tags translate into individual lanes</a>.</p>
|
|
<h2><a class="header" href="#screenshot-diffs" id="screenshot-diffs">Screenshot diffs</a></h2>
|
|
<p>Downloading fresh OSM data or modifying any part of the map importing pipeline
|
|
could easily break things. Expressing invariants about the map output is hard,
|
|
because importing is far from perfect, and OSM data is often quite buggy. So the
|
|
approach to preventing regressions here is to look for visual changes to the
|
|
final rendered map.</p>
|
|
<ol>
|
|
<li>When a new map is opted into this type of test, somebody manually squints
|
|
carefully at it and sanity checks that it works to some degree.</li>
|
|
<li>They use the screen capture tool in debug mode to tile the map into 1920x960
|
|
chunks and screengrab everything.</li>
|
|
<li>Later, somebody regenerates the map with some possible changes.</li>
|
|
<li>They grab screenshots again, then use <code>compare_screenshots.sh</code> to quickly
|
|
look at the visual diff. Changes to intersection geometry, number of lanes,
|
|
rendering, etc are all easy to spot.</li>
|
|
<li>If this manual inspection of the diff is good, they commit the new
|
|
screenshots as the new goldenfiles.</li>
|
|
</ol>
|
|
<h2><a class="header" href="#dataregensh" id="dataregensh">data/regen.sh</a></h2>
|
|
<p>This tool regenerates all maps and scenarios from scratch.
|
|
<code>cargo run --bin updater -- --dry</code> then reveals what files have changed.</p>
|
|
<p>Additionally, this script does a few more tests:</p>
|
|
<ul>
|
|
<li><code>--prebake</code> runs the full weekday scenario on two maps that've previously been
|
|
coerced into being gridlock-free</li>
|
|
</ul>
|
|
<h2><a class="header" href="#integration-tests" id="integration-tests">Integration tests</a></h2>
|
|
<p>The <code>tests</code> crate contains some integration tests.</p>
|
|
<p>One part runs the full importer against really simple <code>.osm</code> files. To iterate
|
|
rapidly on interpreting turn restrictions, it produces goldenfiles describing
|
|
all turns in the tiny map.</p>
|
|
<p>The "smoke-test" section simulates one hour on all maps, flushing out bugs with
|
|
bus spawning, agents hitting odd parts of the map, etc</p>
|
|
<p>The "check proposals" section makes sure the edits shipped with the game still
|
|
load properly.</p>
|
|
<h2><a class="header" href="#old-tests" id="old-tests">Old tests</a></h2>
|
|
<p>Once upon a time, I made a little test harness that would run the simulation
|
|
headlessly (without graphics), set up certain situations forcing a car to park
|
|
in a certain spot, and asserted that different <code>sim/src/events.rs</code> were produced
|
|
in the right order. The <code>map_editor</code> tool was used to manually draw really
|
|
simple maps for these situations. I deleted everything, because the effort to
|
|
specify the input and expected output were too tedious to maintain, and this
|
|
never really helped catch bugs. There was a way to label roads and buildings in
|
|
the synthetic maps, so the test code could assert person 2 made it to the
|
|
"house" building, but even with all of this, it was pretty hard.</p>
|
|
<p>This approach is maybe worth reviving, though.</p>
|
|
<h1><a class="header" href="#mass-importing-many-maps" id="mass-importing-many-maps">Mass importing many maps</a></h1>
|
|
<p>For <a href="https://github.com/dabreegster/abstreet/issues/326">https://github.com/dabreegster/abstreet/issues/326</a>, I'm starting to figure
|
|
out how to import hundreds of maps into A/B Street. There are many issues with
|
|
scaling up the number of supported maps. This document just focuses on
|
|
importing.</p>
|
|
<h2><a class="header" href="#the-current-approach" id="the-current-approach">The current approach</a></h2>
|
|
<p><a href="https://download.bbbike.org/">https://download.bbbike.org/</a> conveniently has 200 OSM extracts for major
|
|
cities world-wide. The <code>data/bbike.sh</code> script downloads these. Then
|
|
<code>data/mass_import.sh</code> attempts to import them into A/B Street.</p>
|
|
<p>The bbike extracts, however, cover huge areas surrounding major cities.
|
|
Importing such large areas is slow, and the result is too large to work well in
|
|
A/B Street or the OSM viewer. Ideally, we want just the area concentrated around
|
|
the "core" of each city.</p>
|
|
<p><a href="https://github.com/dabreegster/abstreet/blob/master/convert_osm/src/bin/extract_cities.rs">https://github.com/dabreegster/abstreet/blob/master/convert_osm/src/bin/extract_cities.rs</a>
|
|
transforms a huge .osm file into smaller pieces, each focusing on one city core.
|
|
This tool looks for administrative boundary relations tagged as cities, produces
|
|
a clipping polygon covering the city, and uses <code>osmconvert</code> to produce a smaller
|
|
<code>.osm</code> file. The tool has two strategies for generating clipping polygons. One
|
|
is to locate the <code>admin_centre</code> or <code>label</code> node for the region, then generate a
|
|
circle of fixed radius around that point. Usually this node is located in the
|
|
city core, so it works reasonably, except for "narrow" cities along a coast. The
|
|
other strategy glues together the relation's multipolygon boundary, then
|
|
simplifies the shape (usually with thousands of points) using a convex hull.
|
|
This strategy tends to produce results that're too large, because city limits
|
|
are often really huge.</p>
|
|
<h2><a class="header" href="#problems" id="problems">Problems</a></h2>
|
|
<ul>
|
|
<li>Outside the US, administrative boundaries don't always have a "city" defined.
|
|
In Tokyo in particular, this name isn't used. I'm not sure which boundary
|
|
level to use yet.</li>
|
|
<li>The tool assumes driving on the right everywhere. OSM has
|
|
<a href="https://wiki.openstreetmap.org/wiki/Key:driving_side">https://wiki.openstreetmap.org/wiki/Key:driving_side</a>, but this is usually
|
|
tagged at the country level, which isn't included in the bbike extracts.</li>
|
|
<li>The resulting maps are all "flattened" in A/B Street's list, so you can't see
|
|
any hierarchy of areas. Two cities with the same name from different areas
|
|
will arbitrarily collide.</li>
|
|
</ul>
|
|
<h1><a class="header" href="#data-organization" id="data-organization">Data organization</a></h1>
|
|
<p>A/B Street includes lots of large binary files to represent converted maps,
|
|
scenarios, and prebaked simulation results. The files are too large to store in
|
|
git, but the files are still logically tied to a version of the code, since the
|
|
format sometimes changes. Additionally, all of the files are too large to
|
|
include in the .zip release that most people use, but it should still be
|
|
possible for players to download the optional content. Also, there are different
|
|
versions of the game floating around, on native and web, that have to be
|
|
associated with the proper version of these files.</p>
|
|
<p>It's all slightly confusing, so this page describes how it all works.</p>
|
|
<h2><a class="header" href="#the-data-itself" id="the-data-itself">The data itself</a></h2>
|
|
<p>If you peek into the <code>data/</code> directory, it's mainly split into 3 subdirectories.
|
|
<code>system/</code> is used when running the game and is the subject of this page.
|
|
<code>input/</code> is used to store input and intermediate files for importing maps, and
|
|
only developers running the importer should care about it. <code>player/</code> contains
|
|
local settings, map edits, and other data created in-game.</p>
|
|
<p><code>data/MANIFEST.json</code> is a listing of all files in <code>data/system/</code>, along with
|
|
their size and md5sum. Different tools compare this manifest to the local
|
|
filesystem to figure out what to do.</p>
|
|
<p>There are also some other scripts and files in <code>data/</code>, but they should probably
|
|
be moved.</p>
|
|
<h2><a class="header" href="#where-the-data-is-stored" id="where-the-data-is-stored">Where the data is stored</a></h2>
|
|
<p><code>data/system/</code> and <code>data/input/</code> are stored in Amazon S3, at
|
|
http://abstreet.s3-website.us-east-2.amazonaws.com. This S3 bucket is organized
|
|
into versions: <code>dev</code>, <code>0.2.17</code>, <code>0.2.18</code>, etc. <code>dev</code> represents the latest
|
|
version of all data files. The numbered versions correspond to
|
|
<a href="https://github.com/dabreegster/abstreet/releases">releases</a> and only contain
|
|
<code>data/system/</code>, not <code>data/input/</code>. Depending how large these directories grow
|
|
over time, I'll commit to keeping around at least 3 of the previous numbered
|
|
versions, but I might delete older ones after that.</p>
|
|
<p>In lieu of a proper document for the release process, the commands used to make
|
|
a versioned copy of the data are something like:</p>
|
|
<pre><code>aws s3 cp --recursive s3://abstreet/dev/data/system s3://abstreet/0.2.17/data/system
|
|
</code></pre>
|
|
<h2><a class="header" href="#native-running-from-source" id="native-running-from-source">Native, running from source</a></h2>
|
|
<p>For people building the game <a href="dev/index.html">from source</a>, the process to keep data
|
|
files fresh is to <code>cargo run --bin updater</code>. This tool calculates md5sums of all
|
|
local files, then compares it with the checked-in <code>data/MANIFEST.json</code>. Any
|
|
difference results in a local file being deleted or a new file from S3 being
|
|
downloaded. By editing <code>data/player/data.json</code> manually or using the UI in the
|
|
game (found by loading a map, then choosing to download more maps), somebody can
|
|
opt into downloading "extra/optional" cities.</p>
|
|
<h2><a class="header" href="#native-running-from-a-release-zip" id="native-running-from-a-release-zip">Native, running from a release .zip</a></h2>
|
|
<p>When the weekly .zip binary release for Mac, Linux, and Windows is produced, the
|
|
<code>game</code> crate is built with <code>--features release_s3</code>. When the downloader UI is
|
|
opened in-game, this causes downloads to occur from a versioned S3 directory,
|
|
like <code>0.2.17</code>, depending on the version string compiled into the game at that
|
|
time. So somebody can run off the weekly release, opt into more cities, and get
|
|
the correct version of the files, even if the format has changed in <code>/dev/</code>
|
|
since then.</p>
|
|
<h2><a class="header" href="#web-running-locally" id="web-running-locally">Web, running locally</a></h2>
|
|
<p>The strategy for managing files gets more interested when the game is compiled
|
|
to WebAssembly, since browsers can't read from the local filesystem.
|
|
<code>game/src/load.rs</code> contains some crazy tricks to instead make asynchronous HTTP
|
|
requests through the browser. When using <code>game/run_web.sh</code>, the files are served
|
|
through a local HTTP server and symlinked to the local copy of <code>data/system/</code>.</p>
|
|
<p>Not all files are loaded through HTTP; some are actually statically compiled
|
|
into the <code>.wasm</code> file itself! <code>abstutil/src/io_web.rs</code> does this magic using the
|
|
<code>include_dir</code> crate. Only a few critical large files, needed at startup, are
|
|
included. There's an IO layer for listing and reading files that, on web, merges
|
|
results from the bundled-in files and the remote files that're declared to exist
|
|
in the bundled-in copy of <code>data/MANIFEST.json</code>.</p>
|
|
<h2><a class="header" href="#web-from-s3" id="web-from-s3">Web, from S3</a></h2>
|
|
<p>Everything's the same, except building with <code>--features wasm_s3</code> causes the game
|
|
to make HTTP requests to the S3 bucket, instead of localhost. The web version
|
|
always pins to <code>/dev</code>, never a release version of the data, since the web client
|
|
is always updated along with the data, for now.</p>
|
|
<h1><a class="header" href="#map-model" id="map-model">Map model</a></h1>
|
|
<p>A/B Street transforms OpenStreetMap (OSM) data into a detailed geometric and
|
|
semantic representation of the world for traffic simulation. This chapter
|
|
describes that map model, with the hopes that it'll be useful for purposes
|
|
beyond this project.</p>
|
|
<h2><a class="header" href="#overview" id="overview">Overview</a></h2>
|
|
<p>A <code>Map</code> covers everything inside some hand-drawn boundary, usually scoped to a
|
|
city or a few of a city's districts. Unlike OSM, it doesn't cover the entire
|
|
world; it only has areas specifically extracted for some purpose.</p>
|
|
<p>A map consists of many objects. Mainly, there are roads, broken down into
|
|
individual lanes, and intersections. A road is a single segment connecting
|
|
exactly two intersections (as opposed to OSM, where a single "way" may span many
|
|
intersections). Lanes within a road have a specific type, which dictates their
|
|
direction of travel (or lack of travel, like on-street parking) and uses.
|
|
Sidewalks are represented as bidirectional lanes. Roads connect at
|
|
intersections, which contain an explicit set of turns, each linking a source
|
|
lane to a destination lane.</p>
|
|
<p>Maps also contain parking lots and buildings, which connect to the nearest
|
|
driveable lane and a sidewalk. Maps have water and park areas, only used for
|
|
drawing. They also represent public transit stops and routes.</p>
|
|
<h2><a class="header" href="#how-is-a-map-used" id="how-is-a-map-used">How is a map used?</a></h2>
|
|
<p>Unlike some GIS systems, maps don't use any kind of database -- they're just a
|
|
file, anywhere from 1 to ~500MB (depending on the size of their boundary). Once
|
|
loaded into memory, different objects from the map can be accessed directly,
|
|
along with a large API to perform various queries.</p>
|
|
<p>Most of the map's API is read-only; once built, a map doesn't change until
|
|
user-created edits are applied.</p>
|
|
<p>The pipeline to import a map from OSM data (and also optional supplementary,
|
|
city-specific data) is complex and may take a few minutes to run, but it happens
|
|
once offline. Applications using maps just read the final file.</p>
|
|
<h2><a class="header" href="#features" id="features">Features</a></h2>
|
|
<p>Why use A/B Street's map model instead of processing OSM directly?</p>
|
|
<p>TODO: Order these better. For each one, show before/after pictures</p>
|
|
<h3><a class="header" href="#area-clipping" id="area-clipping">Area clipping</a></h3>
|
|
<p>Bodies of water, forests, parks, and other areas are represented in OSM as
|
|
relations, requiring the user to stitch together multiple polylines in undefined
|
|
orders and handle inner holes. A/B Street maps handle all of that, and also clip
|
|
the area's polygon to the boundary of the entire map -- including coastlines.</p>
|
|
<h3><a class="header" href="#road-and-intersection-geometry" id="road-and-intersection-geometry">Road and intersection geometry</a></h3>
|
|
<p>OSM represents roads as a polyline of the physical center of the road. A/B
|
|
Street infers the number and type of lanes from OSM metadata, then creates
|
|
individual lanes of appropriate width, each with a center-line and polygon for
|
|
geometry. At intersections, the roads and lanes are "trimmed back" to avoid
|
|
overlapping, and the "common area" becomes the intersection's polygon. This
|
|
heuristic process is reasonably robust to complex shapes, with special treatment
|
|
of highway on/off-ramps, although it does still have some bugs.</p>
|
|
<h3><a class="header" href="#turns" id="turns">Turns</a></h3>
|
|
<p>At each intersection, A/B Street infers all legal movements between vehicle
|
|
lanes and sidewalks. This process makes use of OSM metadata about turn lanes,
|
|
inferring reasonable defaults for multi-lane roads. OSM turn restriction
|
|
relations, which may span a sequence of several roads to describe U-turns around
|
|
complex intersections, are also used.</p>
|
|
<h3><a class="header" href="#parking-lots" id="parking-lots">Parking lots</a></h3>
|
|
<p>OSM models parking lots as areas along with the driveable aisles. Usually the
|
|
capacity of a lot isn't tagged. A/B Street automatically fills paring lots with
|
|
individual stalls along the aisles, estimating the capacity just from this
|
|
geometry.</p>
|
|
<h3><a class="header" href="#stop-signs" id="stop-signs">Stop signs</a></h3>
|
|
<p>At unsignalized intersections, A/B Street infers which roads have to stop, and
|
|
which have right-of-way.</p>
|
|
<h3><a class="header" href="#traffic-signals" id="traffic-signals">Traffic signals</a></h3>
|
|
<p>OSM has no way to describe how traffic signals are configured. A/B Street models
|
|
fixed-timer signals, automatically inferring the number of phases, their
|
|
duration, and the movements that are prioritized and permitted during each
|
|
phase.</p>
|
|
<h3><a class="header" href="#pathfinding" id="pathfinding">Pathfinding</a></h3>
|
|
<p>A/B Street can determine routes along lanes and turns for vehicles and
|
|
pedestrians. These routes obey OSM's turn restriction relations that span
|
|
multiple road segments. They also avoid roads that're tagged as not allowing
|
|
through-traffic, depending on the route's origin and destination and vehicle
|
|
type. The pathfinding optionally makes use of contraction hierarchies to greatly
|
|
speed up query performance, at the cost of a slower offline importing process.</p>
|
|
<h3><a class="header" href="#bridge-z-ordering" id="bridge-z-ordering">Bridge z-ordering</a></h3>
|
|
<p>OSM tags bridges and tunnels, but the roads that happen to pass underneath
|
|
bridges aren't mapped. A/B Street detects these and represents the z-order for
|
|
drawing.</p>
|
|
<h3><a class="header" href="#buildings" id="buildings">Buildings</a></h3>
|
|
<p>Similar to areas, A/B Street consolidates the geometry of OSM buildings, which
|
|
may be split into multiple polygons. Each building is also associated with the
|
|
nearest driveable lane and sidewalk, and metadata is used to infer a land-use
|
|
(like residential and commercial) and commercial amenities available.</p>
|
|
<h3><a class="header" href="#experimental-public-transit" id="experimental-public-transit">Experimental: public transit</a></h3>
|
|
<p>A/B Street uses bus stops and route relations from OSM to build a model of
|
|
public transit routes. OSM makes few guarantees about how the specifics of the
|
|
route are specified, but A/B Street produces specific paths, handling clipping
|
|
to the map boundary.</p>
|
|
<p>... All of this isn't the case yet, but it's a WIP!</p>
|
|
<h3><a class="header" href="#experimental-separated-cyclepaths-tramways-and-walking-paths" id="experimental-separated-cyclepaths-tramways-and-walking-paths">Experimental: separated cyclepaths, tramways, and walking paths</a></h3>
|
|
<p>Some cyclepaths, tram lines, and footpaths in OSM are tagged as separate ways,
|
|
with no association to a "main" road. Sometimes this is true -- they're
|
|
independent trails that only occasionally cross roads. But often they run
|
|
alongside a road. A/B Street attempts to detect these and "snap" them to the
|
|
main road as extra lanes.</p>
|
|
<p>... But this doesn't work yet at all.</p>
|
|
<h1><a class="header" href="#map-model-details" id="map-model-details">Map model details</a></h1>
|
|
<p>A/B Street builds a rich representation of a city map using OpenStreetMap (OSM)
|
|
and other sources. This chapter describes how.</p>
|
|
<p>TODO: Integrate pictures from
|
|
<a href="https://docs.google.com/presentation/d/1cF7qFtjAzkXL_r62CjxBvgQnLvuQ9I2WTE2iX_5tMCY/edit?usp=sharing">these slides</a>.</p>
|
|
<p><a href="https://youtu.be/chYd5I-5oyc?t=439">This recorded presentation</a> covers some of
|
|
this.</p>
|
|
<h2><a class="header" href="#the-map" id="the-map">The map</a></h2>
|
|
<p>A single city is broken down into different pieces...</p>
|
|
<p>A/B Street comes with a few maps, each defined by a bounding/clipping polygon
|
|
for some portion of Seattle. Each map has these objects:</p>
|
|
<ul>
|
|
<li><strong>Roads</strong>: A single road connects two intersections, carrying OSM metadata and
|
|
containing some child lanes.</li>
|
|
<li><strong>Lanes</strong>: An individual lane of traffic. Driving (any vehicle), bus-only, and
|
|
bike-only lanes have a direction. On-street parking lanes don't allow any
|
|
movement, and they have some number of parking spots. Sidewalks are
|
|
bidirectional.</li>
|
|
<li><strong>Intersections</strong>: An intersection has references to all of the incoming and
|
|
outgoing lanes. Most intersections have a stop sign or traffic signal policy
|
|
controlling movement through it.
|
|
<ul>
|
|
<li><strong>Border</strong> intersections on the edge of the map are special places where
|
|
agents may appear or disappear.</li>
|
|
</ul>
|
|
</li>
|
|
<li><strong>Turns</strong>: A turn connects one lane to another, via some intersection.
|
|
(Sidewalks are bidirectional, so specifying the intersection is necessary to
|
|
distinguish crosswalks at each end of a sidewalk.)</li>
|
|
<li><strong>Buildings</strong>: A building has a position, OSM metadata, and a <strong>front path</strong>
|
|
connecting the edge of the building to the nearest sidewalk. Most trips in A/B
|
|
Street begin and end at buildings. Some buildings also contain a number of
|
|
off-street parking spots.</li>
|
|
<li><strong>Area</strong>: An area has geometry and OSM metadata and represents a body of
|
|
water, forest, park, etc. They're just used for drawing.</li>
|
|
<li><strong>Bus stop</strong>: A bus stop is placed some distance along a sidewalk, with a
|
|
pointer to the position on the adjacent driving or bus lane where a bus stops
|
|
for pick-up.</li>
|
|
<li><strong>Bus route</strong>: A bus route has a name and a list of stops that buses will
|
|
cycle between. In the future, they'll include information about the
|
|
frequency/schedule of the route.</li>
|
|
<li><strong>Parking lot</strong>: A parking lot is connected to a road, has a shape, and has
|
|
some internal driving "aisles." The number and position of individual parking
|
|
spots is auto-generated.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#coordinate-system" id="coordinate-system">Coordinate system</a></h2>
|
|
<p>A/B Street converts (longitude, latitude) coordinates into a simpler form.</p>
|
|
<ul>
|
|
<li>An (x, y) point starts with the top-left of the bounding polygon as the
|
|
origin. Note this is screen drawing order, not a Cartesian plane (with Y
|
|
increasing upwards) -- so angle calculations account for this.</li>
|
|
<li>The (x, y) values are f64's trimmed to a few decimal places, with way more
|
|
precision than is really needed. These might become actual fixed-point
|
|
integers later, but for now, a <code>Pt2D</code> skirts around Rust's limits on f64's by
|
|
guaranteeing no NaN's or infinities and thus providing the full <code>Eq</code> trait.</li>
|
|
<li>A few places in map conversion compare points using different thresholds,
|
|
usually below 1 meter. Ideally these epsilon comparisons could be eliminated
|
|
in favor of a fixed-point integer representation, but for now, explicit
|
|
thresholds are useful.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#invariants" id="invariants">Invariants</a></h2>
|
|
<p>Ideally, the finalized maps would satisfy a list of invariants, simplifying the
|
|
traffic simulation and drawing code built on top. But the input data is quite
|
|
messy and for now, most of these aren't quite guaranteed to be true.</p>
|
|
<ul>
|
|
<li>Some minimum length for lanes and turns. Very small lanes can't be drawn, tend
|
|
to break intersection polygons, and may lead to gridlocked traffic.</li>
|
|
<li>Some guarantees that positions along adjacent lanes actually match up, even
|
|
though different lanes on the same road may have different lengths. Examples
|
|
include the position of a bus stop on the sidewalk and bus lane matching up.
|
|
<ul>
|
|
<li>Additionally, parking lanes without an adjacent driving lane or bus stops
|
|
without any driving or bus lanes make no sense and should never occur.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Connectivity -- any sidewalk should be reachable from any other, and most
|
|
driving lanes should be accessible from any others. There are exceptions due
|
|
to border intersections -- if a car spawns on a highway along the border of
|
|
the map, it may be forced to disappear on the opposite border of the map, if
|
|
the highway happens to not have any exits within the map boundary.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#connectivity" id="connectivity">Connectivity</a></h2>
|
|
<p>For a single mode, each lane is connected to two intersections. Turns connect
|
|
two lanes. There are no turns between sidewalks and driving/bike/bus lanes.</p>
|
|
<p>All buildings and parking lots have driveways. This must connect to a sidewalk,
|
|
allowing pedestrians to enter/exit that object. The driveway OPTIONALLY connects
|
|
to the nearest driveable lane. This allows cars to enter/exit that object for
|
|
parking.</p>
|
|
<p>Public transit stops are located somewhere on a sidewalk. They're associated
|
|
with a driveable position where the bus or train stops. In the future, this will
|
|
need to account for dedicated surface-level platforms and for underground
|
|
transit stations, likely associated with a building.</p>
|
|
<p>There's a concept of "parking blackholes." If you treat every road as
|
|
bidirectional without access restrictions, then the graph is connected. But the
|
|
more detailed view has to factor in one-way roads and things near the map
|
|
border. These blackholes influence where cars will try to look for parking
|
|
(since we don't want them entering a blackhole and getting stuck) and also, for
|
|
temporary/unintentional reasons, where pedestrian<->bicycle transitions will
|
|
happen.</p>
|
|
<h1><a class="header" href="#importing" id="importing">Importing</a></h1>
|
|
<p>This chapter describes the process of transforming OSM extracts into A/B
|
|
Street's map model. The steps are:</p>
|
|
<ol>
|
|
<li>A large .osm file is clipped to a hand-drawn boundary region, using
|
|
<code>osmconvert</code></li>
|
|
<li>The <code>convert_osm</code> crate reads the clipped <code>.osm</code>, and a bunch of optional
|
|
supplementary files, and produces a <code>RawMap</code></li>
|
|
<li>Part of the <code>map_model</code> crate transforms the <code>RawMap</code> into the final <code>Map</code></li>
|
|
<li>Other applications read and use the <code>Map</code> file</li>
|
|
</ol>
|
|
<p>The <code>importer</code> crate orchestrates these steps, along with automatically
|
|
downloading any missing input data.</p>
|
|
<p>The rest of these sections describe each step in a bit more detail. Keeping the
|
|
docs up-to-date is hard; the best reference is the code, which is hopefully
|
|
organized clearly.</p>
|
|
<p>Don't be afraid of how complicated this pipeline seems -- each step is
|
|
relatively simple. If it helps, imagine how this started -- just chop up OSM
|
|
ways into road segments, infer lanes for each road, and infer turns between the
|
|
lanes.</p>
|
|
<h1><a class="header" href="#from-osm-to-rawmap-convert_osm-crate" id="from-osm-to-rawmap-convert_osm-crate">From OSM to RawMap (<code>convert_osm</code> crate)</a></h1>
|
|
<p>The first phase of map building reads in data from OSM files and a few others,
|
|
producing a serialized <code>RawMap</code>.</p>
|
|
<p>Only major steps are described; see the code for the rest.</p>
|
|
<h2><a class="header" href="#extractrs" id="extractrs">extract.rs</a></h2>
|
|
<p>Read .osm, extracting the points for road-like ways, buildings, and areas</p>
|
|
<ul>
|
|
<li>Areas usually come from a relation of multiple ways, with the points out of
|
|
order. Gluing all the points together fails when the .osm has some ways
|
|
clipped out. In that case, try to trace along the map boundary if the partial
|
|
area intersects the boundary in a clear way. Otherwise, just use a straight
|
|
line to try to close off the polygon.</li>
|
|
<li>Also read traffic signal locations and turn restrictions between OSM ways</li>
|
|
</ul>
|
|
<h2><a class="header" href="#split_waysrs" id="split_waysrs">split_ways.rs</a></h2>
|
|
<p>Split OSM ways into road segments</p>
|
|
<ul>
|
|
<li>OSM ways cross many intersections, so treat points with multiple ways and the
|
|
points at the beginning and end of a way as intersections, then split the way
|
|
into road segments between two intersections.</li>
|
|
<li>This phase remembers which road segment is the beginning and end of the OSM
|
|
way, for per-lane turn restrictions later</li>
|
|
<li>Apply turn restrictions between roads here. Since OSM ways cross many
|
|
intersections, the turn restrictions only apply to one particular road segment
|
|
that gets created from the way. Make sure the destination of the restriction
|
|
is actually incident to a particular source road.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#clip" id="clip">clip</a></h2>
|
|
<p>Clip the map to the boundary polygon</p>
|
|
<ul>
|
|
<li><code>osmconvert</code> options preserve ways that cross the boundary</li>
|
|
<li>Trim roads that cross the boundary. There may be cases where a road dips out
|
|
of bounds, then immediately comes back in. Disconnecting it isn't ideal, but
|
|
it's better to manually tune the boundary polygon when this happens than try
|
|
to preserve lots of out-of-bounds geometry.</li>
|
|
<li>Area polygons are intersected with the boundary polygon using the <code>clipping</code>
|
|
crate</li>
|
|
</ul>
|
|
<h1><a class="header" href="#roadintersection-geometry-rawmap-to-initialmap" id="roadintersection-geometry-rawmap-to-initialmap">Road/intersection geometry: RawMap to InitialMap</a></h1>
|
|
<p>The remainder of map construction is done in the <code>map_model</code> crate. There's one
|
|
intermediate structure between <code>RawMap</code> and <code>Map</code>, called <code>InitialMap</code>.</p>
|
|
<ul>
|
|
<li><code>make/remove_disconnected.rs</code>: Remove disconnected roads
|
|
<ul>
|
|
<li>Just floodfill from some road, assuming all roads are bidirectional, to get
|
|
different partitions.</li>
|
|
<li>Remove roads from all but the largest partition</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>make/initial/mod.rs</code> and <code>make/initial/lane_specs.rs</code>: Interpret OSM tags to
|
|
figure out what lanes are on each side of each road, also figuring out the
|
|
total width of the road.</li>
|
|
<li><code>make/initial/geometry.rs</code>: Figure out the polygon for each intersection, and
|
|
trim back road center-lines to end at a face of the polygon.
|
|
<ul>
|
|
<li>For every road touching the intersection, get the polyline of each side,
|
|
based on the road's width
|
|
<ul>
|
|
<li>See appendix for how to shift polylines</li>
|
|
</ul>
|
|
</li>
|
|
<li>Sort all the polylines by the angle to the intersection's shared point</li>
|
|
<li>Intersect every polyline with every other polyline
|
|
<ul>
|
|
<li>More specifically -- the second half of each polyline, to get the correct
|
|
collision point</li>
|
|
<li>Look at the perpendicular infinite line to the collision point on the
|
|
shifted polyline, then find where it hits the original center line. Trim
|
|
back the center line by the max distance from these collisions.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Compute the intersection's polygon by considering collisions between
|
|
adjacent roads' polylines</li>
|
|
<li>Deal with short roads and floating point issues by deduping any adjacent
|
|
points closer than 0.1m</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h1><a class="header" href="#initialmap-to-map" id="initialmap-to-map">InitialMap to Map</a></h1>
|
|
<p>Still in the <code>map_model</code> crate.</p>
|
|
<ul>
|
|
<li><code>map.rs</code>'s <code>make_half_map</code>: Expand roads to lanes, using the list of lane
|
|
types from before</li>
|
|
<li><code>make/turns.rs</code>: Generate turns for every intersection.
|
|
<ul>
|
|
<li>Vehicle turns (for cars, bikes, buses)
|
|
<ul>
|
|
<li>Consider every pair of roads in the intersection. Try to match up lane
|
|
types -- if there's a bike lane on both roads, don't add a turn from
|
|
driving->bike or bike->driving. If there's not, then fallback to
|
|
transitions between different lane types.</li>
|
|
<li>Classify the turn based on the difference between the angle of the
|
|
incoming lane's last line and the outgoing lane's first line
|
|
<ul>
|
|
<li>For straight turns, use the Cartesian product to link every incoming
|
|
with every outgoing lane. If the indices dont match up, the turn becomes
|
|
a <code>LaneChangeLeft</code> or <code>LaneChangeRight</code> turn. This is used later for
|
|
intersection policies to prioritize turns appropriately.</li>
|
|
<li>Right and left turns only originate from the one lane on the appropriate
|
|
side</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>Walking turns for pedestrians
|
|
<ul>
|
|
<li>Consider pairs of adjacent roads around the intersection
|
|
<ul>
|
|
<li>Make a crosswalk to the other side of the road, assuming there's a
|
|
sidewalk on both sides</li>
|
|
<li>Make a shared sidewalk corner over to the adjacent road</li>
|
|
<li>If the adjacent road doesn't have a sidewalk on the close side, then
|
|
consider skipping that road and making a crosswalk over to the next
|
|
road. An example of this is a crosswalk over a highway on/off ramp.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>Verify all the turns so far are unique</li>
|
|
<li>Filter by the OSM turn restrictions ("only straight" between road1 and
|
|
road2)</li>
|
|
<li>Try to apply the OSM per-lane restrictions ("straight or left" from lane 3)
|
|
<ul>
|
|
<li>The number of lanes in the OSM metadata might not match up with how many
|
|
lanes created</li>
|
|
<li>Some of these OSM tags are just completely wrong sometimes. If the filter
|
|
makes an incoming lane lose all of its turns, then ignore that tag.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>make/parking_blackholes.rs</code>: Find well-connected roads near "blackhole"
|
|
lanes.
|
|
<ul>
|
|
<li>Starting from most driving/biking lanes, most other lanes are reachable.
|
|
Some aren't -- such as one-way highways inevitably leading from or to a
|
|
border. These are "blackholes" -- pathfinding to or from here may fail.</li>
|
|
<li>Find the largest strongly-connected component (SCC) in the driving graph.
|
|
From every other lane (a blackhole), floodfill both forwards and backwards
|
|
to find the nearest driving lane part of the main SCC.</li>
|
|
<li>Later, if a car needs to park by a building on a blackhole road, it'll
|
|
instead start searching for parking at the redirect. This prevents it from
|
|
being forced to instead exit the map through a border.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>make/buildings.rs</code>: Match buildings up with sidewalks
|
|
<ul>
|
|
<li>Find the closest sidewalk polyline to each building's center. Then draw a
|
|
straight line for the front path between the edge of the building and the
|
|
sidewalk point.</li>
|
|
<li>Filter out buildings too far away from any sidewalk</li>
|
|
<li>The front path might cross through other buildings; this is probably not
|
|
worth fixing.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>make/buildings.rs</code>: Same for parking lots
|
|
<ul>
|
|
<li>Similar process to match parking lots to nearest sidewalk and driving lane</li>
|
|
<li>Try to place parking spots along both sides of parking aisles</li>
|
|
<li>Filter out overlapping spots</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>make/bridges.rs</code>: Find what roads lie beneath bridges, and update their
|
|
Z-order accordingly for later drawing.</li>
|
|
<li><code>stop_signs.rs</code>: Instantiate default stop sign policies
|
|
<ul>
|
|
<li>Rank incoming roads by OSM priority (arterial beats residential)</li>
|
|
<li>If there's only one rank, then make an all-way stop</li>
|
|
<li>Otherwise, the highest rank gets priority and others stop
|
|
<ul>
|
|
<li>Check if there are any conflicts based on this. If so, then fall-back to
|
|
an all way stop.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>traffic_signals.rs</code>: Instantiate default traffic signal policies
|
|
<ul>
|
|
<li>Apply the first predefined policy that works.
|
|
<ul>
|
|
<li>4-way 4 stage, 4-way 2 stage, 3-way 3-stage, degenerate policy for 2
|
|
roads, 2-stage for 4 one-ways</li>
|
|
<li>Fallback to a greedy assignment that just randomly starts a new stage,
|
|
adds all compatible turns, and repeats until all turns are present
|
|
priority in some stage.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>pathfind/mod.rs</code>: Prepare pathfinding
|
|
<ul>
|
|
<li>A/B Street uses contraction hierarchies (CH) for fast routing, using the
|
|
<code>fast_paths</code> crate.</li>
|
|
<li><code>pathfind/vehicle.rs</code>: For cars, bikes, buses
|
|
<ul>
|
|
<li>There's a separate CH for cars, buses, and bikes, since they can use
|
|
slightly different sets of lanes.</li>
|
|
<li>Building the CH for buses and bikes is much faster than the one for cars,
|
|
because the algorithm can re-use the node ordering from the first CH.</li>
|
|
<li>Every lane is a node in the graph, even if it's not an appropriate lane
|
|
type -- it might change later, and reusing orderings is vital for speed.</li>
|
|
<li>If two lanes are connected by a turn, then there's an edge in the graph.
|
|
<ul>
|
|
<li>The edge weight is the length of the lane and turn. Later this could
|
|
take into account speed limit, penalize lane-changing and left turns,
|
|
etc.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>pathfind/walking.rs</code>: For pedestrians
|
|
<ul>
|
|
<li>Only sidewalk lanes are nodes in the graph -- sidewalks can't ever be
|
|
changed in A/B Street, so there's no concern about reusing node orderings.</li>
|
|
<li>All turns between two sidewalks become edges, again using length</li>
|
|
<li>When actually pathfinding, we get back a list of sidewalks. The actual
|
|
paths used in the traffic simulation specify forwards or backwards on a
|
|
sidewalk. Looking at adjacent pairs of sidewalks lets us easily stitch
|
|
together exact directions.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>make/bus_stops.rs</code>: Match bus stops with a sidewalk
|
|
<ul>
|
|
<li>Also precompute the position where the bus stops on the adjacent driving or
|
|
bus lane.</li>
|
|
<li>This "equivalent position on another lane" process has a few weird cases,
|
|
since two lanes on the same road might have different lengths. Right now,
|
|
the same distance from the start of the lane is used, with clamping for
|
|
shorter lanes. Ideally, the position would be found by projecting a
|
|
perpendicular line out from one lane to the other.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>make/bus_stops.rs</code>: Finalize the list of bus routes
|
|
<ul>
|
|
<li>Between each pair of adjacent bus stops, run pathfinding to verify there's
|
|
actually a path for the bus to follow. If any are disconnected, remove the
|
|
bus route</li>
|
|
<li>Remove bus stops that have no routes serving them.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>pathfind/walking.rs</code>: Precompute the CH for pedestrians who will use buses
|
|
<ul>
|
|
<li>Nodes in the graph are sidewalks and every bus stop</li>
|
|
<li>There's an edge with weight 0 between a bus stop and its sidewalk</li>
|
|
<li>There's also an edge with weight 0 between bus stops that're adjacent via
|
|
some route. Ideally this weight would account for the time until the next
|
|
bus and the time spent on the bus, etc.</li>
|
|
<li>Later when figuring out which bus to use for a pedestrian, the resulting
|
|
list of nodes is scanned for the first and last bus stop along the same
|
|
route.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h1><a class="header" href="#development-tricks" id="development-tricks">Development tricks</a></h1>
|
|
<ul>
|
|
<li>Separate phases for fast incremental development
|
|
<ul>
|
|
<li>Don't reimport all data from OSM every time there's a change to part of the
|
|
map construction code!</li>
|
|
<li>For slow steps that don't change often, make them separate binaries -- hence
|
|
<code>convert_osm</code> being separate from the rest.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Don't be afraid of manual intervention
|
|
<ul>
|
|
<li>The data isn't perfect. It's easy to spend lots of time fiddling with code
|
|
to automatically handle all problems</li>
|
|
<li>Instead of automatically resolving problems, prefer good tooling for finding
|
|
and specifying fixes</li>
|
|
<li>Be careful of derivative structures that could get out of sync with OSM.
|
|
Prefer contributing real fixes to OSM.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Screenshot diff testing
|
|
<ul>
|
|
<li>When working on the code for intersection geometry, it's easy to check a few
|
|
example cases get fixed by some change. But what if another part of the map
|
|
regresses somehow?</li>
|
|
<li>Take screenshots of the entire map, keep the checksums under version
|
|
control, look at the diffs visually, and manually verify any changes.</li>
|
|
<li>Implementation details: One huge gif or png is too slow to read and write,
|
|
so take a bunch of tiled screenshots covering everything. Amusingly,
|
|
rendering to a file with <code>glium</code> is slow unless compiling in release mode
|
|
(which isn't an option for quick incremental development). So instead, pan
|
|
to each section of the map, render it, call an external screenshot utility,
|
|
and move on -- just don't wiggle the mouse during this process!</li>
|
|
</ul>
|
|
</li>
|
|
<li>Different IDs for objects make sense during different phases
|
|
<ul>
|
|
<li>For the final product, lanes and such are just a contiguous array, indexed
|
|
by numeric IDs.</li>
|
|
<li>But sometimes, we need IDs that're the same between different boundary
|
|
polygons of maps, so that player edits can be applied anywhere. Using
|
|
(longitude, latitude) pairs hits floating-point serialization and comparison
|
|
issues, so referring to roads as (OSM way ID, OSM node ID 1, OSM node ID 2)
|
|
works instead.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#appendix-polylines" id="appendix-polylines">Appendix: PolyLines</a></h2>
|
|
<p>Add some pictures here to demonstrate how polyline shifting works, the
|
|
explode-to-infinity problem, and the bevel/miter fix.</p>
|
|
<h1><a class="header" href="#live-edits" id="live-edits">Live edits</a></h1>
|
|
<p>A key feature of A/B Street is the player editing the map and seeing how traffic
|
|
responds. The possible edits include:</p>
|
|
<ul>
|
|
<li>Change lane types (driving, bus, bike, parking -- sidewalks are fixed)</li>
|
|
<li>Change speed limits</li>
|
|
<li>Reverse a lane</li>
|
|
<li>Change a stop sign policy (which roads have a stop sign and which have
|
|
priority)</li>
|
|
<li>Change a traffic signal policy</li>
|
|
</ul>
|
|
<p>The map conversion process outlined above takes a few minutes, so reusing this
|
|
process directly to compute a map with edits wouldn't work at all for real
|
|
gameplay. Instead, the process for applying edits is incremental:</p>
|
|
<ul>
|
|
<li>Figure out the actual diff between edits and the current map
|
|
<ul>
|
|
<li>This is necessary for correctness, but also speeds up a sequence of edits
|
|
made in the UI -- only one or two lanes or intersections actually changes
|
|
each time. Of course when loading some saved edits, lots of things might
|
|
change.</li>
|
|
</ul>
|
|
</li>
|
|
<li>For any changed roads, make sure any bus stop on it have a good pointer to
|
|
their equivalent driving position for the bus.</li>
|
|
<li>For any modified intersections, recompute turns and the default intersection
|
|
policies</li>
|
|
<li>Recompute all the CHs for cars, buses, and bikes -- note sidewalks and bus
|
|
stops never change
|
|
<ul>
|
|
<li>This is the slowest step. Critically, the <code>fast_paths</code> crate lets a previous
|
|
node ordering be reused. If just a few edge weights change, then recomputing
|
|
is much faster than starting from scratch.</li>
|
|
<li>While making edits in the UI, we don't actually need to recompute the CH
|
|
after every little tweak. When the player exits edit mode, only then do we
|
|
recompute everything.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p>A list of lanes and intersections actually modified is then returned to the
|
|
drawing layer, which uploads new geometry to the GPU accordingly.</p>
|
|
<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>
|
|
<li>A new OSM viewer/editor, particularly focused on POIs</li>
|
|
<li>Something focusing on 15-minute neighborhoods, with isochrones and nearby
|
|
amenities</li>
|
|
</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>
|
|
<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>
|
|
<h1><a class="header" href="#ab-streets-traffic-simulation" id="ab-streets-traffic-simulation">A/B Street's Traffic Simulation</a></h1>
|
|
<p>This article describes how cars, bikes, buses, and pedestrians are modeled in
|
|
A/B Street. All code lives in the <code>sim</code> crate.</p>
|
|
<p><a href="https://youtu.be/chYd5I-5oyc?t=1086">This recorded presentation</a> covers some of
|
|
this.</p>
|
|
<h1><a class="header" href="#discrete-event-simulation" id="discrete-event-simulation">Discrete-event simulation</a></h1>
|
|
<p>The traffic simulation models different agents (cars, bikes, buses, pedestrians,
|
|
and intersections) over time. Agents don't constantly sense and react to the
|
|
world every second; instead, they remain in some state until something
|
|
interesting happens. This is a discrete-event architecture -- events are
|
|
scheduled for some time in the future, and handling them changes the state of
|
|
some agents. The core simulation loop simply processes events in order -- see
|
|
<code>scheduler.rs</code> and the <code>step</code> method in <code>sim.rs</code>.</p>
|
|
<h2><a class="header" href="#cars" id="cars">Cars</a></h2>
|
|
<p>(Note: Cars, bikes, and buses are all modeled the same way -- bikes just have a
|
|
max speed, and buses/bikes can use restricted lanes.)</p>
|
|
<p>Cars move through a sequence of lanes and turns (movements through an
|
|
intersection). They queue and can't over-take a slow lead vehicle. The main
|
|
simplifying assumption in A/B Street is that cars can instantly accelerate and
|
|
decelerate. This wouldn't model highway driving at all, where things like jam
|
|
waves are important, but it's reasonable for in-city driving. The essence of
|
|
scarcity is the capacity on lanes and the contention at intersections. What
|
|
happens in between isn't vital to get exactly right.</p>
|
|
<p>A car has a few states (<code>mechanics/car.rs</code>):</p>
|
|
<ul>
|
|
<li><strong>Crossing</strong> some distance of a lane/turn over some time interval</li>
|
|
<li><strong>Queued</strong> behind another car on a lane/turn</li>
|
|
<li><strong>WaitingToAdvance</strong> at the end of a lane, blocked on an intersection</li>
|
|
<li>A few states where the car stays in one place: <strong>Parking</strong>, <strong>Unparking</strong>, and
|
|
<strong>Idling</strong> (for buses at a stop)</li>
|
|
</ul>
|
|
<p>State transitions happen in <code>mechanics/driving.rs</code>. This is best explained by an
|
|
example sequence:</p>
|
|
<ul>
|
|
<li>A car enters the Unparking state, taking a fixed 30s to exit a parking spot
|
|
and enter the adjacent driving lane. The driving lane is blocked during this
|
|
time, to mimic somebody pulling out from a parallel parking spot.</li>
|
|
<li>The car is now fully somewhere on the driving lane. It enters the Crossing
|
|
state, covering the remaining distance to the end of the road. The time
|
|
interval is calculated assuming the car travels at the max speed limit of the
|
|
road.</li>
|
|
<li>After that time, the car checks if there's anybody in the queue before it.
|
|
Nope? Then it attempts to initiate a turn through the intersection, but the
|
|
stop sign says no, so the car enters the WaitingToAdvance state.</li>
|
|
<li>Some time later, the stop sign wakes up the car. The car starts the turn,
|
|
entering the Crossing state again.</li>
|
|
<li>After finishing the turn, the car starts Crossing the next lane. When it's
|
|
finished, it turns out there are a few cars ahead of it, so it enters the
|
|
Queued state.</li>
|
|
<li>When the lead vehicle directly in front of the car exits the lane, it wakes up
|
|
the car, putting it in the Crossing state, starting at the appropriate
|
|
following distance behind the lead vehicle. This prevents the car from
|
|
immediately warping to the end of the lane when the lead vehicle is out of the
|
|
way.</li>
|
|
<li>And so on...</li>
|
|
</ul>
|
|
<h3><a class="header" href="#exact-positions" id="exact-positions">Exact positions</a></h3>
|
|
<p>For a discrete-event simulation, we don't usually care exactly where on a lane a
|
|
car is at some time. But we do need to know for drawing and for a few cases
|
|
during simulation, such as determining when a bus is lined up with a bus stop in
|
|
the middle of a lane. <code>mechanics/queue.rs</code> handles this, computing the distance
|
|
of every car in a lane. For cars in the <code>Crossing</code> state, we linearly
|
|
interpolate distance based on the current time. Of course, cars have to remain
|
|
in order, so Queued cars are limited by the lead vehicle's position + the lead
|
|
vehicle's length + a fixed following distance of 1m.</p>
|
|
<p>Another case where we need to know exact positions of cars is to prevent the
|
|
first vehicle on a lane from hitting the back of a car who just left the lane.
|
|
All vehicles have length, and position is tracked by the front of the car. When
|
|
a car's front leaves a lane, its back is still partly in the lane. Logically,
|
|
the new lead car in the lane still needs to act like it's Queued. So each lane
|
|
keeps a "laggy head", pointing to the car with its back partly in the lane.
|
|
After the laggy head has made it sufficient distance along its new turn or lane,
|
|
the laggy head on the old lane can be erased, unblocking the lead vehicle. This
|
|
requires calculating exact distances and some occasionally expensive cases where
|
|
we have to schedule frequent events to check when a laggy head is clear.</p>
|
|
<h2><a class="header" href="#lane-changing" id="lane-changing">Lane-changing</a></h2>
|
|
<p>Lane-changing (LCing) deserves special mention. A/B Street cheats by not
|
|
allowing it on lanes themselves. Instead, at intersections, cars can perform
|
|
turns that shift them over any number of lanes. These LCing turns conflict with
|
|
other turns appropriately, so the contention is still modeled. Why do it this
|
|
way? In a
|
|
<a href="http://apps.cs.utexas.edu/tech_reports/reports/tr/TR-2157.pdf">previous project</a>,
|
|
I tried opportunistic LCing. If a car had room to warp to the equivalent
|
|
distance on the adjacent lane without causing a crash, it would start LCing,
|
|
then take a fixed time to slide over, blocking both lanes throughout. This meant
|
|
cars often failed to LC when they needed to, forcing them to reroute, botching
|
|
their trip times. In many cases the cars would be permanently stuck, because
|
|
pathfinding would return paths requiring LCing that couldn't be pulled off in
|
|
practice due to really short roads. Why not try making the car slow down if
|
|
needed? Eventually it might have to stop, which could lead to unrealistic
|
|
gridlock. This LCing model was using a detailed discrete-time model with cars
|
|
accelerating properly; maybe it's easier with A/B Street's simplified movement
|
|
model.</p>
|
|
<p>Currently in A/B Street, cars will pick the least backed-up lane when there's a
|
|
choice. They make this decision once when they reach the front of a queue; look
|
|
for <code>opportunistically_lanechange</code> in <code>router.rs</code>. The decision could be
|
|
improved.</p>
|
|
<h2><a class="header" href="#pedestrians" id="pedestrians">Pedestrians</a></h2>
|
|
<p>Pedestrian modeling -- in <code>mechanics/walking.rs</code> is way simpler. Pedestrians
|
|
don't need to queue on sidewalks; they can "ghost" through each other. In
|
|
Seattle, there aren't huge crowds of people walking and slowing down, except for
|
|
niche cases like Pike Place Market. So in A/B Street, the only scarce resource
|
|
modeled is the time spent waiting to cross intersections.</p>
|
|
<h2><a class="header" href="#intersections-1" id="intersections-1">Intersections</a></h2>
|
|
<p>I need to flesh this section out. See <code>mechanics/intersections.rs</code> for how stop
|
|
signs and traffic signals work. Two things I need to fix before making this
|
|
section interesting:</p>
|
|
<ul>
|
|
<li>Only wake up relevant agents when a previous agent finishes a turn.</li>
|
|
<li>Don't let an agent start a low-priority turn (like an unprotected left) if
|
|
it'll force a high-priority vehicle approaching to wait. The approaching
|
|
vehicle is still in the Crossing state, so we need to notify intersections
|
|
ahead of time of intended turns and an ETA.</li>
|
|
</ul>
|
|
<p>One contributor to permanent gridlock is cars and bikes being stuck in an
|
|
intersection, preventing conflicting turns from being performed. To help avoid
|
|
this, one of the last checks that stop signs and traffic signals perform before
|
|
accepting a new turn request is that the target lane has enough space for the
|
|
new vehicle. This is "reserved" space, not necessarily currently occupied by
|
|
vehicles in that lane. This accounts for other vehicles performing a turn bound
|
|
for that lane. See <code>try_to_reserve_entry</code> in <code>mechanics/queue.rs</code>. When a car
|
|
completely leaves a lane (determined by the "laggy head" described above), this
|
|
space is freed, and blocked cars are woken up.</p>
|
|
<h2><a class="header" href="#appendix-discrete-time-simulation" id="appendix-discrete-time-simulation">Appendix: discrete-time simulation</a></h2>
|
|
<p>A/B Street's first traffic model was discrete-time, meaning that every agent
|
|
reacted to the world every 0.1s. Cars had a more realistic kinematics model,
|
|
accelerating to change speed and gradually come to a halt. Cars did a worst-case
|
|
estimation of how far ahead they need to lookahead in order to satisfy different
|
|
constraints:</p>
|
|
<ul>
|
|
<li>Don't exceed any speed limits</li>
|
|
<li>Don't hit the lead vehicle (which might suddenly slam on its brakes)</li>
|
|
<li>Stop at the end of a lane, unless the intersection says to go</li>
|
|
</ul>
|
|
<p>After fighting with this approach for a long time, I eventually scrapped it in
|
|
favor of the simpler discrete-event model because:</p>
|
|
<ul>
|
|
<li>It's fundamentally slow; there's lots of busy work where cars in freeflow with
|
|
nothing blocking them or stopped in a long queue constantly check to see if
|
|
anything has changed.</li>
|
|
<li>Figuring out the acceleration to apply for the next 0.1s in order to satisfy
|
|
all of the constraints is really complicated. Floating point inaccuracies
|
|
cause ugly edge cases with speeds that wind up slightly negative and with cars
|
|
coming to a complete stop slightly past the end of a lane. I wound up storing
|
|
the "intent" of an action to auto-correct these errors.</li>
|
|
<li>The realism of having cars accelerate smoothly didn't add value to the core
|
|
idea in A/B Street, which is to model points of contention like parking
|
|
capacity and intersections. (This is the same reason why I don't model bike
|
|
racks for parking bikes -- in Seattle, it's never hard to find something to
|
|
lock to -- this would be very different if Copenhagen was the target.)
|
|
Additionally, the kinematics model made silly assumptions about driving anyway
|
|
-- cars would smash on their accelerators and brakes as hard as possible
|
|
within all of the constraints.</li>
|
|
</ul>
|
|
<h1><a class="header" href="#travel-demand" id="travel-demand">Travel demand</a></h1>
|
|
<p>A/B Street simulates people following a schedule of trips over a day. A single
|
|
<em>trip</em> has a start and endpoint, a departure time, and a mode. Most trips go
|
|
between buildings, but the start or endpoint may also be a border intersection
|
|
to represent something outside the map boundaries. The mode specifies whether
|
|
the person will walk, bike, drive, or use transit. Without a good set of people
|
|
and trips, evaluating some changes to a map is hard -- what if the traffic
|
|
patterns near the change aren't realistic to begin with? This chapter describes
|
|
where the travel demand data comes from.</p>
|
|
<h2><a class="header" href="#scenarios" id="scenarios">Scenarios</a></h2>
|
|
<p>A <em>scenario</em> encodes the people and trips taken over a day. See the
|
|
<a href="https://github.com/dabreegster/abstreet/blob/master/sim/src/make/scenario.rs">code</a>.</p>
|
|
<p>TODO:</p>
|
|
<ul>
|
|
<li>talk about vehicle assignment / parked car seeding</li>
|
|
</ul>
|
|
<h2><a class="header" href="#data-sources" id="data-sources">Data sources</a></h2>
|
|
<h3><a class="header" href="#seattle-soundcast" id="seattle-soundcast">Seattle: Soundcast</a></h3>
|
|
<p>Seattle luckily has the Puget Sound Regional Council, which has produced the
|
|
<a href="https://www.psrc.org/activity-based-travel-model-soundcast">Soundcast model</a>.
|
|
They use census stats, land parcel records, observed vehicle counts, travel
|
|
diaries, and lots of other things I don't understand to produce a detailed model
|
|
of the region. We're currently using their 2014 model; the 2018 one should be
|
|
available sometime in 2020. See the
|
|
<a href="https://github.com/dabreegster/abstreet/tree/master/importer/src/soundcast">code</a>
|
|
for importing their data.</p>
|
|
<p>TODO:</p>
|
|
<ul>
|
|
<li>talk about how trips beginning/ending off-map are handled</li>
|
|
</ul>
|
|
<h3><a class="header" href="#berlin" id="berlin">Berlin</a></h3>
|
|
<p>This work is <a href="https://github.com/dabreegster/abstreet/issues/119">ongoing</a>. See
|
|
the
|
|
<a href="https://github.com/dabreegster/abstreet/blob/master/importer/src/berlin.rs">code</a>.
|
|
So far, we've found a population count per planning area and are randomly
|
|
distributing the number of residents to all residential buildings in each area.</p>
|
|
<h3><a class="header" href="#proletariat-robot" id="proletariat-robot">Proletariat robot</a></h3>
|
|
<p>What if we just want to generate a reasonable model without any city-specific
|
|
data? One of the simplest approaches is just to spawn people beginning at
|
|
residential buildings, make them go to some workplace in the morning, then
|
|
return in the evening. OpenStreetMap building tags can be used to roughly
|
|
classify building types and distinguish small houses from large apartments. See
|
|
the <code>proletariat_robot</code>
|
|
<a href="https://github.com/dabreegster/abstreet/blob/master/sim/src/make/activity_model.rs">code</a>
|
|
for an implementation of this.</p>
|
|
<p>This is <a href="https://github.com/dabreegster/abstreet/issues/154">ongoing</a> work
|
|
spearheaded by Mateusz. Some of the ideas for next steps are to generate
|
|
different types of people (students, workers), give them a set of activities
|
|
with durations (go to school for 7 hours, 1 hour lunch break), and then further
|
|
pick specfic buildings to travel to using more OSM tags.</p>
|
|
<h3><a class="header" href="#custom-import" id="custom-import">Custom import</a></h3>
|
|
<p>If you have your own data, you can import it. The input format is JSON -- an
|
|
example:</p>
|
|
<pre><code>{
|
|
"scenario_name": "monday",
|
|
"people": [
|
|
{
|
|
"origin": {
|
|
"Position": {
|
|
"longitude": -122.303723,
|
|
"latitude": 47.6372834
|
|
}
|
|
},
|
|
"trips": [
|
|
{
|
|
"departure": 10800.0,
|
|
"destination": {
|
|
"Position": {
|
|
"longitude": -122.3075948,
|
|
"latitude": 47.6394773
|
|
}
|
|
},
|
|
"mode": "Drive"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<p>Run the tool:</p>
|
|
<pre><code>cargo run --bin import_traffic -- --map=data/system/seattle/maps/montlake.bin --input=/path/to/input.json
|
|
</code></pre>
|
|
<p>The tool matches input positions to the nearest building or border intersection,
|
|
within 100 meters. The <code>departure</code> time is seconds since midnight. The tool will
|
|
fail if any point doesn't match to a building, or if any of the specified trips
|
|
can't be created (due to graph connectivity problems, for example). If your
|
|
requirements are different or you have any trouble using this format/tool,
|
|
please file a Github issue -- just consider this tool and format a prototype.</p>
|
|
<h2><a class="header" href="#modifying-demand" id="modifying-demand">Modifying demand</a></h2>
|
|
<p>The travel demand model is extremely fixed; the main effect of a different
|
|
random number seed is currently to initially place parked cars in specific
|
|
spots. When the player makes changes to the map, exactly the same people and
|
|
trips are simulated, and we just measure how trip time changes. This is a very
|
|
short-term prediction. If it becomes much more convenient to bike or bus
|
|
somewhere, then more people will do it over time. How can we transform the
|
|
original demand model to respond to these changes?</p>
|
|
<p>Right now, there's very preliminary work in sandbox mode for Seattle weekday
|
|
scenarios. You can cancel all trips for some people (simulating lockdown) or
|
|
modify the mode for some people (change 50% of all driving trips between 7 and
|
|
9am to use transit).</p>
|
|
<h2><a class="header" href="#research" id="research">Research</a></h2>
|
|
<ul>
|
|
<li><a href="https://github.com/replicahq/doppelganger">https://github.com/replicahq/doppelganger</a></li>
|
|
<li><a href="https://github.com/stasmix/popsynth">https://github.com/stasmix/popsynth</a></li>
|
|
<li><a href="https://zephyrtransport.github.io/zephyr-directory/projects/">https://zephyrtransport.github.io/zephyr-directory/projects/</a></li>
|
|
<li><a href="https://activitysim.github.io">https://activitysim.github.io</a></li>
|
|
<li><a href="https://github.com/BayAreaMetro/travel-model-one">https://github.com/BayAreaMetro/travel-model-one</a></li>
|
|
<li><a href="https://github.com/RSGInc/DaySim">https://github.com/RSGInc/DaySim</a></li>
|
|
<li><a href="https://github.com/arup-group/pam">https://github.com/arup-group/pam</a></li>
|
|
<li><a href="https://spatial-microsim-book.robinlovelace.net/smsimr.html">https://spatial-microsim-book.robinlovelace.net/smsimr.html</a></li>
|
|
</ul>
|
|
<h1><a class="header" href="#gridlock" id="gridlock">Gridlock</a></h1>
|
|
<p>Here "gridlock" refers to the general problem of trips getting permanently
|
|
stuck, preventing the full simulation from completing. Most of the work is
|
|
tracked <a href="https://github.com/dabreegster/abstreet/issues/114">here</a>.</p>
|
|
<p>The general lesson is: you can't code your way around all edge cases. The data
|
|
in OSM often needs manual fixes. It's often useful to spend coding effort on
|
|
tools to detect and fix OSM problems.</p>
|
|
<h2><a class="header" href="#problems-1" id="problems-1">Problems</a></h2>
|
|
<p>The choices in the movement model matter. Some gridlock is inherent to any
|
|
system with queueing and conflicting turns. But in reality, people wiggle around
|
|
partly blocked turns. And some of this comes from the treatment of the
|
|
front/back of vehicles.</p>
|
|
<ul>
|
|
<li>Short roads in OSM causing very weird geometry</li>
|
|
<li>Intersection geometry being too large, requiring too much time to cross</li>
|
|
<li>Unrealistic traffic patterns caused by everyone trying to park in one big
|
|
garage (downtown) or take some alley (the UW soundcast issue)</li>
|
|
<li>Too many people try to take an unprotected left turn (often at a stop sign)</li>
|
|
<li>Bad individual traffic signals, usually at 5- or 6-ways</li>
|
|
<li>Groups of traffic signals logically acting as a single intersection</li>
|
|
<li>Separate traffic signals along a corridor being unsynchronized</li>
|
|
<li>Vehicles performing illegal sequences of turns</li>
|
|
<li>Vehicles are stuck with their plan and not reacting to traffic by changing
|
|
route</li>
|
|
<li>Real traffic would result in a gridlock without a deliberate actions to avoid
|
|
it. Such actions range from individual decisions of drivers to police manually
|
|
controlling traffic. Intelligent avoidance of gridlock is not simulated and is
|
|
extremely hard to simulate.</li>
|
|
<li>Vehicles will wait in lane filled with already waiting vehicles, even if there
|
|
is a completely empty lane allowing travel in desired direction. It makes
|
|
easier for entire lane between crossings to fill, contributing to gridlocks.
|
|
Note that while this and other clearly stupid behaviors are clearly
|
|
unrealistic, it is not trivial to implement more realistic and more efficient
|
|
decisions.</li>
|
|
<li>Issues caused by the unrealistic
|
|
<a href="trafficsim/discrete_event.html#lane-changing">lane-changing model</a>
|
|
<ul>
|
|
<li>Two turns that go to the same lane (one going "straight", the other often a
|
|
lane-change) conflict. The conflict is coarse, at the granularity of the
|
|
entire intersection. So if vehicles are piled up in two lanes trying to
|
|
merge into one, then one group is likely to go through as expected, but the
|
|
second group will wait for the first to completely clear the intersection.
|
|
Until then, it looks like a conflicting turn is being done.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#solutions" id="solutions">Solutions</a></h2>
|
|
<p>Divide into implemented or not.</p>
|
|
<ul>
|
|
<li>Synchronizing pairs of signals</li>
|
|
<li>Uber-turns
|
|
<ul>
|
|
<li>for interpreting OSM turn restrictions</li>
|
|
<li>for synchronizing a group of signals</li>
|
|
<li>for locking turn sequences
|
|
<ul>
|
|
<li>Once a vehicle starts an uber-turn, prevent others from starting
|
|
conflicting turns on nearby intersections. Until groups of traffic signals
|
|
are configured as one, this is necessary to prevent somebody from making
|
|
it halfway through a sequence then getting blocked.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>Cycle detector</li>
|
|
<li>block-the-box protection
|
|
<ul>
|
|
<li>the manual list of overrides</li>
|
|
<li>likely shouldn't apply during uber-turns</li>
|
|
<li>is it always fine to block the box at degenerate intersections?</li>
|
|
</ul>
|
|
</li>
|
|
<li>hacks to allow conflicting turns at really broken intersections</li>
|
|
<li>manually timing signals</li>
|
|
<li>penalties for lane choice to make lane usage realistic</li>
|
|
</ul>
|
|
<h3><a class="header" href="#not-implemented" id="not-implemented">Not implemented</a></h3>
|
|
<ul>
|
|
<li>Dynamic rerouting</li>
|
|
<li>Allow multiple vehicles through intersection at once if there is enough space
|
|
on lane where given vehicle is going. Currrently vehicles travel through
|
|
crossings one by one (or, with <code>--disable_block_the_box</code> enabled - will enter
|
|
crossing even if leaving it will be impossible).</li>
|
|
<li>Last resort: if someone's waiting on a turn >5m, just go.</li>
|
|
<li>Uber-turns
|
|
<ul>
|
|
<li>Group both stop sign and traffic signal intersections when looking for
|
|
uber-turns. Even a single traffic signal surrounded by tiny roads with stop
|
|
signs is causing problems.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#strategy-for-resolving" id="strategy-for-resolving">Strategy for resolving</a></h2>
|
|
<p>Because there are so many different causes all tangled together, my approach is
|
|
to simplify the simulation as much as possible. A problem is much easier to
|
|
understand and fix when it's isolated. I've been trying this to get the downtown
|
|
weekday scenario to complete. A list of different techniques to simplify, in no
|
|
particular order:</p>
|
|
<ul>
|
|
<li>Use the <code>--infinite_parking</code> flag to just let everyone park directly in their
|
|
destination buildings. This is useful since downtown has many large parking
|
|
garages with high capacity, but I don't have a data source describing them.</li>
|
|
<li>Use the <code>--disable_turn_conflicts</code> flag, which greatly reduces realism, but
|
|
lets conflicting turns happen simultaneously. (Even with this and other flags,
|
|
downtown still gridlocks!) It also disables traffic signals, so bad inferred
|
|
timing isn't an issue.</li>
|
|
<li>Use the <code>--disable_block_the_box</code> flag to workaround short roads.</li>
|
|
<li>If you notice problems forming from cars stacking up behind slower cyclists,
|
|
there's no over-taking implemented yet. Use the scenario modifiers to convert
|
|
all biking trip to driving:
|
|
<code>--scenario_modifiers='[{"ChangeMode":{"to_mode":"Drive","pct_ppl":100,"departure_filter":[0.0,86400.0],"from_modes":["Bike"]}}]'</code></li>
|
|
<li>If all else fails, use the scenario modifiers to bluntly cancel some
|
|
percentage of all trips.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#fixing-data-used-in-simulation" id="fixing-data-used-in-simulation">Fixing data used in simulation</a></h2>
|
|
<p>Give more examples of changesets.</p>
|
|
<ul>
|
|
<li>upstreaming turn restrictions into OSM to prevent invalid U-turns and other
|
|
crazy movements
|
|
<ul>
|
|
<li>ex: <a href="https://www.openstreetmap.org/changeset/87945050">https://www.openstreetmap.org/changeset/87945050</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>upstreaming lane count fixes into OSM to improve geometry</li>
|
|
</ul>
|
|
<h1><a class="header" href="#multi-modal-trips" id="multi-modal-trips">Multi-modal trips</a></h1>
|
|
<p>A single trip consists of a sequence of <code>TripLegs</code> -- walking, operating a
|
|
vehicle (car or bike), and riding the bus. Depending whether a trip begins or
|
|
ends at a border or building, there are many combinations of these sequences.
|
|
This is a way to categorize them into three groups. I'm not sure it's the
|
|
simplest way to express all the state transitons.</p>
|
|
<h2><a class="header" href="#walking-only-trips" id="walking-only-trips">Walking-only trips</a></h2>
|
|
<p><img src="trafficsim/../mdbook-plantuml-img/bbf8881e880a261530dd998679b4f47108dfc748.svg" alt="" /></p>
|
|
<h2><a class="header" href="#trips-starting-from-a-border" id="trips-starting-from-a-border">Trips starting from a border</a></h2>
|
|
<p><img src="trafficsim/../mdbook-plantuml-img/1cd9d730c8982c5ba59b825b427e712fab82e681.svg" alt="" /></p>
|
|
<h2><a class="header" href="#trips-starting-from-a-building" id="trips-starting-from-a-building">Trips starting from a building</a></h2>
|
|
<p><img src="trafficsim/../mdbook-plantuml-img/92ec1d5cbfccd87df09b67ac1a2b26aebf81eee8.svg" alt="" /></p>
|
|
<h1><a class="header" href="#live-edits-1" id="live-edits-1">Live edits</a></h1>
|
|
<p>When the player edits the map, there's an <a href="trafficsim/../map/edits.html">efficient process</a>
|
|
for applying the edits at the map model and rendering layer. In the middle of a
|
|
simulation, it's less obvious how to apply all edits. Most of the time
|
|
currently, edits cause the simulation to reset to midnight. Applying edits to
|
|
the sim without reset is important for running machine learning experiments and
|
|
for improving the gameplay experience (by having more immediate feedback about
|
|
the consequences of a change).</p>
|
|
<p>The UI has a <code>dirty_from_edits</code> bit to track when changes have been applied
|
|
without reset. This lets us tell the player that by the end of the day, any
|
|
score / results are tentative, because their edits might have a different effect
|
|
earlier in the day.</p>
|
|
<h2><a class="header" href="#what-works-today" id="what-works-today">What works today</a></h2>
|
|
<p>Changes to traffic signals are simple -- <code>incremental_edit_traffic_signal</code>
|
|
happens at the map layer, and then <code>handle_live_edited_traffic_signals</code> at the
|
|
sim layer just resets the current stage to 0 if the previous configuration had
|
|
more stages.</p>
|
|
<h2><a class="header" href="#todo-recalculating-paths" id="todo-recalculating-paths">TODO: Recalculating paths</a></h2>
|
|
<p>Many of the edits will influence routes. For trips that haven't started yet,
|
|
there's nothing to do immediately. Paths are calculated right before the trip
|
|
starts, so slight changes to the start/end of the path due to map edits (like
|
|
where somebody starts biking, for example) are captured naturally.</p>
|
|
<p>For currently active trips, in some cases, rerouting would be ideal but not
|
|
necessary (like if speed limits changed). In other cases -- like changing access
|
|
restrictions, modifying lane types, closing intersections -- the route must be
|
|
recomputed. As a simple first attempt, we could just cancel all active trips
|
|
whose path crosses an edited road or intersection. Later, we can figure out
|
|
rerouting.</p>
|
|
<p>And actually, the only other case to handle is <code>ChangeRouteSchedule</code>, which
|
|
should just be rescheduling the <code>StartBus</code> commands.</p>
|
|
<h2><a class="header" href="#todo-parking" id="todo-parking">TODO: Parking</a></h2>
|
|
<p>What happens if you modify a parking lane while there are cars on it? For now,
|
|
just delete them. Trips later making use of them will just act as if the car
|
|
never had room to be spawned at all and get cancelled or fallback to walking.</p>
|
|
<p>A better resolution would be to relocate them to other parking spots. If the
|
|
owner is home, it'd be neat to have them walk outside, move the car, and go back
|
|
in. But this greatly complicates the simulation -- the edited lane is in a
|
|
transition state for a while, it modifies schedules, the person might not be
|
|
around, etc.</p>
|
|
<h1><a class="header" href="#parking-1" id="parking-1">Parking</a></h1>
|
|
<p>TODO: Fill out the types of parking available, public/private, blackholes, how
|
|
people pick spots, how seeding works, etc.</p>
|
|
<h2><a class="header" href="#infinite-parking" id="infinite-parking">Infinite parking</a></h2>
|
|
<p>If you pass <code>--infinite_parking</code> on the command line, every building gets
|
|
unlimited public spots. This effectively removes the effects of parking from the
|
|
model, since driving trips can always begin or end at their precise building
|
|
(except for blackhole cases). This is useful if a particular map has poor
|
|
parking data and you need to get comparative results about speeding up some
|
|
trips. Often the A/B testing is extremely sensitive, because a parking space
|
|
close to someone's destination is filled up quickly, slowing down the trip.</p>
|
|
<h1><a class="header" href="#project-logistics" id="project-logistics">Project logistics</a></h1>
|
|
<p>This has some background/logistics about the project.</p>
|
|
<h1><a class="header" href="#roadmap" id="roadmap">Roadmap</a></h1>
|
|
<p>A/B Street has been under active development since June 2018. That's a long time
|
|
-- what work is happening now and how can you contribute?</p>
|
|
<h2><a class="header" href="#next-steps-summer-2020" id="next-steps-summer-2020">Next steps, summer 2020</a></h2>
|
|
<p>Afer the alpha launch in June, I plan to focus on:</p>
|
|
<ul>
|
|
<li>shared biking/walking trails like the Burke Gilman</li>
|
|
<li>light rail</li>
|
|
<li>more score functions besides trip time, like safety/comfort</li>
|
|
<li>changing trip mode choice (if you make a bus route more desirable, switch some
|
|
trips)</li>
|
|
<li>web support (so people can try out proposals without installing anything)</li>
|
|
</ul>
|
|
<h2><a class="header" href="#ongoing-work" id="ongoing-work">Ongoing work</a></h2>
|
|
<p>If I had resources to hire a team, this is roughly how I'd organize different
|
|
roles. If you're interested in helping, these aren't strictly defined positions,
|
|
just ideas of related tasks.</p>
|
|
<h3><a class="header" href="#ui-and-data-visualization" id="ui-and-data-visualization">UI and data visualization</a></h3>
|
|
<p>We've got a UX designer, but implementing all of the new designs takes time.
|
|
Also:</p>
|
|
<ul>
|
|
<li>improve color schemes for colorblind players, implement night mode, rain
|
|
effects, etc</li>
|
|
<li>refactor and clean up the GUI library for other Rust users</li>
|
|
<li>lots of data viz design / implementation needed</li>
|
|
</ul>
|
|
<h3><a class="header" href="#game-design" id="game-design">Game design</a></h3>
|
|
<ul>
|
|
<li>the tutorial mode needs attention</li>
|
|
<li>many ideas for challenge/story modes, but playtesting, tuning, and game design
|
|
needed</li>
|
|
</ul>
|
|
<h3><a class="header" href="#map-data--gis" id="map-data--gis">Map data / GIS</a></h3>
|
|
<p>Support more cities:</p>
|
|
<ul>
|
|
<li>write docs/tools to help people add new cities without programming experience</li>
|
|
<li>add support for non-OpenStreetMap input: GeoJSON for parking in Perth, other
|
|
trip demand sources, etc</li>
|
|
<li>fix bugs for driving on the left side of the road</li>
|
|
</ul>
|
|
<p>Improve the quality of map geometry derived from OpenStreetMap:</p>
|
|
<ul>
|
|
<li>try new algorithms to generate intersection polygons</li>
|
|
<li>make tools for easily improving relevant data in OSM</li>
|
|
<li>use ML and lidar/satellite data to get extremely accurate curb / planter /
|
|
sidewalk geometry</li>
|
|
</ul>
|
|
<p>Build tools and organize community mapping:</p>
|
|
<ul>
|
|
<li>organize an effort to map how traffic signals are timed (partly started)</li>
|
|
<li>divide and track work for distributed mapathons</li>
|
|
</ul>
|
|
<p>Bring in new data to understand more about cities:</p>
|
|
<ul>
|
|
<li>PM2.5 pollution</li>
|
|
<li>Tax / land value (is there inequitable access to transit?)</li>
|
|
</ul>
|
|
<h3><a class="header" href="#simulation--modeling" id="simulation--modeling">Simulation / modeling</a></h3>
|
|
<p>Totally new areas:</p>
|
|
<ul>
|
|
<li>light rail</li>
|
|
<li>shared bike/pedestrian paths</li>
|
|
<li>ridesharing</li>
|
|
<li>micromobility (scooters, floating bikeshare)</li>
|
|
<li>more score functions (elevation gain, biking safety)</li>
|
|
<li>generating trip demand / activity models from scratch or modifying existing
|
|
ones</li>
|
|
</ul>
|
|
<p>Improve existing models:</p>
|
|
<ul>
|
|
<li>overtaking / lane-changing</li>
|
|
<li>pedestrian crowds</li>
|
|
<li>instant vehicle acceleration</li>
|
|
<li>pedestrians walking on road shoulders (some streets have no sidewalks)</li>
|
|
<li>buses: transfers, proper schedules, multiple buses per route</li>
|
|
</ul>
|
|
<h3><a class="header" href="#web" id="web">Web</a></h3>
|
|
<p>A/B Street runs on the web via WASM and WebGL; just waiting on vector text
|
|
support. Besides that:</p>
|
|
<ul>
|
|
<li>Share community proposals online, discuss them, vote, etc</li>
|
|
</ul>
|
|
<h2><a class="header" href="#contributing-for-non-programmers" id="contributing-for-non-programmers">Contributing for non-programmers</a></h2>
|
|
<p>There's plenty to do besides programming!</p>
|
|
<ul>
|
|
<li>Mapping, most of which directly contributes to OpenStreetMap:
|
|
<ul>
|
|
<li>sidewalks and crosswalks</li>
|
|
<li><a href="project/../howto/map_parking.html">on-street parking</a></li>
|
|
<li><a href="https://docs.google.com/document/d/1Od_7WvBVYsvpY4etRI0sKmYmZnwXMAXcJxVmm8Iwdcg/edit?usp=sharing">traffic signal timing</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>Playtesting by attempting to implement real proposals would also be helpful,
|
|
to expose where it's awkward for A/B Street to edit the map and to write up
|
|
problems encountered.</li>
|
|
<li>Advocacy: I'm not great at finding the right people to to get ideas
|
|
implemented for real. Maybe you are?</li>
|
|
</ul>
|
|
<h2><a class="header" href="#long-term-vision" id="long-term-vision">Long-term vision</a></h2>
|
|
<p>Longer term, I'd like to take lots of the work in generating and interacting
|
|
with high-detail OpenStreetMap-based maps and generalize it, possibly as a new
|
|
OSM viewer/editor.</p>
|
|
<p>More generally, I'd like to see how simulation can help individuals understand
|
|
and explore other policy decisions related to cities. Domains I'm vaguely
|
|
interested in, but not at all knowledgable about, include land-use / zoning,
|
|
housing, and supply chains. In late March 2020, a new collaborator started a
|
|
pandemic model using the existing simulation of people occupying shared spaces.
|
|
What are other domains could benefit from the rich agent-based model we're
|
|
building?</p>
|
|
<h1><a class="header" href="#project-motivations" id="project-motivations">Project motivations</a></h1>
|
|
<p>I thought it'd be helpful to explain what motivates my work in A/B Street. These
|
|
are just my personal values; I don't intend to make a careful argument about
|
|
these here. In no particular order:</p>
|
|
<ul>
|
|
<li>
|
|
<p><strong>Transparency and reproducibility</strong>: if city government uses data, modeling,
|
|
or simulation to inform a decision affecting the general public, then anybody
|
|
ought to be able to repeat that analysis.</p>
|
|
<ul>
|
|
<li>This means code and data should be open.</li>
|
|
<li>Businesses like <a href="https://replicahq.com/">Sidewalk Lab's Replica</a> and
|
|
<a href="https://www.remix.com/solutions/streets">Remix</a> still need to generate
|
|
income, but it's unclear why governments use taxes to pay for something only
|
|
they see.</li>
|
|
<li>Decision making should be documented clearly. Why were the
|
|
<a href="https://www.seattle.gov/transportation/projects-and-programs/programs/maintenance-and-paving/current-paving-projects/35th-ave-ne">35th Ave bike lanes</a>
|
|
scrapped? Was the amount of on-street parking on nearby residential roads
|
|
factored in? Was there analysis of how trip time is impacted by parking in
|
|
the neighborhood and walking a few blocks to a business on the arterial?</li>
|
|
<li>I'm personally inspired by approaches like
|
|
<a href="https://info.vtaiwan.tw/">vTaiwan</a> and
|
|
<a href="https://po.pdis.nat.gov.tw/en/opengov/">PDIS</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p><strong>Accessibility leads to participation</strong>: There's overhead to taking small
|
|
ideas to advocacy groups or inconveniently timed public meetings. If the
|
|
planning process is easier to interact with, more people will participate.</p>
|
|
<ul>
|
|
<li>Seattle's
|
|
<a href="https://www.seattle.gov/neighborhoods/programs-and-services/your-voice-your-choice">Your Voice, Your Choice</a>
|
|
program is maybe an example of this</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p><strong>Short-term changes</strong>: <a href="https://en.wikipedia.org/wiki/Sound_Transit_3">ST3</a>
|
|
is exciting, but 2040 isn't close. There are much cheaper changes that can be
|
|
implemented sooner.</p>
|
|
<ul>
|
|
<li>Most of the edits in A/B Street are inspired by tactical urbanism; they
|
|
could be prototyped with signs and paint.</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p><strong>The US is too dependent on cars</strong>: This has an unacceptable impact on the
|
|
environment. Even ignoring that, many cities are out of room to build more
|
|
roads. We can't keep scaling population like this.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>Autonomous vehicles will NOT save the day</strong>: They can squeeze more
|
|
throughput out of existing infrastructure, but only up to a point. They might
|
|
encourage people to move and tolerate longer commutes. Mass transit and dense
|
|
land-use patterns handle population growth better.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>Compromise and trade-offs</strong>: I see lots of rhetoric calling for extreme,
|
|
sudden change. I don't want to ban all cars from downtown Seattle, because
|
|
that's not realistic. I want to focus on immediate steps forward. I want to
|
|
come up with estimates about impacting drivers by a median 3 minutes in order
|
|
to save a bus route 1 minute, and to shift public discourse towards that.</p>
|
|
</li>
|
|
</ul>
|
|
<h1><a class="header" href="#project-history" id="project-history">Project history</a></h1>
|
|
<p>As of June 2020.</p>
|
|
<p>tldr: A/B Street has been in active development since June 2018, but the idea
|
|
has been festering since I was about 16.</p>
|
|
<h2><a class="header" href="#retrospective" id="retrospective">Retrospective</a></h2>
|
|
<p>What poor judgments have cost me the most time?</p>
|
|
<ul>
|
|
<li>UI churn: I should've studied some UX on my own and started with a clear idea
|
|
of how to organize everything</li>
|
|
<li>OSM data quality: I should've gained the confidence to upstream fixes earlier</li>
|
|
<li>Intersection geometry: I should've realized sooner that simulation robustness
|
|
is more important than nice appearance.</li>
|
|
<li>Geometry primitives: I sunk too much time into the polyline problem and f64
|
|
precision.</li>
|
|
</ul>
|
|
<h2><a class="header" href="#trivia" id="trivia">Trivia</a></h2>
|
|
<ul>
|
|
<li>The name was almost "Unstreet" or "Superban" (superb urban)</li>
|
|
<li>I hope you enjoy and/or are baffled by the
|
|
<a href="https://github.com/dabreegster/abstreet/releases">release names</a></li>
|
|
</ul>
|
|
<h1><a class="header" href="#backstory" id="backstory">Backstory</a></h1>
|
|
<p>I originally wanted to tell a much longer story here of how I came to work on
|
|
A/B Street, but I'm not sure this is the right time yet. So consider this the
|
|
quick version.</p>
|
|
<p>I grew up in Baton Rouge, where driving is effectively the only mode of
|
|
transport. (I've gone back and made a point of taking long walks to confirm how
|
|
antagonistically the city is designed towards walking.) Very early on, I fell in
|
|
love with a Nintendo 64 game called Banjo Kazooie, which led me to the online
|
|
fan communities of the early 2000's. I wanted to create games too, so I started
|
|
learning programming via library books and lots of questions on IRC. Because I
|
|
never had any confidence in art, I wound up working on
|
|
<a href="https://github.com/dabreegster/mnemonicrl/">roguelikes</a>, which led to a fervent
|
|
interest in pathfinding algorithms and
|
|
<a href="http://www.cs.colorado.edu/%7Eralex/papers/PDF/OOPSLA06antiobjects.pdf">collaborative diffusion</a>.
|
|
When I started driving in high school, I quickly realized how bad people were at
|
|
it. I remember being stuck at the intersection of
|
|
<a href="https://www.openstreetmap.org/node/1279204989">Florida Blvd and Cloud</a> and
|
|
first wondering if the pathfinding algorithms could help with traffic. Can you
|
|
see where this is going?</p>
|
|
<p><img src="project/history/cloud_florida.jpg" alt="Impatience is a virtue" /></p>
|
|
<p>I moved to Austin for college. One of the first days of class, I shuffled down
|
|
the stairs of Gearing Hall past a crackly old speaker apocalyptically announcing
|
|
the weather forecast (details add color, right?) into a seminar demanding a
|
|
totally open-ended first assignment to do something interesting. After I left,
|
|
somebody stopped to ask me for directions, but I didn't know campus well yet. I
|
|
thought about how Google Maps gave really silly walking directions. So I decided
|
|
I'd hand-draw a map of campus, showing all of the construction, how to cut
|
|
through the labryinth that is Welch Hall on hot days, and where to find the 24/7
|
|
robot coffee machines, and hack together a routing engine to help people find
|
|
the shortest path between their classes. The feedback I got on this assignment
|
|
included something along the lines of, "I was really pretty impressed first that
|
|
you would be so stupid as to actually try to do this..."</p>
|
|
<p><img src="project/history/ut_map.png" alt="Hand-mapping UT Austin" /></p>
|
|
<p>But I did, and that led me to discovering OpenStreetMap, which it turns out was
|
|
pretty pivotal. (The first version of my campus map was seeded vaguely off an
|
|
official paper map, but mostly I walked around and invented half-assed surveying
|
|
methods on the spot.) Next semester, I joined a freshman research stream with
|
|
somebody who had worked on <a href="http://www.cs.utexas.edu/%7Eaim/">AIM</a>, UT's
|
|
demonstration that autonomous vehicles wouldn't need traffic lights. Everything
|
|
came together, and I started a 3 year journey of building
|
|
<a href="https://github.com/dabreegster/aorta/">AORTA</a>, a traffic simulator for AVs.
|
|
Guided by the research lab, I explored the really bizarre idea of letting AVs
|
|
<a href="http://www.cs.utexas.edu/%7Eaim/papers/ITSC13-dcarlino.pdf">bid to turn lights green sooner</a>
|
|
and micro-tolling all roads to disincentivize congestion. Both of these
|
|
mechanisms would be incredibly unfair to people without the spare cash to back
|
|
up their high value-of-time, but I brushed this off by saying the currency could
|
|
be based on carpooling, EVs, etc.</p>
|
|
<p><img src="project/history/aorta.gif" alt="Approximately Orchestrated Routing and Transportation Analyzer" /></p>
|
|
<p>It was great to try research in college; I learned I <em>really</em> dislike munging
|
|
data and compressing my work into 6 pages of conference paper LaTeX. So I moved
|
|
to Seattle to work in industry instead, on something completely unrelated to
|
|
transportation. Lots of things began unravelling for me in Seattle, but one of
|
|
them was biking. In Austin, I had picked up mountain biking, and all but stopped
|
|
driving; it was an amazing place to explore and commute by bike. Seattle was
|
|
different. There were many more cyclists around, but the experience felt more
|
|
stressful, the drivers more aggressive. I had plenty of near-misses. I kept
|
|
commuting by bike, but the joy of it was gone. I started noticing how many cars
|
|
were parked on narrow arterials and wondering why that was a fair use of space.
|
|
I started paying attention to the public discourse around bike infrastructure in
|
|
Seattle and feeling like the conversation was... chaotic.</p>
|
|
<p><img src="project/history/manhattan.jpg" alt="Manhattan took walkability seriously" /></p>
|
|
<p>Fast forward to late 2017. This is where I'll omit chunks of the story. I
|
|
visited London, my first experience with a city that took public transit
|
|
seriously. When I returned, lots of latent ideas stopped fermenting and started
|
|
exploding. I threw together a prototype of A/B Street and started the arduous
|
|
process at work of open-sourcing it and applying to a program to let me work it
|
|
on for a few quarters. A few months later, I wound up quitting instead, and
|
|
began to work on A/B Street in earnest.</p>
|
|
<h1><a class="header" href="#year-1-june-2018-2019" id="year-1-june-2018-2019">Year 1 (June 2018-2019)</a></h1>
|
|
<p>I skimmed through git and summarized roughly what I was working on each month,
|
|
calling out milestones. "UI churn" is pretty much constantly happening.</p>
|
|
<ul>
|
|
<li>
|
|
<p>June: polyline geometry and lanes, building paths, protobuf -> serde</p>
|
|
</li>
|
|
<li>
|
|
<p>July: pedestrians, bikes, parked cars, lane edits</p>
|
|
</li>
|
|
<li>
|
|
<p>August: porting AORTA's discrete-time driving model</p>
|
|
</li>
|
|
<li>
|
|
<p>September: multi-leg trips, buses, the first ezgui wizard, randomized
|
|
scenarios</p>
|
|
</li>
|
|
<li>
|
|
<p>October: A/B test mode (and so per-map plugins), forking RNG for
|
|
edit-invariance, intersection geometry</p>
|
|
</li>
|
|
<li>
|
|
<p>November: clipping / borders, using blockface for parking, time travel mode,
|
|
test runner framework</p>
|
|
</li>
|
|
<li>
|
|
<p>December: bezier curves for turns, traffic signal editor, a first attempt at
|
|
merging intersections, right-click menus, a top menu, modal menus</p>
|
|
<ul>
|
|
<li>the grand colorscheme refactor: a python script scraped <code>cs.get_def</code> calls
|
|
at build-time</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>January: careful f64 resolution, ezgui screencapping, synthetic map editor</p>
|
|
<ul>
|
|
<li><strong>grand refactor</strong>: piston to glium</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>February: attempting to use time-space intervals for a new driving model, new
|
|
discrete-event model instead</p>
|
|
<ul>
|
|
<li><strong>Feb 19-27</strong>: conceiving and cutting over to the new discrete event model</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>March: fleshing out DES model (laggy heads), first attempt to build on
|
|
windows, gridlock detection</p>
|
|
</li>
|
|
<li>
|
|
<p>April: first public releases, splash screen and rearranging game modes</p>
|
|
</li>
|
|
<li>
|
|
<p>May: fancier agent rendering, attempting to use census tracts, finding real
|
|
demand data</p>
|
|
<ul>
|
|
<li><strong>milestone</strong>: discovered PSRC Soundcast data, much more realistic trips</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h1><a class="header" href="#year-2-june-2019-2020" id="year-2-june-2019-2020">Year 2 (June 2019-2020)</a></h1>
|
|
<p><img src="project/history/oct_2019.png" alt="Circa October 2019" /></p>
|
|
<ul>
|
|
<li>
|
|
<p>June: contraction hierarchies for pathfinding, stackable game states</p>
|
|
</li>
|
|
<li>
|
|
<p>July: OSM turn restrictions, misc (I think I was in Europe?)</p>
|
|
</li>
|
|
<li>
|
|
<p>August: pedestrian crowds, agent color schemes, parking blackholes, a big
|
|
<code>raw_data</code> refactor to store <code>Pt2D</code>, attended first hackathon</p>
|
|
</li>
|
|
<li>
|
|
<p>September: offstreet parking, associating parked cars with buildings using
|
|
Soundcast (before that, anybody could use any car!), implemented texture
|
|
support for some reason, doing manual <code>MapFixes</code> at scale to fix OSM bugs</p>
|
|
<ul>
|
|
<li><strong>milestone</strong>: got the smallest montlake map to run without gridlock</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>October: parking sim fixes, opportunistic lane-changing, starting challenge
|
|
modes</p>
|
|
</li>
|
|
<li>
|
|
<p>November: prebaked sim results, time-series plots, undo for edit mode, traffic
|
|
signal editor grouping turns</p>
|
|
<ul>
|
|
<li><strong>milestone</strong>: Yuwen joins project</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>December: the UI reform begins (flexbox, minimap, trip timelines, cutting over
|
|
to SVGs, info panels, scrolling), started naming releases sensibly</p>
|
|
<ul>
|
|
<li>Project leaked to <a href="https://news.ycombinator.com/item?id=21763636">HN</a>, woops</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>January: UI reform continues, the modern tutorial mode appears</p>
|
|
</li>
|
|
<li>
|
|
<p>Feburary: UI and tutorial, all text now pure vectors, port to glow+WASM</p>
|
|
</li>
|
|
<li>
|
|
<p>March: lockdowns start in US, start grouping trips as a person, population
|
|
heatmap, left-hand driving, info panel and typography overhauls. started
|
|
engaging with Greenways, started effort to map traffic signals</p>
|
|
</li>
|
|
<li>
|
|
<p>April: Orestis joins and starts the pandemic model, trip tables, the optimize
|
|
commute challenge, refactor for people's schedules and owned vehicles, trip
|
|
time dat viz, MAJOR progress fixing gridlock at the sim layer</p>
|
|
</li>
|
|
<li>
|
|
<p>May: gridlock progress, upstreaming fixes in OSM, differential throughput and
|
|
first real write-up, long-lasting player edits, dedicated parking mapper,
|
|
maybe vanquished the HiDPI bugs, multi-step turn restrictions, random bios for
|
|
people, and docs like this to prep for launch ;)</p>
|
|
<ul>
|
|
<li><strong>milestone</strong>: relying on pure OSM, no more <code>MapFixes</code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h1><a class="header" href="#year-3-june-2020-2021" id="year-3-june-2020-2021">Year 3 (June 2020-2021)</a></h1>
|
|
<ul>
|
|
<li>June: parking lots, real minimap controls, road labels
|
|
<ul>
|
|
<li><strong>June 22</strong>: alpha launch!
|
|
<a href="https://old.reddit.com/r/Seattle/comments/hdtucd/ab_street_think_you_can_fix_seattles_traffic/">r/Seattle</a>,
|
|
<a href="https://old.reddit.com/r/SeattleWA/comments/hdttu8/ab_street_think_you_can_fix_seattles_traffic/">r/SeattleWA</a>,
|
|
<a href="https://old.reddit.com/r/urbanplanning/comments/hdylmo/ab_street_a_traffic_simulation_game/">r/UrbanPlanning</a>,
|
|
<a href="https://news.ycombinator.com/item?id=23605048#23608365">HN</a>,
|
|
<a href="https://www.geekwire.com/2020/want-fix-seattle-traffic-redditor-makes-game-allows-players-tweak-city-streets/">GeekWire</a>,
|
|
<a href="https://www.thestranger.com/slog/2020/06/29/43999454/ab-streets-game-lets-you-create-the-seattle-street-grid-of-your-dreams">The Stranger</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>July: loads of bugfixes, map geometry improvements, UI cleanups,
|
|
access-restricted zones for private neighborhoods and no-through-traffic,
|
|
better traffic generation between home<->work for new maps, complete overhaul
|
|
to bus routes and introduction of light rail, commute pattern explorer,
|
|
importing Krakow and Berlin, smarter lane-changing, walkable shoulders for
|
|
roads without sidewalks
|
|
<ul>
|
|
<li><a href="https://www.youtube.com/watch?v=Pk8V-egsUxU">KING 5 Evening</a> interview</li>
|
|
</ul>
|
|
</li>
|
|
<li>August: Michael joins, multiple traffic signals can be edited together,
|
|
started a headless JSON API, support for other languages in OSM data, started
|
|
congestion capping, backwards-compatible and more robust map edits, two-way
|
|
cycletracks, more cities imported, slurry of bugfixes and performance
|
|
improvements
|
|
<ul>
|
|
<li><a href="https://bikesiliconvalley.org/2020/07/poster_dustin-carlino/">Silicon Valley Bike Summit</a>,
|
|
<a href="https://www.seattlepi.com/local/transportation/slideshow/solve-Seattles-traffic-problem-in-this-video-game-205839.php">Seattle PI</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>September: ...
|
|
<ul>
|
|
<li><a href="https://www.seattlemet.com/news-and-city-life/2020/09/a-new-game-allows-you-to-redesign-seattle-streets">SeattleMet</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>October: ...</li>
|
|
</ul>
|
|
<h1><a class="header" href="#changelog" id="changelog">CHANGELOG</a></h1>
|
|
<p>Every time I upload a new <a href="https://github.com/dabreegster/abstreet/releases">binary
|
|
release</a>, I'll list major
|
|
changes here.</p>
|
|
<p>0.1.0</p>
|
|
<ul>
|
|
<li>First binary release</li>
|
|
</ul>
|
|
<p>0.1.1</p>
|
|
<ul>
|
|
<li>drawing arrows better</li>
|
|
<li>start with a splash screen, make it easy to change maps in-game</li>
|
|
</ul>
|
|
<p>0.1.2</p>
|
|
<ul>
|
|
<li>totally revamp GUI by organizing everything into distinct gameplay modes</li>
|
|
</ul>
|
|
<p>0.1.3</p>
|
|
<ul>
|
|
<li>new warp tool that autocompletes street names</li>
|
|
<li>hideable menus, place context menus better, remove top menu bar, add a simple OSD</li>
|
|
<li>loading screens reflect what's printed to the terminal</li>
|
|
<li>depict pedestrians and bikes with more detail</li>
|
|
<li>tool to scroll through an agent's route</li>
|
|
<li>make simulation speed controls actually work</li>
|
|
</ul>
|
|
<p>0.1.4</p>
|
|
<ul>
|
|
<li>improve stop sign editor UI (toggle entire roads)</li>
|
|
<li>better mouseover / selection rendering</li>
|
|
<li>better traffic signal rendering (show time left, use outlines for yields)</li>
|
|
<li>make cars actually stop and briefly wait at stop signs</li>
|
|
<li>improve edit mode diff visualization (cross-hatching)</li>
|
|
<li>render actual stop signs, not just red lines</li>
|
|
<li>fix intersection policies confused by conflicting straight turns with lane-changing</li>
|
|
<li>fix mac scrolling</li>
|
|
<li>better turn indicators</li>
|
|
<li>nicer unzoomed view of roads, with different colors for big/small roads</li>
|
|
</ul>
|
|
<p>0.1.5</p>
|
|
<p>(release file size jumped from ~15MB to ~70MB because of new PSRC trips)</p>
|
|
<ul>
|
|
<li>improve UX of intersection editors</li>
|
|
<li>define a better set of maps included by default</li>
|
|
<li>improve drawing speed by batching more stuff</li>
|
|
<li>better default traffic signal policies for many cases</li>
|
|
<li>import and visualize census data</li>
|
|
<li>fix missing sidewalks on downtown one-ways</li>
|
|
<li>import and visualize PSRC trip data</li>
|
|
</ul>
|
|
<p>0.1.6</p>
|
|
<ul>
|
|
<li>slider widget for controlling time and speed</li>
|
|
<li>fixing bad polyline geometry in most cases; visualizing routes should no longer be buggy</li>
|
|
<li>handle PSRC trips that begin or end out-of-bounds</li>
|
|
<li>draw agents in unzoomed mode in a way simpler way</li>
|
|
<li>improve edit mode: detect reverts to original, easier lane type switching</li>
|
|
<li>lots of fixes for buses: handle edits better, read sequence of stops correctly from GTFS</li>
|
|
<li>set up A/B tests faster</li>
|
|
</ul>
|
|
<p>0.1.7</p>
|
|
<ul>
|
|
<li>bulk and revert tools in edit mode</li>
|
|
<li>improve turns and default intersection policies when bike/bus lanes involved</li>
|
|
<li>new tool to manually hint for short roads and weird intersections. some problems have now been manually fixed</li>
|
|
<li>scoreboard of trip results for sandbox and A/B test mode</li>
|
|
<li>reduce lag when sim is running at full speeds, but system is too slow</li>
|
|
<li>switch to easbar's contraction hierarchy crate, making all pathfinding INSANELY fast</li>
|
|
<li>remove weird rules about the world freezing when traffic signals are in "overtime"</li>
|
|
</ul>
|
|
<p>0.1.8</p>
|
|
<ul>
|
|
<li>edit mode: convert to a ped scramble cycle, simplify stop sign editor by removing individual turns</li>
|
|
<li>ui: put labels next to sliders, organize modal menus into sections, add a minimize/maximize icon</li>
|
|
<li>A/B test mode: savestate, include time controls and agent following/route tools here</li>
|
|
<li>use more OSM data for turn lanes, turn restrictions from lanes, turn restrictions between entire roads</li>
|
|
<li>dont attempt to cross a traffic signal if there's absolutely no hope</li>
|
|
<li>improve bus route UI tools and make routes using transit more sane</li>
|
|
<li>user-defined shortcuts for jumping between views of a map</li>
|
|
</ul>
|
|
<p>0.1.9</p>
|
|
<ul>
|
|
<li>sliders to pick times in wizards</li>
|
|
<li>fix hidpi scaling</li>
|
|
<li>traffic signal diagram scrolls properly</li>
|
|
<li>easier to instantiate a scenario, show all trips involving a building for a scenario</li>
|
|
<li>colorschemes to show trip duration or time blocked</li>
|
|
<li>label buses with route number</li>
|
|
<li>represent overlapping pedestrians as a labeled crowd</li>
|
|
<li>massive performance boost via real priority queue</li>
|
|
<li>prevent cars from "blocking the box"</li>
|
|
<li>prevent all? aborted trips (due to parking blackholes mostly)</li>
|
|
<li>smarter roam-around-for-parking router</li>
|
|
</ul>
|
|
<p>0.1.10</p>
|
|
<ul>
|
|
<li>sim
|
|
<ul>
|
|
<li>parking in off-street garages and on-street lanes on the off-side of oneways now mostly works</li>
|
|
<li>detect and handle parking blackholes; cars should never get stuck looking for parking now</li>
|
|
<li>let lower-priority turns happen at traffic signals when higher-priority ones blocked</li>
|
|
<li>get closer to FCFS ordering at stop signs</li>
|
|
<li>basic opportunistic lane-changing</li>
|
|
<li>a bus should be seeded for every route now</li>
|
|
</ul>
|
|
</li>
|
|
<li>demand data
|
|
<ul>
|
|
<li>show trips to/from buildings and borders</li>
|
|
<li>make PSRC trips seed and attempt to use parked cars</li>
|
|
</ul>
|
|
</li>
|
|
<li>UI
|
|
<ul>
|
|
<li>different heatmap overlays, like parking availability and busiest areas</li>
|
|
<li>show colorscheme legends when relevant</li>
|
|
<li>interactively seed parked cars, spawn more types of trips</li>
|
|
<li>fix major A/B test mode bug (mismatched scenarios and map edits)</li>
|
|
<li>adjusting sliders, menu placement, dynamic items</li>
|
|
<li>consolidating different tools into a single info panel for objects</li>
|
|
<li>bus route explorer shows entire route, current bus location</li>
|
|
</ul>
|
|
</li>
|
|
<li>map quality
|
|
<ul>
|
|
<li>degenerate intersections only have one crosswalk now</li>
|
|
<li>revamped the map editor for fixing geometry problems, used it in many places</li>
|
|
<li>nicer yellow center lines (dashed when appropriate)</li>
|
|
<li>handling OSM turn restriction relations properly</li>
|
|
<li>fix empty traffic signal phases</li>
|
|
<li>handling bike lanes on certain sides of the road</li>
|
|
<li>starting to upstream manually-verified parking lanes into OSM</li>
|
|
</ul>
|
|
</li>
|
|
<li>new gameplay: reverse direction of lanes</li>
|
|
</ul>
|
|
<p>0.1.11</p>
|
|
<ul>
|
|
<li>small UI fixes: fixed width traffic signal diagram, skip info phase of menus when empty</li>
|
|
<li>start drawing (but not using) shared left-turn lanes from OSM</li>
|
|
<li>fix OSM polylines with redundant points (fixing an issue in ballard)</li>
|
|
<li>improved traffic signal policies in some cases</li>
|
|
<li>started upstreaming some sidewalk tags in OSM to fix inference issues</li>
|
|
<li>fixed misclassified right turns</li>
|
|
<li>adjusting map colors</li>
|
|
<li>handling lakes/ocean polygons from OSM way better</li>
|
|
<li>reorganized sim analytics, added stuff for bus arrivals</li>
|
|
<li>adding new internal road points to map editor. almost ready to really aggressively use it</li>
|
|
<li>skipping parking lanes with no nearby sidewalks, since they're unusable</li>
|
|
<li>fix z-order of bridges/tunnels in unzoomed view</li>
|
|
<li>allow unzooming indefinitely</li>
|
|
<li>move lots of sandbox mode controls (and other modes) to menus under buttons and dedicated buttons</li>
|
|
<li>basic support for marking a lane closed for construction</li>
|
|
<li>improved geometry of sidewalks at dead-ends</li>
|
|
</ul>
|
|
<p>0.1.12</p>
|
|
<ul>
|
|
<li>reorganize everything as different challenge modes. start implementing 3: optimizing a bus route, speeding up all trips, or causing as much gridlock as possible</li>
|
|
<li>improved bus route explorer</li>
|
|
<li>some UI fixes (popup messages in a few places, moving mouse tooltips to the OSD)</li>
|
|
<li>lots of analytics and time-series plots</li>
|
|
</ul>
|
|
<p>0.1.13</p>
|
|
<ul>
|
|
<li>analytics: prebake baseline results properly. hover over plot series. some new modes to see bus network, throughput of a road/intersection over time</li>
|
|
<li>log scale for the speed slider</li>
|
|
<li>add a bulk spawner in freeform mode (F2 on a lane)</li>
|
|
<li>rendering: nicer routes, crosswalks, zoomed car colors</li>
|
|
<li>map data: better stop sign and sidewalk heuristics</li>
|
|
<li>fixed the mac hidpi text rendering issue once and for all?!</li>
|
|
</ul>
|
|
<p>0.1.14</p>
|
|
<ul>
|
|
<li>better crosswalk generation when there's only a sidewalk on one side of a road</li>
|
|
<li>edit mode UI revamp: paintbrush-style buttons to apply changes to lanes</li>
|
|
<li>show error messages and prevent edits, like disconnecting sidewalks</li>
|
|
<li>properly ban bikes from highways (revamped rules for vehicles using a lane)</li>
|
|
<li>new freeform mode tool to spawn bikes</li>
|
|
<li>WIP (not working yet): make bikes prefer bike lanes. some debug heatmaps for path cost</li>
|
|
<li>edit mode has proper undo support</li>
|
|
</ul>
|
|
<p>0.1.15</p>
|
|
<ul>
|
|
<li>minor bugfixes with reverting lane types, preserving stop signs</li>
|
|
<li>incorporate edits into the challenge splash screen, make sure edits are reset when appropriate</li>
|
|
<li>starting a new challenge mode, just focused on traffic signals</li>
|
|
<li>can't leave traffic signal editor with missing turns</li>
|
|
<li>render pedestrian crowds on building front paths</li>
|
|
<li>traffic signals support an offset parameter</li>
|
|
<li>traffic signal visualization and editing revamped to group related turns together</li>
|
|
<li>can preview traffic using a signal from the editor</li>
|
|
<li>actually apply priority at intersections, so protected turns get first dibs over yield turns</li>
|
|
</ul>
|
|
<p>0.1.16</p>
|
|
<ul>
|
|
<li>fix Mac crashing with texture limit bug by switching to texture arrays</li>
|
|
<li>fix crashing simulation when a border intersection was used</li>
|
|
<li>started to implement a new UI design for starting the game</li>
|
|
</ul>
|
|
<p>0.1.17</p>
|
|
<ul>
|
|
<li>more work on the pre-game UI, with some flexbox layouting</li>
|
|
<li>prototype a minimap in sandbox mode. doesn't pan or scroll yet.</li>
|
|
<li>prototype a new speed/time control panel from the mockup</li>
|
|
<li>nicer time warp loading screen</li>
|
|
<li>record and show detailed trip timeline, including time to park</li>
|
|
</ul>
|
|
<p>0.1.18</p>
|
|
<ul>
|
|
<li>map data: infer more building addresses</li>
|
|
<li>some analytics on how long people spend parking and intersection delay over time</li>
|
|
<li>create an options panel, allowing runtime customization of color scheme, traffic signal rendering, etc</li>
|
|
<li>internal changes to map building pipeline to make it much easier for new devs to onboard</li>
|
|
<li>organizing challenges into sub-stages, starting to flesh out specifics for the fix traffic signal track</li>
|
|
<li>much more realistic pedestrian pathfinding</li>
|
|
<li>fix minimap on mac (dpi issues)</li>
|
|
<li>visual tweaks to cars to make front/back easier to distinguish</li>
|
|
<li>internal change to switch most assets from PNG to SVG</li>
|
|
</ul>
|
|
<p>0.1.19</p>
|
|
<ul>
|
|
<li>some challenge modes show a histogram for counting faster/slower trips</li>
|
|
<li>new visualization of current demand per direction at a traffic signal</li>
|
|
<li>implementing some of Yuwen's UI changes: agent counter, split time/speed panel, moved functionality out of the old drop-down menus into a bottom-left tool panel, hiding debug functionality</li>
|
|
<li>replaced right-click context menus with left click to open info panels</li>
|
|
<li>fixed random issues reported by people from HN</li>
|
|
</ul>
|
|
<p>0.1.20</p>
|
|
<ul>
|
|
<li>moved some UI functionality around, pulling graphs into info panel</li>
|
|
<li>interactive legend for the minimap, toggle visibility of different agents</li>
|
|
<li>nicer colors and shapes for cars</li>
|
|
<li>misc simulation bugfixes that might help huge_seattle</li>
|
|
<li>pedestrians choose to use transit more realistically, factoring in time for the bus to drive</li>
|
|
</ul>
|
|
<p>0.1.21</p>
|
|
<ul>
|
|
<li>switch some analytics dashboards to use buttons, not old non-scrolling menus</li>
|
|
<li>scrollbars... at least a start</li>
|
|
<li>preview traffic signal changes from live sim as the base</li>
|
|
<li>traffic signal preview has normal time/speed controls</li>
|
|
<li>traffic signal editor has undo support</li>
|
|
<li>minimap has buttons to pan</li>
|
|
</ul>
|
|
<p>0.1.22</p>
|
|
<ul>
|
|
<li>minimap zoom controls</li>
|
|
<li>traffic signal rendering overhaul</li>
|
|
<li>heatmap colors improved, heatmap appears on minimap</li>
|
|
<li>bus info panel, a start to live delay analytics</li>
|
|
</ul>
|
|
<p>0.1.23</p>
|
|
<ul>
|
|
<li>UI revamps: speed panel, minimap controls, heatmap chooser</li>
|
|
<li>bus timeline</li>
|
|
<li>hide internal IDs normally</li>
|
|
<li>limit map zoom</li>
|
|
<li>fix bugs with crosswalks conflicting with vehicle turns</li>
|
|
</ul>
|
|
<p>0.1.24</p>
|
|
<ul>
|
|
<li>overhaul traffic signal editor UI, and add redo support</li>
|
|
<li>update main edit mode UI, and add redo support</li>
|
|
<li>limit max unzoom</li>
|
|
<li>fix the infamous HiDPI bug once and for all; minimaps should work everywhere</li>
|
|
<li>almost bug-free support for floating, horizontally and vertically scrolling panels</li>
|
|
<li>overhaul top-center panel, rename scenarios to be less confusing</li>
|
|
<li>expose bus analytics outside of challenge mode</li>
|
|
<li>live info panel can exist during a running simulation</li>
|
|
<li>consolidated agent route/trip information into info panel</li>
|
|
</ul>
|
|
<p>0.1.25</p>
|
|
<ul>
|
|
<li>overhauled the tutorial</li>
|
|
<li>tuned top-center panel for sandbox and challenge modes</li>
|
|
<li>make bike and bus lanes more obvious</li>
|
|
<li>show map edits as an overlay anywhere</li>
|
|
<li>tune info panel contents, and show relationships between parked cars and buildings</li>
|
|
<li>fixes to traffic signal editor, like making all-walk conversion idempotent</li>
|
|
<li>nicer throughput and delay plots (sliding windows, grid lines)</li>
|
|
</ul>
|
|
<p>0.1.26</p>
|
|
<ul>
|
|
<li>tutorial improved in a few places</li>
|
|
<li>map data: thinner sidewalks, associate buildings with named amenities</li>
|
|
<li>traffic model: vehicles can spawn on all lanes from a border</li>
|
|
<li>much better gameplay speed (previously was too fast)</li>
|
|
<li>UI tuning: lane editor, minimap, signal editor, heatmap legends don't overwrite minimap</li>
|
|
<li>traffic signal challenge communicates score more clearly</li>
|
|
</ul>
|
|
<p>0.1.27</p>
|
|
<ul>
|
|
<li>edit mode revamped: click to edit stuff. no more lane paintbrushes. autosaving and save as.</li>
|
|
<li>tutorial: can quit and resume tutorial now</li>
|
|
<li>challenge picking flow simplified</li>
|
|
<li>UI: layouting fixes to full-screen / into stuff, popup menus go beneath buttons, plots improved</li>
|
|
<li>internal change to render all text using vector graphics. other than a few text layouting issues, shouldn't be noticeable, except now tooltips in plots don't get covered up</li>
|
|
<li>misc perf improvements (cache SVGs, drawing many circles for unzoomed agents, dont reload prebaked data)</li>
|
|
<li>upgraded winit, glutin, glium -- hopefully no new bugs introduced on any platforms</li>
|
|
</ul>
|
|
<p>0.1.27a</p>
|
|
<ul>
|
|
<li>patch to fix a crash with empty text dimensions on things like building info panels</li>
|
|
</ul>
|
|
<p>0.1.28</p>
|
|
<ul>
|
|
<li>all info panels revamped</li>
|
|
<li>some tutorial stages are much more clear, with an updating goal</li>
|
|
<li>traffic signal scorecard generalized to work for some tutorial too</li>
|
|
<li>adjust how selected agents look</li>
|
|
<li>X button on popup menus</li>
|
|
</ul>
|
|
<p>0.1.29</p>
|
|
<ul>
|
|
<li>new tool to convert between stop signs and traffic signals</li>
|
|
<li>lane editor easier to edit multiple lanes</li>
|
|
<li>info panels: IDs, mostly avoid horizontal scrolling, better info about trips to/from somewhere, move buttons up</li>
|
|
<li>traffic signal editor UI overhaul</li>
|
|
<li>different data in top-right agent meters panel</li>
|
|
<li>tooltips to communicate keybindings better</li>
|
|
<li>new jump-to-time panel, showing when rush hours occur</li>
|
|
<li>speed controls use more useful speeds</li>
|
|
<li>include ongoing trips in measured trip times</li>
|
|
<li>jump to next challenge after completing one</li>
|
|
<li>lots of tutorial tweaks</li>
|
|
</ul>
|
|
<p>0.1.30</p>
|
|
<ul>
|
|
<li>show additional info about traffic patterns and buggy maps</li>
|
|
<li>revamp tutorial UI to group tasks and messages better</li>
|
|
<li>handle different mode transitions when info panel open on an agent</li>
|
|
<li>select entire roads in unzoomed edit mode</li>
|
|
<li>show total time an agent has spent moving / blocked</li>
|
|
<li>use 2-phase traffic signals by default, making the 23rd map successfully complete!</li>
|
|
<li>jump-to-time now optionally points out traffic jams forming</li>
|
|
<li>challenge splash screen improved</li>
|
|
</ul>
|
|
<p>0.1.31</p>
|
|
<ul>
|
|
<li>overhauled trip timeline in agent info panels</li>
|
|
<li>overhauled traffic signal details panel and the per-lane turn explorer</li>
|
|
<li>settings page: show all options at once. add way to scale up text/UI elements for high-DPI displays, and an alternate pan/zoom control scheme</li>
|
|
<li>traffic signal edits can now be exported and used in any slice of Seattle. will be using this to hand-map many of them.</li>
|
|
<li>many small tutorial fixes</li>
|
|
</ul>
|
|
<p>0.1.32</p>
|
|
<ul>
|
|
<li>some UI work on giving focus to textboxes, improving dropdown menus</li>
|
|
<li>road/intersection plots display baseline sim data too</li>
|
|
<li>start associating people with multiple trips, exposing this a little in the UI</li>
|
|
<li>bring back elevation data, introduce a new overlay. the elevation data is still really bad.</li>
|
|
</ul>
|
|
<p>0.1.33</p>
|
|
<ul>
|
|
<li>new "population" overlay, showing people (not just current trips). heatmap and dot map to visualize.</li>
|
|
<li>improved the "delay" overlay to handle roads and intersections</li>
|
|
<li>removed the confusing and useless alternate color schemes for agents</li>
|
|
<li>initial left-hand driving side, tested in Perth, also drawing more arrows for all one-way roads</li>
|
|
<li>loads of internal GUI code refactorings, preparing for a standalone release of the library</li>
|
|
<li>fixed z-buffering and alpha values for web backend</li>
|
|
</ul>
|
|
<p>0.1.34</p>
|
|
<ul>
|
|
<li>info panels have been totally overhauled again. multiple tabs, way more clear representation of agents, trips, and people.</li>
|
|
<li>draw people inside of a building</li>
|
|
<li>applied consistent typography everywhere</li>
|
|
<li>lots of internal refactoring</li>
|
|
</ul>
|
|
<p>0.1.35</p>
|
|
<ul>
|
|
<li>more info panel work, particularly for trips and buses. change plot settings live.</li>
|
|
<li>prototype of a SEIR pandemic model based on time spent in shared spaces, by orestis</li>
|
|
<li>slight heatmap improvements, more coming</li>
|
|
<li>more typography changes</li>
|
|
<li>mouse cursor now changes for buttons and dragging!</li>
|
|
<li>overhaul minimap controls, make layers behavior zoomed in a little better</li>
|
|
<li>new speed panel and jump-to-time modal</li>
|
|
</ul>
|
|
<p>0.1.36</p>
|
|
<ul>
|
|
<li>overhauled simulation data page, with a table to find slow trips and some initial summary visualizations</li>
|
|
<li>plots can change windowing and show/hide series</li>
|
|
<li>layers: fade map to contrast more, better scales/legends</li>
|
|
<li>show relative trip times in info panels</li>
|
|
<li>tools to rewind/ffw to watch particular trips</li>
|
|
<li>refocusing efforts on challenge modes; level 1 of a new one is pretty much ready</li>
|
|
<li>some simulation fixes around parking and a corner case of cars temporarily forming a cycle</li>
|
|
<li>orestis improved the population/pandemic heatmaps</li>
|
|
</ul>
|
|
<p>0.1.37</p>
|
|
<ul>
|
|
<li>optimize commute challenge: high score, live sentiment, second stage</li>
|
|
<li>parked cars are owned by people, not buildings</li>
|
|
<li>info panel improvements for trips</li>
|
|
<li>bike layer suggests places where bike lanes could be helpful</li>
|
|
<li>many improvements to scatter plot</li>
|
|
<li>a new histogram-ish thing for understanding faster/slower trips</li>
|
|
<li>handling scenarios longer than 24 hours better (for pandemic model)</li>
|
|
<li>prototype of commute visualization, grouping buildings by blocks</li>
|
|
<li>sim bugfixes: crosswalk / vehicle turn conflicts, start bikes in bike lanes from borders</li>
|
|
</ul>
|
|
<p>0.1.38</p>
|
|
<ul>
|
|
<li>major internal changes to ensure people's schedules don't have impossible gaps, to associate fixed bikes/cars to a eprson, handle delayed starts to trips</li>
|
|
<li>parking changes: show path to closest free spot, utilization of a lane over time, every building includes at least 1 offstreet spot by default</li>
|
|
<li>progress on removing unrealistic gridlock: detect turn conflict cycles and temporarily allow conflicts, trim last steps of a laggy head</li>
|
|
<li>internal sim alert system. speeds up debugging, could be used for player-facing "traffic jam!" alerts</li>
|
|
</ul>
|
|
<p>0.1.39</p>
|
|
<ul>
|
|
<li>switched to proper OSM-based maps; no more brittle, manual geometry fixes</li>
|
|
<li>more sorting and filtering options in trip table and parking overhead tables</li>
|
|
<li>improve offstreet parking rendering. park closer to destination buildings</li>
|
|
<li>easier process for importing new cities. introducing Los Angeles, Austin, Barranquilla.</li>
|
|
<li>new data updater tool so people can opt-in to new cities</li>
|
|
<li>many internal fixes to prevent gridlock. smarter cycle detection, manual OSM fixes and traffic signal timings</li>
|
|
</ul>
|
|
<p>0.1.40</p>
|
|
<ul>
|
|
<li>differential throughput layer to understand routing diversions</li>
|
|
<li>map edits now reference longer-lasting OSM IDs, can work cross-map</li>
|
|
<li>basemap updates: new areas for west seattle, mt baker, lots of upstreamed fixes in OSM and traffic signals, smarter border matching</li>
|
|
<li>parking: optionally filter on/off-street spots in the layer, allow disconnecting spots via edits</li>
|
|
<li>render some tunnels with lower opacity</li>
|
|
<li>new feature to change speed limits and bulk road selection tools</li>
|
|
<li>first write-up of a real use case (closing lake wash through arboretum)</li>
|
|
<li>make the traffic signal challenge act like a game, with a failure/win state and scoring</li>
|
|
</ul>
|
|
<p>0.1.40a</p>
|
|
<ul>
|
|
<li>added a mode to map parking</li>
|
|
</ul>
|
|
<p>0.1.41</p>
|
|
<ul>
|
|
<li>new parking mapper tool</li>
|
|
<li>include a one-shot .osm importer in the release</li>
|
|
<li>new layer to find different types of amenities / businesses</li>
|
|
<li>adjust traffic signal rendering style</li>
|
|
<li>bulk lane editor for changing speed limits and lane types</li>
|
|
<li>including west seattle and udistrict maps</li>
|
|
<li>include some OSM buildings that were being skipped</li>
|
|
<li>dont pause after opening something from sandbox mode</li>
|
|
<li>adjust turn signals for lane-changing cars</li>
|
|
<li>lots of fixes for monitors with different DPIs, enabled by default</li>
|
|
</ul>
|
|
<p>0.1.42</p>
|
|
<ul>
|
|
<li>many misc UI bugfixes, especially for high-DPI screens</li>
|
|
<li>managing turns across multiple nearby intersections: tool to visualize, handling multi-way OSM turn restrictions, using this to ban illegal movements at the pathfinding layer, starting a traffic signal editor variant to edit these</li>
|
|
<li>rendering improvements: unzoomed agent size, visualizing routes on trip table, transparent roads beneath bridges, draw harbor island</li>
|
|
<li>overhauled street/address finder</li>
|
|
<li>parking mapper: shortcut to open bing</li>
|
|
</ul>
|
|
<p>0.1.43</p>
|
|
<ul>
|
|
<li>new map picker!</li>
|
|
<li>UI polish: traffic signal editor, layers, bus stops, delay plots</li>
|
|
<li>generate more interesting biographies for people</li>
|
|
<li>tuned all the map boundaries</li>
|
|
<li>fleshing out lots of docs in preparation for the alpha release...</li>
|
|
</ul>
|
|
<p>0.1.44</p>
|
|
<ul>
|
|
<li>spawner UI revamped</li>
|
|
<li>model parking lots! and finally model public/private parking</li>
|
|
<li>fix up tutorial</li>
|
|
<li>starting a story map mode</li>
|
|
</ul>
|
|
<p>0.1.45</p>
|
|
<ul>
|
|
<li>overhauled challenge cutscenes and hints</li>
|
|
<li>traffic signal challenge: fix score detection, add meter, much faster startup, no reset-to-midnight required</li>
|
|
<li>layers: use gradient for a few, delay comparison, new UI for picker</li>
|
|
<li>overhauled minimap controls, should be intuitive now</li>
|
|
<li>edit mode changelist UI started</li>
|
|
</ul>
|
|
<p>0.2.0 (alpha launch)</p>
|
|
<ul>
|
|
<li>road names now shown by default, in a new style</li>
|
|
<li>all layers now use gradients and show up zoomed in. worst traffic jam layer revamped.</li>
|
|
<li>scatter and line plot improvements</li>
|
|
<li>internal UI fixes: proper word wrap</li>
|
|
<li>bugfixes for following people riding the bus</li>
|
|
<li>rainbow crosswalks in one neighborhood</li>
|
|
<li>final polishing for launch</li>
|
|
</ul>
|
|
<p>0.2.1</p>
|
|
<ul>
|
|
<li>busy week due to launch, but many new features in the pipeline</li>
|
|
<li>many bug fixes</li>
|
|
<li>edit mode: proper autosave, load proposals, jump between lane/intersection editors</li>
|
|
<li>very first steps on light rail... importing the tracks</li>
|
|
<li>starting a new traffic scenario modifier system, to repeat entire scenario or outright cancel trips for some people. many more ideas for filters and actions coming soon.</li>
|
|
<li>starting to represent private roads</li>
|
|
<li>add a very simple actuated traffic signal</li>
|
|
</ul>
|
|
<p>0.2.2</p>
|
|
<ul>
|
|
<li>the default traffic signal configuration is much smarter now, handling roads with some sidewalks missing and automatically synchronizing pairs of adjacent lights</li>
|
|
<li>much faster startup time for large maps</li>
|
|
<li>better UX for handling unsaved edits</li>
|
|
<li>access-restricted zones: changing existing zones almost completely works, except for granting new access to pedestrians</li>
|
|
<li>new sidewalk corner rendering, more rounded</li>
|
|
<li>ui style standardized for margins, padding</li>
|
|
<li>Javed got camera panning when your cursor is at the edge of the screen to work; enable it in settings</li>
|
|
<li>pulling bus stop/route info from OSM, not GTFS. steps towards light rail.</li>
|
|
<li>experimenting with controls for hiding bridges to see roads underneath; try them in dev mode (ctrl+S)</li>
|
|
<li>many bug fixes</li>
|
|
</ul>
|
|
<p>0.2.3</p>
|
|
<ul>
|
|
<li>lane geometry is dramatically fixed, especially for one-ways</li>
|
|
<li>importing lanes from OSM improved</li>
|
|
<li>UI: bulk select includes select-along-a-route, show all bus routes in the layer, unzoomed zordering for roads/intersections</li>
|
|
<li>traffic scenario modifier can now convert trip modes</li>
|
|
<li>slight progress on light rail, although the train only makes one stop</li>
|
|
<li>vehicles moving through complex intersections with multiple traffic signals will now make it through multiple lights, even if they're unsynchronized</li>
|
|
<li>new random traffic scenario generator that makes people go between houses and workplaces</li>
|
|
<li>access-restricted zones: granular editing of individual roads now mostly works</li>
|
|
<li>removing the hardcoded relative directories, which many people have been having problems with</li>
|
|
<li>many many bug fixes, and some optimizations to reduce release file size</li>
|
|
</ul>
|
|
<p>0.2.4</p>
|
|
<ul>
|
|
<li>bus/train routes overhauled; they're now one-way, regularly spawn every hour, and may begin or end at a border</li>
|
|
<li>new commute pattern explorer tool</li>
|
|
<li>new character art to give cutscenes a bit more personaliy</li>
|
|
<li>some progress on gridlocking maps, both from manual fixes and an attempt to reduce conflicts in multi-turn sequences</li>
|
|
<li>misc UI: show cars seeking parking in unzoomed mode, plot arrival rate at border intersections, consolidate bulk selection controls</li>
|
|
<li>trips modified by an experiment can now be filtered in summaries</li>
|
|
<li>buses, trains, and passengers on them are now properly distinguished in different stats</li>
|
|
<li>include krakow and berlin in release</li>
|
|
<li>buildings with holes in the middle are now rendered properly</li>
|
|
</ul>
|
|
<p>0.2.5</p>
|
|
<ul>
|
|
<li>cars pick lanes better</li>
|
|
<li>overhaul bus/stop/route info panels</li>
|
|
<li>UI: better autocomplete, commuter pattern improvements by Michael, toggles instead of checkboxes, contours for heatmaps, edit mode loader revamp</li>
|
|
<li>internal refactors: turn creation, osm tags, osm parsing</li>
|
|
<li>import living streets from OSM as restricted-access zones, and other importer tweaks for berlin, krakow, san jose, sydney</li>
|
|
</ul>
|
|
<p>0.2.6</p>
|
|
<ul>
|
|
<li>many roads without sidewalks now have a tiny shoulder lane, still enabling pedestrian movement, but with a penalty</li>
|
|
<li>bike trips will stop/start at a better position along the sidewalk now</li>
|
|
<li>support parking lanes on the off-side of a one-way</li>
|
|
<li>UI: search by building names, commuter patterns shows borders better</li>
|
|
<li>transit: make people ride off-map, spawn buses on short roads</li>
|
|
<li>internal cleanups for buttons</li>
|
|
</ul>
|
|
<p>0.2.7</p>
|
|
<ul>
|
|
<li>many intersections with on/off ramps have much better geometry</li>
|
|
<li>lane-changing banned on turn lanes</li>
|
|
<li>lots more work matching bus stops/routes to the map. some progress, also some regressions.</li>
|
|
<li>fixing spawning on tiny borders</li>
|
|
<li>bus spawn rates from GTFS for seattle. started an editor for the schedule.</li>
|
|
<li>internal ezgui refactorings</li>
|
|
</ul>
|
|
<p>0.2.8</p>
|
|
<ul>
|
|
<li>multiple traffic signals can now be synchronized and edited together</li>
|
|
<li>new dashboard for "traffic signal demand" over the entire day and map</li>
|
|
<li>started experimenting with controlling the headless runner via a JSON API</li>
|
|
<li>epic ezgui fix by Michael to consolidate handling of HiDPI scaling</li>
|
|
<li>got a bunch of huge cities importing and loading quickly</li>
|
|
<li>you can now save the trips you manually spawn in freeform mode, then replay them later</li>
|
|
</ul>
|
|
<p>0.2.9</p>
|
|
<ul>
|
|
<li>import Xi'an, add a Chinese font, and add a tool for that group to import their external demand data</li>
|
|
<li>control A/B Street through a graphics-less API, with a Python example</li>
|
|
<li>improve UI for per-direction traffic signal demand</li>
|
|
<li>on/off ramp geometry fixed in a few more cases</li>
|
|
<li>fix some missing parking lot aisles, handle parking lots with 0 spots, and extract parking garages from OSM</li>
|
|
<li>switch road/building language in settings, if OSM data exists</li>
|
|
<li>congestion capping prototype: declare a max number of vehicles that can pass through a zone per hour, view/edit it, and very simple implementation in the sim layer</li>
|
|
<li>add custom-drawn trips to the main scenario, for exploring new demand from a new building</li>
|
|
<li>mkirk fixed up the glow/wasm ezgui backends, letting us remove glium</li>
|
|
<li>make map edit JSON backwards compatible</li>
|
|
<li>better lane/turn markings</li>
|
|
</ul>
|
|
<p>0.2.10</p>
|
|
<ul>
|
|
<li>two-way cycletracks and arbitrary direction changes for roads</li>
|
|
<li>fix map editing for lane reversals, make edits backwards compatible, and massively speed up applying edits</li>
|
|
<li>fleshing out the headless API and tooling for controlling the simulation from any language</li>
|
|
<li>import a few more places, redo left-hand driving support so far</li>
|
|
<li>various bug/performance fixes</li>
|
|
</ul>
|
|
<p>0.2.11</p>
|
|
<ul>
|
|
<li>disabled support for editing the map without resetting the simulation. needs more work, but solid start.</li>
|
|
<li>improvements to API, activity model, congestion capping</li>
|
|
<li>small UI tweaks for parking, editing multiple signals</li>
|
|
<li>fixed last bugs for left-handed driving, should work just as well now</li>
|
|
<li>lots of graphics experiments from the hackathon, not merged yet</li>
|
|
</ul>
|
|
<p>0.2.12</p>
|
|
<ul>
|
|
<li>new textured color scheme and isometric buildings, in settings</li>
|
|
<li>new layer to show how far away people parked</li>
|
|
<li>Massive UI overhauls: jump to time/delay, edit mode, traffic signal editor (now with offsets), lane editor, bulk lane edit, traffic signal demand (individual intersections and all), loading screen</li>
|
|
<li>the Go API example compares trip times and detects gridlock</li>
|
|
<li>infinite parking mode</li>
|
|
<li>show how long a car has been parked in one spot</li>
|
|
<li>bugfix for some pathfinding costs around uber-turns</li>
|
|
<li>start to show a trip's purpose</li>
|
|
</ul>
|
|
<p>0.2.13</p>
|
|
<ul>
|
|
<li>alleyways from OSM imported</li>
|
|
<li>traffic signal minimum time now constrained by crosswalks; thanks Sam!</li>
|
|
<li>UI changes in progress for trip tables, summaries, bulk edit</li>
|
|
<li>more API / Python example work for congestion capping</li>
|
|
<li>bug fixes: isometric buildings, documentation links, dropdown widgets, turn restrictions</li>
|
|
</ul>
|
|
<p>0.2.14</p>
|
|
<ul>
|
|
<li>improve turn generation, with goldenfile tests</li>
|
|
<li>UI adjustments: unzoomed routes, better delay layer, include reasons for cancelled trips, throughput layer counts</li>
|
|
<li>small map importing fixes: multipolygon parking lots</li>
|
|
<li>fix infinite parking and blackholed buildings</li>
|
|
</ul>
|
|
<p>0.2.15</p>
|
|
<ul>
|
|
<li>large internal change allowing asynchronously loading extra files over HTTP for web</li>
|
|
<li>the release of the first web version!</li>
|
|
<li>cars looking for parking now have a "thought bubble" showing this, by Michael</li>
|
|
<li>slow sections of a trip are now shown in the info panel, by Sam</li>
|
|
<li>fix by Michael for handling window resizing in panels</li>
|
|
<li>fix original routes on edited maps</li>
|
|
<li>internal code organization and documentation</li>
|
|
</ul>
|
|
<p>0.2.16</p>
|
|
<ul>
|
|
<li>UI: click unzoomed agents, switch between metric/imperial units, show reason for cancelled trips, new "faded zoom" color scheme based on mapbox, more detailed agent counts in the top-right panel's tooltips</li>
|
|
<li>started a new dedicated OpenStreetMap viewer, will split out from A/B Street later</li>
|
|
<li>fix alpha colors on web</li>
|
|
<li>bugfixes for the new asynchronous map loading</li>
|
|
<li>some substantial simulation performance gains (168s to 90s on one benchmark!)</li>
|
|
<li>lots of progress towards editing the map without resetting the simulation to midnight. please test with --live_map_edits and report any issues</li>
|
|
<li>internal refactoring and code documentation</li>
|
|
</ul>
|
|
<p>0.2.17</p>
|
|
<ul>
|
|
<li>tooling to automatically extract different shapes around cities without an explicit bounding polygon</li>
|
|
<li>imported many maps for an OSM viewer demo</li>
|
|
<li>misc bug fixes, UI tweaks, and perf improvements, especially for the web version</li>
|
|
<li>start using OSM sidewalks data properly in krakow -- more work needed, but better start</li>
|
|
</ul>
|
|
<p>0.2.18</p>
|
|
<ul>
|
|
<li>overhaul data/system management: switch from Dropbox to S3, reorganize files, add an in-game updater</li>
|
|
<li>started a UI for collision dataviz, with data in the UK and Seattle</li>
|
|
<li>improve turns between separate footways</li>
|
|
<li>simplify the process of importing a new city</li>
|
|
</ul>
|
|
<p>0.2.19</p>
|
|
<ul>
|
|
<li>added experimental day/night support; run with --day_night</li>
|
|
<li>slight performance improvements by avoiding applying no-op edits</li>
|
|
<li>new tests for lane-changing behavior, used to more safely allow more realistic behavior blocking "degenerate" intersections</li>
|
|
<li>experimenting with filling in gaps between one-way roads, to represent medians</li>
|
|
</ul>
|
|
<h1><a class="header" href="#references" id="references">References</a></h1>
|
|
<h2><a class="header" href="#example-use-cases" id="example-use-cases">Example use cases</a></h2>
|
|
<ul>
|
|
<li><a href="https://www.reddit.com/r/SeattleWA/comments/9mtgkh/seven_places_to_add_bus_lanes_now/">https://www.reddit.com/r/SeattleWA/comments/9mtgkh/seven_places_to_add_bus_lanes_now/</a></li>
|
|
<li><a href="https://www.reddit.com/r/SeattleWA/comments/9oqkz9/how_traffic_patterns_will_change_after_seattles/">https://www.reddit.com/r/SeattleWA/comments/9oqkz9/how_traffic_patterns_will_change_after_seattles/</a></li>
|
|
<li><a href="https://www.reddit.com/r/Seattle/comments/9orqne/4_fresh_ideas_to_ease_seattles_coming_traffic/">https://www.reddit.com/r/Seattle/comments/9orqne/4_fresh_ideas_to_ease_seattles_coming_traffic/</a></li>
|
|
<li><a href="https://www.reddit.com/r/SeattleWA/comments/cr1r1l/why_the_fuck_does_the_right_lane_convert_to/">https://www.reddit.com/r/SeattleWA/comments/cr1r1l/why_the_fuck_does_the_right_lane_convert_to/</a></li>
|
|
<li><a href="https://twitter.com/transitrunner/status/1175068582142599168">https://twitter.com/transitrunner/status/1175068582142599168</a></li>
|
|
</ul>
|
|
<h2><a class="header" href="#groups-that-may-be-eventually-interested" id="groups-that-may-be-eventually-interested">Groups that may be eventually interested</a></h2>
|
|
<ul>
|
|
<li>Seattle Times Traffic Lab</li>
|
|
<li><a href="https://www.citylab.com/transportation/2018/08/is-it-time-to-rethink-what-a-bike-lane-is/568483/">https://www.citylab.com/transportation/2018/08/is-it-time-to-rethink-what-a-bike-lane-is/568483/</a></li>
|
|
<li><a href="http://openseattle.org/">http://openseattle.org/</a></li>
|
|
<li><a href="https://igniteseattle.com/">https://igniteseattle.com/</a></li>
|
|
<li><a href="http://seattlegreenways.org/">http://seattlegreenways.org/</a></li>
|
|
<li><a href="https://www.livablecities.org/">https://www.livablecities.org/</a></li>
|
|
<li><a href="https://www.reddit.com/r/openstreetmap/comments/a39uv0/ok_so/">https://www.reddit.com/r/openstreetmap/comments/a39uv0/ok_so/</a></li>
|
|
<li><a href="https://mic.comotion.uw.edu/">https://mic.comotion.uw.edu/</a></li>
|
|
<li><a href="https://www.seattleinprogress.com/">https://www.seattleinprogress.com/</a></li>
|
|
<li><a href="http://www.seattle.gov/seattle-pedestrian-advisory-board">http://www.seattle.gov/seattle-pedestrian-advisory-board</a></li>
|
|
<li>Socrata</li>
|
|
<li><a href="http://transportationcamp.org/">http://transportationcamp.org/</a></li>
|
|
<li><a href="https://www.seattle.gov/transportation/projects-and-programs/programs/neighborhood-street-fund">https://www.seattle.gov/transportation/projects-and-programs/programs/neighborhood-street-fund</a></li>
|
|
<li><a href="https://www.seattle.gov/neighborhoods/programs-and-services/your-voice-your-choice">https://www.seattle.gov/neighborhoods/programs-and-services/your-voice-your-choice</a></li>
|
|
<li><a href="https://commuteseattle.com/">https://commuteseattle.com/</a></li>
|
|
<li><a href="https://www.theurbanist.org/">https://www.theurbanist.org/</a></li>
|
|
<li><a href="https://humantransit.org/2019/03/notes-on-simcity-at-30.html">https://humantransit.org/2019/03/notes-on-simcity-at-30.html</a></li>
|
|
<li><a href="https://mynorthwest.com/category/chokepoints/">https://mynorthwest.com/category/chokepoints/</a></li>
|
|
<li><a href="https://blogs.uw.edu/ceadvice/2019/05/08/infrastructure-week-2019-welcome-uw-cee-students-and-faculty/">https://blogs.uw.edu/ceadvice/2019/05/08/infrastructure-week-2019-welcome-uw-cee-students-and-faculty/</a></li>
|
|
<li><a href="https://escience.washington.edu/dssg/">https://escience.washington.edu/dssg/</a></li>
|
|
<li>josie kresner from transport foundry</li>
|
|
<li><a href="https://www.citylab.com/transportation/2019/08/city-planning-transportation-oakland-community-engagement/596050/">https://www.citylab.com/transportation/2019/08/city-planning-transportation-oakland-community-engagement/596050/</a>
|
|
<ul>
|
|
<li>tweeting small problems -> bug tracker</li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="https://www.the74million.org/article/building-a-smarter-and-cheaper-school-bus-system-how-a-boston-mit-partnership-led-to-new-routes-that-are-20-more-efficient-use-400-fewer-buses-save-5-million/">https://www.the74million.org/article/building-a-smarter-and-cheaper-school-bus-system-how-a-boston-mit-partnership-led-to-new-routes-that-are-20-more-efficient-use-400-fewer-buses-save-5-million/</a></li>
|
|
<li><a href="https://www.citylab.com/perspective/2019/10/micromobility-urban-design-car-free-infrastruture-futurama/600163/">https://www.citylab.com/perspective/2019/10/micromobility-urban-design-car-free-infrastruture-futurama/600163/</a></li>
|
|
<li><a href="https://www.sanjorn.com/">https://www.sanjorn.com/</a></li>
|
|
<li><a href="https://ui.kpf.com/">https://ui.kpf.com/</a></li>
|
|
</ul>
|
|
<h2><a class="header" href="#similar-projects" id="similar-projects">Similar projects</a></h2>
|
|
<ul>
|
|
<li>Urban Footprint (<a href="https://news.ycombinator.com/item?id=17895739">https://news.ycombinator.com/item?id=17895739</a>)</li>
|
|
</ul>
|
|
<h2><a class="header" href="#seattle-specific" id="seattle-specific">Seattle-specific</a></h2>
|
|
<p>SDOT asking for feedback:</p>
|
|
<ul>
|
|
<li><a href="http://sdotblog.seattle.gov/2017/02/08/from-signals-to-signs/">http://sdotblog.seattle.gov/2017/02/08/from-signals-to-signs/</a></li>
|
|
<li><a href="https://www.seattle.gov/transportation/projects-and-programs/programs/bike-program/protected-bike-lanes/n-34th-st-mobility-improvements">https://www.seattle.gov/transportation/projects-and-programs/programs/bike-program/protected-bike-lanes/n-34th-st-mobility-improvements</a></li>
|
|
<li><a href="https://www.seattle.gov/transportation/projects-and-programs/programs/transportation-planning/north-downtown-mobility-action-plan">https://www.seattle.gov/transportation/projects-and-programs/programs/transportation-planning/north-downtown-mobility-action-plan</a></li>
|
|
<li><a href="https://www.seattlebikeblog.com/2016/12/01/check-out-seattles-12-winning-neighborhood-led-transportation-ideas/">https://www.seattlebikeblog.com/2016/12/01/check-out-seattles-12-winning-neighborhood-led-transportation-ideas/</a></li>
|
|
</ul>
|
|
<p>Seattlites with opinions and ideas:</p>
|
|
<ul>
|
|
<li>
|
|
<p><a href="http://seattlegreenways.org/">http://seattlegreenways.org/</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.seattlebikeblog.com/2018/01/19/a-roosevelt-junior-redesigned-the-streets-around-his-high-school-and-his-plan-is-better-than-sdots/">https://www.seattlebikeblog.com/2018/01/19/a-roosevelt-junior-redesigned-the-streets-around-his-high-school-and-his-plan-is-better-than-sdots/</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.reddit.com/r/SeattleWA/comments/5rvss5/what_changes_would_you_make_to_seattles_bus/">https://www.reddit.com/r/SeattleWA/comments/5rvss5/what_changes_would_you_make_to_seattles_bus/</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.seattletimes.com/seattle-news/transportation/congestion-tolling-could-finally-break-seattles-working-poor-heres-a-better-idea/">https://www.seattletimes.com/seattle-news/transportation/congestion-tolling-could-finally-break-seattles-working-poor-heres-a-better-idea/</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.reddit.com/r/SeattleWA/comments/86g3p9/id_get_back_an_hour_and_a_half_a_week/">https://www.reddit.com/r/SeattleWA/comments/86g3p9/id_get_back_an_hour_and_a_half_a_week/</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.reddit.com/r/Seattle/comments/4z3ewl/what_are_seattles_worst_intersections/">https://www.reddit.com/r/Seattle/comments/4z3ewl/what_are_seattles_worst_intersections/</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.reddit.com/r/SeattleWA/comments/83h4ri/the_intersection_at_john_and_broadway_desperately/">https://www.reddit.com/r/SeattleWA/comments/83h4ri/the_intersection_at_john_and_broadway_desperately/</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="http://www.seattle.gov/transportation/sdot-document-library/citywide-plans/move-seattle">http://www.seattle.gov/transportation/sdot-document-library/citywide-plans/move-seattle</a></p>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#other-projects" id="other-projects">Other projects</a></h2>
|
|
<ul>
|
|
<li><a href="https://github.com/uwescience/TrafficCruising-DSSG2017">https://github.com/uwescience/TrafficCruising-DSSG2017</a></li>
|
|
<li><a href="http://sharedstreets.io/">http://sharedstreets.io/</a></li>
|
|
<li><a href="https://github.com/twpol/osm-tiles">https://github.com/twpol/osm-tiles</a> attempting to infer nice road geometry
|
|
too</li>
|
|
</ul>
|
|
<h2><a class="header" href="#notes-from-related-work" id="notes-from-related-work">Notes from related work</a></h2>
|
|
<h3><a class="header" href="#smarts-a-hrefhttpspeopleengunimelbeduauetanintist17pdfhttpspeopleengunimelbeduauetanintist17pdfa" id="smarts-a-hrefhttpspeopleengunimelbeduauetanintist17pdfhttpspeopleengunimelbeduauetanintist17pdfa">SMARTS (<a href="https://people.eng.unimelb.edu.au/etanin/tist17.pdf">https://people.eng.unimelb.edu.au/etanin/tist17.pdf</a>)</a></h3>
|
|
<ul>
|
|
<li>Split map into sections, simulate in parallel, load-balance</li>
|
|
<li>has an IDM equation</li>
|
|
<li>tests against real TomTom data of average speed per link</li>
|
|
</ul>
|
|
<h3><a class="header" href="#games" id="games">Games</a></h3>
|
|
<p>SimCity, Cities: Skylines
|
|
<a href="https://steamcommunity.com/sharedfiles/filedetails/?id=583429740">https://steamcommunity.com/sharedfiles/filedetails/?id=583429740</a>
|
|
<a href="https://github.com/fegennari/3DWorld">https://github.com/fegennari/3DWorld</a></p>
|
|
<h3><a class="header" href="#open-source-urban-planning" id="open-source-urban-planning">Open source urban planning</a></h3>
|
|
<p>UrbanSim</p>
|
|
<h3><a class="header" href="#proprietary" id="proprietary">Proprietary</a></h3>
|
|
<p>Sidewalk Labs Model</p>
|
|
<h3><a class="header" href="#maps-for-people" id="maps-for-people">Maps for people</a></h3>
|
|
<p><a href="https://arxiv.org/pdf/1811.01147.pdf">https://arxiv.org/pdf/1811.01147.pdf</a></p>
|
|
<h3><a class="header" href="#gammacsunceduroadnetworkwilkie_tvcgpdf" id="gammacsunceduroadnetworkwilkie_tvcgpdf">gamma.cs.unc.edu/RoadNetwork/wilkie_TVCG.pdf</a></h3>
|
|
<p>section 6.3 talks about offset polylines <a href="http://gamma.cs.unc.edu/RoadNetwork">http://gamma.cs.unc.edu/RoadNetwork</a></p>
|
|
<h3><a class="header" href="#citybound" id="citybound">CityBound</a></h3>
|
|
<p><a href="https://github.com/aeickhoff/descartes">https://github.com/aeickhoff/descartes</a></p>
|
|
<h3><a class="header" href="#discrete-event-simulation-papers" id="discrete-event-simulation-papers">Discrete Event Simulation papers</a></h3>
|
|
<ul>
|
|
<li>
|
|
<p>section 5.1 of Advanced tutorial on microscopic discrete-event traffic
|
|
simulation refers to some DES systems</p>
|
|
<ul>
|
|
<li>Florian, Mahut, and Tremblay 2008</li>
|
|
<li>Sumaryo, Halim, and Ramli 2013</li>
|
|
<li>Salimifard and Ansari 2013</li>
|
|
<li>Burghout, Koutsopoulos, and Andreasson 2006</li>
|
|
<li>Thulasidasan, Kasiviswanathan, Eidenbenz, Galli, Mniszewski, and Romero 2009</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>A Dynamic Traffic Assignment Model for Highly Congested Urban Networks</p>
|
|
<ul>
|
|
<li>section 2.2 models lanes as a moving and queueing part, references other
|
|
possibly useful papers</li>
|
|
<li>dont worry about multiple lanes for the moving part, just the turn queues at
|
|
the end</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="header" href="#tactical-urbanism" id="tactical-urbanism">Tactical urbanism</a></h2>
|
|
<ul>
|
|
<li><a href="https://www.vice.com/en_us/article/pajgyz/rogue-coder-turned-a-parking-spot-into-a-coworking-space">https://www.vice.com/en_us/article/pajgyz/rogue-coder-turned-a-parking-spot-into-a-coworking-space</a></li>
|
|
</ul>
|
|
<h1><a class="header" href="#collaborations" id="collaborations">Collaborations</a></h1>
|
|
<p>We're working with a few different groups on projects using A/B Street.</p>
|
|
<h2><a class="header" href="#glt" id="glt">GLT</a></h2>
|
|
<p>Active as of Sept 2020</p>
|
|
<p><a href="https://www.greenlightstrading.com">Green Lights Trading</a> is applying dynamic
|
|
congestion caps to encourage drivers to find alternate routes, not drive during
|
|
rush hour, or take public transit instead. I'm actively implementing a
|
|
proof-of-concept in A/B Street. It could also be used to explore ideas like a
|
|
downtown congestion charging zone for Seattle.</p>
|
|
<h2><a class="header" href="#xian" id="xian">Xi'an</a></h2>
|
|
<p>Active as of Sept 2020</p>
|
|
<p>A group (with their own demand data!) is studying traffic signal optimization in
|
|
Xi'an. They're using the <a href="project/../dev/api.html">API</a>.</p>
|
|
<h2><a class="header" href="#forecasting-group" id="forecasting-group">Forecasting group</a></h2>
|
|
<p>Active as of Sept 2020</p>
|
|
<p>A research group is making a bunch of live map edits and scheduling new trips in
|
|
the middle of a simulation and using their system to try to predict system-wide
|
|
effects. They're also using the API.</p>
|
|
<h2><a class="header" href="#cityengine" id="cityengine">CityEngine</a></h2>
|
|
<p>Stalled as of Sept 2020</p>
|
|
<p>Edits in A/B Street could be exported to the
|
|
<a href="https://github.com/d-wasserman/shared-row/">shared-row</a> format, then rendered
|
|
in 3D using
|
|
<a href="https://github.com/d-wasserman/Complete_Street_Rule">ArcGIS CityEngine</a>. Not
|
|
blocked on us.</p>
|
|
<h2><a class="header" href="#berlin-1" id="berlin-1">Berlin</a></h2>
|
|
<p>Stalled as of Sept 2020</p>
|
|
<p>A group wants to use A/B Street for various public engagement projects in
|
|
<a href="https://github.com/dabreegster/abstreet/issues/119">Berlin</a>. Mostly blocked on
|
|
getting a reasonable travel demand model.</p>
|
|
<h2><a class="header" href="#manchester" id="manchester">Manchester</a></h2>
|
|
<p>Stalled as of Sept 2020</p>
|
|
<p>A group tentatively wants to engage the public about preventing rat runs and
|
|
making no-through-access zones in Manchester suburbs. Not really blocked on us
|
|
yet.</p>
|
|
<h2><a class="header" href="#pandemic-model" id="pandemic-model">Pandemic model</a></h2>
|
|
<p>Stalled as of Sept 2020</p>
|
|
<p>A group from the Uni of Geneva started a
|
|
<a href="https://github.com/dabreegster/abstreet/tree/master/sim/src/pandemic">COVID-19 model</a>
|
|
that figures out how long people spend in shared indoor spaces.</p>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
|
|
|
|
|
|
|
|
<div style="clear: both"></div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
|
|
|
|
|
|
</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 -->
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
window.addEventListener('load', function() {
|
|
window.setTimeout(window.print, 100);
|
|
});
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|