@cognite/reveal 4.29.3 → 4.30.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.
Files changed (23) hide show
  1. package/dist/index.js +221 -213
  2. package/dist/index.js.map +1 -1
  3. package/dist/packages/360-images/index.d.ts +3 -1
  4. package/dist/packages/360-images/src/Image360Facade.d.ts +25 -1
  5. package/dist/packages/360-images/src/collection/DefaultImage360Collection.d.ts +41 -2
  6. package/dist/packages/360-images/src/collection/Image360Collection.d.ts +25 -0
  7. package/dist/packages/360-images/src/icons/IconCollection.d.ts +114 -6
  8. package/dist/packages/360-images/src/icons/clustering/ClusterRenderingStrategy.d.ts +18 -0
  9. package/dist/packages/360-images/src/icons/clustering/HtmlClusterRenderer.d.ts +47 -0
  10. package/dist/packages/360-images/src/icons/clustering/htmlClusterStyles.d.ts +9 -0
  11. package/dist/packages/360-images/src/icons/clustering/index.d.ts +5 -0
  12. package/dist/packages/360-images/src/types.d.ts +10 -0
  13. package/dist/packages/3d-overlays/src/IconOctree.d.ts +9 -2
  14. package/dist/packages/api/src/api-helpers/Image360ApiHelper.d.ts +16 -1
  15. package/dist/packages/api/src/public/migration/Cognite3DViewer.d.ts +1 -0
  16. package/dist/packages/api/src/public/migration/types.d.ts +38 -1
  17. package/dist/packages/camera-manager/src/DefaultCameraManager.d.ts +7 -1
  18. package/dist/packages/data-providers/index.d.ts +1 -0
  19. package/dist/packages/data-providers/src/Image360ProviderCombiner.d.ts +1 -0
  20. package/dist/packages/data-providers/src/image-360-data-providers/Cdf360ImageAnnotationProvider.d.ts +27 -3
  21. package/dist/packages/data-providers/src/types.d.ts +6 -0
  22. package/dist/packages/data-providers/src/utilities/getExternalIdFromDescriptor.d.ts +9 -0
  23. package/package.json +3 -2
@@ -15,7 +15,9 @@ export { Image360AnnotationIntersection } from './src/annotation/Image360Annotat
15
15
  export { Image360Annotation } from './src/annotation/Image360Annotation';
16
16
  export { DefaultImage360Collection } from './src/collection/DefaultImage360Collection';
17
17
  export { IconsOptions } from './src/icons/IconCollection';
18
- export { Image360CollectionSourceType, Image360IconIntersectionData } from './src/types';
18
+ export { ClusteredIconData } from './src/icons/clustering/ClusterRenderingStrategy';
19
+ export { HtmlClusterRendererOptions } from './src/icons/clustering/HtmlClusterRenderer';
20
+ export { Image360ClusterIntersectionData, Image360CollectionSourceType, Image360IconIntersectionData } from './src/types';
19
21
  export { Image360AnnotationFilter } from './src/annotation/Image360AnnotationFilter';
20
22
  export { DEFAULT_IMAGE_360_OPACITY } from './src/entity/Image360VisualizationBox';
21
23
  export { Image360Action } from './src/Image360Action';
@@ -9,7 +9,7 @@ import { IconCullingScheme } from './icons/IconCollection';
9
9
  import { Image360RevisionEntity } from './entity/Image360RevisionEntity';
10
10
  import { Image360AnnotationFilterOptions } from './annotation/types';
11
11
  import { DataSourceType } from '../../data-providers';
