From 4fdf983c62d732d16f9e69a68243857f7a09db0a Mon Sep 17 00:00:00 2001 From: Tim Deubler Date: Thu, 11 Jul 2024 18:31:09 +0200 Subject: [PATCH] fix query rendered feature with layer filter refactor ray casting Signed-off-by: Tim Deubler --- packages/display/src/Map.ts | 11 +++---- packages/display/src/displays/BasicDisplay.ts | 2 +- .../display/src/displays/webgl/Display.ts | 33 +++++++++++-------- .../display/src/displays/webgl/Raycaster.ts | 13 +++----- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/packages/display/src/Map.ts b/packages/display/src/Map.ts index 2e50c9c7a..4977b0280 100644 --- a/packages/display/src/Map.ts +++ b/packages/display/src/Map.ts @@ -344,7 +344,7 @@ export class Map { private _layerChangeListener(ev) { // refresh render-data if layer is cleared - this.refresh(ev.type === 'clear'??ev.detail.layer); + this.refresh(ev.type === 'clear' ?? ev.detail.layer); } private initViewPort(): [number, number] { @@ -776,12 +776,11 @@ export class Map { if (!w && !h) { // "pixel search" skip3d = true; - layers = (layers || this._layers); - const featureInfo = this._display.getRenderedFeatureAt(x, y, layers); + const featureInfo = this._display.getRenderedFeatureAt(x, y, layers); if (featureInfo.id != null) { - const layer = layers[featureInfo.layerIndex]; - const provider = layer.getProvider(this.getZoomlevel() ^ 0); + const {layer} = featureInfo; + const provider = layer.getProvider(this.getZoomlevel() ^ 0) as FeatureProvider; const feature = provider?.search?.(featureInfo.id); if (feature) { @@ -1323,7 +1322,7 @@ export class Map { * * @param layers - the layer(s) that should be refreshed/re-rendered. */ - refresh(layers?: TileLayer | Layer | (TileLayer|Layer)[]) { + refresh(layers?: TileLayer | Layer | (TileLayer | Layer)[]) { if (!(layers instanceof Array)) { layers = [layers]; } diff --git a/packages/display/src/displays/BasicDisplay.ts b/packages/display/src/displays/BasicDisplay.ts index a9fa85b29..f1dc3baba 100644 --- a/packages/display/src/displays/BasicDisplay.ts +++ b/packages/display/src/displays/BasicDisplay.ts @@ -626,7 +626,7 @@ abstract class Display { getRenderedFeatureAt(screenX: number, screenY: number, layers?: (TileLayer | CustomLayer)[]): { id: number | string | null, z?: number, - layerIndex?: number, + layer?: TileLayer, pointWorld?: number[] } { return {id: null}; diff --git a/packages/display/src/displays/webgl/Display.ts b/packages/display/src/displays/webgl/Display.ts index f6e0aacb2..e8ab5f0b2 100644 --- a/packages/display/src/displays/webgl/Display.ts +++ b/packages/display/src/displays/webgl/Display.ts @@ -66,12 +66,18 @@ const stencilQuad = (quadkey: string, subQuadkey: string) => { return [x, y]; }; +type RendereFeatureResult = { + id: number | string | null; + z: number; + layer: TileLayer +}; export type TileBufferData = { z: number; tiled: true; b: GeometryBuffer; - layerIndex: number; + // layerIndex: number; + layer: Layer, data: { tile: ScreenTile; preview?: [string, number, number, number, number, number, number, number, number]; @@ -365,7 +371,8 @@ class WebGlDisplay extends BasicDisplay { b: buffer, z, data, - layerIndex: layer.index, + layer, + // layerIndex: layer.index, tiled } as TileBufferData; } @@ -578,14 +585,10 @@ class WebGlDisplay extends BasicDisplay { this.factory.destroy(); } - getRenderedFeatureAt(x: number, y: number, layers): { - id: number | string | null; - z: number; - layerIndex: number - } { + getRenderedFeatureAt(x: number, y: number, layers?: TileLayer[]): RendereFeatureResult { // console.time('getRenderedFeatureAt'); this.rayCaster.init(x, y, this.w, this.h, this.s, 1 / this.groundResolution); - + let intersectLayer: Layer = null; const camWorldZ = this.rayCaster.origin[2] - 0.001; const {tileBuffers, min3dZIndex} = this._zSortedTileBuffers; @@ -593,7 +596,9 @@ class WebGlDisplay extends BasicDisplay { while (i--) { let tileBuffer = tileBuffers[i]; if (!tileBuffer.tiled || !tileBuffer.b.pointerEvents) continue; // skip custom layers - let {b: buffer, z, data, tiled} = tileBuffer; + let {b: buffer, z, data, tiled, layer} = tileBuffer; + + if (layers?.indexOf(layer.layer as TileLayer) == -1) continue; let isOnTopOf3d = false; if (buffer.flat) { @@ -609,9 +614,10 @@ class WebGlDisplay extends BasicDisplay { const hitTile = this.rayCaster.intersectAABBox(tileX, tileY, 0, tileX + size, tileY + size, camWorldZ); if (!hitTile) continue; - const id = this.rayCaster.intersect(tileX, tileY, buffer, tileBuffer.layerIndex); - if (isOnTopOf3d && id != null) { - break; + const id = this.rayCaster.intersect(tileX, tileY, buffer); + if (id != null) { + intersectLayer = layer; + if (isOnTopOf3d) break; } } @@ -638,7 +644,8 @@ class WebGlDisplay extends BasicDisplay { // } // } // } - const result = this.rayCaster.getIntersectionTop(); + const result = this.rayCaster.getIntersectionTop(); + result.layer = intersectLayer?.layer as TileLayer; this.viewport(true); return result; } diff --git a/packages/display/src/displays/webgl/Raycaster.ts b/packages/display/src/displays/webgl/Raycaster.ts index a324e65de..6760b28e3 100644 --- a/packages/display/src/displays/webgl/Raycaster.ts +++ b/packages/display/src/displays/webgl/Raycaster.ts @@ -19,12 +19,12 @@ import {add, cross, dot, normalize, scale, subtract, multiply, transformMat4} from 'gl-matrix/vec3'; import {GeometryBuffer} from './buffer/GeometryBuffer'; -import {vec3} from '@here/xyz-maps-common'; export type Vec3 = [number, number, number]; +type Result = { id: number | string; z: number; pointWorld: number[] } class Raycaster { - private result: { id: number | string; z: number; layerIndex: number; pointWorld: number[] }; + private result: Result; // https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm static rayIntersectsTriangle( @@ -268,7 +268,7 @@ class Raycaster { this.result = { id: null, z: Infinity, - layerIndex: null, + // layerIndex: null, pointWorld: null }; } @@ -288,9 +288,8 @@ class Raycaster { return (z - orgZ) / dirZ; } - getIntersectionTop(): { id: number | string, z: number, layerIndex: number } { + getIntersectionTop(): Result { const {result} = this; - if (result.z != Infinity) { result.pointWorld = Raycaster.getPointAtRayLength(result.z, this.origin, this.direction); } @@ -300,8 +299,7 @@ class Raycaster { intersect( tileX: number, tileY: number, - buffer: GeometryBuffer, - layerIndex: number + buffer: GeometryBuffer ) { if (buffer.pointerEvents === false) return; @@ -311,7 +309,6 @@ class Raycaster { if (featureId != null) { result.id = featureId; - result.layerIndex = layerIndex; } return featureId; }