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

Fix zooming out for datasets with very large scale #6304

Merged
merged 5 commits into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
### Changed

### Fixed
- Fixed that zooming out for datasets with very large scale was not possible until the coarsest level. [#6304](https://github.com/scalableminds/webknossos/pull/6304)

### Removed

Expand Down
37 changes: 24 additions & 13 deletions frontend/javascripts/oxalis/model/accessors/flycam_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,27 +128,38 @@ export function _getMaximumZoomForAllResolutions(
maximumCapacity: number,
initializedGpuFactor: number,
): Array<number> {
// maximumIterationCount is used as an upper limit to avoid an endless loop, in case
// the following while loop causes havoc for some reason (e.g., because
// the calculated bucket size isn't strictly increasing anymore). It means,
// that even with the best GPU specs and biggest dataset (i.e., many magnifications),
// wk will at most zoom out until a zoom value of ZOOM_STEP_INTERVAL**maximumIterationCount.
// With the current values, this would indicate a maximum zoom value of ~ 35 000, meaning
// that ~ 15 different magnifications (~ log2 of 35000) are supported properly.
const maximumIterationCount = 120;
let currentIterationCount = 0;
// This function determines which zoom value ranges are valid for the given magnifications.
// The calculation iterates through several zoom values and checks the required bucket capacity
// against the capacity supported by the GPU.
// In each iteration, the last zoom value is incremented as if the user performed a zoom-out action.
//
// In theory, we could simply abort the loop once a maximum zoom value was found for all magnifications.
// However, to avoid an infinite loop in case of violated assumptions (e.g., because the calculated
// bucket size isn't strictly increasing anymore), we calculate an iteration limit.

// For that limit, we specify how many magnifications we want to support at least.
// 15 magnifications means that the highest mag would be something like [32768, 32768, 1024].
const MAX_SUPPORTED_MAGNIFICATION_COUNT = 15;
// From that, we calculate the theoretical maximum zoom value. The dataset scale is taken into account,
// because the entire scene is scaled with that.
const maxSupportedZoomValue = 2 ** MAX_SUPPORTED_MAGNIFICATION_COUNT * Math.max(...datasetScale);
// Since the viewports can be quite large, it can happen that even a zoom value of 1 is not feasible.
// That's why we start the search with a smaller value than 1. We use the ZOOM_STEP_INTERVAL factor
// to ensure that the calculated thresholds correspond to the normal zoom behavior.
let maxZoomValue = 1 / ZOOM_STEP_INTERVAL ** 20;
const ZOOM_IN_START_EXPONENT = 20;
let currentMaxZoomValue = 1 / ZOOM_STEP_INTERVAL ** ZOOM_IN_START_EXPONENT;
const maximumIterationCount =
Math.log(maxSupportedZoomValue) / Math.log(ZOOM_STEP_INTERVAL) + ZOOM_IN_START_EXPONENT;

let currentIterationCount = 0;
let currentResolutionIndex = 0;
const maxZoomValueThresholds = [];

while (
currentIterationCount < maximumIterationCount &&
currentResolutionIndex < resolutions.length
) {
const nextZoomValue = maxZoomValue * ZOOM_STEP_INTERVAL;
const nextZoomValue = currentMaxZoomValue * ZOOM_STEP_INTERVAL;
const nextCapacity = calculateTotalBucketCountForZoomLevel(
viewMode,
loadingStrategy,
Expand All @@ -164,11 +175,11 @@ export function _getMaximumZoomForAllResolutions(
);

if (nextCapacity > maximumCapacity) {
maxZoomValueThresholds.push(maxZoomValue);
maxZoomValueThresholds.push(currentMaxZoomValue);
currentResolutionIndex++;
}

maxZoomValue = nextZoomValue;
currentMaxZoomValue = nextZoomValue;
currentIterationCount++;
}

Expand Down