Compare commits
	
		
			56 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 7a10f5b562 | ||
|  | e7ecb48449 | ||
|  | 441c693bad | ||
|  | e67bb19828 | ||
|  | df6d38b5ad | ||
|  | 3a962c1956 | ||
|  | 5495dd0a53 | ||
|  | d28f0a6d3f | ||
|  | a4e97ba0a9 | ||
|  | 0cc25036e5 | ||
|  | a11cd4e920 | ||
|  | 42a9eaf1fc | ||
|  | 4e631500ea | ||
|  | 8aa84ebf93 | ||
|  | 9fdcc00739 | ||
|  | 7180db1be6 | ||
|  | c6ee1ee508 | ||
|  | 4249d3bfa6 | ||
|  | 60d01395ef | ||
|  | 2e7b12e212 | ||
|  | 1a9c95e2c6 | ||
|  | b3f5bbd27f | ||
|  | f96e16c6bf | ||
|  | d1f19ef616 | ||
|  | 191e83fe40 | ||
|  | 4c4154a288 | ||
|  | be9112f2ad | ||
|  | bb664af25b | ||
|  | 98fa79b6bd | ||
|  | d5524f7b74 | ||
|  | afe681240b | ||
|  | 197e07a605 | ||
|  | 60186d007f | ||
|  | b7f7c6df1c | ||
|  | a1da97514e | ||
|  | 68274eb677 | ||
|  | e04b0b0ecd | ||
|  | 4a7b8819c9 | ||
|  | c0c80ca0f8 | ||
|  | c094e1def7 | ||
|  | d18e4906c5 | ||
|  | b45bb89117 | ||
|  | d7aa5c136a | ||
|  | 0d8eec3d04 | ||
|  | 113e375824 | ||
|  | e461dcfd5c | ||
|  | 51b549de38 | ||
|  | c275019aec | ||
|  | 2796829356 | ||
|  | 6252e4e9e9 | ||
|  | 65d94c9141 | ||
|  | d344d81611 | ||
|  | 54bd875e3e | ||
|  | e3619d963a | ||
|  | c65239853a | ||
|  | 103d955300 | 
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | |||||||
| ISC License (ISC) | ISC License (ISC) | ||||||
| 
 | 
 | ||||||
| Copyright (c) 2012-2016, Jon Atkins <github@jonatkins.com> | Copyright (c) 2012-2016, Jon Atkins <github@jonatkins.com> | ||||||
| Copyright (c) 2016, AJ ONeal <coolaj86@gmail.com> | Copyright (c) 2016, AJ ONeal <aj@daplie.com> | ||||||
| 
 | 
 | ||||||
| Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										184
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								README.md
									
									
									
									
									
								
							| @ -1,31 +1,186 @@ | |||||||
| s2-geometry (JavaScript/ES5.1) | s2-geometry (JavaScript/ES5.1) | ||||||
| ====================== | ====================== | ||||||
| 
 | 
 | ||||||
| A pure JavaScript/ES5.1 port of Google/Niantic's S2 Geometry library (used by **Ingress**, **Pokemon GO**) | | Sponsored by [ppl](https://ppl.family) | ||||||
|  | 
 | ||||||
|  | A pure JavaScript/ES5.1 port of Google/Niantic's S2 Geometry library (as used by **Ingress**, **Pokemon GO**) | ||||||
| 
 | 
 | ||||||
| Currently contains basic support for S2Cell | Currently contains basic support for S2Cell | ||||||
| 
 | 
 | ||||||
|  | <table> | ||||||
|  | <tr> | ||||||
|  | <td></td> | ||||||
|  | <td> | ||||||
|  | Face 2 | ||||||
|  | <br> | ||||||
|  | Orientation A | ||||||
|  | 
 | ||||||
|  | <a href="http://i.imgur.com/SODO4bT.jpg" target="_face2"><img src="http://i.imgur.com/SODO4bTt.jpg" title="Face 2" alt="Face 2"></a> | ||||||
|  | 
 | ||||||
|  | <br> | ||||||
|  | The North Pole<br>(and Canada / Europe) | ||||||
|  | </td> | ||||||
|  | <td></td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|  | <td> | ||||||
|  | Face 0 | ||||||
|  | <br> | ||||||
|  | Orientation A | ||||||
|  | 
 | ||||||
|  | <a href="http://i.imgur.com/dLI5Zd1.jpg" target="_face0"><img src="http://i.imgur.com/dLI5Zd1t.jpg" title="Face 0" alt="Face 0"></a> | ||||||
|  | 
 | ||||||
|  | <br> | ||||||
|  | Africa | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  | Face 1 | ||||||
|  | <br> | ||||||
|  | Orientation D | ||||||
|  | 
 | ||||||
|  | <a href="http://i.imgur.com/duTLDTV.jpg" target="_face1"><img src="http://i.imgur.com/duTLDTVt.jpg" title="Face 1" alt="Face 1"></a> | ||||||
|  | 
 | ||||||
|  | <br> | ||||||
|  | Asia | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  | Face 3 | ||||||
|  | <br> | ||||||
|  | Orientation D | ||||||
|  | 
 | ||||||
|  | <a href="http://i.imgur.com/6Ho35Tc.jpg" target="_face3"><img src="http://i.imgur.com/6Ho35Tct.jpg" title="Face 3" alt="Face 3"></a> | ||||||
|  | 
 | ||||||
|  | <br> | ||||||
|  | Nothing<br>(and Australia) | ||||||
|  | </td> | ||||||
|  | <td> | ||||||
|  | Face 4 | ||||||
|  | <br> | ||||||
|  | Orientation A | ||||||
|  | 
 | ||||||
|  | <a href="http://i.imgur.com/3IBAfqj.jpg" target="_face4"><img src="http://i.imgur.com/3IBAfqjt.jpg" title="Face 4" alt="Face 4"></a> | ||||||
|  | 
 | ||||||
|  | <br> | ||||||
|  | The Americas<br>(and Provo, UT) | ||||||
|  | </td> | ||||||
|  | </tr> | ||||||
|  | <tr> | ||||||
|  | <td></td> | ||||||
|  | <td></td> | ||||||
|  | <td></td> | ||||||
|  | <td> | ||||||
|  | Face 5 | ||||||
|  | <br> | ||||||
|  | Orientation D | ||||||
|  | 
 | ||||||
|  | <a href="http://i.imgur.com/HZCBvgy.jpg" target="_face5"><img src="http://i.imgur.com/HZCBvgyt.jpg" title="Face 5" alt="Face 5"></a> | ||||||
|  | 
 | ||||||
|  | <br> | ||||||
|  | Antarctica | ||||||
|  | </td> | ||||||
|  | </tr> | ||||||
|  | </table> | ||||||
|  | 
 | ||||||
|  | Where is this being used? | ||||||
|  | --------------------- | ||||||
|  | 
 | ||||||
