Compare commits
	
		
			36 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 | 
							
								
								
									
										153
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								README.md
									
									
									
									
									
								
							| @ -1,10 +1,86 @@ | ||||
| s2-geometry (JavaScript/ES5.1) | ||||
| ====================== | ||||
| 
 | ||||
| | 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 | ||||
| 
 | ||||
| <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? | ||||
| --------------------- | ||||
| 
 | ||||
| @ -16,15 +92,57 @@ Simple Examples | ||||
| --------------- | ||||
| 
 | ||||
| ```javascript | ||||
| 'use strict'; | ||||
| 
 | ||||
| var S2 = require('s2-geometry').S2; | ||||
| 
 | ||||
| var lat = 40.2574448; | ||||
| var lng = -111.7089464; | ||||
| 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 } | ||||
| 
 | ||||
| var key = cell.toHilbertQuadkey(); | ||||
| // | ||||
| // 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); | ||||
| ``` | ||||
| 
 | ||||
| Previous and Next | ||||
| @ -37,14 +155,16 @@ You can get the previous and next S2CellId from any given Key: | ||||
| 3. Convert the Key to an Id (uint64 string) | ||||
| 
 | ||||
| ```javascript | ||||
| var key = S2.latLngToKey(40.2574448, -111.7089464);   // '4/032212303102210' | ||||
| var id = S2.toId(key);                                // '9749618446378729472' | ||||
| 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.toId(nextKey); | ||||
| var nextId = S2.keyToId(nextKey); | ||||
| 
 | ||||
| var prevKey = S2.prevKey(key); | ||||
| var prevId = S2.toId(prevKey); | ||||
| var prevId = S2.keyToId(prevKey); | ||||
| 
 | ||||
| var backTenKeys = S2.stepKey(key, -10); | ||||
| 
 | ||||
| // See it | ||||
| console.log(prevKey);                                 // '4/032212303102203' | ||||
| @ -53,7 +173,7 @@ console.log(nextKey);                                 // '4/032212303102211' | ||||
| console.log(nextId); | ||||
| ``` | ||||
| 
 | ||||
| convert Cell Id to Quadkey | ||||
| 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) | ||||
| @ -69,7 +189,7 @@ var face = parts[0];                  // 4 | ||||
| var position = parts[1];              // '032212303102210'; | ||||
| var level = '032212303102210'.length; // 15 | ||||
| 
 | ||||
| var cellId = S2.fromFacePosLevel(face, position, level); | ||||
| var cellId = S2.facePosLevelToId(face, position, level); | ||||
| 
 | ||||
