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

feat(vtkPiecewiseWidget): Support vertical movement of points #488

Merged
merged 4 commits into from
Nov 14, 2023
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
8 changes: 7 additions & 1 deletion src/components/VolumeRendering.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
watch,
watchEffect,
} from 'vue';
import { onKeyDown, onKeyUp } from '@vueuse/core';
import { PresetNameList } from '@/src/vtk/ColorMaps';
import vtkPiecewiseWidget from '@/src/vtk/PiecewiseWidget';
import type { vtkSubscription } from '@kitware/vtk.js/interfaces';
Expand Down Expand Up @@ -119,6 +120,7 @@ export default defineComponent({
{
mode,
shift: pwfWidget.getOpacityPointShift(),
shiftAlpha: pwfWidget.getOpacityValueShift(),
}
);
}
Expand Down Expand Up @@ -227,9 +229,10 @@ export default defineComponent({
const points = getShiftedOpacityFromPreset(
opFunc.preset,
opFunc.mappingRange,
0,
0
);
pwfWidget.setOpacityPoints(points, opFunc.shift);
pwfWidget.setOpacityPoints(points, opFunc.shift, opFunc.shiftAlpha);
}
},
{ immediate: true }
Expand Down Expand Up @@ -279,6 +282,9 @@ export default defineComponent({
const rangeShift = ref(0);
const rangeWidth = ref(0);

onKeyDown('Control', () => pwfWidget.setShiftOpacityValues(true));
onKeyUp('Control', () => pwfWidget.setShiftOpacityValues(false));

// reset case
watch(
[selectedPreset, currentImageID],
Expand Down
3 changes: 2 additions & 1 deletion src/components/VtkThreeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ function useColoringEffect(
const opacityPoints = getShiftedOpacityFromPreset(
opacityFunc.preset,
opacityFunc.mappingRange,
opacityFunc.shift
opacityFunc.shift,
opacityFunc.shiftAlpha
);
if (opacityPoints) {
pwf.setPoints(opacityPoints);
Expand Down
3 changes: 2 additions & 1 deletion src/components/VtkTwoView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,8 @@ export default defineComponent({
const opacityPoints = getShiftedOpacityFromPreset(
opFunc.preset,
opFunc.mappingRange,
opFunc.shift
opFunc.shift,
opFunc.shiftAlpha
);
if (opacityPoints) {
pwf.setPoints(opacityPoints);
Expand Down
1 change: 1 addition & 0 deletions src/io/state-file/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ const OpacityPoints = z.object({
mode: z.literal(vtkPiecewiseFunctionProxy.Mode.Points),
preset: z.string(),
shift: z.number(),
shiftAlpha: z.number(),
mappingRange: z.tuple([z.number(), z.number()]),
}) satisfies z.ZodType<OpacityPoints>;

Expand Down
1 change: 1 addition & 0 deletions src/types/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface OpacityPoints {
// base preset that has the opacity points
preset: string;
shift: number;
shiftAlpha: number;
mappingRange: [number, number];
}

Expand Down
12 changes: 10 additions & 2 deletions src/utils/vtk-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ export function getCSSCoordinatesFromEvent(eventData: any) {
export function getShiftedOpacityFromPreset(
presetName: string,
effectiveRange: [number, number],
shift: number
shift: number,
shiftAlpha: number
) {
const preset = vtkColorMaps.getPresetByName(presetName);
if (preset.OpacityPoints) {
Expand All @@ -128,7 +129,13 @@ export function getShiftedOpacityFromPreset(

const [xmin, xmax] = effectiveRange;
const width = xmax - xmin;
return points.map(([x, y]) => [(x - xmin) / width + shift, y]);
return points.map(([x, y]) => {
// Non-zero values should be affected by shift
// but preset values of zero should not
const shifted = y && y - shiftAlpha;
const yVal = Math.max(Math.min(shifted, 1), 0);
return [(x - xmin) / width + shift, yVal];
});
}
return null;
}
Expand All @@ -146,6 +153,7 @@ export function getOpacityFunctionFromPreset(
mode: vtkPiecewiseFunctionProxy.Mode.Points,
preset: presetName,
shift: 0,
shiftAlpha: 0,
};
}
return {
Expand Down
45 changes: 36 additions & 9 deletions src/vtk/PiecewiseWidget/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ export const ADJUST_POSITION_CURSOR = '-webkit-grab';
* Assumes normalized x/y coordinate points.
*/

export function samplePiecewiseLinear(points, shift = 0, samples = 256) {
export function samplePiecewiseLinear(
points,
shift = 0,
shiftAlpha = 0,
samples = 256
) {
const filledPoints = [...points];
// set endpoints to drop to 0
filledPoints.push([points[0][0], 0]);
Expand Down Expand Up @@ -47,7 +52,11 @@ export function samplePiecewiseLinear(points, shift = 0, samples = 256) {
} else if (slope === -Infinity) {
sampledPoints.push(0);
} else {
sampledPoints.push(slope * (sx - p1[0]) + p1[1]);
// Non-zero values should be affected by shift
// but original values of zero should not
let value = slope * (sx - p1[0]) + p1[1];
value = value && value - shiftAlpha;
sampledPoints.push(value);
}
}
}
Expand All @@ -66,6 +75,7 @@ function vtkPiecewiseWidget(publicAPI, model) {
model.pwMode = Mode.Gaussians;
model.opacityPoints = [];
model.opacityPointShift = 0;
model.opacityValueShift = 0;

publicAPI.setGaussiansMode = () => {
model.pwMode = Mode.Gaussians;
Expand All @@ -82,8 +92,13 @@ function vtkPiecewiseWidget(publicAPI, model) {
publicAPI.getMode = () => model.pwMode;

publicAPI.shiftPosition = (coords, meta) => {
model.opacityPointShift =
meta.originalOpacityPointShift + coords[0] - meta.originalXY[0];
if (model.shiftOpacityValues) {
model.opacityValueShift =
meta.originalOpacityValueShift + coords[1] - meta.originalXY[1];
} else {
model.opacityPointShift =
meta.originalOpacityPointShift + coords[0] - meta.originalXY[0];
}
return true;
};

Expand Down Expand Up @@ -122,6 +137,7 @@ function vtkPiecewiseWidget(publicAPI, model) {
model.dragAction = {
originalXY: mouseCoords,
originalOpacityPointShift: model.opacityPointShift,
originalOpacityValueShift: model.opacityValueShift,
};

return true;
Expand All @@ -140,7 +156,8 @@ function vtkPiecewiseWidget(publicAPI, model) {
if (publicAPI.shiftPosition(normCoords, model.dragAction)) {
model.opacities = samplePiecewiseLinear(
model.opacityPoints,
model.opacityPointShift
model.opacityPointShift,
model.opacityValueShift
);
publicAPI.invokeOpacityChange(publicAPI, true);
}
Expand All @@ -149,22 +166,27 @@ function vtkPiecewiseWidget(publicAPI, model) {
return true;
};

publicAPI.setOpacityPoints = (points, shift = 0) => {
publicAPI.setOpacityPoints = (points, shift = 0, shiftAlpha = 0) => {
if (publicAPI.isModePoints()) {
// deep copy
model.opacityPoints = points.map((p) => [p[0], p[1]]);
model.opacityPointShift = shift;
model.opacityValueShift = shiftAlpha;

model.opacities = samplePiecewiseLinear(
model.opacityPoints,
model.opacityPointShift
model.opacityPointShift,
model.opacityValueShift
);
publicAPI.modified();
}
};

publicAPI.getEffectiveOpacityPoints = () =>
model.opacityPoints.map((p) => [p[0] + model.opacityPointShift, p[1]]);
model.opacityPoints.map((p) => [
p[0] + model.opacityPointShift,
p[1] + model.opacityValueShift,
]);

publicAPI.render = () => {
if (publicAPI.isModePoints()) {
Expand All @@ -188,7 +210,12 @@ export function extend(publicAPI, model, initialValues = {}) {

vtkPiecewiseGaussianWidget.extend(publicAPI, model, initialValues);

macro.setGet(publicAPI, model, ['opacityPoints', 'opacityPointShift']);
macro.setGet(publicAPI, model, [
'opacityPoints',
'opacityPointShift',
'opacityValueShift',
'shiftOpacityValues',
]);

// Object specific methods
vtkPiecewiseWidget(publicAPI, model);
Expand Down
Loading