AgentMaps/devdocs/routing.js.html
noncomputable f077999706 Updates
2018-08-30 01:28:18 -04:00

239 lines
10 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: routing.js</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">Source: routing.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>//** Here we have utilities to convert OSM geojson data into a distance-weighted graph and find the shortest path between two points. **//
let path = require("ngraph.path"),
createGraph = require("ngraph.graph"),
lineSlice = require('@turf/line-slice').default,
lineDistance = require('@turf/line-distance'),
Agentmap = require('./agentmap').Agentmap;
/**
* Convert a layerGroup of streets into a graph.
* @private
*
* @param {LayerGroup} streets - A Leaflet layerGroup of streets, forming a street network.
* @returns {Object} - A graph representing the street network, operable by the ngraph pathfinder.
*/
function streetsToGraph(streets) {
let graph = createGraph();
//For each street, get an array of indices for the start, intersections, and end coordinates, in order from
//start to end. Then, add the coordinates at each index as a node, and an edge between each adjacent node in the array,
//associating the distance between the nodes (between their coordinates) with each edge.
streets.eachLayer(function(street) {
let street_id = street._leaflet_id,
intersection_indices = [],
street_points = street.getLatLngs();
//Populate intersection_indices with the indices of all of the street's intersections in its coordinate array.
for (let cross_street in street.intersections) {
let intersections = street.intersections[cross_street];
for (let intersection of intersections) {
let intersection_index = intersection[1][street_id];
//Ignore duplicate intersection points (caused by 3-way intersections).
if (!intersection_indices.some(other_intersection_index => other_intersection_index === intersection_index)) {
intersection_indices.push(intersection_index);
}
}
}
//Sort the intersection_indices so that they are in order from the start of the street's coordinate array to the end;
//this is why we're not getting the raw coordinates, but their indices first, so they can be sorted.
intersection_indices = intersection_indices.sort(function(a, b) {
return a - b;
});
//Check if beginning and end points of the street are in the intersection_incides; if not, add them.
if (!intersection_indices.some(intersection_index => intersection_index === 0)) {
intersection_indices.unshift(0);
}
if (!intersection_indices.some(intersection_index => intersection_index === street_points.length - 1)) {
intersection_indices.push(street_points.length - 1);
}
//Make a graph out of segments of the street between the start, intersections, and end of the street,
//so that the nodes are the coordinates of the start, end, and intersection points, and the edges are
//the segments between successive nodes. Each edge is associated with the geographic distance between its nodes.
for (let i = 0; i &lt;= intersection_indices.length - 2; i++) {
let node_a = street_points[intersection_indices[i]],
node_b = street_points[intersection_indices[i + 1]],
a_string = encodeLatLng(node_a),
b_string = encodeLatLng(node_b),
start_coords = L.A.pointToCoordinateArray(node_a),
end_coords = L.A.pointToCoordinateArray(node_b),
segment = lineSlice(start_coords, end_coords, street.toGeoJSON()),
distance = lineDistance(segment);
graph.addLink(a_string, b_string, {
distance: distance,
place: { type: "street",
id: street_id }
});
}
});
return graph;
}
/**
* Given an OSM street network (graph), return an A* pathfinder that can operate on it.
* @private
*
* @param {object} graph - An ngraph graph representing an OSM street network.
* @returns {object} - An A* pathfinder for the graph.
*/
function getPathFinder(graph) {
return path.aStar(graph, {
distance(fromNode, toNode, link) {
return link.data.distance;
}
});
}
/**
* Get a path between two points on a graph.
* @private
*
* @param start_int_lat_lng {LatLng} - The coordinates of the nearest intersection on the same street at the start_lat_lng.
* @param goal_int_lat_lng {LatLng} - The coordinates of the nearest intersection on the same street as the goal_lat_lng.
* @param start_lat_lng {LatLng} - The coordinates of the point on the street from which the agent will be traveling.
* @param goal_lat_lng {LatLng} - The coordinates of the point on the street to which the agent should travel.
* @param {Boolean} [sparse=false] - Whether to exclude intersections between the first and last along a street-specific path (which are superfluous for extracting the necessary sub-street).
* @return {Array&lt;Array&lt;number>>} - An array of points along the graph, leading from the start to the end.
*/
function getPath(start_int_lat_lng, goal_int_lat_lng, start_lat_lng, goal_lat_lng, sparse = false) {
let start_coord = encodeLatLng(start_int_lat_lng),
end_coord = encodeLatLng(goal_int_lat_lng),
encoded_path = this.pathfinder.find(start_coord, end_coord),
path = [];
if (encoded_path.length > 0 &amp;&amp; decodeCoordString(encoded_path[0].id).distanceTo(start_int_lat_lng) >
decodeCoordString(encoded_path[0].id).distanceTo(goal_int_lat_lng)) {
encoded_path = encoded_path.reverse();
}
if (sparse === true &amp;&amp; encoded_path.length >= 2) {
let sparse_path = [],
recent_street = null,
current_street = null;
for (let i = 0; i &lt;= encoded_path.length - 2; i++) {
current_street = this.streets.graph.getLink(encoded_path[i].id, encoded_path[i + 1].id) ||
this.streets.graph.getLink(encoded_path[i + 1].id, encoded_path[i].id);
if (recent_street === null || current_street.data.place.id !== recent_street.data.place.id) {
let decoded_coords = decodeCoordString(encoded_path[i].id, current_street.data.place);
sparse_path.push(decoded_coords);
}
//If the last place on the path to the goal is labeled with a different street id than the goal,
//add it to the sparse path.
if (i === encoded_path.length - 2 &amp;&amp; goal_lat_lng.new_place.id !== encoded_path[i + 1]) {
let decoded_coords = decodeCoordString(encoded_path[i + 1].id, current_street.data.place);
sparse_path.push(decoded_coords);
}
}
path = sparse_path;
}
else {
path = encoded_path.map(point => decodeCoordString(point.id, 0));
}
path.unshift(start_lat_lng);
path.push(goal_lat_lng);
//If the goal point lies before the first intersection of the goal street, then the 2nd to last point in the
//path will have the previous street's id attached to it. If the goal lies on a different street, make
//sure the 2nd to last point (the street path intersection point before the goal) has the same street id as the goal.
if (path[path.length - 2].new_place.id !== goal_lat_lng.new_place.id) {
path[path.length - 2].new_place = goal_lat_lng.new_place;
}
return path;
}
/**
* Turn a LatLng object into a string representing its coordinates (to act as a graph node's ID).
* @private
*
* @param {LatLng} lat_lng - The coordinates to encode into a string.
* @returns {string} - A string containing coordinates in the format of "Latitude,Longitude".
*/
function encodeLatLng(lat_lng) {
return lat_lng.lat.toString() + "," + lat_lng.lng.toString();
}
/**
* Turn a string containing coordinates (a graph node's ID) into a LatLng object.
* @private
*
* @param {string} coord_string - A string containing coordinates in the format of "Latitude,Longitude".
* @param {object} place - An object specifying the place of the coordinate string.
* @returns {LatLng} - The coordinates encoded by the coord_string.
*/
function decodeCoordString(coord_string, place) {
let coord_strings = coord_string.split(","),
lat_lng = L.latLng(coord_strings);
lat_lng.new_place = place;
return lat_lng;
}
Agentmap.prototype.getPath = getPath;
exports.streetsToGraph = streetsToGraph;
exports.getPathFinder = getPathFinder;
exports.encodeLatLng = encodeLatLng;
</code></pre>
</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#addStreetLayerIntersections">addStreetLayerIntersections</a></li><li><a href="global.html#agent">agent</a></li><li><a href="global.html#agentmap">agentmap</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#getUnitNeighborLayerIDs">getUnitNeighborLayerIDs</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#setupStreetFeatures">setupStreetFeatures</a></li><li><a href="global.html#setupUnitFeatures">setupUnitFeatures</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 Thu Aug 30 2018 01:00:03 GMT-0400 (Eastern Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>