mirror of
https://github.com/mapillary/mapillary-js.git
synced 2026-02-01 14:33:45 +00:00
feat: change color api to override current mode
This commit is contained in:
parent
17446cf21e
commit
bd10a1b620
@ -2,6 +2,7 @@
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"module": "commonjs",
|
||||
"outDir": "../build/cjs/",
|
||||
"sourceMap": false,
|
||||
|
||||
@ -2409,7 +2409,6 @@ declare var CameraVisualizationMode: {|
|
||||
+Cluster: 2, // 2
|
||||
+ConnectedComponent: 3, // 3
|
||||
+Sequence: 4, // 4
|
||||
+Manual: 5, // 2
|
||||
|};
|
||||
|
||||
declare var OriginalPositionMode: {|
|
||||
@ -2422,7 +2421,6 @@ declare var PointVisualizationMode: {|
|
||||
+Hidden: 0, // 0
|
||||
+Original: 1, // 1
|
||||
+Cluster: 2, // 2
|
||||
+Manual: 3, // 2
|
||||
|};
|
||||
|
||||
/**
|
||||
@ -6607,24 +6605,13 @@ declare class SpatialComponent extends Component<SpatialConfiguration> {
|
||||
constructor(name: string, container: Container, navigator: Navigator): this;
|
||||
|
||||
/**
|
||||
* Configure the cluster color used when painting
|
||||
* clusters manually.
|
||||
*
|
||||
* @description The configured color is applied when the
|
||||
* following visualization modes are set respectively:
|
||||
*
|
||||
* {@link CameraVisualizationMode.Manual}
|
||||
* {@link PointVisualizationMode.Manual}
|
||||
*
|
||||
* @param {string} clusterId - Id of the cluster to configure.
|
||||
* @param {number} color - The color to paint the cluster with.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* spatialComponent.configureClusterColor('my-cluster-id', 0x00ff00);
|
||||
* ```
|
||||
* Get the currently set camera frame override color, or null if
|
||||
* no color is set.
|
||||
* @param {string} clusterId - Id of the cluster.
|
||||
* @returns {string | number | null} The current override color
|
||||
* for the cluster.
|
||||
*/
|
||||
configureClusterColor(clusterId: string, color: number | string): void;
|
||||
getCameraOverrideColor(clusterId: string): string | number | null;
|
||||
|
||||
/**
|
||||
* Returns the image id of the camera frame closest to the current
|
||||
@ -6648,6 +6635,44 @@ declare class SpatialComponent extends Component<SpatialConfiguration> {
|
||||
* ```
|
||||
*/
|
||||
getFrameIdAt(pixelPoint: number[]): Promise<string>;
|
||||
|
||||
/**
|
||||
* Get the currently set point override color, or null if
|
||||
* no color is set.
|
||||
* @param {string} clusterId - Id of the cluster.
|
||||
* @returns {string | number | null} The current override color
|
||||
* for the cluster.
|
||||
*/
|
||||
getPointOverrideColor(clusterId: string): string | number | null;
|
||||
|
||||
/**
|
||||
* Override the camera color for a cluster.
|
||||
* @description The configured color is applied for all visible
|
||||
* visualization modes, overriding the color of the currently
|
||||
* selected mode.
|
||||
* @param {string} clusterId - Id of the cluster to configure.
|
||||
* @param {number | string} color - The color to paint the cameras with.
|
||||
* @example ```js
|
||||
* spatialComponent.setCameraOverrideColor('my-cluster-id', 0x00ff00);
|
||||
* ```
|
||||
*/
|
||||
setCameraOverrideColor(
|
||||
clusterId: string,
|
||||
color: number | string | null
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Override the point color for a cluster.
|
||||
* @description The configured color is applied for all visible
|
||||
* visualization modes, overriding the color of the currently
|
||||
* selected mode.
|
||||
* @param {string} clusterId - Id of the cluster to configure.
|
||||
* @param {number | string} color - The color to paint the points with.
|
||||
* @example ```js
|
||||
* spatialComponent.setPointOverrideColor('my-cluster-id', 0x00ff00);
|
||||
* ```
|
||||
*/
|
||||
setPointOverrideColor(clusterId: string, color: number | string | null): void;
|
||||
_activate(): void;
|
||||
_deactivate(): void;
|
||||
_getDefaultConfiguration(): SpatialConfiguration;
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
import {
|
||||
CameraControls,
|
||||
CameraVisualizationMode,
|
||||
GraphDataProvider,
|
||||
OriginalPositionMode,
|
||||
PointVisualizationMode,
|
||||
Viewer,
|
||||
@ -43,34 +44,63 @@
|
||||
|
||||
let cameraControls = CameraControls.Earth;
|
||||
let spatialActive = true;
|
||||
|
||||
const dataProvider = new GraphDataProvider({ accessToken });
|
||||
const viewer = new Viewer({
|
||||
accessToken,
|
||||
cameraControls,
|
||||
component: { cover: false, spatial: spatialActive },
|
||||
container: "mly",
|
||||
dataProvider,
|
||||
});
|
||||
|
||||
viewer.moveTo(imageId).catch((error) => console.error(error));
|
||||
|
||||
const spatial = viewer.getComponent("spatial");
|
||||
|
||||
viewer.on("click", (event) => {
|
||||
spatial
|
||||
.getFrameIdAt(event.pixelPoint)
|
||||
.then((id) => console.log("Clicked frame:", id));
|
||||
});
|
||||
|
||||
function randomColor() {
|
||||
return `hsl(${Math.floor(360 * Math.random())}, 100%, 75%)`;
|
||||
}
|
||||
let hoveredImageId = null;
|
||||
let paintedClusterId = null;
|
||||
viewer.on("mousemove", async (event) => {
|
||||
function paintCluster(clusterId, color) {
|
||||
spatial.setPointOverrideColor(clusterId, color);
|
||||
spatial.setCameraOverrideColor(clusterId, color);
|
||||
}
|
||||
|
||||
const colors = new Set();
|
||||
viewer.on("image", (event) => {
|
||||
const clusterId = event.image.clusterId;
|
||||
if (colors.has(clusterId)) {
|
||||
const imageId = await spatial.getFrameIdAt(event.pixelPoint);
|
||||
if (imageId === hoveredImageId) {
|
||||
return;
|
||||
}
|
||||
colors.add(clusterId);
|
||||
spatial.configureClusterColor(clusterId, randomColor());
|
||||
hoveredImageId = imageId;
|
||||
|
||||
if (paintedClusterId != null) {
|
||||
paintCluster(paintedClusterId, null);
|
||||
paintedClusterId = null;
|
||||
}
|
||||
|
||||
if (hoveredImageId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const images = await dataProvider.getImages([imageId]);
|
||||
if (images.length !== 1) {
|
||||
return;
|
||||
}
|
||||
const image = images[0];
|
||||
if (image.node.id !== hoveredImageId) {
|
||||
return;
|
||||
}
|
||||
const clusterId = image.node.cluster.id;
|
||||
if (clusterId === paintedClusterId) {
|
||||
return;
|
||||
}
|
||||
|
||||
paintCluster(clusterId, 0xff00ff);
|
||||
paintedClusterId = clusterId;
|
||||
});
|
||||
|
||||
const s = Object.assign({}, spatial.defaultConfiguration, {
|
||||
@ -84,14 +114,12 @@
|
||||
const cluster = camMode.Cluster;
|
||||
const connectedComponent = camMode.ConnectedComponent;
|
||||
const sequence = camMode.Sequence;
|
||||
const manual = camMode.Manual;
|
||||
const camModeRotation = {};
|
||||
camModeRotation[hidden] = homogeneous;
|
||||
camModeRotation[homogeneous] = cluster;
|
||||
camModeRotation[cluster] = connectedComponent;
|
||||
camModeRotation[connectedComponent] = sequence;
|
||||
camModeRotation[sequence] = manual;
|
||||
camModeRotation[manual] = hidden;
|
||||
camModeRotation[sequence] = hidden;
|
||||
|
||||
return function () {
|
||||
s.cameraVisualizationMode =
|
||||
@ -136,12 +164,10 @@
|
||||
const hidden = PointVisualizationMode.Hidden;
|
||||
const original = PointVisualizationMode.Original;
|
||||
const cluster = PointVisualizationMode.Cluster;
|
||||
const manual = PointVisualizationMode.Manual;
|
||||
const pvmRotation = {};
|
||||
pvmRotation[hidden] = original;
|
||||
pvmRotation[original] = cluster;
|
||||
pvmRotation[cluster] = manual;
|
||||
pvmRotation[manual] = hidden;
|
||||
pvmRotation[cluster] = hidden;
|
||||
|
||||
return function () {
|
||||
s.pointVisualizationMode =
|
||||
@ -172,12 +198,6 @@
|
||||
};
|
||||
})();
|
||||
|
||||
function resetManualColor() {
|
||||
for (const clusterId of colors.keys()) {
|
||||
spatial.configureClusterColor(clusterId, randomColor());
|
||||
}
|
||||
}
|
||||
|
||||
window.document.addEventListener("keydown", (e) => {
|
||||
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
|
||||
return;
|
||||
@ -224,9 +244,6 @@
|
||||
case "f":
|
||||
setFilter();
|
||||
break;
|
||||
case "m":
|
||||
resetManualColor();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5,10 +5,6 @@ export function isModeVisible(mode: CameraVisualizationMode): boolean {
|
||||
return mode !== CameraVisualizationMode.Hidden;
|
||||
}
|
||||
|
||||
export function isModeManual(mode: CameraVisualizationMode): boolean {
|
||||
return mode === CameraVisualizationMode.Manual;
|
||||
}
|
||||
|
||||
export function isOverviewState(state: State): boolean {
|
||||
return state === State.Custom || state === State.Earth;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { LngLatAlt } from "../../api/interfaces/LngLatAlt";
|
||||
import { enuToGeodetic, geodeticToEnu } from "../../geo/GeoCoords";
|
||||
|
||||
export const SPATIAL_DEFAULT_MANUAL_COLOR = 0xFFFFFF;
|
||||
export const SPATIAL_DEFAULT_COLOR = 0xFFFFFF;
|
||||
|
||||
export function resetEnu(reference: LngLatAlt, prevEnu: number[], prevReference: LngLatAlt): number[] {
|
||||
const [prevX, prevY, prevZ] = prevEnu;
|
||||
|
||||
@ -97,6 +97,19 @@ export class SpatialComponent extends Component<SpatialConfiguration> {
|
||||
this._spatial = new Spatial();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently set camera frame override color, or null if
|
||||
* no color is set.
|
||||
*
|
||||
* @param {string} clusterId - Id of the cluster.
|
||||
*
|
||||
* @returns {string | number | null} The current override color
|
||||
* for the cluster.
|
||||
*/
|
||||
public getCameraOverrideColor(clusterId: string): string | number | null {
|
||||
return this._scene.getCameraOverrideColor(clusterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image id of the camera frame closest to the current
|
||||
* render camera position at the specified point.
|
||||
@ -149,27 +162,58 @@ export class SpatialComponent extends Component<SpatialConfiguration> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the cluster color used when painting
|
||||
* clusters manually.
|
||||
* Get the currently set point override color, or null if
|
||||
* no color is set.
|
||||
*
|
||||
* @description The configured color is applied when the
|
||||
* following visualization modes are set respectively:
|
||||
* @param {string} clusterId - Id of the cluster.
|
||||
*
|
||||
* {@link CameraVisualizationMode.Manual}
|
||||
* {@link PointVisualizationMode.Manual}
|
||||
* @returns {string | number | null} The current override color
|
||||
* for the cluster.
|
||||
*/
|
||||
public getPointOverrideColor(clusterId: string): string | number | null {
|
||||
return this._scene.getPointOverrideColor(clusterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the camera color for a cluster.
|
||||
*
|
||||
* @description The configured color is applied for all visible
|
||||
* visualization modes, overriding the color of the currently
|
||||
* selected mode.
|
||||
*
|
||||
* @param {string} clusterId - Id of the cluster to configure.
|
||||
* @param {number} color - The color to paint the cluster with.
|
||||
* @param {number | string} color - The color to paint the cameras with.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* spatialComponent.configureClusterColor('my-cluster-id', 0x00ff00);
|
||||
* spatialComponent.setCameraOverrideColor('my-cluster-id', 0x00ff00);
|
||||
* ```
|
||||
*/
|
||||
public configureClusterColor(
|
||||
public setCameraOverrideColor(
|
||||
clusterId: string,
|
||||
color: number | string): void {
|
||||
this._scene.configureClusterColor(clusterId, color);
|
||||
color: number | string | null): void {
|
||||
this._scene.setCameraOverrideColor(clusterId, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the point color for a cluster.
|
||||
*
|
||||
* @description The configured color is applied for all visible
|
||||
* visualization modes, overriding the color of the currently
|
||||
* selected mode.
|
||||
*
|
||||
* @param {string} clusterId - Id of the cluster to configure.
|
||||
* @param {number | string} color - The color to paint the points with.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* spatialComponent.setPointOverrideColor('my-cluster-id', 0x00ff00);
|
||||
* ```
|
||||
*/
|
||||
public setPointOverrideColor(
|
||||
clusterId: string,
|
||||
color: number | string | null): void {
|
||||
this._scene.setPointOverrideColor(clusterId, color);
|
||||
}
|
||||
|
||||
protected _activate(): void {
|
||||
|
||||
@ -19,10 +19,10 @@ import { CellLine } from "./scene/CellLine";
|
||||
import { SpatialIntersection } from "./scene/SpatialIntersection";
|
||||
import { SpatialCell } from "./scene/SpatialCell";
|
||||
import { SpatialAssets } from "./scene/SpatialAssets";
|
||||
import { isModeManual, isModeVisible } from "./Modes";
|
||||
import { isModeVisible } from "./Modes";
|
||||
import { PointVisualizationMode } from "./enums/PointVisualizationMode";
|
||||
import { LngLatAlt } from "../../api/interfaces/LngLatAlt";
|
||||
import { resetEnu, SPATIAL_DEFAULT_MANUAL_COLOR } from "./SpatialCommon";
|
||||
import { resetEnu, SPATIAL_DEFAULT_COLOR } from "./SpatialCommon";
|
||||
|
||||
const NO_CLUSTER_ID = "NO_CLUSTER_ID";
|
||||
const NO_MERGE_ID = "NO_MERGE_ID";
|
||||
@ -66,10 +66,11 @@ export class SpatialScene {
|
||||
private _filter: FilterFunction;
|
||||
|
||||
private _imageCellMap: Map<string, string>;
|
||||
private _clusterCellMap: Map<string, string[]>;
|
||||
private _clusterCellMap: Map<string, Set<string>>;
|
||||
|
||||
private _colors: { hover: string, select: string; };
|
||||
private _manualColors: Map<string, number | string>;
|
||||
private _cameraOverrideColors: Map<string, number | string>;
|
||||
private _pointOverrideColors: Map<string, number | string>;
|
||||
|
||||
constructor(
|
||||
configuration: SpatialConfiguration,
|
||||
@ -104,12 +105,16 @@ export class SpatialScene {
|
||||
this._hoveredId = null;
|
||||
this._selectedId = null;
|
||||
this._colors = { hover: "#FF0000", select: "#FF8000" };
|
||||
this._manualColors = new Map();
|
||||
|
||||
this._cameraOverrideColors = new Map();
|
||||
this._pointOverrideColors = new Map();
|
||||
|
||||
this._filter = () => true;
|
||||
}
|
||||
|
||||
public get needsRender(): boolean { return this._needsRender; }
|
||||
public get needsRender(): boolean {
|
||||
return this._needsRender;
|
||||
}
|
||||
public get intersection(): SpatialIntersection {
|
||||
return this._intersection;
|
||||
}
|
||||
@ -125,26 +130,14 @@ export class SpatialScene {
|
||||
|
||||
const clusterId = reconstruction.id;
|
||||
|
||||
if (!this._manualColors.has(clusterId)) {
|
||||
this._manualColors.set(clusterId, SPATIAL_DEFAULT_MANUAL_COLOR);
|
||||
}
|
||||
|
||||
if (!(clusterId in this._clusters)) {
|
||||
this._clusters[clusterId] = {
|
||||
points: new Object3D(),
|
||||
cellIds: [],
|
||||
};
|
||||
|
||||
const visible = this._getClusterVisible(clusterId);
|
||||
const color = this._getPointColor(clusterId);
|
||||
const cluster = this._clusters[clusterId];
|
||||
|
||||
let color: number | string = null;
|
||||
if (this._pointVisualizationMode === PointVisualizationMode.Cluster) {
|
||||
color = this._assets.getColor(clusterId);
|
||||
} else if (this._pointVisualizationMode === PointVisualizationMode.Manual) {
|
||||
color = this._manualColors.get(clusterId);
|
||||
}
|
||||
|
||||
const points = new ClusterPoints({
|
||||
cluster: reconstruction,
|
||||
color,
|
||||
@ -152,6 +145,7 @@ export class SpatialScene {
|
||||
scale: this._pointSize,
|
||||
translation,
|
||||
});
|
||||
const visible = this._getClusterVisible(clusterId);
|
||||
cluster.points.visible = visible;
|
||||
cluster.points.add(points);
|
||||
this._scene.add(cluster.points);
|
||||
@ -195,16 +189,17 @@ export class SpatialScene {
|
||||
}
|
||||
|
||||
const cell = this._images[cellId];
|
||||
if (cell.hasImage(imageId)) { return; }
|
||||
if (cell.hasImage(imageId)) {
|
||||
return;
|
||||
}
|
||||
cell.addImage({ idMap, image: image });
|
||||
|
||||
let color: number | string = null;
|
||||
if (this._pointVisualizationMode === PointVisualizationMode.Cluster) {
|
||||
const colorId = cell.getColorId(imageId, this._cameraVisualizationMode);
|
||||
color = this._assets.getColor(colorId);
|
||||
} else if (this._pointVisualizationMode === PointVisualizationMode.Manual) {
|
||||
color = this._manualColors.get(idMap.clusterId);
|
||||
}
|
||||
const colorId = cell.getColorId(imageId, this._cameraVisualizationMode);
|
||||
let color: number | string =
|
||||
this._cameraOverrideColors.has(idMap.clusterId) ?
|
||||
this._pointOverrideColors.get(idMap.clusterId) :
|
||||
this._assets.getColor(colorId);
|
||||
|
||||
const visible = this._filter(image);
|
||||
cell.visualize({
|
||||
id: imageId,
|
||||
@ -218,9 +213,12 @@ export class SpatialScene {
|
||||
});
|
||||
|
||||
if (!this._clusterCellMap.has(idMap.clusterId)) {
|
||||
this._clusterCellMap.set(idMap.clusterId, []);
|
||||
this._clusterCellMap.set(idMap.clusterId, new Set());
|
||||
}
|
||||
const clusterCells = this._clusterCellMap.get(idMap.clusterId);
|
||||
if (!clusterCells.has(cellId)) {
|
||||
clusterCells.add(cellId);
|
||||
}
|
||||
this._clusterCellMap.get(idMap.clusterId).push(cellId);
|
||||
this._imageCellMap.set(imageId, cellId);
|
||||
|
||||
if (imageId === this._selectedId) {
|
||||
@ -233,9 +231,6 @@ export class SpatialScene {
|
||||
const clusterVisible = this._getClusterVisible(idMap.clusterId);
|
||||
this._clusters[idMap.clusterId].points.visible = clusterVisible;
|
||||
}
|
||||
if (!this._manualColors.has(idMap.clusterId)) {
|
||||
this._manualColors.set(idMap.clusterId, SPATIAL_DEFAULT_MANUAL_COLOR);
|
||||
}
|
||||
|
||||
this._needsRender = true;
|
||||
}
|
||||
@ -254,39 +249,6 @@ export class SpatialScene {
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public configureClusterColor(
|
||||
clusterId: string,
|
||||
color: number | string): void {
|
||||
this._manualColors.set(clusterId, color);
|
||||
|
||||
if (!(clusterId in this._clusters)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._pointVisualizationMode === PointVisualizationMode.Manual) {
|
||||
const cluster = this._clusters[clusterId];
|
||||
cluster.points.visible = this._getClusterVisible(clusterId);
|
||||
for (const points of cluster.points.children) {
|
||||
(<ClusterPoints>points).setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
const mode = this._cameraVisualizationMode;
|
||||
if (mode === CameraVisualizationMode.Manual) {
|
||||
if (this._clusterCellMap.has(clusterId)) {
|
||||
for (const cellId of this._clusterCellMap.get(clusterId)) {
|
||||
const cell = this._images[cellId];
|
||||
cell.applyColorMap(this._manualColors);
|
||||
}
|
||||
}
|
||||
|
||||
this._highlight(this._hoveredId, this._colors.hover, mode);
|
||||
this._highlight(this._selectedId, this._colors.select, mode);
|
||||
}
|
||||
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public deactivate(): void {
|
||||
this._filter = () => true;
|
||||
this._selectedId = null;
|
||||
@ -295,15 +257,23 @@ export class SpatialScene {
|
||||
this.uncache();
|
||||
}
|
||||
|
||||
public hasCluster(clusterId: string, cellId: string): boolean {
|
||||
return clusterId in this._clusters &&
|
||||
this._clusters[clusterId].cellIds.indexOf(cellId) !== -1;
|
||||
public getCameraOverrideColor(clusterId: string): string | number | null {
|
||||
return this._cameraOverrideColors.get(clusterId);
|
||||
}
|
||||
|
||||
public getPointOverrideColor(clusterId: string): string | number | null {
|
||||
return this._pointOverrideColors.get(clusterId);
|
||||
}
|
||||
|
||||
public hasCell(cellId: string): boolean {
|
||||
return cellId in this._cells;
|
||||
}
|
||||
|
||||
public hasCluster(clusterId: string, cellId: string): boolean {
|
||||
return clusterId in this._clusters &&
|
||||
this._clusters[clusterId].cellIds.indexOf(cellId) !== -1;
|
||||
}
|
||||
|
||||
public hasImage(imageId: string, cellId: string): boolean {
|
||||
return cellId in this._images &&
|
||||
this._images[cellId].hasImage(imageId);
|
||||
@ -354,8 +324,28 @@ export class SpatialScene {
|
||||
}
|
||||
}
|
||||
|
||||
public setCameraOverrideColor(
|
||||
clusterId: string,
|
||||
color: number | string | null): void {
|
||||
|
||||
if (color != null) {
|
||||
this._cameraOverrideColors.set(clusterId, color);
|
||||
} else {
|
||||
this._cameraOverrideColors.delete(clusterId);
|
||||
}
|
||||
|
||||
if (!this._clusterCellMap.has(clusterId)) {
|
||||
return;
|
||||
}
|
||||
const cellIds = this._clusterCellMap.get(clusterId);
|
||||
this._applyCameraColor([...cellIds.keys()]);
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public setCameraSize(cameraSize: number): void {
|
||||
if (Math.abs(cameraSize - this._cameraSize) < 1e-4) { return; }
|
||||
if (Math.abs(cameraSize - this._cameraSize) < 1e-4) {
|
||||
return;
|
||||
}
|
||||
|
||||
const imageCells = this._images;
|
||||
for (const cellId of Object.keys(imageCells)) {
|
||||
@ -368,6 +358,34 @@ export class SpatialScene {
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public setCameraVisualizationMode(mode: CameraVisualizationMode): void {
|
||||
if (mode === this._cameraVisualizationMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._cameraVisualizationMode = mode;
|
||||
|
||||
this._applyCameraColor(Object.keys(this._images));
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public setCellVisibility(visible: boolean): void {
|
||||
if (visible === this._cellsVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const cellId in this._cells) {
|
||||
if (!this._cells.hasOwnProperty(cellId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this._cells[cellId].visible = visible;
|
||||
}
|
||||
|
||||
this._cellsVisible = visible;
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public setFilter(filter: FilterFunction): void {
|
||||
this._filter = filter;
|
||||
const clusterVisibles: { [key: string]: boolean; } = {};
|
||||
@ -388,7 +406,10 @@ export class SpatialScene {
|
||||
const pointsVisible =
|
||||
this._pointVisualizationMode !== PointVisualizationMode.Hidden;
|
||||
for (const clusterId in clusterVisibles) {
|
||||
if (!clusterVisibles.hasOwnProperty(clusterId)) { continue; }
|
||||
if (!clusterVisibles.hasOwnProperty(clusterId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
clusterVisibles[clusterId] &&= pointsVisible;
|
||||
const visible = clusterVisibles[clusterId];
|
||||
if (clusterId in this._clusters) {
|
||||
@ -426,6 +447,20 @@ export class SpatialScene {
|
||||
this._hoveredId = imageId;
|
||||
}
|
||||
|
||||
public setPointOverrideColor(
|
||||
clusterId: string,
|
||||
color: number | string | null): void {
|
||||
|
||||
if (color != null) {
|
||||
this._pointOverrideColors.set(clusterId, color);
|
||||
} else {
|
||||
this._pointOverrideColors.delete(clusterId);
|
||||
}
|
||||
|
||||
this._applyPointColor(clusterId);
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public setPointSize(pointSize: number): void {
|
||||
if (Math.abs(pointSize - this._pointSize) < 1e-4) {
|
||||
return;
|
||||
@ -436,7 +471,6 @@ export class SpatialScene {
|
||||
if (!clusters.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const points of clusters[key].points.children) {
|
||||
(<ClusterPoints>points).resize(pointSize);
|
||||
}
|
||||
@ -452,30 +486,22 @@ export class SpatialScene {
|
||||
}
|
||||
|
||||
this._pointVisualizationMode = mode;
|
||||
|
||||
for (const clusterId in this._clusters) {
|
||||
if (!this._clusters.hasOwnProperty(clusterId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const cluster = this._clusters[clusterId];
|
||||
cluster.points.visible = this._getClusterVisible(clusterId);
|
||||
|
||||
for (const points of cluster.points.children) {
|
||||
let color: string | number = null;
|
||||
if (mode === PointVisualizationMode.Cluster) {
|
||||
color = this._assets.getColor(clusterId);
|
||||
} else if (mode === PointVisualizationMode.Manual) {
|
||||
color = this._manualColors.get(clusterId);
|
||||
}
|
||||
(<ClusterPoints>points).setColor(color);
|
||||
}
|
||||
this._applyPointColor(clusterId);
|
||||
}
|
||||
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public setPositionMode(mode: OriginalPositionMode): void {
|
||||
if (mode === this._positionMode) { return; }
|
||||
if (mode === this._positionMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const cell of Object.values(this._images)) {
|
||||
cell.applyPositionMode(mode);
|
||||
}
|
||||
@ -484,8 +510,9 @@ export class SpatialScene {
|
||||
}
|
||||
|
||||
public setSelectedImage(id: string | null): void {
|
||||
if (this._selectedId === id) { return; }
|
||||
this._needsRender = true;
|
||||
if (this._selectedId === id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._selectedId != null) {
|
||||
this._resetCameraColor(this._selectedId);
|
||||
@ -497,55 +524,6 @@ export class SpatialScene {
|
||||
this._cameraVisualizationMode);
|
||||
|
||||
this._selectedId = id;
|
||||
}
|
||||
|
||||
public setCellVisibility(visible: boolean): void {
|
||||
if (visible === this._cellsVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const cellId in this._cells) {
|
||||
if (!this._cells.hasOwnProperty(cellId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this._cells[cellId].visible = visible;
|
||||
}
|
||||
|
||||
this._cellsVisible = visible;
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public setCameraVisualizationMode(mode: CameraVisualizationMode): void {
|
||||
if (mode === this._cameraVisualizationMode) { return; }
|
||||
|
||||
const visible = isModeVisible(mode);
|
||||
|
||||
if (isModeManual(mode)) {
|
||||
const colors = this._manualColors;
|
||||
for (const cell of Object.values(this._images)) {
|
||||
cell.cameras.visible = visible;
|
||||
cell.applyColorMap(colors);
|
||||
}
|
||||
} else {
|
||||
const assets = this._assets;
|
||||
for (const cell of Object.values(this._images)) {
|
||||
cell.cameras.visible = visible;
|
||||
const cameraMap = cell.getCamerasByMode(mode);
|
||||
cameraMap.forEach(
|
||||
(cameras, colorId) => {
|
||||
const color = assets.getColor(colorId);
|
||||
for (const camera of cameras) {
|
||||
camera.setColor(color);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._highlight(this._hoveredId, this._colors.hover, mode);
|
||||
this._highlight(this._selectedId, this._colors.select, mode);
|
||||
|
||||
this._cameraVisualizationMode = mode;
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
@ -583,6 +561,52 @@ export class SpatialScene {
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
private _applyCameraColor(cellIds: string[]): void {
|
||||
const mode = this._cameraVisualizationMode;
|
||||
|
||||
const visible = isModeVisible(mode);
|
||||
const assets = this._assets;
|
||||
const overrides = this._cameraOverrideColors;
|
||||
const images = this._images;
|
||||
for (const cellId of cellIds) {
|
||||
if (!(cellId in images)) {
|
||||
continue;
|
||||
}
|
||||
const cell = images[cellId];
|
||||
cell.cameras.visible = visible;
|
||||
const cameraMap = cell.getCamerasByMode(mode);
|
||||
cameraMap.forEach(
|
||||
(cameras, colorId) => {
|
||||
let color: number | string = assets.getColor(colorId);
|
||||
for (const camera of cameras) {
|
||||
if (overrides.has(camera.clusterId)) {
|
||||
camera.camera.setColor(overrides.get(camera.clusterId));
|
||||
} else {
|
||||
camera.camera.setColor(color);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this._highlight(this._hoveredId, this._colors.hover, mode);
|
||||
this._highlight(this._selectedId, this._colors.select, mode);
|
||||
|
||||
}
|
||||
|
||||
private _applyPointColor(clusterId: string): void {
|
||||
if (!(clusterId in this._clusters)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cluster = this._clusters[clusterId];
|
||||
cluster.points.visible = this._getClusterVisible(clusterId);
|
||||
|
||||
const color = this._getPointColor(clusterId);
|
||||
for (const points of cluster.points.children) {
|
||||
(<ClusterPoints>points).setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
private _getClusterVisible(clusterId: string): boolean {
|
||||
if (this._pointVisualizationMode === PointVisualizationMode.Hidden) {
|
||||
return false;
|
||||
@ -596,6 +620,19 @@ export class SpatialScene {
|
||||
return visible;
|
||||
}
|
||||
|
||||
private _disposeCell(cellId: string): void {
|
||||
const cell = this._cells[cellId];
|
||||
|
||||
for (const line of cell.children.slice()) {
|
||||
(<CellLine>line).dispose();
|
||||
cell.remove(line);
|
||||
}
|
||||
|
||||
this._scene.remove(cell);
|
||||
|
||||
delete this._cells[cellId];
|
||||
}
|
||||
|
||||
private _disposePoints(cellId: string): void {
|
||||
for (const clusterId of this._cellClusters[cellId].keys) {
|
||||
if (!(clusterId in this._clusters)) {
|
||||
@ -629,19 +666,6 @@ export class SpatialScene {
|
||||
delete this._cellClusters[cellId];
|
||||
}
|
||||
|
||||
private _disposeCell(cellId: string): void {
|
||||
const cell = this._cells[cellId];
|
||||
|
||||
for (const line of cell.children.slice()) {
|
||||
(<CellLine>line).dispose();
|
||||
cell.remove(line);
|
||||
}
|
||||
|
||||
this._scene.remove(cell);
|
||||
|
||||
delete this._cells[cellId];
|
||||
}
|
||||
|
||||
private _getNear(cameraSize: number): number {
|
||||
const near = RAY_NEAR_SCALE *
|
||||
ORIGINAL_CAMERA_SIZE *
|
||||
@ -650,24 +674,16 @@ export class SpatialScene {
|
||||
return Math.max(0.01, near);
|
||||
}
|
||||
|
||||
private _resetCameraColor(imageId: string): void {
|
||||
const nceMap = this._imageCellMap;
|
||||
if (imageId == null || !nceMap.has(imageId)) { return; }
|
||||
|
||||
const cellId = nceMap.get(imageId);
|
||||
const cell = this._images[cellId];
|
||||
const isManual = isModeManual(this._cameraVisualizationMode);
|
||||
if (isManual) {
|
||||
const clusterId = cell.getCluster(imageId);
|
||||
const color = this._manualColors.get(clusterId) ??
|
||||
SPATIAL_DEFAULT_MANUAL_COLOR;
|
||||
cell.applyCameraColor(imageId, color);
|
||||
} else {
|
||||
const colorId = cell.getColorId(imageId, this._cameraVisualizationMode);
|
||||
const color = this._assets.getColor(colorId);
|
||||
cell.applyCameraColor(imageId, color);
|
||||
private _getPointColor(clusterId: string): number | string | null {
|
||||
let color: number | string = null;
|
||||
if (this._pointVisualizationMode === PointVisualizationMode.Cluster) {
|
||||
color = this._assets.getColor(clusterId);
|
||||
}
|
||||
if (this._pointOverrideColors.has(clusterId)) {
|
||||
color = this._pointOverrideColors.get(clusterId);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
private _highlight(
|
||||
@ -675,10 +691,34 @@ export class SpatialScene {
|
||||
color: string | number,
|
||||
mode: CameraVisualizationMode): void {
|
||||
const nceMap = this._imageCellMap;
|
||||
if (imageId == null || !nceMap.has(imageId)) { return; }
|
||||
if (imageId == null || !nceMap.has(imageId)) {
|
||||
return;
|
||||
}
|
||||
const cellId = nceMap.get(imageId);
|
||||
color = mode === CameraVisualizationMode.Homogeneous ?
|
||||
color : SPATIAL_DEFAULT_MANUAL_COLOR;
|
||||
const cell = this._images[cellId];
|
||||
const clusterId = cell.getCluster(imageId);
|
||||
const overridden = this._cameraOverrideColors.get(clusterId);
|
||||
color = mode === CameraVisualizationMode.Homogeneous && !overridden ?
|
||||
color : SPATIAL_DEFAULT_COLOR;
|
||||
|
||||
this._images[cellId].applyCameraColor(imageId, color);
|
||||
}
|
||||
|
||||
private _resetCameraColor(imageId: string): void {
|
||||
const nceMap = this._imageCellMap;
|
||||
if (imageId == null || !nceMap.has(imageId)) { return; }
|
||||
|
||||
const cellId = nceMap.get(imageId);
|
||||
const cell = this._images[cellId];
|
||||
|
||||
const colorId = cell.getColorId(imageId, this._cameraVisualizationMode);
|
||||
let color: number | string = this._assets.getColor(colorId);
|
||||
|
||||
const clusterId = cell.getCluster(imageId);
|
||||
if (this._cameraOverrideColors.has(clusterId)) {
|
||||
color = this._cameraOverrideColors.get(clusterId);
|
||||
}
|
||||
|
||||
cell.applyCameraColor(imageId, color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,14 +26,4 @@ export enum CameraVisualizationMode {
|
||||
* their sequence.
|
||||
*/
|
||||
Sequence,
|
||||
|
||||
/**
|
||||
* Manually paint the camera frustums of each cluster
|
||||
* with a specific color.
|
||||
*
|
||||
* @description If no color has been specified for a
|
||||
* visualized cluster, the cluster will be shown with
|
||||
* a default color.
|
||||
*/
|
||||
Manual,
|
||||
}
|
||||
|
||||
@ -14,14 +14,4 @@ export enum PointVisualizationMode {
|
||||
* cluster with the same random color.
|
||||
*/
|
||||
Cluster,
|
||||
|
||||
/**
|
||||
* Manually paint the points of each cluster with a
|
||||
* specific color.
|
||||
*
|
||||
* @description If no color has been specified for a
|
||||
* visualized cluster, the cluster will be shown with
|
||||
* a default color.
|
||||
*/
|
||||
Manual,
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ export class ClusterPoints extends Points {
|
||||
this.material.dispose();
|
||||
}
|
||||
|
||||
public setColor(color?: string | number): void {
|
||||
public setColor(color: string | number | null): void {
|
||||
this.material.vertexColors = color == null;
|
||||
this.material.color = new Color(color);
|
||||
this.material.needsUpdate = true;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { CameraVisualizationMode } from "../enums/CameraVisualizationMode";
|
||||
|
||||
export class SpatialAssets {
|
||||
private readonly _colors: Map<string, string>;
|
||||
private readonly _colors: Map<string, number | string>;
|
||||
|
||||
constructor() {
|
||||
this._colors = new Map();
|
||||
@ -9,13 +9,15 @@ export class SpatialAssets {
|
||||
this._colors.set(cvm[cvm.Homogeneous], "#FFFFFF");
|
||||
}
|
||||
|
||||
public getColor(id: string): string {
|
||||
public getColor(id: string): number | string {
|
||||
const colors = this._colors;
|
||||
if (!colors.has(id)) { colors.set(id, this._randomColor()); }
|
||||
if (!colors.has(id)) {
|
||||
colors.set(id, this._randomColor());
|
||||
}
|
||||
return colors.get(id);
|
||||
}
|
||||
|
||||
private _randomColor(): string {
|
||||
private _randomColor(): number | string {
|
||||
return `hsl(${Math.floor(360 * Math.random())}, 100%, 60%)`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,9 +15,14 @@ import { isSpherical } from "../../../geo/Geo";
|
||||
import { SphericalCameraFrame } from "./SphericalCameraFrame";
|
||||
import { PerspectiveCameraFrame } from "./PerspectiveCameraFrame";
|
||||
import { LngLatAlt } from "../../../api/interfaces/LngLatAlt";
|
||||
import { resetEnu, SPATIAL_DEFAULT_MANUAL_COLOR } from "../SpatialCommon";
|
||||
import { resetEnu, SPATIAL_DEFAULT_COLOR } from "../SpatialCommon";
|
||||
|
||||
type ColorIdCamerasMap = Map<string, CameraFrameBase[]>;
|
||||
type IDCamera = {
|
||||
camera: CameraFrameBase,
|
||||
clusterId: string,
|
||||
};
|
||||
|
||||
type ColorIdCamerasMap = Map<string, IDCamera[]>;
|
||||
|
||||
type ImageIdMap = {
|
||||
ccId: string;
|
||||
@ -41,6 +46,8 @@ type ImageVisualizationProps = {
|
||||
positionMode: OriginalPositionMode;
|
||||
};
|
||||
|
||||
const DEFAULT_ID = CameraVisualizationMode[CameraVisualizationMode.Homogeneous];
|
||||
|
||||
export class SpatialCell {
|
||||
public readonly cameras: Object3D;
|
||||
public readonly keys: string[];
|
||||
@ -51,6 +58,7 @@ export class SpatialCell {
|
||||
private readonly _cameraFrames: { [key: string]: CameraFrameBase; };
|
||||
private readonly _clusters: ColorIdCamerasMap;
|
||||
private readonly _connectedComponents: ColorIdCamerasMap;
|
||||
private readonly _defaults: ColorIdCamerasMap;
|
||||
private readonly _sequences: ColorIdCamerasMap;
|
||||
private readonly _props: {
|
||||
[id: string]: {
|
||||
@ -73,9 +81,12 @@ export class SpatialCell {
|
||||
this._positions = new Object3D();
|
||||
|
||||
this._cameraFrames = {};
|
||||
|
||||
this._clusters = new Map();
|
||||
this._connectedComponents = new Map();
|
||||
this._defaults = new Map();
|
||||
this._sequences = new Map();
|
||||
|
||||
this._props = {};
|
||||
this.clusterVisibles = {};
|
||||
|
||||
@ -94,15 +105,29 @@ export class SpatialCell {
|
||||
public addImage(props: ImageProps): void {
|
||||
const image = props.image;
|
||||
const id = image.id;
|
||||
if (this.hasImage(id)) { throw new Error(`Image exists ${id}`); }
|
||||
if (this.hasImage(id)) {
|
||||
throw new Error(`Image exists ${id}`);
|
||||
}
|
||||
|
||||
const cId = props.idMap.clusterId;
|
||||
if (!this._clusters.has(cId)) {
|
||||
this._clusters.set(cId, []);
|
||||
}
|
||||
|
||||
const ccId = props.idMap.ccId;
|
||||
if (!(this._connectedComponents.has(ccId))) {
|
||||
this._connectedComponents.set(ccId, []);
|
||||
}
|
||||
const cId = props.idMap.clusterId;
|
||||
if (!this._clusters.has(cId)) { this._clusters.set(cId, []); }
|
||||
|
||||
if (!(this._defaults.has(DEFAULT_ID))) {
|
||||
this._defaults.set(DEFAULT_ID, []);
|
||||
}
|
||||
|
||||
const sId = props.idMap.sequenceId;
|
||||
if (!this._sequences.has(sId)) { this._sequences.set(sId, []); }
|
||||
if (!this._sequences.has(sId)) {
|
||||
this._sequences.set(sId, []);
|
||||
}
|
||||
|
||||
this._props[id] = {
|
||||
image: image,
|
||||
ids: { ccId, clusterId: cId, sequenceId: sId },
|
||||
@ -114,19 +139,6 @@ export class SpatialCell {
|
||||
this._cameraFrames[imageId].setColor(color);
|
||||
}
|
||||
|
||||
public applyColorMap(colors: Map<string, number | string>): void {
|
||||
const frames = this._cameraFrames;
|
||||
const props = this._props;
|
||||
for (const imageId in frames) {
|
||||
if (!frames.hasOwnProperty(imageId)) { continue; }
|
||||
|
||||
const frame = frames[imageId];
|
||||
const clusterId = props[imageId].ids.clusterId;
|
||||
const color = colors.get(clusterId) ?? SPATIAL_DEFAULT_MANUAL_COLOR;
|
||||
frame.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
public applyCameraSize(size: number): void {
|
||||
for (const camera of this.cameras.children) {
|
||||
(<CameraFrameBase>camera).resize(size);
|
||||
@ -170,20 +182,17 @@ export class SpatialCell {
|
||||
this._intersection = null;
|
||||
}
|
||||
|
||||
public getCamerasByMode(
|
||||
mode: CameraVisualizationMode): ColorIdCamerasMap {
|
||||
if (mode === CameraVisualizationMode.Cluster) {
|
||||
return this._clusters;
|
||||
} else if (mode === CameraVisualizationMode.ConnectedComponent) {
|
||||
return this._connectedComponents;
|
||||
} else if (mode === CameraVisualizationMode.Sequence) {
|
||||
return this._sequences;
|
||||
public getCamerasByMode(mode: CameraVisualizationMode): ColorIdCamerasMap {
|
||||
switch (mode) {
|
||||
case CameraVisualizationMode.Cluster:
|
||||
return this._clusters;
|
||||
case CameraVisualizationMode.ConnectedComponent:
|
||||
return this._connectedComponents;
|
||||
case CameraVisualizationMode.Sequence:
|
||||
return this._sequences;
|
||||
default:
|
||||
return this._defaults;
|
||||
}
|
||||
const cvm = CameraVisualizationMode;
|
||||
const defaultId = cvm[cvm.Homogeneous];
|
||||
const cameras = <ColorIdCamerasMap>new Map();
|
||||
cameras.set(defaultId, <CameraFrameBase[]>this.cameras.children);
|
||||
return cameras;
|
||||
}
|
||||
|
||||
public getColorId(imageId: string, mode: CameraVisualizationMode): string {
|
||||
@ -197,7 +206,7 @@ export class SpatialCell {
|
||||
case cvm.Sequence:
|
||||
return props.ids.sequenceId;
|
||||
default:
|
||||
return cvm[cvm.Homogeneous];
|
||||
return DEFAULT_ID;
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,9 +275,11 @@ export class SpatialCell {
|
||||
|
||||
const ids = this._props[id].ids;
|
||||
this.clusterVisibles[ids.clusterId] ||= visible;
|
||||
this._connectedComponents.get(ids.ccId).push(camera);
|
||||
this._clusters.get(ids.clusterId).push(camera);
|
||||
this._sequences.get(ids.sequenceId).push(camera);
|
||||
const idCamera = { camera, clusterId: ids.clusterId };
|
||||
this._clusters.get(ids.clusterId).push(idCamera);
|
||||
this._connectedComponents.get(ids.ccId).push(idCamera);
|
||||
this._defaults.get(DEFAULT_ID).push(idCamera);
|
||||
this._sequences.get(ids.sequenceId).push(idCamera);
|
||||
|
||||
const positionParameters: PositionLineParameters = {
|
||||
material: this._positionMaterial,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user