Node-Red configuration
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

polygonContains.js 2.7KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import {Adder} from "d3-array";
  2. import {cartesian, cartesianCross, cartesianNormalizeInPlace} from "./cartesian.js";
  3. import {abs, asin, atan2, cos, epsilon, epsilon2, halfPi, pi, quarterPi, sign, sin, tau} from "./math.js";
  4. function longitude(point) {
  5. return abs(point[0]) <= pi ? point[0] : sign(point[0]) * ((abs(point[0]) + pi) % tau - pi);
  6. }
  7. export default function(polygon, point) {
  8. var lambda = longitude(point),
  9. phi = point[1],
  10. sinPhi = sin(phi),
  11. normal = [sin(lambda), -cos(lambda), 0],
  12. angle = 0,
  13. winding = 0;
  14. var sum = new Adder();
  15. if (sinPhi === 1) phi = halfPi + epsilon;
  16. else if (sinPhi === -1) phi = -halfPi - epsilon;
  17. for (var i = 0, n = polygon.length; i < n; ++i) {
  18. if (!(m = (ring = polygon[i]).length)) continue;
  19. var ring,
  20. m,
  21. point0 = ring[m - 1],
  22. lambda0 = longitude(point0),
  23. phi0 = point0[1] / 2 + quarterPi,
  24. sinPhi0 = sin(phi0),
  25. cosPhi0 = cos(phi0);
  26. for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
  27. var point1 = ring[j],
  28. lambda1 = longitude(point1),
  29. phi1 = point1[1] / 2 + quarterPi,
  30. sinPhi1 = sin(phi1),
  31. cosPhi1 = cos(phi1),
  32. delta = lambda1 - lambda0,
  33. sign = delta >= 0 ? 1 : -1,
  34. absDelta = sign * delta,
  35. antimeridian = absDelta > pi,
  36. k = sinPhi0 * sinPhi1;
  37. sum.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
  38. angle += antimeridian ? delta + sign * tau : delta;
  39. // Are the longitudes either side of the point’s meridian (lambda),
  40. // and are the latitudes smaller than the parallel (phi)?
  41. if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
  42. var arc = cartesianCross(cartesian(point0), cartesian(point1));
  43. cartesianNormalizeInPlace(arc);
  44. var intersection = cartesianCross(normal, arc);
  45. cartesianNormalizeInPlace(intersection);
  46. var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
  47. if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
  48. winding += antimeridian ^ delta >= 0 ? 1 : -1;
  49. }
  50. }
  51. }
  52. }
  53. // First, determine whether the South pole is inside or outside:
  54. //
  55. // It is inside if:
  56. // * the polygon winds around it in a clockwise direction.
  57. // * the polygon does not (cumulatively) wind around it, but has a negative
  58. // (counter-clockwise) area.
  59. //
  60. // Second, count the (signed) number of times a segment crosses a lambda
  61. // from the point to the South pole. If it is zero, then the point is the
  62. // same side as the South pole.
  63. return (angle < -epsilon || angle < epsilon && sum < -epsilon2) ^ (winding & 1);
  64. }