Skip to content

Commit

Permalink
quick fix for tags breaking precomputed annotations
Browse files Browse the repository at this point in the history
added "Swap visible segments when moving to annotation"
move to annotation now selects the first vertex rather than the centerpoint
  • Loading branch information
chrisj committed Oct 10, 2024
1 parent 8b8a9ea commit 2fd0d32
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/annotation/annotation_layer_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export class AnnotationDisplayState extends RefCounted {
new WatchableAnnotationRelationshipStates(),
);
ignoreNullSegmentFilter = new TrackableBoolean(true);
swapVisibleSegmentsOnMove = new TrackableBoolean(true);
disablePicking = new WatchableValue(false);
displayUnfiltered = makeCachedLazyDerivedWatchableValue(
(map, ignoreNullSegmentFilter) => {
Expand Down
4 changes: 2 additions & 2 deletions src/annotation/frontend_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import {
SliceViewChunkSource,
} from "#src/sliceview/frontend.js";
import { StatusMessage } from "#src/status.js";
import type { WatchableValue } from "#src/trackable_value.js";
import { WatchableValue } from "#src/trackable_value.js";
import type { Borrowed, Owned } from "#src/util/disposable.js";
import { ENDIANNESS, Endianness } from "#src/util/endian.js";
import * as matrix from "#src/util/matrix.js";
Expand Down Expand Up @@ -532,7 +532,7 @@ export class MultiscaleAnnotationSource
) {
super();
this.rank = options.rank;
this.properties.value = options.properties;
this.properties = new WatchableValue(options.properties);
this.annotationPropertySerializers = makeAnnotationPropertySerializers(
this.rank,
this.properties.value,
Expand Down
16 changes: 11 additions & 5 deletions src/datasource/graphene/frontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,7 @@ export class GraphConnection extends SegmentationGraphSourceConnection {
) {
super(graph, layer.displayState.segmentationGroupState.value);
const segmentsState = layer.displayState.segmentationGroupState.value;
this.previousVisibleSegmentCount = segmentsState.visibleSegments.size;
this.registerDisposer(
segmentsState.selectedSegments.changed.add(
(segmentIds: Uint64[] | Uint64 | null, add: boolean) => {
Expand Down Expand Up @@ -1571,6 +1572,8 @@ export class GraphConnection extends SegmentationGraphSourceConnection {
private lastDeselectionMessage: StatusMessage | undefined;
private lastDeselectionMessageExists = false;

private previousVisibleSegmentCount: number;

private visibleSegmentsChanged(segments: Uint64[] | null, added: boolean) {
const { segmentsState } = this;
const {
Expand All @@ -1597,16 +1600,18 @@ export class GraphConnection extends SegmentationGraphSourceConnection {
}
}
if (segments === null) {
const leafSegmentCount = this.segmentsState.selectedSegments.size;
this.segmentsState.segmentEquivalences.clear();
StatusMessage.showTemporaryMessage(
`Hid all ${leafSegmentCount} segments.`,
`Hid all ${this.previousVisibleSegmentCount} segment(s).`,
3000,
);
return;
}
for (const segmentId of segments) {
if (!added) {
if (
!added &&
!isBaseSegmentId(segmentId, this.graph.info.graph.nBitsForLayerId)
) {
const segmentCount = [
...segmentsState.segmentEquivalences.setElements(segmentId),
].length; // Approximation
Expand All @@ -1616,7 +1621,7 @@ export class GraphConnection extends SegmentationGraphSourceConnection {
this.lastDeselectionMessageExists = false;
}
this.lastDeselectionMessage = StatusMessage.showMessage(
`Hid ${segmentCount} segments.`,
`Hid ${segmentCount} segment(s).`,
);
this.lastDeselectionMessageExists = true;
setTimeout(() => {
Expand All @@ -1627,14 +1632,15 @@ export class GraphConnection extends SegmentationGraphSourceConnection {
}, 2000);
}
}
this.previousVisibleSegmentCount = segmentsState.visibleSegments.size;
}

private selectedSegmentsChanged(segments: Uint64[] | null, added: boolean) {
const { segmentsState } = this;
if (segments === null) {
const leafSegmentCount = this.segmentsState.selectedSegments.size;
StatusMessage.showTemporaryMessage(
`Deselected all ${leafSegmentCount} segments.`,
`Deselected all ${leafSegmentCount} segment(s).`,
3000,
);
return;
Expand Down
32 changes: 30 additions & 2 deletions src/layer/annotation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import type { SegmentationDisplayState } from "#src/segmentation_display_state/f
import type { TrackableBoolean } from "#src/trackable_boolean.js";
import { TrackableBooleanCheckbox } from "#src/trackable_boolean.js";
import {
ComputedWatchableValue,
makeCachedLazyDerivedWatchableValue,
WatchableValue,
} from "#src/trackable_value.js";
Expand Down Expand Up @@ -159,6 +160,7 @@ interface LinkedSegmentationLayer {
const LINKED_SEGMENTATION_LAYER_JSON_KEY = "linkedSegmentationLayer";
const FILTER_BY_SEGMENTATION_JSON_KEY = "filterBySegmentation";
const IGNORE_NULL_SEGMENT_FILTER_JSON_KEY = "ignoreNullSegmentFilter";
const SWAP_VISIBLE_SEGMENTS_ON_MOVE_JSON_KEY = "swapVisbleSegmentsOnMove";

class LinkedSegmentationLayers extends RefCounted {
changed = new NullarySignal();
Expand Down Expand Up @@ -705,7 +707,6 @@ export class AnnotationUserLayer extends Base {
this.annotationProjectionRenderScaleTarget.changed.add(
this.specificationChanged.dispatch,
);

this.registerDisposer(
this.localAnnotationProperties.changed.add(() => {
const { localAnnotations } = this;
Expand All @@ -722,12 +723,18 @@ export class AnnotationUserLayer extends Base {
order: -100,
getter: () => new RenderingOptionsTab(this),
});
this.tabs.default = "annotations";
const hideTagsTab = this.registerDisposer(
new ComputedWatchableValue(() => {
return this.localAnnotations === undefined;
}, this.dataSourcesChanged),
);
this.tabs.add("tags", {
label: "Tags",
order: 10,
getter: () => new TagsTab(this),
hidden: hideTagsTab,
});
this.tabs.default = "annotations";
}

syncTagTools = (tagIdentifiers: string[]) => {
Expand Down Expand Up @@ -798,6 +805,9 @@ export class AnnotationUserLayer extends Base {
this.annotationDisplayState.ignoreNullSegmentFilter.restoreState(
specification[IGNORE_NULL_SEGMENT_FILTER_JSON_KEY],
);
this.annotationDisplayState.swapVisibleSegmentsOnMove.restoreState(
specification[SWAP_VISIBLE_SEGMENTS_ON_MOVE_JSON_KEY],
);
this.annotationDisplayState.shader.restoreState(
specification[SHADER_JSON_KEY],
);
Expand Down Expand Up @@ -1043,6 +1053,22 @@ export class AnnotationUserLayer extends Base {
label.appendChild(checkbox.element);
tab.element.appendChild(label);
}
{
const checkbox = tab.registerDisposer(
new TrackableBooleanCheckbox(
this.annotationDisplayState.swapVisibleSegmentsOnMove,
),
);
const label = document.createElement("label");
label.appendChild(
document.createTextNode(
"Swap visible segments when moving to annotation",
),
);
label.title = "Swap visible segments when moving to annotation";
label.appendChild(checkbox.element);
tab.element.appendChild(label);
}
tab.element.appendChild(
tab.registerDisposer(
new LinkedSegmentationLayersWidget(this.linkedSegmentationLayers),
Expand Down Expand Up @@ -1072,6 +1098,8 @@ export class AnnotationUserLayer extends Base {
: localAnnotationRelationships;
x[IGNORE_NULL_SEGMENT_FILTER_JSON_KEY] =
this.annotationDisplayState.ignoreNullSegmentFilter.toJSON();
x[SWAP_VISIBLE_SEGMENTS_ON_MOVE_JSON_KEY] =
this.annotationDisplayState.swapVisibleSegmentsOnMove.toJSON();
x[SHADER_JSON_KEY] = this.annotationDisplayState.shader.toJSON();
x[SHADER_CONTROLS_JSON_KEY] =
this.annotationDisplayState.shaderControls.toJSON();
Expand Down
48 changes: 47 additions & 1 deletion src/ui/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@ export class MergedAnnotationStates
}
}

function getFirstVertexPosition(pos: Float32Array, annotation: Annotation) {
switch (annotation.type) {
case AnnotationType.AXIS_ALIGNED_BOUNDING_BOX:
case AnnotationType.LINE:
pos.set(annotation.pointA);
break;
case AnnotationType.POINT:
pos.set(annotation.point);
break;
case AnnotationType.ELLIPSOID:
pos.set(annotation.center);
break;
}
}

function getCenterPosition(center: Float32Array, annotation: Annotation) {
switch (annotation.type) {
case AnnotationType.AXIS_ALIGNED_BOUNDING_BOX:
Expand All @@ -187,6 +202,7 @@ function getCenterPosition(center: Float32Array, annotation: Annotation) {
break;
}
}
getCenterPosition;

function setLayerPosition(
layer: UserLayer,
Expand Down Expand Up @@ -240,7 +256,7 @@ const moveToAnnotation = (
const { layerRank } = chunkTransform;
const chunkPosition = new Float32Array(layerRank);
const layerPosition = new Float32Array(layerRank);
getCenterPosition(chunkPosition, annotation);
getFirstVertexPosition(chunkPosition, annotation);
matrix.transformPoint(
layerPosition,
chunkTransform.chunkToLayerTransform,
Expand All @@ -249,6 +265,36 @@ const moveToAnnotation = (
layerRank,
);
setLayerPosition(layer, chunkTransform, layerPosition);
if (state.displayState.swapVisibleSegmentsOnMove.value) {
showAnnotationSegments(annotation, state, true);
}
};

const showAnnotationSegments = (
annotation: Annotation,
state: AnnotationLayerState,
onlyVisible = false,
) => {
const { relatedSegments } = annotation;
if (relatedSegments) {
const { source, displayState } = state;
const { relationships } = source;
const { relationshipStates } = displayState;
for (let i = 0, count = relationships.length; i < count; ++i) {
const segmentationState = relationshipStates.get(relationships[i])
.segmentationState.value;
if (segmentationState) {
if (onlyVisible) {
segmentationState.segmentationGroupState.value.visibleSegments.clear();
}
for (const segmentList of relatedSegments) {
segmentationState.segmentationGroupState.value.visibleSegments.add(
segmentList,
);
}
}
}
}
};

export class AnnotationLayerView extends Tab {
Expand Down

0 comments on commit 2fd0d32

Please sign in to comment.