copper3d 3.1.2 → 3.2.1

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.
Files changed (62) hide show
  1. package/dist/Utils/segmentation/DragOperator.d.ts +2 -1
  2. package/dist/Utils/segmentation/DragOperator.js +6 -2
  3. package/dist/Utils/segmentation/DragOperator.js.map +1 -1
  4. package/dist/Utils/segmentation/DrawToolCore.d.ts +6 -0
  5. package/dist/Utils/segmentation/DrawToolCore.js +107 -35
  6. package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
  7. package/dist/Utils/segmentation/NrrdTools.d.ts +5 -1
  8. package/dist/Utils/segmentation/NrrdTools.js +87 -3
  9. package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
  10. package/dist/Utils/segmentation/core/GaussianSmoother.d.ts +55 -0
  11. package/dist/Utils/segmentation/core/GaussianSmoother.js +210 -0
  12. package/dist/Utils/segmentation/core/GaussianSmoother.js.map +1 -0
  13. package/dist/Utils/segmentation/core/MaskVolume.d.ts +9 -0
  14. package/dist/Utils/segmentation/core/MaskVolume.js +11 -0
  15. package/dist/Utils/segmentation/core/MaskVolume.js.map +1 -1
  16. package/dist/Utils/segmentation/core/UndoManager.d.ts +9 -5
  17. package/dist/Utils/segmentation/core/UndoManager.js +21 -14
  18. package/dist/Utils/segmentation/core/UndoManager.js.map +1 -1
  19. package/dist/Utils/segmentation/core/index.d.ts +1 -1
  20. package/dist/Utils/segmentation/core/types.d.ts +5 -1
  21. package/dist/Utils/segmentation/core/types.js.map +1 -1
  22. package/dist/Utils/segmentation/coreTools/GuiState.js +2 -0
  23. package/dist/Utils/segmentation/coreTools/GuiState.js.map +1 -1
  24. package/dist/Utils/segmentation/coreTools/NrrdState.js +2 -0
  25. package/dist/Utils/segmentation/coreTools/NrrdState.js.map +1 -1
  26. package/dist/Utils/segmentation/eventRouter/EventRouter.js +1 -0
  27. package/dist/Utils/segmentation/eventRouter/EventRouter.js.map +1 -1
  28. package/dist/Utils/segmentation/eventRouter/types.d.ts +1 -1
  29. package/dist/Utils/segmentation/tools/DragSliceTool.d.ts +0 -4
  30. package/dist/Utils/segmentation/tools/DragSliceTool.js +2 -19
  31. package/dist/Utils/segmentation/tools/DragSliceTool.js.map +1 -1
  32. package/dist/Utils/segmentation/tools/SliceRenderPipeline.js +8 -1
  33. package/dist/Utils/segmentation/tools/SliceRenderPipeline.js.map +1 -1
  34. package/dist/Utils/segmentation/tools/SphereBrushTool.d.ts +127 -0
  35. package/dist/Utils/segmentation/tools/SphereBrushTool.js +489 -0
  36. package/dist/Utils/segmentation/tools/SphereBrushTool.js.map +1 -0
  37. package/dist/Utils/segmentation/tools/ToolHost.d.ts +4 -1
  38. package/dist/Utils/segmentation/tools/ZoomTool.js +6 -1
  39. package/dist/Utils/segmentation/tools/ZoomTool.js.map +1 -1
  40. package/dist/Utils/segmentation/tools/index.d.ts +2 -1
  41. package/dist/Utils/segmentation/tools/index.js +1 -0
  42. package/dist/Utils/segmentation/tools/index.js.map +1 -1
  43. package/dist/bundle.esm.js +950 -77
  44. package/dist/bundle.umd.js +950 -76
  45. package/dist/index.d.ts +3 -2
  46. package/dist/index.js +3 -3
  47. package/dist/index.js.map +1 -1
  48. package/dist/types/Utils/segmentation/DragOperator.d.ts +2 -1
  49. package/dist/types/Utils/segmentation/DrawToolCore.d.ts +6 -0
  50. package/dist/types/Utils/segmentation/NrrdTools.d.ts +5 -1
  51. package/dist/types/Utils/segmentation/core/GaussianSmoother.d.ts +55 -0
  52. package/dist/types/Utils/segmentation/core/MaskVolume.d.ts +9 -0
  53. package/dist/types/Utils/segmentation/core/UndoManager.d.ts +9 -5
  54. package/dist/types/Utils/segmentation/core/index.d.ts +1 -1
  55. package/dist/types/Utils/segmentation/core/types.d.ts +5 -1
  56. package/dist/types/Utils/segmentation/eventRouter/types.d.ts +1 -1
  57. package/dist/types/Utils/segmentation/tools/DragSliceTool.d.ts +0 -4
  58. package/dist/types/Utils/segmentation/tools/SphereBrushTool.d.ts +127 -0
  59. package/dist/types/Utils/segmentation/tools/ToolHost.d.ts +4 -1
  60. package/dist/types/Utils/segmentation/tools/index.d.ts +2 -1
  61. package/dist/types/index.d.ts +3 -2
  62. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ import { createTexture2D_NRRD } from "./Utils/texture2d";
