Skip to content
Draft
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 frontend/javascripts/admin/rest_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1961,6 +1961,7 @@ export function computeAdHocMesh(
cubeSize: V3.toArray(V3.add(cubeSize, [1, 1, 1])), //cubeSize is in target mag
// Name and type of mapping to apply before building mesh (optional)
mapping: mappingName,
// todop: is this supposed to be the original scale factor?
voxelSizeFactorInUnit: scaleFactor,
mag,
...rest,
Expand Down
81 changes: 52 additions & 29 deletions frontend/javascripts/libs/format_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import utc from "dayjs/plugin/utc";
import weekday from "dayjs/plugin/weekday";
import * as Utils from "libs/utils";
import _ from "lodash";
import { LongUnitToShortUnitMap, UnitShort, type Vector3, type Vector6 } from "viewer/constants";
import {
LongUnitToShortUnitMap,
UnitShort,
type Vector3,
type Vector6,
ShortUnitToLongUnitMap,
} from "viewer/constants";
import { Unicode } from "viewer/constants";

import type { Duration } from "dayjs/plugin/duration";
Expand Down Expand Up @@ -143,6 +149,23 @@ export function formatScale(scale: VoxelSize | null | undefined, roundTo: number
if (scale == null) {
return "";
}
const optimizedScale = optimizeScaleUnitInVoxelSize(scale, roundTo);
const { factor, unit } = optimizedScale;
const scaleInNmRounded = Utils.map3((value) => Utils.roundTo(value, roundTo), factor);
return `${scaleInNmRounded.join(ThinSpace + MultiplicationSymbol + ThinSpace)} ${unit}³/voxel`;
}

export function optimizeScaleUnitInVoxelSize(
scale: VoxelSize,
decimalPrecision: number = 1,
): VoxelSize {
/*
* Changes the unit in VoxelSize so that it is well suited to
* the values in the scale factor.
*/
if (scale == null) {
return scale;
}
const scaleFactor = scale.factor;
const smallestScaleFactor = Math.min(...scaleFactor);
const unitDimension = { unit: LongUnitToShortUnitMap[scale.unit], dimension: 1 };
Expand All @@ -151,13 +174,13 @@ export function formatScale(scale: VoxelSize | null | undefined, roundTo: number
unitDimension,
nmFactorToUnit,
false,
roundTo,
);
const scaleInNmRounded = Utils.map3(
(value) => Utils.roundTo(value / conversionFactor, roundTo),
scaleFactor,
decimalPrecision,
);
return `${scaleInNmRounded.join(ThinSpace + MultiplicationSymbol + ThinSpace)} ${newUnit}³/voxel`;
const adaptedScale = Utils.map3((value) => value / conversionFactor, scaleFactor);
return {
factor: adaptedScale,
unit: ShortUnitToLongUnitMap[newUnit],
};
}

function toOptionalFixed(num: number, decimalPrecision: number): string {
Expand Down Expand Up @@ -193,24 +216,24 @@ function formatNumberInUnit(
}

export const nmFactorToUnit = new Map([
[1e-15, "ym"],
[1e-12, "zm"],
[1e-9, "am"],
[1e-6, "fm"],
[1e-3, "pm"],
[1, "nm"],
[1e3, "µm"],
[1e6, "mm"],
[1e7, "cm"],
[1e9, "m"],
[1e12, "km"],
[1e15, "Mm"],
[1e18, "Gm"],
[1e21, "Tm"],
[1e24, "Pm"],
[1e27, "Em"],
[1e30, "Zm"],
[1e33, "Ym"],
[1e-15, UnitShort.ym],
[1e-12, UnitShort.zm],
[1e-9, UnitShort.am],
[1e-6, UnitShort.fm],
[1e-3, UnitShort.pm],
[1, UnitShort.nm],
[1e3, UnitShort.µm],
[1e6, UnitShort.mm],
[1e7, UnitShort.cm],
[1e9, UnitShort.m],
[1e12, UnitShort.km],
[1e15, UnitShort.Mm],
[1e18, UnitShort.Gm],
[1e21, UnitShort.Tm],
[1e24, UnitShort.Pm],
[1e27, UnitShort.Em],
[1e30, UnitShort.Zm],
[1e33, UnitShort.Ym],
]);

// Accepts a length that is interpreted in the given unit and returns a string
Expand Down Expand Up @@ -345,7 +368,7 @@ export function formatCountToDataAmountUnit(
);
}

const getSortedFactorsAndUnits = _.memoize((unitMap: Map<number, string>) =>
const getSortedFactorsAndUnits = _.memoize(<T extends string>(unitMap: Map<number, T>) =>
Array.from(unitMap.entries()).sort((a, b) => a[0] - b[0]),
);

Expand All @@ -356,13 +379,13 @@ function adjustUnitToDimension(unit: UnitShort | ByteUnit, dimension: number): s
return dimension === 1 ? unit : dimension === 2 ? `${unit}²` : `${unit}³`;
}

function findBestUnitForFormatting(
function findBestUnitForFormatting<T extends string>(
number: number,
{ unit, dimension }: UnitDimension,
unitMap: Map<number, string>,
unitMap: Map<number, T>,
preferShorterDecimals: boolean = false,
decimalPrecision: number = 1,
): [number, string] {
): [number, T] {
const isLengthUnit = unit in UnitsMap;
let factorToNextSmallestCommonUnit = 1;
if (isLengthUnit) {
Expand Down
3 changes: 3 additions & 0 deletions frontend/javascripts/test/reducers/flycam_reducer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const initialState = {
dataLayers: [{ name: "color", type: "color", additionalCoordinates: [] }],
},
},
datasetConfiguration: {
nativelyRenderedLayerName: null,
},
userConfiguration: {
sphericalCapRadius: 100,
dynamicSpaceDirection: true,
Expand Down
24 changes: 12 additions & 12 deletions frontend/javascripts/test/shaders/shader_syntax.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ describe("Shader syntax", () => {
orderedColorLayerNames: ["color_layer_1", "color_layer_2"],
segmentationLayerNames: [],
magnificationsCount: mags.length,
voxelSizeFactor: [1, 1, 1],
// voxelSizeFactor: [1, 1, 1],
isOrthogonal: true,
voxelSizeFactorInverted: [1, 1, 1],
// voxelSizeFactorInverted: [1, 1, 1],
useInterpolation: false,
tpsTransformPerLayer: {},
});
Expand Down Expand Up @@ -98,10 +98,10 @@ describe("Shader syntax", () => {
orderedColorLayerNames: ["color_layer_1", "color_layer_2"],
segmentationLayerNames: ["segmentationLayer"],
magnificationsCount: mags.length,
voxelSizeFactor: [1, 1, 1],
// voxelSizeFactor: [1, 1, 1],
isOrthogonal: true,
useInterpolation: false,
voxelSizeFactorInverted: [1, 1, 1],
// voxelSizeFactorInverted: [1, 1, 1],
tpsTransformPerLayer: {},
});
parser.parse(code);
Expand Down Expand Up @@ -144,10 +144,10 @@ describe("Shader syntax", () => {
orderedColorLayerNames: ["color_layer_1", "color_layer_2"],
segmentationLayerNames: ["segmentationLayer"],
magnificationsCount: mags.length,
voxelSizeFactor: [1, 1, 1],
// voxelSizeFactor: [1, 1, 1],
isOrthogonal: true,
useInterpolation: true,
voxelSizeFactorInverted: [1, 1, 1],
// voxelSizeFactorInverted: [1, 1, 1],
tpsTransformPerLayer: {},
});

Expand Down Expand Up @@ -182,10 +182,10 @@ describe("Shader syntax", () => {
orderedColorLayerNames: ["color_layer_1", "color_layer_2"],
segmentationLayerNames: [],
magnificationsCount: mags.length,
voxelSizeFactor: [1, 1, 1],
// voxelSizeFactor: [1, 1, 1],
isOrthogonal: false,
useInterpolation: false,
voxelSizeFactorInverted: [1, 1, 1],
// voxelSizeFactorInverted: [1, 1, 1],
tpsTransformPerLayer: {},
});
parser.parse(code);
Expand Down Expand Up @@ -228,10 +228,10 @@ describe("Shader syntax", () => {
orderedColorLayerNames: ["color_layer_1", "color_layer_2"],
segmentationLayerNames: ["segmentationLayer"],
magnificationsCount: mags.length,
voxelSizeFactor: [1, 1, 1],
// voxelSizeFactor: [1, 1, 1],
isOrthogonal: false,
useInterpolation: true,
voxelSizeFactorInverted: [1, 1, 1],
// voxelSizeFactorInverted: [1, 1, 1],
tpsTransformPerLayer: {},
});
parser.parse(code);
Expand Down Expand Up @@ -265,10 +265,10 @@ describe("Shader syntax", () => {
orderedColorLayerNames: ["color_layer_1", "color_layer_2"],
segmentationLayerNames: [],
magnificationsCount: mags.length,
voxelSizeFactor: [1, 1, 1],
// voxelSizeFactor: [1, 1, 1],
isOrthogonal: true,
useInterpolation: false,
voxelSizeFactorInverted: [1, 1, 1],
// voxelSizeFactorInverted: [1, 1, 1],
tpsTransformPerLayer: {},
});
parser.parse(code);
Expand Down
17 changes: 13 additions & 4 deletions frontend/javascripts/viewer/api/api_latest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ import {
getMappingInfoOrNull,
getVisibleSegmentationLayer,
} from "viewer/model/accessors/dataset_accessor";
import { flatToNestedMatrix } from "viewer/model/accessors/dataset_layer_transformation_accessor";
import {
flatToNestedMatrix,
getTransformedVoxelSize,
} from "viewer/model/accessors/dataset_layer_transformation_accessor";
import {
getActiveMagIndexForLayer,
getAdditionalCoordinatesAsString,
Expand Down Expand Up @@ -1260,7 +1263,10 @@ class TracingApi {
throw new Error(`Tree with id ${treeId} not found.`);
}

const voxelSizeFactor = state.dataset.dataSource.scale.factor;
const voxelSizeFactor = getTransformedVoxelSize(
state.dataset,
state.datasetConfiguration.nativelyRenderedLayerName,
).factor;
// Pre-allocate vectors
let lengthInUnitAcc = 0;
let lengthInVxAcc = 0;
Expand Down Expand Up @@ -1323,7 +1329,11 @@ class TracingApi {
throw new Error("The nodes are not within the same tree.");
}

const voxelSizeFactor = Store.getState().dataset.dataSource.scale.factor;
const state = Store.getState();
const voxelSizeFactor = getTransformedVoxelSize(
state.dataset,
state.datasetConfiguration.nativelyRenderedLayerName,
).factor;
// We use the Dijkstra algorithm to get the shortest path between the nodes.
const distanceMap: Record<number, number> = {};
// The distance map is also maintained in voxel space. This information is only
Expand All @@ -1347,7 +1357,6 @@ class TracingApi {
});
priorityQueue.queue([sourceNodeId, 0]);

const state = Store.getState();
const getPos = (node: Readonly<MutableNode>) => getNodePosition(node, state);

while (priorityQueue.length > 0) {
Expand Down
6 changes: 6 additions & 0 deletions frontend/javascripts/viewer/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import _ from "lodash";
import { Euler, Matrix4 } from "three";
export type AdditionalCoordinate = { name: string; value: number };

Expand Down Expand Up @@ -495,6 +496,11 @@ export const LongUnitToShortUnitMap: Record<UnitLong, UnitShort> = {
[UnitLong.pc]: UnitShort.pc,
};

export const ShortUnitToLongUnitMap = _.invert(LongUnitToShortUnitMap) as Record<
UnitShort,
UnitLong
>;

export const AllUnits = Object.values(UnitLong);

export enum AnnotationTypeFilterEnum {
Expand Down
17 changes: 14 additions & 3 deletions frontend/javascripts/viewer/controller/camera_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
OrthoViews,
} from "viewer/constants";
import { getDatasetExtentInUnit } from "viewer/model/accessors/dataset_accessor";
import { getTransformedVoxelSize } from "viewer/model/accessors/dataset_layer_transformation_accessor";
import { getPosition, getRotationInRadian } from "viewer/model/accessors/flycam_accessor";
import {
getInputCatcherAspectRatio,
Expand Down Expand Up @@ -132,7 +133,11 @@ class CameraController extends React.PureComponent<Props> {
updateCamViewport(inputCatcherRects?: OrthoViewRects): void {
const state = Store.getState();
const { clippingDistance } = state.userConfiguration;
const scaleFactor = getBaseVoxelInUnit(state.dataset.dataSource.scale.factor);
const transformedScaleFactor = getTransformedVoxelSize(
state.dataset,
state.datasetConfiguration.nativelyRenderedLayerName,
).factor;
const scaleFactor = getBaseVoxelInUnit(transformedScaleFactor);

for (const planeId of OrthoViewValuesWithoutTDView) {
const [width, height] = getPlaneExtentInVoxelFromStore(
Expand Down Expand Up @@ -176,7 +181,10 @@ class CameraController extends React.PureComponent<Props> {
const state = Store.getState();
const globalPosition = getPosition(state.flycam);
// camera position's unit is nm, so convert it.
const cameraPosition = voxelToUnit(state.dataset.dataSource.scale, globalPosition);
const cameraPosition = voxelToUnit(
getTransformedVoxelSize(state.dataset, state.datasetConfiguration.nativelyRenderedLayerName),
globalPosition,
);
// Now set rotation for all cameras respecting the base rotation of each camera.
const globalRotation = getRotationInRadian(state.flycam);
this.flycamRotationEuler.set(globalRotation[0], globalRotation[1], globalRotation[2], "ZYX");
Expand Down Expand Up @@ -258,7 +266,10 @@ export function rotate3DViewTo(
const state = Store.getState();
const { dataset } = state;
const { tdCamera } = state.viewModeData.plane;
const flycamPos = voxelToUnit(dataset.dataSource.scale, getPosition(state.flycam));
const flycamPos = voxelToUnit(
getTransformedVoxelSize(dataset, state.datasetConfiguration.nativelyRenderedLayerName),
getPosition(state.flycam),
);
const flycamRotation = getRotationInRadian(state.flycam);
const datasetExtent = getDatasetExtentInUnit(dataset);
// This distance ensures that the 3D camera is so far "in the back" that all elements in the scene
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import _ from "lodash";
import type { BoundingBoxMinMaxType } from "types/bounding_box";
import type { OrthoView, Point2, Vector2, Vector3 } from "viewer/constants";
import getSceneController from "viewer/controller/scene_controller_provider";
import { getTransformedVoxelSize } from "viewer/model/accessors/dataset_layer_transformation_accessor";
import { getSomeTracing } from "viewer/model/accessors/tracing_accessor";
import {
calculateGlobalDelta,
Expand Down Expand Up @@ -169,7 +170,11 @@ export function getClosestHoveredBoundingBox(

const { userBoundingBoxes } = getSomeTracing(state.annotation);
const indices = Dimension.getIndices(plane);
const planeRatio = getBaseVoxelFactorsInUnit(state.dataset.dataSource.scale);
const transformedVoxelSize = getTransformedVoxelSize(
state.dataset,
state.datasetConfiguration.nativelyRenderedLayerName,
);
const planeRatio = getBaseVoxelFactorsInUnit(transformedVoxelSize);
const thirdDim = indices[2];
const zoomedMaxDistanceToSelection = MAX_DISTANCE_TO_SELECTION * state.flycam.zoomStep;
let currentNearestDistance = zoomedMaxDistanceToSelection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { OrthoBaseRotations, OrthoViewToNumber, OrthoViews } from "viewer/consta
import { getClosestHoveredBoundingBox } from "viewer/controller/combinations/bounding_box_handlers";
import getSceneController from "viewer/controller/scene_controller_provider";
import { getEnabledColorLayers } from "viewer/model/accessors/dataset_accessor";
import { getTransformedVoxelSize } from "viewer/model/accessors/dataset_layer_transformation_accessor";
import {
getActiveMagIndicesForLayers,
getFlycamRotationWithAppendedRotation,
Expand Down Expand Up @@ -203,7 +204,11 @@ export function moveNode(
const vectorRotated = movementVector.set(...vector).applyMatrix4(flycamRotationMatrix);

const zoomFactor = state.flycam.zoomStep;
const scaleFactor = getBaseVoxelFactorsInUnit(state.dataset.dataSource.scale);
const transformedVoxelSize = getTransformedVoxelSize(
state.dataset,
state.datasetConfiguration.nativelyRenderedLayerName,
);
const scaleFactor = getBaseVoxelFactorsInUnit(transformedVoxelSize);

const op = (val: number) => {
if (useFloat || isFlycamRotated) {
Expand Down
Loading
Loading