Compare commits
	
		
			9 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 7a10f5b562 | ||
|  | e7ecb48449 | ||
|  | 441c693bad | ||
|  | e67bb19828 | ||
|  | df6d38b5ad | ||
|  | 3a962c1956 | ||
|  | 5495dd0a53 | ||
|  | d28f0a6d3f | ||
|  | a4e97ba0a9 | 
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
								
							| @ -1,6 +1,8 @@ | |||||||
| s2-geometry (JavaScript/ES5.1) | 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**) | 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 | ||||||
| @ -118,6 +120,13 @@ var key = S2.idToKey(id); | |||||||
| // '9749618446378729472' | // '9749618446378729472' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | // | ||||||
|  | // Convert between Quadkey and Id | ||||||
|  | // | ||||||
|  | var latlng = S2.keyToLatLng(key); | ||||||
|  | var latlng = S2.idToLatLng(id); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| // | // | ||||||
| // Neighbors | // Neighbors | ||||||
| @ -198,3 +207,12 @@ 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'); | ||||||
|  | ``` | ||||||
|  | |||||||
| @ -35,5 +35,5 @@ | |||||||
|     "test", |     "test", | ||||||
|     "tests" |     "tests" | ||||||
|   ], |   ], | ||||||
|   "version": "1.2.8" |   "version": "1.2.9" | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "s2-geometry", |   "name": "s2-geometry", | ||||||
|   "version": "1.2.8", |   "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/Daplie/s2-geometry.js.git" |     "url": "git+https://git.coolaj86.com/coolaj86/s2-geometry.js.git" | ||||||
|   }, |   }, | ||||||
|   "keywords": [ |   "keywords": [ | ||||||
|     "s2", |     "s2", | ||||||
| @ -27,12 +27,12 @@ | |||||||
|     "lat", |     "lat", | ||||||
|     "lng" |     "lng" | ||||||
|   ], |   ], | ||||||
|   "author": "AJ ONeal <aj@daplie.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/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": { |   "dependencies": { | ||||||
|     "long": "^3.2.0" |     "long": "^3.2.0" | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -200,6 +200,30 @@ 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
 | // 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
 | ||||||
| @ -240,9 +264,59 @@ var pointToHilbertQuadList = function(x,y,order,face) { | |||||||
| 
 | 
 | ||||||
| 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.lng) { |   if ((!latLng.lat && latLng.lat !== 0) || (!latLng.lng && latLng.lng !== 0)) { | ||||||
|     throw new Error("Pass { lat: lat, lng: lng } to S2.S2Cell.FromLatLng"); |     throw new Error("Pass { lat: lat, lng: lng } to S2.S2Cell.FromLatLng"); | ||||||
|   } |   } | ||||||
|   var xyz = S2.LatLngToXYZ(latLng); |   var xyz = S2.LatLngToXYZ(latLng); | ||||||
| @ -254,6 +328,7 @@ S2.S2Cell.FromLatLng = function(latLng, level) { | |||||||
| 
 | 
 | ||||||
|   return S2.S2Cell.FromFaceIJ (faceuv[0], ij, level); |   return S2.S2Cell.FromFaceIJ (faceuv[0], ij, level); | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
| /* | /* | ||||||
| S2.faceIjLevelToXyz = function (face, ij, level) { | S2.faceIjLevelToXyz = function (face, ij, level) { | ||||||
|   var st = S2.IJToST(ij, level, [0.5, 0.5]); |   var st = S2.IJToST(ij, level, [0.5, 0.5]); | ||||||
| @ -444,8 +519,21 @@ S2.idToKey = S2.S2Cell.idToKey | |||||||
|   return faceS + '/' + posS; |   return faceS + '/' + posS; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 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.S2Cell.latLngToKey = S2.latLngToKey | ||||||
| = S2.latLngToQuadkey = function (lat, lng, level) { | = 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
 |   // TODO
 | ||||||
|   //
 |   //
 | ||||||
|   // S2.idToLatLng(id)
 |   // S2.idToLatLng(id)
 | ||||||
|  | |||||||
							
								
								
									
										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); | ||||||
|  | } | ||||||
							
								
								
									
										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'); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user