13
13
  import { configKiwriousHeart } from "./Utils/kiwrious/configKiwrious";
14
14
  import kiwrious from "./Utils/kiwrious/configKiwrious";
15
15
  import { NrrdTools } from "./Utils/segmentation/NrrdTools";
16
+ import { GaussianSmoother } from "./Utils/segmentation/core/GaussianSmoother";
16
17
  import { Copper3dTrackballControls } from "./Controls/Copper3dTrackballControls";
17
18
  import { MeshNodeTool } from "./Utils/MeshNodeTool";
18
19
  import { removeGuiFolderChilden } from "./Utils/segmentation/coreTools/gui";
@@ -24,6 +25,6 @@ import type { ToolMode, IAnnotationCallbacks } from "./Utils/segmentation/core/t
24
25
  import { CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss } from "./Utils/segmentation/core/index";
25
26
  import type { LayerId, ChannelValue } from "./Utils/segmentation/core/index";
26
27
  import "./css/style.css";
27
- export declare const REVISION = "v3.1.2-beta";
28
- export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, };
28
+ export declare const REVISION = "v3.2.1-beta";
29
+ export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, GaussianSmoother, };
29
30
  export type { positionType, screenPosType, optsType, nrrdMeshesType, nrrdSliceType, SensorDecodedValue_kiwrious, SensorReadResult_kiwrious, HeartRateResult_kiwrious, loadingBarType, IPaintImage, exportPaintImageType, IOptVTKLoader, ICommXYZ, IGUIStates, IGuiParameterSettings, INrrdStates, NrrdState, GuiState, IGuiMeta, ToolMode, IAnnotationCallbacks, LayerId, ChannelValue, };
package/dist/index.js CHANGED
@@ -14,13 +14,13 @@ import { createTexture2D_NRRD } from "./Utils/texture2d";
14
14
  import { configKiwriousHeart } from "./Utils/kiwrious/configKiwrious";
15
15
  import kiwrious from "./Utils/kiwrious/configKiwrious";
16
16
  import { NrrdTools } from "./Utils/segmentation/NrrdTools";
17
- // Phase 7: Segmentation Module - Unified exports
17
+ import { GaussianSmoother } from "./Utils/segmentation/core/GaussianSmoother";
18
18
  import { Copper3dTrackballControls } from "./Controls/Copper3dTrackballControls";
19
19
  import { MeshNodeTool } from "./Utils/MeshNodeTool";
20
20
  import { removeGuiFolderChilden } from "./Utils/segmentation/coreTools/gui";
21
21
  import { CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss } from "./Utils/segmentation/core/index";
22
22
  import "./css/style.css";
23
- export const REVISION = "v3.1.2-beta";
23
+ export const REVISION = "v3.2.1-beta";
24
24
  console.log(`%cCopper3D Visualisation %cBeta:${REVISION}`, "padding: 3px;color:white; background:#023047", "padding: 3px;color:white; background:#f50a25");
