copper3d 3.4.5 → 3.4.7
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/dist/Utils/segmentation/DrawToolCore.d.ts +19 -2
- package/dist/Utils/segmentation/DrawToolCore.js +58 -13
- package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
- package/dist/Utils/segmentation/NrrdTools.d.ts +0 -1
- package/dist/Utils/segmentation/NrrdTools.js +2 -7
- package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
- package/dist/Utils/segmentation/core/types.d.ts +0 -1
- package/dist/Utils/segmentation/core/types.js.map +1 -1
- package/dist/Utils/segmentation/coreTools/gui.d.ts +0 -1
- package/dist/Utils/segmentation/coreTools/gui.js +21 -29
- package/dist/Utils/segmentation/coreTools/gui.js.map +1 -1
- package/dist/Utils/segmentation/tools/DrawingTool.d.ts +18 -2
- package/dist/Utils/segmentation/tools/DrawingTool.js +60 -21
- package/dist/Utils/segmentation/tools/DrawingTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/ToolHost.d.ts +2 -3
- package/dist/Utils/utils.d.ts +0 -1
- package/dist/Utils/utils.js +0 -80
- package/dist/Utils/utils.js.map +1 -1
- package/dist/bundle.esm.js +141 -149
- package/dist/bundle.umd.js +141 -149
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/types/Utils/segmentation/DrawToolCore.d.ts +19 -2
- package/dist/types/Utils/segmentation/NrrdTools.d.ts +0 -1
- package/dist/types/Utils/segmentation/core/types.d.ts +0 -1
- package/dist/types/Utils/segmentation/coreTools/gui.d.ts +0 -1
- package/dist/types/Utils/segmentation/tools/DrawingTool.d.ts +18 -2
- package/dist/types/Utils/segmentation/tools/ToolHost.d.ts +2 -3
- package/dist/types/Utils/utils.d.ts +0 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/bundle.esm.js
CHANGED
|
@@ -40606,86 +40606,6 @@ function switchPencilIcon(icon, urls) {
|
|
|
40606
40606
|
}
|
|
40607
40607
|
return url;
|
|
40608
40608
|
}
|
|
40609
|
-
function switchEraserSize(size, urls) {
|
|
40610
|
-
let url = "";
|
|
40611
|
-
if (!!urls && urls.length > 0) {
|
|
40612
|
-
if (size <= 3) {
|
|
40613
|
-
url = `url(${urls[0]}) 3 3, crosshair`;
|
|
40614
|
-
}
|
|
40615
|
-
else if (3 < size && size <= 8) {
|
|
40616
|
-
url = `url(${urls[1]}) 8 8, crosshair`;
|
|
40617
|
-
}
|
|
40618
|
-
else if (8 < size && size <= 13) {
|
|
40619
|
-
url = `url(${urls[2]}) 13 13, crosshair`;
|
|
40620
|
-
}
|
|
40621
|
-
else if (13 < size && size <= 18) {
|
|
40622
|
-
url = `url(${urls[3]}) 18 18, crosshair`;
|
|
40623
|
-
}
|
|
40624
|
-
else if (18 < size && size <= 23) {
|
|
40625
|
-
url = `url(${urls[4]}) 23 23, crosshair`;
|
|
40626
|
-
}
|
|
40627
|
-
else if (23 < size && size <= 28) {
|
|
40628
|
-
url = `url(${urls[5]}) 28 28, crosshair`;
|
|
40629
|
-
}
|
|
40630
|
-
else if (28 < size && size <= 33) {
|
|
40631
|
-
url = `url(${urls[6]}) 33 33, crosshair`;
|
|
40632
|
-
}
|
|
40633
|
-
else if (33 < size && size <= 38) {
|
|
40634
|
-
url = `url(${urls[7]}) 38 38, crosshair`;
|
|
40635
|
-
}
|
|
40636
|
-
else if (38 < size && size <= 43) {
|
|
40637
|
-
url = `url(${urls[8]}) 43 43, crosshair`;
|
|
40638
|
-
}
|
|
40639
|
-
else if (43 < size && size <= 48) {
|
|
40640
|
-
url = `url(${urls[9]}) 48 48, crosshair`;
|
|
40641
|
-
}
|
|
40642
|
-
else if (48 < size && size <= 53) {
|
|
40643
|
-
url = `url(${urls[10]}) 52 52, crosshair`;
|
|
40644
|
-
}
|
|
40645
|
-
else {
|
|
40646
|
-
url = `url(${urls[11]}) 52 52, crosshair`;
|
|
40647
|
-
}
|
|
40648
|
-
}
|
|
40649
|
-
else {
|
|
40650
|
-
if (size <= 3) {
|
|
40651
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_3.png) 3 3, crosshair`;
|
|
40652
|
-
}
|
|
40653
|
-
else if (3 < size && size <= 8) {
|
|
40654
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_8.png) 8 8, crosshair`;
|
|
40655
|
-
}
|
|
40656
|
-
else if (8 < size && size <= 13) {
|
|
40657
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_13.png) 13 13, crosshair`;
|
|
40658
|
-
}
|
|
40659
|
-
else if (13 < size && size <= 18) {
|
|
40660
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_18.png) 18 18, crosshair`;
|
|
40661
|
-
}
|
|
40662
|
-
else if (18 < size && size <= 23) {
|
|
40663
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_23.png) 23 23, crosshair`;
|
|
40664
|
-
}
|
|
40665
|
-
else if (23 < size && size <= 28) {
|
|
40666
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_28.png) 28 28, crosshair`;
|
|
40667
|
-
}
|
|
40668
|
-
else if (28 < size && size <= 33) {
|
|
40669
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_33.png) 33 33, crosshair`;
|
|
40670
|
-
}
|
|
40671
|
-
else if (33 < size && size <= 38) {
|
|
40672
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_38.png) 38 38, crosshair`;
|
|
40673
|
-
}
|
|
40674
|
-
else if (38 < size && size <= 43) {
|
|
40675
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_43.png) 43 43, crosshair`;
|
|
40676
|
-
}
|
|
40677
|
-
else if (43 < size && size <= 48) {
|
|
40678
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_48.png) 48 48, crosshair`;
|
|
40679
|
-
}
|
|
40680
|
-
else if (48 < size && size <= 53) {
|
|
40681
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_52.png) 52 52, crosshair`;
|
|
40682
|
-
}
|
|
40683
|
-
else {
|
|
40684
|
-
url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_52.png) 52 52, crosshair`;
|
|
40685
|
-
}
|
|
40686
|
-
}
|
|
40687
|
-
return url;
|
|
40688
|
-
}
|
|
40689
40609
|
function throttle(callback, wait) {
|
|
40690
40610
|
let start = 0;
|
|
40691
40611
|
return function (event) {
|
|
@@ -73002,10 +72922,7 @@ function setupGui(configs) {
|
|
|
73002
72922
|
.name("BrushAndEraserSize")
|
|
73003
72923
|
.min(5)
|
|
73004
72924
|
.max(50)
|
|
73005
|
-
.step(1)
|
|
73006
|
-
.onChange(() => {
|
|
73007
|
-
updateGuiBrushAndEraserSize();
|
|
73008
|
-
});
|
|
72925
|
+
.step(1);
|
|
73009
72926
|
actionsFolder.add(configs.gui_states.mode, "eraser").onChange((value) => {
|
|
73010
72927
|
updateGuiEraserState();
|
|
73011
72928
|
});
|
|
@@ -73133,37 +73050,33 @@ function setupGui(configs) {
|
|
|
73133
73050
|
configs.gui_states.viewConfig.readyToUpdate = true;
|
|
73134
73051
|
});
|
|
73135
73052
|
actionsFolder.open();
|
|
73136
|
-
|
|
73137
|
-
|
|
73138
|
-
|
|
73139
|
-
|
|
73140
|
-
|
|
73141
|
-
|
|
73142
|
-
|
|
73143
|
-
const updatePencilState = () => {
|
|
73144
|
-
if (configs.gui_states.mode.pencil) {
|
|
73145
|
-
// add canvas brush circle move event listeners
|
|
73146
|
-
configs.drawingCanvas.removeEventListener("mouseover", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
|
|
73147
|
-
configs.drawingCanvas.removeEventListener("mouseout", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
|
|
73053
|
+
// Add/remove the hover-tracking listeners that feed the brush/eraser preview
|
|
73054
|
+
// ring (mouseOver position). Present for brush & eraser, removed for pencil.
|
|
73055
|
+
const setBrushHoverTracking = (enabled) => {
|
|
73056
|
+
const handler = configs.drawingPrameters.handleOnDrawingBrushCricleMove;
|
|
73057
|
+
if (enabled) {
|
|
73058
|
+
configs.drawingCanvas.addEventListener("mouseover", handler);
|
|
73059
|
+
configs.drawingCanvas.addEventListener("mouseout", handler);
|
|
73148
73060
|
}
|
|
73149
73061
|
else {
|
|
73150
|
-
|
|
73151
|
-
configs.drawingCanvas.
|
|
73152
|
-
configs.drawingCanvas.addEventListener("mouseout", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
|
|
73062
|
+
configs.drawingCanvas.removeEventListener("mouseover", handler);
|
|
73063
|
+
configs.drawingCanvas.removeEventListener("mouseout", handler);
|
|
73153
73064
|
}
|
|
73065
|
+
};
|
|
73066
|
+
const updatePencilState = () => {
|
|
73067
|
+
// Pencil has no preview ring; brush keeps the hover-tracking listeners.
|
|
73068
|
+
setBrushHoverTracking(!configs.gui_states.mode.pencil);
|
|
73154
73069
|
configs.drawingCanvas.style.cursor = configs.gui_states.viewConfig.defaultPaintCursor;
|
|
73155
73070
|
};
|
|
73156
73071
|
const updateGuiEraserState = () => {
|
|
73157
|
-
//
|
|
73072
|
+
// The eraser shows a dashed preview ring (rendered in DrawToolCore.start),
|
|
73073
|
+
// so it needs the same hover-tracking as the brush. The canvas keeps the
|
|
73074
|
+
// default paint cursor; the ring conveys size (resize via Shift+wheel).
|
|
73158
73075
|
if (configs.gui_states.mode.eraser) {
|
|
73159
|
-
|
|
73160
|
-
? (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize, configs.eraserUrls))
|
|
73161
|
-
: (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize));
|
|
73162
|
-
}
|
|
73163
|
-
else {
|
|
73164
|
-
configs.drawingCanvas.style.cursor =
|
|
73165
|
-
configs.gui_states.viewConfig.defaultPaintCursor;
|
|
73076
|
+
setBrushHoverTracking(true);
|
|
73166
73077
|
}
|
|
73078
|
+
configs.drawingCanvas.style.cursor =
|
|
73079
|
+
configs.gui_states.viewConfig.defaultPaintCursor;
|
|
73167
73080
|
};
|
|
73168
73081
|
const updateGuiSphereState = () => {
|
|
73169
73082
|
var _a, _b, _c, _d;
|
|
@@ -73219,7 +73132,6 @@ function setupGui(configs) {
|
|
|
73219
73132
|
min: 5,
|
|
73220
73133
|
max: 50,
|
|
73221
73134
|
step: 1,
|
|
73222
|
-
onChange: updateGuiBrushAndEraserSize,
|
|
73223
73135
|
},
|
|
73224
73136
|
eraser: {
|
|
73225
73137
|
name: "Eraser",
|
|
@@ -74948,18 +74860,11 @@ class DrawingTool extends BaseTool {
|
|
|
74948
74860
|
this.drawingLines = [];
|
|
74949
74861
|
this.isPainting = true;
|
|
74950
74862
|
this.ctx.protectedData.isDrawing = true;
|
|
74951
|
-
//
|
|
74952
|
-
|
|
74953
|
-
|
|
74954
|
-
|
|
74955
|
-
|
|
74956
|
-
? switchEraserSize(this.ctx.gui_states.drawing.brushAndEraserSize, urls)
|
|
74957
|
-
: switchEraserSize(this.ctx.gui_states.drawing.brushAndEraserSize);
|
|
74958
|
-
}
|
|
74959
|
-
else {
|
|
74960
|
-
this.ctx.protectedData.canvases.drawingCanvas.style.cursor =
|
|
74961
|
-
this.ctx.gui_states.viewConfig.defaultPaintCursor;
|
|
74962
|
-
}
|
|
74863
|
+
// Brush and eraser both show their size via the dashed/solid preview ring
|
|
74864
|
+
// rendered in DrawToolCore.start(); the canvas keeps the default paint
|
|
74865
|
+
// cursor underneath. (The eraser previously swapped in a sized PNG cursor.)
|
|
74866
|
+
this.ctx.protectedData.canvases.drawingCanvas.style.cursor =
|
|
74867
|
+
this.ctx.gui_states.viewConfig.defaultPaintCursor;
|
|
74963
74868
|
// Record draw start position
|
|
74964
74869
|
this.ctx.nrrd_states.interaction.drawStartPos.x = e.offsetX;
|
|
74965
74870
|
this.ctx.nrrd_states.interaction.drawStartPos.y = e.offsetY;
|
|
@@ -75035,9 +74940,15 @@ class DrawingTool extends BaseTool {
|
|
|
75035
74940
|
this.refreshLayerFromVolume();
|
|
75036
74941
|
}
|
|
75037
74942
|
else {
|
|
75038
|
-
// Brush mode: voxels already written
|
|
75039
|
-
//
|
|
74943
|
+
// Brush mode: voxels already written directly into the MaskVolume
|
|
74944
|
+
// during mousemove, so no canvas→voxel bake (syncLayerSliceData) is
|
|
74945
|
+
// needed. But we MUST still notify the backend — unlike pencil/eraser
|
|
74946
|
+
// (which go through syncLayerSliceData) the brush path never fires
|
|
74947
|
+
// onMaskChanged, so brush strokes were silently never persisted via
|
|
74948
|
+
// useReplaceMask. Re-render the final state, then fire onMaskChanged
|
|
74949
|
+
// for the current slice (same pattern as SphereBrushTool.refreshDisplay).
|
|
75040
74950
|
this.refreshLayerFromVolume();
|
|
74951
|
+
this.notifyMaskChanged();
|
|
75041
74952
|
}
|
|
75042
74953
|
}
|
|
75043
74954
|
else {
|
|
@@ -75091,20 +75002,37 @@ class DrawingTool extends BaseTool {
|
|
|
75091
75002
|
return handler;
|
|
75092
75003
|
}
|
|
75093
75004
|
/**
|
|
75094
|
-
* Render brush
|
|
75005
|
+
* Render the size-preview ring for the brush / eraser on the drawing context.
|
|
75006
|
+
*
|
|
75007
|
+
* - Brush: solid outline in the current brush colour.
|
|
75008
|
+
* - Eraser: red dashed outline (matches the sphereEraser preview), so the
|
|
75009
|
+
* eraser no longer needs a sized PNG cursor — the ring tracks the live
|
|
75010
|
+
* `brushAndEraserSize` and is what the user resizes with Shift+wheel.
|
|
75011
|
+
*
|
|
75012
|
+
* Only the pencil has no preview ring (its stroke width is fixed).
|
|
75095
75013
|
*/
|
|
75096
|
-
renderBrushPreview(ctx,
|
|
75014
|
+
renderBrushPreview(ctx, _width, _height) {
|
|
75097
75015
|
if (this.ctx.gui_states.mode.pencil ||
|
|
75098
|
-
this.ctx.gui_states.mode.eraser ||
|
|
75099
75016
|
!this.ctx.nrrd_states.interaction.mouseOver) {
|
|
75100
75017
|
return;
|
|
75101
75018
|
}
|
|
75102
|
-
|
|
75103
|
-
|
|
75019
|
+
const isEraser = this.ctx.gui_states.mode.eraser;
|
|
75020
|
+
// No clearRect here: DrawToolCore.start() clears drawingCtx once per frame
|
|
75021
|
+
// before compositing, and this ring is now drawn on top of the mask so it
|
|
75022
|
+
// stays visible during an active stroke (e.g. while Shift+wheel resizing).
|
|
75023
|
+
ctx.save();
|
|
75104
75024
|
ctx.beginPath();
|
|
75105
75025
|
ctx.arc(this.ctx.nrrd_states.interaction.mouseOverX, this.ctx.nrrd_states.interaction.mouseOverY, this.ctx.gui_states.drawing.brushAndEraserSize / 2 + 1, 0, Math.PI * 2);
|
|
75106
|
-
|
|
75026
|
+
if (isEraser) {
|
|
75027
|
+
ctx.strokeStyle = "#ff4444";
|
|
75028
|
+
ctx.lineWidth = 2;
|
|
75029
|
+
ctx.setLineDash([4, 4]);
|
|
75030
|
+
}
|
|
75031
|
+
else {
|
|
75032
|
+
ctx.strokeStyle = this.ctx.gui_states.drawing.brushColor;
|
|
75033
|
+
}
|
|
75107
75034
|
ctx.stroke();
|
|
75035
|
+
ctx.restore();
|
|
75108
75036
|
}
|
|
75109
75037
|
// ── Brush mode: direct voxel write ────────────────────────────
|
|
75110
75038
|
/**
|
|
@@ -75295,6 +75223,30 @@ class DrawingTool extends BaseTool {
|
|
|
75295
75223
|
this.callbacks.compositeAllLayers();
|
|
75296
75224
|
this.ctx.protectedData.mainPreSlices.mesh.material.map.needsUpdate = true;
|
|
75297
75225
|
}
|
|
75226
|
+
/**
|
|
75227
|
+
* Notify the backend of the brush stroke by firing onMaskChanged for the
|
|
75228
|
+
* current slice. Brush writes voxels straight into the MaskVolume (no canvas
|
|
75229
|
+
* bake), so we read the authoritative slice back from the volume — mirrors
|
|
75230
|
+
* SphereBrushTool.refreshDisplay's notify path. Brush only ever touches the
|
|
75231
|
+
* current view slice (canvasToVoxel3D fixes the slice axis), so a single
|
|
75232
|
+
* slice notification is sufficient.
|
|
75233
|
+
*/
|
|
75234
|
+
notifyMaskChanged() {
|
|
75235
|
+
if (this.ctx.nrrd_states.flags.loadingMaskData)
|
|
75236
|
+
return;
|
|
75237
|
+
try {
|
|
75238
|
+
const layer = this.ctx.gui_states.layerChannel.layer;
|
|
75239
|
+
const vol = this.callbacks.getVolumeForLayer(layer);
|
|
75240
|
+
const channel = this.ctx.gui_states.layerChannel.activeChannel || 1;
|
|
75241
|
+
const axis = this.ctx.protectedData.axis;
|
|
75242
|
+
const sliceIndex = this.ctx.nrrd_states.view.currentSliceIndex;
|
|
75243
|
+
const { data: sliceData, width, height } = vol.getSliceUint8(sliceIndex, axis);
|
|
75244
|
+
this.ctx.callbacks.onMaskChanged(sliceData, layer, channel, sliceIndex, axis, width, height, false);
|
|
75245
|
+
}
|
|
75246
|
+
catch (_a) {
|
|
75247
|
+
// Volume not ready — skip notification
|
|
75248
|
+
}
|
|
75249
|
+
}
|
|
75298
75250
|
// ── Private helpers ────────────────────────────────────────
|
|
75299
75251
|
/** Capture pre-draw slice snapshot for undo */
|
|
75300
75252
|
capturePreDrawSnapshot() {
|
|
@@ -76221,7 +76173,6 @@ class DrawToolCore {
|
|
|
76221
76173
|
handleOnContrastMouseUp: (ev) => { },
|
|
76222
76174
|
handleOnContrastMouseLeave: (ev) => { },
|
|
76223
76175
|
};
|
|
76224
|
-
this.eraserUrls = [];
|
|
76225
76176
|
this.pencilUrls = [];
|
|
76226
76177
|
this.undoManager = new UndoManager();
|
|
76227
76178
|
/** Slice index recorded when paintOnCanvas() starts, guards stale-click */
|
|
@@ -76296,7 +76247,6 @@ class DrawToolCore {
|
|
|
76296
76247
|
filterDrawedImage: (axis, index) => this.renderer.filterDrawedImage(axis, index),
|
|
76297
76248
|
getVolumeForLayer: (layer) => this.renderer.getVolumeForLayer(layer),
|
|
76298
76249
|
pushUndoDelta: (delta) => this.undoManager.push(delta),
|
|
76299
|
-
getEraserUrls: () => this.eraserUrls,
|
|
76300
76250
|
renderSliceToCanvas: (layer, axis, sliceIndex, buffer, ctx, w, h) => this.renderer.renderSliceToCanvas(layer, axis, sliceIndex, buffer, ctx, w, h),
|
|
76301
76251
|
getOrCreateSliceBuffer: (axis) => this.renderer.getOrCreateSliceBuffer(axis),
|
|
76302
76252
|
});
|
|
@@ -76308,7 +76258,6 @@ class DrawToolCore {
|
|
|
76308
76258
|
getOrCreateSliceBuffer: (axis) => this.renderer.getOrCreateSliceBuffer(axis),
|
|
76309
76259
|
setEmptyCanvasSize: (axis) => this.setEmptyCanvasSize(axis),
|
|
76310
76260
|
reloadMasksFromVolume: () => this.reloadMasksFromVolume(),
|
|
76311
|
-
getEraserUrls: () => this.eraserUrls,
|
|
76312
76261
|
});
|
|
76313
76262
|
}
|
|
76314
76263
|
initDrawToolCore() {
|
|
@@ -76463,6 +76412,12 @@ class DrawToolCore {
|
|
|
76463
76412
|
});
|
|
76464
76413
|
// Register wheel handler with EventRouter
|
|
76465
76414
|
this.eventRouter.setWheelHandler((e) => {
|
|
76415
|
+
// Shift + wheel resizes the brush/eraser (like sphereBrush/sphereEraser
|
|
76416
|
+
// radius), independent of whether the left button is held. Consumes the
|
|
76417
|
+
// event so it never falls through to zoom/slice. Pencil is excluded even
|
|
76418
|
+
// though it also uses Shift — see tryBrushEraserResizeWheel.
|
|
76419
|
+
if (this.tryBrushEraserResizeWheel(e))
|
|
76420
|
+
return;
|
|
76466
76421
|
if (this.activeWheelMode === 'zoom') {
|
|
76467
76422
|
this.drawingPrameters.handleMouseZoomSliceWheel(e);
|
|
76468
76423
|
}
|
|
@@ -76476,8 +76431,47 @@ class DrawToolCore {
|
|
|
76476
76431
|
// Bind all event listeners
|
|
76477
76432
|
this.eventRouter.bindAll();
|
|
76478
76433
|
}
|
|
76479
|
-
|
|
76480
|
-
|
|
76434
|
+
/**
|
|
76435
|
+
* Shift + mouse-wheel resize for the brush and eraser tools.
|
|
76436
|
+
*
|
|
76437
|
+
* Mirrors the sphereBrush/sphereEraser "scroll to change radius" UX so the
|
|
76438
|
+
* user no longer has to reach for the B&E Size slider mid-annotation. Active
|
|
76439
|
+
* whenever the EventRouter is in `draw` mode (i.e. Shift is held — with or
|
|
76440
|
+
* without the left button down) and the current tool is brush or eraser.
|
|
76441
|
+
*
|
|
76442
|
+
* Pencil is deliberately excluded: it also draws with Shift, but its stroke
|
|
76443
|
+
* width is fixed and unrelated to `brushAndEraserSize`. Sphere-family tools
|
|
76444
|
+
* keep their own wheel-radius handler (`activeWheelMode === 'sphereBrush'`).
|
|
76445
|
+
*
|
|
76446
|
+
* `gui_states.mode` is the source of truth for the active tool here, not
|
|
76447
|
+
* `eventRouter.getGuiTool()` — the latter is only updated for sphere tools.
|
|
76448
|
+
*
|
|
76449
|
+
* @returns true if the event was handled (and should not fall through to
|
|
76450
|
+
* the zoom/slice/sphere wheel handlers).
|
|
76451
|
+
*/
|
|
76452
|
+
tryBrushEraserResizeWheel(e) {
|
|
76453
|
+
// `draw` mode means Shift is held and neither crosshair nor contrast is
|
|
76454
|
+
// active (EventRouter only enters it for drawing tools under those rules),
|
|
76455
|
+
// so it doubles as the "Shift held, not blocked" gate.
|
|
76456
|
+
if (this.eventRouter.getMode() !== 'draw')
|
|
76457
|
+
return false;
|
|
76458
|
+
const mode = this.state.gui_states.mode;
|
|
76459
|
+
// Brush = no flag set; eraser = mode.eraser. Exclude pencil and all
|
|
76460
|
+
// sphere-family tools.
|
|
76461
|
+
if (mode.pencil || mode.sphere || mode.sphereBrush || mode.sphereEraser) {
|
|
76462
|
+
return false;
|
|
76463
|
+
}
|
|
76464
|
+
e.preventDefault();
|
|
76465
|
+
const drawing = this.state.gui_states.drawing;
|
|
76466
|
+
// Step/bounds match the B&E Size slider config (min 5, max 50, step 1).
|
|
76467
|
+
const next = Math.max(5, Math.min(50, drawing.brushAndEraserSize + (e.deltaY < 0 ? 1 : -1)));
|
|
76468
|
+
if (next === drawing.brushAndEraserSize)
|
|
76469
|
+
return true;
|
|
76470
|
+
drawing.brushAndEraserSize = next;
|
|
76471
|
+
// Both brush and eraser draw a size-preview ring in start() that reads
|
|
76472
|
+
// brushAndEraserSize live, so the new size shows up on the next frame with
|
|
76473
|
+
// no extra work here.
|
|
76474
|
+
return true;
|
|
76481
76475
|
}
|
|
76482
76476
|
setPencilIconUrls(urls) {
|
|
76483
76477
|
this.pencilUrls = urls;
|
|
@@ -76646,6 +76640,7 @@ class DrawToolCore {
|
|
|
76646
76640
|
this.state.protectedData.ctxes.drawingCtx.clearRect(0, 0, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
|
|
76647
76641
|
this.state.protectedData.ctxes.drawingCtx.globalAlpha =
|
|
76648
76642
|
this.state.gui_states.drawing.globalAlpha;
|
|
76643
|
+
const currentMode = this.eventRouter.getMode();
|
|
76649
76644
|
if (this.state.protectedData.isDrawing) {
|
|
76650
76645
|
this.state.protectedData.ctxes.drawingLayerMasterCtx.lineCap = "round";
|
|
76651
76646
|
this.state.protectedData.ctxes.drawingLayerMasterCtx.globalAlpha = 1;
|
|
@@ -76654,16 +76649,18 @@ class DrawToolCore {
|
|
|
76654
76649
|
target.ctx.globalAlpha = 1;
|
|
76655
76650
|
}
|
|
76656
76651
|
}
|
|
76657
|
-
else {
|
|
76658
|
-
|
|
76659
|
-
if (currentMode === 'draw') {
|
|
76660
|
-
this.drawingTool.renderBrushPreview(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
|
|
76661
|
-
}
|
|
76662
|
-
else if (currentMode === 'crosshair' || this.eventRouter.isCrosshairEnabled()) {
|
|
76663
|
-
this.crosshairTool.renderCrosshair(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
|
|
76664
|
-
}
|
|
76652
|
+
else if (currentMode === 'crosshair' || this.eventRouter.isCrosshairEnabled()) {
|
|
76653
|
+
this.crosshairTool.renderCrosshair(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
|
|
76665
76654
|
}
|
|
76666
76655
|
this.state.protectedData.ctxes.drawingCtx.drawImage(this.state.protectedData.canvases.drawingCanvasLayerMaster, 0, 0);
|
|
76656
|
+
// Brush/eraser size ring is drawn AFTER the mask composite so it stays
|
|
76657
|
+
// visible during an active stroke (not just on hover) — e.g. while the
|
|
76658
|
+
// user resizes with Shift+wheel mid-paint. Gated on draw mode so it only
|
|
76659
|
+
// shows for brush/eraser with Shift held (renderBrushPreview itself
|
|
76660
|
+
// skips pencil and the no-hover case).
|
|
76661
|
+
if (currentMode === 'draw') {
|
|
76662
|
+
this.drawingTool.renderBrushPreview(this.state.protectedData.ctxes.drawingCtx);
|
|
76663
|
+
}
|
|
76667
76664
|
if (this.state.gui_states.mode.sphere
|
|
76668
76665
|
|| this.state.gui_states.mode.sphereBrush
|
|
76669
76666
|
|| this.state.gui_states.mode.sphereEraser) {
|
|
@@ -78375,7 +78372,6 @@ class NrrdTools {
|
|
|
78375
78372
|
nrrd_states: this.state.nrrd_states,
|
|
78376
78373
|
drawingCanvas: this.state.protectedData.canvases.drawingCanvas,
|
|
78377
78374
|
drawingPrameters: this.drawCore.drawingPrameters,
|
|
78378
|
-
eraserUrls: this.drawCore.eraserUrls,
|
|
78379
78375
|
pencilUrls: this.drawCore.pencilUrls,
|
|
78380
78376
|
mainPreSlices: this.state.protectedData.mainPreSlices,
|
|
78381
78377
|
protectedData: this.state.protectedData,
|
|
@@ -78408,7 +78404,6 @@ class NrrdTools {
|
|
|
78408
78404
|
this.guiCallbacks = {
|
|
78409
78405
|
updatePencilState: this.guiParameterSettings.pencil.onChange,
|
|
78410
78406
|
updateEraserState: this.guiParameterSettings.eraser.onChange,
|
|
78411
|
-
updateBrushAndEraserSize: this.guiParameterSettings.brushAndEraserSize.onChange,
|
|
78412
78407
|
updateSphereState: this.guiParameterSettings.sphere.onChange,
|
|
78413
78408
|
updateCalDistance: this.guiParameterSettings.activeSphereType.onChange,
|
|
78414
78409
|
updateWindowHigh: this.guiParameterSettings.windowHigh.onChange,
|
|
@@ -78521,9 +78516,9 @@ class NrrdTools {
|
|
|
78521
78516
|
return this.state.gui_states.drawing.globalAlpha;
|
|
78522
78517
|
}
|
|
78523
78518
|
setBrushSize(size) {
|
|
78524
|
-
|
|
78519
|
+
// No cursor side-effect needed: the brush/eraser preview ring reads this
|
|
78520
|
+
// value live each frame (see DrawingTool.renderBrushPreview).
|
|
78525
78521
|
this.state.gui_states.drawing.brushAndEraserSize = Math.max(5, Math.min(50, size));
|
|
78526
|
-
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateBrushAndEraserSize();
|
|
78527
78522
|
}
|
|
78528
78523
|
getBrushSize() {
|
|
78529
78524
|
return this.state.gui_states.drawing.brushAndEraserSize;
|
|
@@ -78758,9 +78753,6 @@ class NrrdTools {
|
|
|
78758
78753
|
enableContrastDragEvents(callback) {
|
|
78759
78754
|
this.drawCore.setupConrastEvents(callback);
|
|
78760
78755
|
}
|
|
78761
|
-
setEraserUrls(urls) {
|
|
78762
|
-
this.drawCore.setEraserUrls(urls);
|
|
78763
|
-
}
|
|
78764
78756
|
setPencilIconUrls(urls) {
|
|
78765
78757
|
this.drawCore.setPencilIconUrls(urls);
|
|
78766
78758
|
}
|
|
@@ -79450,7 +79442,7 @@ function evaluateElement(element, weights) {
|
|
|
79450
79442
|
}
|
|
79451
79443
|
|
|
79452
79444
|
// import * as kiwrious from "copper3d_plugin_heart_k";
|
|
79453
|
-
const REVISION = "v3.4.
|
|
79445
|
+
const REVISION = "v3.4.7-beta";
|
|
79454
79446
|
console.log(`%cCopper3D Visualisation %cBeta:${REVISION}`, "padding: 3px;color:white; background:#023047", "padding: 3px;color:white; background:#f50a25");
|
|
79455
79447
|
|
|
79456
79448
|
export { CHANNEL_COLORS, CHANNEL_HEX_COLORS, CameraViewPoint, Copper3dTrackballControls, GaussianSmoother, MeshNodeTool, NrrdTools, REVISION, addBoxHelper, addLabelToScene, configKiwriousHeart, convert3DPostoScreenPos, convertScreenPosto3DPos, copperMScene, copperMSceneRenderer, copperRenderer, copperRendererOnDemond, copperScene, copperSceneOnDemond, createTexture2D_NRRD, fullScreenListenner, kiwrious, loading, removeGuiFolderChilden, rgbaToCss, rgbaToHex, setHDRFilePath, throttle };
|