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

Add loaded meshes to sharing link #5993

Merged
merged 39 commits into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a95d9d4
add Utils.values which is Object.values but with the correct type, cl…
daniel-wer Jan 26, 2022
0a65443
allow to share ad-hoc computed meshes via link
daniel-wer Jan 26, 2022
6025ca3
clean up isosurface related code, remove auto-loading triggered by fl…
daniel-wer Jan 27, 2022
c56a556
refactor loadPrecomputedMesh method into a saga and adapt usages
daniel-wer Jan 27, 2022
f486a46
floor mesh seed position in url
daniel-wer Jan 27, 2022
8553d24
log to airbrake if the ad-hoc mesh loading limit is reached
daniel-wer Jan 27, 2022
a4f3602
load precomputed meshes from the inside out by sorting chunks
daniel-wer Jan 27, 2022
99fe876
remove unnecessary types
daniel-wer Jan 31, 2022
e39f12d
PR feedback 1
daniel-wer Jan 31, 2022
16d493b
rework task_pool to be a saga and to execute sagas to make it fully c…
daniel-wer Jan 31, 2022
dc7f772
fix mesh sharing via link if no mesh file is active
daniel-wer Feb 1, 2022
8acfa37
more PR feedback
daniel-wer Feb 1, 2022
350f734
include additional information in url for meshes to make sure the sam…
daniel-wer Feb 3, 2022
88abd54
use new kubernetix url
philippotto Feb 8, 2022
e051c30
trigger nightly (needs to be reverted afterwards)
philippotto Feb 8, 2022
c8b8c6b
Merge branch 'master' of github.com:scalableminds/webknossos into mes…
daniel-wer Feb 9, 2022
26a9aa8
fix refresh-datasets in nightly and other outdated kubernetix link
philippotto Feb 9, 2022
d105dbf
upgrade puppeteer from 1.13 to 13.2
philippotto Feb 9, 2022
01a895e
use mappingInfo parameter instead of mappingName and mappingType, PR …
daniel-wer Feb 9, 2022
25adf35
fix deprecation warning
philippotto Feb 9, 2022
498dddd
update two snapshots which only changed subtly
philippotto Feb 9, 2022
13bea43
fix url json schema and fix that mappingInfo was overwritten by meshInfo
daniel-wer Feb 9, 2022
c114ba4
update changelog
daniel-wer Feb 9, 2022
2a98dfd
Downgrade puppeteer to 11.0.0 to avoid that some segments are rendere…
daniel-wer Feb 10, 2022
961f8a1
adapt screenshot snapshots to sensible scalebar
philippotto Feb 14, 2022
b382b1b
trigger nightly now
philippotto Feb 14, 2022
779f669
Merge branch 'master' of github.com:scalableminds/webknossos into mes…
daniel-wer Feb 17, 2022
7441470
add screenshot test for mesh linking, add more logging to screenshot …
daniel-wer Feb 17, 2022
2139c83
adapt docs for sharing link format and hide the format behind a toggl…
daniel-wer Feb 17, 2022
968ad00
use large resource class for nightly tests as well
daniel-wer Feb 17, 2022
9f8c2b3
change screenshot test url temporarily and add more debugging output
daniel-wer Feb 17, 2022
1369467
Merge branch 'meshes-in-link' of github.com:scalableminds/webknossos …
daniel-wer Feb 17, 2022
9d2bdf1
Merge branch 'adapt-screenshots-to-scalebar' of github.com:scalablemi…
daniel-wer Feb 17, 2022
82a1aa2
update puppeteer and pixelmatch, --use-gl=egl, update screenshots, ma…
daniel-wer Feb 17, 2022
b2a385f
check chrome version in CI
daniel-wer Feb 18, 2022
3f779fd
use switftshader and replace screenshots, temporarily slim down night…
daniel-wer Feb 18, 2022
5598681
test meshesinlink PR
daniel-wer Feb 18, 2022
7325ff8
replace meshes screenshot with the one from the CI
daniel-wer Feb 18, 2022
5d47edc
revert temporary changes
daniel-wer Feb 21, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import update from "immutability-helper";
import type { APIUser, APITeam, APITeamMembership } from "types/api_flow_types";
import { updateUser, getEditableTeams } from "admin/admin_rest_api";
import messages from "messages";
import * as Utils from "libs/utils";