25
- export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, };
25
+ export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, GaussianSmoother, };
26
26
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EACL,eAAe,EAGf,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAY,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,QAAQ,MAAM,iCAAiC,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,iDAAiD;AAEjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAiB5E,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAG3G,OAAO,iBAAiB,CAAC;AAEzB,MAAM,CAAC,MAAM,QAAQ,GAAG,aAAa,CAAC;AAEtC,OAAO,CAAC,GAAG,CACT,mCAAmC,QAAQ,EAAE,EAC7C,8CAA8C,EAC9C,8CAA8C,CAC/C,CAAC;AAEF,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,SAAS,EACT,OAAO,EACP,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EACZ,QAAQ,EACR,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,SAAS,GACV,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EACL,eAAe,EAGf,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAY,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,QAAQ,MAAM,iCAAiC,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAE9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAiB5E,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAG3G,OAAO,iBAAiB,CAAC;AAEzB,MAAM,CAAC,MAAM,QAAQ,GAAG,aAAa,CAAC;AAEtC,OAAO,CAAC,GAAG,CACT,mCAAmC,QAAQ,EAAE,EAC7C,8CAA8C,EAC9C,8CAA8C,CAC/C,CAAC;AAEF,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,SAAS,EACT,OAAO,EACP,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EACZ,QAAQ,EACR,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,SAAS,EACT,gBAAgB,GACjB,CAAC"}
@@ -18,9 +18,10 @@ export declare class DragOperator {
18
18
  private setEmptyCanvasSize;
19
19
  private getOrCreateSliceBuffer;
20
20
  private renderSliceToCanvas;
21
+ private compositeAllLayers;
21
22
  private refreshSphereOverlayCb;
22
23
  private eventRouter;
23
- constructor(container: HTMLElement, nrrd_sates: NrrdState, gui_states: GuiState, protectedData: IProtected, drawingPrameters: IDrawingEvents, setSyncsliceNum: () => void, setIsDrawFalse: (target: number) => void, flipDisplayImageByAxis: () => void, setEmptyCanvasSize: (axis?: "x" | "y" | "z") => void, getOrCreateSliceBuffer: (axis: "x" | "y" | "z") => ImageData | null, renderSliceToCanvas: (layer: string, axis: "x" | "y" | "z", sliceIndex: number, buffer: ImageData, targetCtx: CanvasRenderingContext2D, scaledWidth: number, scaledHeight: number) => void);
24
+ constructor(container: HTMLElement, nrrd_sates: NrrdState, gui_states: GuiState, protectedData: IProtected, drawingPrameters: IDrawingEvents, setSyncsliceNum: () => void, setIsDrawFalse: (target: number) => void, flipDisplayImageByAxis: () => void, setEmptyCanvasSize: (axis?: "x" | "y" | "z") => void, getOrCreateSliceBuffer: (axis: "x" | "y" | "z") => ImageData | null, renderSliceToCanvas: (layer: string, axis: "x" | "y" | "z", sliceIndex: number, buffer: ImageData, targetCtx: CanvasRenderingContext2D, scaledWidth: number, scaledHeight: number) => void, compositeAllLayers: () => void);
24
25
  private init;
25
26
  setShowDragNumberDiv(sliceIndexContainer: HTMLDivElement): void;
26
27
  /**
@@ -10,6 +10,7 @@ import { EraserTool } from "./tools/EraserTool";
10
10
  import { PanTool } from "./tools/PanTool";
11
11
  import { DrawingTool } from "./tools/DrawingTool";
12
12
  import { ImageStoreHelper } from "./tools/ImageStoreHelper";
13
+ import { SphereBrushTool } from "./tools/SphereBrushTool";
13
14
  import { UndoManager } from "./core";
14
15
  /**
15
16
  * DrawToolCore — Tool orchestration and event routing.
@@ -41,6 +42,7 @@ export declare class DrawToolCore {
41
42
  protected panTool: PanTool;
42
43
  protected drawingTool: DrawingTool;
43
44
  protected imageStoreHelper: ImageStoreHelper;
45
+ protected sphereBrushTool: SphereBrushTool;
44
46
  /** Slice index recorded when paintOnCanvas() starts, guards stale-click */
45
47
  private paintSliceIndex;
46
48
  /** Wheel event dispatch mode — replaces manual wheel add/remove (Phase 2) */
@@ -131,4 +133,8 @@ export declare class DrawToolCore {
131
133
  enterSphereMode(): void;
132
134
  /** Override in NrrdTools */
133
135
  exitSphereMode(): void;
136
+ /** Override in NrrdTools */
137
+ reloadMasksFromVolume(): void;
138
+ /** Override in NrrdTools */
139
+ updateMouseWheelEvent(): void;
134
140
  }
@@ -79,6 +79,8 @@ export declare class NrrdTools {
79
79
  getOpacity(): number;
80
80
  setBrushSize(size: number): void;
81
81
  getBrushSize(): number;
82
+ setSphereBrushRadius(radius: number): void;
83
+ getSphereBrushRadius(): number;
82
84
  setWindowHigh(value: number): void;
83
85
  setWindowLow(value: number): void;
84
86
  finishWindowAdjustment(): void;
@@ -86,7 +88,9 @@ export declare class NrrdTools {
86
88
  getSliderMeta(key: string): IGuiMeta | null;
87
89
  setPencilColor(hex: string): void;
88
90
  getPencilColor(): string;
89
- executeAction(action: "undo" | "redo" | "clearActiveSliceMask" | "clearActiveLayerMask" | "resetZoom" | "downloadCurrentMask"): void;
91
+ executeAction(action: "undo" | "redo" | "clearActiveSliceMask" | "clearActiveLayerMask" | "resetZoom" | "downloadCurrentMask" | "gaussianSmooth", opts?: {
92
+ sigma?: number;
93
+ }): void;
90
94
  undo(): void;
91
95
  redo(): void;
92
96
  enterKeyboardConfig(): void;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * GaussianSmoother — 3D Gaussian smoothing for segmentation masks.
3
+ *
4
+ * Applies a separable 3D Gaussian blur to a single label channel within a
5
+ * MaskVolume, then thresholds the result back to a binary mask. This smooths
6
+ * jagged edges and fills small holes in segmentation annotations.
7
+ *
8
+ * Pure, stateless utility — no DOM/Canvas/GUI dependencies.
9
+ *
10
+ * Performance: uses direct typed-array access (bypassing getVoxel/setVoxel
11
+ * boundary checks) and branch-free convolution for the interior region.
12
+ */
13
+ import type { MaskVolume } from './MaskVolume';
14
+ export declare class GaussianSmoother {
15
+ /**
16
+ * Smooth a single label channel in-place using separable 3D Gaussian blur.
17
+ *
18
+ * Steps:
19
+ * 1. Extract — create a Float32Array with 1.0 where voxel === channel, 0.0 elsewhere.
20
+ * 2. Blur — apply separable Gaussian (X → Y → Z) on the float buffer.
21
+ * 3. Threshold — binarize at 0.5.
22
+ * 4. Write back — overwrite/erase voxels according to the thresholded result.
23
+ *
24
+ * @param volume The MaskVolume to operate on (modified in-place).
25
+ * @param channel The label value to smooth (must be > 0).
26
+ * @param sigma Base Gaussian sigma in voxel units (default 1.0).
27
+ * @param spacing Optional voxel spacing [sx, sy, sz]. When provided, per-axis
28
+ * sigma is computed as `sigma / spacing[axis]` so that the
29
+ * physical smoothing radius is isotropic.
30
+ */
31
+ static gaussianSmooth3D(volume: MaskVolume, channel: number, sigma?: number, spacing?: [number, number, number]): void;
32
+ /**
33
+ * Generate a normalized 1D Gaussian kernel truncated at ±3σ.
34
+ *
35
+ * @param sigma Standard deviation (in voxels). Must be > 0.
36
+ * @returns Normalized Float32Array of odd length.
37
+ */
38
+ static generateKernel1D(sigma: number): Float32Array;
39
+ /**
40
+ * In-place single-axis convolution with zero-padding at boundaries.
41
+ *
42
+ * Uses a 3-segment approach: left boundary (with bounds check),
43
+ * middle interior (branch-free, ~95% of work), right boundary
44
+ * (with bounds check). This eliminates per-element branching
45
+ * in the hot inner loop.
46
+ *
47
+ * @param data Flat float buffer (width × height × depth).
48
+ * @param width X dimension.
49
+ * @param height Y dimension.
50
+ * @param depth Z dimension.
51
+ * @param axis 0 = X, 1 = Y, 2 = Z.
52
+ * @param kernel 1D convolution kernel (odd length).
53
+ */
54
+ private static convolve1D;
55
+ }
@@ -250,6 +250,15 @@ export declare class MaskVolume {
250
250
  * @returns Channel count (≥ 1).
251
251
  */
252
252
  getChannels(): number;
253
+ /**
254
+ * Return the number of bytes in one complete z-slice.
255
+ *
256
+ * Equal to `width × height × channels`. Useful for direct buffer
257
+ * index arithmetic in performance-critical code paths.
258
+ *
259
+ * @returns Bytes per z-slice.
260
+ */
261
+ getBytesPerSlice(): number;
253
262
  /**
254
263
  * Return total memory used by the backing buffer, in bytes.
255
264
  *
@@ -19,6 +19,8 @@ export interface MaskDelta {
19
19
  /** Full slice data captured after the drawing operation. */
20
20
  newSlice: Uint8Array;
21
21
  }
22
+ /** A single delta or a group of deltas treated as one undo unit. */
23
+ export type UndoEntry = MaskDelta[];
22
24
  export declare class UndoManager {
23
25
  private undoStacks;
24
26
  private redoStacks;
@@ -26,18 +28,20 @@ export declare class UndoManager {
26
28
  constructor();
27
29
  /** Set the currently active layer (determines which stack undo/redo operates on). */
28
30
  setActiveLayer(layer: string): void;
29
- /** Push a delta onto the active layer's undo stack and clear the redo stack. */
31
+ /** Push a single delta onto the active layer's undo stack and clear the redo stack. */
30
32
  push(delta: MaskDelta): void;
33
+ /** Push a group of deltas as a single undo unit (e.g. 3D sphere spanning multiple slices). */
34
+ pushGroup(deltas: MaskDelta[]): void;
31
35
  /**
32
36
  * Undo the last operation on the active layer.
33
- * @returns The delta that was undone, or undefined if nothing to undo.
37
+ * @returns The delta(s) that were undone, or undefined if nothing to undo.
34
38
  */
35
- undo(): MaskDelta | undefined;
39
+ undo(): UndoEntry | undefined;
36
40
  /**
37
41
  * Redo the last undone operation on the active layer.
38
- * @returns The delta that was redone, or undefined if nothing to redo.
42
+ * @returns The delta(s) that were redone, or undefined if nothing to redo.
39
43
  */
40
- redo(): MaskDelta | undefined;
44
+ redo(): UndoEntry | undefined;
41
45
  canUndo(): boolean;
42
46
  canRedo(): boolean;
43
47
  /** Clear undo and redo stacks for a specific layer (called on clearActiveLayer). */
@@ -70,5 +70,5 @@
70
70
  export type { Dimensions, RGBAColor, ChannelColorMap, SliceRenderOptions, LayerId, ChannelValue, ICommXYZ, ICommXY, ISkipSlicesDictType, ToolMode, IDragPrameters, IDrawingEvents, IContrastEvents, IPaintImages, IPaintImage, ILayerRenderTarget, IDownloadImageConfig, INewMaskData, IMaskData, IProtected, IToolModeState, IDrawingConfig, IViewConfig, ILayerChannelState, IGUIStates, IGuiMeta, IGuiParameterSettings, IImageMetadata, IViewState, IInteractionState, ISphereState, IInternalFlags, INrrdStates, IAnnotationCallbacks, IConvertObjType, ICursorPage, IDragOpts, IDrawOpts, IKeyBoardSettings, } from './types';
71
71
  export { RenderMode, MASK_CHANNEL_COLORS, MASK_CHANNEL_CSS_COLORS, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, } from './types';
72
72
  export { MaskVolume } from './MaskVolume';
73
- export type { MaskDelta } from './UndoManager';
73
+ export type { MaskDelta, UndoEntry } from './UndoManager';
74
74
  export { UndoManager } from './UndoManager';
@@ -118,7 +118,7 @@ export interface ISkipSlicesDictType {
118
118
  [key: string]: any;
119
119
  }
120
120
  /** Tool mode types for segmentation tools */
121
- export type ToolMode = "pencil" | "brush" | "eraser" | "sphere" | "calculator";
121
+ export type ToolMode = "pencil" | "brush" | "eraser" | "sphere" | "calculator" | "sphereBrush" | "sphereEraser";
122
122
  export interface IDragPrameters {
123
123
  move: number;
124
124
  y: number;
@@ -137,6 +137,7 @@ export interface IDrawingEvents {
137
137
  handleOnDrawingBrushCricleMove: (ev: MouseEvent) => void;
138
138
  handleMouseZoomSliceWheel: (e: WheelEvent) => void;
139
139
  handleSphereWheel: (e: WheelEvent) => void;
140
+ handleSphereBrushWheel: (e: WheelEvent) => void;
140
141
  }
141
142
  export interface IContrastEvents {
142
143
  move_x: number;
@@ -223,6 +224,8 @@ export interface IToolModeState {
223
224
  pencil: boolean;
224
225
  eraser: boolean;
225
226
  sphere: boolean;
227
+ sphereBrush: boolean;
228
+ sphereEraser: boolean;
226
229
  activeSphereType: "tumour" | "skin" | "nipple" | "ribcage";
227
230
  }
228
231
  /** Drawing configuration — brush/pencil appearance and behavior */
@@ -422,6 +425,7 @@ export interface ISphereState {
422
425
  /** Dedicated MaskVolume for SphereTool 3D sphere data. Type is `any` to avoid circular deps. */
423
426
  sphereMaskVolume: any;
424
427
  sphereRadius: number;
428
+ sphereBrushRadius: number;
425
429
  }
426
430
  /** Internal flags — transient operational flags */
427
431
  export interface IInternalFlags {
@@ -18,7 +18,7 @@ export type InteractionMode = 'idle' | 'draw' | 'drag' | 'contrast' | 'crosshair
18
18
  /**
19
19
  * GUI tool selection (set from UI buttons)
20
20
  */
21
- export type GuiTool = 'pencil' | 'brush' | 'eraser' | 'sphere';
21
+ export type GuiTool = 'pencil' | 'brush' | 'eraser' | 'sphere' | 'sphereBrush' | 'sphereEraser';
22
22
  /**
23
23
  * Keyboard event handler type
24
24
  */
@@ -26,10 +26,6 @@ export declare class DragSliceTool extends BaseTool {
26
26
  setShowDragNumberDiv(div: HTMLDivElement): void;
27
27
  updateIndex(move: number): void;
28
28
  private drawDragSlice;
29
- /**
30
- * Composite all visible layer canvases to the master display canvas.
31
- */
32
- private compositeAllLayers;
33
29
  private cleanCanvases;
34
30
  updateShowNumDiv(contrastNum: number): void;
35
31
  updateCurrentContrastSlice(): any;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * SphereBrushTool — 3D sphere brush and eraser on layer MaskVolume.
3
+ *
4
+ * Unlike SphereTool (which uses its own isolated sphereMaskVolume),
5
+ * this tool writes/erases directly in the active layer's shared MaskVolume —
6
+ * the same volume used by pencil/brush/eraser tools.
7
+ *
8
+ * Two operation modes handled by one class:
9
+ * - **sphereBrush**: Direct click to paint a 3D sphere of the active channel label.
10
+ * - **sphereEraser**: Shift+click to erase a 3D sphere (only voxels matching active channel).
11
+ *
12
+ * Interaction:
13
+ * 1. Pointer-down records sphere center, switches wheel to radius mode.
14
+ * 2. Scroll wheel adjusts sphereBrushRadius [1, 50].
15
+ * 3. Pointer-up writes/erases sphere to volume, captures grouped undo, refreshes canvas.
16
+ */
17
+ import { BaseTool } from "./BaseTool";
18
+ import type { ToolContext } from "./BaseTool";
19
+ import type { SphereBrushHostDeps } from "./ToolHost";
20
+ export declare class SphereBrushTool extends BaseTool {
21
+ private callbacks;
22
+ /** Recorded sphere center in canvas mm-space */
23
+ private centerX;
24
+ private centerY;
25
+ private centerSlice;
26
+ /** Whether a sphere placement is in progress */
27
+ private active;
28
+ /** Current operation mode for the active placement */
29
+ private mode;
30
+ /** Cumulative "before" snapshots for drag-erase undo (z-index → slice data) */
31
+ private dragBeforeSnapshots;
32
+ /** Whether a drag-erase has actually moved (vs. simple click-release) */
33
+ private dragMoved;
34
+ constructor(ctx: ToolContext, callbacks: SphereBrushHostDeps);
35
+ setCallbacks(callbacks: SphereBrushHostDeps): void;
36
+ /**
37
+ * Convert canvas mm-space coordinates to 3D voxel coordinates.
38
+ */
39
+ private canvasToVoxelCenter;
40
+ /**
41
+ * Convert mm radius to per-axis voxel radii.
42
+ */
43
+ private getVoxelRadii;
44
+ /**
45
+ * Compute clamped bounding box for an ellipsoid in voxel space.
46
+ */
47
+ private getBoundingBox;
48
+ /**
49
+ * Write a 3D sphere of the active channel label into the layer's MaskVolume.
50
+ */
51
+ private write3DSphereToBrush;
52
+ /**
53
+ * Erase a 3D sphere from the layer's MaskVolume.
54
+ * Only clears voxels whose current value equals the active channel label.
55
+ */
56
+ private erase3DSphereFromVolume;
57
+ /**
58
+ * Capture slice snapshots for all Z-slices in the bounding box.
59
+ * Used before and after the sphere operation to build MaskDelta groups.
60
+ *
61
+ * We always capture along the Z axis since the 3D sphere spans Z slices.
62
+ */
63
+ private captureSliceSnapshots;
64
+ /**
65
+ * Build MaskDelta group from before/after snapshots.
66
+ */
67
+ private buildUndoGroup;
68
+ /**
69
+ * Draw a preview circle on the sphere canvas during sphere placement.
70
+ */
71
+ drawPreview(mouseX: number, mouseY: number, radius: number, isEraser: boolean): void;
72
+ /**
73
+ * Clear the sphere preview canvas.
74
+ */
75
+ clearPreview(): void;
76
+ /**
77
+ * Get the hex color for the active channel from the layer's MaskVolume.
78
+ */
79
+ private getActiveChannelColor;
80
+ /**
81
+ * Returns a wheel event handler for adjusting sphereBrushRadius.
82
+ * Used in both sphereBrush and sphereEraser modes.
83
+ */
84
+ configSphereBrushWheel(): (e: WheelEvent) => void;
85
+ /**
86
+ * Handle pointer-down in sphereBrush mode (direct click, no Shift needed).
87
+ */
88
+ onSphereBrushClick(e: MouseEvent): void;
89
+ /**
90
+ * Handle pointer-up in sphereBrush mode — write sphere to volume.
91
+ */
92
+ onSphereBrushPointerUp(): void;
93
+ /**
94
+ * Handle pointer-down in sphereEraser mode.
95
+ * Initializes drag tracking for cumulative undo.
96
+ */
97
+ onSphereEraserClick(e: MouseEvent): void;
98
+ /**
99
+ * Handle pointer-move in sphereEraser mode — drag to continuously erase.
100
+ */
101
+ onSphereEraserMove(e: MouseEvent): void;
102
+ /**
103
+ * Handle pointer-up in sphereEraser mode — finalize erase + push undo group.
104
+ * Works for both click-release and drag-release.
105
+ */
106
+ onSphereEraserPointerUp(): void;
107
+ /**
108
+ * Expand cumulative "before" snapshots to cover z range [minZ, maxZ].
109
+ * Only captures slices not yet in the map (preserves original state).
110
+ */
111
+ private expandDragBeforeSnapshots;
112
+ /** Get minimum Z index from drag snapshots */
113
+ private dragMinZ;
114
+ /** Get maximum Z index from drag snapshots */
115
+ private dragMaxZ;
116
+ /**
117
+ * After writing/erasing the sphere in the volume, re-render the current
118
+ * slice's layer canvas and composite all layers to master.
119
+ *
120
+ * @param changedDeltas - If provided, fire onMaskChanged for ALL changed
121
+ * slices (not just the current view slice) so the backend receives the
122
+ * full 3D sphere data for NII/GLTF export.
123
+ */
124
+ private refreshDisplay;
125
+ /** Whether a sphere placement is currently in progress */
126
+ get isActive(): boolean;
127
+ }
@@ -40,6 +40,7 @@ export interface ToolHost {
40
40
  image: ImageData;
41
41
  } | undefined;
42
42
  pushUndoDelta(delta: MaskDelta): void;
43
+ pushUndoGroup(deltas: MaskDelta[]): void;
43
44
  getEraserUrls(): string[];
44
45
  enableCrosshair(): void;
45
46
  setUpSphereOrigins(mouseX: number, mouseY: number, sliceIndex: number): void;
@@ -65,10 +66,12 @@ export type SphereHostDeps = Pick<ToolHost, 'setEmptyCanvasSize' | 'drawImageOnE
65
66
  /** DrawingTool host dependencies */
66
67
  export type DrawingHostDeps = Pick<ToolHost, 'setCurrentLayer' | 'compositeAllLayers' | 'syncLayerSliceData' | 'filterDrawedImage' | 'getVolumeForLayer' | 'pushUndoDelta' | 'getEraserUrls'>;
67
68
  /** DragSliceTool host dependencies */
68
- export type DragSliceHostDeps = Pick<ToolHost, 'setSyncsliceNum' | 'setIsDrawFalse' | 'flipDisplayImageByAxis' | 'setEmptyCanvasSize' | 'getOrCreateSliceBuffer' | 'renderSliceToCanvas' | 'refreshSphereOverlay'>;
69
+ export type DragSliceHostDeps = Pick<ToolHost, 'setSyncsliceNum' | 'setIsDrawFalse' | 'flipDisplayImageByAxis' | 'setEmptyCanvasSize' | 'getOrCreateSliceBuffer' | 'renderSliceToCanvas' | 'refreshSphereOverlay' | 'compositeAllLayers'>;
69
70
  /** LayerChannelManager host dependencies */
70
71
  export type LayerChannelHostDeps = Pick<ToolHost, 'reloadMasksFromVolume' | 'getVolumeForLayer' | 'onChannelColorChanged'>;
71
72
  /** SliceRenderPipeline host dependencies */
72
73
  export type SliceRenderHostDeps = Pick<ToolHost, 'compositeAllLayers' | 'getOrCreateSliceBuffer' | 'renderSliceToCanvas' | 'getVolumeForLayer' | 'refreshSphereOverlay' | 'syncGuiParameterSettings' | 'repraintCurrentContrastSlice' | 'clearUndoHistory' | 'updateShowNumDiv' | 'updateCurrentContrastSlice'>;
73
74
  /** DataLoader host dependencies */
74
75
  export type DataLoaderHostDeps = Pick<ToolHost, 'invalidateSliceBuffer' | 'setDisplaySlicesBaseOnAxis' | 'afterLoadSlice' | 'setEmptyCanvasSize' | 'syncLayerSliceData' | 'reloadMasksFromVolume' | 'resetZoom'>;
76
+ /** SphereBrushTool host dependencies */
77
+ export type SphereBrushHostDeps = Pick<ToolHost, 'getVolumeForLayer' | 'compositeAllLayers' | 'pushUndoGroup' | 'renderSliceToCanvas' | 'getOrCreateSliceBuffer' | 'setEmptyCanvasSize' | 'reloadMasksFromVolume' | 'getEraserUrls'>;
@@ -8,13 +8,14 @@
8
8
  */
9
9
  export { BaseTool } from "./BaseTool";
10
10
  export type { ToolContext } from "./BaseTool";
11
- export type { ToolHost, ImageStoreHostDeps, PanHostDeps, ContrastHostDeps, ZoomHostDeps, SphereHostDeps, DrawingHostDeps, DragSliceHostDeps, LayerChannelHostDeps, SliceRenderHostDeps, DataLoaderHostDeps, } from "./ToolHost";
11
+ export type { ToolHost, ImageStoreHostDeps, PanHostDeps, ContrastHostDeps, ZoomHostDeps, SphereHostDeps, SphereBrushHostDeps, DrawingHostDeps, DragSliceHostDeps, LayerChannelHostDeps, SliceRenderHostDeps, DataLoaderHostDeps, } from "./ToolHost";
12
12
  export { EraserTool } from "./EraserTool";
13
13
  export { DrawingTool } from "./DrawingTool";
14
14
  export { PanTool } from "./PanTool";
15
15
  export { ZoomTool } from "./ZoomTool";
16
16
  export { SphereTool, SPHERE_CHANNEL_MAP } from "./SphereTool";
17
17
  export type { SphereType } from "./SphereTool";
18
+ export { SphereBrushTool } from "./SphereBrushTool";
18
19
  export { CrosshairTool } from "./CrosshairTool";
19
20
  export { ContrastTool } from "./ContrastTool";
20
21
  export { ImageStoreHelper } from "./ImageStoreHelper";
@@ -13,6 +13,7 @@ import { createTexture2D_NRRD } from "./Utils/texture2d";
13
13
  import { configKiwriousHeart } from "./Utils/kiwrious/configKiwrious";
14
14
  import kiwrious from "./Utils/kiwrious/configKiwrious";
15
15
  import { NrrdTools } from "./Utils/segmentation/NrrdTools";
16
+ import { GaussianSmoother } from "./Utils/segmentation/core/GaussianSmoother";
16
17
  import { Copper3dTrackballControls } from "./Controls/Copper3dTrackballControls";
17
18
  import { MeshNodeTool } from "./Utils/MeshNodeTool";
18
19
  import { removeGuiFolderChilden } from "./Utils/segmentation/coreTools/gui";
@@ -24,6 +25,6 @@ import type { ToolMode, IAnnotationCallbacks } from "./Utils/segmentation/core/t
24
25
  import { CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss } from "./Utils/segmentation/core/index";
25
26
  import type { LayerId, ChannelValue } from "./Utils/segmentation/core/index";
26
27
  import "./css/style.css";
27
- export declare const REVISION = "v3.1.2-beta";
28
- export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, };
28
+ export declare const REVISION = "v3.2.1-beta";
29
+ export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, GaussianSmoother, };
29
30
  export type { positionType, screenPosType, optsType, nrrdMeshesType, nrrdSliceType, SensorDecodedValue_kiwrious, SensorReadResult_kiwrious, HeartRateResult_kiwrious, loadingBarType, IPaintImage, exportPaintImageType, IOptVTKLoader, ICommXYZ, IGUIStates, IGuiParameterSettings, INrrdStates, NrrdState, GuiState, IGuiMeta, ToolMode, IAnnotationCallbacks, LayerId, ChannelValue, };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "copper3d",
3
3
  "description": "A 3d visualisation package base on threejs provides multiple scenes and Nrrd image load funtion.",
4
- "version": "3.1.2",
4
+ "version": "3.2.1",
5
5
  "main": "dist/bundle.umd.js",
6
6
  "moudle": "dist/bundle.esm.js",
7
7
  "types": "dist/types/index.d.ts",