Skip to content

Commit

Permalink
feat: Add cellToChildren(parent, resolution)
Browse files Browse the repository at this point in the history
  • Loading branch information
donmccurdy authored Jan 22, 2025
2 parents 08d7c55 + 7a60ea7 commit cdbf057
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
26 changes: 26 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,32 @@ export function cellToParent(quadbin: Quadbin): Quadbin {
return parent;
}

/**
* Returns the children of a cell, in row-major order starting from NW and ending at SE.
*/
export function cellToChildren(quadbin: Quadbin, resolution: bigint): Quadbin[] {
if (resolution < 0 || resolution > 26 || resolution < getResolution(quadbin)) {
throw new Error('Invalid resolution');
}

const zoomLevelMask = ~(0x1fn << 52n);
const blockRange = 1n << ((resolution - ((quadbin >> 52n) & 0x1fn)) << 1n);
const sqrtBlockRange = 1n << (resolution - ((quadbin >> 52n) & 0x1fn));
const blockShift = 52n - (resolution << 1n);

const childBase =
((quadbin & zoomLevelMask) | (resolution << 52n)) & ~((blockRange - 1n) << blockShift);

const children: Quadbin[] = [];
for (let blockRow = 0n; blockRow < sqrtBlockRange; blockRow++) {
for (let blockColumn = 0n; blockColumn < sqrtBlockRange; blockColumn++) {
children.push(childBase | ((blockRow * sqrtBlockRange + blockColumn) << blockShift));
}
}

return children;
}

export function geometryToCells(geometry, resolution: bigint): Quadbin[] {
const zoom = Number(resolution);
return tiles(geometry, {
Expand Down
29 changes: 27 additions & 2 deletions test/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import test from 'tape';
import {
cellToBoundary,
tileToCell,
cellToChildren,
cellToTile,
cellToParent,
geometryToCells,
getResolution,
cellToBoundary
hexToBigInt
} from 'quadbin';

import {tileToQuadkey} from './quadkey-utils.js';
Expand All @@ -31,7 +33,7 @@ test('Quadbin conversion', async t => {
t.end();
});

test('Quadbin getParent', async t => {
test('Quadbin cellToParent', async t => {
let tile = {x: 134, y: 1238, z: 10};
const quadkey = tileToQuadkey(tile);

Expand All @@ -49,6 +51,29 @@ test('Quadbin getParent', async t => {
t.end();
});

test('Quadbin cellToChildren', async t => {
const parentTile = { z: 8, x: 59, y: 97 };
const parent = tileToCell(parentTile);

t.deepEquals(cellToChildren(parent, 8n), [parent], 'children at resolution + 0');

// Order is row major, starting from NW and ending at SE.
t.deepEquals(
cellToChildren(parent, 9n).map(cellToTile),
[
{ z: 9, x: 118, y: 194 }, // nw
{ z: 9, x: 119, y: 194 }, // ne
{ z: 9, x: 118, y: 195 }, // sw
{ z: 9, x: 119, y: 195 } // se
],
'children at resolution + 1'
);

t.deepEquals(cellToChildren(parent, 10n).length, 16, 'children at resolution + 2');

t.end();
});

// Zoom:26 test not agreeing with Python
import PointGeometry from './data/PointGeometry.json' with {type: 'json'};
import MultiPointGeometry from './data/MultiPointGeometry.json' with {type: 'json'};
Expand Down

0 comments on commit cdbf057

Please sign in to comment.