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
JavaScript
;
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;