From 33a1ece5367a610a28f594fd328420362c17bdb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 13 Jun 2024 14:33:02 +0200 Subject: [PATCH 01/10] feat: expose Overlay3DCollection --- viewer/api-entry-points/core.ts | 8 ++- .../3d-overlays/src/Overlay3DCollection.ts | 48 ++++++++++++++++-- .../tools/src/Overlay3D/Overlay3DTool.ts | 49 +++++++------------ 3 files changed, 68 insertions(+), 37 deletions(-) diff --git a/viewer/api-entry-points/core.ts b/viewer/api-entry-points/core.ts index 4b89e6f8638..638ec9c4d17 100644 --- a/viewer/api-entry-points/core.ts +++ b/viewer/api-entry-points/core.ts @@ -116,4 +116,10 @@ export { Image360AnnotationFilterOptions } from '../packages/360-images'; -export { OverlayCollection, OverlayInfo, Overlay3D, DefaultOverlay3DContentType } from '../packages/3d-overlays'; +export { + OverlayCollection, + Overlay3DCollection, + OverlayInfo, + Overlay3D, + DefaultOverlay3DContentType +} from '../packages/3d-overlays'; diff --git a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts index 98750427944..6e77c2f4bbe 100644 --- a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts +++ b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts @@ -2,12 +2,14 @@ * Copyright 2023 Cognite AS */ -import { CanvasTexture, Color, Texture, Object3D, type Camera } from 'three'; +import { CanvasTexture, Color, Texture, Object3D, Camera, WebGLRenderer, Scene, Vector2, Raycaster } from 'three'; import { Overlay3DIcon } from './Overlay3DIcon'; import { Overlay3D } from './Overlay3D'; import { OverlayPointsObject } from './OverlayPointsObject'; import { IconOctree } from './IconOctree'; import { DefaultOverlay3DContentType, OverlayCollection, OverlayInfo } from './OverlayCollection'; +import { minBy } from 'lodash'; +import { CameraManager } from '@reveal/camera-manager'; export type Overlay3DCollectionOptions = { overlayTexture?: Texture; @@ -34,8 +36,16 @@ export class Overlay3DCollection private _overlays: Overlay3DIcon[]; //@ts-ignore Will be removed when clustering is added. private _octree: IconOctree; + private _previousRenderCamera: Camera | undefined; + private readonly _rayCaster = new Raycaster(); - constructor(overlayInfos?: OverlayInfo[], options?: Overlay3DCollectionOptions) { + private _cameraManager: CameraManager; + + constructor( + overlayInfos: OverlayInfo[], + cameraManager: CameraManager, + options?: Overlay3DCollectionOptions + ) { super(); this.defaultOverlayColor = options?.defaultOverlayColor ?? this.defaultOverlayColor; @@ -55,6 +65,8 @@ export class Overlay3DCollection }); this._overlays = this.initializeOverlay3DIcons(overlayInfos ?? []); + this._cameraManager = cameraManager; + cameraManager.on('cameraChange', () => this.onCameraChange(this._cameraManager.getCamera())); this.add(this._overlayPoints); this.updatePointsObject(); @@ -62,6 +74,20 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } + onCameraChange = (camera: Camera): void => { + if (this._previousRenderCamera !== undefined && camera.matrix.equals(this._previousRenderCamera.matrix)) { + return; + } + + this.sortOverlaysRelativeToCamera(camera); + + if (this._previousRenderCamera === undefined) { + this._previousRenderCamera = camera.clone(); + } + + this._previousRenderCamera.copy(camera); + }; + setVisibility(visibility: boolean): void { this._overlayPoints.visible = visibility; } @@ -83,11 +109,10 @@ export class Overlay3DCollection return newIcons; } - sortOverlaysRelativeToCamera(camera: Camera): void { + private sortOverlaysRelativeToCamera(camera: Camera): void { this._overlays = this._overlays.sort((a, b) => { return b.getPosition().distanceToSquared(camera.position) - a.getPosition().distanceToSquared(camera.position); }); - this.updatePointsObject(); } @@ -105,6 +130,21 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } + public intersectOverlays(normalizedCoordinates: Vector2): Overlay3DIcon | undefined { + const camera = this._previousRenderCamera; + if (camera === undefined) { + return undefined; + } + + this._rayCaster.setFromCamera(normalizedCoordinates.clone(), camera); + + const intersections = this._overlays.filter(icon => { + return icon.getVisible() && icon.intersect(this._rayCaster.ray) !== null; + }); + + return minBy(intersections, a => a.getPosition().clone().sub(this._rayCaster.ray.origin).length()); + } + private rebuildOctree(): IconOctree { const icons = this._overlays as Overlay3DIcon[]; const octreeBounds = IconOctree.getMinimalOctreeBoundsFromIcons(icons); diff --git a/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts b/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts index 9e8b324f69a..6b586b794dd 100644 --- a/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts +++ b/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts @@ -84,8 +84,6 @@ export class Overlay3DTool extends Co private readonly _defaultOverlayColor: THREE.Color = new THREE.Color('#fbe50b'); private readonly _defaultTextOverlayToCursorOffset = 20; - private readonly _temporaryVec = new THREE.Vector2(); - private readonly _raycaster = new THREE.Raycaster(); private _overlayCollections: Overlay3DCollection[] = []; private _isVisible = true; @@ -122,14 +120,9 @@ export class Overlay3DTool extends Co ): OverlayCollection { const { _viewer: viewer } = this; - const points = new Overlay3DCollection(overlays, { - defaultOverlayColor: options?.defaultOverlayColor ?? this._defaultOverlayColor, - overlayTexture: options?.overlayTexture, - overlayTextureMask: options?.overlayTextureMask - }); - - viewer.on('cameraChange', () => { - points.sortOverlaysRelativeToCamera(viewer.cameraManager.getCamera()); + const points = new Overlay3DCollection(overlays ?? [], viewer.cameraManager, { + ...options, + defaultOverlayColor: options?.defaultOverlayColor ?? this._defaultOverlayColor }); this._overlayCollections.push(points); @@ -303,43 +296,35 @@ export class Overlay3DTool extends Co } private intersectPointsMarkers(mouseCoords: { offsetX: number; offsetY: number }): Overlay3DIcon | null { - const { _viewer, _raycaster, _temporaryVec } = this; + const { _viewer } = this; - const pixelCoords = getNormalizedPixelCoordinates(_viewer.domElement, mouseCoords.offsetX, mouseCoords.offsetY); + const normalizedCoordinates = getNormalizedPixelCoordinates( + _viewer.domElement, + mouseCoords.offsetX, + mouseCoords.offsetY + ); const camera = _viewer.cameraManager.getCamera(); const cameraDirection = camera.getWorldDirection(new THREE.Vector3()); - _raycaster.setFromCamera(_temporaryVec.copy(pixelCoords), camera); - let intersection: [Overlay3DIcon, THREE.Vector3][] = []; + const intersections: [Overlay3DIcon, THREE.Vector3][] = []; for (const points of this._overlayCollections) { - for (const icon of points.getOverlays() as Overlay3DIcon[]) { - if (icon.getVisible()) { - const inter = icon.intersect(_raycaster.ray); - if (inter) { - intersection.push([icon, inter]); - icon.updateAdaptiveScale({ - camera, - renderSize: _viewer.renderParameters.renderSize, - domElement: _viewer.canvas - }); - } - } + const intersection = points.intersectOverlays(normalizedCoordinates); + if (intersection !== undefined) { + intersections.push([intersection, intersection.getPosition().clone()]); } } - intersection = intersection.filter(([icon, _]) => icon.intersect(_raycaster.ray) !== null); - - intersection = intersection + const sortedIntersections = intersections .map( ([icon, intersection]) => - [icon, intersection.sub(_raycaster.ray.origin)] as [Overlay3DIcon, THREE.Vector3] + [icon, intersection.sub(camera.position)] as [Overlay3DIcon, THREE.Vector3] ) .filter(([, intersection]) => intersection.dot(cameraDirection) > 0) .sort((a, b) => a[1].length() - b[1].length()); - if (intersection.length > 0) { - const intersectedOverlay = intersection[0][0]; + if (sortedIntersections.length > 0) { + const intersectedOverlay = sortedIntersections[0][0]; return intersectedOverlay; } From 592bd8817c225f4c95023d42a517ee1b2a732728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 13 Jun 2024 15:01:28 +0200 Subject: [PATCH 02/10] chore: reformat, small rewrites --- viewer/api-entry-points/core.ts | 1 + viewer/packages/3d-overlays/index.ts | 2 +- viewer/packages/3d-overlays/src/IconOctree.ts | 7 +++-- .../3d-overlays/src/Overlay3DCollection.ts | 16 +++++----- .../tools/src/Overlay3D/Overlay3DTool.ts | 2 +- viewer/reveal.api.md | 31 +++++++++++++++++++ 6 files changed, 46 insertions(+), 13 deletions(-) diff --git a/viewer/api-entry-points/core.ts b/viewer/api-entry-points/core.ts index 638ec9c4d17..13384f28d32 100644 --- a/viewer/api-entry-points/core.ts +++ b/viewer/api-entry-points/core.ts @@ -119,6 +119,7 @@ export { export { OverlayCollection, Overlay3DCollection, + Overlay3DCollectionOptions, OverlayInfo, Overlay3D, DefaultOverlay3DContentType diff --git a/viewer/packages/3d-overlays/index.ts b/viewer/packages/3d-overlays/index.ts index 91a0a8831af..c931c2bfc11 100644 --- a/viewer/packages/3d-overlays/index.ts +++ b/viewer/packages/3d-overlays/index.ts @@ -1,7 +1,7 @@ /*! * Copyright 2023 Cognite AS */ -export { Overlay3DCollection } from './src/Overlay3DCollection'; +export { Overlay3DCollection, Overlay3DCollectionOptions } from './src/Overlay3DCollection'; export { OverlayPointsObject, OverlayPointsParameters } from './src/OverlayPointsObject'; export { Overlay3DIcon } from './src/Overlay3DIcon'; export { Overlay3D } from './src/Overlay3D'; diff --git a/viewer/packages/3d-overlays/src/IconOctree.ts b/viewer/packages/3d-overlays/src/IconOctree.ts index d8afb7b36b4..12d3ec8aed8 100644 --- a/viewer/packages/3d-overlays/src/IconOctree.ts +++ b/viewer/packages/3d-overlays/src/IconOctree.ts @@ -9,20 +9,21 @@ import pullAll from 'lodash/pullAll'; import { Node, PointOctant, PointOctree } from 'sparse-octree'; import { Box3, Matrix4, Vector3 } from 'three'; import { Overlay3DIcon } from './Overlay3DIcon'; +import { DefaultOverlay3DContentType } from './OverlayCollection'; type NodeMetadata = { icon: Overlay3DIcon; level: number; }; -export class IconOctree extends PointOctree { +export class IconOctree extends PointOctree> { private readonly _nodeCenters: Map; - public static getMinimalOctreeBoundsFromIcons(icons: Overlay3DIcon[]): Box3 { + public static getMinimalOctreeBoundsFromIcons(icons: Overlay3DIcon[]): Box3 { return new Box3().setFromPoints(icons.map(icon => icon.getPosition())); } - constructor(icons: Overlay3DIcon[], bounds: Box3, maxLeafSize: number) { + constructor(icons: Overlay3DIcon[], bounds: Box3, maxLeafSize: number) { super(bounds.min, bounds.max, 0, maxLeafSize); icons.forEach(icon => this.set(icon.getPosition(), icon)); this.filterEmptyLeaves(); diff --git a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts index 6e77c2f4bbe..8568e6f8dfa 100644 --- a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts +++ b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts @@ -2,13 +2,13 @@ * Copyright 2023 Cognite AS */ -import { CanvasTexture, Color, Texture, Object3D, Camera, WebGLRenderer, Scene, Vector2, Raycaster } from 'three'; +import { CanvasTexture, Color, Texture, Object3D, Camera, Vector2, Raycaster } from 'three'; import { Overlay3DIcon } from './Overlay3DIcon'; import { Overlay3D } from './Overlay3D'; import { OverlayPointsObject } from './OverlayPointsObject'; import { IconOctree } from './IconOctree'; import { DefaultOverlay3DContentType, OverlayCollection, OverlayInfo } from './OverlayCollection'; -import { minBy } from 'lodash'; +import minBy from 'lodash/minBy'; import { CameraManager } from '@reveal/camera-manager'; export type Overlay3DCollectionOptions = { @@ -35,11 +35,11 @@ export class Overlay3DCollection private readonly _iconRadius = 0.4; private _overlays: Overlay3DIcon[]; //@ts-ignore Will be removed when clustering is added. - private _octree: IconOctree; + private _octree: IconOctree; private _previousRenderCamera: Camera | undefined; private readonly _rayCaster = new Raycaster(); - private _cameraManager: CameraManager; + private readonly _cameraManager: CameraManager; constructor( overlayInfos: OverlayInfo[], @@ -130,7 +130,7 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } - public intersectOverlays(normalizedCoordinates: Vector2): Overlay3DIcon | undefined { + public intersectOverlays(normalizedCoordinates: Vector2): Overlay3D | undefined { const camera = this._previousRenderCamera; if (camera === undefined) { return undefined; @@ -145,11 +145,11 @@ export class Overlay3DCollection return minBy(intersections, a => a.getPosition().clone().sub(this._rayCaster.ray.origin).length()); } - private rebuildOctree(): IconOctree { - const icons = this._overlays as Overlay3DIcon[]; + private rebuildOctree(): IconOctree { + const icons = this._overlays; const octreeBounds = IconOctree.getMinimalOctreeBoundsFromIcons(icons); - return new IconOctree(icons, octreeBounds, 2); + return new IconOctree(icons, octreeBounds, 2); } private updatePointsObject(): void { diff --git a/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts b/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts index 6b586b794dd..bd69166c450 100644 --- a/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts +++ b/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts @@ -306,7 +306,7 @@ export class Overlay3DTool extends Co const camera = _viewer.cameraManager.getCamera(); const cameraDirection = camera.getWorldDirection(new THREE.Vector3()); - const intersections: [Overlay3DIcon, THREE.Vector3][] = []; + const intersections: [Overlay3D, THREE.Vector3][] = []; for (const points of this._overlayCollections) { const intersection = points.intersectOverlays(normalizedCoordinates); diff --git a/viewer/reveal.api.md b/viewer/reveal.api.md index ff871c1e930..07d6b407876 100644 --- a/viewer/reveal.api.md +++ b/viewer/reveal.api.md @@ -9,6 +9,7 @@ import { AnnotationsAssetRef } from '@cognite/sdk'; import { AnnotationsCogniteAnnotationTypesImagesAssetLink } from '@cognite/sdk'; import { AnnotationStatus } from '@cognite/sdk'; import { Box3 } from 'three'; +import { Camera } from 'three'; import { CogniteClient } from '@cognite/sdk'; import { CogniteInternalId } from '@cognite/sdk'; import { Color } from 'three'; @@ -23,6 +24,7 @@ import { PerspectiveCamera } from 'three'; import { Plane } from 'three'; import { Quaternion } from 'three'; import { Raycaster } from 'three'; +import { Texture } from 'three'; import * as THREE from 'three'; import { Vector2 } from 'three'; import { Vector3 } from 'three'; @@ -1570,6 +1572,35 @@ export interface Overlay3D { setVisible(visible: boolean): void; } +// @public (undocumented) +export class Overlay3DCollection extends Object3D implements OverlayCollection { + constructor(overlayInfos: OverlayInfo[], cameraManager: CameraManager, options?: Overlay3DCollectionOptions); + // (undocumented) + addOverlays(overlayInfos: OverlayInfo[]): Overlay3D[]; + // (undocumented) + dispose(): void; + // (undocumented) + getOverlays(): Overlay3D[]; + // (undocumented) + intersectOverlays(normalizedCoordinates: Vector2): Overlay3D | undefined; + // (undocumented) + onCameraChange: (camera: Camera) => void; + // (undocumented) + removeAllOverlays(): void; + // (undocumented) + removeOverlays(overlays: Overlay3D[]): void; + // (undocumented) + setVisibility(visibility: boolean): void; +} + +// @public (undocumented) +export type Overlay3DCollectionOptions = { + overlayTexture?: Texture; + overlayTextureMask?: Texture; + maxPointSize?: number; + defaultOverlayColor?: Color; +}; + // @public export class Overlay3DTool extends Cognite3DViewerToolBase { constructor(viewer: Cognite3DViewer, toolParameters?: Overlay3DToolParameters); From 48a2e4e868557da94efcca60cb7449d61bc2b1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 13 Jun 2024 15:12:04 +0200 Subject: [PATCH 03/10] chore: add comments --- .../3d-overlays/src/Overlay3DCollection.ts | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts index 8568e6f8dfa..31533b38c64 100644 --- a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts +++ b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts @@ -18,6 +18,9 @@ export type Overlay3DCollectionOptions = { defaultOverlayColor?: Color; }; +/** + * A collection of overlay icons with associated data + */ export class Overlay3DCollection extends Object3D implements OverlayCollection @@ -66,7 +69,7 @@ export class Overlay3DCollection this._overlays = this.initializeOverlay3DIcons(overlayInfos ?? []); this._cameraManager = cameraManager; - cameraManager.on('cameraChange', () => this.onCameraChange(this._cameraManager.getCamera())); + cameraManager.on('cameraChange', () => this._onCameraChange(this._cameraManager.getCamera())); this.add(this._overlayPoints); this.updatePointsObject(); @@ -74,7 +77,7 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } - onCameraChange = (camera: Camera): void => { + private _onCameraChange = (camera: Camera): void => { if (this._previousRenderCamera !== undefined && camera.matrix.equals(this._previousRenderCamera.matrix)) { return; } @@ -88,14 +91,23 @@ export class Overlay3DCollection this._previousRenderCamera.copy(camera); }; + /** + * Set whether this collection is visible or not + */ setVisibility(visibility: boolean): void { this._overlayPoints.visible = visibility; } + /** + * Get the overlay icons contained in this collection + */ getOverlays(): Overlay3D[] { return this._overlays; } + /** + * Add more overlays into this collection + */ public addOverlays(overlayInfos: OverlayInfo[]): Overlay3D[] { if (overlayInfos.length + this._overlays.length > this.DefaultMaxPoints) throw new Error('Cannot add more than ' + this.DefaultMaxPoints + ' points'); @@ -116,6 +128,9 @@ export class Overlay3DCollection this.updatePointsObject(); } + /** + * Remove the listed overlays from this collection + */ public removeOverlays(overlays: Overlay3D[]): void { this._overlays = this._overlays.filter(overlay => !overlays.includes(overlay)); @@ -123,6 +138,9 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } + /** + * Clean up all icons in this collection + */ public removeAllOverlays(): void { this._overlays = []; @@ -130,6 +148,9 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } + /** + * Run intersection on icons in this collection. Returns the closest hit + */ public intersectOverlays(normalizedCoordinates: Vector2): Overlay3D | undefined { const camera = this._previousRenderCamera; if (camera === undefined) { @@ -182,6 +203,9 @@ export class Overlay3DCollection }); } + /** + * @obvious + */ public dispose(): void { this._overlays.forEach(overlay => overlay.dispose()); From 99822de02130d2c412b403cbdc5dee5eee1031aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 13 Jun 2024 15:16:07 +0200 Subject: [PATCH 04/10] chore: add more docstrings --- .../3d-overlays/src/Overlay3DCollection.ts | 17 ++++++++++++++++- viewer/reveal.api.md | 13 ++----------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts index 31533b38c64..2c2dfcbe120 100644 --- a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts +++ b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts @@ -11,10 +11,25 @@ import { DefaultOverlay3DContentType, OverlayCollection, OverlayInfo } from './O import minBy from 'lodash/minBy'; import { CameraManager } from '@reveal/camera-manager'; +/** + * Constructor options for the Overlay3DCollection + */ export type Overlay3DCollectionOptions = { + /** + * The texture to display as icons in this collection + */ overlayTexture?: Texture; + /** + * A texture mask for marking what pixels are transparent in the supplied overlayTexture + */ overlayTextureMask?: Texture; + /** + * The maximum display size of each icon in pixels + */ maxPointSize?: number; + /** + * The default color to apply to overlay icons without a color on their own + */ defaultOverlayColor?: Color; }; @@ -77,7 +92,7 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } - private _onCameraChange = (camera: Camera): void => { + private readonly _onCameraChange = (camera: Camera): void => { if (this._previousRenderCamera !== undefined && camera.matrix.equals(this._previousRenderCamera.matrix)) { return; } diff --git a/viewer/reveal.api.md b/viewer/reveal.api.md index 07d6b407876..055502b5b44 100644 --- a/viewer/reveal.api.md +++ b/viewer/reveal.api.md @@ -9,7 +9,6 @@ import { AnnotationsAssetRef } from '@cognite/sdk'; import { AnnotationsCogniteAnnotationTypesImagesAssetLink } from '@cognite/sdk'; import { AnnotationStatus } from '@cognite/sdk'; import { Box3 } from 'three'; -import { Camera } from 'three'; import { CogniteClient } from '@cognite/sdk'; import { CogniteInternalId } from '@cognite/sdk'; import { Color } from 'three'; @@ -1572,28 +1571,20 @@ export interface Overlay3D { setVisible(visible: boolean): void; } -// @public (undocumented) +// @public export class Overlay3DCollection extends Object3D implements OverlayCollection { constructor(overlayInfos: OverlayInfo[], cameraManager: CameraManager, options?: Overlay3DCollectionOptions); - // (undocumented) addOverlays(overlayInfos: OverlayInfo[]): Overlay3D[]; // (undocumented) dispose(): void; - // (undocumented) getOverlays(): Overlay3D[]; - // (undocumented) intersectOverlays(normalizedCoordinates: Vector2): Overlay3D | undefined; - // (undocumented) - onCameraChange: (camera: Camera) => void; - // (undocumented) removeAllOverlays(): void; - // (undocumented) removeOverlays(overlays: Overlay3D[]): void; - // (undocumented) setVisibility(visibility: boolean): void; } -// @public (undocumented) +// @public export type Overlay3DCollectionOptions = { overlayTexture?: Texture; overlayTextureMask?: Texture; From 4d22f63c5679268fe2ae8d8102e9a1b54571a850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 13 Jun 2024 15:17:15 +0200 Subject: [PATCH 05/10] chore: a new docstring --- viewer/packages/3d-overlays/src/Overlay3DCollection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts index 2c2dfcbe120..46e09c56287 100644 --- a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts +++ b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts @@ -219,7 +219,7 @@ export class Overlay3DCollection } /** - * @obvious + * Dispose this collection and icons with all associated resources */ public dispose(): void { this._overlays.forEach(overlay => overlay.dispose()); From 70170b7c3dee352167bdac0f369dd15709e4915b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 13 Jun 2024 15:25:03 +0200 Subject: [PATCH 06/10] chore: update api --- viewer/reveal.api.md | 1 - 1 file changed, 1 deletion(-) diff --git a/viewer/reveal.api.md b/viewer/reveal.api.md index 055502b5b44..2836e779067 100644 --- a/viewer/reveal.api.md +++ b/viewer/reveal.api.md @@ -1575,7 +1575,6 @@ export interface Overlay3D { export class Overlay3DCollection extends Object3D implements OverlayCollection { constructor(overlayInfos: OverlayInfo[], cameraManager: CameraManager, options?: Overlay3DCollectionOptions); addOverlays(overlayInfos: OverlayInfo[]): Overlay3D[]; - // (undocumented) dispose(): void; getOverlays(): Overlay3D[]; intersectOverlays(normalizedCoordinates: Vector2): Overlay3D | undefined; From ed8723cae7079026f3be6622566f2f88a005b15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 13 Jun 2024 16:19:02 +0200 Subject: [PATCH 07/10] chore: remember to remove camera listener --- viewer/packages/3d-overlays/src/Overlay3DCollection.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts index 46e09c56287..a1160d1a0e7 100644 --- a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts +++ b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts @@ -84,7 +84,7 @@ export class Overlay3DCollection this._overlays = this.initializeOverlay3DIcons(overlayInfos ?? []); this._cameraManager = cameraManager; - cameraManager.on('cameraChange', () => this._onCameraChange(this._cameraManager.getCamera())); + cameraManager.on('cameraChange', this._onCameraChange); this.add(this._overlayPoints); this.updatePointsObject(); @@ -92,7 +92,8 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } - private readonly _onCameraChange = (camera: Camera): void => { + private readonly _onCameraChange = (): void => { + const camera = this._cameraManager.getCamera(); if (this._previousRenderCamera !== undefined && camera.matrix.equals(this._previousRenderCamera.matrix)) { return; } @@ -222,6 +223,7 @@ export class Overlay3DCollection * Dispose this collection and icons with all associated resources */ public dispose(): void { + this._cameraManager.off('cameraChange', this._onCameraChange); this._overlays.forEach(overlay => overlay.dispose()); this._overlayPoints.dispose(); From 7a897c04e02e39055fab65b07a54d911eb393c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Fri, 14 Jun 2024 12:15:29 +0200 Subject: [PATCH 08/10] chore: factor out TextOverlay, some simplification --- viewer/packages/3d-overlays/index.ts | 1 + .../3d-overlays/src/Overlay3DCollection.ts | 35 +-------- .../tools/src/Overlay3D/Overlay3DTool.ts | 74 +++---------------- 3 files changed, 14 insertions(+), 96 deletions(-) diff --git a/viewer/packages/3d-overlays/index.ts b/viewer/packages/3d-overlays/index.ts index c931c2bfc11..b0f21d6e89c 100644 --- a/viewer/packages/3d-overlays/index.ts +++ b/viewer/packages/3d-overlays/index.ts @@ -7,3 +7,4 @@ export { Overlay3DIcon } from './src/Overlay3DIcon'; export { Overlay3D } from './src/Overlay3D'; export { OverlayCollection, OverlayInfo, DefaultOverlay3DContentType } from './src/OverlayCollection'; export { IconOctree } from './src/IconOctree'; +export { TextOverlay } from './src/TextOverlay'; diff --git a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts index a1160d1a0e7..72aef216a13 100644 --- a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts +++ b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts @@ -9,7 +9,6 @@ import { OverlayPointsObject } from './OverlayPointsObject'; import { IconOctree } from './IconOctree'; import { DefaultOverlay3DContentType, OverlayCollection, OverlayInfo } from './OverlayCollection'; import minBy from 'lodash/minBy'; -import { CameraManager } from '@reveal/camera-manager'; /** * Constructor options for the Overlay3DCollection @@ -54,16 +53,9 @@ export class Overlay3DCollection private _overlays: Overlay3DIcon[]; //@ts-ignore Will be removed when clustering is added. private _octree: IconOctree; - private _previousRenderCamera: Camera | undefined; private readonly _rayCaster = new Raycaster(); - private readonly _cameraManager: CameraManager; - - constructor( - overlayInfos: OverlayInfo[], - cameraManager: CameraManager, - options?: Overlay3DCollectionOptions - ) { + constructor(overlayInfos: OverlayInfo[], options?: Overlay3DCollectionOptions) { super(); this.defaultOverlayColor = options?.defaultOverlayColor ?? this.defaultOverlayColor; @@ -83,8 +75,6 @@ export class Overlay3DCollection }); this._overlays = this.initializeOverlay3DIcons(overlayInfos ?? []); - this._cameraManager = cameraManager; - cameraManager.on('cameraChange', this._onCameraChange); this.add(this._overlayPoints); this.updatePointsObject(); @@ -92,21 +82,6 @@ export class Overlay3DCollection this._octree = this.rebuildOctree(); } - private readonly _onCameraChange = (): void => { - const camera = this._cameraManager.getCamera(); - if (this._previousRenderCamera !== undefined && camera.matrix.equals(this._previousRenderCamera.matrix)) { - return; - } - - this.sortOverlaysRelativeToCamera(camera); - - if (this._previousRenderCamera === undefined) { - this._previousRenderCamera = camera.clone(); - } - - this._previousRenderCamera.copy(camera); - }; - /** * Set whether this collection is visible or not */ @@ -167,12 +142,7 @@ export class Overlay3DCollection /** * Run intersection on icons in this collection. Returns the closest hit */ - public intersectOverlays(normalizedCoordinates: Vector2): Overlay3D | undefined { - const camera = this._previousRenderCamera; - if (camera === undefined) { - return undefined; - } - + public intersectOverlays(normalizedCoordinates: Vector2, camera: Camera): Overlay3D | undefined { this._rayCaster.setFromCamera(normalizedCoordinates.clone(), camera); const intersections = this._overlays.filter(icon => { @@ -223,7 +193,6 @@ export class Overlay3DCollection * Dispose this collection and icons with all associated resources */ public dispose(): void { - this._cameraManager.off('cameraChange', this._onCameraChange); this._overlays.forEach(overlay => overlay.dispose()); this._overlayPoints.dispose(); diff --git a/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts b/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts index bd69166c450..9008dc97a7f 100644 --- a/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts +++ b/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts @@ -16,7 +16,8 @@ import { OverlayInfo, DefaultOverlay3DContentType, OverlayCollection, - Overlay3D + Overlay3D, + TextOverlay } from '@reveal/3d-overlays'; import { Cognite3DViewerToolBase } from '../Cognite3DViewerToolBase'; @@ -80,14 +81,12 @@ export type OverlayCollectionOptions = { */ export class Overlay3DTool extends Cognite3DViewerToolBase { private readonly _viewer: Cognite3DViewer; - private readonly _textOverlay: HTMLElement; private readonly _defaultOverlayColor: THREE.Color = new THREE.Color('#fbe50b'); - private readonly _defaultTextOverlayToCursorOffset = 20; private _overlayCollections: Overlay3DCollection[] = []; private _isVisible = true; - private _textOverlayVisible = false; + private _textOverlay: TextOverlay; private readonly _events = { hover: new EventTrigger>(), @@ -100,9 +99,7 @@ export class Overlay3DTool extends Co this._viewer = viewer; this._defaultOverlayColor = toolParameters?.defaultOverlayColor ?? this._defaultOverlayColor; - - this._textOverlay = this.createTextOverlay('', this._defaultTextOverlayToCursorOffset); - viewer.domElement.appendChild(this._textOverlay); + this._textOverlay = new TextOverlay(viewer.domElement); viewer.canvas.addEventListener('mousemove', this.onMouseMove); @@ -120,7 +117,7 @@ export class Overlay3DTool extends Co ): OverlayCollection { const { _viewer: viewer } = this; - const points = new Overlay3DCollection(overlays ?? [], viewer.cameraManager, { + const points = new Overlay3DCollection(overlays ?? [], { ...options, defaultOverlayColor: options?.defaultOverlayColor ?? this._defaultOverlayColor }); @@ -174,22 +171,6 @@ export class Overlay3DTool extends Co return this._isVisible; } - /** - * Sets whether text overlay is visible. - * Default is false. - */ - setTextOverlayVisible(visible: boolean): void { - this._textOverlayVisible = visible; - this._textOverlay.style.opacity = visible ? '1' : '0'; - } - - /** - * Gets whether text overlay is visible. - */ - getTextOverlayVisible(): boolean { - return this._textOverlayVisible; - } - /** * Removes all overlays. */ @@ -265,15 +246,16 @@ export class Overlay3DTool extends Co const { _textOverlay: textOverlay } = this; const intersectedOverlay = this.intersectPointsMarkers({ offsetX: event.offsetX, offsetY: event.offsetY }); + + this._textOverlay.reset(); + if (intersectedOverlay) { - this.positionTextOverlay(event); + this._textOverlay.positionTextOverlay(event); this._events.hover.fire({ targetOverlay: intersectedOverlay, mousePosition: event, - htmlTextOverlay: textOverlay + htmlTextOverlay: textOverlay.textOverlay }); - } else { - textOverlay.style.opacity = '0'; } }; @@ -282,19 +264,12 @@ export class Overlay3DTool extends Co if (intersectedOverlay) { this._events.click.fire({ targetOverlay: intersectedOverlay, - htmlTextOverlay: this._textOverlay, + htmlTextOverlay: this._textOverlay.textOverlay, mousePosition: { offsetX: event.offsetX, offsetY: event.offsetY } }); } }; - private positionTextOverlay(event: MouseEvent): void { - const { _textOverlay, _textOverlayVisible } = this; - _textOverlay.style.left = `${event.offsetX}px`; - _textOverlay.style.top = `${event.offsetY}px`; - _textOverlay.style.opacity = _textOverlayVisible ? '1' : '0'; - } - private intersectPointsMarkers(mouseCoords: { offsetX: number; offsetY: number }): Overlay3DIcon | null { const { _viewer } = this; @@ -331,31 +306,4 @@ export class Overlay3DTool extends Co return null; } - - private createTextOverlay(text: string, horizontalOffset: number): HTMLElement { - const textOverlay = document.createElement('div'); - textOverlay.innerText = text; - textOverlay.setAttribute('class', 'text-overlay'); - textOverlay.style.cssText = ` - position: absolute; - - /* Anchor to the center of the element and ignore events */ - transform: translate(${horizontalOffset}px, -50%); - touch-action: none; - user-select: none; - - padding: 7px; - max-width: 200px; - color: #fff; - background: #232323da; - border-radius: 5px; - border: '#ffffff22 solid 2px; - opacity: 0; - transition: opacity 0.3s; - opacity: 0; - z-index: 10; - `; - - return textOverlay; - } } From f0a484210d4f33e2356c43f731801de2dd5f3dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Fri, 14 Jun 2024 14:13:22 +0200 Subject: [PATCH 09/10] fix: add missing file --- .../packages/3d-overlays/src/TextOverlay.ts | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 viewer/packages/3d-overlays/src/TextOverlay.ts diff --git a/viewer/packages/3d-overlays/src/TextOverlay.ts b/viewer/packages/3d-overlays/src/TextOverlay.ts new file mode 100644 index 00000000000..8c0c221f791 --- /dev/null +++ b/viewer/packages/3d-overlays/src/TextOverlay.ts @@ -0,0 +1,78 @@ +/*! + * Copyright 2024 Cognite AS + */ +export class TextOverlay { + private readonly _textOverlay: HTMLElement; + private readonly _defaultTextOverlayToCursorOffset = 20; + private _textOverlayVisible = false; + + constructor(domElement: HTMLElement) { + this._textOverlay = this.createTextOverlay('', this._defaultTextOverlayToCursorOffset); + domElement.appendChild(this._textOverlay); + } + + get textOverlay(): HTMLElement { + return this._textOverlay; + } + + /** + * Sets whether text overlay is visible. + * Default is false. + */ + setTextOverlayEnabled(visible: boolean): void { + this._textOverlayVisible = visible; + this._textOverlay.style.opacity = visible ? '1' : '0'; + } + + /** + * Resets (i.e. hides) text overlay before recalculating position/visibility + */ + reset(): void { + this._textOverlay.style.opacity = '0'; + } + + /** + * Gets whether text overlay is visible. + */ + getTextOverlayEnabled(): boolean { + return this._textOverlayVisible; + } + + dispose(): void { + this._textOverlay.remove(); + } + + public positionTextOverlay(event: MouseEvent): void { + const { _textOverlay, _textOverlayVisible } = this; + _textOverlay.style.left = `${event.offsetX}px`; + _textOverlay.style.top = `${event.offsetY}px`; + _textOverlay.style.opacity = _textOverlayVisible ? '1' : '0'; + } + + private createTextOverlay(text: string, horizontalOffset: number): HTMLElement { + const textOverlay = document.createElement('div'); + textOverlay.innerText = text; + textOverlay.setAttribute('class', 'text-overlay'); + textOverlay.style.cssText = ` + position: absolute; + + /* Anchor to the center of the element and ignore events */ + transform: translate(${horizontalOffset}px, -50%); + touch-action: none; + user-select: none; + + padding: 7px; + max-width: 200px; + color: #fff; + background: #232323da; + border-radius: 5px; + border: '#ffffff22 solid 2px; + opacity: 0; + transition: opacity 0.3s; + opacity: 0; + z-index: 10; + `; + + return textOverlay; + } +} From fb7dd6fda54d93bc571cd1d44e7a586026d7a696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Mon, 17 Jun 2024 16:44:20 +0200 Subject: [PATCH 10/10] chore: refactor to make point sorting self-contained --- viewer/packages/3d-overlays/index.ts | 1 - .../3d-overlays/src/CameraChangeThrottler.ts | 27 ++++++++++++++ .../3d-overlays/src/Overlay3DCollection.ts | 35 +++++++++++++------ .../3d-overlays/src/OverlayPointsObject.ts | 12 +++++-- .../tools/src/Overlay3D/Overlay3DTool.ts | 28 +++++++++++---- .../src/Overlay3D}/TextOverlay.ts | 0 viewer/reveal.api.md | 5 +-- 7 files changed, 86 insertions(+), 22 deletions(-) create mode 100644 viewer/packages/3d-overlays/src/CameraChangeThrottler.ts rename viewer/packages/{3d-overlays/src => tools/src/Overlay3D}/TextOverlay.ts (100%) diff --git a/viewer/packages/3d-overlays/index.ts b/viewer/packages/3d-overlays/index.ts index b0f21d6e89c..c931c2bfc11 100644 --- a/viewer/packages/3d-overlays/index.ts +++ b/viewer/packages/3d-overlays/index.ts @@ -7,4 +7,3 @@ export { Overlay3DIcon } from './src/Overlay3DIcon'; export { Overlay3D } from './src/Overlay3D'; export { OverlayCollection, OverlayInfo, DefaultOverlay3DContentType } from './src/OverlayCollection'; export { IconOctree } from './src/IconOctree'; -export { TextOverlay } from './src/TextOverlay'; diff --git a/viewer/packages/3d-overlays/src/CameraChangeThrottler.ts b/viewer/packages/3d-overlays/src/CameraChangeThrottler.ts new file mode 100644 index 00000000000..7894cde50a2 --- /dev/null +++ b/viewer/packages/3d-overlays/src/CameraChangeThrottler.ts @@ -0,0 +1,27 @@ +/*! + * Copyright 2024 Cognite AS + */ +import throttle from 'lodash/throttle'; +import { Camera, Matrix4 } from 'three'; + +export type Callback = () => void; + +export class CameraChangeThrottler { + private readonly _prevCameraMatrix: Matrix4 = new Matrix4(); + + public call: (camera: Camera, callback: Callback) => void; + + constructor(wait: number = 500) { + this.call = throttle((camera: Camera, callback: Callback) => this._call(camera, callback), wait); + } + + private _call(camera: Camera, callback: Callback) { + if (camera.matrix.equals(this._prevCameraMatrix)) { + return; + } + + callback(); + + this._prevCameraMatrix.copy(camera.matrix); + } +} diff --git a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts index 72aef216a13..86434470c70 100644 --- a/viewer/packages/3d-overlays/src/Overlay3DCollection.ts +++ b/viewer/packages/3d-overlays/src/Overlay3DCollection.ts @@ -2,13 +2,14 @@ * Copyright 2023 Cognite AS */ -import { CanvasTexture, Color, Texture, Object3D, Camera, Vector2, Raycaster } from 'three'; +import { CanvasTexture, Color, Texture, Object3D, Camera, Vector2, Raycaster, WebGLRenderer, Scene } from 'three'; import { Overlay3DIcon } from './Overlay3DIcon'; import { Overlay3D } from './Overlay3D'; import { OverlayPointsObject } from './OverlayPointsObject'; import { IconOctree } from './IconOctree'; import { DefaultOverlay3DContentType, OverlayCollection, OverlayInfo } from './OverlayCollection'; import minBy from 'lodash/minBy'; +import { CameraChangeThrottler } from './CameraChangeThrottler'; /** * Constructor options for the Overlay3DCollection @@ -54,6 +55,7 @@ export class Overlay3DCollection //@ts-ignore Will be removed when clustering is added. private _octree: IconOctree; private readonly _rayCaster = new Raycaster(); + private readonly _cameraChangeDebouncer = new CameraChangeThrottler(); constructor(overlayInfos: OverlayInfo[], options?: Overlay3DCollectionOptions) { super(); @@ -66,17 +68,20 @@ export class Overlay3DCollection mask: options?.overlayTextureMask ?? (options?.overlayTexture ? undefined : defaultOverlayTextures.mask) }; - this._overlayPoints = new OverlayPointsObject(overlayInfos ? overlayInfos.length : this.DefaultMaxPoints, { - spriteTexture: this._sharedTextures.color, - maskTexture: this._sharedTextures.mask, - minPixelSize: this.MinPixelSize, - maxPixelSize: options?.maxPointSize ?? this.MaxPixelSize, - radius: this._iconRadius - }); - - this._overlays = this.initializeOverlay3DIcons(overlayInfos ?? []); + this._overlayPoints = new OverlayPointsObject( + overlayInfos ? overlayInfos.length : this.DefaultMaxPoints, + { + spriteTexture: this._sharedTextures.color, + maskTexture: this._sharedTextures.mask, + minPixelSize: this.MinPixelSize, + maxPixelSize: options?.maxPointSize ?? this.MaxPixelSize, + radius: this._iconRadius + }, + (...args) => this.onBeforeRenderDelegate(...args) + ); + + this._overlays = this.initializeOverlay3DIcons(overlayInfos); this.add(this._overlayPoints); - this.updatePointsObject(); this._octree = this.rebuildOctree(); @@ -112,6 +117,14 @@ export class Overlay3DCollection return newIcons; } + private readonly onBeforeRenderDelegate: Object3D['onBeforeRender'] = ( + _renderer: WebGLRenderer, + _scene: Scene, + camera: Camera + ) => { + this._cameraChangeDebouncer.call(camera, () => this.sortOverlaysRelativeToCamera(camera)); + }; + private sortOverlaysRelativeToCamera(camera: Camera): void { this._overlays = this._overlays.sort((a, b) => { return b.getPosition().distanceToSquared(camera.position) - a.getPosition().distanceToSquared(camera.position); diff --git a/viewer/packages/3d-overlays/src/OverlayPointsObject.ts b/viewer/packages/3d-overlays/src/OverlayPointsObject.ts index c9740686882..41a28ac4a8a 100644 --- a/viewer/packages/3d-overlays/src/OverlayPointsObject.ts +++ b/viewer/packages/3d-overlays/src/OverlayPointsObject.ts @@ -13,6 +13,7 @@ import { Group, LessEqualDepth, Matrix4, + Object3D, Points, RawShaderMaterial, ShaderMaterial, @@ -43,9 +44,14 @@ export class OverlayPointsObject extends Group { private readonly _colorBuffer: Float32Array; private readonly _colorAttribute: BufferAttribute; private readonly _points: { frontPoints: Points; backPoints: Points }; + private readonly _onBeforeRender?: Object3D['onBeforeRender']; private _modelTransform: Matrix4; - constructor(maxNumberOfPoints: number, materialParameters: OverlayPointsParameters) { + constructor( + maxNumberOfPoints: number, + materialParameters: OverlayPointsParameters, + onBeforeRender?: Object3D['onBeforeRender'] + ) { super(); const geometry = new BufferGeometry(); this._positionBuffer = new Float32Array(maxNumberOfPoints * 3); @@ -101,6 +107,7 @@ export class OverlayPointsObject extends Group { this._geometry = geometry; this._frontMaterial = frontMaterial; this._points = { frontPoints, backPoints }; + this._onBeforeRender = onBeforeRender; } public setPoints(points: Vector3[], colors?: Color[]): void { @@ -163,7 +170,8 @@ export class OverlayPointsObject extends Group { private initializePoints(geometry: BufferGeometry, frontMaterial: ShaderMaterial): Points { const frontPoints = createPoints(geometry, frontMaterial); - frontPoints.onBeforeRender = renderer => { + frontPoints.onBeforeRender = (renderer, ...rest) => { + this._onBeforeRender?.(renderer, ...rest); setUniforms(renderer, frontMaterial); }; diff --git a/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts b/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts index 9008dc97a7f..fda23e762d4 100644 --- a/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts +++ b/viewer/packages/tools/src/Overlay3D/Overlay3DTool.ts @@ -16,9 +16,9 @@ import { OverlayInfo, DefaultOverlay3DContentType, OverlayCollection, - Overlay3D, - TextOverlay + Overlay3D } from '@reveal/3d-overlays'; +import { TextOverlay } from './TextOverlay'; import { Cognite3DViewerToolBase } from '../Cognite3DViewerToolBase'; /** @@ -86,7 +86,7 @@ export class Overlay3DTool extends Co private _overlayCollections: Overlay3DCollection[] = []; private _isVisible = true; - private _textOverlay: TextOverlay; + private readonly _textOverlay: TextOverlay; private readonly _events = { hover: new EventTrigger>(), @@ -118,8 +118,9 @@ export class Overlay3DTool extends Co const { _viewer: viewer } = this; const points = new Overlay3DCollection(overlays ?? [], { - ...options, - defaultOverlayColor: options?.defaultOverlayColor ?? this._defaultOverlayColor + defaultOverlayColor: options?.defaultOverlayColor ?? this._defaultOverlayColor, + overlayTexture: options?.overlayTexture, + overlayTextureMask: options?.overlayTextureMask }); this._overlayCollections.push(points); @@ -171,6 +172,21 @@ export class Overlay3DTool extends Co return this._isVisible; } + /** + * Sets whether text overlay is visible. + * Default is false. + */ + setTextOverlayVisible(visible: boolean): void { + this._textOverlay.setTextOverlayEnabled(visible); + } + + /** + * Gets whether text overlay is visible. + */ + getTextOverlayVisible(): boolean { + return this._textOverlay.getTextOverlayEnabled(); + } + /** * Removes all overlays. */ @@ -284,7 +300,7 @@ export class Overlay3DTool extends Co const intersections: [Overlay3D, THREE.Vector3][] = []; for (const points of this._overlayCollections) { - const intersection = points.intersectOverlays(normalizedCoordinates); + const intersection = points.intersectOverlays(normalizedCoordinates, camera); if (intersection !== undefined) { intersections.push([intersection, intersection.getPosition().clone()]); } diff --git a/viewer/packages/3d-overlays/src/TextOverlay.ts b/viewer/packages/tools/src/Overlay3D/TextOverlay.ts similarity index 100% rename from viewer/packages/3d-overlays/src/TextOverlay.ts rename to viewer/packages/tools/src/Overlay3D/TextOverlay.ts diff --git a/viewer/reveal.api.md b/viewer/reveal.api.md index 2836e779067..8964a68e63b 100644 --- a/viewer/reveal.api.md +++ b/viewer/reveal.api.md @@ -9,6 +9,7 @@ import { AnnotationsAssetRef } from '@cognite/sdk'; import { AnnotationsCogniteAnnotationTypesImagesAssetLink } from '@cognite/sdk'; import { AnnotationStatus } from '@cognite/sdk'; import { Box3 } from 'three'; +import { Camera } from 'three'; import { CogniteClient } from '@cognite/sdk'; import { CogniteInternalId } from '@cognite/sdk'; import { Color } from 'three'; @@ -1573,11 +1574,11 @@ export interface Overlay3D { // @public export class Overlay3DCollection extends Object3D implements OverlayCollection { - constructor(overlayInfos: OverlayInfo[], cameraManager: CameraManager, options?: Overlay3DCollectionOptions); + constructor(overlayInfos: OverlayInfo[], options?: Overlay3DCollectionOptions); addOverlays(overlayInfos: OverlayInfo[]): Overlay3D[]; dispose(): void; getOverlays(): Overlay3D[]; - intersectOverlays(normalizedCoordinates: Vector2): Overlay3D | undefined; + intersectOverlays(normalizedCoordinates: Vector2, camera: Camera): Overlay3D | undefined; removeAllOverlays(): void; removeOverlays(overlays: Overlay3D[]): void; setVisibility(visibility: boolean): void;