abstreet/print.html
2020-12-15 20:55:48 +00:00

3943 lines
225 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.22/abstreet_windows_v0_2_22.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.22/abstreet_mac_v0_2_22.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&gt; ../output.txt 2&gt;&amp;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.22/abstreet_linux_v0_2_22.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="#common-issues" id="common-issues">Common issues</a></h2>
<p>If the size of text and panels
<a href="https://github.com/dabreegster/abstreet/issues/381">seems very strange</a>, you
can try editing <code>play_abstreet.sh</code> or <code>play_abstreet.bat</code> and passing
<code>--scale_factor=1</code> on the command line. This value is detected from your monitor
settings, so if you have a Retina or other HiDPI display, things may be too big
or small.</p>
<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>
<li>Snowflake SVG (<a href="https://www.svgrepo.com/page/licensing">https://www.svgrepo.com/page/licensing</a>, CC0)</li>
<li>Jingle Bells (<a href="https://soundcloud.com/royaltyfreebackgroundmusic/creative-commons-music-4061">https://soundcloud.com/royaltyfreebackgroundmusic/creative-commons-music-4061</a>, CC BY-NC-ND)</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 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 &quot;export&quot; 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 &lt; 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>&lt;bounds/&gt;</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 &lt; 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> and <code>data/regen.sh</code>, following <code>tel_aviv</code> as an example.</p>
</li>
<li>
<p>Fill out <code>nice_map_name</code> in <code>map_gui/src/tools/mod.rs</code>.</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 &quot;blackholed&quot;, 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 &quot;ghost&quot; 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 &quot;block the box&quot; -- 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 &quot;synthetic population&quot; 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&amp;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 &quot;compare
before edits&quot; 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 &quot;local access only&quot; 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&amp;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 &quot;repair the bridge&quot; 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 &amp;&amp; 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>Building contraction hierarchies for pathfinding occurs in the --map stage. It
can take a few minutes for larger maps. To view occasional progress updates,
you can run the importer with</p>
<pre><code>RUST_LOG=&quot;fast_paths=debug/contracted node [0-9]+0000 &quot;
</code></pre>
<p>You can rerun specific stages of the importer:</p>
<ul>
<li>If you're modifying the initial OSM data -&gt; 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 -&gt; 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>map_gui</code>: common code to interact with <code>map_model</code> maps</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>
<li><code>experiment</code>: ...</li>
<li><code>parking_mapper</code>: a standalone tool to help map street parking in OSM</li>
<li><code>osm_viewer</code>: a standalone tool to render OSM in detail</li>
<li><code>fifteen_min</code>: a standalone tool to explore 15-minute neighborhoods</li>
<li><code>popdat</code>: use census data to produce traffic simulation input</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>See the <a href="dev/testing.html">testing strategy</a> page.</p>
<h2><a class="header" href="#logging" id="logging">Logging</a></h2>
<p>Prefer using <code>info!</code>, <code>warn!</code>, <code>error!</code>, etc from the <code>log</code> crate rather than
<code>println</code>. 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>Adjust the log level without recompiling via the <code>RUST_LOG</code> env variable.</p>
<pre><code>RUST_LOG=debug cargo run --bin game
</code></pre>
<p>This can be done on a per lib basis:</p>
<pre><code>RUST_LOG=my_lib=debug cargo run --bin game
</code></pre>
<p>Or a module-by-module basis:</p>
<pre><code>RUST_LOG=my_lib::module=debug cargo run --bin game
</code></pre>
<p>You can mix and match:</p>
<pre><code># error logging by default, except the foo:bar module at debug level
# and the entire baz crate at info level
RUST_LOG=error,foo::bar=debug,baz=info cargo run --bin game
</code></pre>
<p>For some special cases, you might want to use regex matching by specifying a
pattern with the &quot;/&quot;:</p>
<pre><code># only log once every 10k
RUST_LOG=&quot;fast_paths=debug/contracted node [0-9]+0000 &quot; mike import_la
</code></pre>
<p>See the <a href="https://docs.rs/env_logger/0.8.2/env_logger/">env_logger
documentation</a> for more usage
examples.</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 &quot;[0:v] fps=12,scale=1024:-1,split [a][b];[a] palettegen [p];[b][p] paletteuse&quot; 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 = [
&quot;-C&quot;, &quot;link-arg=-fuse-ld=lld&quot;,
]
</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 '{ &quot;scenario&quot;: &quot;data/system/seattle/scenarios/downtown/monday.bin&quot;, &quot;modifiers&quot;: [], &quot;edits&quot;: 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&amp;t1=03:00:00&amp;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 a string like &quot;Walk&quot; or
&quot;Drive&quot;. If the trip was cancelled for any reason, duration will be null.</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>
<li><strong>GET /data/get-blocked-by-graph</strong>: Returns a mapping from agent IDs to how
long they've been waiting and why they're blocked.</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 &gt; 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>{ &quot;Private&quot;: [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 &gt; 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 &quot;smoke-test&quot; section simulates one hour on all maps, flushing out bugs with
bus spawning, agents hitting odd parts of the map, etc</p>
<p>The &quot;check proposals&quot; 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
&quot;house&quot; 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 &quot;core&quot; 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 &quot;narrow&quot; 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 &quot;city&quot; 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 &quot;flattened&quot; 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 &quot;extra/optional&quot; 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 &quot;way&quot; 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 &quot;trimmed back&quot; to avoid
overlapping, and the &quot;common area&quot; 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 &quot;main&quot; 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 &quot;snap&quot; 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 &quot;aisles.&quot; 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 &quot;parking blackholes.&quot; 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&lt;-&gt;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-&gt;bike or bike-&gt;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 (&quot;only straight&quot; between road1 and
road2)</li>
<li>Try to apply the OSM per-lane restrictions (&quot;straight or left&quot; 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 &quot;blackhole&quot;
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 &quot;blackholes&quot; -- 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 &quot;equivalent position on another lane&quot; 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 &quot;standard libraries&quot; 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 &quot;live&quot; 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 &quot;sidecar&quot; 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 &quot;laggy head&quot;, 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 &quot;ghost&quot; 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 &quot;reserved&quot; 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 &quot;laggy head&quot; 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 &quot;intent&quot; 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>{
&quot;scenario_name&quot;: &quot;monday&quot;,
&quot;people&quot;: [
{
&quot;origin&quot;: {
&quot;Position&quot;: {
&quot;longitude&quot;: -122.303723,
&quot;latitude&quot;: 47.6372834
}
},
&quot;trips&quot;: [
{
&quot;departure&quot;: 10800.0,
&quot;destination&quot;: {
&quot;Position&quot;: {
&quot;longitude&quot;: -122.3075948,
&quot;latitude&quot;: 47.6394773
}
},
&quot;mode&quot;: &quot;Drive&quot;
}
]
}
]
}
</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>
<li><a href="https://github.com/DLR-VF/TAPAS">https://github.com/DLR-VF/TAPAS</a></li>
<li><a href="https://sumo.dlr.de/docs/Demand/Activity-based_Demand_Generation.html">https://sumo.dlr.de/docs/Demand/Activity-based_Demand_Generation.html</a></li>
</ul>
<h1><a class="header" href="#gridlock" id="gridlock">Gridlock</a></h1>
<p>Here &quot;gridlock&quot; 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 &quot;straight&quot;, 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 &gt;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='[{&quot;ChangeMode&quot;:{&quot;to_mode&quot;:&quot;Drive&quot;,&quot;pct_ppl&quot;:100,&quot;departure_filter&quot;:[0.0,86400.0],&quot;from_modes&quot;:[&quot;Bike&quot;]}}]'</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>
<h2><a class="header" href="#spawning-code-overview" id="spawning-code-overview">Spawning code overview</a></h2>
<p>As of November 2020, starting a traffic simulation works like this:</p>
<ol>
<li>Something creates a <code>Scenario</code>, which defines a bunch of people. Each person
has a schedule of trips, carrying them between <code>TripEndpoints</code> via some
<code>TripMode</code>, leaving at some <code>Time</code>.</li>
<li>When a scenario is instantiated, every trip for every person passes through
<code>TripSpec::maybe_new</code>. This transforms the origin, destination, and mode into
a <code>TripSpec</code>.</li>
<li><code>TripSpec::to_plan</code> further validates these and attempts to repair impossible
plans. Each <code>TripSpec</code> is turned into a list of <code>TripLegs</code>. The <code>TripSpec</code> is
then passed to the discrete-event scheduler inside a <code>Command::StartTrip</code>.
This way, <code>TripManager</code> knows about all trips immediately, and at the right
time, each trip can be initiated.</li>
<li>Later, the scheduler gets one of these commands, and calls
<code>TripManager::start_trip</code> with the <code>TripSpec</code>. Each type of trip has its own
initialization logic to kick off the first leg of the trip.</li>
<li>Most trips have multiple legs. When the first car, bike, or pedestrian
reaches their goal, <code>TripManager</code> gets called with some sort of transition
function to initiate the next leg of the trip, or declare the trip finished.
These transition functions also record stats from that leg of the trip, like
total blocked time.</li>
</ol>
<p>What're the different <code>TripSpec</code> cases, and what <code>TripLegs</code> do they get turned
into?</p>
<ul>
<li><code>VehicleAppearing</code>: Starts at a border. Drive, then maybe walk to the
destination building.</li>
<li><code>SpawningFailure</code>: No trip legs; just create and immediately cancel the trip.</li>
<li><code>UsingParkedCar</code>: Starts at a building. Walk (to the parked car), drive, then
maybe walk to the destination building (after parking again).</li>
<li><code>JustWalking</code>: Just walk between two buildings/borders.</li>
<li><code>UsingBike</code>: Starts at a building. Walk to the nearest bikeable lane, drive,
then maybe walk to the destination building. (Note that starting a bike from a
border uses <code>VehicleAppearing</code>.)</li>
<li><code>UsingTransit</code>: Walk, ride the bus, maybe walk again. No transfers yet; only
rides one bus between two stops.</li>
</ul>
<p><code>TripManager</code> has a whole bunch of transition functions:</p>
<ul>
<li><code>car_reached_parking_spot</code>: drive -&gt; walk, unless the destination building is
where we parked</li>
<li><code>ped_reached_parking_spot</code>: walk -&gt; drive</li>
<li><code>ped_ready_to_bike</code>: walk -&gt; bike</li>
<li><code>bike_reached_end</code>: bike -&gt; walk</li>
<li><code>ped_reached_building</code>: walk -&gt; done</li>
<li><code>ped_reached_bus_stop</code>: walk -&gt; wait or ride bus</li>
<li><code>ped_boarded_bus</code>: waiting -&gt; ride bus</li>
<li><code>person_left_bus</code>: riding bus -&gt; walk</li>
<li><code>ped_reached_border</code>: walk -&gt; done</li>
<li><code>transit_rider_reached_border</code>: ride bus -&gt; done</li>
<li><code>car_or_bike_reached_border</code>: drive -&gt; done</li>
</ul>
<p>There are at least a few use cases motivating the cleanup of all of this
structure:</p>
<ul>
<li>Capping trips through congested areas. Sometimes this just changes the driving
route, but sometimes it needs to cancel trips, convert driving trips to
walking/transit, or delay the trip's start.</li>
<li>Multiple public transit rides in a single trip, aka transferring</li>
<li>Handling live map edits in the middle of a trip</li>
</ul>
<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 &quot;Unstreet&quot; or &quot;Superban&quot; (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, &quot;I was really pretty impressed first that
you would be so stupid as to actually try to do this...&quot;</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. &quot;UI churn&quot; is pretty much constantly happening.</p>
<ul>
<li>
<p>June: polyline geometry and lanes, building paths, protobuf -&gt; 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&lt;-&gt;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 &quot;overtime&quot;</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 &quot;blocking the box&quot;</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 &quot;population&quot; overlay, showing people (not just current trips). heatmap and dot map to visualize.</li>
<li>improved the &quot;delay&quot; 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 &quot;traffic jam!&quot; 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 &quot;traffic signal demand&quot; 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 &quot;thought bubble&quot; 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 &quot;faded zoom&quot; 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 &quot;degenerate&quot; intersections</li>
<li>experimenting with filling in gaps between one-way roads, to represent medians</li>
</ul>
<p>0.2.20</p>
<ul>
<li>prototyped a new 15-minute neighborhood tool</li>
<li>overhaul internal simulation input code -- better performance, way simpler</li>
<li>debug tool to record traffic around a few intersections and replay later</li>
</ul>
<p>0.2.21</p>
<ul>
<li>split separate tools into their own executables</li>
<li>misc bug fixes and other refactoring, focused on GUI code mostly</li>
<li>most of a prototype done for an experiment</li>
<li>map added for north seattle</li>
</ul>
<p>0.2.22</p>
<ul>
<li>vehicles will lane-change less erratically during uber-turns (sequences of turns through multiple traffic signals close together)</li>
<li>debug mode has a &quot;blocked-by graph&quot; tool to understand dependencies between waiting agents</li>
<li>try multiple OpenGL video mode options if the first choice fails (thanks Michael!)</li>
<li>refactoring trip starting code and the minimap</li>
<li>non-Latin fonts now supported on web too, thanks to rustybuzz release</li>
<li>new small maps in Seattle included in the release, and NYC added to optional cities</li>
<li>saving some player state on the web (mostly camera position per map, for the main game)</li>
<li>partial prototype of a new census-based scenario generator, thanks to help from the Amazon SSPA hackathon</li>
<li>significant progress on the experiment, about one week left...</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 -&gt; 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>