UNPKG

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