Skip to content

Commit ed84b5c

Browse files
frcrothphilippotto
andauthored
Neuroglancer Precomputed Mesh (#8236)
Co-authored-by: Philipp Otto <[email protected]>
1 parent 8b852cc commit ed84b5c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1139
-546
lines changed

CHANGELOG.unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
1111
[Commits](https://github.com/scalableminds/webknossos/compare/25.05.0...HEAD)
1212

1313
### Added
14+
- Meshes of Neuroglancer Precomputed Datasets can now be viewed. [#8236](https://github.com/scalableminds/webknossos/pull/8236)
1415
- Added the possibility to join an organization without requiring a paid user slot in case an organization already pays for the same user. Such a user is called a "Guest User". [#8502](https://github.com/scalableminds/webknossos/pull/8502)
1516

1617
### Changed

frontend/javascripts/admin/api/mesh.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Request from "libs/request";
2-
import type { APIDataSourceId } from "types/api_types";
2+
import type { APIDataSourceId, APIMeshFileInfo } from "types/api_types";
33
import type { Vector3, Vector4 } from "viewer/constants";
44
import { doWithToken } from "./token";
55

@@ -10,30 +10,27 @@ export type MeshChunk = {
1010
unmappedSegmentId: number;
1111
};
1212

13-
type MeshLodInfo = {
14-
scale: number;
15-
vertexOffset: Vector3;
16-
chunkShape: Vector3;
13+
export type MeshLodInfo = {
1714
chunks: Array<MeshChunk>;
15+
transform: [Vector4, Vector4, Vector4]; // 4x3 matrix
1816
};
1917

2018
type MeshSegmentInfo = {
21-
chunkShape: Vector3; // unused
22-
gridOrigin: Vector3; // unused
19+
meshFormat: "draco";
2320
lods: Array<MeshLodInfo>;
21+
chunkScale: Vector3;
2422
};
2523

26-
type SegmentInfo = {
27-
transform: [Vector4, Vector4, Vector4]; // 4x3 matrix
28-
meshFormat: "draco";
29-
chunks: MeshSegmentInfo;
24+
type ListMeshChunksRequest = {
25+
meshFile: APIMeshFileInfo;
26+
segmentId: number;
3027
};
3128

3229
export function getMeshfileChunksForSegment(
3330
dataStoreUrl: string,
3431
dataSourceId: APIDataSourceId,
3532
layerName: string,
36-
meshFile: string,
33+
meshFile: APIMeshFileInfo,
3734
segmentId: number,
3835
// targetMappingName is the on-disk mapping name.
3936
// In case of an editable mapping, this should still be the on-disk base
@@ -44,7 +41,7 @@ export function getMeshfileChunksForSegment(
4441
// editableMappingTracingId should be the tracing id, not the editable mapping id.
4542
// If this is set, it is assumed that the request is about an editable mapping.
4643
editableMappingTracingId: string | null | undefined,
47-
): Promise<SegmentInfo> {
44+
): Promise<MeshSegmentInfo> {
4845
return doWithToken((token) => {
4946
const params = new URLSearchParams();
5047
params.append("token", token);
@@ -54,13 +51,14 @@ export function getMeshfileChunksForSegment(
5451
if (editableMappingTracingId != null) {
5552
params.append("editableMappingTracingId", editableMappingTracingId);
5653
}
54+
const payload: ListMeshChunksRequest = {
55+
meshFile,
56+
segmentId,
57+
};
5758
return Request.sendJSONReceiveJSON(
5859
`${dataStoreUrl}/data/datasets/${dataSourceId.owningOrganization}/${dataSourceId.directoryName}/layers/${layerName}/meshes/chunks?${params}`,
5960
{
60-
data: {
61-
meshFile,
62-
segmentId,
63-
},
61+
data: payload,
6462
showErrorToast: false,
6563
},
6664
);
@@ -70,10 +68,11 @@ export function getMeshfileChunksForSegment(
7068
type MeshChunkDataRequest = {
7169
byteOffset: number;
7270
byteSize: number;
71+
segmentId: number | null; // Only relevant for neuroglancer precomputed meshes
7372
};
7473

7574
type MeshChunkDataRequestList = {
76-
meshFile: string;
75+
meshFile: APIMeshFileInfo;
7776
requests: MeshChunkDataRequest[];
7877
};
7978

frontend/javascripts/admin/rest_api.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
type APIMagRestrictions,
2929
type APIMapping,
3030
type APIMaybeUnimportedDataset,
31-
type APIMeshFile,
31+
type APIMeshFileInfo,
3232
type APIOrganization,
3333
type APIOrganizationCompact,
3434
type APIPricingPlanStatus,
@@ -2034,8 +2034,8 @@ export async function getMeshfilesForDatasetLayer(
20342034
dataStoreUrl: string,
20352035
dataSourceId: APIDataSourceId,
20362036
layerName: string,
2037-
): Promise<Array<APIMeshFile>> {
2038-
const meshFiles: Array<APIMeshFile> = await doWithToken((token) =>
2037+
): Promise<Array<APIMeshFileInfo>> {
2038+
const meshFiles: Array<APIMeshFileInfo> = await doWithToken((token) =>
20392039
Request.receiveJSON(
20402040
`${dataStoreUrl}/data/datasets/${dataSourceId.owningOrganization}/${dataSourceId.directoryName}/layers/${layerName}/meshes?token=${token}`,
20412041
),

frontend/javascripts/types/api_types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -941,8 +941,10 @@ export type ServerEditableMapping = {
941941
tracingId: string;
942942
};
943943

944-
export type APIMeshFile = {
945-
meshFileName: string;
944+
export type APIMeshFileInfo = {
945+
name: string;
946+
path: string | null | undefined;
947+
fileType: string | null | undefined;
946948
mappingName?: string | null | undefined;
947949
// 0 - is the first mesh file version
948950
// 1-2 - the format should behave as v0 (refer to voxelytics for actual differences)

frontend/javascripts/viewer/api/api_latest.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,7 +2300,7 @@ class DataApi {
23002300
true,
23012301
false,
23022302
);
2303-
return meshFiles.map((meshFile) => meshFile.meshFileName);
2303+
return meshFiles.map((meshFile) => meshFile.name);
23042304
}
23052305

23062306
/**
@@ -2318,7 +2318,7 @@ class DataApi {
23182318
}
23192319

23202320
const { currentMeshFile } = Store.getState().localSegmentationData[effectiveLayer.name];
2321-
return currentMeshFile != null ? currentMeshFile.meshFileName : null;
2321+
return currentMeshFile != null ? currentMeshFile.name : null;
23222322
}
23232323

23242324
/**
@@ -2351,7 +2351,7 @@ class DataApi {
23512351
if (
23522352
state.localSegmentationData[effectiveLayerName].availableMeshFiles == null ||
23532353
!state.localSegmentationData[effectiveLayerName].availableMeshFiles.find(
2354-
(el) => el.meshFileName === meshFileName,
2354+
(el) => el.name === meshFileName,
23552355
)
23562356
) {
23572357
throw new Error(
@@ -2403,7 +2403,7 @@ class DataApi {
24032403
throw new Error("No segmentation layer was found.");
24042404
}
24052405

2406-
const { mappingName, meshFileName } = currentMeshFile;
2406+
const { mappingName, name: meshFileName } = currentMeshFile;
24072407

24082408
if (mappingName != null) {
24092409
const activeMapping = this.getActiveMapping(effectiveLayerName);

frontend/javascripts/viewer/controller/url_manager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ class UrlManager {
313313

314314
for (const layerName of Object.keys(state.localSegmentationData)) {
315315
const { currentMeshFile } = state.localSegmentationData[layerName];
316-
const currentMeshFileName = currentMeshFile?.meshFileName;
316+
const currentMeshFileName = currentMeshFile?.name;
317317
const localMeshes = getMeshesForCurrentAdditionalCoordinates(state, layerName);
318318
const meshes =
319319
localMeshes != null

frontend/javascripts/viewer/model/actions/annotation_actions.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
APIAnnotationVisibility,
77
APIDataLayer,
88
APIDataset,
9-
APIMeshFile,
9+
APIMeshFileInfo,
1010
APIUserCompact,
1111
EditableLayerProperties,
1212
} from "types/api_types";
@@ -245,7 +245,7 @@ export const maybeFetchMeshFilesAction = (
245245
dataset: APIDataset,
246246
mustRequest: boolean,
247247
autoActivate: boolean = true,
248-
callback: (meshes: Array<APIMeshFile>) => void = _.noop,
248+
callback: (meshes: Array<APIMeshFileInfo>) => void = _.noop,
249249
) =>
250250
({
251251
type: "MAYBE_FETCH_MESH_FILES",
@@ -302,7 +302,7 @@ export const finishedLoadingMeshAction = (layerName: string, segmentId: number)
302302
segmentId,
303303
}) as const;
304304

305-
export const updateMeshFileListAction = (layerName: string, meshFiles: Array<APIMeshFile>) =>
305+
export const updateMeshFileListAction = (layerName: string, meshFiles: Array<APIMeshFileInfo>) =>
306306
({
307307
type: "UPDATE_MESH_FILE_LIST",
308308
layerName,
@@ -374,8 +374,8 @@ export const dispatchMaybeFetchMeshFilesAsync = async (
374374
dataset: APIDataset,
375375
mustRequest: boolean,
376376
autoActivate: boolean = true,
377-
): Promise<Array<APIMeshFile>> => {
378-
const readyDeferred = new Deferred<APIMeshFile[], unknown>();
377+
): Promise<Array<APIMeshFileInfo>> => {
378+
const readyDeferred = new Deferred<APIMeshFileInfo[], unknown>();
379379
const action = maybeFetchMeshFilesAction(
380380
segmentationLayer,
381381
dataset,

frontend/javascripts/viewer/model/reducers/annotation_reducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ function AnnotationReducer(state: WebknossosState, action: Action): WebknossosSt
491491
const { layerName, meshFileName } = action;
492492
const availableMeshFiles = state.localSegmentationData[layerName].availableMeshFiles;
493493
if (availableMeshFiles == null) return state;
494-
const meshFile = availableMeshFiles.find((el) => el.meshFileName === meshFileName);
494+
const meshFile = availableMeshFiles.find((el) => el.name === meshFileName);
495495
return updateKey2(state, "localSegmentationData", layerName, {
496496
currentMeshFile: meshFile,
497497
});

0 commit comments

Comments
 (0)