@niivue/niivue 0.15.1 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/niivue.es.js +108 -118
- package/dist/niivue.umd.js +38 -32
- package/package.json +1 -2
- package/src/hippo.nii.gz +0 -0
- package/src/index.html +8 -3
- package/src/logger.js +13 -15
- package/src/niivue.js +80 -107
- package/src/nvimage.js +16 -0
- package/src/shader-srcs.js +11 -5
- package/dist/assets/niimathWorker.1f52eda8.js +0 -1
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ We host many NiiVue examples via github pages. These are updated and deployed au
|
|
|
38
38
|
|
|
39
39
|
## existing html page
|
|
40
40
|
```html
|
|
41
|
-
<script src="https://unpkg.com/@niivue/niivue@0.
|
|
41
|
+
<script src="https://unpkg.com/@niivue/niivue@0.18.1/dist/niivue.umd.js"></script>
|
|
42
42
|
|
|
43
43
|
<canvas id="gl" height=480 width=640></canvas>
|
|
44
44
|
|
package/dist/niivue.es.js
CHANGED
|
@@ -714,16 +714,22 @@ var fragSliceShader = `#version 300 es
|
|
|
714
714
|
precision highp int;
|
|
715
715
|
precision highp float;
|
|
716
716
|
uniform highp sampler3D volume, overlay;
|
|
717
|
+
uniform float overlays;
|
|
717
718
|
uniform float opacity;
|
|
718
719
|
in vec3 texPos;
|
|
719
720
|
out vec4 color;
|
|
720
721
|
void main() {
|
|
721
722
|
color = vec4(texture(volume, texPos).rgb, opacity);
|
|
722
|
-
vec4 ocolor =
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
723
|
+
vec4 ocolor = vec4(0.0);
|
|
724
|
+
if (overlays < 1.0) {
|
|
725
|
+
ocolor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
726
|
+
} else {
|
|
727
|
+
ocolor = texture(overlay, texPos);
|
|
728
|
+
}
|
|
729
|
+
float aout = ocolor.a + (1.0 - ocolor.a) * color.a;
|
|
730
|
+
if (aout <= 0.0) return;
|
|
731
|
+
color.rgb = ((ocolor.rgb * ocolor.a) + (color.rgb * color.a * (1.0 - ocolor.a))) / aout;
|
|
732
|
+
color.a = aout;
|
|
727
733
|
}`;
|
|
728
734
|
var fragLineShader = `#version 300 es
|
|
729
735
|
#line 189
|
|
@@ -10559,6 +10565,16 @@ NVImage.prototype.vox2mm = function(XYZ, mtx) {
|
|
|
10559
10565
|
let pos3 = fromValues$1(pos[0], pos[1], pos[2]);
|
|
10560
10566
|
return pos3;
|
|
10561
10567
|
};
|
|
10568
|
+
NVImage.prototype.mm2vox = function(mm) {
|
|
10569
|
+
let sform = fromValues$2(...this.hdr.affine.flat());
|
|
10570
|
+
let out = clone(sform);
|
|
10571
|
+
transpose(out, sform);
|
|
10572
|
+
invert(out, out);
|
|
10573
|
+
let pos = fromValues(mm[0], mm[1], mm[2], 1);
|
|
10574
|
+
transformMat4(pos, pos, out);
|
|
10575
|
+
let pos3 = fromValues$1(pos[0], pos[1], pos[2]);
|
|
10576
|
+
return [Math.round(pos3[0]), Math.round(pos3[1]), Math.round(pos3[2])];
|
|
10577
|
+
};
|
|
10562
10578
|
NVImage.prototype.arrayEquals = function(a, b) {
|
|
10563
10579
|
return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((val, index) => val === b[index]);
|
|
10564
10580
|
};
|
|
@@ -10785,35 +10801,37 @@ String.prototype.getBytes = function() {
|
|
|
10785
10801
|
}
|
|
10786
10802
|
return bytes;
|
|
10787
10803
|
};
|
|
10804
|
+
NVImage.prototype.getValue = function(x, y, z) {
|
|
10805
|
+
const { nx, ny } = this.getImageMetadata();
|
|
10806
|
+
return this.img[x + y * nx + z * nx * ny];
|
|
10807
|
+
};
|
|
10788
10808
|
const Log = function(logLevel) {
|
|
10789
|
-
this.
|
|
10790
|
-
this.
|
|
10791
|
-
this.
|
|
10792
|
-
this.ERROR = "error";
|
|
10793
|
-
this.LOG_PREFIX = "NiiVue: ";
|
|
10809
|
+
this.LOGGING_ON = true;
|
|
10810
|
+
this.LOGGING_OFF = false;
|
|
10811
|
+
this.LOG_PREFIX = "NiiVue:";
|
|
10794
10812
|
this.logLevel = logLevel;
|
|
10795
10813
|
};
|
|
10796
10814
|
Log.prototype.getTimeStamp = function() {
|
|
10797
|
-
return `${this.LOG_PREFIX}
|
|
10815
|
+
return `${this.LOG_PREFIX} `;
|
|
10798
10816
|
};
|
|
10799
10817
|
Log.prototype.debug = function() {
|
|
10800
|
-
if (this.logLevel === this.
|
|
10801
|
-
console.log(this.getTimeStamp(), ...arguments);
|
|
10818
|
+
if (this.logLevel === this.LOGGING_ON) {
|
|
10819
|
+
console.log(this.getTimeStamp(), "DEBUG", ...arguments);
|
|
10802
10820
|
}
|
|
10803
10821
|
};
|
|
10804
10822
|
Log.prototype.info = function() {
|
|
10805
|
-
if (this.logLevel === this.
|
|
10806
|
-
console.log(this.getTimeStamp(), ...arguments);
|
|
10823
|
+
if (this.logLevel === this.LOGGING_ON) {
|
|
10824
|
+
console.log(this.getTimeStamp(), "INFO", ...arguments);
|
|
10807
10825
|
}
|
|
10808
10826
|
};
|
|
10809
10827
|
Log.prototype.warn = function() {
|
|
10810
|
-
if (this.logLevel === this.
|
|
10811
|
-
console.warn(this.getTimeStamp(), ...arguments);
|
|
10828
|
+
if (this.logLevel === this.LOGGING_ON) {
|
|
10829
|
+
console.warn(this.getTimeStamp(), "WARN", ...arguments);
|
|
10812
10830
|
}
|
|
10813
10831
|
};
|
|
10814
10832
|
Log.prototype.error = function() {
|
|
10815
|
-
if (this.logLevel === this.
|
|
10816
|
-
console.error(this.getTimeStamp(), ...arguments);
|
|
10833
|
+
if (this.logLevel === this.LOGGING_ON) {
|
|
10834
|
+
console.error(this.getTimeStamp(), "ERROR", ...arguments);
|
|
10817
10835
|
}
|
|
10818
10836
|
};
|
|
10819
10837
|
Log.prototype.setLogLevel = function(logLevel) {
|
|
@@ -12353,11 +12371,6 @@ var defaultFontMetrics = {
|
|
|
12353
12371
|
glyphs,
|
|
12354
12372
|
kerning
|
|
12355
12373
|
};
|
|
12356
|
-
function WorkerWrapper() {
|
|
12357
|
-
return new Worker("./assets/niimathWorker.1f52eda8.js", {
|
|
12358
|
-
"type": "module"
|
|
12359
|
-
});
|
|
12360
|
-
}
|
|
12361
12374
|
const log = new Log();
|
|
12362
12375
|
const Niivue = function(options = {}) {
|
|
12363
12376
|
this.opts = {};
|
|
@@ -12375,7 +12388,7 @@ const Niivue = function(options = {}) {
|
|
|
12375
12388
|
viewModeHotKey: "KeyV",
|
|
12376
12389
|
keyDebounceTime: 50,
|
|
12377
12390
|
isRadiologicalConvention: false,
|
|
12378
|
-
|
|
12391
|
+
logging: false
|
|
12379
12392
|
};
|
|
12380
12393
|
this.canvas = null;
|
|
12381
12394
|
this.gl = null;
|
|
@@ -12445,7 +12458,7 @@ const Niivue = function(options = {}) {
|
|
|
12445
12458
|
this.intensityRange$ = new Subject();
|
|
12446
12459
|
this.scene.location$ = new Subject();
|
|
12447
12460
|
this.scene.loading$ = new Subject();
|
|
12448
|
-
this.loadingText = "
|
|
12461
|
+
this.loadingText = "waiting for images...";
|
|
12449
12462
|
this.currentClipPlaneIndex = 0;
|
|
12450
12463
|
this.lastCalled = new Date().getTime();
|
|
12451
12464
|
this.multiTouchGesture = false;
|
|
@@ -12458,7 +12471,7 @@ const Niivue = function(options = {}) {
|
|
|
12458
12471
|
for (let prop in this.defaults) {
|
|
12459
12472
|
this.opts[prop] = options[prop] === void 0 ? this.defaults[prop] : options[prop];
|
|
12460
12473
|
}
|
|
12461
|
-
log.setLogLevel(this.opts.
|
|
12474
|
+
log.setLogLevel(this.opts.logging);
|
|
12462
12475
|
this.eventsToSubjects = {
|
|
12463
12476
|
location: this.scene.location$,
|
|
12464
12477
|
loading: this.scene.loading$
|
|
@@ -12467,7 +12480,7 @@ const Niivue = function(options = {}) {
|
|
|
12467
12480
|
};
|
|
12468
12481
|
Niivue.prototype.attachTo = async function(id) {
|
|
12469
12482
|
await this.attachToCanvas(document.getElementById(id));
|
|
12470
|
-
log.debug("attached to
|
|
12483
|
+
log.debug("attached to element with id: ", id);
|
|
12471
12484
|
return this;
|
|
12472
12485
|
};
|
|
12473
12486
|
Niivue.prototype.on = function(event, callback) {
|
|
@@ -12592,14 +12605,14 @@ function intensityRaw2Scaled(hdr, raw) {
|
|
|
12592
12605
|
hdr.scl_slope = 1;
|
|
12593
12606
|
return raw * hdr.scl_slope + hdr.scl_inter;
|
|
12594
12607
|
}
|
|
12595
|
-
Niivue.prototype.calculateNewRange = function() {
|
|
12608
|
+
Niivue.prototype.calculateNewRange = function(volIdx = 0) {
|
|
12596
12609
|
if (this.sliceType === this.sliceTypeRender) {
|
|
12597
12610
|
return;
|
|
12598
12611
|
}
|
|
12599
12612
|
let frac = this.canvasPos2frac([this.dragStart[0], this.dragStart[1]]);
|
|
12600
|
-
let startVox = this.frac2vox(frac);
|
|
12613
|
+
let startVox = this.frac2vox(frac, volIdx);
|
|
12601
12614
|
frac = this.canvasPos2frac([this.dragEnd[0], this.dragEnd[1]]);
|
|
12602
|
-
let endVox = this.frac2vox(frac);
|
|
12615
|
+
let endVox = this.frac2vox(frac, volIdx);
|
|
12603
12616
|
let hi = -Number.MAX_VALUE, lo = Number.MAX_VALUE;
|
|
12604
12617
|
let xrange;
|
|
12605
12618
|
let yrange;
|
|
@@ -12614,8 +12627,8 @@ Niivue.prototype.calculateNewRange = function() {
|
|
|
12614
12627
|
} else if (startVox[2] - endVox[2] === 0) {
|
|
12615
12628
|
zrange[1] = startVox[2] + 1;
|
|
12616
12629
|
}
|
|
12617
|
-
const hdr = this.volumes[
|
|
12618
|
-
const img = this.volumes[
|
|
12630
|
+
const hdr = this.volumes[volIdx].hdr;
|
|
12631
|
+
const img = this.volumes[volIdx].img;
|
|
12619
12632
|
const xdim = hdr.dims[1];
|
|
12620
12633
|
const ydim = hdr.dims[2];
|
|
12621
12634
|
for (let z = zrange[0]; z < zrange[1]; z++) {
|
|
@@ -12635,8 +12648,8 @@ Niivue.prototype.calculateNewRange = function() {
|
|
|
12635
12648
|
}
|
|
12636
12649
|
var mnScale = intensityRaw2Scaled(hdr, lo);
|
|
12637
12650
|
var mxScale = intensityRaw2Scaled(hdr, hi);
|
|
12638
|
-
this.volumes[
|
|
12639
|
-
this.volumes[
|
|
12651
|
+
this.volumes[volIdx].cal_min = mnScale;
|
|
12652
|
+
this.volumes[volIdx].cal_max = mxScale;
|
|
12640
12653
|
this.intensityRange$.next([mnScale, mxScale]);
|
|
12641
12654
|
};
|
|
12642
12655
|
Niivue.prototype.mouseUpListener = function() {
|
|
@@ -12847,22 +12860,40 @@ Niivue.prototype.getOverlayIndexByID = function(id) {
|
|
|
12847
12860
|
return -1;
|
|
12848
12861
|
};
|
|
12849
12862
|
Niivue.prototype.setVolume = function(volume, toIndex = 0) {
|
|
12863
|
+
this.volumes.map((v) => {
|
|
12864
|
+
log.debug(v.name);
|
|
12865
|
+
});
|
|
12850
12866
|
let numberOfLoadedImages = this.volumes.length;
|
|
12851
12867
|
if (toIndex > numberOfLoadedImages) {
|
|
12852
12868
|
return;
|
|
12853
12869
|
}
|
|
12854
12870
|
let volIndex = this.getVolumeIndexByID(volume.id);
|
|
12855
|
-
if (volIndex >= 0) {
|
|
12856
|
-
this.volumes.splice(volIndex, 1);
|
|
12857
|
-
}
|
|
12858
12871
|
if (toIndex === 0) {
|
|
12872
|
+
this.volumes.splice(volIndex, 1);
|
|
12859
12873
|
this.volumes.unshift(volume);
|
|
12860
12874
|
this.back = this.volumes[0];
|
|
12875
|
+
this.overlays = this.volumes.slice(1);
|
|
12876
|
+
} else if (toIndex < 0) {
|
|
12877
|
+
this.volumes.splice(this.getVolumeIndexByID(volume.id), 1);
|
|
12878
|
+
this.back = this.volumes[0];
|
|
12879
|
+
if (this.volumes.length > 1) {
|
|
12880
|
+
this.overlays = this.volumes.slice(1);
|
|
12881
|
+
} else {
|
|
12882
|
+
this.overlays = [];
|
|
12883
|
+
}
|
|
12861
12884
|
} else {
|
|
12885
|
+
this.volumes.splice(volIndex, 1);
|
|
12862
12886
|
this.volumes.splice(toIndex, 0, volume);
|
|
12863
12887
|
this.overlays = this.volumes.slice(1);
|
|
12888
|
+
this.back = this.volumes[0];
|
|
12864
12889
|
}
|
|
12865
12890
|
this.updateGLVolume();
|
|
12891
|
+
this.volumes.map((v) => {
|
|
12892
|
+
log.debug(v.name);
|
|
12893
|
+
});
|
|
12894
|
+
};
|
|
12895
|
+
Niivue.prototype.removeVolume = function(volume) {
|
|
12896
|
+
this.setVolume(volume, -1);
|
|
12866
12897
|
};
|
|
12867
12898
|
Niivue.prototype.moveVolumeToBottom = function(volume) {
|
|
12868
12899
|
this.setVolume(volume, 0);
|
|
@@ -12991,12 +13022,11 @@ Niivue.prototype.loadVolumes = async function(volumeList) {
|
|
|
12991
13022
|
this.loadingText = "loading...";
|
|
12992
13023
|
this.drawScene();
|
|
12993
13024
|
} else {
|
|
12994
|
-
this.loadingText = "
|
|
13025
|
+
this.loadingText = "waiting for images...";
|
|
12995
13026
|
}
|
|
12996
13027
|
});
|
|
12997
|
-
if (!this.initialized)
|
|
12998
|
-
|
|
12999
|
-
}
|
|
13028
|
+
if (!this.initialized)
|
|
13029
|
+
;
|
|
13000
13030
|
this.volumes = [];
|
|
13001
13031
|
this.gl.clearColor(0, 0, 0, 1);
|
|
13002
13032
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
@@ -13111,65 +13141,12 @@ Niivue.prototype.initText = async function() {
|
|
|
13111
13141
|
await this.loadDefaultFont();
|
|
13112
13142
|
this.drawLoadingText(this.loadingText);
|
|
13113
13143
|
};
|
|
13114
|
-
Niivue.prototype.processImage = function(imageIndex, cmd, isNewLayer = true) {
|
|
13115
|
-
let image = this.volumes[imageIndex].clone();
|
|
13116
|
-
let metadata = image.getImageMetadata();
|
|
13117
|
-
this.worker.postMessage([metadata, image.img.buffer, cmd, isNewLayer]);
|
|
13118
|
-
};
|
|
13119
|
-
Niivue.prototype.initWasm = async function() {
|
|
13120
|
-
this.worker = WorkerWrapper;
|
|
13121
|
-
this.worker.onmessage = (e) => {
|
|
13122
|
-
const id = e.data.id;
|
|
13123
|
-
let processedImage = this.volumes.find((image) => image.id == id);
|
|
13124
|
-
if (!processedImage) {
|
|
13125
|
-
console.log("image not found");
|
|
13126
|
-
return;
|
|
13127
|
-
}
|
|
13128
|
-
const isNewLayer = e.data.isNewLayer;
|
|
13129
|
-
if (isNewLayer) {
|
|
13130
|
-
processedImage = processedImage.clone();
|
|
13131
|
-
processedImage.id = v4();
|
|
13132
|
-
}
|
|
13133
|
-
let imageBytes = e.data.imageBytes;
|
|
13134
|
-
switch (processedImage.hdr.datatypeCode) {
|
|
13135
|
-
case processedImage.DT_UNSIGNED_CHAR:
|
|
13136
|
-
processedImage.img = new Uint8Array(imageBytes);
|
|
13137
|
-
break;
|
|
13138
|
-
case processedImage.DT_SIGNED_SHORT:
|
|
13139
|
-
processedImage.img = new Int16Array(imageBytes);
|
|
13140
|
-
break;
|
|
13141
|
-
case processedImage.DT_FLOAT:
|
|
13142
|
-
processedImage.img = new Float32Array(imageBytes);
|
|
13143
|
-
break;
|
|
13144
|
-
case processedImage.DT_DOUBLE:
|
|
13145
|
-
throw "datatype " + processedImage.hdr.datatypeCode + " not supported";
|
|
13146
|
-
case processedImage.DT_RGB:
|
|
13147
|
-
processedImage.img = new Uint8Array(imageBytes);
|
|
13148
|
-
break;
|
|
13149
|
-
case processedImage.DT_UINT16:
|
|
13150
|
-
processedImage.img = new Uint16Array(imageBytes);
|
|
13151
|
-
break;
|
|
13152
|
-
case processedImage.DT_RGBA32:
|
|
13153
|
-
processedImage.img = new Uint8Array(imageBytes);
|
|
13154
|
-
break;
|
|
13155
|
-
default:
|
|
13156
|
-
throw "datatype " + processedImage.hdr.datatypeCode + " not supported";
|
|
13157
|
-
}
|
|
13158
|
-
processedImage.trustCalMinMax = false;
|
|
13159
|
-
processedImage.calMinMax();
|
|
13160
|
-
let imageIndex = this.volumes.length;
|
|
13161
|
-
if (isNewLayer) {
|
|
13162
|
-
this.setVolume(processedImage, this.volumes.length);
|
|
13163
|
-
} else {
|
|
13164
|
-
imageIndex = this.volumes.indexOf(processedImage);
|
|
13165
|
-
}
|
|
13166
|
-
this.refreshLayers(processedImage, imageIndex, this.volumes.length);
|
|
13167
|
-
this.drawScene();
|
|
13168
|
-
this.updateGLVolume();
|
|
13169
|
-
};
|
|
13170
|
-
};
|
|
13171
13144
|
Niivue.prototype.init = async function() {
|
|
13172
|
-
|
|
13145
|
+
let rendererInfo = this.gl.getExtension("WEBGL_debug_renderer_info");
|
|
13146
|
+
let vendor = this.gl.getParameter(rendererInfo.UNMASKED_VENDOR_WEBGL);
|
|
13147
|
+
let renderer = this.gl.getParameter(rendererInfo.UNMASKED_RENDERER_WEBGL);
|
|
13148
|
+
log.info("renderer vendor: ", vendor);
|
|
13149
|
+
log.info("renderer: ", renderer);
|
|
13173
13150
|
this.gl.enable(this.gl.CULL_FACE);
|
|
13174
13151
|
this.gl.cullFace(this.gl.FRONT);
|
|
13175
13152
|
this.gl.enable(this.gl.BLEND);
|
|
@@ -13445,6 +13422,8 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
13445
13422
|
this.gl.deleteTexture(blendTexture);
|
|
13446
13423
|
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
|
|
13447
13424
|
this.gl.deleteFramebuffer(fb);
|
|
13425
|
+
this.sliceShader.use(this.gl);
|
|
13426
|
+
this.gl.uniform1f(this.sliceShader.uniforms["overlays"], this.overlays);
|
|
13448
13427
|
this.renderShader.use(this.gl);
|
|
13449
13428
|
let slicescl = this.sliceScale();
|
|
13450
13429
|
let vox = slicescl.vox;
|
|
@@ -13597,7 +13576,13 @@ Niivue.prototype.mouseClick = function(x, y, posChange = 0, isDelta = true) {
|
|
|
13597
13576
|
this.scene.location$.next({
|
|
13598
13577
|
mm: this.frac2mm(this.scene.crosshairPos),
|
|
13599
13578
|
vox: this.frac2vox(this.scene.crosshairPos),
|
|
13600
|
-
frac: this.scene.crosshairPos
|
|
13579
|
+
frac: this.scene.crosshairPos,
|
|
13580
|
+
values: this.volumes.map((v, index) => {
|
|
13581
|
+
let mm = this.frac2mm(this.scene.crosshairPos);
|
|
13582
|
+
let vox = v.mm2vox(mm);
|
|
13583
|
+
let val = v.getValue(...vox);
|
|
13584
|
+
return val;
|
|
13585
|
+
})
|
|
13601
13586
|
});
|
|
13602
13587
|
return;
|
|
13603
13588
|
}
|
|
@@ -13617,7 +13602,13 @@ Niivue.prototype.mouseClick = function(x, y, posChange = 0, isDelta = true) {
|
|
|
13617
13602
|
this.scene.location$.next({
|
|
13618
13603
|
mm: this.frac2mm(this.scene.crosshairPos),
|
|
13619
13604
|
vox: this.frac2vox(this.scene.crosshairPos),
|
|
13620
|
-
frac: this.scene.crosshairPos
|
|
13605
|
+
frac: this.scene.crosshairPos,
|
|
13606
|
+
values: this.volumes.map((v, index) => {
|
|
13607
|
+
let mm = this.frac2mm(this.scene.crosshairPos);
|
|
13608
|
+
let vox = v.mm2vox(mm);
|
|
13609
|
+
let val = v.getValue(...vox);
|
|
13610
|
+
return val;
|
|
13611
|
+
})
|
|
13621
13612
|
});
|
|
13622
13613
|
return;
|
|
13623
13614
|
} else {
|
|
@@ -13911,16 +13902,16 @@ Niivue.prototype.draw3D = function() {
|
|
|
13911
13902
|
this.sync();
|
|
13912
13903
|
return posString;
|
|
13913
13904
|
};
|
|
13914
|
-
Niivue.prototype.mm2frac = function(mm) {
|
|
13905
|
+
Niivue.prototype.mm2frac = function(mm, volIdx = 0) {
|
|
13915
13906
|
let mm4 = fromValues(mm[0], mm[1], mm[2], 1);
|
|
13916
|
-
let d = this.
|
|
13907
|
+
let d = this.volumes[volIdx].hdr.dims;
|
|
13917
13908
|
let frac = [0, 0, 0];
|
|
13918
13909
|
if (typeof d === "undefined") {
|
|
13919
13910
|
return frac;
|
|
13920
13911
|
}
|
|
13921
13912
|
if (d[1] < 1 || d[2] < 1 || d[3] < 1)
|
|
13922
13913
|
return frac;
|
|
13923
|
-
let sform = clone(this.
|
|
13914
|
+
let sform = clone(this.volumes[volIdx].matRAS);
|
|
13924
13915
|
transpose(sform, sform);
|
|
13925
13916
|
invert(sform, sform);
|
|
13926
13917
|
transformMat4(mm4, mm4, sform);
|
|
@@ -13929,32 +13920,31 @@ Niivue.prototype.mm2frac = function(mm) {
|
|
|
13929
13920
|
frac[2] = (mm4[2] + 0.5) / d[3];
|
|
13930
13921
|
return frac;
|
|
13931
13922
|
};
|
|
13932
|
-
Niivue.prototype.vox2frac = function(vox) {
|
|
13923
|
+
Niivue.prototype.vox2frac = function(vox, volIdx = 0) {
|
|
13933
13924
|
let frac = [
|
|
13934
|
-
(vox[0] + 0.5) / this.
|
|
13935
|
-
(vox[1] + 0.5) / this.
|
|
13936
|
-
(vox[2] + 0.5) / this.
|
|
13925
|
+
(vox[0] + 0.5) / this.volumes[volIdx].hdr.dims[1],
|
|
13926
|
+
(vox[1] + 0.5) / this.volumes[volIdx].hdr.dims[2],
|
|
13927
|
+
(vox[2] + 0.5) / this.volumes[volIdx].hdr.dims[3]
|
|
13937
13928
|
];
|
|
13938
13929
|
return frac;
|
|
13939
13930
|
};
|
|
13940
|
-
Niivue.prototype.frac2vox = function(frac) {
|
|
13931
|
+
Niivue.prototype.frac2vox = function(frac, volIdx = 0) {
|
|
13941
13932
|
let vox = [
|
|
13942
|
-
Math.round(frac[0] * this.
|
|
13943
|
-
Math.round(frac[1] * this.
|
|
13944
|
-
Math.round(frac[2] * this.
|
|
13933
|
+
Math.round(frac[0] * this.volumes[volIdx].hdr.dims[1] - 0.5),
|
|
13934
|
+
Math.round(frac[1] * this.volumes[volIdx].hdr.dims[2] - 0.5),
|
|
13935
|
+
Math.round(frac[2] * this.volumes[volIdx].hdr.dims[3] - 0.5)
|
|
13945
13936
|
];
|
|
13946
13937
|
return vox;
|
|
13947
13938
|
};
|
|
13948
|
-
Niivue.prototype.frac2mm = function(frac) {
|
|
13939
|
+
Niivue.prototype.frac2mm = function(frac, volIdx = 0) {
|
|
13949
13940
|
let pos = fromValues(frac[0], frac[1], frac[2], 1);
|
|
13950
|
-
let dim = fromValues(this.
|
|
13951
|
-
let sform = clone(this.
|
|
13941
|
+
let dim = fromValues(this.volumes[volIdx].hdr.dims[1], this.volumes[volIdx].hdr.dims[2], this.volumes[volIdx].hdr.dims[3], 1);
|
|
13942
|
+
let sform = clone(this.volumes[volIdx].matRAS);
|
|
13952
13943
|
transpose(sform, sform);
|
|
13953
13944
|
mul(pos, pos, dim);
|
|
13954
13945
|
let shim = fromValues(-0.5, -0.5, -0.5, 0);
|
|
13955
13946
|
add(pos, pos, shim);
|
|
13956
13947
|
transformMat4(pos, pos, sform);
|
|
13957
|
-
this.mm2frac(pos);
|
|
13958
13948
|
return pos;
|
|
13959
13949
|
};
|
|
13960
13950
|
Niivue.prototype.canvasPos2frac = function(canvasPos) {
|
|
@@ -14023,7 +14013,7 @@ Niivue.prototype.drawScene = function() {
|
|
|
14023
14013
|
this.gl.clearColor(this.opts.backColor[0], this.opts.backColor[1], this.opts.backColor[2], this.opts.backColor[3]);
|
|
14024
14014
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
14025
14015
|
let posString = "";
|
|
14026
|
-
if (
|
|
14016
|
+
if (this.volumes.length === 0 || typeof this.volumes[0].dims === "undefined") {
|
|
14027
14017
|
this.drawLoadingText(this.loadingText);
|
|
14028
14018
|
return;
|
|
14029
14019
|
}
|