UNPKG

atriusmaps-node-sdk

Version:

This project provides an API to Atrius Personal Wayfinder maps within a Node environment. See the README.md for more information

150 lines (144 loc) 5.44 kB
'use strict'; var area = require('@turf/area'); var bboxClip = require('@turf/bbox-clip'); var bboxPolygon = require('@turf/bbox-polygon'); var helpers = require('@turf/helpers'); require('@turf/point-to-line-distance'); var R = require('ramda'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var R__namespace = /*#__PURE__*/_interopNamespaceDefault(R); const pointInPolygon = (point, vs) => { const x = point[0]; const y = point[1]; let inside = false; for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) { const xi = vs[i][0]; const yi = vs[i][1]; const xj = vs[j][0]; const yj = vs[j][1]; const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi; if (intersect) { inside = !inside; } } return inside; }; const bounds2Coords = ({ n, s, e, w }) => [ [n, e], [n, w], [s, w], [s, e], [n, e] ]; const NULL_STRUCTURE_AND_FLOOR = { structure: null, floor: null }; function getStructureAndFloorAtPoint(structures, lat, lng, ord, mapviewBBox, preciseFlag = false) { if (!R__namespace.length(structures)) { return NULL_STRUCTURE_AND_FLOOR; } structures = structures.filter((s) => s.shouldDisplay == null || s.shouldDisplay === true); const floorsToConsider = structures.map((structure) => ({ structure, floor: ordToFloor(structure, ord) })); return getStructureAndFloorWithinFloorsAtPoint(structures, floorsToConsider, lat, lng, mapviewBBox, preciseFlag); } function getStructureAndFloorWithinFloorsAtPoint(structures, floorsToConsider, lat, lng, mapviewBBox, preciseFlag) { const pointWithinFloorsBBox = floorsToConsider.filter((ftc) => ftc.floor).filter((ftc) => pointInPolygon([lat, lng], bounds2Coords(ftc.floor.bounds))); if (preciseFlag) { if (pointWithinFloorsBBox.length === 0) { return NULL_STRUCTURE_AND_FLOOR; } const floorsWithinBoundsPolygon = pointWithinFloorsBBox.filter( (ftc) => pointInPolygon([lat, lng], ftc.floor.boundsPolygon) ); if (floorsWithinBoundsPolygon.length >= 1) { return R__namespace.head(floorsWithinBoundsPolygon); } return NULL_STRUCTURE_AND_FLOOR; } if (pointWithinFloorsBBox.length === 0) { const floorsWithinBuildingBoundingBox = structures.filter((structure) => pointInPolygon([lat, lng], bounds2Coords(structure.bounds))).map((structure) => ({ structure, floor: null })); if (floorsWithinBuildingBoundingBox.length >= 1) { return floorsWithinBuildingBoundingBox[0]; } return NULL_STRUCTURE_AND_FLOOR; } if (pointWithinFloorsBBox.length === 1) { return pointWithinFloorsBBox[0]; } const floorsContainingPoint = pointWithinFloorsBBox.filter( (ftc) => pointInPolygon([lat, lng], ftc.floor.boundsPolygon) ); const prominenceScores = pointWithinFloorsBBox.map( (ftc) => prominence( ftc, mapviewBBox, floorsContainingPoint.some((fcp) => fcp.floor.id === ftc.floor.id) ) ); const bestScore = Math.max.apply(null, prominenceScores); return pointWithinFloorsBBox[prominenceScores.indexOf(bestScore)]; } function prominence({ floor }, mapviewBBox, pointWithinFloorPoly) { const floorPolygon = coords2Poly(floor.boundsPolygon); const mapviewBBoxPoly = bboxPolygon.bboxPolygon(mapviewBBox); const viewableFloorPoly = bboxClip.bboxClip(floorPolygon, mapviewBBox); const floorArea = area.area(viewableFloorPoly); const viewableMapArea = area.area(mapviewBBoxPoly); return floorArea * (pointWithinFloorPoly ? 150 : 100) / viewableMapArea; } const latLngSwap = (point) => [point[1], point[0]]; const coords2Poly = (coords) => helpers.polygon([coords.map(latLngSwap)]); const ordToFloor = (building, ord) => Object.values(building.levels).find((floor) => floor.ordinal === ord); const getFloor = (structures, selectedLevelId) => structures.reduce( (fmatch, building) => Object.values(building.levels).find((floor) => floor.id === selectedLevelId) || fmatch, void 0 ); const getStructureForFloorId = (structures, floorId) => structures.reduce( (sMatch, structure) => buildContainsFloorWithId(structure, floorId) ? structure : sMatch, null ); const buildContainsFloorWithId = (building, floorId) => Object.values(building.levels).reduce((fmatch, floor) => floor.id === floorId ? true : fmatch, false); function bezierCurveTo(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY) { const n = 20; let dt = 0; let dt2 = 0; let dt3 = 0; let t2 = 0; let t3 = 0; const path = [{ x: fromX, y: fromY }]; for (let i = 1, j = 0; i <= n; ++i) { j = i / n; dt = 1 - j; dt2 = dt * dt; dt3 = dt2 * dt; t2 = j * j; t3 = t2 * j; path.push({ x: dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX, y: dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY }); } return path; } exports.bezierCurveTo = bezierCurveTo; exports.getFloor = getFloor; exports.getStructureAndFloorAtPoint = getStructureAndFloorAtPoint; exports.getStructureForFloorId = getStructureForFloorId; exports.ordToFloor = ordToFloor; exports.pointInPolygon = pointInPolygon;