cloudmr-ux 4.6.7 → 4.6.8
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/CmrComponents/niivue-viewer/CloudMrNiivuePanel.d.ts +2 -0
- package/dist/CmrComponents/niivue-viewer/CloudMrNiivuePanel.js +5 -4
- package/dist/CmrComponents/niivue-viewer/CloudMrNiivueViewer.js +80 -13
- package/dist/CmrComponents/niivue-viewer/NiivuePatcher.js +57 -11
- package/dist/CmrComponents/niivue-viewer/penDraftUtils.d.ts +12 -0
- package/dist/CmrComponents/niivue-viewer/penDraftUtils.js +24 -1
- package/dist/CmrComponents/niivue-viewer/shapeDraftUtils.d.ts +12 -0
- package/dist/CmrComponents/niivue-viewer/shapeDraftUtils.js +3 -3
- package/package.json +1 -1
|
@@ -51,6 +51,7 @@ export interface CloudMrNiivuePanelProps {
|
|
|
51
51
|
shapeDraft: import("./shapeDraftUtils").ShapeDraft | null;
|
|
52
52
|
onShapeDraftChange: (draft: import("./shapeDraftUtils").ShapeDraft) => void;
|
|
53
53
|
onApplyShapeDraft: () => void;
|
|
54
|
+
onApplyShapeDraftKeepTool?: () => void;
|
|
54
55
|
onCancelShapeDraft: () => void;
|
|
55
56
|
penDraft: {
|
|
56
57
|
kind: "polyline" | "freehand";
|
|
@@ -71,6 +72,7 @@ export interface CloudMrNiivuePanelProps {
|
|
|
71
72
|
} | null;
|
|
72
73
|
onPenDraftChange: (draft: NonNullable<CloudMrNiivuePanelProps["penDraft"]>) => void;
|
|
73
74
|
onApplyPenDraft: () => void;
|
|
75
|
+
onApplyPenDraftKeepTool?: () => void;
|
|
74
76
|
onCancelPenDraft: () => void;
|
|
75
77
|
}
|
|
76
78
|
export declare function CloudMrNiivuePanel(props: CloudMrNiivuePanelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -107,15 +107,16 @@ export function CloudMrNiivuePanel(props) {
|
|
|
107
107
|
props.resampleImage();
|
|
108
108
|
}, [histogram]);
|
|
109
109
|
function applyDrawShapeTool(tool) {
|
|
110
|
-
var _a, _b;
|
|
110
|
+
var _a, _b, _c, _d;
|
|
111
111
|
if (props.shapeDraft) {
|
|
112
|
-
|
|
112
|
+
// Apply (commit) the current draft rather than discarding it
|
|
113
|
+
(_a = props.onApplyShapeDraftKeepTool) === null || _a === void 0 ? void 0 : _a.call(props);
|
|
113
114
|
}
|
|
114
115
|
if (props.penDraft) {
|
|
115
|
-
props.
|
|
116
|
+
(_b = props.onApplyPenDraftKeepTool) === null || _b === void 0 ? void 0 : _b.call(props);
|
|
116
117
|
}
|
|
117
118
|
if (tool !== "pen") {
|
|
118
|
-
(
|
|
119
|
+
(_d = (_c = props.drawToolkitProps).onPenDrawModeChange) === null || _d === void 0 ? void 0 : _d.call(_c, "freehand");
|
|
119
120
|
}
|
|
120
121
|
props.setDrawShapeTool(tool);
|
|
121
122
|
var nv = props.nv;
|
|
@@ -849,22 +849,28 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
849
849
|
nvSetDrawingEnabled(true);
|
|
850
850
|
}
|
|
851
851
|
}
|
|
852
|
-
function applyPenDraftHandler() {
|
|
853
|
-
var
|
|
852
|
+
function applyPenDraftHandler(_a) {
|
|
853
|
+
var _b;
|
|
854
|
+
var _c = _a === void 0 ? {} : _a, _d = _c.keepTool, keepTool = _d === void 0 ? false : _d;
|
|
854
855
|
var draft = penDraftRef.current;
|
|
855
856
|
if (!draft)
|
|
856
857
|
return;
|
|
857
858
|
applyPenDraft(nv, draft);
|
|
859
|
+
markPenVoxelKind(draft, draft.kind === "polyline" ? 3 : 2);
|
|
858
860
|
if (draft.kind === "polyline") {
|
|
859
|
-
(
|
|
861
|
+
(_b = nv.cloudMrResetPolyline) === null || _b === void 0 ? void 0 : _b.call(nv);
|
|
860
862
|
setPolylineVertexCount(0);
|
|
861
863
|
}
|
|
862
864
|
setPenDraft(null);
|
|
863
865
|
penDraftRef.current = null;
|
|
864
866
|
nv._cloudMrPenDraftActive = false;
|
|
865
867
|
setDrawingChanged(true);
|
|
866
|
-
if (
|
|
867
|
-
|
|
868
|
+
if (!keepTool) {
|
|
869
|
+
// Deactivate tool entirely — palette closes, user re-enters edit by clicking the ROI
|
|
870
|
+
setDrawShapeTool(null);
|
|
871
|
+
nv.opts.deferFreehandCommit = false;
|
|
872
|
+
nv.opts.polylinePenMode = false;
|
|
873
|
+
nvSetDrawingEnabled(false);
|
|
868
874
|
}
|
|
869
875
|
resampleImage();
|
|
870
876
|
}
|
|
@@ -891,6 +897,21 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
891
897
|
nv._cloudMrPenDraftActive = true;
|
|
892
898
|
nvSetDrawingEnabled(false);
|
|
893
899
|
};
|
|
900
|
+
// Called by NiivuePatcher when the user clicks an applied pen ROI to re-edit it.
|
|
901
|
+
// penKind: 2=freehand, 3=polyline
|
|
902
|
+
nv.onPenDraftReopenReady = function (draft, penKind) {
|
|
903
|
+
setPenDraft(draft);
|
|
904
|
+
penDraftRef.current = draft;
|
|
905
|
+
nv._cloudMrPenDraftActive = true;
|
|
906
|
+
// Auto-select pen tool so the palette opens
|
|
907
|
+
setDrawShapeTool("pen");
|
|
908
|
+
var mode = penKind === 3 ? "polyline" : "freehand";
|
|
909
|
+
setPenDrawMode(mode);
|
|
910
|
+
penDrawModeRef.current = mode;
|
|
911
|
+
nv.opts.deferFreehandCommit = false;
|
|
912
|
+
nv.opts.polylinePenMode = false;
|
|
913
|
+
nvSetDrawingEnabled(false);
|
|
914
|
+
};
|
|
894
915
|
nv.onPolylineChange = function (count) {
|
|
895
916
|
var _a, _b;
|
|
896
917
|
setPolylineVertexCount(count);
|
|
@@ -924,19 +945,65 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
924
945
|
nvSetDrawingEnabled(true);
|
|
925
946
|
}
|
|
926
947
|
}
|
|
927
|
-
function
|
|
928
|
-
if (!
|
|
948
|
+
function ensureToolKindBitmap() {
|
|
949
|
+
if (!nv.drawBitmap)
|
|
950
|
+
return;
|
|
951
|
+
if (!nv._cloudMrToolKindBitmap || nv._cloudMrToolKindBitmap.length !== nv.drawBitmap.length) {
|
|
952
|
+
nv._cloudMrToolKindBitmap = new Uint8Array(nv.drawBitmap.length);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
function markShapeVoxelKind(draft) {
|
|
956
|
+
if (!nv.drawBitmap || !(draft === null || draft === void 0 ? void 0 : draft.baseBitmap))
|
|
957
|
+
return;
|
|
958
|
+
ensureToolKindBitmap();
|
|
959
|
+
var tkb = nv._cloudMrToolKindBitmap;
|
|
960
|
+
for (var i = 0; i < nv.drawBitmap.length; i++) {
|
|
961
|
+
if (nv.drawBitmap[i] === draft.penValue && draft.baseBitmap[i] !== draft.penValue) {
|
|
962
|
+
tkb[i] = 1; // shape
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
function markPenVoxelKind(draft, kind) {
|
|
967
|
+
var _a;
|
|
968
|
+
if (!nv.drawBitmap)
|
|
969
|
+
return;
|
|
970
|
+
ensureToolKindBitmap();
|
|
971
|
+
var tkb = nv._cloudMrToolKindBitmap;
|
|
972
|
+
var dims = (_a = nv.back) === null || _a === void 0 ? void 0 : _a.dims;
|
|
973
|
+
if (draft.kind === "freehand" && draft.strokeVoxels && dims) {
|
|
974
|
+
var dx = dims[1];
|
|
975
|
+
var dy = dims[2];
|
|
976
|
+
for (var _i = 0, _b = draft.strokeVoxels; _i < _b.length; _i++) {
|
|
977
|
+
var _c = _b[_i], x = _c[0], y = _c[1], z = _c[2];
|
|
978
|
+
tkb[x + y * dx + z * dx * dy] = kind;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
else if (draft.baseBitmap) {
|
|
982
|
+
for (var i = 0; i < nv.drawBitmap.length; i++) {
|
|
983
|
+
if (nv.drawBitmap[i] === draft.penValue && draft.baseBitmap[i] !== draft.penValue) {
|
|
984
|
+
tkb[i] = kind;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
function applyShapeDraft(_a) {
|
|
990
|
+
var _b = _a === void 0 ? {} : _a, _c = _b.keepTool, keepTool = _c === void 0 ? false : _c;
|
|
991
|
+
var draft = shapeDraftRef.current;
|
|
992
|
+
if (!draft)
|
|
929
993
|
return;
|
|
930
994
|
nv.drawAddUndoBitmap(nv.drawFillOverwrites);
|
|
995
|
+
markShapeVoxelKind(draft);
|
|
931
996
|
setDrawingChanged(true);
|
|
932
997
|
setShapeDraft(null);
|
|
933
998
|
shapeDraftRef.current = null;
|
|
934
999
|
nv._cloudMrShapeDraftActive = false;
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1000
|
+
if (!keepTool) {
|
|
1001
|
+
// Deactivate tool entirely — palette closes, user re-enters edit by clicking the ROI
|
|
1002
|
+
setDrawShapeTool(null);
|
|
1003
|
+
nv.opts.deferShapeCommit = false;
|
|
1004
|
+
nv.opts.penType = NI_PEN_TYPE.PEN;
|
|
1005
|
+
nvSetDrawingEnabled(false);
|
|
1006
|
+
}
|
|
940
1007
|
resampleImage();
|
|
941
1008
|
}
|
|
942
1009
|
function onShapeDraftChange(draft) {
|
|
@@ -1543,7 +1610,7 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
1543
1610
|
props.rois[selectedROI].filename : undefined) }), props.niis[selectedVolume] != undefined && _jsx(CloudMrNiivuePanel, { nv: nv, transformFactors: transformFactors, decimalPrecision: decimalPrecision, locationData: locationData, locationTableVisible: locationTableVisible, pipelineID: props.pipelineID, resampleImage: resampleImage, rois: rois, drawToolkitProps: drawToolkitProps, drawShapeTool: drawShapeTool, setDrawShapeTool: setDrawShapeTool, mins: boundMins, maxs: boundMaxs, mms: mms, min: min, max: max, setMin: setMin, setMax: setMax, unzipAndRenderROI: unpackROI, zipAndSendROI: zipAndSendDrawingLayer, setLabelAlias: setLabelAlias, onAfterRoiUpload: function () {
|
|
1544
1611
|
var _a;
|
|
1545
1612
|
void ((_a = props.refreshPipelineRois) === null || _a === void 0 ? void 0 : _a.call(props));
|
|
1546
|
-
}, gamma: gamma, gammaKey: gammaKey, setGamma: setGamma, shapeDraft: shapeDraft, onShapeDraftChange: onShapeDraftChange, onApplyShapeDraft: applyShapeDraft, onCancelShapeDraft: cancelShapeDraft, penDraft: penDraft, onPenDraftChange: onPenDraftChange, onApplyPenDraft: applyPenDraftHandler, onCancelPenDraft: cancelPenDraftHandler }, "".concat(selectedVolume))] })));
|
|
1613
|
+
}, gamma: gamma, gammaKey: gammaKey, setGamma: setGamma, shapeDraft: shapeDraft, onShapeDraftChange: onShapeDraftChange, onApplyShapeDraft: function () { return applyShapeDraft(); }, onApplyShapeDraftKeepTool: function () { return applyShapeDraft({ keepTool: true }); }, onCancelShapeDraft: cancelShapeDraft, penDraft: penDraft, onPenDraftChange: onPenDraftChange, onApplyPenDraft: function () { return applyPenDraftHandler(); }, onApplyPenDraftKeepTool: function () { return applyPenDraftHandler({ keepTool: true }); }, onCancelPenDraft: cancelPenDraftHandler }, "".concat(selectedVolume))] })));
|
|
1547
1614
|
}
|
|
1548
1615
|
function niiToVolume(nii) {
|
|
1549
1616
|
return {
|
|
@@ -19,9 +19,12 @@ import {
|
|
|
19
19
|
isPolylinePenActive,
|
|
20
20
|
previewPolylineSegment,
|
|
21
21
|
resetPolylineState,
|
|
22
|
+
voxFromMouse,
|
|
22
23
|
} from "./polylinePenUtils.js";
|
|
23
24
|
import {
|
|
24
25
|
captureFreehandDraft,
|
|
26
|
+
capturePenDraftFromClick,
|
|
27
|
+
redrawFreehandDraft,
|
|
25
28
|
shouldDeferFreehandCommit,
|
|
26
29
|
} from "./penDraftUtils.js";
|
|
27
30
|
|
|
@@ -1486,18 +1489,30 @@ function cloudMrTryApplyDraftOnRightClick(nv, event) {
|
|
|
1486
1489
|
return true;
|
|
1487
1490
|
}
|
|
1488
1491
|
|
|
1492
|
+
/** Returns the tool-kind code stored for the voxel under the mouse (0=unknown,1=shape,2=pen freehand,3=pen polyline). */
|
|
1493
|
+
function clickedVoxelToolKind(nv) {
|
|
1494
|
+
const bitmap = nv._cloudMrToolKindBitmap;
|
|
1495
|
+
if (!bitmap || !nv.back?.dims) return 0;
|
|
1496
|
+
const seedVox = voxFromMouse(nv);
|
|
1497
|
+
if (!seedVox) return 0;
|
|
1498
|
+
const dims = nv.back.dims;
|
|
1499
|
+
const dx = dims[1];
|
|
1500
|
+
const dy = dims[2];
|
|
1501
|
+
const idx = seedVox[0] + seedVox[1] * dx + seedVox[2] * dx * dy;
|
|
1502
|
+
return bitmap[idx] || 0;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1489
1505
|
/**
|
|
1490
|
-
* Re-enter rectangle/ellipse edit mode when clicking an existing applied ROI.
|
|
1491
|
-
*
|
|
1492
|
-
* so clicking an ROI after apply always re-enters edit mode.
|
|
1506
|
+
* Re-enter rectangle/ellipse edit mode when clicking an existing applied shape ROI.
|
|
1507
|
+
* Skips voxels that were drawn with the pen tool (those are handled by pen reopen).
|
|
1493
1508
|
*/
|
|
1494
1509
|
function cloudMrTryReopenShapeDraftOnClick(nv) {
|
|
1495
|
-
if (nv._cloudMrShapeDraftActive || nv._cloudMrPenDraftActive)
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1510
|
+
if (nv._cloudMrShapeDraftActive || nv._cloudMrPenDraftActive) return false;
|
|
1511
|
+
if (!isClickWithoutDrag(nv.uiData)) return false;
|
|
1512
|
+
|
|
1513
|
+
// If we know this voxel was drawn with the pen, skip shape reopen
|
|
1514
|
+
const kind = clickedVoxelToolKind(nv);
|
|
1515
|
+
if (kind === 2 || kind === 3) return false;
|
|
1501
1516
|
|
|
1502
1517
|
const reopenDraft = captureShapeDraftFromClick(nv);
|
|
1503
1518
|
if (!reopenDraft) return false;
|
|
@@ -1510,6 +1525,33 @@ function cloudMrTryReopenShapeDraftOnClick(nv) {
|
|
|
1510
1525
|
return true;
|
|
1511
1526
|
}
|
|
1512
1527
|
|
|
1528
|
+
/**
|
|
1529
|
+
* Re-enter pen (freehand) edit mode when clicking an existing applied pen ROI.
|
|
1530
|
+
* Skips voxels that were drawn with a shape tool.
|
|
1531
|
+
*/
|
|
1532
|
+
function cloudMrTryReopenPenDraftOnClick(nv) {
|
|
1533
|
+
if (nv._cloudMrShapeDraftActive || nv._cloudMrPenDraftActive) return false;
|
|
1534
|
+
if (!isClickWithoutDrag(nv.uiData)) return false;
|
|
1535
|
+
|
|
1536
|
+
// Only handle pen voxels — skip if this was drawn with a shape tool
|
|
1537
|
+
const kind = clickedVoxelToolKind(nv);
|
|
1538
|
+
if (kind === 1) return false;
|
|
1539
|
+
|
|
1540
|
+
const draft = capturePenDraftFromClick(nv);
|
|
1541
|
+
if (!draft) return false;
|
|
1542
|
+
|
|
1543
|
+
// Look up pen sub-mode (freehand=2 or polyline=3) from the kind bitmap
|
|
1544
|
+
let penKind = kind; // 2 or 3; if 0 (unknown) default to freehand (2)
|
|
1545
|
+
if (penKind !== 3) penKind = 2;
|
|
1546
|
+
|
|
1547
|
+
redrawFreehandDraft(nv, draft);
|
|
1548
|
+
nv._cloudMrSuppressDrawingChangedMouseUp = true;
|
|
1549
|
+
if (typeof nv.onPenDraftReopenReady === "function") {
|
|
1550
|
+
nv.onPenDraftReopenReady(draft, penKind);
|
|
1551
|
+
}
|
|
1552
|
+
return true;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1513
1555
|
const _mouseDownListener = Niivue.prototype.mouseDownListener;
|
|
1514
1556
|
Niivue.prototype.mouseDownListener = function cloudMrMouseDownListener(e) {
|
|
1515
1557
|
if (e.button === RIGHT_MOUSE_BUTTON && cloudMrTryApplyDraftOnRightClick(this, e)) {
|
|
@@ -1583,14 +1625,18 @@ Niivue.prototype.mouseUpListener = function cloudMrMouseUpListener() {
|
|
|
1583
1625
|
}
|
|
1584
1626
|
|
|
1585
1627
|
if (!pendingDraft?.baseBitmap) {
|
|
1586
|
-
cloudMrTryReopenShapeDraftOnClick(this)
|
|
1628
|
+
if (!cloudMrTryReopenShapeDraftOnClick(this)) {
|
|
1629
|
+
cloudMrTryReopenPenDraftOnClick(this);
|
|
1630
|
+
}
|
|
1587
1631
|
return;
|
|
1588
1632
|
}
|
|
1589
1633
|
if (isDraftTooSmall(pendingDraft.ptA, pendingDraft.ptB)) {
|
|
1590
1634
|
this.drawBitmap.set(pendingDraft.baseBitmap);
|
|
1591
1635
|
this.refreshDrawing(true, false);
|
|
1592
1636
|
this.drawScene();
|
|
1593
|
-
cloudMrTryReopenShapeDraftOnClick(this)
|
|
1637
|
+
if (!cloudMrTryReopenShapeDraftOnClick(this)) {
|
|
1638
|
+
cloudMrTryReopenPenDraftOnClick(this);
|
|
1639
|
+
}
|
|
1594
1640
|
return;
|
|
1595
1641
|
}
|
|
1596
1642
|
this._cloudMrSuppressDrawingChangedMouseUp = true;
|
|
@@ -49,6 +49,18 @@ export function polylineDraftFromNv(nv: any, { filled }?: {
|
|
|
49
49
|
/** Fill polyline interior without closing the outline or committing the draft. */
|
|
50
50
|
export function fillPolylineDraft(nv: any, draft: any): any;
|
|
51
51
|
export function applyPenDraft(nv: any, draft: any): void;
|
|
52
|
+
/**
|
|
53
|
+
* Flood-fill from the clicked voxel to reconstruct a freehand PenDraft for re-editing.
|
|
54
|
+
* Returns null if the click didn't land on a labeled voxel.
|
|
55
|
+
*/
|
|
56
|
+
export function capturePenDraftFromClick(nv: any): {
|
|
57
|
+
kind: string;
|
|
58
|
+
baseBitmap: Uint8Array;
|
|
59
|
+
axCorSag: number;
|
|
60
|
+
penValue: number;
|
|
61
|
+
strokeVoxels: [number, number, number][];
|
|
62
|
+
bounds: object;
|
|
63
|
+
} | null;
|
|
52
64
|
export function cancelPenDraft(nv: any, draft: any): void;
|
|
53
65
|
export type PenDraftKind = 'polyline' | 'freehand';
|
|
54
66
|
export type PenDraft = {
|
|
@@ -18,8 +18,9 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
18
18
|
}
|
|
19
19
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
20
20
|
};
|
|
21
|
-
import { translatePt } from "./shapeDraftUtils";
|
|
21
|
+
import { translatePt, floodFillClusterFromVox, eraseClusterFromBitmap, inferAxCorSagFromBounds, } from "./shapeDraftUtils";
|
|
22
22
|
import { NI_PEN_TYPE } from "./niivuePenType";
|
|
23
|
+
import { voxFromMouse } from "./polylinePenUtils";
|
|
23
24
|
/** @typedef {'polyline' | 'freehand'} PenDraftKind */
|
|
24
25
|
/**
|
|
25
26
|
* @typedef {Object} PenDraft
|
|
@@ -265,6 +266,28 @@ export function applyPenDraft(nv, draft) {
|
|
|
265
266
|
nv.onDrawingChanged("draw");
|
|
266
267
|
}
|
|
267
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Flood-fill from the clicked voxel to reconstruct a freehand PenDraft for re-editing.
|
|
271
|
+
* Returns null if the click didn't land on a labeled voxel.
|
|
272
|
+
*/
|
|
273
|
+
export function capturePenDraftFromClick(nv) {
|
|
274
|
+
var seedVox = voxFromMouse(nv);
|
|
275
|
+
var cluster = floodFillClusterFromVox(nv, seedVox);
|
|
276
|
+
if (!cluster)
|
|
277
|
+
return null;
|
|
278
|
+
var label = cluster.label, visited = cluster.visited, voxels = cluster.voxels, bounds = cluster.bounds;
|
|
279
|
+
var x1 = bounds.x1, y1 = bounds.y1, z1 = bounds.z1, x2 = bounds.x2, y2 = bounds.y2, z2 = bounds.z2;
|
|
280
|
+
var baseBitmap = eraseClusterFromBitmap(nv.drawBitmap, visited);
|
|
281
|
+
var axCorSag = inferAxCorSagFromBounds(x1, y1, z1, x2, y2, z2, nv.drawPenAxCorSag >= 0 ? nv.drawPenAxCorSag : 0);
|
|
282
|
+
return {
|
|
283
|
+
kind: "freehand",
|
|
284
|
+
baseBitmap: baseBitmap,
|
|
285
|
+
axCorSag: axCorSag,
|
|
286
|
+
penValue: label,
|
|
287
|
+
strokeVoxels: voxels,
|
|
288
|
+
bounds: bounds
|
|
289
|
+
};
|
|
290
|
+
}
|
|
268
291
|
export function cancelPenDraft(nv, draft) {
|
|
269
292
|
if (draft === null || draft === void 0 ? void 0 : draft.baseBitmap) {
|
|
270
293
|
nv.drawBitmap.set(draft.baseBitmap);
|
|
@@ -49,6 +49,18 @@ export function captureDeferredShapeDraft(nv: any): {
|
|
|
49
49
|
baseBitmap: Uint8Array | null;
|
|
50
50
|
};
|
|
51
51
|
export function shouldDeferShapeCommit(nv: any): any;
|
|
52
|
+
export function inferAxCorSagFromBounds(x1: any, y1: any, z1: any, x2: any, y2: any, z2: any, fallback?: number): number;
|
|
53
|
+
/**
|
|
54
|
+
* Flood-fill a connected voxel cluster from a seed.
|
|
55
|
+
* @returns {{ label: number, visited: Set<number>, voxels: [number,number,number][], bounds: object } | null}
|
|
56
|
+
*/
|
|
57
|
+
export function floodFillClusterFromVox(nv: any, seedVox: any): {
|
|
58
|
+
label: number;
|
|
59
|
+
visited: Set<number>;
|
|
60
|
+
voxels: [number, number, number][];
|
|
61
|
+
bounds: object;
|
|
62
|
+
} | null;
|
|
63
|
+
export function eraseClusterFromBitmap(bitmap: any, visited: any): Uint8Array;
|
|
52
64
|
/**
|
|
53
65
|
* When the user clicks on an existing filled ROI while the rectangle/ellipse tool
|
|
54
66
|
* is active (but no draft is currently open), flood-fill the clicked cluster to
|
|
@@ -197,7 +197,7 @@ function decodeVoxelIndex(idx, dx, dy) {
|
|
|
197
197
|
var x = rem % dx;
|
|
198
198
|
return [x, y, z];
|
|
199
199
|
}
|
|
200
|
-
function inferAxCorSagFromBounds(x1, y1, z1, x2, y2, z2, fallback) {
|
|
200
|
+
export function inferAxCorSagFromBounds(x1, y1, z1, x2, y2, z2, fallback) {
|
|
201
201
|
if (fallback === void 0) { fallback = 0; }
|
|
202
202
|
var spanX = x2 - x1;
|
|
203
203
|
var spanY = y2 - y1;
|
|
@@ -221,7 +221,7 @@ function sliceKey(axCorSag, x, y, z) {
|
|
|
221
221
|
* Flood-fill a connected voxel cluster from a seed.
|
|
222
222
|
* @returns {{ label: number, visited: Set<number>, voxels: [number,number,number][], bounds: object } | null}
|
|
223
223
|
*/
|
|
224
|
-
function floodFillClusterFromVox(nv, seedVox) {
|
|
224
|
+
export function floodFillClusterFromVox(nv, seedVox) {
|
|
225
225
|
var _a;
|
|
226
226
|
var dims = (_a = nv.back) === null || _a === void 0 ? void 0 : _a.dims;
|
|
227
227
|
if (!dims || !nv.drawBitmap || !seedVox)
|
|
@@ -281,7 +281,7 @@ function floodFillClusterFromVox(nv, seedVox) {
|
|
|
281
281
|
bounds: { x1: x1, y1: y1, z1: z1, x2: x2, y2: y2, z2: z2 }
|
|
282
282
|
};
|
|
283
283
|
}
|
|
284
|
-
function eraseClusterFromBitmap(bitmap, visited) {
|
|
284
|
+
export function eraseClusterFromBitmap(bitmap, visited) {
|
|
285
285
|
var next = new Uint8Array(bitmap);
|
|
286
286
|
visited.forEach(function (idx) {
|
|
287
287
|
next[idx] = 0;
|