@niivue/niivue 0.44.2-dev.1 → 0.45.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/build/index.d.ts +15 -71
- package/build/index.js +197 -459
- package/build/index.js.map +1 -1
- package/build/index.min.js +1 -1
- package/dist/index.d.ts +15 -71
- package/dist/index.js +198 -460
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/niivue.umd.js +27 -66
- package/package.json +1 -1
- package/src/cow.iwm.cbor +0 -0
- package/src/fslmean.iwi.cbor +0 -0
- package/src/index.html +1 -1
- package/src/niivue/index.ts +266 -532
- package/src/nvdocument.ts +5 -25
- package/src/shader-srcs.ts +0 -41
- package/src/types.ts +0 -13
- package/src/index_segment.html +0 -165
- package/src/index_sync.html +0 -289
package/dist/index.js
CHANGED
|
@@ -95525,7 +95525,7 @@ var forEach3 = function() {
|
|
|
95525
95525
|
}();
|
|
95526
95526
|
|
|
95527
95527
|
// package.json
|
|
95528
|
-
var version = "0.
|
|
95528
|
+
var version = "0.45.0";
|
|
95529
95529
|
|
|
95530
95530
|
// src/logger.ts
|
|
95531
95531
|
var _Log = class _Log {
|
|
@@ -96321,46 +96321,6 @@ out vec4 color;
|
|
|
96321
96321
|
void main() {
|
|
96322
96322
|
color = lineColor;
|
|
96323
96323
|
}`;
|
|
96324
|
-
var fragRectOutlineShader = `#version 300 es
|
|
96325
|
-
#line 723
|
|
96326
|
-
precision highp int;
|
|
96327
|
-
precision highp float;
|
|
96328
|
-
|
|
96329
|
-
uniform vec4 lineColor;
|
|
96330
|
-
uniform vec4 leftTopWidthHeight;
|
|
96331
|
-
uniform float thickness; // line thickness in pixels
|
|
96332
|
-
uniform vec2 canvasWidthHeight;
|
|
96333
|
-
|
|
96334
|
-
out vec4 color;
|
|
96335
|
-
|
|
96336
|
-
void main() {
|
|
96337
|
-
// fragment position in screen coordinates
|
|
96338
|
-
vec2 fragCoord = gl_FragCoord.xy;
|
|
96339
|
-
|
|
96340
|
-
// canvas height
|
|
96341
|
-
float canvasHeight = canvasWidthHeight.y;
|
|
96342
|
-
|
|
96343
|
-
// 'top' and 'bottom' to match gl_FragCoord.y coordinate system
|
|
96344
|
-
float top = canvasHeight - leftTopWidthHeight.y;
|
|
96345
|
-
float bottom = top - leftTopWidthHeight.w;
|
|
96346
|
-
|
|
96347
|
-
// left and right edges
|
|
96348
|
-
float left = leftTopWidthHeight.x;
|
|
96349
|
-
float right = left + leftTopWidthHeight.z;
|
|
96350
|
-
|
|
96351
|
-
bool withinLeft = fragCoord.x >= left && fragCoord.x <= left + thickness;
|
|
96352
|
-
bool withinRight = fragCoord.x <= right && fragCoord.x >= right - thickness;
|
|
96353
|
-
bool withinTop = fragCoord.y <= top && fragCoord.y >= top - thickness;
|
|
96354
|
-
bool withinBottom = fragCoord.y >= bottom && fragCoord.y <= bottom + thickness;
|
|
96355
|
-
|
|
96356
|
-
bool isOutline = withinLeft || withinRight || withinTop || withinBottom;
|
|
96357
|
-
|
|
96358
|
-
if (isOutline) {
|
|
96359
|
-
color = lineColor;
|
|
96360
|
-
} else {
|
|
96361
|
-
discard;
|
|
96362
|
-
}
|
|
96363
|
-
}`;
|
|
96364
96324
|
var vertColorbarShader = `#version 300 es
|
|
96365
96325
|
#line 490
|
|
96366
96326
|
layout(location=0) in vec3 pos;
|
|
@@ -119194,7 +119154,6 @@ var DRAG_MODE = /* @__PURE__ */ ((DRAG_MODE2) => {
|
|
|
119194
119154
|
DRAG_MODE2[DRAG_MODE2["pan"] = 3] = "pan";
|
|
119195
119155
|
DRAG_MODE2[DRAG_MODE2["slicer3D"] = 4] = "slicer3D";
|
|
119196
119156
|
DRAG_MODE2[DRAG_MODE2["callbackOnly"] = 5] = "callbackOnly";
|
|
119197
|
-
DRAG_MODE2[DRAG_MODE2["roiSelection"] = 6] = "roiSelection";
|
|
119198
119157
|
return DRAG_MODE2;
|
|
119199
119158
|
})(DRAG_MODE || {});
|
|
119200
119159
|
var DEFAULT_OPTIONS = {
|
|
@@ -119264,27 +119223,10 @@ var DEFAULT_OPTIONS = {
|
|
|
119264
119223
|
renderOverlayBlend: 1,
|
|
119265
119224
|
sliceMosaicString: "",
|
|
119266
119225
|
centerMosaic: false,
|
|
119267
|
-
penSize: 1,
|
|
119268
|
-
// in voxels, since all drawing is done using bitmap indices
|
|
119269
119226
|
clickToSegment: false,
|
|
119270
|
-
clickToSegmentRadius:
|
|
119271
|
-
|
|
119272
|
-
clickToSegmentBright: true
|
|
119273
|
-
clickToSegmentAutoIntensity: false,
|
|
119274
|
-
// new option, but keep clickToSegmentBright for backwards compatibility
|
|
119275
|
-
clickToSegmentIntensityMax: NaN,
|
|
119276
|
-
// NaN will use auto threshold (default flood fill behavior from before)
|
|
119277
|
-
clickToSegmentIntensityMin: NaN,
|
|
119278
|
-
// NaN will use auto threshold (default flood fill behavior from before)
|
|
119279
|
-
// 0 will use auto threshold (default flood fill behavior from before)
|
|
119280
|
-
// Take the voxel intensity at the click point and use this percentage +/- to threshold the flood fill operation.
|
|
119281
|
-
// If greater than 0, clickedVoxelIntensity +/- clickedVoxelIntensity * clickToSegmentPercent will be used
|
|
119282
|
-
// for the clickToSegmentIntensityMin and clickToSegmentIntensityMax values.
|
|
119283
|
-
clickToSegmentPercent: 0,
|
|
119284
|
-
clickToSegmentMaxDistanceMM: Number.POSITIVE_INFINITY,
|
|
119285
|
-
// default value is infinity for backwards compatibility with flood fill routine.
|
|
119286
|
-
selectionBoxLineThickness: 4,
|
|
119287
|
-
selectionBoxIsOutline: false
|
|
119227
|
+
clickToSegmentRadius: 2,
|
|
119228
|
+
clickToSegmentSteps: 10,
|
|
119229
|
+
clickToSegmentBright: true
|
|
119288
119230
|
};
|
|
119289
119231
|
var INITIAL_SCENE_DATA = {
|
|
119290
119232
|
gamma: 1,
|
|
@@ -120978,11 +120920,12 @@ var defaultSaveImageOptions = {
|
|
|
120978
120920
|
isSaveDrawing: false,
|
|
120979
120921
|
volumeByIndex: 0
|
|
120980
120922
|
};
|
|
120981
|
-
var Niivue = class {
|
|
120923
|
+
var Niivue = class _Niivue {
|
|
120982
120924
|
/**
|
|
120983
120925
|
* @param options - options object to set modifiable Niivue properties
|
|
120984
120926
|
*/
|
|
120985
120927
|
constructor(options = DEFAULT_OPTIONS) {
|
|
120928
|
+
__publicField(this, "loaders", {});
|
|
120986
120929
|
__publicField(this, "canvas", null);
|
|
120987
120930
|
// the reference to the canvas element on the page
|
|
120988
120931
|
__publicField(this, "_gl", null);
|
|
@@ -121025,7 +120968,6 @@ var Niivue = class {
|
|
|
121025
120968
|
__publicField(this, "orientCubeShader");
|
|
121026
120969
|
__publicField(this, "orientCubeShaderVAO", null);
|
|
121027
120970
|
__publicField(this, "rectShader");
|
|
121028
|
-
__publicField(this, "rectOutlineShader");
|
|
121029
120971
|
__publicField(this, "renderShader");
|
|
121030
120972
|
__publicField(this, "lineShader");
|
|
121031
120973
|
__publicField(this, "line3DShader");
|
|
@@ -121078,20 +121020,7 @@ var Niivue = class {
|
|
|
121078
121020
|
__publicField(this, "extentsMax");
|
|
121079
121021
|
// ResizeObserver
|
|
121080
121022
|
__publicField(this, "resizeObserver", null);
|
|
121081
|
-
|
|
121082
|
-
__publicField(this, "syncOpts", {
|
|
121083
|
-
"3d": false,
|
|
121084
|
-
// legacy option
|
|
121085
|
-
"2d": false,
|
|
121086
|
-
// legacy option
|
|
121087
|
-
zoomPan: false,
|
|
121088
|
-
cal_min: false,
|
|
121089
|
-
cal_max: false,
|
|
121090
|
-
clipPlane: false,
|
|
121091
|
-
gamma: false,
|
|
121092
|
-
sliceType: false,
|
|
121093
|
-
crosshair: false
|
|
121094
|
-
});
|
|
121023
|
+
__publicField(this, "syncOpts", {});
|
|
121095
121024
|
__publicField(this, "readyForSync", false);
|
|
121096
121025
|
// UI Data
|
|
121097
121026
|
__publicField(this, "uiData", {
|
|
@@ -121570,9 +121499,6 @@ var Niivue = class {
|
|
|
121570
121499
|
* @see {@link https://niivue.github.io/niivue/features/sync.mesh.html | live demo usage}
|
|
121571
121500
|
*/
|
|
121572
121501
|
syncWith(otherNV, syncOpts = { "2d": true, "3d": true }) {
|
|
121573
|
-
if (!(otherNV instanceof Array)) {
|
|
121574
|
-
otherNV = [otherNV];
|
|
121575
|
-
}
|
|
121576
121502
|
this.otherNV = otherNV;
|
|
121577
121503
|
this.syncOpts = { ...syncOpts };
|
|
121578
121504
|
}
|
|
@@ -121588,55 +121514,9 @@ var Niivue = class {
|
|
|
121588
121514
|
* @see {@link https://niivue.github.io/niivue/features/sync.mesh.html | live demo usage}
|
|
121589
121515
|
*/
|
|
121590
121516
|
broadcastTo(otherNV, syncOpts = { "2d": true, "3d": true }) {
|
|
121591
|
-
if (!(otherNV instanceof Array)) {
|
|
121592
|
-
otherNV = [otherNV];
|
|
121593
|
-
}
|
|
121594
121517
|
this.otherNV = otherNV;
|
|
121595
121518
|
this.syncOpts = syncOpts;
|
|
121596
121519
|
}
|
|
121597
|
-
doSync3d(otherNV) {
|
|
121598
|
-
otherNV.scene.renderAzimuth = this.scene.renderAzimuth;
|
|
121599
|
-
otherNV.scene.renderElevation = this.scene.renderElevation;
|
|
121600
|
-
otherNV.scene.volScaleMultiplier = this.scene.volScaleMultiplier;
|
|
121601
|
-
}
|
|
121602
|
-
// both crosshair and zoomPan
|
|
121603
|
-
doSync2d(otherNV) {
|
|
121604
|
-
const thisMM = this.frac2mm(this.scene.crosshairPos);
|
|
121605
|
-
otherNV.scene.crosshairPos = otherNV.mm2frac(thisMM);
|
|
121606
|
-
otherNV.scene.pan2Dxyzmm = vec4_exports.clone(this.scene.pan2Dxyzmm);
|
|
121607
|
-
}
|
|
121608
|
-
doSyncGamma(otherNV) {
|
|
121609
|
-
const thisGamma = this.scene.gamma;
|
|
121610
|
-
const otherGamma = otherNV.scene.gamma;
|
|
121611
|
-
if (thisGamma !== otherGamma) {
|
|
121612
|
-
otherNV.setGamma(thisGamma);
|
|
121613
|
-
}
|
|
121614
|
-
}
|
|
121615
|
-
doSyncZoomPan(otherNV) {
|
|
121616
|
-
otherNV.scene.pan2Dxyzmm = vec4_exports.clone(this.scene.pan2Dxyzmm);
|
|
121617
|
-
}
|
|
121618
|
-
doSyncCrosshair(otherNV) {
|
|
121619
|
-
const thisMM = this.frac2mm(this.scene.crosshairPos);
|
|
121620
|
-
otherNV.scene.crosshairPos = otherNV.mm2frac(thisMM);
|
|
121621
|
-
}
|
|
121622
|
-
doSyncCalMin(otherNV) {
|
|
121623
|
-
if (this.volumes[0].cal_min !== otherNV.volumes[0].cal_min) {
|
|
121624
|
-
otherNV.volumes[0].cal_min = this.volumes[0].cal_min;
|
|
121625
|
-
otherNV.updateGLVolume();
|
|
121626
|
-
}
|
|
121627
|
-
}
|
|
121628
|
-
doSyncCalMax(otherNV) {
|
|
121629
|
-
if (this.volumes[0].cal_max !== otherNV.volumes[0].cal_max) {
|
|
121630
|
-
otherNV.volumes[0].cal_max = this.volumes[0].cal_max;
|
|
121631
|
-
otherNV.updateGLVolume();
|
|
121632
|
-
}
|
|
121633
|
-
}
|
|
121634
|
-
doSyncSliceType(otherNV) {
|
|
121635
|
-
otherNV.setSliceType(this.opts.sliceType);
|
|
121636
|
-
}
|
|
121637
|
-
doSyncClipPlane(otherNV) {
|
|
121638
|
-
otherNV.setClipPlane(this.scene.clipPlaneDepthAziElev);
|
|
121639
|
-
}
|
|
121640
121520
|
/**
|
|
121641
121521
|
* Sync the scene controls (orientation, crosshair location, etc.) from one Niivue instance to another. useful for using one canvas to drive another.
|
|
121642
121522
|
* @internal
|
|
@@ -121653,39 +121533,46 @@ var Niivue = class {
|
|
|
121653
121533
|
if (!this.gl.canvas.matches(":focus")) {
|
|
121654
121534
|
return;
|
|
121655
121535
|
}
|
|
121656
|
-
|
|
121657
|
-
|
|
121658
|
-
|
|
121659
|
-
|
|
121660
|
-
if (
|
|
121661
|
-
this.
|
|
121662
|
-
}
|
|
121663
|
-
if (this.syncOpts.crosshair) {
|
|
121664
|
-
this.doSyncCrosshair(this.otherNV[i2]);
|
|
121665
|
-
}
|
|
121666
|
-
if (this.syncOpts.zoomPan) {
|
|
121667
|
-
this.doSyncZoomPan(this.otherNV[i2]);
|
|
121668
|
-
}
|
|
121669
|
-
if (this.syncOpts.sliceType) {
|
|
121670
|
-
this.doSyncSliceType(this.otherNV[i2]);
|
|
121671
|
-
}
|
|
121672
|
-
if (this.syncOpts.cal_min) {
|
|
121673
|
-
this.doSyncCalMin(this.otherNV[i2]);
|
|
121674
|
-
}
|
|
121675
|
-
if (this.syncOpts.cal_max) {
|
|
121676
|
-
this.doSyncCalMax(this.otherNV[i2]);
|
|
121677
|
-
}
|
|
121678
|
-
if (this.syncOpts.clipPlane) {
|
|
121679
|
-
this.doSyncClipPlane(this.otherNV[i2]);
|
|
121536
|
+
const thisMM = this.frac2mm(this.scene.crosshairPos);
|
|
121537
|
+
if (this.otherNV instanceof _Niivue) {
|
|
121538
|
+
const thisGamma = this.scene.gamma;
|
|
121539
|
+
const otherGamma = this.otherNV.scene.gamma;
|
|
121540
|
+
if (thisGamma !== otherGamma) {
|
|
121541
|
+
this.otherNV.setGamma(thisGamma);
|
|
121680
121542
|
}
|
|
121681
121543
|
if (this.syncOpts["2d"]) {
|
|
121682
|
-
this.
|
|
121544
|
+
this.otherNV.scene.crosshairPos = this.otherNV.mm2frac(thisMM);
|
|
121545
|
+
this.otherNV.scene.pan2Dxyzmm = vec4_exports.clone(this.scene.pan2Dxyzmm);
|
|
121683
121546
|
}
|
|
121684
121547
|
if (this.syncOpts["3d"]) {
|
|
121685
|
-
this.
|
|
121548
|
+
this.otherNV.scene.renderAzimuth = this.scene.renderAzimuth;
|
|
121549
|
+
this.otherNV.scene.renderElevation = this.scene.renderElevation;
|
|
121550
|
+
this.otherNV.scene.volScaleMultiplier = this.scene.volScaleMultiplier;
|
|
121551
|
+
}
|
|
121552
|
+
this.otherNV.drawScene();
|
|
121553
|
+
this.otherNV.createOnLocationChange();
|
|
121554
|
+
} else if (Array.isArray(this.otherNV)) {
|
|
121555
|
+
for (let i2 = 0; i2 < this.otherNV.length; i2++) {
|
|
121556
|
+
if (this.otherNV[i2] === this) {
|
|
121557
|
+
continue;
|
|
121558
|
+
}
|
|
121559
|
+
const thisGamma = this.scene.gamma;
|
|
121560
|
+
const otherGamma = this.otherNV[i2].scene.gamma;
|
|
121561
|
+
if (thisGamma !== otherGamma) {
|
|
121562
|
+
this.otherNV[i2].setGamma(thisGamma);
|
|
121563
|
+
}
|
|
121564
|
+
if (this.syncOpts["2d"]) {
|
|
121565
|
+
this.otherNV[i2].scene.crosshairPos = this.otherNV[i2].mm2frac(thisMM);
|
|
121566
|
+
this.otherNV[i2].scene.pan2Dxyzmm = vec4_exports.clone(this.scene.pan2Dxyzmm);
|
|
121567
|
+
}
|
|
121568
|
+
if (this.syncOpts["3d"]) {
|
|
121569
|
+
this.otherNV[i2].scene.renderAzimuth = this.scene.renderAzimuth;
|
|
121570
|
+
this.otherNV[i2].scene.renderElevation = this.scene.renderElevation;
|
|
121571
|
+
this.otherNV[i2].scene.volScaleMultiplier = this.scene.volScaleMultiplier;
|
|
121572
|
+
}
|
|
121573
|
+
this.otherNV[i2].drawScene();
|
|
121574
|
+
this.otherNV[i2].createOnLocationChange();
|
|
121686
121575
|
}
|
|
121687
|
-
this.otherNV[i2].drawScene();
|
|
121688
|
-
this.otherNV[i2].createOnLocationChange();
|
|
121689
121576
|
}
|
|
121690
121577
|
}
|
|
121691
121578
|
/** Not documented publicly for now
|
|
@@ -122002,9 +121889,6 @@ var Niivue = class {
|
|
|
122002
121889
|
const fracStart = this.canvasPos2frac([this.uiData.dragStart[0], this.uiData.dragStart[1]]);
|
|
122003
121890
|
const fracEnd = this.canvasPos2frac([this.uiData.dragEnd[0], this.uiData.dragEnd[1]]);
|
|
122004
121891
|
this.generateMouseUpCallback(fracStart, fracEnd);
|
|
122005
|
-
if (this.opts.dragMode === 6 /* roiSelection */) {
|
|
122006
|
-
return;
|
|
122007
|
-
}
|
|
122008
121892
|
if (this.opts.dragMode !== 1 /* contrast */) {
|
|
122009
121893
|
return;
|
|
122010
121894
|
}
|
|
@@ -122356,6 +122240,11 @@ var Niivue = class {
|
|
|
122356
122240
|
if (ext === "GZ") {
|
|
122357
122241
|
ext = re.exec(fullname.slice(0, -3))[1];
|
|
122358
122242
|
ext = ext.toUpperCase();
|
|
122243
|
+
} else if (ext === "CBOR") {
|
|
122244
|
+
const endExt = ext;
|
|
122245
|
+
ext = re.exec(fullname.slice(0, -5))[1];
|
|
122246
|
+
ext = ext.toUpperCase();
|
|
122247
|
+
ext = `${ext}.${endExt}`;
|
|
122359
122248
|
}
|
|
122360
122249
|
return upperCase ? ext : ext.toLowerCase();
|
|
122361
122250
|
}
|
|
@@ -122376,6 +122265,28 @@ var Niivue = class {
|
|
|
122376
122265
|
}
|
|
122377
122266
|
async addVolumesFromUrl(imageOptionsArray) {
|
|
122378
122267
|
const promises = imageOptionsArray.map(async (imageItem) => {
|
|
122268
|
+
const ext = this.getFileExt(imageItem.url);
|
|
122269
|
+
if (this.loaders[ext]) {
|
|
122270
|
+
let itemToLoad = imageItem.url;
|
|
122271
|
+
const toExt = this.loaders[ext].toExt;
|
|
122272
|
+
let name = imageItem.name || imageItem.url;
|
|
122273
|
+
name = name.split("/").pop();
|
|
122274
|
+
if (typeof imageItem.url === "string") {
|
|
122275
|
+
const url = imageItem.url;
|
|
122276
|
+
try {
|
|
122277
|
+
const response = await fetch(url);
|
|
122278
|
+
if (!response.ok) {
|
|
122279
|
+
throw new Error(`Failed to load file: ${response.statusText}`);
|
|
122280
|
+
}
|
|
122281
|
+
itemToLoad = await response.arrayBuffer();
|
|
122282
|
+
} catch (error) {
|
|
122283
|
+
throw new Error(`Failed to load url ${url}: ${error}`);
|
|
122284
|
+
}
|
|
122285
|
+
}
|
|
122286
|
+
const buffer2 = await this.loaders[ext].loader(itemToLoad);
|
|
122287
|
+
imageItem.url = buffer2;
|
|
122288
|
+
imageItem.name = `${name}.${toExt}`;
|
|
122289
|
+
}
|
|
122379
122290
|
const imageOptions = {
|
|
122380
122291
|
url: imageItem.url,
|
|
122381
122292
|
headers: imageItem.headers,
|
|
@@ -122515,6 +122426,40 @@ var Niivue = class {
|
|
|
122515
122426
|
this.addVolume(volume);
|
|
122516
122427
|
});
|
|
122517
122428
|
}
|
|
122429
|
+
/* useLoader
|
|
122430
|
+
|
|
122431
|
+
registers an external file loader for niivue to use when reading files.
|
|
122432
|
+
|
|
122433
|
+
the loader must return an array buffer of the file contents for niivue
|
|
122434
|
+
to parse and the extension of the file so niivue can infer the file type to load.
|
|
122435
|
+
|
|
122436
|
+
example:
|
|
122437
|
+
|
|
122438
|
+
const myCustomLoader = (File) => {
|
|
122439
|
+
// ... do parsing here ...
|
|
122440
|
+
return {
|
|
122441
|
+
arrayBuffer: ArrayBuffer,
|
|
122442
|
+
fileExt: 'iwi.cbor',
|
|
122443
|
+
positions: Float32Array | [], // allows for mesh loading to mz3
|
|
122444
|
+
indices: Uint32Array | [], // allows for mesh loading to mz3
|
|
122445
|
+
}
|
|
122446
|
+
|
|
122447
|
+
nv.useLoader({
|
|
122448
|
+
loader: myCustomLoader,
|
|
122449
|
+
fileExt: 'iwi.cbor',
|
|
122450
|
+
toExt: 'nii'
|
|
122451
|
+
})
|
|
122452
|
+
|
|
122453
|
+
*/
|
|
122454
|
+
useLoader(loader, fileExt, toExt) {
|
|
122455
|
+
this.loaders = {
|
|
122456
|
+
...this.loaders,
|
|
122457
|
+
[fileExt.toUpperCase()]: {
|
|
122458
|
+
loader,
|
|
122459
|
+
toExt
|
|
122460
|
+
}
|
|
122461
|
+
};
|
|
122462
|
+
}
|
|
122518
122463
|
// not included in public docs
|
|
122519
122464
|
dropListener(e) {
|
|
122520
122465
|
e.stopPropagation();
|
|
@@ -124186,6 +124131,37 @@ var Niivue = class {
|
|
|
124186
124131
|
this.document.meshes = this.meshes;
|
|
124187
124132
|
return this.document.download(fileName, compress);
|
|
124188
124133
|
}
|
|
124134
|
+
// generic loadImages that wraps loadVolumes and loadMeshes
|
|
124135
|
+
async loadImages(images) {
|
|
124136
|
+
const volumes = [];
|
|
124137
|
+
const meshes = [];
|
|
124138
|
+
for (const image of images) {
|
|
124139
|
+
if ("url" in image) {
|
|
124140
|
+
const ext = this.getFileExt(image.url);
|
|
124141
|
+
if (this.loaders[ext]) {
|
|
124142
|
+
const toExt = this.loaders[ext].toExt.toUpperCase();
|
|
124143
|
+
if (MESH_EXTENSIONS.includes(toExt)) {
|
|
124144
|
+
meshes.push(image);
|
|
124145
|
+
} else {
|
|
124146
|
+
volumes.push(image);
|
|
124147
|
+
}
|
|
124148
|
+
continue;
|
|
124149
|
+
}
|
|
124150
|
+
if (MESH_EXTENSIONS.includes(ext.toUpperCase())) {
|
|
124151
|
+
meshes.push(image);
|
|
124152
|
+
} else {
|
|
124153
|
+
volumes.push(image);
|
|
124154
|
+
}
|
|
124155
|
+
}
|
|
124156
|
+
}
|
|
124157
|
+
if (volumes.length > 0) {
|
|
124158
|
+
await this.loadVolumes(volumes);
|
|
124159
|
+
}
|
|
124160
|
+
if (meshes.length > 0) {
|
|
124161
|
+
await this.loadMeshes(meshes);
|
|
124162
|
+
}
|
|
124163
|
+
return this;
|
|
124164
|
+
}
|
|
124189
124165
|
/**
|
|
124190
124166
|
* load an array of volume objects
|
|
124191
124167
|
* @param volumeList - the array of objects to load. each object must have a resolvable "url" property at a minimum
|
|
@@ -124205,27 +124181,7 @@ var Niivue = class {
|
|
|
124205
124181
|
this.volumes = [];
|
|
124206
124182
|
this.gl.clearColor(0, 0, 0, 1);
|
|
124207
124183
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
124208
|
-
|
|
124209
|
-
await this.addVolumesFromUrl(volumeList);
|
|
124210
|
-
return this;
|
|
124211
|
-
}
|
|
124212
|
-
const imageOptions = {
|
|
124213
|
-
url: volumeList[0].url,
|
|
124214
|
-
headers: volumeList[0].headers,
|
|
124215
|
-
name: volumeList[0].name,
|
|
124216
|
-
colormap: volumeList[0].colormap ? volumeList[0].colormap : volumeList[0].colorMap,
|
|
124217
|
-
colormapNegative: volumeList[0].colormapNegative ? volumeList[0].colormapNegative : volumeList[0].colorMapNegative,
|
|
124218
|
-
opacity: volumeList[0].opacity,
|
|
124219
|
-
urlImgData: volumeList[0].urlImgData,
|
|
124220
|
-
cal_min: volumeList[0].cal_min,
|
|
124221
|
-
cal_max: volumeList[0].cal_max,
|
|
124222
|
-
trustCalMinMax: this.opts.trustCalMinMax,
|
|
124223
|
-
isManifest: volumeList[0].isManifest,
|
|
124224
|
-
frame4D: volumeList[0].frame4D,
|
|
124225
|
-
limitFrames4D: volumeList[0].limitFrames4D || this.opts.limitFrames4D,
|
|
124226
|
-
colorbarVisible: volumeList[0].colorbarVisible
|
|
124227
|
-
};
|
|
124228
|
-
await this.addVolumeFromUrl(imageOptions);
|
|
124184
|
+
await this.addVolumesFromUrl(volumeList);
|
|
124229
124185
|
return this;
|
|
124230
124186
|
}
|
|
124231
124187
|
/**
|
|
@@ -124256,6 +124212,28 @@ var Niivue = class {
|
|
|
124256
124212
|
async addMeshesFromUrl(meshOptions) {
|
|
124257
124213
|
const promises = meshOptions.map(async (meshItem) => {
|
|
124258
124214
|
const ext = this.getFileExt(meshItem.url);
|
|
124215
|
+
if (this.loaders[ext]) {
|
|
124216
|
+
let itemToLoad = meshItem.url;
|
|
124217
|
+
const toExt = this.loaders[ext].toExt;
|
|
124218
|
+
let name = meshItem.name || meshItem.url;
|
|
124219
|
+
name = name.split("/").pop();
|
|
124220
|
+
if (typeof meshItem.url === "string") {
|
|
124221
|
+
const url = meshItem.url;
|
|
124222
|
+
try {
|
|
124223
|
+
const response = await fetch(url);
|
|
124224
|
+
if (!response.ok) {
|
|
124225
|
+
throw new Error(`Failed to load file: ${response.statusText}`);
|
|
124226
|
+
}
|
|
124227
|
+
itemToLoad = await response.arrayBuffer();
|
|
124228
|
+
} catch (error) {
|
|
124229
|
+
throw new Error(`Failed to load url ${url}: ${error}`);
|
|
124230
|
+
}
|
|
124231
|
+
}
|
|
124232
|
+
const { positions, indices } = await this.loaders[ext].loader(itemToLoad);
|
|
124233
|
+
meshItem.name = `${name}.${toExt}`;
|
|
124234
|
+
const mz3 = NVMeshUtilities.createMZ3(positions, indices, false);
|
|
124235
|
+
meshItem.buffer = mz3;
|
|
124236
|
+
}
|
|
124259
124237
|
if (ext === "JCON" || ext === "JSON") {
|
|
124260
124238
|
const response = await fetch(meshItem.url, {});
|
|
124261
124239
|
const json = await response.json();
|
|
@@ -124296,13 +124274,7 @@ var Niivue = class {
|
|
|
124296
124274
|
this.meshes = [];
|
|
124297
124275
|
this.gl.clearColor(0, 0, 0, 1);
|
|
124298
124276
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
124299
|
-
|
|
124300
|
-
await this.addMeshesFromUrl(meshList);
|
|
124301
|
-
this.updateGLVolume();
|
|
124302
|
-
this.drawScene();
|
|
124303
|
-
return this;
|
|
124304
|
-
}
|
|
124305
|
-
await this.addMeshFromUrl(meshList[0]);
|
|
124277
|
+
await this.addMeshesFromUrl(meshList);
|
|
124306
124278
|
this.updateGLVolume();
|
|
124307
124279
|
this.drawScene();
|
|
124308
124280
|
return this;
|
|
@@ -124576,23 +124548,6 @@ var Niivue = class {
|
|
|
124576
124548
|
y = Math.min(Math.max(y, 0), dy - 1);
|
|
124577
124549
|
z = Math.min(Math.max(z, 0), dz - 1);
|
|
124578
124550
|
this.drawBitmap[x + y * dx + z * dx * dy] = penValue;
|
|
124579
|
-
const isAx = this.drawPenAxCorSag === 0;
|
|
124580
|
-
const isCor = this.drawPenAxCorSag === 1;
|
|
124581
|
-
const isSag = this.drawPenAxCorSag === 2;
|
|
124582
|
-
if (this.opts.penSize > 1) {
|
|
124583
|
-
const halfPenSize = Math.floor(this.opts.penSize / 2);
|
|
124584
|
-
for (let i2 = -halfPenSize; i2 <= halfPenSize; i2++) {
|
|
124585
|
-
for (let j = -halfPenSize; j <= halfPenSize; j++) {
|
|
124586
|
-
if (isAx) {
|
|
124587
|
-
this.drawBitmap[x + i2 + (y + j) * dx + z * dx * dy] = penValue;
|
|
124588
|
-
} else if (isCor) {
|
|
124589
|
-
this.drawBitmap[x + i2 + y * dx + (z + j) * dx * dy] = penValue;
|
|
124590
|
-
} else if (isSag) {
|
|
124591
|
-
this.drawBitmap[x + (y + j) * dx + (z + i2) * dx * dy] = penValue;
|
|
124592
|
-
}
|
|
124593
|
-
}
|
|
124594
|
-
}
|
|
124595
|
-
}
|
|
124596
124551
|
}
|
|
124597
124552
|
// not included in public docs
|
|
124598
124553
|
// create line between to voxels in drawing
|
|
@@ -124674,98 +124629,6 @@ var Niivue = class {
|
|
|
124674
124629
|
}
|
|
124675
124630
|
}
|
|
124676
124631
|
}
|
|
124677
|
-
/**
|
|
124678
|
-
* Performs a 1-voxel binary dilation on a connected cluster within the drawing mask using the drawFloodFillCore function.
|
|
124679
|
-
*
|
|
124680
|
-
* @param seedXYZ - voxel index of the seed voxel in the mask array.
|
|
124681
|
-
* @param neighbors - Number of neighbors to consider for connectivity and dilation (6, 18, or 26).
|
|
124682
|
-
*/
|
|
124683
|
-
drawingBinaryDilationWithSeed(seedXYZ, neighbors = 6) {
|
|
124684
|
-
try {
|
|
124685
|
-
let xyz2vx = function(pt) {
|
|
124686
|
-
return pt[0] + pt[1] * nx + pt[2] * nxy;
|
|
124687
|
-
};
|
|
124688
|
-
const mask = this.drawBitmap;
|
|
124689
|
-
const xDim = this.back.dims[1];
|
|
124690
|
-
const yDim = this.back.dims[2];
|
|
124691
|
-
const zDim = this.back.dims[3];
|
|
124692
|
-
const nx = xDim;
|
|
124693
|
-
const nxy = xDim * yDim;
|
|
124694
|
-
const totalVoxels = nxy * zDim;
|
|
124695
|
-
const seedIndex = xyz2vx(seedXYZ);
|
|
124696
|
-
if (seedIndex < 0 || seedIndex >= totalVoxels) {
|
|
124697
|
-
throw new Error("Seed index is out of bounds.");
|
|
124698
|
-
}
|
|
124699
|
-
const seedValue = mask[seedIndex];
|
|
124700
|
-
if (seedValue === 0) {
|
|
124701
|
-
throw new Error("Seed voxel is not part of a filled cluster.");
|
|
124702
|
-
}
|
|
124703
|
-
const img = mask.slice();
|
|
124704
|
-
for (let i2 = 0; i2 < totalVoxels; i2++) {
|
|
124705
|
-
img[i2] = img[i2] === seedValue ? 1 : 0;
|
|
124706
|
-
}
|
|
124707
|
-
this.drawFloodFillCore(img, seedIndex, neighbors);
|
|
124708
|
-
const outputMask = mask.slice();
|
|
124709
|
-
const neighborOffsets = [];
|
|
124710
|
-
const offsets6 = [-nxy, nxy, -xDim, xDim, -1, 1];
|
|
124711
|
-
neighborOffsets.push(...offsets6);
|
|
124712
|
-
if (neighbors > 6) {
|
|
124713
|
-
neighborOffsets.push(
|
|
124714
|
-
-xDim - 1,
|
|
124715
|
-
-xDim + 1,
|
|
124716
|
-
xDim - 1,
|
|
124717
|
-
xDim + 1,
|
|
124718
|
-
-nxy - xDim,
|
|
124719
|
-
-nxy + xDim,
|
|
124720
|
-
-nxy - 1,
|
|
124721
|
-
-nxy + 1,
|
|
124722
|
-
nxy - xDim,
|
|
124723
|
-
nxy + xDim,
|
|
124724
|
-
nxy - 1,
|
|
124725
|
-
nxy + 1
|
|
124726
|
-
);
|
|
124727
|
-
}
|
|
124728
|
-
if (neighbors > 18) {
|
|
124729
|
-
neighborOffsets.push(
|
|
124730
|
-
-nxy - xDim - 1,
|
|
124731
|
-
-nxy - xDim + 1,
|
|
124732
|
-
-nxy + xDim - 1,
|
|
124733
|
-
-nxy + xDim + 1,
|
|
124734
|
-
nxy - xDim - 1,
|
|
124735
|
-
nxy - xDim + 1,
|
|
124736
|
-
nxy + xDim - 1,
|
|
124737
|
-
nxy + xDim + 1
|
|
124738
|
-
);
|
|
124739
|
-
}
|
|
124740
|
-
for (let idx = 0; idx < totalVoxels; idx++) {
|
|
124741
|
-
if (img[idx] === 2) {
|
|
124742
|
-
const x = idx % xDim;
|
|
124743
|
-
const y = Math.floor(idx % nxy / xDim);
|
|
124744
|
-
const z = Math.floor(idx / nxy);
|
|
124745
|
-
for (const offset of neighborOffsets) {
|
|
124746
|
-
const neighborIdx = idx + offset;
|
|
124747
|
-
if (neighborIdx < 0 || neighborIdx >= totalVoxels) {
|
|
124748
|
-
continue;
|
|
124749
|
-
}
|
|
124750
|
-
const nx2 = neighborIdx % xDim;
|
|
124751
|
-
const ny = Math.floor(neighborIdx % nxy / xDim);
|
|
124752
|
-
const nz = Math.floor(neighborIdx / nxy);
|
|
124753
|
-
if (Math.abs(nx2 - x) > 1 || Math.abs(ny - y) > 1 || Math.abs(nz - z) > 1) {
|
|
124754
|
-
continue;
|
|
124755
|
-
}
|
|
124756
|
-
if (mask[neighborIdx] === 0) {
|
|
124757
|
-
outputMask[neighborIdx] = seedValue;
|
|
124758
|
-
}
|
|
124759
|
-
}
|
|
124760
|
-
}
|
|
124761
|
-
}
|
|
124762
|
-
this.drawBitmap = outputMask;
|
|
124763
|
-
this.drawAddUndoBitmap();
|
|
124764
|
-
this.refreshDrawing(true);
|
|
124765
|
-
} catch (error) {
|
|
124766
|
-
log.error("Error in drawingBinaryDilationWithSeed:", error);
|
|
124767
|
-
}
|
|
124768
|
-
}
|
|
124769
124632
|
// a voxel can be defined as having 6, 18 or 26 neighbors:
|
|
124770
124633
|
// 6: neighbors share faces (distance=1)
|
|
124771
124634
|
// 18: neighbors share faces (distance=1) or edges (1.4)
|
|
@@ -124847,7 +124710,7 @@ var Niivue = class {
|
|
|
124847
124710
|
}
|
|
124848
124711
|
// not included in public docs
|
|
124849
124712
|
// set all connected voxels in drawing to new color
|
|
124850
|
-
drawFloodFill(seedXYZ, newColor = 0, growSelectedCluster = 0, forceMin = NaN, forceMax = NaN, neighbors = 6
|
|
124713
|
+
drawFloodFill(seedXYZ, newColor = 0, growSelectedCluster = 0, forceMin = NaN, forceMax = NaN, neighbors = 6) {
|
|
124851
124714
|
if (!this.drawBitmap) {
|
|
124852
124715
|
throw new Error("drawBitmap undefined");
|
|
124853
124716
|
}
|
|
@@ -124869,25 +124732,9 @@ var Niivue = class {
|
|
|
124869
124732
|
if (img.length !== nxy * dims[2]) {
|
|
124870
124733
|
return;
|
|
124871
124734
|
}
|
|
124872
|
-
function vx2xyz(vx) {
|
|
124873
|
-
const Z = Math.floor(vx / nxy);
|
|
124874
|
-
const Y = Math.floor((vx - Z * nxy) / nx);
|
|
124875
|
-
const X = Math.floor(vx % nx);
|
|
124876
|
-
return [X, Y, Z];
|
|
124877
|
-
}
|
|
124878
124735
|
function xyz2vx(pt) {
|
|
124879
124736
|
return pt[0] + pt[1] * nx + pt[2] * nxy;
|
|
124880
124737
|
}
|
|
124881
|
-
const vx2mm = (xyz) => {
|
|
124882
|
-
return this.vox2mm(xyz, this.back.matRAS);
|
|
124883
|
-
};
|
|
124884
|
-
const seedMM = vx2mm(seedXYZ);
|
|
124885
|
-
const maxDistanceMM2 = maxDistanceMM ** 2;
|
|
124886
|
-
function isWithinDistance(vx) {
|
|
124887
|
-
const xyzMM = vx2mm(vx2xyz(vx));
|
|
124888
|
-
const dist22 = (xyzMM[0] - seedMM[0]) ** 2 + (xyzMM[1] - seedMM[1]) ** 2 + (xyzMM[2] - seedMM[2]) ** 2;
|
|
124889
|
-
return dist22 <= maxDistanceMM2;
|
|
124890
|
-
}
|
|
124891
124738
|
const seedVx = xyz2vx(seedXYZ);
|
|
124892
124739
|
const seedColor = img[seedVx];
|
|
124893
124740
|
if (seedColor === newColor) {
|
|
@@ -124901,9 +124748,6 @@ var Niivue = class {
|
|
|
124901
124748
|
for (let i2 = 1; i2 < nxyz; i2++) {
|
|
124902
124749
|
img[i2] = 0;
|
|
124903
124750
|
if (this.drawBitmap[i2] === seedColor) {
|
|
124904
|
-
if (!isWithinDistance(i2)) {
|
|
124905
|
-
continue;
|
|
124906
|
-
}
|
|
124907
124751
|
img[i2] = 1;
|
|
124908
124752
|
}
|
|
124909
124753
|
}
|
|
@@ -124933,9 +124777,6 @@ var Niivue = class {
|
|
|
124933
124777
|
for (let i2 = 1; i2 < nxyz; i2++) {
|
|
124934
124778
|
img[i2] = 0;
|
|
124935
124779
|
if (backImg[i2] >= mn && backImg[i2] <= mx) {
|
|
124936
|
-
if (!isWithinDistance(i2)) {
|
|
124937
|
-
continue;
|
|
124938
|
-
}
|
|
124939
124780
|
img[i2] = 1;
|
|
124940
124781
|
}
|
|
124941
124782
|
}
|
|
@@ -125557,8 +125398,6 @@ var Niivue = class {
|
|
|
125557
125398
|
gl.bindVertexArray(this.unusedVAO);
|
|
125558
125399
|
this.rectShader = new Shader(gl, vertRectShader, fragRectShader);
|
|
125559
125400
|
this.rectShader.use(gl);
|
|
125560
|
-
this.rectOutlineShader = new Shader(gl, vertRectShader, fragRectOutlineShader);
|
|
125561
|
-
this.rectOutlineShader.use(gl);
|
|
125562
125401
|
this.lineShader = new Shader(gl, vertLineShader, fragRectShader);
|
|
125563
125402
|
this.lineShader.use(gl);
|
|
125564
125403
|
this.line3DShader = new Shader(gl, vertLine3DShader, fragRectShader);
|
|
@@ -125711,37 +125550,14 @@ var Niivue = class {
|
|
|
125711
125550
|
}
|
|
125712
125551
|
/**
|
|
125713
125552
|
* basic statistics for selected voxel-based image
|
|
125714
|
-
* @param
|
|
125715
|
-
*
|
|
125716
|
-
*
|
|
125717
|
-
*
|
|
125718
|
-
* - roiIsMask: a boolean indicating if the ROI is used as a mask
|
|
125719
|
-
* - startVox: the starting voxel coordinates
|
|
125720
|
-
* - endVox: the ending voxel coordinates
|
|
125721
|
-
* @returns numeric values to describe image or regions of images
|
|
125722
|
-
* @example
|
|
125723
|
-
* niivue.getDescriptives({
|
|
125724
|
-
* layer: 0,
|
|
125725
|
-
* masks: [],
|
|
125726
|
-
* drawingIsMask: true, // drawingIsMask and roiIsMask are mutually exclusive
|
|
125727
|
-
* roiIsMask: false,
|
|
125728
|
-
* startVox: [10, 20, 30], // ignored if roiIsMask is false
|
|
125729
|
-
* endVox: [40, 50, 60] // ignored if roiIsMask is false
|
|
125730
|
-
* });
|
|
125553
|
+
* @param layer - selects image to describe
|
|
125554
|
+
* @param masks - are optional binary images to filter voxles
|
|
125555
|
+
* @returns numeric values to describe image
|
|
125556
|
+
* @example niivue.getDescriptives(0);
|
|
125731
125557
|
* @see {@link https://niivue.github.io/niivue/features/draw2.html | live demo usage}
|
|
125732
125558
|
*/
|
|
125733
|
-
getDescriptives(
|
|
125734
|
-
const {
|
|
125735
|
-
layer = 0,
|
|
125736
|
-
masks = [],
|
|
125737
|
-
drawingIsMask = false,
|
|
125738
|
-
roiIsMask = false,
|
|
125739
|
-
startVox = [0, 0, 0],
|
|
125740
|
-
endVox = [0, 0, 0]
|
|
125741
|
-
} = options;
|
|
125742
|
-
let area = null;
|
|
125559
|
+
getDescriptives(layer = 0, masks = [], drawingIsMask = false) {
|
|
125743
125560
|
const hdr = this.volumes[layer].hdr;
|
|
125744
|
-
const pixDimsRAS = this.volumes[layer].pixDimsRAS;
|
|
125745
125561
|
let slope = hdr.scl_slope;
|
|
125746
125562
|
if (isNaN(slope)) {
|
|
125747
125563
|
slope = 1;
|
|
@@ -125779,37 +125595,6 @@ var Niivue = class {
|
|
|
125779
125595
|
mask[i2] = 0;
|
|
125780
125596
|
}
|
|
125781
125597
|
}
|
|
125782
|
-
} else if (masks.length < 1 && roiIsMask) {
|
|
125783
|
-
mask.fill(0);
|
|
125784
|
-
console.log("startVox", startVox);
|
|
125785
|
-
console.log("endVox", endVox);
|
|
125786
|
-
const xrange = this.calculateMinMaxVoxIdx([startVox[0], endVox[0]]);
|
|
125787
|
-
const yrange = this.calculateMinMaxVoxIdx([startVox[1], endVox[1]]);
|
|
125788
|
-
const zrange = this.calculateMinMaxVoxIdx([startVox[2], endVox[2]]);
|
|
125789
|
-
if (startVox[0] - endVox[0] === 0) {
|
|
125790
|
-
xrange[1] = startVox[0] + 1;
|
|
125791
|
-
} else if (startVox[1] - endVox[1] === 0) {
|
|
125792
|
-
yrange[1] = startVox[1] + 1;
|
|
125793
|
-
} else if (startVox[2] - endVox[2] === 0) {
|
|
125794
|
-
zrange[1] = startVox[2] + 1;
|
|
125795
|
-
}
|
|
125796
|
-
const xdim = hdr.dims[1];
|
|
125797
|
-
const ydim = hdr.dims[2];
|
|
125798
|
-
for (let z = zrange[0]; z < zrange[1]; z++) {
|
|
125799
|
-
const zi = z * xdim * ydim;
|
|
125800
|
-
for (let y = yrange[0]; y < yrange[1]; y++) {
|
|
125801
|
-
const yi = y * xdim;
|
|
125802
|
-
for (let x = xrange[0]; x < xrange[1]; x++) {
|
|
125803
|
-
const index = zi + yi + x;
|
|
125804
|
-
mask[index] = 1;
|
|
125805
|
-
}
|
|
125806
|
-
}
|
|
125807
|
-
}
|
|
125808
|
-
const xmm = Math.abs(pixDimsRAS[1] * (endVox[0] - startVox[0]));
|
|
125809
|
-
const ymm = Math.abs(pixDimsRAS[2] * (endVox[1] - startVox[1]));
|
|
125810
|
-
const zmm = Math.abs(pixDimsRAS[3] * (endVox[2] - startVox[2]));
|
|
125811
|
-
const mms = [xmm, ymm, zmm];
|
|
125812
|
-
area = mms.filter((m) => m !== 0).reduce((a, b) => a * b, 1);
|
|
125813
125598
|
}
|
|
125814
125599
|
let k = 0;
|
|
125815
125600
|
let M = 0;
|
|
@@ -125863,8 +125648,7 @@ var Niivue = class {
|
|
|
125863
125648
|
cal_min: this.volumes[layer].cal_min,
|
|
125864
125649
|
cal_max: this.volumes[layer].cal_max,
|
|
125865
125650
|
robust_min: this.volumes[layer].robust_min,
|
|
125866
|
-
robust_max: this.volumes[layer].robust_max
|
|
125867
|
-
area
|
|
125651
|
+
robust_max: this.volumes[layer].robust_max
|
|
125868
125652
|
};
|
|
125869
125653
|
}
|
|
125870
125654
|
// not included in public docs
|
|
@@ -127419,51 +127203,30 @@ var Niivue = class {
|
|
|
127419
127203
|
}
|
|
127420
127204
|
if (this.opts.drawingEnabled) {
|
|
127421
127205
|
const pt = this.frac2vox(this.scene.crosshairPos);
|
|
127206
|
+
const ptMM = this.frac2mm(this.scene.crosshairPos);
|
|
127422
127207
|
if (this.opts.clickToSegment) {
|
|
127423
|
-
const
|
|
127424
|
-
|
|
127425
|
-
this.opts.clickToSegmentIntensityMax = voxelIntensity * (1 + this.opts.clickToSegmentPercent);
|
|
127426
|
-
this.opts.clickToSegmentIntensityMin = voxelIntensity * (1 - this.opts.clickToSegmentPercent);
|
|
127427
|
-
}
|
|
127428
|
-
if (this.opts.clickToSegmentAutoIntensity) {
|
|
127429
|
-
if (voxelIntensity > (this.back.cal_min + this.back.cal_max) * 0.5) {
|
|
127430
|
-
this.opts.clickToSegmentBright = true;
|
|
127431
|
-
} else {
|
|
127432
|
-
this.opts.clickToSegmentBright = false;
|
|
127433
|
-
}
|
|
127434
|
-
}
|
|
127208
|
+
const radius = this.opts.clickToSegmentRadius;
|
|
127209
|
+
const steps = this.opts.clickToSegmentSteps;
|
|
127435
127210
|
const brightOrDark = this.opts.clickToSegmentBright ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
|
|
127211
|
+
this.drawPenFillPts = [];
|
|
127436
127212
|
this.drawPenAxCorSag = axCorSag;
|
|
127437
|
-
|
|
127438
|
-
const
|
|
127439
|
-
const
|
|
127440
|
-
|
|
127441
|
-
|
|
127442
|
-
const
|
|
127443
|
-
const
|
|
127444
|
-
|
|
127445
|
-
|
|
127446
|
-
|
|
127447
|
-
|
|
127448
|
-
|
|
127449
|
-
|
|
127450
|
-
|
|
127451
|
-
this.drawFloodFill(
|
|
127452
|
-
[pt[0], pt[1], pt[2]],
|
|
127453
|
-
0,
|
|
127454
|
-
brightOrDark,
|
|
127455
|
-
this.opts.clickToSegmentIntensityMin,
|
|
127456
|
-
this.opts.clickToSegmentIntensityMax,
|
|
127457
|
-
this.opts.floodFillNeighbors,
|
|
127458
|
-
this.opts.clickToSegmentMaxDistanceMM
|
|
127459
|
-
);
|
|
127213
|
+
for (let i3 = 1; i3 <= steps; i3++) {
|
|
127214
|
+
const angle3 = i3 / steps * 2 * Math.PI;
|
|
127215
|
+
const xMM = ptMM[0] + radius * Math.cos(angle3);
|
|
127216
|
+
const yMM = ptMM[1] + radius * Math.sin(angle3);
|
|
127217
|
+
const zMM = ptMM[2];
|
|
127218
|
+
const xVox = this.back.mm2vox([xMM, yMM, zMM])[0];
|
|
127219
|
+
const yVox = this.back.mm2vox([xMM, yMM, zMM])[1];
|
|
127220
|
+
const zVox = this.back.mm2vox([xMM, yMM, zMM])[2];
|
|
127221
|
+
this.drawPt(xVox, yVox, zVox, this.opts.penValue);
|
|
127222
|
+
this.drawPenFillPts.push([xVox, yVox, pt[2]]);
|
|
127223
|
+
if (i3 === steps) {
|
|
127224
|
+
this.drawFloodFill([xVox, yVox, pt[2]], 0, brightOrDark, NaN, NaN, this.opts.floodFillNeighbors);
|
|
127225
|
+
}
|
|
127226
|
+
}
|
|
127460
127227
|
this.drawScene();
|
|
127461
127228
|
this.createOnLocationChange(axCorSag);
|
|
127462
|
-
const info = this.getDescriptives(
|
|
127463
|
-
layer: 0,
|
|
127464
|
-
masks: [],
|
|
127465
|
-
drawingIsMask: true
|
|
127466
|
-
});
|
|
127229
|
+
const info = this.getDescriptives(0, [], true);
|
|
127467
127230
|
this.onClickToSegment({ mL: info.volumeML, mm3: info.volumeMM3 });
|
|
127468
127231
|
return;
|
|
127469
127232
|
}
|
|
@@ -127681,41 +127444,20 @@ var Niivue = class {
|
|
|
127681
127444
|
if (!this.rectShader) {
|
|
127682
127445
|
throw new Error("rectShader undefined");
|
|
127683
127446
|
}
|
|
127684
|
-
|
|
127685
|
-
|
|
127686
|
-
|
|
127687
|
-
|
|
127688
|
-
|
|
127689
|
-
this.
|
|
127690
|
-
|
|
127691
|
-
|
|
127692
|
-
|
|
127693
|
-
|
|
127694
|
-
|
|
127695
|
-
|
|
127696
|
-
|
|
127697
|
-
|
|
127698
|
-
this.gl.bindVertexArray(this.unusedVAO);
|
|
127699
|
-
} else {
|
|
127700
|
-
this.rectOutlineShader.use(this.gl);
|
|
127701
|
-
this.gl.enable(this.gl.BLEND);
|
|
127702
|
-
this.gl.uniform1f(this.rectOutlineShader.uniforms.thickness, this.opts.selectionBoxLineThickness);
|
|
127703
|
-
this.gl.uniform4fv(this.rectOutlineShader.uniforms.lineColor, lineColor);
|
|
127704
|
-
this.gl.uniform2fv(this.rectOutlineShader.uniforms.canvasWidthHeight, [
|
|
127705
|
-
this.gl.canvas.width,
|
|
127706
|
-
this.gl.canvas.height
|
|
127707
|
-
]);
|
|
127708
|
-
this.gl.uniform4f(
|
|
127709
|
-
this.rectOutlineShader.uniforms.leftTopWidthHeight,
|
|
127710
|
-
leftTopWidthHeight[0],
|
|
127711
|
-
leftTopWidthHeight[1],
|
|
127712
|
-
leftTopWidthHeight[2],
|
|
127713
|
-
leftTopWidthHeight[3]
|
|
127714
|
-
);
|
|
127715
|
-
this.gl.bindVertexArray(this.genericVAO);
|
|
127716
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
127717
|
-
this.gl.bindVertexArray(this.unusedVAO);
|
|
127718
|
-
}
|
|
127447
|
+
this.rectShader.use(this.gl);
|
|
127448
|
+
this.gl.enable(this.gl.BLEND);
|
|
127449
|
+
this.gl.uniform4fv(this.rectShader.uniforms.lineColor, lineColor);
|
|
127450
|
+
this.gl.uniform2fv(this.rectShader.uniforms.canvasWidthHeight, [this.gl.canvas.width, this.gl.canvas.height]);
|
|
127451
|
+
this.gl.uniform4f(
|
|
127452
|
+
this.rectShader.uniforms.leftTopWidthHeight,
|
|
127453
|
+
leftTopWidthHeight[0],
|
|
127454
|
+
leftTopWidthHeight[1],
|
|
127455
|
+
leftTopWidthHeight[2],
|
|
127456
|
+
leftTopWidthHeight[3]
|
|
127457
|
+
);
|
|
127458
|
+
this.gl.bindVertexArray(this.genericVAO);
|
|
127459
|
+
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
127460
|
+
this.gl.bindVertexArray(this.unusedVAO);
|
|
127719
127461
|
}
|
|
127720
127462
|
drawCircle(leftTopWidthHeight, circleColor = this.opts.fontColor, fillPercent = 1) {
|
|
127721
127463
|
if (!this.circleShader) {
|
|
@@ -130417,14 +130159,10 @@ var Niivue = class {
|
|
|
130417
130159
|
width,
|
|
130418
130160
|
height
|
|
130419
130161
|
]);
|
|
130420
|
-
return;
|
|
130421
130162
|
}
|
|
130422
130163
|
if (this.opts.clickToSegment) {
|
|
130423
130164
|
const x = this.mousePos[0];
|
|
130424
130165
|
const y = this.mousePos[1];
|
|
130425
|
-
if (this.inRenderTile(x, y) >= 0) {
|
|
130426
|
-
return;
|
|
130427
|
-
}
|
|
130428
130166
|
const tileIdx = this.tileIndex(x, y);
|
|
130429
130167
|
if (tileIdx > -1) {
|
|
130430
130168
|
const fovMM = this.screenSlices[tileIdx].fovMM;
|