Skip to content

Commit

Permalink
feat(experimental): Add Image360Intersection to AnyIntersection resul…
Browse files Browse the repository at this point in the history
…t and bump to 4.21.0 (#4846)

* feat(experimental): Add Image360Intersection to Any-intersection result

* chore: mark as beta

* chore: make return type more clean

* chore: lint fix and update API

* chore: fix import path

* chore: bump react version to 4.21.0
  • Loading branch information
haakonflatval-cognite authored Nov 5, 2024
1 parent af85c21 commit 7a1313b
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 32 deletions.
2 changes: 1 addition & 1 deletion viewer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cognite/reveal",
"version": "4.20.1",
"version": "4.21.0",
"description": "WebGL based 3D viewer for CAD and point clouds processed in Cognite Data Fusion.",
"homepage": "https://github.com/cognitedata/reveal/tree/master/viewer",
"repository": {
Expand Down
21 changes: 17 additions & 4 deletions viewer/packages/360-images/src/Image360Facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Image360RevisionEntity } from './entity/Image360RevisionEntity';
import { Image360AnnotationFilterOptions } from './annotation/types';
import { AsyncSequencer } from '@reveal/utilities/src/AsyncSequencer';
import { DataSourceType } from '@reveal/data-providers';
import { Image360IconIntersectionData } from './types';

export class Image360Facade<T extends DataSourceType> {
private readonly _image360Collections: DefaultImage360Collection<T>[];
Expand Down Expand Up @@ -121,7 +122,7 @@ export class Image360Facade<T extends DataSourceType> {
return imageCollection[0];
}

public intersect(coords: THREE.Vector2, camera: THREE.Camera): Image360Entity<T> | undefined {
public intersect(coords: THREE.Vector2, camera: THREE.Camera): Image360IconIntersectionData<T> | undefined {
const cameraDirection = camera.getWorldDirection(new THREE.Vector3());
const cameraPosition = camera.position.clone();
const collectionMatrix = new THREE.Matrix4();
Expand All @@ -143,7 +144,9 @@ export class Image360Facade<T extends DataSourceType> {
.map(intersectionToCameraSpace)
.filter(isInFrontOfCamera)
.sort(byDistanceToCamera)
.map(selectEntity)
.map(([entity, intersectionPoint]) =>
createIntersection(collection, entity, intersectionPoint, camera.position)
)
);

return first(intersections);
Expand Down Expand Up @@ -207,8 +210,18 @@ export class Image360Facade<T extends DataSourceType> {
return a.lengthSq() - b.lengthSq();
}

function selectEntity([entity, _]: [Image360Entity<T>, THREE.Vector3]): Image360Entity<T> {
return entity;
function createIntersection(
image360Collection: DefaultImage360Collection<T>,
image360: Image360Entity<T>,
intersectionPoint: THREE.Vector3,
cameraPosition: THREE.Vector3
): Image360IconIntersectionData<T> {
return {
image360,
image360Collection,
point: intersectionPoint,
distanceToCamera: intersectionPoint.distanceTo(cameraPosition)
};
}
}

Expand Down
11 changes: 11 additions & 0 deletions viewer/packages/360-images/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
* Copyright 2023 Cognite AS
*/

import { Vector3 } from 'three';
import { Image360 } from './entity/Image360';
import { Image360Revision } from './entity/Image360Revision';
import { DataSourceType } from '@reveal/data-providers';
import { Image360Entity } from './entity/Image360Entity';
import { DefaultImage360Collection } from './collection/DefaultImage360Collection';

/**
* Delegate for 360 image mode entered events.
Expand All @@ -14,3 +18,10 @@ export type Image360EnteredDelegate = (image360: Image360, revision: Image360Rev
* Delegate for 360 image mode exited events.
*/
export type Image360ExitedDelegate = () => void;

export type Image360IconIntersectionData<T extends DataSourceType = DataSourceType> = {
image360Collection: DefaultImage360Collection<T>;
image360: Image360Entity<T>;
point: Vector3;
distanceToCamera: number;
};
11 changes: 7 additions & 4 deletions viewer/packages/360-images/visual-tests/Image360.VisualTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,15 @@ export default class Image360VisualTestFixture extends StreamingVisualTestFixtur
renderer.domElement.addEventListener('click', async event => {
const { x, y } = event;
const ndcCoordinates = getNormalizedPixelCoordinates(renderer.domElement, x, y);
const entity = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera);
const intersection = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera);

if (entity === undefined) {
if (intersection === undefined) {
this.render();
return;
}

const entity = intersection.image360;

await facade.preload(entity, entity.getActiveRevision());
entity.image360Visualization.visible = true;
entity.icon.setVisible(false);
Expand Down Expand Up @@ -193,11 +195,12 @@ export default class Image360VisualTestFixture extends StreamingVisualTestFixtur
renderer.domElement.addEventListener('mousemove', async event => {
const { x, y } = event;
const ndcCoordinates = getNormalizedPixelCoordinates(renderer.domElement, x, y);
const entity = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera);
if (entity === undefined) {
const intersection = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera);
if (intersection === undefined) {
this.render();
return;
}
const entity = intersection.image360;
entity.icon.selected = true;
await facade.preload(entity, entity.getActiveRevision());
entity.image360Visualization.visible = false;
Expand Down
19 changes: 12 additions & 7 deletions viewer/packages/api/src/api-helpers/Image360ApiHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { Image360WithCollection } from '../public/types';
import { DEFAULT_IMAGE_360_OPACITY } from '@reveal/360-images/src/entity/Image360VisualizationBox';
import { Image360History } from '@reveal/360-images/src/Image360History';
import { Image360Action } from '@reveal/360-images/src/Image360Action';
import { Image360IconIntersectionData } from '@reveal/360-images/src/types';

export class Image360ApiHelper<DataSourceT extends DataSourceType> {
private readonly _image360Facade: Image360Facade<DataSourceT>;
Expand Down Expand Up @@ -568,20 +569,22 @@ export class Image360ApiHelper<DataSourceT extends DataSourceType> {
if (this._transitionInProgress) {
return Promise.resolve(false);
}
const entity = this.intersect360ImageIcons(event.offsetX, event.offsetY);
if (entity === undefined) {
const intersection = this.intersect360ImageIcons(event.offsetX, event.offsetY);
if (intersection === undefined) {
return Promise.resolve(false);
}
return this.enter360ImageInternal(entity);
return this.enter360ImageInternal(intersection.image360);
}

public intersect360ImageIcons(offsetX: number, offsetY: number): Image360Entity<DataSourceT> | undefined {
public intersect360ImageIcons(
offsetX: number,
offsetY: number
): Image360IconIntersectionData<DataSourceT> | undefined {
const ndcCoordinates = getNormalizedPixelCoordinates(this._domElement, offsetX, offsetY);
const entity = this._image360Facade.intersect(
return this._image360Facade.intersect(
new Vector2(ndcCoordinates.x, ndcCoordinates.y),
this._activeCameraManager.getCamera()
);
return entity;
}

public intersect360ImageAnnotations(offsetX: number, offsetY: number): Image360AnnotationIntersection | undefined {
Expand Down Expand Up @@ -611,11 +614,13 @@ export class Image360ApiHelper<DataSourceT extends DataSourceType> {
this._interactionState.lastMousePosition = { offsetX, offsetY };
this._image360Facade.allIconsSelected = false;
const ndcCoordinates = getNormalizedPixelCoordinates(this._domElement, offsetX, offsetY);
const entity = this._image360Facade.intersect(
const intersection = this._image360Facade.intersect(
new Vector2(ndcCoordinates.x, ndcCoordinates.y),
this._activeCameraManager.getCamera()
);

const entity = intersection?.image360;

if (entity === this._interactionState.currentImage360Hovered) {
entity?.icon.updateHoverSpriteScale();
return;
Expand Down
28 changes: 14 additions & 14 deletions viewer/packages/api/src/public/migration/Cognite3DViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ import {
ResolutionOptions,
RenderParameters,
AnyIntersection,
AddModelOptions
AddModelOptions,
Image360IconIntersection
} from './types';
import { RevealManager } from '../RevealManager';
import { CogniteModel, Image360WithCollection } from '../types';
Expand Down Expand Up @@ -1659,7 +1660,7 @@ export class Cognite3DViewer<DataSourceT extends DataSourceType = ClassicDataSou
* ```
*/
async getIntersectionFromPixel(offsetX: number, offsetY: number): Promise<null | Intersection<DataSourceT>> {
if (this.isIntersecting360Icon(new THREE.Vector2(offsetX, offsetY))) {
if (this.intersect360Icons(new THREE.Vector2(offsetX, offsetY)) !== undefined) {
return null;
}
return this.intersectModels(offsetX, offsetY) as Promise<Intersection<DataSourceT> | null>;
Expand All @@ -1682,8 +1683,9 @@ export class Cognite3DViewer<DataSourceT extends DataSourceType = ClassicDataSou
predicate?: (customObject: ICustomObject) => boolean;
}
): Promise<AnyIntersection<DataSourceT> | undefined> {
if ((options?.stopOnHitting360Icon ?? true) && this.isIntersecting360Icon(pixelCoords)) {
return undefined;
const image360IconIntersection = this.intersect360Icons(pixelCoords);
if (this.intersect360Icons(pixelCoords) !== undefined) {
return image360IconIntersection;
}

const predicate = options?.predicate;
Expand Down Expand Up @@ -1740,18 +1742,16 @@ export class Cognite3DViewer<DataSourceT extends DataSourceType = ClassicDataSou
return true;
}

private isIntersecting360Icon(vector: THREE.Vector2): boolean {
if (this._image360ApiHelper === undefined) {
return false;
}

const image360Intersection = this._image360ApiHelper.intersect360ImageIcons(vector.x, vector.y);

if (image360Intersection !== undefined) {
return true;
private intersect360Icons(vector: THREE.Vector2): Image360IconIntersection<DataSourceT> | undefined {
const iconIntersection = this._image360ApiHelper?.intersect360ImageIcons(vector.x, vector.y);
if (iconIntersection === undefined) {
return undefined;
}

return false;
return {
type: 'image360Icon',
...iconIntersection
};
}

/**
Expand Down
31 changes: 30 additions & 1 deletion viewer/packages/api/src/public/migration/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { EdlOptions } from '@reveal/rendering';
import { Cognite3DViewer } from './Cognite3DViewer';
import { DefaultCameraManager } from '@reveal/camera-manager';
import { CdfModelIdentifier, CommonModelOptions } from '@reveal/data-providers';
import { Image360AnnotationFilterOptions } from '@reveal/360-images';
import { Image360, Image360AnnotationFilterOptions, Image360Collection } from '@reveal/360-images';
import type { Vector2, WebGLRenderTarget, WebGLRenderer, Matrix4, Vector3 } from 'three';
import { CustomObjectIntersection } from '@reveal/utilities';
import { ClassicDataSourceType, DataSourceType, DMDataSourceType } from '@reveal/data-providers';
Expand Down Expand Up @@ -294,6 +294,34 @@ export type Intersection<T extends DataSourceType = ClassicDataSourceType> =
| CadIntersection
| PointCloudIntersection<T>;

/**
* Represents the result from a 360 intersection test.
* @module @cognite/reveal
* @beta
*/
export type Image360IconIntersection<T extends DataSourceType = DataSourceType> = {
/**
* The intersection type.
*/
type: 'image360Icon';
/**
* The image360 that was intersected.
*/
image360: Image360<T>;
/**
* The image360 collection that was intersected.
*/
image360Collection: Image360Collection<T>;
/**
* Coordinate of the intersection.
*/
point: Vector3;
/**
* Distance from the camera to the intersection.
*/
distanceToCamera: number;
};

/**
* Represents the result from {@link Cognite3DViewer.getAnyIntersectionFromPixel}.
* @module @cognite/reveal
Expand All @@ -302,6 +330,7 @@ export type Intersection<T extends DataSourceType = ClassicDataSourceType> =
export type AnyIntersection<T extends DataSourceType = DataSourceType> =
| CadIntersection
| PointCloudIntersection<T>
| Image360IconIntersection<T>
| CustomObjectIntersection;

/**
Expand Down
11 changes: 10 additions & 1 deletion viewer/reveal.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class AnnotationIdPointCloudObjectCollection extends PointCloudAnnotation
}

// @beta
export type AnyIntersection<T extends DataSourceType = DataSourceType> = CadIntersection | PointCloudIntersection<T> | CustomObjectIntersection;
export type AnyIntersection<T extends DataSourceType = DataSourceType> = CadIntersection | PointCloudIntersection<T> | Image360IconIntersection<T> | CustomObjectIntersection;

// @public
export interface AreaCollection {
Expand Down Expand Up @@ -1307,6 +1307,15 @@ export type Image360EnteredDelegate = (image360: Image360, revision: Image360Rev
// @public
export type Image360ExitedDelegate = () => void;

// @beta
export type Image360IconIntersection<T extends DataSourceType = DataSourceType> = {
type: 'image360Icon';
image360: Image360<T>;
image360Collection: Image360Collection<T>;
point: Vector3;
distanceToCamera: number;
};

// @public
export type Image360IconStyle = {
color?: Color;
Expand Down

0 comments on commit 7a1313b

Please sign in to comment.