mirror of
https://github.com/protomaps/PMTiles.git
synced 2026-02-04 10:51:07 +00:00
handle leaf levels other than 7
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
|||||||
getUint24,
|
getUint24,
|
||||||
getUint48,
|
getUint48,
|
||||||
queryLeafdir,
|
queryLeafdir,
|
||||||
|
queryLeafLevel,
|
||||||
queryTile,
|
queryTile,
|
||||||
parseEntry,
|
parseEntry,
|
||||||
Entry,
|
Entry,
|
||||||
@@ -79,6 +80,35 @@ test("get leafdir", (assertion) => {
|
|||||||
assertion.ok(queryTile(view, 14, 16383, 16383) === null);
|
assertion.ok(queryTile(view, 14, 16383, 16383) === null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("derive the leaf level", (assertion) => {
|
||||||
|
let data = createDirectory([
|
||||||
|
{
|
||||||
|
z: 6,
|
||||||
|
x: 3,
|
||||||
|
y: 3,
|
||||||
|
offset: 0,
|
||||||
|
length: 0,
|
||||||
|
is_dir: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
let view = new DataView(data);
|
||||||
|
let level = queryLeafLevel(view);
|
||||||
|
assertion.ok(level === 6);
|
||||||
|
data = createDirectory([
|
||||||
|
{
|
||||||
|
z: 6,
|
||||||
|
x: 3,
|
||||||
|
y: 3,
|
||||||
|
offset: 0,
|
||||||
|
length: 0,
|
||||||
|
is_dir: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
view = new DataView(data);
|
||||||
|
level = queryLeafLevel(view);
|
||||||
|
assertion.ok(level === null);
|
||||||
|
});
|
||||||
|
|
||||||
test("convert spec v1 directory to spec v2 directory", (assertion) => {
|
test("convert spec v1 directory to spec v2 directory", (assertion) => {
|
||||||
let data = createDirectory([
|
let data = createDirectory([
|
||||||
{
|
{
|
||||||
|
|||||||
112
js/pmtiles.ts
112
js/pmtiles.ts
@@ -16,6 +16,39 @@ export const getUint48 = (view: DataView, pos: number) => {
|
|||||||
return shift(view.getUint32(pos + 2, true), 16) + view.getUint16(pos, true);
|
return shift(view.getUint32(pos + 2, true), 16) + view.getUint16(pos, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface Zxy {
|
||||||
|
z: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Header {
|
||||||
|
version: number;
|
||||||
|
json_size: number;
|
||||||
|
root_entries: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Root {
|
||||||
|
header: Header;
|
||||||
|
buffer: ArrayBuffer;
|
||||||
|
dir: DataView;
|
||||||
|
// etag: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Entry {
|
||||||
|
z: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
offset: number;
|
||||||
|
length: number;
|
||||||
|
is_dir: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CachedLeaf {
|
||||||
|
lastUsed: number;
|
||||||
|
buffer: Promise<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
const compare = (
|
const compare = (
|
||||||
tz: number,
|
tz: number,
|
||||||
tx: number,
|
tx: number,
|
||||||
@@ -88,6 +121,14 @@ const queryView = (
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const queryLeafLevel = (view: DataView): number | null => {
|
||||||
|
if (view.byteLength < 17) return null;
|
||||||
|
let numEntries = view.byteLength / 17;
|
||||||
|
let entry = parseEntry(view, numEntries - 1);
|
||||||
|
if (entry.is_dir) return entry.z;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
const entrySort = (a: Entry, b: Entry): number => {
|
const entrySort = (a: Entry, b: Entry): number => {
|
||||||
if (a.is_dir && !b.is_dir) {
|
if (a.is_dir && !b.is_dir) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -159,47 +200,17 @@ export const createDirectory = (entries: Entry[]): ArrayBuffer => {
|
|||||||
return buffer;
|
return buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Zxy {
|
export const deriveLeaf = (root: Root, tile: Zxy): Zxy | null => {
|
||||||
z: number;
|
const leaf_level = queryLeafLevel(root.dir);
|
||||||
x: number;
|
if (leaf_level) {
|
||||||
y: number;
|
let level_diff = tile.z - leaf_level;
|
||||||
}
|
let leaf_x = Math.trunc(tile.x / (1 << level_diff));
|
||||||
|
let leaf_y = Math.trunc(tile.y / (1 << level_diff));
|
||||||
// TODO: handle different leaf levels
|
return { z: leaf_level, x: leaf_x, y: leaf_y };
|
||||||
export const deriveLeaf = (tile: Zxy): Zxy => {
|
}
|
||||||
let z7_tile_diff = tile.z - 7;
|
return null;
|
||||||
let z7_x = Math.trunc(tile.x / (1 << z7_tile_diff));
|
|
||||||
let z7_y = Math.trunc(tile.y / (1 << z7_tile_diff));
|
|
||||||
return { z: 7, x: z7_x, y: z7_y };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Header {
|
|
||||||
version: number;
|
|
||||||
json_size: number;
|
|
||||||
root_entries: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Root {
|
|
||||||
header: Header;
|
|
||||||
buffer: ArrayBuffer;
|
|
||||||
dir: DataView;
|
|
||||||
// etag: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Entry {
|
|
||||||
z: number;
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
offset: number;
|
|
||||||
length: number;
|
|
||||||
is_dir: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CachedLeaf {
|
|
||||||
lastUsed: number;
|
|
||||||
buffer: Promise<ArrayBuffer>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const parseHeader = (dataview: DataView): Header => {
|
export const parseHeader = (dataview: DataView): Header => {
|
||||||
var magic = dataview.getUint16(0, true);
|
var magic = dataview.getUint16(0, true);
|
||||||
if (magic !== 19792) {
|
if (magic !== 19792) {
|
||||||
@@ -329,17 +340,18 @@ export class PMTiles {
|
|||||||
let entry = queryTile(root.dir, z, x, y);
|
let entry = queryTile(root.dir, z, x, y);
|
||||||
if (entry) return entry;
|
if (entry) return entry;
|
||||||
|
|
||||||
let leafcoords = deriveLeaf({ z: z, x: x, y: y });
|
let leafcoords = deriveLeaf(root, { z: z, x: x, y: y });
|
||||||
let leafdir_entry = queryLeafdir(
|
if (leafcoords) {
|
||||||
root.dir,
|
let leafdir_entry = queryLeafdir(
|
||||||
leafcoords.z,
|
root.dir,
|
||||||
leafcoords.x,
|
leafcoords.z,
|
||||||
leafcoords.y
|
leafcoords.x,
|
||||||
);
|
leafcoords.y
|
||||||
|
);
|
||||||
if (leafdir_entry) {
|
if (leafdir_entry) {
|
||||||
let leafdir = await this.getLeafdir(root.header.version, leafdir_entry);
|
let leafdir = await this.getLeafdir(root.header.version, leafdir_entry);
|
||||||
return queryTile(new DataView(leafdir), z, x, y);
|
return queryTile(new DataView(leafdir), z, x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user