Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ad-hoc meshes compatible with ND segmentations #7394

Merged
merged 53 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
923a216
Add additional coordinates to ad-hoc mesh request params
frcroth Oct 17, 2023
36bae08
WIP: pass add coordinates in context menu in view port
dieknolle3333 Oct 23, 2023
5e17e91
add 4D mesh to scene
dieknolle3333 Oct 24, 2023
30bf498
enable changing color and removing meshes
dieknolle3333 Oct 25, 2023
811c3c1
WIP: only show meshes for current additional coordinates
dieknolle3333 Oct 30, 2023
6545a0d
only show meshes in current additional coordinates
dieknolle3333 Oct 30, 2023
36e46b2
fix mesh update after changing color of segment and ND mesh download
dieknolle3333 Oct 31, 2023
82b3ca2
commit before changing code structure
dieknolle3333 Oct 31, 2023
7b02f84
only show meshes in current add coordinates
dieknolle3333 Oct 31, 2023
89f5a56
fix case where no additional coordinates are given
dieknolle3333 Nov 1, 2023
84f0bf0
WIP: try to adjust segments view and add comment about batch actions
dieknolle3333 Nov 1, 2023
15320c2
WIP: saving progress
dieknolle3333 Nov 6, 2023
38df01e
store add coordinates in localsegmentation data in store state
dieknolle3333 Nov 7, 2023
299f5f9
WIP: fixed segment list, mesh loading and reloading
dieknolle3333 Nov 8, 2023
247bb44
add string conversion for additional coordinates and remove some Stor…
dieknolle3333 Nov 13, 2023
adc3b6d
fix segment multiselect
dieknolle3333 Nov 13, 2023
38cdce0
making sgement mesh controller react class component, probably reverting
dieknolle3333 Nov 13, 2023
a0b736b
move additional coordinate to string method to flycam accessor
dieknolle3333 Nov 13, 2023
ffba849
fix context menu and refactor mesh visibility change in mesh saga
dieknolle3333 Nov 14, 2023
f2a60ad
merge master
dieknolle3333 Nov 14, 2023
e5a1e9d
fix yarn.lock
dieknolle3333 Nov 15, 2023
4a61f35
disable segment stats in nd datasets for now
dieknolle3333 Nov 15, 2023
6e7134d
fix visibility toggle and color change
dieknolle3333 Nov 15, 2023
6ee80c5
fix loading of meshes without voxels and removing of meshes
dieknolle3333 Nov 20, 2023
3649d70
fix edge case after removing mesh and mesh download
dieknolle3333 Nov 22, 2023
b457ac8
add some comments and make code prettier
dieknolle3333 Nov 22, 2023
36c1f86
Merge branch 'master' into adhoc-mesh-additional-coordinates
dieknolle3333 Nov 22, 2023
e971675
add changelog
dieknolle3333 Nov 22, 2023
74da01a
refactor segment mesh controller and getAddCoordAsString()
dieknolle3333 Nov 27, 2023
8c4461d
Merge branch 'master' into adhoc-mesh-additional-coordinates
dieknolle3333 Nov 27, 2023
0397da4
WIP: refactor typing of localSegmentationData.meshes
dieknolle3333 Nov 28, 2023
2ed0404
refactor code, commit before revertig stuff in mesh saga
dieknolle3333 Nov 29, 2023
41fb573
WIP: refactor code after code review
dieknolle3333 Nov 29, 2023
0d702a7
merge master
dieknolle3333 Nov 29, 2023
281a805
lint :)
dieknolle3333 Nov 29, 2023
18b1566
WIP: work on code review
dieknolle3333 Dec 4, 2023
369d661
WIP: fix mesh download
dieknolle3333 Dec 4, 2023
42bfbd9
Merge branch 'master' into adhoc-mesh-additional-coordinates
dieknolle3333 Dec 4, 2023
5274990
WIP: improve var naming
dieknolle3333 Dec 4, 2023
461fe0f
merge master
dieknolle3333 Dec 6, 2023
d0432d2
only remove mesh in current dimension
dieknolle3333 Dec 6, 2023
85c06a7
reduce cyclic dependencies
philippotto Dec 6, 2023
c619c76
fix tests by setting scene controller in test setup
philippotto Dec 6, 2023
cb1e331
improve typing
dieknolle3333 Dec 6, 2023
eb072a9
improve naming and types
dieknolle3333 Dec 6, 2023
4f2642a
adapt check-cyclic-dependencies.js so that it ensures that the amount…
philippotto Dec 7, 2023
a22a22a
Merge branch 'adhoc-mesh-additional-coordinates' of github.com:scalab…
philippotto Dec 7, 2023
c81cf37
address review: fix bug when adding new segments
dieknolle3333 Dec 11, 2023
cb00820
Merge branch 'master' into adhoc-mesh-additional-coordinates
dieknolle3333 Dec 11, 2023
7d92806
Merge branch 'master' into adhoc-mesh-additional-coordinates
dieknolle3333 Dec 11, 2023
ebe9106
merge master
dieknolle3333 Dec 13, 2023
f0c34a1
fix bug concerning precomputed meshes
dieknolle3333 Dec 13, 2023
534ef44
avoid implicit any types
philippotto Dec 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
[Commits](https://github.com/scalableminds/webknossos/compare/23.12.0...HEAD)

### Added
- Zarr datasets can now be directly uploaded to WEBKNOSSOS. [#7397](https://github.com/scalableminds/webknossos/pull/7397)
- Added support for reading uint24 rgb layers in datasets with zarr2/zarr3/n5/neuroglancerPrecomputed format, as used for voxelytics predictions. [#7413](https://github.com/scalableminds/webknossos/pull/7413)
- Adding a remote dataset can now be done by providing a Neuroglancer URI. [#7416](https://github.com/scalableminds/webknossos/pull/7416)
- Added a filter to the Task List->Stats column to quickly filter for tasks with "Prending", "In-Progress" or "Finished" instances. [#7430](https://github.com/scalableminds/webknossos/pull/7430)
- Added support for S3-compliant object storage services (e.g. MinIO) as a storage backend for remote datasets. [#7453](https://github.com/scalableminds/webknossos/pull/7453)
- Added support for blosc compressed N5 datasets. [#7465](https://github.com/scalableminds/webknossos/pull/7465)
- Added route for triggering the compute segment index worker job. [#7471](https://github.com/scalableminds/webknossos/pull/7471)
- Adhoc mesh rendering is now available for ND datasets.[#7394](https://github.com/scalableminds/webknossos/pull/7394)

### Changed
Expand Down
15 changes: 12 additions & 3 deletions frontend/javascripts/oxalis/api/api_latest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ import Constants, {
AnnotationToolEnum,
TDViewDisplayModeEnum,
MappingStatusEnum,
EMPTY_OBJECT,
} from "oxalis/constants";
import DataLayer from "oxalis/model/data_layer";
import type { OxalisModel } from "oxalis/model";
Expand Down Expand Up @@ -2257,8 +2258,12 @@ class DataApi {
layerName,
).name;

if (Store.getState().localSegmentationData[effectiveLayerName].meshes[segmentId] != null) {
if (Store.getState().localSegmentationData[effectiveLayerName].meshes?.[segmentId] != null) {
Store.dispatch(updateMeshVisibilityAction(effectiveLayerName, segmentId, isVisible));
} else {
throw new Error(
dieknolle3333 marked this conversation as resolved.
Show resolved Hide resolved
`Mesh for segment ${segmentId} was not found in OxalisState.localSegmentationData.`,
philippotto marked this conversation as resolved.
Show resolved Hide resolved
dieknolle3333 marked this conversation as resolved.
Show resolved Hide resolved
);
}
}

Expand All @@ -2275,8 +2280,12 @@ class DataApi {
layerName,
).name;

if (Store.getState().localSegmentationData[effectiveLayerName].meshes[segmentId] != null) {
if (Store.getState().localSegmentationData[effectiveLayerName].meshes?.[segmentId] != null) {
Store.dispatch(removeMeshAction(effectiveLayerName, segmentId));
} else {
throw new Error(
`Mesh for segment ${segmentId} was not found in OxalisState.localSegmentationData.`,
dieknolle3333 marked this conversation as resolved.
Show resolved Hide resolved
);
}
}

Expand All @@ -2293,7 +2302,7 @@ class DataApi {
layerName,
).name;
const segmentIds = Object.keys(
Store.getState().localSegmentationData[effectiveLayerName].meshes,
Store.getState().localSegmentationData[effectiveLayerName].meshes || EMPTY_OBJECT,
);

for (const segmentId of segmentIds) {
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,4 @@ export enum BLEND_MODES {

export const Identity4x4 = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
export const IdentityTransform = { type: "affine", affineMatrix: Identity4x4 } as const;
export const EMPTY_OBJECT = {};
dieknolle3333 marked this conversation as resolved.
Show resolved Hide resolved
200 changes: 84 additions & 116 deletions frontend/javascripts/oxalis/controller/segment_mesh_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,17 @@ export default class SegmentMeshController {
layerName: string,
additionalCoordinates?: AdditionalCoordinate[] | null,
): boolean {
const additionalCoordinatesString = getAdditionalCoordinatesAsString(
additionalCoordinates || null,
return (
this.getMeshGroups(getAdditionalCoordinatesAsString(additionalCoordinates), layerName, id) !=
null
);

if (
this.meshesGroupsPerSegmentationId[additionalCoordinatesString] == null ||
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName] == null
)
return false;

const segments = this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName];
if (!segments) {
return false;
}
return segments[id] != null;
}

addMeshFromVertices(
vertices: Float32Array,
segmentationId: number,
layerName: string,
additionalCoordinates?: AdditionalCoordinate[],
additionalCoordinates?: AdditionalCoordinate[] | undefined | null,
): void {
if (vertices.length === 0) return;
let bufferGeometry = new THREE.BufferGeometry();
Expand All @@ -71,7 +60,7 @@ export default class SegmentMeshController {
null,
NO_LOD_MESH_INDEX,
layerName,
additionalCoordinates || null,
additionalCoordinates,
);
}

Expand Down Expand Up @@ -113,114 +102,67 @@ export default class SegmentMeshController {
scale: Vector3 | null = null,
lod: number,
layerName: string,
additionalCoordinates: AdditionalCoordinate[] | null,
additionalCoordinates: AdditionalCoordinate[] | null | undefined,
): void {
const additionalCoordinatesString = getAdditionalCoordinatesAsString(
additionalCoordinates || null,
const additionalCoordinatesString = getAdditionalCoordinatesAsString(additionalCoordinates);
const newGroup = new THREE.Group();
const keys = [additionalCoordinatesString, layerName, segmentationId, lod];
_.set(
this.meshesGroupsPerSegmentationId,
keys,
_.get(this.meshesGroupsPerSegmentationId, keys, newGroup),
dieknolle3333 marked this conversation as resolved.
Show resolved Hide resolved
);
if (this.meshesGroupsPerSegmentationId[additionalCoordinatesString] == null) {
this.meshesGroupsPerSegmentationId[additionalCoordinatesString] = {};
}

if (this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName] == null) {
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName] = {};
}
if (
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][segmentationId] ==
null
) {
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][segmentationId] =
{};
if (lod === NO_LOD_MESH_INDEX) {
this.meshesLODRootGroup.addNoLODSupportedMesh(newGroup);
} else {
this.meshesLODRootGroup.addLODMesh(newGroup, lod);
}
if (
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][segmentationId][
lod
] == null
) {
const newGroup = new THREE.Group();
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][segmentationId][
lod
] = newGroup;
if (lod === NO_LOD_MESH_INDEX) {
this.meshesLODRootGroup.addNoLODSupportedMesh(newGroup);
} else {
this.meshesLODRootGroup.addLODMesh(newGroup, lod);
}
// @ts-ignore
newGroup.cellId = segmentationId;
if (scale != null) {
newGroup.scale.copy(new THREE.Vector3(...scale));
}
// @ts-ignore
newGroup.cellId = segmentationId;
if (scale != null) {
newGroup.scale.copy(new THREE.Vector3(...scale));
}
const mesh = this.constructMesh(segmentationId, geometry);
if (offset) {
mesh.translateX(offset[0]);
mesh.translateY(offset[1]);
mesh.translateZ(offset[2]);
}
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][segmentationId][
lod
].add(mesh);
this.addMeshToMeshGroups(additionalCoordinatesString, layerName, segmentationId, lod, mesh);
}

removeMeshById(
segmentationId: number,
layerName: string,
additionalCoordinates: AdditionalCoordinate[] | null,
): void {
// either remove a mesh for specific additional coordinates, or remove all meshes for a segment per default.
let additionalCoordinatesToRemoveMeshes;
if (additionalCoordinates == null) {
additionalCoordinatesToRemoveMeshes = Object.keys(this.meshesGroupsPerSegmentationId);
} else {
additionalCoordinatesToRemoveMeshes = [
getAdditionalCoordinatesAsString(additionalCoordinates),
];
}
for (const additionalCoordinatesString of additionalCoordinatesToRemoveMeshes) {
if (
this.meshesGroupsPerSegmentationId[additionalCoordinatesString] == null ||
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName] == null ||
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][
segmentationId
] == null
) {
return;
}
_.forEach(
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][segmentationId],
(meshGroup, lod) => {
const lodNumber = parseInt(lod);
if (lodNumber !== NO_LOD_MESH_INDEX) {
this.meshesLODRootGroup.removeLODMesh(meshGroup, lodNumber);
} else {
this.meshesLODRootGroup.removeNoLODSupportedMesh(meshGroup);
}
},
);
delete this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][
segmentationId
];
removeMeshById(segmentationId: number, layerName: string): void {
const additionalCoordinates = Store.getState().flycam.additionalCoordinates;
const additionalCoordKey = getAdditionalCoordinatesAsString(additionalCoordinates);
if (this.getMeshGroups(additionalCoordKey, layerName, segmentationId) == null) {
return;
}
_.forEach(
this.getMeshGroups(additionalCoordKey, layerName, segmentationId),
(meshGroup, lod) => {
const lodNumber = parseInt(lod);
if (lodNumber !== NO_LOD_MESH_INDEX) {
this.meshesLODRootGroup.removeLODMesh(meshGroup, lodNumber);
} else {
this.meshesLODRootGroup.removeNoLODSupportedMesh(meshGroup);
}
},
);
this.removeMeshFromMeshGroups(additionalCoordKey, layerName, segmentationId);
}

getMeshGeometryInBestLOD(
segmentId: number,
layerName: string,
additionalCoordinates?: AdditionalCoordinate[] | null,
): THREE.Group {
const additionalCoordinatesString = getAdditionalCoordinatesAsString(
additionalCoordinates || null,
);

const additionalCoordKey = getAdditionalCoordinatesAsString(additionalCoordinates);
const bestLod = Math.min(
...Object.keys(
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][segmentId],
).map((lodVal) => parseInt(lodVal)),
...Object.keys(this.getMeshGroups(additionalCoordKey, layerName, segmentId)).map((lodVal) =>
parseInt(lodVal),
),
);
return this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][segmentId][
bestLod
];
return this.getMeshGroupsByLOD(additionalCoordinates, layerName, segmentId, bestLod);
}

setMeshVisibility(
Expand All @@ -229,20 +171,10 @@ export default class SegmentMeshController {
layerName: string,
additionalCoordinates?: AdditionalCoordinate[] | null,
): void {
const additionalCoordinatesString = getAdditionalCoordinatesAsString(
additionalCoordinates || null,
);

if (this.meshesGroupsPerSegmentationId[additionalCoordinatesString] == null) {
return;
}

_.forEach(
this.meshesGroupsPerSegmentationId[additionalCoordinatesString][layerName][id],
(meshGroup) => {
meshGroup.visible = visibility;
},
);
const additionalCoordKey = getAdditionalCoordinatesAsString(additionalCoordinates);
_.forEach(this.getMeshGroups(additionalCoordKey, layerName, id), (meshGroup) => {
meshGroup.visible = visibility;
});
}

setMeshColor(id: number, layerName: string): void {
Expand Down Expand Up @@ -296,4 +228,40 @@ export default class SegmentMeshController {
this.meshesLODRootGroup.add(directionalLight2);
this.meshesLODRootGroup.add(pointLight);
}

getMeshGroupsByLOD(
additionalCoordinates: AdditionalCoordinate[] | null | undefined,
layerName: string,
segmentationId: number,
lod: number,
) {
const additionalCoordKey = getAdditionalCoordinatesAsString(additionalCoordinates);
const keys = [additionalCoordKey, layerName, segmentationId, lod];
return _.get(this.meshesGroupsPerSegmentationId, keys, null);
}

getMeshGroups(additionalCoordKey: string, layerName: string, segmentationId: number) {
const keys = [additionalCoordKey, layerName, segmentationId];
return _.get(this.meshesGroupsPerSegmentationId, keys, null);
}

addMeshToMeshGroups(
additionalCoordKey: string,
layerName: string,
segmentationId: number,
lod: number,
mesh: THREE.Mesh<THREE.BufferGeometry, THREE.MeshLambertMaterial>,
) {
this.meshesGroupsPerSegmentationId[additionalCoordKey][layerName][segmentationId][lod].add(
mesh,
);
}

removeMeshFromMeshGroups(
additionalCoordinateKey: string,
layerName: string,
segmentationId: number,
) {
delete this.meshesGroupsPerSegmentationId[additionalCoordinateKey][layerName][segmentationId];
}
}
9 changes: 6 additions & 3 deletions frontend/javascripts/oxalis/controller/url_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,12 @@ class UrlManager {
for (const layerName of Object.keys(state.localSegmentationData)) {
const { meshes: localMeshes, currentMeshFile } = state.localSegmentationData[layerName];
const currentMeshFileName = currentMeshFile?.meshFileName;
const meshes = Utils.values(localMeshes)
.filter(({ isVisible }) => isVisible)
.map(mapMeshInfoToUrlMeshDescriptor);
const meshes =
localMeshes != null
? Utils.values(localMeshes as Record<number, MeshInformation>)
.filter(({ isVisible }) => isVisible)
.map(mapMeshInfoToUrlMeshDescriptor)
: [];

if (currentMeshFileName != null || meshes.length > 0) {
stateByLayer[layerName] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ function _getPosition(flycam: Flycam): Vector3 {
}

export function getAdditionalCoordinatesAsString(
additionalCoordinates: AdditionalCoordinate[] | null,
additionalCoordinates: AdditionalCoordinate[] | null | undefined,
): string {
if (additionalCoordinates != null && additionalCoordinates.length > 0) {
return additionalCoordinates
Expand Down
Loading