UNPKG

ridematcher

Version:
183 lines (145 loc) 6.28 kB
'use strict'; var _Promise = require('babel-runtime/core-js/promise')['default']; var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default']; Object.defineProperty(exports, '__esModule', { value: true }); exports.findMatches = findMatches; exports.findRidepoolMatches = findRidepoolMatches; var _rbush = require('rbush'); var _rbush2 = _interopRequireDefault(_rbush); var _turfDestination = require('turf-destination'); var _turfDestination2 = _interopRequireDefault(_turfDestination); var _turfDistance = require('turf-distance'); var _turfDistance2 = _interopRequireDefault(_turfDistance); var _turfPoint = require('turf-point'); var _turfPoint2 = _interopRequireDefault(_turfPoint); /** * Compute the number of potential carpool matches within a commuter population. * * @param {Array} commuters Array of commuters to match to each other * @param {Object} opts Options object * @returns {Promise} promise * @example * import {findMatches} from 'ridematcher' * findMatches({ * commuters: [{ * _id: 1, * from: [-77.4875, 39.0436], * to: [..] * }], { * radius: .5, * units: 'miles' * }}).then((matches) => { * console.log(matches) // map of commuter id's to matching commuter id's * }, handleError) */ function findMatches(commuters) { var opts = arguments[1] === undefined ? {} : arguments[1]; return new _Promise(function (resolve, reject) { if (!commuters) return reject('No commuters.'); var tree = (0, _rbush2['default'])(); tree.load(commuters.map(function (c) { var to = c.to || c.from; return [c.from[0], c.from[1], to[0], to[1], c]; })); var responses = {}; var RADIUS = opts.radius || 0.25; var DIST = RADIUS * Math.sqrt(2); var UNITS = opts.units || 'miles'; commuters.forEach(function (commuter) { var fromPoint = (0, _turfPoint2['default'])(commuter.from); // construct bbox var bottomLeft = (0, _turfDestination2['default'])(fromPoint, DIST, -135, UNITS); var topRight = (0, _turfDestination2['default'])(fromPoint, DIST, 45, UNITS); // do the initial bbox search var results = tree.search(bottomLeft.geometry.coordinates.concat(topRight.geometry.coordinates)); // filter the matches var matches = results.reduce(function (matches, result) { var match = result[4]._id; var matchPoint = (0, _turfPoint2['default'])([result[0], result[1]]); // ignore self match if (match === commuter._id) return matches; // ignore matches where distance exceeds search radius var distance = (0, _turfDistance2['default'])(fromPoint, matchPoint, UNITS); if (distance > RADIUS) return matches; matches.push({ _id: match, distance: distance }); return matches; }, []); responses[commuter._id] = matches; }); resolve(responses); }); } /** * Find matches for a single commute against a set of car/vanpools * * @param {Array} from Search origin lng/lat * @param {Array} to Search destination lng/lat * @param {Array} ridepools Array of car/vanpools to match against * @param {Object} opts Options object * @returns {Promise} promise * @example * import {findRidepoolMatches} from 'ridematcher' * findMatches( * from: [-77.4875, 39.0436], * to: [..], * ridepools: [{ * _id: 1, * from: [-77.4875, 39.0436], * to: [..] * }], { * radius: .5, * units: 'miles' * }}).then((matches) => { * console.log(matches) // map of commuter id's to matching commuter id's * }, handleError) */ function findRidepoolMatches(from, to, ridepools) { var opts = arguments[3] === undefined ? {} : arguments[3]; return new _Promise(function (resolve, reject) { if (!ridepools) return reject('No ridepools.'); var fromTree = (0, _rbush2['default'])(); fromTree.load(ridepools.map(function (r) { return [r.from[0], r.from[1], r.from[0], r.from[1], r]; })); var toTree = (0, _rbush2['default'])(); toTree.load(ridepools.map(function (r) { return [r.to[0], r.to[1], r.to[0], r.to[1], r]; })); var responses = {}; var RADIUS = opts.radius || 0.25; var DIST = RADIUS * Math.sqrt(2); var UNITS = opts.units || 'miles'; var fromPoint = (0, _turfPoint2['default'])(from); var toPoint = (0, _turfPoint2['default'])(to); // find the pools matching the 'from' search point var fromBottomLeft = (0, _turfDestination2['default'])(fromPoint, DIST, -135, UNITS); var fromTopRight = (0, _turfDestination2['default'])(fromPoint, DIST, 45, UNITS); var s = fromBottomLeft.geometry.coordinates.concat(fromTopRight.geometry.coordinates); var fromMatches = fromTree.search(s); fromMatches = fromMatches.filter(function (match) { var distance = (0, _turfDistance2['default'])(fromPoint, (0, _turfPoint2['default'])([match[0], match[1]]), UNITS); return distance <= RADIUS; }).map(function (match) { return match[4]; }); // find the pools matching the 'to' search point var toBottomLeft = (0, _turfDestination2['default'])(toPoint, DIST, -135, UNITS); var toTopRight = (0, _turfDestination2['default'])(toPoint, DIST, 45, UNITS); var toMatches = toTree.search(toBottomLeft.geometry.coordinates.concat(toTopRight.geometry.coordinates)); toMatches = toMatches.filter(function (match) { var distance = (0, _turfDistance2['default'])(toPoint, (0, _turfPoint2['default'])([match[0], match[1]]), UNITS); return distance <= RADIUS; }).map(function (match) { return match[4]; }); // return the intersection of the two match sets resolve(fromMatches.filter(function (n) { return toMatches.indexOf(n) != -1; })); }); }