copper3d 2.2.3 → 3.0.0
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 +1056 -5
- package/dist/Scene/copperScene.d.ts +3 -0
- package/dist/Scene/copperScene.js +13 -0
- package/dist/Scene/copperScene.js.map +1 -1
- package/dist/Utils/segmentation/CommToolsData.d.ts +109 -6
- package/dist/Utils/segmentation/CommToolsData.js +314 -50
- package/dist/Utils/segmentation/CommToolsData.js.map +1 -1
- package/dist/Utils/segmentation/DragOperator.d.ts +13 -7
- package/dist/Utils/segmentation/DragOperator.js +51 -165
- package/dist/Utils/segmentation/DragOperator.js.map +1 -1
- package/dist/Utils/segmentation/DrawToolCore.d.ts +57 -76
- package/dist/Utils/segmentation/DrawToolCore.js +368 -878
- package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
- package/dist/Utils/segmentation/NrrdTools.d.ts +277 -15
- package/dist/Utils/segmentation/NrrdTools.js +594 -232
- package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
- package/dist/Utils/segmentation/core/MaskVolume.d.ts +477 -0
- package/dist/Utils/segmentation/core/MaskVolume.js +1238 -0
- package/dist/Utils/segmentation/core/MaskVolume.js.map +1 -0
- package/dist/Utils/segmentation/core/MigrationUtils.d.ts +97 -0
- package/dist/Utils/segmentation/core/MigrationUtils.js +163 -0
- package/dist/Utils/segmentation/core/MigrationUtils.js.map +1 -0
- package/dist/Utils/segmentation/core/UndoManager.d.ts +47 -0
- package/dist/Utils/segmentation/core/UndoManager.js +86 -0
- package/dist/Utils/segmentation/core/UndoManager.js.map +1 -0
- package/dist/Utils/segmentation/core/index.d.ts +76 -0
- package/dist/Utils/segmentation/core/index.js +75 -0
- package/dist/Utils/segmentation/core/index.js.map +1 -0
- package/dist/Utils/segmentation/core/types.d.ts +106 -0
- package/dist/Utils/segmentation/core/types.js +98 -0
- package/dist/Utils/segmentation/core/types.js.map +1 -0
- package/dist/Utils/segmentation/coreTools/coreType.d.ts +55 -36
- package/dist/Utils/segmentation/coreTools/coreType.js.map +1 -1
- package/dist/Utils/segmentation/coreTools/gui.d.ts +6 -16
- package/dist/Utils/segmentation/coreTools/gui.js +23 -27
- package/dist/Utils/segmentation/coreTools/gui.js.map +1 -1
- package/dist/Utils/segmentation/eventRouter/EventRouter.d.ts +144 -0
- package/dist/Utils/segmentation/eventRouter/EventRouter.js +369 -0
- package/dist/Utils/segmentation/eventRouter/EventRouter.js.map +1 -0
- package/dist/Utils/segmentation/eventRouter/index.d.ts +7 -0
- package/dist/Utils/segmentation/eventRouter/index.js +7 -0
- package/dist/Utils/segmentation/eventRouter/index.js.map +1 -0
- package/dist/Utils/segmentation/eventRouter/types.d.ts +70 -0
- package/dist/Utils/segmentation/eventRouter/types.js +7 -0
- package/dist/Utils/segmentation/eventRouter/types.js.map +1 -0
- package/dist/Utils/segmentation/tools/BaseTool.d.ts +25 -0
- package/dist/Utils/segmentation/tools/BaseTool.js +18 -0
- package/dist/Utils/segmentation/tools/BaseTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/ContrastTool.d.ts +26 -0
- package/dist/Utils/segmentation/tools/ContrastTool.js +118 -0
- package/dist/Utils/segmentation/tools/ContrastTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/CrosshairTool.d.ts +30 -0
- package/dist/Utils/segmentation/tools/CrosshairTool.js +157 -0
- package/dist/Utils/segmentation/tools/CrosshairTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/DragSliceTool.d.ts +44 -0
- package/dist/Utils/segmentation/tools/DragSliceTool.js +170 -0
- package/dist/Utils/segmentation/tools/DragSliceTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/EraserTool.d.ts +16 -0
- package/dist/Utils/segmentation/tools/EraserTool.js +92 -0
- package/dist/Utils/segmentation/tools/EraserTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/ImageStoreHelper.d.ts +65 -0
- package/dist/Utils/segmentation/tools/ImageStoreHelper.js +174 -0
- package/dist/Utils/segmentation/tools/ImageStoreHelper.js.map +1 -0
- package/dist/Utils/segmentation/tools/SphereTool.d.ts +38 -0
- package/dist/Utils/segmentation/tools/SphereTool.js +193 -0
- package/dist/Utils/segmentation/tools/SphereTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/ZoomTool.d.ts +20 -0
- package/dist/Utils/segmentation/tools/ZoomTool.js +59 -0
- package/dist/Utils/segmentation/tools/ZoomTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/index.d.ts +22 -0
- package/dist/Utils/segmentation/tools/index.js +23 -0
- package/dist/Utils/segmentation/tools/index.js.map +1 -0
- package/dist/bundle.esm.js +4740 -1979
- package/dist/bundle.umd.js +4743 -1978
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/types/Renderer/copperRenderer.d.ts +1 -1
- package/dist/types/Renderer/copperRendererOnDemond.d.ts +1 -1
- package/dist/types/Scene/copperScene.d.ts +3 -0
- package/dist/types/Utils/segmentation/CommToolsData.d.ts +109 -6
- package/dist/types/Utils/segmentation/DragOperator.d.ts +13 -7
- package/dist/types/Utils/segmentation/DrawToolCore.d.ts +57 -76
- package/dist/types/Utils/segmentation/NrrdTools.d.ts +277 -15
- package/dist/types/Utils/segmentation/core/MaskVolume.d.ts +477 -0
- package/dist/types/Utils/segmentation/core/MigrationUtils.d.ts +97 -0
- package/dist/types/Utils/segmentation/core/UndoManager.d.ts +47 -0
- package/dist/types/Utils/segmentation/core/index.d.ts +76 -0
- package/dist/types/Utils/segmentation/core/types.d.ts +106 -0
- package/dist/types/Utils/segmentation/coreTools/coreType.d.ts +55 -36
- package/dist/types/Utils/segmentation/coreTools/gui.d.ts +6 -16
- package/dist/types/Utils/segmentation/eventRouter/EventRouter.d.ts +144 -0
- package/dist/types/Utils/segmentation/eventRouter/index.d.ts +7 -0
- package/dist/types/Utils/segmentation/eventRouter/types.d.ts +70 -0
- package/dist/types/Utils/segmentation/tools/BaseTool.d.ts +25 -0
- package/dist/types/Utils/segmentation/tools/ContrastTool.d.ts +26 -0
- package/dist/types/Utils/segmentation/tools/CrosshairTool.d.ts +30 -0
- package/dist/types/Utils/segmentation/tools/DragSliceTool.d.ts +44 -0
- package/dist/types/Utils/segmentation/tools/EraserTool.d.ts +16 -0
- package/dist/types/Utils/segmentation/tools/ImageStoreHelper.d.ts +65 -0
- package/dist/types/Utils/segmentation/tools/SphereTool.d.ts +38 -0
- package/dist/types/Utils/segmentation/tools/ZoomTool.d.ts +20 -0
- package/dist/types/Utils/segmentation/tools/index.d.ts +22 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/types/types.d.ts +3 -3
- package/dist/types/types.d.ts +3 -3
- package/package.json +1 -1
- package/dist/Utils/segmentation/coreTools/archive.d.ts +0 -1
- package/dist/Utils/segmentation/coreTools/archive.js +0 -23
- package/dist/Utils/segmentation/coreTools/archive.js.map +0 -1
- package/dist/types/Utils/segmentation/coreTools/archive.d.ts +0 -1
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { CommToolsData } from "./CommToolsData";
|
|
2
|
-
import { switchEraserSize, switchPencilIcon
|
|
2
|
+
import { switchEraserSize, switchPencilIcon } from "../utils";
|
|
3
|
+
import { EventRouter } from "./eventRouter";
|
|
4
|
+
import { SphereTool } from "./tools/SphereTool";
|
|
5
|
+
import { CrosshairTool } from "./tools/CrosshairTool";
|
|
6
|
+
import { ContrastTool } from "./tools/ContrastTool";
|
|
7
|
+
import { ZoomTool } from "./tools/ZoomTool";
|
|
8
|
+
import { EraserTool } from "./tools/EraserTool";
|
|
9
|
+
import { ImageStoreHelper } from "./tools/ImageStoreHelper";
|
|
10
|
+
import { UndoManager } from "./core";
|
|
3
11
|
export class DrawToolCore extends CommToolsData {
|
|
4
|
-
constructor(container) {
|
|
12
|
+
constructor(container, options) {
|
|
5
13
|
const mainAreaContainer = document.createElement("div");
|
|
6
|
-
super(container, mainAreaContainer);
|
|
14
|
+
super(container, mainAreaContainer, options);
|
|
7
15
|
this.drawingPrameters = {
|
|
8
16
|
handleOnDrawingMouseDown: (ev) => { },
|
|
9
17
|
handleOnDrawingMouseMove: (ev) => { },
|
|
@@ -28,7 +36,13 @@ export class DrawToolCore extends CommToolsData {
|
|
|
28
36
|
};
|
|
29
37
|
this.eraserUrls = [];
|
|
30
38
|
this.pencilUrls = [];
|
|
31
|
-
this.
|
|
39
|
+
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
|
+
// Centralized event router
|
|
45
|
+
this.eventRouter = null;
|
|
32
46
|
// need to return to parent
|
|
33
47
|
this.start = () => { };
|
|
34
48
|
/*************************************May consider to move outside *******************************************/
|
|
@@ -40,69 +54,146 @@ export class DrawToolCore extends CommToolsData {
|
|
|
40
54
|
this.protectedData.ctxes.drawingCtx.stroke();
|
|
41
55
|
};
|
|
42
56
|
this.configContrastDragMode = () => {
|
|
43
|
-
this.
|
|
44
|
-
this.container.addEventListener("pointerdown", this.contrastEventPrameters.handleOnContrastMouseDown, true);
|
|
45
|
-
this.container.addEventListener("pointerup", this.contrastEventPrameters.handleOnContrastMouseUp, true);
|
|
57
|
+
this.contrastTool.configContrastDragMode();
|
|
46
58
|
};
|
|
47
59
|
this.removeContrastDragMode = () => {
|
|
48
|
-
this.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
this.contrastTool.removeContrastDragMode();
|
|
61
|
+
};
|
|
62
|
+
this.updateSlicesContrast = (value, flag) => {
|
|
63
|
+
this.contrastTool.updateSlicesContrast(value, flag);
|
|
64
|
+
};
|
|
65
|
+
this.repraintCurrentContrastSlice = () => {
|
|
66
|
+
this.contrastTool.repraintCurrentContrastSlice();
|
|
54
67
|
};
|
|
55
68
|
this.container = container;
|
|
56
69
|
this.mainAreaContainer = mainAreaContainer;
|
|
70
|
+
this.initTools();
|
|
57
71
|
this.initDrawToolCore();
|
|
58
72
|
}
|
|
73
|
+
initTools() {
|
|
74
|
+
const toolCtx = {
|
|
75
|
+
nrrd_states: this.nrrd_states,
|
|
76
|
+
gui_states: this.gui_states,
|
|
77
|
+
protectedData: this.protectedData,
|
|
78
|
+
cursorPage: this.cursorPage,
|
|
79
|
+
};
|
|
80
|
+
this.imageStoreHelper = new ImageStoreHelper(toolCtx, {
|
|
81
|
+
setEmptyCanvasSize: (axis) => this.setEmptyCanvasSize(axis),
|
|
82
|
+
drawImageOnEmptyImage: (canvas) => this.drawImageOnEmptyImage(canvas),
|
|
83
|
+
});
|
|
84
|
+
this.sphereTool = new SphereTool(toolCtx, {
|
|
85
|
+
setEmptyCanvasSize: (axis) => this.setEmptyCanvasSize(axis),
|
|
86
|
+
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
|
+
});
|
|
90
|
+
this.crosshairTool = new CrosshairTool(toolCtx);
|
|
91
|
+
this.contrastTool = new ContrastTool(toolCtx, this.container, this.contrastEventPrameters, {
|
|
92
|
+
setIsDrawFalse: (target) => this.setIsDrawFalse(target),
|
|
93
|
+
setSyncsliceNum: () => this.setSyncsliceNum(),
|
|
94
|
+
});
|
|
95
|
+
this.zoomTool = new ZoomTool(toolCtx, this.container, this.mainAreaContainer, {
|
|
96
|
+
resetPaintAreaUIPosition: (l, t) => this.resetPaintAreaUIPosition(l, t),
|
|
97
|
+
resizePaintArea: (moveDistance) => this.resizePaintArea(moveDistance),
|
|
98
|
+
setIsDrawFalse: (target) => this.setIsDrawFalse(target),
|
|
99
|
+
});
|
|
100
|
+
this.eraserTool = new EraserTool(toolCtx);
|
|
101
|
+
}
|
|
59
102
|
initDrawToolCore() {
|
|
60
|
-
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
103
|
+
// Initialize EventRouter for centralized event handling
|
|
104
|
+
this.eventRouter = new EventRouter({
|
|
105
|
+
container: this.container,
|
|
106
|
+
canvas: this.protectedData.canvases.drawingCanvas,
|
|
107
|
+
onModeChange: (prevMode, newMode) => {
|
|
108
|
+
// Use string comparison to avoid TypeScript narrowing issues
|
|
109
|
+
const prev = prevMode;
|
|
110
|
+
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') {
|
|
66
117
|
this.protectedData.Is_Shift_Pressed = false;
|
|
67
|
-
return;
|
|
68
118
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
119
|
+
if (next === 'contrast') {
|
|
120
|
+
this.protectedData.Is_Ctrl_Pressed = true;
|
|
121
|
+
this.protectedData.Is_Shift_Pressed = false;
|
|
122
|
+
this.configContrastDragMode();
|
|
123
|
+
}
|
|
124
|
+
else if (prev === 'contrast') {
|
|
125
|
+
this.protectedData.Is_Ctrl_Pressed = false;
|
|
126
|
+
this.removeContrastDragMode();
|
|
127
|
+
this.gui_states.readyToUpdate = true;
|
|
128
|
+
}
|
|
129
|
+
if (next === 'crosshair') {
|
|
130
|
+
this.nrrd_states.enableCursorChoose = true;
|
|
131
|
+
this.protectedData.Is_Draw = false;
|
|
132
|
+
}
|
|
133
|
+
else if (prev === 'crosshair') {
|
|
134
|
+
this.nrrd_states.enableCursorChoose = false;
|
|
135
|
+
}
|
|
76
136
|
}
|
|
77
|
-
|
|
137
|
+
});
|
|
138
|
+
// Configure keyboard settings from class field
|
|
139
|
+
this.eventRouter.setKeyboardSettings(this._keyboardSettings);
|
|
140
|
+
// Track undo flag for Ctrl+Z handling
|
|
141
|
+
let undoFlag = false;
|
|
142
|
+
// Register keyboard handlers with EventRouter
|
|
143
|
+
this.eventRouter.setKeydownHandler((ev) => {
|
|
144
|
+
var _a;
|
|
145
|
+
if (this._configKeyBoard)
|
|
146
|
+
return;
|
|
147
|
+
// Handle undo (Ctrl+Z)
|
|
148
|
+
if ((ev.ctrlKey || ev.metaKey) && ev.key === this._keyboardSettings.undo) {
|
|
78
149
|
undoFlag = true;
|
|
79
150
|
this.undoLastPainting();
|
|
80
151
|
}
|
|
152
|
+
// Handle redo (Ctrl+<redo key> or Ctrl+Shift+<undo key>)
|
|
153
|
+
const redoKey = this._keyboardSettings.redo;
|
|
154
|
+
const undoKeyUpper = this._keyboardSettings.undo.toUpperCase();
|
|
155
|
+
if ((ev.ctrlKey || ev.metaKey) && (ev.key === redoKey || (ev.shiftKey && ev.key === undoKeyUpper))) {
|
|
156
|
+
this.redoLastPainting();
|
|
157
|
+
}
|
|
158
|
+
// Handle crosshair toggle
|
|
159
|
+
if (ev.key === this._keyboardSettings.crosshair) {
|
|
160
|
+
if (!this.gui_states.sphere && !this.gui_states.calculator) {
|
|
161
|
+
(_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.toggleCrosshair();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Handle draw mode (Shift key) - EventRouter already tracks this
|
|
165
|
+
if (ev.key === this._keyboardSettings.draw && !this.gui_states.sphere && !this.gui_states.calculator) {
|
|
166
|
+
if (this.protectedData.Is_Ctrl_Pressed) {
|
|
167
|
+
return; // Ctrl takes priority
|
|
168
|
+
}
|
|
169
|
+
// EventRouter will set mode to 'draw' via internal handler
|
|
170
|
+
}
|
|
81
171
|
});
|
|
82
|
-
this.
|
|
83
|
-
|
|
172
|
+
this.eventRouter.setKeyupHandler((ev) => {
|
|
173
|
+
var _a, _b, _c, _d;
|
|
174
|
+
if (this._configKeyBoard)
|
|
84
175
|
return;
|
|
85
|
-
|
|
176
|
+
// Handle Ctrl key release (contrast mode toggle)
|
|
177
|
+
if (this._keyboardSettings.contrast.includes(ev.key)) {
|
|
86
178
|
if (undoFlag) {
|
|
87
179
|
this.gui_states.readyToUpdate = true;
|
|
88
180
|
undoFlag = false;
|
|
89
181
|
return;
|
|
90
182
|
}
|
|
91
|
-
//
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
183
|
+
// Skip mode toggle when contrast shortcut is disabled
|
|
184
|
+
if (!((_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.isContrastEnabled()))
|
|
185
|
+
return;
|
|
186
|
+
// Toggle contrast mode manually since it's on keyup
|
|
187
|
+
if (((_b = this.eventRouter) === null || _b === void 0 ? void 0 : _b.getMode()) !== 'contrast') {
|
|
188
|
+
(_c = this.eventRouter) === null || _c === void 0 ? void 0 : _c.setMode('contrast');
|
|
96
189
|
}
|
|
97
190
|
else {
|
|
98
|
-
this.
|
|
99
|
-
this.gui_states.readyToUpdate = true;
|
|
191
|
+
(_d = this.eventRouter) === null || _d === void 0 ? void 0 : _d.setMode('idle');
|
|
100
192
|
}
|
|
101
193
|
}
|
|
102
|
-
if (ev.key === this.nrrd_states.keyboardSettings.draw) {
|
|
103
|
-
this.protectedData.Is_Shift_Pressed = false;
|
|
104
|
-
}
|
|
105
194
|
});
|
|
195
|
+
// Bind all event listeners
|
|
196
|
+
this.eventRouter.bindAll();
|
|
106
197
|
}
|
|
107
198
|
setEraserUrls(urls) {
|
|
108
199
|
this.eraserUrls = urls;
|
|
@@ -114,31 +205,21 @@ export class DrawToolCore extends CommToolsData {
|
|
|
114
205
|
this.gui_states.defaultPaintCursor;
|
|
115
206
|
}
|
|
116
207
|
setCurrentLayer() {
|
|
117
|
-
|
|
118
|
-
let
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
break;
|
|
124
|
-
case "label2":
|
|
125
|
-
ctx = this.protectedData.ctxes.drawingLayerTwoCtx;
|
|
126
|
-
canvas = this.protectedData.canvases.drawingCanvasLayerTwo;
|
|
127
|
-
break;
|
|
128
|
-
case "label3":
|
|
129
|
-
ctx = this.protectedData.ctxes.drawingLayerThreeCtx;
|
|
130
|
-
canvas = this.protectedData.canvases.drawingCanvasLayerThree;
|
|
131
|
-
break;
|
|
132
|
-
default:
|
|
133
|
-
ctx = this.protectedData.ctxes.drawingLayerOneCtx;
|
|
134
|
-
canvas = this.protectedData.canvases.drawingCanvasLayerOne;
|
|
135
|
-
break;
|
|
208
|
+
const layer = this.gui_states.layer;
|
|
209
|
+
let target = this.protectedData.layerTargets.get(layer);
|
|
210
|
+
if (!target) {
|
|
211
|
+
// Fallback to first layer
|
|
212
|
+
const firstId = this.nrrd_states.layers[0];
|
|
213
|
+
target = this.protectedData.layerTargets.get(firstId);
|
|
136
214
|
}
|
|
137
|
-
return { ctx, canvas };
|
|
215
|
+
return { ctx: target.ctx, canvas: target.canvas };
|
|
138
216
|
}
|
|
139
217
|
draw(opts) {
|
|
140
218
|
if (!!opts) {
|
|
141
219
|
this.nrrd_states.getMask = opts === null || opts === void 0 ? void 0 : opts.getMaskData;
|
|
220
|
+
if (opts === null || opts === void 0 ? void 0 : opts.onClearLayerVolume) {
|
|
221
|
+
this.nrrd_states.onClearLayerVolume = opts.onClearLayerVolume;
|
|
222
|
+
}
|
|
142
223
|
this.nrrd_states.getSphere = opts === null || opts === void 0 ? void 0 : opts.getSphereData;
|
|
143
224
|
this.nrrd_states.getCalculateSpherePositions = opts === null || opts === void 0 ? void 0 : opts.getCalculateSpherePositionsData;
|
|
144
225
|
}
|
|
@@ -195,10 +276,7 @@ export class DrawToolCore extends CommToolsData {
|
|
|
195
276
|
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
196
277
|
}
|
|
197
278
|
clearSpherePrintStoreImages() {
|
|
198
|
-
this.
|
|
199
|
-
this.protectedData.maskData.paintImages.y.length = 0;
|
|
200
|
-
this.protectedData.maskData.paintImages.z.length = 0;
|
|
201
|
-
this.createEmptyPaintImage(this.nrrd_states.dimensions, this.protectedData.maskData.paintImages);
|
|
279
|
+
this.sphereTool.clearSpherePrintStoreImages();
|
|
202
280
|
}
|
|
203
281
|
paintOnCanvas() {
|
|
204
282
|
var _a, _b, _c;
|
|
@@ -225,13 +303,16 @@ export class DrawToolCore extends CommToolsData {
|
|
|
225
303
|
this.protectedData.previousDrawingImage =
|
|
226
304
|
this.protectedData.ctxes.drawingCtx.getImageData(0, 0, this.protectedData.canvases.drawingCanvas.width, this.protectedData.canvases.drawingCanvas.height);
|
|
227
305
|
// let a global variable to store the wheel move event
|
|
228
|
-
|
|
306
|
+
// Remove existing listener before creating a new one to prevent leaks
|
|
307
|
+
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
308
|
+
if (this._keyboardSettings.mouseWheel === "Scroll:Zoom") {
|
|
229
309
|
this.drawingPrameters.handleMouseZoomSliceWheel = this.configMouseZoomWheel();
|
|
230
310
|
}
|
|
231
311
|
else {
|
|
232
312
|
this.drawingPrameters.handleMouseZoomSliceWheel = this.configMouseSliceWheel();
|
|
233
313
|
}
|
|
234
|
-
//
|
|
314
|
+
// Keep wheel as direct addEventListener due to dynamic add/remove patterns in handleOnDrawingMouseUp
|
|
315
|
+
// EventRouter routing would conflict with the dynamic wheel switching (zoom vs sphere wheel)
|
|
235
316
|
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel, {
|
|
236
317
|
passive: false,
|
|
237
318
|
});
|
|
@@ -318,6 +399,16 @@ export class DrawToolCore extends CommToolsData {
|
|
|
318
399
|
}
|
|
319
400
|
this.nrrd_states.drawStartPos.x = e.offsetX;
|
|
320
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
|
+
}
|
|
321
412
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
322
413
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointermove", this.drawingPrameters.handleOnDrawingMouseMove);
|
|
323
414
|
}
|
|
@@ -350,8 +441,17 @@ export class DrawToolCore extends CommToolsData {
|
|
|
350
441
|
return;
|
|
351
442
|
}
|
|
352
443
|
};
|
|
353
|
-
//
|
|
354
|
-
|
|
444
|
+
// Route pointerdown through EventRouter for centralized event management
|
|
445
|
+
// The handler is still the existing logic, just registered through EventRouter
|
|
446
|
+
if (this.eventRouter) {
|
|
447
|
+
this.eventRouter.setPointerDownHandler((e) => {
|
|
448
|
+
this.drawingPrameters.handleOnDrawingMouseDown(e);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
// Fallback for legacy mode without EventRouter
|
|
453
|
+
this.protectedData.canvases.drawingCanvas.addEventListener("pointerdown", this.drawingPrameters.handleOnDrawingMouseDown, true);
|
|
454
|
+
}
|
|
355
455
|
const sphere = (e) => {
|
|
356
456
|
// set sphere size
|
|
357
457
|
this.protectedData.canvases.drawingCanvas.removeEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel);
|
|
@@ -372,31 +472,19 @@ export class DrawToolCore extends CommToolsData {
|
|
|
372
472
|
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleSphereWheel, true);
|
|
373
473
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointerup", this.drawingPrameters.handleOnDrawingMouseUp);
|
|
374
474
|
};
|
|
375
|
-
const
|
|
475
|
+
const redrawPreviousImageToLayerCtx = (ctx) => {
|
|
376
476
|
var _a;
|
|
377
|
-
|
|
378
|
-
switch (label) {
|
|
379
|
-
case "label1":
|
|
380
|
-
paintImages = this.protectedData.maskData.paintImagesLabel1;
|
|
381
|
-
break;
|
|
382
|
-
case "label2":
|
|
383
|
-
paintImages = this.protectedData.maskData.paintImagesLabel2;
|
|
384
|
-
break;
|
|
385
|
-
case "label3":
|
|
386
|
-
paintImages = this.protectedData.maskData.paintImagesLabel3;
|
|
387
|
-
break;
|
|
388
|
-
default:
|
|
389
|
-
paintImages = this.protectedData.maskData.paintImages;
|
|
390
|
-
break;
|
|
391
|
-
}
|
|
392
|
-
const tempPreImg = (_a = this.filterDrawedImage(this.protectedData.axis, this.nrrd_states.currentIndex, paintImages)) === null || _a === void 0 ? void 0 : _a.image;
|
|
477
|
+
const tempPreImg = (_a = this.filterDrawedImage(this.protectedData.axis, this.nrrd_states.currentIndex)) === null || _a === void 0 ? void 0 : _a.image;
|
|
393
478
|
this.protectedData.canvases.emptyCanvas.width =
|
|
394
479
|
this.protectedData.canvases.emptyCanvas.width;
|
|
395
|
-
if (tempPreImg
|
|
480
|
+
if (tempPreImg) {
|
|
396
481
|
this.protectedData.previousDrawingImage = tempPreImg;
|
|
397
482
|
}
|
|
398
483
|
this.protectedData.ctxes.emptyCtx.putImageData(tempPreImg, 0, 0);
|
|
399
|
-
//
|
|
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;
|
|
400
488
|
ctx.drawImage(this.protectedData.canvases.emptyCanvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
401
489
|
};
|
|
402
490
|
this.drawingPrameters.handleOnDrawingMouseUp = (e) => {
|
|
@@ -407,13 +495,12 @@ export class DrawToolCore extends CommToolsData {
|
|
|
407
495
|
ctx.closePath();
|
|
408
496
|
this.protectedData.canvases.drawingCanvas.removeEventListener("pointermove", this.drawingPrameters.handleOnDrawingMouseMove);
|
|
409
497
|
if (!this.gui_states.Eraser) {
|
|
410
|
-
if (this.gui_states.
|
|
411
|
-
|
|
412
|
-
this.protectedData.canvases.drawingCanvasLayerMaster.width;
|
|
498
|
+
if (this.gui_states.pencil) {
|
|
499
|
+
// Clear only the current layer canvas (NOT master)
|
|
413
500
|
canvas.width = canvas.width;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
//
|
|
501
|
+
// Redraw previous layer data from volume
|
|
502
|
+
redrawPreviousImageToLayerCtx(ctx);
|
|
503
|
+
// Draw new pencil strokes on current layer canvas
|
|
417
504
|
ctx.beginPath();
|
|
418
505
|
ctx.moveTo(lines[0].x, lines[0].y);
|
|
419
506
|
for (let i = 1; i < lines.length; i++) {
|
|
@@ -423,36 +510,37 @@ export class DrawToolCore extends CommToolsData {
|
|
|
423
510
|
ctx.lineWidth = 1;
|
|
424
511
|
ctx.fillStyle = this.gui_states.fillColor;
|
|
425
512
|
ctx.fill();
|
|
426
|
-
//
|
|
427
|
-
this.
|
|
513
|
+
// Composite ALL layers to master (not just current layer)
|
|
514
|
+
this.compositeAllLayers();
|
|
428
515
|
}
|
|
429
516
|
}
|
|
430
517
|
this.protectedData.previousDrawingImage =
|
|
431
518
|
this.protectedData.ctxes.drawingLayerMasterCtx.getImageData(0, 0, this.protectedData.canvases.drawingCanvasLayerMaster.width, this.protectedData.canvases.drawingCanvasLayerMaster.height);
|
|
432
|
-
this.storeAllImages(this.nrrd_states.currentIndex, this.gui_states.
|
|
519
|
+
this.storeAllImages(this.nrrd_states.currentIndex, this.gui_states.layer);
|
|
433
520
|
if (this.gui_states.Eraser) {
|
|
434
|
-
const
|
|
435
|
-
this.storeEachLayerImage(this.nrrd_states.currentIndex,
|
|
436
|
-
this.storeEachLayerImage(this.nrrd_states.currentIndex,
|
|
521
|
+
const restLayers = this.getRestLayer();
|
|
522
|
+
this.storeEachLayerImage(this.nrrd_states.currentIndex, restLayers[0]);
|
|
523
|
+
this.storeEachLayerImage(this.nrrd_states.currentIndex, restLayers[1]);
|
|
437
524
|
}
|
|
438
525
|
Is_Painting = false;
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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;
|
|
456
544
|
}
|
|
457
545
|
// add wheel after pointer up
|
|
458
546
|
this.protectedData.canvases.drawingCanvas.addEventListener("wheel", this.drawingPrameters.handleMouseZoomSliceWheel, {
|
|
@@ -504,13 +592,12 @@ export class DrawToolCore extends CommToolsData {
|
|
|
504
592
|
else {
|
|
505
593
|
return;
|
|
506
594
|
}
|
|
507
|
-
if (!this.gui_states.
|
|
595
|
+
if (!this.gui_states.pencil) {
|
|
508
596
|
this.setIsDrawFalse(100);
|
|
509
597
|
}
|
|
510
598
|
};
|
|
511
599
|
this.protectedData.canvases.drawingCanvas.addEventListener("pointerleave", (e) => {
|
|
512
600
|
Is_Painting = false;
|
|
513
|
-
// (this.sceneIn as copperScene).controls.enabled = true;
|
|
514
601
|
if (leftclicked) {
|
|
515
602
|
leftclicked = false;
|
|
516
603
|
this.protectedData.ctxes.drawingLayerMasterCtx.closePath();
|
|
@@ -523,7 +610,7 @@ export class DrawToolCore extends CommToolsData {
|
|
|
523
610
|
this.protectedData.canvases.drawingCanvas.removeEventListener("pointermove", this.drawingPrameters.handleOnPanMouseMove);
|
|
524
611
|
}
|
|
525
612
|
this.setIsDrawFalse(100);
|
|
526
|
-
if (this.gui_states.
|
|
613
|
+
if (this.gui_states.pencil) {
|
|
527
614
|
this.setIsDrawFalse(1000);
|
|
528
615
|
}
|
|
529
616
|
});
|
|
@@ -535,16 +622,14 @@ export class DrawToolCore extends CommToolsData {
|
|
|
535
622
|
if (this.protectedData.Is_Draw) {
|
|
536
623
|
this.protectedData.ctxes.drawingLayerMasterCtx.lineCap = "round";
|
|
537
624
|
this.protectedData.ctxes.drawingLayerMasterCtx.globalAlpha = 1;
|
|
538
|
-
this.protectedData.
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
this.protectedData.ctxes.drawingLayerThreeCtx.lineCap = "round";
|
|
543
|
-
this.protectedData.ctxes.drawingLayerThreeCtx.globalAlpha = 1;
|
|
625
|
+
for (const [, target] of this.protectedData.layerTargets) {
|
|
626
|
+
target.ctx.lineCap = "round";
|
|
627
|
+
target.ctx.globalAlpha = 1;
|
|
628
|
+
}
|
|
544
629
|
}
|
|
545
630
|
else {
|
|
546
631
|
if (this.protectedData.Is_Shift_Pressed) {
|
|
547
|
-
if (!this.gui_states.
|
|
632
|
+
if (!this.gui_states.pencil &&
|
|
548
633
|
!this.gui_states.Eraser &&
|
|
549
634
|
this.nrrd_states.Mouse_Over) {
|
|
550
635
|
this.protectedData.ctxes.drawingCtx.clearRect(0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
@@ -565,6 +650,8 @@ export class DrawToolCore extends CommToolsData {
|
|
|
565
650
|
this.drawLine(0, ey, this.nrrd_states.changedHeight, ey);
|
|
566
651
|
}
|
|
567
652
|
}
|
|
653
|
+
// globalAlpha was set to gui_states.globalAlpha at the top of start().
|
|
654
|
+
// Master stores full-alpha pixels; transparency applied here only.
|
|
568
655
|
this.protectedData.ctxes.drawingCtx.drawImage(this.protectedData.canvases.drawingCanvasLayerMaster, 0, 0);
|
|
569
656
|
}
|
|
570
657
|
else {
|
|
@@ -575,7 +662,7 @@ export class DrawToolCore extends CommToolsData {
|
|
|
575
662
|
drawLinesOnLayer(ctx, x, y) {
|
|
576
663
|
ctx.beginPath();
|
|
577
664
|
ctx.moveTo(this.nrrd_states.drawStartPos.x, this.nrrd_states.drawStartPos.y);
|
|
578
|
-
if (this.gui_states.
|
|
665
|
+
if (this.gui_states.pencil) {
|
|
579
666
|
ctx.strokeStyle = this.gui_states.color;
|
|
580
667
|
ctx.lineWidth = this.gui_states.lineWidth;
|
|
581
668
|
}
|
|
@@ -589,8 +676,10 @@ export class DrawToolCore extends CommToolsData {
|
|
|
589
676
|
}
|
|
590
677
|
paintOnCanvasLayer(x, y) {
|
|
591
678
|
let { ctx, canvas } = this.setCurrentLayer();
|
|
679
|
+
// Draw only on the current layer canvas (not master directly)
|
|
592
680
|
this.drawLinesOnLayer(ctx, x, y);
|
|
593
|
-
|
|
681
|
+
// Composite all layers to master to preserve other layers' data
|
|
682
|
+
this.compositeAllLayers();
|
|
594
683
|
// reset drawing start position to current position.
|
|
595
684
|
this.nrrd_states.drawStartPos.x = x;
|
|
596
685
|
this.nrrd_states.drawStartPos.y = y;
|
|
@@ -624,15 +713,13 @@ export class DrawToolCore extends CommToolsData {
|
|
|
624
713
|
* it should be hide, so we don't need to add it to mainAreaContainer
|
|
625
714
|
*/
|
|
626
715
|
this.protectedData.canvases.drawingCanvasLayerMaster.width =
|
|
627
|
-
this.
|
|
628
|
-
this.protectedData.canvases.drawingCanvasLayerTwo.width =
|
|
629
|
-
this.protectedData.canvases.drawingCanvasLayerThree.width =
|
|
630
|
-
this.nrrd_states.changedWidth;
|
|
716
|
+
this.nrrd_states.changedWidth;
|
|
631
717
|
this.protectedData.canvases.drawingCanvasLayerMaster.height =
|
|
632
|
-
this.
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
718
|
+
this.nrrd_states.changedHeight;
|
|
719
|
+
for (const [, target] of this.protectedData.layerTargets) {
|
|
720
|
+
target.canvas.width = this.nrrd_states.changedWidth;
|
|
721
|
+
target.canvas.height = this.nrrd_states.changedHeight;
|
|
722
|
+
}
|
|
636
723
|
/**
|
|
637
724
|
* display and drawing canvas container
|
|
638
725
|
*/
|
|
@@ -646,67 +733,11 @@ export class DrawToolCore extends CommToolsData {
|
|
|
646
733
|
this.mainAreaContainer.appendChild(this.protectedData.canvases.drawingCanvas);
|
|
647
734
|
}
|
|
648
735
|
useEraser() {
|
|
649
|
-
|
|
650
|
-
var calcWidth = radius - this.nrrd_states.stepClear;
|
|
651
|
-
var calcHeight = Math.sqrt(radius * radius - calcWidth * calcWidth);
|
|
652
|
-
var posX = x - calcWidth;
|
|
653
|
-
var posY = y - calcHeight;
|
|
654
|
-
var widthX = 2 * calcWidth;
|
|
655
|
-
var heightY = 2 * calcHeight;
|
|
656
|
-
if (this.nrrd_states.stepClear <= radius) {
|
|
657
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.clearRect(posX, posY, widthX, heightY);
|
|
658
|
-
this.protectedData.ctxes.drawingLayerOneCtx.clearRect(posX, posY, widthX, heightY);
|
|
659
|
-
this.protectedData.ctxes.drawingLayerTwoCtx.clearRect(posX, posY, widthX, heightY);
|
|
660
|
-
this.protectedData.ctxes.drawingLayerThreeCtx.clearRect(posX, posY, widthX, heightY);
|
|
661
|
-
this.nrrd_states.stepClear += 1;
|
|
662
|
-
clearArc(x, y, radius);
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
return clearArc;
|
|
736
|
+
return this.eraserTool.createClearArc();
|
|
666
737
|
}
|
|
667
738
|
// drawing canvas mouse zoom wheel
|
|
668
739
|
configMouseZoomWheel() {
|
|
669
|
-
|
|
670
|
-
const handleMouseZoomSliceWheelMove = (e) => {
|
|
671
|
-
if (this.protectedData.Is_Shift_Pressed) {
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
e.preventDefault();
|
|
675
|
-
// this.nrrd_states.originWidth;
|
|
676
|
-
const delta = e.detail ? e.detail > 0 : e.wheelDelta < 0;
|
|
677
|
-
this.protectedData.Is_Draw = true;
|
|
678
|
-
var rect = this.container.getBoundingClientRect();
|
|
679
|
-
const ratioL = (e.clientX - rect.left -
|
|
680
|
-
this.mainAreaContainer.offsetLeft -
|
|
681
|
-
this.protectedData.canvases.drawingCanvas.offsetLeft) /
|
|
682
|
-
this.protectedData.canvases.drawingCanvas.offsetWidth;
|
|
683
|
-
const ratioT = (e.clientY - rect.top -
|
|
684
|
-
this.mainAreaContainer.offsetTop -
|
|
685
|
-
this.protectedData.canvases.drawingCanvas.offsetTop) /
|
|
686
|
-
this.protectedData.canvases.drawingCanvas.offsetHeight;
|
|
687
|
-
const ratioDelta = !delta ? 1 + 0.1 : 1 - 0.1;
|
|
688
|
-
const w = this.protectedData.canvases.drawingCanvas.offsetWidth * ratioDelta;
|
|
689
|
-
const h = this.protectedData.canvases.drawingCanvas.offsetHeight * ratioDelta;
|
|
690
|
-
const l = Math.round(e.clientX - this.mainAreaContainer.offsetLeft - w * ratioL - rect.left);
|
|
691
|
-
const t = Math.round(e.clientY - this.mainAreaContainer.offsetTop - h * ratioT - rect.top);
|
|
692
|
-
moveDistance = w / this.nrrd_states.originWidth;
|
|
693
|
-
if (moveDistance > 8) {
|
|
694
|
-
moveDistance = 8;
|
|
695
|
-
// this.resetPaintAreaUIPosition();
|
|
696
|
-
}
|
|
697
|
-
else if (moveDistance < 1) {
|
|
698
|
-
moveDistance = 1;
|
|
699
|
-
this.resetPaintAreaUIPosition();
|
|
700
|
-
this.resizePaintArea(moveDistance);
|
|
701
|
-
}
|
|
702
|
-
else {
|
|
703
|
-
this.resetPaintAreaUIPosition(l, t);
|
|
704
|
-
this.resizePaintArea(moveDistance);
|
|
705
|
-
}
|
|
706
|
-
this.setIsDrawFalse(1000);
|
|
707
|
-
this.nrrd_states.sizeFoctor = moveDistance;
|
|
708
|
-
};
|
|
709
|
-
return handleMouseZoomSliceWheelMove;
|
|
740
|
+
return this.zoomTool.configMouseZoomWheel();
|
|
710
741
|
}
|
|
711
742
|
configMouseSliceWheel() {
|
|
712
743
|
/**
|
|
@@ -716,348 +747,60 @@ export class DrawToolCore extends CommToolsData {
|
|
|
716
747
|
throw new Error("Child class must implement abstract redrawDisplayCanvas, currently you can find it in NrrdTools.");
|
|
717
748
|
}
|
|
718
749
|
enableCrosshair() {
|
|
719
|
-
this.
|
|
720
|
-
switch (this.protectedData.axis) {
|
|
721
|
-
case "x":
|
|
722
|
-
this.cursorPage.x.updated = true;
|
|
723
|
-
this.cursorPage.y.updated = false;
|
|
724
|
-
this.cursorPage.z.updated = false;
|
|
725
|
-
break;
|
|
726
|
-
case "y":
|
|
727
|
-
this.cursorPage.x.updated = false;
|
|
728
|
-
this.cursorPage.y.updated = true;
|
|
729
|
-
this.cursorPage.z.updated = false;
|
|
730
|
-
break;
|
|
731
|
-
case "z":
|
|
732
|
-
this.cursorPage.x.updated = false;
|
|
733
|
-
this.cursorPage.y.updated = false;
|
|
734
|
-
this.cursorPage.z.updated = true;
|
|
735
|
-
break;
|
|
736
|
-
}
|
|
750
|
+
this.crosshairTool.enableCrosshair();
|
|
737
751
|
}
|
|
738
752
|
drawImageOnEmptyImage(canvas) {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
753
|
+
const ctx = this.protectedData.ctxes.emptyCtx;
|
|
754
|
+
const w = this.protectedData.canvases.emptyCanvas.width;
|
|
755
|
+
const h = this.protectedData.canvases.emptyCanvas.height;
|
|
756
|
+
// No flip needed: the layer canvas screen coordinates already match the
|
|
757
|
+
// Three.js source coordinate system used by MaskVolume. Applying a flip
|
|
758
|
+
// here would invert cross-axis slice indices (e.g. coronal slice 220
|
|
759
|
+
// becoming 228 when total=448).
|
|
760
|
+
ctx.imageSmoothingEnabled = false;
|
|
761
|
+
ctx.drawImage(canvas, 0, 0, w, h);
|
|
762
|
+
}
|
|
763
|
+
/****************************Sphere functions (delegated to SphereTool)****************************************************/
|
|
748
764
|
drawCalculatorSphereOnEachViews(axis) {
|
|
749
|
-
|
|
750
|
-
this.setSphereCanvasSize(axis);
|
|
751
|
-
// get drawingSphere canvas for storing
|
|
752
|
-
const ctx = this.protectedData.ctxes.drawingSphereCtx;
|
|
753
|
-
const canvas = this.protectedData.canvases.drawingSphereCanvas;
|
|
754
|
-
let tumourPosition = !!this.nrrd_states.tumourSphereOrigin ? Object.assign(this.getSpherePosition(this.nrrd_states.tumourSphereOrigin, axis), { color: this.nrrd_states.tumourColor }) : null;
|
|
755
|
-
let skinPosition = !!this.nrrd_states.skinSphereOrigin ? Object.assign(this.getSpherePosition(this.nrrd_states.skinSphereOrigin, axis), { color: this.nrrd_states.skinColor }) : null;
|
|
756
|
-
let ribcagePosition = !!this.nrrd_states.ribSphereOrigin ? Object.assign(this.getSpherePosition(this.nrrd_states.ribSphereOrigin, axis), { color: this.nrrd_states.ribcageColor }) : null;
|
|
757
|
-
let nipplePosition = !!this.nrrd_states.nippleSphereOrigin ? Object.assign(this.getSpherePosition(this.nrrd_states.nippleSphereOrigin, axis), { color: this.nrrd_states.nippleColor }) : null;
|
|
758
|
-
let positionGroup = [];
|
|
759
|
-
if (!!tumourPosition)
|
|
760
|
-
positionGroup.push(tumourPosition);
|
|
761
|
-
if (!!skinPosition)
|
|
762
|
-
positionGroup.push(skinPosition);
|
|
763
|
-
if (!!ribcagePosition)
|
|
764
|
-
positionGroup.push(ribcagePosition);
|
|
765
|
-
if (!!nipplePosition)
|
|
766
|
-
positionGroup.push(nipplePosition);
|
|
767
|
-
let copyPosition = JSON.parse(JSON.stringify(positionGroup));
|
|
768
|
-
let rePositionGroup = [];
|
|
769
|
-
// group same slice points
|
|
770
|
-
positionGroup.forEach((p) => {
|
|
771
|
-
let temp = [];
|
|
772
|
-
let sameIndex = [];
|
|
773
|
-
for (let i = 0; i < copyPosition.length; i++) {
|
|
774
|
-
if (p.z == copyPosition[i].z) {
|
|
775
|
-
temp.push(copyPosition[i]);
|
|
776
|
-
sameIndex.push(i);
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
sameIndex.reverse();
|
|
780
|
-
sameIndex.forEach(i => copyPosition.splice(i, 1));
|
|
781
|
-
if (temp.length > 0)
|
|
782
|
-
rePositionGroup.push(temp);
|
|
783
|
-
if (copyPosition.length == 0) {
|
|
784
|
-
return;
|
|
785
|
-
}
|
|
786
|
-
});
|
|
787
|
-
rePositionGroup.forEach((group) => {
|
|
788
|
-
group.forEach(p => {
|
|
789
|
-
this.drawSphereCore(ctx, p.x, p.y, this.nrrd_states.sphereRadius, p.color);
|
|
790
|
-
});
|
|
791
|
-
this.storeSphereImages(group[0].z, axis);
|
|
792
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
/****************************Sphere functions****************************************************/
|
|
796
|
-
// for sphere
|
|
797
|
-
storeSphereImages(index, axis) {
|
|
798
|
-
this.setEmptyCanvasSize(axis);
|
|
799
|
-
this.drawImageOnEmptyImage(this.protectedData.canvases.drawingSphereCanvas);
|
|
800
|
-
let imageData = this.protectedData.ctxes.emptyCtx.getImageData(0, 0, this.protectedData.canvases.emptyCanvas.width, this.protectedData.canvases.emptyCanvas.height);
|
|
801
|
-
this.storeImageToAxis(index, this.protectedData.maskData.paintImages, imageData, axis);
|
|
765
|
+
this.sphereTool.drawCalculatorSphereOnEachViews(axis);
|
|
802
766
|
}
|
|
803
767
|
drawSphereOnEachViews(decay, axis) {
|
|
804
|
-
|
|
805
|
-
this.setSphereCanvasSize(axis);
|
|
806
|
-
const mouseX = this.nrrd_states.sphereOrigin[axis][0];
|
|
807
|
-
const mouseY = this.nrrd_states.sphereOrigin[axis][1];
|
|
808
|
-
const originIndex = this.nrrd_states.sphereOrigin[axis][2];
|
|
809
|
-
const preIndex = originIndex - decay;
|
|
810
|
-
const nextIndex = originIndex + decay;
|
|
811
|
-
const ctx = this.protectedData.ctxes.drawingSphereCtx;
|
|
812
|
-
const canvas = this.protectedData.canvases.drawingSphereCanvas;
|
|
813
|
-
if (preIndex === nextIndex) {
|
|
814
|
-
this.drawSphereCore(ctx, mouseX, mouseY, this.nrrd_states.sphereRadius, this.gui_states.fillColor);
|
|
815
|
-
this.storeSphereImages(preIndex, axis);
|
|
816
|
-
}
|
|
817
|
-
else {
|
|
818
|
-
this.drawSphereCore(ctx, mouseX, mouseY, (this.nrrd_states.sphereRadius - decay), this.gui_states.fillColor);
|
|
819
|
-
this.drawImageOnEmptyImage(canvas);
|
|
820
|
-
this.storeSphereImages(preIndex, axis);
|
|
821
|
-
this.storeSphereImages(nextIndex, axis);
|
|
822
|
-
}
|
|
823
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
824
|
-
}
|
|
825
|
-
/**
|
|
826
|
-
*
|
|
827
|
-
* @param ctx draw sphere canvas ctx
|
|
828
|
-
* @param x width must be match the origin size, size factor 1, ignore the size factor
|
|
829
|
-
* @param y height must be match the origin size, size factor 1, ignore the size factor
|
|
830
|
-
* @param radius radius must be match the origin size, size factor 1, ignore the size factor
|
|
831
|
-
* @param color sphere color
|
|
832
|
-
*/
|
|
833
|
-
drawSphereCore(ctx, x, y, radius, color) {
|
|
834
|
-
ctx.beginPath();
|
|
835
|
-
ctx.arc(x, y, radius, 0, 2 * Math.PI);
|
|
836
|
-
ctx.fillStyle = color;
|
|
837
|
-
ctx.fill();
|
|
838
|
-
ctx.closePath();
|
|
768
|
+
this.sphereTool.drawSphereOnEachViews(decay, axis);
|
|
839
769
|
}
|
|
840
|
-
setSphereCanvasSize(axis) {
|
|
841
|
-
switch (!!axis ? axis : this.protectedData.axis) {
|
|
842
|
-
case "x":
|
|
843
|
-
this.protectedData.canvases.drawingSphereCanvas.width =
|
|
844
|
-
this.nrrd_states.nrrd_z_mm;
|
|
845
|
-
this.protectedData.canvases.drawingSphereCanvas.height =
|
|
846
|
-
this.nrrd_states.nrrd_y_mm;
|
|
847
|
-
break;
|
|
848
|
-
case "y":
|
|
849
|
-
this.protectedData.canvases.drawingSphereCanvas.width =
|
|
850
|
-
this.nrrd_states.nrrd_x_mm;
|
|
851
|
-
this.protectedData.canvases.drawingSphereCanvas.height =
|
|
852
|
-
this.nrrd_states.nrrd_z_mm;
|
|
853
|
-
break;
|
|
854
|
-
case "z":
|
|
855
|
-
this.protectedData.canvases.drawingSphereCanvas.width =
|
|
856
|
-
this.nrrd_states.nrrd_x_mm;
|
|
857
|
-
this.protectedData.canvases.drawingSphereCanvas.height =
|
|
858
|
-
this.nrrd_states.nrrd_y_mm;
|
|
859
|
-
break;
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
// drawing canvas mouse shpere wheel
|
|
863
770
|
configMouseSphereWheel() {
|
|
864
|
-
|
|
865
|
-
e.preventDefault();
|
|
866
|
-
if (e.deltaY < 0) {
|
|
867
|
-
this.nrrd_states.sphereRadius += 1;
|
|
868
|
-
}
|
|
869
|
-
else {
|
|
870
|
-
this.nrrd_states.sphereRadius -= 1;
|
|
871
|
-
}
|
|
872
|
-
// limited the radius max and min
|
|
873
|
-
this.nrrd_states.sphereRadius = Math.max(1, Math.min(this.nrrd_states.sphereRadius, 50));
|
|
874
|
-
// get mouse position
|
|
875
|
-
const mouseX = this.nrrd_states.sphereOrigin[this.protectedData.axis][0];
|
|
876
|
-
const mouseY = this.nrrd_states.sphereOrigin[this.protectedData.axis][1];
|
|
877
|
-
this.drawSphere(mouseX, mouseY, this.nrrd_states.sphereRadius);
|
|
878
|
-
};
|
|
879
|
-
return sphereEvent;
|
|
771
|
+
return this.sphereTool.configMouseSphereWheel();
|
|
880
772
|
}
|
|
881
773
|
drawCalculatorSphere(radius) {
|
|
882
|
-
|
|
883
|
-
const [canvas, ctx] = this.clearSphereCanvas();
|
|
884
|
-
if (!!this.nrrd_states.tumourSphereOrigin && this.nrrd_states.tumourSphereOrigin[this.protectedData.axis][2] === this.nrrd_states.currentIndex) {
|
|
885
|
-
this.drawSphereCore(ctx, this.nrrd_states.tumourSphereOrigin[this.protectedData.axis][0], this.nrrd_states.tumourSphereOrigin[this.protectedData.axis][1], radius, this.nrrd_states.tumourColor);
|
|
886
|
-
}
|
|
887
|
-
if (!!this.nrrd_states.skinSphereOrigin && this.nrrd_states.skinSphereOrigin[this.protectedData.axis][2] === this.nrrd_states.currentIndex) {
|
|
888
|
-
this.drawSphereCore(ctx, this.nrrd_states.skinSphereOrigin[this.protectedData.axis][0], this.nrrd_states.skinSphereOrigin[this.protectedData.axis][1], radius, this.nrrd_states.skinColor);
|
|
889
|
-
}
|
|
890
|
-
if (!!this.nrrd_states.ribSphereOrigin && this.nrrd_states.ribSphereOrigin[this.protectedData.axis][2] === this.nrrd_states.currentIndex) {
|
|
891
|
-
this.drawSphereCore(ctx, this.nrrd_states.ribSphereOrigin[this.protectedData.axis][0], this.nrrd_states.ribSphereOrigin[this.protectedData.axis][1], radius, this.nrrd_states.ribcageColor);
|
|
892
|
-
}
|
|
893
|
-
if (!!this.nrrd_states.nippleSphereOrigin && this.nrrd_states.nippleSphereOrigin[this.protectedData.axis][2] === this.nrrd_states.currentIndex) {
|
|
894
|
-
this.drawSphereCore(ctx, this.nrrd_states.nippleSphereOrigin[this.protectedData.axis][0], this.nrrd_states.nippleSphereOrigin[this.protectedData.axis][1], radius, this.nrrd_states.nippleColor);
|
|
895
|
-
}
|
|
896
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.drawImage(canvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
774
|
+
this.sphereTool.drawCalculatorSphere(radius);
|
|
897
775
|
}
|
|
898
776
|
drawSphere(mouseX, mouseY, radius) {
|
|
899
|
-
|
|
900
|
-
// clear canvas
|
|
901
|
-
const [canvas, ctx] = this.clearSphereCanvas();
|
|
902
|
-
this.drawSphereCore(ctx, mouseX, mouseY, radius, this.gui_states.fillColor);
|
|
903
|
-
console.log("when drawing shpere on canvas");
|
|
904
|
-
console.log("Line 1256 mastercanvasesize:", this.protectedData.canvases.drawingCanvasLayerMaster.width, this.protectedData.canvases.drawingCanvasLayerMaster.height);
|
|
905
|
-
console.log("current xy:", mouseX, mouseY);
|
|
906
|
-
console.log("current changed width:", this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
907
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.drawImage(canvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
908
|
-
}
|
|
909
|
-
clearSphereCanvas() {
|
|
910
|
-
// this.protectedData.canvases.drawingSphereCanvas.width =
|
|
911
|
-
// this.protectedData.canvases.drawingCanvasLayerMaster.width;
|
|
912
|
-
// this.protectedData.canvases.drawingSphereCanvas.height =
|
|
913
|
-
// this.protectedData.canvases.drawingCanvasLayerMaster.height;
|
|
914
|
-
// clear drawingCanvasLayerMaster
|
|
915
|
-
this.protectedData.canvases.drawingCanvasLayerMaster.width = this.protectedData.canvases.drawingCanvasLayerMaster.width;
|
|
916
|
-
// resize sphere canvas size to original size
|
|
917
|
-
this.protectedData.canvases.drawingSphereCanvas.width = this.protectedData.canvases.originCanvas.width;
|
|
918
|
-
this.protectedData.canvases.drawingSphereCanvas.height = this.protectedData.canvases.originCanvas.height;
|
|
919
|
-
const canvas = this.protectedData.canvases.drawingSphereCanvas;
|
|
920
|
-
const ctx = this.protectedData.ctxes.drawingSphereCtx;
|
|
921
|
-
return [canvas, ctx];
|
|
777
|
+
this.sphereTool.drawSphere(mouseX, mouseY, radius);
|
|
922
778
|
}
|
|
923
779
|
/**
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
* When we switch into different axis' views, we need to convert current view's the depth to the pixel distance in other views width or height, and convert the current view's width or height from pixel distance to mm distance as other views' depth (slice index) in general.
|
|
928
|
-
*
|
|
929
|
-
* Then as for the crosshair (Cursor Inspector), we also need to convert the cursor point (x, y, z) to other views' (x, y, z).
|
|
930
|
-
*
|
|
931
|
-
* @param from "x" | "y" | "z", current view axis, "x: sagittle, y: coronal, z: axial".
|
|
932
|
-
* @param to "x" | "y" | "z", target view axis (where you want jump to), "x: sagittle, y: coronal, z: axial".
|
|
933
|
-
* @param cursorNumX number, cursor point x on current axis's slice. (pixel distance)
|
|
934
|
-
* @param cursorNumY number, cursor point y on current axis's slice. (pixel distance)
|
|
935
|
-
* @param currentSliceIndex number, current axis's slice's index/depth. (mm distance)
|
|
936
|
-
* @returns
|
|
937
|
-
*/
|
|
780
|
+
* Convert cursor point between axis views.
|
|
781
|
+
* Delegated to CrosshairTool.
|
|
782
|
+
*/
|
|
938
783
|
convertCursorPoint(from, to, cursorNumX, cursorNumY, currentSliceIndex) {
|
|
939
|
-
|
|
940
|
-
const dimensions = nrrd.dimensions;
|
|
941
|
-
const ratios = nrrd.ratios;
|
|
942
|
-
const { nrrd_x_mm, nrrd_y_mm, nrrd_z_mm } = nrrd;
|
|
943
|
-
let currentIndex = 0;
|
|
944
|
-
let oldIndex = 0;
|
|
945
|
-
let convertCursorNumX = 0;
|
|
946
|
-
let convertCursorNumY = 0;
|
|
947
|
-
const convertIndex = {
|
|
948
|
-
x: {
|
|
949
|
-
y: (val) => Math.ceil((val / nrrd_x_mm) * dimensions[0]),
|
|
950
|
-
z: (val) => Math.ceil((val / nrrd_z_mm) * dimensions[2]),
|
|
951
|
-
},
|
|
952
|
-
y: {
|
|
953
|
-
x: (val) => Math.ceil((val / nrrd_y_mm) * dimensions[1]),
|
|
954
|
-
z: (val) => Math.ceil((1 - val / nrrd_z_mm) * dimensions[2]),
|
|
955
|
-
},
|
|
956
|
-
z: {
|
|
957
|
-
x: (val) => Math.ceil((val / nrrd_x_mm) * dimensions[0]),
|
|
958
|
-
y: (val) => Math.ceil((val / nrrd_y_mm) * dimensions[1]),
|
|
959
|
-
},
|
|
960
|
-
};
|
|
961
|
-
const convertCursor = {
|
|
962
|
-
x: {
|
|
963
|
-
y: (sliceIndex) => Math.ceil((sliceIndex / dimensions[0]) * nrrd_x_mm),
|
|
964
|
-
z: (sliceIndex) => Math.ceil((sliceIndex / dimensions[0]) * nrrd_x_mm),
|
|
965
|
-
},
|
|
966
|
-
y: {
|
|
967
|
-
x: (sliceIndex) => Math.ceil((sliceIndex / dimensions[1]) * nrrd_y_mm),
|
|
968
|
-
z: (sliceIndex) => Math.ceil((sliceIndex / dimensions[1]) * nrrd_y_mm),
|
|
969
|
-
},
|
|
970
|
-
z: {
|
|
971
|
-
x: (sliceIndex) => Math.ceil((sliceIndex / dimensions[2]) * nrrd_z_mm),
|
|
972
|
-
y: (sliceIndex) => Math.ceil((1 - sliceIndex / dimensions[2]) * nrrd_z_mm),
|
|
973
|
-
},
|
|
974
|
-
};
|
|
975
|
-
if (from === to) {
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
if (from === "z" && to === "x") {
|
|
979
|
-
currentIndex = convertIndex[from][to](cursorNumX);
|
|
980
|
-
oldIndex = currentIndex * ratios[to];
|
|
981
|
-
convertCursorNumX = convertCursor[from][to](currentSliceIndex);
|
|
982
|
-
convertCursorNumY = cursorNumY;
|
|
983
|
-
}
|
|
984
|
-
else if (from === "y" && to === "x") {
|
|
985
|
-
currentIndex = convertIndex[from][to](cursorNumX);
|
|
986
|
-
oldIndex = currentIndex * ratios.x;
|
|
987
|
-
convertCursorNumY = convertCursor[from][to](currentSliceIndex);
|
|
988
|
-
convertCursorNumX = dimensions[2] * ratios.z - cursorNumY;
|
|
989
|
-
}
|
|
990
|
-
else if (from === "z" && to === "y") {
|
|
991
|
-
currentIndex = convertIndex[from][to](cursorNumY);
|
|
992
|
-
oldIndex = currentIndex * ratios[to];
|
|
993
|
-
convertCursorNumY = convertCursor[from][to](currentSliceIndex);
|
|
994
|
-
convertCursorNumX = cursorNumX;
|
|
995
|
-
}
|
|
996
|
-
else if (from === "x" && to === "y") {
|
|
997
|
-
currentIndex = convertIndex[from][to](cursorNumY);
|
|
998
|
-
oldIndex = currentIndex * ratios[to];
|
|
999
|
-
convertCursorNumX = convertCursor[from][to](currentSliceIndex);
|
|
1000
|
-
convertCursorNumY = dimensions[2] * ratios.z - cursorNumX;
|
|
1001
|
-
}
|
|
1002
|
-
else if (from === "x" && to === "z") {
|
|
1003
|
-
currentIndex = convertIndex[from][to](cursorNumX);
|
|
1004
|
-
oldIndex = currentIndex * ratios[to];
|
|
1005
|
-
convertCursorNumX = convertCursor[from][to](currentSliceIndex);
|
|
1006
|
-
convertCursorNumY = cursorNumY;
|
|
1007
|
-
}
|
|
1008
|
-
else if (from === "y" && to === "z") {
|
|
1009
|
-
currentIndex = convertIndex[from][to](cursorNumY);
|
|
1010
|
-
oldIndex = currentIndex * ratios.z;
|
|
1011
|
-
convertCursorNumY = convertCursor[from][to](currentSliceIndex);
|
|
1012
|
-
convertCursorNumX = cursorNumX;
|
|
1013
|
-
}
|
|
1014
|
-
else {
|
|
1015
|
-
return;
|
|
1016
|
-
}
|
|
1017
|
-
return { currentIndex, oldIndex, convertCursorNumX, convertCursorNumY };
|
|
784
|
+
return this.crosshairTool.convertCursorPoint(from, to, cursorNumX, cursorNumY, currentSliceIndex);
|
|
1018
785
|
}
|
|
1019
786
|
setUpSphereOrigins(mouseX, mouseY, sliceIndex) {
|
|
1020
|
-
|
|
1021
|
-
const convertObj = this.convertCursorPoint(from, to, mouseX, mouseY, sliceIndex);
|
|
1022
|
-
return {
|
|
1023
|
-
convertCursorNumX: convertObj === null || convertObj === void 0 ? void 0 : convertObj.convertCursorNumX,
|
|
1024
|
-
convertCursorNumY: convertObj === null || convertObj === void 0 ? void 0 : convertObj.convertCursorNumY,
|
|
1025
|
-
currentIndex: convertObj === null || convertObj === void 0 ? void 0 : convertObj.currentIndex,
|
|
1026
|
-
};
|
|
1027
|
-
};
|
|
1028
|
-
const axisConversions = {
|
|
1029
|
-
x: { axisTo1: "y", axisTo2: "z" },
|
|
1030
|
-
y: { axisTo1: "z", axisTo2: "x" },
|
|
1031
|
-
z: { axisTo1: "x", axisTo2: "y" },
|
|
1032
|
-
};
|
|
1033
|
-
const { axisTo1, axisTo2 } = axisConversions[this.protectedData.axis];
|
|
1034
|
-
this.nrrd_states.sphereOrigin[axisTo1] = [
|
|
1035
|
-
convertCursor(this.protectedData.axis, axisTo1).convertCursorNumX,
|
|
1036
|
-
convertCursor(this.protectedData.axis, axisTo1).convertCursorNumY,
|
|
1037
|
-
convertCursor(this.protectedData.axis, axisTo1).currentIndex,
|
|
1038
|
-
];
|
|
1039
|
-
this.nrrd_states.sphereOrigin[axisTo2] = [
|
|
1040
|
-
convertCursor(this.protectedData.axis, axisTo2).convertCursorNumX,
|
|
1041
|
-
convertCursor(this.protectedData.axis, axisTo2).convertCursorNumY,
|
|
1042
|
-
convertCursor(this.protectedData.axis, axisTo2).currentIndex,
|
|
1043
|
-
];
|
|
1044
|
-
}
|
|
1045
|
-
/****************************label div controls****************************************************/
|
|
1046
|
-
getRestLabel() {
|
|
1047
|
-
const labels = this.nrrd_states.labels;
|
|
1048
|
-
const restLabel = labels.filter((item) => {
|
|
1049
|
-
return item !== this.gui_states.label;
|
|
1050
|
-
});
|
|
1051
|
-
return restLabel;
|
|
787
|
+
this.crosshairTool.setUpSphereOrigins(mouseX, mouseY, sliceIndex);
|
|
1052
788
|
}
|
|
1053
|
-
/****************************
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
789
|
+
/****************************layer div controls****************************************************/
|
|
790
|
+
getRestLayer() {
|
|
791
|
+
const layers = this.nrrd_states.layers;
|
|
792
|
+
const restLayer = layers.filter((item) => {
|
|
793
|
+
return item !== this.gui_states.layer;
|
|
1057
794
|
});
|
|
795
|
+
return restLayer;
|
|
1058
796
|
}
|
|
797
|
+
/**************************** Undo/Redo functions (Phase 6 — Delta-based) ****************************/
|
|
1059
798
|
/**
|
|
1060
|
-
* Clear mask on current slice canvas
|
|
799
|
+
* Clear mask on current slice canvas.
|
|
800
|
+
*
|
|
801
|
+
* Phase 2: Clears the MaskVolume slice for all three layers,
|
|
802
|
+
* re-stores, and notifies external via getMask callback with clearFlag=true.
|
|
803
|
+
* Phase 6: Also records a MaskDelta for undo support.
|
|
1061
804
|
*/
|
|
1062
805
|
clearPaint() {
|
|
1063
806
|
this.protectedData.Is_Draw = true;
|
|
@@ -1067,391 +810,138 @@ export class DrawToolCore extends CommToolsData {
|
|
|
1067
810
|
this.protectedData.mainPreSlices.repaint.call(this.protectedData.mainPreSlices);
|
|
1068
811
|
this.protectedData.previousDrawingImage =
|
|
1069
812
|
this.protectedData.ctxes.emptyCtx.createImageData(1, 1);
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
if (undo.layers.label1.length > 0) {
|
|
1099
|
-
const image = undo.layers.label1[undo.layers.label1.length - 1];
|
|
1100
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.drawImage(image, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
1101
|
-
}
|
|
1102
|
-
if (undo.layers.label2.length > 0) {
|
|
1103
|
-
const image = undo.layers.label2[undo.layers.label2.length - 1];
|
|
1104
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.drawImage(image, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
1105
|
-
}
|
|
1106
|
-
if (undo.layers.label3.length > 0) {
|
|
1107
|
-
const image = undo.layers.label3[undo.layers.label3.length - 1];
|
|
1108
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.drawImage(image, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
813
|
+
// Phase 2 + 6: Clear volume slices and record undo delta
|
|
814
|
+
try {
|
|
815
|
+
const axis = this.protectedData.axis;
|
|
816
|
+
const idx = this.nrrd_states.currentIndex;
|
|
817
|
+
const activeLayer = this.gui_states.layer;
|
|
818
|
+
const vol = this.getVolumeForLayer(activeLayer);
|
|
819
|
+
// Capture old slice for undo before clearing
|
|
820
|
+
const oldSlice = vol.getSliceUint8(idx, axis).data.slice();
|
|
821
|
+
// Clear only the active layer (clear also clears all for canvas consistency)
|
|
822
|
+
const { layer1, layer2, layer3 } = this.protectedData.maskData.volumes;
|
|
823
|
+
layer1.clearSlice(idx, axis);
|
|
824
|
+
layer2.clearSlice(idx, axis);
|
|
825
|
+
layer3.clearSlice(idx, axis);
|
|
826
|
+
// New (all-zero) slice for undo newSlice
|
|
827
|
+
const { data: newSlice, width, height } = vol.getSliceUint8(idx, axis);
|
|
828
|
+
// Push clearPaint delta to UndoManager (supports undo)
|
|
829
|
+
this.undoManager.push({
|
|
830
|
+
layerId: activeLayer,
|
|
831
|
+
axis,
|
|
832
|
+
sliceIndex: idx,
|
|
833
|
+
oldSlice,
|
|
834
|
+
newSlice: newSlice.slice(),
|
|
835
|
+
});
|
|
836
|
+
// Notify external that slice was cleared
|
|
837
|
+
if (!this.nrrd_states.loadMaskJson && !this.gui_states.sphere && !this.gui_states.calculator) {
|
|
838
|
+
const activeChannel = this.gui_states.activeChannel || 1;
|
|
839
|
+
this.nrrd_states.getMask(newSlice, activeLayer, activeChannel, idx, axis, width, height, true // clearFlag = true
|
|
840
|
+
);
|
|
1109
841
|
}
|
|
1110
|
-
this.protectedData.previousDrawingImage =
|
|
1111
|
-
this.protectedData.ctxes.drawingLayerMasterCtx.getImageData(0, 0, this.protectedData.canvases.drawingCanvasLayerMaster.width, this.protectedData.canvases.drawingCanvasLayerMaster.height);
|
|
1112
|
-
this.storeAllImages(this.nrrd_states.currentIndex, this.gui_states.label);
|
|
1113
|
-
this.setIsDrawFalse(1000);
|
|
1114
842
|
}
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
storeImageToAxis(index, paintedImages, imageData, axis) {
|
|
1118
|
-
var _a, _b, _c;
|
|
1119
|
-
let temp = {
|
|
1120
|
-
index,
|
|
1121
|
-
image: imageData,
|
|
1122
|
-
};
|
|
1123
|
-
let drawedImage;
|
|
1124
|
-
switch (!!axis ? axis : this.protectedData.axis) {
|
|
1125
|
-
case "x":
|
|
1126
|
-
drawedImage = this.filterDrawedImage("x", index, paintedImages);
|
|
1127
|
-
drawedImage
|
|
1128
|
-
? (drawedImage.image = imageData)
|
|
1129
|
-
: (_a = paintedImages.x) === null || _a === void 0 ? void 0 : _a.push(temp);
|
|
1130
|
-
break;
|
|
1131
|
-
case "y":
|
|
1132
|
-
drawedImage = this.filterDrawedImage("y", index, paintedImages);
|
|
1133
|
-
drawedImage
|
|
1134
|
-
? (drawedImage.image = imageData)
|
|
1135
|
-
: (_b = paintedImages.y) === null || _b === void 0 ? void 0 : _b.push(temp);
|
|
1136
|
-
break;
|
|
1137
|
-
case "z":
|
|
1138
|
-
drawedImage = this.filterDrawedImage("z", index, paintedImages);
|
|
1139
|
-
drawedImage
|
|
1140
|
-
? (drawedImage.image = imageData)
|
|
1141
|
-
: (_c = paintedImages.z) === null || _c === void 0 ? void 0 : _c.push(temp);
|
|
1142
|
-
break;
|
|
843
|
+
catch (_a) {
|
|
844
|
+
// Volume not ready (1×1×1 placeholder) — continue with legacy path
|
|
1143
845
|
}
|
|
846
|
+
this.storeAllImages(this.nrrd_states.currentIndex, this.gui_states.layer);
|
|
847
|
+
const restLayers = this.getRestLayer();
|
|
848
|
+
this.storeEachLayerImage(this.nrrd_states.currentIndex, restLayers[0]);
|
|
849
|
+
this.storeEachLayerImage(this.nrrd_states.currentIndex, restLayers[1]);
|
|
850
|
+
this.setIsDrawFalse(1000);
|
|
1144
851
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
852
|
+
/**
|
|
853
|
+
* Undo the last drawing operation on the active layer.
|
|
854
|
+
* Restores the MaskVolume slice to its pre-draw state, re-renders
|
|
855
|
+
* the canvas, and notifies the backend.
|
|
856
|
+
*/
|
|
857
|
+
undoLastPainting() {
|
|
858
|
+
const delta = this.undoManager.undo();
|
|
859
|
+
if (!delta)
|
|
860
|
+
return;
|
|
861
|
+
try {
|
|
862
|
+
const vol = this.getVolumeForLayer(delta.layerId);
|
|
863
|
+
vol.setSliceUint8(delta.sliceIndex, delta.oldSlice, delta.axis);
|
|
1151
864
|
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
switch (this.protectedData.axis) {
|
|
1155
|
-
case "x":
|
|
1156
|
-
const maskData_x = this.checkSharedPlaceSlice(this.nrrd_states.nrrd_x_pixel, this.nrrd_states.nrrd_y_pixel, imageData);
|
|
1157
|
-
const marked_a_x = this.sliceArrayV(maskData_x, this.nrrd_states.nrrd_y_pixel, this.nrrd_states.nrrd_z_pixel);
|
|
1158
|
-
const marked_b_x = this.sliceArrayH(maskData_x, this.nrrd_states.nrrd_y_pixel, this.nrrd_states.nrrd_z_pixel);
|
|
1159
|
-
// const ratio_a_x =
|
|
1160
|
-
// this.nrrd_states.nrrd_z / this.nrrd_states.dimensions[2];
|
|
1161
|
-
// const ratio_b_x =
|
|
1162
|
-
// this.nrrd_states.nrrd_y / this.nrrd_states.dimensions[1];
|
|
1163
|
-
const convertXIndex = index;
|
|
1164
|
-
// from x the target z will replace the col pixel
|
|
1165
|
-
this.replaceVerticalColPixels(this.protectedData.maskData.paintImages.z, this.nrrd_states.dimensions[2],
|
|
1166
|
-
// this.nrrd_states.ratios.z,
|
|
1167
|
-
1, marked_a_x, this.nrrd_states.nrrd_x_pixel, convertXIndex);
|
|
1168
|
-
// from x the target y will replace the col pixel
|
|
1169
|
-
this.replaceVerticalColPixels(this.protectedData.maskData.paintImages.y, this.nrrd_states.dimensions[1],
|
|
1170
|
-
// this.nrrd_states.ratios.y,
|
|
1171
|
-
1, marked_b_x, this.nrrd_states.nrrd_x_pixel, convertXIndex);
|
|
1172
|
-
break;
|
|
1173
|
-
case "y":
|
|
1174
|
-
const maskData_y = this.checkSharedPlaceSlice(this.nrrd_states.nrrd_x_pixel, this.nrrd_states.nrrd_y_pixel, imageData);
|
|
1175
|
-
const marked_a_y = this.sliceArrayV(maskData_y, this.nrrd_states.nrrd_z_pixel, this.nrrd_states.nrrd_x_pixel);
|
|
1176
|
-
const marked_b_y = this.sliceArrayH(maskData_y, this.nrrd_states.nrrd_z_pixel, this.nrrd_states.nrrd_x_pixel);
|
|
1177
|
-
// const ratio_a_y =
|
|
1178
|
-
// this.nrrd_states.nrrd_x / this.nrrd_states.dimensions[0];
|
|
1179
|
-
// const ratio_b_y =
|
|
1180
|
-
// this.nrrd_states.nrrd_z / this.nrrd_states.dimensions[2];
|
|
1181
|
-
const convertYIndex = index;
|
|
1182
|
-
this.replaceHorizontalRowPixels(this.protectedData.maskData.paintImages.x, this.nrrd_states.dimensions[0],
|
|
1183
|
-
// this.nrrd_states.ratios.x,
|
|
1184
|
-
1, marked_a_y, this.nrrd_states.nrrd_z_pixel, convertYIndex);
|
|
1185
|
-
this.replaceHorizontalRowPixels(this.protectedData.maskData.paintImages.z, this.nrrd_states.dimensions[2],
|
|
1186
|
-
// this.nrrd_states.ratios.z,
|
|
1187
|
-
1, marked_b_y, this.nrrd_states.nrrd_x_pixel, convertYIndex);
|
|
1188
|
-
break;
|
|
1189
|
-
case "z":
|
|
1190
|
-
// for x slices get cols' pixels
|
|
1191
|
-
// for y slices get rows' pixels
|
|
1192
|
-
// 1. slice z 的 y轴对应了slice y的index,所以我们可以通过slice z 确定在y轴上那些行是有pixels的,我们就可以将它的y坐标(或者是行号)对应到slice y的index,并将该index下的marked image提取出来。
|
|
1193
|
-
// 2. 接着我们可以通过当前slice z 的index,来确定marked image 需要替换或重组的 行 pixel array。
|
|
1194
|
-
const maskData_z = this.checkSharedPlaceSlice(this.nrrd_states.nrrd_x_pixel, this.nrrd_states.nrrd_y_pixel, imageData);
|
|
1195
|
-
// 1. get slice z's each row's and col's pixel as a 2d array.
|
|
1196
|
-
// 1.1 get the cols' 2d array for slice x
|
|
1197
|
-
const marked_a_z = this.sliceArrayV(maskData_z, this.nrrd_states.nrrd_y_pixel, this.nrrd_states.nrrd_x_pixel);
|
|
1198
|
-
// 1.2 get the rows' 2d array for slice y
|
|
1199
|
-
const marked_b_z = this.sliceArrayH(maskData_z, this.nrrd_states.nrrd_y_pixel, this.nrrd_states.nrrd_x_pixel);
|
|
1200
|
-
// 1.3 get x axis ratio for converting, to match the number slice x with the slice z's x axis pixel number.
|
|
1201
|
-
// const ratio_a_z =
|
|
1202
|
-
// this.nrrd_states.nrrd_x / this.nrrd_states.dimensions[0];
|
|
1203
|
-
// // 1.4 get y axis ratio for converting
|
|
1204
|
-
// const ratio_b_z =
|
|
1205
|
-
// this.nrrd_states.nrrd_y / this.nrrd_states.dimensions[1];
|
|
1206
|
-
// 1.5 To identify which row/col data should be replace
|
|
1207
|
-
const convertZIndex = index;
|
|
1208
|
-
// 2. Mapping coordinates
|
|
1209
|
-
// from z the target x will replace the col pixel
|
|
1210
|
-
this.replaceVerticalColPixels(this.protectedData.maskData.paintImages.x, this.nrrd_states.dimensions[0],
|
|
1211
|
-
// this.nrrd_states.ratios.x,
|
|
1212
|
-
1, marked_a_z, this.nrrd_states.nrrd_z_pixel, convertZIndex);
|
|
1213
|
-
// from z the target y will replace row pixel
|
|
1214
|
-
this.replaceHorizontalRowPixels(this.protectedData.maskData.paintImages.y, this.nrrd_states.dimensions[1],
|
|
1215
|
-
// this.nrrd_states.ratios.y,
|
|
1216
|
-
1, marked_b_z, this.nrrd_states.nrrd_x_pixel, convertZIndex);
|
|
1217
|
-
break;
|
|
865
|
+
catch (_a) {
|
|
866
|
+
return; // Volume not ready
|
|
1218
867
|
}
|
|
1219
|
-
this.
|
|
1220
|
-
if (
|
|
1221
|
-
this.
|
|
868
|
+
this.protectedData.Is_Draw = true;
|
|
869
|
+
if (delta.axis === this.protectedData.axis && delta.sliceIndex === this.nrrd_states.currentIndex) {
|
|
870
|
+
this.applyUndoRedoToCanvas(delta.layerId);
|
|
1222
871
|
}
|
|
1223
|
-
}
|
|
1224
|
-
storeImageToLabel(index, canvas, paintedImages) {
|
|
1225
872
|
if (!this.nrrd_states.loadMaskJson) {
|
|
1226
|
-
this.
|
|
1227
|
-
|
|
873
|
+
const { data: sliceData, width, height } = this.getVolumeForLayer(delta.layerId)
|
|
874
|
+
.getSliceUint8(delta.sliceIndex, delta.axis);
|
|
875
|
+
this.nrrd_states.getMask(sliceData, delta.layerId, this.gui_states.activeChannel || 1, delta.sliceIndex, delta.axis, width, height, false);
|
|
1228
876
|
}
|
|
1229
|
-
|
|
1230
|
-
this.storeImageToAxis(index, paintedImages, imageData);
|
|
1231
|
-
// this.setEmptyCanvasSize()
|
|
1232
|
-
return imageData;
|
|
877
|
+
this.setIsDrawFalse(1000);
|
|
1233
878
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
case "label3":
|
|
1247
|
-
imageData = this.storeImageToLabel(index, this.protectedData.canvases.drawingCanvasLayerThree, this.protectedData.maskData.paintImagesLabel3);
|
|
1248
|
-
break;
|
|
879
|
+
/**
|
|
880
|
+
* Redo the last undone operation on the active layer.
|
|
881
|
+
* Reapplies the MaskVolume slice to its post-draw state, re-renders
|
|
882
|
+
* the canvas, and notifies the backend.
|
|
883
|
+
*/
|
|
884
|
+
redoLastPainting() {
|
|
885
|
+
const delta = this.undoManager.redo();
|
|
886
|
+
if (!delta)
|
|
887
|
+
return;
|
|
888
|
+
try {
|
|
889
|
+
const vol = this.getVolumeForLayer(delta.layerId);
|
|
890
|
+
vol.setSliceUint8(delta.sliceIndex, delta.newSlice, delta.axis);
|
|
1249
891
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
this.nrrd_states.getMask(imageData, this.nrrd_states.currentIndex, label, this.nrrd_states.nrrd_x_pixel, this.nrrd_states.nrrd_y_pixel, this.nrrd_states.clearAllFlag);
|
|
892
|
+
catch (_a) {
|
|
893
|
+
return; // Volume not ready
|
|
1253
894
|
}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
const arr2D = [];
|
|
1258
|
-
for (let i = 0; i < row; i++) {
|
|
1259
|
-
const start = i * col * 4;
|
|
1260
|
-
const end = (i + 1) * col * 4;
|
|
1261
|
-
const temp = arr.slice(start, end);
|
|
1262
|
-
arr2D.push(temp);
|
|
895
|
+
this.protectedData.Is_Draw = true;
|
|
896
|
+
if (delta.axis === this.protectedData.axis && delta.sliceIndex === this.nrrd_states.currentIndex) {
|
|
897
|
+
this.applyUndoRedoToCanvas(delta.layerId);
|
|
1263
898
|
}
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
const base = col * 4;
|
|
1269
|
-
for (let i = 0; i < col; i++) {
|
|
1270
|
-
const temp = [];
|
|
1271
|
-
for (let j = 0; j < row; j++) {
|
|
1272
|
-
const index = base * j + i * 4;
|
|
1273
|
-
temp.push(arr[index]);
|
|
1274
|
-
temp.push(arr[index + 1]);
|
|
1275
|
-
temp.push(arr[index + 2]);
|
|
1276
|
-
temp.push(arr[index + 3]);
|
|
1277
|
-
}
|
|
1278
|
-
arr2D.push(temp);
|
|
899
|
+
if (!this.nrrd_states.loadMaskJson) {
|
|
900
|
+
const { data: sliceData, width, height } = this.getVolumeForLayer(delta.layerId)
|
|
901
|
+
.getSliceUint8(delta.sliceIndex, delta.axis);
|
|
902
|
+
this.nrrd_states.getMask(sliceData, delta.layerId, this.gui_states.activeChannel || 1, delta.sliceIndex, delta.axis, width, height, false);
|
|
1279
903
|
}
|
|
1280
|
-
|
|
904
|
+
this.setIsDrawFalse(1000);
|
|
1281
905
|
}
|
|
1282
906
|
/**
|
|
1283
|
-
*
|
|
1284
|
-
*
|
|
1285
|
-
* @param length : the target view slice's dimention (total slice index num)
|
|
1286
|
-
* @param ratio : the target slice image's width/height ratio of its dimention length
|
|
1287
|
-
* @param markedArr : current painted image's vertical 2d Array
|
|
1288
|
-
* @param targetWidth : the target image width
|
|
1289
|
-
* @param convertIndex : Mapping current image's index to target slice image's width/height pixel start point
|
|
907
|
+
* Re-render a layer canvas from MaskVolume and composite to master.
|
|
908
|
+
* Called after writing oldSlice/newSlice back to the volume during undo/redo.
|
|
1290
909
|
*/
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
const
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
}
|
|
910
|
+
applyUndoRedoToCanvas(layerId) {
|
|
911
|
+
let target = this.protectedData.layerTargets.get(layerId);
|
|
912
|
+
if (!target) {
|
|
913
|
+
const firstId = this.nrrd_states.layers[0];
|
|
914
|
+
target = this.protectedData.layerTargets.get(firstId);
|
|
915
|
+
}
|
|
916
|
+
const { ctx, canvas } = target;
|
|
917
|
+
// Clear and re-render the affected layer canvas from MaskVolume
|
|
918
|
+
canvas.width = canvas.width;
|
|
919
|
+
const buffer = this.getOrCreateSliceBuffer(this.protectedData.axis);
|
|
920
|
+
if (buffer) {
|
|
921
|
+
this.renderSliceToCanvas(layerId, this.protectedData.axis, this.nrrd_states.currentIndex, buffer, ctx, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
1304
922
|
}
|
|
923
|
+
// Re-composite all layers to master
|
|
924
|
+
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);
|
|
1305
928
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
* @param length : the target view slice's dimention (total slice index num)
|
|
1310
|
-
* @param ratio : the target slice image's width/height ratio of its dimention length
|
|
1311
|
-
* @param markedArr : current painted image's horizontal 2d Array
|
|
1312
|
-
* @param targetWidth : the target image width
|
|
1313
|
-
* @param convertIndex : Mapping current image's index to target slice image's width/height pixel start point
|
|
1314
|
-
*/
|
|
1315
|
-
replaceHorizontalRowPixels(paintImageArray, length, ratio, markedArr, targetWidth, convertIndex) {
|
|
1316
|
-
for (let i = 0, len = length; i < len; i++) {
|
|
1317
|
-
const index = Math.floor(i * ratio);
|
|
1318
|
-
const convertImageArray = paintImageArray[i].image.data;
|
|
1319
|
-
const mark_data = markedArr[index];
|
|
1320
|
-
const start = targetWidth * convertIndex * 4;
|
|
1321
|
-
for (let j = 0, len = mark_data.length; j < len; j++) {
|
|
1322
|
-
convertImageArray[start + j] = mark_data[j];
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
929
|
+
/****************************Store images (delegated to ImageStoreHelper)****************************************************/
|
|
930
|
+
storeImageToAxis(index, paintedImages, imageData, axis) {
|
|
931
|
+
this.imageStoreHelper.storeImageToAxis(index, paintedImages, imageData, axis);
|
|
1325
932
|
}
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
let maskData = this.protectedData.ctxes.emptyCtx.createImageData(width, height).data;
|
|
1329
|
-
if (this.nrrd_states.sharedPlace.z.includes(this.nrrd_states.currentIndex)) {
|
|
1330
|
-
const sharedPlaceArr = this.findSliceInSharedPlace();
|
|
1331
|
-
sharedPlaceArr.push(imageData);
|
|
1332
|
-
if (sharedPlaceArr.length > 0) {
|
|
1333
|
-
for (let i = 0; i < sharedPlaceArr.length; i++) {
|
|
1334
|
-
this.replaceArray(maskData, sharedPlaceArr[i].data);
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
else {
|
|
1339
|
-
maskData = imageData.data;
|
|
1340
|
-
}
|
|
1341
|
-
return maskData;
|
|
933
|
+
storeAllImages(index, layer) {
|
|
934
|
+
this.imageStoreHelper.storeAllImages(index, layer);
|
|
1342
935
|
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
for (let i = 0, len = replaceArr.length; i < len; i++) {
|
|
1346
|
-
if (replaceArr[i] === 0 || mainArr[i] !== 0) {
|
|
1347
|
-
continue;
|
|
1348
|
-
}
|
|
1349
|
-
else {
|
|
1350
|
-
mainArr[i] = replaceArr[i];
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
936
|
+
storeImageToLayer(index, canvas, paintedImages) {
|
|
937
|
+
return this.imageStoreHelper.storeImageToLayer(index, canvas, paintedImages);
|
|
1353
938
|
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
const base = Math.floor(this.nrrd_states.currentIndex *
|
|
1357
|
-
this.nrrd_states.ratios[this.protectedData.axis]);
|
|
1358
|
-
for (let i = 1; i <= 3; i++) {
|
|
1359
|
-
const index = this.nrrd_states.currentIndex - i;
|
|
1360
|
-
if (index < this.nrrd_states.minIndex) {
|
|
1361
|
-
break;
|
|
1362
|
-
}
|
|
1363
|
-
else {
|
|
1364
|
-
const newIndex = Math.floor(index * this.nrrd_states.ratios[this.protectedData.axis]);
|
|
1365
|
-
if (newIndex === base) {
|
|
1366
|
-
sharedPlaceImages.push(this.protectedData.maskData.paintImages[this.protectedData.axis][index].image);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
for (let i = 1; i <= 3; i++) {
|
|
1371
|
-
const index = this.nrrd_states.currentIndex + i;
|
|
1372
|
-
if (index > this.nrrd_states.maxIndex) {
|
|
1373
|
-
break;
|
|
1374
|
-
}
|
|
1375
|
-
else {
|
|
1376
|
-
const newIndex = Math.floor(index * this.nrrd_states.ratios[this.protectedData.axis]);
|
|
1377
|
-
if (newIndex === base) {
|
|
1378
|
-
sharedPlaceImages.push(this.protectedData.maskData.paintImages[this.protectedData.axis][index].image);
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
return sharedPlaceImages;
|
|
939
|
+
storeEachLayerImage(index, layer) {
|
|
940
|
+
this.imageStoreHelper.storeEachLayerImage(index, layer);
|
|
1383
941
|
}
|
|
1384
|
-
/******************************** Utils gui related functions ***************************************/
|
|
1385
|
-
/**
|
|
1386
|
-
* Set up root container events fns for drag function
|
|
1387
|
-
* @param callback
|
|
1388
|
-
*/
|
|
942
|
+
/******************************** Utils gui related functions (delegated to ContrastTool) ***************************************/
|
|
1389
943
|
setupConrastEvents(callback) {
|
|
1390
|
-
this.
|
|
1391
|
-
this.contrastEventPrameters.h = this.container.offsetHeight;
|
|
1392
|
-
this.contrastEventPrameters.handleOnContrastMouseDown = (ev) => {
|
|
1393
|
-
if (ev.button === 0) {
|
|
1394
|
-
this.contrastEventPrameters.x = ev.offsetX / this.contrastEventPrameters.x;
|
|
1395
|
-
this.contrastEventPrameters.y = ev.offsetY / this.contrastEventPrameters.h;
|
|
1396
|
-
this.container.addEventListener("pointermove", this.contrastEventPrameters.handleOnContrastMouseMove);
|
|
1397
|
-
}
|
|
1398
|
-
};
|
|
1399
|
-
this.contrastEventPrameters.handleOnContrastMouseUp = (ev) => {
|
|
1400
|
-
this.container.removeEventListener("pointermove", this.contrastEventPrameters.handleOnContrastMouseMove);
|
|
1401
|
-
};
|
|
1402
|
-
this.contrastEventPrameters.handleOnContrastMouseMove = throttle((ev) => {
|
|
1403
|
-
if (this.contrastEventPrameters.y - ev.offsetY / this.contrastEventPrameters.h >= 0) {
|
|
1404
|
-
this.contrastEventPrameters.move_y = -Math.ceil((this.contrastEventPrameters.y - ev.offsetY / this.contrastEventPrameters.h) * 10);
|
|
1405
|
-
}
|
|
1406
|
-
else {
|
|
1407
|
-
this.contrastEventPrameters.move_y = -Math.floor((this.contrastEventPrameters.y - ev.offsetY / this.contrastEventPrameters.h) * 10);
|
|
1408
|
-
}
|
|
1409
|
-
if (this.contrastEventPrameters.move_y !== 0 && Math.abs(this.contrastEventPrameters.move_y) === 1) {
|
|
1410
|
-
callback(this.contrastEventPrameters.move_y, "vertical");
|
|
1411
|
-
}
|
|
1412
|
-
if (this.contrastEventPrameters.x - ev.offsetX / this.contrastEventPrameters.w >= 0) {
|
|
1413
|
-
this.contrastEventPrameters.move_x = -Math.ceil((this.contrastEventPrameters.x - ev.offsetX / this.contrastEventPrameters.w) * 10);
|
|
1414
|
-
}
|
|
1415
|
-
else {
|
|
1416
|
-
this.contrastEventPrameters.move_x = -Math.floor((this.contrastEventPrameters.x - ev.offsetX / this.contrastEventPrameters.w) * 10);
|
|
1417
|
-
}
|
|
1418
|
-
if (this.contrastEventPrameters.move_x !== 0 && Math.abs(this.contrastEventPrameters.move_x) === 1) {
|
|
1419
|
-
callback(this.contrastEventPrameters.move_x, "horizental");
|
|
1420
|
-
}
|
|
1421
|
-
this.contrastEventPrameters.x = ev.offsetX / this.contrastEventPrameters.w;
|
|
1422
|
-
this.contrastEventPrameters.y = ev.offsetY / this.contrastEventPrameters.h;
|
|
1423
|
-
}, 100);
|
|
1424
|
-
}
|
|
1425
|
-
updateSlicesContrast(value, flag) {
|
|
1426
|
-
switch (flag) {
|
|
1427
|
-
case "lowerThreshold":
|
|
1428
|
-
this.protectedData.displaySlices.forEach((slice, index) => {
|
|
1429
|
-
slice.volume.lowerThreshold = value;
|
|
1430
|
-
});
|
|
1431
|
-
break;
|
|
1432
|
-
case "upperThreshold":
|
|
1433
|
-
this.protectedData.displaySlices.forEach((slice, index) => {
|
|
1434
|
-
slice.volume.upperThreshold = value;
|
|
1435
|
-
});
|
|
1436
|
-
break;
|
|
1437
|
-
case "windowLow":
|
|
1438
|
-
this.protectedData.displaySlices.forEach((slice, index) => {
|
|
1439
|
-
slice.volume.windowLow = value;
|
|
1440
|
-
});
|
|
1441
|
-
break;
|
|
1442
|
-
case "windowHigh":
|
|
1443
|
-
this.protectedData.displaySlices.forEach((slice, index) => {
|
|
1444
|
-
slice.volume.windowHigh = value;
|
|
1445
|
-
});
|
|
1446
|
-
break;
|
|
1447
|
-
}
|
|
1448
|
-
this.repraintCurrentContrastSlice();
|
|
1449
|
-
}
|
|
1450
|
-
repraintCurrentContrastSlice() {
|
|
1451
|
-
this.setSyncsliceNum();
|
|
1452
|
-
this.protectedData.displaySlices.forEach((slice, index) => {
|
|
1453
|
-
slice.repaint.call(slice);
|
|
1454
|
-
});
|
|
944
|
+
this.contrastTool.setupConrastEvents(callback);
|
|
1455
945
|
}
|
|
1456
946
|
}
|
|
1457
947
|
//# sourceMappingURL=DrawToolCore.js.map
|