12
- import { Image360IconIntersectionData } from './types';
12
+ import { Image360ClusterIntersectionData, Image360IconIntersectionData } from './types';
13
13
  export declare class Image360Facade<T extends DataSourceType> {
14
14
  private readonly _entityFactory;
15
15
  private readonly _image360Collections;
@@ -29,5 +29,29 @@ export declare class Image360Facade<T extends DataSourceType> {
29
29
  preload(entity: Image360Entity<T>, revision: Image360RevisionEntity<T>, lockDownload?: boolean): Promise<void>;
30
30
  getCollectionContainingEntity(entity: Image360Entity<T>): DefaultImage360Collection<T>;
31
31
  intersect(coords: Vector2, camera: Camera): Image360IconIntersectionData<T> | undefined;
32
+ /**
33
+ * Intersect with cluster icons. Returns cluster data if a cluster is hit.
34
+ * Also updates hover state to highlight only the closest cluster.
35
+ * @param coords - Normalized screen coordinates (-1 to 1)
36
+ * @param camera - The camera used for the intersection
37
+ * @returns Cluster intersection data if a cluster is hit, undefined otherwise
38
+ */
39
+ intersectCluster(coords: Vector2, camera: Camera): Image360ClusterIntersectionData<T> | undefined;
40
+ /**
41
+ * Finds the closest cluster candidate.
42
+ * @param coords - Normalized screen coordinates (-1 to 1)
43
+ * @param camera - The camera used for the intersection
44
+ * @returns The closest cluster candidate, undefined if no cluster is hit
45
+ */
46
+ private findClosestCluster;
47
+ /**
48
+ * Applies cluster hover on the given candidate's collection.
49
+ * @param candidate - The cluster candidate to apply hover to
50
+ */
51
+ private applyClusterHover;
52
+ /**
53
+ * Clear hovered cluster state for all collections.
54
+ */
55
+ clearHoveredClusters(): void;
32
56
  dispose(): void;
33
57
  }
@@ -5,11 +5,12 @@ import { EventTrigger } from '../../../utilities';
5
5
  import { AssetAnnotationImage360Info, AssetHybridAnnotationImage360Info, Image360AnnotationAssetFilter, Image360AnnotationAssetQueryResult, Image360Collection } from './Image360Collection';
6
6
  import { Image360Entity } from '../entity/Image360Entity';
7
7
  import { Image360EnteredDelegate, Image360ExitedDelegate } from '../types';
8
- import { IconCollection, IconCullingScheme } from '../icons/IconCollection';
8
+ import { ClusterIntersectionData, IconCollection, IconCullingScheme } from '../icons/IconCollection';
9
+ import { Overlay3DIcon } from '../../../3d-overlays';
9
10
  import { Image360AnnotationAppearance } from '../annotation/types';
10
11
  import { ClassicDataSourceType, DataSourceType, DMDataSourceType, Image360FileDescriptor, Image360Provider } from '../../../data-providers';
11
12
  import { Image360AnnotationFilter } from '../annotation/Image360AnnotationFilter';
12
- import { Matrix4 } from 'three';
13
+ import { Matrix4, Ray } from 'three';
13
14
  import { InstanceReference } from '../../../data-providers/src/types';
14
15
  /**
15
16
  * Default implementation of {@link Image360Collection}. Used for events when entering
@@ -31,6 +32,10 @@ export declare class DefaultImage360Collection<T extends DataSourceType> impleme
31
32
  private readonly _annotationFilter;
32
33
  private readonly _events;
33
34
  private readonly _icons;
35
+ /**
36
+ * A map containing the image360Entities by their icon.
37
+ */
38
+ private readonly _image360EntitiesMap;
34
39
  private _isCollectionVisible;
35
40
  private readonly _sourceId;
36
41
  private readonly _collectionLabel;
@@ -90,6 +95,40 @@ export declare class DefaultImage360Collection<T extends DataSourceType> impleme
90
95
  setSelectedForAll(selected: boolean): void;
91
96
  setSelectedVisibility(visible: boolean): boolean;
92
97
  setCullingScheme(scheme: IconCullingScheme): void;
98
+ /**
99
+ * Get the current cluster distance threshold.
100
+ * @returns The current distance threshold for clustering
101
+ */
102
+ getClusterDistanceThreshold(): number;
103
+ /**
104
+ * Set the cluster distance threshold.
105
+ * @param threshold - The new distance threshold (default: 100)
106
+ */
107
+ setClusterDistanceThreshold(threshold: number): void;
108
+ /**
109
+ * Get the current maximum octree depth for clustering.
110
+ * @returns The current max depth, or undefined if no limit
111
+ */
112
+ getMaxOctreeDepth(): number | undefined;
113
+ /**
114
+ * Set the maximum octree depth for clustering.
115
+ * @param depth - The new max depth
116
+ */
117
+ setMaxOctreeDepth(depth: number | undefined): void;
118
+ /**
119
+ * Check if HTML cluster rendering is enabled.
120
+ * @returns true if HTML clusters are enabled
121
+ */
122
+ isHtmlClustersEnabled(): boolean;
123
+ intersectCluster(ray: Ray): ClusterIntersectionData | undefined;
124
+ /**
125
+ * Get entities corresponding to the given icons using map lookups.
126
+ * @param icons - Array of Overlay3DIcon to look up
127
+ * @returns Array of Image360Entity corresponding to the icons
128
+ */
129
+ getEntitiesFromIcons(icons: Overlay3DIcon[]): Image360Entity<T>[];
130
+ clearHoveredCluster(): void;
131
+ setHoveredClusterIcon(icon: Overlay3DIcon | undefined): void;
93
132
  remove(entity: Image360Entity<T>): void;
94
133
  dispose(): void;
95
134
  get needsRedraw(): boolean;
@@ -158,6 +158,31 @@ export interface Image360Collection<T extends DataSourceType = ClassicDataSource
158
158
  * @param opacity The opacity of the icons
159
159
  */
160
160
  setIconsOpacity(opacity: number): void;
161
+ /**
162
+ * Get the current cluster distance threshold.
163
+ * @returns The current distance threshold for clustering
164
+ */
165
+ getClusterDistanceThreshold(): number;
166
+ /**
167
+ * Set the cluster distance threshold.
168
+ * @param threshold - The new distance threshold
169
+ */
170
+ setClusterDistanceThreshold(threshold: number): void;
171
+ /**
172
+ * Get the current maximum octree depth for clustering.
173
+ * @returns The current max depth, or undefined if no limit
174
+ */
175
+ getMaxOctreeDepth(): number | undefined;
176
+ /**
177
+ * Set the maximum octree depth for clustering.
178
+ * @param depth - The new max depth
179
+ */
180
+ setMaxOctreeDepth(depth: number | undefined): void;
181
+ /**
182
+ * Check if HTML cluster rendering is enabled.
183
+ * @returns true if HTML clusters are enabled
184
+ */
185
+ isHtmlClustersEnabled(): boolean;
161
186
  /**
162
187
  * Subscribes to events on 360 Image datasets. There are several event types:
163
188
  * 'image360Entered' - Subscribes to a event for entering 360 image mode.
@@ -1,16 +1,42 @@
1
1
  /*!
2
2
  * Copyright 2023 Cognite AS
3
3
  */
4
- import { Matrix4, Vector3 } from 'three';
4
+ import { Matrix4, Ray, Vector3 } from 'three';
5
5
  import { BeforeSceneRenderedDelegate, EventTrigger, SceneHandler } from '../../../utilities';
6
- import { Overlay3DIcon } from '../../../3d-overlays';
6
+ import { DefaultOverlay3DContentType, IconOctree, Overlay3DIcon } from '../../../3d-overlays';
7
+ import { PointOctant } from 'sparse-octree';
8
+ import { HtmlClusterRendererOptions } from './clustering/HtmlClusterRenderer';
7
9
  export type IconCullingScheme = 'clustered' | 'proximity';
8
10
  export type IconsOptions = {
9
11
  platformMaxPointsSize?: number;
12
+ htmlClusterOptions?: HtmlClusterRendererOptions;
13
+ clusterDistanceThreshold?: number;
14
+ maxOctreeDepth?: number;
15
+ enableHtmlClusters?: boolean;
16
+ };
17
+ export type ClusteredIcon = {
18
+ icon: Overlay3DIcon;
19
+ isCluster: boolean;
20
+ clusterSize: number;
21
+ clusterPosition: Vector3;
22
+ sizeScale: number;
23
+ clusterIcons?: Overlay3DIcon[];
24
+ };
25
+ export type ClusterIntersectionData = {
26
+ clusterPosition: Vector3;
27
+ clusterSize: number;
28
+ clusterIcons: Overlay3DIcon[];
29
+ representativeIcon: Overlay3DIcon;
10
30
  };
11
31
  export declare class IconCollection {
12
32
  private static readonly MinPixelSize;
13
33
  private static readonly DefaultMaxPixelSize;
34
+ private static readonly DefaultProjectionMatrixElement;
35
+ private static readonly DefaultRenderHeight;
36
+ private static readonly DefaultProximityPointLimit;
37
+ private static readonly DefaultProximityRadius;
38
+ private static readonly DefaultClusterDistanceThreshold;
39
+ private static readonly DefaultMaxOctreeDepth;
14
40
  private readonly _maxPixelSize;
15
41
  private readonly _sceneHandler;
16
42
  private readonly _sharedTexture;
@@ -21,18 +47,100 @@ export declare class IconCollection {
21
47
  private readonly _computeProximityPointsEventHandler;
22
48
  private readonly _onBeforeSceneRenderedEvent;
23
49
  private readonly _iconRadius;
24
- private _activeCullingSchemeEventHandeler;
25
- private _iconCullingScheme;
50
+ private readonly _renderPositions;
51
+ private readonly _renderColors;
52
+ private readonly _setNeedsRedraw;
53
+ private readonly _lastLODCameraPosition;
54
+ private readonly _minClusterPixelSize;
55
+ private readonly _htmlRenderer;
56
+ private readonly _enableHtmlClusters;
57
+ private _lastProjectionMatrixElement;
58
+ private _lastRenderHeight;
26
59
  private _proximityRadius;
27
60
  private _proximityPointLimit;
61
+ private _clusterDistanceThreshold;
62
+ private _maxOctreeDepth;
63
+ private _activeCullingSchemeEventHandeler;
64
+ private _iconCullingScheme;
65
+ private _visibleClusteredIcons;
66
+ private _hoveredClusterIcon;
67
+ private _cachedClusteredIcons;
28
68
  get icons(): Overlay3DIcon[];
29
69
  set hoverSpriteVisibility(value: boolean);
30
70
  setCullingScheme(scheme: IconCullingScheme): void;
31
71
  set360IconCullingRestrictions(radius: number, pointLimit: number): void;
32
- constructor(points: Vector3[], sceneHandler: SceneHandler, onBeforeSceneRendered: EventTrigger<BeforeSceneRenderedDelegate>, iconOptions?: IconsOptions);
72
+ getClusterDistanceThreshold(): number;
73
+ setClusterDistanceThreshold(threshold: number): void;
74
+ getMaxOctreeDepth(): number | undefined;
75
+ isHtmlClustersEnabled(): boolean;
76
+ setMaxOctreeDepth(depth: number | undefined): void;
77
+ constructor(points: Vector3[], sceneHandler: SceneHandler, onBeforeSceneRendered: EventTrigger<BeforeSceneRenderedDelegate>, iconOptions?: IconsOptions, setNeedsRedraw?: () => void);
33
78
  setTransform(transform: Matrix4): void;
34
79
  getTransform(out?: Matrix4): Matrix4;
35
- private setIconClustersByLOD;
80
+ /**
81
+ * Intersect a ray with visible clusters. Returns cluster data if a cluster is hit.
82
+ * Only works when HTML clusters are enabled.
83
+ * @param ray - Ray in model space (ray.origin is camera position in model space)
84
+ * @returns ClusterIntersectionData if a cluster is hit, undefined otherwise
85
+ */
86
+ intersectCluster(ray: Ray): ClusterIntersectionData | undefined;
87
+ setHoveredClusterIcon(icon: Overlay3DIcon | undefined): void;
88
+ clearHoveredCluster(): void;
89
+ /**
90
+ * Get the currently visible clustered icons (for external intersection handling).
91
+ */
92
+ getVisibleClusteredIcons(): readonly ClusteredIcon[];
93
+ /**
94
+ * LOD-based icon filtering with cluster visualization.
95
+ * Shows clusters based on distance/LOD and visualizes them with a count texture.
96
+ * @param octree - The octree to use for clustering
97
+ * @param iconSprites - The icon sprites to use for rendering
98
+ * @returns A BeforeSceneRenderedDelegate function that sets the icons by LOD with cluster visualization
99
+ */
100
+ private setIconsByLODWithClustering;
101
+ /**
102
+ * LOD-based icon filtering
103
+ * Shows individual icons based on distance/LOD without pure cluster icons visualization.
104
+ * @param octree - The octree to use for clustering
105
+ * @param iconSprites - The icon sprites to use for rendering
106
+ * @returns A BeforeSceneRenderedDelegate function that sets the icons by LOD without cluster visualization
107
+ */
108
+ private setIconsByLOD;
109
+ /**
110
+ * Update the cluster rendering.
111
+ * @param visibleClusters - The visible clustered icons
112
+ * @param iconSprites - The icon sprites to use for rendering
113
+ * @param params - The parameters for the rendering
114
+ * @param params.renderer - The WebGL renderer
115
+ * @param params.camera - The perspective camera
116
+ * @param params.modelTransform - The model transform matrix
117
+ */
118
+ private updateClusterRendering;
119
+ private calculateCentroid;
120
+ /**
121
+ * Build clustered icons from octree LOD nodes.
122
+ * Processes each node to determine if it should be shown as a cluster or individual icons.
123
+ * @param octree - The octree to use for clustering
124
+ * @param nodes - The nodes to process
125
+ * @param clusterIconSizeMultiplier - The size multiplier for the cluster icons
126
+ * @returns The clustered icons
127
+ */
128
+ buildClusteredIconsFromNodes(octree: IconOctree, nodes: PointOctant<Overlay3DIcon<DefaultOverlay3DContentType>>[], clusterIconSizeMultiplier: number): ClusteredIcon[];
129
+ /**
130
+ * Filter clustered icons by frustum visibility and update culled state.
131
+ * Returns only the visible icons that pass frustum culling and visibility checks.
132
+ * @param frustum - The frustum to use for culling
133
+ * @param clusteredIcons - The clustered icons to filter
134
+ * @returns The visible clustered icons
135
+ */
136
+ private filterVisibleClusteredIcons;
137
+ /**
138
+ * Build render data arrays from visible icons and update the icon sprites.
139
+ * Only renders individual icons (non-clusters)
140
+ * @param visibleIcons - The visible icons to render
141
+ * @param iconSprites - The icon sprites to use for rendering
142
+ */
143
+ private updateIconSpritesRenderData;
36
144
  private computeProximityPoints;
37
145
  private initializeImage360Icons;
38
146
  dispose(): void;
@@ -0,0 +1,18 @@
1
+ /*!
2
+ * Copyright 2026 Cognite AS
3
+ */
4
+ import { Matrix4, PerspectiveCamera, Vector3, WebGLRenderer } from 'three';
5
+ import { Overlay3DIcon } from '../../../../3d-overlays';
6
+ export type ClusteredIconData = {
7
+ icon: Overlay3DIcon;
8
+ isCluster: boolean;
9
+ clusterSize: number;
10
+ clusterPosition: Vector3;
11
+ sizeScale: number;
12
+ clusterIcons?: Overlay3DIcon[];
13
+ };
14
+ export type ClusterRenderParams = {
15
+ renderer: WebGLRenderer;
16
+ camera: PerspectiveCamera;
17
+ modelTransform: Matrix4;
18
+ };
@@ -0,0 +1,47 @@
1
+ /*!
2
+ * Copyright 2026 Cognite AS
3
+ */
4
+ import { Overlay3DIcon } from '../../../../3d-overlays';
5
+ import { ClusteredIconData, ClusterRenderParams } from './ClusterRenderingStrategy';
6
+ export type HtmlClusterRendererOptions = {
7
+ maxPoolSize?: number;
8
+ classPrefix?: string;
9
+ enableHoverAnimations?: boolean;
10
+ zIndex?: number;
11
+ };
12
+ /** HTML-based cluster rendering for high-definition text display */
13
+ export declare class HtmlClusterRenderer {
14
+ private readonly _container;
15
+ private readonly _elementPool;
16
+ private readonly _activeElements;
17
+ private readonly _maxPoolSize;
18
+ private readonly _classPrefix;
19
+ private readonly _enableHoverAnimations;
20
+ private readonly _zIndex;
21
+ private readonly _countSpanName;
22
+ private readonly _baseSize;
23
+ private readonly _minSize;
24
+ private readonly _maxSize;
25
+ private readonly _pendingReleaseTimeouts;
26
+ private _hoveredClusterIcon;
27
+ private _isVisible;
28
+ private _isAttached;
29
+ private _domElement;
30
+ private readonly _tempPosition;
31
+ private readonly _tempProjectedPosition;
32
+ constructor(options?: HtmlClusterRendererOptions);
33
+ updateClusters(visibleClusters: ClusteredIconData[], params: ClusterRenderParams): void;
34
+ setHoveredCluster(icon: Overlay3DIcon | undefined): void;
35
+ getHoveredCluster(): Overlay3DIcon | undefined;
36
+ setVisible(visible: boolean): void;
37
+ dispose(): void;
38
+ private createContainer;
39
+ private injectStyles;
40
+ private ensureAttached;
41
+ private updateContainerSize;
42
+ private acquireElement;
43
+ private releaseElement;
44
+ private createClusterElement;
45
+ private updateClusterElement;
46
+ private setElementHovered;
47
+ }
@@ -0,0 +1,9 @@
1
+ /*!
2
+ * Copyright 2026 Cognite AS
3
+ */
4
+ /**
5
+ * Generates CSS styles for HTML cluster icons.
6
+ * @param classPrefix - The CSS class prefix for cluster elements
7
+ * @returns The complete CSS stylesheet as a string
8
+ */
9
+ export declare function generateClusterStyles(classPrefix: string): string;
@@ -0,0 +1,5 @@
1
+ /*!
2
+ * Copyright 2026 Cognite AS
3
+ */
4
+ export { ClusteredIconData, ClusterRenderParams } from './ClusterRenderingStrategy';
5
+ export { HtmlClusterRenderer, HtmlClusterRendererOptions } from './HtmlClusterRenderer';
@@ -25,3 +25,13 @@ export type Image360IconIntersectionData<T extends DataSourceType = DataSourceTy
25
25
  point: Vector3;
26
26
  distanceToCamera: number;
27
27
  };
28
+ /**
29
+ * Data for a cluster intersection result
30
+ */
31
+ export type Image360ClusterIntersectionData<T extends DataSourceType = DataSourceType> = {
32
+ image360Collection: DefaultImage360Collection<T>;
33
+ clusterPosition: Vector3;
34
+ clusterSize: number;
35
+ clusterIcons: Image360Entity<T>[];
36
+ distanceToCamera: number;
37
+ };
@@ -37,17 +37,24 @@ export declare class IconOctree<ContentType = DefaultOverlay3DContentType> exten
37
37
  /**
38
38
  * Get LOD nodes based purely on camera distance.
39
39
  * This provides consistent behavior regardless of view angle.
40
- *
41
40
  * @param cameraPosition - Camera position in model space
42
41
  * @param distanceThreshold - Distance from camera within which all icons are shown (no clustering)
43
42
  * @param clusteringLevel - The octree level at which to cluster far icons (higher = finer clusters)
44
43
  * @returns Set of PointOctant nodes selected for LOD based on distance
45
44
  */
46
45
  getLODByDistance(cameraPosition: Vector3 | undefined, distanceThreshold: number, clusteringLevel?: number): Set<PointOctant<Overlay3DIcon>>;
46
+ /**
47
+ * Get LOD nodes based on camera distance with enhanced clustering for pure cluster visualization.
48
+ * Uses node size awareness and max depth control for better cluster granularity.
49
+ * @param cameraPosition - Camera position for distance calculation
50
+ * @param distanceThreshold - Distance threshold for "close" icons
51
+ * @param maxOctreeDepth - Maximum octree depth to expand to (controls cluster granularity)
52
+ * @returns Set of PointOctant nodes selected for LOD based on camera distance
53
+ */
54
+ getLODByDistanceWithClustering(cameraPosition: Vector3 | undefined, distanceThreshold: number, maxOctreeDepth?: number): Set<PointOctant<Overlay3DIcon>>;
47
55
  /**
48
56
  * Get all icons from a node's subtree that are within the given distance from a point.
49
57
  * Also returns the representative icon if no close icons are found (for clustering).
50
- *
51
58
  * @param node - The octree node to get icons from
52
59
  * @param cameraPosition - Camera position for distance calculation
53
60
  * @param distanceThreshold - Distance threshold for "close" icons
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { type Matrix4 } from 'three';
5
5
  import { CogniteClient, Metadata } from '@cognite/sdk';
6
- import { Image360Collection, Image360Entity, Image360, IconsOptions, Image360RevisionEntity, Image360AnnotationIntersection, Image360AnnotationFilterOptions, Image360IconIntersectionData, Image360Action } from '../../../360-images';
6
+ import { Image360Collection, Image360Entity, Image360, IconsOptions, Image360RevisionEntity, Image360AnnotationIntersection, Image360AnnotationFilterOptions, Image360IconIntersectionData, Image360ClusterIntersectionData, Image360Action } from '../../../360-images';
7
7
  import { DataSourceType, Image360DataModelIdentifier } from '../../../data-providers';
8
8
  import { BeforeSceneRenderedDelegate, EventTrigger, InputHandler, PointerEventData, SceneHandler } from '../../../utilities';
9
9
  import { ProxyCameraManager } from '../../../camera-manager';
@@ -49,6 +49,21 @@ export declare class Image360ApiHelper<DataSourceT extends DataSourceType> {
49
49
  private findRevisionIdToEnter;
50
50
  private enter360ImageOnIntersect;
51
51
  intersect360ImageIcons(offsetX: number, offsetY: number): Image360IconIntersectionData<DataSourceT> | undefined;
52
+ /**
53
+ * Intersect with cluster icons at the given screen position.
54
+ * @param offsetX - X offset in pixels from the DOM element
55
+ * @param offsetY - Y offset in pixels from the DOM element
56
+ * @returns Cluster intersection data if a cluster is hit, undefined otherwise
57
+ */
58
+ intersect360ImageClusters(offsetX: number, offsetY: number): Image360ClusterIntersectionData<DataSourceT> | undefined;
59
+ /**
60
+ * Zoom the camera toward a cluster position.
61
+ * The camera moves to a position nearby the cluster centroid (not exactly at it)
62
+ * so that the cluster icons become visible and expand.
63
+ * @param clusterData - The cluster intersection data
64
+ * @returns Promise that resolves to true when the zoom is complete
65
+ */
66
+ zoomToCluster(clusterData: Image360ClusterIntersectionData<DataSourceT>): Promise<boolean>;
52
67
  intersect360ImageAnnotations(offsetX: number, offsetY: number): Image360AnnotationIntersection<DataSourceT> | undefined;
53
68
  private setHoverIconOnIntersect;
54
69
  private exit360ImageByTween;
@@ -704,6 +704,7 @@ export declare class Cognite3DViewer<DataSourceT extends DataSourceType = Classi
704
704
  */
705
705
  onHover360Images(event: PointerEvent): boolean;
706
706
  private intersect360Icons;
707
+ private intersect360Clusters;
707
708
  /**
708
709
  * Check for intersections with 360 annotations through the given pixel.
709
710
  * Similar to {@link Cognite3DViewer.getIntersectionFromPixel}, but checks 360 image annotations
@@ -158,6 +158,12 @@ export interface Cognite3DViewerOptions {
158
158
  * @beta
159
159
  */
160
160
  hasEventListeners?: boolean;
161
+ /**
162
+ * Enable HTML-based cluster rendering for 360 image icons.
163
+ * When enabled, nearby 360 icons are grouped into clusters with a count display.
164
+ * @default false
165
+ */
166
+ enableHtmlClusters?: boolean;
161
167
  }
162
168
  /**
163
169
  * @module @cognite/reveal
@@ -264,12 +270,43 @@ export type Image360IconIntersection<T extends DataSourceType = DataSourceType>
264
270
  */
265
271
  distanceToCamera: number;
266
272
  };
