Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: styling for 360 icons #3757

Merged
merged 14 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions viewer/api-entry-points/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export {
Image360Collection,
Image360EnteredDelegate,
Image360ExitedDelegate,
Image360IconStyle,
Image360AnnotationIntersection,
Image360AnnotationAppearance,
Image360Annotation,
Expand Down
2 changes: 1 addition & 1 deletion viewer/packages/360-images/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright 2022 Cognite AS
*/

export { Image360 } from './src/entity/Image360';
export { Image360, Image360IconStyle } from './src/entity/Image360';
export { Image360Revision } from './src/entity/Image360Revision';
export {
Image360Collection,
Expand Down
22 changes: 22 additions & 0 deletions viewer/packages/360-images/src/entity/Image360.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@
import { Image360Revision } from './Image360Revision';
import { Image360Visualization } from './Image360Visualization';

import { Color } from 'three';

/**
* Image360 icon style
*/
export type Image360IconStyle = {
/**
* A color tint to apply to the 360 icon
*/
color?: Color;
};

/**
* A single 360 image "station", which may consist of several revisions
* captured in approximately the same location
Expand Down Expand Up @@ -46,4 +58,14 @@ export interface Image360 {
* @returns The active revision.
*/
getActiveRevision(): Image360Revision;

/**
* Get a copy of the style assigned to the icon of this entity
*/
getIconStyle(): Image360IconStyle;

/**
* Assign a style to the icon of this entity
*/
setIconStyle(style: Image360IconStyle): void;
}
14 changes: 13 additions & 1 deletion viewer/packages/360-images/src/entity/Image360Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { DeviceDescriptor, SceneHandler } from '@reveal/utilities';
import { Image360DataProvider } from '@reveal/data-providers';
import { Image360 } from './Image360';
import { Image360, Image360IconStyle } from './Image360';
import { Historical360ImageSet, Image360EventDescriptor } from '@reveal/data-providers/src/types';
import { Image360RevisionEntity } from './Image360RevisionEntity';
import minBy from 'lodash/minBy';
Expand All @@ -13,13 +13,16 @@ import { ImageAnnotationObject } from '../annotation/ImageAnnotationObject';
import { Overlay3DIcon } from '@reveal/3d-overlays';
import { Image360AnnotationFilter } from '../annotation/Image360AnnotationFilter';

import cloneDeep from 'lodash/cloneDeep';

export class Image360Entity implements Image360 {
private readonly _revisions: Image360RevisionEntity[];
private readonly _imageMetadata: Image360EventDescriptor;
private readonly _transform: THREE.Matrix4;
private readonly _image360Icon: Overlay3DIcon;
private readonly _image360VisualizationBox: Image360VisualizationBox;
private _activeRevision: Image360RevisionEntity;
private _iconStyle: Image360IconStyle = {};

/**
* Get a copy of the model-to-world transformation matrix
Expand Down Expand Up @@ -160,4 +163,13 @@ export class Image360Entity implements Image360 {
this._revisions.forEach(revision => revision.dispose());
this._image360Icon.dispose();
}

public getIconStyle(): Image360IconStyle {
return cloneDeep(this._iconStyle);
}

public setIconStyle(style: Image360IconStyle): void {
this._iconStyle = style;
this._image360Icon.setColor(style.color);
}
}
19 changes: 12 additions & 7 deletions viewer/packages/360-images/src/icons/IconCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ export class IconCollection {
spriteTexture: sharedTexture,
minPixelSize: IconCollection.MinPixelSize,
maxPixelSize: this._maxPixelSize,
radius: this._iconRadius
radius: this._iconRadius,
maskTexture: sharedTexture
});
iconsSprites.setPoints(points);

const spriteTexture = this.createHoverIconTexture();
this._hoverSprite = this.createHoverSprite(spriteTexture);
Expand Down Expand Up @@ -133,7 +133,11 @@ export class IconCollection {

this._icons.forEach(icon => (icon.culled = true));
selectedIcons.forEach(icon => (icon.culled = false));
iconSprites.setPoints(selectedIcons.filter(icon => icon.getVisible()).map(icon => icon.getPosition()));
const visibleIcons = selectedIcons.filter(icon => icon.getVisible());
iconSprites.setPoints(
visibleIcons.map(icon => icon.getPosition()),
visibleIcons.map(icon => icon.getColor())
);
};
}

Expand All @@ -159,11 +163,12 @@ export class IconCollection {

this._icons.forEach(icon => (icon.culled = true));
closestPoints.forEach(icon => (icon.culled = false));

const closestVisibleReversedPoints = closestPoints.filter(icon => icon.getVisible()).reverse();

iconSprites.setPoints(
closestPoints
.filter(icon => icon.getVisible())
.reverse()
.map(p => p.getPosition())
closestVisibleReversedPoints.map(p => p.getPosition()),
closestVisibleReversedPoints.map(p => p.getColor())
);
};
}
Expand Down
98 changes: 69 additions & 29 deletions viewer/packages/360-images/unit-tests/Image360Entity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,79 @@ import { DeviceDescriptor, SceneHandler } from '@reveal/utilities';
import { Historical360ImageSet } from '@reveal/data-providers/src/types';
import { Image360AnnotationFilter } from '../src/annotation/Image360AnnotationFilter';

function createMockImage360(options?: { customTranslation?: THREE.Matrix4 }) {
const image360Descriptor: Historical360ImageSet = {
id: '0',
label: 'testEntity',
collectionId: '0',
collectionLabel: 'test_collection',
transform: new THREE.Matrix4(),
imageRevisions: [
{
timestamp: undefined,
faceDescriptors: []
}
]
};

const mockSceneHandler = new Mock<SceneHandler>().setup(p => p.addCustomObject(It.IsAny())).returns();
const mock360ImageProvider = new Mock<Image360Provider<any>>();
const mock360ImageIcon = new Overlay3DIcon(
{ position: new THREE.Vector3(), minPixelSize: 10, maxPixelSize: 10, iconRadius: 10 },
{}
);

const testTranslation = options?.customTranslation ?? new THREE.Matrix4();
const desktopDevice: DeviceDescriptor = { deviceType: 'desktop' };

return new Image360Entity(
image360Descriptor,
mockSceneHandler.object(),
mock360ImageProvider.object(),
new Image360AnnotationFilter({}),
testTranslation,
mock360ImageIcon,
desktopDevice
);
}

describe(Image360Entity.name, () => {
test('transformation should be respected', () => {
const image360Descriptor: Historical360ImageSet = {
id: '0',
label: 'testEntity',
collectionId: '0',
collectionLabel: 'test_collection',
transform: new THREE.Matrix4(),
imageRevisions: [
{
timestamp: undefined,
faceDescriptors: []
}
]
};

const mockSceneHandler = new Mock<SceneHandler>().setup(p => p.addCustomObject(It.IsAny())).returns();
const mock360ImageProvider = new Mock<Image360Provider<any>>();
const mock360ImageIcon = new Mock<Overlay3DIcon>().object();

const testTranslation = new THREE.Matrix4().makeTranslation(4, 5, 6);
const desktopDevice: DeviceDescriptor = { deviceType: 'desktop' };

const entity = new Image360Entity(
image360Descriptor,
mockSceneHandler.object(),
mock360ImageProvider.object(),
new Image360AnnotationFilter({}),
testTranslation,
mock360ImageIcon,
desktopDevice
);
const entity = createMockImage360({ customTranslation: testTranslation });

expect(entity.transform.equals(testTranslation)).toBeTrue();
});

test('set icon color is returned in getter', () => {
const entity = createMockImage360();

const { color: originalColor } = entity.getIconStyle();

expect(originalColor).toBe(undefined);

const testColor = new THREE.Color(0.2, 0.3, 0.4);
entity.setIconStyle({ color: testColor });

const { color: gottenColor } = entity.getIconStyle();

expect(gottenColor?.toArray()).toEqual(testColor.toArray());
});

test('setting undefined icon color resets image360 icon color', () => {
const entity = createMockImage360();

const testColor = new THREE.Color(0.2, 0.3, 0.4);
entity.setIconStyle({ color: testColor });

const { color: firstColor } = entity.getIconStyle();

expect(firstColor).not.toBe(undefined);

entity.setIconStyle({ color: undefined });

const { color: secondColor } = entity.getIconStyle();

expect(secondColor).toBe(undefined);
});
});
12 changes: 9 additions & 3 deletions viewer/packages/3d-overlays/src/Overlay3DIcon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class Overlay3DIcon<ContentType = DefaultOverlay3DContentType> implements
private readonly _hoverSprite?: THREE.Sprite;
private readonly _content: ContentType;
private readonly _raycastBoundingSphere = new Sphere();
private readonly _defaultColor: Color;

private _adaptiveScale = 1;
private _visible = true;
Expand All @@ -58,6 +59,7 @@ export class Overlay3DIcon<ContentType = DefaultOverlay3DContentType> implements
this._hoverSprite = hoverSprite;
this._content = content;
this._color = color ?? this._color;
this._defaultColor = this._color;

this._setAdaptiveScale = this.setupAdaptiveScaling(position);

Expand Down Expand Up @@ -127,9 +129,13 @@ export class Overlay3DIcon<ContentType = DefaultOverlay3DContentType> implements
}
}

setColor(color: Color): void {
this._color = color;
this._events.parametersChange.fire({ color, visble: this.getVisible() });
setColor(color: Color | undefined): void {
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
if (color === undefined) {
this._color = this._defaultColor;
} else {
this._color = color;
}
this._events.parametersChange.fire({ color: this._color, visble: this.getVisible() });
}

getColor(): Color {
Expand Down
7 changes: 7 additions & 0 deletions viewer/reveal.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -794,10 +794,12 @@ export type HtmlOverlayToolOptions = {
// @public
export interface Image360 {
getActiveRevision(): Image360Revision;
getIconStyle(): Image360IconStyle;
getRevisions(): Image360Revision[];
readonly id: string;
readonly image360Visualization: Image360Visualization;
readonly label: string | undefined;
setIconStyle(style: Image360IconStyle): void;
readonly transform: THREE.Matrix4;
}

Expand Down Expand Up @@ -867,6 +869,11 @@ export type Image360EnteredDelegate = (image360: Image360, revision: Image360Rev
// @public
export type Image360ExitedDelegate = () => void;

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

// @public
export interface Image360Revision {
readonly date: Date | undefined;
Expand Down
Loading