Skip to content

Commit be42307

Browse files
authored
Clean up green task bounding boxes (#8535)
* only show green task bounding boxes if a task exists; show them for all tracing layers * update changelog * rename to updateTaskBoundingBoxes and add docstring
1 parent 52ce953 commit be42307

File tree

3 files changed

+55
-21
lines changed

3 files changed

+55
-21
lines changed

CHANGELOG.unreleased.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
1919
- Replaced fixed threshold of 40 meshes by a dynamic limit based on the number of triangles in the mesh for the "Create Animation" job. [#8588](https://github.com/scalableminds/webknossos/pull/8588)
2020

2121
### Fixed
22+
- Fixed that layer bounding boxes were sometimes colored green even though this should only happen for tasks. [#8535](https://github.com/scalableminds/webknossos/pull/8535)
2223

2324
### Removed
2425

frontend/javascripts/oxalis/controller/scene_controller.ts

+44-21
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import {
4646
} from "oxalis/model/accessors/dataset_layer_transformation_accessor";
4747
import { getActiveMagIndicesForLayers, getPosition } from "oxalis/model/accessors/flycam_accessor";
4848
import { getSkeletonTracing } from "oxalis/model/accessors/skeletontracing_accessor";
49-
import { getSomeTracing } from "oxalis/model/accessors/tracing_accessor";
49+
import { getSomeTracing, getTaskBoundingBoxes } from "oxalis/model/accessors/tracing_accessor";
5050
import { getPlaneScalingFactor } from "oxalis/model/accessors/view_mode_accessor";
5151
import { sceneControllerReadyAction } from "oxalis/model/actions/actions";
5252
import Dimensions from "oxalis/model/dimensions";
@@ -84,7 +84,7 @@ class SceneController {
8484
layerBoundingBoxes!: { [layerName: string]: Cube };
8585
annotationToolsGeometryGroup!: THREE.Group;
8686
highlightedBBoxId: number | null | undefined;
87-
taskBoundingBox: Cube | null | undefined;
87+
taskCubeByTracingId: Record<string, Cube | null | undefined> = {};
8888
contour!: ContourGeometry;
8989
quickSelectGeometry!: QuickSelectGeometry;
9090
lineMeasurementGeometry!: LineMeasurementGeometry;
@@ -231,6 +231,7 @@ class SceneController {
231231
showCrossSections: true,
232232
isHighlighted: false,
233233
});
234+
this.datasetBoundingBox.getMeshes().forEach((mesh) => this.rootNode.add(mesh));
234235

235236
this.contour = new ContourGeometry();
236237
this.quickSelectGeometry = new QuickSelectGeometry();
@@ -260,8 +261,6 @@ class SceneController {
260261
...planeMeshes,
261262
);
262263

263-
const taskBoundingBox = getSomeTracing(state.annotation).boundingBox;
264-
this.buildTaskingBoundingBox(taskBoundingBox);
265264
if (state.annotation.skeleton != null) {
266265
this.addSkeleton((_state) => getSkeletonTracing(_state.annotation), true);
267266
}
@@ -326,24 +325,48 @@ class SceneController {
326325
this.rootNode.remove(skeletonGroup);
327326
}
328327

329-
buildTaskingBoundingBox(taskBoundingBox: BoundingBoxType | null | undefined): void {
330-
if (taskBoundingBox != null) {
331-
if (this.taskBoundingBox != null) {
332-
this.taskBoundingBox.getMeshes().forEach((mesh) => this.rootNode.remove(mesh));
328+
updateTaskBoundingBoxes(
329+
taskCubeByTracingId: Record<string, BoundingBoxType | null | undefined>,
330+
): void {
331+
/*
332+
Ensures that a green task bounding box is rendered in the scene for
333+
each layer.
334+
The update is implemented by simply removing the old geometry and
335+
adding a new one. Since this function is executed very rarely,
336+
this is not a performance problem.
337+
*/
338+
for (const [tracingId, boundingBox] of Object.entries(taskCubeByTracingId)) {
339+
let taskCube = this.taskCubeByTracingId[tracingId];
340+
// Remove the old box if it exists
341+
if (taskCube != null) {
342+
taskCube.getMeshes().forEach((mesh) => this.rootNode.remove(mesh));
343+
}
344+
this.taskCubeByTracingId[tracingId] = null;
345+
if (boundingBox == null || Store.getState().task == null) {
346+
continue;
333347
}
334-
335348
const { viewMode } = Store.getState().temporaryConfiguration;
336-
this.taskBoundingBox = new Cube({
337-
min: taskBoundingBox.min,
338-
max: taskBoundingBox.max,
349+
taskCube = new Cube({
350+
min: boundingBox.min,
351+
max: boundingBox.max,
339352
color: 0x00ff00,
340353
showCrossSections: true,
341354
isHighlighted: false,
342355
});
343-
this.taskBoundingBox.getMeshes().forEach((mesh) => this.rootNode.add(mesh));
356+
taskCube.getMeshes().forEach((mesh) => this.rootNode.add(mesh));
344357

345358
if (constants.MODES_ARBITRARY.includes(viewMode)) {
346-
this.taskBoundingBox?.setVisibility(false);
359+
taskCube?.setVisibility(false);
360+
}
361+
362+
this.taskCubeByTracingId[tracingId] = taskCube;
363+
}
364+
}
365+
366+
forEachTaskCube(fn: (cube: Cube) => void) {
367+
for (const cube of Object.values(this.taskCubeByTracingId)) {
368+
if (cube != null) {
369+
fn(cube);
347370
}
348371
}
349372
}
@@ -369,7 +392,7 @@ class SceneController {
369392
bbCube.updateForCam(id);
370393
});
371394

372-
this.taskBoundingBox?.updateForCam(id);
395+
this.forEachTaskCube((cube) => cube.updateForCam(id));
373396

374397
this.segmentMeshController.meshesLayerLODRootGroup.visible = id === OrthoViews.TDView;
375398
if (this.splitBoundaryMesh != null) {
@@ -623,8 +646,7 @@ class SceneController {
623646

624647
this.datasetBoundingBox.setVisibility(false);
625648
this.userBoundingBoxGroup.visible = false;
626-
627-
this.taskBoundingBox?.setVisibility(false);
649+
this.forEachTaskCube((cube) => cube.setVisibility(false));
628650

629651
if (this.segmentMeshController.meshesLayerLODRootGroup != null) {
630652
this.segmentMeshController.meshesLayerLODRootGroup.visible = false;
@@ -639,7 +661,7 @@ class SceneController {
639661
this.datasetBoundingBox.setVisibility(true);
640662
this.userBoundingBoxGroup.visible = true;
641663

642-
this.taskBoundingBox?.setVisibility(true);
664+
this.forEachTaskCube((cube) => cube.setVisibility(true));
643665
}
644666

645667
destroy() {
@@ -670,7 +692,7 @@ class SceneController {
670692
this.datasetBoundingBox.destroy();
671693
this.userBoundingBoxes.forEach((cube) => cube.destroy());
672694
Object.values(this.layerBoundingBoxes).forEach((cube) => cube.destroy());
673-
this.taskBoundingBox?.destroy();
695+
this.forEachTaskCube((cube) => cube.destroy());
674696

675697
for (const plane of _.values(this.planes)) {
676698
plane.destroy();
@@ -712,8 +734,9 @@ class SceneController {
712734
this.updateMeshesAccordingToLayerVisibility(),
713735
),
714736
listenToStoreProperty(
715-
(storeState) => getSomeTracing(storeState.annotation).boundingBox,
716-
(bb) => this.buildTaskingBoundingBox(bb),
737+
(storeState) => getTaskBoundingBoxes(storeState.annotation),
738+
(boundingBoxesByTracingId) => this.updateTaskBoundingBoxes(boundingBoxesByTracingId),
739+
true,
717740
),
718741
listenToStoreProperty(
719742
(storeState) =>

frontend/javascripts/oxalis/model/accessors/tracing_accessor.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import _ from "lodash";
12
import type { Vector3 } from "oxalis/constants";
23
import type { SaveQueueType } from "oxalis/model/actions/save_actions";
34
import type {
@@ -12,6 +13,7 @@ import type {
1213
import type { ServerTracing, TracingType } from "types/api_types";
1314
import { TracingTypeEnum } from "types/api_types";
1415
import BoundingBox from "../bucket_data_handling/bounding_box";
16+
import { reuseInstanceOnEquality } from "./accessor_helpers";
1517

1618
export function maybeGetSomeTracing(
1719
annotation: StoreAnnotation,
@@ -89,6 +91,14 @@ export function selectTracing(
8991
return tracing;
9092
}
9193

94+
function _getTaskBoundingBoxes(annotation: StoreAnnotation) {
95+
const layers = _.compact([annotation.skeleton, ...annotation.volumes, annotation.readOnly]);
96+
97+
return Object.fromEntries(layers.map((l) => [l.tracingId, l.boundingBox]));
98+
}
99+
100+
export const getTaskBoundingBoxes = reuseInstanceOnEquality(_getTaskBoundingBoxes);
101+
92102
export const getUserBoundingBoxesFromState = (state: OxalisState): Array<UserBoundingBox> => {
93103
const maybeSomeTracing = maybeGetSomeTracing(state.annotation);
94104
return maybeSomeTracing != null ? maybeSomeTracing.userBoundingBoxes : [];

0 commit comments

Comments
 (0)