273
+ /**
274
+ * Represents the result from a 360 cluster intersection test.
275
+ * @module @cognite/reveal
276
+ * @beta
277
+ */
278
+ export type Image360ClusterIntersection<T extends DataSourceType = DataSourceType> = {
279
+ /**
280
+ * The intersection type.
281
+ */
282
+ type: 'image360Cluster';
283
+ /**
284
+ * The image360 collection containing the cluster.
285
+ */
286
+ image360Collection: Image360Collection<T>;
287
+ /**
288
+ * The world position of the cluster centroid.
289
+ */
290
+ clusterPosition: Vector3;
291
+ /**
292
+ * The number of icons in the cluster.
293
+ */
294
+ clusterSize: number;
295
+ /**
296
+ * The image360 entities in the cluster.
297
+ */
298
+ clusterIcons: Image360<T>[];
299
+ /**
300
+ * Distance from the camera to the cluster.
301
+ */
302
+ distanceToCamera: number;
303
+ };
267
304
  /**
268
305
  * Represents the result from {@link Cognite3DViewer.getAnyIntersectionFromPixel}.
269
306
  * @module @cognite/reveal
270
307
  * @beta
271
308
  */
272
- export type AnyIntersection<T extends DataSourceType = DataSourceType> = CadIntersection | PointCloudIntersection<T> | Image360IconIntersection<T> | CustomObjectIntersection;
309
+ export type AnyIntersection<T extends DataSourceType = DataSourceType> = CadIntersection | PointCloudIntersection<T> | Image360IconIntersection<T> | Image360ClusterIntersection<T> | CustomObjectIntersection;
273
310
  /**
274
311
  * @module @cognite/reveal
275
312
  */
