Skip to content

Commit c3b8e28

Browse files
authored
fix: picking on non-geospatial tile layer with modelMatrix (#9703)
1 parent 54cbca9 commit c3b8e28

File tree

4 files changed

+108
-5
lines changed

4 files changed

+108
-5
lines changed

modules/geo-layers/src/tile-layer/tile-layer.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
Tileset2DProps
2727
} from '../tileset-2d/index';
2828
import {urlType, URLTemplate, getURLFromTemplate} from '../tileset-2d/index';
29+
import {Matrix4} from '@math.gl/core';
2930

3031
const defaultProps: DefaultProps<TileLayerProps> = {
3132
TilesetClass: Tileset2D,
@@ -401,6 +402,11 @@ export default class TileLayer<DataT = any, ExtraPropsT extends {} = {}> extends
401402

402403
filterSubLayer({layer, cullRect}: FilterContext) {
403404
const {tile} = (layer as Layer<{tile: Tile2DHeader}>).props;
404-
return this.state.tileset!.isTileVisible(tile, cullRect);
405+
const {modelMatrix} = this.props;
406+
return this.state.tileset!.isTileVisible(
407+
tile,
408+
cullRect,
409+
modelMatrix ? new Matrix4(modelMatrix) : null
410+
);
405411
}
406412
}

modules/geo-layers/src/tileset-2d/tileset-2d.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {Matrix4, equals, NumericArray} from '@math.gl/core';
99

1010
import {Tile2DHeader} from './tile-2d-header';
1111

12-
import {getTileIndices, tileToBoundingBox, getCullBounds} from './utils';
12+
import {getTileIndices, tileToBoundingBox, getCullBounds, transformBox} from './utils';
1313
import {Bounds, TileIndex, ZRange} from './types';
1414
import {TileLoadProps} from './types';
1515
import {memoize} from './memoize';
@@ -291,7 +291,8 @@ export class Tileset2D {
291291
// eslint-disable-next-line complexity
292292
isTileVisible(
293293
tile: Tile2DHeader,
294-
cullRect?: {x: number; y: number; width: number; height: number}
294+
cullRect?: {x: number; y: number; width: number; height: number},
295+
modelMatrix?: Matrix4 | null
295296
): boolean {
296297
if (!tile.isVisible) {
297298
return false;
@@ -303,12 +304,19 @@ export class Tileset2D {
303304
z: this._zRange,
304305
cullRect
305306
});
306-
const {bbox} = tile;
307+
let {bbox} = tile;
307308
for (const [minX, minY, maxX, maxY] of boundsArr) {
308309
let overlaps;
309310
if ('west' in bbox) {
310311
overlaps = bbox.west < maxX && bbox.east > minX && bbox.south < maxY && bbox.north > minY;
311312
} else {
313+
if (modelMatrix && !Matrix4.IDENTITY.equals(modelMatrix)) {
314+
const [left, top, right, bottom] = transformBox(
315+
[bbox.left, bbox.top, bbox.right, bbox.bottom],
316+
modelMatrix
317+
);
318+
bbox = {left, top, right, bottom};
319+
}
312320
// top/bottom could be swapped depending on the indexing system
313321
const y0 = Math.min(bbox.top, bbox.bottom);
314322
const y1 = Math.max(bbox.top, bbox.bottom);

modules/geo-layers/src/tileset-2d/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const urlType = {
3939
}
4040
};
4141

42-
function transformBox(bbox: Bounds, modelMatrix: Matrix4): Bounds {
42+
export function transformBox(bbox: Bounds, modelMatrix: Matrix4): Bounds {
4343
const transformedCoords = [
4444
// top-left
4545
modelMatrix.transformAsPoint([bbox[0], bbox[1]]),

test/modules/geo-layers/tileset-2d/tileset-2d.spec.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,95 @@ test('Tileset2D#isTileVisible', async t => {
548548
t.end();
549549
});
550550

551+
test('Tileset2D#isTileVisibleWithModelMatrix', async t => {
552+
const cullRect = {x: 0, y: 0, width: 256, height: 256};
553+
const identityMatrix = new Matrix4();
554+
const translationMatrix = new Matrix4().translate([512, 0, 0]);
555+
const rotationMatrix = new Matrix4().rotateZ(Math.PI / 2);
556+
557+
const testCases = [
558+
{
559+
title: 'identity',
560+
viewport: new OrthographicView().makeViewport({
561+
width: 1024,
562+
height: 512,
563+
viewState: {
564+
target: [512, 256, 0],
565+
zoom: 0
566+
}
567+
}),
568+
modelMatrix: identityMatrix,
569+
checks: [
570+
{id: '0-0-0', modelMatrix: identityMatrix, result: true},
571+
{id: '1-0-0', modelMatrix: identityMatrix, result: true}
572+
]
573+
},
574+
{
575+
title: 'translation',
576+
viewport: new OrthographicView().makeViewport({
577+
width: 1024,
578+
height: 512,
579+
viewState: {
580+
target: [512, 256, 0],
581+
zoom: 0
582+
}
583+
}),
584+
modelMatrix: translationMatrix,
585+
checks: [
586+
{id: '0-0-0', modelMatrix: translationMatrix, result: true},
587+
{id: '0-0-0', cullRect, modelMatrix: translationMatrix, result: false},
588+
{id: '1-0-0', modelMatrix: translationMatrix, result: false}
589+
]
590+
},
591+
{
592+
title: 'rotation',
593+
viewport: new OrthographicView().makeViewport({
594+
width: 1024,
595+
height: 512,
596+
viewState: {
597+
target: [-512, 256, 0],
598+
zoom: 0
599+
}
600+
}),
601+
modelMatrix: rotationMatrix,
602+
checks: [
603+
{id: '0-0-0', modelMatrix: rotationMatrix, result: true},
604+
{id: '0-0-0', cullRect, modelMatrix: rotationMatrix, result: false},
605+
{id: '0-1-0', modelMatrix: rotationMatrix, result: true},
606+
{id: '0-1-0', cullRect, modelMatrix: rotationMatrix, result: true}
607+
]
608+
}
609+
];
610+
611+
let viewport, options;
612+
const updateTileset = () => tileset.update(viewport, options);
613+
const tileset = new Tileset2D({
614+
getTileData,
615+
onTileLoad: updateTileset,
616+
onTileError: updateTileset
617+
});
618+
619+
for (const testCase of testCases) {
620+
t.comment(testCase.title);
621+
viewport = testCase.viewport;
622+
options = {modelMatrix: testCase.modelMatrix};
623+
624+
updateTileset();
625+
await sleep(10);
626+
627+
for (const {id, cullRect, modelMatrix, result} of testCase.checks) {
628+
const tile = tileset._cache.get(id);
629+
t.is(
630+
tileset.isTileVisible(tile, cullRect, modelMatrix),
631+
result,
632+
`isTileVisible with modelMatrix ${cullRect ? 'with cullRect ' : ''}returns correct value for ${id}`
633+
);
634+
}
635+
}
636+
637+
t.end();
638+
});
639+
551640
function validateVisibility(strategy, selectedTiles, tiles) {
552641
/* eslint-disable default-case */
553642
switch (strategy) {

0 commit comments

Comments
 (0)