1 | import processPolygon from 'point-in-big-polygon'
|
2 | import { ringArea as ringAreaSpherical } from 'topojson/lib/topojson/spherical.js'
|
3 | import { ringArea as ringAreaCartesian } from 'topojson/lib/topojson/cartesian.js'
|
4 |
|
5 | /**
|
6 | * Modifies the point order of the given polygon rings such that the first ring is ordered
|
7 | * clockwise and all others anti-clockwise. Modification happens in-place.
|
8 | *
|
9 | * @param {Array} rings - Polygon rings to reorder (in-place)
|
10 | * @param {boolean} [isCartesian=false] - whether coordinates are cartesian or spherical degrees
|
11 | */
|
12 | export function ensureClockwisePolygon (rings, isCartesian = false) {
|
13 | // first ring = exterior, clockwise
|
14 | // other rings = interior, anti-clockwise
|
15 | let ringAreaFn = isCartesian ? ringAreaCartesian : ringAreaSpherical
|
16 | for (let i = 0; i < rings.length; i++) {
|
17 | let area = ringAreaFn(rings[i])
|
18 | if ((i === 0 && area < 0) || (i > 0 && area > 0)) {
|
19 | rings[i].reverse()
|
20 | }
|
21 | }
|
22 | }
|
23 |
|
24 | /**
|
25 | * Preprocesses an array of polygons to answer the point-in-polygon question efficiently.
|
26 | *
|
27 | * @param {Array} polygons - A list of polygons where the exterior ring of each polygon is in clockwise and the interior rings in anti-clockwise order.
|
28 | * @return {function} A function classify(point) which returns the index of the first found polygon containing point, or -1 if not in any polygon.
|
29 | */
|
30 | export function getPointInPolygonsFn (polygons) {
|
31 | let classifiers = polygons.map(processPolygon)
|
32 | let npolys = polygons.length
|
33 |
|
34 | return point => {
|
35 | for (let i = 0; i < npolys; i++) {
|
36 | if (classifiers[i](point) <= 0) {
|
37 | return i
|
38 | }
|
39 | }
|
40 | return -1
|
41 | }
|
42 | }
|