copper3d 3.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +195 -28
- package/dist/Utils/segmentation/CommToolsData.d.ts +24 -9
- package/dist/Utils/segmentation/CommToolsData.js +65 -139
- package/dist/Utils/segmentation/CommToolsData.js.map +1 -1
- package/dist/Utils/segmentation/DragOperator.d.ts +10 -2
- package/dist/Utils/segmentation/DragOperator.js +14 -4
- package/dist/Utils/segmentation/DragOperator.js.map +1 -1
- package/dist/Utils/segmentation/DrawToolCore.d.ts +23 -16
- package/dist/Utils/segmentation/DrawToolCore.js +218 -401
- package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
- package/dist/Utils/segmentation/NrrdTools.d.ts +152 -10
- package/dist/Utils/segmentation/NrrdTools.js +599 -202
- package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
- package/dist/Utils/segmentation/core/MaskVolume.d.ts +1 -1
- package/dist/Utils/segmentation/core/MaskVolume.js +24 -3
- package/dist/Utils/segmentation/core/MaskVolume.js.map +1 -1
- package/dist/Utils/segmentation/core/UndoManager.d.ts +1 -1
- package/dist/Utils/segmentation/core/UndoManager.js +1 -1
- package/dist/Utils/segmentation/core/index.d.ts +0 -2
- package/dist/Utils/segmentation/core/index.js +0 -1
- package/dist/Utils/segmentation/core/index.js.map +1 -1
- package/dist/Utils/segmentation/core/types.js +24 -24
- package/dist/Utils/segmentation/core/types.js.map +1 -1
- package/dist/Utils/segmentation/coreTools/GuiState.d.ts +22 -0
- package/dist/Utils/segmentation/coreTools/GuiState.js +48 -0
- package/dist/Utils/segmentation/coreTools/GuiState.js.map +1 -0
- package/dist/Utils/segmentation/coreTools/NrrdState.d.ts +25 -0
- package/dist/Utils/segmentation/coreTools/NrrdState.js +85 -0
- package/dist/Utils/segmentation/coreTools/NrrdState.js.map +1 -0
- package/dist/Utils/segmentation/coreTools/coreType.d.ts +88 -62
- package/dist/Utils/segmentation/coreTools/coreType.js.map +1 -1
- package/dist/Utils/segmentation/coreTools/divControlTools.js +1 -1
- package/dist/Utils/segmentation/coreTools/divControlTools.js.map +1 -1
- package/dist/Utils/segmentation/coreTools/gui.d.ts +12 -12
- package/dist/Utils/segmentation/coreTools/gui.js +81 -107
- package/dist/Utils/segmentation/coreTools/gui.js.map +1 -1
- package/dist/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -1
- package/dist/Utils/segmentation/eventRouter/EventRouter.js +15 -10
- package/dist/Utils/segmentation/eventRouter/EventRouter.js.map +1 -1
- package/dist/Utils/segmentation/eventRouter/types.d.ts +3 -3
- package/dist/Utils/segmentation/tools/BaseTool.d.ts +8 -5
- package/dist/Utils/segmentation/tools/BaseTool.js +1 -2
- package/dist/Utils/segmentation/tools/BaseTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/CrosshairTool.js +25 -25
- package/dist/Utils/segmentation/tools/CrosshairTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/DragSliceTool.d.ts +2 -0
- package/dist/Utils/segmentation/tools/DragSliceTool.js +63 -53
- package/dist/Utils/segmentation/tools/DragSliceTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/DrawingTool.d.ts +93 -0
- package/dist/Utils/segmentation/tools/DrawingTool.js +222 -0
- package/dist/Utils/segmentation/tools/DrawingTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/EraserTool.js +8 -8
- package/dist/Utils/segmentation/tools/EraserTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/ImageStoreHelper.d.ts +11 -28
- package/dist/Utils/segmentation/tools/ImageStoreHelper.js +39 -82
- package/dist/Utils/segmentation/tools/ImageStoreHelper.js.map +1 -1
- package/dist/Utils/segmentation/tools/PanTool.d.ts +53 -0
- package/dist/Utils/segmentation/tools/PanTool.js +90 -0
- package/dist/Utils/segmentation/tools/PanTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/SphereTool.d.ts +208 -1
- package/dist/Utils/segmentation/tools/SphereTool.js +456 -45
- package/dist/Utils/segmentation/tools/SphereTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/ZoomTool.js +3 -3
- package/dist/Utils/segmentation/tools/ZoomTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/index.d.ts +6 -2
- package/dist/Utils/segmentation/tools/index.js +4 -1
- package/dist/Utils/segmentation/tools/index.js.map +1 -1
- package/dist/bundle.esm.js +2452 -1492
- package/dist/bundle.umd.js +2452 -1492
- package/dist/index.d.ts +6 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/Utils/segmentation/CommToolsData.d.ts +24 -9
- package/dist/types/Utils/segmentation/DragOperator.d.ts +10 -2
- package/dist/types/Utils/segmentation/DrawToolCore.d.ts +23 -16
- package/dist/types/Utils/segmentation/NrrdTools.d.ts +152 -10
- package/dist/types/Utils/segmentation/core/MaskVolume.d.ts +1 -1
- package/dist/types/Utils/segmentation/core/UndoManager.d.ts +1 -1
- package/dist/types/Utils/segmentation/core/index.d.ts +0 -2
- package/dist/types/Utils/segmentation/coreTools/GuiState.d.ts +22 -0
- package/dist/types/Utils/segmentation/coreTools/NrrdState.d.ts +25 -0
- package/dist/types/Utils/segmentation/coreTools/coreType.d.ts +88 -62
- package/dist/types/Utils/segmentation/coreTools/gui.d.ts +12 -12
- package/dist/types/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -1
- package/dist/types/Utils/segmentation/eventRouter/types.d.ts +3 -3
- package/dist/types/Utils/segmentation/tools/BaseTool.d.ts +8 -5
- package/dist/types/Utils/segmentation/tools/DragSliceTool.d.ts +2 -0
- package/dist/types/Utils/segmentation/tools/DrawingTool.d.ts +93 -0
- package/dist/types/Utils/segmentation/tools/ImageStoreHelper.d.ts +11 -28
- package/dist/types/Utils/segmentation/tools/PanTool.d.ts +53 -0
- package/dist/types/Utils/segmentation/tools/SphereTool.d.ts +208 -1
- package/dist/types/Utils/segmentation/tools/index.d.ts +6 -2
- package/dist/types/index.d.ts +6 -3
- package/package.json +1 -1
- package/dist/Utils/segmentation/core/MigrationUtils.d.ts +0 -97
- package/dist/Utils/segmentation/core/MigrationUtils.js +0 -163
- package/dist/Utils/segmentation/core/MigrationUtils.js.map +0 -1
- package/dist/types/Utils/segmentation/core/MigrationUtils.d.ts +0 -97
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { setupGui } from "./coreTools/gui";
|
|
2
|
-
import { autoFocusDiv } from "./coreTools/divControlTools";
|
|
2
|
+
import { autoFocusDiv, enableDownload } from "./coreTools/divControlTools";
|
|
3
3
|
import { DragOperator } from "./DragOperator";
|
|
4
4
|
import { DrawToolCore } from "./DrawToolCore";
|
|
5
|
-
import { MaskVolume, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss } from "./core";
|
|
5
|
+
import { MaskVolume, CHANNEL_HEX_COLORS, MASK_CHANNEL_COLORS, rgbaToHex, rgbaToCss } from "./core";
|
|
6
|
+
import { SPHERE_CHANNEL_MAP, SPHERE_LABELS } from "./tools/SphereTool";
|
|
6
7
|
/**
|
|
7
8
|
* Core NRRD annotation tool for medical image segmentation.
|
|
8
9
|
*
|
|
@@ -21,15 +22,19 @@ export class NrrdTools extends DrawToolCore {
|
|
|
21
22
|
this.initState = true;
|
|
22
23
|
this._sliceRAFId = null;
|
|
23
24
|
this._pendingSliceStep = 0;
|
|
25
|
+
/** Whether calculator mode is active (not part of gui_states interface) */
|
|
26
|
+
this._calculatorActive = false;
|
|
27
|
+
/** Stored closure callbacks from gui.ts setupGui() */
|
|
28
|
+
this.guiCallbacks = null;
|
|
24
29
|
this.container = container;
|
|
25
|
-
this.protectedData.previousDrawingImage =
|
|
26
|
-
this.protectedData.ctxes.emptyCtx.createImageData(1, 1);
|
|
27
30
|
this.init();
|
|
28
31
|
this.dragOperator = new DragOperator(this.container, this.nrrd_states, this.gui_states, this.protectedData, this.drawingPrameters, this.setSyncsliceNum.bind(this), this.setIsDrawFalse.bind(this), this.flipDisplayImageByAxis.bind(this), this.setEmptyCanvasSize.bind(this), this.getOrCreateSliceBuffer.bind(this), this.renderSliceToCanvas.bind(this));
|
|
29
32
|
// Inject EventRouter into DragOperator for centralized event handling
|
|
30
33
|
if (this.eventRouter) {
|
|
31
34
|
this.dragOperator.setEventRouter(this.eventRouter);
|
|
32
35
|
}
|
|
36
|
+
// Wire sphere overlay refresh callback into DragOperator → DragSliceTool
|
|
37
|
+
this.dragOperator.setRefreshSphereOverlay(() => this.refreshSphereOverlay());
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* core function for drag slices
|
|
@@ -83,8 +88,8 @@ export class NrrdTools extends DrawToolCore {
|
|
|
83
88
|
protectedData: this.protectedData,
|
|
84
89
|
removeDragMode: this.dragOperator.removeDragMode,
|
|
85
90
|
configDragMode: this.dragOperator.configDragMode,
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
clearActiveLayer: this.clearActiveLayer,
|
|
92
|
+
clearActiveSlice: this.clearActiveSlice,
|
|
88
93
|
updateSlicesContrast: this.updateSlicesContrast,
|
|
89
94
|
setMainAreaSize: this.setMainAreaSize,
|
|
90
95
|
resetPaintAreaUIPosition: this.resetPaintAreaUIPosition,
|
|
@@ -94,81 +99,361 @@ export class NrrdTools extends DrawToolCore {
|
|
|
94
99
|
resetLayerCanvas: this.resetLayerCanvas,
|
|
95
100
|
redrawDisplayCanvas: this.redrawDisplayCanvas,
|
|
96
101
|
flipDisplayImageByAxis: this.flipDisplayImageByAxis,
|
|
97
|
-
filterDrawedImage: this.filterDrawedImage,
|
|
98
102
|
setEmptyCanvasSize: this.setEmptyCanvasSize,
|
|
99
|
-
|
|
103
|
+
syncLayerSliceData: this.syncLayerSliceData,
|
|
100
104
|
drawImageOnEmptyImage: this.drawImageOnEmptyImage,
|
|
101
|
-
storeEachLayerImage: this.storeEachLayerImage,
|
|
102
|
-
storeImageToLayer: this.storeImageToLayer,
|
|
103
105
|
getRestLayer: this.getRestLayer,
|
|
104
106
|
setIsDrawFalse: this.setIsDrawFalse,
|
|
105
107
|
getVolumeForLayer: this.getVolumeForLayer.bind(this),
|
|
108
|
+
undoLastPainting: this.undoLastPainting.bind(this),
|
|
109
|
+
redoLastPainting: this.redoLastPainting.bind(this),
|
|
110
|
+
resetZoom: () => this.executeAction("resetZoom"),
|
|
111
|
+
downloadCurrentMask: () => this.executeAction("downloadCurrentMask"),
|
|
106
112
|
};
|
|
107
113
|
this.guiParameterSettings = setupGui(guiOptions);
|
|
114
|
+
// Store closure callbacks for programmatic access (Phase 1 Task 1.2)
|
|
115
|
+
this.guiCallbacks = {
|
|
116
|
+
updatePencilState: this.guiParameterSettings.pencil.onChange,
|
|
117
|
+
updateEraserState: this.guiParameterSettings.eraser.onChange,
|
|
118
|
+
updateBrushAndEraserSize: this.guiParameterSettings.brushAndEraserSize.onChange,
|
|
119
|
+
updateSphereState: this.guiParameterSettings.sphere.onChange,
|
|
120
|
+
updateCalDistance: this.guiParameterSettings.activeSphereType.onChange,
|
|
121
|
+
updateWindowHigh: this.guiParameterSettings.windowHigh.onChange,
|
|
122
|
+
updateWindowLow: this.guiParameterSettings.windowLow.onChange,
|
|
123
|
+
finishContrastAdjustment: this.guiParameterSettings.windowHigh.onFinished,
|
|
124
|
+
};
|
|
108
125
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Sync guiParameterSettings with current volume metadata.
|
|
128
|
+
* Called internally when slices are loaded or switched.
|
|
129
|
+
*/
|
|
130
|
+
syncGuiParameterSettings() {
|
|
131
|
+
if (this.guiParameterSettings && this.protectedData.mainPreSlices) {
|
|
112
132
|
this.guiParameterSettings.windowHigh.value = this.guiParameterSettings.windowLow.value = this.protectedData.mainPreSlices.volume;
|
|
113
133
|
this.guiParameterSettings.windowHigh.max = this.guiParameterSettings.windowLow.max = this.protectedData.mainPreSlices.volume.max;
|
|
114
134
|
this.guiParameterSettings.windowHigh.min = this.guiParameterSettings.windowLow.min = this.protectedData.mainPreSlices.volume.min;
|
|
115
135
|
}
|
|
116
|
-
return {
|
|
117
|
-
guiState: this.gui_states,
|
|
118
|
-
guiSetting: this.guiParameterSettings,
|
|
119
|
-
};
|
|
120
136
|
}
|
|
121
137
|
// ── Layer & Channel Management API ─────────────────────────────────────
|
|
122
138
|
/**
|
|
123
139
|
* Set the active layer and update fillColor/brushColor to match the active channel.
|
|
124
140
|
*/
|
|
125
141
|
setActiveLayer(layerId) {
|
|
126
|
-
this.gui_states.layer = layerId;
|
|
142
|
+
this.gui_states.layerChannel.layer = layerId;
|
|
127
143
|
this.syncBrushColor();
|
|
128
144
|
}
|
|
129
145
|
/**
|
|
130
146
|
* Set the active channel (1-8) and update fillColor/brushColor.
|
|
131
147
|
*/
|
|
132
148
|
setActiveChannel(channel) {
|
|
133
|
-
this.gui_states.activeChannel = channel;
|
|
149
|
+
this.gui_states.layerChannel.activeChannel = channel;
|
|
134
150
|
this.syncBrushColor();
|
|
135
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Set the active sphere type for the SphereTool.
|
|
154
|
+
* Replaces direct mutation of `gui_states.activeSphereType`.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* nrrdTools.setActiveSphereType('nipple');
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
setActiveSphereType(type) {
|
|
162
|
+
this.gui_states.mode.activeSphereType = type;
|
|
163
|
+
// Apply color side-effect: update fillColor/brushColor from sphere channel map
|
|
164
|
+
const mapping = SPHERE_CHANNEL_MAP[type];
|
|
165
|
+
if (mapping) {
|
|
166
|
+
const volume = this.getVolumeForLayer(mapping.layer);
|
|
167
|
+
const color = volume
|
|
168
|
+
? rgbaToHex(volume.getChannelColor(mapping.channel))
|
|
169
|
+
: (CHANNEL_HEX_COLORS[mapping.channel] || '#00ff00');
|
|
170
|
+
this.gui_states.drawing.fillColor = color;
|
|
171
|
+
this.gui_states.drawing.brushColor = color;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get the currently active sphere type.
|
|
176
|
+
*/
|
|
177
|
+
getActiveSphereType() {
|
|
178
|
+
return this.gui_states.mode.activeSphereType;
|
|
179
|
+
}
|
|
180
|
+
// ── Phase 1: GUI API — Mode Management ──────────────────────────────────
|
|
181
|
+
/**
|
|
182
|
+
* Set the current tool mode. Handles deactivation of the previous mode
|
|
183
|
+
* and activation of the new mode, including all gui.ts side-effects.
|
|
184
|
+
*
|
|
185
|
+
* Replaces direct mutation of `guiSettings.value.guiState["pencil"]` etc.
|
|
186
|
+
* from Vue components.
|
|
187
|
+
*/
|
|
188
|
+
setMode(mode) {
|
|
189
|
+
if (!this.guiCallbacks)
|
|
190
|
+
return;
|
|
191
|
+
const prevSphere = this.gui_states.mode.sphere;
|
|
192
|
+
const prevCalculator = this._calculatorActive;
|
|
193
|
+
// Reset all mode flags
|
|
194
|
+
this.gui_states.mode.pencil = false;
|
|
195
|
+
this.gui_states.mode.eraser = false;
|
|
196
|
+
this.gui_states.mode.sphere = false;
|
|
197
|
+
this._calculatorActive = false;
|
|
198
|
+
// Activate new mode
|
|
199
|
+
switch (mode) {
|
|
200
|
+
case "pencil":
|
|
201
|
+
this.gui_states.mode.pencil = true;
|
|
202
|
+
this.guiCallbacks.updatePencilState();
|
|
203
|
+
break;
|
|
204
|
+
case "brush":
|
|
205
|
+
// brush = pencil off + eraser off (default brush mode)
|
|
206
|
+
this.guiCallbacks.updatePencilState();
|
|
207
|
+
break;
|
|
208
|
+
case "eraser":
|
|
209
|
+
this.gui_states.mode.eraser = true;
|
|
210
|
+
this.guiCallbacks.updateEraserState();
|
|
211
|
+
break;
|
|
212
|
+
case "sphere":
|
|
213
|
+
this.gui_states.mode.sphere = true;
|
|
214
|
+
break;
|
|
215
|
+
case "calculator":
|
|
216
|
+
this.gui_states.mode.sphere = true;
|
|
217
|
+
this._calculatorActive = true;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
// Handle sphere mode transitions
|
|
221
|
+
if (prevSphere && !this.gui_states.mode.sphere) {
|
|
222
|
+
this.guiCallbacks.updateSphereState(); // exits sphere mode
|
|
223
|
+
}
|
|
224
|
+
if (!prevSphere && this.gui_states.mode.sphere) {
|
|
225
|
+
this.guiCallbacks.updateSphereState(); // enters sphere mode
|
|
226
|
+
}
|
|
227
|
+
// Handle calculator exit side-effect
|
|
228
|
+
if (prevCalculator && !this._calculatorActive) {
|
|
229
|
+
// calculator was exited — sphere onChange already handled above
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get the current tool mode based on gui_states flags.
|
|
234
|
+
*/
|
|
235
|
+
getMode() {
|
|
236
|
+
if (this._calculatorActive)
|
|
237
|
+
return "calculator";
|
|
238
|
+
if (this.gui_states.mode.sphere)
|
|
239
|
+
return "sphere";
|
|
240
|
+
if (this.gui_states.mode.eraser)
|
|
241
|
+
return "eraser";
|
|
242
|
+
if (this.gui_states.mode.pencil)
|
|
243
|
+
return "pencil";
|
|
244
|
+
return "brush";
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Check if calculator mode is active.
|
|
248
|
+
*/
|
|
249
|
+
isCalculatorActive() {
|
|
250
|
+
return this._calculatorActive;
|
|
251
|
+
}
|
|
252
|
+
// ── Phase 1: GUI API — Slider Methods ───────────────────────────────────
|
|
253
|
+
/**
|
|
254
|
+
* Set mask overlay opacity.
|
|
255
|
+
* @param value Opacity value [0.1, 1]
|
|
256
|
+
*/
|
|
257
|
+
setOpacity(value) {
|
|
258
|
+
this.gui_states.drawing.globalAlpha = Math.max(0.1, Math.min(1, value));
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get the current mask overlay opacity.
|
|
262
|
+
*/
|
|
263
|
+
getOpacity() {
|
|
264
|
+
return this.gui_states.drawing.globalAlpha;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Set brush and eraser size, and trigger cursor update.
|
|
268
|
+
* @param size Brush size [5, 50]
|
|
269
|
+
*/
|
|
270
|
+
setBrushSize(size) {
|
|
271
|
+
var _a;
|
|
272
|
+
this.gui_states.drawing.brushAndEraserSize = Math.max(5, Math.min(50, size));
|
|
273
|
+
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateBrushAndEraserSize();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get the current brush/eraser size.
|
|
277
|
+
*/
|
|
278
|
+
getBrushSize() {
|
|
279
|
+
return this.gui_states.drawing.brushAndEraserSize;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Set window high (image contrast) value.
|
|
283
|
+
* Call finishWindowAdjustment() when the user finishes dragging.
|
|
284
|
+
*/
|
|
285
|
+
setWindowHigh(value) {
|
|
286
|
+
var _a;
|
|
287
|
+
this.gui_states.viewConfig.readyToUpdate = false;
|
|
288
|
+
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateWindowHigh(value);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Set window low (image center) value.
|
|
292
|
+
* Call finishWindowAdjustment() when the user finishes dragging.
|
|
293
|
+
*/
|
|
294
|
+
setWindowLow(value) {
|
|
295
|
+
var _a;
|
|
296
|
+
this.gui_states.viewConfig.readyToUpdate = false;
|
|
297
|
+
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateWindowLow(value);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Finish a window/contrast adjustment (repaint all contrast slices).
|
|
301
|
+
*/
|
|
302
|
+
finishWindowAdjustment() {
|
|
303
|
+
var _a;
|
|
304
|
+
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.finishContrastAdjustment();
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Adjust contrast by delta, used for drag-based contrast adjustment.
|
|
308
|
+
* @param type "windowHigh" or "windowLow"
|
|
309
|
+
* @param delta Delta amount to adjust
|
|
310
|
+
*/
|
|
311
|
+
adjustContrast(type, delta) {
|
|
312
|
+
var _a, _b;
|
|
313
|
+
if (!this.guiParameterSettings)
|
|
314
|
+
return;
|
|
315
|
+
const setting = this.guiParameterSettings[type];
|
|
316
|
+
// setting.value is the volume object at runtime (typed as null in interface)
|
|
317
|
+
const vol = setting.value;
|
|
318
|
+
const currentValue = type === "windowHigh"
|
|
319
|
+
? ((_a = vol === null || vol === void 0 ? void 0 : vol.windowHigh) !== null && _a !== void 0 ? _a : 0)
|
|
320
|
+
: ((_b = vol === null || vol === void 0 ? void 0 : vol.windowLow) !== null && _b !== void 0 ? _b : 0);
|
|
321
|
+
const newValue = currentValue + delta;
|
|
322
|
+
if (newValue >= setting.max || newValue <= 0)
|
|
323
|
+
return;
|
|
324
|
+
if (type === "windowHigh") {
|
|
325
|
+
this.setWindowHigh(newValue);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
this.setWindowLow(newValue);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get slider metadata for UI configuration.
|
|
333
|
+
* @param key Slider key: "globalAlpha", "brushAndEraserSize", "windowHigh", "windowLow"
|
|
334
|
+
* @returns IGuiMeta with min, max, step, and current value
|
|
335
|
+
*/
|
|
336
|
+
getSliderMeta(key) {
|
|
337
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
338
|
+
if (!this.guiParameterSettings)
|
|
339
|
+
return null;
|
|
340
|
+
const setting = this.guiParameterSettings[key];
|
|
341
|
+
if (!setting)
|
|
342
|
+
return null;
|
|
343
|
+
let value;
|
|
344
|
+
if (key === "windowHigh") {
|
|
345
|
+
value = (_b = (_a = setting.value) === null || _a === void 0 ? void 0 : _a.windowHigh) !== null && _b !== void 0 ? _b : 0;
|
|
346
|
+
}
|
|
347
|
+
else if (key === "windowLow") {
|
|
348
|
+
value = (_d = (_c = setting.value) === null || _c === void 0 ? void 0 : _c.windowLow) !== null && _d !== void 0 ? _d : 0;
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
value = (_e = this.gui_states.drawing[key]) !== null && _e !== void 0 ? _e : 0;
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
min: (_f = setting.min) !== null && _f !== void 0 ? _f : 0,
|
|
355
|
+
max: (_g = setting.max) !== null && _g !== void 0 ? _g : 100,
|
|
356
|
+
step: (_h = setting.step) !== null && _h !== void 0 ? _h : 1,
|
|
357
|
+
value,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
// ── Phase 1: GUI API — Color & Action Methods ──────────────────────────
|
|
361
|
+
/**
|
|
362
|
+
* Set the pencil stroke color.
|
|
363
|
+
*/
|
|
364
|
+
setPencilColor(hex) {
|
|
365
|
+
this.gui_states.drawing.color = hex;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Get the current pencil stroke color.
|
|
369
|
+
*/
|
|
370
|
+
getPencilColor() {
|
|
371
|
+
return this.gui_states.drawing.color;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Execute a named UI action.
|
|
375
|
+
* @param action Action name
|
|
376
|
+
*
|
|
377
|
+
* Renamed from original gui_states methods:
|
|
378
|
+
* - "clearActiveSliceMask" (was "clear") — clear annotations on current slice
|
|
379
|
+
* - "clearActiveLayerMask" (was "clearAll") — clear annotations on all slices for active layer
|
|
380
|
+
*/
|
|
381
|
+
executeAction(action) {
|
|
382
|
+
switch (action) {
|
|
383
|
+
case "undo":
|
|
384
|
+
this.undo();
|
|
385
|
+
break;
|
|
386
|
+
case "redo":
|
|
387
|
+
this.redo();
|
|
388
|
+
break;
|
|
389
|
+
case "clearActiveSliceMask":
|
|
390
|
+
this.clearActiveSlice();
|
|
391
|
+
break;
|
|
392
|
+
case "clearActiveLayerMask": {
|
|
393
|
+
const text = "Are you sure remove annotations on All slice?";
|
|
394
|
+
if (confirm(text) === true) {
|
|
395
|
+
this.nrrd_states.flags.clearAllFlag = true;
|
|
396
|
+
this.clearActiveSlice();
|
|
397
|
+
this.clearActiveLayer();
|
|
398
|
+
}
|
|
399
|
+
this.nrrd_states.flags.clearAllFlag = false;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
case "resetZoom":
|
|
403
|
+
this.nrrd_states.view.sizeFactor = this.baseCanvasesSize;
|
|
404
|
+
this.gui_states.viewConfig.mainAreaSize = this.baseCanvasesSize;
|
|
405
|
+
this.resizePaintArea(this.nrrd_states.view.sizeFactor);
|
|
406
|
+
this.resetPaintAreaUIPosition();
|
|
407
|
+
break;
|
|
408
|
+
case "downloadCurrentMask": {
|
|
409
|
+
const config = {
|
|
410
|
+
axis: this.protectedData.axis,
|
|
411
|
+
currentSliceIndex: this.nrrd_states.view.currentSliceIndex,
|
|
412
|
+
drawingCanvas: this.protectedData.canvases.drawingCanvas,
|
|
413
|
+
originWidth: this.nrrd_states.image.originWidth,
|
|
414
|
+
originHeight: this.nrrd_states.image.originHeight,
|
|
415
|
+
};
|
|
416
|
+
enableDownload(config);
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
136
421
|
/**
|
|
137
422
|
* Sync brush/fill color from the active layer's volume color map.
|
|
138
423
|
* Falls back to global CHANNEL_HEX_COLORS if volume not available.
|
|
139
424
|
*/
|
|
140
425
|
syncBrushColor() {
|
|
141
|
-
const channel = this.gui_states.activeChannel || 1;
|
|
142
|
-
const layer = this.gui_states.layer;
|
|
426
|
+
const channel = this.gui_states.layerChannel.activeChannel || 1;
|
|
427
|
+
const layer = this.gui_states.layerChannel.layer;
|
|
143
428
|
const volume = this.protectedData.maskData.volumes[layer];
|
|
144
429
|
if (volume) {
|
|
145
430
|
const hex = rgbaToHex(volume.getChannelColor(channel));
|
|
146
|
-
this.gui_states.fillColor = hex;
|
|
147
|
-
this.gui_states.brushColor = hex;
|
|
431
|
+
this.gui_states.drawing.fillColor = hex;
|
|
432
|
+
this.gui_states.drawing.brushColor = hex;
|
|
148
433
|
}
|
|
149
434
|
else {
|
|
150
435
|
const hex = CHANNEL_HEX_COLORS[channel] || '#00ff00';
|
|
151
|
-
this.gui_states.fillColor = hex;
|
|
152
|
-
this.gui_states.brushColor = hex;
|
|
436
|
+
this.gui_states.drawing.fillColor = hex;
|
|
437
|
+
this.gui_states.drawing.brushColor = hex;
|
|
153
438
|
}
|
|
154
439
|
}
|
|
155
440
|
/**
|
|
156
441
|
* Get the currently active layer id.
|
|
157
442
|
*/
|
|
158
443
|
getActiveLayer() {
|
|
159
|
-
return this.gui_states.layer;
|
|
444
|
+
return this.gui_states.layerChannel.layer;
|
|
160
445
|
}
|
|
161
446
|
/**
|
|
162
447
|
* Get the currently active channel value.
|
|
163
448
|
*/
|
|
164
449
|
getActiveChannel() {
|
|
165
|
-
return this.gui_states.activeChannel;
|
|
450
|
+
return this.gui_states.layerChannel.activeChannel;
|
|
166
451
|
}
|
|
167
452
|
/**
|
|
168
453
|
* Set visibility of a layer and re-render.
|
|
169
454
|
*/
|
|
170
455
|
setLayerVisible(layerId, visible) {
|
|
171
|
-
this.gui_states.layerVisibility[layerId] = visible;
|
|
456
|
+
this.gui_states.layerChannel.layerVisibility[layerId] = visible;
|
|
172
457
|
this.reloadMasksFromVolume();
|
|
173
458
|
}
|
|
174
459
|
/**
|
|
@@ -176,14 +461,14 @@ export class NrrdTools extends DrawToolCore {
|
|
|
176
461
|
*/
|
|
177
462
|
isLayerVisible(layerId) {
|
|
178
463
|
var _a;
|
|
179
|
-
return (_a = this.gui_states.layerVisibility[layerId]) !== null && _a !== void 0 ? _a : true;
|
|
464
|
+
return (_a = this.gui_states.layerChannel.layerVisibility[layerId]) !== null && _a !== void 0 ? _a : true;
|
|
180
465
|
}
|
|
181
466
|
/**
|
|
182
467
|
* Set visibility of a specific channel within a layer and re-render.
|
|
183
468
|
*/
|
|
184
469
|
setChannelVisible(layerId, channel, visible) {
|
|
185
|
-
if (this.gui_states.channelVisibility[layerId]) {
|
|
186
|
-
this.gui_states.channelVisibility[layerId][channel] = visible;
|
|
470
|
+
if (this.gui_states.layerChannel.channelVisibility[layerId]) {
|
|
471
|
+
this.gui_states.layerChannel.channelVisibility[layerId][channel] = visible;
|
|
187
472
|
}
|
|
188
473
|
this.reloadMasksFromVolume();
|
|
189
474
|
}
|
|
@@ -192,21 +477,21 @@ export class NrrdTools extends DrawToolCore {
|
|
|
192
477
|
*/
|
|
193
478
|
isChannelVisible(layerId, channel) {
|
|
194
479
|
var _a, _b;
|
|
195
|
-
return (_b = (_a = this.gui_states.channelVisibility[layerId]) === null || _a === void 0 ? void 0 : _a[channel]) !== null && _b !== void 0 ? _b : true;
|
|
480
|
+
return (_b = (_a = this.gui_states.layerChannel.channelVisibility[layerId]) === null || _a === void 0 ? void 0 : _a[channel]) !== null && _b !== void 0 ? _b : true;
|
|
196
481
|
}
|
|
197
482
|
/**
|
|
198
483
|
* Get the full layer visibility map.
|
|
199
484
|
*/
|
|
200
485
|
getLayerVisibility() {
|
|
201
|
-
return Object.assign({}, this.gui_states.layerVisibility);
|
|
486
|
+
return Object.assign({}, this.gui_states.layerChannel.layerVisibility);
|
|
202
487
|
}
|
|
203
488
|
/**
|
|
204
489
|
* Get the full channel visibility map.
|
|
205
490
|
*/
|
|
206
491
|
getChannelVisibility() {
|
|
207
492
|
const result = {};
|
|
208
|
-
for (const layerId of this.nrrd_states.layers) {
|
|
209
|
-
result[layerId] = Object.assign({}, this.gui_states.channelVisibility[layerId]);
|
|
493
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
494
|
+
result[layerId] = Object.assign({}, this.gui_states.layerChannel.channelVisibility[layerId]);
|
|
210
495
|
}
|
|
211
496
|
return result;
|
|
212
497
|
}
|
|
@@ -255,11 +540,11 @@ export class NrrdTools extends DrawToolCore {
|
|
|
255
540
|
return;
|
|
256
541
|
}
|
|
257
542
|
volume.setChannelColor(channel, color);
|
|
258
|
-
if (layerId === this.gui_states.layer && channel === this.gui_states.activeChannel) {
|
|
543
|
+
if (layerId === this.gui_states.layerChannel.layer && channel === this.gui_states.layerChannel.activeChannel) {
|
|
259
544
|
this.syncBrushColor();
|
|
260
545
|
}
|
|
261
546
|
this.reloadMasksFromVolume();
|
|
262
|
-
this.
|
|
547
|
+
this.annotationCallbacks.onChannelColorChanged(layerId, channel, color);
|
|
263
548
|
}
|
|
264
549
|
/**
|
|
265
550
|
* Get the current color for a specific channel in a specific layer.
|
|
@@ -310,7 +595,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
310
595
|
for (const [ch, color] of Object.entries(colorMap)) {
|
|
311
596
|
volume.setChannelColor(Number(ch), color);
|
|
312
597
|
}
|
|
313
|
-
if (layerId === this.gui_states.layer) {
|
|
598
|
+
if (layerId === this.gui_states.layerChannel.layer) {
|
|
314
599
|
this.syncBrushColor();
|
|
315
600
|
}
|
|
316
601
|
this.reloadMasksFromVolume();
|
|
@@ -322,13 +607,13 @@ export class NrrdTools extends DrawToolCore {
|
|
|
322
607
|
* @param color RGBAColor object
|
|
323
608
|
*/
|
|
324
609
|
setAllLayersChannelColor(channel, color) {
|
|
325
|
-
for (const layerId of this.nrrd_states.layers) {
|
|
610
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
326
611
|
const volume = this.protectedData.maskData.volumes[layerId];
|
|
327
612
|
if (volume) {
|
|
328
613
|
volume.setChannelColor(channel, color);
|
|
329
614
|
}
|
|
330
615
|
}
|
|
331
|
-
if (channel === this.gui_states.activeChannel) {
|
|
616
|
+
if (channel === this.gui_states.layerChannel.activeChannel) {
|
|
332
617
|
this.syncBrushColor();
|
|
333
618
|
}
|
|
334
619
|
this.reloadMasksFromVolume();
|
|
@@ -347,7 +632,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
347
632
|
* ```
|
|
348
633
|
*/
|
|
349
634
|
resetChannelColors(layerId, channel) {
|
|
350
|
-
const layers = layerId ? [layerId] : this.nrrd_states.layers;
|
|
635
|
+
const layers = layerId ? [layerId] : this.nrrd_states.image.layers;
|
|
351
636
|
for (const lid of layers) {
|
|
352
637
|
const volume = this.protectedData.maskData.volumes[lid];
|
|
353
638
|
if (volume) {
|
|
@@ -522,28 +807,39 @@ export class NrrdTools extends DrawToolCore {
|
|
|
522
807
|
setAllSlices(allSlices) {
|
|
523
808
|
this.protectedData.allSlicesArray = [...allSlices];
|
|
524
809
|
const randomSlice = this.protectedData.allSlicesArray[0];
|
|
525
|
-
this.nrrd_states.nrrd_x_mm = randomSlice.z.canvas.width;
|
|
526
|
-
this.nrrd_states.nrrd_y_mm = randomSlice.z.canvas.height;
|
|
527
|
-
this.nrrd_states.nrrd_z_mm = randomSlice.x.canvas.width;
|
|
528
|
-
this.nrrd_states.nrrd_x_pixel = randomSlice.x.volume.dimensions[0];
|
|
529
|
-
this.nrrd_states.nrrd_y_pixel = randomSlice.x.volume.dimensions[1];
|
|
530
|
-
this.nrrd_states.nrrd_z_pixel = randomSlice.x.volume.dimensions[2];
|
|
531
|
-
this.nrrd_states.voxelSpacing = randomSlice.x.volume.spacing;
|
|
532
|
-
this.nrrd_states.ratios.x = randomSlice.x.volume.spacing[0];
|
|
533
|
-
this.nrrd_states.ratios.y = randomSlice.x.volume.spacing[1];
|
|
534
|
-
this.nrrd_states.ratios.z = randomSlice.x.volume.spacing[2];
|
|
535
|
-
this.nrrd_states.dimensions = randomSlice.x.volume.dimensions;
|
|
810
|
+
this.nrrd_states.image.nrrd_x_mm = randomSlice.z.canvas.width;
|
|
811
|
+
this.nrrd_states.image.nrrd_y_mm = randomSlice.z.canvas.height;
|
|
812
|
+
this.nrrd_states.image.nrrd_z_mm = randomSlice.x.canvas.width;
|
|
813
|
+
this.nrrd_states.image.nrrd_x_pixel = randomSlice.x.volume.dimensions[0];
|
|
814
|
+
this.nrrd_states.image.nrrd_y_pixel = randomSlice.x.volume.dimensions[1];
|
|
815
|
+
this.nrrd_states.image.nrrd_z_pixel = randomSlice.x.volume.dimensions[2];
|
|
816
|
+
this.nrrd_states.image.voxelSpacing = randomSlice.x.volume.spacing;
|
|
817
|
+
this.nrrd_states.image.ratios.x = randomSlice.x.volume.spacing[0];
|
|
818
|
+
this.nrrd_states.image.ratios.y = randomSlice.x.volume.spacing[1];
|
|
819
|
+
this.nrrd_states.image.ratios.z = randomSlice.x.volume.spacing[2];
|
|
820
|
+
this.nrrd_states.image.dimensions = randomSlice.x.volume.dimensions;
|
|
536
821
|
// Phase 2 Day 9: Re-initialize MaskVolume with real NRRD dimensions.
|
|
537
822
|
// This replaces the 1×1×1 placeholders from CommToolsData constructor
|
|
538
823
|
// and "turns on" all Day 7/8 volume read/write paths.
|
|
539
824
|
// Invalidate reusable buffer from previous dataset
|
|
540
825
|
this.invalidateSliceBuffer();
|
|
541
|
-
const [vw, vh, vd] = this.nrrd_states.dimensions;
|
|
542
|
-
this.protectedData.maskData.volumes = this.nrrd_states.layers.reduce((acc, id) => {
|
|
826
|
+
const [vw, vh, vd] = this.nrrd_states.image.dimensions;
|
|
827
|
+
this.protectedData.maskData.volumes = this.nrrd_states.image.layers.reduce((acc, id) => {
|
|
543
828
|
acc[id] = new MaskVolume(vw, vh, vd, 1);
|
|
544
829
|
return acc;
|
|
545
830
|
}, {});
|
|
546
|
-
|
|
831
|
+
// Create dedicated SphereMaskVolume for 3D sphere data.
|
|
832
|
+
// Separate from layer volumes to avoid polluting draw mask data.
|
|
833
|
+
// Cleared in reset() when switching cases.
|
|
834
|
+
this.nrrd_states.sphere.sphereMaskVolume = new MaskVolume(vw, vh, vd, 1);
|
|
835
|
+
// Derive sphere label colors from SPHERE_CHANNEL_MAP → MASK_CHANNEL_COLORS
|
|
836
|
+
// so that volume rendering matches the preview circle colors.
|
|
837
|
+
for (const [type, { channel }] of Object.entries(SPHERE_CHANNEL_MAP)) {
|
|
838
|
+
const label = SPHERE_LABELS[type];
|
|
839
|
+
const c = MASK_CHANNEL_COLORS[channel];
|
|
840
|
+
this.nrrd_states.sphere.sphereMaskVolume.setChannelColor(label, { r: c.r, g: c.g, b: c.b, a: c.a });
|
|
841
|
+
}
|
|
842
|
+
this.nrrd_states.image.spaceOrigin = randomSlice.x.volume.header.space_origin.map((item) => {
|
|
547
843
|
return item * 1;
|
|
548
844
|
});
|
|
549
845
|
this.protectedData.allSlicesArray.forEach((item, index) => {
|
|
@@ -552,13 +848,13 @@ export class NrrdTools extends DrawToolCore {
|
|
|
552
848
|
item.z.contrastOrder = index;
|
|
553
849
|
});
|
|
554
850
|
// Phase 3: initPaintImages removed (MaskVolume initialized separately)
|
|
555
|
-
// this.initPaintImages(this.nrrd_states.dimensions);
|
|
851
|
+
// this.initPaintImages(this.nrrd_states.image.dimensions);
|
|
556
852
|
// init displayslices array, the axis default is "z"
|
|
557
853
|
this.setDisplaySlicesBaseOnAxis();
|
|
558
854
|
this.afterLoadSlice();
|
|
559
855
|
}
|
|
560
856
|
loadingMaskByLayer(masks, index, imageData) {
|
|
561
|
-
let imageDataLable = this.protectedData.ctxes.emptyCtx.createImageData(this.nrrd_states.nrrd_x_pixel, this.nrrd_states.nrrd_y_pixel);
|
|
857
|
+
let imageDataLable = this.protectedData.ctxes.emptyCtx.createImageData(this.nrrd_states.image.nrrd_x_pixel, this.nrrd_states.image.nrrd_y_pixel);
|
|
562
858
|
this.setEmptyCanvasSize();
|
|
563
859
|
for (let j = 0; j < masks[index].data.length; j++) {
|
|
564
860
|
imageDataLable.data[j] = masks[index].data[j];
|
|
@@ -569,7 +865,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
569
865
|
// need to remove
|
|
570
866
|
setMasksData(masksData, loadingBar) {
|
|
571
867
|
if (!!masksData) {
|
|
572
|
-
this.nrrd_states.
|
|
868
|
+
this.nrrd_states.flags.loadingMaskData = true;
|
|
573
869
|
if (loadingBar) {
|
|
574
870
|
let { loadingContainer, progress } = loadingBar;
|
|
575
871
|
loadingContainer.style.display = "flex";
|
|
@@ -578,32 +874,22 @@ export class NrrdTools extends DrawToolCore {
|
|
|
578
874
|
this.setEmptyCanvasSize();
|
|
579
875
|
const len = masksData["layer1"].length;
|
|
580
876
|
for (let i = 0; i < len; i++) {
|
|
581
|
-
let imageData = this.protectedData.ctxes.emptyCtx.createImageData(this.nrrd_states.nrrd_x_pixel, this.nrrd_states.nrrd_y_pixel);
|
|
582
|
-
let imageDataLayer1, imageDataLayer2, imageDataLayer3;
|
|
877
|
+
let imageData = this.protectedData.ctxes.emptyCtx.createImageData(this.nrrd_states.image.nrrd_x_pixel, this.nrrd_states.image.nrrd_y_pixel);
|
|
583
878
|
if (masksData["layer1"][i].data.length > 0) {
|
|
584
|
-
this.
|
|
585
|
-
imageDataLayer1 = this.loadingMaskByLayer(masksData["layer1"], i, imageData);
|
|
586
|
-
this.protectedData.ctxes.emptyCtx.putImageData(imageDataLayer1, 0, 0);
|
|
587
|
-
this.storeEachLayerImage(i, "layer1");
|
|
879
|
+
this.loadingMaskByLayer(masksData["layer1"], i, imageData);
|
|
588
880
|
}
|
|
589
881
|
if (masksData["layer2"][i].data.length > 0) {
|
|
590
|
-
this.
|
|
591
|
-
imageDataLayer2 = this.loadingMaskByLayer(masksData["layer2"], i, imageData);
|
|
592
|
-
this.protectedData.ctxes.emptyCtx.putImageData(imageDataLayer2, 0, 0);
|
|
593
|
-
this.storeEachLayerImage(i, "layer2");
|
|
882
|
+
this.loadingMaskByLayer(masksData["layer2"], i, imageData);
|
|
594
883
|
}
|
|
595
884
|
if (masksData["layer3"][i].data.length > 0) {
|
|
596
|
-
this.
|
|
597
|
-
imageDataLayer3 = this.loadingMaskByLayer(masksData["layer3"], i, imageData);
|
|
598
|
-
this.protectedData.ctxes.emptyCtx.putImageData(imageDataLayer3, 0, 0);
|
|
599
|
-
this.storeEachLayerImage(i, "layer3");
|
|
885
|
+
this.loadingMaskByLayer(masksData["layer3"], i, imageData);
|
|
600
886
|
}
|
|
601
887
|
this.setEmptyCanvasSize();
|
|
602
888
|
this.protectedData.ctxes.emptyCtx.putImageData(imageData, 0, 0);
|
|
603
|
-
this.
|
|
889
|
+
this.syncLayerSliceData(i, "default");
|
|
604
890
|
}
|
|
605
|
-
this.nrrd_states.
|
|
606
|
-
this.
|
|
891
|
+
this.nrrd_states.flags.loadingMaskData = false;
|
|
892
|
+
this.executeAction("resetZoom");
|
|
607
893
|
if (loadingBar) {
|
|
608
894
|
loadingBar.loadingContainer.style.display = "none";
|
|
609
895
|
}
|
|
@@ -645,7 +931,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
645
931
|
}
|
|
646
932
|
// Reload the current slice from MaskVolume to canvas
|
|
647
933
|
this.reloadMasksFromVolume();
|
|
648
|
-
this.
|
|
934
|
+
this.executeAction("resetZoom");
|
|
649
935
|
}
|
|
650
936
|
catch (error) {
|
|
651
937
|
console.error("Error loading NIfTI masks:", error);
|
|
@@ -657,31 +943,69 @@ export class NrrdTools extends DrawToolCore {
|
|
|
657
943
|
}
|
|
658
944
|
}
|
|
659
945
|
setShowInMainArea() {
|
|
660
|
-
this.nrrd_states.showContrast = true;
|
|
946
|
+
this.nrrd_states.view.showContrast = true;
|
|
661
947
|
}
|
|
662
948
|
getCurrentImageDimension() {
|
|
663
|
-
return this.nrrd_states.dimensions;
|
|
949
|
+
return this.nrrd_states.image.dimensions;
|
|
664
950
|
}
|
|
665
951
|
getVoxelSpacing() {
|
|
666
|
-
return this.nrrd_states.voxelSpacing;
|
|
952
|
+
return this.nrrd_states.image.voxelSpacing;
|
|
667
953
|
}
|
|
668
954
|
getSpaceOrigin() {
|
|
669
|
-
return this.nrrd_states.spaceOrigin;
|
|
955
|
+
return this.nrrd_states.image.spaceOrigin;
|
|
670
956
|
}
|
|
671
957
|
getMaskData() {
|
|
672
958
|
return this.protectedData.maskData;
|
|
673
959
|
}
|
|
674
|
-
|
|
960
|
+
/**
|
|
961
|
+
* Programmatically place a calculator sphere at the given position.
|
|
962
|
+
*
|
|
963
|
+
* Replicates the full mouse-down → mouse-up flow (handleSphereClick + pointerup)
|
|
964
|
+
* so that backend-supplied sphere data is stored identically to a manual click.
|
|
965
|
+
*
|
|
966
|
+
* @param x - X coordinate in unscaled (original) image space
|
|
967
|
+
* @param y - Y coordinate in unscaled (original) image space
|
|
968
|
+
* @param sliceIndex - Target slice index (z-axis)
|
|
969
|
+
* @param cal_position - Sphere type to place
|
|
970
|
+
*/
|
|
675
971
|
setCalculateDistanceSphere(x, y, sliceIndex, cal_position) {
|
|
676
|
-
this.nrrd_states.sphereRadius = 5;
|
|
677
|
-
// move to
|
|
678
|
-
const steps = sliceIndex - this.nrrd_states.
|
|
972
|
+
this.nrrd_states.sphere.sphereRadius = 5;
|
|
973
|
+
// move to target slice
|
|
974
|
+
const steps = sliceIndex - this.nrrd_states.view.currentSliceIndex;
|
|
679
975
|
this.setSliceMoving(steps * this.protectedData.displaySlices.length);
|
|
680
|
-
//
|
|
681
|
-
// if user
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
976
|
+
// --- simulate mouse-down (mirrors DrawToolCore.handleSphereClick) ---
|
|
977
|
+
// if user has zoomed the panel, we need to consider the size factor
|
|
978
|
+
const mouseX = x * this.nrrd_states.view.sizeFactor;
|
|
979
|
+
const mouseY = y * this.nrrd_states.view.sizeFactor;
|
|
980
|
+
// 1. record origin on current axis
|
|
981
|
+
this.nrrd_states.sphere.sphereOrigin[this.protectedData.axis] = [
|
|
982
|
+
mouseX, mouseY, sliceIndex,
|
|
983
|
+
];
|
|
984
|
+
// compute origins for all 3 axes (crosshairTool is protected)
|
|
985
|
+
this.crosshairTool.setUpSphereOrigins(mouseX, mouseY, sliceIndex);
|
|
986
|
+
// 2. store a deep copy of the origin for the specific sphere type
|
|
987
|
+
const originCopy = JSON.parse(JSON.stringify(this.nrrd_states.sphere.sphereOrigin));
|
|
988
|
+
switch (cal_position) {
|
|
989
|
+
case "tumour":
|
|
990
|
+
this.nrrd_states.sphere.tumourSphereOrigin = originCopy;
|
|
991
|
+
break;
|
|
992
|
+
case "skin":
|
|
993
|
+
this.nrrd_states.sphere.skinSphereOrigin = originCopy;
|
|
994
|
+
break;
|
|
995
|
+
case "nipple":
|
|
996
|
+
this.nrrd_states.sphere.nippleSphereOrigin = originCopy;
|
|
997
|
+
break;
|
|
998
|
+
case "ribcage":
|
|
999
|
+
this.nrrd_states.sphere.ribSphereOrigin = originCopy;
|
|
1000
|
+
break;
|
|
1001
|
+
}
|
|
1002
|
+
// 3. draw sphere preview on canvas
|
|
1003
|
+
this.drawCalculatorSphere(this.nrrd_states.sphere.sphereRadius);
|
|
1004
|
+
// --- simulate mouse-up ---
|
|
1005
|
+
// 4. write all placed calculator spheres into sphereMaskVolume
|
|
1006
|
+
this.sphereTool.writeAllCalculatorSpheresToVolume();
|
|
1007
|
+
// 5. re-render sphere overlay from volume
|
|
1008
|
+
this.sphereTool.refreshSphereCanvas();
|
|
685
1009
|
}
|
|
686
1010
|
/**
|
|
687
1011
|
* Switch all contrast slices' orientation
|
|
@@ -690,24 +1014,24 @@ export class NrrdTools extends DrawToolCore {
|
|
|
690
1014
|
setSliceOrientation(axisTo) {
|
|
691
1015
|
var _a;
|
|
692
1016
|
let convetObj;
|
|
693
|
-
if (((_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.isCrosshairEnabled()) || this.gui_states.sphere) {
|
|
1017
|
+
if (((_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.isCrosshairEnabled()) || this.gui_states.mode.sphere) {
|
|
694
1018
|
if (this.protectedData.axis === "z") {
|
|
695
|
-
this.cursorPage.z.index = this.nrrd_states.
|
|
696
|
-
this.cursorPage.z.cursorPageX = this.nrrd_states.cursorPageX;
|
|
697
|
-
this.cursorPage.z.cursorPageY = this.nrrd_states.cursorPageY;
|
|
1019
|
+
this.cursorPage.z.index = this.nrrd_states.view.currentSliceIndex;
|
|
1020
|
+
this.cursorPage.z.cursorPageX = this.nrrd_states.interaction.cursorPageX;
|
|
1021
|
+
this.cursorPage.z.cursorPageY = this.nrrd_states.interaction.cursorPageY;
|
|
698
1022
|
}
|
|
699
1023
|
else if (this.protectedData.axis === "x") {
|
|
700
|
-
this.cursorPage.x.index = this.nrrd_states.
|
|
701
|
-
this.cursorPage.x.cursorPageX = this.nrrd_states.cursorPageX;
|
|
702
|
-
this.cursorPage.x.cursorPageY = this.nrrd_states.cursorPageY;
|
|
1024
|
+
this.cursorPage.x.index = this.nrrd_states.view.currentSliceIndex;
|
|
1025
|
+
this.cursorPage.x.cursorPageX = this.nrrd_states.interaction.cursorPageX;
|
|
1026
|
+
this.cursorPage.x.cursorPageY = this.nrrd_states.interaction.cursorPageY;
|
|
703
1027
|
}
|
|
704
1028
|
else if (this.protectedData.axis === "y") {
|
|
705
|
-
this.cursorPage.y.index = this.nrrd_states.
|
|
706
|
-
this.cursorPage.y.cursorPageX = this.nrrd_states.cursorPageX;
|
|
707
|
-
this.cursorPage.y.cursorPageY = this.nrrd_states.cursorPageY;
|
|
1029
|
+
this.cursorPage.y.index = this.nrrd_states.view.currentSliceIndex;
|
|
1030
|
+
this.cursorPage.y.cursorPageX = this.nrrd_states.interaction.cursorPageX;
|
|
1031
|
+
this.cursorPage.y.cursorPageY = this.nrrd_states.interaction.cursorPageY;
|
|
708
1032
|
}
|
|
709
1033
|
if (axisTo === "z") {
|
|
710
|
-
if (this.nrrd_states.isCursorSelect && !this.cursorPage.z.updated) {
|
|
1034
|
+
if (this.nrrd_states.interaction.isCursorSelect && !this.cursorPage.z.updated) {
|
|
711
1035
|
if (this.protectedData.axis === "x") {
|
|
712
1036
|
// convert x to z
|
|
713
1037
|
convetObj = this.convertCursorPoint("x", "z", this.cursorPage.x.cursorPageX, this.cursorPage.x.cursorPageY, this.cursorPage.x.index);
|
|
@@ -719,15 +1043,15 @@ export class NrrdTools extends DrawToolCore {
|
|
|
719
1043
|
}
|
|
720
1044
|
else {
|
|
721
1045
|
// not cursor select, freedom to switch x -> z or y -> z and z -> x or z -> y
|
|
722
|
-
this.nrrd_states.
|
|
723
|
-
this.nrrd_states.
|
|
724
|
-
this.cursorPage.z.index * this.nrrd_states.ratios.z;
|
|
725
|
-
this.nrrd_states.cursorPageX = this.cursorPage.z.cursorPageX;
|
|
726
|
-
this.nrrd_states.cursorPageY = this.cursorPage.z.cursorPageY;
|
|
1046
|
+
this.nrrd_states.view.currentSliceIndex = this.cursorPage.z.index;
|
|
1047
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1048
|
+
this.cursorPage.z.index * this.nrrd_states.image.ratios.z;
|
|
1049
|
+
this.nrrd_states.interaction.cursorPageX = this.cursorPage.z.cursorPageX;
|
|
1050
|
+
this.nrrd_states.interaction.cursorPageY = this.cursorPage.z.cursorPageY;
|
|
727
1051
|
}
|
|
728
1052
|
}
|
|
729
1053
|
else if (axisTo === "x") {
|
|
730
|
-
if (this.nrrd_states.isCursorSelect && !this.cursorPage.x.updated) {
|
|
1054
|
+
if (this.nrrd_states.interaction.isCursorSelect && !this.cursorPage.x.updated) {
|
|
731
1055
|
if (this.protectedData.axis === "z") {
|
|
732
1056
|
// convert z to x
|
|
733
1057
|
convetObj = this.convertCursorPoint("z", "x", this.cursorPage.z.cursorPageX, this.cursorPage.z.cursorPageY, this.cursorPage.z.index);
|
|
@@ -739,15 +1063,15 @@ export class NrrdTools extends DrawToolCore {
|
|
|
739
1063
|
}
|
|
740
1064
|
else {
|
|
741
1065
|
// not cursor select, freedom to switch z -> x or y -> x and x -> z or x -> y
|
|
742
|
-
this.nrrd_states.
|
|
743
|
-
this.nrrd_states.
|
|
744
|
-
this.cursorPage.x.index * this.nrrd_states.ratios.x;
|
|
745
|
-
this.nrrd_states.cursorPageX = this.cursorPage.x.cursorPageX;
|
|
746
|
-
this.nrrd_states.cursorPageY = this.cursorPage.x.cursorPageY;
|
|
1066
|
+
this.nrrd_states.view.currentSliceIndex = this.cursorPage.x.index;
|
|
1067
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1068
|
+
this.cursorPage.x.index * this.nrrd_states.image.ratios.x;
|
|
1069
|
+
this.nrrd_states.interaction.cursorPageX = this.cursorPage.x.cursorPageX;
|
|
1070
|
+
this.nrrd_states.interaction.cursorPageY = this.cursorPage.x.cursorPageY;
|
|
747
1071
|
}
|
|
748
1072
|
}
|
|
749
1073
|
else if (axisTo === "y") {
|
|
750
|
-
if (this.nrrd_states.isCursorSelect && !this.cursorPage.y.updated) {
|
|
1074
|
+
if (this.nrrd_states.interaction.isCursorSelect && !this.cursorPage.y.updated) {
|
|
751
1075
|
if (this.protectedData.axis === "z") {
|
|
752
1076
|
// convert z to y
|
|
753
1077
|
convetObj = this.convertCursorPoint("z", "y", this.cursorPage.z.cursorPageX, this.cursorPage.z.cursorPageY, this.cursorPage.z.index);
|
|
@@ -759,19 +1083,19 @@ export class NrrdTools extends DrawToolCore {
|
|
|
759
1083
|
}
|
|
760
1084
|
else {
|
|
761
1085
|
// not cursor select, freedom to switch z -> y or x -> y and y -> z or y -> x
|
|
762
|
-
this.nrrd_states.
|
|
763
|
-
this.nrrd_states.
|
|
764
|
-
this.cursorPage.y.index * this.nrrd_states.ratios.y;
|
|
765
|
-
this.nrrd_states.cursorPageX = this.cursorPage.y.cursorPageX;
|
|
766
|
-
this.nrrd_states.cursorPageY = this.cursorPage.y.cursorPageY;
|
|
1086
|
+
this.nrrd_states.view.currentSliceIndex = this.cursorPage.y.index;
|
|
1087
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1088
|
+
this.cursorPage.y.index * this.nrrd_states.image.ratios.y;
|
|
1089
|
+
this.nrrd_states.interaction.cursorPageX = this.cursorPage.y.cursorPageX;
|
|
1090
|
+
this.nrrd_states.interaction.cursorPageY = this.cursorPage.y.cursorPageY;
|
|
767
1091
|
}
|
|
768
1092
|
}
|
|
769
1093
|
if (convetObj) {
|
|
770
1094
|
// update convert cursor point, when cursor select
|
|
771
|
-
this.nrrd_states.
|
|
772
|
-
this.nrrd_states.
|
|
773
|
-
this.nrrd_states.cursorPageX = convetObj.convertCursorNumX;
|
|
774
|
-
this.nrrd_states.cursorPageY = convetObj.convertCursorNumY;
|
|
1095
|
+
this.nrrd_states.view.currentSliceIndex = convetObj.currentNewSliceIndex;
|
|
1096
|
+
this.nrrd_states.view.preSliceIndex = convetObj.preSliceIndex;
|
|
1097
|
+
this.nrrd_states.interaction.cursorPageX = convetObj.convertCursorNumX;
|
|
1098
|
+
this.nrrd_states.interaction.cursorPageY = convetObj.convertCursorNumY;
|
|
775
1099
|
convetObj = undefined;
|
|
776
1100
|
switch (axisTo) {
|
|
777
1101
|
case "x":
|
|
@@ -789,47 +1113,52 @@ export class NrrdTools extends DrawToolCore {
|
|
|
789
1113
|
this.cursorPage.y.updated &&
|
|
790
1114
|
this.cursorPage.z.updated) {
|
|
791
1115
|
// one point convert to all axis, reset all updated status
|
|
792
|
-
this.nrrd_states.isCursorSelect = false;
|
|
1116
|
+
this.nrrd_states.interaction.isCursorSelect = false;
|
|
793
1117
|
}
|
|
794
1118
|
}
|
|
795
1119
|
this.protectedData.axis = axisTo;
|
|
796
1120
|
this.resetDisplaySlicesStatus();
|
|
797
|
-
// for sphere plan a
|
|
798
|
-
if (this.gui_states.sphere && !this.nrrd_states.spherePlanB) {
|
|
799
|
-
this.drawSphere(this.nrrd_states.sphereOrigin[axisTo][0] * this.nrrd_states.sizeFoctor, this.nrrd_states.sphereOrigin[axisTo][1] * this.nrrd_states.sizeFoctor, this.nrrd_states.sphereRadius);
|
|
800
|
-
}
|
|
801
1121
|
}
|
|
802
1122
|
addSkip(index) {
|
|
803
1123
|
this.protectedData.skipSlicesDic[index] =
|
|
804
1124
|
this.protectedData.backUpDisplaySlices[index];
|
|
805
1125
|
if (index >= this.protectedData.displaySlices.length) {
|
|
806
|
-
this.nrrd_states.contrastNum = this.protectedData.displaySlices.length;
|
|
1126
|
+
this.nrrd_states.view.contrastNum = this.protectedData.displaySlices.length;
|
|
807
1127
|
}
|
|
808
1128
|
else {
|
|
809
|
-
this.nrrd_states.contrastNum = index;
|
|
1129
|
+
this.nrrd_states.view.contrastNum = index;
|
|
810
1130
|
}
|
|
811
1131
|
this.resetDisplaySlicesStatus();
|
|
812
1132
|
}
|
|
813
1133
|
removeSkip(index) {
|
|
814
1134
|
this.protectedData.skipSlicesDic[index] = undefined;
|
|
815
|
-
this.nrrd_states.contrastNum = 0;
|
|
1135
|
+
this.nrrd_states.view.contrastNum = 0;
|
|
816
1136
|
this.resetDisplaySlicesStatus();
|
|
817
1137
|
}
|
|
818
|
-
|
|
1138
|
+
/**
|
|
1139
|
+
* Reset the entire NrrdTools instance comprehensively.
|
|
1140
|
+
* This clears ALL data across ALL layers globally, resets the Canvas visuals,
|
|
1141
|
+
* undo/redo history, volume models, index parameters, and sphere overlays.
|
|
1142
|
+
* Primarily used when switching cases/datasets or when a completely fresh state is needed.
|
|
1143
|
+
* It is heavier than `clearActiveLayer` or `clearActiveSlice`.
|
|
1144
|
+
*/
|
|
1145
|
+
reset() {
|
|
819
1146
|
// To effectively reduce the js memory garbage
|
|
820
1147
|
this.protectedData.allSlicesArray.length = 0;
|
|
821
1148
|
this.protectedData.displaySlices.length = 0;
|
|
822
1149
|
// Phase 6: Clear all undo/redo stacks
|
|
823
1150
|
this.undoManager.clearAll();
|
|
824
1151
|
// Phase 3: Reset MaskVolume storage to 1×1×1 placeholders
|
|
825
|
-
this.protectedData.maskData.volumes = this.nrrd_states.layers.reduce((acc, id) => {
|
|
1152
|
+
this.protectedData.maskData.volumes = this.nrrd_states.image.layers.reduce((acc, id) => {
|
|
826
1153
|
acc[id] = new MaskVolume(1, 1, 1, 1);
|
|
827
1154
|
return acc;
|
|
828
1155
|
}, {});
|
|
1156
|
+
// Clear dedicated SphereMaskVolume
|
|
1157
|
+
this.nrrd_states.sphere.sphereMaskVolume = null;
|
|
829
1158
|
// Invalidate reusable slice buffer
|
|
830
1159
|
this.invalidateSliceBuffer();
|
|
831
1160
|
this.clearDictionary(this.protectedData.skipSlicesDic);
|
|
832
|
-
// this.nrrd_states.previousPanelL = this.nrrd_states.previousPanelT = -99999;
|
|
1161
|
+
// this.nrrd_states.view.previousPanelL = this.nrrd_states.view.previousPanelT = -99999;
|
|
833
1162
|
this.protectedData.canvases.displayCanvas.style.left =
|
|
834
1163
|
this.protectedData.canvases.drawingCanvas.style.left = "";
|
|
835
1164
|
this.protectedData.canvases.displayCanvas.style.top =
|
|
@@ -837,21 +1166,19 @@ export class NrrdTools extends DrawToolCore {
|
|
|
837
1166
|
this.protectedData.backUpDisplaySlices.length = 0;
|
|
838
1167
|
this.protectedData.mainPreSlices = undefined;
|
|
839
1168
|
this.protectedData.currentShowingSlice = undefined;
|
|
840
|
-
this.protectedData.previousDrawingImage =
|
|
841
|
-
this.protectedData.ctxes.emptyCtx.createImageData(1, 1);
|
|
842
1169
|
this.initState = true;
|
|
843
1170
|
this.protectedData.axis = "z";
|
|
844
|
-
this.nrrd_states.
|
|
845
|
-
this.gui_states.mainAreaSize = this.baseCanvasesSize;
|
|
1171
|
+
this.nrrd_states.view.sizeFactor = this.baseCanvasesSize;
|
|
1172
|
+
this.gui_states.viewConfig.mainAreaSize = this.baseCanvasesSize;
|
|
846
1173
|
this.resetLayerCanvas();
|
|
847
1174
|
this.protectedData.canvases.drawingCanvas.width =
|
|
848
1175
|
this.protectedData.canvases.drawingCanvas.width;
|
|
849
1176
|
this.protectedData.canvases.displayCanvas.width =
|
|
850
1177
|
this.protectedData.canvases.displayCanvas.width;
|
|
851
|
-
this.nrrd_states.tumourSphereOrigin = null;
|
|
852
|
-
this.nrrd_states.ribSphereOrigin = null;
|
|
853
|
-
this.nrrd_states.skinSphereOrigin = null;
|
|
854
|
-
this.nrrd_states.nippleSphereOrigin = null;
|
|
1178
|
+
this.nrrd_states.sphere.tumourSphereOrigin = null;
|
|
1179
|
+
this.nrrd_states.sphere.ribSphereOrigin = null;
|
|
1180
|
+
this.nrrd_states.sphere.skinSphereOrigin = null;
|
|
1181
|
+
this.nrrd_states.sphere.nippleSphereOrigin = null;
|
|
855
1182
|
}
|
|
856
1183
|
setSliceMoving(step) {
|
|
857
1184
|
if (this.protectedData.mainPreSlices) {
|
|
@@ -864,7 +1191,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
864
1191
|
this._sliceRAFId = null;
|
|
865
1192
|
const totalStep = this._pendingSliceStep;
|
|
866
1193
|
this._pendingSliceStep = 0;
|
|
867
|
-
this.protectedData.
|
|
1194
|
+
this.protectedData.isDrawing = true;
|
|
868
1195
|
this.setSyncsliceNum();
|
|
869
1196
|
this.dragOperator.updateIndex(totalStep);
|
|
870
1197
|
this.setIsDrawFalse(1000);
|
|
@@ -872,14 +1199,14 @@ export class NrrdTools extends DrawToolCore {
|
|
|
872
1199
|
}
|
|
873
1200
|
}
|
|
874
1201
|
setMainAreaSize(factor) {
|
|
875
|
-
this.nrrd_states.
|
|
876
|
-
if (this.nrrd_states.
|
|
877
|
-
this.nrrd_states.
|
|
1202
|
+
this.nrrd_states.view.sizeFactor = factor;
|
|
1203
|
+
if (this.nrrd_states.view.sizeFactor >= 8) {
|
|
1204
|
+
this.nrrd_states.view.sizeFactor = 8;
|
|
878
1205
|
}
|
|
879
|
-
else if (this.nrrd_states.
|
|
880
|
-
this.nrrd_states.
|
|
1206
|
+
else if (this.nrrd_states.view.sizeFactor <= 1) {
|
|
1207
|
+
this.nrrd_states.view.sizeFactor = 1;
|
|
881
1208
|
}
|
|
882
|
-
this.resizePaintArea(this.nrrd_states.
|
|
1209
|
+
this.resizePaintArea(this.nrrd_states.view.sizeFactor);
|
|
883
1210
|
this.resetPaintAreaUIPosition();
|
|
884
1211
|
// this.setIsDrawFalse(1000);
|
|
885
1212
|
}
|
|
@@ -893,27 +1220,27 @@ export class NrrdTools extends DrawToolCore {
|
|
|
893
1220
|
return this.nrrd_states;
|
|
894
1221
|
}
|
|
895
1222
|
getMaxSliceNum() {
|
|
896
|
-
if (this.nrrd_states.showContrast) {
|
|
1223
|
+
if (this.nrrd_states.view.showContrast) {
|
|
897
1224
|
return [
|
|
898
|
-
this.nrrd_states.maxIndex,
|
|
899
|
-
this.nrrd_states.maxIndex * this.protectedData.displaySlices.length,
|
|
1225
|
+
this.nrrd_states.view.maxIndex,
|
|
1226
|
+
this.nrrd_states.view.maxIndex * this.protectedData.displaySlices.length,
|
|
900
1227
|
];
|
|
901
1228
|
}
|
|
902
1229
|
else {
|
|
903
|
-
return [this.nrrd_states.maxIndex];
|
|
1230
|
+
return [this.nrrd_states.view.maxIndex];
|
|
904
1231
|
}
|
|
905
1232
|
}
|
|
906
1233
|
getCurrentSlicesNumAndContrastNum() {
|
|
907
1234
|
return {
|
|
908
|
-
|
|
909
|
-
contrastIndex: this.nrrd_states.contrastNum,
|
|
1235
|
+
currentSliceIndex: this.nrrd_states.view.currentSliceIndex,
|
|
1236
|
+
contrastIndex: this.nrrd_states.view.contrastNum,
|
|
910
1237
|
};
|
|
911
1238
|
}
|
|
912
1239
|
getCurrentSliceIndex() {
|
|
913
|
-
return Math.ceil(this.protectedData.mainPreSlices.index / this.nrrd_states.RSARatio);
|
|
1240
|
+
return Math.ceil(this.protectedData.mainPreSlices.index / this.nrrd_states.image.RSARatio);
|
|
914
1241
|
}
|
|
915
1242
|
getIsShowContrastState() {
|
|
916
|
-
return this.nrrd_states.showContrast;
|
|
1243
|
+
return this.nrrd_states.view.showContrast;
|
|
917
1244
|
}
|
|
918
1245
|
/**
|
|
919
1246
|
* Give a delay time to finish the last drawing before upcoming interrupt opreations.
|
|
@@ -923,7 +1250,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
923
1250
|
*/
|
|
924
1251
|
setIsDrawFalse(target) {
|
|
925
1252
|
this.preTimer = setTimeout(() => {
|
|
926
|
-
this.protectedData.
|
|
1253
|
+
this.protectedData.isDrawing = false;
|
|
927
1254
|
if (this.preTimer) {
|
|
928
1255
|
window.clearTimeout(this.preTimer);
|
|
929
1256
|
this.preTimer = undefined;
|
|
@@ -978,35 +1305,37 @@ export class NrrdTools extends DrawToolCore {
|
|
|
978
1305
|
// (also calls resizePaintArea → reloads masks, resizes canvases)
|
|
979
1306
|
this.setOriginCanvasAndPre();
|
|
980
1307
|
// update the show number div on top area
|
|
981
|
-
this.dragOperator.updateShowNumDiv(this.nrrd_states.contrastNum);
|
|
1308
|
+
this.dragOperator.updateShowNumDiv(this.nrrd_states.view.contrastNum);
|
|
982
1309
|
// repaint all contrast images
|
|
983
1310
|
this.repraintCurrentContrastSlice();
|
|
984
1311
|
// Refresh display after contrast repaint (no need for full resizePaintArea
|
|
985
1312
|
// since canvases were already resized in setOriginCanvasAndPre above)
|
|
986
1313
|
this.redrawDisplayCanvas();
|
|
987
1314
|
this.compositeAllLayers();
|
|
1315
|
+
// Sync slider metadata with current volume (replaces old getGuiSettings() side-effect)
|
|
1316
|
+
this.syncGuiParameterSettings();
|
|
988
1317
|
}
|
|
989
1318
|
setMainPreSlice() {
|
|
990
1319
|
this.protectedData.mainPreSlices = this.protectedData.displaySlices[0];
|
|
991
1320
|
if (this.protectedData.mainPreSlices) {
|
|
992
|
-
this.nrrd_states.RSARatio = this.protectedData.mainPreSlices.RSARatio;
|
|
1321
|
+
this.nrrd_states.image.RSARatio = this.protectedData.mainPreSlices.RSARatio;
|
|
993
1322
|
}
|
|
994
1323
|
}
|
|
995
1324
|
setOriginCanvasAndPre() {
|
|
996
1325
|
if (this.protectedData.mainPreSlices) {
|
|
997
|
-
if (this.nrrd_states.
|
|
998
|
-
this.nrrd_states.
|
|
1326
|
+
if (this.nrrd_states.view.preSliceIndex > this.nrrd_states.view.maxIndex)
|
|
1327
|
+
this.nrrd_states.view.preSliceIndex = this.nrrd_states.view.maxIndex;
|
|
999
1328
|
if (this.initState) {
|
|
1000
|
-
this.nrrd_states.
|
|
1329
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1001
1330
|
this.protectedData.mainPreSlices.initIndex *
|
|
1002
|
-
this.nrrd_states.RSARatio;
|
|
1003
|
-
this.nrrd_states.
|
|
1331
|
+
this.nrrd_states.image.RSARatio;
|
|
1332
|
+
this.nrrd_states.view.currentSliceIndex =
|
|
1004
1333
|
this.protectedData.mainPreSlices.initIndex;
|
|
1005
1334
|
}
|
|
1006
1335
|
else {
|
|
1007
1336
|
// !need to change
|
|
1008
1337
|
// todo
|
|
1009
|
-
this.protectedData.mainPreSlices.index = this.nrrd_states.
|
|
1338
|
+
this.protectedData.mainPreSlices.index = this.nrrd_states.view.preSliceIndex;
|
|
1010
1339
|
}
|
|
1011
1340
|
this.protectedData.canvases.originCanvas =
|
|
1012
1341
|
this.protectedData.mainPreSlices.canvas;
|
|
@@ -1017,34 +1346,35 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1017
1346
|
this.setMainPreSlice();
|
|
1018
1347
|
this.setOriginCanvasAndPre();
|
|
1019
1348
|
this.protectedData.currentShowingSlice = this.protectedData.mainPreSlices;
|
|
1020
|
-
this.nrrd_states.
|
|
1021
|
-
this.protectedData.mainPreSlices.initIndex * this.nrrd_states.RSARatio;
|
|
1022
|
-
this.nrrd_states.
|
|
1349
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1350
|
+
this.protectedData.mainPreSlices.initIndex * this.nrrd_states.image.RSARatio;
|
|
1351
|
+
this.nrrd_states.view.currentSliceIndex = this.protectedData.mainPreSlices.initIndex;
|
|
1023
1352
|
// Phase 6: Reset undo/redo stacks on new dataset load
|
|
1024
1353
|
this.undoManager.clearAll();
|
|
1025
1354
|
// compute max index
|
|
1026
1355
|
this.updateMaxIndex();
|
|
1027
|
-
this.dragOperator.updateShowNumDiv(this.nrrd_states.contrastNum);
|
|
1356
|
+
this.dragOperator.updateShowNumDiv(this.nrrd_states.view.contrastNum);
|
|
1357
|
+
this.syncGuiParameterSettings();
|
|
1028
1358
|
this.initState = false;
|
|
1029
1359
|
}
|
|
1030
1360
|
updateMaxIndex() {
|
|
1031
1361
|
if (this.protectedData.mainPreSlices) {
|
|
1032
|
-
this.nrrd_states.maxIndex = this.protectedData.mainPreSlices.MaxIndex;
|
|
1362
|
+
this.nrrd_states.view.maxIndex = this.protectedData.mainPreSlices.MaxIndex;
|
|
1033
1363
|
}
|
|
1034
1364
|
}
|
|
1035
1365
|
/**
|
|
1036
1366
|
* Update the original canvas size, allow set to threejs load one (pixel distance not the mm).
|
|
1037
|
-
* Then update the changedWidth and changedHeight based on the
|
|
1367
|
+
* Then update the changedWidth and changedHeight based on the sizeFactor.
|
|
1038
1368
|
*/
|
|
1039
1369
|
updateOriginAndChangedWH() {
|
|
1040
|
-
this.nrrd_states.originWidth =
|
|
1370
|
+
this.nrrd_states.image.originWidth =
|
|
1041
1371
|
this.protectedData.canvases.originCanvas.width;
|
|
1042
|
-
this.nrrd_states.originHeight =
|
|
1372
|
+
this.nrrd_states.image.originHeight =
|
|
1043
1373
|
this.protectedData.canvases.originCanvas.height;
|
|
1044
1374
|
// Let resizePaintArea be the sole setter of changedWidth/changedHeight.
|
|
1045
1375
|
// Setting them here would defeat the sizeChanged detection in resizePaintArea,
|
|
1046
1376
|
// causing canvas elements to keep stale dimensions after axis switches.
|
|
1047
|
-
this.resizePaintArea(this.nrrd_states.
|
|
1377
|
+
this.resizePaintArea(this.nrrd_states.view.sizeFactor);
|
|
1048
1378
|
this.resetPaintAreaUIPosition();
|
|
1049
1379
|
}
|
|
1050
1380
|
/**
|
|
@@ -1061,17 +1391,24 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1061
1391
|
appendLoadingbar(loadingbar) {
|
|
1062
1392
|
this.protectedData.mainAreaContainer.appendChild(loadingbar);
|
|
1063
1393
|
}
|
|
1064
|
-
|
|
1394
|
+
/**
|
|
1395
|
+
* Clear all annotations on the currently active layer across its entire 3D volume.
|
|
1396
|
+
* This resets all voxels globally for the active layer's `MaskVolume` (depth, width, height)
|
|
1397
|
+
* and triggers the `onClearLayerVolume` event to sync the wiped volume to the backend.
|
|
1398
|
+
* It also clears the undo/redo stack for the active layer ONLY.
|
|
1399
|
+
* Other background layers are not impacted by this operation.
|
|
1400
|
+
*/
|
|
1401
|
+
clearActiveLayer() {
|
|
1065
1402
|
// Phase 3 Task 3.1: Only clear the active layer's MaskVolume
|
|
1066
|
-
if (this.nrrd_states.dimensions.length === 3) {
|
|
1067
|
-
const [w, h, d] = this.nrrd_states.dimensions;
|
|
1068
|
-
const activeLayer = this.gui_states.layer;
|
|
1403
|
+
if (this.nrrd_states.image.dimensions.length === 3) {
|
|
1404
|
+
const [w, h, d] = this.nrrd_states.image.dimensions;
|
|
1405
|
+
const activeLayer = this.gui_states.layerChannel.layer;
|
|
1069
1406
|
// Re-init only the active layer's MaskVolume
|
|
1070
1407
|
this.protectedData.maskData.volumes[activeLayer] = new MaskVolume(w, h, d, 1);
|
|
1071
1408
|
// Phase 6 Task 6.6: Clear undo/redo stack for this layer (volume too large to snapshot)
|
|
1072
1409
|
this.undoManager.clearLayer(activeLayer);
|
|
1073
1410
|
// Phase 3 Task 3.2: Notify external that this layer's volume was cleared
|
|
1074
|
-
this.
|
|
1411
|
+
this.annotationCallbacks.onLayerVolumeCleared(activeLayer);
|
|
1075
1412
|
}
|
|
1076
1413
|
// Invalidate reusable slice buffer
|
|
1077
1414
|
this.invalidateSliceBuffer();
|
|
@@ -1110,6 +1447,59 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1110
1447
|
target.canvas.width = target.canvas.width;
|
|
1111
1448
|
}
|
|
1112
1449
|
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Enter sphere mode.
|
|
1452
|
+
*
|
|
1453
|
+
* Clears all layer canvases and the master composite canvas so that
|
|
1454
|
+
* only the sphere overlay is visible. Does NOT touch MaskVolume data.
|
|
1455
|
+
* Also disables drag mode to prevent slice dragging conflicts.
|
|
1456
|
+
*
|
|
1457
|
+
* Called when sphere mode is toggled on (keyboard shortcut or GUI).
|
|
1458
|
+
*/
|
|
1459
|
+
enterSphereMode() {
|
|
1460
|
+
var _a;
|
|
1461
|
+
// Disable left-click drag for slice navigation
|
|
1462
|
+
this.dragOperator.removeDragMode();
|
|
1463
|
+
// Tell EventRouter we're in sphere mode so Shift/draw is blocked
|
|
1464
|
+
(_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.setGuiTool('sphere');
|
|
1465
|
+
// Clear all layer canvases (NOT MaskVolumes — just visual canvas)
|
|
1466
|
+
const w = this.nrrd_states.view.changedWidth;
|
|
1467
|
+
const h = this.nrrd_states.view.changedHeight;
|
|
1468
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
1469
|
+
const target = this.protectedData.layerTargets.get(layerId);
|
|
1470
|
+
if (target) {
|
|
1471
|
+
target.ctx.clearRect(0, 0, target.canvas.width, target.canvas.height);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
// Clear master composite canvas
|
|
1475
|
+
this.protectedData.ctxes.drawingLayerMasterCtx.clearRect(0, 0, w, h);
|
|
1476
|
+
// Refresh sphere overlay from volume (shows existing sphere data on re-entry)
|
|
1477
|
+
this.refreshSphereOverlay();
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* Exit sphere mode.
|
|
1481
|
+
*
|
|
1482
|
+
* Clears sphere overlay, restores all layer MaskVolume data onto
|
|
1483
|
+
* their canvases by temporarily lifting the sphere guard in
|
|
1484
|
+
* reloadMasksFromVolume and calling it.
|
|
1485
|
+
*
|
|
1486
|
+
* Called when sphere mode is toggled off (keyboard shortcut or GUI).
|
|
1487
|
+
*/
|
|
1488
|
+
exitSphereMode() {
|
|
1489
|
+
var _a;
|
|
1490
|
+
// Restore left-click drag for slice navigation
|
|
1491
|
+
this.dragOperator.configDragMode();
|
|
1492
|
+
// Restore EventRouter guiTool to pencil (default drawing tool)
|
|
1493
|
+
(_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.setGuiTool('pencil');
|
|
1494
|
+
// Clear sphere canvas overlay
|
|
1495
|
+
this.protectedData.ctxes.drawingSphereCtx.clearRect(0, 0, this.protectedData.canvases.drawingSphereCanvas.width, this.protectedData.canvases.drawingSphereCanvas.height);
|
|
1496
|
+
// resetLayerCanvas clears the layer canvas elements
|
|
1497
|
+
this.resetLayerCanvas();
|
|
1498
|
+
// Temporarily lift sphere guard so reloadMasksFromVolume can run.
|
|
1499
|
+
// gui_states.sphere is already set to false by the caller before
|
|
1500
|
+
// calling this method, so reloadMasksFromVolume will proceed normally.
|
|
1501
|
+
this.reloadMasksFromVolume();
|
|
1502
|
+
}
|
|
1113
1503
|
redrawMianPreOnDisplayCanvas() {
|
|
1114
1504
|
var _a;
|
|
1115
1505
|
this.protectedData.canvases.displayCanvas.width =
|
|
@@ -1121,8 +1511,8 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1121
1511
|
if (this.protectedData.mainPreSlices) {
|
|
1122
1512
|
this.protectedData.mainPreSlices.repaint.call(this.protectedData.mainPreSlices);
|
|
1123
1513
|
this.flipDisplayImageByAxis();
|
|
1124
|
-
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.drawImage(this.protectedData.canvases.originCanvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
1125
|
-
this.resizePaintArea(this.nrrd_states.
|
|
1514
|
+
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.drawImage(this.protectedData.canvases.originCanvas, 0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
1515
|
+
this.resizePaintArea(this.nrrd_states.view.sizeFactor);
|
|
1126
1516
|
}
|
|
1127
1517
|
}
|
|
1128
1518
|
/**
|
|
@@ -1130,10 +1520,10 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1130
1520
|
* @param factor number
|
|
1131
1521
|
*/
|
|
1132
1522
|
resizePaintArea(factor) {
|
|
1133
|
-
const newWidth = Math.floor(this.nrrd_states.originWidth * factor);
|
|
1134
|
-
const newHeight = Math.floor(this.nrrd_states.originHeight * factor);
|
|
1135
|
-
const sizeChanged = newWidth !== this.nrrd_states.changedWidth ||
|
|
1136
|
-
newHeight !== this.nrrd_states.changedHeight;
|
|
1523
|
+
const newWidth = Math.floor(this.nrrd_states.image.originWidth * factor);
|
|
1524
|
+
const newHeight = Math.floor(this.nrrd_states.image.originHeight * factor);
|
|
1525
|
+
const sizeChanged = newWidth !== this.nrrd_states.view.changedWidth ||
|
|
1526
|
+
newHeight !== this.nrrd_states.view.changedHeight;
|
|
1137
1527
|
// Always clear display/drawing/origin canvases (needed for contrast updates)
|
|
1138
1528
|
this.protectedData.canvases.originCanvas.width =
|
|
1139
1529
|
this.protectedData.canvases.originCanvas.width;
|
|
@@ -1146,8 +1536,8 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1146
1536
|
// Skipping this avoids the expensive reloadMasksFromVolume() call
|
|
1147
1537
|
// during contrast toggle (where size stays the same).
|
|
1148
1538
|
this.resetLayerCanvas();
|
|
1149
|
-
this.nrrd_states.changedWidth = newWidth;
|
|
1150
|
-
this.nrrd_states.changedHeight = newHeight;
|
|
1539
|
+
this.nrrd_states.view.changedWidth = newWidth;
|
|
1540
|
+
this.nrrd_states.view.changedHeight = newHeight;
|
|
1151
1541
|
this.protectedData.canvases.displayCanvas.width = newWidth;
|
|
1152
1542
|
this.protectedData.canvases.displayCanvas.height = newHeight;
|
|
1153
1543
|
this.protectedData.canvases.drawingCanvas.width = newWidth;
|
|
@@ -1169,18 +1559,25 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1169
1559
|
// valid data, just recomposite to master for the start() render loop.
|
|
1170
1560
|
this.compositeAllLayers();
|
|
1171
1561
|
}
|
|
1562
|
+
// Refresh sphere overlay from volume after resize/contrast change
|
|
1563
|
+
this.refreshSphereOverlay();
|
|
1172
1564
|
}
|
|
1173
1565
|
/**
|
|
1174
1566
|
* Phase 3: Reload all mask layers from MaskVolume using buffer reuse
|
|
1175
1567
|
* Replaces the old reloadMaskToLayer approach
|
|
1176
1568
|
*/
|
|
1177
1569
|
reloadMasksFromVolume() {
|
|
1570
|
+
// When sphere mode is active, do NOT redraw layer masks.
|
|
1571
|
+
// Layer mask data should remain hidden until the user exits sphere mode.
|
|
1572
|
+
if (this.gui_states.mode.sphere) {
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1178
1575
|
const axis = this.protectedData.axis;
|
|
1179
|
-
let sliceIndex = this.nrrd_states.
|
|
1576
|
+
let sliceIndex = this.nrrd_states.view.currentSliceIndex;
|
|
1180
1577
|
// Clamp sliceIndex to valid range for current axis
|
|
1181
|
-
// (
|
|
1578
|
+
// (currentSliceIndex may not be updated yet when switching axes)
|
|
1182
1579
|
try {
|
|
1183
|
-
const vol = this.getVolumeForLayer(this.nrrd_states.layers[0]);
|
|
1580
|
+
const vol = this.getVolumeForLayer(this.nrrd_states.image.layers[0]);
|
|
1184
1581
|
const dims = vol.getDimensions();
|
|
1185
1582
|
const maxSlice = axis === "x" ? dims.width : axis === "y" ? dims.height : dims.depth;
|
|
1186
1583
|
if (sliceIndex >= maxSlice)
|
|
@@ -1193,10 +1590,10 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1193
1590
|
const buffer = this.getOrCreateSliceBuffer(axis);
|
|
1194
1591
|
if (!buffer)
|
|
1195
1592
|
return;
|
|
1196
|
-
const w = this.nrrd_states.changedWidth;
|
|
1197
|
-
const h = this.nrrd_states.changedHeight;
|
|
1593
|
+
const w = this.nrrd_states.view.changedWidth;
|
|
1594
|
+
const h = this.nrrd_states.view.changedHeight;
|
|
1198
1595
|
// Clear and render each layer using the shared buffer
|
|
1199
|
-
for (const layerId of this.nrrd_states.layers) {
|
|
1596
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
1200
1597
|
const target = this.protectedData.layerTargets.get(layerId);
|
|
1201
1598
|
if (!target)
|
|
1202
1599
|
continue;
|
|
@@ -1217,15 +1614,15 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1217
1614
|
var _a, _b, _c, _d, _e, _f;
|
|
1218
1615
|
if (this.protectedData.axis === "x") {
|
|
1219
1616
|
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.scale(-1, -1);
|
|
1220
|
-
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.translate(-this.nrrd_states.changedWidth, -this.nrrd_states.changedHeight);
|
|
1617
|
+
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.translate(-this.nrrd_states.view.changedWidth, -this.nrrd_states.view.changedHeight);
|
|
1221
1618
|
}
|
|
1222
1619
|
else if (this.protectedData.axis === "z") {
|
|
1223
1620
|
(_c = this.protectedData.ctxes.displayCtx) === null || _c === void 0 ? void 0 : _c.scale(1, -1);
|
|
1224
|
-
(_d = this.protectedData.ctxes.displayCtx) === null || _d === void 0 ? void 0 : _d.translate(0, -this.nrrd_states.changedHeight);
|
|
1621
|
+
(_d = this.protectedData.ctxes.displayCtx) === null || _d === void 0 ? void 0 : _d.translate(0, -this.nrrd_states.view.changedHeight);
|
|
1225
1622
|
}
|
|
1226
1623
|
else if (this.protectedData.axis === "y") {
|
|
1227
1624
|
(_e = this.protectedData.ctxes.displayCtx) === null || _e === void 0 ? void 0 : _e.scale(1, -1);
|
|
1228
|
-
(_f = this.protectedData.ctxes.displayCtx) === null || _f === void 0 ? void 0 : _f.translate(0, -this.nrrd_states.changedHeight);
|
|
1625
|
+
(_f = this.protectedData.ctxes.displayCtx) === null || _f === void 0 ? void 0 : _f.translate(0, -this.nrrd_states.view.changedHeight);
|
|
1229
1626
|
}
|
|
1230
1627
|
}
|
|
1231
1628
|
clearDictionary(dic) {
|
|
@@ -1242,21 +1639,21 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1242
1639
|
switch (!!axis ? axis : this.protectedData.axis) {
|
|
1243
1640
|
case "x":
|
|
1244
1641
|
this.protectedData.canvases.emptyCanvas.width =
|
|
1245
|
-
this.nrrd_states.nrrd_z_pixel;
|
|
1642
|
+
this.nrrd_states.image.nrrd_z_pixel;
|
|
1246
1643
|
this.protectedData.canvases.emptyCanvas.height =
|
|
1247
|
-
this.nrrd_states.nrrd_y_pixel;
|
|
1644
|
+
this.nrrd_states.image.nrrd_y_pixel;
|
|
1248
1645
|
break;
|
|
1249
1646
|
case "y":
|
|
1250
1647
|
this.protectedData.canvases.emptyCanvas.width =
|
|
1251
|
-
this.nrrd_states.nrrd_x_pixel;
|
|
1648
|
+
this.nrrd_states.image.nrrd_x_pixel;
|
|
1252
1649
|
this.protectedData.canvases.emptyCanvas.height =
|
|
1253
|
-
this.nrrd_states.nrrd_z_pixel;
|
|
1650
|
+
this.nrrd_states.image.nrrd_z_pixel;
|
|
1254
1651
|
break;
|
|
1255
1652
|
case "z":
|
|
1256
1653
|
this.protectedData.canvases.emptyCanvas.width =
|
|
1257
|
-
this.nrrd_states.nrrd_x_pixel;
|
|
1654
|
+
this.nrrd_states.image.nrrd_x_pixel;
|
|
1258
1655
|
this.protectedData.canvases.emptyCanvas.height =
|
|
1259
|
-
this.nrrd_states.nrrd_y_pixel;
|
|
1656
|
+
this.nrrd_states.image.nrrd_y_pixel;
|
|
1260
1657
|
break;
|
|
1261
1658
|
}
|
|
1262
1659
|
}
|
|
@@ -1278,7 +1675,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1278
1675
|
this.protectedData.currentShowingSlice.repaint.call(this.protectedData.currentShowingSlice);
|
|
1279
1676
|
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.save();
|
|
1280
1677
|
this.flipDisplayImageByAxis();
|
|
1281
|
-
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.drawImage(this.protectedData.currentShowingSlice.canvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
1678
|
+
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.drawImage(this.protectedData.currentShowingSlice.canvas, 0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
1282
1679
|
(_c = this.protectedData.ctxes.displayCtx) === null || _c === void 0 ? void 0 : _c.restore();
|
|
1283
1680
|
}
|
|
1284
1681
|
}
|