UNPKG

@radarlabs/s2

Version:

Node.js JavaScript and TypeScript bindings for the Google S2 geolocation library.

302 lines (265 loc) 13.3 kB
// magic incantation from step 3 @ https://github.com/mapbox/node-pre-gyp#readme const binary = require('@mapbox/node-pre-gyp'); const path = require('path'); var binding_path = binary.find(path.resolve('./package.json')); const s2 = require(binding_path); // long, lat pairs of 11201 postal code const postalCode11201 = [[-73.995069,40.703102],[-73.995138,40.70298],[-73.996698,40.700877],[-73.9975,40.699653],[-73.998032,40.698762],[-73.998376,40.698048],[-73.998847,40.697141],[-73.998763,40.69711],[-73.998857,40.69692],[-73.99894,40.696941],[-73.998991,40.696812],[-73.999182,40.696885],[-73.999295,40.696795],[-73.999474,40.696704],[-73.999535,40.696578],[-73.999478,40.696466],[-73.999428,40.69641],[-73.99942,40.696361],[-73.999461,40.69628],[-73.999604,40.696069],[-73.999882,40.695605],[-74.000277,40.694959],[-74.000701,40.694388],[-74.000959,40.694069],[-74.001194,40.693484],[-74.001277,40.693298],[-74.001317,40.693208],[-74.001542,40.692786],[-74.001744,40.692407],[-74.001818,40.692222],[-74.001969,40.691843],[-74.001332,40.691225],[-74.000699,40.690612],[-74.00096,40.690132],[-74.001853,40.690388],[-74.001963,40.690136],[-74.002178,40.690206],[-74.002427,40.690273],[-74.002616,40.690324],[-74.002763,40.690364],[-74.002993,40.690427],[-74.003024,40.690349],[-74.003409,40.689613],[-74.00382,40.68893],[-74.003919,40.68886],[-74.004593,40.688215],[-74.005038,40.687561],[-74.00563,40.686784],[-74.005874,40.686207],[-74.00635,40.686285],[-74.006406,40.686289],[-74.006444,40.686296],[-74.006506,40.686314],[-74.006594,40.686347],[-74.006755,40.686413],[-74.006875,40.686464],[-74.006989,40.686509],[-74.00702,40.686526],[-74.007064,40.686504],[-74.00715,40.686475],[-74.007243,40.686449],[-74.007411,40.686388],[-74.007497,40.686344],[-74.007536,40.686315],[-74.007623,40.686285],[-74.00767,40.686269],[-74.00773,40.686254],[-74.007778,40.686245],[-74.007843,40.686238],[-74.007899,40.686251],[-74.007929,40.686276],[-74.00795,40.686293],[-74.008164,40.686175],[-74.008425,40.686016],[-74.008386,40.685969],[-74.008135,40.685615],[-74.005497,40.685847],[-74.004853,40.685668],[-74.004504,40.686301],[-74.002364,40.685737],[-74.002039,40.686404],[-74.001718,40.687069],[-74.001389,40.687751],[-74.001278,40.687715],[-74.000539,40.687481],[-74.000054,40.687318],[-73.999962,40.687286],[-73.999863,40.687251],[-73.999696,40.687198],[-73.998932,40.686948],[-73.998276,40.686729],[-73.998189,40.6867],[-73.997278,40.686398],[-73.996488,40.686138],[-73.996358,40.686096],[-73.99618,40.686037],[-73.995386,40.685775],[-73.994538,40.685495],[-73.994408,40.685453],[-73.994578,40.6851],[-73.992192,40.684178],[-73.991952,40.684084],[-73.989992,40.683319],[-73.989556,40.683956],[-73.989129,40.68459],[-73.988712,40.685224],[-73.988289,40.685869],[-73.987859,40.686504],[-73.987429,40.687138],[-73.987,40.687773],[-73.986568,40.688408],[-73.9844,40.687564],[-73.983988,40.688175],[-73.983572,40.688786],[-73.982715,40.688459],[-73.982416,40.688896],[-73.982098,40.689358],[-73.981068,40.688945],[-73.98087,40.688866],[-73.980258,40.688638],[-73.980429,40.689901],[-73.97951,40.689863],[-73.978624,40.689831],[-73.977939,40.689806],[-73.977098,40.689773],[-73.976102,40.689737],[-73.975106,40.689698],[-73.974109,40.689663],[-73.973264,40.689627],[-73.973126,40.689622],[-73.97354,40.691707],[-73.973855,40.693287],[-73.97422,40.693301],[-73.974985,40.693329],[-73.975848,40.693361],[-73.977827,40.693438],[-73.979168,40.693489],[-73.979195,40.693695],[-73.979218,40.693765],[-73.979259,40.69382],[-73.97933,40.693891],[-73.979481,40.694013],[-73.979805,40.694241],[-73.979883,40.694308],[-73.979944,40.694385],[-73.980139,40.694683],[-73.980243,40.695457],[-73.980263,40.695634],[-73.980356,40.696178],[-73.979537,40.696172],[-73.979529,40.696298],[-73.979524,40.696381],[-73.979529,40.696529],[-73.980388,40.696507],[-73.980447,40.69667],[-73.980515,40.697437],[-73.980544,40.698246],[-73.980462,40.699703],[-73.980455,40.700852],[-73.980729,40.701268],[-73.980649,40.701561],[-73.980455,40.702248],[-73.980224,40.703063],[-73.979988,40.703541],[-73.979603,40.704177],[-73.979466,40.704462],[-73.979328,40.704746],[-73.979168,40.705279],[-73.979171,40.705301],[-73.979372,40.705443],[-73.979233,40.705769],[-73.979479,40.705825],[-73.980332,40.705846],[-73.980907,40.705907],[-73.980987,40.705374],[-73.981856,40.70549],[-73.982033,40.705515],[-73.98221,40.70554],[-73.982329,40.705552],[-73.982449,40.705547],[-73.982455,40.705509],[-73.982572,40.705518],[-73.982748,40.705532],[-73.982741,40.705576],[-73.982825,40.705558],[-73.98308,40.705519],[-73.98308,40.70548],[-73.983227,40.705482],[-73.983351,40.705451],[-73.983398,40.705467],[-73.983426,40.705577],[-73.983442,40.705645],[-73.984189,40.705582],[-73.985852,40.705415],[-73.986434,40.705349],[-73.986429,40.705083],[-73.98653,40.704979],[-73.986623,40.704979],[-73.986641,40.705018],[-73.98669,40.705075],[-73.986762,40.705118],[-73.986866,40.705161],[-73.987271,40.705181],[-73.987449,40.705166],[-73.987577,40.705158],[-73.987957,40.705134],[-73.989224,40.705137],[-73.989424,40.705137],[-73.989495,40.705145],[-73.989608,40.705158],[-73.989861,40.705175],[-73.990549,40.705144],[-73.990696,40.705131],[-73.990882,40.705124],[-73.99148,40.705625],[-73.992722,40.705544],[-73.993853,40.704829],[-73.993713,40.70452],[-73.993693,40.704476],[-73.993775,40.704449],[-73.993807,40.70454],[-73.993861,40.704556],[-73.994341,40.704429],[-73.994498,40.704318],[-73.994565,40.704265],[-73.994618,40.704226],[-73.994797,40.704096],[-73.994714,40.703997],[-73.994816,40.703906],[-73.994881,40.703813],[-73.994882,40.703788],[-73.994992,40.703654],[-73.994858,40.703566],[-73.994663,40.703431],[-73.994806,40.703296],[-73.995069,40.703102]]; const unnormalized = [ [-119.74242645808715,39.57982985652839], [-119.74457144737244,39.579904675483704], [-119.7435238,39.5835421], [-119.7378725,39.5808519], [-119.7393411397934,39.57999050617218], [-119.74242645808715,39.57982985652839] ]; test("RegionCoverer#getCoveringTokens works", () => { const lls = postalCode11201.map((latlng) => { const [lng, lat] = latlng; return new s2.LatLng(lat, lng); }); // Invalid loop with duplicate points (first and last are the same) expect(() => new s2.RegionCoverer.getCoveringTokens(null, {})).toThrow('s2.LatLng[]'); expect(() => new s2.RegionCoverer.getCoveringTokens([], {})).toThrow('was empty'); expect(() => new s2.RegionCoverer.getCoveringTokens(lls, {})).toThrow('duplicate vertex'); // level-14 s2 cells let covering = s2.RegionCoverer.getCoveringTokens(lls.slice(1), { min: 14, max: 14 }); let coveringTokens = new Set(covering); let expectedTokens = new Set([ '89c25a31', '89c25a33', '89c25a35', '89c25a37', '89c25a39', '89c25a3b', '89c25a41', '89c25a43', '89c25a45', '89c25a47', '89c25a49', '89c25a4b', '89c25a4d', '89c25a4f', '89c25a51', '89c25a53', '89c25a5b', '89c25a5d', '89c25a67', '89c25bb1', '89c25bb3', '89c25bb5', '89c25bb7', '89c25bcb', '89c25bcd', '89c25bd3' ]); expect(coveringTokens).toEqual(expectedTokens); // levels 12-20 covering = s2.RegionCoverer.getCoveringTokens(lls.slice(1), { min: 12, max: 20 }); coveringTokens = new Set(covering); expect(coveringTokens).toEqual(new Set([ '89c25a34', '89c25a3c', '89c25a5', '89c25a674', '89c25bb4', '89c25bcb', '89c25bcd', '89c25bd3' ])); }); test("RegionCoverer can cover unnormalized loops", () => { const lls = unnormalized.map((latlng) => { const [lng, lat] = latlng; return new s2.LatLng(lat, lng); }); // generate s2 cells let covering = s2.RegionCoverer.getCoveringTokens(lls.slice(1), { min: 14, max: 20 }); let coveringTokens = new Set(covering); let expectedTokens = new Set([ '809938fe4', '809938ffc', '809939004', '809939014', '80993901c', '809939021f', '809939023', '80993903c', ]); expect(coveringTokens).toEqual(expectedTokens); }); test("RegionCoverer#getCovering works", () => { const lls = postalCode11201.map((latlng) => { const [lng, lat] = latlng; return new s2.LatLng(lat, lng); }); // Invalid loop with duplicate points (first and last are the same) expect(() => new s2.RegionCoverer.getCovering(null, {})).toThrow('s2.LatLng[]'); expect(() => new s2.RegionCoverer.getCovering([], {})).toThrow('was empty'); expect(() => new s2.RegionCoverer.getCovering(lls, {})).toThrow('duplicate vertex'); // level-14 s2 cells let covering = s2.RegionCoverer.getCovering(lls.slice(1), { min: 14, max: 14 }); let coveringCellIds = covering.cellIds(); let coveringTokens = new Set(covering.tokens()); let expectedTokens = new Set([ '89c25a31', '89c25a33', '89c25a35', '89c25a37', '89c25a39', '89c25a3b', '89c25a41', '89c25a43', '89c25a45', '89c25a47', '89c25a49', '89c25a4b', '89c25a4d', '89c25a4f', '89c25a51', '89c25a53', '89c25a5b', '89c25a5d', '89c25a67', '89c25bb1', '89c25bb3', '89c25bb5', '89c25bb7', '89c25bcb', '89c25bcd', '89c25bd3' ]); expect(coveringTokens).toEqual(expectedTokens); expect(new Set(coveringCellIds.map(id => id.token()))).toEqual(expectedTokens); // levels 12-20 covering = s2.RegionCoverer.getCovering(lls.slice(1), { min: 12, max: 20 }); coveringCellIds = covering.cellIds(); coveringTokens = new Set(covering.tokens()); expectedTokens = new Set([ '89c25a34', '89c25a3c', '89c25a5', '89c25a674', '89c25bb4', '89c25bcb', '89c25bcd', '89c25bd3' ]); expect(coveringTokens).toEqual(expectedTokens); expect(new Set(coveringCellIds.map(id => id.token()))).toEqual(expectedTokens); }); test("RegionCoverer#getCoveringIds works", () => { const lls = postalCode11201.map((latlng) => { const [lng, lat] = latlng; return new s2.LatLng(lat, lng); }); // Invalid loop with duplicate points (first and last are the same) expect(() => new s2.RegionCoverer.getCoveringIds(null, {})).toThrow('s2.LatLng[]'); expect(() => new s2.RegionCoverer.getCoveringIds([], {})).toThrow('was empty'); expect(() => new s2.RegionCoverer.getCoveringIds(lls, {})).toThrow('duplicate vertex'); // level-14 s2 cells let covering = s2.RegionCoverer .getCoveringIds(lls.slice(1), { min: 14, max: 14 }) .sort(); let expectedIds = BigUint64Array.of( 9926595695177891840n, 9926595703767826432n, 9926595798257106944n, 9926595806847041536n, 9926595815436976128n, 9926595824026910720n, 9926595832616845312n, 9926595841206779904n, 9926595875566518272n, 9926595884156452864n, 9926595927106125824n, 9926597344445333504n, 9926595712357761024n, 9926597353035268096n, 9926597361625202688n, 9926597370215137280n, 9926597456114483200n, 9926597464704417792n, 9926597490474221568n, 9926595720947695616n, 9926595729537630208n, 9926595738127564800n, 9926595763897368576n, 9926595772487303168n, 9926595781077237760n, 9926595789667172352n ).sort(); for (let i = 0; i < expectedIds.length; i++) { expect(covering[i]).toEqual(expectedIds[i]); } // levels 12-20 covering = s2.RegionCoverer .getCoveringIds(lls.slice(1), { min: 12, max: 20 }) .sort(); expectedIds = BigUint64Array.of( 9926595708062793728n, 9926595742422532096n, 9926595828321878016n, 9926595928179867648n, 9926597357330235392n, 9926597456114483200n, 9926597464704417792n, 9926597490474221568n, ).sort(); for (let i = 0; i < expectedIds.length; i++) { expect(covering[i]).toEqual(expectedIds[i]); } }); test("RegionCoverer#getRadiusCovering works", () => { const dumbo = [40.7033, -73.9881]; const ll = new s2.LatLng(...dumbo); const cellUnion = s2.RegionCoverer.getRadiusCovering(ll, 3000, { min: 5, max: 20 }); const ids = cellUnion.ids().sort(); const expected = [ 9926594780349857792n, 9926594866249203712n, 9926595003688157184n, 9926595433184886784n, 9926595759602401280n, 9926596532696514560n, 9926596567056252928n, 9926597408869842944n, ].sort(); for (let i = 0; i < expected.length; i++) { expect(ids[i]).toEqual(expected[i]); } }); test("RegionCoverer#getRadiusCoveringIds works", () => { const dumbo = [40.7033, -73.9881]; const ll = new s2.LatLng(...dumbo); const ids = s2.RegionCoverer.getRadiusCoveringIds(ll, 3000, { min: 5, max: 20 }).sort(); const expected = [ 9926594780349857792n, 9926594866249203712n, 9926595003688157184n, 9926595433184886784n, 9926595759602401280n, 9926596532696514560n, 9926596567056252928n, 9926597408869842944n, ].sort(); for (let i = 0; i < expected.length; i++) { expect(ids[i]).toEqual(expected[i]); } }); test("RegionCoverer#getRadiusCoveringTokens works", () => { const dumbo = [40.7033, -73.9881]; const ll = new s2.LatLng(...dumbo); const tokens = s2.RegionCoverer.getRadiusCoveringTokens(ll, 1000, { min: 12, max: 12 }).sort(); const expected = [ '89c25a3', '89c25a5', '89c25bb', '89c25bd', ].sort(); for (let i = 0; i < expected.length; i++) { expect(tokens[i]).toEqual(expected[i]); } });