Skip to content

Commit

Permalink
graphene find path
Browse files Browse the repository at this point in the history
- added keybind for clearing 'escape'
- clearing path when adding a third point
- cancelling find path requests when clearing the path
  • Loading branch information
chrisj committed Nov 22, 2023
1 parent fd723ef commit 582cb06
Showing 1 changed file with 41 additions and 15 deletions.
56 changes: 41 additions & 15 deletions src/neuroglancer/datasource/graphene/frontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import {Uint64} from 'neuroglancer/util/uint64';
import {makeDeleteButton} from 'neuroglancer/widget/delete_button';
import {DependentViewContext} from 'neuroglancer/widget/dependent_view_widget';
import {makeIcon} from 'neuroglancer/widget/icon';
import {CancellationToken, CancellationTokenSource} from 'src/neuroglancer/util/cancellation';

function vec4FromVec3(vec: vec3, alpha = 0) {
const res = vec4.clone([...vec]);
Expand Down Expand Up @@ -1070,7 +1071,11 @@ class GraphConnection extends SegmentationGraphSourceConnection {
findPathState.target.value = undefined;
}
});
let findPathCancellation: CancellationTokenSource|undefined = undefined;
const findPathChanged = () => {
if (findPathCancellation) {
findPathCancellation.cancel();
}
const {path, source, target} = findPathState;
const annotationSource = findPathGroup.source;
if (source.value && !source.value.annotationReference) {
Expand All @@ -1093,12 +1098,18 @@ class GraphConnection extends SegmentationGraphSourceConnection {
};
this.registerDisposer(findPathState.changed.add(findPathChanged));
this.registerDisposer(findPathState.triggerPathUpdate.add(() => {
if (findPathCancellation) {
findPathCancellation.cancel();
}
const loadedSubsource = getGraphLoadedSubsource(this.layer)!;
const annotationToNanometers =
loadedSubsource.loadedDataSource.transform.inputSpace.value.scales.map(x => x / 1e-9);
this.submitFindPath(findPathState.precisionMode.value, annotationToNanometers)
findPathCancellation = new CancellationTokenSource();
this.submitFindPath(
findPathState.precisionMode.value, annotationToNanometers, findPathCancellation)
.then(success => {
success;
findPathCancellation = undefined;
});
}));
findPathChanged(); // initial state
Expand Down Expand Up @@ -1380,13 +1391,14 @@ class GraphConnection extends SegmentationGraphSourceConnection {
merges.changed.dispatch();
}

async submitFindPath(precisionMode: boolean, annotationToNanometers: Float64Array):
Promise<boolean> {
async submitFindPath(
precisionMode: boolean, annotationToNanometers: Float64Array,
cancellationToken?: CancellationToken): Promise<boolean> {
const {state: {findPathState}} = this;
const {source, target} = findPathState;
if (!source.value || !target.value) return false;
const centroids = await this.graph.findPath(
source.value, target.value, precisionMode, annotationToNanometers);
source.value, target.value, precisionMode, annotationToNanometers, cancellationToken);
StatusMessage.showTemporaryMessage('Path found!', 5000);
findPathState.centroids.value = centroids;
return true;
Expand Down Expand Up @@ -1431,6 +1443,10 @@ async function withErrorMessageHTTP(promise: Promise<Response>, options: {
status.setVisible(true);
throw new Error(`[${e.response.status}] ${errorPrefix}${msg}`);
}
if (e instanceof DOMException && e.name === 'AbortError') {
dispose();
StatusMessage.showTemporaryMessage('Request was aborted.');
}
throw e;
}
}
Expand Down Expand Up @@ -1546,7 +1562,9 @@ class GrapheneGraphServerInterface {
return res;
}

async findPath(first: SegmentSelection, second: SegmentSelection, precisionMode: boolean) {
async findPath(
first: SegmentSelection, second: SegmentSelection, precisionMode: boolean,
cancellationToken?: CancellationToken) {
const {url} = this;
if (url === '') {
return Promise.reject(GRAPH_SERVER_NOT_SPECIFIED);
Expand All @@ -1560,7 +1578,7 @@ class GrapheneGraphServerInterface {
[String(second.rootId), ...second.position],
]),
},
responseIdentity);
responseIdentity, cancellationToken);

const response = await withErrorMessageHTTP(promise, {
initialMessage: `Finding path between ${first.segmentId} and ${second.segmentId}`,
Expand Down Expand Up @@ -1636,13 +1654,15 @@ class GrapheneGraphSource extends SegmentationGraphSource {

async findPath(
first: SegmentSelection, second: SegmentSelection, precisionMode: boolean,
annotationToNanometers: Float64Array): Promise<number[][]> {
annotationToNanometers: Float64Array,
cancellationToken?: CancellationToken): Promise<number[][]> {
const {l2CacheUrl, table} = this.info.app;
const l2CacheAvailable = precisionMode &&
await this.isL2CacheUrlAvailable(); // don't check if available if we don't need it
let {centroids, l2_path} = await this.graphServer.findPath(
selectionInNanometers(first, annotationToNanometers),
selectionInNanometers(second, annotationToNanometers), precisionMode && !l2CacheAvailable);
selectionInNanometers(second, annotationToNanometers), precisionMode && !l2CacheAvailable,
cancellationToken);
if (precisionMode && l2CacheAvailable && l2_path) {
const repCoordinatesUrl = `${l2CacheUrl}/table/${table}/attributes`;
try {
Expand All @@ -1653,7 +1673,7 @@ class GrapheneGraphSource extends SegmentationGraphSource {
l2_ids: l2_path,
}),
},
responseJson);
responseJson, cancellationToken);

// many reasons why an l2 id might not have info
// l2 cache has a process that takes time for new ids (even hours)
Expand Down Expand Up @@ -1875,7 +1895,7 @@ const addSelection =
};
const ref = source.add(annotation);
selection.annotationReference = ref;
}
};

