@developmentseed/deck.gl-raster 0.5.0-beta.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gpu-modules/composite-bands.d.ts +85 -0
- package/dist/gpu-modules/composite-bands.d.ts.map +1 -0
- package/dist/gpu-modules/composite-bands.js +141 -0
- package/dist/gpu-modules/composite-bands.js.map +1 -0
- package/dist/gpu-modules/cutline-bbox.d.ts +70 -0
- package/dist/gpu-modules/cutline-bbox.d.ts.map +1 -0
- package/dist/gpu-modules/cutline-bbox.js +100 -0
- package/dist/gpu-modules/cutline-bbox.js.map +1 -0
- package/dist/gpu-modules/index.d.ts +6 -0
- package/dist/gpu-modules/index.d.ts.map +1 -1
- package/dist/gpu-modules/index.js +3 -0
- package/dist/gpu-modules/index.js.map +1 -1
- package/dist/gpu-modules/linear-rescale.d.ts +39 -0
- package/dist/gpu-modules/linear-rescale.d.ts.map +1 -0
- package/dist/gpu-modules/linear-rescale.js +40 -0
- package/dist/gpu-modules/linear-rescale.js.map +1 -0
- package/dist/gpu-modules/types.d.ts +10 -1
- package/dist/gpu-modules/types.d.ts.map +1 -1
- package/dist/index.d.ts +5 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/layer-utils.d.ts +28 -0
- package/dist/layer-utils.d.ts.map +1 -0
- package/dist/layer-utils.js +56 -0
- package/dist/layer-utils.js.map +1 -0
- package/dist/mesh-layer/mesh-layer.d.ts.map +1 -1
- package/dist/mesh-layer/mesh-layer.js +10 -1
- package/dist/mesh-layer/mesh-layer.js.map +1 -1
- package/dist/multi-raster-tileset/index.d.ts +5 -0
- package/dist/multi-raster-tileset/index.d.ts.map +1 -0
- package/dist/multi-raster-tileset/index.js +3 -0
- package/dist/multi-raster-tileset/index.js.map +1 -0
- package/dist/multi-raster-tileset/multi-tileset-descriptor.d.ts +75 -0
- package/dist/multi-raster-tileset/multi-tileset-descriptor.d.ts.map +1 -0
- package/dist/multi-raster-tileset/multi-tileset-descriptor.js +97 -0
- package/dist/multi-raster-tileset/multi-tileset-descriptor.js.map +1 -0
- package/dist/multi-raster-tileset/secondary-tile-resolver.d.ts +129 -0
- package/dist/multi-raster-tileset/secondary-tile-resolver.d.ts.map +1 -0
- package/dist/multi-raster-tileset/secondary-tile-resolver.js +88 -0
- package/dist/multi-raster-tileset/secondary-tile-resolver.js.map +1 -0
- package/dist/raster-tileset/index.d.ts +4 -1
- package/dist/raster-tileset/index.d.ts.map +1 -1
- package/dist/raster-tileset/index.js +2 -1
- package/dist/raster-tileset/index.js.map +1 -1
- package/dist/raster-tileset/raster-tile-traversal.d.ts +29 -51
- package/dist/raster-tileset/raster-tile-traversal.d.ts.map +1 -1
- package/dist/raster-tileset/raster-tile-traversal.js +113 -171
- package/dist/raster-tileset/raster-tile-traversal.js.map +1 -1
- package/dist/raster-tileset/raster-tileset-2d.d.ts +8 -22
- package/dist/raster-tileset/raster-tileset-2d.d.ts.map +1 -1
- package/dist/raster-tileset/raster-tileset-2d.js +18 -81
- package/dist/raster-tileset/raster-tileset-2d.js.map +1 -1
- package/dist/raster-tileset/tile-matrix-set.d.ts +20 -0
- package/dist/raster-tileset/tile-matrix-set.d.ts.map +1 -0
- package/dist/raster-tileset/tile-matrix-set.js +121 -0
- package/dist/raster-tileset/tile-matrix-set.js.map +1 -0
- package/dist/raster-tileset/tileset-interface.d.ts +78 -0
- package/dist/raster-tileset/tileset-interface.d.ts.map +1 -0
- package/dist/raster-tileset/tileset-interface.js +2 -0
- package/dist/raster-tileset/tileset-interface.js.map +1 -0
- package/dist/raster-tileset/types.d.ts +10 -18
- package/dist/raster-tileset/types.d.ts.map +1 -1
- package/package.json +14 -14
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* This file implements tile traversal for generic 2D tilesets
|
|
3
|
-
* TileMatrixSet tile layouts.
|
|
2
|
+
* This file implements tile traversal for generic 2D tilesets.
|
|
4
3
|
*
|
|
5
4
|
* The main algorithm works as follows:
|
|
6
5
|
*
|
|
@@ -8,26 +7,29 @@
|
|
|
8
7
|
* necessarily the whole world)
|
|
9
8
|
* 2. Test if each tile is visible using viewport frustum culling
|
|
10
9
|
* 3. For visible tiles, compute distance-based LOD (Level of Detail)
|
|
11
|
-
* 4. If LOD is insufficient, recursively subdivide into
|
|
10
|
+
* 4. If LOD is insufficient, recursively subdivide into child tiles
|
|
12
11
|
* 5. Select tiles at appropriate zoom levels based on distance from camera
|
|
13
12
|
*
|
|
14
13
|
* The result is a set of tiles at varying zoom levels that efficiently
|
|
15
14
|
* cover the visible area with appropriate detail.
|
|
15
|
+
*
|
|
16
|
+
* The traversal is driven by a {@link TilesetDescriptor}, which abstracts over
|
|
17
|
+
* both OGC TileMatrixSet grids and Zarr multiscale pyramids.
|
|
16
18
|
*/
|
|
17
19
|
import type { Viewport } from "@deck.gl/core";
|
|
18
|
-
import type { TileMatrix, TileMatrixSet } from "@developmentseed/morecantile";
|
|
19
20
|
import type { OrientedBoundingBox } from "@math.gl/culling";
|
|
20
21
|
import { CullingVolume } from "@math.gl/culling";
|
|
21
|
-
import type {
|
|
22
|
+
import type { TilesetDescriptor, TilesetLevel } from "./tileset-interface.js";
|
|
23
|
+
import type { Bounds, TileIndex, ZRange } from "./types.js";
|
|
22
24
|
/**
|
|
23
|
-
* Raster Tile Node - represents a single tile in
|
|
25
|
+
* Raster Tile Node - represents a single tile in a tileset pyramid.
|
|
24
26
|
*
|
|
25
27
|
* Akin to the upstream OSMNode class.
|
|
26
28
|
*
|
|
27
29
|
* This node class uses the following coordinate system:
|
|
28
30
|
*
|
|
29
|
-
* - x: tile column (0 to
|
|
30
|
-
* - y: tile row (0 to
|
|
31
|
+
* - x: tile column (0 to TilesetLevel.matrixWidth, left to right)
|
|
32
|
+
* - y: tile row (0 to TilesetLevel.matrixHeight, top to bottom)
|
|
31
33
|
* - z: overview level. This assumes ordering where: 0 = coarsest, higher = finer
|
|
32
34
|
*/
|
|
33
35
|
export declare class RasterTileNode {
|
|
@@ -37,7 +39,7 @@ export declare class RasterTileNode {
|
|
|
37
39
|
y: number;
|
|
38
40
|
/** Zoom index assumed to be (higher = finer detail) */
|
|
39
41
|
z: number;
|
|
40
|
-
private
|
|
42
|
+
private descriptor;
|
|
41
43
|
/**
|
|
42
44
|
* Flag indicating whether any descendant of this tile is visible.
|
|
43
45
|
*
|
|
@@ -53,35 +55,32 @@ export declare class RasterTileNode {
|
|
|
53
55
|
private selected?;
|
|
54
56
|
/** A cache of the children of this node. */
|
|
55
57
|
private _children?;
|
|
56
|
-
private projectTo3857;
|
|
57
|
-
private projectTo4326;
|
|
58
58
|
/**
|
|
59
59
|
* A cached bounding volume for this tile, used for frustum culling
|
|
60
60
|
*
|
|
61
61
|
* This stores the result of `getBoundingVolume`.
|
|
62
62
|
*/
|
|
63
63
|
private _boundingVolume?;
|
|
64
|
-
constructor(x: number, y: number, z: number, {
|
|
65
|
-
|
|
66
|
-
projectTo3857: ProjectionFunction;
|
|
67
|
-
projectTo4326: ProjectionFunction;
|
|
64
|
+
constructor(x: number, y: number, z: number, { descriptor }: {
|
|
65
|
+
descriptor: TilesetDescriptor;
|
|
68
66
|
});
|
|
69
|
-
/** Get
|
|
70
|
-
get
|
|
67
|
+
/** Get the level info for this tile's z index. */
|
|
68
|
+
get level(): TilesetLevel;
|
|
71
69
|
/** Get the children of this node.
|
|
72
70
|
*
|
|
73
71
|
* Find all tiles at level this.z + 1 whose spatial extent overlaps this tile.
|
|
74
72
|
*
|
|
75
|
-
* A
|
|
76
|
-
*
|
|
73
|
+
* A tileset pyramid is not guaranteed to be a quadtree — it is a stack of
|
|
74
|
+
* independent grids. We find children by mapping the parent tile's CRS bounds
|
|
75
|
+
* into the child grid using {@link TilesetLevel.crsBoundsToTileRange}.
|
|
77
76
|
*/
|
|
78
77
|
get children(): RasterTileNode[] | null;
|
|
79
78
|
/**
|
|
80
79
|
* Recursively traverse the tile pyramid to determine if this tile (or its
|
|
81
80
|
* descendants) should be rendered.
|
|
82
81
|
*
|
|
83
|
-
* I.e.
|
|
84
|
-
* into its children
|
|
82
|
+
* I.e. "Given this tile node, should I render this tile, or should I recurse
|
|
83
|
+
* into its children?"
|
|
85
84
|
*
|
|
86
85
|
* The algorithm performs:
|
|
87
86
|
* 1. Visibility culling - reject tiles outside the view frustum
|
|
@@ -99,9 +98,9 @@ export declare class RasterTileNode {
|
|
|
99
98
|
project: ((xyz: number[]) => number[]) | null;
|
|
100
99
|
cullingVolume: CullingVolume;
|
|
101
100
|
elevationBounds: ZRange;
|
|
102
|
-
/** Minimum (coarsest)
|
|
101
|
+
/** Minimum (coarsest) overview level */
|
|
103
102
|
minZ: number;
|
|
104
|
-
/** Maximum (finest)
|
|
103
|
+
/** Maximum (finest) overview level */
|
|
105
104
|
maxZ?: number;
|
|
106
105
|
/** Optional geographic bounds filter */
|
|
107
106
|
bounds?: Bounds;
|
|
@@ -111,7 +110,7 @@ export declare class RasterTileNode {
|
|
|
111
110
|
* Recursively traverses the entire tree and gathers tiles where selected=true.
|
|
112
111
|
*
|
|
113
112
|
* @param result - Accumulator array for selected tiles
|
|
114
|
-
* @returns Array of selected
|
|
113
|
+
* @returns Array of selected RasterTileNode tiles
|
|
115
114
|
*/
|
|
116
115
|
getSelected(result?: RasterTileNode[]): RasterTileNode[];
|
|
117
116
|
/**
|
|
@@ -141,38 +140,17 @@ export declare class RasterTileNode {
|
|
|
141
140
|
private _getGenericBoundingVolume;
|
|
142
141
|
}
|
|
143
142
|
/**
|
|
144
|
-
*
|
|
143
|
+
* Get tile indices visible in viewport.
|
|
145
144
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* the corners.
|
|
145
|
+
* Uses frustum culling driven by a {@link TilesetDescriptor}, which abstracts
|
|
146
|
+
* over OGC TileMatrixSet grids and Zarr multiscale pyramids.
|
|
149
147
|
*
|
|
150
|
-
*
|
|
148
|
+
* Overview levels follow the descriptor ordering: index 0 = coarsest, higher = finer.
|
|
151
149
|
*/
|
|
152
|
-
declare function
|
|
153
|
-
x: number;
|
|
154
|
-
y: number;
|
|
155
|
-
}): [number, number, number, number];
|
|
156
|
-
/**
|
|
157
|
-
* Get tile indices visible in viewport
|
|
158
|
-
* Uses frustum culling similar to OSM implementation
|
|
159
|
-
*
|
|
160
|
-
* Overviews follow TileMatrixSet ordering: index 0 = coarsest, higher = finer
|
|
161
|
-
*/
|
|
162
|
-
export declare function getTileIndices(metadata: TileMatrixSet, opts: {
|
|
150
|
+
export declare function getTileIndices(descriptor: TilesetDescriptor, opts: {
|
|
163
151
|
viewport: Viewport;
|
|
164
152
|
maxZ: number;
|
|
165
153
|
zRange: ZRange | null;
|
|
166
|
-
|
|
167
|
-
projectTo4326: ProjectionFunction;
|
|
168
|
-
wgs84Bounds: CornerBounds;
|
|
154
|
+
wgs84Bounds: Bounds;
|
|
169
155
|
}): TileIndex[];
|
|
170
|
-
/**
|
|
171
|
-
* Exports only for use in testing
|
|
172
|
-
*/
|
|
173
|
-
export declare const __TEST_EXPORTS: {
|
|
174
|
-
computeProjectedTileBounds: typeof computeProjectedTileBounds;
|
|
175
|
-
RasterTileNode: typeof RasterTileNode;
|
|
176
|
-
};
|
|
177
|
-
export {};
|
|
178
156
|
//# sourceMappingURL=raster-tile-traversal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raster-tile-traversal.d.ts","sourceRoot":"","sources":["../../src/raster-tileset/raster-tile-traversal.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"raster-tile-traversal.d.ts","sourceRoot":"","sources":["../../src/raster-tileset/raster-tile-traversal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,aAAa,EAGd,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,KAAK,EACV,MAAM,EAIN,SAAS,EACT,MAAM,EACP,MAAM,YAAY,CAAC;AAiEpB;;;;;;;;;;GAUG;AACH,qBAAa,cAAc;IACzB,yBAAyB;IACzB,CAAC,EAAE,MAAM,CAAC;IAEV,0BAA0B;IAC1B,CAAC,EAAE,MAAM,CAAC;IAEV,uDAAuD;IACvD,CAAC,EAAE,MAAM,CAAC;IAEV,OAAO,CAAC,UAAU,CAAoB;IAEtC;;;;;OAKG;IACH,OAAO,CAAC,YAAY,CAAC,CAAU;IAE/B;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,CAAU;IAE3B,4CAA4C;IAC5C,OAAO,CAAC,SAAS,CAAC,CAA0B;IAE5C;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAAC,CAItB;gBAGA,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,EAAE,UAAU,EAAE,EAAE;QAAE,UAAU,EAAE,iBAAiB,CAAA;KAAE;IAQnD,kDAAkD;IAClD,IAAI,KAAK,IAAI,YAAY,CAExB;IAED;;;;;;;OAOG;IACH,IAAI,QAAQ,IAAI,cAAc,EAAE,GAAG,IAAI,CA+BtC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,MAAM,EAAE;QACb,QAAQ,EAAE,QAAQ,CAAC;QAEnB,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;QAE9C,aAAa,EAAE,aAAa,CAAC;QAE7B,eAAe,EAAE,MAAM,CAAC;QACxB,wCAAwC;QACxC,IAAI,EAAE,MAAM,CAAC;QACb,sCAAsC;QACtC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,wCAAwC;QACxC,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO;IAiFX;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,GAAE,cAAc,EAAO,GAAG,cAAc,EAAE;IAY5D;;;;;;OAMG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO;IAUhE;;;;;;OAMG;IACH,iBAAiB,CACf,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,CAAC,GAAG,IAAI,GAC5C;QAAE,cAAc,EAAE,mBAAmB,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE;IAgCrE;;;;OAIG;IACH,OAAO,CAAC,yBAAyB;CAiDlC;AA4GD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,iBAAiB,EAC7B,IAAI,EAAE;IACJ,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,GACA,SAAS,EAAE,CA4Fb"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* This file implements tile traversal for generic 2D tilesets
|
|
3
|
-
* TileMatrixSet tile layouts.
|
|
2
|
+
* This file implements tile traversal for generic 2D tilesets.
|
|
4
3
|
*
|
|
5
4
|
* The main algorithm works as follows:
|
|
6
5
|
*
|
|
@@ -8,14 +7,16 @@
|
|
|
8
7
|
* necessarily the whole world)
|
|
9
8
|
* 2. Test if each tile is visible using viewport frustum culling
|
|
10
9
|
* 3. For visible tiles, compute distance-based LOD (Level of Detail)
|
|
11
|
-
* 4. If LOD is insufficient, recursively subdivide into
|
|
10
|
+
* 4. If LOD is insufficient, recursively subdivide into child tiles
|
|
12
11
|
* 5. Select tiles at appropriate zoom levels based on distance from camera
|
|
13
12
|
*
|
|
14
13
|
* The result is a set of tiles at varying zoom levels that efficiently
|
|
15
14
|
* cover the visible area with appropriate detail.
|
|
15
|
+
*
|
|
16
|
+
* The traversal is driven by a {@link TilesetDescriptor}, which abstracts over
|
|
17
|
+
* both OGC TileMatrixSet grids and Zarr multiscale pyramids.
|
|
16
18
|
*/
|
|
17
19
|
import { _GlobeViewport, assert } from "@deck.gl/core";
|
|
18
|
-
import { xy_bounds } from "@developmentseed/morecantile";
|
|
19
20
|
import { CullingVolume, makeOrientedBoundingBoxFromPoints, Plane, } from "@math.gl/culling";
|
|
20
21
|
import { lngLatToWorld, worldToLngLat } from "@math.gl/web-mercator";
|
|
21
22
|
/**
|
|
@@ -74,18 +75,15 @@ const EPSG_3857_CIRCUMFERENCE = 2 * Math.PI * WGS84_ELLIPSOID_A;
|
|
|
74
75
|
const EPSG_3857_HALF_CIRCUMFERENCE = EPSG_3857_CIRCUMFERENCE / 2;
|
|
75
76
|
// Maximum latitude representable in Web Mercator (EPSG:3857), in degrees.
|
|
76
77
|
const MAX_WEB_MERCATOR_LAT = 85.05112877980659;
|
|
77
|
-
// 0.28 mm per pixel
|
|
78
|
-
// https://docs.ogc.org/is/17-083r4/17-083r4.html#toc15
|
|
79
|
-
const SCREEN_PIXEL_SIZE = 0.00028;
|
|
80
78
|
/**
|
|
81
|
-
* Raster Tile Node - represents a single tile in
|
|
79
|
+
* Raster Tile Node - represents a single tile in a tileset pyramid.
|
|
82
80
|
*
|
|
83
81
|
* Akin to the upstream OSMNode class.
|
|
84
82
|
*
|
|
85
83
|
* This node class uses the following coordinate system:
|
|
86
84
|
*
|
|
87
|
-
* - x: tile column (0 to
|
|
88
|
-
* - y: tile row (0 to
|
|
85
|
+
* - x: tile column (0 to TilesetLevel.matrixWidth, left to right)
|
|
86
|
+
* - y: tile row (0 to TilesetLevel.matrixHeight, top to bottom)
|
|
89
87
|
* - z: overview level. This assumes ordering where: 0 = coarsest, higher = finer
|
|
90
88
|
*/
|
|
91
89
|
export class RasterTileNode {
|
|
@@ -95,7 +93,7 @@ export class RasterTileNode {
|
|
|
95
93
|
y;
|
|
96
94
|
/** Zoom index assumed to be (higher = finer detail) */
|
|
97
95
|
z;
|
|
98
|
-
|
|
96
|
+
descriptor;
|
|
99
97
|
/**
|
|
100
98
|
* Flag indicating whether any descendant of this tile is visible.
|
|
101
99
|
*
|
|
@@ -111,61 +109,50 @@ export class RasterTileNode {
|
|
|
111
109
|
selected;
|
|
112
110
|
/** A cache of the children of this node. */
|
|
113
111
|
_children;
|
|
114
|
-
projectTo3857;
|
|
115
|
-
projectTo4326;
|
|
116
112
|
/**
|
|
117
113
|
* A cached bounding volume for this tile, used for frustum culling
|
|
118
114
|
*
|
|
119
115
|
* This stores the result of `getBoundingVolume`.
|
|
120
116
|
*/
|
|
121
117
|
_boundingVolume;
|
|
122
|
-
constructor(x, y, z, {
|
|
118
|
+
constructor(x, y, z, { descriptor }) {
|
|
123
119
|
this.x = x;
|
|
124
120
|
this.y = y;
|
|
125
121
|
this.z = z;
|
|
126
|
-
this.
|
|
127
|
-
this.projectTo3857 = projectTo3857;
|
|
128
|
-
this.projectTo4326 = projectTo4326;
|
|
122
|
+
this.descriptor = descriptor;
|
|
129
123
|
}
|
|
130
|
-
/** Get
|
|
131
|
-
get
|
|
132
|
-
return this.
|
|
124
|
+
/** Get the level info for this tile's z index. */
|
|
125
|
+
get level() {
|
|
126
|
+
return this.descriptor.levels[this.z];
|
|
133
127
|
}
|
|
134
128
|
/** Get the children of this node.
|
|
135
129
|
*
|
|
136
130
|
* Find all tiles at level this.z + 1 whose spatial extent overlaps this tile.
|
|
137
131
|
*
|
|
138
|
-
* A
|
|
139
|
-
*
|
|
132
|
+
* A tileset pyramid is not guaranteed to be a quadtree — it is a stack of
|
|
133
|
+
* independent grids. We find children by mapping the parent tile's CRS bounds
|
|
134
|
+
* into the child grid using {@link TilesetLevel.crsBoundsToTileRange}.
|
|
140
135
|
*/
|
|
141
136
|
get children() {
|
|
142
137
|
if (!this._children) {
|
|
143
|
-
const maxZ = this.
|
|
138
|
+
const maxZ = this.descriptor.levels.length - 1;
|
|
144
139
|
if (this.z >= maxZ) {
|
|
145
140
|
// Already at finest resolution, no children
|
|
146
141
|
this._children = null;
|
|
147
142
|
return null;
|
|
148
143
|
}
|
|
149
|
-
// In TileMatrixSet ordering: refine to z + 1 (finer detail)
|
|
150
|
-
const parentMatrix = this.tileMatrix;
|
|
151
144
|
const childZ = this.z + 1;
|
|
152
|
-
const
|
|
153
|
-
// Compute this tile's bounds in
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
y: this.y,
|
|
157
|
-
});
|
|
145
|
+
const childLevel = this.descriptor.levels[childZ];
|
|
146
|
+
// Compute this tile's bounds in the source CRS
|
|
147
|
+
const parentCorners = this.level.projectedTileCorners(this.x, this.y);
|
|
148
|
+
const parentBounds = cornersToBounds(parentCorners);
|
|
158
149
|
// Find overlapping child index range
|
|
159
|
-
const { minCol, maxCol, minRow, maxRow } =
|
|
150
|
+
const { minCol, maxCol, minRow, maxRow } = childLevel.crsBoundsToTileRange(...parentBounds);
|
|
160
151
|
const children = [];
|
|
161
|
-
const {
|
|
152
|
+
const { descriptor } = this;
|
|
162
153
|
for (let y = minRow; y <= maxRow; y++) {
|
|
163
154
|
for (let x = minCol; x <= maxCol; x++) {
|
|
164
|
-
children.push(new RasterTileNode(x, y, childZ, {
|
|
165
|
-
metadata,
|
|
166
|
-
projectTo3857,
|
|
167
|
-
projectTo4326,
|
|
168
|
-
}));
|
|
155
|
+
children.push(new RasterTileNode(x, y, childZ, { descriptor }));
|
|
169
156
|
}
|
|
170
157
|
}
|
|
171
158
|
this._children = children.length > 0 ? children : null;
|
|
@@ -176,8 +163,8 @@ export class RasterTileNode {
|
|
|
176
163
|
* Recursively traverse the tile pyramid to determine if this tile (or its
|
|
177
164
|
* descendants) should be rendered.
|
|
178
165
|
*
|
|
179
|
-
* I.e.
|
|
180
|
-
* into its children
|
|
166
|
+
* I.e. "Given this tile node, should I render this tile, or should I recurse
|
|
167
|
+
* into its children?"
|
|
181
168
|
*
|
|
182
169
|
* The algorithm performs:
|
|
183
170
|
* 1. Visibility culling - reject tiles outside the view frustum
|
|
@@ -194,7 +181,7 @@ export class RasterTileNode {
|
|
|
194
181
|
// Reset state
|
|
195
182
|
this.childVisible = false;
|
|
196
183
|
this.selected = false;
|
|
197
|
-
const { viewport, cullingVolume, elevationBounds, minZ, maxZ = this.
|
|
184
|
+
const { viewport, cullingVolume, elevationBounds, minZ, maxZ = this.descriptor.levels.length - 1, project, bounds, } = params;
|
|
198
185
|
// Get bounding volume for this tile
|
|
199
186
|
const { boundingVolume, commonSpaceBounds } = this.getBoundingVolume(elevationBounds, project);
|
|
200
187
|
// Step 1: Bounds checking
|
|
@@ -212,29 +199,14 @@ export class RasterTileNode {
|
|
|
212
199
|
const children = this.children;
|
|
213
200
|
// LOD (Level of Detail) selection (only if allowed at this level)
|
|
214
201
|
// Only select this tile if no child is visible (prevents overlapping tiles)
|
|
215
|
-
//
|
|
202
|
+
// "When pitch is low, force selection at maxZ."
|
|
216
203
|
if (!this.childVisible && this.z >= minZ) {
|
|
217
204
|
const metersPerScreenPixel = getMetersPerPixelAtBoundingVolume(boundingVolume, viewport.zoom);
|
|
218
|
-
|
|
219
|
-
const tileMetersPerPixel = this.tileMatrix.scaleDenominator * SCREEN_PIXEL_SIZE;
|
|
220
|
-
// console.log("tileMetersPerPixel", tileMetersPerPixel);
|
|
221
|
-
// const screenScaleDenominator = metersPerScreenPixel / SCREEN_PIXEL_SIZE;
|
|
222
|
-
// console.log("screenScaleDenominator", screenScaleDenominator);
|
|
223
|
-
// TODO: in the future we could try adding a bias
|
|
224
|
-
// const LOD_BIAS = 0.75;
|
|
225
|
-
// this.tileMatrix.scaleDenominator <= screenScaleDenominator * LOD_BIAS
|
|
226
|
-
// console.log(
|
|
227
|
-
// "this.tileMatrix.scaleDenominator",
|
|
228
|
-
// this.tileMatrix.scaleDenominator,
|
|
229
|
-
// );
|
|
230
|
-
// console.log(
|
|
231
|
-
// "tileMetersPerPixel <= metersPerScreenPixel",
|
|
232
|
-
// tileMetersPerPixel <= metersPerScreenPixel,
|
|
233
|
-
// );
|
|
205
|
+
const tileMetersPerPixel = this.level.metersPerPixel;
|
|
234
206
|
if (tileMetersPerPixel <= metersPerScreenPixel ||
|
|
235
207
|
this.z >= maxZ ||
|
|
236
208
|
(children === null && this.z >= minZ)) {
|
|
237
|
-
//
|
|
209
|
+
// "Select this tile when its scale is at least as detailed as the screen."
|
|
238
210
|
this.selected = true;
|
|
239
211
|
return true;
|
|
240
212
|
}
|
|
@@ -261,7 +233,7 @@ export class RasterTileNode {
|
|
|
261
233
|
* Recursively traverses the entire tree and gathers tiles where selected=true.
|
|
262
234
|
*
|
|
263
235
|
* @param result - Accumulator array for selected tiles
|
|
264
|
-
* @returns Array of selected
|
|
236
|
+
* @returns Array of selected RasterTileNode tiles
|
|
265
237
|
*/
|
|
266
238
|
getSelected(result = []) {
|
|
267
239
|
if (this.selected) {
|
|
@@ -325,13 +297,9 @@ export class RasterTileNode {
|
|
|
325
297
|
*
|
|
326
298
|
*/
|
|
327
299
|
_getGenericBoundingVolume(zRange) {
|
|
328
|
-
const tileMatrix = this.tileMatrix;
|
|
329
300
|
const [minZ, maxZ] = zRange;
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
y: this.y,
|
|
333
|
-
});
|
|
334
|
-
const refPointsEPSG3857 = sampleReferencePointsInEPSG3857(REF_POINTS_9, tileCrsBounds, this.projectTo3857, this.projectTo4326);
|
|
301
|
+
const tileCorners = this.level.projectedTileCorners(this.x, this.y);
|
|
302
|
+
const refPointsEPSG3857 = sampleReferencePointsInEPSG3857(REF_POINTS_9, tileCorners, this.descriptor.projectTo3857, this.descriptor.projectTo4326);
|
|
335
303
|
const commonSpacePositions = refPointsEPSG3857.map((xy) => rescaleEPSG3857ToCommonSpace(xy));
|
|
336
304
|
const refPointPositions = [];
|
|
337
305
|
for (const p of commonSpacePositions) {
|
|
@@ -364,24 +332,6 @@ export class RasterTileNode {
|
|
|
364
332
|
};
|
|
365
333
|
}
|
|
366
334
|
}
|
|
367
|
-
/**
|
|
368
|
-
* Compute the projected tile bounds in the tile matrix's CRS.
|
|
369
|
-
*
|
|
370
|
-
* Because it's a linear transformation from the tile index to projected bounds,
|
|
371
|
-
* we don't need to sample this for each of the reference points. We only need
|
|
372
|
-
* the corners.
|
|
373
|
-
*
|
|
374
|
-
* @return The bounding box as [minX, minY, maxX, maxY] in projected CRS.
|
|
375
|
-
*/
|
|
376
|
-
function computeProjectedTileBounds(tileMatrix, { x, y, }) {
|
|
377
|
-
const bounds = xy_bounds(tileMatrix, { x, y });
|
|
378
|
-
return [
|
|
379
|
-
bounds.lowerLeft[0],
|
|
380
|
-
bounds.lowerLeft[1],
|
|
381
|
-
bounds.upperRight[0],
|
|
382
|
-
bounds.upperRight[1],
|
|
383
|
-
];
|
|
384
|
-
}
|
|
385
335
|
/**
|
|
386
336
|
* Wrap a forward projection to EPSG:3857 so that it never returns NaN.
|
|
387
337
|
*
|
|
@@ -417,22 +367,25 @@ function makeClampedForwardTo3857(projectTo3857, projectTo4326) {
|
|
|
417
367
|
};
|
|
418
368
|
}
|
|
419
369
|
/**
|
|
420
|
-
* Sample the selected reference points in EPSG:3857
|
|
370
|
+
* Sample the selected reference points in EPSG:3857.
|
|
371
|
+
*
|
|
372
|
+
* Reference points are given as `[relX, relY]` fractions in `[0, 1]` and are
|
|
373
|
+
* bilinearly interpolated across the tile's four CRS corners. For axis-aligned
|
|
374
|
+
* tiles this is equivalent to the old AABB lerp; for rotated tiles it correctly
|
|
375
|
+
* samples the actual quadrilateral rather than its bounding box.
|
|
421
376
|
*
|
|
422
|
-
* Note that EPSG:3857 is **not** the same as deck.gl's common space
|
|
423
|
-
* common space is
|
|
424
|
-
* meters.
|
|
377
|
+
* Note that EPSG:3857 is **not** the same as deck.gl's common space — deck.gl's
|
|
378
|
+
* common space is 512 units wide, while EPSG:3857 uses meters.
|
|
425
379
|
*
|
|
426
|
-
* @param
|
|
427
|
-
* @param
|
|
380
|
+
* @param refPoints Reference points as `[relX, relY]` fractions in `[0, 1]`.
|
|
381
|
+
* @param tileCorners The four CRS corners of the tile.
|
|
428
382
|
*/
|
|
429
|
-
function sampleReferencePointsInEPSG3857(refPoints,
|
|
430
|
-
const
|
|
383
|
+
function sampleReferencePointsInEPSG3857(refPoints, tileCorners, projectTo3857, projectTo4326) {
|
|
384
|
+
const { topLeft, topRight, bottomLeft, bottomRight } = tileCorners;
|
|
431
385
|
const clampedProjectTo3857 = makeClampedForwardTo3857(projectTo3857, projectTo4326);
|
|
432
386
|
const refPointPositions = [];
|
|
433
387
|
for (const [relX, relY] of refPoints) {
|
|
434
|
-
const geoX =
|
|
435
|
-
const geoY = minY + relY * (maxY - minY);
|
|
388
|
+
const [geoX, geoY] = bilerpPoint(topLeft, topRight, bottomLeft, bottomRight, relX, relY);
|
|
436
389
|
refPointPositions.push(clampedProjectTo3857(geoX, geoY));
|
|
437
390
|
}
|
|
438
391
|
return refPointPositions;
|
|
@@ -442,10 +395,6 @@ function sampleReferencePointsInEPSG3857(refPoints, tileBounds, projectTo3857, p
|
|
|
442
395
|
*
|
|
443
396
|
* Similar to the upstream code here:
|
|
444
397
|
* https://github.com/visgl/deck.gl/blob/b0134f025148b52b91320d16768ab5d14a745328/modules/geo-layers/src/tileset-2d/tile-2d-traversal.ts#L172-L177
|
|
445
|
-
*
|
|
446
|
-
* @param {number[]} xy [xy description]
|
|
447
|
-
*
|
|
448
|
-
* @return {number} [return description]
|
|
449
398
|
*/
|
|
450
399
|
function rescaleEPSG3857ToCommonSpace([x, y]) {
|
|
451
400
|
// Clamp Y to Web Mercator bounds
|
|
@@ -456,63 +405,14 @@ function rescaleEPSG3857ToCommonSpace([x, y]) {
|
|
|
456
405
|
];
|
|
457
406
|
}
|
|
458
407
|
/**
|
|
459
|
-
*
|
|
460
|
-
* overlap a parent tile.
|
|
461
|
-
*
|
|
462
|
-
* TileMatrixSets are not guaranteed to form a strict quadtree: successive
|
|
463
|
-
* TileMatrix levels may differ by non-integer refinement ratios and may not
|
|
464
|
-
* align perfectly in tile space. As a result, parent/child relationships
|
|
465
|
-
* cannot be inferred from zoom level or resolution alone.
|
|
466
|
-
*
|
|
467
|
-
* This function determines parent→child relationships by:
|
|
468
|
-
* 1. Treating each TileMatrix as an independent, axis-aligned grid in CRS space
|
|
469
|
-
* 2. Mapping the parent tile's CRS bounding box into the child grid
|
|
470
|
-
* 3. Returning the inclusive range of child tile indices whose spatial extent
|
|
471
|
-
* intersects the parent tile
|
|
472
|
-
*
|
|
473
|
-
* The returned indices are clamped to the valid extents of the child matrix
|
|
474
|
-
* (`[0, matrixWidth)` and `[0, matrixHeight)`).
|
|
475
|
-
*
|
|
476
|
-
* Assumptions:
|
|
477
|
-
* - The TileMatrix grid is axis-aligned in CRS space
|
|
478
|
-
* - `cornerOfOrigin` is `"topLeft"`
|
|
479
|
-
* - Tiles are rectangular and uniformly sized within a TileMatrix
|
|
408
|
+
* Get tile indices visible in viewport.
|
|
480
409
|
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
* @param childMatrix The TileMatrix definition for the child zoom level
|
|
410
|
+
* Uses frustum culling driven by a {@link TilesetDescriptor}, which abstracts
|
|
411
|
+
* over OGC TileMatrixSet grids and Zarr multiscale pyramids.
|
|
484
412
|
*
|
|
485
|
-
*
|
|
486
|
-
* `{ minCol, maxCol, minRow, maxRow }`, identifying all child tiles
|
|
487
|
-
* that spatially overlap the parent tile
|
|
413
|
+
* Overview levels follow the descriptor ordering: index 0 = coarsest, higher = finer.
|
|
488
414
|
*/
|
|
489
|
-
function
|
|
490
|
-
const [pMinX, pMinY, pMaxX, pMaxY] = parentBounds;
|
|
491
|
-
const { tileWidth, tileHeight, cellSize, matrixWidth, matrixHeight, pointOfOrigin, } = childMatrix;
|
|
492
|
-
const childTileWidthCRS = tileWidth * cellSize;
|
|
493
|
-
const childTileHeightCRS = tileHeight * cellSize;
|
|
494
|
-
// Note: we assume top left origin
|
|
495
|
-
const originX = pointOfOrigin[0];
|
|
496
|
-
const originY = pointOfOrigin[1];
|
|
497
|
-
// Convert CRS bounds → tile indices
|
|
498
|
-
let minCol = Math.floor((pMinX - originX) / childTileWidthCRS);
|
|
499
|
-
let maxCol = Math.floor((pMaxX - originX) / childTileWidthCRS);
|
|
500
|
-
let minRow = Math.floor((originY - pMaxY) / childTileHeightCRS);
|
|
501
|
-
let maxRow = Math.floor((originY - pMinY) / childTileHeightCRS);
|
|
502
|
-
// Clamp to matrix bounds
|
|
503
|
-
minCol = Math.max(0, Math.min(matrixWidth - 1, minCol));
|
|
504
|
-
maxCol = Math.max(0, Math.min(matrixWidth - 1, maxCol));
|
|
505
|
-
minRow = Math.max(0, Math.min(matrixHeight - 1, minRow));
|
|
506
|
-
maxRow = Math.max(0, Math.min(matrixHeight - 1, maxRow));
|
|
507
|
-
return { minCol, maxCol, minRow, maxRow };
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Get tile indices visible in viewport
|
|
511
|
-
* Uses frustum culling similar to OSM implementation
|
|
512
|
-
*
|
|
513
|
-
* Overviews follow TileMatrixSet ordering: index 0 = coarsest, higher = finer
|
|
514
|
-
*/
|
|
515
|
-
export function getTileIndices(metadata, opts) {
|
|
415
|
+
export function getTileIndices(descriptor, opts) {
|
|
516
416
|
const { viewport, maxZ, zRange, wgs84Bounds } = opts;
|
|
517
417
|
// Only define `project` function for Globe viewports, same as upstream
|
|
518
418
|
const project = viewport instanceof _GlobeViewport && viewport.resolution
|
|
@@ -551,9 +451,7 @@ export function getTileIndices(metadata, opts) {
|
|
|
551
451
|
// In our case we want LOD to be evaluated at **all** levels, so we set the
|
|
552
452
|
// minZ to 0
|
|
553
453
|
const minZ = 0;
|
|
554
|
-
const
|
|
555
|
-
const [minLng, minLat] = lowerLeft;
|
|
556
|
-
const [maxLng, maxLat] = upperRight;
|
|
454
|
+
const [minLng, minLat, maxLng, maxLat] = wgs84Bounds;
|
|
557
455
|
const bottomLeft = lngLatToWorld([minLng, minLat]);
|
|
558
456
|
const topRight = lngLatToWorld([maxLng, maxLat]);
|
|
559
457
|
const bounds = [
|
|
@@ -562,19 +460,15 @@ export function getTileIndices(metadata, opts) {
|
|
|
562
460
|
topRight[0],
|
|
563
461
|
topRight[1],
|
|
564
462
|
];
|
|
565
|
-
// Start from coarsest
|
|
566
|
-
const
|
|
567
|
-
// Create root tiles at coarsest level
|
|
463
|
+
// Start from coarsest level
|
|
464
|
+
const rootLevel = descriptor.levels[0];
|
|
465
|
+
// Create root tiles at coarsest level.
|
|
568
466
|
// In contrary to OSM tiling, we might have more than one tile at the
|
|
569
|
-
// coarsest level (z=0)
|
|
467
|
+
// coarsest level (z=0).
|
|
570
468
|
const roots = [];
|
|
571
|
-
for (let y = 0; y <
|
|
572
|
-
for (let x = 0; x <
|
|
573
|
-
roots.push(new RasterTileNode(x, y, 0, {
|
|
574
|
-
metadata,
|
|
575
|
-
projectTo3857: opts.projectTo3857,
|
|
576
|
-
projectTo4326: opts.projectTo4326,
|
|
577
|
-
}));
|
|
469
|
+
for (let y = 0; y < rootLevel.matrixHeight; y++) {
|
|
470
|
+
for (let x = 0; x < rootLevel.matrixWidth; x++) {
|
|
471
|
+
roots.push(new RasterTileNode(x, y, 0, { descriptor }));
|
|
578
472
|
}
|
|
579
473
|
}
|
|
580
474
|
// Traverse and update visibility
|
|
@@ -616,10 +510,58 @@ function getMetersPerPixelAtBoundingVolume(boundingVolume, zoom) {
|
|
|
616
510
|
return getMetersPerPixel(lat, zoom);
|
|
617
511
|
}
|
|
618
512
|
/**
|
|
619
|
-
*
|
|
513
|
+
* Compute the axis-aligned bounding box of a rotated tile rectangle.
|
|
514
|
+
*/
|
|
515
|
+
function cornersToBounds({ topLeft, topRight, bottomLeft, bottomRight, }) {
|
|
516
|
+
const xs = [topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]];
|
|
517
|
+
const ys = [topLeft[1], topRight[1], bottomLeft[1], bottomRight[1]];
|
|
518
|
+
return [Math.min(...xs), Math.min(...ys), Math.max(...xs), Math.max(...ys)];
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Bilinearly interpolate a 2D point over a unit square.
|
|
522
|
+
*
|
|
523
|
+
* Given four corner points of a quadrilateral, this evaluates the bilinear
|
|
524
|
+
* interpolation at normalized coordinates `(x, y)` ∈ [0, 1]². The mapping is:
|
|
525
|
+
*
|
|
526
|
+
* p(x, y) =
|
|
527
|
+
* p00 * (1 - x) * (1 - y) +
|
|
528
|
+
* p10 * x * (1 - y) +
|
|
529
|
+
* p01 * (1 - x) * y +
|
|
530
|
+
* p11 * x * y
|
|
531
|
+
*
|
|
532
|
+
* where:
|
|
533
|
+
* - `p00` corresponds to (x=0, y=0) (top-left)
|
|
534
|
+
* - `p10` corresponds to (x=1, y=0) (top-right)
|
|
535
|
+
* - `p01` corresponds to (x=0, y=1) (bottom-left)
|
|
536
|
+
* - `p11` corresponds to (x=1, y=1) (bottom-right)
|
|
537
|
+
*
|
|
538
|
+
* This performs interpolation in Euclidean space (component-wise on x/y),
|
|
539
|
+
* producing a bilinear mapping from the unit square to the quadrilateral
|
|
540
|
+
* defined by the four input points.
|
|
541
|
+
*
|
|
542
|
+
* @param p00 - Point at (0, 0), typically top-left.
|
|
543
|
+
* @param p10 - Point at (1, 0), typically top-right.
|
|
544
|
+
* @param p01 - Point at (0, 1), typically bottom-left.
|
|
545
|
+
* @param p11 - Point at (1, 1), typically bottom-right.
|
|
546
|
+
* @param x - Normalized horizontal coordinate in [0, 1].
|
|
547
|
+
* @param y - Normalized vertical coordinate in [0, 1].
|
|
548
|
+
* @returns Interpolated 2D point `[x, y]`.
|
|
549
|
+
*
|
|
550
|
+
* @remarks
|
|
551
|
+
* - Reduces to linear interpolation along edges when `x = 0/1` or `y = 0/1`.
|
|
552
|
+
* - Produces an affine mapping only if the four points form a parallelogram;
|
|
553
|
+
* otherwise the interior mapping is bilinear (not affine).
|
|
554
|
+
* - No CRS or geodesic behavior is implied; inputs are treated as Cartesian
|
|
555
|
+
* coordinates.
|
|
620
556
|
*/
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
557
|
+
function bilerpPoint(p00, p10, p01, p11, x, y) {
|
|
558
|
+
const w00 = (1 - x) * (1 - y);
|
|
559
|
+
const w10 = x * (1 - y);
|
|
560
|
+
const w01 = (1 - x) * y;
|
|
561
|
+
const w11 = x * y;
|
|
562
|
+
return [
|
|
563
|
+
p00[0] * w00 + p10[0] * w10 + p01[0] * w01 + p11[0] * w11,
|
|
564
|
+
p00[1] * w00 + p10[1] * w10 + p01[1] * w01 + p11[1] * w11,
|
|
565
|
+
];
|
|
566
|
+
}
|
|
625
567
|
//# sourceMappingURL=raster-tile-traversal.js.map
|