Compare commits
	
		
			51 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 | 
							
								
								
									
										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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										174
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										174
									
								
								README.md
									
									
									
									
									
								
							@ -1,23 +1,148 @@
 | 
				
			|||||||
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 }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
					Previous and Next
 | 
				
			||||||
@ -29,31 +154,33 @@ You can get the previous and next S2CellId from any given Key:
 | 
				
			|||||||
2. Get the Previous or Next Key
 | 
					2. Get the Previous or Next Key
 | 
				
			||||||
3. Convert the Key to an Id (uint64 string)
 | 
					3. Convert the Key to an Id (uint64 string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```javascript
 | 
				
			||||||
var key = S2.latLngToKey(40.2574448, -111.7089464);
 | 
					var key = S2.latLngToKey(40.2574448, -111.7089464, 15);   // '4/032212303102210'
 | 
				
			||||||
var id = S2.toId(key);
 | 
					var id = S2.keyToId(key);                                 // '9749618446378729472'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var nextKey = S2.nextKey(key);
 | 
					var nextKey = S2.nextKey(key);
 | 
				
			||||||
var nextId = S2.toId(nextKey);
 | 
					var nextId = S2.keyToId(nextKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var prevKey = S2.prevKey(key);
 | 
					var prevKey = S2.prevKey(key);
 | 
				
			||||||
var prevId = S2.toId(prevKey);
 | 
					var prevId = S2.keyToId(prevKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var backTenKeys = S2.stepKey(key, -10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// See it
 | 
					// See it
 | 
				
			||||||
console.log(prevKey);
 | 
					console.log(prevKey);                                 // '4/032212303102203'
 | 
				
			||||||
console.log(key);
 | 
					console.log(key);                                     // '4/032212303102210'
 | 
				
			||||||
console.log(nextKey);
 | 
					console.log(nextKey);                                 // '4/032212303102211'
 | 
				
			||||||
console.log(nextId);
 | 
					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)
 | 
					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'
 | 
				
			||||||
@ -62,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);
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
@ -71,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.2.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--) {
 | 
				
			||||||
@ -206,19 +264,82 @@ var pointToHilbertQuadList = function(x,y,order) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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;
 | 
				
			||||||
@ -234,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() {
 | 
				
			||||||
@ -251,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) {
 | 
				
			||||||
@ -284,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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@ -316,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;
 | 
				
			||||||
@ -328,16 +457,22 @@ 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);
 | 
					
 | 
				
			||||||
  while (bin.length < 3) {
 | 
					  bin = faceB + posB;
 | 
				
			||||||
    bin = '0' + bin;
 | 
					  // 1-bit lsb marker
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  bin += posB;
 | 
					 | 
				
			||||||
  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';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -345,22 +480,33 @@ S2.fromFacePosLevel = function (faceN, posS, levelN) {
 | 
				
			|||||||
  return Long.fromString(bin, true, 2).toString(10);
 | 
					  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('/');
 | 
					  var parts = key.split('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return S2.fromFacePosLevel(parts[0], parts[1], parts[1].length);
 | 
					  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 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);
 | 
				
			||||||
@ -373,7 +519,21 @@ S2.toKey = S2.fromId = S2.fromCellId = S2.toHilbertQuadkey = function (idS) {
 | 
				
			|||||||
  return faceS + '/' + posS;
 | 
					  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
 | 
					  // TODO
 | 
				
			||||||
  //
 | 
					  //
 | 
				
			||||||
  // S2.idToLatLng(id)
 | 
					  // S2.idToLatLng(id)
 | 
				
			||||||
@ -423,45 +583,12 @@ S2.stepKey = function (key, num) {
 | 
				
			|||||||
  return faceS + '/' + otherS;
 | 
					  return faceS + '/' + otherS;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
S2.prevKey = function (key) {
 | 
					S2.S2Cell.prevKey = S2.prevKey = function (key) {
 | 
				
			||||||
  return S2.stepKey(key, -1);
 | 
					  return S2.stepKey(key, -1);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
S2.nextKey = function (key) {
 | 
					S2.S2Cell.nextKey = S2.nextKey = function (key) {
 | 
				
			||||||
  return S2.stepKey(key, 1);
 | 
					  return S2.stepKey(key, 1);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
})('undefined' !== typeof window ? window : module.exports);
 | 
					})('undefined' !== typeof module ? module.exports : window);
 | 
				
			||||||
 | 
					 | 
				
			||||||
(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);
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										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');
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
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;
 | 
				
			||||||
@ -9,11 +9,15 @@ var S2 = require('s2geometry-node');
 | 
				
			|||||||
//var lng = -111.6630927;
 | 
					//var lng = -111.6630927;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Kyderman's test location
 | 
					// Kyderman's test location
 | 
				
			||||||
var lat = 51.352085106718384;
 | 
					//var lat = 51.352085106718384;
 | 
				
			||||||
var lng = -2.9877930879592896;
 | 
					//var lng = -2.9877930879592896;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var s2latlng = new S2.S2LatLng(lat, lng);
 | 
					// Toeler's test location
 | 
				
			||||||
var cellId = new S2.S2CellId(s2latlng).parent(15);
 | 
					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 = [];
 | 
				
			||||||
@ -43,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