|  | * [pokemap-webapp](https://github.com/Daplie/pokemap-webapp) | ||||||
|  | * [node-pokemap](https://github.com/Daplie/node-pokemap) | ||||||
|  | * [Pokemon-GO-node-api](https://github.com/Daplie/Pokemon-GO-node-api) | ||||||
|  | 
 | ||||||
| Simple Examples | Simple Examples | ||||||
| --------------- | --------------- | ||||||
| 
 | 
 | ||||||
| ```javascript | ```javascript | ||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var S2 = require('s2-geometry').S2; | ||||||
|  | 
 | ||||||
|  | var lat = 40.2574448; | ||||||
|  | var lng = -111.7089464; | ||||||
| var level = 15; | var level = 15; | ||||||
| var latlng = { lat: 40.2574448, lng: -111.7089464 }; |  | ||||||
| var cell = S2.S2Cell.FromLatLng(latlng, level); |  | ||||||
| 
 | 
 | ||||||
| cell.getNeighbors();  // [ cellLeft, cellDown, cellRight, cellUp ] |  | ||||||
| 
 | 
 | ||||||
| cell.getLatLng();     // { lat: 40.2574448, lng: -111.7089464 } | 
 | ||||||
|  | // | ||||||
|  | // Convert from Lat / Lng | ||||||
|  | // | ||||||
|  | var key = S2.latLngToKey(lat, lng, level); | ||||||
|  | // '4/032212303102210' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // | ||||||
|  | // Convert between Hilbert Curve Quadtree Key and S2 Cell Id | ||||||
|  | // | ||||||
|  | var id = S2.keyToId(key); | ||||||
|  | // '9749618446378729472' | ||||||
|  | 
 | ||||||
|  | var key = S2.idToKey(id); | ||||||
|  | // '9749618446378729472' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // | ||||||
|  | // Convert between Quadkey and Id | ||||||
|  | // | ||||||
|  | var latlng = S2.keyToLatLng(key); | ||||||
|  | var latlng = S2.idToLatLng(id); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // | ||||||
|  | // Neighbors | ||||||
|  | // | ||||||
|  | var neighbors = S2.latLngToNeighborKeys(lat, lng, level); | ||||||
|  | // [ keyLeft, keyDown, keyRight, keyUp ] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // | ||||||
|  | // Previous, Next, and Step | ||||||
|  | // | ||||||
|  | var nextKey = S2.nextKey(key); | ||||||
|  | var prevKey = S2.prevKey(key); | ||||||
|  | 
 | ||||||
|  | var backTenKeys = S2.stepKey(key, -10); | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| convert Cell Id to Quadkey | Previous and Next | ||||||
|  | ----------------- | ||||||
|  | 
 | ||||||
|  | You can get the previous and next S2CellId from any given Key: | ||||||
|  | 
 | ||||||
|  | 1. Convert from Lat/Lng to Key (Face and Hilbert Curve Quadtree) | ||||||
|  | 2. Get the Previous or Next Key | ||||||
|  | 3. Convert the Key to an Id (uint64 string) | ||||||
|  | 
 | ||||||
|  | ```javascript | ||||||
|  | var key = S2.latLngToKey(40.2574448, -111.7089464, 15);   // '4/032212303102210' | ||||||
|  | var id = S2.keyToId(key);                                 // '9749618446378729472' | ||||||
|  | 
 | ||||||
|  | var nextKey = S2.nextKey(key); | ||||||
|  | var nextId = S2.keyToId(nextKey); | ||||||
|  | 
 | ||||||
|  | var prevKey = S2.prevKey(key); | ||||||
|  | var prevId = S2.keyToId(prevKey); | ||||||
|  | 
 | ||||||
|  | var backTenKeys = S2.stepKey(key, -10); | ||||||
|  | 
 | ||||||
|  | // See it | ||||||
|  | console.log(prevKey);                                 // '4/032212303102203' | ||||||
|  | console.log(key);                                     // '4/032212303102210' | ||||||
|  | console.log(nextKey);                                 // '4/032212303102211' | ||||||
|  | console.log(nextId); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | convert Cell Id to Hilbert Curve Quad Tree | ||||||
| ------------------ | ------------------ | ||||||
| 
 | 
 | ||||||
| Convert from base 10 (decimal) `S2 Cell Id` to base 4 `quadkey` (aka hilbert curve quadtree id) | Convert from base 10 (decimal) `S2 Cell Id` to base 4 `quadkey` (aka hilbert curve quadtree id) | ||||||
| 
 | 
 | ||||||
| Example '4/032212303102210' becomes '9749618446378729472' | Example '4/032212303102210' becomes '9749618446378729472' | ||||||
| 
 | 
 | ||||||
| ``` | ```javascript | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var quadkey = '4/032212303102210' | var quadkey = '4/032212303102210' | ||||||
| @ -34,7 +189,7 @@ var face = parts[0];                  // 4 | |||||||
| var position = parts[1];              // '032212303102210'; | var position = parts[1];              // '032212303102210'; | ||||||
| var level = '032212303102210'.length; // 15 | var level = '032212303102210'.length; // 15 | ||||||
| 
 | 
 | ||||||
| var cellId = S2.fromFacePosLevel(face, position, level); | var cellId = S2.facePosLevelToId(face, position, level); | ||||||
| 
 | 
 | ||||||
| console.log(cellId); | console.log(cellId); | ||||||
| ``` | ``` | ||||||
| @ -43,12 +198,21 @@ Convert from hilbert quadtree id to s2 cell id: | |||||||
| 
 | 
 | ||||||
| Example '9749618446378729472' becomes '4/032212303102210' | Example '9749618446378729472' becomes '4/032212303102210' | ||||||
| 
 | 
 | ||||||
| ``` | ```javascript | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var cellId = '9749618446378729472'; | var cellId = '9749618446378729472'; | ||||||
| 
 | 
 | ||||||
| var hilbertQuadkey = S2.toHilbertQuadkey(cellId); | var hilbertQuadkey = S2.idToKey(cellId); | ||||||
| 
 | 
 | ||||||
| console.log(hilbertQuadkey); | console.log(hilbertQuadkey); | ||||||
| ``` | ``` | ||||||
|  | 
 | ||||||
|  | Convert Key and Id to LatLng | ||||||
|  | --------------------- | ||||||
|  | 
 | ||||||
|  | ```javascript | ||||||
|  | var latlng = S2.keyToLatLng('4/032212303102210'); | ||||||
|  | 
 | ||||||
|  | var latlng = S2.idToLatLng('9749618446378729472'); | ||||||
|  | ``` | ||||||
|  | |||||||
| @ -34,5 +34,6 @@ | |||||||
|     "bower_components", |     "bower_components", | ||||||
|     "test", |     "test", | ||||||
|     "tests" |     "tests" | ||||||
|   ] |   ], | ||||||
|  |   "version": "1.2.9" | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "s2-geometry", |   "name": "s2-geometry", | ||||||
|   "version": "1.1.1", |   "version": "1.2.10", | ||||||
|   "description": "A pure JavaScript/ES5.1 port of Google/Niantic's S2 Geometry library (used by Ingress, Pokemon GO)", |   "description": "A pure JavaScript/ES5.1 port of Google/Niantic's S2 Geometry library (used by Ingress, Pokemon GO)", | ||||||
|   "main": "src/s2geometry.js", |   "main": "src/s2geometry.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
| @ -8,7 +8,7 @@ | |||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|     "url": "git+https://github.com/coolaj86/s2-geometry-javascript.git" |     "url": "git+https://git.coolaj86.com/coolaj86/s2-geometry.js.git" | ||||||
|   }, |   }, | ||||||
|   "keywords": [ |   "keywords": [ | ||||||
|     "s2", |     "s2", | ||||||
| @ -28,11 +28,11 @@ | |||||||
|     "lng" |     "lng" | ||||||
|   ], |   ], | ||||||
|   "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", |   "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", | ||||||
|   "license": "ISC", |   "license": "(MIT or Apache-2 or ISC)", | ||||||
|   "bugs": { |   "bugs": { | ||||||
|     "url": "https://github.com/coolaj86/s2-geometry-javascript/issues" |     "url": "https://git.coolaj86.com/coolaj86/s2-geometry.js/issues" | ||||||
|   }, |   }, | ||||||
|   "homepage": "https://github.com/coolaj86/s2-geometry-javascript#readme", |   "homepage": "https://git.coolaj86.com/coolaj86/s2-geometry.js#readme", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "long": "^3.2.0" |     "long": "^3.2.0" | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -25,9 +25,29 @@ | |||||||
| (function (exports) { | (function (exports) { | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var S2 = exports.S2 = {}; | var S2 = exports.S2 = { L: {} }; | ||||||
| 
 | 
 | ||||||
| var LatLngToXYZ = function(latLng) { | S2.L.LatLng = function (/*Number*/ rawLat, /*Number*/ rawLng, /*Boolean*/ noWrap) { | ||||||
|  |   var lat = parseFloat(rawLat, 10); | ||||||
|  |   var lng = parseFloat(rawLng, 10); | ||||||
|  | 
 | ||||||
|  |   if (isNaN(lat) || isNaN(lng)) { | ||||||
|  |     throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')'); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (noWrap !== true) { | ||||||
|  |     lat = Math.max(Math.min(lat, 90), -90);                 // clamp latitude into -90..90
 | ||||||
|  |     lng = (lng + 180) % 360 + ((lng < -180 || lng === 180) ? 180 : -180);   // wrap longtitude into -180..180
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return { lat: lat, lng: lng }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | S2.L.LatLng.DEG_TO_RAD = Math.PI / 180; | ||||||
|  | S2.L.LatLng.RAD_TO_DEG = 180 / Math.PI; | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | S2.LatLngToXYZ = function(latLng) { | ||||||
|   // http://stackoverflow.com/questions/8981943/lat-long-to-x-y-z-position-in-js-not-working
 |   // http://stackoverflow.com/questions/8981943/lat-long-to-x-y-z-position-in-js-not-working
 | ||||||
|   var lat = latLng.lat; |   var lat = latLng.lat; | ||||||
|   var lon = latLng.lng; |   var lon = latLng.lng; | ||||||
| @ -48,8 +68,19 @@ var LatLngToXYZ = function(latLng) { | |||||||
|   , rad * sinLat |   , rad * sinLat | ||||||
|   ]; |   ]; | ||||||
| }; | }; | ||||||
|  | */ | ||||||
|  | S2.LatLngToXYZ = function(latLng) { | ||||||
|  |   var d2r = S2.L.LatLng.DEG_TO_RAD; | ||||||
| 
 | 
 | ||||||
| var XYZToLatLng = function(xyz) { |   var phi = latLng.lat*d2r; | ||||||
|  |   var theta = latLng.lng*d2r; | ||||||
|  | 
 | ||||||
|  |   var cosphi = Math.cos(phi); | ||||||
|  | 
 | ||||||
|  |   return [Math.cos(theta)*cosphi, Math.sin(theta)*cosphi, Math.sin(phi)]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | S2.XYZToLatLng = function(xyz) { | ||||||
|   var r2d = S2.L.LatLng.RAD_TO_DEG; |   var r2d = S2.L.LatLng.RAD_TO_DEG; | ||||||
| 
 | 
 | ||||||
|   var lat = Math.atan2(xyz[2], Math.sqrt(xyz[0]*xyz[0]+xyz[1]*xyz[1])); |   var lat = Math.atan2(xyz[2], Math.sqrt(xyz[0]*xyz[0]+xyz[1]*xyz[1])); | ||||||
| @ -96,7 +127,7 @@ var faceXYZToUV = function(face,xyz) { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| var XYZToFaceUV = function(xyz) { | S2.XYZToFaceUV = function(xyz) { | ||||||
|   var face = largestAbsComponent(xyz); |   var face = largestAbsComponent(xyz); | ||||||
| 
 | 
 | ||||||
|   if (xyz[face] < 0) { |   if (xyz[face] < 0) { | ||||||
| @ -108,7 +139,7 @@ var XYZToFaceUV = function(xyz) { | |||||||
|   return [face, uv]; |   return [face, uv]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| var FaceUVToXYZ = function(face,uv) { | S2.FaceUVToXYZ = function(face,uv) { | ||||||
|   var u = uv[0]; |   var u = uv[0]; | ||||||
|   var v = uv[1]; |   var v = uv[1]; | ||||||
| 
 | 
 | ||||||
| @ -131,7 +162,7 @@ var singleSTtoUV = function(st) { | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| var STToUV = function(st) { | S2.STToUV = function(st) { | ||||||
|   return [singleSTtoUV(st[0]), singleSTtoUV(st[1])]; |   return [singleSTtoUV(st[0]), singleSTtoUV(st[1])]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -143,12 +174,12 @@ var singleUVtoST = function(uv) { | |||||||
|     return 1 - 0.5 * Math.sqrt (1 - 3*uv); |     return 1 - 0.5 * Math.sqrt (1 - 3*uv); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| var UVToST = function(uv) { | S2.UVToST = function(uv) { | ||||||
|   return [singleUVtoST(uv[0]), singleUVtoST(uv[1])]; |   return [singleUVtoST(uv[0]), singleUVtoST(uv[1])]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| var STToIJ = function(st,order) { | S2.STToIJ = function(st,order) { | ||||||
|   var maxSize = (1<<order); |   var maxSize = (1<<order); | ||||||
| 
 | 
 | ||||||
|   var singleSTtoIJ = function(st) { |   var singleSTtoIJ = function(st) { | ||||||
| @ -160,7 +191,7 @@ var STToIJ = function(st,order) { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| var IJToST = function(ij,order,offsets) { | S2.IJToST = function(ij,order,offsets) { | ||||||
|   var maxSize = (1<<order); |   var maxSize = (1<<order); | ||||||
| 
 | 
 | ||||||
|   return [ |   return [ | ||||||
| @ -169,12 +200,36 @@ var IJToST = function(ij,order,offsets) { | |||||||
|   ]; |   ]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | var rotateAndFlipQuadrant = function(n, point, rx, ry) | ||||||
|  | { | ||||||
|  | 	var newX, newY; | ||||||
|  | 	if(ry == 0) | ||||||
|  | 	{ | ||||||
|  | 		if(rx == 1){ | ||||||
|  | 			point.x = n - 1 - point.x; | ||||||
|  | 			point.y = n - 1 - point.y | ||||||
|  | 
 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  |     var x = point.x; | ||||||
|  | 		point.x = point.y | ||||||
|  | 		point.y = x; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| // hilbert space-filling curve
 | // hilbert space-filling curve
 | ||||||
| // based on http://blog.notdot.net/2009/11/Damn-Cool-Algorithms-Spatial-indexing-with-Quadtrees-and-Hilbert-Curves
 | // based on http://blog.notdot.net/2009/11/Damn-Cool-Algorithms-Spatial-indexing-with-Quadtrees-and-Hilbert-Curves
 | ||||||
| // note: rather then calculating the final integer hilbert position, we just return the list of quads
 | // note: rather then calculating the final integer hilbert position, we just return the list of quads
 | ||||||
| // this ensures no precision issues whth large orders (S3 cell IDs use up to 30), and is more
 | // this ensures no precision issues whth large orders (S3 cell IDs use up to 30), and is more
 | ||||||
| // convenient for pulling out the individual bits as needed later
 | // convenient for pulling out the individual bits as needed later
 | ||||||
| var pointToHilbertQuadList = function(x,y,order) { | var pointToHilbertQuadList = function(x,y,order,face) { | ||||||
|   var hilbertMap = { |   var hilbertMap = { | ||||||
|     'a': [ [0,'d'], [1,'a'], [3,'b'], [2,'a'] ], |     'a': [ [0,'d'], [1,'a'], [3,'b'], [2,'a'] ], | ||||||
|     'b': [ [2,'b'], [1,'b'], [3,'a'], [0,'c'] ], |     'b': [ [2,'b'], [1,'b'], [3,'a'], [0,'c'] ], | ||||||
| @ -182,7 +237,10 @@ var pointToHilbertQuadList = function(x,y,order) { | |||||||
|     'd': [ [0,'a'], [3,'c'], [1,'d'], [2,'d'] ] |     'd': [ [0,'a'], [3,'c'], [1,'d'], [2,'d'] ] | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   var currentSquare='a'; |   if ('number' !== typeof face) { | ||||||
|  |     console.warn(new Error("called pointToHilbertQuadList without face value, defaulting to '0'").stack); | ||||||
|  |   } | ||||||
|  |   var currentSquare = (face % 2) ? 'd' : 'a'; | ||||||
|   var positions = []; |   var positions = []; | ||||||
| 
 | 
 | ||||||
|   for (var i=order-1; i>=0; i--) { |   for (var i=order-1; i>=0; i--) { | ||||||
| @ -202,24 +260,86 @@ var pointToHilbertQuadList = function(x,y,order) { | |||||||
|   return positions; |   return positions; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| // S2Cell class
 | // S2Cell class
 | ||||||
| 
 | 
 | ||||||
| S2.S2Cell = function(){}; | S2.S2Cell = function(){}; | ||||||
| 
 | 
 | ||||||
|  | S2.S2Cell.FromHilbertQuadKey = function(hilbertQuadkey) { | ||||||
|  |   var parts = hilbertQuadkey.split('/'); | ||||||
|  |   var face = parseInt(parts[0]); | ||||||
|  |   var position = parts[1]; | ||||||
|  |   var maxLevel = position.length; | ||||||
|  |   var point = { | ||||||
|  |     x : 0, | ||||||
|  |     y: 0 | ||||||
|  |   }; | ||||||
|  |   var i; | ||||||
|  |   var level; | ||||||
|  |   var bit; | ||||||
|  |   var rx, ry; | ||||||
|  |   var val; | ||||||
|  | 
 | ||||||
|  | 	for(i = maxLevel - 1; i >= 0; i--) { | ||||||
|  | 
 | ||||||
|  | 		level = maxLevel - i; | ||||||
|  | 		bit = position[i]; | ||||||
|  | 		rx = 0; | ||||||
|  |     ry = 0; | ||||||
|  | 		if (bit === '1') { | ||||||
|  | 			ry = 1; | ||||||
|  | 		} | ||||||
|  | 		else if (bit === '2') { | ||||||
|  | 			rx = 1; | ||||||
|  | 			ry = 1; | ||||||
|  | 		} | ||||||
|  | 		else if (bit === '3') { | ||||||
|  | 			rx = 1; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		val = Math.pow(2, level - 1); | ||||||
|  | 		rotateAndFlipQuadrant(val, point, rx, ry); | ||||||
|  | 
 | ||||||
|  | 		point.x += val * rx; | ||||||
|  | 		point.y += val * ry; | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |   if (face % 2 === 1) { | ||||||
|  |     var t = point.x; | ||||||
|  |     point.x = point.y; | ||||||
|  |     point.y = t; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   return S2.S2Cell.FromFaceIJ(parseInt(face), [point.x, point.y], level); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| //static method to construct
 | //static method to construct
 | ||||||
| S2.S2Cell.FromLatLng = function(latLng, level) { | S2.S2Cell.FromLatLng = function(latLng, level) { | ||||||
|  |   if ((!latLng.lat && latLng.lat !== 0) || (!latLng.lng && latLng.lng !== 0)) { | ||||||
|  |     throw new Error("Pass { lat: lat, lng: lng } to S2.S2Cell.FromLatLng"); | ||||||
|  |   } | ||||||
|  |   var xyz = S2.LatLngToXYZ(latLng); | ||||||
| 
 | 
 | ||||||
|   var xyz = LatLngToXYZ(latLng); |   var faceuv = S2.XYZToFaceUV(xyz); | ||||||
|  |   var st = S2.UVToST(faceuv[1]); | ||||||
| 
 | 
 | ||||||
|   var faceuv = XYZToFaceUV(xyz); |   var ij = S2.STToIJ(st,level); | ||||||
|   var st = UVToST(faceuv[1]); |  | ||||||
| 
 |  | ||||||
|   var ij = STToIJ(st,level); |  | ||||||
| 
 | 
 | ||||||
|   return S2.S2Cell.FromFaceIJ (faceuv[0], ij, level); |   return S2.S2Cell.FromFaceIJ (faceuv[0], ij, level); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /* | ||||||
|  | S2.faceIjLevelToXyz = function (face, ij, level) { | ||||||
|  |   var st = S2.IJToST(ij, level, [0.5, 0.5]); | ||||||
|  |   var uv = S2.STToUV(st); | ||||||
|  |   var xyz = S2.FaceUVToXYZ(face, uv); | ||||||
|  | 
 | ||||||
|  |   return S2.XYZToLatLng(xyz); | ||||||
|  |   return xyz; | ||||||
|  | }; | ||||||
|  | */ | ||||||
|  | 
 | ||||||
| S2.S2Cell.FromFaceIJ = function(face,ij,level) { | S2.S2Cell.FromFaceIJ = function(face,ij,level) { | ||||||
|   var cell = new S2.S2Cell(); |   var cell = new S2.S2Cell(); | ||||||
|   cell.face = face; |   cell.face = face; | ||||||
| @ -235,11 +355,11 @@ S2.S2Cell.prototype.toString = function() { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| S2.S2Cell.prototype.getLatLng = function() { | S2.S2Cell.prototype.getLatLng = function() { | ||||||
|   var st = IJToST(this.ij,this.level, [0.5,0.5]); |   var st = S2.IJToST(this.ij,this.level, [0.5,0.5]); | ||||||
|   var uv = STToUV(st); |   var uv = S2.STToUV(st); | ||||||
|   var xyz = FaceUVToXYZ(this.face, uv); |   var xyz = S2.FaceUVToXYZ(this.face, uv); | ||||||
| 
 | 
 | ||||||
|   return XYZToLatLng(xyz); |   return S2.XYZToLatLng(xyz); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| S2.S2Cell.prototype.getCornerLatLngs = function() { | S2.S2Cell.prototype.getCornerLatLngs = function() { | ||||||
| @ -252,27 +372,32 @@ S2.S2Cell.prototype.getCornerLatLngs = function() { | |||||||
|   ]; |   ]; | ||||||
| 
 | 
 | ||||||
|   for (var i=0; i<4; i++) { |   for (var i=0; i<4; i++) { | ||||||
|     var st = IJToST(this.ij, this.level, offsets[i]); |     var st = S2.IJToST(this.ij, this.level, offsets[i]); | ||||||
|     var uv = STToUV(st); |     var uv = S2.STToUV(st); | ||||||
|     var xyz = FaceUVToXYZ(this.face, uv); |     var xyz = S2.FaceUVToXYZ(this.face, uv); | ||||||
| 
 | 
 | ||||||
|     result.push ( XYZToLatLng(xyz) ); |     result.push ( S2.XYZToLatLng(xyz) ); | ||||||
|   } |   } | ||||||
|   return result; |   return result; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| S2.S2Cell.prototype.getFaceAndQuads = function () { | S2.S2Cell.prototype.getFaceAndQuads = function () { | ||||||
|   var quads = pointToHilbertQuadList(this.ij[0], this.ij[1], this.level); |   var quads = pointToHilbertQuadList(this.ij[0], this.ij[1], this.level, this.face); | ||||||
| 
 | 
 | ||||||
|   return [this.face,quads]; |   return [this.face,quads]; | ||||||
| }; | }; | ||||||
| S2.S2Cell.prototype.toHilbertQuadkey = function () { | S2.S2Cell.prototype.toHilbertQuadkey = function () { | ||||||
|   var quads = pointToHilbertQuadList(this.ij[0], this.ij[1], this.level); |   var quads = pointToHilbertQuadList(this.ij[0], this.ij[1], this.level, this.face); | ||||||
| 
 | 
 | ||||||
|   return this.face.toString(10) + '/' + quads.join(''); |   return this.face.toString(10) + '/' + quads.join(''); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | S2.latLngToNeighborKeys = S2.S2Cell.latLngToNeighborKeys = function (lat, lng, level) { | ||||||
|  |   return S2.S2Cell.FromLatLng({ lat: lat, lng: lng }, level).getNeighbors().map(function (cell) { | ||||||
|  |     return cell.toHilbertQuadkey(); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
| S2.S2Cell.prototype.getNeighbors = function() { | S2.S2Cell.prototype.getNeighbors = function() { | ||||||
| 
 | 
 | ||||||
|   var fromFaceIJWrap = function(face,ij,level) { |   var fromFaceIJWrap = function(face,ij,level) { | ||||||
| @ -285,14 +410,14 @@ S2.S2Cell.prototype.getNeighbors = function() { | |||||||
|       // with the assumption that they're only a little past the borders we can just take the points as
 |       // with the assumption that they're only a little past the borders we can just take the points as
 | ||||||
|       // just beyond the cube face, project to XYZ, then re-create FaceUV from the XYZ vector
 |       // just beyond the cube face, project to XYZ, then re-create FaceUV from the XYZ vector
 | ||||||
| 
 | 
 | ||||||
|       var st = IJToST(ij,level,[0.5,0.5]); |       var st = S2.IJToST(ij,level,[0.5,0.5]); | ||||||
|       var uv = STToUV(st); |       var uv = S2.STToUV(st); | ||||||
|       var xyz = FaceUVToXYZ(face,uv); |       var xyz = S2.FaceUVToXYZ(face,uv); | ||||||
|       var faceuv = XYZToFaceUV(xyz); |       var faceuv = S2.XYZToFaceUV(xyz); | ||||||
|       face = faceuv[0]; |       face = faceuv[0]; | ||||||
|       uv = faceuv[1]; |       uv = faceuv[1]; | ||||||
|       st = UVToST(uv); |       st = S2.UVToST(uv); | ||||||
|       ij = STToIJ(st,level); |       ij = S2.STToIJ(st,level); | ||||||
|       return S2.S2Cell.FromFaceIJ (face, ij, level); |       return S2.S2Cell.FromFaceIJ (face, ij, level); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| @ -317,10 +442,13 @@ S2.S2Cell.prototype.getNeighbors = function() { | |||||||
| //
 | //
 | ||||||
| S2.FACE_BITS = 3; | S2.FACE_BITS = 3; | ||||||
| S2.MAX_LEVEL = 30; | S2.MAX_LEVEL = 30; | ||||||
| S2.POS_BITS = (2 * S2.MAX_LEVEL) + 1; | S2.POS_BITS = (2 * S2.MAX_LEVEL) + 1; // 61 (60 bits of data, 1 bit lsb marker)
 | ||||||
| 
 | 
 | ||||||
| S2.fromFacePosLevel = function (faceN, posS, levelN) { | S2.facePosLevelToId = S2.S2Cell.facePosLevelToId = S2.fromFacePosLevel = function (faceN, posS, levelN) { | ||||||
|   var Long = exports.dcodeIO && exports.dcodeIO.Long || require('long'); |   var Long = exports.dcodeIO && exports.dcodeIO.Long || require('long'); | ||||||
|  |   var faceB; | ||||||
|  |   var posB; | ||||||
|  |   var bin; | ||||||
| 
 | 
 | ||||||
|   if (!levelN) { |   if (!levelN) { | ||||||
|     levelN = posS.length; |     levelN = posS.length; | ||||||
| @ -329,30 +457,56 @@ S2.fromFacePosLevel = function (faceN, posS, levelN) { | |||||||
|     posS = posS.substr(0, levelN); |     posS = posS.substr(0, levelN); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   var posB = Long.fromString(posS, true, 4).toString(2); |   // 3-bit face value
 | ||||||
|  |   faceB = Long.fromString(faceN.toString(10), true, 10).toString(2); | ||||||
|  |   while (faceB.length < S2.FACE_BITS) { | ||||||
|  |     faceB = '0' + faceB; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // 60-bit position value
 | ||||||
|  |   posB = Long.fromString(posS, true, 4).toString(2); | ||||||
|   while (posB.length < (2 * levelN)) { |   while (posB.length < (2 * levelN)) { | ||||||
|     posB = '0' + posB; |     posB = '0' + posB; | ||||||
|   } |   } | ||||||
|   var bin = Long.fromString(faceN.toString(10), true, 10).toString(2); | 
 | ||||||
|   bin += posB; |   bin = faceB + posB; | ||||||
|  |   // 1-bit lsb marker
 | ||||||
|   bin += '1'; |   bin += '1'; | ||||||
|  |   // n-bit padding to 64-bits
 | ||||||
|   while (bin.length < (S2.FACE_BITS + S2.POS_BITS)) { |   while (bin.length < (S2.FACE_BITS + S2.POS_BITS)) { | ||||||
|     bin += '0'; |     bin += '0'; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return Long.fromString(bin, true, 2).toString(); |   return Long.fromString(bin, true, 2).toString(10); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| S2.toHilbertQuadkey = function (idS) { | S2.keyToId = S2.S2Cell.keyToId | ||||||
|  | = S2.toId = S2.toCellId = S2.fromKey | ||||||
|  | = function (key) { | ||||||
|  |   var parts = key.split('/'); | ||||||
|  | 
 | ||||||
|  |   return S2.fromFacePosLevel(parts[0], parts[1], parts[1].length); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | S2.idToKey = S2.S2Cell.idToKey | ||||||
|  | = S2.S2Cell.toKey = S2.toKey | ||||||
|  | = S2.fromId = S2.fromCellId | ||||||
|  | = S2.S2Cell.toHilbertQuadkey  = S2.toHilbertQuadkey | ||||||
|  | = function (idS) { | ||||||
|   var Long = exports.dcodeIO && exports.dcodeIO.Long || require('long'); |   var Long = exports.dcodeIO && exports.dcodeIO.Long || require('long'); | ||||||
|   var bin = Long.fromString(idS, true, 10).toString(2); |   var bin = Long.fromString(idS, true, 10).toString(2); | ||||||
|   var lsbIndex = bin.lastIndexOf('1'); |  | ||||||
| 
 | 
 | ||||||
|  |   while (bin.length < (S2.FACE_BITS + S2.POS_BITS)) { | ||||||
|  |     bin = '0' + bin; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // MUST come AFTER binstr has been left-padded with '0's
 | ||||||
|  |   var lsbIndex = bin.lastIndexOf('1'); | ||||||
|   // substr(start, len)
 |   // substr(start, len)
 | ||||||
|   // substring(start, end)
 |   // substring(start, end) // includes start, does not include end
 | ||||||
|   var faceB = bin.substr(0, 3); |   var faceB = bin.substring(0, 3); | ||||||
|   // posB will always be a multiple of 2 (or it's invalid)
 |   // posB will always be a multiple of 2 (or it's invalid)
 | ||||||
|   var posB = bin.substring(4, lsbIndex); |   var posB = bin.substring(3, lsbIndex); | ||||||
|   var levelN = posB.length / 2; |   var levelN = posB.length / 2; | ||||||
| 
 | 
 | ||||||
|   var faceS = Long.fromString(faceB, true, 2).toString(10); |   var faceS = Long.fromString(faceB, true, 2).toString(10); | ||||||
| @ -365,37 +519,76 @@ S2.toHilbertQuadkey = function (idS) { | |||||||
|   return faceS + '/' + posS; |   return faceS + '/' + posS; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| })('undefined' !== typeof window ? window : module.exports); | S2.keyToLatLng = S2.S2Cell.keyToLatLng = function (key) { | ||||||
| 
 |   var cell2 = S2.S2Cell.FromHilbertQuadKey(key); | ||||||
| (function (exports) { |   return cell2.getLatLng(); | ||||||
| 'use strict'; |  | ||||||
| 
 |  | ||||||
|   // Adapted from Leafletjs https://searchcode.com/codesearch/view/42525008/
 |  | ||||||
| 
 |  | ||||||
|   var L = {}; |  | ||||||
|   var S2 = exports.S2; |  | ||||||
| 
 |  | ||||||
|   if (!exports.L) { |  | ||||||
|     exports.L = L; |  | ||||||
|   } |  | ||||||
|   S2.L = L; |  | ||||||
| 
 |  | ||||||
|   L.LatLng = function (/*Number*/ rawLat, /*Number*/ rawLng, /*Boolean*/ noWrap) { |  | ||||||
|     var lat = parseFloat(rawLat, 10); |  | ||||||
|     var lng = parseFloat(rawLng, 10); |  | ||||||
| 
 |  | ||||||
|     if (isNaN(lat) || isNaN(lng)) { |  | ||||||
|       throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')'); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (noWrap !== true) { |  | ||||||
|       lat = Math.max(Math.min(lat, 90), -90);                 // clamp latitude into -90..90
 |  | ||||||
|       lng = (lng + 180) % 360 + ((lng < -180 || lng === 180) ? 180 : -180);   // wrap longtitude into -180..180
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return { lat: lat, lng: lng }; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|   L.LatLng.DEG_TO_RAD = Math.PI / 180; | S2.idToLatLng = S2.S2Cell.idToLatLng = function (id) { | ||||||
|   L.LatLng.RAD_TO_DEG = 180 / Math.PI; |   var key = S2.idToKey(id); | ||||||
| })('undefined' !== typeof window ? window : module.exports); |   return S2.keyToLatLng(key); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | S2.S2Cell.latLngToKey = S2.latLngToKey | ||||||
|  | = S2.latLngToQuadkey = function (lat, lng, level) { | ||||||
|  |   if (isNaN(level) || level < 1 || level > 30) { | ||||||
|  |     throw new Error("'level' is not a number between 1 and 30 (but it should be)"); | ||||||
|  |   } | ||||||
|  |   // TODO
 | ||||||
|  |   //
 | ||||||
|  |   // S2.idToLatLng(id)
 | ||||||
|  |   // S2.keyToLatLng(key)
 | ||||||
|  |   // S2.nextFace(key)     // prevent wrapping on nextKey
 | ||||||
|  |   // S2.prevFace(key)     // prevent wrapping on prevKey
 | ||||||
|  |   //
 | ||||||
|  |   // .toKeyArray(id)  // face,quadtree
 | ||||||
|  |   // .toKey(id)       // hilbert
 | ||||||
|  |   // .toPoint(id)     // ij
 | ||||||
|  |   // .toId(key)       // uint64 (as string)
 | ||||||
|  |   // .toLong(key)     // long.js
 | ||||||
|  |   // .toLatLng(id)    // object? or array?, or string (with comma)?
 | ||||||
|  |   //
 | ||||||
|  |   // maybe S2.HQ.x, S2.GPS.x, S2.CI.x?
 | ||||||
|  |   return S2.S2Cell.FromLatLng({ lat: lat, lng: lng }, level).toHilbertQuadkey(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | S2.stepKey = function (key, num) { | ||||||
|  |   var Long = exports.dcodeIO && exports.dcodeIO.Long || require('long'); | ||||||
|  |   var parts = key.split('/'); | ||||||
|  | 
 | ||||||
|  |   var faceS = parts[0]; | ||||||
|  |   var posS = parts[1]; | ||||||
|  |   var level = parts[1].length; | ||||||
|  | 
 | ||||||
|  |   var posL = Long.fromString(posS, true, 4); | ||||||
|  |   // TODO handle wrapping (0 === pos + 1)
 | ||||||
|  |   // (only on the 12 edges of the globe)
 | ||||||
|  |   var otherL; | ||||||
|  |   if (num > 0) { | ||||||
|  |     otherL = posL.add(Math.abs(num)); | ||||||
|  |   } | ||||||
|  |   else if (num < 0) { | ||||||
|  |     otherL = posL.subtract(Math.abs(num)); | ||||||
|  |   } | ||||||
|  |   var otherS = otherL.toString(4); | ||||||
|  | 
 | ||||||
|  |   if ('0' === otherS) { | ||||||
|  |     console.warning(new Error("face/position wrapping is not yet supported")); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   while (otherS.length < level) { | ||||||
|  |     otherS = '0' + otherS; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return faceS + '/' + otherS; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | S2.S2Cell.prevKey = S2.prevKey = function (key) { | ||||||
|  |   return S2.stepKey(key, -1); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | S2.S2Cell.nextKey = S2.nextKey = function (key) { | ||||||
|  |   return S2.stepKey(key, 1); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | })('undefined' !== typeof module ? module.exports : window); | ||||||
|  | |||||||
							
								
								
									
										84
									
								
								tests/conversions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								tests/conversions.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var Long = require('long'); | ||||||
|  | var s2node = require('s2geometry-node'); | ||||||
|  | var S2 = require('../src/s2geometry.js').S2; | ||||||
|  | 
 | ||||||
|  | var tests = [ | ||||||
|  |   { 'name': 'Provo, UT' | ||||||
|  |   , 'lat': 40.2574448 | ||||||
|  |   , 'lng': -111.7089464 | ||||||
|  |   , 'key': '' | ||||||
|  |   , 'id': '' | ||||||
|  |   } | ||||||
|  | , { 'name': 'Startup Building' | ||||||
|  |   , 'lat': 40.2262363 | ||||||
|  |   , 'lng': -111.6630927 | ||||||
|  |   , 'key': '' | ||||||
|  |   , 'id': '' | ||||||
|  |   } | ||||||
|  | , { 'name': "Kyderman's" | ||||||
|  |   , 'lat': 51.352085106718384 // 51.352085106718384
 | ||||||
|  |   , 'lng': -2.9877930879592896 // -2.9877930879592896
 | ||||||
|  |   , 'key': '' | ||||||
|  |   , 'id': '' | ||||||
|  |   } | ||||||
|  | , { 'name': "Toeler's" | ||||||
|  |   , 'lat': -43.525166 // -43.5261282
 | ||||||
|  |   , 'lng': 172.655096 // 172.6561085
 | ||||||
|  |   , 'key': '' | ||||||
|  |   , 'id': '' | ||||||
|  |   } | ||||||
|  | /* | ||||||
|  | , { 'name': "" | ||||||
|  |   , 'lat': 0 | ||||||
|  |   , 'lng': 0 | ||||||
|  |   , 'key': '' | ||||||
|  |   , 'id': '' | ||||||
|  |   } | ||||||
|  | */ | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | // get known-expected values
 | ||||||
|  | tests.forEach(function (loc) { | ||||||
|  |   var level = 15; | ||||||
|  |   var s2nLatLng = new s2node.S2LatLng(loc.lat, loc.lng); | ||||||
|  |   var s2nId = new s2node.S2CellId(s2nLatLng).parent(level); | ||||||
|  |   var s2nCell = new s2node.S2Cell(s2nId); | ||||||
|  | 
 | ||||||
|  |   loc.face = s2nCell.face(); | ||||||
|  |   loc.id = s2nId.id(); | ||||||
|  |   loc.key = s2nId.toString(); | ||||||
|  |   loc.lat = s2nId.toLatLng().toString().split(',')[0]; | ||||||
|  |   loc.lng = s2nId.toLatLng().toString().split(',')[1]; | ||||||
|  |   loc.level = s2nId.level(); // always 15
 | ||||||
|  |   loc.point = s2nId.toPoint()// .toArray();
 | ||||||
|  | 
 | ||||||
|  |   //console.log(JSON.stringify(loc, null, '  '));
 | ||||||
|  | 
 | ||||||
|  |   var key = S2.latLngToQuadkey(loc.lat, loc.lng, level); | ||||||
|  |   var id = S2.toId(key); | ||||||
|  |   var key2 = S2.toKey(id); | ||||||
|  |   var id2 = S2.toId(key2); | ||||||
|  | 
 | ||||||
|  |   if (loc.key !== key || loc.id !== id) { | ||||||
|  |     console.error("Error testing " + loc.name + " @ " + loc.lat + ',' + loc.lng); | ||||||
|  |     console.error("Calculated/Expected:"); | ||||||
|  |     console.error(id, ':', loc.id); | ||||||
|  |     console.error(key, " : ", loc.key); | ||||||
|  |     console.error(loc.point.x(), loc.point.y(), loc.point.z()); | ||||||
|  |     console.error(Long.fromString(id, true, 10).toString(2)); | ||||||
|  |     console.error(Long.fromString(loc.id, true, 10).toString(2)); | ||||||
|  | 
 | ||||||
|  |     throw new Error('Test Failed'); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (loc.key !== key2 || loc.id !== id2) { | ||||||
|  |     console.error("Error testing " + loc.name + " @ " + loc.lat + ',' + loc.lng); | ||||||
|  |     console.error("Secondary Key / ID conversion failed: Calculated/Expected:"); | ||||||
|  |     console.error(id2, ':', loc.id); | ||||||
|  |     console.error(key2, " : ", loc.key); | ||||||
|  | 
 | ||||||
|  |     throw new Error('Test Failed'); | ||||||
|  |   } | ||||||
|  | }); | ||||||
							
								
								
									
										79
									
								
								tests/debug.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								tests/debug.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | //var oS2 = require('./s2geometry.old.js').S2;
 | ||||||
|  | var jS2 = require('../src/s2geometry.js').S2; | ||||||
|  | var nS2 = require('s2geometry-node'); | ||||||
|  | 
 | ||||||
|  | var lat = -43.525166; | ||||||
|  | var lng = 172.655096; | ||||||
|  | //var id = '8678661352471920640';
 | ||||||
|  | 
 | ||||||
|  | var tests = [ | ||||||
|  |   [ -13.846153846153854, -41.53846153846155 ]   // face 0
 | ||||||
|  | , [ -13.846153846153854, 96.92307692307692 ]    // face 1
 | ||||||
|  | , [ 41.53846153846153, -124.61538461538463 ]    // face 2
 | ||||||
|  | , [ -152.30769230769232, 41.53846153846153 ]    // face 3
 | ||||||
|  | , [ -152.30769230769232, 69.23076923076923 ]    // face 4
 | ||||||
|  | , [ -124.61538461538463, -69.23076923076924 ]   // face 5
 | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | var tests = [ | ||||||
|  |   [ -3.9832738, 12.6825449,   'The Congo          (Africa)' ] | ||||||
|  | , [ 19.0827696, 72.7407752,   'Mumbai, India      (Asia)' ] | ||||||
|  | , [ 68.5207533, -74.9563282,  'Greenland          (North Pole)' ] | ||||||
|  | , [ -1.573289, -158.957890,   'The Pacific Ocean  (nowhere)' ] | ||||||
|  | , [ 40.2573137, -111.7091177, 'Provo, UT, USA     (Americas)' ] | ||||||
|  | , [ -46.362972,-73.7431064,   'Antarctica         (South Pole)' ] | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | var bugReports = [ | ||||||
|  |   // https://github.com/jonatkins/s2-geometry-javascript/issues/12
 | ||||||
|  |   [ -6.120097, 106.846511, '@Skeec' ] | ||||||
|  |   // https://github.com/coolaj86/s2-geometry-javascript/issues/8#issuecomment-237204759
 | ||||||
|  | , [ -33.87347601637759, 151.1954084522501 ] | ||||||
|  |   // https://github.com/Daplie/s2-geometry.js/issues/1
 | ||||||
|  | , [ 45.74528835847731, 12.5516625, '@vekexasia' ] | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | tests.concat(bugReports).forEach(function (pair, i) { | ||||||
|  |   var lat = pair[0]; | ||||||
|  |   var lng = pair[1]; | ||||||
|  |   var comment = pair[2] && ('(' + pair[2] + ')') || ''; | ||||||
|  | 
 | ||||||
|  |   console.log(''); | ||||||
|  |   console.log(''); | ||||||
|  | 
 | ||||||
|  |   if (i < 6) { | ||||||
|  |     console.log('FACE', i); | ||||||
|  |   } | ||||||
|  |   console.log('Lat/Lng', '=', lat + ',' + lng, comment); | ||||||
|  | 
 | ||||||
|  |   //
 | ||||||
|  |   // Lat / Lng to XYZ
 | ||||||
|  |   //
 | ||||||
|  |   var nS2LatLng = new nS2.S2LatLng(lat, lng).toPoint(); | ||||||
|  |   //var nXyz = [ nS2LatLng.x(), nS2LatLng.y(), nS2LatLng.z() ];
 | ||||||
|  |   //var jXyz = jS2.LatLngToXYZ({ lat: lat, lng: lng });
 | ||||||
|  |   /* | ||||||
|  |   console.log(''); | ||||||
|  |   console.log('XYZ'); | ||||||
|  |   console.log('=', nXyz); | ||||||
|  |   console.log('j', jXyz); | ||||||
|  |   */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   var nCell = new nS2.S2CellId(nS2LatLng).parent(15); | ||||||
|  |   var jCell = jS2.S2Cell.FromLatLng({ lat: lat, lng: lng }, 15); | ||||||
|  |   /* | ||||||
|  |   console.log(''); | ||||||
|  |   console.log('F,IJ,L'); | ||||||
|  |   console.log('j', jCell.toString()); | ||||||
|  |   */ | ||||||
|  | 
 | ||||||
|  |   var nKey = nCell.toString(); | ||||||
|  |   var jQuad = jCell.getFaceAndQuads(); | ||||||
|  |   var jKey = jQuad[0] + '/' + jQuad[1].join(''); | ||||||
|  |   console.log('Quadkey'); | ||||||
|  |   console.log('=', nKey); | ||||||
|  |   console.log('j', jKey, "(" + jS2.toId(jKey) + ")"); | ||||||
|  | }); | ||||||
							
								
								
									
										32
									
								
								tests/exhaustive.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/exhaustive.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var jS2 = require('../src/s2geometry.js').S2; | ||||||
|  | var nS2 = require('s2geometry-node'); | ||||||
|  | 
 | ||||||
|  | var x, y; | ||||||
|  | 
 | ||||||
|  | function checkReal(lat, lng) { | ||||||
|  |   var nS2LatLng = new nS2.S2LatLng(lat, lng).toPoint(); | ||||||
|  |   var nCell = new nS2.S2CellId(nS2LatLng).parent(15); | ||||||
|  |   var jCell = jS2.S2Cell.FromLatLng({ lat: lat, lng: lng }, 15); | ||||||
|  |   var nKey = nCell.toString(); | ||||||
|  |   var jQuad = jCell.getFaceAndQuads(); | ||||||
|  |   var jKey = jQuad[0] + '/' + jQuad[1].join(''); | ||||||
|  | 
 | ||||||
|  |   if (nKey !== jKey) { | ||||||
|  |     console.log(''); | ||||||
|  |     console.log('Quadkey'); | ||||||
|  |     console.log('=', nKey); | ||||||
|  |     console.log('j', jKey); | ||||||
|  |     throw new Error("values didn't match expected"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | console.log('Exhaustive check of about 518,400 random lat,lng coordinates of the earth (about every 0.5°)'); | ||||||
|  | console.log('(this will take several seconds)'); | ||||||
|  | for (x = -180; x <= 180; x += (0 + Math.random())) { | ||||||
|  |   for (y = -180; y <= 180; y += (0 + Math.random())) { | ||||||
|  |     checkReal(x, y); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | console.log('PASS'); | ||||||
							
								
								
									
										2053
									
								
								tests/generated-locations.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2053
									
								
								tests/generated-locations.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										36
									
								
								tests/hilbert-to-cell.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								tests/hilbert-to-cell.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var S2 = require('../src/s2geometry.js').S2; | ||||||
|  | 
 | ||||||
|  | for(var level = 1; level <= 20; level++) { | ||||||
|  | 	var success = 0; | ||||||
|  | 	var total = 0; | ||||||
|  | 	for (var x = -180.0; x < 180; x += 0.5) { | ||||||
|  | 		for (var y = -180.0; y < 180; y += 0.5) { | ||||||
|  | 
 | ||||||
|  | 				var latlng = { lat: x, lng: y }; | ||||||
|  | 				var cell = S2.S2Cell.FromLatLng(latlng, level); | ||||||
|  | 				var quadKey = cell.toHilbertQuadkey(); | ||||||
|  | 				var cell2 = S2.S2Cell.FromHilbertQuadKey(quadKey); | ||||||
|  | 
 | ||||||
|  | 				if(cell.face != cell2.face || | ||||||
|  | 					cell.ij[0] != cell2.ij[0] || | ||||||
|  | 					cell.ij[1] != cell2.ij[1] || | ||||||
|  | 					cell.level != cell2.level) | ||||||
|  | 					{ | ||||||
|  | 						/*console.log({ | ||||||
|  | 							cell: cell, | ||||||
|  | 							cell2: cell2})*/ | ||||||
|  | 
 | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						success++; | ||||||
|  | 					} | ||||||
|  | 					total++; | ||||||
|  | 				// check equal
 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	console.log("level:" + level + "\t total:" + total + "\t success:" + success); | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								tests/js-vs-go.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/js-vs-go.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var tests = require('./generated-locations.json'); | ||||||
|  | var jS2 = require('../src/s2geometry.js').S2; | ||||||
|  | 
 | ||||||
|  | function checkReal(loc) { | ||||||
|  |   var jCell = jS2.S2Cell.FromLatLng({ lat: loc.lat, lng: loc.lng }, 15); | ||||||
|  |   var jQuad = jCell.getFaceAndQuads(); | ||||||
|  |   var jKey = jQuad[0] + '/' + jQuad[1].join(''); | ||||||
|  | 
 | ||||||
|  |   if (loc.quadkey !== jKey) { | ||||||
|  |     loc.badFace = jCell.face; | ||||||
|  |     loc.badI = jCell.ij[0]; | ||||||
|  |     loc.badJ = jCell.ij[1]; | ||||||
|  |     loc.badQuad = jKey; | ||||||
|  |     loc.badId = jS2.toId(jKey); | ||||||
|  |     console.log(JSON.stringify(loc, null, '  ') + ','); | ||||||
|  |     console.log(''); | ||||||
|  |     console.log('Lat/Lng:', loc.lat, loc.lng); | ||||||
|  |     console.log(''); | ||||||
|  |     console.log('I, J:'); | ||||||
|  |     console.log('=', loc.i, loc.j); | ||||||
|  |     console.log('j', jCell.ij.join(', ')); | ||||||
|  |     console.log(''); | ||||||
|  |     console.log('Quadkey'); | ||||||
|  |     console.log('=', loc.quadkey); | ||||||
|  |     console.log('j', jKey); | ||||||
|  |     throw new Error("values didn't match expected"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | tests.forEach(checkReal); | ||||||
|  | console.log('PASS'); | ||||||
							
								
								
									
										48
									
								
								tests/key-id-to-latlng.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								tests/key-id-to-latlng.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var S2 = require('../src/s2geometry.js').S2; | ||||||
|  | var x, y; | ||||||
|  | var count = 0; | ||||||
|  | 
 | ||||||
|  | function refCheck() { | ||||||
|  |   var refKey = '4/032212303102210'; | ||||||
|  |   var latlng = { | ||||||
|  |     'lat': 40.2574448 | ||||||
|  |   , 'lng': -111.7089464 | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   var key = S2.latLngToKey(latlng.lat, latlng.lng, 15); | ||||||
|  |   if (key !== refKey) { | ||||||
|  |     throw new Error("reference doesn't match"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var latlng1 = S2.keyToLatLng('4/032212303102210'); | ||||||
|  |   var key1 = S2.latLngToKey(latlng1.lat, latlng1.lng, 15); | ||||||
|  |   if (key1 !== refKey) { | ||||||
|  |     throw new Error("reference 1 doesn't match"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var latlng2 = S2.idToLatLng('9749618446378729472'); | ||||||
|  |   var key2 = S2.latLngToKey(latlng2.lat, latlng2.lng, 15); | ||||||
|  |   if (key2 !== refKey) { | ||||||
|  |     throw new Error("reference 2 doesn't match"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function checkReal(lat, lng) { | ||||||
|  |   var key = S2.latLngToKey(lat, lng, 15); | ||||||
|  |   var latlng = S2.keyToLatLng(key); | ||||||
|  |   var key2 = S2.latLngToKey(latlng.lat, latlng.lng, 15); | ||||||
|  |   if (key !== key2) { | ||||||
|  |     throw new Error("keys do not match", latlng, key, key2); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | for (x = -180; x <= 180; x += (0 + Math.random())) { | ||||||
|  |   for (y = -180; y <= 180; y += (0 + Math.random())) { | ||||||
|  |     count += 1; | ||||||
|  |     checkReal(x, y); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | console.log('PASS:', count, 'random locations without any key mismatches'); | ||||||
							
								
								
									
										72
									
								
								tests/prev-next.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								tests/prev-next.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var S2 = require('../src/s2geometry.js').S2; | ||||||
|  | 
 | ||||||
|  | function getNeighbors(lat, lng, step) { | ||||||
|  |     //var step = 10;
 | ||||||
|  |     var level = 15; | ||||||
|  |     var origin = S2.latLngToQuadkey(lat, lng, level); | ||||||
|  |     var walk = []; | ||||||
|  |     // 10 before and 10 after
 | ||||||
|  |     var next = S2.nextKey(origin); | ||||||
|  |     var prev = S2.prevKey(origin); | ||||||
|  |     var i; | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < step; i++) { | ||||||
|  |         walk.unshift(S2.toId(prev)); | ||||||
|  |         prev = S2.prevKey(prev); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     walk.push(S2.toId(origin)); | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < step; i++) { | ||||||
|  |         // in range(10):
 | ||||||
|  |         walk.push(S2.toId(next)); | ||||||
|  |         next = S2.nextKey(next); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return walk; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | // Startup Building in Provo
 | ||||||
|  | var lat = 40.2262363; | ||||||
|  | var lng = -111.6630927; | ||||||
|  | 
 | ||||||
|  | var walk = getNeighbors(lat, lng, 5); | ||||||
|  | 
 | ||||||
|  | walk.forEach(function (cellId, i) { | ||||||
|  |   var key = S2.fromId(cellId); | ||||||
|  |   var face = parseInt(key.substr(0, 1), 10); | ||||||
|  |   var pos = key.substr(2); | ||||||
|  |   var level = pos.length; | ||||||
|  | 
 | ||||||
|  |   // TODO
 | ||||||
|  |   // S2.keyToLatLng(key);
 | ||||||
|  |   // S2.idToLatLng(id);
 | ||||||
|  | 
 | ||||||
|  |   // ! because converting CellId / HilbertQuadkey to LatLng is not implemented... yet
 | ||||||
|  |   console.log(-((walk.length - 1) / 2) + i, face, cellId, S2.fromId(cellId), '!', level); | ||||||
|  | }); | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Kyderman's test location
 | ||||||
|  | var lat = 51.352085106718384; | ||||||
|  | var lng = -2.9877930879592896; | ||||||
|  | var walk = getNeighbors(lat, lng, 5); | ||||||
|  | 
 | ||||||
|  | walk.forEach(function (cellId, i) { | ||||||
|  |   var key = S2.fromId(cellId); | ||||||
|  |   var face = parseInt(key.substr(0, 1), 10); | ||||||
|  |   var pos = key.substr(2); | ||||||
|  |   var level = pos.length; | ||||||
|  | 
 | ||||||
|  |   // TODO
 | ||||||
|  |   // S2.keyToLatLng(key);
 | ||||||
|  |   // S2.idToLatLng(id);
 | ||||||
|  | 
 | ||||||
|  |   // ! because converting CellId / HilbertQuadkey to LatLng is not implemented... yet
 | ||||||
|  |   console.log(-((walk.length - 1) / 2) + i, face, cellId, S2.fromId(cellId), '!', level); | ||||||
|  | }); | ||||||
| @ -1,15 +1,23 @@ | |||||||
| var S2 = require('s2geometry-node'); | var s2n = require('s2geometry-node'); | ||||||
| 
 | 
 | ||||||
| // Provo, UT (Center St)
 | // Provo, UT (Center St)
 | ||||||
| //var lat = 40.2574448;
 | //var lat = 40.2574448;
 | ||||||
| //var lng = -111.7089464;
 | //var lng = -111.7089464;
 | ||||||
| 
 | 
 | ||||||
| // Startup Building in Provo
 | // Startup Building in Provo
 | ||||||
| var lat = 40.2262363; | //var lat = 40.2262363;
 | ||||||
| var lng = -111.6630927; | //var lng = -111.6630927;
 | ||||||
| 
 | 
 | ||||||
| var s2latlng = new S2.S2LatLng(lat, lng); | // Kyderman's test location
 | ||||||
| var cellId = new S2.S2CellId(s2latlng).parent(15); | //var lat = 51.352085106718384;
 | ||||||
|  | //var lng = -2.9877930879592896;
 | ||||||
|  | 
 | ||||||
|  | // Toeler's test location
 | ||||||
|  | var lat = -43.5261282; | ||||||
|  | var lng = 172.6561085; | ||||||
|  | 
 | ||||||
|  | var s2nlatlng = new s2n.S2LatLng(lat, lng); | ||||||
|  | var cellId = new s2n.S2CellId(s2nlatlng).parent(15); | ||||||
| var cell; | var cell; | ||||||
| 
 | 
 | ||||||
| var walk = []; | var walk = []; | ||||||
| @ -39,6 +47,6 @@ walk.forEach(function (parts) { | |||||||
|   var i = parts[0]; |   var i = parts[0]; | ||||||
|   var cellId = parts[1]; |   var cellId = parts[1]; | ||||||
| 
 | 
 | ||||||
|   cell = new S2.S2Cell(cellId); |   cell = new s2n.S2Cell(cellId); | ||||||
|   console.log(i, cell.face(), cellId.id(), cellId.toString(), cellId.toLatLng().toString(), cellId.level()); |   console.log(i, cell.face(), cellId.id(), cellId.toString(), cellId.toLatLng().toString(), cellId.level()); | ||||||
| }); | }); | ||||||
|  | |||||||
							
								
								
									
										51
									
								
								tests/simple.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								tests/simple.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var S2 = require('../src/s2geometry.js').S2; | ||||||
|  | 
 | ||||||
|  | var lat = 40.2574448; | ||||||
|  | var lng = -111.7089464; | ||||||
|  | var level = 15; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // Convert from Lat / Lng
 | ||||||
|  | //
 | ||||||
|  | var key = S2.latLngToKey(lat, lng, level); | ||||||
|  | console.log(key); | ||||||
|  | // '4/032212303102210'
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // Convert between Hilbert Curve Quadtree Key and S2 Cell Id
 | ||||||
|  | //
 | ||||||
|  | var id = S2.keyToId(key); | ||||||
|  | console.log(id); | ||||||
|  | // '9749618446378729472'
 | ||||||
|  | 
 | ||||||
|  | var key = S2.idToKey(id); | ||||||
|  | console.log(key); | ||||||
|  | // '9749618446378729472'
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // Neighbors
 | ||||||
|  | //
 | ||||||
|  | var neighbors = S2.latLngToNeighborKeys(lat, lng, level); | ||||||
|  | console.log(neighbors); | ||||||
|  | // [ keyLeft, keyDown, keyRight, keyUp ]
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // Previous, Next, and Step
 | ||||||
|  | //
 | ||||||
|  | var nextKey = S2.nextKey(key); | ||||||
|  | console.log(nextKey); | ||||||
|  | var prevKey = S2.prevKey(key); | ||||||
|  | console.log(prevKey); | ||||||
|  | 
 | ||||||
|  | var backTenKeys = S2.stepKey(key, -10); | ||||||
|  | console.log(backTenKeys); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user