cloudmr-ux 4.5.0 → 4.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CmrComponents/niivue-viewer/CloudMrNiivuePanel.d.ts +23 -2
- package/dist/CmrComponents/niivue-viewer/CloudMrNiivuePanel.js +11 -2
- package/dist/CmrComponents/niivue-viewer/CloudMrNiivueViewer.js +99 -39
- package/dist/CmrComponents/niivue-viewer/NiivuePatcher.js +45 -0
- package/dist/CmrComponents/niivue-viewer/PenDraftOverlay.d.ts +10 -0
- package/dist/CmrComponents/niivue-viewer/PenDraftOverlay.js +201 -0
- package/dist/CmrComponents/niivue-viewer/mro-draw-toolkit/DrawColorPlatte.d.ts +5 -4
- package/dist/CmrComponents/niivue-viewer/mro-draw-toolkit/DrawColorPlatte.js +7 -8
- package/dist/CmrComponents/niivue-viewer/mro-draw-toolkit/MroDrawToolkit.js +6 -4
- package/dist/CmrComponents/niivue-viewer/penDraftUtils.d.ts +74 -0
- package/dist/CmrComponents/niivue-viewer/penDraftUtils.js +261 -0
- package/package.json +1 -1
|
@@ -7,8 +7,10 @@ export type CloudMrDrawToolkitProps = Omit<DrawToolkitProps, "rois" | "selectedR
|
|
|
7
7
|
onPenDrawModeChange?: (mode: "freehand" | "polyline") => void;
|
|
8
8
|
polylineVertexCount?: number;
|
|
9
9
|
onCancelPolyline?: () => void;
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
onApplyPenDraft?: () => void;
|
|
11
|
+
onCancelPenDraft?: () => void;
|
|
12
|
+
onCloseFillPenDraft?: () => void;
|
|
13
|
+
penDraftActive?: boolean;
|
|
12
14
|
shapeDraftActive?: boolean;
|
|
13
15
|
onApplyShapeDraft?: () => void;
|
|
14
16
|
onCancelShapeDraft?: () => void;
|
|
@@ -48,5 +50,24 @@ export interface CloudMrNiivuePanelProps {
|
|
|
48
50
|
onShapeDraftChange: (draft: import("./shapeDraftUtils").ShapeDraft) => void;
|
|
49
51
|
onApplyShapeDraft: () => void;
|
|
50
52
|
onCancelShapeDraft: () => void;
|
|
53
|
+
penDraft: {
|
|
54
|
+
kind: "polyline" | "freehand";
|
|
55
|
+
baseBitmap: Uint8Array;
|
|
56
|
+
axCorSag: number;
|
|
57
|
+
penValue: number;
|
|
58
|
+
vertices?: [number, number, number][];
|
|
59
|
+
strokeVoxels?: [number, number, number][];
|
|
60
|
+
bounds?: {
|
|
61
|
+
x1: number;
|
|
62
|
+
y1: number;
|
|
63
|
+
x2: number;
|
|
64
|
+
y2: number;
|
|
65
|
+
z1: number;
|
|
66
|
+
z2: number;
|
|
67
|
+
};
|
|
68
|
+
} | null;
|
|
69
|
+
onPenDraftChange: (draft: NonNullable<CloudMrNiivuePanelProps["penDraft"]>) => void;
|
|
70
|
+
onApplyPenDraft: () => void;
|
|
71
|
+
onCancelPenDraft: () => void;
|
|
51
72
|
}
|
|
52
73
|
export declare function CloudMrNiivuePanel(props: CloudMrNiivuePanelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -56,6 +56,7 @@ import { NiivueContrastAdjustments } from "../niivue-contrast-adjustments/Niivue
|
|
|
56
56
|
import { NiivueRoiTable } from "../niivue-roi-table/NiivueRoiTable";
|
|
57
57
|
import { MroDrawToolkit } from "./mro-draw-toolkit/MroDrawToolkit";
|
|
58
58
|
import { ShapeDraftOverlay } from "./ShapeDraftOverlay";
|
|
59
|
+
import { PenDraftOverlay } from "./PenDraftOverlay";
|
|
59
60
|
export function CloudMrNiivuePanel(props) {
|
|
60
61
|
var _this = this;
|
|
61
62
|
var canvas = React.useRef(null);
|
|
@@ -110,12 +111,17 @@ export function CloudMrNiivuePanel(props) {
|
|
|
110
111
|
if (props.shapeDraft) {
|
|
111
112
|
props.onCancelShapeDraft();
|
|
112
113
|
}
|
|
114
|
+
if (props.penDraft) {
|
|
115
|
+
props.onCancelPenDraft();
|
|
116
|
+
}
|
|
113
117
|
if (tool !== "pen") {
|
|
114
118
|
(_b = (_a = props.drawToolkitProps).onPenDrawModeChange) === null || _b === void 0 ? void 0 : _b.call(_a, "freehand");
|
|
115
119
|
}
|
|
116
120
|
props.setDrawShapeTool(tool);
|
|
117
121
|
var nv = props.nv;
|
|
118
122
|
nv.opts.deferShapeCommit = tool === "rectangle" || tool === "ellipse";
|
|
123
|
+
nv.opts.deferFreehandCommit =
|
|
124
|
+
tool === "pen" && props.drawToolkitProps.penDrawMode === "freehand";
|
|
119
125
|
nv.opts.penType =
|
|
120
126
|
tool === "rectangle"
|
|
121
127
|
? NI_PEN_TYPE.RECTANGLE
|
|
@@ -150,8 +156,11 @@ export function CloudMrNiivuePanel(props) {
|
|
|
150
156
|
if (props.shapeDraft) {
|
|
151
157
|
props.onCancelShapeDraft();
|
|
152
158
|
}
|
|
159
|
+
if (props.penDraft) {
|
|
160
|
+
props.onCancelPenDraft();
|
|
161
|
+
}
|
|
153
162
|
props.setDrawShapeTool(null);
|
|
154
|
-
}, shapeDraftActive: props.shapeDraft != null, onApplyShapeDraft: props.onApplyShapeDraft, onCancelShapeDraft: props.onCancelShapeDraft, style: {
|
|
163
|
+
}, shapeDraftActive: props.shapeDraft != null, penDraftActive: props.penDraft != null, onApplyShapeDraft: props.onApplyShapeDraft, onCancelShapeDraft: props.onCancelShapeDraft, style: {
|
|
155
164
|
marginBottom: 0,
|
|
156
165
|
width: "100%",
|
|
157
166
|
flexShrink: 0
|
|
@@ -182,7 +191,7 @@ export function CloudMrNiivuePanel(props) {
|
|
|
182
191
|
left: 0,
|
|
183
192
|
width: "100%",
|
|
184
193
|
height: "100%"
|
|
185
|
-
} }), props.shapeDraft && (_jsx(ShapeDraftOverlay, { nv: props.nv, draft: props.shapeDraft, onDraftChange: props.onShapeDraftChange, overlayKey: props.mms }))] }))] })), _jsxs(Box, __assign({ sx: {
|
|
194
|
+
} }), props.shapeDraft && (_jsx(ShapeDraftOverlay, { nv: props.nv, draft: props.shapeDraft, onDraftChange: props.onShapeDraftChange, overlayKey: props.mms })), props.penDraft && (_jsx(PenDraftOverlay, { nv: props.nv, draft: props.penDraft, onDraftChange: props.onPenDraftChange, overlayKey: props.mms }))] }))] })), _jsxs(Box, __assign({ sx: {
|
|
186
195
|
width: {
|
|
187
196
|
xs: "100%",
|
|
188
197
|
md: "35%"
|
|
@@ -63,6 +63,7 @@ import { SettingsPanel } from './SettingsPanel';
|
|
|
63
63
|
import { NumberPicker } from './NumberPicker';
|
|
64
64
|
import { ColorPicker } from './ColorPicker';
|
|
65
65
|
import { LayersPanel } from './LayersPanel';
|
|
66
|
+
import { applyPenDraft, cancelPenDraft, polylineDraftFromNv, syncPolylineDraftToNv, } from './penDraftUtils';
|
|
66
67
|
import { CloudMrNiivuePanel } from './CloudMrNiivuePanel';
|
|
67
68
|
import { Niivue } from './NiivuePatcher';
|
|
68
69
|
import NVSwitch from './Switch';
|
|
@@ -172,17 +173,22 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
172
173
|
var _23 = useState(null), shapeDraft = _23[0], setShapeDraft = _23[1];
|
|
173
174
|
var _24 = useState("freehand"), penDrawMode = _24[0], setPenDrawMode = _24[1];
|
|
174
175
|
var _25 = useState(0), polylineVertexCount = _25[0], setPolylineVertexCount = _25[1];
|
|
175
|
-
var _26 = useState(
|
|
176
|
+
var _26 = useState(null), penDraft = _26[0], setPenDraft = _26[1];
|
|
177
|
+
var _27 = useState(1), brushSize = _27[0], setBrushSize = _27[1];
|
|
176
178
|
var shapeDraftRef = React.useRef(null);
|
|
179
|
+
var penDraftRef = React.useRef(null);
|
|
177
180
|
var drawShapeToolRef = React.useRef(null);
|
|
181
|
+
var penDrawModeRef = React.useRef("freehand");
|
|
178
182
|
drawShapeToolRef.current = drawShapeTool;
|
|
179
183
|
shapeDraftRef.current = shapeDraft;
|
|
184
|
+
penDraftRef.current = penDraft;
|
|
185
|
+
penDrawModeRef.current = penDrawMode;
|
|
180
186
|
React.useEffect(function () {
|
|
181
187
|
nv.opts.penBounds = 0;
|
|
182
188
|
nv.opts.penSize = 1;
|
|
183
189
|
}, []);
|
|
184
|
-
var
|
|
185
|
-
var
|
|
190
|
+
var _28 = React.useState(1.0), gamma = _28[0], setGamma = _28[1];
|
|
191
|
+
var _29 = React.useState(0), gammaKey = _29[0], setGammaKey = _29[1];
|
|
186
192
|
// Niivue → React bridge so other places (Toolbar) can force the UI to reset
|
|
187
193
|
nv.onResetGamma = function () {
|
|
188
194
|
setGamma(1.0);
|
|
@@ -227,13 +233,13 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
227
233
|
// setLayers([...nv.volumes])
|
|
228
234
|
// }, [])
|
|
229
235
|
// values dualslider
|
|
230
|
-
var
|
|
236
|
+
var _30 = useState(0), rangeKey = _30[0], setRangeKey = _30[1];
|
|
231
237
|
nv.onResetContrast = function () {
|
|
232
238
|
setRangeKey(rangeKey + 1);
|
|
233
239
|
};
|
|
234
|
-
var
|
|
235
|
-
var
|
|
236
|
-
var
|
|
240
|
+
var _31 = useState([0, 0, 0]), boundMins = _31[0], setBoundMins = _31[1];
|
|
241
|
+
var _32 = useState([1, 1, 1]), boundMaxs = _32[0], setBoundMaxs = _32[1];
|
|
242
|
+
var _33 = useState([0.5, 0.5, 0.5]), mms = _33[0], setMMs = _33[1];
|
|
237
243
|
nv.onImageLoaded = function () {
|
|
238
244
|
var _a, _b;
|
|
239
245
|
var oldCrosshairPos = __spreadArray([], nv.scene.crosshairPos, true);
|
|
@@ -516,7 +522,7 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
516
522
|
setTextsVisible(true);
|
|
517
523
|
}
|
|
518
524
|
}
|
|
519
|
-
var
|
|
525
|
+
var _34 = useState("pan"), dragMode = _34[0], setDragMode = _34[1];
|
|
520
526
|
function nvSetDragMode(dragMode) {
|
|
521
527
|
switch (dragMode) {
|
|
522
528
|
case "none":
|
|
@@ -729,7 +735,7 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
729
735
|
nv.opts.crosshairWidth = w;
|
|
730
736
|
nv.drawScene();
|
|
731
737
|
}
|
|
732
|
-
var
|
|
738
|
+
var _35 = useState({}), labelMapping = _35[0], setLabelMapping = _35[1];
|
|
733
739
|
function resampleImage(mapping) {
|
|
734
740
|
if (mapping === void 0) { mapping = labelMapping; }
|
|
735
741
|
var el = typeof document !== "undefined" ? document.getElementById("histoplot") : null;
|
|
@@ -745,30 +751,82 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
745
751
|
function syncPenDrawMode(mode) {
|
|
746
752
|
var _a;
|
|
747
753
|
setPenDrawMode(mode);
|
|
754
|
+
penDrawModeRef.current = mode;
|
|
748
755
|
nv.opts.polylinePenMode = mode === "polyline";
|
|
749
756
|
nv.opts.isFilledPen = mode === "freehand";
|
|
757
|
+
nv.opts.deferFreehandCommit =
|
|
758
|
+
drawShapeToolRef.current === "pen" && mode === "freehand";
|
|
750
759
|
if (mode === "freehand") {
|
|
751
760
|
(_a = nv.cloudMrCancelPolyline) === null || _a === void 0 ? void 0 : _a.call(nv);
|
|
752
761
|
}
|
|
753
762
|
}
|
|
754
|
-
function
|
|
763
|
+
function cancelPenDraftHandler() {
|
|
755
764
|
var _a;
|
|
756
|
-
|
|
765
|
+
var draft = penDraftRef.current;
|
|
766
|
+
if (!draft)
|
|
767
|
+
return;
|
|
768
|
+
cancelPenDraft(nv, draft);
|
|
769
|
+
if (draft.kind === "polyline") {
|
|
770
|
+
(_a = nv.cloudMrResetPolyline) === null || _a === void 0 ? void 0 : _a.call(nv);
|
|
771
|
+
setPolylineVertexCount(0);
|
|
772
|
+
}
|
|
773
|
+
setPenDraft(null);
|
|
774
|
+
penDraftRef.current = null;
|
|
775
|
+
nv._cloudMrPenDraftActive = false;
|
|
776
|
+
if (drawShapeToolRef.current === "pen") {
|
|
777
|
+
nvSetDrawingEnabled(true);
|
|
778
|
+
}
|
|
757
779
|
}
|
|
758
|
-
function
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
780
|
+
function applyPenDraftHandler(fillClosed) {
|
|
781
|
+
var _a;
|
|
782
|
+
if (fillClosed === void 0) { fillClosed = false; }
|
|
783
|
+
var draft = penDraftRef.current;
|
|
784
|
+
if (!draft)
|
|
785
|
+
return;
|
|
786
|
+
applyPenDraft(nv, draft, { fillClosed: fillClosed });
|
|
787
|
+
if (draft.kind === "polyline") {
|
|
788
|
+
(_a = nv.cloudMrResetPolyline) === null || _a === void 0 ? void 0 : _a.call(nv);
|
|
789
|
+
setPolylineVertexCount(0);
|
|
762
790
|
}
|
|
791
|
+
setPenDraft(null);
|
|
792
|
+
penDraftRef.current = null;
|
|
793
|
+
nv._cloudMrPenDraftActive = false;
|
|
794
|
+
setDrawingChanged(true);
|
|
795
|
+
if (drawShapeToolRef.current === "pen") {
|
|
796
|
+
nvSetDrawingEnabled(true);
|
|
797
|
+
}
|
|
798
|
+
resampleImage();
|
|
763
799
|
}
|
|
764
|
-
function
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
800
|
+
function onPenDraftChange(draft) {
|
|
801
|
+
setPenDraft(draft);
|
|
802
|
+
penDraftRef.current = draft;
|
|
803
|
+
if (draft.kind === "polyline") {
|
|
804
|
+
syncPolylineDraftToNv(nv, draft);
|
|
768
805
|
}
|
|
769
806
|
}
|
|
807
|
+
function cancelPolylineDraft() {
|
|
808
|
+
cancelPenDraftHandler();
|
|
809
|
+
}
|
|
810
|
+
nv.onPenDraftReady = function (draft) {
|
|
811
|
+
setPenDraft(draft);
|
|
812
|
+
penDraftRef.current = draft;
|
|
813
|
+
nv._cloudMrPenDraftActive = true;
|
|
814
|
+
nvSetDrawingEnabled(false);
|
|
815
|
+
};
|
|
770
816
|
nv.onPolylineChange = function (count) {
|
|
817
|
+
var _a;
|
|
771
818
|
setPolylineVertexCount(count);
|
|
819
|
+
if (penDrawModeRef.current === "polyline" && count >= 2) {
|
|
820
|
+
var draft = polylineDraftFromNv(nv);
|
|
821
|
+
if (draft) {
|
|
822
|
+
setPenDraft(draft);
|
|
823
|
+
penDraftRef.current = draft;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
else if (((_a = penDraftRef.current) === null || _a === void 0 ? void 0 : _a.kind) === "polyline") {
|
|
827
|
+
setPenDraft(null);
|
|
828
|
+
penDraftRef.current = null;
|
|
829
|
+
}
|
|
772
830
|
};
|
|
773
831
|
function cancelShapeDraft() {
|
|
774
832
|
var draft = shapeDraftRef.current;
|
|
@@ -808,7 +866,7 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
808
866
|
nvSetDrawingEnabled(false);
|
|
809
867
|
};
|
|
810
868
|
React.useEffect(function () {
|
|
811
|
-
if (!shapeDraft && !
|
|
869
|
+
if (!shapeDraft && !penDraft) {
|
|
812
870
|
return undefined;
|
|
813
871
|
}
|
|
814
872
|
var onKeyDown = function (event) {
|
|
@@ -817,8 +875,8 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
817
875
|
if (shapeDraft) {
|
|
818
876
|
cancelShapeDraft();
|
|
819
877
|
}
|
|
820
|
-
else if (
|
|
821
|
-
|
|
878
|
+
else if (penDraft) {
|
|
879
|
+
cancelPenDraftHandler();
|
|
822
880
|
}
|
|
823
881
|
return;
|
|
824
882
|
}
|
|
@@ -827,19 +885,19 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
827
885
|
if (shapeDraft) {
|
|
828
886
|
applyShapeDraft();
|
|
829
887
|
}
|
|
830
|
-
else if (
|
|
831
|
-
|
|
888
|
+
else if (penDraft) {
|
|
889
|
+
applyPenDraftHandler(false);
|
|
832
890
|
}
|
|
833
891
|
}
|
|
834
892
|
};
|
|
835
893
|
window.addEventListener("keydown", onKeyDown);
|
|
836
894
|
return function () { return window.removeEventListener("keydown", onKeyDown); };
|
|
837
|
-
}, [shapeDraft,
|
|
895
|
+
}, [shapeDraft, penDraft]);
|
|
838
896
|
function nvUpdateSelectionBoxColor(rgb01) {
|
|
839
897
|
setSelectionBoxColor(__spreadArray(__spreadArray([], rgb01, true), [0.5], false));
|
|
840
898
|
nv.setSelectionBoxColor(__spreadArray(__spreadArray([], rgb01, true), [0.5], false));
|
|
841
899
|
}
|
|
842
|
-
var
|
|
900
|
+
var _36 = React.useState('axial'), sliceType = _36[0], setSliceType = _36[1];
|
|
843
901
|
function nvUpdateSliceType(newSliceType) {
|
|
844
902
|
setSliceType(newSliceType);
|
|
845
903
|
if (newSliceType === 'axial') {
|
|
@@ -979,14 +1037,14 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
979
1037
|
return [2 /*return*/];
|
|
980
1038
|
});
|
|
981
1039
|
}); };
|
|
982
|
-
var
|
|
983
|
-
var
|
|
984
|
-
var
|
|
985
|
-
}), saveConfirmCallback =
|
|
986
|
-
var
|
|
987
|
-
var
|
|
988
|
-
var
|
|
989
|
-
var
|
|
1040
|
+
var _37 = useState(''), selectedROI = _37[0], setSelectedDrawingLayer = _37[1];
|
|
1041
|
+
var _38 = useState(false), saveDialogOpen = _38[0], setSaveDialogOpen = _38[1];
|
|
1042
|
+
var _39 = useState(function () {
|
|
1043
|
+
}), saveConfirmCallback = _39[0], setSaveConfirmCallback = _39[1];
|
|
1044
|
+
var _40 = useState(false), confirmationOpen = _40[0], setConfirmationOpen = _40[1];
|
|
1045
|
+
var _41 = useState(function () { }), warningConfirmationCallback = _41[0], setWarningConfirmationCallback = _41[1];
|
|
1046
|
+
var _42 = useState(function () { }), warningCancelCallback = _42[0], setWarningCancelCallback = _42[1];
|
|
1047
|
+
var _43 = useState(false), drawingChanged = _43[0], setDrawingChanged = _43[1];
|
|
990
1048
|
// When new drawing strokes are made on top of a saved ROI, reset the dropdown
|
|
991
1049
|
// so it shows the "ROI Layer" placeholder instead of the stale saved name.
|
|
992
1050
|
React.useEffect(function () {
|
|
@@ -1313,8 +1371,8 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
1313
1371
|
cancelShapeDraft();
|
|
1314
1372
|
return;
|
|
1315
1373
|
}
|
|
1316
|
-
if (
|
|
1317
|
-
|
|
1374
|
+
if (penDraftRef.current) {
|
|
1375
|
+
cancelPenDraftHandler();
|
|
1318
1376
|
return;
|
|
1319
1377
|
}
|
|
1320
1378
|
nv.drawUndo();
|
|
@@ -1333,8 +1391,10 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
1333
1391
|
onPenDrawModeChange: syncPenDrawMode,
|
|
1334
1392
|
polylineVertexCount: polylineVertexCount,
|
|
1335
1393
|
onCancelPolyline: cancelPolylineDraft,
|
|
1336
|
-
|
|
1337
|
-
|
|
1394
|
+
onApplyPenDraft: function () { return applyPenDraftHandler(false); },
|
|
1395
|
+
onCancelPenDraft: cancelPenDraftHandler,
|
|
1396
|
+
onCloseFillPenDraft: function () { return applyPenDraftHandler(true); },
|
|
1397
|
+
penDraftActive: penDraft != null,
|
|
1338
1398
|
brushSize: brushSize,
|
|
1339
1399
|
updateBrushSize: nvUpdateBrushSize
|
|
1340
1400
|
};
|
|
@@ -1352,7 +1412,7 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
1352
1412
|
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 () {
|
|
1353
1413
|
var _a;
|
|
1354
1414
|
void ((_a = props.refreshPipelineRois) === null || _a === void 0 ? void 0 : _a.call(props));
|
|
1355
|
-
}, gamma: gamma, gammaKey: gammaKey, setGamma: setGamma, shapeDraft: shapeDraft, onShapeDraftChange: onShapeDraftChange, onApplyShapeDraft: applyShapeDraft, onCancelShapeDraft: cancelShapeDraft }, "".concat(selectedVolume))] })));
|
|
1415
|
+
}, gamma: gamma, gammaKey: gammaKey, setGamma: setGamma, shapeDraft: shapeDraft, onShapeDraftChange: onShapeDraftChange, onApplyShapeDraft: applyShapeDraft, onCancelShapeDraft: cancelShapeDraft, penDraft: penDraft, onPenDraftChange: onPenDraftChange, onApplyPenDraft: function () { return applyPenDraftHandler(false); }, onCancelPenDraft: cancelPenDraftHandler }, "".concat(selectedVolume))] })));
|
|
1356
1416
|
}
|
|
1357
1417
|
function niiToVolume(nii) {
|
|
1358
1418
|
return {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "./shapeDraftUtils.js";
|
|
10
10
|
import {
|
|
11
11
|
addPolylineVertex,
|
|
12
|
+
axCorSagFromMouse,
|
|
12
13
|
cancelPolyline,
|
|
13
14
|
finishPolyline,
|
|
14
15
|
isClickWithoutDrag,
|
|
@@ -16,6 +17,10 @@ import {
|
|
|
16
17
|
previewPolylineSegment,
|
|
17
18
|
resetPolylineState,
|
|
18
19
|
} from "./polylinePenUtils.js";
|
|
20
|
+
import {
|
|
21
|
+
captureFreehandDraft,
|
|
22
|
+
shouldDeferFreehandCommit,
|
|
23
|
+
} from "./penDraftUtils.js";
|
|
19
24
|
|
|
20
25
|
/*
|
|
21
26
|
* bitmapOverlay — in-browser state only: remembers each voxel's label *before* Group
|
|
@@ -496,6 +501,31 @@ Niivue.prototype.drawPenFilled = function () {
|
|
|
496
501
|
this.drawBitmap[index] = value;
|
|
497
502
|
}
|
|
498
503
|
})
|
|
504
|
+
if (shouldDeferFreehandCommit(this) && this._cloudMrFreehandSessionStartBitmap) {
|
|
505
|
+
this._cloudMrSkipNextUndoBitmap = true;
|
|
506
|
+
this.hiddenBitmap = new Uint8Array(this.drawBitmap.length);
|
|
507
|
+
for (let i = 0; i < this.drawBitmap.length; i++) {
|
|
508
|
+
let pen = this.drawBitmap[i];
|
|
509
|
+
if (!this.getLabelVisibility(pen)) {
|
|
510
|
+
this.hiddenBitmap[i] = this.drawBitmap[i];
|
|
511
|
+
this.drawBitmap[i] = 0;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
this.refreshDrawing(false);
|
|
515
|
+
this.drawScene();
|
|
516
|
+
const axCorSag =
|
|
517
|
+
this.drawPenAxCorSag >= 0 ? this.drawPenAxCorSag : this._cloudMrFreehandAxCorSag;
|
|
518
|
+
const draft = captureFreehandDraft(
|
|
519
|
+
this,
|
|
520
|
+
this._cloudMrFreehandSessionStartBitmap,
|
|
521
|
+
axCorSag,
|
|
522
|
+
);
|
|
523
|
+
this._cloudMrFreehandSessionStartBitmap = null;
|
|
524
|
+
if (draft && typeof this.onPenDraftReady === "function") {
|
|
525
|
+
this.onPenDraftReady(draft);
|
|
526
|
+
}
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
499
529
|
this.drawAddUndoBitmap()
|
|
500
530
|
// Post-processing to hide hidden voxels
|
|
501
531
|
this.hiddenBitmap = new Uint8Array(this.drawBitmap.length);
|
|
@@ -1435,6 +1465,21 @@ Niivue.prototype.cloudMrResetPolyline = function cloudMrResetPolyline() {
|
|
|
1435
1465
|
resetPolylineState(this);
|
|
1436
1466
|
};
|
|
1437
1467
|
|
|
1468
|
+
const _mouseDownListener = Niivue.prototype.mouseDownListener;
|
|
1469
|
+
Niivue.prototype.mouseDownListener = function cloudMrMouseDownListener(e) {
|
|
1470
|
+
if (shouldDeferFreehandCommit(this) && this.drawBitmap) {
|
|
1471
|
+
this._cloudMrFreehandSessionStartBitmap = this.drawBitmap.slice();
|
|
1472
|
+
this._cloudMrFreehandAxCorSag = -1;
|
|
1473
|
+
}
|
|
1474
|
+
_mouseDownListener.call(this, e);
|
|
1475
|
+
if (shouldDeferFreehandCommit(this) && this._cloudMrFreehandSessionStartBitmap) {
|
|
1476
|
+
const axCorSag = axCorSagFromMouse(this);
|
|
1477
|
+
if (axCorSag >= 0) {
|
|
1478
|
+
this._cloudMrFreehandAxCorSag = axCorSag;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1438
1483
|
const _mouseClick = Niivue.prototype.mouseClick;
|
|
1439
1484
|
Niivue.prototype.mouseClick = function cloudMrMouseClick(...args) {
|
|
1440
1485
|
if (isPolylinePenActive(this)) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adjust handles for polyline (vertex drag) or freehand (bbox move/resize) drafts.
|
|
3
|
+
*/
|
|
4
|
+
export function PenDraftOverlay({ nv, draft, onDraftChange, overlayKey }: {
|
|
5
|
+
nv: any;
|
|
6
|
+
draft: any;
|
|
7
|
+
onDraftChange: any;
|
|
8
|
+
overlayKey: any;
|
|
9
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export default PenDraftOverlay;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
13
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
14
|
+
if (ar || !(i in from)) {
|
|
15
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
16
|
+
ar[i] = from[i];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
20
|
+
};
|
|
21
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
23
|
+
import { boundsToFreehandCorners, redrawFreehandDraft, redrawPolylineDraft, resizeFreehandDraft, syncPolylineDraftToNv, translateFreehandDraft, translatePolylineVertices, updatePolylineVertex, } from "./penDraftUtils";
|
|
24
|
+
import { canvasDeltaToVoxDelta, clientToCanvasPos, translatePt, voxToOverlayPos, voxUnderClient, } from "./shapeDraftUtils";
|
|
25
|
+
var HANDLE_SIZE = 10;
|
|
26
|
+
var ACCENT = "#580f8b";
|
|
27
|
+
/**
|
|
28
|
+
* Adjust handles for polyline (vertex drag) or freehand (bbox move/resize) drafts.
|
|
29
|
+
*/
|
|
30
|
+
export function PenDraftOverlay(_a) {
|
|
31
|
+
var nv = _a.nv, draft = _a.draft, onDraftChange = _a.onDraftChange, overlayKey = _a.overlayKey;
|
|
32
|
+
var dragRef = useRef(null);
|
|
33
|
+
var draftRef = useRef(draft);
|
|
34
|
+
draftRef.current = draft;
|
|
35
|
+
var onPointerMoveRef = useRef(null);
|
|
36
|
+
var finishDragRef = useRef(null);
|
|
37
|
+
var _b = useState(0), setTick = _b[1];
|
|
38
|
+
var bump = useCallback(function () { return setTick(function (t) { return t + 1; }); }, []);
|
|
39
|
+
useEffect(function () {
|
|
40
|
+
var onMove = function () { return bump(); };
|
|
41
|
+
window.addEventListener("resize", onMove);
|
|
42
|
+
return function () { return window.removeEventListener("resize", onMove); };
|
|
43
|
+
}, [bump]);
|
|
44
|
+
var isPolyline = (draft === null || draft === void 0 ? void 0 : draft.kind) === "polyline";
|
|
45
|
+
var vertexCss = useMemo(function () {
|
|
46
|
+
if (!isPolyline || !(draft === null || draft === void 0 ? void 0 : draft.vertices))
|
|
47
|
+
return [];
|
|
48
|
+
return draft.vertices
|
|
49
|
+
.map(function (vox) { return voxToOverlayPos(nv, vox, draft.axCorSag); })
|
|
50
|
+
.filter(Boolean);
|
|
51
|
+
}, [draft, isPolyline, nv, overlayKey]);
|
|
52
|
+
var freehandCorners = useMemo(function () {
|
|
53
|
+
if (isPolyline || !(draft === null || draft === void 0 ? void 0 : draft.bounds))
|
|
54
|
+
return [];
|
|
55
|
+
return boundsToFreehandCorners(draft.bounds, draft.axCorSag);
|
|
56
|
+
}, [draft, isPolyline, overlayKey]);
|
|
57
|
+
var cornerCss = useMemo(function () {
|
|
58
|
+
if (isPolyline)
|
|
59
|
+
return vertexCss;
|
|
60
|
+
return freehandCorners
|
|
61
|
+
.map(function (vox) { return voxToOverlayPos(nv, vox, draft.axCorSag); })
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
}, [draft === null || draft === void 0 ? void 0 : draft.axCorSag, freehandCorners, isPolyline, nv, overlayKey, vertexCss]);
|
|
64
|
+
var centerCss = useMemo(function () {
|
|
65
|
+
var _a;
|
|
66
|
+
if (!draft)
|
|
67
|
+
return null;
|
|
68
|
+
if (isPolyline && ((_a = draft.vertices) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
69
|
+
var xs = draft.vertices.map(function (v) { return v[0]; });
|
|
70
|
+
var ys = draft.vertices.map(function (v) { return v[1]; });
|
|
71
|
+
var zs = draft.vertices.map(function (v) { return v[2]; });
|
|
72
|
+
return voxToOverlayPos(nv, [
|
|
73
|
+
(Math.min.apply(Math, xs) + Math.max.apply(Math, xs)) / 2,
|
|
74
|
+
(Math.min.apply(Math, ys) + Math.max.apply(Math, ys)) / 2,
|
|
75
|
+
(Math.min.apply(Math, zs) + Math.max.apply(Math, zs)) / 2,
|
|
76
|
+
], draft.axCorSag);
|
|
77
|
+
}
|
|
78
|
+
if (draft.bounds) {
|
|
79
|
+
var b = draft.bounds;
|
|
80
|
+
return voxToOverlayPos(nv, [(b.x1 + b.x2) / 2, (b.y1 + b.y2) / 2, (b.z1 + b.z2) / 2], draft.axCorSag);
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}, [draft, isPolyline, nv, overlayKey]);
|
|
84
|
+
var boxStyle = useMemo(function () {
|
|
85
|
+
if (cornerCss.length < 2)
|
|
86
|
+
return null;
|
|
87
|
+
var xs = cornerCss.map(function (p) { return p.x; });
|
|
88
|
+
var ys = cornerCss.map(function (p) { return p.y; });
|
|
89
|
+
var left = Math.min.apply(Math, xs);
|
|
90
|
+
var top = Math.min.apply(Math, ys);
|
|
91
|
+
var width = Math.max.apply(Math, xs) - left;
|
|
92
|
+
var height = Math.max.apply(Math, ys) - top;
|
|
93
|
+
if (width < 2 && height < 2)
|
|
94
|
+
return null;
|
|
95
|
+
return { left: left, top: top, width: Math.max(width, 2), height: Math.max(height, 2) };
|
|
96
|
+
}, [cornerCss]);
|
|
97
|
+
var applyDraft = useCallback(function (nextDraft) {
|
|
98
|
+
if (nextDraft.kind === "polyline") {
|
|
99
|
+
redrawPolylineDraft(nv, nextDraft);
|
|
100
|
+
syncPolylineDraftToNv(nv, nextDraft);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
redrawFreehandDraft(nv, nextDraft);
|
|
104
|
+
}
|
|
105
|
+
onDraftChange(nextDraft);
|
|
106
|
+
}, [nv, onDraftChange]);
|
|
107
|
+
finishDragRef.current = function () {
|
|
108
|
+
dragRef.current = null;
|
|
109
|
+
if (onPointerMoveRef.current) {
|
|
110
|
+
window.removeEventListener("pointermove", onPointerMoveRef.current);
|
|
111
|
+
}
|
|
112
|
+
if (finishDragRef.current) {
|
|
113
|
+
window.removeEventListener("pointerup", finishDragRef.current);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
onPointerMoveRef.current = function (event) {
|
|
117
|
+
var drag = dragRef.current;
|
|
118
|
+
var current = draftRef.current;
|
|
119
|
+
if (!drag || !current)
|
|
120
|
+
return;
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
if (drag.mode === "move") {
|
|
123
|
+
var canvas = nv.canvas || document.getElementById("niiCanvas");
|
|
124
|
+
if (!canvas)
|
|
125
|
+
return;
|
|
126
|
+
var startCanvas = clientToCanvasPos(canvas, drag.startClientX, drag.startClientY);
|
|
127
|
+
var endCanvas = clientToCanvasPos(canvas, event.clientX, event.clientY);
|
|
128
|
+
var delta = canvasDeltaToVoxDelta(nv, startCanvas, endCanvas);
|
|
129
|
+
if (current.kind === "polyline") {
|
|
130
|
+
applyDraft(__assign(__assign({}, current), { vertices: translatePolylineVertices(drag.startVertices, delta) }));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
applyDraft(translateFreehandDraft(current, delta));
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
var vox = voxUnderClient(nv, event.clientX, event.clientY);
|
|
138
|
+
if (!vox)
|
|
139
|
+
return;
|
|
140
|
+
if (current.kind === "polyline") {
|
|
141
|
+
applyDraft(__assign(__assign({}, current), { vertices: updatePolylineVertex(drag.startVertices, drag.cornerIndex, vox) }));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
applyDraft(resizeFreehandDraft(current, drag.cornerIndex, vox));
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
var startDrag = useCallback(function (event, mode, cornerIndex) {
|
|
148
|
+
var _a, _b;
|
|
149
|
+
if (cornerIndex === void 0) { cornerIndex = -1; }
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
event.stopPropagation();
|
|
152
|
+
dragRef.current = {
|
|
153
|
+
mode: mode,
|
|
154
|
+
cornerIndex: cornerIndex,
|
|
155
|
+
startClientX: event.clientX,
|
|
156
|
+
startClientY: event.clientY,
|
|
157
|
+
startVertices: (_b = (_a = draft.vertices) === null || _a === void 0 ? void 0 : _a.map(function (v) { return __spreadArray([], v, true); })) !== null && _b !== void 0 ? _b : []
|
|
158
|
+
};
|
|
159
|
+
window.addEventListener("pointermove", onPointerMoveRef.current);
|
|
160
|
+
window.addEventListener("pointerup", finishDragRef.current);
|
|
161
|
+
}, [draft.vertices]);
|
|
162
|
+
useEffect(function () { return function () {
|
|
163
|
+
var _a;
|
|
164
|
+
(_a = finishDragRef.current) === null || _a === void 0 ? void 0 : _a.call(finishDragRef);
|
|
165
|
+
}; }, []);
|
|
166
|
+
if (!draft || !boxStyle)
|
|
167
|
+
return null;
|
|
168
|
+
var handleStyle = {
|
|
169
|
+
position: "absolute",
|
|
170
|
+
width: HANDLE_SIZE,
|
|
171
|
+
height: HANDLE_SIZE,
|
|
172
|
+
marginLeft: -HANDLE_SIZE / 2,
|
|
173
|
+
marginTop: -HANDLE_SIZE / 2,
|
|
174
|
+
borderRadius: "50%",
|
|
175
|
+
background: "#fff",
|
|
176
|
+
border: "2px solid ".concat(ACCENT),
|
|
177
|
+
boxSizing: "border-box",
|
|
178
|
+
cursor: "pointer",
|
|
179
|
+
zIndex: 3,
|
|
180
|
+
touchAction: "none",
|
|
181
|
+
pointerEvents: "auto"
|
|
182
|
+
};
|
|
183
|
+
return (_jsxs("div", __assign({ style: {
|
|
184
|
+
position: "absolute",
|
|
185
|
+
inset: 0,
|
|
186
|
+
zIndex: 2,
|
|
187
|
+
pointerEvents: "none",
|
|
188
|
+
overflow: "hidden"
|
|
189
|
+
}, "aria-label": "Adjust pen ROI" }, { children: [_jsx("div", { style: {
|
|
190
|
+
position: "absolute",
|
|
191
|
+
left: boxStyle.left,
|
|
192
|
+
top: boxStyle.top,
|
|
193
|
+
width: boxStyle.width,
|
|
194
|
+
height: boxStyle.height,
|
|
195
|
+
border: "2px dashed ".concat(ACCENT),
|
|
196
|
+
background: "rgba(88, 15, 139, 0.08)",
|
|
197
|
+
boxSizing: "border-box",
|
|
198
|
+
pointerEvents: "none"
|
|
199
|
+
} }), centerCss && (_jsx("div", { role: "presentation", onPointerDown: function (e) { return startDrag(e, "move"); }, style: __assign(__assign({}, handleStyle), { left: centerCss.x, top: centerCss.y, cursor: "move", borderRadius: 2, width: 12, height: 12, marginLeft: -6, marginTop: -6 }), title: "Move shape" })), cornerCss.map(function (pos, i) { return (_jsx("div", { role: "presentation", onPointerDown: function (e) { return startDrag(e, "corner", i); }, style: __assign(__assign({}, handleStyle), { left: pos.x, top: pos.y, cursor: isPolyline ? "grab" : "nwse-resize" }), title: isPolyline ? "Move vertex" : "Resize shape" }, "handle-".concat(i))); })] })));
|
|
200
|
+
}
|
|
201
|
+
export default PenDraftOverlay;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export default function DrawColorPlatte({ expanded, updateDrawPen, setDrawingEnabled, showPenModes, penDrawMode, onPenDrawModeChange, polylineVertexCount,
|
|
1
|
+
export default function DrawColorPlatte({ expanded, updateDrawPen, setDrawingEnabled, showPenModes, penDrawMode, onPenDrawModeChange, polylineVertexCount, penDraftActive, onApplyPenDraft, onCancelPenDraft, onCloseFillPenDraft, brushSize, updateBrushSize, shapeDraftActive, onApplyShapeDraft, onCancelShapeDraft, }: {
|
|
2
2
|
expanded: any;
|
|
3
3
|
updateDrawPen: any;
|
|
4
4
|
setDrawingEnabled: any;
|
|
@@ -6,9 +6,10 @@ export default function DrawColorPlatte({ expanded, updateDrawPen, setDrawingEna
|
|
|
6
6
|
penDrawMode?: string | undefined;
|
|
7
7
|
onPenDrawModeChange: any;
|
|
8
8
|
polylineVertexCount?: number | undefined;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
penDraftActive?: boolean | undefined;
|
|
10
|
+
onApplyPenDraft: any;
|
|
11
|
+
onCancelPenDraft: any;
|
|
12
|
+
onCloseFillPenDraft: any;
|
|
12
13
|
brushSize?: number | undefined;
|
|
13
14
|
updateBrushSize: any;
|
|
14
15
|
shapeDraftActive?: boolean | undefined;
|
|
@@ -11,8 +11,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
* Pen palette adds freehand vs straight-line mode; rectangle/ellipse show Apply/Cancel while adjusting.
|
|
14
|
+
* Pen palette adds freehand vs polyline mode; pen/shape drafts show Apply/Cancel while adjusting.
|
|
16
15
|
*/
|
|
17
16
|
import { Stack, IconButton, Button, Tooltip, Typography } from "@mui/material";
|
|
18
17
|
import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord";
|
|
@@ -38,7 +37,7 @@ var modeBtnSx = function (active) { return ({
|
|
|
38
37
|
px: 0.75
|
|
39
38
|
}); };
|
|
40
39
|
export default function DrawColorPlatte(_a) {
|
|
41
|
-
var expanded = _a.expanded, updateDrawPen = _a.updateDrawPen, setDrawingEnabled = _a.setDrawingEnabled, _b = _a.showPenModes, showPenModes = _b === void 0 ? false : _b, _c = _a.penDrawMode, penDrawMode = _c === void 0 ? "freehand" : _c, onPenDrawModeChange = _a.onPenDrawModeChange, _d = _a.polylineVertexCount, polylineVertexCount = _d === void 0 ? 0 : _d,
|
|
40
|
+
var expanded = _a.expanded, updateDrawPen = _a.updateDrawPen, setDrawingEnabled = _a.setDrawingEnabled, _b = _a.showPenModes, showPenModes = _b === void 0 ? false : _b, _c = _a.penDrawMode, penDrawMode = _c === void 0 ? "freehand" : _c, onPenDrawModeChange = _a.onPenDrawModeChange, _d = _a.polylineVertexCount, polylineVertexCount = _d === void 0 ? 0 : _d, _e = _a.penDraftActive, penDraftActive = _e === void 0 ? false : _e, onApplyPenDraft = _a.onApplyPenDraft, onCancelPenDraft = _a.onCancelPenDraft, onCloseFillPenDraft = _a.onCloseFillPenDraft, _f = _a.brushSize, brushSize = _f === void 0 ? 1 : _f, updateBrushSize = _a.updateBrushSize, _g = _a.shapeDraftActive, shapeDraftActive = _g === void 0 ? false : _g, onApplyShapeDraft = _a.onApplyShapeDraft, onCancelShapeDraft = _a.onCancelShapeDraft;
|
|
42
41
|
return (_jsxs(Stack, __assign({ style: {
|
|
43
42
|
position: "absolute",
|
|
44
43
|
top: "100%",
|
|
@@ -52,10 +51,10 @@ export default function DrawColorPlatte(_a) {
|
|
|
52
51
|
borderTopLeftRadius: "6pt",
|
|
53
52
|
borderTopRightRadius: "6pt",
|
|
54
53
|
background: "#333"
|
|
55
|
-
}, direction: "column", spacing: 0.5, sx: { py: expanded ? 0.5 : 0 } }, { children: [showPenModes && expanded && (_jsxs(Stack, __assign({ direction: "row", alignItems: "center", spacing: 0.5, sx: { px: 0.75, pt: 0.25 } }, { children: [_jsx(Button, __assign({ size: "small", onClick: function () { return onPenDrawModeChange === null || onPenDrawModeChange === void 0 ? void 0 : onPenDrawModeChange("freehand"); }, sx: modeBtnSx(penDrawMode === "freehand") }, { children: "Freehand" })), _jsx(Button, __assign({ size: "small", onClick: function () { return onPenDrawModeChange === null || onPenDrawModeChange === void 0 ? void 0 : onPenDrawModeChange("polyline"); }, sx: modeBtnSx(penDrawMode === "polyline") }, { children: "
|
|
54
|
+
}, direction: "column", spacing: 0.5, sx: { py: expanded ? 0.5 : 0 } }, { children: [showPenModes && expanded && (_jsxs(Stack, __assign({ direction: "row", alignItems: "center", spacing: 0.5, sx: { px: 0.75, pt: 0.25 } }, { children: [_jsx(Button, __assign({ size: "small", onClick: function () { return onPenDrawModeChange === null || onPenDrawModeChange === void 0 ? void 0 : onPenDrawModeChange("freehand"); }, sx: modeBtnSx(penDrawMode === "freehand") }, { children: "Freehand" })), _jsx(Button, __assign({ size: "small", onClick: function () { return onPenDrawModeChange === null || onPenDrawModeChange === void 0 ? void 0 : onPenDrawModeChange("polyline"); }, sx: modeBtnSx(penDrawMode === "polyline") }, { children: "Polyline" }))] }))), showPenModes && expanded && updateBrushSize && (_jsx(BrushSizeSlider, { label: "Line thickness", brushSize: brushSize, updateBrushSize: updateBrushSize })), _jsx(Stack, __assign({ direction: "row" }, { children: FILLED_COLORS.map(function (color, index) { return (_jsx(IconButton, __assign({ onClick: function () {
|
|
56
55
|
updateDrawPen({ target: { value: index + 1 } });
|
|
57
56
|
setDrawingEnabled(true);
|
|
58
|
-
} }, { children: _jsx(FiberManualRecordIcon, { sx: color.sx }) }), index)); }) })), showPenModes && penDrawMode === "polyline" && expanded && polylineVertexCount === 0 && (_jsx(Typography, __assign({ sx: { px: 1, pb: 0.5, fontSize: "0.68rem", color: "#aaa", userSelect: "none" } }, { children: "Click each
|
|
57
|
+
} }, { children: _jsx(FiberManualRecordIcon, { sx: color.sx }) }), index)); }) })), showPenModes && penDrawMode === "polyline" && expanded && polylineVertexCount === 0 && (_jsx(Typography, __assign({ sx: { px: 1, pb: 0.5, fontSize: "0.68rem", color: "#aaa", userSelect: "none" } }, { children: "Click each vertex to draw connected line segments" }))), showPenModes && penDraftActive && expanded && (_jsxs(Stack, __assign({ direction: "row", alignItems: "center", justifyContent: "space-between", sx: { px: 1, py: 0.5, borderTop: "1px solid #555", width: "100%" } }, { children: [_jsx(Tooltip, __assign({ title: "Cancel (Esc)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "cancel pen draft", onClick: function () { return onCancelPenDraft === null || onCancelPenDraft === void 0 ? void 0 : onCancelPenDraft(); }, startIcon: _jsx(CloseIcon, { sx: { fontSize: ACTION_ICON_SIZE } }), sx: {
|
|
59
58
|
color: "#ccc",
|
|
60
59
|
fontSize: ACTION_FONT_SIZE,
|
|
61
60
|
textTransform: "none",
|
|
@@ -63,14 +62,14 @@ export default function DrawColorPlatte(_a) {
|
|
|
63
62
|
py: 0.25,
|
|
64
63
|
px: 0.75,
|
|
65
64
|
"& .MuiButton-startIcon": { mr: 0.5, ml: 0 }
|
|
66
|
-
} }, { children: "Cancel" })) })), _jsxs(Stack, __assign({ direction: "row", alignItems: "center", spacing: 1 }, { children: [polylineVertexCount >= 3 && (_jsx(Tooltip, __assign({ title: "Connect last point to first and fill" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "close and fill polyline", onClick: function () { return
|
|
65
|
+
} }, { children: "Cancel" })) })), _jsxs(Stack, __assign({ direction: "row", alignItems: "center", spacing: 1 }, { children: [penDrawMode === "polyline" && polylineVertexCount >= 3 && (_jsx(Tooltip, __assign({ title: "Connect last point to first and fill" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "close and fill polyline", onClick: function () { return onCloseFillPenDraft === null || onCloseFillPenDraft === void 0 ? void 0 : onCloseFillPenDraft(); }, sx: {
|
|
67
66
|
color: "#c9a0e8",
|
|
68
67
|
fontSize: ACTION_FONT_SIZE,
|
|
69
68
|
textTransform: "none",
|
|
70
69
|
minWidth: 0,
|
|
71
70
|
py: 0.25,
|
|
72
71
|
px: 0.75
|
|
73
|
-
} }, { children: "Close & fill" })) }))), _jsx(Tooltip, __assign({ title: "
|
|
72
|
+
} }, { children: "Close & fill" })) }))), _jsx(Tooltip, __assign({ title: "Apply (Enter)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "apply pen draft", onClick: function () { return onApplyPenDraft === null || onApplyPenDraft === void 0 ? void 0 : onApplyPenDraft(); }, startIcon: _jsx(CheckIcon, { sx: { fontSize: ACTION_ICON_SIZE } }), sx: {
|
|
74
73
|
color: "#c9a0e8",
|
|
75
74
|
fontSize: ACTION_FONT_SIZE,
|
|
76
75
|
textTransform: "none",
|
|
@@ -78,7 +77,7 @@ export default function DrawColorPlatte(_a) {
|
|
|
78
77
|
py: 0.25,
|
|
79
78
|
px: 0.75,
|
|
80
79
|
"& .MuiButton-startIcon": { mr: 0.5, ml: 0 }
|
|
81
|
-
} }, { children: "
|
|
80
|
+
} }, { children: "Apply" })) }))] }))] }))), shapeDraftActive && expanded && (_jsxs(Stack, __assign({ direction: "row", alignItems: "center", justifyContent: "space-between", sx: { px: 1, py: 0.5, borderTop: "1px solid #555", width: "100%" } }, { children: [_jsx(Tooltip, __assign({ title: "Cancel shape (Esc)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "cancel shape", onClick: function () { return onCancelShapeDraft === null || onCancelShapeDraft === void 0 ? void 0 : onCancelShapeDraft(); }, startIcon: _jsx(CloseIcon, { sx: { fontSize: ACTION_ICON_SIZE } }), sx: {
|
|
82
81
|
color: "#ccc",
|
|
83
82
|
fontSize: ACTION_FONT_SIZE,
|
|
84
83
|
textTransform: "none",
|
|
@@ -71,13 +71,15 @@ export function MroDrawToolkit(props) {
|
|
|
71
71
|
var _d = useState(undefined), setMaskColor = _d[1];
|
|
72
72
|
var filled = props.drawPen > 7;
|
|
73
73
|
useEffect(function () {
|
|
74
|
-
if (!props.shapeDraftActive)
|
|
74
|
+
if (!props.shapeDraftActive && !props.penDraftActive)
|
|
75
75
|
return;
|
|
76
76
|
if (drawShapeTool === "rectangle")
|
|
77
77
|
setExpandedOption("r");
|
|
78
78
|
else if (drawShapeTool === "ellipse")
|
|
79
79
|
setExpandedOption("l");
|
|
80
|
-
|
|
80
|
+
else if (drawShapeTool === "pen")
|
|
81
|
+
setExpandedOption("d");
|
|
82
|
+
}, [props.shapeDraftActive, props.penDraftActive, drawShapeTool]);
|
|
81
83
|
var shapeSelectedSx = function (shape) {
|
|
82
84
|
return drawShapeTool === shape
|
|
83
85
|
? { backgroundColor: "rgba(88, 15, 139, 0.12)", color: "#580f8b" }
|
|
@@ -149,7 +151,7 @@ export function MroDrawToolkit(props) {
|
|
|
149
151
|
var _a;
|
|
150
152
|
if (clickTargetIsNiivueCanvas(event.target))
|
|
151
153
|
return;
|
|
152
|
-
if (props.shapeDraftActive)
|
|
154
|
+
if (props.shapeDraftActive || props.penDraftActive)
|
|
153
155
|
return;
|
|
154
156
|
setExpandedOption("n");
|
|
155
157
|
setExpandOpacityOptions(false);
|
|
@@ -170,7 +172,7 @@ export function MroDrawToolkit(props) {
|
|
|
170
172
|
alignItems: "center",
|
|
171
173
|
gap: 4,
|
|
172
174
|
overflow: "visible"
|
|
173
|
-
} }, { children: [_jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "d" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Pen" }, { children: _jsx(IconButton, __assign({ "aria-label": "pen", size: "small", onClick: clickPen, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("pen")) }, { children: _jsx(DrawIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "d", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, showPenModes: true, penDrawMode: props.penDrawMode, onPenDrawModeChange: props.onPenDrawModeChange, polylineVertexCount: props.polylineVertexCount, onCancelPolyline: props.onCancelPolyline,
|
|
175
|
+
} }, { children: [_jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "d" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Pen" }, { children: _jsx(IconButton, __assign({ "aria-label": "pen", size: "small", onClick: clickPen, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("pen")) }, { children: _jsx(DrawIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "d", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, showPenModes: true, penDrawMode: props.penDrawMode, onPenDrawModeChange: props.onPenDrawModeChange, polylineVertexCount: props.polylineVertexCount, onCancelPolyline: props.onCancelPolyline, penDraftActive: props.penDraftActive, onApplyPenDraft: props.onApplyPenDraft, onCancelPenDraft: props.onCancelPenDraft, onCloseFillPenDraft: props.onCloseFillPenDraft, brushSize: props.brushSize, updateBrushSize: props.updateBrushSize })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "r" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Rectangle" }, { children: _jsx(IconButton, __assign({ "aria-label": "rectangle", size: "small", onClick: clickRectangle, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("rectangle")) }, { children: _jsx(CropSquareOutlinedIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "r", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, shapeDraftActive: props.shapeDraftActive && drawShapeTool === "rectangle", onApplyShapeDraft: props.onApplyShapeDraft, onCancelShapeDraft: props.onCancelShapeDraft })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "l" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Ellipse" }, { children: _jsx(IconButton, __assign({ "aria-label": "ellipse", size: "small", onClick: clickEllipse, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("ellipse")) }, { children: _jsx(CircleOutlinedIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "l", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, shapeDraftActive: props.shapeDraftActive && drawShapeTool === "ellipse", onApplyShapeDraft: props.onApplyShapeDraft, onCancelShapeDraft: props.onCancelShapeDraft })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "e" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Eraser" }, { children: _jsx(IconButton, __assign({ "aria-label": "erase", size: "small", onClick: clickEraser, sx: toolBtnSx }, { children: filled || expandedOption !== "e" ? (_jsx(EraserIcon, {})) : (_jsx(AutoFixNormalOutlinedIcon, { sx: { color: ICON_COLOR } })) })) })), _jsx(EraserPlatte, { expandEraseOptions: expandedOption === "e", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, brushSize: props.brushSize, updateBrushSize: props.updateBrushSize })] })), _jsx(Tooltip, __assign({ title: "Undo" }, { children: _jsx(IconButton, __assign({ "aria-label": "revert", size: "small", onClick: function () { return props.drawUndo(); }, sx: toolBtnSx }, { children: _jsx(ReplyIcon, { sx: { color: ICON_COLOR } }) })) })), _jsx(Tooltip, __assign({ title: "Save screenshot" }, { children: _jsx("span", { children: _jsx(IconButton, __assign({ "aria-label": "capture", size: "small", disabled: !vol, onClick: function () { return vol && props.nv.saveScene("".concat(vol.name, "_drawing.png")); }, sx: toolBtnSx }, { children: _jsx(CameraAltIcon, { sx: { color: ICON_COLOR } }) })) }) })), _jsx(Tooltip, __assign({ title: "Clear drawing" }, { children: _jsx(IconButton, __assign({ "aria-label": "delete", size: "small", onClick: function () {
|
|
174
176
|
props.nv.clearDrawing();
|
|
175
177
|
props.resampleImage();
|
|
176
178
|
props.setDrawingChanged(false);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** @typedef {'polyline' | 'freehand'} PenDraftKind */
|
|
2
|
+
/**
|
|
3
|
+
* @typedef {Object} PenDraft
|
|
4
|
+
* @property {PenDraftKind} kind
|
|
5
|
+
* @property {Uint8Array} baseBitmap
|
|
6
|
+
* @property {number} axCorSag
|
|
7
|
+
* @property {number} penValue
|
|
8
|
+
* @property {[number, number, number][]} [vertices]
|
|
9
|
+
* @property {[number, number, number][]} [strokeVoxels]
|
|
10
|
+
* @property {{ x1: number, y1: number, x2: number, y2: number, z1: number, z2: number }} [bounds]
|
|
11
|
+
*/
|
|
12
|
+
export function isFreehandPenActive(nv: any): any;
|
|
13
|
+
export function shouldDeferFreehandCommit(nv: any): any;
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} PenDraft
|
|
16
|
+
* @property {PenDraftKind} kind
|
|
17
|
+
* @property {Uint8Array} baseBitmap
|
|
18
|
+
* @property {number} axCorSag
|
|
19
|
+
* @property {number} penValue
|
|
20
|
+
* @property {[number, number, number][]} [vertices]
|
|
21
|
+
* @property {[number, number, number][]} [strokeVoxels]
|
|
22
|
+
* @property {{ x1: number, y1: number, x2: number, y2: number, z1: number, z2: number }} [bounds]
|
|
23
|
+
*/
|
|
24
|
+
export function redrawPolylineDraft(nv: any, draft: any): void;
|
|
25
|
+
export function translatePolylineVertices(vertices: any, delta: any): any;
|
|
26
|
+
export function updatePolylineVertex(vertices: any, index: any, newVox: any): any;
|
|
27
|
+
export function syncPolylineDraftToNv(nv: any, draft: any): void;
|
|
28
|
+
export function captureFreehandDraft(nv: any, sessionStartBitmap: any, axCorSag: any): {
|
|
29
|
+
kind: string;
|
|
30
|
+
baseBitmap: Uint8Array;
|
|
31
|
+
axCorSag: any;
|
|
32
|
+
penValue: any;
|
|
33
|
+
strokeVoxels: number[][];
|
|
34
|
+
bounds: {
|
|
35
|
+
x1: number;
|
|
36
|
+
y1: number;
|
|
37
|
+
z1: number;
|
|
38
|
+
x2: number;
|
|
39
|
+
y2: number;
|
|
40
|
+
z2: number;
|
|
41
|
+
};
|
|
42
|
+
} | null;
|
|
43
|
+
export function redrawFreehandDraft(nv: any, draft: any): void;
|
|
44
|
+
export function translateFreehandDraft(draft: any, delta: any): any;
|
|
45
|
+
export function resizeFreehandDraft(draft: any, cornerIndex: any, newVox: any): any;
|
|
46
|
+
export function boundsToFreehandCorners(bounds: any, axCorSag: any): any[][];
|
|
47
|
+
export function polylineDraftFromNv(nv: any): {
|
|
48
|
+
kind: string;
|
|
49
|
+
vertices: any;
|
|
50
|
+
baseBitmap: Uint8Array;
|
|
51
|
+
axCorSag: any;
|
|
52
|
+
penValue: any;
|
|
53
|
+
} | null;
|
|
54
|
+
export function applyPenDraft(nv: any, draft: any, { fillClosed }?: {
|
|
55
|
+
fillClosed?: boolean | undefined;
|
|
56
|
+
}): void;
|
|
57
|
+
export function cancelPenDraft(nv: any, draft: any): void;
|
|
58
|
+
export type PenDraftKind = 'polyline' | 'freehand';
|
|
59
|
+
export type PenDraft = {
|
|
60
|
+
kind: PenDraftKind;
|
|
61
|
+
baseBitmap: Uint8Array;
|
|
62
|
+
axCorSag: number;
|
|
63
|
+
penValue: number;
|
|
64
|
+
vertices?: [number, number, number][] | undefined;
|
|
65
|
+
strokeVoxels?: [number, number, number][] | undefined;
|
|
66
|
+
bounds?: {
|
|
67
|
+
x1: number;
|
|
68
|
+
y1: number;
|
|
69
|
+
x2: number;
|
|
70
|
+
y2: number;
|
|
71
|
+
z1: number;
|
|
72
|
+
z2: number;
|
|
73
|
+
} | undefined;
|
|
74
|
+
};
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
13
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
14
|
+
if (ar || !(i in from)) {
|
|
15
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
16
|
+
ar[i] = from[i];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
20
|
+
};
|
|
21
|
+
import { translatePt } from "./shapeDraftUtils";
|
|
22
|
+
import { NI_PEN_TYPE } from "./niivuePenType";
|
|
23
|
+
/** @typedef {'polyline' | 'freehand'} PenDraftKind */
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {Object} PenDraft
|
|
26
|
+
* @property {PenDraftKind} kind
|
|
27
|
+
* @property {Uint8Array} baseBitmap
|
|
28
|
+
* @property {number} axCorSag
|
|
29
|
+
* @property {number} penValue
|
|
30
|
+
* @property {[number, number, number][]} [vertices]
|
|
31
|
+
* @property {[number, number, number][]} [strokeVoxels]
|
|
32
|
+
* @property {{ x1: number, y1: number, x2: number, y2: number, z1: number, z2: number }} [bounds]
|
|
33
|
+
*/
|
|
34
|
+
export function isFreehandPenActive(nv) {
|
|
35
|
+
return (nv.opts.isFilledPen &&
|
|
36
|
+
nv.opts.drawingEnabled &&
|
|
37
|
+
nv.opts.penType === NI_PEN_TYPE.PEN &&
|
|
38
|
+
!nv.opts.polylinePenMode);
|
|
39
|
+
}
|
|
40
|
+
export function shouldDeferFreehandCommit(nv) {
|
|
41
|
+
return !!nv.opts.deferFreehandCommit && isFreehandPenActive(nv);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {Object} PenDraft
|
|
45
|
+
* @property {PenDraftKind} kind
|
|
46
|
+
* @property {Uint8Array} baseBitmap
|
|
47
|
+
* @property {number} axCorSag
|
|
48
|
+
* @property {number} penValue
|
|
49
|
+
* @property {[number, number, number][]} [vertices]
|
|
50
|
+
* @property {[number, number, number][]} [strokeVoxels]
|
|
51
|
+
* @property {{ x1: number, y1: number, x2: number, y2: number, z1: number, z2: number }} [bounds]
|
|
52
|
+
*/
|
|
53
|
+
export function redrawPolylineDraft(nv, draft) {
|
|
54
|
+
var _a;
|
|
55
|
+
if (!((_a = draft === null || draft === void 0 ? void 0 : draft.vertices) === null || _a === void 0 ? void 0 : _a.length) || !draft.baseBitmap)
|
|
56
|
+
return;
|
|
57
|
+
nv.drawBitmap.set(draft.baseBitmap);
|
|
58
|
+
nv.drawPenAxCorSag = draft.axCorSag;
|
|
59
|
+
for (var i = 1; i < draft.vertices.length; i++) {
|
|
60
|
+
nv.drawPenLine(draft.vertices[i], draft.vertices[i - 1], draft.penValue);
|
|
61
|
+
}
|
|
62
|
+
nv.refreshDrawing(false, false);
|
|
63
|
+
nv.drawScene();
|
|
64
|
+
}
|
|
65
|
+
export function translatePolylineVertices(vertices, delta) {
|
|
66
|
+
return vertices.map(function (v) { return translatePt(v, delta); });
|
|
67
|
+
}
|
|
68
|
+
export function updatePolylineVertex(vertices, index, newVox) {
|
|
69
|
+
var next = vertices.map(function (v) { return __spreadArray([], v, true); });
|
|
70
|
+
next[index] = __spreadArray([], newVox, true);
|
|
71
|
+
return next;
|
|
72
|
+
}
|
|
73
|
+
export function syncPolylineDraftToNv(nv, draft) {
|
|
74
|
+
nv._cloudMrPolylineVertices = draft.vertices.map(function (v) { return __spreadArray([], v, true); });
|
|
75
|
+
if (nv.drawBitmap) {
|
|
76
|
+
nv._cloudMrPolylineBaseBitmap = nv.drawBitmap.slice();
|
|
77
|
+
}
|
|
78
|
+
nv._cloudMrPolylineAxCorSag = draft.axCorSag;
|
|
79
|
+
}
|
|
80
|
+
export function captureFreehandDraft(nv, sessionStartBitmap, axCorSag) {
|
|
81
|
+
var _a;
|
|
82
|
+
if (!nv.drawBitmap || !sessionStartBitmap)
|
|
83
|
+
return null;
|
|
84
|
+
var penValue = nv.opts.penValue;
|
|
85
|
+
var dims = (_a = nv.back) === null || _a === void 0 ? void 0 : _a.dims;
|
|
86
|
+
if (!dims)
|
|
87
|
+
return null;
|
|
88
|
+
var strokeVoxels = [];
|
|
89
|
+
for (var i = 0; i < nv.drawBitmap.length; i++) {
|
|
90
|
+
if (nv.drawBitmap[i] === penValue && sessionStartBitmap[i] !== penValue) {
|
|
91
|
+
var z = Math.floor(i / (dims[1] * dims[2]));
|
|
92
|
+
var rem = i - z * dims[1] * dims[2];
|
|
93
|
+
var y = Math.floor(rem / dims[1]);
|
|
94
|
+
var x = rem % dims[1];
|
|
95
|
+
strokeVoxels.push([x, y, z]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (strokeVoxels.length === 0)
|
|
99
|
+
return null;
|
|
100
|
+
var x1 = Infinity;
|
|
101
|
+
var y1 = Infinity;
|
|
102
|
+
var z1 = Infinity;
|
|
103
|
+
var x2 = -Infinity;
|
|
104
|
+
var y2 = -Infinity;
|
|
105
|
+
var z2 = -Infinity;
|
|
106
|
+
for (var _i = 0, strokeVoxels_1 = strokeVoxels; _i < strokeVoxels_1.length; _i++) {
|
|
107
|
+
var _b = strokeVoxels_1[_i], x = _b[0], y = _b[1], z = _b[2];
|
|
108
|
+
x1 = Math.min(x1, x);
|
|
109
|
+
y1 = Math.min(y1, y);
|
|
110
|
+
z1 = Math.min(z1, z);
|
|
111
|
+
x2 = Math.max(x2, x);
|
|
112
|
+
y2 = Math.max(y2, y);
|
|
113
|
+
z2 = Math.max(z2, z);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
kind: "freehand",
|
|
117
|
+
baseBitmap: new Uint8Array(sessionStartBitmap),
|
|
118
|
+
axCorSag: axCorSag,
|
|
119
|
+
penValue: penValue,
|
|
120
|
+
strokeVoxels: strokeVoxels,
|
|
121
|
+
bounds: { x1: x1, y1: y1, z1: z1, x2: x2, y2: y2, z2: z2 }
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export function redrawFreehandDraft(nv, draft) {
|
|
125
|
+
var _a;
|
|
126
|
+
if (!((_a = draft === null || draft === void 0 ? void 0 : draft.strokeVoxels) === null || _a === void 0 ? void 0 : _a.length) || !draft.baseBitmap)
|
|
127
|
+
return;
|
|
128
|
+
nv.drawBitmap.set(draft.baseBitmap);
|
|
129
|
+
for (var _i = 0, _b = draft.strokeVoxels; _i < _b.length; _i++) {
|
|
130
|
+
var _c = _b[_i], x = _c[0], y = _c[1], z = _c[2];
|
|
131
|
+
nv.drawPt(x, y, z, draft.penValue);
|
|
132
|
+
}
|
|
133
|
+
nv.refreshDrawing(false, false);
|
|
134
|
+
nv.drawScene();
|
|
135
|
+
}
|
|
136
|
+
export function translateFreehandDraft(draft, delta) {
|
|
137
|
+
return __assign(__assign({}, draft), { strokeVoxels: draft.strokeVoxels.map(function (v) { return translatePt(v, delta); }), bounds: draft.bounds
|
|
138
|
+
? {
|
|
139
|
+
x1: draft.bounds.x1 + delta[0],
|
|
140
|
+
y1: draft.bounds.y1 + delta[1],
|
|
141
|
+
z1: draft.bounds.z1 + delta[2],
|
|
142
|
+
x2: draft.bounds.x2 + delta[0],
|
|
143
|
+
y2: draft.bounds.y2 + delta[1],
|
|
144
|
+
z2: draft.bounds.z2 + delta[2]
|
|
145
|
+
}
|
|
146
|
+
: draft.bounds });
|
|
147
|
+
}
|
|
148
|
+
export function resizeFreehandDraft(draft, cornerIndex, newVox) {
|
|
149
|
+
if (!draft.bounds)
|
|
150
|
+
return draft;
|
|
151
|
+
var axCorSag = draft.axCorSag;
|
|
152
|
+
var b = __assign({}, draft.bounds);
|
|
153
|
+
var corners = boundsToFreehandCorners(b, axCorSag);
|
|
154
|
+
corners[cornerIndex] = __spreadArray([], newVox, true);
|
|
155
|
+
var xs = corners.map(function (c) { return c[0]; });
|
|
156
|
+
var ys = corners.map(function (c) { return c[1]; });
|
|
157
|
+
var zs = corners.map(function (c) { return c[2]; });
|
|
158
|
+
var nextBounds = {
|
|
159
|
+
x1: Math.min.apply(Math, xs),
|
|
160
|
+
y1: Math.min.apply(Math, ys),
|
|
161
|
+
z1: Math.min.apply(Math, zs),
|
|
162
|
+
x2: Math.max.apply(Math, xs),
|
|
163
|
+
y2: Math.max.apply(Math, ys),
|
|
164
|
+
z2: Math.max.apply(Math, zs)
|
|
165
|
+
};
|
|
166
|
+
var oldW = Math.max(1, b.x2 - b.x1);
|
|
167
|
+
var oldH = Math.max(1, b.y2 - b.y1);
|
|
168
|
+
var newW = Math.max(1, nextBounds.x2 - nextBounds.x1);
|
|
169
|
+
var newH = Math.max(1, nextBounds.y2 - nextBounds.y1);
|
|
170
|
+
var scaled = draft.strokeVoxels.map(function (v) {
|
|
171
|
+
var relH = (v[0] - b.x1) / oldW;
|
|
172
|
+
var relV = (v[1] - b.y1) / oldH;
|
|
173
|
+
if (axCorSag === 0) {
|
|
174
|
+
return [
|
|
175
|
+
Math.round(nextBounds.x1 + relH * newW),
|
|
176
|
+
Math.round(nextBounds.y1 + relV * newH),
|
|
177
|
+
v[2],
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
if (axCorSag === 1) {
|
|
181
|
+
return [
|
|
182
|
+
Math.round(nextBounds.x1 + relH * newW),
|
|
183
|
+
v[1],
|
|
184
|
+
Math.round(nextBounds.y1 + relV * newH),
|
|
185
|
+
];
|
|
186
|
+
}
|
|
187
|
+
return [
|
|
188
|
+
v[0],
|
|
189
|
+
Math.round(nextBounds.x1 + relH * newW),
|
|
190
|
+
Math.round(nextBounds.y1 + relV * newH),
|
|
191
|
+
];
|
|
192
|
+
});
|
|
193
|
+
return __assign(__assign({}, draft), { strokeVoxels: scaled, bounds: nextBounds });
|
|
194
|
+
}
|
|
195
|
+
export function boundsToFreehandCorners(bounds, axCorSag) {
|
|
196
|
+
var x1 = bounds.x1, y1 = bounds.y1, z1 = bounds.z1, x2 = bounds.x2, y2 = bounds.y2, z2 = bounds.z2;
|
|
197
|
+
if (axCorSag === 0) {
|
|
198
|
+
var z = Math.round((z1 + z2) / 2);
|
|
199
|
+
return [
|
|
200
|
+
[x1, y1, z],
|
|
201
|
+
[x2, y1, z],
|
|
202
|
+
[x1, y2, z],
|
|
203
|
+
[x2, y2, z],
|
|
204
|
+
];
|
|
205
|
+
}
|
|
206
|
+
if (axCorSag === 1) {
|
|
207
|
+
var y = Math.round((y1 + y2) / 2);
|
|
208
|
+
return [
|
|
209
|
+
[x1, y, z1],
|
|
210
|
+
[x2, y, z1],
|
|
211
|
+
[x1, y, z2],
|
|
212
|
+
[x2, y, z2],
|
|
213
|
+
];
|
|
214
|
+
}
|
|
215
|
+
var x = Math.round((x1 + x2) / 2);
|
|
216
|
+
return [
|
|
217
|
+
[x, y1, z1],
|
|
218
|
+
[x, y2, z1],
|
|
219
|
+
[x, y1, z2],
|
|
220
|
+
[x, y2, z2],
|
|
221
|
+
];
|
|
222
|
+
}
|
|
223
|
+
export function polylineDraftFromNv(nv) {
|
|
224
|
+
var vertices = nv._cloudMrPolylineVertices;
|
|
225
|
+
var baseBitmap = nv._cloudMrPolylineSessionStartBitmap;
|
|
226
|
+
if (!(vertices === null || vertices === void 0 ? void 0 : vertices.length) || vertices.length < 2 || !baseBitmap)
|
|
227
|
+
return null;
|
|
228
|
+
return {
|
|
229
|
+
kind: "polyline",
|
|
230
|
+
vertices: vertices.map(function (v) { return __spreadArray([], v, true); }),
|
|
231
|
+
baseBitmap: new Uint8Array(baseBitmap),
|
|
232
|
+
axCorSag: nv._cloudMrPolylineAxCorSag,
|
|
233
|
+
penValue: nv.opts.penValue
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
export function applyPenDraft(nv, draft, _a) {
|
|
237
|
+
var _b = _a === void 0 ? {} : _a, _c = _b.fillClosed, fillClosed = _c === void 0 ? false : _c;
|
|
238
|
+
if (draft.kind === "polyline") {
|
|
239
|
+
redrawPolylineDraft(nv, draft);
|
|
240
|
+
if (fillClosed && draft.vertices.length >= 3) {
|
|
241
|
+
nv.drawPenAxCorSag = draft.axCorSag;
|
|
242
|
+
nv.drawPenLine(draft.vertices[0], draft.vertices[draft.vertices.length - 1], draft.penValue);
|
|
243
|
+
nv.drawPenFillPts = draft.vertices.map(function (v) { return __spreadArray([], v, true); });
|
|
244
|
+
nv.drawPenFilled();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
redrawFreehandDraft(nv, draft);
|
|
249
|
+
}
|
|
250
|
+
nv.drawAddUndoBitmap(nv.drawFillOverwrites);
|
|
251
|
+
if (typeof nv.onDrawingChanged === "function") {
|
|
252
|
+
nv.onDrawingChanged("draw");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
export function cancelPenDraft(nv, draft) {
|
|
256
|
+
if (draft === null || draft === void 0 ? void 0 : draft.baseBitmap) {
|
|
257
|
+
nv.drawBitmap.set(draft.baseBitmap);
|
|
258
|
+
nv.refreshDrawing(true, false);
|
|
259
|
+
nv.drawScene();
|
|
260
|
+
}
|
|
261
|
+
}
|