Skip to content

Commit

Permalink
feat: Fixes for the architecture (#4569)
Browse files Browse the repository at this point in the history
* Initial commit

* Added comments

* Update Cognite3DViewer.ts

* Fixes

* Fixed according to review

* Fix doc and let statement
  • Loading branch information
nilscognite authored Jun 5, 2024
1 parent f3ee5a6 commit 36188d0
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 50 deletions.
102 changes: 63 additions & 39 deletions viewer/packages/api/src/public/migration/Cognite3DViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1568,34 +1568,47 @@ export class Cognite3DViewer {
* @param pixelCoords Pixel coordinate in pixels (relative to the domElement).
* @param options
* @param options.stopOnHitting360Icon
* @param options.predicate Check whether a CustomObject should be intersected.
* @returns A promise that if there was an intersection then return the intersection object - otherwise it
* returns `null` if there were no intersections.
* @beta
*/
public async getAnyIntersectionFromPixel(
pixelCoords: THREE.Vector2,
options?: { stopOnHitting360Icon?: boolean }
options?: {
stopOnHitting360Icon?: boolean;
predicate?: (customObject: ICustomObject) => boolean;
}
): Promise<AnyIntersection | undefined> {
if ((options?.stopOnHitting360Icon ?? true) && this.isIntersecting360Icon(pixelCoords)) {
return undefined;
}

const modelIntersection = await this.intersectModels(pixelCoords.x, pixelCoords.y, { asyncCADIntersection: false });

// Find any custom object intersection closer to the camera than the model intersection
const customObjectIntersection = this.getCustomObjectIntersectionIfCloser(
pixelCoords,
modelIntersection?.distanceToCamera
);
if (customObjectIntersection !== undefined) {
// No intersection
return customObjectIntersection;
const predicate = options?.predicate;
let intersection: AnyIntersection | undefined = this.getCustomObjectIntersectionIfCloser(pixelCoords, {
useDepthTest: false,
predicate
});
if (intersection !== undefined) {
return intersection;
}
const modelIntersection = await this.intersectModels(pixelCoords.x, pixelCoords.y, {
asyncCADIntersection: false
});
if (modelIntersection !== null) {
intersection = modelIntersection;
}
if (modelIntersection != null) {
// Custom object intersection
return modelIntersection;
// Find any custom object intersection closer to the camera than the model intersection
const closestDistanceToCamera = intersection?.distanceToCamera;
const customIntersectionPass2 = this.getCustomObjectIntersectionIfCloser(pixelCoords, {
useDepthTest: true,
closestDistanceToCamera,
predicate
});
if (customIntersectionPass2 !== undefined) {
intersection = customIntersectionPass2;
}
return undefined;
return intersection;
}

private isIntersecting360Icon(vector: THREE.Vector2): boolean {
Expand Down Expand Up @@ -1685,7 +1698,9 @@ export class Cognite3DViewer {
const start = Date.now();

this._events.beforeSceneRendered.fire({ frameNumber, renderer: this.renderer, camera });

this._sceneHandler.customObjects.forEach(customObject => {
customObject.beforeRender(camera);
});
this.revealManager.render(camera);
this.revealManager.resetRedraw();
this._image360ApiHelper?.resetRedraw();
Expand Down Expand Up @@ -1772,14 +1787,25 @@ export class Cognite3DViewer {

private getCustomObjectIntersectionIfCloser(
pixelCoords: THREE.Vector2,
closestDistanceToCamera: number | undefined
options: {
useDepthTest: boolean;
closestDistanceToCamera?: number;
predicate?: (customObject: ICustomObject) => boolean;
}
): CustomObjectIntersection | undefined {
let intersectInput: CustomObjectIntersectInput | undefined = undefined; // Lazy creation for speed
let closestIntersection: CustomObjectIntersection | undefined = undefined;
let closestDistanceToCamera = options.closestDistanceToCamera;
this._sceneHandler.customObjects.forEach(customObject => {
if (options.predicate !== undefined && !options.predicate(customObject)) {
return;
}
if (!customObject.object.visible) {
return;
}
if (options.useDepthTest !== customObject.useDepthTest) {
return;
}
if (!customObject.shouldPick) {
return;
}
Expand All @@ -1806,41 +1832,39 @@ export class Cognite3DViewer {
offsetY: number,
pickBoundingBox: boolean
): Promise<CameraManagerCallbackData> {
const modelIntersection = await this.intersectModels(offsetX, offsetY, { asyncCADIntersection: false });
const pixelCoords = new THREE.Vector2(offsetX, offsetY);

// Find any custom object intersection closer to the camera than the model intersection
const customObjectIntersection = this.getCustomObjectIntersectionIfCloser(
new THREE.Vector2(offsetX, offsetY),
modelIntersection?.distanceToCamera
);
if (customObjectIntersection === undefined && modelIntersection === null) {
const intersection = await this.getAnyIntersectionFromPixel(pixelCoords);
if (intersection === undefined) {
// No intersection
return {
intersection: null,
pickedBoundingBox: undefined,
modelsBoundingBox: this.getSceneBoundingBox()
};
}
if (customObjectIntersection) {
// Custom object intersection
if (intersection.type === 'customObject') {
return {
intersection: customObjectIntersection,
pickedBoundingBox: pickBoundingBox ? customObjectIntersection.boundingBox : undefined,
intersection,
pickedBoundingBox: pickBoundingBox ? intersection.boundingBox : undefined,
modelsBoundingBox: this.getSceneBoundingBox()
};
}
if (intersection.type === 'cad') {
const getBoundingBox = async (intersection: CadIntersection): Promise<THREE.Box3 | undefined> => {
const model = intersection.model;
const treeIndex = intersection.treeIndex;
return model.getBoundingBoxByTreeIndex(treeIndex);
};
return {
intersection,
pickedBoundingBox: pickBoundingBox ? await getBoundingBox(intersection) : undefined,
modelsBoundingBox: this.getSceneBoundingBox()
};
}
const getBoundingBox = async (intersection: Intersection | null): Promise<THREE.Box3 | undefined> => {
if (intersection?.type !== 'cad') {
return undefined;
}
const model = intersection.model;
const treeIndex = intersection.treeIndex;
return model.getBoundingBoxByTreeIndex(treeIndex);
};
// Model intersection
return {
intersection: modelIntersection,
pickedBoundingBox: pickBoundingBox ? await getBoundingBox(modelIntersection) : undefined,
intersection,
pickedBoundingBox: undefined,
modelsBoundingBox: this.getSceneBoundingBox()
};
}
Expand Down
40 changes: 30 additions & 10 deletions viewer/packages/utilities/src/customObject/CustomObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright 2024 Cognite AS
*/

import { Object3D, Box3 } from 'three';
import { Object3D, Box3, PerspectiveCamera } from 'three';
import { CustomObjectIntersection } from './CustomObjectIntersection';
import { CustomObjectIntersectInput } from './CustomObjectIntersectInput';
import { ICustomObject } from './ICustomObject';
Expand All @@ -17,6 +17,7 @@ export class CustomObject implements ICustomObject {
private _isPartOfBoundingBox: boolean = true;
private _shouldPick: boolean = false;
private _shouldPickBoundingBox: boolean = false;
private _useDepthTest: boolean = true;

/**
* Constructor
Expand Down Expand Up @@ -60,15 +61,6 @@ export class CustomObject implements ICustomObject {
this._shouldPick = value;
}

/**
* Get the bounding box from the object
* @beta
*/
getBoundingBox(target: Box3): Box3 {
target.setFromObject(this.object);
return target;
}

/**
* Set or get whether it should be also give the bounding box when picked by the camera
* Default is false.
Expand All @@ -82,6 +74,28 @@ export class CustomObject implements ICustomObject {
this._shouldPickBoundingBox = value;
}

/**
* Get whether it should be rendered with depth test (on top on other objects)
* Default is true.
* @beta
*/
get useDepthTest(): boolean {
return this._useDepthTest;
}

set useDepthTest(value: boolean) {
this._useDepthTest = value;
}

/**
* Get the bounding box from the object
* @beta
*/
getBoundingBox(target: Box3): Box3 {
target.setFromObject(this.object);
return target;
}

/**
* Intersect the object with the raycaster.
* This function can be overridden to provide custom intersection logic.
Expand Down Expand Up @@ -117,4 +131,10 @@ export class CustomObject implements ICustomObject {
}
return customObjectIntersection;
}

/**
* This method is called before rendering of the custom object
* @beta
*/
beforeRender(_camera: PerspectiveCamera): void {}
}
15 changes: 14 additions & 1 deletion viewer/packages/utilities/src/customObject/ICustomObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright 2024 Cognite AS
*/

import { Object3D, Box3 } from 'three';
import { Object3D, Box3, PerspectiveCamera } from 'three';
import { CustomObjectIntersection } from './CustomObjectIntersection';
import { CustomObjectIntersectInput } from './CustomObjectIntersectInput';

Expand Down Expand Up @@ -39,6 +39,13 @@ export interface ICustomObject {
*/
get shouldPickBoundingBox(): boolean;

/**
* Get whether it should be rendered with depth test (on top on other objects)
* Default is true.
* @beta
*/
get useDepthTest(): boolean;

/**
* Get the bounding box from the object
* @beta
Expand All @@ -54,4 +61,10 @@ export interface ICustomObject {
intersectInput: CustomObjectIntersectInput,
closestDistance: number | undefined
): undefined | CustomObjectIntersection;

/**
* This method is called before rendering of the custom object
* @beta
*/
beforeRender(camera: PerspectiveCamera): void;
}
6 changes: 6 additions & 0 deletions viewer/reveal.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ export class Cognite3DViewer {
// @beta
getAnyIntersectionFromPixel(pixelCoords: THREE.Vector2, options?: {
stopOnHitting360Icon?: boolean;
predicate?: (customObject: ICustomObject) => boolean;
}): Promise<AnyIntersection | undefined>;
// @deprecated
getClippingPlanes(): THREE.Plane[];
Expand Down Expand Up @@ -756,6 +757,7 @@ export enum Corner {
// @beta
export class CustomObject implements ICustomObject {
constructor(object: Object3D);
beforeRender(_camera: PerspectiveCamera): void;
getBoundingBox(target: Box3): Box3;
intersectIfCloser(intersectInput: CustomObjectIntersectInput, closestDistance: number | undefined): undefined | CustomObjectIntersection;
get isPartOfBoundingBox(): boolean;
Expand All @@ -765,6 +767,8 @@ export class CustomObject implements ICustomObject {
set shouldPick(value: boolean);
get shouldPickBoundingBox(): boolean;
set shouldPickBoundingBox(value: boolean);
get useDepthTest(): boolean;
set useDepthTest(value: boolean);
}

// @beta
Expand Down Expand Up @@ -1096,12 +1100,14 @@ export type HtmlOverlayToolOptions = {

// @beta
export interface ICustomObject {
beforeRender(camera: PerspectiveCamera): void;
getBoundingBox(target: Box3): Box3;
intersectIfCloser(intersectInput: CustomObjectIntersectInput, closestDistance: number | undefined): undefined | CustomObjectIntersection;
get isPartOfBoundingBox(): boolean;
get object(): Object3D;
get shouldPick(): boolean;
get shouldPickBoundingBox(): boolean;
get useDepthTest(): boolean;
}

// @beta
Expand Down

0 comments on commit 36188d0

Please sign in to comment.