@@ -103,7 +103,13 @@ export declare class DefaultCameraManager implements CameraManager {
103
103
  setCameraControlsOptions(controlsOptions: CameraControlsOptions): void;
104
104
  update(deltaTime: number, boundingBox: THREE.Box3): void;
105
105
  dispose(): void;
106
- private moveCameraTo;
106
+ /**
107
+ * Animates the camera to the given position and target.
108
+ * @param position Desired camera position in world space.
109
+ * @param target Desired look-at target in world space.
110
+ * @param duration Duration of the animation in milliseconds. If omitted, a default is derived from distance.
111
+ */
112
+ moveCameraTo(position: THREE.Vector3, target: THREE.Vector3, duration?: number, keyboardNavigationEnabled?: boolean): void;
107
113
  private moveCameraTargetTo;
108
114
  private updateCameraNearAndFar;
109
115
  private calculateAnimationStartTarget;
@@ -32,5 +32,6 @@ export { Image360ProviderCombiner } from './src/Image360ProviderCombiner';
32
32
  export { BinaryFileProvider, JsonFileProvider, File3dFormat, BlobOutputMetadata, Image360Descriptor, Image360FileProvider, Image360Face, Image360Texture, Image360FileDescriptor, ImageAssetLinkAnnotationInfo, ImageInstanceLinkAnnotationInfo, InstanceReference, Image360Id, Image360RevisionId } from './src/types';
33
33
  export { fetchDMModelIdFromRevisionId } from './src/requests/fetchDMModelIdFromRevisionId';
34
34
  export { isDMPointCloudVolumeObject, isClassicPointCloudVolumeObject, isDMPointCloudVolume, isClassicPointCloudVolume } from './src/utilities/utils';
35
+ export { getExternalIdFromDescriptor } from './src/utilities/getExternalIdFromDescriptor';
35
36
  export { DataSourceType, ClassicDataSourceType, DMDataSourceType, ClassicModelIdentifierType, DMModelIdentifierType, isClassicIdentifier, isDMIdentifier, InternalDataSourceType, LocalDataSourceType, LocalModelIdentifierType, isLocalIdentifier, GenericDataSourceType } from './src/DataSourceType';
36
37
  export { LocalAddModelOptions, CommonModelOptions, InternalAddModelOptions, AddModelOptionsWithModelRevisionId } from './src/utilities/internalAddModelOptions';
@@ -15,6 +15,7 @@ export declare class Image360ProviderCombiner<T extends DataSourceType> implemen
15
15
  get360ImageFiles(image360FaceDescriptors: Image360FileDescriptor[], abortSignal?: AbortSignal): Promise<Image360Face[]>;
16
16
  getLowResolution360ImageFiles(image360FaceDescriptors: Image360FileDescriptor[], abortSignal?: AbortSignal): Promise<Image360Face[]>;
17
17
  getRelevant360ImageAnnotations(annotationSpecifier: Image360AnnotationSpecifier<T>): Promise<T['image360AnnotationType'][]>;
18
+ resolveFileIdToExternalIdMapping(annotations: T['image360AnnotationType'][], descriptors: Image360FileDescriptor[]): Promise<Map<number, string>>;
18
19
  findImageAnnotationsForInstance(instanceFilter: Image360AnnotationInstanceReference<T>, collection: DefaultImage360Collection<T>): Promise<Image360AnnotationAssetQueryResult<T>[]>;
19
20
  getAllImage360AnnotationInfos(source: 'assets', collection: DefaultImage360Collection<T>, annotationFilter: Image360AnnotationFilterDelegate<T>): Promise<AssetAnnotationImage360Info<ClassicDataSourceType>[]>;
20
21
  getAllImage360AnnotationInfos(source: 'hybrid', collection: DefaultImage360Collection<T>, annotationFilter: Image360AnnotationFilterDelegate<T>): Promise<AssetHybridAnnotationImage360Info[]>;
@@ -1,23 +1,47 @@
1
1
  /*!
2
2
  * Copyright 2022 Cognite AS
3
3
  */
4
- import { CogniteClient } from '@cognite/sdk';
5
- import { Image360AnnotationFilterDelegate, Image360AnnotationProvider, Image360AnnotationSpecifier, InstanceReference } from '../types';
4
+ import { AnnotationModel, CogniteClient } from '@cognite/sdk';
5
+ import { Image360AnnotationFilterDelegate, Image360AnnotationProvider, Image360AnnotationSpecifier, Image360FileDescriptor, InstanceReference } from '../types';
6
6
  import { ClassicDataSourceType, DataSourceType, DMDataSourceType } from '../DataSourceType';
7
7
  import { AssetAnnotationImage360Info, AssetHybridAnnotationImage360Info, DefaultImage360Collection, Image360AnnotationAssetQueryResult } from '../../../360-images';
8
8
  export declare class Cdf360ImageAnnotationProvider implements Image360AnnotationProvider<ClassicDataSourceType> {
9
9
  private readonly _client;
10
10
  private readonly _collectionToInstanceReferenceToAnnotationMap;
11
+ private readonly _collectionAnnotationsCache;
12
+ private readonly _collectionFileIdMapCache;
11
13
  constructor(client: CogniteClient);
12
14
  findImageAnnotationsForInstance(asset: InstanceReference<DataSourceType>, collection: DefaultImage360Collection<ClassicDataSourceType>): Promise<Image360AnnotationAssetQueryResult<ClassicDataSourceType>[]>;
13
15
  private fetchImageAnnotationsForInstance;
16
+ /**
17
+ * Gets all annotations for a collection
18
+ */
19
+ private getAllAnnotationsForCollection;
20
+ /**
21
+ * Gets the fileId to entity/revision mapping
22
+ */
23
+ private getFileIdToEntityRevisionMap;
14
24
  private cacheResult;
15
25
  getRelevant360ImageAnnotations(annotationSpecifier: Image360AnnotationSpecifier<ClassicDataSourceType>): Promise<ClassicDataSourceType['image360AnnotationType'][]>;
26
+ /**
27
+ * Fetches file info for the given IDs and returns a map of fileId -> externalId.
28
+ */
29
+ private fetchFileIdToExternalIdMapping;
30
+ /**
31
+ * Resolves the mapping from internal file IDs to external IDs.
32
+ * This is needed to match annotations (which have annotatedResourceId) to descriptors (which may have externalId).
33
+ */
34
+ resolveFileIdToExternalIdMapping(annotations: AnnotationModel[], descriptors: Image360FileDescriptor[]): Promise<Map<number, string>>;
16
35
  getAllImage360AnnotationInfos(source: 'assets', collection: DefaultImage360Collection<ClassicDataSourceType>, annotationFilter: Image360AnnotationFilterDelegate<ClassicDataSourceType>): Promise<AssetAnnotationImage360Info<ClassicDataSourceType>[]>;
17
36
  getAllImage360AnnotationInfos(source: 'hybrid', collection: DefaultImage360Collection<ClassicDataSourceType>, annotationFilter: Image360AnnotationFilterDelegate<ClassicDataSourceType>): Promise<AssetHybridAnnotationImage360Info[]>;
18
37
  getAllImage360AnnotationInfos(source: 'cdm', collection: DefaultImage360Collection<ClassicDataSourceType>, annotationFilter: Image360AnnotationFilterDelegate<ClassicDataSourceType>): Promise<AssetAnnotationImage360Info<DMDataSourceType>[]>;
19
38
  getAllImage360AnnotationInfos(source: 'all', collection: DefaultImage360Collection<ClassicDataSourceType>, annotationFilter: Image360AnnotationFilterDelegate<ClassicDataSourceType>): Promise<AssetAnnotationImage360Info<DataSourceType>[]>;
20
- private createFileIdToEntityRevisionMap;
39
+ /**
40
+ * Builds a mapping from annotatedResourceId (internal file ID) to entity/revision.
41
+ * For legacy descriptors with fileId, uses the fileId directly.
42
+ * For new descriptors with externalId, resolves the mapping via one batched API call.
43
+ */
44
+ private buildFileIdToEntityRevisionMap;
21
45
  private fetchAllAnnotations;
22
46
  private listFileAnnotations;
23
47
  }
@@ -32,6 +32,12 @@ export type Image360AnnotationSpecifier<T extends DataSourceType> = {
32
32
  export type InstanceReference<T extends DataSourceType> = T extends ClassicDataSourceType ? IdEither : DMInstanceRef;
33
33
  export interface Image360AnnotationProvider<T extends DataSourceType> {
34
34
  getRelevant360ImageAnnotations(annotationSpecifier: Image360AnnotationSpecifier<T>): Promise<T['image360AnnotationType'][]>;
35
+ /**
36
+ * Resolves the mapping from internal file IDs (annotatedResourceId) to external IDs.
37
+ * This is needed to match annotations to face descriptors when descriptors use externalId.
38
+ * Optional - if not implemented, the caller should build mapping from descriptors only.
39
+ */
40
+ resolveFileIdToExternalIdMapping?(annotations: T['image360AnnotationType'][], descriptors: Image360FileDescriptor[]): Promise<Map<number, string>>;
35
41
  findImageAnnotationsForInstance(instanceFilter: Image360AnnotationInstanceReference<T>, collection: DefaultImage360Collection<T>): Promise<Image360AnnotationAssetQueryResult<T>[]>;
36
42
  getAllImage360AnnotationInfos(source: 'assets', collection: DefaultImage360Collection<T>, annotationFilter: Image360AnnotationFilterDelegate<T>): Promise<AssetAnnotationImage360Info<ClassicDataSourceType>[]>;
37
43
  getAllImage360AnnotationInfos(source: 'hybrid', collection: DefaultImage360Collection<T>, annotationFilter: Image360AnnotationFilterDelegate<T>): Promise<AssetHybridAnnotationImage360Info[]>;
@@ -0,0 +1,9 @@
1
+ /*!
2
+ * Copyright 2025 Cognite AS
3
+ */
4
+ import { Image360FileDescriptor } from '../types';
5
+ /**
6
+ * Gets the externalId from a file descriptor, if available.
7
+ * Works with both direct externalId and instanceId.externalId.
8
+ */
9
+ export declare function getExternalIdFromDescriptor(desc: Image360FileDescriptor): string | undefined;