@niivue/niivue 0.15.0 → 0.18.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/README.md +1 -1
- package/dist/niivue.es.js +105 -119
- package/dist/niivue.umd.js +39 -33
- package/package.json +3 -4
- package/src/hippo.nii.gz +0 -0
- package/src/index.html +9 -4
- package/src/logger.js +13 -15
- package/src/niivue.js +75 -103
- 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.0/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,12 +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
|
-
var niiMathWorker = new WorkerWrapper();
|
|
12362
12374
|
const log = new Log();
|
|
12363
12375
|
const Niivue = function(options = {}) {
|
|
12364
12376
|
this.opts = {};
|
|
@@ -12376,7 +12388,7 @@ const Niivue = function(options = {}) {
|
|
|
12376
12388
|
viewModeHotKey: "KeyV",
|
|
12377
12389
|
keyDebounceTime: 50,
|
|
12378
12390
|
isRadiologicalConvention: false,
|
|
12379
|
-
|
|
12391
|
+
logging: false
|
|
12380
12392
|
};
|
|
12381
12393
|
this.canvas = null;
|
|
12382
12394
|
this.gl = null;
|
|
@@ -12446,7 +12458,7 @@ const Niivue = function(options = {}) {
|
|
|
12446
12458
|
this.intensityRange$ = new Subject();
|
|
12447
12459
|
this.scene.location$ = new Subject();
|
|
12448
12460
|
this.scene.loading$ = new Subject();
|
|
12449
|
-
this.loadingText = "
|
|
12461
|
+
this.loadingText = "waiting for images...";
|
|
12450
12462
|
this.currentClipPlaneIndex = 0;
|
|
12451
12463
|
this.lastCalled = new Date().getTime();
|
|
12452
12464
|
this.multiTouchGesture = false;
|
|
@@ -12459,7 +12471,7 @@ const Niivue = function(options = {}) {
|
|
|
12459
12471
|
for (let prop in this.defaults) {
|
|
12460
12472
|
this.opts[prop] = options[prop] === void 0 ? this.defaults[prop] : options[prop];
|
|
12461
12473
|
}
|
|
12462
|
-
log.setLogLevel(this.opts.
|
|
12474
|
+
log.setLogLevel(this.opts.logging);
|
|
12463
12475
|
this.eventsToSubjects = {
|
|
12464
12476
|
location: this.scene.location$,
|
|
12465
12477
|
loading: this.scene.loading$
|
|
@@ -12468,7 +12480,7 @@ const Niivue = function(options = {}) {
|
|
|
12468
12480
|
};
|
|
12469
12481
|
Niivue.prototype.attachTo = async function(id) {
|
|
12470
12482
|
await this.attachToCanvas(document.getElementById(id));
|
|
12471
|
-
log.debug("attached to
|
|
12483
|
+
log.debug("attached to element with id: ", id);
|
|
12472
12484
|
return this;
|
|
12473
12485
|
};
|
|
12474
12486
|
Niivue.prototype.on = function(event, callback) {
|
|
@@ -12593,14 +12605,14 @@ function intensityRaw2Scaled(hdr, raw) {
|
|
|
12593
12605
|
hdr.scl_slope = 1;
|
|
12594
12606
|
return raw * hdr.scl_slope + hdr.scl_inter;
|
|
12595
12607
|
}
|
|
12596
|
-
Niivue.prototype.calculateNewRange = function() {
|
|
12608
|
+
Niivue.prototype.calculateNewRange = function(volIdx = 0) {
|
|
12597
12609
|
if (this.sliceType === this.sliceTypeRender) {
|
|
12598
12610
|
return;
|
|
12599
12611
|
}
|
|
12600
12612
|
let frac = this.canvasPos2frac([this.dragStart[0], this.dragStart[1]]);
|
|
12601
|
-
let startVox = this.frac2vox(frac);
|
|
12613
|
+
let startVox = this.frac2vox(frac, volIdx);
|
|
12602
12614
|
frac = this.canvasPos2frac([this.dragEnd[0], this.dragEnd[1]]);
|
|
12603
|
-
let endVox = this.frac2vox(frac);
|
|
12615
|
+
let endVox = this.frac2vox(frac, volIdx);
|
|
12604
12616
|
let hi = -Number.MAX_VALUE, lo = Number.MAX_VALUE;
|
|
12605
12617
|
let xrange;
|
|
12606
12618
|
let yrange;
|
|
@@ -12615,8 +12627,8 @@ Niivue.prototype.calculateNewRange = function() {
|
|
|
12615
12627
|
} else if (startVox[2] - endVox[2] === 0) {
|
|
12616
12628
|
zrange[1] = startVox[2] + 1;
|
|
12617
12629
|
}
|
|
12618
|
-
const hdr = this.volumes[
|
|
12619
|
-
const img = this.volumes[
|
|
12630
|
+
const hdr = this.volumes[volIdx].hdr;
|
|
12631
|
+
const img = this.volumes[volIdx].img;
|
|
12620
12632
|
const xdim = hdr.dims[1];
|
|
12621
12633
|
const ydim = hdr.dims[2];
|
|
12622
12634
|
for (let z = zrange[0]; z < zrange[1]; z++) {
|
|
@@ -12636,8 +12648,8 @@ Niivue.prototype.calculateNewRange = function() {
|
|
|
12636
12648
|
}
|
|
12637
12649
|
var mnScale = intensityRaw2Scaled(hdr, lo);
|
|
12638
12650
|
var mxScale = intensityRaw2Scaled(hdr, hi);
|
|
12639
|
-
this.volumes[
|
|
12640
|
-
this.volumes[
|
|
12651
|
+
this.volumes[volIdx].cal_min = mnScale;
|
|
12652
|
+
this.volumes[volIdx].cal_max = mxScale;
|
|
12641
12653
|
this.intensityRange$.next([mnScale, mxScale]);
|
|
12642
12654
|
};
|
|
12643
12655
|
Niivue.prototype.mouseUpListener = function() {
|
|
@@ -12848,22 +12860,37 @@ Niivue.prototype.getOverlayIndexByID = function(id) {
|
|
|
12848
12860
|
return -1;
|
|
12849
12861
|
};
|
|
12850
12862
|
Niivue.prototype.setVolume = function(volume, toIndex = 0) {
|
|
12863
|
+
this.volumes.map((v) => {
|
|
12864
|
+
log.debug(v.name);
|
|
12865
|
+
});
|
|
12851
12866
|
let numberOfLoadedImages = this.volumes.length;
|
|
12852
12867
|
if (toIndex > numberOfLoadedImages) {
|
|
12853
12868
|
return;
|
|
12854
12869
|
}
|
|
12855
|
-
|
|
12856
|
-
if (volIndex >= 0) {
|
|
12857
|
-
this.volumes.splice(volIndex, 1);
|
|
12858
|
-
}
|
|
12870
|
+
this.getVolumeIndexByID(volume.id);
|
|
12859
12871
|
if (toIndex === 0) {
|
|
12860
12872
|
this.volumes.unshift(volume);
|
|
12861
12873
|
this.back = this.volumes[0];
|
|
12874
|
+
this.overlays = this.volumes.slice(1);
|
|
12875
|
+
} else if (toIndex < 0) {
|
|
12876
|
+
this.volumes.splice(this.getVolumeIndexByID(volume.id), 1);
|
|
12877
|
+
this.back = this.volumes[0];
|
|
12878
|
+
if (this.volumes.length > 1) {
|
|
12879
|
+
this.overlays = this.volumes.slice(1);
|
|
12880
|
+
} else {
|
|
12881
|
+
this.overlays = [];
|
|
12882
|
+
}
|
|
12862
12883
|
} else {
|
|
12863
12884
|
this.volumes.splice(toIndex, 0, volume);
|
|
12864
12885
|
this.overlays = this.volumes.slice(1);
|
|
12865
12886
|
}
|
|
12866
12887
|
this.updateGLVolume();
|
|
12888
|
+
this.volumes.map((v) => {
|
|
12889
|
+
log.debug(v.name);
|
|
12890
|
+
});
|
|
12891
|
+
};
|
|
12892
|
+
Niivue.prototype.removeVolume = function(volume) {
|
|
12893
|
+
this.setVolume(volume, -1);
|
|
12867
12894
|
};
|
|
12868
12895
|
Niivue.prototype.moveVolumeToBottom = function(volume) {
|
|
12869
12896
|
this.setVolume(volume, 0);
|
|
@@ -12992,12 +13019,11 @@ Niivue.prototype.loadVolumes = async function(volumeList) {
|
|
|
12992
13019
|
this.loadingText = "loading...";
|
|
12993
13020
|
this.drawScene();
|
|
12994
13021
|
} else {
|
|
12995
|
-
this.loadingText = "
|
|
13022
|
+
this.loadingText = "waiting for images...";
|
|
12996
13023
|
}
|
|
12997
13024
|
});
|
|
12998
|
-
if (!this.initialized)
|
|
12999
|
-
|
|
13000
|
-
}
|
|
13025
|
+
if (!this.initialized)
|
|
13026
|
+
;
|
|
13001
13027
|
this.volumes = [];
|
|
13002
13028
|
this.gl.clearColor(0, 0, 0, 1);
|
|
13003
13029
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
@@ -13112,65 +13138,12 @@ Niivue.prototype.initText = async function() {
|
|
|
13112
13138
|
await this.loadDefaultFont();
|
|
13113
13139
|
this.drawLoadingText(this.loadingText);
|
|
13114
13140
|
};
|
|
13115
|
-
Niivue.prototype.processImage = function(imageIndex, cmd, isNewLayer = true) {
|
|
13116
|
-
let image = this.volumes[imageIndex].clone();
|
|
13117
|
-
let metadata = image.getImageMetadata();
|
|
13118
|
-
this.worker.postMessage([metadata, image.img.buffer, cmd, isNewLayer]);
|
|
13119
|
-
};
|
|
13120
|
-
Niivue.prototype.initWasm = async function() {
|
|
13121
|
-
this.worker = niiMathWorker;
|
|
13122
|
-
this.worker.onmessage = (e) => {
|
|
13123
|
-
const id = e.data.id;
|
|
13124
|
-
let processedImage = this.volumes.find((image) => image.id == id);
|
|
13125
|
-
if (!processedImage) {
|
|
13126
|
-
console.log("image not found");
|
|
13127
|
-
return;
|
|
13128
|
-
}
|
|
13129
|
-
const isNewLayer = e.data.isNewLayer;
|
|
13130
|
-
if (isNewLayer) {
|
|
13131
|
-
processedImage = processedImage.clone();
|
|
13132
|
-
processedImage.id = v4();
|
|
13133
|
-
}
|
|
13134
|
-
let imageBytes = e.data.imageBytes;
|
|
13135
|
-
switch (processedImage.hdr.datatypeCode) {
|
|
13136
|
-
case processedImage.DT_UNSIGNED_CHAR:
|
|
13137
|
-
processedImage.img = new Uint8Array(imageBytes);
|
|
13138
|
-
break;
|
|
13139
|
-
case processedImage.DT_SIGNED_SHORT:
|
|
13140
|
-
processedImage.img = new Int16Array(imageBytes);
|
|
13141
|
-
break;
|
|
13142
|
-
case processedImage.DT_FLOAT:
|
|
13143
|
-
processedImage.img = new Float32Array(imageBytes);
|
|
13144
|
-
break;
|
|
13145
|
-
case processedImage.DT_DOUBLE:
|
|
13146
|
-
throw "datatype " + processedImage.hdr.datatypeCode + " not supported";
|
|
13147
|
-
case processedImage.DT_RGB:
|
|
13148
|
-
processedImage.img = new Uint8Array(imageBytes);
|
|
13149
|
-
break;
|
|
13150
|
-
case processedImage.DT_UINT16:
|
|
13151
|
-
processedImage.img = new Uint16Array(imageBytes);
|
|
13152
|
-
break;
|
|
13153
|
-
case processedImage.DT_RGBA32:
|
|
13154
|
-
processedImage.img = new Uint8Array(imageBytes);
|
|
13155
|
-
break;
|
|
13156
|
-
default:
|
|
13157
|
-
throw "datatype " + processedImage.hdr.datatypeCode + " not supported";
|
|
13158
|
-
}
|
|
13159
|
-
processedImage.trustCalMinMax = false;
|
|
13160
|
-
processedImage.calMinMax();
|
|
13161
|
-
let imageIndex = this.volumes.length;
|
|
13162
|
-
if (isNewLayer) {
|
|
13163
|
-
this.setVolume(processedImage, this.volumes.length);
|
|
13164
|
-
} else {
|
|
13165
|
-
imageIndex = this.volumes.indexOf(processedImage);
|
|
13166
|
-
}
|
|
13167
|
-
this.refreshLayers(processedImage, imageIndex, this.volumes.length);
|
|
13168
|
-
this.drawScene();
|
|
13169
|
-
this.updateGLVolume();
|
|
13170
|
-
};
|
|
13171
|
-
};
|
|
13172
13141
|
Niivue.prototype.init = async function() {
|
|
13173
|
-
|
|
13142
|
+
let rendererInfo = this.gl.getExtension("WEBGL_debug_renderer_info");
|
|
13143
|
+
let vendor = this.gl.getParameter(rendererInfo.UNMASKED_VENDOR_WEBGL);
|
|
13144
|
+
let renderer = this.gl.getParameter(rendererInfo.UNMASKED_RENDERER_WEBGL);
|
|
13145
|
+
log.info("renderer vendor: ", vendor);
|
|
13146
|
+
log.info("renderer: ", renderer);
|
|
13174
13147
|
this.gl.enable(this.gl.CULL_FACE);
|
|
13175
13148
|
this.gl.cullFace(this.gl.FRONT);
|
|
13176
13149
|
this.gl.enable(this.gl.BLEND);
|
|
@@ -13446,6 +13419,8 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
13446
13419
|
this.gl.deleteTexture(blendTexture);
|
|
13447
13420
|
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
|
|
13448
13421
|
this.gl.deleteFramebuffer(fb);
|
|
13422
|
+
this.sliceShader.use(this.gl);
|
|
13423
|
+
this.gl.uniform1f(this.sliceShader.uniforms["overlays"], this.overlays);
|
|
13449
13424
|
this.renderShader.use(this.gl);
|
|
13450
13425
|
let slicescl = this.sliceScale();
|
|
13451
13426
|
let vox = slicescl.vox;
|
|
@@ -13598,7 +13573,13 @@ Niivue.prototype.mouseClick = function(x, y, posChange = 0, isDelta = true) {
|
|
|
13598
13573
|
this.scene.location$.next({
|
|
13599
13574
|
mm: this.frac2mm(this.scene.crosshairPos),
|
|
13600
13575
|
vox: this.frac2vox(this.scene.crosshairPos),
|
|
13601
|
-
frac: this.scene.crosshairPos
|
|
13576
|
+
frac: this.scene.crosshairPos,
|
|
13577
|
+
values: this.volumes.map((v, index) => {
|
|
13578
|
+
let mm = this.frac2mm(this.scene.crosshairPos);
|
|
13579
|
+
let vox = v.mm2vox(mm);
|
|
13580
|
+
let val = v.getValue(...vox);
|
|
13581
|
+
return val;
|
|
13582
|
+
})
|
|
13602
13583
|
});
|
|
13603
13584
|
return;
|
|
13604
13585
|
}
|
|
@@ -13618,7 +13599,13 @@ Niivue.prototype.mouseClick = function(x, y, posChange = 0, isDelta = true) {
|
|
|
13618
13599
|
this.scene.location$.next({
|
|
13619
13600
|
mm: this.frac2mm(this.scene.crosshairPos),
|
|
13620
13601
|
vox: this.frac2vox(this.scene.crosshairPos),
|
|
13621
|
-
frac: this.scene.crosshairPos
|
|
13602
|
+
frac: this.scene.crosshairPos,
|
|
13603
|
+
values: this.volumes.map((v, index) => {
|
|
13604
|
+
let mm = this.frac2mm(this.scene.crosshairPos);
|
|
13605
|
+
let vox = v.mm2vox(mm);
|
|
13606
|
+
let val = v.getValue(...vox);
|
|
13607
|
+
return val;
|
|
13608
|
+
})
|
|
13622
13609
|
});
|
|
13623
13610
|
return;
|
|
13624
13611
|
} else {
|
|
@@ -13912,16 +13899,16 @@ Niivue.prototype.draw3D = function() {
|
|
|
13912
13899
|
this.sync();
|
|
13913
13900
|
return posString;
|
|
13914
13901
|
};
|
|
13915
|
-
Niivue.prototype.mm2frac = function(mm) {
|
|
13902
|
+
Niivue.prototype.mm2frac = function(mm, volIdx = 0) {
|
|
13916
13903
|
let mm4 = fromValues(mm[0], mm[1], mm[2], 1);
|
|
13917
|
-
let d = this.
|
|
13904
|
+
let d = this.volumes[volIdx].hdr.dims;
|
|
13918
13905
|
let frac = [0, 0, 0];
|
|
13919
13906
|
if (typeof d === "undefined") {
|
|
13920
13907
|
return frac;
|
|
13921
13908
|
}
|
|
13922
13909
|
if (d[1] < 1 || d[2] < 1 || d[3] < 1)
|
|
13923
13910
|
return frac;
|
|
13924
|
-
let sform = clone(this.
|
|
13911
|
+
let sform = clone(this.volumes[volIdx].matRAS);
|
|
13925
13912
|
transpose(sform, sform);
|
|
13926
13913
|
invert(sform, sform);
|
|
13927
13914
|
transformMat4(mm4, mm4, sform);
|
|
@@ -13930,32 +13917,31 @@ Niivue.prototype.mm2frac = function(mm) {
|
|
|
13930
13917
|
frac[2] = (mm4[2] + 0.5) / d[3];
|
|
13931
13918
|
return frac;
|
|
13932
13919
|
};
|
|
13933
|
-
Niivue.prototype.vox2frac = function(vox) {
|
|
13920
|
+
Niivue.prototype.vox2frac = function(vox, volIdx = 0) {
|
|
13934
13921
|
let frac = [
|
|
13935
|
-
(vox[0] + 0.5) / this.
|
|
13936
|
-
(vox[1] + 0.5) / this.
|
|
13937
|
-
(vox[2] + 0.5) / this.
|
|
13922
|
+
(vox[0] + 0.5) / this.volumes[volIdx].hdr.dims[1],
|
|
13923
|
+
(vox[1] + 0.5) / this.volumes[volIdx].hdr.dims[2],
|
|
13924
|
+
(vox[2] + 0.5) / this.volumes[volIdx].hdr.dims[3]
|
|
13938
13925
|
];
|
|
13939
13926
|
return frac;
|
|
13940
13927
|
};
|
|
13941
|
-
Niivue.prototype.frac2vox = function(frac) {
|
|
13928
|
+
Niivue.prototype.frac2vox = function(frac, volIdx = 0) {
|
|
13942
13929
|
let vox = [
|
|
13943
|
-
Math.round(frac[0] * this.
|
|
13944
|
-
Math.round(frac[1] * this.
|
|
13945
|
-
Math.round(frac[2] * this.
|
|
13930
|
+
Math.round(frac[0] * this.volumes[volIdx].hdr.dims[1] - 0.5),
|
|
13931
|
+
Math.round(frac[1] * this.volumes[volIdx].hdr.dims[2] - 0.5),
|
|
13932
|
+
Math.round(frac[2] * this.volumes[volIdx].hdr.dims[3] - 0.5)
|
|
13946
13933
|
];
|
|
13947
13934
|
return vox;
|
|
13948
13935
|
};
|
|
13949
|
-
Niivue.prototype.frac2mm = function(frac) {
|
|
13936
|
+
Niivue.prototype.frac2mm = function(frac, volIdx = 0) {
|
|
13950
13937
|
let pos = fromValues(frac[0], frac[1], frac[2], 1);
|
|
13951
|
-
let dim = fromValues(this.
|
|
13952
|
-
let sform = clone(this.
|
|
13938
|
+
let dim = fromValues(this.volumes[volIdx].hdr.dims[1], this.volumes[volIdx].hdr.dims[2], this.volumes[volIdx].hdr.dims[3], 1);
|
|
13939
|
+
let sform = clone(this.volumes[volIdx].matRAS);
|
|
13953
13940
|
transpose(sform, sform);
|
|
13954
13941
|
mul(pos, pos, dim);
|
|
13955
13942
|
let shim = fromValues(-0.5, -0.5, -0.5, 0);
|
|
13956
13943
|
add(pos, pos, shim);
|
|
13957
13944
|
transformMat4(pos, pos, sform);
|
|
13958
|
-
this.mm2frac(pos);
|
|
13959
13945
|
return pos;
|
|
13960
13946
|
};
|
|
13961
13947
|
Niivue.prototype.canvasPos2frac = function(canvasPos) {
|