123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- 'use strict';
- var invariant = require('@turf/invariant');
- var helpers = require('@turf/helpers');
- var calcBbox = require('@turf/bbox');
- var explode = require('@turf/explode');
- var nearestPoint = require('@turf/nearest-point');
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
- var calcBbox__default = /*#__PURE__*/_interopDefaultLegacy(calcBbox);
- var explode__default = /*#__PURE__*/_interopDefaultLegacy(explode);
- var nearestPoint__default = /*#__PURE__*/_interopDefaultLegacy(nearestPoint);
- /**
- * Finds the tangents of a {@link Polygon|(Multi)Polygon} from a {@link Point}.
- *
- * @name polygonTangents
- * @param {Coord} pt to calculate the tangent points from
- * @param {Feature<Polygon|MultiPolygon>} polygon to get tangents from
- * @returns {FeatureCollection<Point>} Feature Collection containing the two tangent points
- * @example
- * var polygon = turf.polygon([[[11, 0], [22, 4], [31, 0], [31, 11], [21, 15], [11, 11], [11, 0]]]);
- * var point = turf.point([61, 5]);
- *
- * var tangents = turf.polygonTangents(point, polygon)
- *
- * //addToMap
- * var addToMap = [tangents, point, polygon];
- */
- function polygonTangents(pt, polygon) {
- var pointCoords = invariant.getCoords(pt);
- var polyCoords = invariant.getCoords(polygon);
- var rtan;
- var ltan;
- var enext;
- var eprev;
- var bbox = calcBbox__default['default'](polygon);
- var nearestPtIndex = 0;
- var nearest = null;
- // If the point lies inside the polygon bbox then we need to be a bit trickier
- // otherwise points lying inside reflex angles on concave polys can have issues
- if (
- pointCoords[0] > bbox[0] &&
- pointCoords[0] < bbox[2] &&
- pointCoords[1] > bbox[1] &&
- pointCoords[1] < bbox[3]
- ) {
- nearest = nearestPoint__default['default'](pt, explode__default['default'](polygon));
- nearestPtIndex = nearest.properties.featureIndex;
- }
- var type = invariant.getType(polygon);
- switch (type) {
- case "Polygon":
- rtan = polyCoords[0][nearestPtIndex];
- ltan = polyCoords[0][0];
- if (nearest !== null) {
- if (nearest.geometry.coordinates[1] < pointCoords[1])
- ltan = polyCoords[0][nearestPtIndex];
- }
- eprev = isLeft(
- polyCoords[0][0],
- polyCoords[0][polyCoords[0].length - 1],
- pointCoords
- );
- var out = processPolygon(
- polyCoords[0],
- pointCoords,
- eprev,
- enext,
- rtan,
- ltan);
- rtan = out[0];
- ltan = out[1];
- break;
- case "MultiPolygon":
- var closestFeature = 0;
- var closestVertex = 0;
- var verticesCounted = 0;
- for (var i = 0; i < polyCoords[0].length; i++) {
- closestFeature = i;
- var verticeFound = false;
- for (var i2 = 0; i2 < polyCoords[0][i].length; i2++) {
- closestVertex = i2;
- if (verticesCounted === nearestPtIndex) {
- verticeFound = true;
- break;
- }
- verticesCounted++;
- }
- if (verticeFound) break;
- }
- rtan = polyCoords[0][closestFeature][closestVertex];
- ltan = polyCoords[0][closestFeature][closestVertex];
- eprev = isLeft(
- polyCoords[0][0][0],
- polyCoords[0][0][polyCoords[0][0].length - 1],
- pointCoords
- );
- polyCoords.forEach(function (ring) {
- var out = processPolygon(
- ring[0],
- pointCoords,
- eprev,
- enext,
- rtan,
- ltan);
- rtan = out[0];
- ltan = out[1];
- });
- break;
- }
- return helpers.featureCollection([helpers.point(rtan), helpers.point(ltan)]);
- }
- function processPolygon(polygonCoords, ptCoords, eprev, enext, rtan, ltan) {
- for (var i = 0; i < polygonCoords.length; i++) {
- var currentCoords = polygonCoords[i];
- var nextCoordPair = polygonCoords[i + 1];
- if (i === polygonCoords.length - 1) {
- nextCoordPair = polygonCoords[0];
- }
- enext = isLeft(currentCoords, nextCoordPair, ptCoords);
- if (eprev <= 0 && enext > 0) {
- if (!isBelow(ptCoords, currentCoords, rtan)) {
- rtan = currentCoords;
- }
- } else if (eprev > 0 && enext <= 0) {
- if (!isAbove(ptCoords, currentCoords, ltan)) {
- ltan = currentCoords;
- }
- }
- eprev = enext;
- }
- return [rtan, ltan];
- }
- function isAbove(point1, point2, point3) {
- return isLeft(point1, point2, point3) > 0;
- }
- function isBelow(point1, point2, point3) {
- return isLeft(point1, point2, point3) < 0;
- }
- function isLeft(point1, point2, point3) {
- return (
- (point2[0] - point1[0]) * (point3[1] - point1[1]) -
- (point3[0] - point1[0]) * (point2[1] - point1[1])
- );
- }
- module.exports = polygonTangents;
- module.exports.default = polygonTangents;
|