AgentMaps/devdocs/index.html
noncomputable ac63cd6b0a Updates
2018-08-01 23:39:04 -04:00

210 lines
15 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Home</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Home</h1>
<h3> </h3>
<section>
<article><h1>AgentMaps - Simulate Societies on Web Maps</h1><p>AgentMaps is a Javascript framework for building and visualizing geospatial agent-based simulations.
It is based on the <a href="https://leafletjs.com/">Leaflet</a> interactive mapping <a href="https://github.com/Leaflet/Leaflet">library</a> and functions as an extension of it.
Given some information about a neighborhood, like a pair of points containing it and <a href="http://geojson.org/">GeoJSON</a> data representing its streets,
AgentMaps lets you quickly and easily do the following:</p>
<ul>
<li>Generate buildings (&quot;units&quot;) along the streets.</li>
<li>Inspect and navigate between buildings and streets.</li>
<li>Generate agents and embed them into the map in a custom way.</li>
<li>Schedule agents to move between units and streets (&quot;places&quot;).</li>
<li>Track the time and control the state of the simulation.</li>
</ul>
<p>In short, it's something like a bare-bones SimCity generator.</p>
<h4>Table of Contents</h4><p><a href="#prerequisites">Prerequisites</a></p>
<p><a href="#basic-walkthrough">Basic Walkthrough</a></p>
<p><a href="#documentation">Documentation</a></p>
<p><a href="#demos">Demos</a></p>
<p><a href="#feature-wishlist">Feature Wishlist</a></p>
<p><a href="#authors">Authors</a></p>
<p><a href="#acknowledgements">Acknowledgements</a></p>
<h1>Getting Started</h1><h2>Prerequisites<a name="prerequisites"></h2><p>First of all, you can find a bundle for AgentMaps here: <a href="https://unpkg.com/agentmaps@1/dist/agentmaps.js">https://unpkg.com/agentmaps@1/dist/agentmaps.js</a>.</p>
<p>Making simulations with AgentMaps will be a lot easier for you if you have a good understanding of the following:</p>
<ul>
<li>Basic Javascript!</li>
<li>Using <a href="https://leafletjs.com/">Leaflet</a></li>
</ul>
<p>Leaflet doesn't come bundled with AgentMaps, so you'll have to either include it in your web page with its own \&lt;script> tag or
install it with <a href="https://www.npmjs.com/package/leaflet">npm</a>. Everything in AgentMaps exists within Leaflet's L namespace as L.A,
so AgentMaps classes and functions are accessed with L.A.ClassName and L.A.functionName repsectively.</p>
<p>It might also help you to be familiar with <a href="http://turfjs.org/">turf.js</a>, a library that contains lots of tools which make geospatial computations (like intersection detection and line slicing) quick and easy.</p>
<p>AgentMaps expects geographic data in the form of <a href="http://geojson.org/">GeoJSON</a>, a data format for representing geospatial information,
so it might be useful to take a look at that. You don't really need to handle GeoJSON directly to use AgentMaps, though.</p>
<p>How do you get the GeoJSON data of some neighborhood you're interested in? I use <a href="https://www.openstreetmap.org/">OpenStreetMap</a> (OSM),
a free, collaborative map of the world! You can get a JSON file by using the &quot;export&quot; tool on the OSM website;
you can also use it to get the coordinates of the two points bounding your neighborhood.</p>
<p>All of the above is pretty important to be able to contribute to AgentMaps or understand its internal implementation as well.</p>
<h2>Basic Walkthrough<a name="basic-walkthrough"></h2><p>Here, we'll walk through building a simple AgentMaps simulation. I suggest looking at the detailed <a href="#documentations">documentation</a> for
all of the AgentMaps functions and classes used here to get a better understanding of how they work, what kinds of input they expect, and
what you can expect them to do in response. If you're not so familiar with Leaflet, I suggest doing the same with the <a href="https://leafletjs.com/reference-1.3.2.html">Leaflet docs</a>.</p>
<p>Create an HTML document that loads the Leaflet stylesheet and script, contains a \&lt;div> in which to insert the Leaflet map, and
loads AgentMaps at the end:</p>
<pre class="prettyprint source lang-HTML"><code>&lt;!DOCTYPE HTML>
&lt;html>
&lt;head>
&lt;link rel=&quot;stylesheet&quot; href=&quot;leaflet_style.css&quot;>
&lt;script src=&quot;leaflet_script.js&quot;>&lt;/script>
&lt;/head>
&lt;body>
&lt;div id=&quot;demo_map&quot; style=&quot;height:400px&quot;>&lt;/div>
&lt;script src=&quot;agentmaps.js&quot;>&lt;/script>
&lt;/body>
&lt;/html></code></pre><p>Assume we have the GeoJSON of a neighborhood stored in a variable like this, where the ellipses stand in for a list of map features (like streets):</p>
<pre class="prettyprint source lang-javascript"><code>let map_data = {
&quot;type&quot;: &quot;FeatureCollection&quot;,
&quot;features&quot;: [
...
...
...
]
};</code></pre><p>Have the two corners of a rectangle containing the neighborhood of interest stored as an array of their coordinates, [longitude, latitude]:</p>
<pre class="prettyprint source lang-javascript"><code>let bounding_points = [[43.3071, -88.0158], [43.2884, -87.9759]];</code></pre><p>Create a Leaflet map in the demo_map \&lt;div> of our HTML document:</p>
<pre class="prettyprint source lang-javascript"><code>let map = L.map(&quot;demo_map&quot;).fitBounds(bounding_points);</code></pre><p>The map will be empty, so tile it with OpenStreetMap's map tiles to see what's where:</p>
<pre class="prettyprint source lang-javascript"><code>L.tileLayer(
&quot;http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png&quot;,
{
attribution: &quot;Thanks to &lt;a href=\&quot;http://openstreetmap.org\&quot;>OpenStreetMap&lt;/a> community&quot;,
}
).addTo(map);</code></pre><p>Now that we have our map in place and the geographic data for our neighborhood in hand, create an Agentmap from the map:</p>
<pre class="prettyprint source lang-javascript"><code>let agentmap = L.A.agentmap(map);</code></pre><p>Now generate buildings and functional roads on the map based on that geographic data:</p>
<pre class="prettyprint source lang-javascript"><code>agentmap.buildingify(map_data, bounding_points);</code></pre><p>Now you can spawn agents onto the map according to the rules of a custom agentFeatureMaker function. We'll use the built-in seqUnitAgentMaker,
which just assigns a number to each agent it generates in sequence, counting up from 0 to the number of agents you want, and placing each agent
in the center of the unit whose ID is the corresponding number. We'll make 50:</p>
<pre class="prettyprint source lang-javascript"><code>agentmap.agentify(50, agentmap.seqUnitAgentMaker, {radius: .5, color: &quot;red&quot;, fillColor: &quot;red&quot;});</code></pre><p>The Agentmap simulation will start once we call <code>agentmap.run()</code>. From then on, its operation is divided up into consecutive &quot;ticks&quot;.
At each tick, each agent moves further along its scheduled path (for now, we haven't scheduled anything for our agents) and the agentmap
runs the <code>agentmap.update_func()</code> that we can define (we we haven't done yet).
The ticks are identified by a number, starting from 0, and each next tick is 1 greater.
The tick at any point in the simulation is set in <code>agentmap.state.ticks</code> and it functions as a kind of clock.
We can call <code>agentmap.pause()</code> to stop the simulation, during which the ticks elapsed won't change, and then <code>agentmap.run()</code> to continue it.</p>
<p>So, let's define an update function:</p>
<pre class="prettyprint source lang-javascript"><code>agentmap.update_func = function() {
};</code></pre><p>What do we want to do on each tick? That is, what will we put in the function body?
A simple simulation might involve the agents moving to a random unit every 300 ticks.</p>
<p>So first, we will have the update_func check if the current number of ticks is a multiple of 300,
as we only want to do anything every 300 ticks:</p>
<pre class="prettyprint source lang-javascript"><code>if (agentmap.state.ticks % 300 === 0) {
}</code></pre><p>Then, if the tick is a multiple of 300, we want to tell each agent to do something,
so we will set up a loop that goes through and operates on each agent:</p>
<pre class="prettyprint source lang-javascript"><code>agentmap.agents.eachLayer(function(agent) {
}</code></pre><p>Now, for each agent, we'll generate a random number between 0 and the greatest unit index and
store the unit with that index, its ID, and the coordinates of its center:</p>
<pre class="prettyprint source lang-javascript"><code>let random_index = Math.floor(agentmap.units.count() * Math.random()),
random_unit = agentmap.units.getLayers()[random_index],
random_unit_id = agentmap.units.getLayerId(random_unit),
random_unit_center = random_unit.getBounds().getCenter();</code></pre><p>Then we will tell the agent to stop whatever it's doing and start traveling to that unit's center:</p>
<pre class="prettyprint source lang-javascript"><code>agent.setTravelToPlace(random_unit_center, {&quot;unit&quot;: random_unit_id}, true);
agent.startTrip();</code></pre><p>Altogether, our update_func will look like this:</p>
<pre class="prettyprint source lang-javascript"><code>agentmap.update_func = function() {
if (agentmap.state.ticks % 300 === 0) {
agentmap.agents.eachLayer(function(agent) {
let random_index = Math.floor(agentmap.units.count() * Math.random()),
random_unit = agentmap.units.getLayers()[random_index],
random_unit_id = agentmap.units.getLayerId(random_unit),
random_unit_center = random_unit.getBounds().getCenter();
agent.setTravelToPlace(random_unit_center, {&quot;unit&quot;: random_unit_id}, true);
agent.startTrip();
}
}
}</code></pre><p>Finally, now that we've got our Agentmap in place, buildings and agents loaded, and update_func defined, we can add:</p>
<pre class="prettyprint source lang-javascript"><code>agentmap.run();</code></pre><p>Once we load our HTML document, the simulation should begin and we can watch our agents moving about the neighborhood.</p>
<h2>Documentation<a name="documentation"></h2><p>Documentation for all the necessary features for people who want to use AgentMaps is available at <a href="https://noncomputable.github.io/AgentMaps/docs/index.html">https://noncomputable.github.io/AgentMaps/docs/index.html</a>.</p>
<p>Documentation for people who want to contribute to AgentMaps or understand its internals is available here <a href="https://noncomputable.github.io/AgentMaps/devdocs/index.html">https://noncomputable.github.io/AgentMaps/devdocs/index.html</a>.</p>
<h2>Demos<a name="demos"></h2><p>You can find a slightly more substantial demonstration of AgentMaps live <a href="https://noncomputable.github.io/AgentMaps/demos/epidemic/epidemic.html">here</a>.
You can find the corresponding code under /demos/epidemic/ in the gh-pages branch <a href="https://github.com/noncomputable/AgentMaps/tree/gh-pages/demos/epidemic">here</a>.</p>
<h1>Feature Wishlist<a name="feature-wishlist"></h1><p>I've been stuffed with other work, so it'd be really cool if anyone wants to come along and help make AgentMaps better and more useful.
Here are some things I think would be great for AgentMaps to have. If you add them before I do, I'll credit your name next to them.</p>
<ul>
<li>Sidewalks: streets and sidewalks should be divided and made into distinct places that agents can distinguish and navigate between.</li>
<li>Architectural Variety: buildings vary in size, dimension, and shape a lot--they're not all identical rectangles. Users should be able
to specify these customizations and AgentMaps should be able to generate and embed them appropriately.<ul>
<li>For example, what if the GeoJSON the user provides contains a big park? The street parallel to it probably shouldn't be dotted with normal sized units--it should probably be one big unit itself!</li>
</ul>
</li>
<li>Urban Development: buildings, streets, and sidewalks change! Users should be able to easily specify these changes and AgentMaps should be able to
incorporate them coherently.</li>
<li>Optimization: <ul>
<li>Make utilities for running spatial computations on agents and buildings faster. Otherwise users may tend to default to naive implementations that hinder them from be able to do what they want to do. </li>
</ul>
</li>
</ul>
<h1>Authors<a name="authors"></h1><ul>
<li>Andrew - Came up with AgentMaps.</li>
</ul>
<h1>Acknowledgements<a name="acknowledgements"></h1><p>I've only had a few extended conversations which involved me talking and thinking about this project outloud over the last few months, and those probably influenced how I went forward with it. The people I've had those discussions with are:</p>
<ul>
<li>I. (&quot;Wheels&quot;) Errati</li>
<li>G. (&quot;help me fix gh-pages&quot;) Jello</li>
<li>M. Singh</li>
</ul>
<p>Thank you to anyone who somehow benefits from this.</p></article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Agent.html">Agent</a></li><li><a href="Agentmap.html">Agentmap</a></li></ul><h3>Global</h3><ul><li><a href="global.html#agentify">agentify</a></li><li><a href="global.html#agentmap">agentmap</a></li><li><a href="global.html#buildingify">buildingify</a></li><li><a href="global.html#decodeCoordString">decodeCoordString</a></li><li><a href="global.html#encodeLatLng">encodeLatLng</a></li><li><a href="global.html#generateUnitFeatures">generateUnitFeatures</a></li><li><a href="global.html#getIntersections">getIntersections</a></li><li><a href="global.html#getPath">getPath</a></li><li><a href="global.html#getPathFinder">getPathFinder</a></li><li><a href="global.html#getStreetFeatures">getStreetFeatures</a></li><li><a href="global.html#getUnitAnchors">getUnitAnchors</a></li><li><a href="global.html#getUnitFeatures">getUnitFeatures</a></li><li><a href="global.html#isPointCoordinates">isPointCoordinates</a></li><li><a href="global.html#noOverlaps">noOverlaps</a></li><li><a href="global.html#pointToCoordinateArray">pointToCoordinateArray</a></li><li><a href="global.html#reversedCoordinates">reversedCoordinates</a></li><li><a href="global.html#streetsToGraph">streetsToGraph</a></li><li><a href="global.html#unitsOutOfStreets">unitsOutOfStreets</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Wed Aug 01 2018 23:38:55 GMT-0400 (Eastern Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>