-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add cache for coveringTiles #666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,16 @@ import EdgeInsets from './edge_insets'; | |
| import {UnwrappedTileID, OverscaledTileID, CanonicalTileID} from '../source/tile_id'; | ||
| import type {PaddingOptions} from './edge_insets'; | ||
|
|
||
| type TileParameters = { | ||
| overscaledZ: number; | ||
| wrap: number; | ||
| z: number; | ||
| x: number; | ||
| y: number; | ||
| } | ||
|
|
||
| type CacheEntry = Array<TileParameters> | ||
|
|
||
| /** | ||
| * A single transform, generally used for a single tile to be | ||
| * scaled, rotated, and zoomed. | ||
|
|
@@ -53,6 +63,7 @@ class Transform { | |
| _constraining: boolean; | ||
| _posMatrixCache: {[_: string]: mat4}; | ||
| _alignedPosMatrixCache: {[_: string]: mat4}; | ||
| _coveringTilesCache: {[_: string]: CacheEntry}; | ||
|
|
||
| constructor(minZoom?: number, maxZoom?: number, minPitch?: number, maxPitch?: number, renderWorldCopies?: boolean) { | ||
| this.tileSize = 512; // constant | ||
|
|
@@ -78,6 +89,7 @@ class Transform { | |
| this._edgeInsets = new EdgeInsets(); | ||
| this._posMatrixCache = {}; | ||
| this._alignedPosMatrixCache = {}; | ||
| this._coveringTilesCache = {}; | ||
| } | ||
|
|
||
| clone(): Transform { | ||
|
|
@@ -321,13 +333,24 @@ class Transform { | |
| maxzoom?: number; | ||
| roundZoom?: boolean; | ||
| reparseOverscaled?: boolean; | ||
| renderWorldCopies?: boolean; | ||
| } | ||
| ): Array<OverscaledTileID> { | ||
| const castToOverscaledTileIDs = (cacheEntry: CacheEntry): Array<OverscaledTileID> => { | ||
| return cacheEntry.map(it => new OverscaledTileID(it.overscaledZ, it.wrap, it.z, it.x, it.y)); | ||
| }; | ||
|
|
||
| const optionsKey = JSON.stringify([options, this._renderWorldCopies]); | ||
| if (this._coveringTilesCache[optionsKey]) { | ||
| return castToOverscaledTileIDs(this._coveringTilesCache[optionsKey]); | ||
| } | ||
|
|
||
| let z = this.coveringZoomLevel(options); | ||
| const actualZ = z; | ||
|
|
||
| if (options.minzoom !== undefined && z < options.minzoom) return []; | ||
| if (options.minzoom !== undefined && z < options.minzoom) { | ||
| this._coveringTilesCache[optionsKey] = []; | ||
| return []; | ||
| } | ||
| if (options.maxzoom !== undefined && z > options.maxzoom) z = options.maxzoom; | ||
|
|
||
| const centerCoord = MercatorCoordinate.fromLngLat(this.center); | ||
|
|
@@ -358,7 +381,10 @@ class Transform { | |
|
|
||
| // Do a depth-first traversal to find visible tiles and proper levels of detail | ||
| const stack = []; | ||
| const result = []; | ||
| const preCacheEntry = [] as Array<{ | ||
| tileParameters: TileParameters; | ||
| distanceSq: number; | ||
| }>; | ||
| const maxZoom = z; | ||
| const overscaledZ = options.reparseOverscaled ? actualZ : z; | ||
|
|
||
|
|
@@ -401,8 +427,13 @@ class Transform { | |
|
|
||
| // Have we reached the target depth or is the tile too far away to be any split further? | ||
| if (it.zoom === maxZoom || (longestDim > distToSplit && it.zoom >= minZoom)) { | ||
| result.push({ | ||
| tileID: new OverscaledTileID(it.zoom === maxZoom ? overscaledZ : it.zoom, it.wrap, it.zoom, x, y), | ||
| preCacheEntry.push({ | ||
| tileParameters: { | ||
| overscaledZ: it.zoom === maxZoom ? overscaledZ : it.zoom, | ||
| wrap: it.wrap, | ||
| z: it.zoom, | ||
| x, y | ||
| }, | ||
| distanceSq: vec2.sqrLen([centerPoint[0] - 0.5 - x, centerPoint[1] - 0.5 - y]) | ||
| }); | ||
| continue; | ||
|
|
@@ -416,7 +447,10 @@ class Transform { | |
| } | ||
| } | ||
|
|
||
| return result.sort((a, b) => a.distanceSq - b.distanceSq).map(a => a.tileID); | ||
| const cacheEntry = preCacheEntry.sort((a, b) => a.distanceSq - b.distanceSq).map(a => a.tileParameters); | ||
| this._coveringTilesCache[optionsKey] = cacheEntry; | ||
|
|
||
| return castToOverscaledTileIDs(cacheEntry); | ||
| } | ||
|
|
||
| resize(width: number, height: number) { | ||
|
|
@@ -767,6 +801,7 @@ class Transform { | |
|
|
||
| this._posMatrixCache = {}; | ||
| this._alignedPosMatrixCache = {}; | ||
| this._coveringTilesCache = {}; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this the only place the cache needs to be invalidated? Is this the right place? @JannikGM
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't resize() also invalidate the cache?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. transform.zoom = 0;
expect(transform.coveringTiles(options)).toEqual([]);
transform.zoom = 1;
expect(transform.coveringTiles(options)).toEqual([
new OverscaledTileID(1, 0, 1, 0, 0),
new OverscaledTileID(1, 0, 1, 1, 0),
new OverscaledTileID(1, 0, 1, 0, 1),
new OverscaledTileID(1, 0, 1, 1, 1)]);Or like whenever someone changes
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Zoom would result in a different cache key, so it's probably ok (assuming I understand what you wrote).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are only two hard things in Computer Science: cache invalidation, naming things, and off-by-one errors. |
||
| } | ||
|
|
||
| maxPitchScaleFactor() { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to split this test into several tests and have the title to be a bit more meaningful.
As a rule of thumb, a test should not have more than one assert/expect. Although I think this rule is a bit too strict and test can have a few expects, this test is not the case.