Skip to content

Commit

Permalink
feat: Add new options for 360 images and 360 icons (#4809)
Browse files Browse the repository at this point in the history
* Initial commit

* Clean up

* Fix doc

* Fix api

* Fixed according to code review

* Update package.json
  • Loading branch information
nilscognite authored Oct 17, 2024
1 parent c493c61 commit 5395a37
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 100 deletions.
1 change: 0 additions & 1 deletion examples/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Reveal examples</title>
<script defer src="/bundle.js"></script><script defer src="/bundle.js"></script><script defer src="/bundle.js"></script><script defer src="/bundle.js"></script><script defer src="/bundle.js"></script><script defer src="/bundle.js"></script></head>
<body style="padding: 0; margin: 0">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
Expand Down
2 changes: 1 addition & 1 deletion examples/src/pages/Viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ export function Viewer() {
const pointCloudUi = new PointCloudUi(viewer, gui.addFolder('Point clouds'));
await modelUi.restoreModelsFromUrl();
const image360Ui = new Image360UI(viewer, gui.addFolder('360 Images'));
new Image360StylingUI(image360Ui, gui.addFolder('360 annotation styling'));
new Image360StylingUI(viewer, gui.addFolder('360 annotation styling'));

const controlsGui = gui.addFolder('Camera controls');
const mouseWheelActionTypes = ['zoomToCursor', 'zoomPastCursor', 'zoomToTarget'];
Expand Down
9 changes: 4 additions & 5 deletions examples/src/utils/Image360StylingUI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@

import * as dat from 'dat.gui';

import { Image360UI } from './Image360UI';

import * as THREE from 'three';
import { Cognite3DViewer } from '@cognite/reveal';

export class Image360StylingUI {
constructor(image360Ui: Image360UI, gui: dat.GUI) {
constructor(viewer: Cognite3DViewer, gui: dat.GUI) {
const state = {
color: '#ffffff',
visible: true
};

const actions = {
addStyle: () => {
image360Ui.collections.forEach(coll =>
coll.setDefaultAnnotationStyle({
viewer.get360ImageCollections().forEach(collections =>
collections.setDefaultAnnotationStyle({
color: new THREE.Color(state.color as THREE.ColorRepresentation).convertLinearToSRGB(),
visible: state.visible
})
Expand Down
101 changes: 57 additions & 44 deletions examples/src/utils/Image360UI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ import * as dat from 'dat.gui';
export class Image360UI {
private viewer: Cognite3DViewer;
private gui: dat.GUI;
private entities: Image360[] = [];
private selectedEntity: Image360 | undefined;
private _lastAnnotation: Image360Annotation | undefined = undefined;
private _collections: Image360Collection[] = [];

private async handleIntersectionAsync(intersectionPromise: Promise<Image360AnnotationIntersection | null>) {
const intersection = await intersectionPromise;
Expand All @@ -33,10 +31,6 @@ export class Image360UI {
this._lastAnnotation = intersection.annotation;
}

get collections(): Image360Collection[] {
return this._collections;
}

private params = {
siteId: getSiteIdFromUrl() ?? '', // For instance: helideck-site-2-jpeg
space: getSpaceFromUrl() ?? '',
Expand Down Expand Up @@ -66,14 +60,16 @@ export class Image360UI {
radians: 0
};

private opacity = {
alpha: 1
private images360Settings = {
opacity: 1
};

private iconCulling = {
private icons360Setting = {
visible: true,
opacity: 1,
occludedIconsVisible: true,
radius: Infinity,
limit: 50,
hideAll: false
limit: 50
};

private imageRevisions = {
Expand All @@ -99,8 +95,8 @@ export class Image360UI {
});

const optionsFolder = this.gui.addFolder('Add Options (Events)');
optionsFolder.hide();
const optionsFolderFdm = this.gui.addFolder('Add Options (Data Models)');
optionsFolderFdm.hide();
// events
optionsFolder.add(this.params, 'siteId').name('Site ID');

Expand All @@ -124,36 +120,54 @@ export class Image360UI {
this.gui.add(this.params, 'add').name('Add image set');
this.gui.add(this.params, 'remove').name('Remove image set');

this.gui.add(this.opacity, 'alpha', 0, 1, 0.01).onChange(() => {
this.entities.forEach(p => (p.image360Visualization.opacity = this.opacity.alpha));
this.viewer.requestRedraw();
});

gui.add(this.params, 'assetId').name('Asset ID');
gui.add(this.params, 'findAsset').name('Find asset');

this.gui
.add(this.iconCulling, 'radius', 0, 10000, 1)
.name('Culling radius')
.add(this.images360Settings, 'opacity', 0, 1, 0.01)
.name('Image opacity')
.onChange(() => {
this.set360IconCullingRestrictions();
for (const collection of viewer.get360ImageCollections()) {
collection.setImagesOpacity(this.images360Settings.opacity);
}
});

this.gui
.add(this.iconCulling, 'limit', 0, 10000, 1)
.name('Number of points')
.add(this.icons360Setting, 'visible')
.name('Show all 360 images')
.onChange(() => {
for (const collection of viewer.get360ImageCollections()) {
collection.setIconsVisibility(this.icons360Setting.visible);
}
});
this.gui
.add(this.icons360Setting, 'opacity', 0, 1, 0.01)
.name('Icon opacity')
.onChange(() => {
for (const collection of viewer.get360ImageCollections()) {
collection.setIconsOpacity(this.icons360Setting.opacity);
}
});
this.gui
.add(this.icons360Setting, 'occludedIconsVisible')
.name('Set occluded icons visible')
.onChange(() => {
for (const collection of viewer.get360ImageCollections()) {
collection.setOccludedIconsVisible(this.icons360Setting.occludedIconsVisible);
}
});
this.gui
.add(this.icons360Setting, 'radius', 0, 10000, 1)
.name('Icon Culling radius')
.onChange(() => {
this.set360IconCullingRestrictions();
});

this.gui
.add(this.iconCulling, 'hideAll')
.name('Hide all 360 images')
.add(this.icons360Setting, 'limit', 0, 10000, 1)
.name('Icon Number of points')
.onChange(() => {
if (this._collections.length > 0) {
this._collections.forEach(p => p.setIconsVisibility(!this.iconCulling.hideAll));
this.viewer.requestRedraw();
}
this.set360IconCullingRestrictions();
});

this.gui.add(this.params, 'saveToUrl').name('Save 360 site to URL');
Expand All @@ -163,11 +177,13 @@ export class Image360UI {
.add(this.imageRevisions, 'targetDate')
.name('Revision date (Unix epoch time):')
.onChange(() => {
if (this.collections.length === 0) return;

const collections = this.viewer.get360ImageCollections();
if (collections.length === 0) {
return;
}
const date =
this.imageRevisions.targetDate.length > 0 ? new Date(Number(this.imageRevisions.targetDate)) : undefined;
this.collections.forEach(p => (p.targetRevisionDate = date));
collections.forEach(p => (p.targetRevisionDate = date));
if (this.selectedEntity) viewer.enter360Image(this.selectedEntity);
});

Expand Down Expand Up @@ -207,14 +223,11 @@ export class Image360UI {

const collection = await this.addCollection();

collection.setIconsVisibility(!this.iconCulling.hideAll);
collection.setIconsVisibility(this.icons360Setting.visible);
collection.on('image360Entered', (entity, _) => {
this.selectedEntity = entity;
});
this.viewer.on('click', event => this.onAnnotationClicked(event));
this._collections.push(collection);
this.entities = this.entities.concat(collection.image360Entities);

this.viewer.requestRedraw();
}

Expand Down Expand Up @@ -248,16 +261,16 @@ export class Image360UI {
}

private async set360IconCullingRestrictions() {
if (this._collections.length > 0) {
this._collections.forEach(p => p.set360IconCullingRestrictions(this.iconCulling.radius, this.iconCulling.limit));
this.viewer.requestRedraw();
const collections = this.viewer.get360ImageCollections();
if (collections.length === 0) {
return;
}
collections.forEach(p => p.set360IconCullingRestrictions(this.icons360Setting.radius, this.icons360Setting.limit));
this.viewer.requestRedraw();
}

private async removeAll360Images() {
this._collections.forEach(p => this.viewer.remove360ImageSet(p));
this.entities = [];
this._collections = [];
this.viewer.get360ImageCollections().forEach(p => this.viewer.remove360ImageSet(p));
}

private onAnnotationClicked(event: { offsetX: number; offsetY: number; button?: number }): void {
Expand Down Expand Up @@ -286,12 +299,12 @@ export class Image360UI {
if (this.params.assetId.length === 0) {
return;
}

const assetId = Number(this.params.assetId);

const revisionsAndEntities = (
await Promise.all(
this.collections.map(async coll => await coll.findImageAnnotations({ assetRef: { id: assetId } }))
this.viewer
.get360ImageCollections()
.map(async collection => await collection.findImageAnnotations({ assetRef: { id: assetId } }))
)
).flat(1);

Expand Down
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.18.0",
"version": "4.19.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
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { Image360 } from '../entity/Image360';
import { Image360Revision } from '../entity/Image360Revision';
import { ImageAssetLinkAnnotationInfo } from '@reveal/data-providers';
import { Matrix4 } from 'three';
import { DEFAULT_IMAGE_360_OPACITY } from '../entity/Image360VisualizationBox';

type Image360Events = 'image360Entered' | 'image360Exited';

Expand Down Expand Up @@ -161,21 +162,45 @@ export class DefaultImage360Collection implements Image360Collection {
this._icons.set360IconCullingRestrictions(radius, pointLimit);
}

/**
* Gets visibility of all 360 image icons.
* @returns true if all icons are visible, false if all icons are invisible
*/
getIconsVisibility(): boolean {
return this._isCollectionVisible;
}

/**
* Set visibility of all 360 image icons.
* @param visible If true all icons are made visible according to the active culling scheme. If false all icons are hidden.
*/
public setIconsVisibility(visible: boolean): void {
this._isCollectionVisible = visible;
this.image360Entities.forEach(entity => entity.icon.setVisible(visible));
public setIconsVisibility(value: boolean): void {
this._isCollectionVisible = value;
this.image360Entities.forEach(entity => entity.icon.setVisible(value));
this._needsRedraw = true;
}

public isOccludedIconsVisible(): boolean {
return this._icons.isOccludedVisible();
}

public setOccludedIconsVisible(value: boolean): void {
this._icons.setOccludedVisible(value);
this._needsRedraw = true;
}

public getIconsOpacity(): number {
return this._icons.getOpacity();
}

public setIconsOpacity(value: number): void {
this._icons.setOpacity(value);
this._needsRedraw = true;
}

public getImagesOpacity(): number {
for (const entity of this.image360Entities) {
return entity.image360Visualization.opacity;
}
return DEFAULT_IMAGE_360_OPACITY;
}

public setImagesOpacity(value: number): void {
for (const entity of this.image360Entities) {
entity.image360Visualization.opacity = value;
}
this._needsRedraw = true;
}

Expand Down
36 changes: 36 additions & 0 deletions viewer/packages/360-images/src/collection/Image360Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,42 @@ export interface Image360Collection {
*/
setIconsVisibility(visible: boolean): void;

/**
* Check if the occluded icons are visible
* @returns true is occluded icons are visible
*/
isOccludedIconsVisible(): boolean;

/**
* Set the occluded icons visible
* @param visible
*/
setOccludedIconsVisible(visible: boolean): void;

/**
* Get the opacity of the images
* @returns The opacity of the images
*/
getImagesOpacity(): number;

/**
* Set the opacity of the images
* @param opacity The opacity of the images
*/
setImagesOpacity(opacity: number): void;

/**
* Get the opacity of the icons
* @returns The opacity of the icons
*/
getIconsOpacity(): number;

/**
* Set the opacity of the icons
* @param opacity The opacity of the icons
*/
setIconsOpacity(opacity: number): void;

/**
* Subscribes to events on 360 Image datasets. There are several event types:
* 'image360Entered' - Subscribes to a event for entering 360 image mode.
Expand Down
Loading

0 comments on commit 5395a37

Please sign in to comment.