const synchronizeAnnotationSource =
(source: WatchableSet<SegmentSelection>, state: AnnotationLayerState) => {
Expand Down Expand Up @@ -2324,6 +2344,7 @@ class MergeSegmentsTool extends LayerTool<SegmentationUserLayer> {

const FIND_PATH_INPUT_EVENT_MAP = EventActionMap.fromObject({
'at:shift?+enter': {action: 'submit'},
'escape': {action: 'clearPath'},
'at:shift?+control+mousedown0': {action: 'add-point'},
});

Expand All @@ -2342,6 +2363,11 @@ class FindPathTool extends LayerTool<SegmentationUserLayer> {
const submitAction = () => {
findPathState.triggerPathUpdate.dispatch();
};
const clearPath = () => {
findPathState.source.reset();
findPathState.target.reset();
findPathState.centroids.reset();
};
body.appendChild(makeIcon({
text: 'Submit',
title: 'Submit Find Path',
Expand All @@ -2352,11 +2378,7 @@ class FindPathTool extends LayerTool<SegmentationUserLayer> {
body.appendChild(makeIcon({
text: 'Clear',
title: 'Clear Find Path',
onClick: () => {
findPathState.source.reset();
findPathState.target.reset();
findPathState.centroids.reset();
}
onClick: clearPath,
}));
const checkbox = activation.registerDisposer(new TrackableBooleanCheckbox(precisionMode));
const label = document.createElement('label');
Expand Down Expand Up @@ -2405,6 +2427,9 @@ class FindPathTool extends LayerTool<SegmentationUserLayer> {
activation.bindAction('add-point', event => {
event.stopPropagation();
(async () => {
if (source.value && target.value) {
clearPath();
}
if (!source.value) { // first selection
const selection = maybeGetSelection(this, segmentationGroupState.visibleSegments);
if (selection) {
Expand All @@ -2418,6 +2443,7 @@ class FindPathTool extends LayerTool<SegmentationUserLayer> {
}
})();
});
activation.bindAction('clearPath', clearPath);
}

toJSON() {
Expand Down

0 comments on commit 582cb06

Please sign in to comment.