| console.log(cellId); | ||||
| ``` | ||||
| @ -83,7 +203,16 @@ Example '9749618446378729472' becomes '4/032212303102210' | ||||
| 
 | ||||
| var cellId = '9749618446378729472'; | ||||
| 
 | ||||
| var hilbertQuadkey = S2.toHilbertQuadkey(cellId); | ||||
| var hilbertQuadkey = S2.idToKey(cellId); | ||||
| 
 | ||||
| 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", | ||||
|     "test", | ||||
|     "tests" | ||||
|   ] | ||||
|   ], | ||||
|   "version": "1.2.9" | ||||
| } | ||||
|  | ||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "s2-geometry", | ||||
|   "version": "1.2.4", | ||||
|   "version": "1.2.10", | ||||
|   "description": "A pure JavaScript/ES5.1 port of Google/Niantic's S2 Geometry library (used by Ingress, Pokemon GO)", | ||||
|   "main": "src/s2geometry.js", | ||||
|   "scripts": { | ||||
| @ -8,7 +8,7 @@ | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "git+https://github.com/Daplie/s2-geometry.js.git" | ||||
|     "url": "git+https://git.coolaj86.com/coolaj86/s2-geometry.js.git" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "s2", | ||||
| @ -27,12 +27,12 @@ | ||||
|     "lat", | ||||
|     "lng" | ||||
|   ], | ||||
|   "author": "AJ ONeal <aj@daplie.com> (https://coolaj86.com/)", | ||||
|   "license": "ISC", | ||||
|   "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", | ||||
|   "license": "(MIT or Apache-2 or ISC)", | ||||
|   "bugs": { | ||||
|     "url": "https://github.com/Daplie/s2-geometry.js/issues" | ||||
|     "url": "https://git.coolaj86.com/coolaj86/s2-geometry.js/issues" | ||||
|   }, | ||||
|   "homepage": "https://github.com/Daplie/s2-geometry.js#readme", | ||||
|   "homepage": "https://git.coolaj86.com/coolaj86/s2-geometry.js#readme", | ||||
|   "dependencies": { | ||||
|     "long": "^3.2.0" | ||||
|   } | ||||
|  | ||||
| @ -22,10 +22,29 @@ | ||||
| // - i,j: they always use 30 bits, adjusting as needed. we use 0 to (1<<level)-1 instead
 | ||||
| //        (so GetSizeIJ for a cell is always 1)
 | ||||
| 
 | ||||
| (function(exports) { | ||||
| (function (exports) { | ||||
| 'use strict'; | ||||
| 
 | ||||
| var S2 = exports.S2 = {}; | ||||
| var S2 = exports.S2 = { L: {} }; | ||||
| 
 | ||||
| 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) { | ||||
| @ -181,12 +200,36 @@ S2.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
 | ||||
| // 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
 | ||||
| // 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
 | ||||
| var pointToHilbertQuadList = function(x,y,order) { | ||||
| var pointToHilbertQuadList = function(x,y,order,face) { | ||||
|   var hilbertMap = { | ||||
|     'a': [ [0,'d'], [1,'a'], [3,'b'], [2,'a'] ], | ||||
|     'b': [ [2,'b'], [1,'b'], [3,'a'], [0,'c'] ], | ||||
| @ -194,7 +237,10 @@ var pointToHilbertQuadList = function(x,y,order) { | ||||
|     '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 = []; | ||||
| 
 | ||||
|   for (var i=order-1; i>=0; i--) { | ||||
| @ -218,9 +264,59 @@ var pointToHilbertQuadList = function(x,y,order) { | ||||
| 
 | ||||
| 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
 | ||||
| S2.S2Cell.FromLatLng = function(latLng, level) { | ||||
|   if (!latLng.lat || !latLng.lng) { | ||||
|   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); | ||||
| @ -232,6 +328,7 @@ S2.S2Cell.FromLatLng = function(latLng, 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]); | ||||
| @ -286,16 +383,21 @@ S2.S2Cell.prototype.getCornerLatLngs = 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]; | ||||
| }; | ||||
| 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(''); | ||||
| }; | ||||
| 
 | ||||
| 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() { | ||||
| 
 | ||||
|   var fromFaceIJWrap = function(face,ij,level) { | ||||
| @ -342,7 +444,7 @@ S2.FACE_BITS = 3; | ||||
| S2.MAX_LEVEL = 30; | ||||
| 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 faceB; | ||||
|   var posB; | ||||
| @ -378,13 +480,19 @@ S2.fromFacePosLevel = function (faceN, posS, levelN) { | ||||
|   return Long.fromString(bin, true, 2).toString(10); | ||||
| }; | ||||
| 
 | ||||
| S2.toId = S2.toCellId = S2.fromKey = function (key) { | ||||
| 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.toKey = S2.fromId = S2.fromCellId = S2.toHilbertQuadkey = function (idS) { | ||||
| 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 bin = Long.fromString(idS, true, 10).toString(2); | ||||
| 
 | ||||
| @ -411,7 +519,21 @@ S2.toKey = S2.fromId = S2.fromCellId = S2.toHilbertQuadkey = function (idS) { | ||||
|   return faceS + '/' + posS; | ||||
| }; | ||||
| 
 | ||||
| S2.latLngToKey = S2.latLngToQuadkey = function (lat, lng, level) { | ||||
| S2.keyToLatLng = S2.S2Cell.keyToLatLng = function (key) { | ||||
|   var cell2 = S2.S2Cell.FromHilbertQuadKey(key); | ||||
|   return cell2.getLatLng(); | ||||
| }; | ||||
| 
 | ||||
| S2.idToLatLng = S2.S2Cell.idToLatLng = function (id) { | ||||
|   var key = S2.idToKey(id); | ||||
|   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)
 | ||||
| @ -461,45 +583,12 @@ S2.stepKey = function (key, num) { | ||||
|   return faceS + '/' + otherS; | ||||
| }; | ||||
| 
 | ||||
| S2.prevKey = function (key) { | ||||
| S2.S2Cell.prevKey = S2.prevKey = function (key) { | ||||
|   return S2.stepKey(key, -1); | ||||
| }; | ||||
| 
 | ||||
| S2.nextKey = function (key) { | ||||
| S2.S2Cell.nextKey = S2.nextKey = function (key) { | ||||
|   return S2.stepKey(key, 1); | ||||
| }; | ||||
| 
 | ||||
| })('undefined' !== typeof window ? window : module.exports); | ||||
| 
 | ||||
| (function (exports) { | ||||
| '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; | ||||
|   L.LatLng.RAD_TO_DEG = 180 / Math.PI; | ||||
| })('undefined' !== typeof window ? window : module.exports); | ||||
| })('undefined' !== typeof module ? module.exports : window); | ||||
|  | ||||
							
								
								
									
										101
									
								
								tests/debug.js
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								tests/debug.js
									
									
									
									
									
								
							| @ -8,43 +8,72 @@ var lat = -43.525166; | ||||
| var lng = 172.655096; | ||||
| //var id = '8678661352471920640';
 | ||||
| 
 | ||||
| console.log(''); | ||||
| console.log('Lat/Lng'); | ||||
| console.log('=', lat + ',' + lng); | ||||
| 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
 | ||||
| ]; | ||||
| 
 | ||||
| //
 | ||||
| // Lat / Lng to XYZ
 | ||||
| //
 | ||||
| var nS2LatLng = new nS2.S2LatLng(lat, lng).toPoint(); | ||||
| var nXyz = [ nS2LatLng.x(), nS2LatLng.y(), nS2LatLng.z() ]; | ||||
| //var oXyz = oS2.LatLngToXYZ({ lat: lat, lng: lng });
 | ||||
| var jXyz = jS2.LatLngToXYZ({ lat: lat, lng: lng }); | ||||
| console.log(''); | ||||
| console.log('XYZ'); | ||||
| console.log('=', nXyz); | ||||
| //console.log('o', oXyz);
 | ||||
| console.log('j', jXyz); | ||||
| 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 oCell = oS2.S2Cell.FromLatLng({ lat: lat, lng: lng }, 15);
 | ||||
| var jCell = jS2.S2Cell.FromLatLng({ lat: lat, lng: lng }, 15); | ||||
| console.log(''); | ||||
| console.log('F,IJ,L'); | ||||
| //console.log('=', cellN);
 | ||||
| //console.log('o', oCell.toString());
 | ||||
| console.log('j', jCell.toString()); | ||||
|   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 oQuad = oCell.getFaceAndQuads();
 | ||||
| //var oKey = oQuad[0] + '/' + oQuad[1].join('');
 | ||||
| var jQuad = jCell.getFaceAndQuads(); | ||||
| var jKey = jQuad[0] + '/' + jQuad[1].join(''); | ||||
| console.log(''); | ||||
| console.log('Quadkey'); | ||||
| console.log('=', nKey); | ||||
| //console.log('o', oKey);
 | ||||
| console.log('j', jKey); | ||||
| 
 | ||||
| //var nCellId = new nS2.S2CellId(id);
 | ||||
| //console.log(nCellId.toLatLng().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'); | ||||
| @ -1,4 +1,4 @@ | ||||
| var S2 = require('s2geometry-node'); | ||||
| var s2n = require('s2geometry-node'); | ||||
| 
 | ||||
| // Provo, UT (Center St)
 | ||||
| //var lat = 40.2574448;
 | ||||
| @ -16,8 +16,8 @@ var S2 = require('s2geometry-node'); | ||||
| var lat = -43.5261282; | ||||
| var lng = 172.6561085; | ||||
| 
 | ||||
| var s2latlng = new S2.S2LatLng(lat, lng); | ||||
| var cellId = new S2.S2CellId(s2latlng).parent(15); | ||||
| var s2nlatlng = new s2n.S2LatLng(lat, lng); | ||||
| var cellId = new s2n.S2CellId(s2nlatlng).parent(15); | ||||
| var cell; | ||||
| 
 | ||||
| var walk = []; | ||||
| @ -47,6 +47,6 @@ walk.forEach(function (parts) { | ||||
|   var i = parts[0]; | ||||
|   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()); | ||||
| }); | ||||
|  | ||||
							
								
								
									
										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