UNPKG

geographic-math

Version:
51 lines (40 loc) 2.09 kB
const getAngle = (center, { lat, lon }) => Math.atan2(lon - center.lon, lat - center.lat); const getCenter = (polygon) => { const sum = polygon.reduce((acc, { lat, lon }) => ({ lat: acc.lat + lat, lon: acc.lon + lon }), { lat: 0, lon: 0 }); return { lat: sum.lat / polygon.length, lon: sum.lon / polygon.length }; }; const getCartesianDistance = ({ lat: latTarget, lon: lonTarget }, { lat, lon }) => Math.sqrt( (lat - latTarget) * (lat - latTarget) + (lon - lonTarget) * (lon - lonTarget) ); const getLine = ({ lat: lat1, lon: lon1 }, { lat: lat2, lon: lon2 }) => ([ lon1 - lon2, lat2 - lat1, lat1 * lon2 - lat2 * lon1, ]); const getLinesIntersection = ([a1, b1, c1], [a2, b2, c2]) => ({ lat: -1 * (c1 * b2 - c2 * b1) / (a1 * b2 - a2 * b1), lon: -1 * (a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1), }); const getNeighbours = (targetAngle, coordinates) => { const biggerIndex = coordinates.findIndex(({ angle }) => angle > targetAngle); return [coordinates[(biggerIndex - 1 + coordinates.length) % coordinates.length], coordinates[biggerIndex]]; }; const getDistance = ({ lat: lat1, lon: lon1 }, { lat: lat2, lon: lon2 }) => { const denominator = 57.2958; const x = Math.sin(lat1 / denominator) * Math.sin(lat2 / denominator) + Math.cos(lat1 / denominator) * Math.cos(lat2 / denominator) * Math.cos((lon2 - lon1) / denominator); return 3958.75 * Math.atan(Math.sqrt(1 - x * x) / x) * 1.609; }; const isInside = (position, polygon) => { const center = getCenter(polygon); const coordinates = polygon.map(position => Object.assign({}, position, { angle: getAngle(center, position)})); coordinates.sort(({ angle: angleA }, { angle: angleB }) => angleA - angleB); const neighbours = getNeighbours(getAngle(center, position), coordinates); const intersection = getLinesIntersection(getLine(center, position), getLine(neighbours[0], neighbours[1])); return getCartesianDistance(center, intersection) >= getCartesianDistance(center, position); }; module.exports = { getDistance, isInside, };