@niivue/niivue 0.40.0 → 0.41.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/build/index.d.ts +59 -77
- package/build/index.js +591 -615
- package/build/index.js.map +1 -1
- package/build/index.min.js +1 -1
- package/package.json +38 -36
- package/src/colortables.ts +1 -1
- package/src/index.html +1 -1
- package/src/niivue/index.ts +176 -189
- package/src/niivue-object3D.ts +42 -13
- package/src/nvconnectome.ts +10 -8
- package/src/nvdocument.ts +7 -6
- package/src/nvimage/index.ts +6 -14
- package/src/nvimage/utils.ts +0 -8
- package/src/nvmesh-loaders.ts +175 -160
- package/src/nvmesh-types.ts +14 -14
- package/src/nvmesh.ts +113 -279
- package/src/shader-srcs.ts +135 -44
- package/src/types.ts +1 -0
package/build/index.js
CHANGED
|
@@ -10,11 +10,10 @@ var __publicField = (obj, key, value) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/niivue/index.ts
|
|
13
|
-
import { Subject } from "rxjs";
|
|
14
13
|
import { mat4 as mat46, vec2, vec3 as vec310, vec4 as vec47 } from "gl-matrix";
|
|
15
14
|
|
|
16
15
|
// package.json
|
|
17
|
-
var version = "0.
|
|
16
|
+
var version = "0.41.1";
|
|
18
17
|
|
|
19
18
|
// src/logger.ts
|
|
20
19
|
var _Log = class _Log {
|
|
@@ -745,8 +744,109 @@ out vec4 color;` + kDrawFunc + `void main() {
|
|
|
745
744
|
if ((isAlphaClipDark) && (background.a == 0.0)) color.a = 0.0; //FSLeyes clipping range
|
|
746
745
|
vec4 ocolor = vec4(0.0);
|
|
747
746
|
float overlayAlpha = overlayAlphaShader;
|
|
748
|
-
if (overlays > 0.0)
|
|
747
|
+
if (overlays > 0.0) {
|
|
749
748
|
ocolor = texture(overlay, texPos);
|
|
749
|
+
//dFdx for "boxing" issue 435 has aliasing on some implementations (coarse vs fine)
|
|
750
|
+
//however, this only identifies 50% of the edges due to aliasing effects
|
|
751
|
+
// http://www.aclockworkberry.com/shader-derivative-functions/
|
|
752
|
+
// https://bgolus.medium.com/distinctive-derivative-differences-cce38d36797b
|
|
753
|
+
//if ((ocolor.a >= 1.0) && ((dFdx(ocolor.a) != 0.0) || (dFdy(ocolor.a) != 0.0) ))
|
|
754
|
+
// ocolor.rbg = vec3(0.0, 0.0, 0.0);
|
|
755
|
+
bool isOutlineBelowNotAboveThreshold = true;
|
|
756
|
+
if (isOutlineBelowNotAboveThreshold) {
|
|
757
|
+
if ((overlayOutlineWidth > 0.0) && (ocolor.a < 1.0)) { //check voxel neighbors for edge
|
|
758
|
+
vec3 vx = (overlayOutlineWidth ) / vec3(textureSize(overlay, 0));
|
|
759
|
+
//6 voxel neighbors that share a face
|
|
760
|
+
vec3 vxR = vec3(texPos.x+vx.x, texPos.y, texPos.z);
|
|
761
|
+
vec3 vxL = vec3(texPos.x-vx.x, texPos.y, texPos.z);
|
|
762
|
+
vec3 vxA = vec3(texPos.x, texPos.y+vx.y, texPos.z);
|
|
763
|
+
vec3 vxP = vec3(texPos.x, texPos.y-vx.y, texPos.z);
|
|
764
|
+
vec3 vxS = vec3(texPos.x, texPos.y, texPos.z+vx.z);
|
|
765
|
+
vec3 vxI = vec3(texPos.x, texPos.y, texPos.z-vx.z);
|
|
766
|
+
float a = 0.0;
|
|
767
|
+
if (axCorSag != 2) {
|
|
768
|
+
a = max(a, texture(overlay, vxR).a);
|
|
769
|
+
a = max(a, texture(overlay, vxL).a);
|
|
770
|
+
}
|
|
771
|
+
if (axCorSag != 1) {
|
|
772
|
+
a = max(a, texture(overlay, vxA).a);
|
|
773
|
+
a = max(a, texture(overlay, vxP).a);
|
|
774
|
+
}
|
|
775
|
+
if (axCorSag != 0) {
|
|
776
|
+
a = max(a, texture(overlay, vxS).a);
|
|
777
|
+
a = max(a, texture(overlay, vxI).a);
|
|
778
|
+
}
|
|
779
|
+
bool isCheckCorners = true;
|
|
780
|
+
if (isCheckCorners) {
|
|
781
|
+
//12 voxel neighbors that share an edge
|
|
782
|
+
vec3 vxRA = vec3(texPos.x+vx.x, texPos.y+vx.y, texPos.z);
|
|
783
|
+
vec3 vxLA = vec3(texPos.x-vx.x, texPos.y+vx.y, texPos.z);
|
|
784
|
+
vec3 vxRP = vec3(texPos.x+vx.x, texPos.y-vx.y, texPos.z);
|
|
785
|
+
vec3 vxLP = vec3(texPos.x-vx.x, texPos.y-vx.y, texPos.z);
|
|
786
|
+
vec3 vxRS = vec3(texPos.x+vx.x, texPos.y, texPos.z+vx.z);
|
|
787
|
+
vec3 vxLS = vec3(texPos.x-vx.x, texPos.y, texPos.z+vx.z);
|
|
788
|
+
vec3 vxRI = vec3(texPos.x+vx.x, texPos.y, texPos.z-vx.z);
|
|
789
|
+
vec3 vxLI = vec3(texPos.x-vx.x, texPos.y, texPos.z-vx.z);
|
|
790
|
+
vec3 vxAS = vec3(texPos.x, texPos.y+vx.y, texPos.z+vx.z);
|
|
791
|
+
vec3 vxPS = vec3(texPos.x, texPos.y-vx.y, texPos.z+vx.z);
|
|
792
|
+
vec3 vxAI = vec3(texPos.x, texPos.y+vx.y, texPos.z-vx.z);
|
|
793
|
+
vec3 vxPI = vec3(texPos.x, texPos.y-vx.y, texPos.z-vx.z);
|
|
794
|
+
|
|
795
|
+
if (axCorSag == 0) { //axial corners
|
|
796
|
+
a = max(a, texture(overlay, vxRA).a);
|
|
797
|
+
a = max(a, texture(overlay, vxLA).a);
|
|
798
|
+
a = max(a, texture(overlay, vxRP).a);
|
|
799
|
+
a = max(a, texture(overlay, vxLP).a);
|
|
800
|
+
}
|
|
801
|
+
if (axCorSag == 1) { //coronal corners
|
|
802
|
+
a = max(a, texture(overlay, vxRS).a);
|
|
803
|
+
a = max(a, texture(overlay, vxLS).a);
|
|
804
|
+
a = max(a, texture(overlay, vxRI).a);
|
|
805
|
+
a = max(a, texture(overlay, vxLI).a);
|
|
806
|
+
}
|
|
807
|
+
if (axCorSag == 2) { //sagittal corners
|
|
808
|
+
a = max(a, texture(overlay, vxAS).a);
|
|
809
|
+
a = max(a, texture(overlay, vxPS).a);
|
|
810
|
+
a = max(a, texture(overlay, vxAI).a);
|
|
811
|
+
a = max(a, texture(overlay, vxPI).a);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (a >= 1.0) {
|
|
815
|
+
ocolor = vec4(0.0, 0.0, 0.0, 1.0);
|
|
816
|
+
overlayAlpha = 1.0;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
} else {
|
|
821
|
+
if ((overlayOutlineWidth > 0.0) && (ocolor.a >= 1.0)) { //check voxel neighbors for edge
|
|
822
|
+
vec3 vx = (overlayOutlineWidth ) / vec3(textureSize(overlay, 0));
|
|
823
|
+
vec3 vxR = vec3(texPos.x+vx.x, texPos.y, texPos.z);
|
|
824
|
+
vec3 vxL = vec3(texPos.x-vx.x, texPos.y, texPos.z);
|
|
825
|
+
vec3 vxA = vec3(texPos.x, texPos.y+vx.y, texPos.z);
|
|
826
|
+
vec3 vxP = vec3(texPos.x, texPos.y-vx.y, texPos.z);
|
|
827
|
+
vec3 vxS = vec3(texPos.x, texPos.y, texPos.z+vx.z);
|
|
828
|
+
vec3 vxI = vec3(texPos.x, texPos.y, texPos.z-vx.z);
|
|
829
|
+
float a = 1.0;
|
|
830
|
+
if (axCorSag != 2) {
|
|
831
|
+
a = min(a, texture(overlay, vxR).a);
|
|
832
|
+
a = min(a, texture(overlay, vxL).a);
|
|
833
|
+
}
|
|
834
|
+
if (axCorSag != 1) {
|
|
835
|
+
a = min(a, texture(overlay, vxA).a);
|
|
836
|
+
a = min(a, texture(overlay, vxP).a);
|
|
837
|
+
}
|
|
838
|
+
if (axCorSag != 0) {
|
|
839
|
+
a = min(a, texture(overlay, vxS).a);
|
|
840
|
+
a = min(a, texture(overlay, vxI).a);
|
|
841
|
+
}
|
|
842
|
+
if (a < 1.0) {
|
|
843
|
+
ocolor = vec4(0.0, 0.0, 0.0, 1.0);
|
|
844
|
+
overlayAlpha = 1.0;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
} //outline above threshold
|
|
848
|
+
}
|
|
849
|
+
|
|
750
850
|
`;
|
|
751
851
|
var kFragSliceTail = ` ocolor.a *= overlayAlpha;
|
|
752
852
|
vec4 dcolor = drawColor(texture(drawing, texPos).r, drawOpacity);
|
|
@@ -1004,7 +1104,7 @@ uniform float layer;
|
|
|
1004
1104
|
uniform highp sampler2D colormap;
|
|
1005
1105
|
uniform lowp sampler3D blend3D;
|
|
1006
1106
|
uniform float opacity;
|
|
1007
|
-
uniform
|
|
1107
|
+
uniform vec4 xyzaFrac;
|
|
1008
1108
|
uniform mat4 mtx;
|
|
1009
1109
|
void main(void) {
|
|
1010
1110
|
vec4 vx = vec4(TexCoord.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
@@ -1012,41 +1112,30 @@ void main(void) {
|
|
|
1012
1112
|
FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
1013
1113
|
if (idx == uint(0))
|
|
1014
1114
|
return;
|
|
1015
|
-
|
|
1016
|
-
|
|
1115
|
+
//idx = ((idx - uint(1)) % uint(100))+uint(1);
|
|
1116
|
+
float textureWidth = float(textureSize(colormap, 0).x);
|
|
1117
|
+
float fx = (float(idx)+0.5) / textureWidth;
|
|
1118
|
+
float nlayer = float(textureSize(colormap, 0).y);
|
|
1119
|
+
float y = ((2.0 * layer) + 1.5)/nlayer;
|
|
1120
|
+
FragColor = texture(colormap, vec2(fx, y)).rgba;
|
|
1121
|
+
float alpha = FragColor.a;
|
|
1122
|
+
FragColor.a *= opacity;
|
|
1123
|
+
if (xyzaFrac.a > 0.0) { //outline
|
|
1124
|
+
vx = vec4(TexCoord.x+xyzaFrac.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
1017
1125
|
uint R = uint(texture(intensityVol, vx.xyz).r);
|
|
1018
|
-
vx = vec4(TexCoord.x-
|
|
1126
|
+
vx = vec4(TexCoord.x-xyzaFrac.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
1019
1127
|
uint L = uint(texture(intensityVol, vx.xyz).r);
|
|
1020
|
-
vx = vec4(TexCoord.x, TexCoord.y+
|
|
1128
|
+
vx = vec4(TexCoord.x, TexCoord.y+xyzaFrac.y, coordZ, 1.0) * mtx;
|
|
1021
1129
|
uint A = uint(texture(intensityVol, vx.xyz).r);
|
|
1022
|
-
vx = vec4(TexCoord.x, TexCoord.y-
|
|
1130
|
+
vx = vec4(TexCoord.x, TexCoord.y-xyzaFrac.y, coordZ, 1.0) * mtx;
|
|
1023
1131
|
uint P = uint(texture(intensityVol, vx.xyz).r);
|
|
1024
|
-
vx = vec4(TexCoord.x, TexCoord.y, coordZ+
|
|
1132
|
+
vx = vec4(TexCoord.x, TexCoord.y, coordZ+xyzaFrac.z, 1.0) * mtx;
|
|
1025
1133
|
uint S = uint(texture(intensityVol, vx.xyz).r);
|
|
1026
|
-
vx = vec4(TexCoord.x, TexCoord.y, coordZ-
|
|
1134
|
+
vx = vec4(TexCoord.x, TexCoord.y, coordZ-xyzaFrac.z, 1.0) * mtx;
|
|
1027
1135
|
uint I = uint(texture(intensityVol, vx.xyz).r);
|
|
1028
|
-
if ((idx
|
|
1029
|
-
|
|
1136
|
+
if ((idx != R) || (idx != L) || (idx != A) || (idx != P) || (idx != S) || (idx != I))
|
|
1137
|
+
FragColor.a = alpha * xyzaFrac.a;
|
|
1030
1138
|
}
|
|
1031
|
-
idx = ((idx - uint(1)) % uint(100))+uint(1);
|
|
1032
|
-
float textureWidth = float(textureSize(colormap, 0).x);
|
|
1033
|
-
float fx = (float(idx)+0.5) / textureWidth;
|
|
1034
|
-
float nlayer = float(textureSize(colormap, 0).y);
|
|
1035
|
-
float y = ((2.0 * layer) + 1.5)/nlayer;
|
|
1036
|
-
FragColor = texture(colormap, vec2(fx, y)).rgba;
|
|
1037
|
-
//FragColor.a *= opacity;
|
|
1038
|
-
FragColor.a = opacity;
|
|
1039
|
-
return;
|
|
1040
|
-
|
|
1041
|
-
if (layer < 2.0) return;
|
|
1042
|
-
//vec2 texXY = TexCoord.xy*0.5 +vec2(0.5,0.5);
|
|
1043
|
-
//vec4 prevColor = texture(blend3D, vec3(texXY, coordZ));
|
|
1044
|
-
vec4 prevColor = texture(blend3D, vec3(TexCoord.xy, coordZ));
|
|
1045
|
-
// https://en.wikipedia.org/wiki/Alpha_compositing
|
|
1046
|
-
float aout = FragColor.a + (1.0 - FragColor.a) * prevColor.a;
|
|
1047
|
-
if (aout <= 0.0) return;
|
|
1048
|
-
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a * (1.0 - FragColor.a))) / aout;
|
|
1049
|
-
FragColor.a = aout;
|
|
1050
1139
|
}`;
|
|
1051
1140
|
var fragOrientShader = `#line 691
|
|
1052
1141
|
precision highp int;
|
|
@@ -1187,28 +1276,28 @@ var fragGrowCutShader = `#version 300 es
|
|
|
1187
1276
|
uniform int finalPass;
|
|
1188
1277
|
uniform float coordZ;
|
|
1189
1278
|
uniform lowp sampler3D in3D;
|
|
1190
|
-
uniform highp isampler3D
|
|
1191
|
-
uniform highp isampler3D
|
|
1192
|
-
uniform highp isampler3D
|
|
1279
|
+
uniform highp isampler3D backTex; // background
|
|
1280
|
+
uniform highp isampler3D labelTex; // label
|
|
1281
|
+
uniform highp isampler3D strengthTex; // strength
|
|
1193
1282
|
void main(void) {
|
|
1194
1283
|
vec3 interpolatedTextureCoordinate = vec3(TexCoord.xy, coordZ);
|
|
1195
|
-
ivec3 size = textureSize(
|
|
1284
|
+
ivec3 size = textureSize(backTex, 0);
|
|
1196
1285
|
ivec3 texelIndex = ivec3(floor(interpolatedTextureCoordinate * vec3(size)));
|
|
1197
|
-
int background = texelFetch(
|
|
1198
|
-
label = texelFetch(
|
|
1199
|
-
strength = texelFetch(
|
|
1286
|
+
int background = texelFetch(backTex, texelIndex, 0).r;
|
|
1287
|
+
label = texelFetch(labelTex, texelIndex, 0).r;
|
|
1288
|
+
strength = texelFetch(strengthTex, texelIndex, 0).r;
|
|
1200
1289
|
for (int k = -1; k <= 1; k++) {
|
|
1201
1290
|
for (int j = -1; j <= 1; j++) {
|
|
1202
1291
|
for (int i = -1; i <= 1; i++) {
|
|
1203
1292
|
if (i != 0 && j != 0 && k != 0) {
|
|
1204
1293
|
ivec3 neighborIndex = texelIndex + ivec3(i,j,k);
|
|
1205
|
-
int neighborBackground = texelFetch(
|
|
1206
|
-
int neighborStrength = texelFetch(
|
|
1294
|
+
int neighborBackground = texelFetch(backTex, neighborIndex, 0).r;
|
|
1295
|
+
int neighborStrength = texelFetch(strengthTex, neighborIndex, 0).r;
|
|
1207
1296
|
int strengthCost = abs(neighborBackground - background);
|
|
1208
1297
|
int takeoverStrength = neighborStrength - strengthCost;
|
|
1209
1298
|
if (takeoverStrength > strength) {
|
|
1210
1299
|
strength = takeoverStrength;
|
|
1211
|
-
label = texelFetch(
|
|
1300
|
+
label = texelFetch(labelTex, neighborIndex, 0).r;
|
|
1212
1301
|
}
|
|
1213
1302
|
}
|
|
1214
1303
|
}
|
|
@@ -1222,7 +1311,7 @@ void main(void) {
|
|
|
1222
1311
|
for (int j = -1; j <= 1; j++)
|
|
1223
1312
|
for (int i = -1; i <= 1; i++) {
|
|
1224
1313
|
ivec3 neighborIndex = texelIndex + ivec3(i,j,k);
|
|
1225
|
-
int ilabel = texelFetch(
|
|
1314
|
+
int ilabel = texelFetch(labelTex, neighborIndex, 0).r;
|
|
1226
1315
|
if ((ilabel < 0) || (ilabel > 3))
|
|
1227
1316
|
ok = 0;
|
|
1228
1317
|
else
|
|
@@ -1279,9 +1368,11 @@ uniform mat4 mvpMtx;
|
|
|
1279
1368
|
uniform mat4 normMtx;
|
|
1280
1369
|
out vec4 vClr;
|
|
1281
1370
|
out vec3 vN;
|
|
1371
|
+
out vec4 vP;
|
|
1282
1372
|
void main(void) {
|
|
1283
1373
|
vec3 lightPosition = vec3(0.0, 0.0, -10.0);
|
|
1284
|
-
|
|
1374
|
+
vP = vec4(pos, 1.0);
|
|
1375
|
+
gl_Position = mvpMtx * vP;
|
|
1285
1376
|
vN = normalize((normMtx * vec4(norm.xyz,1.0)).xyz);
|
|
1286
1377
|
//vV = -vec3(modelMtx*vec4(pos,1.0));
|
|
1287
1378
|
vClr = clr;
|
|
@@ -2825,8 +2916,8 @@ __publicField(_NiivueObject3D, "CULL_FACE", 2);
|
|
|
2825
2916
|
__publicField(_NiivueObject3D, "CULL_FRONT", 4);
|
|
2826
2917
|
__publicField(_NiivueObject3D, "CULL_BACK", 8);
|
|
2827
2918
|
__publicField(_NiivueObject3D, "ENABLE_DEPTH_TEST", 16);
|
|
2828
|
-
__publicField(_NiivueObject3D, "generateCrosshairs", function(gl, id, xyzMM, xyzMin, xyzMax, radius, sides = 20) {
|
|
2829
|
-
const geometry = _NiivueObject3D.generateCrosshairsGeometry(gl, xyzMM, xyzMin, xyzMax, radius, sides);
|
|
2919
|
+
__publicField(_NiivueObject3D, "generateCrosshairs", function(gl, id, xyzMM, xyzMin, xyzMax, radius, sides = 20, gap = 0) {
|
|
2920
|
+
const geometry = _NiivueObject3D.generateCrosshairsGeometry(gl, xyzMM, xyzMin, xyzMax, radius, sides, gap);
|
|
2830
2921
|
return new _NiivueObject3D(
|
|
2831
2922
|
id,
|
|
2832
2923
|
geometry.vertexBuffer,
|
|
@@ -2837,18 +2928,40 @@ __publicField(_NiivueObject3D, "generateCrosshairs", function(gl, id, xyzMM, xyz
|
|
|
2837
2928
|
);
|
|
2838
2929
|
});
|
|
2839
2930
|
// not included in public docs
|
|
2840
|
-
__publicField(_NiivueObject3D, "generateCrosshairsGeometry", function(gl, xyzMM, xyzMin, xyzMax, radius, sides = 20) {
|
|
2931
|
+
__publicField(_NiivueObject3D, "generateCrosshairsGeometry", function(gl, xyzMM, xyzMin, xyzMax, radius, sides = 20, gap = 0) {
|
|
2841
2932
|
const vertices = [];
|
|
2842
2933
|
const indices = [];
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2934
|
+
const gapX = radius * gap;
|
|
2935
|
+
if (gapX <= 0) {
|
|
2936
|
+
let start = vec3.fromValues(xyzMin[0], xyzMM[1], xyzMM[2]);
|
|
2937
|
+
let dest = vec3.fromValues(xyzMax[0], xyzMM[1], xyzMM[2]);
|
|
2938
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
2939
|
+
start = vec3.fromValues(xyzMM[0], xyzMin[1], xyzMM[2]);
|
|
2940
|
+
dest = vec3.fromValues(xyzMM[0], xyzMax[1], xyzMM[2]);
|
|
2941
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
2942
|
+
start = vec3.fromValues(xyzMM[0], xyzMM[1], xyzMin[2]);
|
|
2943
|
+
dest = vec3.fromValues(xyzMM[0], xyzMM[1], xyzMax[2]);
|
|
2944
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
2945
|
+
} else {
|
|
2946
|
+
let start = vec3.fromValues(xyzMin[0], xyzMM[1], xyzMM[2]);
|
|
2947
|
+
let dest = vec3.fromValues(xyzMM[0] - gapX, xyzMM[1], xyzMM[2]);
|
|
2948
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides, false);
|
|
2949
|
+
start = vec3.fromValues(xyzMM[0] + gapX, xyzMM[1], xyzMM[2]);
|
|
2950
|
+
dest = vec3.fromValues(xyzMax[0], xyzMM[1], xyzMM[2]);
|
|
2951
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides, false);
|
|
2952
|
+
start = vec3.fromValues(xyzMM[0], xyzMin[1], xyzMM[2]);
|
|
2953
|
+
dest = vec3.fromValues(xyzMM[0], xyzMM[1] - gapX, xyzMM[2]);
|
|
2954
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides, false);
|
|
2955
|
+
start = vec3.fromValues(xyzMM[0], xyzMM[1] + gapX, xyzMM[2]);
|
|
2956
|
+
dest = vec3.fromValues(xyzMM[0], xyzMax[1], xyzMM[2]);
|
|
2957
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides, false);
|
|
2958
|
+
start = vec3.fromValues(xyzMM[0], xyzMM[1], xyzMin[2]);
|
|
2959
|
+
dest = vec3.fromValues(xyzMM[0], xyzMM[1], xyzMM[2] - gapX);
|
|
2960
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides, false);
|
|
2961
|
+
start = vec3.fromValues(xyzMM[0], xyzMM[1], xyzMM[2] + gapX);
|
|
2962
|
+
dest = vec3.fromValues(xyzMM[0], xyzMM[1], xyzMax[2]);
|
|
2963
|
+
_NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides, false);
|
|
2964
|
+
}
|
|
2852
2965
|
const vertexBuffer = gl.createBuffer();
|
|
2853
2966
|
if (vertexBuffer === null) {
|
|
2854
2967
|
throw new Error("could not instantiate vertex buffer");
|
|
@@ -11044,7 +11157,7 @@ var ColorTables = class {
|
|
|
11044
11157
|
const cmap = this.colormapFromKey(key);
|
|
11045
11158
|
return this.makeLut(cmap.R, cmap.G, cmap.B, cmap.A, cmap.I, isInvert);
|
|
11046
11159
|
}
|
|
11047
|
-
makeLabelLut(cm, alphaFill =
|
|
11160
|
+
makeLabelLut(cm, alphaFill = 255) {
|
|
11048
11161
|
if (cm.R === void 0 || cm.G === void 0 || cm.B === void 0) {
|
|
11049
11162
|
throw new Error(`Invalid colormap table: ${cm}`);
|
|
11050
11163
|
}
|
|
@@ -11383,11 +11496,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11383
11496
|
const offsetPt0 = [];
|
|
11384
11497
|
offsetPt0.push(npt);
|
|
11385
11498
|
const pts = [];
|
|
11386
|
-
const
|
|
11387
|
-
dps.push({
|
|
11388
|
-
id: "tract",
|
|
11389
|
-
vals: []
|
|
11390
|
-
});
|
|
11499
|
+
const bundleTags = [];
|
|
11391
11500
|
for (let t = 0; t < n_tracts; t++) {
|
|
11392
11501
|
line = readStr();
|
|
11393
11502
|
const new_tracts = readNumericTag("ni_dimen=");
|
|
@@ -11407,13 +11516,18 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11407
11516
|
}
|
|
11408
11517
|
npt += new_pts;
|
|
11409
11518
|
offsetPt0.push(npt);
|
|
11410
|
-
|
|
11519
|
+
bundleTags.push(bundleTag);
|
|
11411
11520
|
}
|
|
11412
11521
|
line = readStr();
|
|
11413
11522
|
}
|
|
11523
|
+
const dps = [];
|
|
11524
|
+
dps.push({
|
|
11525
|
+
id: "tract",
|
|
11526
|
+
vals: Float32Array.from(bundleTags)
|
|
11527
|
+
});
|
|
11414
11528
|
return {
|
|
11415
|
-
pts,
|
|
11416
|
-
offsetPt0,
|
|
11529
|
+
pts: new Float32Array(pts),
|
|
11530
|
+
offsetPt0: new Uint32Array(offsetPt0),
|
|
11417
11531
|
dps
|
|
11418
11532
|
};
|
|
11419
11533
|
}
|
|
@@ -11502,8 +11616,8 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11502
11616
|
}
|
|
11503
11617
|
return mat2;
|
|
11504
11618
|
}
|
|
11505
|
-
let offsetPt0 =
|
|
11506
|
-
let pts =
|
|
11619
|
+
let offsetPt0 = new Uint32Array(0);
|
|
11620
|
+
let pts = new Float32Array(0);
|
|
11507
11621
|
const mat = readMatV4(buffer);
|
|
11508
11622
|
if (!("trans_to_mni" in mat)) {
|
|
11509
11623
|
throw new Error("TT format file must have 'trans_to_mni'");
|
|
@@ -11535,8 +11649,6 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11535
11649
|
m[15]
|
|
11536
11650
|
);
|
|
11537
11651
|
mat42.transpose(trans_to_mni, trans_to_mni);
|
|
11538
|
-
const zoomMat = mat42.create();
|
|
11539
|
-
mat42.transpose(zoomMat, zoomMat);
|
|
11540
11652
|
function parse_tt(track) {
|
|
11541
11653
|
const dv = new DataView(track.buffer);
|
|
11542
11654
|
const pos = [];
|
|
@@ -11574,12 +11686,10 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11574
11686
|
for (let i2 = 0; i2 < npt; i2++) {
|
|
11575
11687
|
pts[i2] = pts[i2] / 32;
|
|
11576
11688
|
}
|
|
11577
|
-
const vox2mmMat = mat42.create();
|
|
11578
|
-
mat42.mul(vox2mmMat, trans_to_mni, zoomMat);
|
|
11579
11689
|
let v = 0;
|
|
11580
11690
|
for (let i2 = 0; i2 < npt / 3; i2++) {
|
|
11581
11691
|
const pos2 = vec42.fromValues(pts[v], pts[v + 1], pts[v + 2], 1);
|
|
11582
|
-
vec42.transformMat4(pos2, pos2,
|
|
11692
|
+
vec42.transformMat4(pos2, pos2, trans_to_mni);
|
|
11583
11693
|
pts[v++] = pos2[0];
|
|
11584
11694
|
pts[v++] = pos2[1];
|
|
11585
11695
|
pts[v++] = pos2[2];
|
|
@@ -11603,7 +11713,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11603
11713
|
}
|
|
11604
11714
|
let noff = 0;
|
|
11605
11715
|
let npt = 0;
|
|
11606
|
-
let pts = [];
|
|
11716
|
+
let pts = new Float32Array([]);
|
|
11607
11717
|
const offsetPt0 = [];
|
|
11608
11718
|
const dpg = [];
|
|
11609
11719
|
const dps = [];
|
|
@@ -11678,31 +11788,21 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11678
11788
|
if (pname.includes("groups")) {
|
|
11679
11789
|
dpg.push({
|
|
11680
11790
|
id: tag,
|
|
11681
|
-
vals:
|
|
11791
|
+
vals: Float32Array.from(vals.slice())
|
|
11682
11792
|
});
|
|
11683
11793
|
continue;
|
|
11684
11794
|
}
|
|
11685
11795
|
if (pname.includes("dpv")) {
|
|
11686
|
-
let mn = vals[0];
|
|
11687
|
-
let mx = vals[0];
|
|
11688
|
-
for (let i2 = 1; i2 < vals.length; i2++) {
|
|
11689
|
-
mn = Math.min(vals[i2], mn);
|
|
11690
|
-
mx = Math.max(vals[i2], mx);
|
|
11691
|
-
}
|
|
11692
11796
|
dpv.push({
|
|
11693
11797
|
id: tag,
|
|
11694
|
-
vals:
|
|
11695
|
-
global_min: mn,
|
|
11696
|
-
global_max: mx,
|
|
11697
|
-
cal_min: mn,
|
|
11698
|
-
cal_max: mx
|
|
11798
|
+
vals: Float32Array.from(vals.slice())
|
|
11699
11799
|
});
|
|
11700
11800
|
continue;
|
|
11701
11801
|
}
|
|
11702
11802
|
if (pname.includes("dps")) {
|
|
11703
11803
|
dps.push({
|
|
11704
11804
|
id: tag,
|
|
11705
|
-
vals:
|
|
11805
|
+
vals: Float32Array.from(vals.slice())
|
|
11706
11806
|
});
|
|
11707
11807
|
continue;
|
|
11708
11808
|
}
|
|
@@ -11714,7 +11814,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11714
11814
|
}
|
|
11715
11815
|
if (fname.startsWith("positions.3.")) {
|
|
11716
11816
|
npt = nval;
|
|
11717
|
-
pts =
|
|
11817
|
+
pts = new Float32Array(vals);
|
|
11718
11818
|
}
|
|
11719
11819
|
}
|
|
11720
11820
|
if (noff === 0 || npt === 0) {
|
|
@@ -11725,8 +11825,8 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11725
11825
|
}
|
|
11726
11826
|
offsetPt0[noff] = npt / 3;
|
|
11727
11827
|
return {
|
|
11728
|
-
pts
|
|
11729
|
-
offsetPt0:
|
|
11828
|
+
pts,
|
|
11829
|
+
offsetPt0: new Uint32Array(offsetPt0),
|
|
11730
11830
|
dpg,
|
|
11731
11831
|
dps,
|
|
11732
11832
|
dpv,
|
|
@@ -11886,23 +11986,16 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11886
11986
|
if (vers > 2 || hdr_sz !== 1e3 || magic !== 1128354388) {
|
|
11887
11987
|
throw new Error("Not a valid TRK file");
|
|
11888
11988
|
}
|
|
11889
|
-
const dps = [];
|
|
11890
|
-
const dpv = [];
|
|
11891
11989
|
const n_scalars = reader.getInt16(36, true);
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
global_max: 0,
|
|
11902
|
-
cal_min: 0,
|
|
11903
|
-
cal_max: 0
|
|
11904
|
-
});
|
|
11905
|
-
}
|
|
11990
|
+
const dpv = [];
|
|
11991
|
+
for (let i2 = 0; i2 < n_scalars; i2++) {
|
|
11992
|
+
const arr = new Uint8Array(buffer.slice(38 + i2 * 20, 58 + i2 * 20));
|
|
11993
|
+
const str = new TextDecoder().decode(arr).split("\0").shift();
|
|
11994
|
+
dpv.push({
|
|
11995
|
+
id: str.trim(),
|
|
11996
|
+
// TODO can we guarantee this?
|
|
11997
|
+
vals: []
|
|
11998
|
+
});
|
|
11906
11999
|
}
|
|
11907
12000
|
const voxel_sizeX = reader.getFloat32(12, true);
|
|
11908
12001
|
const voxel_sizeY = reader.getFloat32(16, true);
|
|
@@ -11926,16 +12019,15 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11926
12019
|
1
|
|
11927
12020
|
);
|
|
11928
12021
|
const n_properties = reader.getInt16(238, true);
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
}
|
|
12022
|
+
const dps = [];
|
|
12023
|
+
for (let i2 = 0; i2 < n_properties; i2++) {
|
|
12024
|
+
const arr = new Uint8Array(buffer.slice(240 + i2 * 20, 260 + i2 * 20));
|
|
12025
|
+
const str = new TextDecoder().decode(arr).split("\0").shift();
|
|
12026
|
+
dps.push({
|
|
12027
|
+
id: str.trim(),
|
|
12028
|
+
// TODO can we guarantee this?
|
|
12029
|
+
vals: []
|
|
12030
|
+
});
|
|
11939
12031
|
}
|
|
11940
12032
|
const mat = mat42.create();
|
|
11941
12033
|
for (let i2 = 0; i2 < 16; i2++) {
|
|
@@ -11947,9 +12039,6 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11947
12039
|
}
|
|
11948
12040
|
const vox2mmMat = mat42.create();
|
|
11949
12041
|
mat42.mul(vox2mmMat, zoomMat, mat);
|
|
11950
|
-
vox2mmMat[3] = mat[3];
|
|
11951
|
-
vox2mmMat[7] = mat[7];
|
|
11952
|
-
vox2mmMat[11] = mat[11];
|
|
11953
12042
|
let i32 = null;
|
|
11954
12043
|
let f32 = null;
|
|
11955
12044
|
i32 = new Int32Array(buffer.slice(hdr_sz));
|
|
@@ -11991,15 +12080,19 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
11991
12080
|
}
|
|
11992
12081
|
}
|
|
11993
12082
|
}
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
|
|
11997
|
-
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
|
|
12001
|
-
|
|
12002
|
-
|
|
12083
|
+
const dps32 = [];
|
|
12084
|
+
for (let i2 = 0; i2 < dps.length; i2++) {
|
|
12085
|
+
dps32.push({
|
|
12086
|
+
id: dps[i2].id,
|
|
12087
|
+
vals: Float32Array.from(dps[i2].vals)
|
|
12088
|
+
});
|
|
12089
|
+
}
|
|
12090
|
+
const dpv32 = [];
|
|
12091
|
+
for (let s = 0; s < dpv.length; s++) {
|
|
12092
|
+
dpv32.push({
|
|
12093
|
+
id: dpv[i].id,
|
|
12094
|
+
vals: Float32Array.from(dpv[i].vals)
|
|
12095
|
+
});
|
|
12003
12096
|
}
|
|
12004
12097
|
offsetPt0[noffset++] = npt;
|
|
12005
12098
|
pts = pts.slice(0, npt3);
|
|
@@ -12007,8 +12100,8 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12007
12100
|
return {
|
|
12008
12101
|
pts,
|
|
12009
12102
|
offsetPt0,
|
|
12010
|
-
dps,
|
|
12011
|
-
dpv
|
|
12103
|
+
dps: dps32,
|
|
12104
|
+
dpv: dpv32
|
|
12012
12105
|
};
|
|
12013
12106
|
}
|
|
12014
12107
|
// readTRK()
|
|
@@ -12166,7 +12259,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12166
12259
|
} else {
|
|
12167
12260
|
throw new Error("Unsupported ASCII VTK datatype " + items[0]);
|
|
12168
12261
|
}
|
|
12169
|
-
const indices = new
|
|
12262
|
+
const indices = new Uint32Array(tris);
|
|
12170
12263
|
return {
|
|
12171
12264
|
positions,
|
|
12172
12265
|
indices
|
|
@@ -12174,7 +12267,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12174
12267
|
}
|
|
12175
12268
|
// readTxtVTK()
|
|
12176
12269
|
// read mesh overlay to influence vertex colors
|
|
12177
|
-
static readLayer(name = "", buffer, nvmesh, opacity = 0.5, colormap = "warm", colormapNegative = "winter", useNegativeCmap = false, cal_min = null, cal_max = null,
|
|
12270
|
+
static readLayer(name = "", buffer, nvmesh, opacity = 0.5, colormap = "warm", colormapNegative = "winter", useNegativeCmap = false, cal_min = null, cal_max = null, outlineBorder = 0) {
|
|
12178
12271
|
const layer = {
|
|
12179
12272
|
colormapInvert: false,
|
|
12180
12273
|
alphaThreshold: false,
|
|
@@ -12212,7 +12305,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12212
12305
|
const mx2 = vals.reduce((acc, current) => Math.max(acc, current));
|
|
12213
12306
|
nvmesh.dpv.push({
|
|
12214
12307
|
id: tag,
|
|
12215
|
-
vals:
|
|
12308
|
+
vals: Float32Array.from(vals.slice()),
|
|
12216
12309
|
global_min: mn2,
|
|
12217
12310
|
global_max: mx2,
|
|
12218
12311
|
cal_min: mn2,
|
|
@@ -12271,7 +12364,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12271
12364
|
}
|
|
12272
12365
|
layer.nFrame4D = layer.values.length / n_vert;
|
|
12273
12366
|
layer.frame4D = 0;
|
|
12274
|
-
layer.
|
|
12367
|
+
layer.outlineBorder = outlineBorder;
|
|
12275
12368
|
let mn = layer.values[0];
|
|
12276
12369
|
let mx = layer.values[0];
|
|
12277
12370
|
for (let i = 0; i < layer.values.length; i++) {
|
|
@@ -12624,7 +12717,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12624
12717
|
}
|
|
12625
12718
|
if (ntri < 1) {
|
|
12626
12719
|
ntri = parseInt(items[0]);
|
|
12627
|
-
indices = new
|
|
12720
|
+
indices = new Uint32Array(ntri * 3);
|
|
12628
12721
|
continue;
|
|
12629
12722
|
}
|
|
12630
12723
|
if (t >= ntri * 3) {
|
|
@@ -12680,7 +12773,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12680
12773
|
positions[j + 2] = parseFloat(items[2]);
|
|
12681
12774
|
j += 3;
|
|
12682
12775
|
}
|
|
12683
|
-
const indices = new
|
|
12776
|
+
const indices = new Uint32Array(ntri * 3);
|
|
12684
12777
|
j = 0;
|
|
12685
12778
|
for (let i = 0; i < ntri; i++) {
|
|
12686
12779
|
line = readStr();
|
|
@@ -12862,7 +12955,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12862
12955
|
} else {
|
|
12863
12956
|
throw new Error("Unsupported binary VTK datatype " + items[0]);
|
|
12864
12957
|
}
|
|
12865
|
-
const indices = new
|
|
12958
|
+
const indices = new Uint32Array(tris);
|
|
12866
12959
|
return {
|
|
12867
12960
|
positions,
|
|
12868
12961
|
indices
|
|
@@ -12883,7 +12976,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12883
12976
|
const nvert = reader.getUint32(28, true);
|
|
12884
12977
|
const vcoffset = reader.getUint32(48, true);
|
|
12885
12978
|
let pos = hdrBytes;
|
|
12886
|
-
const indices = new
|
|
12979
|
+
const indices = new Uint32Array(buffer, pos, nface * 3);
|
|
12887
12980
|
pos += nface * 3 * 4;
|
|
12888
12981
|
const positions = new Float32Array(buffer, pos, nvert * 3);
|
|
12889
12982
|
for (let i = 0; i < nvert * 3; i += 3) {
|
|
@@ -12941,7 +13034,11 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12941
13034
|
isSCALAR = true;
|
|
12942
13035
|
}
|
|
12943
13036
|
if (isSCALAR) {
|
|
12944
|
-
|
|
13037
|
+
let nv = n_vert;
|
|
13038
|
+
if (n_vert === 0) {
|
|
13039
|
+
nv = nvert;
|
|
13040
|
+
}
|
|
13041
|
+
const FSizeWoScalars = 16 + nskip + (isFace ? 1 : 0) * nface * 12 + (isVert ? 1 : 0) * nv * 12 + (isRGBA ? 1 : 0) * nv * 4;
|
|
12945
13042
|
const scalarFloats = Math.floor((_buffer.byteLength - FSizeWoScalars) / bytesPerScalar);
|
|
12946
13043
|
if (nvert !== n_vert && scalarFloats % n_vert === 0) {
|
|
12947
13044
|
log.warn("Issue 729: mz3 mismatch scalar NVERT does not match mesh NVERT");
|
|
@@ -12962,7 +13059,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12962
13059
|
let filepos = 16 + nskip;
|
|
12963
13060
|
let indices = null;
|
|
12964
13061
|
if (isFace) {
|
|
12965
|
-
indices = new
|
|
13062
|
+
indices = new Uint32Array(_buffer, filepos, nface * 3);
|
|
12966
13063
|
filepos += nface * 3 * 4;
|
|
12967
13064
|
}
|
|
12968
13065
|
let positions = null;
|
|
@@ -13116,7 +13213,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13116
13213
|
positions2[v + 2] = parseFloat(items[2]);
|
|
13117
13214
|
v += 3;
|
|
13118
13215
|
}
|
|
13119
|
-
let indices2 = new
|
|
13216
|
+
let indices2 = new Uint32Array(nface * 3);
|
|
13120
13217
|
let f = 0;
|
|
13121
13218
|
for (let i = 0; i < nface; i++) {
|
|
13122
13219
|
line = readStr();
|
|
@@ -13126,7 +13223,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13126
13223
|
break;
|
|
13127
13224
|
}
|
|
13128
13225
|
if (f + nTri * 3 > indices2.length) {
|
|
13129
|
-
const c = new
|
|
13226
|
+
const c = new Uint32Array(indices2.length + indices2.length);
|
|
13130
13227
|
c.set(indices2);
|
|
13131
13228
|
indices2 = c.slice();
|
|
13132
13229
|
}
|
|
@@ -13176,7 +13273,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13176
13273
|
pos += vertStride;
|
|
13177
13274
|
}
|
|
13178
13275
|
}
|
|
13179
|
-
const indices = new
|
|
13276
|
+
const indices = new Uint32Array(nface * 3);
|
|
13180
13277
|
let isTriangular = true;
|
|
13181
13278
|
let j = 0;
|
|
13182
13279
|
if (indexCountBytes === 1 && indexBytes === 4 && indexStrideBytes === 13) {
|
|
@@ -13267,7 +13364,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13267
13364
|
header = lines[line].trim().split(/\s+/);
|
|
13268
13365
|
line++;
|
|
13269
13366
|
const num_f = parseInt(header[0]);
|
|
13270
|
-
const indices = new
|
|
13367
|
+
const indices = new Uint32Array(num_f * 3);
|
|
13271
13368
|
for (let i = 0; i < num_f; i++) {
|
|
13272
13369
|
const items = lines[line].trim().split(/\s+/);
|
|
13273
13370
|
line++;
|
|
@@ -13352,7 +13449,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13352
13449
|
}
|
|
13353
13450
|
}
|
|
13354
13451
|
const positions = new Float32Array(pts);
|
|
13355
|
-
const indices = new
|
|
13452
|
+
const indices = new Uint32Array(t);
|
|
13356
13453
|
return {
|
|
13357
13454
|
positions,
|
|
13358
13455
|
indices
|
|
@@ -13398,16 +13495,58 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13398
13495
|
i++;
|
|
13399
13496
|
}
|
|
13400
13497
|
const positions = new Float32Array(pts);
|
|
13401
|
-
const indices = new
|
|
13498
|
+
const indices = new Uint32Array(t);
|
|
13402
13499
|
return {
|
|
13403
13500
|
positions,
|
|
13404
13501
|
indices
|
|
13405
13502
|
};
|
|
13406
13503
|
}
|
|
13407
13504
|
// readOFF()
|
|
13505
|
+
static readOBJMNI(buffer) {
|
|
13506
|
+
const enc = new TextDecoder("utf-8");
|
|
13507
|
+
const txt = enc.decode(buffer);
|
|
13508
|
+
const items = txt.trim().split(/\s*,\s*|\s+/);
|
|
13509
|
+
if (items.length < 1 || items[0] !== "P") {
|
|
13510
|
+
log.warn("This is not a valid MNI OBJ mesh.");
|
|
13511
|
+
}
|
|
13512
|
+
let j = 6;
|
|
13513
|
+
const nVert = parseInt(items[j++]);
|
|
13514
|
+
const nVertX3 = nVert * 3;
|
|
13515
|
+
const positions = new Float32Array(nVertX3);
|
|
13516
|
+
for (let i = 0; i < nVertX3; i++) {
|
|
13517
|
+
positions[i] = parseFloat(items[j++]);
|
|
13518
|
+
}
|
|
13519
|
+
j += nVertX3;
|
|
13520
|
+
const nTri = parseInt(items[j++]);
|
|
13521
|
+
const colour_flag = parseInt(items[j++]);
|
|
13522
|
+
if (nTri < 1 || colour_flag < 0 || colour_flag > 2) {
|
|
13523
|
+
log.warn("This is not a valid MNI OBJ mesh.");
|
|
13524
|
+
}
|
|
13525
|
+
let num_c = 1;
|
|
13526
|
+
if (colour_flag === 1) {
|
|
13527
|
+
num_c = nTri;
|
|
13528
|
+
} else if (colour_flag === 1) {
|
|
13529
|
+
num_c = nVert;
|
|
13530
|
+
}
|
|
13531
|
+
j += num_c * 4;
|
|
13532
|
+
j += nTri;
|
|
13533
|
+
const nTriX3 = nTri * 3;
|
|
13534
|
+
const indices = new Uint32Array(nTriX3);
|
|
13535
|
+
for (let i = 0; i < nTriX3; i++) {
|
|
13536
|
+
indices[i] = parseInt(items[j++]);
|
|
13537
|
+
}
|
|
13538
|
+
return {
|
|
13539
|
+
positions,
|
|
13540
|
+
indices
|
|
13541
|
+
};
|
|
13542
|
+
}
|
|
13543
|
+
// readOBJMNI()
|
|
13408
13544
|
static readOBJ(buffer) {
|
|
13409
13545
|
const enc = new TextDecoder("utf-8");
|
|
13410
13546
|
const txt = enc.decode(buffer);
|
|
13547
|
+
if (txt[0] === "P") {
|
|
13548
|
+
return this.readOBJMNI(buffer);
|
|
13549
|
+
}
|
|
13411
13550
|
const lines = txt.split("\n");
|
|
13412
13551
|
const n = lines.length;
|
|
13413
13552
|
const pts = [];
|
|
@@ -13441,7 +13580,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13441
13580
|
}
|
|
13442
13581
|
}
|
|
13443
13582
|
const positions = new Float32Array(pts);
|
|
13444
|
-
const indices = new
|
|
13583
|
+
const indices = new Uint32Array(t);
|
|
13445
13584
|
return {
|
|
13446
13585
|
positions,
|
|
13447
13586
|
indices
|
|
@@ -13476,7 +13615,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13476
13615
|
offset += 4;
|
|
13477
13616
|
}
|
|
13478
13617
|
nf *= 3;
|
|
13479
|
-
const indices = new
|
|
13618
|
+
const indices = new Uint32Array(nf);
|
|
13480
13619
|
for (let i = 0; i < nf; i++) {
|
|
13481
13620
|
indices[i] = view.getUint32(offset, false);
|
|
13482
13621
|
offset += 4;
|
|
@@ -13593,7 +13732,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13593
13732
|
const nNearest = reader.getUint32(pos, true);
|
|
13594
13733
|
pos += 4 + 4 * nNearest;
|
|
13595
13734
|
}
|
|
13596
|
-
const indices = new
|
|
13735
|
+
const indices = new Uint32Array(nTri * 3);
|
|
13597
13736
|
for (let i = 0; i < nTri * 3; i++) {
|
|
13598
13737
|
indices[i] = reader.getInt32(pos, true);
|
|
13599
13738
|
pos += 4;
|
|
@@ -13632,7 +13771,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13632
13771
|
throw new Error("Unable to parse ASCII STL file.");
|
|
13633
13772
|
}
|
|
13634
13773
|
const positions = new Float32Array(pts);
|
|
13635
|
-
const indices = new
|
|
13774
|
+
const indices = new Uint32Array(npts);
|
|
13636
13775
|
for (let i = 0; i < npts; i++) {
|
|
13637
13776
|
indices[i] = i;
|
|
13638
13777
|
}
|
|
@@ -13658,7 +13797,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13658
13797
|
if (buffer.byteLength < 80 + 4 + ntri * 50) {
|
|
13659
13798
|
throw new Error("STL file too small to store triangles = " + ntri);
|
|
13660
13799
|
}
|
|
13661
|
-
const indices = new
|
|
13800
|
+
const indices = new Uint32Array(ntri3);
|
|
13662
13801
|
const positions = new Float32Array(ntri3 * 3);
|
|
13663
13802
|
let pos = 80 + 4 + 12;
|
|
13664
13803
|
let v = 0;
|
|
@@ -13753,7 +13892,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13753
13892
|
let indexCount = 0;
|
|
13754
13893
|
let surfaceNumberOfVertices = 0;
|
|
13755
13894
|
let brainStructure = "";
|
|
13756
|
-
let vertexIndices = new
|
|
13895
|
+
let vertexIndices = new Uint32Array();
|
|
13757
13896
|
const bytes = new Uint8Array(buffer);
|
|
13758
13897
|
let pos = 552;
|
|
13759
13898
|
let line;
|
|
@@ -13803,7 +13942,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13803
13942
|
if (items.length < indexCount) {
|
|
13804
13943
|
log.error("Error parsing VertexIndices");
|
|
13805
13944
|
}
|
|
13806
|
-
vertexIndices = new
|
|
13945
|
+
vertexIndices = new Uint32Array(indexCount);
|
|
13807
13946
|
for (let i = 0; i < indexCount; i++) {
|
|
13808
13947
|
vertexIndices[i] = parseInt(items[i]);
|
|
13809
13948
|
}
|
|
@@ -14099,33 +14238,20 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14099
14238
|
static readX3D(buffer) {
|
|
14100
14239
|
const len = buffer.byteLength;
|
|
14101
14240
|
if (len < 20) {
|
|
14102
|
-
throw new Error("File too small to be
|
|
14241
|
+
throw new Error("File too small to be X3D: bytes = " + len);
|
|
14103
14242
|
}
|
|
14104
14243
|
const bytes = new Uint8Array(buffer);
|
|
14105
14244
|
let pos = 0;
|
|
14106
|
-
function
|
|
14107
|
-
while (pos < len && bytes[pos]
|
|
14245
|
+
function readStr() {
|
|
14246
|
+
while (pos < len && bytes[pos] !== 60) {
|
|
14108
14247
|
pos++;
|
|
14109
14248
|
}
|
|
14110
|
-
const
|
|
14111
|
-
while (pos < len && bytes[pos] !==
|
|
14249
|
+
const startP = pos;
|
|
14250
|
+
while (pos < len && bytes[pos] !== 62) {
|
|
14112
14251
|
pos++;
|
|
14113
14252
|
}
|
|
14114
|
-
pos
|
|
14115
|
-
|
|
14116
|
-
return "";
|
|
14117
|
-
}
|
|
14118
|
-
return new TextDecoder().decode(buffer.slice(startPos, pos - 1)).trim();
|
|
14119
|
-
}
|
|
14120
|
-
function readStr() {
|
|
14121
|
-
let line2 = readStrX();
|
|
14122
|
-
if (!line2.startsWith("<") || line2.endsWith(">")) {
|
|
14123
|
-
return line2;
|
|
14124
|
-
}
|
|
14125
|
-
while (pos < len && !line2.endsWith(">")) {
|
|
14126
|
-
line2 += readStrX();
|
|
14127
|
-
}
|
|
14128
|
-
return line2;
|
|
14253
|
+
const endP = pos;
|
|
14254
|
+
return new TextDecoder().decode(buffer.slice(startP, endP + 1)).trim();
|
|
14129
14255
|
}
|
|
14130
14256
|
let line = readStr();
|
|
14131
14257
|
function readStringTag(TagName) {
|
|
@@ -14146,22 +14272,30 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14146
14272
|
const delimiter = line[fpos + TagName.length + 1];
|
|
14147
14273
|
const spos = line.indexOf(delimiter, fpos) + 1;
|
|
14148
14274
|
const epos = line.indexOf(delimiter, spos);
|
|
14149
|
-
|
|
14150
|
-
|
|
14275
|
+
let str = line.slice(spos, epos).trim();
|
|
14276
|
+
str = str.replace(/,\s*$/, "");
|
|
14277
|
+
const items = str.trim().split(/\s*,\s*|\s+/);
|
|
14151
14278
|
if (items.length < 2) {
|
|
14152
14279
|
return parseFloat(str);
|
|
14153
14280
|
}
|
|
14154
|
-
|
|
14281
|
+
let ret = new Array(items.length);
|
|
14282
|
+
let j = 0;
|
|
14155
14283
|
for (let i = 0; i < items.length; i++) {
|
|
14156
|
-
|
|
14284
|
+
const v = parseFloat(items[i]);
|
|
14285
|
+
if (!isFinite(v)) {
|
|
14286
|
+
continue;
|
|
14287
|
+
}
|
|
14288
|
+
ret[j] = v;
|
|
14289
|
+
j++;
|
|
14157
14290
|
}
|
|
14291
|
+
ret = ret.slice(0, j);
|
|
14158
14292
|
return ret;
|
|
14159
14293
|
}
|
|
14160
14294
|
if (!line.includes("xml version")) {
|
|
14161
14295
|
log.warn("Not a X3D image");
|
|
14162
14296
|
}
|
|
14163
14297
|
let positions = [];
|
|
14164
|
-
|
|
14298
|
+
let indices = [];
|
|
14165
14299
|
let rgba255 = [];
|
|
14166
14300
|
let color = [];
|
|
14167
14301
|
let translation = [0, 0, 0, 0];
|
|
@@ -14239,12 +14373,20 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14239
14373
|
height = -2;
|
|
14240
14374
|
coordIndex = readNumericTag("coordIndex");
|
|
14241
14375
|
}
|
|
14376
|
+
if (line.startsWith("<IndexedTriangleSet")) {
|
|
14377
|
+
height = -7;
|
|
14378
|
+
coordIndex = readNumericTag("index");
|
|
14379
|
+
}
|
|
14242
14380
|
if (line.startsWith("<IndexedTriangleStripSet")) {
|
|
14243
14381
|
height = -3;
|
|
14244
14382
|
coordIndex = readNumericTag("index");
|
|
14245
14383
|
}
|
|
14246
14384
|
if (line.startsWith("<Coordinate")) {
|
|
14247
14385
|
point = readNumericTag("point");
|
|
14386
|
+
const rem = point.length % 3;
|
|
14387
|
+
if (rem !== 0) {
|
|
14388
|
+
point = point.slice(0, -rem);
|
|
14389
|
+
}
|
|
14248
14390
|
}
|
|
14249
14391
|
if (line.startsWith("<Color")) {
|
|
14250
14392
|
color = readNumericTag("color");
|
|
@@ -14262,7 +14404,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14262
14404
|
log.warn("Unsupported x3d shape: ElevationGrid");
|
|
14263
14405
|
}
|
|
14264
14406
|
}
|
|
14265
|
-
if (height < -3) {
|
|
14407
|
+
if (height < -3 && height !== -7) {
|
|
14266
14408
|
} else if (height < -1) {
|
|
14267
14409
|
if (coordIndex.length < 1 || point.length < 3 || point.length === void 0) {
|
|
14268
14410
|
log.warn("Indexed mesh must specify indices and points");
|
|
@@ -14270,7 +14412,9 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14270
14412
|
}
|
|
14271
14413
|
const idx0 = Math.floor(positions.length / 3);
|
|
14272
14414
|
let j = 2;
|
|
14273
|
-
if (height === -
|
|
14415
|
+
if (height === -7) {
|
|
14416
|
+
indices = [...indices, ...coordIndex];
|
|
14417
|
+
} else if (height === -2) {
|
|
14274
14418
|
let triStart = 0;
|
|
14275
14419
|
while (j < coordIndex.length) {
|
|
14276
14420
|
if (coordIndex[j] >= 0) {
|
|
@@ -14329,9 +14473,9 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14329
14473
|
}
|
|
14330
14474
|
}
|
|
14331
14475
|
return {
|
|
14332
|
-
positions,
|
|
14333
|
-
indices:
|
|
14334
|
-
rgba255
|
|
14476
|
+
positions: Float32Array.from(positions),
|
|
14477
|
+
indices: Uint32Array.from(indices),
|
|
14478
|
+
rgba255: Uint8Array.from(rgba255)
|
|
14335
14479
|
};
|
|
14336
14480
|
}
|
|
14337
14481
|
// readX3D()
|
|
@@ -14399,7 +14543,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14399
14543
|
}
|
|
14400
14544
|
len = tag.contentEndPos;
|
|
14401
14545
|
let positions = new Float32Array();
|
|
14402
|
-
let indices = new
|
|
14546
|
+
let indices = new Uint32Array();
|
|
14403
14547
|
let scalars = new Float32Array();
|
|
14404
14548
|
let anatomicalStructurePrimary = "";
|
|
14405
14549
|
let isIdx = false;
|
|
@@ -14526,7 +14670,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14526
14670
|
if (dataType !== 8) {
|
|
14527
14671
|
log.warn("expect indices as INT32");
|
|
14528
14672
|
}
|
|
14529
|
-
indices = new
|
|
14673
|
+
indices = new Uint32Array(datBin.buffer);
|
|
14530
14674
|
if (isColMajor) {
|
|
14531
14675
|
const tmp = indices.slice();
|
|
14532
14676
|
const np = tmp.length / 3;
|
|
@@ -14659,7 +14803,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14659
14803
|
|
|
14660
14804
|
// src/nvmesh.ts
|
|
14661
14805
|
var NVMeshFromUrlOptions = class {
|
|
14662
|
-
constructor(url = "", gl = null, name = "", opacity = 1, rgba255 = [255, 255, 255, 255], visible = true, layers = [], colorbarVisible = true) {
|
|
14806
|
+
constructor(url = "", gl = null, name = "", opacity = 1, rgba255 = new Uint8Array([255, 255, 255, 255]), visible = true, layers = [], colorbarVisible = true) {
|
|
14663
14807
|
__publicField(this, "url");
|
|
14664
14808
|
__publicField(this, "gl");
|
|
14665
14809
|
__publicField(this, "name");
|
|
@@ -14694,7 +14838,7 @@ var NVMesh = class _NVMesh {
|
|
|
14694
14838
|
* @param colorbarVisible - does this mesh display a colorbar
|
|
14695
14839
|
* @param anatomicalStructurePrimary - region for mesh. Default is an empty string
|
|
14696
14840
|
*/
|
|
14697
|
-
constructor(pts, tris, name = "", rgba255 = [255, 255, 255, 255], opacity = 1, visible = true, gl, connectome = null, dpg = null, dps = null, dpv = null, colorbarVisible = true, anatomicalStructurePrimary = "") {
|
|
14841
|
+
constructor(pts, tris, name = "", rgba255 = new Uint8Array([255, 255, 255, 255]), opacity = 1, visible = true, gl, connectome = null, dpg = null, dps = null, dpv = null, colorbarVisible = true, anatomicalStructurePrimary = "") {
|
|
14698
14842
|
__publicField(this, "id");
|
|
14699
14843
|
__publicField(this, "name");
|
|
14700
14844
|
__publicField(this, "anatomicalStructurePrimary");
|
|
@@ -14742,6 +14886,7 @@ var NVMesh = class _NVMesh {
|
|
|
14742
14886
|
__publicField(this, "vertexCount", 1);
|
|
14743
14887
|
__publicField(this, "nodeScale", 4);
|
|
14744
14888
|
__publicField(this, "edgeScale", 1);
|
|
14889
|
+
__publicField(this, "legendLineThickness", 0);
|
|
14745
14890
|
__publicField(this, "nodeColormap", "warm");
|
|
14746
14891
|
__publicField(this, "edgeColormap", "warm");
|
|
14747
14892
|
__publicField(this, "nodeColormapNegative");
|
|
@@ -14804,6 +14949,15 @@ var NVMesh = class _NVMesh {
|
|
|
14804
14949
|
this.dpg = dpg;
|
|
14805
14950
|
this.dps = dps;
|
|
14806
14951
|
this.dpv = dpv;
|
|
14952
|
+
if (dpg) {
|
|
14953
|
+
this.initValuesArray(dpg);
|
|
14954
|
+
}
|
|
14955
|
+
if (dps) {
|
|
14956
|
+
this.initValuesArray(dps);
|
|
14957
|
+
}
|
|
14958
|
+
if (dpv) {
|
|
14959
|
+
this.initValuesArray(dpv);
|
|
14960
|
+
}
|
|
14807
14961
|
this.offsetPt0 = tris;
|
|
14808
14962
|
this.updateFibers(gl);
|
|
14809
14963
|
gl.bindVertexArray(this.vaoFiber);
|
|
@@ -14828,6 +14982,17 @@ var NVMesh = class _NVMesh {
|
|
|
14828
14982
|
this.tris = tris;
|
|
14829
14983
|
this.updateMesh(gl);
|
|
14830
14984
|
}
|
|
14985
|
+
initValuesArray(va) {
|
|
14986
|
+
for (let i = 0; i < va.length; i++) {
|
|
14987
|
+
const mn = va[i].vals.reduce((acc, current) => Math.min(acc, current));
|
|
14988
|
+
const mx = va[i].vals.reduce((acc, current) => Math.max(acc, current));
|
|
14989
|
+
va[i].global_min = mn;
|
|
14990
|
+
va[i].global_max = mx;
|
|
14991
|
+
va[i].cal_min = mn;
|
|
14992
|
+
va[i].cal_max = mx;
|
|
14993
|
+
}
|
|
14994
|
+
return va;
|
|
14995
|
+
}
|
|
14831
14996
|
// given streamlines (which webGL renders as a single pixel), extrude to cylinders
|
|
14832
14997
|
linesToCylinders(gl, posClrF32, indices) {
|
|
14833
14998
|
function v4ToV3(v4) {
|
|
@@ -14923,7 +15088,7 @@ var NVMesh = class _NVMesh {
|
|
|
14923
15088
|
}
|
|
14924
15089
|
}
|
|
14925
15090
|
const nidx = (n_line_vtx - n_streamlines) * cyl_sides * 2 * 3;
|
|
14926
|
-
const idxs = new
|
|
15091
|
+
const idxs = new Uint32Array(nidx);
|
|
14927
15092
|
let idx = 0;
|
|
14928
15093
|
vtx = 0;
|
|
14929
15094
|
for (let i = 1; i < n_count; i++) {
|
|
@@ -14955,9 +15120,9 @@ var NVMesh = class _NVMesh {
|
|
|
14955
15120
|
vtx += cyl_sides;
|
|
14956
15121
|
}
|
|
14957
15122
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
|
14958
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
|
|
15123
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Uint32Array.from(idxs), gl.STATIC_DRAW);
|
|
14959
15124
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
14960
|
-
gl.bufferData(gl.ARRAY_BUFFER,
|
|
15125
|
+
gl.bufferData(gl.ARRAY_BUFFER, Float32Array.from(f32), gl.STATIC_DRAW);
|
|
14961
15126
|
this.indexCount = nidx;
|
|
14962
15127
|
}
|
|
14963
15128
|
// linesToCylinders
|
|
@@ -14972,7 +15137,7 @@ var NVMesh = class _NVMesh {
|
|
|
14972
15137
|
const n_count = offsetPt0.length - 1;
|
|
14973
15138
|
const npt = pts.length / 3;
|
|
14974
15139
|
if (!this.fiberLengths) {
|
|
14975
|
-
this.fiberLengths =
|
|
15140
|
+
this.fiberLengths = new Uint32Array(n_count);
|
|
14976
15141
|
for (let i = 0; i < n_count; i++) {
|
|
14977
15142
|
const vStart3 = offsetPt0[i] * 3;
|
|
14978
15143
|
const vEnd3 = (offsetPt0[i + 1] - 1) * 3;
|
|
@@ -14981,7 +15146,7 @@ var NVMesh = class _NVMesh {
|
|
|
14981
15146
|
const v = vec34.fromValues(pts[j + 0] - pts[j + 3], pts[j + 1] - pts[j + 4], pts[j + 2] - pts[j + 5]);
|
|
14982
15147
|
len += vec34.len(v);
|
|
14983
15148
|
}
|
|
14984
|
-
this.fiberLengths
|
|
15149
|
+
this.fiberLengths[i] = len;
|
|
14985
15150
|
}
|
|
14986
15151
|
}
|
|
14987
15152
|
const posClrF32 = new Float32Array(npt * 4);
|
|
@@ -15194,119 +15359,12 @@ var NVMesh = class _NVMesh {
|
|
|
15194
15359
|
} else {
|
|
15195
15360
|
this.indexCount = indices.length;
|
|
15196
15361
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
15197
|
-
gl.bufferData(gl.ARRAY_BUFFER,
|
|
15362
|
+
gl.bufferData(gl.ARRAY_BUFFER, Uint32Array.from(posClrU32), gl.STATIC_DRAW);
|
|
15198
15363
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
|
15199
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
|
|
15364
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Uint32Array.from(indices), gl.STATIC_DRAW);
|
|
15200
15365
|
}
|
|
15201
15366
|
}
|
|
15202
15367
|
// updateFibers()
|
|
15203
|
-
// internal function filters connectome to identify which color, size and visibility of nodes and edges
|
|
15204
|
-
updateConnectome(gl) {
|
|
15205
|
-
const tris = [];
|
|
15206
|
-
const nNode = this.nodes.X.length;
|
|
15207
|
-
let hasEdges = false;
|
|
15208
|
-
if (nNode > 1 && this.edges) {
|
|
15209
|
-
let nEdges = this.edges.length;
|
|
15210
|
-
if (nEdges = nNode * nNode) {
|
|
15211
|
-
hasEdges = true;
|
|
15212
|
-
} else {
|
|
15213
|
-
log.warn("Expected %d edges not %d", nNode * nNode, nEdges);
|
|
15214
|
-
}
|
|
15215
|
-
}
|
|
15216
|
-
const pts = [];
|
|
15217
|
-
const rgba255 = [];
|
|
15218
|
-
let lut = cmapper.colormap(this.nodeColormap, this.colormapInvert);
|
|
15219
|
-
let lutNeg = cmapper.colormap(this.nodeColormapNegative, this.colormapInvert);
|
|
15220
|
-
let hasNeg = this.nodeColormapNegative !== void 0;
|
|
15221
|
-
let min = this.nodeMinColor;
|
|
15222
|
-
let max = this.nodeMaxColor;
|
|
15223
|
-
for (let i = 0; i < nNode; i++) {
|
|
15224
|
-
const radius = this.nodes.Size[i] * this.nodeScale;
|
|
15225
|
-
if (radius <= 0) {
|
|
15226
|
-
continue;
|
|
15227
|
-
}
|
|
15228
|
-
let color = this.nodes.Color[i];
|
|
15229
|
-
let isNeg = false;
|
|
15230
|
-
if (hasNeg && color < 0) {
|
|
15231
|
-
isNeg = true;
|
|
15232
|
-
color = -color;
|
|
15233
|
-
}
|
|
15234
|
-
if (min < max) {
|
|
15235
|
-
if (color < min) {
|
|
15236
|
-
continue;
|
|
15237
|
-
}
|
|
15238
|
-
color = (color - min) / (max - min);
|
|
15239
|
-
} else {
|
|
15240
|
-
color = 1;
|
|
15241
|
-
}
|
|
15242
|
-
color = Math.round(Math.max(Math.min(255, color * 255))) * 4;
|
|
15243
|
-
let rgba = [lut[color], lut[color + 1], lut[color + 2], 255];
|
|
15244
|
-
if (isNeg) {
|
|
15245
|
-
rgba = [lutNeg[color], lutNeg[color + 1], lutNeg[color + 2], 255];
|
|
15246
|
-
}
|
|
15247
|
-
const pt = [
|
|
15248
|
-
this.nodes.X[i],
|
|
15249
|
-
this.nodes.Y[i],
|
|
15250
|
-
this.nodes.Z[i]
|
|
15251
|
-
];
|
|
15252
|
-
NiivueObject3D.makeColoredSphere(pts, tris, rgba255, radius, pt, rgba);
|
|
15253
|
-
}
|
|
15254
|
-
if (hasEdges) {
|
|
15255
|
-
lut = cmapper.colormap(this.edgeColormap, this.colormapInvert);
|
|
15256
|
-
lutNeg = cmapper.colormap(this.edgeColormapNegative, this.colormapInvert);
|
|
15257
|
-
hasNeg = this.edgeColormapNegative !== void 0;
|
|
15258
|
-
min = this.edgeMin;
|
|
15259
|
-
max = this.edgeMax;
|
|
15260
|
-
for (let i = 0; i < nNode - 1; i++) {
|
|
15261
|
-
for (let j = i + 1; j < nNode; j++) {
|
|
15262
|
-
let color = this.edges[i * nNode + j];
|
|
15263
|
-
let isNeg = false;
|
|
15264
|
-
if (hasNeg && color < 0) {
|
|
15265
|
-
isNeg = true;
|
|
15266
|
-
color = -color;
|
|
15267
|
-
}
|
|
15268
|
-
const radius = color * this.edgeScale;
|
|
15269
|
-
if (radius <= 0) {
|
|
15270
|
-
continue;
|
|
15271
|
-
}
|
|
15272
|
-
if (min < max) {
|
|
15273
|
-
if (color < min) {
|
|
15274
|
-
continue;
|
|
15275
|
-
}
|
|
15276
|
-
color = (color - min) / (max - min);
|
|
15277
|
-
} else {
|
|
15278
|
-
color = 1;
|
|
15279
|
-
}
|
|
15280
|
-
color = Math.round(Math.max(Math.min(255, color * 255))) * 4;
|
|
15281
|
-
let rgba = [lut[color], lut[color + 1], lut[color + 2], 255];
|
|
15282
|
-
if (isNeg) {
|
|
15283
|
-
rgba = [lutNeg[color], lutNeg[color + 1], lutNeg[color + 2], 255];
|
|
15284
|
-
}
|
|
15285
|
-
const pti = [
|
|
15286
|
-
this.nodes.X[i],
|
|
15287
|
-
this.nodes.Y[i],
|
|
15288
|
-
this.nodes.Z[i]
|
|
15289
|
-
];
|
|
15290
|
-
const ptj = [
|
|
15291
|
-
this.nodes.X[j],
|
|
15292
|
-
this.nodes.Y[j],
|
|
15293
|
-
this.nodes.Z[j]
|
|
15294
|
-
];
|
|
15295
|
-
NiivueObject3D.makeColoredCylinder(pts, tris, rgba255, pti, ptj, radius, rgba);
|
|
15296
|
-
}
|
|
15297
|
-
}
|
|
15298
|
-
}
|
|
15299
|
-
const obj = NVMeshUtilities.getExtents(pts);
|
|
15300
|
-
this.furthestVertexFromOrigin = obj.mxDx;
|
|
15301
|
-
this.extentsMin = obj.extentsMin;
|
|
15302
|
-
this.extentsMax = obj.extentsMax;
|
|
15303
|
-
const posNormClr = this.generatePosNormClr(pts, tris, rgba255);
|
|
15304
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
|
15305
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int32Array(tris), gl.STATIC_DRAW);
|
|
15306
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
15307
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(posNormClr), gl.STATIC_DRAW);
|
|
15308
|
-
this.indexCount = tris.length;
|
|
15309
|
-
}
|
|
15310
15368
|
// given X,Y,Z coordinates in world space, return index of nearest vertex as well as
|
|
15311
15369
|
// the distance of this closest vertex to the coordinates
|
|
15312
15370
|
indexNearestXYZmm(Xmm, Ymm, Zmm) {
|
|
@@ -15334,7 +15392,6 @@ var NVMesh = class _NVMesh {
|
|
|
15334
15392
|
return;
|
|
15335
15393
|
}
|
|
15336
15394
|
if (this.hasConnectome) {
|
|
15337
|
-
this.updateConnectome(gl);
|
|
15338
15395
|
return;
|
|
15339
15396
|
}
|
|
15340
15397
|
if (!this.pts || !this.tris || !this.rgba255) {
|
|
@@ -15359,6 +15416,9 @@ var NVMesh = class _NVMesh {
|
|
|
15359
15416
|
if (opacity <= 0 || layer.cal_min > layer.cal_max) {
|
|
15360
15417
|
continue;
|
|
15361
15418
|
}
|
|
15419
|
+
if (layer.outlineBorder === void 0) {
|
|
15420
|
+
layer.outlineBorder = 0;
|
|
15421
|
+
}
|
|
15362
15422
|
if (layer.isAdditiveBlend === void 0) {
|
|
15363
15423
|
layer.isAdditiveBlend = false;
|
|
15364
15424
|
}
|
|
@@ -15380,23 +15440,23 @@ var NVMesh = class _NVMesh {
|
|
|
15380
15440
|
rgba8[k + 2] = lut2[idx + 2];
|
|
15381
15441
|
k += 4;
|
|
15382
15442
|
}
|
|
15383
|
-
let opaque = new Array(nvtx).fill(
|
|
15384
|
-
if (layer.
|
|
15443
|
+
let opaque = new Array(nvtx).fill(false);
|
|
15444
|
+
if (layer.outlineBorder > 0) {
|
|
15385
15445
|
opaque = NVMeshUtilities.getClusterBoundary(rgba8, this.tris);
|
|
15386
15446
|
}
|
|
15387
15447
|
k = 0;
|
|
15388
15448
|
for (let j = 0; j < layer.values.length; j++) {
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15449
|
+
let opa = opacity;
|
|
15450
|
+
if (opaque[j]) {
|
|
15451
|
+
opa = layer.outlineBorder;
|
|
15392
15452
|
}
|
|
15393
15453
|
let vtx = j * 28 + 24;
|
|
15394
15454
|
if (this.f32PerVertex !== 7) {
|
|
15395
15455
|
vtx = j * 20 + 16;
|
|
15396
15456
|
}
|
|
15397
|
-
u8[vtx + 0] = lerp(u8[vtx + 0], rgba8[k + 0],
|
|
15398
|
-
u8[vtx + 1] = lerp(u8[vtx + 1], rgba8[k + 1],
|
|
15399
|
-
u8[vtx + 2] = lerp(u8[vtx + 2], rgba8[k + 2],
|
|
15457
|
+
u8[vtx + 0] = lerp(u8[vtx + 0], rgba8[k + 0], opa);
|
|
15458
|
+
u8[vtx + 1] = lerp(u8[vtx + 1], rgba8[k + 1], opa);
|
|
15459
|
+
u8[vtx + 2] = lerp(u8[vtx + 2], rgba8[k + 2], opa);
|
|
15400
15460
|
k += 4;
|
|
15401
15461
|
}
|
|
15402
15462
|
continue;
|
|
@@ -15404,7 +15464,7 @@ var NVMesh = class _NVMesh {
|
|
|
15404
15464
|
if (layer.values instanceof Uint8Array) {
|
|
15405
15465
|
const rgba8 = new Uint8Array(layer.values.buffer);
|
|
15406
15466
|
let opaque = new Array(nvtx).fill(true);
|
|
15407
|
-
if (layer.
|
|
15467
|
+
if (layer.outlineBorder > 0) {
|
|
15408
15468
|
opaque = NVMeshUtilities.getClusterBoundary(rgba8, this.tris);
|
|
15409
15469
|
}
|
|
15410
15470
|
let k = 0;
|
|
@@ -15413,14 +15473,13 @@ var NVMesh = class _NVMesh {
|
|
|
15413
15473
|
if (this.f32PerVertex !== 7) {
|
|
15414
15474
|
vtx = j * 20 + 16;
|
|
15415
15475
|
}
|
|
15416
|
-
|
|
15417
|
-
|
|
15418
|
-
|
|
15419
|
-
continue;
|
|
15476
|
+
let opa = opacity;
|
|
15477
|
+
if (opaque[j]) {
|
|
15478
|
+
opa = layer.outlineBorder;
|
|
15420
15479
|
}
|
|
15421
|
-
u8[vtx + 0] = lerp(u8[vtx + 0], rgba8[k + 0],
|
|
15422
|
-
u8[vtx + 1] = lerp(u8[vtx + 1], rgba8[k + 1],
|
|
15423
|
-
u8[vtx + 2] = lerp(u8[vtx + 2], rgba8[k + 2],
|
|
15480
|
+
u8[vtx + 0] = lerp(u8[vtx + 0], rgba8[k + 0], opa);
|
|
15481
|
+
u8[vtx + 1] = lerp(u8[vtx + 1], rgba8[k + 1], opa);
|
|
15482
|
+
u8[vtx + 2] = lerp(u8[vtx + 2], rgba8[k + 2], opa);
|
|
15424
15483
|
k += 4;
|
|
15425
15484
|
}
|
|
15426
15485
|
continue;
|
|
@@ -15447,7 +15506,7 @@ var NVMesh = class _NVMesh {
|
|
|
15447
15506
|
if (!layer.isTransparentBelowCalMin) {
|
|
15448
15507
|
mnCal = Number.NEGATIVE_INFINITY;
|
|
15449
15508
|
}
|
|
15450
|
-
if (
|
|
15509
|
+
if (layer.outlineBorder <= 0) {
|
|
15451
15510
|
for (let j = 0; j < nvtx; j++) {
|
|
15452
15511
|
const v = layer.values[j + frameOffset];
|
|
15453
15512
|
if (v < mnCal) {
|
|
@@ -15470,9 +15529,10 @@ var NVMesh = class _NVMesh {
|
|
|
15470
15529
|
additiveRGBA[j4 + 2] = additiveBlend(additiveRGBA[j4 + 2], lut[v255 + 2]);
|
|
15471
15530
|
additiveRGBA[j4 + 3] = additiveBlend(additiveRGBA[j4 + 3], 255);
|
|
15472
15531
|
} else {
|
|
15473
|
-
|
|
15474
|
-
u8[vtx +
|
|
15475
|
-
u8[vtx +
|
|
15532
|
+
const opa = opacity;
|
|
15533
|
+
u8[vtx + 0] = lerp(u8[vtx + 0], lut[v255 + 0], opa);
|
|
15534
|
+
u8[vtx + 1] = lerp(u8[vtx + 1], lut[v255 + 1], opa);
|
|
15535
|
+
u8[vtx + 2] = lerp(u8[vtx + 2], lut[v255 + 2], opa);
|
|
15476
15536
|
}
|
|
15477
15537
|
}
|
|
15478
15538
|
} else {
|
|
@@ -15487,23 +15547,26 @@ var NVMesh = class _NVMesh {
|
|
|
15487
15547
|
}
|
|
15488
15548
|
const opaque = NVMeshUtilities.getClusterBoundaryU8(v255s, this.tris);
|
|
15489
15549
|
for (let j = 0; j < nvtx; j++) {
|
|
15490
|
-
|
|
15491
|
-
if (!opaque[j]) {
|
|
15550
|
+
if (v255s[j] < 1) {
|
|
15492
15551
|
continue;
|
|
15493
15552
|
}
|
|
15494
|
-
|
|
15553
|
+
let opa = opacity;
|
|
15554
|
+
if (opaque[j]) {
|
|
15555
|
+
opa = layer.outlineBorder;
|
|
15556
|
+
}
|
|
15557
|
+
const v255 = v255s[j] * 4;
|
|
15495
15558
|
let vtx = j * 28 + 24;
|
|
15496
15559
|
if (this.f32PerVertex !== 7) {
|
|
15497
15560
|
vtx = j * 20 + 16;
|
|
15498
15561
|
}
|
|
15499
|
-
u8[vtx + 0] = lerp(u8[vtx + 0], lut[v255 + 0],
|
|
15500
|
-
u8[vtx + 1] = lerp(u8[vtx + 1], lut[v255 + 1],
|
|
15501
|
-
u8[vtx + 2] = lerp(u8[vtx + 2], lut[v255 + 2],
|
|
15562
|
+
u8[vtx + 0] = lerp(u8[vtx + 0], lut[v255 + 0], opa);
|
|
15563
|
+
u8[vtx + 1] = lerp(u8[vtx + 1], lut[v255 + 1], opa);
|
|
15564
|
+
u8[vtx + 2] = lerp(u8[vtx + 2], lut[v255 + 2], opa);
|
|
15502
15565
|
}
|
|
15503
15566
|
}
|
|
15504
15567
|
if (layer.useNegativeCmap) {
|
|
15505
15568
|
const lut2 = cmapper.colormap(layer.colormapNegative, layer.colormapInvert);
|
|
15506
|
-
if (
|
|
15569
|
+
if (layer.outlineBorder <= 0) {
|
|
15507
15570
|
let mn2 = layer.cal_min;
|
|
15508
15571
|
let mx = layer.cal_max;
|
|
15509
15572
|
if (isFinite(layer.cal_minNeg) && isFinite(layer.cal_minNeg)) {
|
|
@@ -15560,17 +15623,18 @@ var NVMesh = class _NVMesh {
|
|
|
15560
15623
|
const opaque = NVMeshUtilities.getClusterBoundaryU8(v255s, this.tris);
|
|
15561
15624
|
for (let j = 0; j < nvtx; j++) {
|
|
15562
15625
|
let v255 = 255;
|
|
15563
|
-
|
|
15564
|
-
|
|
15626
|
+
let opa = opacity;
|
|
15627
|
+
if (opaque[j]) {
|
|
15628
|
+
opa = layer.outlineBorder;
|
|
15565
15629
|
}
|
|
15566
15630
|
v255 = Math.min(255, v255) * 4;
|
|
15567
15631
|
let vtx = j * 28 + 24;
|
|
15568
15632
|
if (this.f32PerVertex !== 7) {
|
|
15569
15633
|
vtx = j * 20 + 16;
|
|
15570
15634
|
}
|
|
15571
|
-
u8[vtx + 0] = lerp(u8[vtx + 0], lut2[v255 + 0],
|
|
15572
|
-
u8[vtx + 1] = lerp(u8[vtx + 1], lut2[v255 + 1],
|
|
15573
|
-
u8[vtx + 2] = lerp(u8[vtx + 2], lut2[v255 + 2],
|
|
15635
|
+
u8[vtx + 0] = lerp(u8[vtx + 0], lut2[v255 + 0], opa);
|
|
15636
|
+
u8[vtx + 1] = lerp(u8[vtx + 1], lut2[v255 + 1], opa);
|
|
15637
|
+
u8[vtx + 2] = lerp(u8[vtx + 2], lut2[v255 + 2], opa);
|
|
15574
15638
|
}
|
|
15575
15639
|
}
|
|
15576
15640
|
}
|
|
@@ -15600,9 +15664,9 @@ var NVMesh = class _NVMesh {
|
|
|
15600
15664
|
}
|
|
15601
15665
|
}
|
|
15602
15666
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
|
15603
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
|
|
15667
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Uint32Array.from(this.tris), gl.STATIC_DRAW);
|
|
15604
15668
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
15605
|
-
gl.bufferData(gl.ARRAY_BUFFER,
|
|
15669
|
+
gl.bufferData(gl.ARRAY_BUFFER, Float32Array.from(posNormClr), gl.STATIC_DRAW);
|
|
15606
15670
|
this.indexCount = this.tris.length;
|
|
15607
15671
|
this.vertexCount = this.pts.length;
|
|
15608
15672
|
}
|
|
@@ -15689,75 +15753,10 @@ var NVMesh = class _NVMesh {
|
|
|
15689
15753
|
}
|
|
15690
15754
|
return f32;
|
|
15691
15755
|
}
|
|
15692
|
-
static loadConnectomeFromFreeSurfer(json, gl, name = "", opacity = 1, visible = true) {
|
|
15693
|
-
let isValid = true;
|
|
15694
|
-
if (json.data_type === void 0) {
|
|
15695
|
-
isValid = false;
|
|
15696
|
-
} else if (json.data_type !== "fs_pointset") {
|
|
15697
|
-
isValid = false;
|
|
15698
|
-
}
|
|
15699
|
-
if (json.points === void 0) {
|
|
15700
|
-
isValid = false;
|
|
15701
|
-
}
|
|
15702
|
-
if (!isValid) {
|
|
15703
|
-
throw Error("not a valid FreeSurfer json pointset");
|
|
15704
|
-
}
|
|
15705
|
-
const jcon = {
|
|
15706
|
-
nodes: {
|
|
15707
|
-
names: [],
|
|
15708
|
-
prefilled: [],
|
|
15709
|
-
X: [],
|
|
15710
|
-
Y: [],
|
|
15711
|
-
Z: [],
|
|
15712
|
-
Color: [],
|
|
15713
|
-
Size: []
|
|
15714
|
-
},
|
|
15715
|
-
edges: [],
|
|
15716
|
-
// @ts-expect-error not sure where this should come from
|
|
15717
|
-
name: this.data_type
|
|
15718
|
-
};
|
|
15719
|
-
if (!json.points) {
|
|
15720
|
-
throw new Error("points are not set!");
|
|
15721
|
-
}
|
|
15722
|
-
for (let i = 0; i < json.points.length; i++) {
|
|
15723
|
-
let name2 = "";
|
|
15724
|
-
if (json.points[i].comments) {
|
|
15725
|
-
if (json.points[i].comments[0].text) {
|
|
15726
|
-
name2 = json.points[i].comments[0].text;
|
|
15727
|
-
}
|
|
15728
|
-
}
|
|
15729
|
-
jcon.nodes.names.push(name2);
|
|
15730
|
-
let prefilled = "";
|
|
15731
|
-
if (json.points[i].comments) {
|
|
15732
|
-
if (json.points[i].comments[0].prefilled) {
|
|
15733
|
-
prefilled = json.points[i].comments[0].prefilled;
|
|
15734
|
-
}
|
|
15735
|
-
}
|
|
15736
|
-
jcon.nodes.prefilled.push(prefilled);
|
|
15737
|
-
jcon.nodes.X.push(json.points[i].coordinates.x);
|
|
15738
|
-
jcon.nodes.Y.push(json.points[i].coordinates.y);
|
|
15739
|
-
jcon.nodes.Z.push(json.points[i].coordinates.z);
|
|
15740
|
-
jcon.nodes.Color.push(1);
|
|
15741
|
-
jcon.nodes.Size.push(1);
|
|
15742
|
-
}
|
|
15743
|
-
return new _NVMesh([], [], name, [], opacity, visible, gl, jcon);
|
|
15744
|
-
}
|
|
15745
|
-
// loadConnectomeFromFreeSurfer
|
|
15746
|
-
// read connectome saved as JSON
|
|
15747
|
-
static loadConnectomeFromJSON(json, gl, name = "", opacity = 1, visible = true) {
|
|
15748
|
-
if ("name" in json) {
|
|
15749
|
-
name = this.name;
|
|
15750
|
-
}
|
|
15751
|
-
if (!("nodes" in json)) {
|
|
15752
|
-
throw Error("not a valid jcon connectome file");
|
|
15753
|
-
}
|
|
15754
|
-
return new _NVMesh([], [], name, [], opacity, visible, gl, json);
|
|
15755
|
-
}
|
|
15756
|
-
// loadConnectomeFromJSON()
|
|
15757
15756
|
// wrapper to read meshes, tractograms and connectomes regardless of format
|
|
15758
|
-
static readMesh(buffer, name, gl, opacity = 1, rgba255 = [255, 255, 255, 255], visible = true) {
|
|
15759
|
-
let tris = [];
|
|
15760
|
-
let pts = [];
|
|
15757
|
+
static readMesh(buffer, name, gl, opacity = 1, rgba255 = new Uint8Array([255, 255, 255, 255]), visible = true) {
|
|
15758
|
+
let tris = new Uint32Array([]);
|
|
15759
|
+
let pts = new Float32Array([]);
|
|
15761
15760
|
let anatomicalStructurePrimary = "";
|
|
15762
15761
|
let obj;
|
|
15763
15762
|
const re = /(?:\.([^.]+))?$/;
|
|
@@ -15768,12 +15767,12 @@ var NVMesh = class _NVMesh {
|
|
|
15768
15767
|
ext = ext.toUpperCase();
|
|
15769
15768
|
}
|
|
15770
15769
|
if (ext === "JCON") {
|
|
15771
|
-
|
|
15770
|
+
log.error("you should never see this message: load using nvconnectome not nvmesh");
|
|
15772
15771
|
}
|
|
15773
15772
|
if (ext === "JSON") {
|
|
15774
|
-
|
|
15773
|
+
log.error("you should never see this message: load using nvconnectome not nvmesh");
|
|
15775
15774
|
}
|
|
15776
|
-
rgba255[3] = Math.max(
|
|
15775
|
+
rgba255[3] = Math.max(1, rgba255[3]);
|
|
15777
15776
|
if (ext === "TCK" || ext === "TRK" || ext === "TT" || ext === "TRX" || ext === "TRACT") {
|
|
15778
15777
|
if (ext === "TCK") {
|
|
15779
15778
|
obj = NVMeshLoaders.readTCK(buffer);
|
|
@@ -15787,12 +15786,12 @@ var NVMesh = class _NVMesh {
|
|
|
15787
15786
|
obj = NVMeshLoaders.readTRK(buffer);
|
|
15788
15787
|
}
|
|
15789
15788
|
if (typeof obj === "undefined") {
|
|
15790
|
-
const pts2 = [0, 0, 0, 0, 0, 0];
|
|
15791
|
-
const offsetPt0 = [0];
|
|
15789
|
+
const pts2 = new Float32Array([0, 0, 0, 0, 0, 0]);
|
|
15790
|
+
const offsetPt0 = new Uint32Array([0]);
|
|
15792
15791
|
obj = { pts: pts2, offsetPt0 };
|
|
15793
15792
|
log.error("Creating empty tracts");
|
|
15794
15793
|
}
|
|
15795
|
-
rgba255[3] =
|
|
15794
|
+
rgba255[3] = 0;
|
|
15796
15795
|
return new _NVMesh(
|
|
15797
15796
|
obj.pts,
|
|
15798
15797
|
obj.offsetPt0,
|
|
@@ -15840,10 +15839,10 @@ var NVMesh = class _NVMesh {
|
|
|
15840
15839
|
} else if (ext === "FIB" || ext === "VTK") {
|
|
15841
15840
|
obj = NVMeshLoaders.readVTK(buffer);
|
|
15842
15841
|
if ("offsetPt0" in obj) {
|
|
15843
|
-
rgba255[3] =
|
|
15842
|
+
rgba255[3] = 0;
|
|
15844
15843
|
return new _NVMesh(
|
|
15845
|
-
|
|
15846
|
-
|
|
15844
|
+
obj.pts,
|
|
15845
|
+
obj.offsetPt0,
|
|
15847
15846
|
name,
|
|
15848
15847
|
rgba255,
|
|
15849
15848
|
// colormap,
|
|
@@ -15874,20 +15873,21 @@ var NVMesh = class _NVMesh {
|
|
|
15874
15873
|
if (!obj.indices) {
|
|
15875
15874
|
throw new Error("indices not loaded");
|
|
15876
15875
|
}
|
|
15877
|
-
pts =
|
|
15878
|
-
tris =
|
|
15876
|
+
pts = obj.positions;
|
|
15877
|
+
tris = obj.indices;
|
|
15879
15878
|
if ("rgba255" in obj && obj.rgba255.length > 0) {
|
|
15880
15879
|
rgba255 = obj.rgba255;
|
|
15881
15880
|
}
|
|
15882
15881
|
if ("colors" in obj && obj.colors && obj.colors.length === pts.length) {
|
|
15883
|
-
rgba255 = [];
|
|
15884
15882
|
const n = pts.length / 3;
|
|
15883
|
+
rgba255 = new Uint8Array(n * 4);
|
|
15885
15884
|
let c = 0;
|
|
15885
|
+
let k = 0;
|
|
15886
15886
|
for (let i = 0; i < n; i++) {
|
|
15887
|
-
rgba255
|
|
15888
|
-
rgba255
|
|
15889
|
-
rgba255
|
|
15890
|
-
rgba255
|
|
15887
|
+
rgba255[k++] = obj.colors[c] * 255;
|
|
15888
|
+
rgba255[k++] = obj.colors[c + 1] * 255;
|
|
15889
|
+
rgba255[k++] = obj.colors[c + 2] * 255;
|
|
15890
|
+
rgba255[k++] = 255;
|
|
15891
15891
|
c += 3;
|
|
15892
15892
|
}
|
|
15893
15893
|
}
|
|
@@ -15896,6 +15896,7 @@ var NVMesh = class _NVMesh {
|
|
|
15896
15896
|
if (ntri < 1 || npt < 3) {
|
|
15897
15897
|
throw new Error("Mesh should have at least one triangle and three vertices");
|
|
15898
15898
|
}
|
|
15899
|
+
rgba255[3] = Math.max(1, rgba255[3]);
|
|
15899
15900
|
const nvm = new _NVMesh(
|
|
15900
15901
|
pts,
|
|
15901
15902
|
tris,
|
|
@@ -16039,7 +16040,7 @@ var NVMesh = class _NVMesh {
|
|
|
16039
16040
|
throw Error(response.statusText);
|
|
16040
16041
|
}
|
|
16041
16042
|
const buffer = await response.arrayBuffer();
|
|
16042
|
-
const nvmesh = await this.readMesh(buffer, name, gl, opacity, rgba255, visible);
|
|
16043
|
+
const nvmesh = await this.readMesh(buffer, name, gl, opacity, new Uint8Array(rgba255), visible);
|
|
16043
16044
|
if (!layers || layers.length < 1) {
|
|
16044
16045
|
return nvmesh;
|
|
16045
16046
|
}
|
|
@@ -16082,7 +16083,7 @@ var NVMesh = class _NVMesh {
|
|
|
16082
16083
|
throw new Error("rendering context must be set");
|
|
16083
16084
|
}
|
|
16084
16085
|
const buffer = await _NVMesh.readFileAsync(file);
|
|
16085
|
-
const nvmesh = _NVMesh.readMesh(buffer, name, gl, opacity, rgba255, visible);
|
|
16086
|
+
const nvmesh = _NVMesh.readMesh(buffer, name, gl, opacity, new Uint8Array(rgba255), visible);
|
|
16086
16087
|
if (!layers || layers.length < 1) {
|
|
16087
16088
|
return nvmesh;
|
|
16088
16089
|
}
|
|
@@ -16120,7 +16121,7 @@ var NVMesh = class _NVMesh {
|
|
|
16120
16121
|
return bytes.buffer;
|
|
16121
16122
|
}
|
|
16122
16123
|
const buffer = base64ToArrayBuffer(base64);
|
|
16123
|
-
const nvmesh = await _NVMesh.readMesh(buffer, name, gl, opacity, rgba255, visible);
|
|
16124
|
+
const nvmesh = await _NVMesh.readMesh(buffer, name, gl, opacity, new Uint8Array(rgba255), visible);
|
|
16124
16125
|
if (!layers || layers.length < 1) {
|
|
16125
16126
|
return nvmesh;
|
|
16126
16127
|
}
|
|
@@ -16210,7 +16211,7 @@ var NVMesh = class _NVMesh {
|
|
|
16210
16211
|
return NVMeshLoaders.readTSF(buffer);
|
|
16211
16212
|
}
|
|
16212
16213
|
static readTT(buffer) {
|
|
16213
|
-
return NVMeshLoaders.
|
|
16214
|
+
return NVMeshLoaders.readTT(buffer);
|
|
16214
16215
|
}
|
|
16215
16216
|
static readTRX(buffer) {
|
|
16216
16217
|
return NVMeshLoaders.readTRX(buffer);
|
|
@@ -17950,7 +17951,7 @@ var NVIMAGE_TYPE = Object.freeze({
|
|
|
17950
17951
|
return imageType;
|
|
17951
17952
|
}
|
|
17952
17953
|
});
|
|
17953
|
-
var NVImageFromUrlOptions = (url, urlImageData = "", name = "", colormap = "gray", opacity = 1, cal_min = NaN, cal_max = NaN, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false,
|
|
17954
|
+
var NVImageFromUrlOptions = (url, urlImageData = "", name = "", colormap = "gray", opacity = 1, cal_min = NaN, cal_max = NaN, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false, useQFormNotSForm = false, colormapNegative = "", frame4D = 0, imageType = NVIMAGE_TYPE.UNKNOWN, cal_minNeg = NaN, cal_maxNeg = NaN, colorbarVisible = true, alphaThreshold = false, colormapLabel = []) => {
|
|
17954
17955
|
return {
|
|
17955
17956
|
url,
|
|
17956
17957
|
urlImageData,
|
|
@@ -17963,7 +17964,6 @@ var NVImageFromUrlOptions = (url, urlImageData = "", name = "", colormap = "gray
|
|
|
17963
17964
|
trustCalMinMax,
|
|
17964
17965
|
percentileFrac,
|
|
17965
17966
|
ignoreZeroVoxels,
|
|
17966
|
-
visible,
|
|
17967
17967
|
useQFormNotSForm,
|
|
17968
17968
|
colormapNegative,
|
|
17969
17969
|
imageType,
|
|
@@ -18165,7 +18165,6 @@ var NVImage = class _NVImage {
|
|
|
18165
18165
|
* @param trustCalMinMax - whether or not to trust cal_min and cal_max from the nifti header (trusting results in faster loading)
|
|
18166
18166
|
* @param percentileFrac - the percentile to use for setting the robust range of the display values (smart intensity setting for images with large ranges)
|
|
18167
18167
|
* @param ignoreZeroVoxels - whether or not to ignore zero voxels in setting the robust range of display values
|
|
18168
|
-
* @param visible - whether or not this image is to be visible
|
|
18169
18168
|
* @param useQFormNotSForm - give precedence to QForm (Quaternion) or SForm (Matrix)
|
|
18170
18169
|
* @param colormapNegative - a color map to use for symmetrical negative intensities
|
|
18171
18170
|
* @param frame4D - volume displayed, 0 indexed, must be less than nFrame4D
|
|
@@ -18181,7 +18180,7 @@ var NVImage = class _NVImage {
|
|
|
18181
18180
|
* @param colorbarVisible - TODO
|
|
18182
18181
|
* @param colormapLabel - TODO
|
|
18183
18182
|
*/
|
|
18184
|
-
constructor(dataBuffer = null, name = "", colormap = "gray", opacity = 1, pairedImgData = null, cal_min = NaN, cal_max = NaN, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false,
|
|
18183
|
+
constructor(dataBuffer = null, name = "", colormap = "gray", opacity = 1, pairedImgData = null, cal_min = NaN, cal_max = NaN, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false, useQFormNotSForm = false, colormapNegative = "", frame4D = 0, imageType = NVIMAGE_TYPE.UNKNOWN, cal_minNeg = NaN, cal_maxNeg = NaN, colorbarVisible = true, colormapLabel = null) {
|
|
18185
18184
|
__publicField(this, "name");
|
|
18186
18185
|
__publicField(this, "id");
|
|
18187
18186
|
__publicField(this, "url");
|
|
@@ -18202,7 +18201,6 @@ var NVImage = class _NVImage {
|
|
|
18202
18201
|
__publicField(this, "cal_minNeg");
|
|
18203
18202
|
__publicField(this, "cal_maxNeg");
|
|
18204
18203
|
__publicField(this, "colorbarVisible", true);
|
|
18205
|
-
__publicField(this, "visible");
|
|
18206
18204
|
__publicField(this, "modulationImage", null);
|
|
18207
18205
|
__publicField(this, "modulateAlpha", 0);
|
|
18208
18206
|
// if !=0, mod transparency with expon power |Alpha|
|
|
@@ -18305,7 +18303,6 @@ var NVImage = class _NVImage {
|
|
|
18305
18303
|
this.cal_minNeg = cal_minNeg;
|
|
18306
18304
|
this.cal_maxNeg = cal_maxNeg;
|
|
18307
18305
|
this.colorbarVisible = colorbarVisible;
|
|
18308
|
-
this.visible = visible;
|
|
18309
18306
|
this.useQFormNotSForm = useQFormNotSForm;
|
|
18310
18307
|
if (!dataBuffer) {
|
|
18311
18308
|
return;
|
|
@@ -20568,7 +20565,6 @@ var NVImage = class _NVImage {
|
|
|
20568
20565
|
trustCalMinMax = true,
|
|
20569
20566
|
percentileFrac = 0.02,
|
|
20570
20567
|
ignoreZeroVoxels = false,
|
|
20571
|
-
visible = true,
|
|
20572
20568
|
useQFormNotSForm = false,
|
|
20573
20569
|
colormapNegative = "",
|
|
20574
20570
|
frame4D = 0,
|
|
@@ -20710,7 +20706,6 @@ var NVImage = class _NVImage {
|
|
|
20710
20706
|
trustCalMinMax,
|
|
20711
20707
|
percentileFrac,
|
|
20712
20708
|
ignoreZeroVoxels,
|
|
20713
|
-
visible,
|
|
20714
20709
|
useQFormNotSForm,
|
|
20715
20710
|
colormapNegative,
|
|
20716
20711
|
frame4D,
|
|
@@ -20755,7 +20750,6 @@ var NVImage = class _NVImage {
|
|
|
20755
20750
|
trustCalMinMax = true,
|
|
20756
20751
|
percentileFrac = 0.02,
|
|
20757
20752
|
ignoreZeroVoxels = false,
|
|
20758
|
-
visible = true,
|
|
20759
20753
|
useQFormNotSForm = false,
|
|
20760
20754
|
colormapNegative = "",
|
|
20761
20755
|
frame4D = 0,
|
|
@@ -20845,7 +20839,6 @@ var NVImage = class _NVImage {
|
|
|
20845
20839
|
trustCalMinMax,
|
|
20846
20840
|
percentileFrac,
|
|
20847
20841
|
ignoreZeroVoxels,
|
|
20848
|
-
visible,
|
|
20849
20842
|
useQFormNotSForm,
|
|
20850
20843
|
colormapNegative,
|
|
20851
20844
|
frame4D,
|
|
@@ -20877,8 +20870,7 @@ var NVImage = class _NVImage {
|
|
|
20877
20870
|
cal_max = NaN,
|
|
20878
20871
|
trustCalMinMax = true,
|
|
20879
20872
|
percentileFrac = 0.02,
|
|
20880
|
-
ignoreZeroVoxels = false
|
|
20881
|
-
visible = true
|
|
20873
|
+
ignoreZeroVoxels = false
|
|
20882
20874
|
}) {
|
|
20883
20875
|
function base64ToArrayBuffer(base642) {
|
|
20884
20876
|
const binary_string = window.atob(base642);
|
|
@@ -20903,8 +20895,7 @@ var NVImage = class _NVImage {
|
|
|
20903
20895
|
cal_max,
|
|
20904
20896
|
trustCalMinMax,
|
|
20905
20897
|
percentileFrac,
|
|
20906
|
-
ignoreZeroVoxels
|
|
20907
|
-
visible
|
|
20898
|
+
ignoreZeroVoxels
|
|
20908
20899
|
);
|
|
20909
20900
|
} catch (err) {
|
|
20910
20901
|
log.debug(err);
|
|
@@ -20923,7 +20914,7 @@ var NVImage = class _NVImage {
|
|
|
20923
20914
|
*/
|
|
20924
20915
|
clone() {
|
|
20925
20916
|
const clonedImage = new _NVImage();
|
|
20926
|
-
clonedImage.id =
|
|
20917
|
+
clonedImage.id = uuidv42();
|
|
20927
20918
|
clonedImage.hdr = Object.assign({}, this.hdr);
|
|
20928
20919
|
clonedImage.img = this.img.slice();
|
|
20929
20920
|
clonedImage.calculateRAS();
|
|
@@ -21172,8 +21163,6 @@ var NVImage = class _NVImage {
|
|
|
21172
21163
|
// percentileFrac
|
|
21173
21164
|
this.ignoreZeroVoxels,
|
|
21174
21165
|
// ignoreZeroVoxels
|
|
21175
|
-
this.visible,
|
|
21176
|
-
// visible
|
|
21177
21166
|
this.useQFormNotSForm,
|
|
21178
21167
|
// useQFormNotSForm
|
|
21179
21168
|
this.colormapNegative,
|
|
@@ -21356,6 +21345,7 @@ var DEFAULT_OPTIONS = {
|
|
|
21356
21345
|
textHeight: 0.06,
|
|
21357
21346
|
colorbarHeight: 0.05,
|
|
21358
21347
|
crosshairWidth: 1,
|
|
21348
|
+
crosshairGap: 0,
|
|
21359
21349
|
rulerWidth: 4,
|
|
21360
21350
|
show3Dcrosshair: false,
|
|
21361
21351
|
backColor: [0, 0, 0, 1],
|
|
@@ -21373,7 +21363,7 @@ var DEFAULT_OPTIONS = {
|
|
|
21373
21363
|
keyDebounceTime: 50,
|
|
21374
21364
|
isNearestInterpolation: false,
|
|
21375
21365
|
isResizeCanvas: true,
|
|
21376
|
-
|
|
21366
|
+
atlasOutline: 0,
|
|
21377
21367
|
isRuler: false,
|
|
21378
21368
|
isColorbar: false,
|
|
21379
21369
|
isOrientCube: false,
|
|
@@ -21649,7 +21639,6 @@ var NVDocument = class _NVDocument {
|
|
|
21649
21639
|
trustCalMinMax: true,
|
|
21650
21640
|
percentileFrac: 0.02,
|
|
21651
21641
|
ignoreZeroVoxels: false,
|
|
21652
|
-
visible: true,
|
|
21653
21642
|
useQFormNotSForm: false,
|
|
21654
21643
|
colormapNegative: "",
|
|
21655
21644
|
colormapLabel: [],
|
|
@@ -21695,7 +21684,6 @@ var NVDocument = class _NVDocument {
|
|
|
21695
21684
|
trustCalMinMax: true,
|
|
21696
21685
|
percentileFrac: 0.02,
|
|
21697
21686
|
ignoreZeroVoxels: false,
|
|
21698
|
-
visible: true,
|
|
21699
21687
|
useQFormNotSForm: false,
|
|
21700
21688
|
colormapNegative: "",
|
|
21701
21689
|
colormapLabel: [],
|
|
@@ -21737,7 +21725,7 @@ var NVDocument = class _NVDocument {
|
|
|
21737
21725
|
pts: mesh.pts,
|
|
21738
21726
|
tris: mesh.tris,
|
|
21739
21727
|
name: mesh.name,
|
|
21740
|
-
rgba255: mesh.rgba255,
|
|
21728
|
+
rgba255: Uint8Array.from(mesh.rgba255),
|
|
21741
21729
|
opacity: mesh.opacity,
|
|
21742
21730
|
connectome: mesh.connectome,
|
|
21743
21731
|
dpg: mesh.dpg,
|
|
@@ -21748,7 +21736,7 @@ var NVDocument = class _NVDocument {
|
|
|
21748
21736
|
values: layer.values,
|
|
21749
21737
|
nFrame4D: layer.nFrame4D,
|
|
21750
21738
|
frame4D: 0,
|
|
21751
|
-
|
|
21739
|
+
outlineBorder: layer.outlineBorder,
|
|
21752
21740
|
global_min: layer.global_min,
|
|
21753
21741
|
global_max: layer.global_max,
|
|
21754
21742
|
cal_min: layer.cal_min,
|
|
@@ -21774,6 +21762,7 @@ var NVDocument = class _NVDocument {
|
|
|
21774
21762
|
nodeMaxColor: mesh.nodeMaxColor,
|
|
21775
21763
|
nodeMinColor: mesh.nodeMinColor,
|
|
21776
21764
|
nodeScale: mesh.nodeScale,
|
|
21765
|
+
legendLineThickness: mesh.legendLineThickness,
|
|
21777
21766
|
offsetPt0: mesh.offsetPt0,
|
|
21778
21767
|
nodes: mesh.nodes
|
|
21779
21768
|
};
|
|
@@ -21917,14 +21906,14 @@ var defaultOptions = {
|
|
|
21917
21906
|
edgeColormapNegative: "winter",
|
|
21918
21907
|
edgeMin: 2,
|
|
21919
21908
|
edgeMax: 6,
|
|
21920
|
-
edgeScale: 1
|
|
21909
|
+
edgeScale: 1,
|
|
21910
|
+
legendLineThickness: 0
|
|
21921
21911
|
};
|
|
21922
21912
|
var NVConnectome = class _NVConnectome extends NVMesh {
|
|
21923
21913
|
constructor(gl, connectome) {
|
|
21924
|
-
super([], [], connectome.name, [], 1, true, gl, connectome);
|
|
21914
|
+
super(new Float32Array([]), new Uint32Array([]), connectome.name, new Uint8Array([]), 1, true, gl, connectome);
|
|
21925
21915
|
__publicField(this, "gl");
|
|
21926
21916
|
__publicField(this, "nodesChanged");
|
|
21927
|
-
__publicField(this, "legendLineThickness");
|
|
21928
21917
|
this.gl = gl;
|
|
21929
21918
|
this.type = "connectome" /* CONNECTOME */;
|
|
21930
21919
|
if (this.nodes) {
|
|
@@ -22200,19 +22189,22 @@ var NVConnectome = class _NVConnectome extends NVMesh {
|
|
|
22200
22189
|
const ptj = vec38.fromValues(nodes[edge.second].x, nodes[edge.second].y, nodes[edge.second].z);
|
|
22201
22190
|
NiivueObject3D.makeColoredCylinder(pts, tris, rgba255, pti, ptj, radius, rgba);
|
|
22202
22191
|
}
|
|
22203
|
-
const
|
|
22192
|
+
const pts32 = new Float32Array(pts);
|
|
22193
|
+
const tris32 = new Uint32Array(tris);
|
|
22194
|
+
const obj = NVMeshUtilities.getExtents(pts32);
|
|
22204
22195
|
this.furthestVertexFromOrigin = obj.mxDx;
|
|
22205
22196
|
this.extentsMin = obj.extentsMin;
|
|
22206
22197
|
this.extentsMax = obj.extentsMax;
|
|
22207
|
-
const posNormClr = this.generatePosNormClr(
|
|
22198
|
+
const posNormClr = this.generatePosNormClr(pts32, tris32, new Uint8Array(rgba255));
|
|
22208
22199
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
|
22209
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
|
|
22200
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Uint32Array.from(tris32), gl.STATIC_DRAW);
|
|
22210
22201
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
22211
|
-
gl.bufferData(gl.ARRAY_BUFFER,
|
|
22202
|
+
gl.bufferData(gl.ARRAY_BUFFER, Float32Array.from(posNormClr), gl.STATIC_DRAW);
|
|
22212
22203
|
this.indexCount = tris.length;
|
|
22213
22204
|
}
|
|
22214
22205
|
updateMesh(gl) {
|
|
22215
22206
|
this.updateConnectome(gl);
|
|
22207
|
+
this.updateLabels();
|
|
22216
22208
|
}
|
|
22217
22209
|
json() {
|
|
22218
22210
|
const json = {};
|
|
@@ -23013,6 +23005,22 @@ var MESH_EXTENSIONS = [
|
|
|
23013
23005
|
var LEFT_MOUSE_BUTTON = 0;
|
|
23014
23006
|
var CENTER_MOUSE_BUTTON = 1;
|
|
23015
23007
|
var RIGHT_MOUSE_BUTTON = 2;
|
|
23008
|
+
var TEXTURE0_BACK_VOL = 33984;
|
|
23009
|
+
var TEXTURE1_COLORMAPS = 33985;
|
|
23010
|
+
var TEXTURE2_OVERLAY_VOL = 33986;
|
|
23011
|
+
var TEXTURE3_FONT = 33987;
|
|
23012
|
+
var TEXTURE4_THUMBNAIL = 33988;
|
|
23013
|
+
var TEXTURE5_MATCAP = 33989;
|
|
23014
|
+
var TEXTURE6_GRADIENT = 33990;
|
|
23015
|
+
var TEXTURE7_DRAW = 33991;
|
|
23016
|
+
var TEXTURE8_GRADIENT_TEMP = 33992;
|
|
23017
|
+
var TEXTURE9_ORIENT = 33993;
|
|
23018
|
+
var TEXTURE10_BLEND = 33994;
|
|
23019
|
+
var TEXTURE11_GC_BACK = 33995;
|
|
23020
|
+
var TEXTURE12_GC_STRENGTH0 = 33996;
|
|
23021
|
+
var TEXTURE13_GC_STRENGTH1 = 33997;
|
|
23022
|
+
var TEXTURE14_GC_LABEL0 = 33998;
|
|
23023
|
+
var TEXTURE15_GC_LABEL1 = 33999;
|
|
23016
23024
|
var defaultSaveImageOptions = {
|
|
23017
23025
|
filename: "",
|
|
23018
23026
|
isSaveDrawing: false,
|
|
@@ -23115,6 +23123,8 @@ var Niivue = class _Niivue {
|
|
|
23115
23123
|
__publicField(this, "position");
|
|
23116
23124
|
__publicField(this, "extentsMin");
|
|
23117
23125
|
__publicField(this, "extentsMax");
|
|
23126
|
+
// ResizeObserver
|
|
23127
|
+
__publicField(this, "resizeObserver", null);
|
|
23118
23128
|
__publicField(this, "syncOpts", {});
|
|
23119
23129
|
__publicField(this, "readyForSync", false);
|
|
23120
23130
|
// UI Data
|
|
@@ -23140,13 +23150,7 @@ var Niivue = class _Niivue {
|
|
|
23140
23150
|
dragEnd: [0, 0],
|
|
23141
23151
|
dragClipPlaneStartDepthAziElev: [0, 0, 0],
|
|
23142
23152
|
lastTwoTouchDistance: 0,
|
|
23143
|
-
multiTouchGesture: false
|
|
23144
|
-
loading$: new Subject()
|
|
23145
|
-
// whether or not the scene is loading
|
|
23146
|
-
});
|
|
23147
|
-
// mapping of keys (event strings) to rxjs subjects
|
|
23148
|
-
__publicField(this, "eventsToSubjects", {
|
|
23149
|
-
loading: this.uiData.loading$
|
|
23153
|
+
multiTouchGesture: false
|
|
23150
23154
|
});
|
|
23151
23155
|
__publicField(this, "back", null);
|
|
23152
23156
|
// base layer; defines image space to work in. Defined as this.volumes[0] in Niivue.loadVolumes
|
|
@@ -23435,8 +23439,6 @@ var Niivue = class _Niivue {
|
|
|
23435
23439
|
__publicField(this, "initialized", false);
|
|
23436
23440
|
__publicField(this, "currentDrawUndoBitmap");
|
|
23437
23441
|
__publicField(this, "loadingText");
|
|
23438
|
-
// rxjs subscriptions. Keeping a reference array like this allows us to unsubscribe later
|
|
23439
|
-
__publicField(this, "subscriptions", []);
|
|
23440
23442
|
for (const name in options) {
|
|
23441
23443
|
if (typeof options[name] === "function") {
|
|
23442
23444
|
this[name] = options[name];
|
|
@@ -23529,57 +23531,6 @@ var Niivue = class _Niivue {
|
|
|
23529
23531
|
log.debug("attached to element with id: ", id);
|
|
23530
23532
|
return this;
|
|
23531
23533
|
}
|
|
23532
|
-
// on handles matching event strings (event) with know rxjs subjects within NiiVue.
|
|
23533
|
-
// if the event string exists (e.g. 'location') then the corresponding rxjs subject reference
|
|
23534
|
-
// is extracted from this.eventsToSubjects and the callback passed as the second argument to NiiVue.on
|
|
23535
|
-
// is added to the subsciptions to the next method. These callbacks are called whenever subject.next is called within
|
|
23536
|
-
// various NiiVue methods.
|
|
23537
|
-
/**
|
|
23538
|
-
* register a callback function to run when known Niivue events happen
|
|
23539
|
-
* @param event - the name of the event to watch for. Event names are shown in the type column
|
|
23540
|
-
* @param callback - the function to call when the event happens
|
|
23541
|
-
* @example
|
|
23542
|
-
* niivue = new Niivue()
|
|
23543
|
-
*
|
|
23544
|
-
* // 'location' update event is fired when the crosshair changes position via user input
|
|
23545
|
-
* function doSomethingWithLocationData(data)\{
|
|
23546
|
-
* // data has the shape \{mm: [N, N, N], vox: [N, N, N], frac: [N, N, N], values: this.volumes.map(v =\> \{return val\})\}
|
|
23547
|
-
* //...
|
|
23548
|
-
* \}
|
|
23549
|
-
*/
|
|
23550
|
-
on(event, callback) {
|
|
23551
|
-
const knownEvents = Object.keys(this.eventsToSubjects);
|
|
23552
|
-
if (!knownEvents.includes(event)) {
|
|
23553
|
-
return;
|
|
23554
|
-
}
|
|
23555
|
-
const subject = this.eventsToSubjects[event];
|
|
23556
|
-
const subscription = subject.subscribe({
|
|
23557
|
-
next: (data) => callback(data)
|
|
23558
|
-
});
|
|
23559
|
-
this.subscriptions.push({ [event]: subscription });
|
|
23560
|
-
}
|
|
23561
|
-
/**
|
|
23562
|
-
* off unsubscribes events and subjects (the opposite of on)
|
|
23563
|
-
* @param event - the name of the event to watch for. Event names are shown in the type column
|
|
23564
|
-
* @example
|
|
23565
|
-
* niivue = new Niivue()
|
|
23566
|
-
* niivue.off('location')
|
|
23567
|
-
*/
|
|
23568
|
-
off(event) {
|
|
23569
|
-
const knownEvents = Object.keys(this.eventsToSubjects);
|
|
23570
|
-
if (!knownEvents.includes(event)) {
|
|
23571
|
-
return;
|
|
23572
|
-
}
|
|
23573
|
-
const nsubs = this.subscriptions.length;
|
|
23574
|
-
for (let i = 0; i < nsubs; i++) {
|
|
23575
|
-
const key = Object.keys(this.subscriptions[i])[0];
|
|
23576
|
-
if (key === event) {
|
|
23577
|
-
this.subscriptions[i][event].unsubscribe();
|
|
23578
|
-
this.subscriptions.splice(i, 1);
|
|
23579
|
-
return;
|
|
23580
|
-
}
|
|
23581
|
-
}
|
|
23582
|
-
}
|
|
23583
23534
|
/**
|
|
23584
23535
|
* attach the Niivue instance to a canvas element directly
|
|
23585
23536
|
* @param canvas - the canvas element reference
|
|
@@ -23606,6 +23557,8 @@ var Niivue = class _Niivue {
|
|
|
23606
23557
|
this.canvas.width = this.canvas.offsetWidth;
|
|
23607
23558
|
this.canvas.height = this.canvas.offsetHeight;
|
|
23608
23559
|
window.addEventListener("resize", this.resizeListener.bind(this));
|
|
23560
|
+
this.resizeObserver = new ResizeObserver(this.resizeListener.bind(this));
|
|
23561
|
+
this.resizeObserver.observe(this.canvas.parentElement);
|
|
23609
23562
|
}
|
|
23610
23563
|
this.registerInteractions();
|
|
23611
23564
|
await this.init();
|
|
@@ -24263,6 +24216,12 @@ var Niivue = class _Niivue {
|
|
|
24263
24216
|
this.moveCrosshairInVox(0, -1, 0);
|
|
24264
24217
|
} else if (e.code === "KeyK" && this.opts.sliceType !== 4 /* RENDER */) {
|
|
24265
24218
|
this.moveCrosshairInVox(0, 1, 0);
|
|
24219
|
+
} else if (e.code === "KeyM" && this.opts.sliceType !== 4 /* RENDER */) {
|
|
24220
|
+
this.opts.dragMode++;
|
|
24221
|
+
if (this.opts.dragMode >= 4 /* slicer3D */) {
|
|
24222
|
+
this.opts.dragMode = 0 /* none */;
|
|
24223
|
+
}
|
|
24224
|
+
log.info("drag mode changed to ", DRAG_MODE[this.opts.dragMode]);
|
|
24266
24225
|
} else if (e.code === "ArrowLeft") {
|
|
24267
24226
|
this.setFrame4D(this.volumes[0].id, this.volumes[0].frame4D - 1);
|
|
24268
24227
|
} else if (e.code === "ArrowRight") {
|
|
@@ -24499,7 +24458,6 @@ var Niivue = class _Niivue {
|
|
|
24499
24458
|
gl: this.gl,
|
|
24500
24459
|
name: file.name
|
|
24501
24460
|
}).then((mesh) => {
|
|
24502
|
-
this.uiData.loading$.next(false);
|
|
24503
24461
|
this.addMesh(mesh);
|
|
24504
24462
|
}).catch((e2) => {
|
|
24505
24463
|
throw e2;
|
|
@@ -24576,6 +24534,9 @@ var Niivue = class _Niivue {
|
|
|
24576
24534
|
* @see {@link https://niivue.github.io/niivue/features/layout.html|live demo usage}
|
|
24577
24535
|
*/
|
|
24578
24536
|
setMultiplanarLayout(layout) {
|
|
24537
|
+
if (typeof layout === "string") {
|
|
24538
|
+
layout = parseInt(layout);
|
|
24539
|
+
}
|
|
24579
24540
|
this.opts.multiplanarLayout = layout;
|
|
24580
24541
|
this.drawScene();
|
|
24581
24542
|
}
|
|
@@ -24806,7 +24767,7 @@ var Niivue = class _Niivue {
|
|
|
24806
24767
|
const perm = drawingBitmap.permRAS;
|
|
24807
24768
|
const vx = dims[1] * dims[2] * dims[3];
|
|
24808
24769
|
this.drawBitmap = new Uint8Array(vx);
|
|
24809
|
-
this.drawTexture = this.r8Tex(this.drawTexture,
|
|
24770
|
+
this.drawTexture = this.r8Tex(this.drawTexture, TEXTURE7_DRAW, this.back.dims, true);
|
|
24810
24771
|
const layout = [0, 0, 0];
|
|
24811
24772
|
for (let i = 0; i < 3; i++) {
|
|
24812
24773
|
for (let j2 = 0; j2 < 3; j2++) {
|
|
@@ -25211,6 +25172,24 @@ var Niivue = class _Niivue {
|
|
|
25211
25172
|
this.updateGLVolume();
|
|
25212
25173
|
this.onMeshPropertyChanged(idx, key, val);
|
|
25213
25174
|
}
|
|
25175
|
+
/**
|
|
25176
|
+
* returns the index of the mesh vertex that is closest to the provided coordinates
|
|
25177
|
+
* @param id - identity of mesh to change
|
|
25178
|
+
* @param Xmm - location in left/right dimension
|
|
25179
|
+
* @param Ymm - location in posterior/anterior dimension
|
|
25180
|
+
* @param Zmm - location in foot/head dimension
|
|
25181
|
+
* @returns the an array where ret[0] is the mesh index and ret[1] is distance from vertex to coordinates
|
|
25182
|
+
* @example niivue.indexNearestXYZmm(niivue.meshes[0].id, -22, 42, 13)
|
|
25183
|
+
* @see {@link https://niivue.github.io/niivue/features/clipplanes.html | live demo usage}
|
|
25184
|
+
*/
|
|
25185
|
+
indexNearestXYZmm(mesh, Xmm, Ymm, Zmm) {
|
|
25186
|
+
const idx = this.getMeshIndexByID(mesh);
|
|
25187
|
+
if (idx < 0) {
|
|
25188
|
+
log.warn("indexNearestXYZmm() id not loaded", mesh);
|
|
25189
|
+
return [NaN, NaN];
|
|
25190
|
+
}
|
|
25191
|
+
return this.meshes[idx].indexNearestXYZmm(Xmm, Ymm, Zmm);
|
|
25192
|
+
}
|
|
25214
25193
|
/**
|
|
25215
25194
|
* reverse triangle winding of mesh (swap front and back faces)
|
|
25216
25195
|
* @param id - identity of mesh to change
|
|
@@ -25996,14 +25975,8 @@ var Niivue = class _Niivue {
|
|
|
25996
25975
|
* @see {@link https://niivue.github.io/niivue/features/mask.html|live demo usage}
|
|
25997
25976
|
*/
|
|
25998
25977
|
async loadVolumes(volumeList) {
|
|
25999
|
-
this.
|
|
26000
|
-
|
|
26001
|
-
this.loadingText = "loading...";
|
|
26002
|
-
this.drawScene();
|
|
26003
|
-
} else {
|
|
26004
|
-
this.loadingText = this.opts.loadingText;
|
|
26005
|
-
}
|
|
26006
|
-
});
|
|
25978
|
+
this.loadingText = "loading...";
|
|
25979
|
+
this.drawScene();
|
|
26007
25980
|
if (this.thumbnailVisible) {
|
|
26008
25981
|
this.deferredVolumes = volumeList;
|
|
26009
25982
|
return this;
|
|
@@ -26011,9 +25984,7 @@ var Niivue = class _Niivue {
|
|
|
26011
25984
|
this.volumes = [];
|
|
26012
25985
|
this.gl.clearColor(0, 0, 0, 1);
|
|
26013
25986
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
26014
|
-
this.uiData.loading$.next(false);
|
|
26015
25987
|
for (let i = 0; i < volumeList.length; i++) {
|
|
26016
|
-
this.uiData.loading$.next(true);
|
|
26017
25988
|
if (volumeList[i].colorMap !== void 0) {
|
|
26018
25989
|
volumeList[i].colormap = volumeList[i].colorMap;
|
|
26019
25990
|
}
|
|
@@ -26034,7 +26005,6 @@ var Niivue = class _Niivue {
|
|
|
26034
26005
|
colorbarVisible: volumeList[i].colorbarVisible
|
|
26035
26006
|
};
|
|
26036
26007
|
await this.addVolumeFromUrl(imageOptions);
|
|
26037
|
-
this.uiData.loading$.next(false);
|
|
26038
26008
|
}
|
|
26039
26009
|
return this;
|
|
26040
26010
|
}
|
|
@@ -26043,6 +26013,16 @@ var Niivue = class _Niivue {
|
|
|
26043
26013
|
* @see {@link https://niivue.github.io/niivue/features/multiuser.meshes.html|live demo usage}
|
|
26044
26014
|
*/
|
|
26045
26015
|
async addMeshFromUrl(meshOptions) {
|
|
26016
|
+
const ext = this.getFileExt(meshOptions.url);
|
|
26017
|
+
if (ext === "JCON" || ext === "JSON") {
|
|
26018
|
+
const response = await fetch(meshOptions.url, {});
|
|
26019
|
+
const json = await response.json();
|
|
26020
|
+
const mesh2 = this.loadConnectomeAsMesh(json);
|
|
26021
|
+
this.mediaUrlMap.set(mesh2, meshOptions.url);
|
|
26022
|
+
this.onMeshAddedFromUrl(meshOptions, mesh2);
|
|
26023
|
+
this.addMesh(mesh2);
|
|
26024
|
+
return mesh2;
|
|
26025
|
+
}
|
|
26046
26026
|
const mesh = await NVMesh.loadFromUrl({ ...meshOptions, gl: this.gl });
|
|
26047
26027
|
this.mediaUrlMap.set(mesh, meshOptions.url);
|
|
26048
26028
|
this.onMeshAddedFromUrl(meshOptions, mesh);
|
|
@@ -26059,14 +26039,8 @@ var Niivue = class _Niivue {
|
|
|
26059
26039
|
* @see {@link https://niivue.github.io/niivue/features/meshes.html|live demo usage}
|
|
26060
26040
|
*/
|
|
26061
26041
|
async loadMeshes(meshList) {
|
|
26062
|
-
this.
|
|
26063
|
-
|
|
26064
|
-
this.loadingText = "loading...";
|
|
26065
|
-
this.drawScene();
|
|
26066
|
-
} else {
|
|
26067
|
-
this.loadingText = this.opts.loadingText;
|
|
26068
|
-
}
|
|
26069
|
-
});
|
|
26042
|
+
this.loadingText = "loading...";
|
|
26043
|
+
this.drawScene();
|
|
26070
26044
|
if (this.thumbnailVisible) {
|
|
26071
26045
|
this.deferredMeshes = meshList;
|
|
26072
26046
|
return this;
|
|
@@ -26076,11 +26050,8 @@ var Niivue = class _Niivue {
|
|
|
26076
26050
|
this.meshes = [];
|
|
26077
26051
|
this.gl.clearColor(0, 0, 0, 1);
|
|
26078
26052
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
26079
|
-
this.uiData.loading$.next(false);
|
|
26080
26053
|
for (let i = 0; i < meshList.length; i++) {
|
|
26081
|
-
this.uiData.loading$.next(true);
|
|
26082
26054
|
await this.addMeshFromUrl(meshList[i]);
|
|
26083
|
-
this.uiData.loading$.next(false);
|
|
26084
26055
|
}
|
|
26085
26056
|
this.drawScene();
|
|
26086
26057
|
return this;
|
|
@@ -26133,6 +26104,22 @@ var Niivue = class _Niivue {
|
|
|
26133
26104
|
);
|
|
26134
26105
|
this.drawScene();
|
|
26135
26106
|
}
|
|
26107
|
+
loadConnectomeAsMesh(json) {
|
|
26108
|
+
let connectome = json;
|
|
26109
|
+
if ("data_type" in json && json.data_type === "fs_pointset") {
|
|
26110
|
+
connectome = NVConnectome.convertFreeSurferConnectome(json);
|
|
26111
|
+
log.warn("converted FreeSurfer connectome", connectome);
|
|
26112
|
+
} else if ("nodes" in json) {
|
|
26113
|
+
const nodes = json.nodes;
|
|
26114
|
+
if ("names" in nodes && "X" in nodes && "Y" in nodes && "Z" in nodes && "Color" in nodes && "Size" in nodes) {
|
|
26115
|
+
connectome = NVConnectome.convertLegacyConnectome(json);
|
|
26116
|
+
log.warn("converted legacy connectome", connectome);
|
|
26117
|
+
}
|
|
26118
|
+
} else {
|
|
26119
|
+
throw new Error("not a known connectome format");
|
|
26120
|
+
}
|
|
26121
|
+
return new NVConnectome(this.gl, connectome);
|
|
26122
|
+
}
|
|
26136
26123
|
/**
|
|
26137
26124
|
* load a connectome specified by json
|
|
26138
26125
|
* @param connectome - model
|
|
@@ -26140,27 +26127,13 @@ var Niivue = class _Niivue {
|
|
|
26140
26127
|
* @see {@link https://niivue.github.io/niivue/features/connectome.html|live demo usage}
|
|
26141
26128
|
*/
|
|
26142
26129
|
loadConnectome(json) {
|
|
26143
|
-
this.
|
|
26144
|
-
|
|
26145
|
-
this.loadingText = "loading...";
|
|
26146
|
-
this.drawScene();
|
|
26147
|
-
} else {
|
|
26148
|
-
this.loadingText = this.opts.loadingText;
|
|
26149
|
-
}
|
|
26150
|
-
});
|
|
26130
|
+
this.loadingText = "loading...";
|
|
26131
|
+
this.drawScene();
|
|
26151
26132
|
this.meshes = [];
|
|
26152
26133
|
this.gl.clearColor(0, 0, 0, 1);
|
|
26153
26134
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
26154
|
-
this.
|
|
26155
|
-
let connectome = json;
|
|
26156
|
-
const nodes = json.nodes;
|
|
26157
|
-
if ("names" in nodes && "X" in nodes && "Y" in nodes && "Z" in nodes && "Color" in nodes && "Size" in nodes) {
|
|
26158
|
-
connectome = NVConnectome.convertLegacyConnectome(json);
|
|
26159
|
-
log.warn("converted legacy connectome", connectome);
|
|
26160
|
-
}
|
|
26161
|
-
const mesh = new NVConnectome(this.gl, connectome);
|
|
26135
|
+
const mesh = this.loadConnectomeAsMesh(json);
|
|
26162
26136
|
this.addMesh(mesh);
|
|
26163
|
-
this.uiData.loading$.next(false);
|
|
26164
26137
|
this.drawScene();
|
|
26165
26138
|
return this;
|
|
26166
26139
|
}
|
|
@@ -26181,7 +26154,7 @@ var Niivue = class _Niivue {
|
|
|
26181
26154
|
this.drawBitmap = new Uint8Array(vx);
|
|
26182
26155
|
this.drawClearAllUndoBitmaps();
|
|
26183
26156
|
this.drawAddUndoBitmap();
|
|
26184
|
-
this.drawTexture = this.r8Tex(this.drawTexture,
|
|
26157
|
+
this.drawTexture = this.r8Tex(this.drawTexture, TEXTURE7_DRAW, this.back.dims, true);
|
|
26185
26158
|
this.refreshDrawing(false);
|
|
26186
26159
|
}
|
|
26187
26160
|
// not included in public docs
|
|
@@ -26242,29 +26215,29 @@ var Niivue = class _Niivue {
|
|
|
26242
26215
|
gl.viewport(0, 0, this.back.dims[1], this.back.dims[2]);
|
|
26243
26216
|
gl.disable(gl.BLEND);
|
|
26244
26217
|
let img16 = img2ras16(this.back);
|
|
26245
|
-
const background = this.r16Tex(null,
|
|
26218
|
+
const background = this.r16Tex(null, TEXTURE11_GC_BACK, this.back.dims, img16);
|
|
26246
26219
|
for (let i = 1; i < nv; i++) {
|
|
26247
26220
|
img16[i] = this.drawBitmap[i];
|
|
26248
26221
|
}
|
|
26249
|
-
const label0 = this.r16Tex(null,
|
|
26250
|
-
const label1 = this.r16Tex(null,
|
|
26222
|
+
const label0 = this.r16Tex(null, TEXTURE14_GC_LABEL0, this.back.dims, img16);
|
|
26223
|
+
const label1 = this.r16Tex(null, TEXTURE15_GC_LABEL1, this.back.dims, img16);
|
|
26251
26224
|
const kMAX_STRENGTH = 1e4;
|
|
26252
26225
|
for (let i = 1; i < nv; i++) {
|
|
26253
26226
|
if (img16[i] > 0) {
|
|
26254
26227
|
img16[i] = kMAX_STRENGTH;
|
|
26255
26228
|
}
|
|
26256
26229
|
}
|
|
26257
|
-
const strength0 = this.r16Tex(null,
|
|
26258
|
-
const strength1 = this.r16Tex(null,
|
|
26230
|
+
const strength0 = this.r16Tex(null, TEXTURE12_GC_STRENGTH0, this.back.dims, img16);
|
|
26231
|
+
const strength1 = this.r16Tex(null, TEXTURE13_GC_STRENGTH1, this.back.dims, img16);
|
|
26259
26232
|
gl.bindVertexArray(this.genericVAO);
|
|
26260
26233
|
const shader = this.growCutShader;
|
|
26261
26234
|
shader.use(gl);
|
|
26262
26235
|
const iterations = 128;
|
|
26263
26236
|
gl.uniform1i(shader.uniforms.finalPass, 0);
|
|
26264
|
-
gl.uniform1i(shader.uniforms.
|
|
26237
|
+
gl.uniform1i(shader.uniforms.backTex, 11);
|
|
26265
26238
|
for (let j = 0; j < iterations; j++) {
|
|
26266
|
-
gl.uniform1i(shader.uniforms.
|
|
26267
|
-
gl.uniform1i(shader.uniforms.
|
|
26239
|
+
gl.uniform1i(shader.uniforms.labelTex, 14);
|
|
26240
|
+
gl.uniform1i(shader.uniforms.strengthTex, 12);
|
|
26268
26241
|
for (let i = 0; i < this.back.dims[3]; i++) {
|
|
26269
26242
|
const coordZ = 1 / this.back.dims[3] * (i + 0.5);
|
|
26270
26243
|
gl.uniform1f(shader.uniforms.coordZ, coordZ);
|
|
@@ -26280,8 +26253,8 @@ var Niivue = class _Niivue {
|
|
|
26280
26253
|
if (j === iterations - 1) {
|
|
26281
26254
|
gl.uniform1i(shader.uniforms.finalPass, 1);
|
|
26282
26255
|
}
|
|
26283
|
-
gl.uniform1i(shader.uniforms.
|
|
26284
|
-
gl.uniform1i(shader.uniforms.
|
|
26256
|
+
gl.uniform1i(shader.uniforms.labelTex, 15);
|
|
26257
|
+
gl.uniform1i(shader.uniforms.strengthTex, 13);
|
|
26285
26258
|
for (let i = 0; i < this.back.dims[3]; i++) {
|
|
26286
26259
|
const coordZ = 1 / this.back.dims[3] * (i + 0.5);
|
|
26287
26260
|
gl.uniform1f(shader.uniforms.coordZ, coordZ);
|
|
@@ -26327,14 +26300,6 @@ var Niivue = class _Niivue {
|
|
|
26327
26300
|
for (let i = 1; i < nv; i++) {
|
|
26328
26301
|
this.drawBitmap[i] = img16[i];
|
|
26329
26302
|
}
|
|
26330
|
-
gl.activeTexture(gl.TEXTURE2);
|
|
26331
|
-
gl.bindTexture(gl.TEXTURE_3D, this.overlayTexture);
|
|
26332
|
-
gl.activeTexture(gl.TEXTURE3);
|
|
26333
|
-
gl.bindTexture(gl.TEXTURE_2D, this.fontTexture);
|
|
26334
|
-
gl.activeTexture(gl.TEXTURE4);
|
|
26335
|
-
gl.bindTexture(gl.TEXTURE_2D, this.bmpTexture);
|
|
26336
|
-
gl.activeTexture(gl.TEXTURE7);
|
|
26337
|
-
gl.bindTexture(gl.TEXTURE_3D, this.drawTexture);
|
|
26338
26303
|
gl.deleteTexture(background);
|
|
26339
26304
|
gl.deleteTexture(strength0);
|
|
26340
26305
|
gl.deleteTexture(strength1);
|
|
@@ -26760,7 +26725,7 @@ var Niivue = class _Niivue {
|
|
|
26760
26725
|
*/
|
|
26761
26726
|
closeDrawing() {
|
|
26762
26727
|
this.drawClearAllUndoBitmaps();
|
|
26763
|
-
this.rgbaTex(this.drawTexture,
|
|
26728
|
+
this.rgbaTex(this.drawTexture, TEXTURE7_DRAW, [2, 2, 2, 2], true);
|
|
26764
26729
|
this.drawBitmap = null;
|
|
26765
26730
|
this.drawScene();
|
|
26766
26731
|
}
|
|
@@ -26786,7 +26751,7 @@ var Niivue = class _Niivue {
|
|
|
26786
26751
|
} else if (vx !== this.drawBitmap.length) {
|
|
26787
26752
|
log.warn("Drawing bitmap must match the background image");
|
|
26788
26753
|
}
|
|
26789
|
-
this.gl.activeTexture(
|
|
26754
|
+
this.gl.activeTexture(TEXTURE7_DRAW);
|
|
26790
26755
|
this.gl.bindTexture(this.gl.TEXTURE_3D, this.drawTexture);
|
|
26791
26756
|
this.gl.texSubImage3D(
|
|
26792
26757
|
this.gl.TEXTURE_3D,
|
|
@@ -26897,11 +26862,11 @@ var Niivue = class _Niivue {
|
|
|
26897
26862
|
this.bmpTexture = this.gl.createTexture();
|
|
26898
26863
|
pngTexture = this.bmpTexture;
|
|
26899
26864
|
this.bmpTextureWH = img.width / img.height;
|
|
26900
|
-
this.gl.activeTexture(
|
|
26865
|
+
this.gl.activeTexture(TEXTURE4_THUMBNAIL);
|
|
26901
26866
|
this.bmpShader.use(this.gl);
|
|
26902
26867
|
this.gl.uniform1i(this.bmpShader.uniforms.bmpTexture, 4);
|
|
26903
26868
|
} else if (textureNum === 5) {
|
|
26904
|
-
this.gl.activeTexture(
|
|
26869
|
+
this.gl.activeTexture(TEXTURE5_MATCAP);
|
|
26905
26870
|
if (this.matCapTexture !== null) {
|
|
26906
26871
|
this.gl.deleteTexture(this.matCapTexture);
|
|
26907
26872
|
}
|
|
@@ -26909,7 +26874,7 @@ var Niivue = class _Niivue {
|
|
|
26909
26874
|
pngTexture = this.matCapTexture;
|
|
26910
26875
|
} else {
|
|
26911
26876
|
this.fontShader.use(this.gl);
|
|
26912
|
-
this.gl.activeTexture(
|
|
26877
|
+
this.gl.activeTexture(TEXTURE3_FONT);
|
|
26913
26878
|
this.gl.uniform1i(this.fontShader.uniforms.fontTexture, 3);
|
|
26914
26879
|
if (this.fontTexture !== null) {
|
|
26915
26880
|
this.gl.deleteTexture(this.fontTexture);
|
|
@@ -27144,9 +27109,9 @@ var Niivue = class _Niivue {
|
|
|
27144
27109
|
this.gl.cullFace(this.gl.FRONT);
|
|
27145
27110
|
this.gl.enable(this.gl.BLEND);
|
|
27146
27111
|
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
|
|
27147
|
-
this.volumeTexture = this.rgbaTex(this.volumeTexture,
|
|
27148
|
-
this.overlayTexture = this.rgbaTex(this.overlayTexture,
|
|
27149
|
-
this.drawTexture = this.r8Tex(this.drawTexture,
|
|
27112
|
+
this.volumeTexture = this.rgbaTex(this.volumeTexture, TEXTURE0_BACK_VOL, [2, 2, 2, 2], true);
|
|
27113
|
+
this.overlayTexture = this.rgbaTex(this.overlayTexture, TEXTURE2_OVERLAY_VOL, [2, 2, 2, 2], true);
|
|
27114
|
+
this.drawTexture = this.r8Tex(this.drawTexture, TEXTURE7_DRAW, [2, 2, 2, 2], true);
|
|
27150
27115
|
const rectStrip = [
|
|
27151
27116
|
1,
|
|
27152
27117
|
1,
|
|
@@ -27283,10 +27248,10 @@ var Niivue = class _Niivue {
|
|
|
27283
27248
|
gl.disable(gl.CULL_FACE);
|
|
27284
27249
|
gl.viewport(0, 0, hdr.dims[1], hdr.dims[2]);
|
|
27285
27250
|
gl.disable(gl.BLEND);
|
|
27286
|
-
const tempTex3D = this.rgbaTex(null,
|
|
27251
|
+
const tempTex3D = this.rgbaTex(null, TEXTURE8_GRADIENT_TEMP, hdr.dims);
|
|
27287
27252
|
const blurShader = this.blurShader;
|
|
27288
27253
|
blurShader.use(gl);
|
|
27289
|
-
gl.activeTexture(
|
|
27254
|
+
gl.activeTexture(TEXTURE0_BACK_VOL);
|
|
27290
27255
|
gl.bindTexture(gl.TEXTURE_3D, this.volumeTexture);
|
|
27291
27256
|
const blurRadius = 0.7;
|
|
27292
27257
|
gl.uniform1i(blurShader.uniforms.intensityVol, 0);
|
|
@@ -27303,20 +27268,20 @@ var Niivue = class _Niivue {
|
|
|
27303
27268
|
}
|
|
27304
27269
|
const sobelShader = this.sobelShader;
|
|
27305
27270
|
sobelShader.use(gl);
|
|
27306
|
-
gl.activeTexture(
|
|
27271
|
+
gl.activeTexture(TEXTURE8_GRADIENT_TEMP);
|
|
27307
27272
|
gl.bindTexture(gl.TEXTURE_3D, tempTex3D);
|
|
27308
|
-
gl.uniform1i(sobelShader.uniforms.intensityVol,
|
|
27273
|
+
gl.uniform1i(sobelShader.uniforms.intensityVol, 8);
|
|
27309
27274
|
const sobelRadius = 0.7;
|
|
27310
27275
|
gl.uniform1f(sobelShader.uniforms.dX, sobelRadius / hdr.dims[1]);
|
|
27311
27276
|
gl.uniform1f(sobelShader.uniforms.dY, sobelRadius / hdr.dims[2]);
|
|
27312
27277
|
gl.uniform1f(sobelShader.uniforms.dZ, sobelRadius / hdr.dims[3]);
|
|
27313
27278
|
gl.uniform1f(sobelShader.uniforms.coordZ, 0.5);
|
|
27314
27279
|
gl.bindVertexArray(vao2);
|
|
27315
|
-
gl.activeTexture(
|
|
27280
|
+
gl.activeTexture(TEXTURE0_BACK_VOL);
|
|
27316
27281
|
if (this.gradientTexture !== null) {
|
|
27317
27282
|
gl.deleteTexture(this.gradientTexture);
|
|
27318
27283
|
}
|
|
27319
|
-
this.gradientTexture = this.rgbaTex(this.gradientTexture,
|
|
27284
|
+
this.gradientTexture = this.rgbaTex(this.gradientTexture, TEXTURE6_GRADIENT, hdr.dims);
|
|
27320
27285
|
for (let i = 0; i < hdr.dims[3] - 1; i++) {
|
|
27321
27286
|
const coordZ = 1 / hdr.dims[3] * (i + 0.5);
|
|
27322
27287
|
gl.uniform1f(sobelShader.uniforms.coordZ, coordZ);
|
|
@@ -27498,7 +27463,7 @@ var Niivue = class _Niivue {
|
|
|
27498
27463
|
this.back.matRAS = overlayItem.matRAS;
|
|
27499
27464
|
this.back.dims = overlayItem.dimsRAS;
|
|
27500
27465
|
this.back.pixDims = overlayItem.pixDimsRAS;
|
|
27501
|
-
outTexture = this.rgbaTex(this.volumeTexture,
|
|
27466
|
+
outTexture = this.rgbaTex(this.volumeTexture, TEXTURE0_BACK_VOL, overlayItem.dimsRAS);
|
|
27502
27467
|
const { volScale: volScale2, vox: vox2 } = this.sliceScale(true);
|
|
27503
27468
|
this.volScale = volScale2;
|
|
27504
27469
|
this.vox = vox2;
|
|
@@ -27547,7 +27512,7 @@ var Niivue = class _Niivue {
|
|
|
27547
27512
|
);
|
|
27548
27513
|
mat46.invert(mtx, mtx);
|
|
27549
27514
|
if (layer === 1) {
|
|
27550
|
-
outTexture = this.rgbaTex(this.overlayTexture,
|
|
27515
|
+
outTexture = this.rgbaTex(this.overlayTexture, TEXTURE2_OVERLAY_VOL, this.back.dims);
|
|
27551
27516
|
this.overlayTexture = outTexture;
|
|
27552
27517
|
this.overlayTextureID = outTexture;
|
|
27553
27518
|
} else {
|
|
@@ -27560,7 +27525,7 @@ var Niivue = class _Niivue {
|
|
|
27560
27525
|
this.gl.viewport(0, 0, this.back.dims[1], this.back.dims[2]);
|
|
27561
27526
|
this.gl.disable(this.gl.BLEND);
|
|
27562
27527
|
const tempTex3D = this.gl.createTexture();
|
|
27563
|
-
this.gl.activeTexture(
|
|
27528
|
+
this.gl.activeTexture(TEXTURE9_ORIENT);
|
|
27564
27529
|
this.gl.bindTexture(this.gl.TEXTURE_3D, tempTex3D);
|
|
27565
27530
|
this.gl.texParameteri(this.gl.TEXTURE_3D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
|
|
27566
27531
|
this.gl.texParameteri(this.gl.TEXTURE_3D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
|
|
@@ -27709,22 +27674,22 @@ var Niivue = class _Niivue {
|
|
|
27709
27674
|
const isUseCopyTexSubImage3D = false;
|
|
27710
27675
|
if (isUseCopyTexSubImage3D) {
|
|
27711
27676
|
if (layer > 1) {
|
|
27712
|
-
blendTexture = this.rgbaTex(blendTexture,
|
|
27677
|
+
blendTexture = this.rgbaTex(blendTexture, TEXTURE10_BLEND, this.back.dims, true);
|
|
27713
27678
|
this.gl.bindTexture(this.gl.TEXTURE_3D, blendTexture);
|
|
27714
27679
|
for (let i = 0; i < this.back.dims[3]; i++) {
|
|
27715
27680
|
this.gl.framebufferTextureLayer(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.overlayTexture, 0, i);
|
|
27716
|
-
this.gl.activeTexture(
|
|
27681
|
+
this.gl.activeTexture(TEXTURE10_BLEND);
|
|
27717
27682
|
this.gl.copyTexSubImage3D(this.gl.TEXTURE_3D, 0, 0, 0, i, 0, 0, this.back.dims[1], this.back.dims[2]);
|
|
27718
27683
|
}
|
|
27719
27684
|
} else {
|
|
27720
|
-
blendTexture = this.rgbaTex(blendTexture,
|
|
27685
|
+
blendTexture = this.rgbaTex(blendTexture, TEXTURE10_BLEND, [2, 2, 2, 2], true);
|
|
27721
27686
|
}
|
|
27722
27687
|
} else {
|
|
27723
27688
|
if (layer > 1) {
|
|
27724
27689
|
if (!this.back.dims) {
|
|
27725
27690
|
throw new Error("back.dims undefined");
|
|
27726
27691
|
}
|
|
27727
|
-
blendTexture = this.rgbaTex(blendTexture,
|
|
27692
|
+
blendTexture = this.rgbaTex(blendTexture, TEXTURE10_BLEND, this.back.dims);
|
|
27728
27693
|
this.gl.bindTexture(this.gl.TEXTURE_3D, blendTexture);
|
|
27729
27694
|
const passShader = this.passThroughShader;
|
|
27730
27695
|
passShader.use(this.gl);
|
|
@@ -27736,11 +27701,11 @@ var Niivue = class _Niivue {
|
|
|
27736
27701
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
27737
27702
|
}
|
|
27738
27703
|
} else {
|
|
27739
|
-
blendTexture = this.rgbaTex(blendTexture,
|
|
27704
|
+
blendTexture = this.rgbaTex(blendTexture, TEXTURE10_BLEND, [2, 2, 2, 2]);
|
|
27740
27705
|
}
|
|
27741
27706
|
}
|
|
27742
27707
|
orientShader.use(this.gl);
|
|
27743
|
-
this.gl.activeTexture(
|
|
27708
|
+
this.gl.activeTexture(TEXTURE1_COLORMAPS);
|
|
27744
27709
|
let colormapLabelTexture = null;
|
|
27745
27710
|
if (overlayItem.colormapLabel !== null && overlayItem.colormapLabel.lut.length > 7) {
|
|
27746
27711
|
const nLabel = overlayItem.colormapLabel.max - overlayItem.colormapLabel.min + 1;
|
|
@@ -27783,8 +27748,8 @@ var Niivue = class _Niivue {
|
|
|
27783
27748
|
this.gl.uniform1f(orientShader.uniforms.cal_minNeg ?? null, mnNeg);
|
|
27784
27749
|
this.gl.uniform1f(orientShader.uniforms.cal_maxNeg ?? null, mxNeg);
|
|
27785
27750
|
this.gl.bindTexture(this.gl.TEXTURE_3D, tempTex3D);
|
|
27786
|
-
this.gl.uniform1i(orientShader.uniforms.intensityVol ?? null,
|
|
27787
|
-
this.gl.uniform1i(orientShader.uniforms.blend3D ?? null,
|
|
27751
|
+
this.gl.uniform1i(orientShader.uniforms.intensityVol ?? null, 9);
|
|
27752
|
+
this.gl.uniform1i(orientShader.uniforms.blend3D ?? null, 10);
|
|
27788
27753
|
this.gl.uniform1i(orientShader.uniforms.colormap ?? null, 1);
|
|
27789
27754
|
this.gl.uniform1f(orientShader.uniforms.scl_inter ?? null, hdr.scl_inter);
|
|
27790
27755
|
this.gl.uniform1f(orientShader.uniforms.scl_slope ?? null, hdr.scl_slope);
|
|
@@ -27880,13 +27845,16 @@ var Niivue = class _Niivue {
|
|
|
27880
27845
|
if (!this.back.dims) {
|
|
27881
27846
|
throw new Error("back.dims undefined");
|
|
27882
27847
|
}
|
|
27848
|
+
let outline = 0;
|
|
27883
27849
|
if (hdr.intent_code === 1002) {
|
|
27884
|
-
|
|
27885
|
-
if (!this.opts.isAtlasOutline) {
|
|
27886
|
-
x = -x;
|
|
27887
|
-
}
|
|
27888
|
-
this.gl.uniform3fv(orientShader.uniforms.xyzFrac, [x, 1 / this.back.dims[2], 1 / this.back.dims[3]]);
|
|
27850
|
+
outline = this.opts.atlasOutline;
|
|
27889
27851
|
}
|
|
27852
|
+
this.gl.uniform4fv(orientShader.uniforms.xyzaFrac, [
|
|
27853
|
+
1 / this.back.dims[1],
|
|
27854
|
+
1 / this.back.dims[2],
|
|
27855
|
+
1 / this.back.dims[3],
|
|
27856
|
+
outline
|
|
27857
|
+
]);
|
|
27890
27858
|
log.debug("back dims: ", this.back.dims);
|
|
27891
27859
|
for (let i = 0; i < this.back.dims[3]; i++) {
|
|
27892
27860
|
const coordZ = 1 / this.back.dims[3] * (i + 0.5);
|
|
@@ -27944,11 +27912,11 @@ var Niivue = class _Niivue {
|
|
|
27944
27912
|
this.gl.uniform1f(shader.uniforms.drawOpacity, this.drawOpacity);
|
|
27945
27913
|
if (colormapLabelTexture !== null) {
|
|
27946
27914
|
this.gl.deleteTexture(colormapLabelTexture);
|
|
27947
|
-
this.gl.activeTexture(
|
|
27915
|
+
this.gl.activeTexture(TEXTURE1_COLORMAPS);
|
|
27948
27916
|
this.gl.bindTexture(this.gl.TEXTURE_2D, this.colormapTexture);
|
|
27949
27917
|
}
|
|
27950
27918
|
this.gl.uniform1i(shader.uniforms.drawing, 7);
|
|
27951
|
-
this.gl.activeTexture(
|
|
27919
|
+
this.gl.activeTexture(TEXTURE7_DRAW);
|
|
27952
27920
|
this.gl.bindTexture(this.gl.TEXTURE_3D, this.drawTexture);
|
|
27953
27921
|
this.updateInterpolation(layer);
|
|
27954
27922
|
}
|
|
@@ -28021,7 +27989,7 @@ var Niivue = class _Niivue {
|
|
|
28021
27989
|
/**
|
|
28022
27990
|
* modulate intensity of one image based on intensity of another
|
|
28023
27991
|
* @param idTarget - the ID of the NVImage to be biased
|
|
28024
|
-
* @param idModulation - the ID of the NVImage that controls bias (
|
|
27992
|
+
* @param idModulation - the ID of the NVImage that controls bias (empty string to disable modulation)
|
|
28025
27993
|
* @param modulateAlpha - does the modulation influence alpha transparency (values greater than 1).
|
|
28026
27994
|
* @example niivue.setModulationImage(niivue.volumes[0].id, niivue.volumes[1].id);
|
|
28027
27995
|
* @see {@link https://niivue.github.io/niivue/features/modulate.html|live demo scalar usage}
|
|
@@ -28030,7 +27998,9 @@ var Niivue = class _Niivue {
|
|
|
28030
27998
|
setModulationImage(idTarget, idModulation, modulateAlpha = 0) {
|
|
28031
27999
|
const idxTarget = this.getVolumeIndexByID(idTarget);
|
|
28032
28000
|
let idxModulation = null;
|
|
28033
|
-
|
|
28001
|
+
if (idModulation.length > 0) {
|
|
28002
|
+
idxModulation = this.getVolumeIndexByID(idModulation);
|
|
28003
|
+
}
|
|
28034
28004
|
this.volumes[idxTarget].modulationImage = idxModulation;
|
|
28035
28005
|
this.volumes[idxTarget].modulateAlpha = modulateAlpha;
|
|
28036
28006
|
this.updateGLVolume();
|
|
@@ -28100,7 +28070,7 @@ var Niivue = class _Niivue {
|
|
|
28100
28070
|
*/
|
|
28101
28071
|
getFrame4D(id) {
|
|
28102
28072
|
const idx = this.getVolumeIndexByID(id);
|
|
28103
|
-
return this.volumes[idx].
|
|
28073
|
+
return this.volumes[idx].frame4D;
|
|
28104
28074
|
}
|
|
28105
28075
|
// not included in public docs
|
|
28106
28076
|
colormapFromKey(name) {
|
|
@@ -28121,7 +28091,7 @@ var Niivue = class _Niivue {
|
|
|
28121
28091
|
return null;
|
|
28122
28092
|
}
|
|
28123
28093
|
texture = this.gl.createTexture();
|
|
28124
|
-
this.gl.activeTexture(
|
|
28094
|
+
this.gl.activeTexture(TEXTURE1_COLORMAPS);
|
|
28125
28095
|
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
28126
28096
|
this.gl.texStorage2D(this.gl.TEXTURE_2D, 1, this.gl.RGBA8, nCol, nRow);
|
|
28127
28097
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
|
@@ -28761,7 +28731,7 @@ var Niivue = class _Niivue {
|
|
|
28761
28731
|
throw new Error("colorbarShader undefined");
|
|
28762
28732
|
}
|
|
28763
28733
|
this.colorbarShader.use(this.gl);
|
|
28764
|
-
this.gl.activeTexture(
|
|
28734
|
+
this.gl.activeTexture(TEXTURE1_COLORMAPS);
|
|
28765
28735
|
this.gl.bindTexture(this.gl.TEXTURE_2D, this.colormapTexture);
|
|
28766
28736
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
|
|
28767
28737
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
|
|
@@ -29004,16 +28974,16 @@ var Niivue = class _Niivue {
|
|
|
29004
28974
|
interp = this.gl.NEAREST;
|
|
29005
28975
|
}
|
|
29006
28976
|
if (layer === 0) {
|
|
29007
|
-
this.gl.activeTexture(
|
|
28977
|
+
this.gl.activeTexture(TEXTURE0_BACK_VOL);
|
|
29008
28978
|
} else {
|
|
29009
|
-
this.gl.activeTexture(
|
|
28979
|
+
this.gl.activeTexture(TEXTURE2_OVERLAY_VOL);
|
|
29010
28980
|
}
|
|
29011
28981
|
this.gl.texParameteri(this.gl.TEXTURE_3D, this.gl.TEXTURE_MIN_FILTER, interp);
|
|
29012
28982
|
this.gl.texParameteri(this.gl.TEXTURE_3D, this.gl.TEXTURE_MAG_FILTER, interp);
|
|
29013
28983
|
}
|
|
29014
28984
|
// not included in public docs
|
|
29015
28985
|
setAtlasOutline(isOutline) {
|
|
29016
|
-
this.opts.
|
|
28986
|
+
this.opts.atlasOutline = isOutline;
|
|
29017
28987
|
this.updateGLVolume();
|
|
29018
28988
|
this.drawScene();
|
|
29019
28989
|
}
|
|
@@ -29576,6 +29546,12 @@ var Niivue = class _Niivue {
|
|
|
29576
29546
|
if (graph.opacity <= 0 || graph.LTWH[2] <= 5 || graph.LTWH[3] <= 5) {
|
|
29577
29547
|
return;
|
|
29578
29548
|
}
|
|
29549
|
+
if (graph.LTWH[0] + graph.LTWH[2] > this.gl.canvas.width) {
|
|
29550
|
+
return;
|
|
29551
|
+
}
|
|
29552
|
+
if (graph.LTWH[1] + graph.LTWH[3] > this.gl.canvas.height) {
|
|
29553
|
+
return;
|
|
29554
|
+
}
|
|
29579
29555
|
graph.backColor = [0.15, 0.15, 0.15, graph.opacity];
|
|
29580
29556
|
graph.lineColor = [1, 1, 1, 1];
|
|
29581
29557
|
if (this.opts.backColor[0] + this.opts.backColor[1] + this.opts.backColor[2] > 1.5) {
|
|
@@ -29839,7 +29815,7 @@ var Niivue = class _Niivue {
|
|
|
29839
29815
|
shader.use(this.gl);
|
|
29840
29816
|
gl.uniform1i(shader.uniforms.backgroundMasksOverlays, this.backgroundMasksOverlays);
|
|
29841
29817
|
if (this.gradientTextureAmount > 0) {
|
|
29842
|
-
gl.activeTexture(
|
|
29818
|
+
gl.activeTexture(TEXTURE6_GRADIENT);
|
|
29843
29819
|
gl.bindTexture(gl.TEXTURE_3D, this.gradientTexture);
|
|
29844
29820
|
const modelMatrix = this.calculateModelMatrix(azimuth, elevation);
|
|
29845
29821
|
const iModelMatrix = mat46.create();
|
|
@@ -30247,7 +30223,7 @@ var Niivue = class _Niivue {
|
|
|
30247
30223
|
continue;
|
|
30248
30224
|
}
|
|
30249
30225
|
if (shader.isMatcap) {
|
|
30250
|
-
gl.activeTexture(
|
|
30226
|
+
gl.activeTexture(TEXTURE5_MATCAP);
|
|
30251
30227
|
gl.bindTexture(gl.TEXTURE_2D, this.matCapTexture);
|
|
30252
30228
|
}
|
|
30253
30229
|
gl.bindVertexArray(this.meshes[i].vao);
|
|
@@ -30307,7 +30283,7 @@ var Niivue = class _Niivue {
|
|
|
30307
30283
|
radius = range[0] * 0.02;
|
|
30308
30284
|
}
|
|
30309
30285
|
radius *= this.opts.crosshairWidth;
|
|
30310
|
-
this.crosshairs3D = NiivueObject3D.generateCrosshairs(this.gl, 1, mm, mn, mx, radius);
|
|
30286
|
+
this.crosshairs3D = NiivueObject3D.generateCrosshairs(this.gl, 1, mm, mn, mx, radius, 20, this.opts.crosshairGap);
|
|
30311
30287
|
this.crosshairs3D.mm = mm;
|
|
30312
30288
|
}
|
|
30313
30289
|
if (!this.surfaceShader) {
|