copper3d 3.4.8 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Loader/copperDicomLoader.d.ts +7 -1
- package/dist/Loader/copperDicomLoader.js +45 -0
- package/dist/Loader/copperDicomLoader.js.map +1 -1
- package/dist/Renderer/baseRenderer.d.ts +3 -0
- package/dist/Renderer/baseRenderer.js +20 -0
- package/dist/Renderer/baseRenderer.js.map +1 -1
- package/dist/Renderer/copperMSceneRenderer.d.ts +3 -0
- package/dist/Renderer/copperMSceneRenderer.js +22 -0
- package/dist/Renderer/copperMSceneRenderer.js.map +1 -1
- package/dist/Renderer/copperRenderer.js +2 -0
- package/dist/Renderer/copperRenderer.js.map +1 -1
- package/dist/Scene/copperScene.d.ts +8 -3
- package/dist/Scene/copperScene.js +173 -34
- package/dist/Scene/copperScene.js.map +1 -1
- package/dist/Utils/segmentation/DrawToolCore.d.ts +3 -0
- package/dist/Utils/segmentation/DrawToolCore.js +29 -1
- package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
- package/dist/Utils/segmentation/NrrdTools.d.ts +54 -0
- package/dist/Utils/segmentation/NrrdTools.js +119 -0
- package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
- package/dist/Utils/segmentation/core/index.d.ts +1 -1
- package/dist/Utils/segmentation/core/index.js +1 -1
- package/dist/Utils/segmentation/core/index.js.map +1 -1
- package/dist/Utils/segmentation/core/types.d.ts +11 -1
- package/dist/Utils/segmentation/core/types.js +30 -0
- package/dist/Utils/segmentation/core/types.js.map +1 -1
- package/dist/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -0
- package/dist/Utils/segmentation/eventRouter/EventRouter.js +37 -6
- package/dist/Utils/segmentation/eventRouter/EventRouter.js.map +1 -1
- package/dist/Utils/segmentation/eventRouter/types.d.ts +3 -2
- package/dist/Utils/segmentation/tools/AiAssistTool.d.ts +146 -0
- package/dist/Utils/segmentation/tools/AiAssistTool.js +470 -0
- package/dist/Utils/segmentation/tools/AiAssistTool.js.map +1 -0
- package/dist/Utils/texture2d.d.ts +8 -6
- package/dist/Utils/texture2d.js +30 -37
- package/dist/Utils/texture2d.js.map +1 -1
- package/dist/bundle.esm.js +975 -557
- package/dist/bundle.umd.js +976 -556
- package/dist/index.d.ts +6 -5
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/types/Loader/copperDicomLoader.d.ts +7 -1
- package/dist/types/Renderer/baseRenderer.d.ts +3 -0
- package/dist/types/Renderer/copperMSceneRenderer.d.ts +3 -0
- package/dist/types/Scene/copperScene.d.ts +8 -3
- package/dist/types/Utils/segmentation/DrawToolCore.d.ts +3 -0
- package/dist/types/Utils/segmentation/NrrdTools.d.ts +54 -0
- package/dist/types/Utils/segmentation/core/index.d.ts +1 -1
- package/dist/types/Utils/segmentation/core/types.d.ts +11 -1
- package/dist/types/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -0
- package/dist/types/Utils/segmentation/eventRouter/types.d.ts +3 -2
- package/dist/types/Utils/segmentation/tools/AiAssistTool.d.ts +146 -0
- package/dist/types/Utils/texture2d.d.ts +8 -6
- package/dist/types/index.d.ts +6 -5
- package/dist/types/types/types.d.ts +43 -1
- package/dist/types/types.d.ts +43 -1
- package/package.json +1 -1
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AiAssistTool — interactive prompt-based segmentation (experimental).
|
|
3
|
+
*
|
|
4
|
+
* The clinician left-clicks foreground / background points (or drags a box /
|
|
5
|
+
* scribbles) on the current slice; a backend model returns a region mask that
|
|
6
|
+
* is written into an INDEPENDENT scratch MaskVolume (`aiAssistMaskVolume`,
|
|
7
|
+
* registered as `maskData.volumes['aiScratch']`) — never the validated layers.
|
|
8
|
+
*
|
|
9
|
+
* Network lives in the app layer: this tool only (a) maps screen → voxel-slice
|
|
10
|
+
* coordinates, (b) accumulates the prompt for the current slice, (c) fires
|
|
11
|
+
* `onPrompt` so the app can call the backend, and (d) applies the returned mask
|
|
12
|
+
* via `applyMask`. The app's `useAiAssist` composable wires (c)→(d).
|
|
13
|
+
*
|
|
14
|
+
* Sandbox: snapshot on enter (`snapshot`), then on exit either `discard`
|
|
15
|
+
* (restore snapshot) or merge is handled by NrrdTools (clone + pushGroup).
|
|
16
|
+
*
|
|
17
|
+
* Coordinate mapping supports all three views (axial/sagittal/coronal); it
|
|
18
|
+
* inverts the per-axis display transform of RenderingUtils.renderSliceToCanvas
|
|
19
|
+
* (only coronal 'y' is vertically flipped). Merge captures painted voxels from
|
|
20
|
+
* any view (the scratch is a full 3D volume).
|
|
21
|
+
*/
|
|
22
|
+
import { BaseTool } from "./BaseTool";
|
|
23
|
+
import { MaskVolume, AI_MASK_CHANNEL_COLORS } from "../core";
|
|
24
|
+
/** Scratch volume key in maskData.volumes — kept OUT of image.layers so
|
|
25
|
+
* compositeAllLayers ignores it (we render it ourselves in start()). */
|
|
26
|
+
export const AI_SCRATCH_LAYER = "aiScratch";
|
|
27
|
+
export class AiAssistTool extends BaseTool {
|
|
28
|
+
constructor(ctx, host) {
|
|
29
|
+
super(ctx);
|
|
30
|
+
/** Independent scratch volume (also registered at maskData.volumes['aiScratch']). */
|
|
31
|
+
this.scratchVol = null;
|
|
32
|
+
/** Snapshot of the scratch buffer taken on enter (for discard). */
|
|
33
|
+
this.snapshotData = null;
|
|
34
|
+
/** Frozen regions ("New region" commits here). Pixels recorded here survive a
|
|
35
|
+
* later re-prediction — even on the SAME channel — so multiple separate regions
|
|
36
|
+
* can be drawn without the newest prediction wiping the previous ones. Null =
|
|
37
|
+
* nothing frozen yet (applySliceRle then behaves as a single live region). */
|
|
38
|
+
this.committedVol = null;
|
|
39
|
+
this.promptTool = "point";
|
|
40
|
+
this.polarity = 1; // 1 = foreground (positive), 0 = background
|
|
41
|
+
/** Target channel/label (1-8) the AI paints into — the "AI layer" channel. */
|
|
42
|
+
this.channel = 1;
|
|
43
|
+
/** Scribble brush radius (px), user-adjustable via slider. */
|
|
44
|
+
this.scribbleSize = 5;
|
|
45
|
+
/** Accumulated prompts for the CURRENT slice; reset on slice/axis change. */
|
|
46
|
+
this.points = [];
|
|
47
|
+
this.scribble = [];
|
|
48
|
+
this.activeSlice = -1;
|
|
49
|
+
// Drag state (box / scribble) — voxel coords for the prompt
|
|
50
|
+
this.dragging = false;
|
|
51
|
+
this.dragStart = null;
|
|
52
|
+
// Screen-space (display px) copies for the LIVE preview drawn each frame.
|
|
53
|
+
this.dragScreenStart = null;
|
|
54
|
+
this.dragScreen = null;
|
|
55
|
+
this.screenScribble = [];
|
|
56
|
+
// Live cursor position (screen px) for the scribble brush-size preview ring —
|
|
57
|
+
// updated on every hover move so the ring follows the mouse like the paint brush.
|
|
58
|
+
this.hoverScreen = null;
|
|
59
|
+
/** Fired when a prompt gesture completes — app calls backend, then applyMask(). */
|
|
60
|
+
this.onPrompt = null;
|
|
61
|
+
this.host = host;
|
|
62
|
+
}
|
|
63
|
+
// ── Configuration (driven from the panel via NrrdTools) ────────────────────
|
|
64
|
+
setPromptTool(tool) {
|
|
65
|
+
// Switching tool starts a clean gesture — drop any stale points/box/scribble
|
|
66
|
+
// and drag state so the next click behaves predictably.
|
|
67
|
+
if (tool !== this.promptTool) {
|
|
68
|
+
this.resetPrompts();
|
|
69
|
+
this.dragging = false;
|
|
70
|
+
this.dragStart = null;
|
|
71
|
+
}
|
|
72
|
+
this.promptTool = tool;
|
|
73
|
+
}
|
|
74
|
+
setPolarity(label) { this.polarity = label === 0 ? 0 : 1; }
|
|
75
|
+
setScribbleSize(size) {
|
|
76
|
+
this.scribbleSize = Math.max(1, Math.min(40, Math.round(size)));
|
|
77
|
+
}
|
|
78
|
+
setChannel(channel) {
|
|
79
|
+
const c = Math.max(1, Math.min(8, Math.round(channel)));
|
|
80
|
+
// Changing channel starts a NEW region in the new colour — otherwise the
|
|
81
|
+
// accumulated points would be re-predicted and repainted in the new label,
|
|
82
|
+
// recolouring the previous channel's region.
|
|
83
|
+
if (c !== this.channel)
|
|
84
|
+
this.resetPrompts();
|
|
85
|
+
this.channel = c;
|
|
86
|
+
}
|
|
87
|
+
getChannel() { return this.channel; }
|
|
88
|
+
getScratchVolume() { return this.scratchVol; }
|
|
89
|
+
/** Serialize the scratch volume as per-z-slice RLE (only NON-empty slices),
|
|
90
|
+
* for persisting to ai_generated_nii_LPS on the backend. Binary (any channel →
|
|
91
|
+
* 1); RLE is alternating run lengths starting with a 0-run — the exact format
|
|
92
|
+
* the backend's rle_decode expects. Uses getSliceUint8 (the same path the
|
|
93
|
+
* clinician layer's /api/mask/replace uses) so orientation matches. */
|
|
94
|
+
getScratchSlices() {
|
|
95
|
+
if (!this.scratchVol)
|
|
96
|
+
return null;
|
|
97
|
+
const { depth } = this.scratchVol.getDimensions();
|
|
98
|
+
const out = [];
|
|
99
|
+
let width = 0;
|
|
100
|
+
let height = 0;
|
|
101
|
+
for (let z = 0; z < depth; z++) {
|
|
102
|
+
const { data, width: w, height: h } = this.scratchVol.getSliceUint8(z, "z");
|
|
103
|
+
width = w;
|
|
104
|
+
height = h;
|
|
105
|
+
// RLE-encode (binarized) in one pass; skip fully-empty slices.
|
|
106
|
+
const runs = [];
|
|
107
|
+
let value = 0; // always begin with a 0-run (matches backend rle_encode)
|
|
108
|
+
let count = 0;
|
|
109
|
+
let any = false;
|
|
110
|
+
for (let i = 0; i < data.length; i++) {
|
|
111
|
+
const v = data[i] !== 0 ? 1 : 0;
|
|
112
|
+
if (v)
|
|
113
|
+
any = true;
|
|
114
|
+
if (v === value) {
|
|
115
|
+
count++;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
runs.push(count);
|
|
119
|
+
value = v;
|
|
120
|
+
count = 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
runs.push(count);
|
|
124
|
+
if (any)
|
|
125
|
+
out.push({ sliceIndex: z, rle: runs });
|
|
126
|
+
}
|
|
127
|
+
return { axis: "z", width, height, slices: out };
|
|
128
|
+
}
|
|
129
|
+
// ── Sandbox lifecycle ──────────────────────────────────────────────────────
|
|
130
|
+
/** Create (or reuse) the scratch volume sized to the layer grid and register
|
|
131
|
+
* it under maskData.volumes['aiScratch']. Snapshots the empty buffer. */
|
|
132
|
+
enter() {
|
|
133
|
+
const volumes = this.ctx.protectedData.maskData.volumes;
|
|
134
|
+
const baseId = this.ctx.nrrd_states.image.layers[0];
|
|
135
|
+
const base = volumes[baseId];
|
|
136
|
+
if (!base)
|
|
137
|
+
return;
|
|
138
|
+
const d = base.getDimensions();
|
|
139
|
+
if (!this.scratchVol ||
|
|
140
|
+
this.scratchVol.getDimensions().width !== d.width ||
|
|
141
|
+
this.scratchVol.getDimensions().height !== d.height ||
|
|
142
|
+
this.scratchVol.getDimensions().depth !== d.depth) {
|
|
143
|
+
this.scratchVol = new MaskVolume(d.width, d.height, d.depth, 1);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
this.scratchVol.clear();
|
|
147
|
+
}
|
|
148
|
+
volumes[AI_SCRATCH_LAYER] = this.scratchVol;
|
|
149
|
+
// Paint the AI scratch with the AI-Assist palette (channel 1 = cyan) so the 2D
|
|
150
|
+
// overlay matches the cyan ai_generated GLB. Scoped to THIS volume only — the
|
|
151
|
+
// global palette / clinician mask colours are untouched.
|
|
152
|
+
for (let ch = 1; ch <= 8; ch++) {
|
|
153
|
+
const c = AI_MASK_CHANNEL_COLORS[ch];
|
|
154
|
+
if (c)
|
|
155
|
+
this.scratchVol.setChannelColor(ch, { r: c.r, g: c.g, b: c.b, a: c.a });
|
|
156
|
+
}
|
|
157
|
+
this.snapshotData = this.scratchVol.getRawData().slice();
|
|
158
|
+
this.committedVol = null; // nothing frozen at session start
|
|
159
|
+
this.resetPrompts();
|
|
160
|
+
}
|
|
161
|
+
/** Remove the scratch volume from the registry and drop references. */
|
|
162
|
+
exit() {
|
|
163
|
+
const volumes = this.ctx.protectedData.maskData.volumes;
|
|
164
|
+
delete volumes[AI_SCRATCH_LAYER];
|
|
165
|
+
this.scratchVol = null;
|
|
166
|
+
this.snapshotData = null;
|
|
167
|
+
this.committedVol = null;
|
|
168
|
+
this.resetPrompts();
|
|
169
|
+
this.dragging = false;
|
|
170
|
+
this.dragStart = null;
|
|
171
|
+
}
|
|
172
|
+
/** Discard everything painted since enter() — restore the snapshot. */
|
|
173
|
+
discard() {
|
|
174
|
+
if (this.scratchVol && this.snapshotData) {
|
|
175
|
+
this.scratchVol.setRawData(this.snapshotData.slice());
|
|
176
|
+
}
|
|
177
|
+
this.committedVol = null; // discard wipes frozen regions too
|
|
178
|
+
this.resetPrompts();
|
|
179
|
+
}
|
|
180
|
+
/** "New region": freeze every voxel painted so far so it survives later
|
|
181
|
+
* re-predictions (even on the same channel), then start a fresh prompt set.
|
|
182
|
+
* This is what makes drawing multiple separate regions actually work — without
|
|
183
|
+
* it the next prediction's same-channel cleanup erases the previous region. */
|
|
184
|
+
commitRegion() {
|
|
185
|
+
if (this.scratchVol) {
|
|
186
|
+
const d = this.scratchVol.getDimensions();
|
|
187
|
+
if (!this.committedVol ||
|
|
188
|
+
this.committedVol.getDimensions().width !== d.width ||
|
|
189
|
+
this.committedVol.getDimensions().height !== d.height ||
|
|
190
|
+
this.committedVol.getDimensions().depth !== d.depth) {
|
|
191
|
+
this.committedVol = new MaskVolume(d.width, d.height, d.depth, 1);
|
|
192
|
+
}
|
|
193
|
+
this.committedVol.setRawData(this.scratchVol.getRawData().slice());
|
|
194
|
+
}
|
|
195
|
+
this.resetPrompts();
|
|
196
|
+
}
|
|
197
|
+
/** Clear the in-progress prompt set (e.g. slice/axis change). Does NOT freeze —
|
|
198
|
+
* use commitRegion() for the "New region" action. */
|
|
199
|
+
resetPrompts() {
|
|
200
|
+
this.points = [];
|
|
201
|
+
this.scribble = [];
|
|
202
|
+
this.box = undefined;
|
|
203
|
+
this.dragScreenStart = null;
|
|
204
|
+
this.dragScreen = null;
|
|
205
|
+
this.screenScribble = [];
|
|
206
|
+
}
|
|
207
|
+
// ── Coordinate mapping (all three views) ───────────────────────────────────
|
|
208
|
+
//
|
|
209
|
+
// Mapping must INVERT exactly what RenderingUtils.renderSliceToCanvas does to
|
|
210
|
+
// display the overlay (it is the renderer used by renderOverlay):
|
|
211
|
+
// - axial (z) / sagittal (x): no flip
|
|
212
|
+
// - coronal (y): vertical flip (scale(1,-1))
|
|
213
|
+
// Slice voxel dims & canvas mm extents per axis (matches MaskVolume
|
|
214
|
+
// getSliceDimensions + SphereTool.setSphereCanvasSize):
|
|
215
|
+
// z → (W=width, H=height) over (x_mm, y_mm)
|
|
216
|
+
// y → (W=width, H=depth ) over (x_mm, z_mm) [vertical flip]
|
|
217
|
+
// x → (W=depth, H=height) over (z_mm, y_mm)
|
|
218
|
+
/** Voxel-slice (width,height) for the current axis. */
|
|
219
|
+
sliceDims() {
|
|
220
|
+
if (!this.scratchVol)
|
|
221
|
+
return null;
|
|
222
|
+
const d = this.scratchVol.getDimensions();
|
|
223
|
+
switch (this.ctx.protectedData.axis) {
|
|
224
|
+
case "z": return { w: d.width, h: d.height };
|
|
225
|
+
case "y": return { w: d.width, h: d.depth };
|
|
226
|
+
case "x": return { w: d.depth, h: d.height };
|
|
227
|
+
default: return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/** Screen offset → voxel-slice (vx,vy) for the current axis. */
|
|
231
|
+
toVoxel(e) {
|
|
232
|
+
const sd = this.sliceDims();
|
|
233
|
+
if (!sd || !this.scratchVol)
|
|
234
|
+
return null;
|
|
235
|
+
const nrrd = this.ctx.nrrd_states;
|
|
236
|
+
const img = nrrd.image;
|
|
237
|
+
const mx = e.offsetX / nrrd.view.sizeFactor;
|
|
238
|
+
const my = e.offsetY / nrrd.view.sizeFactor;
|
|
239
|
+
let hMM, vMM, flipV;
|
|
240
|
+
switch (this.ctx.protectedData.axis) {
|
|
241
|
+
case "z":
|
|
242
|
+
hMM = img.nrrd_x_mm;
|
|
243
|
+
vMM = img.nrrd_y_mm;
|
|
244
|
+
flipV = false;
|
|
245
|
+
break;
|
|
246
|
+
case "y":
|
|
247
|
+
hMM = img.nrrd_x_mm;
|
|
248
|
+
vMM = img.nrrd_z_mm;
|
|
249
|
+
flipV = true;
|
|
250
|
+
break;
|
|
251
|
+
case "x":
|
|
252
|
+
hMM = img.nrrd_z_mm;
|
|
253
|
+
vMM = img.nrrd_y_mm;
|
|
254
|
+
flipV = false;
|
|
255
|
+
break;
|
|
256
|
+
default: return null;
|
|
257
|
+
}
|
|
258
|
+
const vx = Math.round(mx * sd.w / hMM);
|
|
259
|
+
let vy = Math.round(my * sd.h / vMM);
|
|
260
|
+
if (flipV)
|
|
261
|
+
vy = sd.h - 1 - vy;
|
|
262
|
+
if (vx < 0 || vx >= sd.w || vy < 0 || vy >= sd.h)
|
|
263
|
+
return null;
|
|
264
|
+
return { vx, vy, w: sd.w, h: sd.h };
|
|
265
|
+
}
|
|
266
|
+
// ── Pointer handlers (left button; right stays pan in EventRouter) ──────────
|
|
267
|
+
onPointerDown(e) {
|
|
268
|
+
const hit = this.toVoxel(e);
|
|
269
|
+
if (!hit)
|
|
270
|
+
return;
|
|
271
|
+
this.syncSlice();
|
|
272
|
+
if (this.promptTool === "point") {
|
|
273
|
+
this.points.push({ x: hit.vx, y: hit.vy, label: this.polarity });
|
|
274
|
+
this.emit();
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
// box / scribble: begin a drag
|
|
278
|
+
this.dragging = true;
|
|
279
|
+
this.dragStart = { x: hit.vx, y: hit.vy };
|
|
280
|
+
this.dragScreenStart = { x: e.offsetX, y: e.offsetY };
|
|
281
|
+
this.dragScreen = { x: e.offsetX, y: e.offsetY };
|
|
282
|
+
this.screenScribble = [];
|
|
283
|
+
if (this.promptTool === "scribble") {
|
|
284
|
+
this.scribble.push({ x: hit.vx, y: hit.vy, label: this.polarity });
|
|
285
|
+
this.screenScribble.push({ x: e.offsetX, y: e.offsetY });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
onPointerMove(e) {
|
|
290
|
+
// Track hover for the scribble preview ring even when not drawing.
|
|
291
|
+
this.hoverScreen = { x: e.offsetX, y: e.offsetY };
|
|
292
|
+
if (!this.dragging)
|
|
293
|
+
return;
|
|
294
|
+
// Track screen pos first so the live preview follows even slightly out of bounds.
|
|
295
|
+
this.dragScreen = { x: e.offsetX, y: e.offsetY };
|
|
296
|
+
const hit = this.toVoxel(e);
|
|
297
|
+
if (!hit)
|
|
298
|
+
return;
|
|
299
|
+
if (this.promptTool === "scribble") {
|
|
300
|
+
this.scribble.push({ x: hit.vx, y: hit.vy, label: this.polarity });
|
|
301
|
+
this.screenScribble.push({ x: e.offsetX, y: e.offsetY });
|
|
302
|
+
}
|
|
303
|
+
else if (this.promptTool === "box" && this.dragStart) {
|
|
304
|
+
this.box = {
|
|
305
|
+
x0: this.dragStart.x, y0: this.dragStart.y,
|
|
306
|
+
x1: hit.vx, y1: hit.vy,
|
|
307
|
+
label: this.polarity, // foreground box grows within; background box excludes
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
onPointerUp(_e) {
|
|
312
|
+
if (!this.dragging)
|
|
313
|
+
return;
|
|
314
|
+
this.dragging = false;
|
|
315
|
+
this.emit();
|
|
316
|
+
this.dragStart = null;
|
|
317
|
+
this.dragScreenStart = null;
|
|
318
|
+
this.dragScreen = null;
|
|
319
|
+
this.screenScribble = [];
|
|
320
|
+
}
|
|
321
|
+
/** Reset the accumulated prompt set when the user scrubs to a new slice. */
|
|
322
|
+
syncSlice() {
|
|
323
|
+
const slice = this.ctx.nrrd_states.view.currentSliceIndex;
|
|
324
|
+
if (slice !== this.activeSlice) {
|
|
325
|
+
this.activeSlice = slice;
|
|
326
|
+
this.resetPrompts();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
emit() {
|
|
330
|
+
if (!this.onPrompt)
|
|
331
|
+
return;
|
|
332
|
+
const sd = this.sliceDims();
|
|
333
|
+
if (!sd)
|
|
334
|
+
return;
|
|
335
|
+
this.onPrompt({
|
|
336
|
+
axis: this.ctx.protectedData.axis,
|
|
337
|
+
sliceIndex: this.ctx.nrrd_states.view.currentSliceIndex,
|
|
338
|
+
width: sd.w,
|
|
339
|
+
height: sd.h,
|
|
340
|
+
points: [...this.points],
|
|
341
|
+
box: this.box,
|
|
342
|
+
scribble: this.scribble.length ? [...this.scribble] : undefined,
|
|
343
|
+
scribbleRadius: this.scribbleSize,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
// ── Apply backend result → scratch volume ──────────────────────────────────
|
|
347
|
+
applyMask(result) {
|
|
348
|
+
if (!this.scratchVol)
|
|
349
|
+
return;
|
|
350
|
+
// 3D result (engine B): write each slice across the covered span.
|
|
351
|
+
if (result.slices && result.sliceRange) {
|
|
352
|
+
const [lo] = result.sliceRange;
|
|
353
|
+
for (let k = 0; k < result.slices.length; k++) {
|
|
354
|
+
this.applySliceRle(result.slices[k], result.axis, lo + k, result.width, result.height);
|
|
355
|
+
}
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
// 2D result (engines mock / regiongrow / medsam2d): single slice.
|
|
359
|
+
this.applySliceRle(result.rle, result.axis, result.sliceIndex, result.width, result.height);
|
|
360
|
+
}
|
|
361
|
+
/** Merge one RLE-encoded predicted slice into the scratch volume at sliceIndex.
|
|
362
|
+
* Predicted pixels → current channel; stale current-channel pixels cleared
|
|
363
|
+
* UNLESS they belong to a frozen (committed) region; OTHER channels preserved. */
|
|
364
|
+
applySliceRle(rle, axis, sliceIndex, width, height) {
|
|
365
|
+
if (!this.scratchVol)
|
|
366
|
+
return;
|
|
367
|
+
const predicted = new Uint8Array(width * height);
|
|
368
|
+
let pos = 0;
|
|
369
|
+
let value = 0;
|
|
370
|
+
for (const run of rle) {
|
|
371
|
+
if (value === 1 && run > 0) {
|
|
372
|
+
const end = Math.min(pos + run, predicted.length);
|
|
373
|
+
for (let i = pos; i < end; i++)
|
|
374
|
+
predicted[i] = 1;
|
|
375
|
+
}
|
|
376
|
+
pos += run;
|
|
377
|
+
value ^= 1;
|
|
378
|
+
}
|
|
379
|
+
const ch = this.channel;
|
|
380
|
+
try {
|
|
381
|
+
const out = this.scratchVol.getSliceUint8(sliceIndex, axis).data; // copy
|
|
382
|
+
// Frozen same-channel pixels for this slice (if any region was committed).
|
|
383
|
+
let frozen = null;
|
|
384
|
+
if (this.committedVol) {
|
|
385
|
+
try {
|
|
386
|
+
frozen = this.committedVol.getSliceUint8(sliceIndex, axis).data;
|
|
387
|
+
}
|
|
388
|
+
catch (_a) {
|
|
389
|
+
frozen = null;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const n = Math.min(out.length, predicted.length);
|
|
393
|
+
for (let i = 0; i < n; i++) {
|
|
394
|
+
if (predicted[i])
|
|
395
|
+
out[i] = ch;
|
|
396
|
+
// Clear stale LIVE same-channel pixels (refinement), but never erase a
|
|
397
|
+
// frozen region committed via "New region".
|
|
398
|
+
else if (out[i] === ch && !(frozen && frozen[i] === ch))
|
|
399
|
+
out[i] = 0;
|
|
400
|
+
}
|
|
401
|
+
this.scratchVol.setSliceUint8(sliceIndex, out, axis);
|
|
402
|
+
}
|
|
403
|
+
catch (_b) {
|
|
404
|
+
// slice out of bounds / dims changed — ignore
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// ── Overlay render (called from DrawToolCore.start() while in aiAssist) ──────
|
|
408
|
+
renderOverlay(targetCtx) {
|
|
409
|
+
if (!this.scratchVol)
|
|
410
|
+
return;
|
|
411
|
+
const axis = this.ctx.protectedData.axis;
|
|
412
|
+
const slice = this.ctx.nrrd_states.view.currentSliceIndex;
|
|
413
|
+
const buffer = this.host.getOrCreateSliceBuffer(axis);
|
|
414
|
+
if (!buffer)
|
|
415
|
+
return;
|
|
416
|
+
try {
|
|
417
|
+
this.host.renderSliceToCanvas(AI_SCRATCH_LAYER, axis, slice, buffer, targetCtx, this.ctx.nrrd_states.view.changedWidth, this.ctx.nrrd_states.view.changedHeight);
|
|
418
|
+
}
|
|
419
|
+
catch (_a) {
|
|
420
|
+
// volume not ready / slice out of bounds
|
|
421
|
+
}
|
|
422
|
+
// Live drag preview (screen space) — rubber-band box / scribble stroke so the
|
|
423
|
+
// user sees the gesture before the prediction lands on pointer-up.
|
|
424
|
+
if (this.dragging && this.dragScreenStart && this.dragScreen) {
|
|
425
|
+
targetCtx.save();
|
|
426
|
+
// Green-ish for foreground (include), red-ish for background (exclude).
|
|
427
|
+
const color = this.polarity === 1 ? "rgba(120,255,180,0.95)" : "rgba(255,120,120,0.95)";
|
|
428
|
+
targetCtx.strokeStyle = color;
|
|
429
|
+
if (this.promptTool === "box") {
|
|
430
|
+
targetCtx.setLineDash([5, 4]);
|
|
431
|
+
targetCtx.lineWidth = 1.5;
|
|
432
|
+
const x = Math.min(this.dragScreenStart.x, this.dragScreen.x);
|
|
433
|
+
const y = Math.min(this.dragScreenStart.y, this.dragScreen.y);
|
|
434
|
+
const w = Math.abs(this.dragScreen.x - this.dragScreenStart.x);
|
|
435
|
+
const h = Math.abs(this.dragScreen.y - this.dragScreenStart.y);
|
|
436
|
+
targetCtx.strokeRect(x, y, w, h);
|
|
437
|
+
}
|
|
438
|
+
else if (this.promptTool === "scribble" && this.screenScribble.length > 1) {
|
|
439
|
+
targetCtx.lineCap = "round";
|
|
440
|
+
targetCtx.lineJoin = "round";
|
|
441
|
+
// Stroke thickness reflects the scribble brush size (diameter ≈ 2·radius).
|
|
442
|
+
targetCtx.lineWidth = Math.max(2, this.scribbleSize * 2);
|
|
443
|
+
targetCtx.beginPath();
|
|
444
|
+
targetCtx.moveTo(this.screenScribble[0].x, this.screenScribble[0].y);
|
|
445
|
+
for (let i = 1; i < this.screenScribble.length; i++) {
|
|
446
|
+
targetCtx.lineTo(this.screenScribble[i].x, this.screenScribble[i].y);
|
|
447
|
+
}
|
|
448
|
+
targetCtx.stroke();
|
|
449
|
+
}
|
|
450
|
+
targetCtx.restore();
|
|
451
|
+
}
|
|
452
|
+
// Scribble brush-size preview ring (when NOT dragging) — a circle centred on
|
|
453
|
+
// the cursor whose radius = scribbleSize, so the user sees the brush size and
|
|
454
|
+
// how the slider changes it (mirrors the paint brush's preview ring). Drawn
|
|
455
|
+
// every frame from the live hover position by copper3d's render loop.
|
|
456
|
+
if (this.promptTool === "scribble" && !this.dragging && this.hoverScreen) {
|
|
457
|
+
targetCtx.save();
|
|
458
|
+
const fg = this.polarity === 1;
|
|
459
|
+
targetCtx.strokeStyle = fg ? "rgba(120,255,180,0.9)" : "rgba(255,120,120,0.9)";
|
|
460
|
+
targetCtx.lineWidth = 1.5;
|
|
461
|
+
if (!fg)
|
|
462
|
+
targetCtx.setLineDash([4, 4]); // dashed for background (exclude), like the eraser
|
|
463
|
+
targetCtx.beginPath();
|
|
464
|
+
targetCtx.arc(this.hoverScreen.x, this.hoverScreen.y, Math.max(2, this.scribbleSize), 0, Math.PI * 2);
|
|
465
|
+
targetCtx.stroke();
|
|
466
|
+
targetCtx.restore();
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
//# sourceMappingURL=AiAssistTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiAssistTool.js","sourceRoot":"","sources":["../../../../src/Utils/segmentation/tools/AiAssistTool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAG7D;yEACyE;AACzE,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAoC5C,MAAM,OAAO,YAAa,SAAQ,QAAQ;IAwCxC,YAAY,GAAgB,EAAE,IAAsB;QAClD,KAAK,CAAC,GAAG,CAAC,CAAC;QAtCb,qFAAqF;QAC7E,eAAU,GAAsB,IAAI,CAAC;QAC7C,mEAAmE;QAC3D,iBAAY,GAAsB,IAAI,CAAC;QAC/C;;;uFAG+E;QACvE,iBAAY,GAAsB,IAAI,CAAC;QAEvC,eAAU,GAAiB,OAAO,CAAC;QACnC,aAAQ,GAAW,CAAC,CAAC,CAAC,4CAA4C;QAC1E,8EAA8E;QACtE,YAAO,GAAW,CAAC,CAAC;QAC5B,8DAA8D;QACtD,iBAAY,GAAW,CAAC,CAAC;QAEjC,6EAA6E;QACrE,WAAM,GAAoB,EAAE,CAAC;QAC7B,aAAQ,GAAoB,EAAE,CAAC;QAE/B,gBAAW,GAAG,CAAC,CAAC,CAAC;QAEzB,4DAA4D;QACpD,aAAQ,GAAG,KAAK,CAAC;QACjB,cAAS,GAAoC,IAAI,CAAC;QAC1D,0EAA0E;QAClE,oBAAe,GAAoC,IAAI,CAAC;QACxD,eAAU,GAAoC,IAAI,CAAC;QACnD,mBAAc,GAA+B,EAAE,CAAC;QACxD,8EAA8E;QAC9E,kFAAkF;QAC1E,gBAAW,GAAoC,IAAI,CAAC;QAE5D,mFAAmF;QACnF,aAAQ,GAAgD,IAAI,CAAC;QAI3D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,8EAA8E;IAE9E,aAAa,CAAC,IAAkB;QAC9B,6EAA6E;QAC7E,wDAAwD;QACxD,IAAI,IAAI,KAAK,IAAI,CAAC,UAAU,EAAE;YAC5B,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;SACvB;QACD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACzB,CAAC;IACD,WAAW,CAAC,KAAa,IAAU,IAAI,CAAC,QAAQ,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,eAAe,CAAC,IAAY;QAC1B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,UAAU,CAAC,OAAe;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACxD,yEAAyE;QACzE,2EAA2E;QAC3E,6CAA6C;QAC7C,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,YAAY,EAAE,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,UAAU,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,gBAAgB,KAAwB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjE;;;;4EAIwE;IACxE,gBAAgB;QAId,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAClC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;QAClD,MAAM,GAAG,GAA4C,EAAE,CAAC;QACxD,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;YAC9B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC5E,KAAK,GAAG,CAAC,CAAC;YAAC,MAAM,GAAG,CAAC,CAAC;YACtB,+DAA+D;YAC/D,MAAM,IAAI,GAAa,EAAE,CAAC;YAC1B,IAAI,KAAK,GAAG,CAAC,CAAC,CAAG,yDAAyD;YAC1E,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,GAAG,GAAG,KAAK,CAAC;YAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACpC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChC,IAAI,CAAC;oBAAE,GAAG,GAAG,IAAI,CAAC;gBAClB,IAAI,CAAC,KAAK,KAAK,EAAE;oBAAE,KAAK,EAAE,CAAC;iBAAE;qBACxB;oBAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAAC,KAAK,GAAG,CAAC,CAAC;oBAAC,KAAK,GAAG,CAAC,CAAC;iBAAE;aACjD;YACD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACjB,IAAI,GAAG;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;SACjD;QACD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACnD,CAAC;IAED,8EAA8E;IAE9E;8EAC0E;IAC1E,KAAK;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAE/B,IAAI,CAAC,IAAI,CAAC,UAAU;YAClB,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;YACjD,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YACnD,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE;YACnD,IAAI,CAAC,UAAU,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;SACjE;aAAM;YACL,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;SACzB;QACD,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;QAC5C,+EAA+E;QAC/E,8EAA8E;QAC9E,yDAAyD;QACzD,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE;YAC9B,MAAM,CAAC,GAAG,sBAAsB,CAAC,EAAE,CAAC,CAAC;YACrC,IAAI,CAAC;gBAAE,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAChF;QACD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC;QACzD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,kCAAkC;QAC5D,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,uEAAuE;IACvE,IAAI;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC;QACxD,OAAO,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,uEAAuE;IACvE,OAAO;QACL,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,YAAY,EAAE;YACxC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;SACvD;QACD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,mCAAmC;QAC7D,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED;;;oFAGgF;IAChF,YAAY;QACV,IAAI,IAAI,CAAC,UAAU,EAAE;YACnB,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;YAC1C,IAAI,CAAC,IAAI,CAAC,YAAY;gBACpB,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;gBACnD,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;gBACrD,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE;gBACrD,IAAI,CAAC,YAAY,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;aACnE;YACD,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;SACpE;QACD,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED;0DACsD;IACtD,YAAY;QACV,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED,8EAA8E;IAC9E,EAAE;IACF,8EAA8E;IAC9E,kEAAkE;IAClE,wCAAwC;IACxC,+CAA+C;IAC/C,oEAAoE;IACpE,wDAAwD;IACxD,+CAA+C;IAC/C,iEAAiE;IACjE,+CAA+C;IAE/C,uDAAuD;IAC/C,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAClC,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;QAC1C,QAAQ,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE;YACnC,KAAK,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;YAC7C,KAAK,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;YAC5C,KAAK,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;YAC7C,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC;SACtB;IACH,CAAC;IAED,gEAAgE;IACxD,OAAO,CAAC,CAAa;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC;QACvB,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;QAC5C,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;QAE5C,IAAI,GAAW,EAAE,GAAW,EAAE,KAAc,CAAC;QAC7C,QAAQ,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE;YACnC,KAAK,GAAG;gBAAE,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC;gBAAC,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC;gBAAC,KAAK,GAAG,KAAK,CAAC;gBAAC,MAAM;YACzE,KAAK,GAAG;gBAAE,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC;gBAAC,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC;gBAAC,KAAK,GAAG,IAAI,CAAC;gBAAC,MAAM;YACxE,KAAK,GAAG;gBAAE,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC;gBAAC,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC;gBAAC,KAAK,GAAG,KAAK,CAAC;gBAAC,MAAM;YACzE,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC;SACtB;QAED,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QACvC,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QACrC,IAAI,KAAK;YAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9D,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;IACtC,CAAC;IAED,+EAA+E;IAE/E,aAAa,CAAC,CAAa;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,CAAC,SAAS,EAAE,CAAC;QAEjB,IAAI,IAAI,CAAC,UAAU,KAAK,OAAO,EAAE;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjE,IAAI,CAAC,IAAI,EAAE,CAAC;SACb;aAAM;YACL,+BAA+B;YAC/B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;YAC1C,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YACtD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YACjD,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,UAAU,KAAK,UAAU,EAAE;gBAClC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACnE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;aAC1D;SACF;IACH,CAAC;IAED,aAAa,CAAC,CAAa;QACzB,mEAAmE;QACnE,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QAClD,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,kFAAkF;QAClF,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,IAAI,CAAC,UAAU,KAAK,UAAU,EAAE;YAClC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACnE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;SAC1D;aAAM,IAAI,IAAI,CAAC,UAAU,KAAK,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE;YACtD,IAAI,CAAC,GAAG,GAAG;gBACT,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC1C,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE;gBACtB,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,uDAAuD;aAC9E,CAAC;SACH;IACH,CAAC;IAED,WAAW,CAAC,EAAc;QACxB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED,4EAA4E;IACpE,SAAS;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC;QAC1D,IAAI,KAAK,KAAK,IAAI,CAAC,WAAW,EAAE;YAC9B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,IAAI,CAAC,YAAY,EAAE,CAAC;SACrB;IACH,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,IAAI,CAAC,QAAQ,CAAC;YACZ,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI;YACjC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB;YACvD,KAAK,EAAE,EAAE,CAAC,CAAC;YACX,MAAM,EAAE,EAAE,CAAC,CAAC;YACZ,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;YACxB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;YAC/D,cAAc,EAAE,IAAI,CAAC,YAAY;SAClC,CAAC,CAAC;IACL,CAAC;IAED,8EAA8E;IAE9E,SAAS,CAAC,MAAoB;QAC5B,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAC7B,kEAAkE;QAClE,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,UAAU,EAAE;YACtC,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC;YAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBAC7C,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;aACxF;YACD,OAAO;SACR;QACD,kEAAkE;QAClE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9F,CAAC;IAED;;uFAEmF;IAC3E,aAAa,CACnB,GAAa,EAAE,IAAqB,EAAE,UAAkB,EAAE,KAAa,EAAE,MAAc;QAEvF,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAC7B,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;QACjD,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE;YACrB,IAAI,KAAK,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE;gBAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;gBAClD,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE;oBAAE,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;aAClD;YACD,GAAG,IAAI,GAAG,CAAC;YACX,KAAK,IAAI,CAAC,CAAC;SACZ;QACD,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACxB,IAAI;YACF,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO;YACzE,2EAA2E;YAC3E,IAAI,MAAM,GAAsB,IAAI,CAAC;YACrC,IAAI,IAAI,CAAC,YAAY,EAAE;gBACrB,IAAI;oBAAE,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC;iBAAE;gBAAC,WAAM;oBAAE,MAAM,GAAG,IAAI,CAAC;iBAAE;aAClG;YACD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;YACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;gBAC1B,IAAI,SAAS,CAAC,CAAC,CAAC;oBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;gBAC9B,uEAAuE;gBACvE,4CAA4C;qBACvC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;oBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;aACrE;YACD,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;SACtD;QAAC,WAAM;YACN,8CAA8C;SAC/C;IACH,CAAC;IAED,gFAAgF;IAEhF,aAAa,CAAC,SAAmC;QAC/C,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,IAAI;YACF,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAC3B,gBAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAChD,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,EACtC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CACxC,CAAC;SACH;QAAC,WAAM;YACN,yCAAyC;SAC1C;QAED,8EAA8E;QAC9E,mEAAmE;QACnE,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,UAAU,EAAE;YAC5D,SAAS,CAAC,IAAI,EAAE,CAAC;YACjB,wEAAwE;YACxE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,wBAAwB,CAAC;YACxF,SAAS,CAAC,WAAW,GAAG,KAAK,CAAC;YAC9B,IAAI,IAAI,CAAC,UAAU,KAAK,KAAK,EAAE;gBAC7B,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC9B,SAAS,CAAC,SAAS,GAAG,GAAG,CAAC;gBAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAC9D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAC9D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;gBAC/D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;gBAC/D,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;aAClC;iBAAM,IAAI,IAAI,CAAC,UAAU,KAAK,UAAU,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC3E,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC;gBAC5B,SAAS,CAAC,QAAQ,GAAG,OAAO,CAAC;gBAC7B,2EAA2E;gBAC3E,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;gBACzD,SAAS,CAAC,SAAS,EAAE,CAAC;gBACtB,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;oBACnD,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBACtE;gBACD,SAAS,CAAC,MAAM,EAAE,CAAC;aACpB;YACD,SAAS,CAAC,OAAO,EAAE,CAAC;SACrB;QAED,6EAA6E;QAC7E,8EAA8E;QAC9E,4EAA4E;QAC5E,sEAAsE;QACtE,IAAI,IAAI,CAAC,UAAU,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE;YACxE,SAAS,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC;YAC/B,SAAS,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,uBAAuB,CAAC;YAC/E,SAAS,CAAC,SAAS,GAAG,GAAG,CAAC;YAC1B,IAAI,CAAC,EAAE;gBAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,mDAAmD;YAC3F,SAAS,CAAC,SAAS,EAAE,CAAC;YACtB,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACtG,SAAS,CAAC,MAAM,EAAE,CAAC;YACnB,SAAS,CAAC,OAAO,EAAE,CAAC;SACrB;IACH,CAAC;CACF"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { copperVolumeType } from "../types/types";
|
|
3
3
|
import { GUI } from "dat.gui";
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
export declare function createTexture2D_Array(copperVolume: copperVolumeType, depth: number, scene: THREE.Scene, gui?: GUI): {
|
|
7
|
-
mesh: THREE.Mesh<THREE.PlaneGeometry, THREE.ShaderMaterial, THREE.Object3DEventMap>;
|
|
4
|
+
export interface texture2dResult {
|
|
5
|
+
mesh: THREE.Mesh;
|
|
8
6
|
copperVolume: copperVolumeType;
|
|
9
|
-
updateTexture: (
|
|
10
|
-
|
|
7
|
+
updateTexture: (copperVolume: copperVolumeType) => void;
|
|
8
|
+
setFrame: (i: number) => void;
|
|
9
|
+
setWindow: (center: number, width: number) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createTexture2D_NRRD(data: Uint8Array, width: number, height: number, depth: number, callback: (mesh: THREE.Mesh) => void): void;
|
|
12
|
+
export declare function createTexture2D_Array(copperVolume: copperVolumeType, depth: number, scene: THREE.Scene, gui?: GUI, aligned?: boolean): texture2dResult;
|
package/dist/Utils/texture2d.js
CHANGED
|
@@ -1,35 +1,20 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
|
-
import { unzipSync } from "fflate";
|
|
3
2
|
import { getLut } from "../Loader/copperDicomLoader";
|
|
4
3
|
import vert_2d from "../lib/shader/texture2d_vertex.glsl";
|
|
5
4
|
import frag_2d from "../lib/shader/texture2d_frag.glsl";
|
|
6
5
|
let planeWidth = 80;
|
|
7
6
|
let planeHeight = 80;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
diffuse: { value: texture },
|
|
20
|
-
depth: { value: 1 },
|
|
21
|
-
size: { value: new THREE.Vector2(planeWidth, planeHeight) },
|
|
22
|
-
},
|
|
23
|
-
vertexShader: vert_2d,
|
|
24
|
-
fragmentShader: frag_2d,
|
|
25
|
-
glslVersion: THREE.GLSL3,
|
|
26
|
-
side: THREE.DoubleSide,
|
|
27
|
-
});
|
|
28
|
-
const geometry = new THREE.PlaneGeometry(planeWidth, planeHeight);
|
|
29
|
-
const mesh = new THREE.Mesh(geometry, material);
|
|
30
|
-
mesh.name = "texture2d_mesh_zip";
|
|
31
|
-
scene.add(mesh);
|
|
32
|
-
});
|
|
7
|
+
// Build a quad from the 4 world-space image-plane corners (preserves real pose).
|
|
8
|
+
function buildAlignedQuad(c) {
|
|
9
|
+
const g = new THREE.BufferGeometry();
|
|
10
|
+
// two triangles: tl,bl,tr / tr,bl,br
|
|
11
|
+
g.setAttribute("position", new THREE.BufferAttribute(new Float32Array([...c.tl, ...c.bl, ...c.tr, ...c.tr, ...c.bl, ...c.br]), 3));
|
|
12
|
+
// vertex order is tl, bl, tr, tr, bl, br. The fragment shader flips v (vUv.y = 1-uv.y)
|
|
13
|
+
// and DataArrayTexture has no flipY, so the image-top (data row 0) must map to the
|
|
14
|
+
// top world corner: tl/tr get uv.y = 1.
|
|
15
|
+
g.setAttribute("uv", new THREE.BufferAttribute(new Float32Array([0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0]), 2));
|
|
16
|
+
g.computeVertexNormals();
|
|
17
|
+
return g;
|
|
33
18
|
}
|
|
34
19
|
export function createTexture2D_NRRD(data, width, height, depth, callback) {
|
|
35
20
|
const texture = new THREE.DataArrayTexture(data, width, height, depth);
|
|
@@ -39,7 +24,7 @@ export function createTexture2D_NRRD(data, width, height, depth, callback) {
|
|
|
39
24
|
uniforms: {
|
|
40
25
|
diffuse: { value: texture },
|
|
41
26
|
depth: { value: 1 },
|
|
42
|
-
|
|
27
|
+
uOpacity: { value: 1 },
|
|
43
28
|
},
|
|
44
29
|
vertexShader: vert_2d,
|
|
45
30
|
fragmentShader: frag_2d,
|
|
@@ -51,13 +36,9 @@ export function createTexture2D_NRRD(data, width, height, depth, callback) {
|
|
|
51
36
|
mesh.name = "texture2d_mesh_zip";
|
|
52
37
|
callback(mesh);
|
|
53
38
|
}
|
|
54
|
-
export function createTexture2D_Array(copperVolume, depth, scene, gui) {
|
|
39
|
+
export function createTexture2D_Array(copperVolume, depth, scene, gui, aligned = false) {
|
|
55
40
|
planeWidth = copperVolume.width / 2;
|
|
56
41
|
planeHeight = copperVolume.height / 2;
|
|
57
|
-
const state = {
|
|
58
|
-
windowWidth: copperVolume.windowWidth,
|
|
59
|
-
windowCenter: copperVolume.windowCenter,
|
|
60
|
-
};
|
|
61
42
|
const texture = new THREE.DataArrayTexture(copperVolume.uint8, copperVolume.width, copperVolume.height, depth);
|
|
62
43
|
texture.format = THREE.RedFormat;
|
|
63
44
|
texture.needsUpdate = true;
|
|
@@ -84,18 +65,22 @@ export function createTexture2D_Array(copperVolume, depth, scene, gui) {
|
|
|
84
65
|
const material = new THREE.ShaderMaterial({
|
|
85
66
|
uniforms: {
|
|
86
67
|
diffuse: { value: texture },
|
|
87
|
-
depth: { value:
|
|
88
|
-
|
|
68
|
+
depth: { value: 0 },
|
|
69
|
+
uOpacity: { value: 1 },
|
|
89
70
|
},
|
|
90
71
|
vertexShader: vert_2d,
|
|
91
72
|
fragmentShader: frag_2d,
|
|
92
73
|
glslVersion: THREE.GLSL3,
|
|
93
74
|
side: THREE.DoubleSide,
|
|
94
75
|
});
|
|
95
|
-
|
|
76
|
+
// Aligned world-space quad only when explicitly requested and geometry tags exist;
|
|
77
|
+
// otherwise the legacy centred plane (keeps existing loadDicom behaviour unchanged).
|
|
78
|
+
const geometry = aligned && copperVolume.corners
|
|
79
|
+
? buildAlignedQuad(copperVolume.corners)
|
|
80
|
+
: new THREE.PlaneGeometry(planeWidth, planeHeight);
|
|
96
81
|
const mesh = new THREE.Mesh(geometry, material);
|
|
97
|
-
scene.add(mesh);
|
|
98
82
|
mesh.name = "texture2d_mesh_array";
|
|
83
|
+
scene.add(mesh);
|
|
99
84
|
function updateTexture(copperVolumeUp) {
|
|
100
85
|
if (!!copperVolumeUp) {
|
|
101
86
|
let voiLUT;
|
|
@@ -106,6 +91,14 @@ export function createTexture2D_Array(copperVolume, depth, scene, gui) {
|
|
|
106
91
|
texture.needsUpdate = true;
|
|
107
92
|
}
|
|
108
93
|
}
|
|
109
|
-
|
|
94
|
+
function setFrame(i) {
|
|
95
|
+
material.uniforms.depth.value = i;
|
|
96
|
+
}
|
|
97
|
+
function setWindow(center, width) {
|
|
98
|
+
copperVolume.windowCenter = center;
|
|
99
|
+
copperVolume.windowWidth = width;
|
|
100
|
+
updateTexture(copperVolume);
|
|
101
|
+
}
|
|
102
|
+
return { mesh, copperVolume, updateTexture, setFrame, setWindow };
|
|
110
103
|
}
|
|
111
104
|
//# sourceMappingURL=texture2d.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"texture2d.js","sourceRoot":"","sources":["../../src/Utils/texture2d.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"texture2d.js","sourceRoot":"","sources":["../../src/Utils/texture2d.ts"],"names":[],"mappings":"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"}
|