const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
Expand Down Expand Up @@ -129,7 +130,7 @@ class PermissionsAndTeamsModalView extends React.PureComponent<TeamRoleModalProp
setPermissionsAndTeams = () => {
const newUserPromises = this.props.users.map(user => {
if (this.props.selectedUserIds.includes(user.id)) {
const newTeams = ((Object.values(this.state.selectedTeams): any): Array<APITeamMembership>);
const newTeams = Utils.values(this.state.selectedTeams);
const newUser = Object.assign({}, user, { teams: newTeams });
if (this.props.activeUser.isAdmin && this.props.selectedUserIds.length === 1) {
// If the current user is admin and only one user is edited we also update the permissions.
Expand Down
13 changes: 9 additions & 4 deletions frontend/javascripts/libs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export function mod(x: number, n: number) {
return ((x % n) + n) % n;
}

export function values<K, V>(o: { [K]: V }): Array<V> {
// $FlowIssue[incompatible-return] remove once https://github.com/facebook/flow/issues/2221 is fixed
return Object.values(o);
}

export function map2<A, B>(fn: (A, number) => B, tuple: [A, A]): [B, B] {
const [x, y] = tuple;
return [fn(x, 0), fn(y, 1)];
Expand Down Expand Up @@ -514,8 +519,8 @@ export function filterWithSearchQueryOR<T: { +[string]: mixed }, P: $Keys<T>>(
_.some(properties, fieldName => {
const value = typeof fieldName === "function" ? fieldName(model) : model[fieldName];
if (value != null && (typeof value === "string" || value instanceof Object)) {
const values = getRecursiveValues(value);
return _.some(values, v => v != null && v.toString().match(regexp));
const recursiveValues = getRecursiveValues(value);
return _.some(recursiveValues, v => v != null && v.toString().match(regexp));
} else {
return false;
}
Expand Down Expand Up @@ -545,8 +550,8 @@ export function filterWithSearchQueryAND<T: { +[string]: mixed }, P: $Keys<T>>(
_.some(properties, fieldName => {
const value = typeof fieldName === "function" ? fieldName(model) : model[fieldName];
if (value !== null && (typeof value === "string" || value instanceof Object)) {
const values = getRecursiveValues(value);
return _.some(values, v => v != null && v.toString().match(pattern));
const recursiveValues = getRecursiveValues(value);
return _.some(recursiveValues, v => v != null && v.toString().match(pattern));
} else {
return false;
}
Expand Down
23 changes: 12 additions & 11 deletions frontend/javascripts/oxalis/api/api_latest.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ import {
} from "oxalis/model/helpers/position_converter";
import { callDeep } from "oxalis/view/right-border-tabs/tree_hierarchy_view_helpers";
import { centerTDViewAction } from "oxalis/model/actions/view_mode_actions";
import { changeActiveIsosurfaceCellAction } from "oxalis/model/actions/segmentation_actions";
import {
loadAdHocMeshAction,
loadPrecomputedMeshAction,
} from "oxalis/model/actions/segmentation_actions";
import { discardSaveQueuesAction } from "oxalis/model/actions/save_actions";
import {
doWithToken,
Expand Down Expand Up @@ -79,10 +82,7 @@ import {
getRotation,
getRequestLogZoomStep,
} from "oxalis/model/accessors/flycam_accessor";
import {
loadMeshFromFile,
maybeFetchMeshFiles,
} from "oxalis/view/right-border-tabs/segments_tab/segments_view_helper";
import { maybeFetchMeshFiles } from "oxalis/view/right-border-tabs/segments_tab/segments_view_helper";
import { overwriteAction } from "oxalis/model/helpers/overwrite_action_middleware";
import { parseNml } from "oxalis/model/helpers/nml_helpers";
import { rotate3DViewTo } from "oxalis/controller/camera_controller";
Expand Down Expand Up @@ -140,6 +140,7 @@ import * as Utils from "libs/utils";
import dimensions from "oxalis/model/dimensions";
import messages from "messages";
import window, { location } from "libs/window";
import DataLayer from "oxalis/model/data_layer";

type OutdatedDatasetConfigurationKeys = "segmentationOpacity" | "isSegmentationDisabled";

Expand Down Expand Up @@ -1009,9 +1010,7 @@ class DataApi {
*/
async reloadBuckets(layerName: string): Promise<void> {
await Promise.all(
Object.keys(this.model.dataLayers).map(async currentLayerName => {
const dataLayer = this.model.dataLayers[currentLayerName];

Utils.values(this.model.dataLayers).map(async (dataLayer: DataLayer) => {
if (dataLayer.name === layerName) {
if (dataLayer.cube.isSegmentation) {
await Model.ensureSavedState();
Expand All @@ -1030,7 +1029,7 @@ class DataApi {
if (hasVolumeTracings(Store.getState().tracing)) {
await Model.ensureSavedState();
}
_.forEach(this.model.dataLayers, dataLayer => {
_.forEach(this.model.dataLayers, (dataLayer: DataLayer) => {
dataLayer.cube.collectAllBuckets();
dataLayer.layerRenderingManager.refresh();
});
Expand Down Expand Up @@ -1654,7 +1653,9 @@ class DataApi {
}
}

await loadMeshFromFile(segmentId, seedPosition, meshFileName, segmentationLayer, dataset);
Store.dispatch(
daniel-wer marked this conversation as resolved.
Show resolved Hide resolved
loadPrecomputedMeshAction(segmentId, seedPosition, meshFileName, effectiveLayerName),
);
}

/**
Expand All @@ -1666,7 +1667,7 @@ class DataApi {
* api.data.computeMeshOnDemand(segmentId, currentPosition);
*/
computeMeshOnDemand(segmentId: number, seedPosition: Vector3) {
Store.dispatch(changeActiveIsosurfaceCellAction(segmentId, seedPosition, true));
Store.dispatch(loadAdHocMeshAction(segmentId, seedPosition));
}

/**
Expand Down
32 changes: 30 additions & 2 deletions frontend/javascripts/oxalis/controller/url_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { V3 } from "libs/mjs";
import { applyState } from "oxalis/model_initialization";
import { getRotation, getPosition } from "oxalis/model/accessors/flycam_accessor";
import { getSkeletonTracing, getActiveNode } from "oxalis/model/accessors/skeletontracing_accessor";
import Store, { type OxalisState, type MappingType } from "oxalis/store";
import Store, {
type OxalisState,
type MappingType,
type IsosurfaceInformation,
} from "oxalis/store";
import * as Utils from "libs/utils";
import constants, {
type ViewMode,
Expand All @@ -22,12 +26,22 @@ import { validateUrlStateJSON } from "types/validation";

const MAX_UPDATE_INTERVAL = 1000;

type Mesh = {|
daniel-wer marked this conversation as resolved.
Show resolved Hide resolved
+segmentId: number,
+seedPosition: Vector3,
+isPrecomputed: boolean,
|};

export type UrlStateByLayer = {
[layerName: string]: {
meshInfo?: {
meshFileName: string,
meshes?: Array<Mesh>,
},
mappingInfo?: {
mappingName: string,
mappingType: MappingType,
agglomerateIdsToImport?: [number],
agglomerateIdsToImport?: Array<number>,
},
},
};
Expand Down Expand Up @@ -181,6 +195,20 @@ class UrlManager {
stateByLayer[layerName] = { mappingInfo: { mappingName, mappingType } };
}
}
for (const layerName of Object.keys(state.localSegmentationData)) {
const { isosurfaces, currentMeshFile } = state.localSegmentationData[layerName];
if (currentMeshFile != null) {
const { meshFileName } = currentMeshFile;
const meshes = Utils.values(isosurfaces)
.filter(({ isVisible }: IsosurfaceInformation) => isVisible)
.map(({ segmentId, seedPosition, isPrecomputed }: IsosurfaceInformation) => ({
daniel-wer marked this conversation as resolved.
Show resolved Hide resolved
segmentId,
seedPosition,
isPrecomputed,
}));
stateByLayer[layerName] = { meshInfo: { meshFileName, meshes } };
}
}
const stateByLayerOptional = _.size(stateByLayer) > 0 ? { stateByLayer } : {};

// $FlowIssue[incompatible-exact] See https://github.com/facebook/flow/issues/2977
Expand Down
12 changes: 6 additions & 6 deletions frontend/javascripts/oxalis/merger_mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import api from "oxalis/api/internal_api";
import messages from "messages";

type MergerModeState = {
treeColors: Object,
colorMapping: Object,
nodesPerSegment: Object,
treeColors: { [number]: ?number },
colorMapping: { [number]: number },
nodesPerSegment: { [number]: number },
nodes: Array<NodeWithTreeId>,
// A properly initialized merger mode should always
// have a segmentationLayerName. However, some edge cases
Expand All @@ -41,7 +41,7 @@ function getTreeColor(treeId: number, mergerModeState: MergerModeState) {
const { treeColors } = mergerModeState;
let color = treeColors[treeId];
// Generate a new color if tree was never seen before
if (color === undefined) {
if (color == null) {
color = Math.ceil(127 * Math.random());
treeColors[treeId] = color;
}
Expand Down Expand Up @@ -252,8 +252,8 @@ function shuffleColorOfCurrentTree(mergerModeState: MergerModeState) {
treeColors[activeTreeId] = undefined;
// Applies the change of the color to all connected segments
Object.keys(colorMapping).forEach(key => {
if (colorMapping[key] === oldColor) {
colorMapping[key] = getTreeColor(activeTreeId, mergerModeState);
if (colorMapping[+key] === oldColor) {
colorMapping[+key] = getTreeColor(activeTreeId, mergerModeState);
}
});
// Update the segmentation
Expand Down
23 changes: 9 additions & 14 deletions frontend/javascripts/oxalis/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ export class OxalisModel {
}

getAllLayers(): Array<DataLayer> {
// $FlowIssue[incompatible-return] remove once https://github.com/facebook/flow/issues/2221 is fixed
return Object.values(this.dataLayers);
return Utils.values(this.dataLayers);
}

getColorLayers(): Array<DataLayer> {
Expand All @@ -100,22 +99,18 @@ export class OxalisModel {
}

getSegmentationLayers(): Array<DataLayer> {
return Object.keys(this.dataLayers)
.map(k => this.dataLayers[k])
.filter(
dataLayer =>
getLayerByName(Store.getState().dataset, dataLayer.name).category === "segmentation",
);
return Utils.values(this.dataLayers).filter(
dataLayer =>
getLayerByName(Store.getState().dataset, dataLayer.name).category === "segmentation",
);
}

getSegmentationTracingLayers(): Array<DataLayer> {
return Object.keys(this.dataLayers)
.map(k => this.dataLayers[k])
.filter(dataLayer => {
const layer = getLayerByName(Store.getState().dataset, dataLayer.name);
return Utils.values(this.dataLayers).filter(dataLayer => {
const layer = getLayerByName(Store.getState().dataset, dataLayer.name);

return layer.category === "segmentation" && layer.tracingId != null;
});
return layer.category === "segmentation" && layer.tracingId != null;
});
}

getSomeSegmentationLayer(): ?DataLayer {
Expand Down
4 changes: 2 additions & 2 deletions frontend/javascripts/oxalis/model/actions/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { AnnotationActionTypes } from "oxalis/model/actions/annotation_actions";
import type { DatasetAction } from "oxalis/model/actions/dataset_actions";
import type { FlycamAction } from "oxalis/model/actions/flycam_actions";
import type { IsosurfaceAction } from "oxalis/model/actions/segmentation_actions";
import type { SegmentationAction } from "oxalis/model/actions/segmentation_actions";
import type { SaveAction } from "oxalis/model/actions/save_actions";
import type { SettingAction } from "oxalis/model/actions/settings_actions";
import type { SkeletonTracingAction } from "oxalis/model/actions/skeletontracing_actions";
Expand All @@ -24,7 +24,7 @@ export type Action =
| FlycamAction
| UserAction
| UiAction
| IsosurfaceAction;
| SegmentationAction;

export const wkReadyAction = () => ({
type: "WK_READY",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,6 @@ export type RefreshIsosurfacesAction = {
type: "REFRESH_ISOSURFACES",
};

export type FinishedRefreshingIsosurfacesAction = {
type: "FINISHED_REFRESHING_ISOSURFACES",
};
export type RefreshIsosurfaceAction = {
type: "REFRESH_ISOSURFACE",
layerName: string,
Expand Down Expand Up @@ -195,7 +192,6 @@ export type AnnotationActionTypes =
| UpdateIsosurfaceVisibilityAction
| TriggerIsosurfaceDownloadAction
| RefreshIsosurfacesAction
| FinishedRefreshingIsosurfacesAction
| RefreshIsosurfaceAction
| StartedLoadingIsosurfaceAction
| FinishedLoadingIsosurfaceAction
Expand Down Expand Up @@ -367,10 +363,6 @@ export const refreshIsosurfacesAction = (): RefreshIsosurfacesAction => ({
type: "REFRESH_ISOSURFACES",
});

export const finishedRefreshingIsosurfacesAction = (): FinishedRefreshingIsosurfacesAction => ({
type: "FINISHED_REFRESHING_ISOSURFACES",
});

export const refreshIsosurfaceAction = (
layerName: string,
cellId: number,
Expand Down
3 changes: 0 additions & 3 deletions frontend/javascripts/oxalis/model/actions/flycam_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ type SetPositionAction = {
type: "SET_POSITION",
position: Vector3,
dimensionToSkip: ?number,
shouldRefreshIsosurface: boolean,
};
type SetRotationAction = { type: "SET_ROTATION", rotation: Vector3 };
type SetDirectionAction = { type: "SET_DIRECTION", direction: Vector3 };
Expand Down Expand Up @@ -81,12 +80,10 @@ export const setZoomStepAction = (zoomStep: number): SetZoomStepAction => ({
export const setPositionAction = (
position: Vector3,
dimensionToSkip: ?number,
shouldRefreshIsosurface: boolean = true,
): SetPositionAction => ({
type: "SET_POSITION",
position,
dimensionToSkip,
shouldRefreshIsosurface,
});
export const setRotationAction = (rotation: Vector3): SetRotationAction => ({
type: "SET_ROTATION",
Expand Down
38 changes: 29 additions & 9 deletions frontend/javascripts/oxalis/model/actions/segmentation_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,42 @@

import type { Vector3 } from "oxalis/constants";

export type ChangeActiveIsosurfaceCellAction = {
type: "CHANGE_ACTIVE_ISOSURFACE_CELL",
export type LoadAdHocMeshAction = {
type: "LOAD_AD_HOC_MESH_ACTION",
cellId: number,
seedPosition: Vector3,
shouldReload: boolean,
layerName?: string,
};
export type LoadPrecomputedMeshAction = {
type: "LOAD_PRECOMPUTED_MESH_ACTION",
cellId: number,
seedPosition: Vector3,
meshFileName: string,
layerName?: string,
};

export type IsosurfaceAction = ChangeActiveIsosurfaceCellAction;
export type SegmentationAction = LoadAdHocMeshAction | LoadPrecomputedMeshAction;

export const loadAdHocMeshAction = (
cellId: number,
seedPosition: Vector3,
layerName?: string,
): LoadAdHocMeshAction => ({
type: "LOAD_AD_HOC_MESH_ACTION",
cellId,
seedPosition,
layerName,
});

export const changeActiveIsosurfaceCellAction = (
export const loadPrecomputedMeshAction = (
cellId: number,
seedPosition: Vector3,
shouldReload: boolean,
): ChangeActiveIsosurfaceCellAction => ({
type: "CHANGE_ACTIVE_ISOSURFACE_CELL",
meshFileName: string,
layerName?: string,
): LoadPrecomputedMeshAction => ({
type: "LOAD_PRECOMPUTED_MESH_ACTION",
cellId,
seedPosition,
shouldReload,
meshFileName,
layerName,
});
Loading