copper3d 3.0.0 → 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 +32 -18
- package/dist/Utils/segmentation/CommToolsData.js +69 -152
- package/dist/Utils/segmentation/CommToolsData.js.map +1 -1
- package/dist/Utils/segmentation/DragOperator.d.ts +10 -2
- package/dist/Utils/segmentation/DragOperator.js +18 -8
- package/dist/Utils/segmentation/DragOperator.js.map +1 -1
- package/dist/Utils/segmentation/DrawToolCore.d.ts +24 -18
- package/dist/Utils/segmentation/DrawToolCore.js +255 -436
- package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
- package/dist/Utils/segmentation/NrrdTools.d.ts +152 -10
- package/dist/Utils/segmentation/NrrdTools.js +604 -203
- package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
- package/dist/Utils/segmentation/core/MaskVolume.d.ts +1 -34
- package/dist/Utils/segmentation/core/MaskVolume.js +24 -124
- 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 -65
- 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 -9
- 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 -0
- package/dist/Utils/segmentation/eventRouter/EventRouter.js +19 -8
- 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 +11 -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 +12 -32
- package/dist/Utils/segmentation/tools/ImageStoreHelper.js +45 -102
- 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 -3
- 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 +5 -4
- 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 +2451 -1622
- package/dist/bundle.umd.js +2451 -1622
- 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 +32 -18
- package/dist/types/Utils/segmentation/DragOperator.d.ts +10 -2
- package/dist/types/Utils/segmentation/DrawToolCore.d.ts +24 -18
- package/dist/types/Utils/segmentation/NrrdTools.d.ts +152 -10
- package/dist/types/Utils/segmentation/core/MaskVolume.d.ts +1 -34
- 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 -65
- package/dist/types/Utils/segmentation/coreTools/gui.d.ts +12 -9
- package/dist/types/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -0
- package/dist/types/Utils/segmentation/eventRouter/types.d.ts +3 -3
- package/dist/types/Utils/segmentation/tools/BaseTool.d.ts +11 -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 +12 -32
- package/dist/types/Utils/segmentation/tools/PanTool.d.ts +53 -0
- package/dist/types/Utils/segmentation/tools/SphereTool.d.ts +208 -3
- 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,11 +1,13 @@
|
|
|
1
1
|
import { CommToolsData } from "./CommToolsData";
|
|
2
|
-
import {
|
|
2
|
+
import { switchPencilIcon } from "../utils";
|
|
3
3
|
import { EventRouter } from "./eventRouter";
|
|
4
4
|
import { SphereTool } from "./tools/SphereTool";
|
|
5
5
|
import { CrosshairTool } from "./tools/CrosshairTool";
|
|
6
6
|
import { ContrastTool } from "./tools/ContrastTool";
|
|
7
7
|
import { ZoomTool } from "./tools/ZoomTool";
|
|
8
8
|
import { EraserTool } from "./tools/EraserTool";
|
|
9
|
+
import { PanTool } from "./tools/PanTool";
|
|
10
|
+
import { DrawingTool } from "./tools/DrawingTool";
|
|
9
11
|
import { ImageStoreHelper } from "./tools/ImageStoreHelper";
|
|
10
12
|
import { UndoManager } from "./core";
|
|
11
13
|
export class DrawToolCore extends CommToolsData {
|
|
@@ -37,12 +39,10 @@ export class DrawToolCore extends CommToolsData {
|
|
|
37
39
|
this.eraserUrls = [];
|
|
38
40
|
this.pencilUrls = [];
|
|
39
41
|
this.undoManager = new UndoManager();
|
|
40
|
-
/** Snapshot of the active layer's slice captured on mouse-down (before drawing). */
|
|
41
|
-
this.preDrawSlice = null;
|
|
42
|
-
this.preDrawAxis = "z";
|
|
43
|
-
this.preDrawSliceIndex = 0;
|
|
44
42
|
// Centralized event router
|
|
45
43
|
this.eventRouter = null;
|
|
44
|
+
/** Slice index recorded when paintOnCanvas() starts, guards stale-click */
|
|
45
|
+
this.paintSliceIndex = 0;
|
|
46
46
|
// need to return to parent
|
|
47
47
|
this.start = () => { };
|
|
48
48
|
/*************************************May consider to move outside *******************************************/
|
|
@@ -50,7 +50,7 @@ export class DrawToolCore extends CommToolsData {
|
|
|
50
50
|
this.protectedData.ctxes.drawingCtx.beginPath();
|
|
51
51
|
this.protectedData.ctxes.drawingCtx.moveTo(x1, y1);
|
|
52
52
|
this.protectedData.ctxes.drawingCtx.lineTo(x2, y2);
|
|
53
|
-
this.protectedData.ctxes.drawingCtx.strokeStyle = this.gui_states.color;
|
|
53
|
+
this.protectedData.ctxes.drawingCtx.strokeStyle = this.gui_states.drawing.color;
|
|
54
54
|
this.protectedData.ctxes.drawingCtx.stroke();
|
|
55
55
|
};
|
|
56
56
|
this.configContrastDragMode = () => {
|
|
@@ -76,6 +76,7 @@ export class DrawToolCore extends CommToolsData {
|
|
|
76
76
|
gui_states: this.gui_states,
|
|
77
77
|
protectedData: this.protectedData,
|
|
78
78
|
cursorPage: this.cursorPage,
|
|
79
|
+
callbacks: this.annotationCallbacks,
|
|
79
80
|
};
|
|
80
81
|
this.imageStoreHelper = new ImageStoreHelper(toolCtx, {
|
|
81
82
|
setEmptyCanvasSize: (axis) => this.setEmptyCanvasSize(axis),
|
|
@@ -84,8 +85,6 @@ export class DrawToolCore extends CommToolsData {
|
|
|
84
85
|
this.sphereTool = new SphereTool(toolCtx, {
|
|
85
86
|
setEmptyCanvasSize: (axis) => this.setEmptyCanvasSize(axis),
|
|
86
87
|
drawImageOnEmptyImage: (canvas) => this.drawImageOnEmptyImage(canvas),
|
|
87
|
-
storeImageToAxis: (index, paintedImages, imageData, axis) => this.imageStoreHelper.storeImageToAxis(index, paintedImages, imageData, axis),
|
|
88
|
-
createEmptyPaintImage: (dimensions, paintImages) => this.createEmptyPaintImage(dimensions, paintImages),
|
|
89
88
|
});
|
|
90
89
|
this.crosshairTool = new CrosshairTool(toolCtx);
|
|
91
90
|
this.contrastTool = new ContrastTool(toolCtx, this.container, this.contrastEventPrameters, {
|
|
@@ -98,6 +97,18 @@ export class DrawToolCore extends CommToolsData {
|
|
|
98
97
|
setIsDrawFalse: (target) => this.setIsDrawFalse(target),
|
|
99
98
|
});
|
|
100
99
|
this.eraserTool = new EraserTool(toolCtx);
|
|
100
|
+
this.panTool = new PanTool(toolCtx, {
|
|
101
|
+
zoomActionAfterDrawSphere: () => this.zoomActionAfterDrawSphere(),
|
|
102
|
+
});
|
|
103
|
+
this.drawingTool = new DrawingTool(toolCtx, {
|
|
104
|
+
setCurrentLayer: () => this.setCurrentLayer(),
|
|
105
|
+
compositeAllLayers: () => this.compositeAllLayers(),
|
|
106
|
+
syncLayerSliceData: (index, layer) => this.syncLayerSliceData(index, layer),
|
|
107
|
+
filterDrawedImage: (axis, index) => this.filterDrawedImage(axis, index),
|
|
108
|
+
getVolumeForLayer: (layer) => this.getVolumeForLayer(layer),
|
|
109
|
+
pushUndoDelta: (delta) => this.undoManager.push(delta),
|
|
110
|
+
getEraserUrls: () => this.eraserUrls,
|
|
111
|
+
});
|
|
101
112
|
}
|
|
102
113
|
initDrawToolCore() {
|
|
103
114
|
// Initialize EventRouter for centralized event handling
|
|
@@ -108,40 +119,28 @@ export class DrawToolCore extends CommToolsData {
|
|
|
108
119
|
// Use string comparison to avoid TypeScript narrowing issues
|
|
109
120
|
const prev = prevMode;
|
|
110
121
|
const next = newMode;
|
|
111
|
-
// Sync EventRouter mode changes with existing state flags
|
|
112
|
-
if (next === 'draw') {
|
|
113
|
-
this.protectedData.Is_Shift_Pressed = true;
|
|
114
|
-
this.nrrd_states.enableCursorChoose = false;
|
|
115
|
-
}
|
|
116
|
-
else if (prev === 'draw') {
|
|
117
|
-
this.protectedData.Is_Shift_Pressed = false;
|
|
118
|
-
}
|
|
119
122
|
if (next === 'contrast') {
|
|
120
|
-
this.protectedData.Is_Ctrl_Pressed = true;
|
|
121
|
-
this.protectedData.Is_Shift_Pressed = false;
|
|
122
123
|
this.configContrastDragMode();
|
|
123
124
|
}
|
|
124
125
|
else if (prev === 'contrast') {
|
|
125
|
-
this.protectedData.Is_Ctrl_Pressed = false;
|
|
126
126
|
this.removeContrastDragMode();
|
|
127
|
-
this.gui_states.readyToUpdate = true;
|
|
127
|
+
this.gui_states.viewConfig.readyToUpdate = true;
|
|
128
128
|
}
|
|
129
129
|
if (next === 'crosshair') {
|
|
130
|
-
this.
|
|
131
|
-
this.protectedData.Is_Draw = false;
|
|
132
|
-
}
|
|
133
|
-
else if (prev === 'crosshair') {
|
|
134
|
-
this.nrrd_states.enableCursorChoose = false;
|
|
130
|
+
this.protectedData.isDrawing = false;
|
|
135
131
|
}
|
|
136
132
|
}
|
|
137
133
|
});
|
|
134
|
+
// Inject eventRouter into ToolContext so tools can query mode/state
|
|
135
|
+
const toolCtx = this.sphereTool['ctx'];
|
|
136
|
+
toolCtx.eventRouter = this.eventRouter;
|
|
138
137
|
// Configure keyboard settings from class field
|
|
139
138
|
this.eventRouter.setKeyboardSettings(this._keyboardSettings);
|
|
140
139
|
// Track undo flag for Ctrl+Z handling
|
|
141
140
|
let undoFlag = false;
|
|
142
141
|
// Register keyboard handlers with EventRouter
|
|
143
142
|
this.eventRouter.setKeydownHandler((ev) => {
|
|
144
|
-
var _a;
|
|
143
|
+
var _a, _b, _c, _d;
|
|
145
144
|
if (this._configKeyBoard)
|
|
146
145
|
return;
|
|
147
146
|
// Handle undo (Ctrl+Z)
|
|
@@ -155,40 +154,58 @@ export class DrawToolCore extends CommToolsData {
|
|
|
155
154
|
if ((ev.ctrlKey || ev.metaKey) && (ev.key === redoKey || (ev.shiftKey && ev.key === undoKeyUpper))) {
|
|
156
155
|
this.redoLastPainting();
|
|
157
156
|
}
|
|
158
|
-
// Handle crosshair toggle
|
|
157
|
+
// Handle crosshair toggle (allowed in drawing tools AND sphere mode)
|
|
159
158
|
if (ev.key === this._keyboardSettings.crosshair) {
|
|
160
|
-
|
|
161
|
-
(_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.toggleCrosshair();
|
|
162
|
-
}
|
|
159
|
+
(_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.toggleCrosshair();
|
|
163
160
|
}
|
|
164
161
|
// Handle draw mode (Shift key) - EventRouter already tracks this
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
// EventRouter's handleKeyDown will enforce mutual exclusion
|
|
163
|
+
if (ev.key === this._keyboardSettings.draw && !this.gui_states.mode.sphere) {
|
|
164
|
+
if ((_b = this.eventRouter) === null || _b === void 0 ? void 0 : _b.isCtrlHeld()) {
|
|
167
165
|
return; // Ctrl takes priority
|
|
168
166
|
}
|
|
169
167
|
// EventRouter will set mode to 'draw' via internal handler
|
|
170
168
|
}
|
|
169
|
+
// Handle sphere mode toggle
|
|
170
|
+
if (ev.key === this._keyboardSettings.sphere) {
|
|
171
|
+
// Block during draw mode or contrast mode
|
|
172
|
+
if (((_c = this.eventRouter) === null || _c === void 0 ? void 0 : _c.isShiftHeld()) || ((_d = this.eventRouter) === null || _d === void 0 ? void 0 : _d.isCtrlHeld())) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
this.gui_states.mode.sphere = !this.gui_states.mode.sphere;
|
|
176
|
+
if (this.gui_states.mode.sphere) {
|
|
177
|
+
this.enterSphereMode();
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
this.exitSphereMode();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
171
183
|
});
|
|
172
184
|
this.eventRouter.setKeyupHandler((ev) => {
|
|
173
|
-
var _a, _b, _c, _d;
|
|
185
|
+
var _a, _b, _c, _d, _e, _f;
|
|
174
186
|
if (this._configKeyBoard)
|
|
175
187
|
return;
|
|
176
188
|
// Handle Ctrl key release (contrast mode toggle)
|
|
177
189
|
if (this._keyboardSettings.contrast.includes(ev.key)) {
|
|
178
190
|
if (undoFlag) {
|
|
179
|
-
this.gui_states.readyToUpdate = true;
|
|
191
|
+
this.gui_states.viewConfig.readyToUpdate = true;
|
|
180
192
|
undoFlag = false;
|
|
181
193
|
return;
|
|
182
194
|
}
|
|
183
195
|
// Skip mode toggle when contrast shortcut is disabled
|
|
184
196
|
if (!((_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.isContrastEnabled()))
|
|
185
197
|
return;
|
|
198
|
+
// Block contrast toggle during crosshair, draw, or sphere (mutual exclusion)
|
|
199
|
+
if (((_b = this.eventRouter) === null || _b === void 0 ? void 0 : _b.isCrosshairEnabled()) || ((_c = this.eventRouter) === null || _c === void 0 ? void 0 : _c.getMode()) === 'draw')
|
|
200
|
+
return;
|
|
201
|
+
if (this.gui_states.mode.sphere)
|
|
202
|
+
return;
|
|
186
203
|
// Toggle contrast mode manually since it's on keyup
|
|
187
|
-
if (((
|
|
188
|
-
(
|
|
204
|
+
if (((_d = this.eventRouter) === null || _d === void 0 ? void 0 : _d.getMode()) !== 'contrast') {
|
|
205
|
+
(_e = this.eventRouter) === null || _e === void 0 ? void 0 : _e.setMode('contrast');
|
|
189
206
|
}
|
|
190
207
|
else {
|
|
191
|
-
(
|
|
208
|
+
(_f = this.eventRouter) === null || _f === void 0 ? void 0 : _f.setMode('idle');
|
|
192
209
|
}
|
|
193
210
|
}
|
|
194
211
|
});
|
|
@@ -200,78 +217,38 @@ export class DrawToolCore extends CommToolsData {
|
|
|
200
217
|
}
|
|
201
218
|
setPencilIconUrls(urls) {
|
|
202
219
|
this.pencilUrls = urls;
|
|
203
|
-
this.gui_states.defaultPaintCursor = switchPencilIcon("dot", this.pencilUrls);
|
|
220
|
+
this.gui_states.viewConfig.defaultPaintCursor = switchPencilIcon("dot", this.pencilUrls);
|
|
204
221
|
this.protectedData.canvases.drawingCanvas.style.cursor =
|
|
205
|
-
this.gui_states.defaultPaintCursor;
|
|
222
|
+
this.gui_states.viewConfig.defaultPaintCursor;
|
|
206
223
|
}
|
|
207
224
|
setCurrentLayer() {
|
|
208
|
-
const layer = this.gui_states.layer;
|
|
225
|
+
const layer = this.gui_states.layerChannel.layer;
|
|
209
226
|
let target = this.protectedData.layerTargets.get(layer);
|
|
210
227
|
if (!target) {
|
|
211
228
|
// Fallback to first layer
|
|
212
|
-
const firstId = this.nrrd_states.layers[0];
|
|
229
|
+
const firstId = this.nrrd_states.image.layers[0];
|
|
213
230
|
target = this.protectedData.layerTargets.get(firstId);
|
|
214
231
|
}
|
|
215
232
|
return { ctx: target.ctx, canvas: target.canvas };
|
|
216
233
|
}
|
|
217
234
|
draw(opts) {
|
|
218
235
|
if (!!opts) {
|
|
219
|
-
|
|
220
|
-
if (opts
|
|
221
|
-
this.
|
|
236
|
+
// Phase 2: Store callbacks in annotationCallbacks instead of nrrd_states
|
|
237
|
+
if (opts.getMaskData) {
|
|
238
|
+
this.annotationCallbacks.onMaskChanged = opts.getMaskData;
|
|
239
|
+
}
|
|
240
|
+
if (opts.onClearLayerVolume) {
|
|
241
|
+
this.annotationCallbacks.onLayerVolumeCleared = opts.onClearLayerVolume;
|
|
242
|
+
}
|
|
243
|
+
if (opts.getSphereData) {
|
|
244
|
+
this.annotationCallbacks.onSphereChanged = opts.getSphereData;
|
|
245
|
+
}
|
|
246
|
+
if (opts.getCalculateSpherePositionsData) {
|
|
247
|
+
this.annotationCallbacks.onCalculatorPositionsChanged = opts.getCalculateSpherePositionsData;
|
|
222
248
|
}
|
|
223
|
-
this.nrrd_states.getSphere = opts === null || opts === void 0 ? void 0 : opts.getSphereData;
|
|
224
|
-
this.nrrd_states.getCalculateSpherePositions = opts === null || opts === void 0 ? void 0 : opts.getCalculateSpherePositionsData;
|
|
225
249
|
}
|
|
226
250
|
this.paintOnCanvas();
|
|
227
251
|
}
|
|
228
|
-
drawCalSphereDown(x, y, sliceIndex, cal_position) {
|
|
229
|
-
this.nrrd_states.sphereRadius = 5;
|
|
230
|
-
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
231
|
-
let mouseX = x / this.nrrd_states.sizeFoctor;
|
|
232
|
-
let mouseY = y / this.nrrd_states.sizeFoctor;
|
|
233
|
-
// record mouseX,Y, and enable crosshair function
|
|
234
|
-
this.nrrd_states.sphereOrigin[this.protectedData.axis] = [
|
|
235
|
-
mouseX,
|
|
236
|
-
mouseY,
|
|
237
|
-
sliceIndex,
|
|
238
|
-
];
|
|
239
|
-
this.setUpSphereOrigins(mouseX, mouseY, sliceIndex);
|
|
240
|
-
// Note the sphere origin here is x, y, z
|
|
241
|
-
// x: pixel x, y: pixel y, z: slice index (mm)
|
|
242
|
-
switch (cal_position) {
|
|
243
|
-
case "tumour":
|
|
244
|
-
this.nrrd_states.tumourSphereOrigin = JSON.parse(JSON.stringify(this.nrrd_states.sphereOrigin));
|
|
245
|
-
break;
|
|
246
|
-
case "skin":
|
|
247
|
-
this.nrrd_states.skinSphereOrigin = JSON.parse(JSON.stringify(this.nrrd_states.sphereOrigin));
|
|
248
|
-
break;
|
|
249
|
-
case "nipple":
|
|
250
|
-
this.nrrd_states.nippleSphereOrigin = JSON.parse(JSON.stringify(this.nrrd_states.sphereOrigin));
|
|
251
|
-
break;
|
|
252
|
-
case "ribcage":
|
|
253
|
-
this.nrrd_states.ribSphereOrigin = JSON.parse(JSON.stringify(this.nrrd_states.sphereOrigin));
|
|
254
|
-
break;
|
|
255
|
-
}
|
|
256
|
-
this.nrrd_states.cursorPageX = mouseX;
|
|
257
|
-
this.nrrd_states.cursorPageY = mouseY;
|
|
258
|
-
this.enableCrosshair();
|
|
259
|
-
// draw circle setup width/height for sphere canvas
|
|
260
|
-
this.drawCalculatorSphere(this.nrrd_states.sphereRadius);
|
|
261
|
-
this.protectedData.canvases.drawingCanvas.addEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
262
|
-
}
|
|
263
|
-
drawCalSphereUp() {
|
|
264
|
-
// TODO send data to outside
|
|
265
|
-
// this.clearStoreImages();
|
|
266
|
-
this.clearSpherePrintStoreImages();
|
|
267
|
-
this.drawCalculatorSphereOnEachViews("x");
|
|
268
|
-
this.drawCalculatorSphereOnEachViews("y");
|
|
269
|
-
this.drawCalculatorSphereOnEachViews("z");
|
|
270
|
-
!!this.nrrd_states.getCalculateSpherePositions &&
|
|
271
|
-
this.nrrd_states.getCalculateSpherePositions(this.nrrd_states.tumourSphereOrigin, this.nrrd_states.skinSphereOrigin, this.nrrd_states.ribSphereOrigin, this.nrrd_states.nippleSphereOrigin, this.protectedData.axis);
|
|
272
|
-
this.zoomActionAfterDrawSphere();
|
|
273
|
-
this.protectedData.canvases.drawingCanvas.removeEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
274
|
-
}
|
|
275
252
|
zoomActionAfterDrawSphere() {
|
|
276
253
|
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
277
254
|
}
|
|
@@ -280,28 +257,16 @@ export class DrawToolCore extends CommToolsData {
|
|
|
280
257
|
}
|
|
281
258
|
paintOnCanvas() {
|
|
282
259
|
var _a, _b, _c;
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
let rightclicked = false;
|
|
288
|
-
let panelMoveInnerX = 0;
|
|
289
|
-
let panelMoveInnerY = 0;
|
|
290
|
-
// todo
|
|
291
|
-
// let currentSliceIndex = this.protectedData.mainPreSlices.index;
|
|
292
|
-
let currentSliceIndex = this.protectedData.mainPreSlices.index;
|
|
293
|
-
// draw lines starts position
|
|
294
|
-
let Is_Painting = false;
|
|
295
|
-
let lines = [];
|
|
296
|
-
const clearArc = this.useEraser();
|
|
260
|
+
// Initialize tools for this paint cycle
|
|
261
|
+
this.drawingTool.reset(this.useEraser());
|
|
262
|
+
this.panTool.reset();
|
|
263
|
+
this.paintSliceIndex = this.protectedData.mainPreSlices.index;
|
|
297
264
|
this.updateOriginAndChangedWH();
|
|
298
265
|
this.initAllCanvas();
|
|
299
266
|
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.save();
|
|
300
267
|
this.flipDisplayImageByAxis();
|
|
301
|
-
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.drawImage(this.protectedData.canvases.originCanvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
268
|
+
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.drawImage(this.protectedData.canvases.originCanvas, 0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
302
269
|
(_c = this.protectedData.ctxes.displayCtx) === null || _c === void 0 ? void 0 : _c.restore();
|
|
303
|
-
this.protectedData.previousDrawingImage =
|
|
304
|
-
this.protectedData.ctxes.drawingCtx.getImageData(0, 0, this.protectedData.canvases.drawingCanvas.width, this.protectedData.canvases.drawingCanvas.height);
|
|
305
270
|
// let a global variable to store the wheel move event
|
|
306
271
|
// Remove existing listener before creating a new one to prevent leaks
|
|
307
272
|
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
@@ -318,124 +283,62 @@ export class DrawToolCore extends CommToolsData {
|
|
|
318
283
|
});
|
|
319
284
|
// sphere Wheel
|
|
320
285
|
this.drawingPrameters.handleSphereWheel = this.configMouseSphereWheel();
|
|
321
|
-
// pan move
|
|
322
|
-
this.drawingPrameters.handleOnPanMouseMove = (e) => {
|
|
323
|
-
this.protectedData.canvases.drawingCanvas.style.cursor = "grabbing";
|
|
324
|
-
this.nrrd_states.previousPanelL = e.clientX - panelMoveInnerX;
|
|
325
|
-
this.nrrd_states.previousPanelT = e.clientY - panelMoveInnerY;
|
|
326
|
-
this.protectedData.canvases.displayCanvas.style.left =
|
|
327
|
-
this.protectedData.canvases.drawingCanvas.style.left =
|
|
328
|
-
this.nrrd_states.previousPanelL + "px";
|
|
329
|
-
this.protectedData.canvases.displayCanvas.style.top =
|
|
330
|
-
this.protectedData.canvases.drawingCanvas.style.top =
|
|
331
|
-
this.nrrd_states.previousPanelT + "px";
|
|
332
|
-
};
|
|
286
|
+
// pan move — now handled by PanTool (listeners managed internally)
|
|
333
287
|
// brush circle move
|
|
334
288
|
this.drawingPrameters.handleOnDrawingBrushCricleMove = (e) => {
|
|
335
289
|
e.preventDefault();
|
|
336
|
-
this.nrrd_states.
|
|
337
|
-
this.nrrd_states.
|
|
338
|
-
if (this.nrrd_states.
|
|
339
|
-
this.nrrd_states.
|
|
340
|
-
this.nrrd_states.
|
|
290
|
+
this.nrrd_states.interaction.mouseOverX = e.offsetX;
|
|
291
|
+
this.nrrd_states.interaction.mouseOverY = e.offsetY;
|
|
292
|
+
if (this.nrrd_states.interaction.mouseOverX === undefined) {
|
|
293
|
+
this.nrrd_states.interaction.mouseOverX = e.clientX;
|
|
294
|
+
this.nrrd_states.interaction.mouseOverY = e.clientY;
|
|
341
295
|
}
|
|
342
296
|
if (e.type === "mouseout") {
|
|
343
|
-
this.nrrd_states.
|
|
297
|
+
this.nrrd_states.interaction.mouseOver = false;
|
|
344
298
|
this.protectedData.canvases.drawingCanvas.removeEventListener("mousemove", this.drawingPrameters.handleOnDrawingBrushCricleMove);
|
|
345
299
|
}
|
|
346
300
|
else if (e.type === "mouseover") {
|
|
347
|
-
this.nrrd_states.
|
|
301
|
+
this.nrrd_states.interaction.mouseOver = true;
|
|
348
302
|
this.protectedData.canvases.drawingCanvas.addEventListener("mousemove", this.drawingPrameters.handleOnDrawingBrushCricleMove);
|
|
349
303
|
}
|
|
350
304
|
};
|
|
351
|
-
// drawing move
|
|
305
|
+
// drawing move — delegated to DrawingTool
|
|
352
306
|
this.drawingPrameters.handleOnDrawingMouseMove = (e) => {
|
|
353
|
-
this.
|
|
354
|
-
if (Is_Painting) {
|
|
355
|
-
if (this.gui_states.Eraser) {
|
|
356
|
-
this.nrrd_states.stepClear = 1;
|
|
357
|
-
// drawingCtx.clearRect(e.offsetX - 5, e.offsetY - 5, 25, 25);
|
|
358
|
-
clearArc(e.offsetX, e.offsetY, this.gui_states.brushAndEraserSize);
|
|
359
|
-
}
|
|
360
|
-
else {
|
|
361
|
-
lines.push({ x: e.offsetX, y: e.offsetY });
|
|
362
|
-
this.paintOnCanvasLayer(e.offsetX, e.offsetY);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
307
|
+
this.drawingTool.onPointerMove(e);
|
|
365
308
|
};
|
|
366
309
|
this.drawingPrameters.handleOnDrawingMouseDown = (e) => {
|
|
367
|
-
|
|
310
|
+
var _a, _b, _c;
|
|
311
|
+
if (this.drawingTool.isActive || this.panTool.isActive) {
|
|
368
312
|
this.protectedData.canvases.drawingCanvas.removeEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
369
313
|
this.protectedData.ctxes.drawingLayerMasterCtx.closePath();
|
|
370
314
|
return;
|
|
371
315
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (currentSliceIndex !== this.protectedData.mainPreSlices.index) {
|
|
375
|
-
this.protectedData.previousDrawingImage =
|
|
376
|
-
this.protectedData.ctxes.emptyCtx.createImageData(1, 1);
|
|
377
|
-
currentSliceIndex = this.protectedData.mainPreSlices.index;
|
|
316
|
+
if (this.paintSliceIndex !== this.protectedData.mainPreSlices.index) {
|
|
317
|
+
this.paintSliceIndex = this.protectedData.mainPreSlices.index;
|
|
378
318
|
}
|
|
379
319
|
// remove it when mouse click down
|
|
380
320
|
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
381
321
|
if (e.button === 0) {
|
|
382
|
-
if (this.
|
|
383
|
-
|
|
384
|
-
lines = [];
|
|
385
|
-
Is_Painting = true;
|
|
386
|
-
this.protectedData.Is_Draw = true;
|
|
387
|
-
if (this.gui_states.Eraser) {
|
|
388
|
-
// this.protectedData.canvases.drawingCanvas.style.cursor =
|
|
389
|
-
// "url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_48.png) 48 48, crosshair";
|
|
390
|
-
this.eraserUrls.length > 0
|
|
391
|
-
? (this.protectedData.canvases.drawingCanvas.style.cursor =
|
|
392
|
-
switchEraserSize(this.gui_states.brushAndEraserSize, this.eraserUrls))
|
|
393
|
-
: (this.protectedData.canvases.drawingCanvas.style.cursor =
|
|
394
|
-
switchEraserSize(this.gui_states.brushAndEraserSize));
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
this.protectedData.canvases.drawingCanvas.style.cursor =
|
|
398
|
-
this.gui_states.defaultPaintCursor;
|
|
399
|
-
}
|
|
400
|
-
this.nrrd_states.drawStartPos.x = e.offsetX;
|
|
401
|
-
this.nrrd_states.drawStartPos.y = e.offsetY;
|
|
402
|
-
// Capture pre-draw slice snapshot for undo
|
|
403
|
-
try {
|
|
404
|
-
this.preDrawAxis = this.protectedData.axis;
|
|
405
|
-
this.preDrawSliceIndex = this.nrrd_states.currentIndex;
|
|
406
|
-
const vol = this.getVolumeForLayer(this.gui_states.layer);
|
|
407
|
-
this.preDrawSlice = vol.getSliceUint8(this.preDrawSliceIndex, this.preDrawAxis).data.slice();
|
|
408
|
-
}
|
|
409
|
-
catch (_a) {
|
|
410
|
-
this.preDrawSlice = null;
|
|
411
|
-
}
|
|
322
|
+
if (((_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.getMode()) === 'draw') {
|
|
323
|
+
this.drawingTool.onPointerDown(e);
|
|
412
324
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
413
325
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointermove", this.drawingPrameters.handleOnDrawingMouseMove);
|
|
414
326
|
}
|
|
415
|
-
else if (this.
|
|
416
|
-
this.nrrd_states.cursorPageX =
|
|
417
|
-
e.offsetX / this.nrrd_states.
|
|
418
|
-
this.nrrd_states.cursorPageY =
|
|
419
|
-
e.offsetY / this.nrrd_states.
|
|
327
|
+
else if ((_b = this.eventRouter) === null || _b === void 0 ? void 0 : _b.isCrosshairEnabled()) {
|
|
328
|
+
this.nrrd_states.interaction.cursorPageX =
|
|
329
|
+
e.offsetX / this.nrrd_states.view.sizeFactor;
|
|
330
|
+
this.nrrd_states.interaction.cursorPageY =
|
|
331
|
+
e.offsetY / this.nrrd_states.view.sizeFactor;
|
|
420
332
|
this.enableCrosshair();
|
|
421
333
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
422
334
|
}
|
|
423
|
-
else if (this.gui_states.sphere && !this.
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
else if (this.gui_states.calculator && !this.nrrd_states.enableCursorChoose) {
|
|
427
|
-
this.drawCalSphereDown(e.offsetX, e.offsetY, this.nrrd_states.currentIndex, this.gui_states.cal_distance);
|
|
335
|
+
else if (this.gui_states.mode.sphere && !((_c = this.eventRouter) === null || _c === void 0 ? void 0 : _c.isCrosshairEnabled())) {
|
|
336
|
+
this.handleSphereClick(e);
|
|
428
337
|
}
|
|
429
338
|
}
|
|
430
339
|
else if (e.button === 2) {
|
|
431
|
-
|
|
432
|
-
let offsetX = this.protectedData.canvases.drawingCanvas.offsetLeft;
|
|
433
|
-
let offsetY = this.protectedData.canvases.drawingCanvas.offsetTop;
|
|
434
|
-
panelMoveInnerX = e.clientX - offsetX;
|
|
435
|
-
panelMoveInnerY = e.clientY - offsetY;
|
|
436
|
-
this.protectedData.canvases.drawingCanvas.style.cursor = "grab";
|
|
340
|
+
this.panTool.onPointerDown(e);
|
|
437
341
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
438
|
-
this.protectedData.canvases.drawingCanvas.addEventListener("pointermove", this.drawingPrameters.handleOnPanMouseMove);
|
|
439
342
|
}
|
|
440
343
|
else {
|
|
441
344
|
return;
|
|
@@ -452,174 +355,65 @@ export class DrawToolCore extends CommToolsData {
|
|
|
452
355
|
// Fallback for legacy mode without EventRouter
|
|
453
356
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointerdown", this.drawingPrameters.handleOnDrawingMouseDown, true);
|
|
454
357
|
}
|
|
455
|
-
const sphere = (e) => {
|
|
456
|
-
// set sphere size
|
|
457
|
-
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
458
|
-
let mouseX = e.offsetX / this.nrrd_states.sizeFoctor;
|
|
459
|
-
let mouseY = e.offsetY / this.nrrd_states.sizeFoctor;
|
|
460
|
-
// record mouseX,Y, and enable crosshair function
|
|
461
|
-
this.nrrd_states.sphereOrigin[this.protectedData.axis] = [
|
|
462
|
-
mouseX,
|
|
463
|
-
mouseY,
|
|
464
|
-
this.nrrd_states.currentIndex,
|
|
465
|
-
];
|
|
466
|
-
this.setUpSphereOrigins(mouseX, mouseY, this.nrrd_states.currentIndex);
|
|
467
|
-
this.nrrd_states.cursorPageX = mouseX;
|
|
468
|
-
this.nrrd_states.cursorPageY = mouseY;
|
|
469
|
-
this.enableCrosshair();
|
|
470
|
-
// draw circle setup width/height for sphere canvas
|
|
471
|
-
this.drawSphere(mouseX, mouseY, this.nrrd_states.sphereRadius);
|
|
472
|
-
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleSphereWheel, true);
|
|
473
|
-
this.protectedData.canvases.drawingCanvas.addEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
474
|
-
};
|
|
475
|
-
const redrawPreviousImageToLayerCtx = (ctx) => {
|
|
476
|
-
var _a;
|
|
477
|
-
const tempPreImg = (_a = this.filterDrawedImage(this.protectedData.axis, this.nrrd_states.currentIndex)) === null || _a === void 0 ? void 0 : _a.image;
|
|
478
|
-
this.protectedData.canvases.emptyCanvas.width =
|
|
479
|
-
this.protectedData.canvases.emptyCanvas.width;
|
|
480
|
-
if (tempPreImg) {
|
|
481
|
-
this.protectedData.previousDrawingImage = tempPreImg;
|
|
482
|
-
}
|
|
483
|
-
this.protectedData.ctxes.emptyCtx.putImageData(tempPreImg, 0, 0);
|
|
484
|
-
// No flip needed: MaskVolume stores in source coordinates (matching the
|
|
485
|
-
// Three.js / layer canvas convention). The layer canvas is in screen
|
|
486
|
-
// coordinates, which already match the source coordinate system.
|
|
487
|
-
ctx.imageSmoothingEnabled = false;
|
|
488
|
-
ctx.drawImage(this.protectedData.canvases.emptyCanvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
489
|
-
};
|
|
490
358
|
this.drawingPrameters.handleOnDrawingMouseUp = (e) => {
|
|
359
|
+
var _a, _b, _c;
|
|
491
360
|
if (e.button === 0) {
|
|
492
|
-
if (this.
|
|
493
|
-
|
|
494
|
-
let { ctx, canvas } = this.setCurrentLayer();
|
|
495
|
-
ctx.closePath();
|
|
361
|
+
if (((_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.getMode()) === 'draw' || this.drawingTool.painting) {
|
|
362
|
+
this.drawingTool.onPointerUp(e);
|
|
496
363
|
this.protectedData.canvases.drawingCanvas.removeEventListener("pointermove", this.drawingPrameters.handleOnDrawingMouseMove);
|
|
497
|
-
if (!this.gui_states.Eraser) {
|
|
498
|
-
if (this.gui_states.pencil) {
|
|
499
|
-
// Clear only the current layer canvas (NOT master)
|
|
500
|
-
canvas.width = canvas.width;
|
|
501
|
-
// Redraw previous layer data from volume
|
|
502
|
-
redrawPreviousImageToLayerCtx(ctx);
|
|
503
|
-
// Draw new pencil strokes on current layer canvas
|
|
504
|
-
ctx.beginPath();
|
|
505
|
-
ctx.moveTo(lines[0].x, lines[0].y);
|
|
506
|
-
for (let i = 1; i < lines.length; i++) {
|
|
507
|
-
ctx.lineTo(lines[i].x, lines[i].y);
|
|
508
|
-
}
|
|
509
|
-
ctx.closePath();
|
|
510
|
-
ctx.lineWidth = 1;
|
|
511
|
-
ctx.fillStyle = this.gui_states.fillColor;
|
|
512
|
-
ctx.fill();
|
|
513
|
-
// Composite ALL layers to master (not just current layer)
|
|
514
|
-
this.compositeAllLayers();
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
this.protectedData.previousDrawingImage =
|
|
518
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.getImageData(0, 0, this.protectedData.canvases.drawingCanvasLayerMaster.width, this.protectedData.canvases.drawingCanvasLayerMaster.height);
|
|
519
|
-
this.storeAllImages(this.nrrd_states.currentIndex, this.gui_states.layer);
|
|
520
|
-
if (this.gui_states.Eraser) {
|
|
521
|
-
const restLayers = this.getRestLayer();
|
|
522
|
-
this.storeEachLayerImage(this.nrrd_states.currentIndex, restLayers[0]);
|
|
523
|
-
this.storeEachLayerImage(this.nrrd_states.currentIndex, restLayers[1]);
|
|
524
|
-
}
|
|
525
|
-
Is_Painting = false;
|
|
526
|
-
// Push delta to UndoManager (new Delta-based undo system)
|
|
527
|
-
if (this.preDrawSlice) {
|
|
528
|
-
try {
|
|
529
|
-
const vol = this.getVolumeForLayer(this.gui_states.layer);
|
|
530
|
-
const { data: newSlice } = vol.getSliceUint8(this.preDrawSliceIndex, this.preDrawAxis);
|
|
531
|
-
const delta = {
|
|
532
|
-
layerId: this.gui_states.layer,
|
|
533
|
-
axis: this.preDrawAxis,
|
|
534
|
-
sliceIndex: this.preDrawSliceIndex,
|
|
535
|
-
oldSlice: this.preDrawSlice,
|
|
536
|
-
newSlice: newSlice.slice(),
|
|
537
|
-
};
|
|
538
|
-
this.undoManager.push(delta);
|
|
539
|
-
}
|
|
540
|
-
catch (_a) {
|
|
541
|
-
// Volume not ready — skip
|
|
542
|
-
}
|
|
543
|
-
this.preDrawSlice = null;
|
|
544
|
-
}
|
|
545
364
|
// add wheel after pointer up
|
|
546
365
|
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel, {
|
|
547
366
|
passive: false,
|
|
548
367
|
});
|
|
549
368
|
}
|
|
550
|
-
else if (this.gui_states.sphere &&
|
|
551
|
-
!this.
|
|
552
|
-
//
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
for (let i = 0; i < this.nrrd_states.sphereRadius; i++) {
|
|
559
|
-
this.drawSphereOnEachViews(i, "x");
|
|
560
|
-
this.drawSphereOnEachViews(i, "y");
|
|
561
|
-
this.drawSphereOnEachViews(i, "z");
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
!!this.nrrd_states.getSphere &&
|
|
565
|
-
this.nrrd_states.getSphere(this.nrrd_states.sphereOrigin.z, this.nrrd_states.sphereRadius / this.nrrd_states.sizeFoctor);
|
|
369
|
+
else if (this.gui_states.mode.sphere &&
|
|
370
|
+
!((_b = this.eventRouter) === null || _b === void 0 ? void 0 : _b.isCrosshairEnabled())) {
|
|
371
|
+
// Write all placed calculator spheres to volume
|
|
372
|
+
this.sphereTool.writeAllCalculatorSpheresToVolume();
|
|
373
|
+
// Render current slice from volume to sphere canvas
|
|
374
|
+
this.sphereTool.refreshSphereCanvas();
|
|
375
|
+
this.annotationCallbacks.onSphereChanged(this.nrrd_states.sphere.sphereOrigin.z, this.nrrd_states.sphere.sphereRadius / this.nrrd_states.view.sizeFactor);
|
|
376
|
+
this.annotationCallbacks.onCalculatorPositionsChanged(this.nrrd_states.sphere.tumourSphereOrigin, this.nrrd_states.sphere.skinSphereOrigin, this.nrrd_states.sphere.ribSphereOrigin, this.nrrd_states.sphere.nippleSphereOrigin, this.protectedData.axis);
|
|
566
377
|
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleSphereWheel, true);
|
|
567
378
|
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
568
379
|
this.protectedData.canvases.drawingCanvas.removeEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
380
|
+
this.zoomActionAfterDrawSphere();
|
|
569
381
|
}
|
|
570
|
-
else if (
|
|
571
|
-
this.
|
|
382
|
+
else if (this.gui_states.mode.sphere &&
|
|
383
|
+
((_c = this.eventRouter) === null || _c === void 0 ? void 0 : _c.isCrosshairEnabled())) {
|
|
572
384
|
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
573
385
|
this.protectedData.canvases.drawingCanvas.removeEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
574
386
|
}
|
|
575
|
-
else if (this.gui_states.calculator &&
|
|
576
|
-
!this.nrrd_states.enableCursorChoose) {
|
|
577
|
-
// When mouse up
|
|
578
|
-
this.drawCalSphereUp();
|
|
579
|
-
}
|
|
580
387
|
}
|
|
581
388
|
else if (e.button === 2) {
|
|
582
|
-
|
|
583
|
-
this.protectedData.canvases.drawingCanvas.style.cursor = "grab";
|
|
584
|
-
setTimeout(() => {
|
|
585
|
-
this.protectedData.canvases.drawingCanvas.style.cursor = this.gui_states.defaultPaintCursor;
|
|
586
|
-
}, 2000);
|
|
587
|
-
this.protectedData.canvases.drawingCanvas.removeEventListener("pointermove", this.drawingPrameters.handleOnPanMouseMove);
|
|
588
|
-
if (this.gui_states.sphere || this.gui_states.calculator) {
|
|
589
|
-
this.zoomActionAfterDrawSphere();
|
|
590
|
-
}
|
|
389
|
+
this.panTool.onPointerUp(e, this.gui_states.viewConfig.defaultPaintCursor);
|
|
591
390
|
}
|
|
592
391
|
else {
|
|
593
392
|
return;
|
|
594
393
|
}
|
|
595
|
-
if (!this.gui_states.pencil) {
|
|
394
|
+
if (!this.gui_states.mode.pencil) {
|
|
596
395
|
this.setIsDrawFalse(100);
|
|
597
396
|
}
|
|
598
397
|
};
|
|
599
|
-
this.protectedData.canvases.drawingCanvas.addEventListener("pointerleave", (
|
|
600
|
-
|
|
601
|
-
if (
|
|
602
|
-
leftclicked = false;
|
|
603
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.closePath();
|
|
398
|
+
this.protectedData.canvases.drawingCanvas.addEventListener("pointerleave", () => {
|
|
399
|
+
const wasDrawing = this.drawingTool.onPointerLeave();
|
|
400
|
+
if (wasDrawing) {
|
|
604
401
|
this.protectedData.canvases.drawingCanvas.removeEventListener("pointermove", this.drawingPrameters.handleOnDrawingMouseMove);
|
|
605
402
|
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleSphereWheel, true);
|
|
606
403
|
}
|
|
607
|
-
|
|
608
|
-
rightclicked = false;
|
|
609
|
-
this.protectedData.canvases.drawingCanvas.style.cursor = "grab";
|
|
610
|
-
this.protectedData.canvases.drawingCanvas.removeEventListener("pointermove", this.drawingPrameters.handleOnPanMouseMove);
|
|
611
|
-
}
|
|
404
|
+
this.panTool.onPointerLeave();
|
|
612
405
|
this.setIsDrawFalse(100);
|
|
613
|
-
if (this.gui_states.pencil) {
|
|
406
|
+
if (this.gui_states.mode.pencil) {
|
|
614
407
|
this.setIsDrawFalse(1000);
|
|
615
408
|
}
|
|
616
409
|
});
|
|
617
410
|
this.start = () => {
|
|
618
|
-
|
|
619
|
-
|
|
411
|
+
var _a, _b;
|
|
412
|
+
if (this.gui_states.viewConfig.readyToUpdate) {
|
|
413
|
+
this.protectedData.ctxes.drawingCtx.clearRect(0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
620
414
|
this.protectedData.ctxes.drawingCtx.globalAlpha =
|
|
621
|
-
this.gui_states.globalAlpha;
|
|
622
|
-
if (this.protectedData.
|
|
415
|
+
this.gui_states.drawing.globalAlpha;
|
|
416
|
+
if (this.protectedData.isDrawing) {
|
|
623
417
|
this.protectedData.ctxes.drawingLayerMasterCtx.lineCap = "round";
|
|
624
418
|
this.protectedData.ctxes.drawingLayerMasterCtx.globalAlpha = 1;
|
|
625
419
|
for (const [, target] of this.protectedData.layerTargets) {
|
|
@@ -628,63 +422,82 @@ export class DrawToolCore extends CommToolsData {
|
|
|
628
422
|
}
|
|
629
423
|
}
|
|
630
424
|
else {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
425
|
+
// Use EventRouter mode for mutually exclusive crosshair vs draw rendering
|
|
426
|
+
const currentMode = (_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.getMode();
|
|
427
|
+
if (currentMode === 'draw') {
|
|
428
|
+
// Draw mode: show brush circle preview
|
|
429
|
+
if (!this.gui_states.mode.pencil &&
|
|
430
|
+
!this.gui_states.mode.eraser &&
|
|
431
|
+
this.nrrd_states.interaction.mouseOver) {
|
|
432
|
+
this.protectedData.ctxes.drawingCtx.clearRect(0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
636
433
|
this.protectedData.ctxes.drawingCtx.fillStyle =
|
|
637
|
-
this.gui_states.brushColor;
|
|
434
|
+
this.gui_states.drawing.brushColor;
|
|
638
435
|
this.protectedData.ctxes.drawingCtx.beginPath();
|
|
639
|
-
this.protectedData.ctxes.drawingCtx.arc(this.nrrd_states.
|
|
436
|
+
this.protectedData.ctxes.drawingCtx.arc(this.nrrd_states.interaction.mouseOverX, this.nrrd_states.interaction.mouseOverY, this.gui_states.drawing.brushAndEraserSize / 2 + 1, 0, Math.PI * 2);
|
|
640
437
|
this.protectedData.ctxes.drawingCtx.strokeStyle =
|
|
641
|
-
this.gui_states.brushColor;
|
|
438
|
+
this.gui_states.drawing.brushColor;
|
|
642
439
|
this.protectedData.ctxes.drawingCtx.stroke();
|
|
643
440
|
}
|
|
644
441
|
}
|
|
645
|
-
if (this.
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
const
|
|
649
|
-
this.
|
|
650
|
-
this.drawLine(0,
|
|
442
|
+
else if (currentMode === 'crosshair' || ((_b = this.eventRouter) === null || _b === void 0 ? void 0 : _b.isCrosshairEnabled())) {
|
|
443
|
+
// Crosshair mode: show red cross lines (mutually exclusive with draw)
|
|
444
|
+
this.protectedData.ctxes.drawingCtx.clearRect(0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
445
|
+
const ex = this.nrrd_states.interaction.cursorPageX * this.nrrd_states.view.sizeFactor;
|
|
446
|
+
const ey = this.nrrd_states.interaction.cursorPageY * this.nrrd_states.view.sizeFactor;
|
|
447
|
+
this.drawLine(ex, 0, ex, this.nrrd_states.view.changedWidth);
|
|
448
|
+
this.drawLine(0, ey, this.nrrd_states.view.changedHeight, ey);
|
|
651
449
|
}
|
|
652
450
|
}
|
|
653
|
-
// globalAlpha was set to gui_states.globalAlpha at the top of start().
|
|
451
|
+
// globalAlpha was set to gui_states.drawing.globalAlpha at the top of start().
|
|
654
452
|
// Master stores full-alpha pixels; transparency applied here only.
|
|
655
453
|
this.protectedData.ctxes.drawingCtx.drawImage(this.protectedData.canvases.drawingCanvasLayerMaster, 0, 0);
|
|
454
|
+
// Draw sphere overlay from cached sphere canvas (separate from master).
|
|
455
|
+
// During preview: drawSphere/drawCalculatorSphere update the sphere canvas.
|
|
456
|
+
// After placement: refreshSphereCanvas renders from sphereMaskVolume.
|
|
457
|
+
if (this.gui_states.mode.sphere) {
|
|
458
|
+
this.protectedData.ctxes.drawingCtx.drawImage(this.protectedData.canvases.drawingSphereCanvas, 0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
459
|
+
}
|
|
656
460
|
}
|
|
657
461
|
else {
|
|
658
462
|
this.redrawDisplayCanvas();
|
|
659
463
|
}
|
|
660
464
|
};
|
|
661
465
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
466
|
+
/** Extracted from paintOnCanvas() — handles sphere placement on left-click */
|
|
467
|
+
handleSphereClick(e) {
|
|
468
|
+
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
469
|
+
let mouseX = e.offsetX / this.nrrd_states.view.sizeFactor;
|
|
470
|
+
let mouseY = e.offsetY / this.nrrd_states.view.sizeFactor;
|
|
471
|
+
// record mouseX,Y, and enable crosshair function
|
|
472
|
+
this.nrrd_states.sphere.sphereOrigin[this.protectedData.axis] = [
|
|
473
|
+
mouseX,
|
|
474
|
+
mouseY,
|
|
475
|
+
this.nrrd_states.view.currentSliceIndex,
|
|
476
|
+
];
|
|
477
|
+
this.setUpSphereOrigins(mouseX, mouseY, this.nrrd_states.view.currentSliceIndex);
|
|
478
|
+
// Store origin for the active sphere type
|
|
479
|
+
const calPos = this.gui_states.mode.activeSphereType;
|
|
480
|
+
switch (calPos) {
|
|
481
|
+
case "tumour":
|
|
482
|
+
this.nrrd_states.sphere.tumourSphereOrigin = JSON.parse(JSON.stringify(this.nrrd_states.sphere.sphereOrigin));
|
|
483
|
+
break;
|
|
484
|
+
case "skin":
|
|
485
|
+
this.nrrd_states.sphere.skinSphereOrigin = JSON.parse(JSON.stringify(this.nrrd_states.sphere.sphereOrigin));
|
|
486
|
+
break;
|
|
487
|
+
case "nipple":
|
|
488
|
+
this.nrrd_states.sphere.nippleSphereOrigin = JSON.parse(JSON.stringify(this.nrrd_states.sphere.sphereOrigin));
|
|
489
|
+
break;
|
|
490
|
+
case "ribcage":
|
|
491
|
+
this.nrrd_states.sphere.ribSphereOrigin = JSON.parse(JSON.stringify(this.nrrd_states.sphere.sphereOrigin));
|
|
492
|
+
break;
|
|
672
493
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
this.drawLinesOnLayer(ctx, x, y);
|
|
681
|
-
// Composite all layers to master to preserve other layers' data
|
|
682
|
-
this.compositeAllLayers();
|
|
683
|
-
// reset drawing start position to current position.
|
|
684
|
-
this.nrrd_states.drawStartPos.x = x;
|
|
685
|
-
this.nrrd_states.drawStartPos.y = y;
|
|
686
|
-
// need to flag the map as needing updating.
|
|
687
|
-
this.protectedData.mainPreSlices.mesh.material.map.needsUpdate = true;
|
|
494
|
+
this.nrrd_states.interaction.cursorPageX = mouseX;
|
|
495
|
+
this.nrrd_states.interaction.cursorPageY = mouseY;
|
|
496
|
+
this.enableCrosshair();
|
|
497
|
+
// draw circle setup width/height for sphere canvas
|
|
498
|
+
this.drawCalculatorSphere(this.nrrd_states.sphere.sphereRadius);
|
|
499
|
+
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleSphereWheel, true);
|
|
500
|
+
this.protectedData.canvases.drawingCanvas.addEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
688
501
|
}
|
|
689
502
|
initAllCanvas() {
|
|
690
503
|
/**
|
|
@@ -693,42 +506,42 @@ export class DrawToolCore extends CommToolsData {
|
|
|
693
506
|
this.protectedData.canvases.displayCanvas.style.position = "absolute";
|
|
694
507
|
this.protectedData.canvases.displayCanvas.style.zIndex = "9";
|
|
695
508
|
this.protectedData.canvases.displayCanvas.width =
|
|
696
|
-
this.nrrd_states.changedWidth;
|
|
509
|
+
this.nrrd_states.view.changedWidth;
|
|
697
510
|
this.protectedData.canvases.displayCanvas.height =
|
|
698
|
-
this.nrrd_states.changedHeight;
|
|
511
|
+
this.nrrd_states.view.changedHeight;
|
|
699
512
|
/**
|
|
700
513
|
* drawing canvas
|
|
701
514
|
*/
|
|
702
515
|
this.protectedData.canvases.drawingCanvas.style.zIndex = "10";
|
|
703
516
|
this.protectedData.canvases.drawingCanvas.style.position = "absolute";
|
|
704
517
|
this.protectedData.canvases.drawingCanvas.width =
|
|
705
|
-
this.nrrd_states.changedWidth;
|
|
518
|
+
this.nrrd_states.view.changedWidth;
|
|
706
519
|
this.protectedData.canvases.drawingCanvas.height =
|
|
707
|
-
this.nrrd_states.changedHeight;
|
|
520
|
+
this.nrrd_states.view.changedHeight;
|
|
708
521
|
this.protectedData.canvases.drawingCanvas.style.cursor =
|
|
709
|
-
this.gui_states.defaultPaintCursor;
|
|
522
|
+
this.gui_states.viewConfig.defaultPaintCursor;
|
|
710
523
|
this.protectedData.canvases.drawingCanvas.oncontextmenu = () => false;
|
|
711
524
|
/**
|
|
712
525
|
* layer1
|
|
713
526
|
* it should be hide, so we don't need to add it to mainAreaContainer
|
|
714
527
|
*/
|
|
715
528
|
this.protectedData.canvases.drawingCanvasLayerMaster.width =
|
|
716
|
-
this.nrrd_states.changedWidth;
|
|
529
|
+
this.nrrd_states.view.changedWidth;
|
|
717
530
|
this.protectedData.canvases.drawingCanvasLayerMaster.height =
|
|
718
|
-
this.nrrd_states.changedHeight;
|
|
531
|
+
this.nrrd_states.view.changedHeight;
|
|
719
532
|
for (const [, target] of this.protectedData.layerTargets) {
|
|
720
|
-
target.canvas.width = this.nrrd_states.changedWidth;
|
|
721
|
-
target.canvas.height = this.nrrd_states.changedHeight;
|
|
533
|
+
target.canvas.width = this.nrrd_states.view.changedWidth;
|
|
534
|
+
target.canvas.height = this.nrrd_states.view.changedHeight;
|
|
722
535
|
}
|
|
723
536
|
/**
|
|
724
537
|
* display and drawing canvas container
|
|
725
538
|
*/
|
|
726
|
-
// this.mainAreaContainer.style.width = this.nrrd_states.changedWidth + "px";
|
|
727
|
-
// this.mainAreaContainer.style.height = this.nrrd_states.changedHeight + "px";
|
|
539
|
+
// this.mainAreaContainer.style.width = this.nrrd_states.view.changedWidth + "px";
|
|
540
|
+
// this.mainAreaContainer.style.height = this.nrrd_states.view.changedHeight + "px";
|
|
728
541
|
this.mainAreaContainer.style.width =
|
|
729
|
-
this.nrrd_states.originWidth * 8 + "px";
|
|
542
|
+
this.nrrd_states.image.originWidth * 8 + "px";
|
|
730
543
|
this.mainAreaContainer.style.height =
|
|
731
|
-
this.nrrd_states.originHeight * 8 + "px";
|
|
544
|
+
this.nrrd_states.image.originHeight * 8 + "px";
|
|
732
545
|
this.mainAreaContainer.appendChild(this.protectedData.canvases.displayCanvas);
|
|
733
546
|
this.mainAreaContainer.appendChild(this.protectedData.canvases.drawingCanvas);
|
|
734
547
|
}
|
|
@@ -776,6 +589,15 @@ export class DrawToolCore extends CommToolsData {
|
|
|
776
589
|
drawSphere(mouseX, mouseY, radius) {
|
|
777
590
|
this.sphereTool.drawSphere(mouseX, mouseY, radius);
|
|
778
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* Refresh sphere canvas from sphereMaskVolume for the current slice/axis.
|
|
594
|
+
* Called after view changes (slice switch, zoom, contrast, axis switch).
|
|
595
|
+
*/
|
|
596
|
+
refreshSphereOverlay() {
|
|
597
|
+
if (this.gui_states.mode.sphere) {
|
|
598
|
+
this.sphereTool.refreshSphereCanvas();
|
|
599
|
+
}
|
|
600
|
+
}
|
|
779
601
|
/**
|
|
780
602
|
* Convert cursor point between axis views.
|
|
781
603
|
* Delegated to CrosshairTool.
|
|
@@ -788,44 +610,42 @@ export class DrawToolCore extends CommToolsData {
|
|
|
788
610
|
}
|
|
789
611
|
/****************************layer div controls****************************************************/
|
|
790
612
|
getRestLayer() {
|
|
791
|
-
const layers = this.nrrd_states.layers;
|
|
613
|
+
const layers = this.nrrd_states.image.layers;
|
|
792
614
|
const restLayer = layers.filter((item) => {
|
|
793
|
-
return item !== this.gui_states.layer;
|
|
615
|
+
return item !== this.gui_states.layerChannel.layer;
|
|
794
616
|
});
|
|
795
617
|
return restLayer;
|
|
796
618
|
}
|
|
797
619
|
/**************************** Undo/Redo functions (Phase 6 — Delta-based) ****************************/
|
|
798
620
|
/**
|
|
799
|
-
* Clear mask on current slice canvas.
|
|
621
|
+
* Clear the mask on the current slice canvas for the active layer ONLY.
|
|
622
|
+
*
|
|
623
|
+
* This method only clears the active layer's MaskVolume slice data for the
|
|
624
|
+
* currently viewed slice index. Other slices in the same layer remain intact.
|
|
625
|
+
* Other background layers are also left untouched.
|
|
626
|
+
* After clearing, all layer canvases are re-rendered from the `MaskVolume`
|
|
627
|
+
* to keep the visuals in sync.
|
|
800
628
|
*
|
|
801
|
-
*
|
|
802
|
-
* re-stores, and notifies external via getMask callback with clearFlag=true.
|
|
803
|
-
* Phase 6: Also records a MaskDelta for undo support.
|
|
629
|
+
* The operation is recorded to the UndoManager to allow for user rollback.
|
|
804
630
|
*/
|
|
805
|
-
|
|
806
|
-
this.protectedData.
|
|
807
|
-
this.resetLayerCanvas();
|
|
631
|
+
clearActiveSlice() {
|
|
632
|
+
this.protectedData.isDrawing = true;
|
|
808
633
|
this.protectedData.canvases.originCanvas.width =
|
|
809
634
|
this.protectedData.canvases.originCanvas.width;
|
|
810
635
|
this.protectedData.mainPreSlices.repaint.call(this.protectedData.mainPreSlices);
|
|
811
|
-
|
|
812
|
-
this.protectedData.ctxes.emptyCtx.createImageData(1, 1);
|
|
813
|
-
// Phase 2 + 6: Clear volume slices and record undo delta
|
|
636
|
+
// Clear only the active layer's MaskVolume slice and record undo delta
|
|
814
637
|
try {
|
|
815
638
|
const axis = this.protectedData.axis;
|
|
816
|
-
const idx = this.nrrd_states.
|
|
817
|
-
const activeLayer = this.gui_states.layer;
|
|
639
|
+
const idx = this.nrrd_states.view.currentSliceIndex;
|
|
640
|
+
const activeLayer = this.gui_states.layerChannel.layer;
|
|
818
641
|
const vol = this.getVolumeForLayer(activeLayer);
|
|
819
642
|
// Capture old slice for undo before clearing
|
|
820
643
|
const oldSlice = vol.getSliceUint8(idx, axis).data.slice();
|
|
821
|
-
// Clear only the active layer
|
|
822
|
-
|
|
823
|
-
layer1.clearSlice(idx, axis);
|
|
824
|
-
layer2.clearSlice(idx, axis);
|
|
825
|
-
layer3.clearSlice(idx, axis);
|
|
644
|
+
// Clear only the active layer's MaskVolume slice
|
|
645
|
+
vol.clearSlice(idx, axis);
|
|
826
646
|
// New (all-zero) slice for undo newSlice
|
|
827
647
|
const { data: newSlice, width, height } = vol.getSliceUint8(idx, axis);
|
|
828
|
-
// Push
|
|
648
|
+
// Push clearActiveSlice delta to UndoManager (supports undo)
|
|
829
649
|
this.undoManager.push({
|
|
830
650
|
layerId: activeLayer,
|
|
831
651
|
axis,
|
|
@@ -834,19 +654,30 @@ export class DrawToolCore extends CommToolsData {
|
|
|
834
654
|
newSlice: newSlice.slice(),
|
|
835
655
|
});
|
|
836
656
|
// Notify external that slice was cleared
|
|
837
|
-
if (!this.nrrd_states.
|
|
838
|
-
const activeChannel = this.gui_states.activeChannel || 1;
|
|
839
|
-
this.
|
|
657
|
+
if (!this.nrrd_states.flags.loadingMaskData && !this.gui_states.mode.sphere) {
|
|
658
|
+
const activeChannel = this.gui_states.layerChannel.activeChannel || 1;
|
|
659
|
+
this.annotationCallbacks.onMaskChanged(newSlice, activeLayer, activeChannel, idx, axis, width, height, true // clearFlag = true
|
|
840
660
|
);
|
|
841
661
|
}
|
|
842
662
|
}
|
|
843
663
|
catch (_a) {
|
|
844
|
-
// Volume not ready (1×1×1 placeholder)
|
|
664
|
+
// Volume not ready (1×1×1 placeholder)
|
|
665
|
+
}
|
|
666
|
+
// Re-render ALL layers from MaskVolume to canvas (rebuilds visuals from source of truth)
|
|
667
|
+
this.resetLayerCanvas();
|
|
668
|
+
const buffer = this.getOrCreateSliceBuffer(this.protectedData.axis);
|
|
669
|
+
if (buffer) {
|
|
670
|
+
const w = this.nrrd_states.view.changedWidth;
|
|
671
|
+
const h = this.nrrd_states.view.changedHeight;
|
|
672
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
673
|
+
const target = this.protectedData.layerTargets.get(layerId);
|
|
674
|
+
if (!target)
|
|
675
|
+
continue;
|
|
676
|
+
target.ctx.clearRect(0, 0, w, h);
|
|
677
|
+
this.renderSliceToCanvas(layerId, this.protectedData.axis, this.nrrd_states.view.currentSliceIndex, buffer, target.ctx, w, h);
|
|
678
|
+
}
|
|
845
679
|
}
|
|
846
|
-
this.
|
|
847
|
-
const restLayers = this.getRestLayer();
|
|
848
|
-
this.storeEachLayerImage(this.nrrd_states.currentIndex, restLayers[0]);
|
|
849
|
-
this.storeEachLayerImage(this.nrrd_states.currentIndex, restLayers[1]);
|
|
680
|
+
this.compositeAllLayers();
|
|
850
681
|
this.setIsDrawFalse(1000);
|
|
851
682
|
}
|
|
852
683
|
/**
|
|
@@ -865,14 +696,14 @@ export class DrawToolCore extends CommToolsData {
|
|
|
865
696
|
catch (_a) {
|
|
866
697
|
return; // Volume not ready
|
|
867
698
|
}
|
|
868
|
-
this.protectedData.
|
|
869
|
-
if (delta.axis === this.protectedData.axis && delta.sliceIndex === this.nrrd_states.
|
|
699
|
+
this.protectedData.isDrawing = true;
|
|
700
|
+
if (delta.axis === this.protectedData.axis && delta.sliceIndex === this.nrrd_states.view.currentSliceIndex) {
|
|
870
701
|
this.applyUndoRedoToCanvas(delta.layerId);
|
|
871
702
|
}
|
|
872
|
-
if (!this.nrrd_states.
|
|
703
|
+
if (!this.nrrd_states.flags.loadingMaskData) {
|
|
873
704
|
const { data: sliceData, width, height } = this.getVolumeForLayer(delta.layerId)
|
|
874
705
|
.getSliceUint8(delta.sliceIndex, delta.axis);
|
|
875
|
-
this.
|
|
706
|
+
this.annotationCallbacks.onMaskChanged(sliceData, delta.layerId, this.gui_states.layerChannel.activeChannel || 1, delta.sliceIndex, delta.axis, width, height, false);
|
|
876
707
|
}
|
|
877
708
|
this.setIsDrawFalse(1000);
|
|
878
709
|
}
|
|
@@ -892,14 +723,14 @@ export class DrawToolCore extends CommToolsData {
|
|
|
892
723
|
catch (_a) {
|
|
893
724
|
return; // Volume not ready
|
|
894
725
|
}
|
|
895
|
-
this.protectedData.
|
|
896
|
-
if (delta.axis === this.protectedData.axis && delta.sliceIndex === this.nrrd_states.
|
|
726
|
+
this.protectedData.isDrawing = true;
|
|
727
|
+
if (delta.axis === this.protectedData.axis && delta.sliceIndex === this.nrrd_states.view.currentSliceIndex) {
|
|
897
728
|
this.applyUndoRedoToCanvas(delta.layerId);
|
|
898
729
|
}
|
|
899
|
-
if (!this.nrrd_states.
|
|
730
|
+
if (!this.nrrd_states.flags.loadingMaskData) {
|
|
900
731
|
const { data: sliceData, width, height } = this.getVolumeForLayer(delta.layerId)
|
|
901
732
|
.getSliceUint8(delta.sliceIndex, delta.axis);
|
|
902
|
-
this.
|
|
733
|
+
this.annotationCallbacks.onMaskChanged(sliceData, delta.layerId, this.gui_states.layerChannel.activeChannel || 1, delta.sliceIndex, delta.axis, width, height, false);
|
|
903
734
|
}
|
|
904
735
|
this.setIsDrawFalse(1000);
|
|
905
736
|
}
|
|
@@ -910,7 +741,7 @@ export class DrawToolCore extends CommToolsData {
|
|
|
910
741
|
applyUndoRedoToCanvas(layerId) {
|
|
911
742
|
let target = this.protectedData.layerTargets.get(layerId);
|
|
912
743
|
if (!target) {
|
|
913
|
-
const firstId = this.nrrd_states.layers[0];
|
|
744
|
+
const firstId = this.nrrd_states.image.layers[0];
|
|
914
745
|
target = this.protectedData.layerTargets.get(firstId);
|
|
915
746
|
}
|
|
916
747
|
const { ctx, canvas } = target;
|
|
@@ -918,26 +749,14 @@ export class DrawToolCore extends CommToolsData {
|
|
|
918
749
|
canvas.width = canvas.width;
|
|
919
750
|
const buffer = this.getOrCreateSliceBuffer(this.protectedData.axis);
|
|
920
751
|
if (buffer) {
|
|
921
|
-
this.renderSliceToCanvas(layerId, this.protectedData.axis, this.nrrd_states.
|
|
752
|
+
this.renderSliceToCanvas(layerId, this.protectedData.axis, this.nrrd_states.view.currentSliceIndex, buffer, ctx, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
922
753
|
}
|
|
923
754
|
// Re-composite all layers to master
|
|
924
755
|
this.compositeAllLayers();
|
|
925
|
-
// Update previousDrawingImage from master
|
|
926
|
-
this.protectedData.previousDrawingImage =
|
|
927
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.getImageData(0, 0, this.protectedData.canvases.drawingCanvasLayerMaster.width, this.protectedData.canvases.drawingCanvasLayerMaster.height);
|
|
928
756
|
}
|
|
929
757
|
/****************************Store images (delegated to ImageStoreHelper)****************************************************/
|
|
930
|
-
|
|
931
|
-
this.imageStoreHelper.
|
|
932
|
-
}
|
|
933
|
-
storeAllImages(index, layer) {
|
|
934
|
-
this.imageStoreHelper.storeAllImages(index, layer);
|
|
935
|
-
}
|
|
936
|
-
storeImageToLayer(index, canvas, paintedImages) {
|
|
937
|
-
return this.imageStoreHelper.storeImageToLayer(index, canvas, paintedImages);
|
|
938
|
-
}
|
|
939
|
-
storeEachLayerImage(index, layer) {
|
|
940
|
-
this.imageStoreHelper.storeEachLayerImage(index, layer);
|
|
758
|
+
syncLayerSliceData(index, layer) {
|
|
759
|
+
this.imageStoreHelper.syncLayerSliceData(index, layer);
|
|
941
760
|
}
|
|
942
761
|
/******************************** Utils gui related functions (delegated to ContrastTool) ***************************************/
|
|
943
762
|
setupConrastEvents(callback) {
|