@niivue/niivue 0.26.3 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/niivue.es.js +2378 -711
- package/dist/niivue.umd.js +283 -288
- package/package.json +3 -3
- package/src/colortables.js +1 -1
- package/src/index.html +18 -59
- package/src/meshes.html +25 -51
- package/src/niivue.js +1611 -709
- package/src/nvimage.js +200 -103
- package/src/nvmesh.js +328 -99
- package/src/nvmessage.js +86 -0
- package/src/orientCube.js +64 -0
- package/src/shader-srcs.js +269 -271
- package/src/indexDraw.html +0 -198
- package/src/indexMM.html +0 -229
- package/src/indexModulate.html +0 -223
- package/src/niivue-shader3D.js +0 -17
package/dist/niivue.es.js
CHANGED
|
@@ -364,6 +364,26 @@ function translate(out, a, v) {
|
|
|
364
364
|
}
|
|
365
365
|
return out;
|
|
366
366
|
}
|
|
367
|
+
function scale$1(out, a, v) {
|
|
368
|
+
var x2 = v[0], y = v[1], z = v[2];
|
|
369
|
+
out[0] = a[0] * x2;
|
|
370
|
+
out[1] = a[1] * x2;
|
|
371
|
+
out[2] = a[2] * x2;
|
|
372
|
+
out[3] = a[3] * x2;
|
|
373
|
+
out[4] = a[4] * y;
|
|
374
|
+
out[5] = a[5] * y;
|
|
375
|
+
out[6] = a[6] * y;
|
|
376
|
+
out[7] = a[7] * y;
|
|
377
|
+
out[8] = a[8] * z;
|
|
378
|
+
out[9] = a[9] * z;
|
|
379
|
+
out[10] = a[10] * z;
|
|
380
|
+
out[11] = a[11] * z;
|
|
381
|
+
out[12] = a[12];
|
|
382
|
+
out[13] = a[13];
|
|
383
|
+
out[14] = a[14];
|
|
384
|
+
out[15] = a[15];
|
|
385
|
+
return out;
|
|
386
|
+
}
|
|
367
387
|
function rotateX(out, a, rad) {
|
|
368
388
|
var s = Math.sin(rad);
|
|
369
389
|
var c2 = Math.cos(rad);
|
|
@@ -747,6 +767,31 @@ vec4 applyClip (vec3 dir, inout vec4 samplePos, inout float len, inout bool isCl
|
|
|
747
767
|
samplePos = vec4(samplePos.xyz+dir * disBackFace, disBackFace);
|
|
748
768
|
}
|
|
749
769
|
return samplePos;
|
|
770
|
+
}
|
|
771
|
+
float frac2ndc(vec3 frac) {
|
|
772
|
+
//https://stackoverflow.com/questions/7777913/how-to-render-depth-linearly-in-modern-opengl-with-gl-fragcoord-z-in-fragment-sh
|
|
773
|
+
vec4 pos = vec4(frac.xyz, 1.0); //fraction
|
|
774
|
+
vec4 dim = vec4(vec3(textureSize(volume, 0)), 1.0);
|
|
775
|
+
pos = pos * dim;
|
|
776
|
+
vec4 shim = vec4(-0.5, -0.5, -0.5, 0.0);
|
|
777
|
+
pos += shim;
|
|
778
|
+
vec4 mm = transpose(matRAS) * pos;
|
|
779
|
+
float z_ndc = (mvpMtx * vec4(mm.xyz, 1.0)).z;
|
|
780
|
+
return (z_ndc + 1.0) / 2.0;
|
|
781
|
+
}
|
|
782
|
+
vec4 drawColor(float scalar) {
|
|
783
|
+
vec4 dcolor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
784
|
+
if (scalar <= 0.0) return dcolor;
|
|
785
|
+
dcolor.a = drawOpacity;
|
|
786
|
+
if (scalar >= (4.0/255.0))
|
|
787
|
+
dcolor.rgb = vec3(scalar,0.0,scalar);
|
|
788
|
+
else if (scalar >= (3.0/255.0))
|
|
789
|
+
dcolor.b = 1.0;
|
|
790
|
+
else if (scalar >= (2.0/255.0))
|
|
791
|
+
dcolor.g = 1.0;
|
|
792
|
+
else
|
|
793
|
+
dcolor.r = 1.0;
|
|
794
|
+
return dcolor;
|
|
750
795
|
}`;
|
|
751
796
|
var fragRenderShader = `#version 300 es
|
|
752
797
|
#line 14
|
|
@@ -763,26 +808,15 @@ uniform float backOpacity;
|
|
|
763
808
|
uniform mat4 mvpMtx;
|
|
764
809
|
uniform mat4 matRAS;
|
|
765
810
|
uniform vec4 clipPlaneColor;
|
|
811
|
+
uniform float drawOpacity;
|
|
812
|
+
uniform highp sampler3D drawing;
|
|
766
813
|
in vec3 vColor;
|
|
767
814
|
out vec4 fColor;
|
|
768
|
-
` + kRenderFunc + `
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
pos = pos * dim;
|
|
774
|
-
vec4 shim = vec4(-0.5, -0.5, -0.5, 0.0);
|
|
775
|
-
pos += shim;
|
|
776
|
-
vec4 mm = transpose(matRAS) * pos;
|
|
777
|
-
float z_ndc = (mvpMtx * vec4(mm.xyz, 1.0)).z;
|
|
778
|
-
return (z_ndc + 1.0) / 2.0;
|
|
779
|
-
|
|
780
|
-
}
|
|
781
|
-
void main() {
|
|
782
|
-
if (fColor.x > 2.0) {
|
|
783
|
-
fColor = vec4(1.0, 0.0, 0.0, 0.5);
|
|
784
|
-
return;
|
|
785
|
-
}
|
|
815
|
+
` + kRenderFunc + `void main() {
|
|
816
|
+
if (fColor.x > 2.0) {
|
|
817
|
+
fColor = vec4(1.0, 0.0, 0.0, 0.5);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
786
820
|
fColor = vec4(0.0,0.0,0.0,0.0);
|
|
787
821
|
vec4 clipPlaneColorX = clipPlaneColor;
|
|
788
822
|
//if (clipPlaneColor.a < 0.0)
|
|
@@ -818,23 +852,20 @@ void main() {
|
|
|
818
852
|
vec4 deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
819
853
|
while (samplePos.a <= len) {
|
|
820
854
|
float val = texture(volume, samplePos.xyz).a;
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
}
|
|
855
|
+
if (val > 0.01)
|
|
856
|
+
break;
|
|
824
857
|
samplePos += deltaDirFast; //advance ray position
|
|
825
858
|
}
|
|
826
|
-
if ((samplePos.a >= len) && ((overlays < 1.0) || (backgroundMasksOverlays > 0)))
|
|
827
|
-
|
|
859
|
+
if ((samplePos.a >= len) && (((overlays < 1.0) && (drawOpacity <= 0.0) ) || (backgroundMasksOverlays > 0))) {
|
|
860
|
+
if (isClip)
|
|
828
861
|
fColor += clipPlaneColorX;
|
|
829
|
-
}
|
|
830
862
|
return;
|
|
831
863
|
}
|
|
832
864
|
fColor = vec4(1.0, 1.0, 1.0, 1.0);
|
|
833
865
|
//gl_FragDepth = frac2ndc(samplePos.xyz); //crude due to fast pass resolution
|
|
834
866
|
samplePos -= deltaDirFast;
|
|
835
|
-
|
|
867
|
+
if (samplePos.a < 0.0)
|
|
836
868
|
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
837
|
-
}
|
|
838
869
|
//end: fast pass
|
|
839
870
|
vec4 colAcc = vec4(0.0,0.0,0.0,0.0);
|
|
840
871
|
vec4 firstHit = vec4(0.0,0.0,0.0,2.0 * lenNoClip);
|
|
@@ -856,51 +887,52 @@ void main() {
|
|
|
856
887
|
break;
|
|
857
888
|
}
|
|
858
889
|
}
|
|
859
|
-
|
|
890
|
+
if (firstHit.a < len)
|
|
860
891
|
gl_FragDepth = frac2ndc(firstHit.xyz);
|
|
861
|
-
}
|
|
862
892
|
colAcc.a = (colAcc.a / earlyTermination) * backOpacity;
|
|
863
893
|
fColor = colAcc;
|
|
864
894
|
//if (isClip) //CR
|
|
865
895
|
if ((isColorPlaneInVolume) && (clipPos.a != samplePos.a) && (abs(firstHit.a - clipPos.a) < deltaDir.a))
|
|
866
896
|
fColor.rgb = mix(fColor.rgb, clipPlaneColorX.rgb, abs(clipPlaneColor.a));
|
|
867
897
|
//fColor.rgb = mix(fColor.rgb, clipPlaneColorX.rgb, clipPlaneColorX.a * 0.65);
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
}
|
|
898
|
+
if ((overlays < 1.0) && (drawOpacity <= 0.0))
|
|
899
|
+
return;
|
|
871
900
|
//overlay pass
|
|
872
901
|
len = lenNoClip;
|
|
873
902
|
samplePos = vec4(start.xyz, 0.0); //ray position
|
|
874
903
|
//start: OPTIONAL fast pass: rapid traversal until first hit
|
|
875
|
-
stepSizeFast = sliceSize * 1.
|
|
904
|
+
stepSizeFast = sliceSize * 1.0;
|
|
876
905
|
deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
877
906
|
while (samplePos.a <= len) {
|
|
878
907
|
float val = texture(overlay, samplePos.xyz).a;
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
908
|
+
if (drawOpacity > 0.0)
|
|
909
|
+
val = max(val, texture(drawing, samplePos.xyz).r);
|
|
910
|
+
if (val > 0.001)
|
|
911
|
+
break;
|
|
882
912
|
samplePos += deltaDirFast; //advance ray position
|
|
883
913
|
}
|
|
884
914
|
if (samplePos.a >= len) {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
return;
|
|
915
|
+
if (isClip && (fColor.a == 0.0))
|
|
916
|
+
fColor += clipPlaneColorX;
|
|
917
|
+
return;
|
|
889
918
|
}
|
|
890
919
|
samplePos -= deltaDirFast;
|
|
891
|
-
|
|
920
|
+
if (samplePos.a < 0.0)
|
|
892
921
|
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
893
|
-
}
|
|
894
922
|
//end: fast pass
|
|
895
923
|
float overFarthest = len;
|
|
896
924
|
colAcc = vec4(0.0, 0.0, 0.0, 0.0);
|
|
925
|
+
|
|
897
926
|
samplePos += deltaDir * ran; //jitter ray
|
|
898
927
|
vec4 overFirstHit = vec4(0.0,0.0,0.0,2.0 * len);
|
|
899
|
-
|
|
928
|
+
if (backgroundMasksOverlays > 0)
|
|
900
929
|
samplePos = firstHit;
|
|
901
|
-
}
|
|
902
930
|
while (samplePos.a <= len) {
|
|
903
931
|
vec4 colorSample = texture(overlay, samplePos.xyz);
|
|
932
|
+
if ((colorSample.a < 0.01) && (drawOpacity > 0.0)) {
|
|
933
|
+
float val = texture(drawing, samplePos.xyz).r;
|
|
934
|
+
colorSample = drawColor(val);
|
|
935
|
+
}
|
|
904
936
|
samplePos += deltaDir; //advance ray position
|
|
905
937
|
if (colorSample.a >= 0.01) {
|
|
906
938
|
if (overFirstHit.a > len)
|
|
@@ -913,19 +945,19 @@ void main() {
|
|
|
913
945
|
break;
|
|
914
946
|
}
|
|
915
947
|
}
|
|
916
|
-
if (samplePos.a >= len) {
|
|
917
|
-
|
|
948
|
+
//if (samplePos.a >= len) {
|
|
949
|
+
if (colAcc.a <= 0.0) {
|
|
950
|
+
if (isClip && (fColor.a == 0.0))
|
|
918
951
|
fColor += clipPlaneColorX;
|
|
919
|
-
}
|
|
920
952
|
return;
|
|
921
953
|
}
|
|
954
|
+
|
|
922
955
|
//if (overFirstHit.a < len)
|
|
923
956
|
gl_FragDepth = frac2ndc(overFirstHit.xyz);
|
|
924
957
|
float overMix = colAcc.a;
|
|
925
958
|
float overlayDepth = 0.3;
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
}
|
|
959
|
+
if (fColor.a <= 0.0)
|
|
960
|
+
overMix = 1.0;
|
|
929
961
|
else if (((overFarthest) > backNearest)) {
|
|
930
962
|
float dx = (overFarthest - backNearest)/1.73;
|
|
931
963
|
dx = fColor.a * pow(dx, overlayDepth);
|
|
@@ -1016,10 +1048,10 @@ void main(void) {
|
|
|
1016
1048
|
texPos = vec3(pos.x, pos.y, slice);
|
|
1017
1049
|
if (axCorSag > 1)
|
|
1018
1050
|
texPos = vec3(slice, pos.x, pos.y);
|
|
1019
|
-
|
|
1051
|
+
else if (axCorSag > 0)
|
|
1020
1052
|
texPos = vec3(pos.x, slice, pos.y);
|
|
1021
1053
|
vec4 mm = frac2mm * vec4(texPos, 1.0);
|
|
1022
|
-
//vec4 mm =
|
|
1054
|
+
//vec4 mm = vec4(texPos, 1.0) * frac2mm;
|
|
1023
1055
|
gl_Position = mvpMtx * mm;
|
|
1024
1056
|
//gl_Position = mm;
|
|
1025
1057
|
}`;
|
|
@@ -1102,45 +1134,6 @@ void main() {
|
|
|
1102
1134
|
float fmap = (0.5 + layer) / nlayer;
|
|
1103
1135
|
color = vec4(texture(colormap, vec2(vColor.x, fmap)).rgb, 1.0);
|
|
1104
1136
|
}`;
|
|
1105
|
-
var vertGraphShader = `#version 300 es
|
|
1106
|
-
#line 229
|
|
1107
|
-
layout(location=0) in vec3 pos;
|
|
1108
|
-
uniform float thickness;
|
|
1109
|
-
uniform vec2 canvasWidthHeight;
|
|
1110
|
-
uniform vec4 leftTopRightBottom;
|
|
1111
|
-
void main(void) {
|
|
1112
|
-
//convert pixel x,y space 1..canvasWidth,1..canvasHeight to WebGL 1..-1,-1..1
|
|
1113
|
-
float ny = (leftTopRightBottom.x-leftTopRightBottom.z);
|
|
1114
|
-
float nx = (leftTopRightBottom.y-leftTopRightBottom.w);
|
|
1115
|
-
float len = sqrt((nx*nx)+(ny*ny));
|
|
1116
|
-
if (len > 0.0) {
|
|
1117
|
-
nx = 0.5*thickness*nx/len;
|
|
1118
|
-
ny = 0.5*thickness*ny/len;
|
|
1119
|
-
}
|
|
1120
|
-
vec2 frac;
|
|
1121
|
-
if (pos.y < 0.5)
|
|
1122
|
-
frac.y = leftTopRightBottom.y;
|
|
1123
|
-
else
|
|
1124
|
-
frac.y = leftTopRightBottom.w;
|
|
1125
|
-
if (pos.x < 0.5) {
|
|
1126
|
-
frac.x = leftTopRightBottom.x;
|
|
1127
|
-
frac.y = leftTopRightBottom.y;
|
|
1128
|
-
} else {
|
|
1129
|
-
frac.x = leftTopRightBottom.z;
|
|
1130
|
-
frac.y = leftTopRightBottom.w;
|
|
1131
|
-
}
|
|
1132
|
-
if (pos.y < 0.5) {
|
|
1133
|
-
frac.x += nx;
|
|
1134
|
-
frac.y -= ny;
|
|
1135
|
-
} else {
|
|
1136
|
-
frac.x -= nx;
|
|
1137
|
-
frac.y += ny;
|
|
1138
|
-
}
|
|
1139
|
-
frac.x /= canvasWidthHeight.x;
|
|
1140
|
-
frac.y = 1.0 - (frac.y / canvasWidthHeight.y);
|
|
1141
|
-
frac = (frac * 2.0) - 1.0;
|
|
1142
|
-
gl_Position = vec4(frac, 0.0, 1.0);
|
|
1143
|
-
}`;
|
|
1144
1137
|
var vertRectShader = `#version 300 es
|
|
1145
1138
|
#line 229
|
|
1146
1139
|
layout(location=0) in vec3 pos;
|
|
@@ -1219,13 +1212,13 @@ uniform float screenPxRange;
|
|
|
1219
1212
|
in vec2 vUV;
|
|
1220
1213
|
out vec4 color;
|
|
1221
1214
|
float median(float r, float g, float b) {
|
|
1222
|
-
|
|
1215
|
+
return max(min(r, g), min(max(r, g), b));
|
|
1223
1216
|
}
|
|
1224
1217
|
void main() {
|
|
1225
1218
|
vec3 msd = texture(fontTexture, vUV).rgb;
|
|
1226
1219
|
float sd = median(msd.r, msd.g, msd.b);
|
|
1227
|
-
|
|
1228
|
-
|
|
1220
|
+
float screenPxDistance = screenPxRange*(sd - 0.5);
|
|
1221
|
+
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
|
|
1229
1222
|
color = vec4(fontColor.rgb , fontColor.a * opacity);
|
|
1230
1223
|
}`;
|
|
1231
1224
|
var vertOrientShader = `#version 300 es
|
|
@@ -1235,8 +1228,8 @@ precision highp float;
|
|
|
1235
1228
|
in vec3 vPos;
|
|
1236
1229
|
out vec2 TexCoord;
|
|
1237
1230
|
void main() {
|
|
1238
|
-
|
|
1239
|
-
|
|
1231
|
+
TexCoord = vPos.xy;
|
|
1232
|
+
gl_Position = vec4( (vPos.xy-vec2(0.5,0.5)) * 2.0, 0.0, 1.0);
|
|
1240
1233
|
}`;
|
|
1241
1234
|
var fragOrientShaderU = `#version 300 es
|
|
1242
1235
|
uniform highp usampler3D intensityVol;
|
|
@@ -1261,42 +1254,45 @@ uniform float opacity;
|
|
|
1261
1254
|
uniform vec3 xyzFrac;
|
|
1262
1255
|
uniform mat4 mtx;
|
|
1263
1256
|
void main(void) {
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
FragColor.a
|
|
1257
|
+
vec4 vx = vec4(TexCoord.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
1258
|
+
uint idx = texture(intensityVol, vx.xyz).r;
|
|
1259
|
+
FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
1260
|
+
if (idx == uint(0))
|
|
1261
|
+
return;
|
|
1262
|
+
if (xyzFrac.x > 0.0) { //outline
|
|
1263
|
+
vx = vec4(TexCoord.x+xyzFrac.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
1264
|
+
uint R = texture(intensityVol, vx.xyz).r;
|
|
1265
|
+
vx = vec4(TexCoord.x-xyzFrac.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
1266
|
+
uint L = texture(intensityVol, vx.xyz).r;
|
|
1267
|
+
vx = vec4(TexCoord.x, TexCoord.y+xyzFrac.y, coordZ, 1.0) * mtx;
|
|
1268
|
+
uint A = texture(intensityVol, vx.xyz).r;
|
|
1269
|
+
vx = vec4(TexCoord.x, TexCoord.y-xyzFrac.y, coordZ, 1.0) * mtx;
|
|
1270
|
+
uint P = texture(intensityVol, vx.xyz).r;
|
|
1271
|
+
vx = vec4(TexCoord.x, TexCoord.y, coordZ+xyzFrac.z, 1.0) * mtx;
|
|
1272
|
+
uint S = texture(intensityVol, vx.xyz).r;
|
|
1273
|
+
vx = vec4(TexCoord.x, TexCoord.y, coordZ-xyzFrac.z, 1.0) * mtx;
|
|
1274
|
+
uint I = texture(intensityVol, vx.xyz).r;
|
|
1275
|
+
if ((idx == R) && (idx == L) && (idx == A) && (idx == P) && (idx == S) && (idx == I))
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
idx = ((idx - uint(1)) % uint(100))+uint(1);
|
|
1279
|
+
float fx = (float(idx)+0.5) / 256.0;
|
|
1280
|
+
float nlayer = float(textureSize(colormap, 0).y) * 0.5; //0.5 as both each layer has positive and negative color slot
|
|
1281
|
+
float y = (2.0 * layer + 1.0)/(4.0 * nlayer);
|
|
1282
|
+
//float y = (2.0 * layer + 1.0)/(4.0 * numLayers);
|
|
1283
|
+
FragColor = texture(colormap, vec2(fx, y)).rgba;
|
|
1284
|
+
//FragColor.a *= opacity;
|
|
1285
|
+
FragColor.a = opacity;
|
|
1286
|
+
return;
|
|
1287
|
+
|
|
1288
|
+
if (layer < 2.0) return;
|
|
1289
|
+
vec2 texXY = TexCoord.xy*0.5 +vec2(0.5,0.5);
|
|
1290
|
+
vec4 prevColor = texture(blend3D, vec3(texXY, coordZ));
|
|
1291
|
+
// https://en.wikipedia.org/wiki/Alpha_compositing
|
|
1292
|
+
float aout = FragColor.a + (1.0 - FragColor.a) * prevColor.a;
|
|
1293
|
+
if (aout <= 0.0) return;
|
|
1294
|
+
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a * (1.0 - FragColor.a))) / aout;
|
|
1295
|
+
FragColor.a = aout;
|
|
1300
1296
|
}`;
|
|
1301
1297
|
var fragOrientShader = `#line 309
|
|
1302
1298
|
precision highp int;
|
|
@@ -1317,40 +1313,40 @@ uniform highp sampler3D modulationVol;
|
|
|
1317
1313
|
uniform float opacity;
|
|
1318
1314
|
uniform mat4 mtx;
|
|
1319
1315
|
void main(void) {
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1316
|
+
vec4 vx = vec4(TexCoord.xy, coordZ, 1.0) * mtx;
|
|
1317
|
+
float f = (scl_slope * float(texture(intensityVol, vx.xyz).r)) + scl_inter;
|
|
1318
|
+
bool isNegative = (f < 0.0);
|
|
1319
|
+
float r = max(0.00001, abs(cal_max - cal_min));
|
|
1320
|
+
float mn = min(cal_min, cal_max);
|
|
1321
|
+
float txl = mix(0.0, 1.0, (f - mn) / r);
|
|
1322
|
+
//https://stackoverflow.com/questions/5879403/opengl-texture-coordinates-in-pixel-space
|
|
1323
|
+
float nlayer = float(textureSize(colormap, 0).y) * 0.5; //0.5 as both each layer has positive and negative color slot
|
|
1324
|
+
float y = (2.0 * layer + 1.0)/(4.0 * nlayer);
|
|
1325
|
+
FragColor = texture(colormap, vec2(txl, y)).rgba;
|
|
1326
|
+
if (isNegative) {
|
|
1327
|
+
y = (2.0 * layer + nlayer + nlayer + 1.0)/(4.0 * nlayer);
|
|
1328
|
+
//select texels at positions 0 and 1 of lookup table:
|
|
1329
|
+
vec4 v0 = texture(colormap, vec2(0.5/256.0, y));
|
|
1330
|
+
vec4 v1 = texture(colormap, vec2(1.5/256.0, y));
|
|
1331
|
+
txl = mix(0.0, 1.0, (- f - mn) / r);
|
|
1332
|
+
//detect bogus color: negative color slot not used than
|
|
1333
|
+
// v0 = 1,1,1,0 and v1 = 0,0,0,1
|
|
1334
|
+
if ((v0.r != 1.0) || (v0.a != 0.0) || (v1.r != 0.0) || (v1.a != 1.0))
|
|
1335
|
+
FragColor = texture(colormap, vec2(txl, y));
|
|
1336
|
+
}
|
|
1337
|
+
if (layer > 0.7)
|
|
1338
|
+
FragColor.a = step(0.00001, FragColor.a);
|
|
1339
|
+
if (modulation > 0)
|
|
1340
|
+
FragColor.rgb *= texture(modulationVol, vx.xyz).r;
|
|
1341
|
+
FragColor.a *= opacity;
|
|
1342
|
+
if (layer < 1.0) return;
|
|
1343
|
+
vec2 texXY = TexCoord.xy*0.5 +vec2(0.5,0.5);
|
|
1344
|
+
vec4 prevColor = texture(blend3D, vec3(texXY, coordZ));
|
|
1345
|
+
// https://en.wikipedia.org/wiki/Alpha_compositing
|
|
1346
|
+
float aout = FragColor.a + (1.0 - FragColor.a) * prevColor.a;
|
|
1347
|
+
if (aout <= 0.0) return;
|
|
1348
|
+
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a * (1.0 - FragColor.a))) / aout;
|
|
1349
|
+
FragColor.a = aout;
|
|
1354
1350
|
}`;
|
|
1355
1351
|
var fragRGBOrientShader = `#line 309
|
|
1356
1352
|
precision highp int;
|
|
@@ -1372,14 +1368,14 @@ uniform bool hasAlpha;
|
|
|
1372
1368
|
uniform int modulation;
|
|
1373
1369
|
uniform highp sampler3D modulationVol;
|
|
1374
1370
|
void main(void) {
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1371
|
+
vec4 vx = vec4(TexCoord.xy, coordZ, 1.0) * mtx;
|
|
1372
|
+
uvec4 aColor = texture(intensityVol, vx.xyz);
|
|
1373
|
+
FragColor = vec4(float(aColor.r) / 255.0, float(aColor.g) / 255.0, float(aColor.b) / 255.0, float(aColor.a) / 255.0);
|
|
1374
|
+
if (modulation > 0)
|
|
1375
|
+
FragColor.rgb *= texture(modulationVol, vx.xyz).r;
|
|
1376
|
+
if (!hasAlpha)
|
|
1377
|
+
FragColor.a = (FragColor.r * 0.21 + FragColor.g * 0.72 + FragColor.b * 0.07);
|
|
1378
|
+
FragColor.a *= opacity;
|
|
1383
1379
|
}`;
|
|
1384
1380
|
var vertPassThroughShader = `#version 300 es
|
|
1385
1381
|
#line 283
|
|
@@ -1388,8 +1384,8 @@ precision highp float;
|
|
|
1388
1384
|
in vec3 vPos;
|
|
1389
1385
|
out vec2 TexCoord;
|
|
1390
1386
|
void main() {
|
|
1391
|
-
|
|
1392
|
-
|
|
1387
|
+
TexCoord = vPos.xy;
|
|
1388
|
+
gl_Position = vec4(vPos.x, vPos.y, 0.0, 1.0);
|
|
1393
1389
|
}`;
|
|
1394
1390
|
var fragPassThroughShader = `#version 300 es
|
|
1395
1391
|
precision highp int;
|
|
@@ -1408,70 +1404,70 @@ precision highp float;
|
|
|
1408
1404
|
in vec3 vPos;
|
|
1409
1405
|
out vec2 TexCoord;
|
|
1410
1406
|
void main() {
|
|
1411
|
-
|
|
1412
|
-
|
|
1407
|
+
TexCoord = vPos.xy;
|
|
1408
|
+
gl_Position = vec4((vPos.x - 0.5) * 2.0, (vPos.y - 0.5) * 2.0, 0.0, 1.0);
|
|
1413
1409
|
}`;
|
|
1414
1410
|
var fragGrowCutShader = `#version 300 es
|
|
1415
1411
|
#line 742
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1412
|
+
precision highp float;
|
|
1413
|
+
precision highp int;
|
|
1414
|
+
precision highp isampler3D;
|
|
1415
|
+
layout(location = 0) out int label;
|
|
1416
|
+
layout(location = 1) out int strength;
|
|
1417
|
+
in vec2 TexCoord;
|
|
1418
|
+
uniform int finalPass;
|
|
1419
|
+
uniform float coordZ;
|
|
1420
|
+
uniform lowp sampler3D in3D;
|
|
1421
|
+
uniform highp isampler3D inputTexture0; // background
|
|
1422
|
+
uniform highp isampler3D inputTexture1; // label
|
|
1423
|
+
uniform highp isampler3D inputTexture2; // strength
|
|
1428
1424
|
void main(void) {
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1425
|
+
vec3 interpolatedTextureCoordinate = vec3(TexCoord.xy, coordZ);
|
|
1426
|
+
ivec3 size = textureSize(inputTexture0, 0);
|
|
1427
|
+
ivec3 texelIndex = ivec3(floor(interpolatedTextureCoordinate * vec3(size)));
|
|
1428
|
+
int background = texelFetch(inputTexture0, texelIndex, 0).r;
|
|
1429
|
+
label = texelFetch(inputTexture1, texelIndex, 0).r;
|
|
1430
|
+
strength = texelFetch(inputTexture2, texelIndex, 0).r;
|
|
1431
|
+
for (int k = -1; k <= 1; k++) {
|
|
1432
|
+
for (int j = -1; j <= 1; j++) {
|
|
1433
|
+
for (int i = -1; i <= 1; i++) {
|
|
1434
|
+
if (i != 0 && j != 0 && k != 0) {
|
|
1435
|
+
ivec3 neighborIndex = texelIndex + ivec3(i,j,k);
|
|
1436
|
+
int neighborBackground = texelFetch(inputTexture0, neighborIndex, 0).r;
|
|
1437
|
+
int neighborStrength = texelFetch(inputTexture2, neighborIndex, 0).r;
|
|
1438
|
+
int strengthCost = abs(neighborBackground - background);
|
|
1439
|
+
int takeoverStrength = neighborStrength - strengthCost;
|
|
1440
|
+
if (takeoverStrength > strength) {
|
|
1441
|
+
strength = takeoverStrength;
|
|
1442
|
+
label = texelFetch(inputTexture1, neighborIndex, 0).r;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
if (finalPass < 1)
|
|
1449
|
+
return;
|
|
1450
|
+
int ok = 1;
|
|
1451
|
+
ivec4 labelCount = ivec4(0,0,0,0);
|
|
1452
|
+
for (int k = -1; k <= 1; k++)
|
|
1453
|
+
for (int j = -1; j <= 1; j++)
|
|
1454
|
+
for (int i = -1; i <= 1; i++) {
|
|
1455
|
+
ivec3 neighborIndex = texelIndex + ivec3(i,j,k);
|
|
1456
|
+
int ilabel = texelFetch(inputTexture1, neighborIndex, 0).r;
|
|
1457
|
+
if ((ilabel < 0) || (ilabel > 3))
|
|
1458
|
+
ok = 0;
|
|
1459
|
+
else
|
|
1460
|
+
labelCount[ilabel]++;
|
|
1461
|
+
}
|
|
1462
|
+
if (ok != 1) {
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
int maxIdx = 0;
|
|
1466
|
+
for (int i = 1; i < 4; i++) {
|
|
1467
|
+
if (labelCount[i] > labelCount[maxIdx])
|
|
1468
|
+
maxIdx = i;
|
|
1469
|
+
}
|
|
1470
|
+
label = maxIdx;
|
|
1475
1471
|
}`;
|
|
1476
1472
|
var vertSurfaceShader = `#version 300 es
|
|
1477
1473
|
layout(location=0) in vec3 pos;
|
|
@@ -1529,7 +1525,6 @@ precision highp float;
|
|
|
1529
1525
|
uniform float opacity;
|
|
1530
1526
|
out vec4 color;
|
|
1531
1527
|
vec4 packFloatToVec4i(const float value) {
|
|
1532
|
-
//this Papaya function uses BSD 3-clause license Copyright (c) 2012-2015, RII-UTHSCSA
|
|
1533
1528
|
const vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
|
|
1534
1529
|
const vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
|
|
1535
1530
|
vec4 res = fract(value * bitSh);
|
|
@@ -1560,7 +1555,7 @@ void main() {
|
|
|
1560
1555
|
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
1561
1556
|
vec3 l = normalize(lightPosition);
|
|
1562
1557
|
float df = max(0.0, dot(n, l));
|
|
1563
|
-
float sf =
|
|
1558
|
+
float sf = pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1564
1559
|
const float A = 0.1;
|
|
1565
1560
|
const float B = 0.3;
|
|
1566
1561
|
const float C = 0.6;
|
|
@@ -1602,11 +1597,10 @@ void main() {
|
|
|
1602
1597
|
vec3 l = normalize(lightPosition);
|
|
1603
1598
|
float lightNormDot = dot(n, l);
|
|
1604
1599
|
float view = abs(dot(n,r)); //with respect to viewer
|
|
1605
|
-
|
|
1606
1600
|
if (PenWidth < view) discard;
|
|
1607
1601
|
vec3 a = vClr.rgb * ambient;
|
|
1608
1602
|
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1609
|
-
float s =
|
|
1603
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1610
1604
|
color.rgb = a + d + s;
|
|
1611
1605
|
color.a = opacity;
|
|
1612
1606
|
}`;
|
|
@@ -1629,7 +1623,7 @@ void main() {
|
|
|
1629
1623
|
float lightNormDot = dot(n, l);
|
|
1630
1624
|
vec3 a = vClr.rgb * ambient;
|
|
1631
1625
|
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1632
|
-
float s =
|
|
1626
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1633
1627
|
color = vec4(a + d + s, opacity);
|
|
1634
1628
|
}`;
|
|
1635
1629
|
var fragMeshMatteShader = `#version 300 es
|
|
@@ -1640,7 +1634,6 @@ in vec4 vClr;
|
|
|
1640
1634
|
in vec3 vN, vL, vV;
|
|
1641
1635
|
out vec4 color;
|
|
1642
1636
|
void main() {
|
|
1643
|
-
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
1644
1637
|
float ambient = 0.35;
|
|
1645
1638
|
float diffuse = 0.6;
|
|
1646
1639
|
vec3 n = normalize(vN);
|
|
@@ -1675,7 +1668,7 @@ void main() {
|
|
|
1675
1668
|
vec3 a = vClr.rgb * ambient;
|
|
1676
1669
|
a *= mix(downClr, upClr, ax);
|
|
1677
1670
|
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1678
|
-
float s =
|
|
1671
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1679
1672
|
color = vec4(a + d + s, opacity);
|
|
1680
1673
|
}`;
|
|
1681
1674
|
var fragMeshShaderSHBlue = `#version 300 es
|
|
@@ -1707,8 +1700,7 @@ const vec3 L21 = vec3(-0.0572703, -0.0502192, -0.0363410);
|
|
|
1707
1700
|
const vec3 L22 = vec3( 0.0203348, -0.0044201, -0.0452180);
|
|
1708
1701
|
vec3 SH(vec3 vNormal) {
|
|
1709
1702
|
vNormal = vec3(vNormal.x,vNormal.z,vNormal.y);
|
|
1710
|
-
|
|
1711
|
-
vec3 diffuseColor = C1 * L22 * (vNormal.x * vNormal.x - vNormal.y * vNormal.y) +
|
|
1703
|
+
vec3 diffuseColor = C1 * L22 * (vNormal.x * vNormal.x - vNormal.y * vNormal.y) +
|
|
1712
1704
|
C3 * L20 * vNormal.z * vNormal.z +
|
|
1713
1705
|
C4 * L00 -
|
|
1714
1706
|
C5 * L20 +
|
|
@@ -1729,20 +1721,11 @@ void main() {
|
|
|
1729
1721
|
vec3 n = normalize(vN);
|
|
1730
1722
|
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
1731
1723
|
vec3 l = normalize(lightPosition);
|
|
1732
|
-
float s =
|
|
1724
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1733
1725
|
vec3 a = vClr.rgb * ambient;
|
|
1734
1726
|
vec3 d = vClr.rgb * diffuse * SH(-reflect(n, vec3(l.x, l.y, -l.z)) );
|
|
1735
1727
|
color = vec4(a + d + s, opacity);
|
|
1736
1728
|
}`;
|
|
1737
|
-
var fragDepthPickingShader = `#version 300 es
|
|
1738
|
-
precision highp int;
|
|
1739
|
-
precision highp float;
|
|
1740
|
-
uniform int id;
|
|
1741
|
-
in vec3 vColor;
|
|
1742
|
-
out vec4 color;
|
|
1743
|
-
void main() {
|
|
1744
|
-
color = vec4(vColor, float(id & 255) / 255.0);
|
|
1745
|
-
}`;
|
|
1746
1729
|
var fragVolumePickingShader = `#version 300 es
|
|
1747
1730
|
#line 506
|
|
1748
1731
|
//precision highp int;
|
|
@@ -1753,12 +1736,17 @@ uniform vec3 texVox;
|
|
|
1753
1736
|
uniform vec4 clipPlane;
|
|
1754
1737
|
uniform highp sampler3D volume, overlay;
|
|
1755
1738
|
uniform float overlays;
|
|
1756
|
-
uniform
|
|
1739
|
+
uniform mat4 matRAS;
|
|
1740
|
+
uniform mat4 mvpMtx;
|
|
1741
|
+
uniform float drawOpacity;
|
|
1742
|
+
uniform highp sampler3D drawing;
|
|
1757
1743
|
in vec3 vColor;
|
|
1758
1744
|
out vec4 fColor;
|
|
1759
1745
|
` + kRenderFunc + `
|
|
1760
1746
|
void main() {
|
|
1747
|
+
int id = 254;
|
|
1761
1748
|
vec3 start = vColor;
|
|
1749
|
+
gl_FragDepth = 0.0;
|
|
1762
1750
|
fColor = vec4(0.0, 0.0, 0.0, 0.0); //assume no hit: ID = 0
|
|
1763
1751
|
float fid = float(id & 255)/ 255.0;
|
|
1764
1752
|
vec3 backPosition = GetBackPosition(start);
|
|
@@ -1782,6 +1770,7 @@ void main() {
|
|
|
1782
1770
|
float val = texture(volume, samplePos.xyz).a;
|
|
1783
1771
|
if (val > 0.01) {
|
|
1784
1772
|
fColor = vec4(samplePos.rgb, fid);
|
|
1773
|
+
gl_FragDepth = frac2ndc(samplePos.xyz);
|
|
1785
1774
|
break;
|
|
1786
1775
|
}
|
|
1787
1776
|
samplePos += deltaDirFast; //advance ray position
|
|
@@ -1798,6 +1787,7 @@ void main() {
|
|
|
1798
1787
|
float val = texture(overlay, samplePos.xyz).a;
|
|
1799
1788
|
if (val > 0.01) {
|
|
1800
1789
|
fColor = vec4(samplePos.rgb, fid);
|
|
1790
|
+
gl_FragDepth = frac2ndc(samplePos.xyz);
|
|
1801
1791
|
return;
|
|
1802
1792
|
}
|
|
1803
1793
|
samplePos += deltaDirFast; //advance ray position
|
|
@@ -1805,6 +1795,31 @@ void main() {
|
|
|
1805
1795
|
//if (fColor.a == 0.0) discard; //no hit in either background or overlays
|
|
1806
1796
|
//you only get here if there is a hit with the background that is closer than any overlay
|
|
1807
1797
|
}`;
|
|
1798
|
+
var vertOrientCubeShader = `#version 300 es
|
|
1799
|
+
// an attribute is an input (in) to a vertex shader.
|
|
1800
|
+
// It will receive data from a buffer
|
|
1801
|
+
layout(location=0) in vec3 a_position;
|
|
1802
|
+
layout(location=1) in vec3 a_color;
|
|
1803
|
+
// A matrix to transform the positions by
|
|
1804
|
+
uniform mat4 u_matrix;
|
|
1805
|
+
out vec3 vColor;
|
|
1806
|
+
// all shaders have a main function
|
|
1807
|
+
void main() {
|
|
1808
|
+
// Multiply the position by the matrix.
|
|
1809
|
+
vec4 pos = vec4(a_position, 1.0);
|
|
1810
|
+
gl_Position = u_matrix * vec4(pos);
|
|
1811
|
+
vColor = a_color;
|
|
1812
|
+
}
|
|
1813
|
+
`;
|
|
1814
|
+
var fragOrientCubeShader = `#version 300 es
|
|
1815
|
+
precision highp float;
|
|
1816
|
+
uniform vec4 u_color;
|
|
1817
|
+
in vec3 vColor;
|
|
1818
|
+
// we need to declare an output for the fragment shader
|
|
1819
|
+
out vec4 outColor;
|
|
1820
|
+
void main() {
|
|
1821
|
+
outColor = vec4(vColor, 1.0);
|
|
1822
|
+
}`;
|
|
1808
1823
|
/*! *****************************************************************************
|
|
1809
1824
|
Copyright (c) Microsoft Corporation.
|
|
1810
1825
|
|
|
@@ -2844,6 +2859,1016 @@ function interval(period, scheduler) {
|
|
|
2844
2859
|
}
|
|
2845
2860
|
return timer(period, period, scheduler);
|
|
2846
2861
|
}
|
|
2862
|
+
const orientCube = new Float32Array([
|
|
2863
|
+
-1,
|
|
2864
|
+
-1,
|
|
2865
|
+
-1,
|
|
2866
|
+
0.28,
|
|
2867
|
+
0.28,
|
|
2868
|
+
0.28,
|
|
2869
|
+
-1,
|
|
2870
|
+
-1,
|
|
2871
|
+
-1,
|
|
2872
|
+
0.28,
|
|
2873
|
+
0.28,
|
|
2874
|
+
0.28,
|
|
2875
|
+
-1,
|
|
2876
|
+
1,
|
|
2877
|
+
-1,
|
|
2878
|
+
0.28,
|
|
2879
|
+
0.28,
|
|
2880
|
+
0.28,
|
|
2881
|
+
1,
|
|
2882
|
+
-1,
|
|
2883
|
+
-1,
|
|
2884
|
+
0.28,
|
|
2885
|
+
0.28,
|
|
2886
|
+
0.28,
|
|
2887
|
+
1,
|
|
2888
|
+
1,
|
|
2889
|
+
-1,
|
|
2890
|
+
0.28,
|
|
2891
|
+
0.28,
|
|
2892
|
+
0.28,
|
|
2893
|
+
1,
|
|
2894
|
+
1,
|
|
2895
|
+
-1,
|
|
2896
|
+
0.28,
|
|
2897
|
+
0.28,
|
|
2898
|
+
0.28,
|
|
2899
|
+
-1,
|
|
2900
|
+
-1,
|
|
2901
|
+
1,
|
|
2902
|
+
0.8,
|
|
2903
|
+
0.8,
|
|
2904
|
+
0.8,
|
|
2905
|
+
-1,
|
|
2906
|
+
-1,
|
|
2907
|
+
1,
|
|
2908
|
+
0.8,
|
|
2909
|
+
0.8,
|
|
2910
|
+
0.8,
|
|
2911
|
+
1,
|
|
2912
|
+
-1,
|
|
2913
|
+
1,
|
|
2914
|
+
0.8,
|
|
2915
|
+
0.8,
|
|
2916
|
+
0.8,
|
|
2917
|
+
-1,
|
|
2918
|
+
1,
|
|
2919
|
+
1,
|
|
2920
|
+
0.8,
|
|
2921
|
+
0.8,
|
|
2922
|
+
0.8,
|
|
2923
|
+
1,
|
|
2924
|
+
1,
|
|
2925
|
+
1,
|
|
2926
|
+
0.8,
|
|
2927
|
+
0.8,
|
|
2928
|
+
0.8,
|
|
2929
|
+
1,
|
|
2930
|
+
1,
|
|
2931
|
+
1,
|
|
2932
|
+
0.8,
|
|
2933
|
+
0.8,
|
|
2934
|
+
0.8,
|
|
2935
|
+
-1,
|
|
2936
|
+
1,
|
|
2937
|
+
-1,
|
|
2938
|
+
0,
|
|
2939
|
+
0,
|
|
2940
|
+
0.74,
|
|
2941
|
+
-1,
|
|
2942
|
+
1,
|
|
2943
|
+
-1,
|
|
2944
|
+
0,
|
|
2945
|
+
0,
|
|
2946
|
+
0.74,
|
|
2947
|
+
-1,
|
|
2948
|
+
1,
|
|
2949
|
+
1,
|
|
2950
|
+
0,
|
|
2951
|
+
0,
|
|
2952
|
+
0.74,
|
|
2953
|
+
1,
|
|
2954
|
+
1,
|
|
2955
|
+
-1,
|
|
2956
|
+
0,
|
|
2957
|
+
0,
|
|
2958
|
+
0.74,
|
|
2959
|
+
1,
|
|
2960
|
+
1,
|
|
2961
|
+
1,
|
|
2962
|
+
0,
|
|
2963
|
+
0,
|
|
2964
|
+
0.74,
|
|
2965
|
+
1,
|
|
2966
|
+
1,
|
|
2967
|
+
1,
|
|
2968
|
+
0,
|
|
2969
|
+
0,
|
|
2970
|
+
0.74,
|
|
2971
|
+
-1,
|
|
2972
|
+
-1,
|
|
2973
|
+
-1,
|
|
2974
|
+
0.42,
|
|
2975
|
+
0,
|
|
2976
|
+
0.42,
|
|
2977
|
+
-1,
|
|
2978
|
+
-1,
|
|
2979
|
+
-1,
|
|
2980
|
+
0.42,
|
|
2981
|
+
0,
|
|
2982
|
+
0.42,
|
|
2983
|
+
1,
|
|
2984
|
+
-1,
|
|
2985
|
+
-1,
|
|
2986
|
+
0.42,
|
|
2987
|
+
0,
|
|
2988
|
+
0.42,
|
|
2989
|
+
-1,
|
|
2990
|
+
-1,
|
|
2991
|
+
1,
|
|
2992
|
+
0.42,
|
|
2993
|
+
0,
|
|
2994
|
+
0.42,
|
|
2995
|
+
1,
|
|
2996
|
+
-1,
|
|
2997
|
+
1,
|
|
2998
|
+
0.42,
|
|
2999
|
+
0,
|
|
3000
|
+
0.42,
|
|
3001
|
+
1,
|
|
3002
|
+
-1,
|
|
3003
|
+
1,
|
|
3004
|
+
0.42,
|
|
3005
|
+
0,
|
|
3006
|
+
0.42,
|
|
3007
|
+
-1,
|
|
3008
|
+
-1,
|
|
3009
|
+
-1,
|
|
3010
|
+
0.64,
|
|
3011
|
+
0,
|
|
3012
|
+
0,
|
|
3013
|
+
-1,
|
|
3014
|
+
-1,
|
|
3015
|
+
-1,
|
|
3016
|
+
0.64,
|
|
3017
|
+
0,
|
|
3018
|
+
0,
|
|
3019
|
+
-1,
|
|
3020
|
+
-1,
|
|
3021
|
+
1,
|
|
3022
|
+
0.64,
|
|
3023
|
+
0,
|
|
3024
|
+
0,
|
|
3025
|
+
-1,
|
|
3026
|
+
1,
|
|
3027
|
+
-1,
|
|
3028
|
+
0.64,
|
|
3029
|
+
0,
|
|
3030
|
+
0,
|
|
3031
|
+
-1,
|
|
3032
|
+
1,
|
|
3033
|
+
1,
|
|
3034
|
+
0.64,
|
|
3035
|
+
0,
|
|
3036
|
+
0,
|
|
3037
|
+
-1,
|
|
3038
|
+
1,
|
|
3039
|
+
1,
|
|
3040
|
+
0.64,
|
|
3041
|
+
0,
|
|
3042
|
+
0,
|
|
3043
|
+
1,
|
|
3044
|
+
-1,
|
|
3045
|
+
-1,
|
|
3046
|
+
0,
|
|
3047
|
+
0.5,
|
|
3048
|
+
0,
|
|
3049
|
+
1,
|
|
3050
|
+
-1,
|
|
3051
|
+
-1,
|
|
3052
|
+
0,
|
|
3053
|
+
0.5,
|
|
3054
|
+
0,
|
|
3055
|
+
1,
|
|
3056
|
+
1,
|
|
3057
|
+
-1,
|
|
3058
|
+
0,
|
|
3059
|
+
0.5,
|
|
3060
|
+
0,
|
|
3061
|
+
1,
|
|
3062
|
+
-1,
|
|
3063
|
+
1,
|
|
3064
|
+
0,
|
|
3065
|
+
0.5,
|
|
3066
|
+
0,
|
|
3067
|
+
1,
|
|
3068
|
+
1,
|
|
3069
|
+
1,
|
|
3070
|
+
0,
|
|
3071
|
+
0.5,
|
|
3072
|
+
0,
|
|
3073
|
+
1,
|
|
3074
|
+
1,
|
|
3075
|
+
1,
|
|
3076
|
+
0,
|
|
3077
|
+
0.5,
|
|
3078
|
+
0,
|
|
3079
|
+
-0.45,
|
|
3080
|
+
1,
|
|
3081
|
+
-0.8,
|
|
3082
|
+
0,
|
|
3083
|
+
0,
|
|
3084
|
+
0,
|
|
3085
|
+
-0.45,
|
|
3086
|
+
1,
|
|
3087
|
+
-0.8,
|
|
3088
|
+
0,
|
|
3089
|
+
0,
|
|
3090
|
+
0,
|
|
3091
|
+
-0.45,
|
|
3092
|
+
1,
|
|
3093
|
+
0.8,
|
|
3094
|
+
0,
|
|
3095
|
+
0,
|
|
3096
|
+
0,
|
|
3097
|
+
-0.25,
|
|
3098
|
+
1,
|
|
3099
|
+
-0.8,
|
|
3100
|
+
0,
|
|
3101
|
+
0,
|
|
3102
|
+
0,
|
|
3103
|
+
-0.25,
|
|
3104
|
+
1,
|
|
3105
|
+
0.8,
|
|
3106
|
+
0,
|
|
3107
|
+
0,
|
|
3108
|
+
0,
|
|
3109
|
+
-0.25,
|
|
3110
|
+
1,
|
|
3111
|
+
0.8,
|
|
3112
|
+
0,
|
|
3113
|
+
0,
|
|
3114
|
+
0,
|
|
3115
|
+
-0.25,
|
|
3116
|
+
1,
|
|
3117
|
+
0.6,
|
|
3118
|
+
0,
|
|
3119
|
+
0,
|
|
3120
|
+
0,
|
|
3121
|
+
-0.25,
|
|
3122
|
+
1,
|
|
3123
|
+
0.6,
|
|
3124
|
+
0,
|
|
3125
|
+
0,
|
|
3126
|
+
0,
|
|
3127
|
+
-0.25,
|
|
3128
|
+
1,
|
|
3129
|
+
0.8,
|
|
3130
|
+
0,
|
|
3131
|
+
0,
|
|
3132
|
+
0,
|
|
3133
|
+
0.45,
|
|
3134
|
+
1,
|
|
3135
|
+
0.6,
|
|
3136
|
+
0,
|
|
3137
|
+
0,
|
|
3138
|
+
0,
|
|
3139
|
+
0.25,
|
|
3140
|
+
1,
|
|
3141
|
+
0.8,
|
|
3142
|
+
0,
|
|
3143
|
+
0,
|
|
3144
|
+
0,
|
|
3145
|
+
0.25,
|
|
3146
|
+
1,
|
|
3147
|
+
0.8,
|
|
3148
|
+
0,
|
|
3149
|
+
0,
|
|
3150
|
+
0,
|
|
3151
|
+
0.25,
|
|
3152
|
+
1,
|
|
3153
|
+
0.1,
|
|
3154
|
+
0,
|
|
3155
|
+
0,
|
|
3156
|
+
0,
|
|
3157
|
+
0.25,
|
|
3158
|
+
1,
|
|
3159
|
+
0.1,
|
|
3160
|
+
0,
|
|
3161
|
+
0,
|
|
3162
|
+
0,
|
|
3163
|
+
0.25,
|
|
3164
|
+
1,
|
|
3165
|
+
0.6,
|
|
3166
|
+
0,
|
|
3167
|
+
0,
|
|
3168
|
+
0,
|
|
3169
|
+
0.45,
|
|
3170
|
+
1,
|
|
3171
|
+
0.1,
|
|
3172
|
+
0,
|
|
3173
|
+
0,
|
|
3174
|
+
0,
|
|
3175
|
+
0.45,
|
|
3176
|
+
1,
|
|
3177
|
+
0.6,
|
|
3178
|
+
0,
|
|
3179
|
+
0,
|
|
3180
|
+
0,
|
|
3181
|
+
0.45,
|
|
3182
|
+
1,
|
|
3183
|
+
0.6,
|
|
3184
|
+
0,
|
|
3185
|
+
0,
|
|
3186
|
+
0,
|
|
3187
|
+
-0.25,
|
|
3188
|
+
1,
|
|
3189
|
+
-0.1,
|
|
3190
|
+
0,
|
|
3191
|
+
0,
|
|
3192
|
+
0,
|
|
3193
|
+
-0.25,
|
|
3194
|
+
1,
|
|
3195
|
+
-0.1,
|
|
3196
|
+
0,
|
|
3197
|
+
0,
|
|
3198
|
+
0,
|
|
3199
|
+
-0.25,
|
|
3200
|
+
1,
|
|
3201
|
+
0.1,
|
|
3202
|
+
0,
|
|
3203
|
+
0,
|
|
3204
|
+
0,
|
|
3205
|
+
0.25,
|
|
3206
|
+
1,
|
|
3207
|
+
-0.1,
|
|
3208
|
+
0,
|
|
3209
|
+
0,
|
|
3210
|
+
0,
|
|
3211
|
+
0.45,
|
|
3212
|
+
1,
|
|
3213
|
+
0.1,
|
|
3214
|
+
0,
|
|
3215
|
+
0,
|
|
3216
|
+
0,
|
|
3217
|
+
0.45,
|
|
3218
|
+
1,
|
|
3219
|
+
0.1,
|
|
3220
|
+
0,
|
|
3221
|
+
0,
|
|
3222
|
+
0,
|
|
3223
|
+
0.45,
|
|
3224
|
+
-1,
|
|
3225
|
+
-0.8,
|
|
3226
|
+
0,
|
|
3227
|
+
0,
|
|
3228
|
+
0,
|
|
3229
|
+
0.45,
|
|
3230
|
+
-1,
|
|
3231
|
+
-0.8,
|
|
3232
|
+
0,
|
|
3233
|
+
0,
|
|
3234
|
+
0,
|
|
3235
|
+
0.05,
|
|
3236
|
+
-1,
|
|
3237
|
+
0.8,
|
|
3238
|
+
0,
|
|
3239
|
+
0,
|
|
3240
|
+
0,
|
|
3241
|
+
0.25,
|
|
3242
|
+
-1,
|
|
3243
|
+
-0.8,
|
|
3244
|
+
0,
|
|
3245
|
+
0,
|
|
3246
|
+
0,
|
|
3247
|
+
-0.15,
|
|
3248
|
+
-1,
|
|
3249
|
+
0.8,
|
|
3250
|
+
0,
|
|
3251
|
+
0,
|
|
3252
|
+
0,
|
|
3253
|
+
-0.15,
|
|
3254
|
+
-1,
|
|
3255
|
+
0.8,
|
|
3256
|
+
0,
|
|
3257
|
+
0,
|
|
3258
|
+
0,
|
|
3259
|
+
-0.25,
|
|
3260
|
+
-1,
|
|
3261
|
+
-0.8,
|
|
3262
|
+
0,
|
|
3263
|
+
0,
|
|
3264
|
+
0,
|
|
3265
|
+
-0.25,
|
|
3266
|
+
-1,
|
|
3267
|
+
-0.8,
|
|
3268
|
+
0,
|
|
3269
|
+
0,
|
|
3270
|
+
0,
|
|
3271
|
+
0.05,
|
|
3272
|
+
-1,
|
|
3273
|
+
0.8,
|
|
3274
|
+
0,
|
|
3275
|
+
0,
|
|
3276
|
+
0,
|
|
3277
|
+
-0.45,
|
|
3278
|
+
-1,
|
|
3279
|
+
-0.8,
|
|
3280
|
+
0,
|
|
3281
|
+
0,
|
|
3282
|
+
0,
|
|
3283
|
+
-0.15,
|
|
3284
|
+
-1,
|
|
3285
|
+
0.8,
|
|
3286
|
+
0,
|
|
3287
|
+
0,
|
|
3288
|
+
0,
|
|
3289
|
+
-0.15,
|
|
3290
|
+
-1,
|
|
3291
|
+
0.8,
|
|
3292
|
+
0,
|
|
3293
|
+
0,
|
|
3294
|
+
0,
|
|
3295
|
+
0.13,
|
|
3296
|
+
-1,
|
|
3297
|
+
-0.3,
|
|
3298
|
+
0,
|
|
3299
|
+
0,
|
|
3300
|
+
0,
|
|
3301
|
+
0.13,
|
|
3302
|
+
-1,
|
|
3303
|
+
-0.3,
|
|
3304
|
+
0,
|
|
3305
|
+
0,
|
|
3306
|
+
0,
|
|
3307
|
+
0.07,
|
|
3308
|
+
-1,
|
|
3309
|
+
-0.1,
|
|
3310
|
+
0,
|
|
3311
|
+
0,
|
|
3312
|
+
0,
|
|
3313
|
+
-0.33,
|
|
3314
|
+
-1,
|
|
3315
|
+
-0.3,
|
|
3316
|
+
0,
|
|
3317
|
+
0,
|
|
3318
|
+
0,
|
|
3319
|
+
-0.27,
|
|
3320
|
+
-1,
|
|
3321
|
+
-0.1,
|
|
3322
|
+
0,
|
|
3323
|
+
0,
|
|
3324
|
+
0,
|
|
3325
|
+
-0.27,
|
|
3326
|
+
-1,
|
|
3327
|
+
-0.1,
|
|
3328
|
+
0,
|
|
3329
|
+
0,
|
|
3330
|
+
0,
|
|
3331
|
+
-0.45,
|
|
3332
|
+
0.6,
|
|
3333
|
+
1,
|
|
3334
|
+
0,
|
|
3335
|
+
0,
|
|
3336
|
+
0,
|
|
3337
|
+
-0.45,
|
|
3338
|
+
0.6,
|
|
3339
|
+
1,
|
|
3340
|
+
0,
|
|
3341
|
+
0,
|
|
3342
|
+
0,
|
|
3343
|
+
-0.45,
|
|
3344
|
+
0.4,
|
|
3345
|
+
1,
|
|
3346
|
+
0,
|
|
3347
|
+
0,
|
|
3348
|
+
0,
|
|
3349
|
+
-0.25,
|
|
3350
|
+
0.8,
|
|
3351
|
+
1,
|
|
3352
|
+
0,
|
|
3353
|
+
0,
|
|
3354
|
+
0,
|
|
3355
|
+
-0.25,
|
|
3356
|
+
0.4,
|
|
3357
|
+
1,
|
|
3358
|
+
0,
|
|
3359
|
+
0,
|
|
3360
|
+
0,
|
|
3361
|
+
-0.25,
|
|
3362
|
+
0.4,
|
|
3363
|
+
1,
|
|
3364
|
+
0,
|
|
3365
|
+
0,
|
|
3366
|
+
0,
|
|
3367
|
+
-0.25,
|
|
3368
|
+
0.8,
|
|
3369
|
+
1,
|
|
3370
|
+
0,
|
|
3371
|
+
0,
|
|
3372
|
+
0,
|
|
3373
|
+
-0.25,
|
|
3374
|
+
0.8,
|
|
3375
|
+
1,
|
|
3376
|
+
0,
|
|
3377
|
+
0,
|
|
3378
|
+
0,
|
|
3379
|
+
-0.25,
|
|
3380
|
+
0.6,
|
|
3381
|
+
1,
|
|
3382
|
+
0,
|
|
3383
|
+
0,
|
|
3384
|
+
0,
|
|
3385
|
+
0.25,
|
|
3386
|
+
0.8,
|
|
3387
|
+
1,
|
|
3388
|
+
0,
|
|
3389
|
+
0,
|
|
3390
|
+
0,
|
|
3391
|
+
0.45,
|
|
3392
|
+
0.6,
|
|
3393
|
+
1,
|
|
3394
|
+
0,
|
|
3395
|
+
0,
|
|
3396
|
+
0,
|
|
3397
|
+
0.45,
|
|
3398
|
+
0.6,
|
|
3399
|
+
1,
|
|
3400
|
+
0,
|
|
3401
|
+
0,
|
|
3402
|
+
0,
|
|
3403
|
+
0.25,
|
|
3404
|
+
0.8,
|
|
3405
|
+
1,
|
|
3406
|
+
0,
|
|
3407
|
+
0,
|
|
3408
|
+
0,
|
|
3409
|
+
0.25,
|
|
3410
|
+
0.8,
|
|
3411
|
+
1,
|
|
3412
|
+
0,
|
|
3413
|
+
0,
|
|
3414
|
+
0,
|
|
3415
|
+
0.25,
|
|
3416
|
+
-0.1,
|
|
3417
|
+
1,
|
|
3418
|
+
0,
|
|
3419
|
+
0,
|
|
3420
|
+
0,
|
|
3421
|
+
0.45,
|
|
3422
|
+
0.6,
|
|
3423
|
+
1,
|
|
3424
|
+
0,
|
|
3425
|
+
0,
|
|
3426
|
+
0,
|
|
3427
|
+
0.45,
|
|
3428
|
+
0.1,
|
|
3429
|
+
1,
|
|
3430
|
+
0,
|
|
3431
|
+
0,
|
|
3432
|
+
0,
|
|
3433
|
+
0.45,
|
|
3434
|
+
0.1,
|
|
3435
|
+
1,
|
|
3436
|
+
0,
|
|
3437
|
+
0,
|
|
3438
|
+
0,
|
|
3439
|
+
-0.25,
|
|
3440
|
+
0.1,
|
|
3441
|
+
1,
|
|
3442
|
+
0,
|
|
3443
|
+
0,
|
|
3444
|
+
0,
|
|
3445
|
+
-0.25,
|
|
3446
|
+
0.1,
|
|
3447
|
+
1,
|
|
3448
|
+
0,
|
|
3449
|
+
0,
|
|
3450
|
+
0,
|
|
3451
|
+
-0.45,
|
|
3452
|
+
-0.1,
|
|
3453
|
+
1,
|
|
3454
|
+
0,
|
|
3455
|
+
0,
|
|
3456
|
+
0,
|
|
3457
|
+
0.25,
|
|
3458
|
+
0.1,
|
|
3459
|
+
1,
|
|
3460
|
+
0,
|
|
3461
|
+
0,
|
|
3462
|
+
0,
|
|
3463
|
+
0.25,
|
|
3464
|
+
-0.1,
|
|
3465
|
+
1,
|
|
3466
|
+
0,
|
|
3467
|
+
0,
|
|
3468
|
+
0,
|
|
3469
|
+
0.25,
|
|
3470
|
+
-0.1,
|
|
3471
|
+
1,
|
|
3472
|
+
0,
|
|
3473
|
+
0,
|
|
3474
|
+
0,
|
|
3475
|
+
-0.45,
|
|
3476
|
+
-0.1,
|
|
3477
|
+
1,
|
|
3478
|
+
0,
|
|
3479
|
+
0,
|
|
3480
|
+
0,
|
|
3481
|
+
-0.45,
|
|
3482
|
+
-0.1,
|
|
3483
|
+
1,
|
|
3484
|
+
0,
|
|
3485
|
+
0,
|
|
3486
|
+
0,
|
|
3487
|
+
-0.45,
|
|
3488
|
+
-0.6,
|
|
3489
|
+
1,
|
|
3490
|
+
0,
|
|
3491
|
+
0,
|
|
3492
|
+
0,
|
|
3493
|
+
-0.25,
|
|
3494
|
+
-0.1,
|
|
3495
|
+
1,
|
|
3496
|
+
0,
|
|
3497
|
+
0,
|
|
3498
|
+
0,
|
|
3499
|
+
-0.25,
|
|
3500
|
+
-0.8,
|
|
3501
|
+
1,
|
|
3502
|
+
0,
|
|
3503
|
+
0,
|
|
3504
|
+
0,
|
|
3505
|
+
-0.25,
|
|
3506
|
+
-0.8,
|
|
3507
|
+
1,
|
|
3508
|
+
0,
|
|
3509
|
+
0,
|
|
3510
|
+
0,
|
|
3511
|
+
-0.25,
|
|
3512
|
+
-0.6,
|
|
3513
|
+
1,
|
|
3514
|
+
0,
|
|
3515
|
+
0,
|
|
3516
|
+
0,
|
|
3517
|
+
-0.25,
|
|
3518
|
+
-0.6,
|
|
3519
|
+
1,
|
|
3520
|
+
0,
|
|
3521
|
+
0,
|
|
3522
|
+
0,
|
|
3523
|
+
-0.25,
|
|
3524
|
+
-0.8,
|
|
3525
|
+
1,
|
|
3526
|
+
0,
|
|
3527
|
+
0,
|
|
3528
|
+
0,
|
|
3529
|
+
0.45,
|
|
3530
|
+
-0.6,
|
|
3531
|
+
1,
|
|
3532
|
+
0,
|
|
3533
|
+
0,
|
|
3534
|
+
0,
|
|
3535
|
+
0.25,
|
|
3536
|
+
-0.8,
|
|
3537
|
+
1,
|
|
3538
|
+
0,
|
|
3539
|
+
0,
|
|
3540
|
+
0,
|
|
3541
|
+
0.25,
|
|
3542
|
+
-0.8,
|
|
3543
|
+
1,
|
|
3544
|
+
0,
|
|
3545
|
+
0,
|
|
3546
|
+
0,
|
|
3547
|
+
0.25,
|
|
3548
|
+
-0.4,
|
|
3549
|
+
1,
|
|
3550
|
+
0,
|
|
3551
|
+
0,
|
|
3552
|
+
0,
|
|
3553
|
+
0.25,
|
|
3554
|
+
-0.4,
|
|
3555
|
+
1,
|
|
3556
|
+
0,
|
|
3557
|
+
0,
|
|
3558
|
+
0,
|
|
3559
|
+
0.25,
|
|
3560
|
+
-0.6,
|
|
3561
|
+
1,
|
|
3562
|
+
0,
|
|
3563
|
+
0,
|
|
3564
|
+
0,
|
|
3565
|
+
0.45,
|
|
3566
|
+
-0.4,
|
|
3567
|
+
1,
|
|
3568
|
+
0,
|
|
3569
|
+
0,
|
|
3570
|
+
0,
|
|
3571
|
+
0.45,
|
|
3572
|
+
-0.6,
|
|
3573
|
+
1,
|
|
3574
|
+
0,
|
|
3575
|
+
0,
|
|
3576
|
+
0,
|
|
3577
|
+
0.45,
|
|
3578
|
+
-0.6,
|
|
3579
|
+
1,
|
|
3580
|
+
0,
|
|
3581
|
+
0,
|
|
3582
|
+
0,
|
|
3583
|
+
-0.1,
|
|
3584
|
+
-0.8,
|
|
3585
|
+
-1,
|
|
3586
|
+
0,
|
|
3587
|
+
0,
|
|
3588
|
+
0,
|
|
3589
|
+
-0.1,
|
|
3590
|
+
-0.8,
|
|
3591
|
+
-1,
|
|
3592
|
+
0,
|
|
3593
|
+
0,
|
|
3594
|
+
0,
|
|
3595
|
+
-0.1,
|
|
3596
|
+
0.8,
|
|
3597
|
+
-1,
|
|
3598
|
+
0,
|
|
3599
|
+
0,
|
|
3600
|
+
0,
|
|
3601
|
+
0.1,
|
|
3602
|
+
-0.8,
|
|
3603
|
+
-1,
|
|
3604
|
+
0,
|
|
3605
|
+
0,
|
|
3606
|
+
0,
|
|
3607
|
+
0.1,
|
|
3608
|
+
0.8,
|
|
3609
|
+
-1,
|
|
3610
|
+
0,
|
|
3611
|
+
0,
|
|
3612
|
+
0,
|
|
3613
|
+
0.1,
|
|
3614
|
+
0.8,
|
|
3615
|
+
-1,
|
|
3616
|
+
0,
|
|
3617
|
+
0,
|
|
3618
|
+
0,
|
|
3619
|
+
-1,
|
|
3620
|
+
-0.45,
|
|
3621
|
+
-0.8,
|
|
3622
|
+
0,
|
|
3623
|
+
0,
|
|
3624
|
+
0,
|
|
3625
|
+
-1,
|
|
3626
|
+
-0.45,
|
|
3627
|
+
-0.8,
|
|
3628
|
+
0,
|
|
3629
|
+
0,
|
|
3630
|
+
0,
|
|
3631
|
+
-1,
|
|
3632
|
+
-0.45,
|
|
3633
|
+
0.8,
|
|
3634
|
+
0,
|
|
3635
|
+
0,
|
|
3636
|
+
0,
|
|
3637
|
+
-1,
|
|
3638
|
+
-0.25,
|
|
3639
|
+
-0.8,
|
|
3640
|
+
0,
|
|
3641
|
+
0,
|
|
3642
|
+
0,
|
|
3643
|
+
-1,
|
|
3644
|
+
-0.25,
|
|
3645
|
+
0.8,
|
|
3646
|
+
0,
|
|
3647
|
+
0,
|
|
3648
|
+
0,
|
|
3649
|
+
-1,
|
|
3650
|
+
-0.25,
|
|
3651
|
+
0.8,
|
|
3652
|
+
0,
|
|
3653
|
+
0,
|
|
3654
|
+
0,
|
|
3655
|
+
-1,
|
|
3656
|
+
-0.25,
|
|
3657
|
+
-0.8,
|
|
3658
|
+
0,
|
|
3659
|
+
0,
|
|
3660
|
+
0,
|
|
3661
|
+
-1,
|
|
3662
|
+
-0.25,
|
|
3663
|
+
-0.8,
|
|
3664
|
+
0,
|
|
3665
|
+
0,
|
|
3666
|
+
0,
|
|
3667
|
+
-1,
|
|
3668
|
+
-0.25,
|
|
3669
|
+
-0.6,
|
|
3670
|
+
0,
|
|
3671
|
+
0,
|
|
3672
|
+
0,
|
|
3673
|
+
-1,
|
|
3674
|
+
0.45,
|
|
3675
|
+
-0.8,
|
|
3676
|
+
0,
|
|
3677
|
+
0,
|
|
3678
|
+
0,
|
|
3679
|
+
-1,
|
|
3680
|
+
0.45,
|
|
3681
|
+
-0.6,
|
|
3682
|
+
0,
|
|
3683
|
+
0,
|
|
3684
|
+
0,
|
|
3685
|
+
-1,
|
|
3686
|
+
0.45,
|
|
3687
|
+
-0.6,
|
|
3688
|
+
0,
|
|
3689
|
+
0,
|
|
3690
|
+
0,
|
|
3691
|
+
1,
|
|
3692
|
+
0.45,
|
|
3693
|
+
-0.8,
|
|
3694
|
+
0,
|
|
3695
|
+
0,
|
|
3696
|
+
0,
|
|
3697
|
+
1,
|
|
3698
|
+
0.45,
|
|
3699
|
+
-0.8,
|
|
3700
|
+
0,
|
|
3701
|
+
0,
|
|
3702
|
+
0,
|
|
3703
|
+
1,
|
|
3704
|
+
0.45,
|
|
3705
|
+
0.8,
|
|
3706
|
+
0,
|
|
3707
|
+
0,
|
|
3708
|
+
0,
|
|
3709
|
+
1,
|
|
3710
|
+
0.25,
|
|
3711
|
+
-0.8,
|
|
3712
|
+
0,
|
|
3713
|
+
0,
|
|
3714
|
+
0,
|
|
3715
|
+
1,
|
|
3716
|
+
0.25,
|
|
3717
|
+
0.8,
|
|
3718
|
+
0,
|
|
3719
|
+
0,
|
|
3720
|
+
0,
|
|
3721
|
+
1,
|
|
3722
|
+
0.25,
|
|
3723
|
+
0.8,
|
|
3724
|
+
0,
|
|
3725
|
+
0,
|
|
3726
|
+
0,
|
|
3727
|
+
1,
|
|
3728
|
+
0.25,
|
|
3729
|
+
0.6,
|
|
3730
|
+
0,
|
|
3731
|
+
0,
|
|
3732
|
+
0,
|
|
3733
|
+
1,
|
|
3734
|
+
0.25,
|
|
3735
|
+
0.6,
|
|
3736
|
+
0,
|
|
3737
|
+
0,
|
|
3738
|
+
0,
|
|
3739
|
+
1,
|
|
3740
|
+
0.25,
|
|
3741
|
+
0.8,
|
|
3742
|
+
0,
|
|
3743
|
+
0,
|
|
3744
|
+
0,
|
|
3745
|
+
1,
|
|
3746
|
+
-0.45,
|
|
3747
|
+
0.6,
|
|
3748
|
+
0,
|
|
3749
|
+
0,
|
|
3750
|
+
0,
|
|
3751
|
+
1,
|
|
3752
|
+
-0.25,
|
|
3753
|
+
0.8,
|
|
3754
|
+
0,
|
|
3755
|
+
0,
|
|
3756
|
+
0,
|
|
3757
|
+
1,
|
|
3758
|
+
-0.25,
|
|
3759
|
+
0.8,
|
|
3760
|
+
0,
|
|
3761
|
+
0,
|
|
3762
|
+
0,
|
|
3763
|
+
1,
|
|
3764
|
+
-0.25,
|
|
3765
|
+
0.1,
|
|
3766
|
+
0,
|
|
3767
|
+
0,
|
|
3768
|
+
0,
|
|
3769
|
+
1,
|
|
3770
|
+
-0.25,
|
|
3771
|
+
0.1,
|
|
3772
|
+
0,
|
|
3773
|
+
0,
|
|
3774
|
+
0,
|
|
3775
|
+
1,
|
|
3776
|
+
-0.25,
|
|
3777
|
+
0.6,
|
|
3778
|
+
0,
|
|
3779
|
+
0,
|
|
3780
|
+
0,
|
|
3781
|
+
1,
|
|
3782
|
+
-0.45,
|
|
3783
|
+
0.1,
|
|
3784
|
+
0,
|
|
3785
|
+
0,
|
|
3786
|
+
0,
|
|
3787
|
+
1,
|
|
3788
|
+
-0.45,
|
|
3789
|
+
0.6,
|
|
3790
|
+
0,
|
|
3791
|
+
0,
|
|
3792
|
+
0,
|
|
3793
|
+
1,
|
|
3794
|
+
-0.45,
|
|
3795
|
+
0.6,
|
|
3796
|
+
0,
|
|
3797
|
+
0,
|
|
3798
|
+
0,
|
|
3799
|
+
1,
|
|
3800
|
+
0.25,
|
|
3801
|
+
-0.1,
|
|
3802
|
+
0,
|
|
3803
|
+
0,
|
|
3804
|
+
0,
|
|
3805
|
+
1,
|
|
3806
|
+
0.25,
|
|
3807
|
+
-0.1,
|
|
3808
|
+
0,
|
|
3809
|
+
0,
|
|
3810
|
+
0,
|
|
3811
|
+
1,
|
|
3812
|
+
0.25,
|
|
3813
|
+
0.1,
|
|
3814
|
+
0,
|
|
3815
|
+
0,
|
|
3816
|
+
0,
|
|
3817
|
+
1,
|
|
3818
|
+
-0.25,
|
|
3819
|
+
-0.1,
|
|
3820
|
+
0,
|
|
3821
|
+
0,
|
|
3822
|
+
0,
|
|
3823
|
+
1,
|
|
3824
|
+
-0.45,
|
|
3825
|
+
0.1,
|
|
3826
|
+
0,
|
|
3827
|
+
0,
|
|
3828
|
+
0,
|
|
3829
|
+
1,
|
|
3830
|
+
-0.45,
|
|
3831
|
+
0.1,
|
|
3832
|
+
0,
|
|
3833
|
+
0,
|
|
3834
|
+
0,
|
|
3835
|
+
1,
|
|
3836
|
+
-0.25,
|
|
3837
|
+
-0.8,
|
|
3838
|
+
0,
|
|
3839
|
+
0,
|
|
3840
|
+
0,
|
|
3841
|
+
1,
|
|
3842
|
+
-0.25,
|
|
3843
|
+
-0.8,
|
|
3844
|
+
0,
|
|
3845
|
+
0,
|
|
3846
|
+
0,
|
|
3847
|
+
1,
|
|
3848
|
+
-0.05,
|
|
3849
|
+
-0.1,
|
|
3850
|
+
0,
|
|
3851
|
+
0,
|
|
3852
|
+
0,
|
|
3853
|
+
1,
|
|
3854
|
+
-0.45,
|
|
3855
|
+
-0.8,
|
|
3856
|
+
0,
|
|
3857
|
+
0,
|
|
3858
|
+
0,
|
|
3859
|
+
1,
|
|
3860
|
+
-0.25,
|
|
3861
|
+
-0.1,
|
|
3862
|
+
0,
|
|
3863
|
+
0,
|
|
3864
|
+
0,
|
|
3865
|
+
1,
|
|
3866
|
+
-0.25,
|
|
3867
|
+
-0.1,
|
|
3868
|
+
0,
|
|
3869
|
+
0,
|
|
3870
|
+
0
|
|
3871
|
+
]);
|
|
2847
3872
|
var NiivueObject3D = function(id, vertexBuffer, mode, indexCount, indexBuffer = null, vao = null) {
|
|
2848
3873
|
this.BLEND = 1;
|
|
2849
3874
|
this.CULL_FACE = 2;
|
|
@@ -103542,6 +104567,22 @@ function isPlatformLittleEndian() {
|
|
|
103542
104567
|
new DataView(buffer2).setInt16(0, 256, true);
|
|
103543
104568
|
return new Int16Array(buffer2)[0] === 256;
|
|
103544
104569
|
}
|
|
104570
|
+
function NVImageFromUrlOptions(url, urlImageData = "", name = "", colorMap = "gray", opacity = 1, cal_min = NaN, cal_max = NaN, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false, visible = true, colorMapNegative = "") {
|
|
104571
|
+
return {
|
|
104572
|
+
url,
|
|
104573
|
+
urlImageData,
|
|
104574
|
+
name,
|
|
104575
|
+
colorMap,
|
|
104576
|
+
opacity,
|
|
104577
|
+
cal_min,
|
|
104578
|
+
cal_max,
|
|
104579
|
+
trustCalMinMax,
|
|
104580
|
+
percentileFrac,
|
|
104581
|
+
ignoreZeroVoxels,
|
|
104582
|
+
visible,
|
|
104583
|
+
colorMapNegative
|
|
104584
|
+
};
|
|
104585
|
+
}
|
|
103545
104586
|
function NVImage(dataBuffer, name = "", colorMap = "gray", opacity = 1, pairedImgData = null, cal_min = NaN, cal_max = NaN, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false, visible = true, isDICOMDIR = false, useQFormNotSForm = false, colorMapNegative = "") {
|
|
103546
104587
|
this.DT_NONE = 0;
|
|
103547
104588
|
this.DT_UNKNOWN = 0;
|
|
@@ -103868,9 +104909,9 @@ NVImage.prototype.calculateOblique = function() {
|
|
|
103868
104909
|
let XY = Math.abs(90 - angle(X1mm, Y1mm) * (180 / Math.PI));
|
|
103869
104910
|
let XZ = Math.abs(90 - angle(X1mm, Z1mm) * (180 / Math.PI));
|
|
103870
104911
|
let YZ = Math.abs(90 - angle(Y1mm, Z1mm) * (180 / Math.PI));
|
|
103871
|
-
|
|
103872
|
-
if (
|
|
103873
|
-
log
|
|
104912
|
+
this.maxShearDeg = Math.max(Math.max(XY, XZ), YZ);
|
|
104913
|
+
if (this.maxShearDeg > 0.1)
|
|
104914
|
+
console.log("Warning: voxels are rhomboidal, maximum shear is %f degrees.", this.maxShearDeg);
|
|
103874
104915
|
let dim = fromValues(this.dimsRAS[1], this.dimsRAS[2], this.dimsRAS[3], 1);
|
|
103875
104916
|
let sform = clone$1(this.matRAS);
|
|
103876
104917
|
transpose(sform, sform);
|
|
@@ -103986,7 +105027,8 @@ NVImage.prototype.readDICOM = function(buf) {
|
|
|
103986
105027
|
this.series = new daikon.Series();
|
|
103987
105028
|
if (Array.isArray(buf)) {
|
|
103988
105029
|
for (let i2 = 0; i2 < buf.length; i2++) {
|
|
103989
|
-
|
|
105030
|
+
const dataview = new DataView(buf[i2]);
|
|
105031
|
+
let image3 = daikon.Series.parseImage(dataview);
|
|
103990
105032
|
if (image3 === null) {
|
|
103991
105033
|
console.error(daikon.Series.parserError);
|
|
103992
105034
|
} else if (image3.hasPixelData()) {
|
|
@@ -104064,8 +105106,6 @@ NVImage.prototype.readDICOM = function(buf) {
|
|
|
104064
105106
|
[0, 0, 0, 1]
|
|
104065
105107
|
];
|
|
104066
105108
|
}
|
|
104067
|
-
console.log("DICOM", this.series.images[0]);
|
|
104068
|
-
console.log("NIfTI", hdr);
|
|
104069
105109
|
let imgRaw = [];
|
|
104070
105110
|
let data;
|
|
104071
105111
|
let length2 = this.series.validatePixelDataLength(this.series.images[0]);
|
|
@@ -104215,30 +105255,6 @@ NVImage.prototype.readVMR = function(buffer2) {
|
|
|
104215
105255
|
let nBytes = hdr.dims[1] * hdr.dims[2] * hdr.dims[3];
|
|
104216
105256
|
if (version >= 4) {
|
|
104217
105257
|
let pos = 8 + nBytes;
|
|
104218
|
-
reader.getUint16(pos, true);
|
|
104219
|
-
reader.getUint16(pos + 2, true);
|
|
104220
|
-
reader.getUint16(pos + 4, true);
|
|
104221
|
-
reader.getUint16(pos + 6, true);
|
|
104222
|
-
reader.getUint32(pos + 8, true);
|
|
104223
|
-
reader.getUint32(pos + 12, true);
|
|
104224
|
-
reader.getFloat32(pos + 16, true);
|
|
104225
|
-
reader.getFloat32(pos + 20, true);
|
|
104226
|
-
reader.getFloat32(pos + 24, true);
|
|
104227
|
-
reader.getFloat32(pos + 28, true);
|
|
104228
|
-
reader.getFloat32(pos + 32, true);
|
|
104229
|
-
reader.getFloat32(pos + 36, true);
|
|
104230
|
-
reader.getFloat32(pos + 40, true);
|
|
104231
|
-
reader.getFloat32(pos + 44, true);
|
|
104232
|
-
reader.getFloat32(pos + 48, true);
|
|
104233
|
-
reader.getFloat32(pos + 52, true);
|
|
104234
|
-
reader.getFloat32(pos + 56, true);
|
|
104235
|
-
reader.getFloat32(pos + 60, true);
|
|
104236
|
-
reader.getUint32(pos + 64, true);
|
|
104237
|
-
reader.getUint32(pos + 68, true);
|
|
104238
|
-
reader.getFloat32(pos + 72, true);
|
|
104239
|
-
reader.getFloat32(pos + 76, true);
|
|
104240
|
-
reader.getFloat32(pos + 80, true);
|
|
104241
|
-
reader.getFloat32(pos + 84, true);
|
|
104242
105258
|
let nSpatialTransforms = reader.getUint32(pos + 88, true);
|
|
104243
105259
|
pos = pos + 92;
|
|
104244
105260
|
if (nSpatialTransforms > 0) {
|
|
@@ -104247,7 +105263,6 @@ NVImage.prototype.readVMR = function(buffer2) {
|
|
|
104247
105263
|
while (pos < len2 && reader.getUint8(pos) !== 0)
|
|
104248
105264
|
pos++;
|
|
104249
105265
|
pos++;
|
|
104250
|
-
reader.getUint32(pos, true);
|
|
104251
105266
|
pos += 4;
|
|
104252
105267
|
while (pos < len2 && reader.getUint8(pos) !== 0)
|
|
104253
105268
|
pos++;
|
|
@@ -104258,16 +105273,9 @@ NVImage.prototype.readVMR = function(buffer2) {
|
|
|
104258
105273
|
pos += 4;
|
|
104259
105274
|
}
|
|
104260
105275
|
}
|
|
104261
|
-
reader.getUint8(pos);
|
|
104262
|
-
reader.getUint8(pos + 1);
|
|
104263
105276
|
hdr.pixDims[1] = reader.getFloat32(pos + 2, true);
|
|
104264
105277
|
hdr.pixDims[2] = reader.getFloat32(pos + 6, true);
|
|
104265
105278
|
hdr.pixDims[3] = reader.getFloat32(pos + 10, true);
|
|
104266
|
-
reader.getUint8(pos + 14);
|
|
104267
|
-
reader.getUint8(pos + 15);
|
|
104268
|
-
reader.getInt32(pos + 16, true);
|
|
104269
|
-
reader.getInt32(pos + 20, true);
|
|
104270
|
-
reader.getInt32(pos + 24, true);
|
|
104271
105279
|
}
|
|
104272
105280
|
console.log("Warning: VMR spatial transform not implemented");
|
|
104273
105281
|
hdr.affine = [
|
|
@@ -104299,8 +105307,6 @@ NVImage.prototype.readMGH = function(buffer2) {
|
|
|
104299
105307
|
let depth = reader.getInt32(12, false);
|
|
104300
105308
|
let nframes = reader.getInt32(16, false);
|
|
104301
105309
|
let mtype = reader.getInt32(20, false);
|
|
104302
|
-
reader.getInt32(24, false);
|
|
104303
|
-
reader.getInt16(28, false);
|
|
104304
105310
|
let spacingX = reader.getFloat32(30, false);
|
|
104305
105311
|
let spacingY = reader.getFloat32(34, false);
|
|
104306
105312
|
let spacingZ = reader.getFloat32(38, false);
|
|
@@ -104313,9 +105319,6 @@ NVImage.prototype.readMGH = function(buffer2) {
|
|
|
104313
105319
|
let zr = reader.getFloat32(66, false);
|
|
104314
105320
|
let za = reader.getFloat32(70, false);
|
|
104315
105321
|
let zs = reader.getFloat32(74, false);
|
|
104316
|
-
reader.getFloat32(78, false);
|
|
104317
|
-
reader.getFloat32(82, false);
|
|
104318
|
-
reader.getFloat32(86, false);
|
|
104319
105322
|
if (version !== 1 || mtype < 0 || mtype > 4)
|
|
104320
105323
|
console.log("Not a valid MGH file");
|
|
104321
105324
|
if (mtype === 0) {
|
|
@@ -105001,7 +106004,6 @@ NVImage.prototype.readNRRD = function(dataBuffer, pairedImgData) {
|
|
|
105001
106004
|
[0, 0, 0, 1]
|
|
105002
106005
|
];
|
|
105003
106006
|
}
|
|
105004
|
-
hdr.dims[1] * hdr.dims[2] * hdr.dims[3];
|
|
105005
106007
|
if (isDetached && pairedImgData) {
|
|
105006
106008
|
return pairedImgData.slice();
|
|
105007
106009
|
}
|
|
@@ -105477,14 +106479,15 @@ NVImage.loadFromFile = async function({
|
|
|
105477
106479
|
}
|
|
105478
106480
|
} else {
|
|
105479
106481
|
dataBuffer = await this.readFileAsync(file);
|
|
106482
|
+
name = file.name;
|
|
105480
106483
|
}
|
|
105481
106484
|
let pairedImgData = null;
|
|
105482
106485
|
if (urlImgData) {
|
|
105483
106486
|
pairedImgData = await this.readFileAsync(urlImgData);
|
|
105484
106487
|
}
|
|
105485
|
-
name = file.name;
|
|
105486
106488
|
nvimage = new NVImage(dataBuffer, name, colorMap, opacity, pairedImgData, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, visible, isDICOMDIR);
|
|
105487
106489
|
} catch (err2) {
|
|
106490
|
+
console.log(err2);
|
|
105488
106491
|
log$2.debug(err2);
|
|
105489
106492
|
}
|
|
105490
106493
|
return nvimage;
|
|
@@ -105742,6 +106745,24 @@ NVImage.prototype.toNiivueObject3D = function(id, gl) {
|
|
|
105742
106745
|
];
|
|
105743
106746
|
return obj3D;
|
|
105744
106747
|
};
|
|
106748
|
+
NVImage.prototype.applyOptionsUpdate = function(options) {
|
|
106749
|
+
this.hdr.cal_min = options.cal_min;
|
|
106750
|
+
this.hdr.cal_max = options.cal_max;
|
|
106751
|
+
delete options["url"];
|
|
106752
|
+
delete options["urlImageData"];
|
|
106753
|
+
delete options["cal_min"];
|
|
106754
|
+
delete options["cal_max"];
|
|
106755
|
+
Object.assign(this, options);
|
|
106756
|
+
};
|
|
106757
|
+
NVImage.prototype.getImageOptions = function() {
|
|
106758
|
+
let options = null;
|
|
106759
|
+
try {
|
|
106760
|
+
options = new NVImageFromUrlOptions("", "", this.name, this.colorMap, this.opacity, this.hdr.cal_min, this.hdr.cal_max, this.trustCalMinMax, this.percentileFrac, this.ignoreZeroVoxels, this.visible, this.colorMapNegative);
|
|
106761
|
+
} catch (e) {
|
|
106762
|
+
console.log(e);
|
|
106763
|
+
}
|
|
106764
|
+
return options;
|
|
106765
|
+
};
|
|
105745
106766
|
const colortables = function() {
|
|
105746
106767
|
this.version = 0.1;
|
|
105747
106768
|
this.gamma = 1;
|
|
@@ -105765,7 +106786,7 @@ colortables.prototype.colormap = function(lutName = "") {
|
|
|
105765
106786
|
return this.makeLut(cmaps[defaultLutName].R, cmaps[defaultLutName].G, cmaps[defaultLutName].B, cmaps[defaultLutName].A, cmaps[defaultLutName].I);
|
|
105766
106787
|
};
|
|
105767
106788
|
colortables.prototype.colormapFromKey = function(name) {
|
|
105768
|
-
let availMaps =
|
|
106789
|
+
let availMaps = this.colorMaps();
|
|
105769
106790
|
for (let i2 = 0; i2 < availMaps.length; i2++) {
|
|
105770
106791
|
let key2 = availMaps[i2];
|
|
105771
106792
|
if (name.toLowerCase() === key2.toLowerCase()) {
|
|
@@ -105799,7 +106820,18 @@ colortables.prototype.makeLut = function(Rs, Gs, Bs, As, Is) {
|
|
|
105799
106820
|
};
|
|
105800
106821
|
const cmapper$1 = new colortables();
|
|
105801
106822
|
const log$1 = new Log();
|
|
105802
|
-
function
|
|
106823
|
+
function NVMeshFromUrlOptions(url = "", gl = null, name = "", opacity = 1, rgba255 = [255, 255, 255, 255], visible = true, layers = []) {
|
|
106824
|
+
return {
|
|
106825
|
+
url,
|
|
106826
|
+
gl,
|
|
106827
|
+
name,
|
|
106828
|
+
opacity,
|
|
106829
|
+
rgba255,
|
|
106830
|
+
visible,
|
|
106831
|
+
layers
|
|
106832
|
+
};
|
|
106833
|
+
}
|
|
106834
|
+
function NVMesh(pts, tris, name = "", rgba255 = [255, 255, 255, 255], opacity = 1, visible = true, gl, connectome = null, dpg = null, dps = null, dpv = null) {
|
|
105803
106835
|
this.name = name;
|
|
105804
106836
|
this.id = v4();
|
|
105805
106837
|
let obj = getExtents(pts);
|
|
@@ -105808,6 +106840,7 @@ function NVMesh(pts, tris, name = "", rgba255 = [1, 0, 0, 0], opacity = 1, visib
|
|
|
105808
106840
|
this.extentsMax = obj.extentsMax;
|
|
105809
106841
|
this.opacity = opacity > 1 ? 1 : opacity;
|
|
105810
106842
|
this.visible = visible;
|
|
106843
|
+
this.meshShaderIndex = 0;
|
|
105811
106844
|
this.indexBuffer = gl.createBuffer();
|
|
105812
106845
|
this.vertexBuffer = gl.createBuffer();
|
|
105813
106846
|
this.vao = gl.createVertexArray();
|
|
@@ -106085,6 +107118,45 @@ NVMesh.prototype.updateConnectome = function(gl) {
|
|
|
106085
107118
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(posNormClr), gl.STATIC_DRAW);
|
|
106086
107119
|
this.indexCount = tris.length;
|
|
106087
107120
|
};
|
|
107121
|
+
function getClusterBoundaryU8(u82, faces) {
|
|
107122
|
+
const border = new Array(u82.length).fill(false);
|
|
107123
|
+
const binary = new Array(u82.length).fill(false);
|
|
107124
|
+
for (let i2 = 0; i2 < u82.length; i2++)
|
|
107125
|
+
if (u82[i2] > 0)
|
|
107126
|
+
binary[i2] = true;
|
|
107127
|
+
let nTri = faces.length / 3;
|
|
107128
|
+
let j = 0;
|
|
107129
|
+
for (let i2 = 0; i2 < nTri; i2++) {
|
|
107130
|
+
let v0 = faces[j];
|
|
107131
|
+
let v1 = faces[j + 1];
|
|
107132
|
+
let v2 = faces[j + 2];
|
|
107133
|
+
j += 3;
|
|
107134
|
+
if (binary[v0] === binary[v1] && binary[v0] === binary[v2] && binary[v1] === binary[v2])
|
|
107135
|
+
continue;
|
|
107136
|
+
border[v0] = true;
|
|
107137
|
+
border[v1] = true;
|
|
107138
|
+
border[v2] = true;
|
|
107139
|
+
}
|
|
107140
|
+
return border;
|
|
107141
|
+
}
|
|
107142
|
+
function getClusterBoundary(rgba8, faces) {
|
|
107143
|
+
var rgba32 = new Uint32Array(rgba8.buffer);
|
|
107144
|
+
const border = new Array(rgba32.length).fill(false);
|
|
107145
|
+
let nTri = faces.length / 3;
|
|
107146
|
+
let j = 0;
|
|
107147
|
+
for (let i2 = 0; i2 < nTri; i2++) {
|
|
107148
|
+
let v0 = faces[j];
|
|
107149
|
+
let v1 = faces[j + 1];
|
|
107150
|
+
let v2 = faces[j + 2];
|
|
107151
|
+
j += 3;
|
|
107152
|
+
if (rgba32[v0] === rgba32[v1] && rgba32[v0] === rgba32[v2] && rgba32[v1] === rgba32[v2])
|
|
107153
|
+
continue;
|
|
107154
|
+
border[v0] = true;
|
|
107155
|
+
border[v1] = true;
|
|
107156
|
+
border[v2] = true;
|
|
107157
|
+
}
|
|
107158
|
+
return border;
|
|
107159
|
+
}
|
|
106088
107160
|
NVMesh.prototype.updateMesh = function(gl) {
|
|
106089
107161
|
if (this.offsetPt0) {
|
|
106090
107162
|
this.updateFibers(gl);
|
|
@@ -106104,16 +107176,25 @@ NVMesh.prototype.updateMesh = function(gl) {
|
|
|
106104
107176
|
let lerp2 = function(x2, y, a) {
|
|
106105
107177
|
return x2 * (1 - a) + y * a;
|
|
106106
107178
|
};
|
|
107179
|
+
let nvtx = this.pts.length / 3;
|
|
106107
107180
|
let layer = this.layers[i2];
|
|
106108
|
-
if (layer.opacity <= 0 || layer.cal_min
|
|
107181
|
+
if (layer.opacity <= 0 || layer.cal_min > layer.cal_max)
|
|
106109
107182
|
continue;
|
|
106110
107183
|
let opacity = layer.opacity;
|
|
106111
107184
|
var u82 = new Uint8Array(posNormClr.buffer);
|
|
106112
107185
|
if (layer.values.constructor === Uint32Array) {
|
|
106113
107186
|
let rgba8 = new Uint8Array(layer.values.buffer);
|
|
107187
|
+
let opaque = new Array(nvtx).fill(true);
|
|
107188
|
+
if (layer.isOutlineBorder)
|
|
107189
|
+
opaque = getClusterBoundary(rgba8, this.tris);
|
|
106114
107190
|
let k = 0;
|
|
106115
107191
|
for (let j = 0; j < layer.values.length; j++) {
|
|
106116
107192
|
let vtx = j * 28 + 24;
|
|
107193
|
+
if (!opaque[j]) {
|
|
107194
|
+
u82[vtx + 3] = 0;
|
|
107195
|
+
k += 4;
|
|
107196
|
+
continue;
|
|
107197
|
+
}
|
|
106117
107198
|
u82[vtx + 0] = lerp2(u82[vtx + 0], rgba8[k + 0], opacity);
|
|
106118
107199
|
u82[vtx + 1] = lerp2(u82[vtx + 1], rgba8[k + 1], opacity);
|
|
106119
107200
|
u82[vtx + 2] = lerp2(u82[vtx + 2], rgba8[k + 2], opacity);
|
|
@@ -106123,34 +107204,76 @@ NVMesh.prototype.updateMesh = function(gl) {
|
|
|
106123
107204
|
}
|
|
106124
107205
|
let lut = cmapper$1.colormap(layer.colorMap);
|
|
106125
107206
|
let frame = Math.min(Math.max(layer.frame4D, 0), layer.nFrame4D - 1);
|
|
106126
|
-
let nvtx = this.pts.length / 3;
|
|
106127
107207
|
let frameOffset = nvtx * frame;
|
|
106128
107208
|
if (layer.useNegativeCmap) {
|
|
106129
107209
|
layer.cal_min = Math.max(0, layer.cal_min);
|
|
106130
107210
|
layer.cal_max = Math.max(layer.cal_min + 1e-6, layer.cal_max);
|
|
106131
107211
|
}
|
|
106132
107212
|
let scale255 = 255 / (layer.cal_max - layer.cal_min);
|
|
106133
|
-
|
|
106134
|
-
let v255 = Math.round((layer.values[j + frameOffset] - layer.cal_min) * scale255);
|
|
106135
|
-
if (v255 < 0)
|
|
106136
|
-
continue;
|
|
106137
|
-
v255 = Math.min(255, v255) * 4;
|
|
106138
|
-
let vtx = j * 28 + 24;
|
|
106139
|
-
u82[vtx + 0] = lerp2(u82[vtx + 0], lut[v255 + 0], opacity);
|
|
106140
|
-
u82[vtx + 1] = lerp2(u82[vtx + 1], lut[v255 + 1], opacity);
|
|
106141
|
-
u82[vtx + 2] = lerp2(u82[vtx + 2], lut[v255 + 2], opacity);
|
|
106142
|
-
}
|
|
106143
|
-
if (layer.useNegativeCmap) {
|
|
106144
|
-
let lut2 = cmapper$1.colormap(layer.colorMapNegative);
|
|
107213
|
+
if (!layer.isOutlineBorder) {
|
|
106145
107214
|
for (let j = 0; j < nvtx; j++) {
|
|
106146
|
-
let v255 = Math.round((
|
|
107215
|
+
let v255 = Math.round((layer.values[j + frameOffset] - layer.cal_min) * scale255);
|
|
106147
107216
|
if (v255 < 0)
|
|
106148
107217
|
continue;
|
|
106149
107218
|
v255 = Math.min(255, v255) * 4;
|
|
106150
107219
|
let vtx = j * 28 + 24;
|
|
106151
|
-
u82[vtx + 0] = lerp2(u82[vtx + 0],
|
|
106152
|
-
u82[vtx + 1] = lerp2(u82[vtx + 1],
|
|
106153
|
-
u82[vtx + 2] = lerp2(u82[vtx + 2],
|
|
107220
|
+
u82[vtx + 0] = lerp2(u82[vtx + 0], lut[v255 + 0], opacity);
|
|
107221
|
+
u82[vtx + 1] = lerp2(u82[vtx + 1], lut[v255 + 1], opacity);
|
|
107222
|
+
u82[vtx + 2] = lerp2(u82[vtx + 2], lut[v255 + 2], opacity);
|
|
107223
|
+
}
|
|
107224
|
+
} else {
|
|
107225
|
+
let v255s = new Uint8Array(nvtx);
|
|
107226
|
+
for (let j = 0; j < nvtx; j++) {
|
|
107227
|
+
let v255 = Math.round((layer.values[j + frameOffset] - layer.cal_min) * scale255);
|
|
107228
|
+
if (v255 < 0)
|
|
107229
|
+
continue;
|
|
107230
|
+
v255 = Math.min(255, v255);
|
|
107231
|
+
v255s[j] = v255;
|
|
107232
|
+
}
|
|
107233
|
+
let opaque = getClusterBoundaryU8(v255s, this.tris);
|
|
107234
|
+
for (let j = 0; j < nvtx; j++) {
|
|
107235
|
+
let v255 = 255;
|
|
107236
|
+
if (!opaque[j])
|
|
107237
|
+
continue;
|
|
107238
|
+
v255 = Math.min(255, v255) * 4;
|
|
107239
|
+
let vtx = j * 28 + 24;
|
|
107240
|
+
u82[vtx + 0] = lerp2(u82[vtx + 0], lut[v255 + 0], opacity);
|
|
107241
|
+
u82[vtx + 1] = lerp2(u82[vtx + 1], lut[v255 + 1], opacity);
|
|
107242
|
+
u82[vtx + 2] = lerp2(u82[vtx + 2], lut[v255 + 2], opacity);
|
|
107243
|
+
}
|
|
107244
|
+
}
|
|
107245
|
+
if (layer.useNegativeCmap) {
|
|
107246
|
+
let lut2 = cmapper$1.colormap(layer.colorMapNegative);
|
|
107247
|
+
if (!layer.isOutlineBorder) {
|
|
107248
|
+
for (let j = 0; j < nvtx; j++) {
|
|
107249
|
+
let v255 = Math.round((-layer.values[j + frameOffset] - layer.cal_min) * scale255);
|
|
107250
|
+
if (v255 < 0)
|
|
107251
|
+
continue;
|
|
107252
|
+
v255 = Math.min(255, v255) * 4;
|
|
107253
|
+
let vtx = j * 28 + 24;
|
|
107254
|
+
u82[vtx + 0] = lerp2(u82[vtx + 0], lut2[v255 + 0], opacity);
|
|
107255
|
+
u82[vtx + 1] = lerp2(u82[vtx + 1], lut2[v255 + 1], opacity);
|
|
107256
|
+
u82[vtx + 2] = lerp2(u82[vtx + 2], lut2[v255 + 2], opacity);
|
|
107257
|
+
}
|
|
107258
|
+
} else {
|
|
107259
|
+
let v255s = new Uint8Array(nvtx);
|
|
107260
|
+
for (let j = 0; j < nvtx; j++) {
|
|
107261
|
+
let v255 = Math.round((-layer.values[j + frameOffset] - layer.cal_min) * scale255);
|
|
107262
|
+
if (v255 < 0)
|
|
107263
|
+
continue;
|
|
107264
|
+
v255s[j] = Math.min(255, v255);
|
|
107265
|
+
}
|
|
107266
|
+
let opaque = getClusterBoundaryU8(v255s, this.tris);
|
|
107267
|
+
for (let j = 0; j < nvtx; j++) {
|
|
107268
|
+
let v255 = 255;
|
|
107269
|
+
if (!opaque[j])
|
|
107270
|
+
continue;
|
|
107271
|
+
v255 = Math.min(255, v255) * 4;
|
|
107272
|
+
let vtx = j * 28 + 24;
|
|
107273
|
+
u82[vtx + 0] = lerp2(u82[vtx + 0], lut2[v255 + 0], opacity);
|
|
107274
|
+
u82[vtx + 1] = lerp2(u82[vtx + 1], lut2[v255 + 1], opacity);
|
|
107275
|
+
u82[vtx + 2] = lerp2(u82[vtx + 2], lut2[v255 + 2], opacity);
|
|
107276
|
+
}
|
|
106154
107277
|
}
|
|
106155
107278
|
}
|
|
106156
107279
|
}
|
|
@@ -106336,7 +107459,6 @@ NVMesh.readTRACT = function(buffer2) {
|
|
|
106336
107459
|
let bundleTag = readNumericTag("Bundle_Tag=");
|
|
106337
107460
|
let isLittleEndian2 = line.includes("binary.lsbfirst");
|
|
106338
107461
|
for (let i2 = 0; i2 < new_tracts; i2++) {
|
|
106339
|
-
reader.getUint32(pos, isLittleEndian2);
|
|
106340
107462
|
pos += 4;
|
|
106341
107463
|
let new_pts = reader.getUint32(pos, isLittleEndian2) / 3;
|
|
106342
107464
|
pos += 4;
|
|
@@ -106768,10 +107890,7 @@ NVMesh.readSMP = function(buffer2, n_vert) {
|
|
|
106768
107890
|
return scalars;
|
|
106769
107891
|
};
|
|
106770
107892
|
NVMesh.readSTC = function(buffer2, n_vert) {
|
|
106771
|
-
buffer2.byteLength;
|
|
106772
107893
|
var reader = new DataView(buffer2);
|
|
106773
|
-
reader.getFloat32(0, false);
|
|
106774
|
-
reader.getFloat32(4, false);
|
|
106775
107894
|
let n_vertex = reader.getInt32(8, false);
|
|
106776
107895
|
if (n_vertex !== n_vert) {
|
|
106777
107896
|
console.log("Overlay has " + n_vertex + " vertices, expected " + n_vert);
|
|
@@ -106793,7 +107912,6 @@ NVMesh.readCURV = function(buffer2, n_vert) {
|
|
|
106793
107912
|
let sig1 = view.getUint8(1);
|
|
106794
107913
|
let sig2 = view.getUint8(2);
|
|
106795
107914
|
let n_vertex = view.getUint32(3, false);
|
|
106796
|
-
view.getUint32(7, false);
|
|
106797
107915
|
let n_time = view.getUint32(11, false);
|
|
106798
107916
|
if (sig0 !== 255 || sig1 !== 255 || sig2 !== 255)
|
|
106799
107917
|
log$1.debug("Unable to recognize file type: does not appear to be FreeSurfer format.");
|
|
@@ -107385,7 +108503,7 @@ NVMesh.readPLY = function(buffer2) {
|
|
|
107385
108503
|
indices
|
|
107386
108504
|
};
|
|
107387
108505
|
};
|
|
107388
|
-
NVMesh.readLayer = function(name, buffer2, nvmesh, opacity = 0.5, colorMap = "warm", colorMapNegative = "winter", useNegativeCmap = false, cal_min = null, cal_max = null) {
|
|
108506
|
+
NVMesh.readLayer = function(name, buffer2, nvmesh, opacity = 0.5, colorMap = "warm", colorMapNegative = "winter", useNegativeCmap = false, cal_min = null, cal_max = null, isOutlineBorder = false) {
|
|
107389
108507
|
let layer = [];
|
|
107390
108508
|
let n_vert = nvmesh.vertexCount / 3;
|
|
107391
108509
|
if (n_vert < 3)
|
|
@@ -107421,6 +108539,7 @@ NVMesh.readLayer = function(name, buffer2, nvmesh, opacity = 0.5, colorMap = "wa
|
|
|
107421
108539
|
return;
|
|
107422
108540
|
layer.nFrame4D = layer.values.length / n_vert;
|
|
107423
108541
|
layer.frame4D = 0;
|
|
108542
|
+
layer.isOutlineBorder = isOutlineBorder;
|
|
107424
108543
|
let mn = layer.values[0];
|
|
107425
108544
|
let mx = layer.values[0];
|
|
107426
108545
|
for (var i2 = 0; i2 < layer.values.length; i2++) {
|
|
@@ -107445,7 +108564,6 @@ NVMesh.readOFF = function(buffer2) {
|
|
|
107445
108564
|
var enc = new TextDecoder("utf-8");
|
|
107446
108565
|
var txt = enc.decode(buffer2);
|
|
107447
108566
|
var lines = txt.split("\n");
|
|
107448
|
-
lines.length;
|
|
107449
108567
|
let pts = [];
|
|
107450
108568
|
let t = [];
|
|
107451
108569
|
let i2 = 0;
|
|
@@ -107688,8 +108806,10 @@ NVMesh.readNII2 = function(buffer2, n_vert = 0) {
|
|
|
107688
108806
|
return scalars;
|
|
107689
108807
|
}
|
|
107690
108808
|
let voxoffset2 = Number(reader.getBigInt64(168, isLittleEndian2));
|
|
107691
|
-
reader.getFloat64(176, isLittleEndian2);
|
|
107692
|
-
reader.getFloat64(184, isLittleEndian2);
|
|
108809
|
+
let scl_slope = reader.getFloat64(176, isLittleEndian2);
|
|
108810
|
+
let scl_inter = reader.getFloat64(184, isLittleEndian2);
|
|
108811
|
+
if (scl_slope !== 1 || scl_inter !== 0)
|
|
108812
|
+
console.log("ignoring scale slope and intercept");
|
|
107693
108813
|
let intent_code = reader.getUint32(504, isLittleEndian2);
|
|
107694
108814
|
let datatype = reader.getUint16(12, isLittleEndian2);
|
|
107695
108815
|
if (datatype !== 2 && datatype !== 4 && datatype !== 8 && datatype !== 16) {
|
|
@@ -107839,7 +108959,6 @@ NVMesh.readNII2 = function(buffer2, n_vert = 0) {
|
|
|
107839
108959
|
};
|
|
107840
108960
|
NVMesh.readNII = function(buffer2, n_vert = 0) {
|
|
107841
108961
|
let scalars = [];
|
|
107842
|
-
buffer2.byteLength;
|
|
107843
108962
|
let isLittleEndian2 = true;
|
|
107844
108963
|
var reader = new DataView(buffer2);
|
|
107845
108964
|
var magic = reader.getUint16(0, isLittleEndian2);
|
|
@@ -107864,8 +108983,10 @@ NVMesh.readNII = function(buffer2, n_vert = 0) {
|
|
|
107864
108983
|
if (magic !== 348)
|
|
107865
108984
|
console.log("Not a valid NIfTI image.");
|
|
107866
108985
|
let voxoffset2 = reader.getFloat32(108, isLittleEndian2);
|
|
107867
|
-
reader.getFloat32(112, isLittleEndian2);
|
|
107868
|
-
reader.getFloat32(116, isLittleEndian2);
|
|
108986
|
+
let scl_slope = reader.getFloat32(112, isLittleEndian2);
|
|
108987
|
+
let scl_inter = reader.getFloat32(116, isLittleEndian2);
|
|
108988
|
+
if (scl_slope !== 1 || scl_inter !== 0)
|
|
108989
|
+
console.log("ignoring scale slope and intercept");
|
|
107869
108990
|
let datatype = reader.getUint16(70, isLittleEndian2);
|
|
107870
108991
|
if (datatype !== 2 && datatype !== 4 && datatype !== 8 && datatype !== 16) {
|
|
107871
108992
|
console.log("Unsupported NIfTI datatype " + datatype);
|
|
@@ -108149,7 +109270,6 @@ NVMesh.readX3D = function(buffer2, n_vert = 0) {
|
|
|
108149
109270
|
rotation[1],
|
|
108150
109271
|
rotation[2]
|
|
108151
109272
|
]);
|
|
108152
|
-
fromValues(translation[0], translation[1], translation[2], 1);
|
|
108153
109273
|
let pti = fromValues(0, -height * 0.5, 0, 1);
|
|
108154
109274
|
let ptj = fromValues(0, +height * 0.5, 0, 1);
|
|
108155
109275
|
transformMat4(pti, pti, r);
|
|
@@ -110409,8 +111529,82 @@ var WebSocketSubject = function(_super) {
|
|
|
110409
111529
|
function webSocket(urlConfigOrSource) {
|
|
110410
111530
|
return new WebSocketSubject(urlConfigOrSource);
|
|
110411
111531
|
}
|
|
111532
|
+
const UPDATE = "update";
|
|
111533
|
+
const CREATE = "create";
|
|
111534
|
+
const JOIN = "join";
|
|
111535
|
+
const ADD_VOLUME_URL = "add volume url";
|
|
111536
|
+
const REMOVE_VOLUME_URL = "remove volume media";
|
|
111537
|
+
const ADD_MESH_URL = "add mesh url";
|
|
111538
|
+
const REMOVE_MESH_URL = "remove mesh media";
|
|
111539
|
+
const SET_4D_VOL_INDEX = "set 4d vol index";
|
|
111540
|
+
const UPDATE_IMAGE_OPTIONS = "update image options";
|
|
111541
|
+
function NVMesssageUpdateData(azimuth, elevation, clipPlane, zoom) {
|
|
111542
|
+
return {
|
|
111543
|
+
azimuth,
|
|
111544
|
+
elevation,
|
|
111545
|
+
clipPlane,
|
|
111546
|
+
zoom
|
|
111547
|
+
};
|
|
111548
|
+
}
|
|
111549
|
+
function NVMessageSet4DVolumeIndexData(url, index) {
|
|
111550
|
+
return {
|
|
111551
|
+
url,
|
|
111552
|
+
index
|
|
111553
|
+
};
|
|
111554
|
+
}
|
|
111555
|
+
function NVMessage(messageType, messageData = "", sessionKey = "") {
|
|
111556
|
+
let message = {};
|
|
111557
|
+
message.key = sessionKey;
|
|
111558
|
+
message.op = messageType;
|
|
111559
|
+
switch (messageType) {
|
|
111560
|
+
case UPDATE:
|
|
111561
|
+
Object.assign(message, messageData);
|
|
111562
|
+
break;
|
|
111563
|
+
case UPDATE_IMAGE_OPTIONS:
|
|
111564
|
+
case ADD_VOLUME_URL:
|
|
111565
|
+
message.urlImageOptions = messageData;
|
|
111566
|
+
break;
|
|
111567
|
+
case ADD_MESH_URL:
|
|
111568
|
+
message.urlMeshOptions = messageData;
|
|
111569
|
+
break;
|
|
111570
|
+
case REMOVE_VOLUME_URL:
|
|
111571
|
+
case REMOVE_MESH_URL:
|
|
111572
|
+
message.url = messageData;
|
|
111573
|
+
break;
|
|
111574
|
+
case SET_4D_VOL_INDEX:
|
|
111575
|
+
message.url = messageData.url;
|
|
111576
|
+
message.index = messageData.index;
|
|
111577
|
+
break;
|
|
111578
|
+
}
|
|
111579
|
+
return message;
|
|
111580
|
+
}
|
|
110412
111581
|
const log = new Log();
|
|
110413
111582
|
const cmapper = new colortables();
|
|
111583
|
+
const MESH_EXTENSIONS = [
|
|
111584
|
+
"ASC",
|
|
111585
|
+
"DFS",
|
|
111586
|
+
"FSM",
|
|
111587
|
+
"PIAL",
|
|
111588
|
+
"ORIG",
|
|
111589
|
+
"INFLATED",
|
|
111590
|
+
"SMOOTHWM",
|
|
111591
|
+
"SPHERE",
|
|
111592
|
+
"WHITE",
|
|
111593
|
+
"GII",
|
|
111594
|
+
"MZ3",
|
|
111595
|
+
"NV",
|
|
111596
|
+
"OBJ",
|
|
111597
|
+
"OFF",
|
|
111598
|
+
"PLY",
|
|
111599
|
+
"SRF",
|
|
111600
|
+
"STL",
|
|
111601
|
+
"TCK",
|
|
111602
|
+
"TRACT",
|
|
111603
|
+
"TRK",
|
|
111604
|
+
"TRX",
|
|
111605
|
+
"VTK",
|
|
111606
|
+
"X3D"
|
|
111607
|
+
];
|
|
110414
111608
|
function Niivue(options = {}) {
|
|
110415
111609
|
this.opts = {};
|
|
110416
111610
|
this.defaults = {
|
|
@@ -110428,17 +111622,24 @@ function Niivue(options = {}) {
|
|
|
110428
111622
|
trustCalMinMax: true,
|
|
110429
111623
|
clipPlaneHotKey: "KeyC",
|
|
110430
111624
|
viewModeHotKey: "KeyV",
|
|
111625
|
+
doubleTouchTimeout: 500,
|
|
111626
|
+
longTouchTimeout: 1e3,
|
|
110431
111627
|
keyDebounceTime: 50,
|
|
110432
111628
|
isNearestInterpolation: false,
|
|
110433
111629
|
isAtlasOutline: false,
|
|
110434
111630
|
isRuler: false,
|
|
110435
111631
|
isColorbar: false,
|
|
111632
|
+
isOrientCube: false,
|
|
111633
|
+
multiplanarPadPixels: 0,
|
|
110436
111634
|
isRadiologicalConvention: false,
|
|
110437
111635
|
meshThicknessOn2D: Infinity,
|
|
110438
111636
|
isDragShowsMeasurementTool: false,
|
|
111637
|
+
isDragForPanZoom: false,
|
|
111638
|
+
isDepthPickMesh: false,
|
|
110439
111639
|
isCornerOrientationText: false,
|
|
110440
111640
|
sagittalNoseLeft: false,
|
|
110441
111641
|
isSliceMM: false,
|
|
111642
|
+
isHighResolutionCapable: true,
|
|
110442
111643
|
logging: false,
|
|
110443
111644
|
loadingText: "waiting for images...",
|
|
110444
111645
|
dragAndDropEnabled: true,
|
|
@@ -110446,11 +111647,20 @@ function Niivue(options = {}) {
|
|
|
110446
111647
|
penValue: 1,
|
|
110447
111648
|
isFilledPen: false,
|
|
110448
111649
|
thumbnail: "",
|
|
111650
|
+
maxDrawUndoBitmaps: 8,
|
|
110449
111651
|
onLocationChange: () => {
|
|
110450
111652
|
},
|
|
110451
111653
|
onIntensityChange: () => {
|
|
110452
111654
|
},
|
|
110453
111655
|
onImageLoaded: () => {
|
|
111656
|
+
},
|
|
111657
|
+
onError: () => {
|
|
111658
|
+
},
|
|
111659
|
+
onInfo: () => {
|
|
111660
|
+
},
|
|
111661
|
+
onWarn: () => {
|
|
111662
|
+
},
|
|
111663
|
+
onDebug: () => {
|
|
110454
111664
|
}
|
|
110455
111665
|
};
|
|
110456
111666
|
this.canvas = null;
|
|
@@ -110459,8 +111669,6 @@ function Niivue(options = {}) {
|
|
|
110459
111669
|
this.volumeTexture = null;
|
|
110460
111670
|
this.drawTexture = null;
|
|
110461
111671
|
this.drawBitmap = null;
|
|
110462
|
-
this.maxDrawUndoBitmaps = 8;
|
|
110463
|
-
this.currentDrawUndoBitmap = this.maxDrawUndoBitmaps;
|
|
110464
111672
|
this.drawUndoBitmaps = [];
|
|
110465
111673
|
this.drawOpacity = 0.8;
|
|
110466
111674
|
this.colorbarHeight = 0;
|
|
@@ -110472,10 +111680,12 @@ function Niivue(options = {}) {
|
|
|
110472
111680
|
this.overlayTextureID = [];
|
|
110473
111681
|
this.sliceShader = null;
|
|
110474
111682
|
this.sliceMMShader = null;
|
|
111683
|
+
this.orientCubeShader = null;
|
|
111684
|
+
this.orientCubeShaderVAO = null;
|
|
110475
111685
|
this.rectShader = null;
|
|
110476
|
-
this.graphShader = null;
|
|
110477
111686
|
this.renderShader = null;
|
|
110478
|
-
this.
|
|
111687
|
+
this.pickingMeshShader = null;
|
|
111688
|
+
this.pickingImageShader = null;
|
|
110479
111689
|
this.colorbarShader = null;
|
|
110480
111690
|
this.fontShader = null;
|
|
110481
111691
|
this.fontTexture = null;
|
|
@@ -110491,11 +111701,9 @@ function Niivue(options = {}) {
|
|
|
110491
111701
|
this.orientShaderF = null;
|
|
110492
111702
|
this.orientShaderRGBU = null;
|
|
110493
111703
|
this.surfaceShader = null;
|
|
110494
|
-
this.meshShader = null;
|
|
110495
111704
|
this.genericVAO = null;
|
|
110496
111705
|
this.unusedVAO = null;
|
|
110497
111706
|
this.crosshairs3D = null;
|
|
110498
|
-
this.pickingSurfaceShader = null;
|
|
110499
111707
|
this.DEFAULT_FONT_GLYPH_SHEET = defaultFontPNG;
|
|
110500
111708
|
this.DEFAULT_FONT_METRICS = defaultFontMetrics;
|
|
110501
111709
|
this.fontMets = null;
|
|
@@ -110523,11 +111731,15 @@ function Niivue(options = {}) {
|
|
|
110523
111731
|
this.scene.mouseButtonRightDown = false;
|
|
110524
111732
|
this.scene.mouseDepthPicker = false;
|
|
110525
111733
|
this.scene.pan2Dxyzmm = [0, 0, 0, 1];
|
|
110526
|
-
this.scene.
|
|
111734
|
+
this.scene.pan2DxyzmmAtMouseDown = [0, 0, 0, 1];
|
|
110527
111735
|
this.scene.prevX = 0;
|
|
110528
111736
|
this.scene.prevY = 0;
|
|
110529
111737
|
this.scene.currX = 0;
|
|
110530
111738
|
this.scene.currY = 0;
|
|
111739
|
+
this.currentTouchTime = 0;
|
|
111740
|
+
this.lastTouchTime = 0;
|
|
111741
|
+
this.touchTimer = null;
|
|
111742
|
+
this.doubleTouch = false;
|
|
110531
111743
|
this.back = {};
|
|
110532
111744
|
this.overlays = [];
|
|
110533
111745
|
this.volumes = [];
|
|
@@ -110588,10 +111800,6 @@ function Niivue(options = {}) {
|
|
|
110588
111800
|
{
|
|
110589
111801
|
Name: "Toon",
|
|
110590
111802
|
Frag: fragMeshToonShader
|
|
110591
|
-
},
|
|
110592
|
-
{
|
|
110593
|
-
Name: "Depth",
|
|
110594
|
-
Frag: fragMeshDepthShader
|
|
110595
111803
|
}
|
|
110596
111804
|
];
|
|
110597
111805
|
this.isController = false;
|
|
@@ -110600,10 +111808,12 @@ function Niivue(options = {}) {
|
|
|
110600
111808
|
this.sessionUrl = "";
|
|
110601
111809
|
this.serverConnection$ = null;
|
|
110602
111810
|
this.interval$ = null;
|
|
111811
|
+
this.mediaUrlMap = /* @__PURE__ */ new Map();
|
|
110603
111812
|
this.initialized = false;
|
|
110604
111813
|
for (let prop in this.defaults) {
|
|
110605
111814
|
this.opts[prop] = options[prop] === void 0 ? this.defaults[prop] : options[prop];
|
|
110606
111815
|
}
|
|
111816
|
+
this.currentDrawUndoBitmap = this.opts.maxDrawUndoBitmaps;
|
|
110607
111817
|
if (this.opts.drawingEnabled) {
|
|
110608
111818
|
this.createEmptyDrawing();
|
|
110609
111819
|
}
|
|
@@ -110616,6 +111826,11 @@ function Niivue(options = {}) {
|
|
|
110616
111826
|
loading: this.scene.loading$
|
|
110617
111827
|
};
|
|
110618
111828
|
this.subscriptions = [];
|
|
111829
|
+
if (this.opts.isHighResolutionCapable) {
|
|
111830
|
+
this.scene.dpr = window.devicePixelRatio || 1;
|
|
111831
|
+
} else {
|
|
111832
|
+
this.scene.dpr = 1;
|
|
111833
|
+
}
|
|
110619
111834
|
}
|
|
110620
111835
|
Niivue.prototype.saveScene = function(filename = "") {
|
|
110621
111836
|
function saveBlob(blob, name) {
|
|
@@ -110719,49 +111934,80 @@ Niivue.prototype.connectToServer = function(wsServerUrl, sessionName) {
|
|
|
110719
111934
|
Niivue.prototype.setUpdateInterval = function() {
|
|
110720
111935
|
this.interval$ = interval(300);
|
|
110721
111936
|
this.interval$.subscribe(() => {
|
|
110722
|
-
this.serverConnection$.next(
|
|
110723
|
-
op: "update",
|
|
110724
|
-
azimuth: this.scene.renderAzimuth,
|
|
110725
|
-
elevation: this.scene.renderElevation,
|
|
110726
|
-
clipPlane: this.scene.clipPlane,
|
|
110727
|
-
zoom: this.volScaleMultiplier,
|
|
110728
|
-
key: this.sessionKey
|
|
110729
|
-
});
|
|
111937
|
+
this.serverConnection$.next(new NVMessage(UPDATE, new NVMesssageUpdateData(this.scene.renderAzimuth, this.scene.renderElevation, this.scene.clipPlane, this.volScaleMultiplier), this.sessionKey));
|
|
110730
111938
|
});
|
|
110731
111939
|
};
|
|
111940
|
+
Niivue.prototype.handleMessage = function(msg2, sessionCreatedCallback, sessionJoinedCallback) {
|
|
111941
|
+
switch (msg2["op"]) {
|
|
111942
|
+
case UPDATE:
|
|
111943
|
+
this.scene.renderAzimuth = msg2["azimuth"];
|
|
111944
|
+
this.scene.renderElevation = msg2["elevation"];
|
|
111945
|
+
this.volScaleMultiplier = msg2["zoom"];
|
|
111946
|
+
this.scene.clipPlane = msg2["clipPlane"];
|
|
111947
|
+
this.drawScene();
|
|
111948
|
+
break;
|
|
111949
|
+
case CREATE:
|
|
111950
|
+
console.log(msg2);
|
|
111951
|
+
if (!msg2["isError"]) {
|
|
111952
|
+
this.isInSession = true;
|
|
111953
|
+
this.sessionKey = msg2["key"];
|
|
111954
|
+
this.setUpdateInterval();
|
|
111955
|
+
}
|
|
111956
|
+
if (sessionCreatedCallback) {
|
|
111957
|
+
sessionCreatedCallback(msg2["message"], msg2["url"], msg2["key"], msg2["isError"], msg2["userKey"]);
|
|
111958
|
+
}
|
|
111959
|
+
break;
|
|
111960
|
+
case JOIN:
|
|
111961
|
+
this.isInSession = true;
|
|
111962
|
+
this.isController = msg2["isController"];
|
|
111963
|
+
if (this.isController) {
|
|
111964
|
+
this.setUpdateInterval();
|
|
111965
|
+
}
|
|
111966
|
+
if (sessionJoinedCallback) {
|
|
111967
|
+
sessionJoinedCallback(msg2["message"], msg2["url"], msg2["isController"], msg2["userKey"]);
|
|
111968
|
+
}
|
|
111969
|
+
break;
|
|
111970
|
+
case ADD_MESH_URL:
|
|
111971
|
+
this.addMeshFromUrl(msg2["urlMeshOptions"], false);
|
|
111972
|
+
break;
|
|
111973
|
+
case ADD_VOLUME_URL:
|
|
111974
|
+
this.addVolumeFromUrl(msg2["urlImageOptions"], false);
|
|
111975
|
+
break;
|
|
111976
|
+
case REMOVE_VOLUME_URL:
|
|
111977
|
+
{
|
|
111978
|
+
let volume = this.getMediaByUrl(msg2["url"]);
|
|
111979
|
+
if (volume) {
|
|
111980
|
+
this.removeVolume(volume, false);
|
|
111981
|
+
}
|
|
111982
|
+
}
|
|
111983
|
+
break;
|
|
111984
|
+
case REMOVE_MESH_URL: {
|
|
111985
|
+
let mesh = this.getMediaByUrl(msg2["url"]);
|
|
111986
|
+
if (mesh) {
|
|
111987
|
+
this.removeMesh(mesh, false);
|
|
111988
|
+
}
|
|
111989
|
+
}
|
|
111990
|
+
case SET_4D_VOL_INDEX:
|
|
111991
|
+
{
|
|
111992
|
+
let volume = this.getMediaByUrl(msg2["url"]);
|
|
111993
|
+
if (volume) {
|
|
111994
|
+
this.setFrame4D(volume.id, msg2["index"]);
|
|
111995
|
+
}
|
|
111996
|
+
}
|
|
111997
|
+
break;
|
|
111998
|
+
case UPDATE_IMAGE_OPTIONS: {
|
|
111999
|
+
let volume = this.getMediaByUrl(msg2["urlImageOptions"].url);
|
|
112000
|
+
if (volume) {
|
|
112001
|
+
volume.applyOptionsUpdate(msg2["urlImageOptions"]);
|
|
112002
|
+
this.updateGLVolume();
|
|
112003
|
+
}
|
|
112004
|
+
}
|
|
112005
|
+
}
|
|
112006
|
+
};
|
|
110732
112007
|
Niivue.prototype.subscribeToServer = function(sessionCreatedCallback, sessionJoinedCallback) {
|
|
110733
112008
|
this.serverConnection$.subscribe({
|
|
110734
112009
|
next: (msg2) => {
|
|
110735
|
-
|
|
110736
|
-
case "update":
|
|
110737
|
-
this.scene.renderAzimuth = msg2["azimuth"];
|
|
110738
|
-
this.scene.renderElevation = msg2["elevation"];
|
|
110739
|
-
this.volScaleMultiplier = msg2["zoom"];
|
|
110740
|
-
this.scene.clipPlane = msg2["clipPlane"];
|
|
110741
|
-
this.drawScene();
|
|
110742
|
-
break;
|
|
110743
|
-
case "create":
|
|
110744
|
-
console.log(msg2);
|
|
110745
|
-
if (!msg2["isError"]) {
|
|
110746
|
-
this.isInSession = true;
|
|
110747
|
-
this.sessionKey = msg2["key"];
|
|
110748
|
-
this.setUpdateInterval();
|
|
110749
|
-
}
|
|
110750
|
-
if (sessionCreatedCallback) {
|
|
110751
|
-
sessionCreatedCallback(msg2["message"], msg2["url"], msg2["key"], msg2["isError"]);
|
|
110752
|
-
}
|
|
110753
|
-
break;
|
|
110754
|
-
case "join":
|
|
110755
|
-
this.isInSession = true;
|
|
110756
|
-
this.isController = msg2["isController"];
|
|
110757
|
-
if (this.isController) {
|
|
110758
|
-
this.setUpdateInterval();
|
|
110759
|
-
}
|
|
110760
|
-
if (sessionJoinedCallback) {
|
|
110761
|
-
sessionJoinedCallback(msg2["message"], msg2["url"], msg2["isController"]);
|
|
110762
|
-
}
|
|
110763
|
-
break;
|
|
110764
|
-
}
|
|
112010
|
+
this.handleMessage(msg2, sessionCreatedCallback, sessionJoinedCallback);
|
|
110765
112011
|
},
|
|
110766
112012
|
error: (err2) => console.log(err2),
|
|
110767
112013
|
complete: () => console.log("complete")
|
|
@@ -110770,17 +112016,12 @@ Niivue.prototype.subscribeToServer = function(sessionCreatedCallback, sessionJoi
|
|
|
110770
112016
|
Niivue.prototype.createSession = function(wsServerUrl, sessionName, sessionCreatedCallback) {
|
|
110771
112017
|
this.connectToServer(wsServerUrl, sessionName);
|
|
110772
112018
|
this.subscribeToServer(sessionCreatedCallback);
|
|
110773
|
-
this.serverConnection$.next(
|
|
110774
|
-
op: "create"
|
|
110775
|
-
});
|
|
112019
|
+
this.serverConnection$.next(new NVMessage(CREATE));
|
|
110776
112020
|
};
|
|
110777
112021
|
Niivue.prototype.joinSession = function(wsServerUrl, sessionName, key2, sessionJoinedCallback) {
|
|
110778
112022
|
this.connectToServer(wsServerUrl, sessionName);
|
|
110779
112023
|
this.subscribeToServer(null, sessionJoinedCallback);
|
|
110780
|
-
this.serverConnection$.next(
|
|
110781
|
-
op: "join",
|
|
110782
|
-
key: key2
|
|
110783
|
-
});
|
|
112024
|
+
this.serverConnection$.next(new NVMessage(JOIN, key2));
|
|
110784
112025
|
};
|
|
110785
112026
|
Niivue.prototype.closeSession = function() {
|
|
110786
112027
|
this.interval$.complete();
|
|
@@ -110794,8 +112035,19 @@ Niivue.prototype.arrayEquals = function(a, b) {
|
|
|
110794
112035
|
Niivue.prototype.resizeListener = function() {
|
|
110795
112036
|
this.canvas.style.width = "100%";
|
|
110796
112037
|
this.canvas.style.height = "100%";
|
|
110797
|
-
this.
|
|
110798
|
-
|
|
112038
|
+
if (this.opts.isHighResolutionCapable) {
|
|
112039
|
+
this.scene.dpr = window.devicePixelRatio || 1;
|
|
112040
|
+
console.log("devicePixelRatio: " + this.scene.dpr);
|
|
112041
|
+
} else {
|
|
112042
|
+
this.scene.dpr = 1;
|
|
112043
|
+
}
|
|
112044
|
+
if (this.canvas.parentElement.hasOwnProperty("width")) {
|
|
112045
|
+
this.canvas.width = this.canvas.parentElement.width * this.scene.dpr;
|
|
112046
|
+
this.canvas.height = this.canvas.parentElement.height * this.scene.dpr;
|
|
112047
|
+
} else {
|
|
112048
|
+
this.canvas.width = this.canvas.offsetWidth * this.scene.dpr;
|
|
112049
|
+
this.canvas.height = this.canvas.offsetHeight * this.scene.dpr;
|
|
112050
|
+
}
|
|
110799
112051
|
this.drawScene();
|
|
110800
112052
|
};
|
|
110801
112053
|
Niivue.prototype.getRelativeMousePosition = function(event, target) {
|
|
@@ -110809,8 +112061,6 @@ Niivue.prototype.getRelativeMousePosition = function(event, target) {
|
|
|
110809
112061
|
Niivue.prototype.getNoPaddingNoBorderCanvasRelativeMousePosition = function(event, target) {
|
|
110810
112062
|
target = target || event.target;
|
|
110811
112063
|
var pos = this.getRelativeMousePosition(event, target);
|
|
110812
|
-
pos.x = pos.x * target.width / target.clientWidth;
|
|
110813
|
-
pos.y = pos.y * target.height / target.clientHeight;
|
|
110814
112064
|
return pos;
|
|
110815
112065
|
};
|
|
110816
112066
|
Niivue.prototype.mouseContextMenuListener = function(e) {
|
|
@@ -110835,10 +112085,11 @@ Niivue.prototype.mouseLeftButtonHandler = function(e) {
|
|
|
110835
112085
|
this.mouseDown(pos.x, pos.y);
|
|
110836
112086
|
};
|
|
110837
112087
|
Niivue.prototype.mouseRightButtonHandler = function(e) {
|
|
110838
|
-
this.isDragging = true;
|
|
110839
112088
|
let pos = this.getNoPaddingNoBorderCanvasRelativeMousePosition(e, this.gl.canvas);
|
|
110840
|
-
this.
|
|
110841
|
-
this.
|
|
112089
|
+
this.setDragStart(pos.x, pos.y);
|
|
112090
|
+
if (!this.isDragging)
|
|
112091
|
+
this.scene.pan2DxyzmmAtMouseDown = this.scene.pan2Dxyzmm.slice();
|
|
112092
|
+
this.isDragging = true;
|
|
110842
112093
|
this.dragClipPlaneStartDepthAziElev = this.scene.clipPlaneDepthAziElev;
|
|
110843
112094
|
return;
|
|
110844
112095
|
};
|
|
@@ -110870,13 +112121,11 @@ Niivue.prototype.calculateNewRange = function(volIdx = 0) {
|
|
|
110870
112121
|
if (frac[0] < 0)
|
|
110871
112122
|
return;
|
|
110872
112123
|
let endVox = this.frac2vox(frac, volIdx);
|
|
110873
|
-
let hi = -Number.MAX_VALUE
|
|
110874
|
-
let
|
|
110875
|
-
let
|
|
110876
|
-
let
|
|
110877
|
-
|
|
110878
|
-
yrange = this.calculateMinMaxVoxIdx([startVox[1], endVox[1]]);
|
|
110879
|
-
zrange = this.calculateMinMaxVoxIdx([startVox[2], endVox[2]]);
|
|
112124
|
+
let hi = -Number.MAX_VALUE;
|
|
112125
|
+
let lo = Number.MAX_VALUE;
|
|
112126
|
+
let xrange = this.calculateMinMaxVoxIdx([startVox[0], endVox[0]]);
|
|
112127
|
+
let yrange = this.calculateMinMaxVoxIdx([startVox[1], endVox[1]]);
|
|
112128
|
+
let zrange = this.calculateMinMaxVoxIdx([startVox[2], endVox[2]]);
|
|
110880
112129
|
if (startVox[0] - endVox[0] === 0) {
|
|
110881
112130
|
xrange[1] = startVox[0] + 1;
|
|
110882
112131
|
} else if (startVox[1] - endVox[1] === 0) {
|
|
@@ -110923,6 +112172,8 @@ Niivue.prototype.mouseUpListener = function() {
|
|
|
110923
112172
|
this.drawPenAxCorSag = -1;
|
|
110924
112173
|
if (this.isDragging) {
|
|
110925
112174
|
this.isDragging = false;
|
|
112175
|
+
if (this.opts.isDragForPanZoom)
|
|
112176
|
+
return;
|
|
110926
112177
|
if (this.opts.isDragShowsMeasurementTool)
|
|
110927
112178
|
return;
|
|
110928
112179
|
this.calculateNewRange();
|
|
@@ -110939,7 +112190,26 @@ Niivue.prototype.checkMultitouch = function(e) {
|
|
|
110939
112190
|
};
|
|
110940
112191
|
Niivue.prototype.touchStartListener = function(e) {
|
|
110941
112192
|
e.preventDefault();
|
|
112193
|
+
if (!this.touchTimer) {
|
|
112194
|
+
this.touchTimer = setTimeout(() => {
|
|
112195
|
+
this.resetBriCon(e);
|
|
112196
|
+
}, this.opts.longTouchTimeout);
|
|
112197
|
+
}
|
|
110942
112198
|
this.scene.touchdown = true;
|
|
112199
|
+
this.currentTouchTime = new Date().getTime();
|
|
112200
|
+
let timeSinceTouch = this.currentTouchTime - this.lastTouchTime;
|
|
112201
|
+
if (timeSinceTouch < this.opts.doubleTouchTimeout && timeSinceTouch > 0) {
|
|
112202
|
+
this.doubleTouch = true;
|
|
112203
|
+
this.setDragStart(e.targetTouches[0].clientX - e.target.getBoundingClientRect().left, e.targetTouches[0].clientY - e.target.getBoundingClientRect().top);
|
|
112204
|
+
this.resetBriCon(e);
|
|
112205
|
+
this.lastTouchTime = this.currentTouchTime;
|
|
112206
|
+
return;
|
|
112207
|
+
} else {
|
|
112208
|
+
this.doubleTouch = false;
|
|
112209
|
+
this.setDragStart(0, 0);
|
|
112210
|
+
this.setDragEnd(0, 0);
|
|
112211
|
+
this.lastTouchTime = this.currentTouchTime;
|
|
112212
|
+
}
|
|
110943
112213
|
if (this.scene.touchdown && e.touches.length < 2) {
|
|
110944
112214
|
this.multiTouchGesture = false;
|
|
110945
112215
|
} else {
|
|
@@ -110947,10 +112217,23 @@ Niivue.prototype.touchStartListener = function(e) {
|
|
|
110947
112217
|
}
|
|
110948
112218
|
setTimeout(this.checkMultitouch.bind(this), 1, e);
|
|
110949
112219
|
};
|
|
110950
|
-
Niivue.prototype.touchEndListener = function() {
|
|
112220
|
+
Niivue.prototype.touchEndListener = function(e) {
|
|
112221
|
+
e.preventDefault();
|
|
110951
112222
|
this.scene.touchdown = false;
|
|
110952
112223
|
this.lastTwoTouchDistance = 0;
|
|
110953
112224
|
this.multiTouchGesture = false;
|
|
112225
|
+
if (this.touchTimer) {
|
|
112226
|
+
clearTimeout(this.touchTimer);
|
|
112227
|
+
this.touchTimer = null;
|
|
112228
|
+
}
|
|
112229
|
+
if (this.isDragging) {
|
|
112230
|
+
this.isDragging = false;
|
|
112231
|
+
if (this.opts.isDragShowsMeasurementTool)
|
|
112232
|
+
return;
|
|
112233
|
+
this.calculateNewRange();
|
|
112234
|
+
this.refreshLayers(this.volumes[0], 0, this.volumes.length);
|
|
112235
|
+
}
|
|
112236
|
+
this.drawScene();
|
|
110954
112237
|
};
|
|
110955
112238
|
Niivue.prototype.mouseMoveListener = function(e) {
|
|
110956
112239
|
if (this.scene.mousedown) {
|
|
@@ -110959,8 +112242,7 @@ Niivue.prototype.mouseMoveListener = function(e) {
|
|
|
110959
112242
|
this.mouseClick(pos.x, pos.y);
|
|
110960
112243
|
this.mouseMove(pos.x, pos.y);
|
|
110961
112244
|
} else if (this.scene.mouseButtonRightDown) {
|
|
110962
|
-
this.
|
|
110963
|
-
this.dragEnd[1] = pos.y;
|
|
112245
|
+
this.setDragEnd(pos.x, pos.y);
|
|
110964
112246
|
}
|
|
110965
112247
|
this.drawScene();
|
|
110966
112248
|
this.scene.prevX = this.scene.currX;
|
|
@@ -110968,12 +112250,24 @@ Niivue.prototype.mouseMoveListener = function(e) {
|
|
|
110968
112250
|
}
|
|
110969
112251
|
};
|
|
110970
112252
|
Niivue.prototype.resetBriCon = function(msg2 = null) {
|
|
112253
|
+
if (this.isDragging)
|
|
112254
|
+
return;
|
|
110971
112255
|
let isRender = false;
|
|
110972
|
-
if (this.sliceType === this.sliceTypeRender)
|
|
112256
|
+
if (this.sliceType === this.sliceTypeRender)
|
|
110973
112257
|
isRender = true;
|
|
110974
|
-
|
|
112258
|
+
let x2 = 0;
|
|
112259
|
+
let y = 0;
|
|
110975
112260
|
if (msg2 !== null) {
|
|
110976
|
-
if (
|
|
112261
|
+
if (msg2.targetTouches !== void 0) {
|
|
112262
|
+
x2 = msg2.targetTouches[0].clientX - msg2.target.getBoundingClientRect().left;
|
|
112263
|
+
y = msg2.targetTouches[0].clientY - msg2.target.getBoundingClientRect().top;
|
|
112264
|
+
} else {
|
|
112265
|
+
x2 = msg2.offsetX;
|
|
112266
|
+
y = msg2.offsetY;
|
|
112267
|
+
}
|
|
112268
|
+
x2 *= this.scene.dpr;
|
|
112269
|
+
y *= this.scene.dpr;
|
|
112270
|
+
if (this.inRenderTile(x2, y) >= 0)
|
|
110977
112271
|
isRender = true;
|
|
110978
112272
|
}
|
|
110979
112273
|
if (isRender) {
|
|
@@ -110982,15 +112276,37 @@ Niivue.prototype.resetBriCon = function(msg2 = null) {
|
|
|
110982
112276
|
this.drawScene();
|
|
110983
112277
|
return;
|
|
110984
112278
|
}
|
|
112279
|
+
if (this.doubleTouch)
|
|
112280
|
+
return;
|
|
110985
112281
|
this.volumes[0].cal_min = this.volumes[0].robust_min;
|
|
110986
112282
|
this.volumes[0].cal_max = this.volumes[0].robust_max;
|
|
110987
112283
|
this.opts.onIntensityChange(this.volumes[0]);
|
|
110988
112284
|
this.refreshLayers(this.volumes[0], 0, this.volumes.length);
|
|
110989
112285
|
this.drawScene();
|
|
110990
112286
|
};
|
|
112287
|
+
Niivue.prototype.setDragStart = function(x2, y) {
|
|
112288
|
+
x2 *= this.scene.dpr;
|
|
112289
|
+
y *= this.scene.dpr;
|
|
112290
|
+
this.dragStart[0] = x2;
|
|
112291
|
+
this.dragStart[1] = y;
|
|
112292
|
+
};
|
|
112293
|
+
Niivue.prototype.setDragEnd = function(x2, y) {
|
|
112294
|
+
x2 *= this.scene.dpr;
|
|
112295
|
+
y *= this.scene.dpr;
|
|
112296
|
+
this.dragEnd[0] = x2;
|
|
112297
|
+
this.dragEnd[1] = y;
|
|
112298
|
+
};
|
|
110991
112299
|
Niivue.prototype.touchMoveListener = function(e) {
|
|
110992
112300
|
if (this.scene.touchdown && e.touches.length < 2) {
|
|
110993
112301
|
var rect = this.canvas.getBoundingClientRect();
|
|
112302
|
+
if (!this.isDragging)
|
|
112303
|
+
this.scene.pan2DxyzmmAtMouseDown = this.scene.pan2Dxyzmm.slice();
|
|
112304
|
+
this.isDragging = true;
|
|
112305
|
+
if (this.doubleTouch && this.isDragging) {
|
|
112306
|
+
this.setDragEnd(e.targetTouches[0].clientX - e.target.getBoundingClientRect().left, e.targetTouches[0].clientY - e.target.getBoundingClientRect().top);
|
|
112307
|
+
this.drawScene();
|
|
112308
|
+
return;
|
|
112309
|
+
}
|
|
110994
112310
|
this.mouseClick(e.touches[0].clientX - rect.left, e.touches[0].clientY - rect.top);
|
|
110995
112311
|
this.mouseMove(e.touches[0].clientX - rect.left, e.touches[0].clientY - rect.top);
|
|
110996
112312
|
} else {
|
|
@@ -111090,6 +112406,9 @@ Niivue.prototype.keyDownListener = function(e) {
|
|
|
111090
112406
|
Niivue.prototype.wheelListener = function(e) {
|
|
111091
112407
|
e.preventDefault();
|
|
111092
112408
|
e.stopPropagation();
|
|
112409
|
+
if (this.thumbnailVisible) {
|
|
112410
|
+
return;
|
|
112411
|
+
}
|
|
111093
112412
|
var rect = this.canvas.getBoundingClientRect();
|
|
111094
112413
|
if (e.deltaY < 0) {
|
|
111095
112414
|
this.sliceScroll2D(-0.01, e.clientX - rect.left, e.clientY - rect.top);
|
|
@@ -111133,6 +112452,77 @@ Niivue.prototype.getFileExt = function(fullname, upperCase = true) {
|
|
|
111133
112452
|
}
|
|
111134
112453
|
return upperCase ? ext : ext.toLowerCase();
|
|
111135
112454
|
};
|
|
112455
|
+
Niivue.prototype.loadVolumeFromUrl = async function(imageOptions) {
|
|
112456
|
+
let volume = await NVImage.loadFromUrl(imageOptions);
|
|
112457
|
+
return volume;
|
|
112458
|
+
};
|
|
112459
|
+
Niivue.prototype.notifySubscribersOfOptionChange = function(volume) {
|
|
112460
|
+
if (this.isInSession) {
|
|
112461
|
+
if (this.mediaUrlMap.has(volume)) {
|
|
112462
|
+
let imageOptions = volume.getImageOptions();
|
|
112463
|
+
imageOptions.url = this.mediaUrlMap.get(volume);
|
|
112464
|
+
this.serverConnection$.next(new NVMessage(UPDATE_IMAGE_OPTIONS, imageOptions, this.sessionKey));
|
|
112465
|
+
console.log("update called");
|
|
112466
|
+
}
|
|
112467
|
+
}
|
|
112468
|
+
};
|
|
112469
|
+
Niivue.prototype.addVolumeFromUrl = async function(imageOptions, notifySubscribers = true) {
|
|
112470
|
+
let volume = await this.loadVolumeFromUrl(imageOptions);
|
|
112471
|
+
this.addVolume(volume);
|
|
112472
|
+
if (!this.mediaUrlMap.has(volume) && imageOptions.url) {
|
|
112473
|
+
this.mediaUrlMap.set(volume, imageOptions.url);
|
|
112474
|
+
if (this.isInSession && notifySubscribers) {
|
|
112475
|
+
this.serverConnection$.next(new NVMessage(ADD_VOLUME_URL, imageOptions, this.sessionKey));
|
|
112476
|
+
}
|
|
112477
|
+
}
|
|
112478
|
+
return volume;
|
|
112479
|
+
};
|
|
112480
|
+
Niivue.prototype.getMediaByUrl = function(url) {
|
|
112481
|
+
return [...this.mediaUrlMap.entries()].filter((v) => v[1] == url).map((v) => v[0]).pop();
|
|
112482
|
+
};
|
|
112483
|
+
Niivue.prototype.removeVolumeByUrl = function(url) {
|
|
112484
|
+
let volume = this.getMediaByUrl(url);
|
|
112485
|
+
if (volume) {
|
|
112486
|
+
this.removeVolume(volume);
|
|
112487
|
+
}
|
|
112488
|
+
};
|
|
112489
|
+
Niivue.prototype.readDirectory = function(directory) {
|
|
112490
|
+
let reader = directory.createReader();
|
|
112491
|
+
let allEntiresInDir = [];
|
|
112492
|
+
let getFileObjects = async (fileSystemEntries) => {
|
|
112493
|
+
let allFileObects = [];
|
|
112494
|
+
async function getFile(fileEntry) {
|
|
112495
|
+
try {
|
|
112496
|
+
return await new Promise((resolve, reject) => fileEntry.file(resolve, reject));
|
|
112497
|
+
} catch (err2) {
|
|
112498
|
+
console.log(err2);
|
|
112499
|
+
}
|
|
112500
|
+
}
|
|
112501
|
+
for (let i2 = 0; i2 < fileSystemEntries.length; i2++) {
|
|
112502
|
+
allFileObects.push(await getFile(fileSystemEntries[i2]));
|
|
112503
|
+
}
|
|
112504
|
+
return allFileObects;
|
|
112505
|
+
};
|
|
112506
|
+
let readEntries = () => {
|
|
112507
|
+
reader.readEntries(async (entries) => {
|
|
112508
|
+
if (entries.length) {
|
|
112509
|
+
allEntiresInDir = allEntiresInDir.concat(entries);
|
|
112510
|
+
readEntries();
|
|
112511
|
+
} else {
|
|
112512
|
+
let allFileObects = await getFileObjects(allEntiresInDir);
|
|
112513
|
+
let volume = await NVImage.loadFromFile({
|
|
112514
|
+
file: allFileObects,
|
|
112515
|
+
name: directory.name,
|
|
112516
|
+
urlImgData: null,
|
|
112517
|
+
isDICOMDIR: true
|
|
112518
|
+
});
|
|
112519
|
+
this.addVolume(volume);
|
|
112520
|
+
}
|
|
112521
|
+
});
|
|
112522
|
+
};
|
|
112523
|
+
readEntries();
|
|
112524
|
+
return allEntiresInDir;
|
|
112525
|
+
};
|
|
111136
112526
|
Niivue.prototype.dropListener = async function(e) {
|
|
111137
112527
|
e.stopPropagation();
|
|
111138
112528
|
e.preventDefault();
|
|
@@ -111142,8 +112532,15 @@ Niivue.prototype.dropListener = async function(e) {
|
|
|
111142
112532
|
const dt = e.dataTransfer;
|
|
111143
112533
|
const url = dt.getData("text/uri-list");
|
|
111144
112534
|
if (url) {
|
|
111145
|
-
let
|
|
111146
|
-
this.
|
|
112535
|
+
let imageOptions = new NVImageFromUrlOptions(url);
|
|
112536
|
+
let ext = this.getFileExt(url);
|
|
112537
|
+
console.log("dropped ext");
|
|
112538
|
+
console.log(ext);
|
|
112539
|
+
if (MESH_EXTENSIONS.includes(ext)) {
|
|
112540
|
+
this.addMeshFromUrl({ url });
|
|
112541
|
+
} else {
|
|
112542
|
+
this.addVolumeFromUrl(imageOptions);
|
|
112543
|
+
}
|
|
111147
112544
|
} else {
|
|
111148
112545
|
const items = dt.items;
|
|
111149
112546
|
if (items.length > 0) {
|
|
@@ -111154,6 +112551,7 @@ Niivue.prototype.dropListener = async function(e) {
|
|
|
111154
112551
|
}
|
|
111155
112552
|
for (const item of items) {
|
|
111156
112553
|
const entry = item.getAsEntry || item.webkitGetAsEntry();
|
|
112554
|
+
console.log(entry);
|
|
111157
112555
|
if (entry.isFile) {
|
|
111158
112556
|
let ext = this.getFileExt(entry.name);
|
|
111159
112557
|
if (ext === "PNG") {
|
|
@@ -111176,7 +112574,7 @@ Niivue.prototype.dropListener = async function(e) {
|
|
|
111176
112574
|
if (entry.name.lastIndexOf("BRIK") !== -1) {
|
|
111177
112575
|
continue;
|
|
111178
112576
|
}
|
|
111179
|
-
if (ext
|
|
112577
|
+
if (MESH_EXTENSIONS.includes(ext)) {
|
|
111180
112578
|
entry.file(async (file) => {
|
|
111181
112579
|
let mesh = await NVMesh.loadFromFile({
|
|
111182
112580
|
file,
|
|
@@ -111205,8 +112603,9 @@ Niivue.prototype.dropListener = async function(e) {
|
|
|
111205
112603
|
this.addVolume(volume);
|
|
111206
112604
|
}
|
|
111207
112605
|
});
|
|
111208
|
-
} else if (entry.isDirectory)
|
|
111209
|
-
;
|
|
112606
|
+
} else if (entry.isDirectory) {
|
|
112607
|
+
this.readDirectory(entry);
|
|
112608
|
+
}
|
|
111210
112609
|
}
|
|
111211
112610
|
}
|
|
111212
112611
|
}
|
|
@@ -111236,6 +112635,15 @@ Niivue.prototype.setSliceMM = function(isSliceMM) {
|
|
|
111236
112635
|
Niivue.prototype.getRadiologicalConvention = function() {
|
|
111237
112636
|
return this.opts.isRadiologicalConvention;
|
|
111238
112637
|
};
|
|
112638
|
+
Niivue.prototype.setHighResolutionCapable = function(isHighResolutionCapable) {
|
|
112639
|
+
this.opts.isHighResolutionCapable = isHighResolutionCapable;
|
|
112640
|
+
if (!this.opts.isHighResolutionCapable) {
|
|
112641
|
+
this.scene.dpr = 1;
|
|
112642
|
+
}
|
|
112643
|
+
console.log("HighDPI feature is experimental");
|
|
112644
|
+
this.resizeListener();
|
|
112645
|
+
this.drawScene();
|
|
112646
|
+
};
|
|
111239
112647
|
Niivue.prototype.addVolume = function(volume) {
|
|
111240
112648
|
this.volumes.push(volume);
|
|
111241
112649
|
let idx = this.volumes.length === 1 ? 0 : this.volumes.length - 1;
|
|
@@ -111332,12 +112740,12 @@ Niivue.prototype.drawAddUndoBitmap = async function(fnm) {
|
|
|
111332
112740
|
return false;
|
|
111333
112741
|
}
|
|
111334
112742
|
this.currentDrawUndoBitmap++;
|
|
111335
|
-
if (this.currentDrawUndoBitmap >= this.maxDrawUndoBitmaps)
|
|
112743
|
+
if (this.currentDrawUndoBitmap >= this.opts.maxDrawUndoBitmaps)
|
|
111336
112744
|
this.currentDrawUndoBitmap = 0;
|
|
111337
112745
|
this.drawUndoBitmaps[this.currentDrawUndoBitmap] = encodeRLE(this.drawBitmap);
|
|
111338
112746
|
};
|
|
111339
112747
|
Niivue.prototype.drawClearAllUndoBitmaps = async function() {
|
|
111340
|
-
this.currentDrawUndoBitmap = this.maxDrawUndoBitmaps;
|
|
112748
|
+
this.currentDrawUndoBitmap = this.opts.maxDrawUndoBitmaps;
|
|
111341
112749
|
if (this.drawUndoBitmaps.length < 1)
|
|
111342
112750
|
return;
|
|
111343
112751
|
for (let i2 = this.drawUndoBitmaps.length - 1; i2 >= 0; i2--)
|
|
@@ -111364,7 +112772,7 @@ Niivue.prototype.loadDrawing = async function(fnm) {
|
|
|
111364
112772
|
if (this.drawBitmap)
|
|
111365
112773
|
console.log("Overwriting open drawing!");
|
|
111366
112774
|
this.drawClearAllUndoBitmaps();
|
|
111367
|
-
let volume = await
|
|
112775
|
+
let volume = await this.addVolumeFromUrl(new NVImageFromUrlOptions(fnm));
|
|
111368
112776
|
let dims = volume.hdr.dims;
|
|
111369
112777
|
if (dims[1] !== this.back.hdr.dims[1] || dims[2] !== this.back.hdr.dims[2] || dims[3] !== this.back.hdr.dims[3]) {
|
|
111370
112778
|
console.log("drawing dimensions do not match background image");
|
|
@@ -111502,6 +112910,8 @@ Niivue.prototype.saveImage = async function(fnm, isSaveDrawing = false) {
|
|
|
111502
112910
|
return true;
|
|
111503
112911
|
};
|
|
111504
112912
|
Niivue.prototype.getMeshIndexByID = function(id) {
|
|
112913
|
+
if (typeof id === "number")
|
|
112914
|
+
return id;
|
|
111505
112915
|
let n = this.meshes.length;
|
|
111506
112916
|
for (let i2 = 0; i2 < n; i2++) {
|
|
111507
112917
|
let id_i = this.meshes[i2].id;
|
|
@@ -111542,10 +112952,6 @@ Niivue.prototype.setPan2Dxyzmm = function(xyzmmZoom) {
|
|
|
111542
112952
|
this.scene.pan2Dxyzmm = xyzmmZoom;
|
|
111543
112953
|
this.drawScene();
|
|
111544
112954
|
};
|
|
111545
|
-
Niivue.prototype.setScale2D = function(zoomFactor) {
|
|
111546
|
-
this.scene.scale2D = zoomFactor;
|
|
111547
|
-
this.drawScene();
|
|
111548
|
-
};
|
|
111549
112955
|
Niivue.prototype.setRenderAzimuthElevation = function(a, e) {
|
|
111550
112956
|
this.scene.renderAzimuth = a;
|
|
111551
112957
|
this.scene.renderElevation = e;
|
|
@@ -111617,11 +113023,43 @@ Niivue.prototype.setMesh = function(mesh, toIndex = 0) {
|
|
|
111617
113023
|
log.debug(m.name);
|
|
111618
113024
|
});
|
|
111619
113025
|
};
|
|
111620
|
-
Niivue.prototype.removeVolume = function(volume) {
|
|
113026
|
+
Niivue.prototype.removeVolume = function(volume, notifySubscribers = true) {
|
|
111621
113027
|
this.setVolume(volume, -1);
|
|
113028
|
+
if (this.mediaUrlMap.has(volume)) {
|
|
113029
|
+
let url = this.mediaUrlMap.get(volume);
|
|
113030
|
+
if (notifySubscribers && this.isInSession) {
|
|
113031
|
+
this.serverConnection$.next(new NVMessage(REMOVE_VOLUME_URL, url, this.sessionKey));
|
|
113032
|
+
}
|
|
113033
|
+
this.mediaUrlMap.delete(volume);
|
|
113034
|
+
}
|
|
113035
|
+
};
|
|
113036
|
+
Niivue.prototype.removeVolumeByIndex = function(index) {
|
|
113037
|
+
if (index >= this.volumes.length) {
|
|
113038
|
+
throw "Index of volume out of bounds";
|
|
113039
|
+
}
|
|
113040
|
+
this.removeVolume(this.volumes[index]);
|
|
113041
|
+
};
|
|
113042
|
+
Niivue.prototype.removeVolumeByIndex = function(index) {
|
|
113043
|
+
if (index >= this.volumes.length) {
|
|
113044
|
+
throw "Index of volume out of bounds";
|
|
113045
|
+
}
|
|
113046
|
+
this.removeVolume(this.volumes[index]);
|
|
113047
|
+
};
|
|
113048
|
+
Niivue.prototype.removeVolumeByIndex = function(index) {
|
|
113049
|
+
if (index >= this.volumes.length) {
|
|
113050
|
+
throw "Index of volume out of bounds";
|
|
113051
|
+
}
|
|
113052
|
+
this.removeVolume(this.volumes[index]);
|
|
111622
113053
|
};
|
|
111623
|
-
Niivue.prototype.removeMesh = function(mesh) {
|
|
113054
|
+
Niivue.prototype.removeMesh = function(mesh, notifySubscribers = true) {
|
|
111624
113055
|
this.setMesh(mesh, -1);
|
|
113056
|
+
let url = this.mediaUrlMap.get(mesh);
|
|
113057
|
+
if (url) {
|
|
113058
|
+
this.mediaUrlMap.delete(mesh);
|
|
113059
|
+
if (notifySubscribers && this.isInSession) {
|
|
113060
|
+
this.serverConnection$.next(new NVMessage(REMOVE_MESH_URL, url, this.sessionKey));
|
|
113061
|
+
}
|
|
113062
|
+
}
|
|
111625
113063
|
};
|
|
111626
113064
|
Niivue.prototype.moveVolumeToBottom = function(volume) {
|
|
111627
113065
|
this.setVolume(volume, 0);
|
|
@@ -111638,11 +113076,15 @@ Niivue.prototype.moveVolumeToTop = function(volume) {
|
|
|
111638
113076
|
this.setVolume(volume, this.volumes.length - 1);
|
|
111639
113077
|
};
|
|
111640
113078
|
Niivue.prototype.mouseDown = function mouseDown(x2, y) {
|
|
113079
|
+
x2 *= this.scene.dpr;
|
|
113080
|
+
y *= this.scene.dpr;
|
|
111641
113081
|
if (this.inRenderTile(x2, y) < 0)
|
|
111642
113082
|
return;
|
|
111643
113083
|
this.mousePos = [x2, y];
|
|
111644
113084
|
};
|
|
111645
113085
|
Niivue.prototype.mouseMove = function mouseMove(x2, y) {
|
|
113086
|
+
x2 *= this.scene.dpr;
|
|
113087
|
+
y *= this.scene.dpr;
|
|
111646
113088
|
if (this.inRenderTile(x2, y) < 0)
|
|
111647
113089
|
return;
|
|
111648
113090
|
this.scene.renderAzimuth += x2 - this.mousePos[0];
|
|
@@ -111676,6 +113118,11 @@ Niivue.prototype.setCrosshairColor = function(color) {
|
|
|
111676
113118
|
this.opts.crosshairColor = color;
|
|
111677
113119
|
this.drawScene();
|
|
111678
113120
|
};
|
|
113121
|
+
Niivue.prototype.setCrosshairWidth = function(crosshairWidth) {
|
|
113122
|
+
this.opts.crosshairWidth = crosshairWidth;
|
|
113123
|
+
this.crosshairs3D.mm[0] = NaN;
|
|
113124
|
+
this.drawScene();
|
|
113125
|
+
};
|
|
111679
113126
|
Niivue.prototype.setDrawingEnabled = function(trueOrFalse) {
|
|
111680
113127
|
this.opts.drawingEnabled = trueOrFalse;
|
|
111681
113128
|
if (this.opts.drawingEnabled) {
|
|
@@ -111691,14 +113138,19 @@ Niivue.prototype.setPenValue = function(penValue, isFilledPen = false) {
|
|
|
111691
113138
|
};
|
|
111692
113139
|
Niivue.prototype.setDrawOpacity = function(opacity) {
|
|
111693
113140
|
this.drawOpacity = opacity;
|
|
111694
|
-
this.sliceShader.use(this.gl);
|
|
111695
|
-
this.gl.uniform1f(this.sliceShader.uniforms["drawOpacity"], this.drawOpacity);
|
|
111696
113141
|
this.drawScene();
|
|
111697
113142
|
};
|
|
111698
113143
|
Niivue.prototype.setSelectionBoxColor = function(color) {
|
|
111699
113144
|
this.opts.selectionBoxColor = color;
|
|
111700
113145
|
};
|
|
111701
113146
|
Niivue.prototype.sliceScroll2D = function(posChange, x2, y, isDelta = true) {
|
|
113147
|
+
if (posChange !== 0 && this.opts.isDragForPanZoom) {
|
|
113148
|
+
let zoom = this.scene.pan2Dxyzmm[3] * (1 + 10 * posChange);
|
|
113149
|
+
zoom = Math.round(zoom * 10) / 10;
|
|
113150
|
+
this.scene.pan2Dxyzmm[3] = zoom;
|
|
113151
|
+
this.drawScene();
|
|
113152
|
+
return;
|
|
113153
|
+
}
|
|
111702
113154
|
this.mouseClick(x2, y, posChange, isDelta);
|
|
111703
113155
|
};
|
|
111704
113156
|
Niivue.prototype.setSliceType = function(st) {
|
|
@@ -111721,7 +113173,7 @@ Niivue.prototype.setScale = function(scale2) {
|
|
|
111721
113173
|
Niivue.prototype.setClipPlaneColor = function(color) {
|
|
111722
113174
|
this.opts.clipPlaneColor = color;
|
|
111723
113175
|
this.renderShader.use(this.gl);
|
|
111724
|
-
this.gl.uniform4fv(this.renderShader.
|
|
113176
|
+
this.gl.uniform4fv(this.renderShader.clipPlaneClrLoc, this.opts.clipPlaneColor);
|
|
111725
113177
|
this.drawScene();
|
|
111726
113178
|
};
|
|
111727
113179
|
Niivue.prototype.overlayRGBA = function(volume) {
|
|
@@ -111782,7 +113234,7 @@ Niivue.prototype.loadVolumes = async function(volumeList) {
|
|
|
111782
113234
|
this.scene.loading$.next(false);
|
|
111783
113235
|
for (let i2 = 0; i2 < volumeList.length; i2++) {
|
|
111784
113236
|
this.scene.loading$.next(true);
|
|
111785
|
-
let
|
|
113237
|
+
let imageOptions = {
|
|
111786
113238
|
url: volumeList[i2].url,
|
|
111787
113239
|
name: volumeList[i2].name,
|
|
111788
113240
|
colorMap: volumeList[i2].colorMap,
|
|
@@ -111792,12 +113244,30 @@ Niivue.prototype.loadVolumes = async function(volumeList) {
|
|
|
111792
113244
|
cal_min: volumeList[i2].cal_min,
|
|
111793
113245
|
cal_max: volumeList[i2].cal_max,
|
|
111794
113246
|
trustCalMinMax: this.opts.trustCalMinMax
|
|
111795
|
-
}
|
|
113247
|
+
};
|
|
113248
|
+
await this.addVolumeFromUrl(imageOptions);
|
|
111796
113249
|
this.scene.loading$.next(false);
|
|
111797
|
-
this.addVolume(volume);
|
|
111798
113250
|
}
|
|
111799
113251
|
return this;
|
|
111800
113252
|
};
|
|
113253
|
+
Niivue.prototype.addMeshFromUrl = async function(meshOptions, notifySubscribers = true) {
|
|
113254
|
+
let mesh = await this.loadMeshFromUrl(meshOptions);
|
|
113255
|
+
this.addMesh(mesh);
|
|
113256
|
+
if (!this.mediaUrlMap.has(mesh) && meshOptions.url) {
|
|
113257
|
+
this.mediaUrlMap.set(mesh, meshOptions.url);
|
|
113258
|
+
if (this.isInSession && notifySubscribers) {
|
|
113259
|
+
this.serverConnection$.next(new NVMessage(ADD_MESH_URL, meshOptions, this.sessionKey));
|
|
113260
|
+
}
|
|
113261
|
+
}
|
|
113262
|
+
return mesh;
|
|
113263
|
+
};
|
|
113264
|
+
Niivue.prototype.loadMeshFromUrl = async function(meshOptions) {
|
|
113265
|
+
let options = new NVMeshFromUrlOptions();
|
|
113266
|
+
options.gl = this.gl;
|
|
113267
|
+
Object.assign(options, meshOptions);
|
|
113268
|
+
let mesh = await NVMesh.loadFromUrl(options);
|
|
113269
|
+
return mesh;
|
|
113270
|
+
};
|
|
111801
113271
|
Niivue.prototype.loadMeshes = async function(meshList) {
|
|
111802
113272
|
this.on("loading", (isLoading) => {
|
|
111803
113273
|
if (isLoading) {
|
|
@@ -111819,17 +113289,8 @@ Niivue.prototype.loadMeshes = async function(meshList) {
|
|
|
111819
113289
|
this.scene.loading$.next(false);
|
|
111820
113290
|
for (let i2 = 0; i2 < meshList.length; i2++) {
|
|
111821
113291
|
this.scene.loading$.next(true);
|
|
111822
|
-
|
|
111823
|
-
url: meshList[i2].url,
|
|
111824
|
-
gl: this.gl,
|
|
111825
|
-
name: meshList[i2].name,
|
|
111826
|
-
opacity: meshList[i2].opacity,
|
|
111827
|
-
rgba255: meshList[i2].rgba255,
|
|
111828
|
-
visible: meshList[i2].visible,
|
|
111829
|
-
layers: meshList[i2].layers
|
|
111830
|
-
});
|
|
113292
|
+
await this.addMeshFromUrl(meshList[i2]);
|
|
111831
113293
|
this.scene.loading$.next(false);
|
|
111832
|
-
this.addMesh(mesh);
|
|
111833
113294
|
}
|
|
111834
113295
|
this.drawScene();
|
|
111835
113296
|
return this;
|
|
@@ -111843,8 +113304,6 @@ Niivue.prototype.loadConnectome = async function(json) {
|
|
|
111843
113304
|
this.loadingText = this.opts.loadingText;
|
|
111844
113305
|
}
|
|
111845
113306
|
});
|
|
111846
|
-
if (!this.initialized)
|
|
111847
|
-
;
|
|
111848
113307
|
this.meshes = [];
|
|
111849
113308
|
this.gl.clearColor(0, 0, 0, 1);
|
|
111850
113309
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
@@ -112480,33 +113939,53 @@ Niivue.prototype.loadDefaultFont = async function() {
|
|
|
112480
113939
|
Niivue.prototype.initText = async function() {
|
|
112481
113940
|
this.fontShader = new Shader(this.gl, vertFontShader, fragFontShader);
|
|
112482
113941
|
this.fontShader.use(this.gl);
|
|
113942
|
+
this.fontShader.screenPxRangeLoc = this.fontShader.uniforms["screenPxRange"];
|
|
113943
|
+
this.fontShader.fontColorLoc = this.fontShader.uniforms["fontColor"];
|
|
113944
|
+
this.fontShader.canvasWidthHeightLoc = this.fontShader.uniforms["canvasWidthHeight"];
|
|
113945
|
+
this.fontShader.leftTopWidthHeightLoc = this.fontShader.uniforms["leftTopWidthHeight"];
|
|
113946
|
+
this.fontShader.uvLeftTopWidthHeightLoc = this.fontShader.uniforms["uvLeftTopWidthHeight"];
|
|
112483
113947
|
await this.loadDefaultFont();
|
|
112484
113948
|
this.drawLoadingText(this.loadingText);
|
|
112485
113949
|
};
|
|
112486
|
-
Niivue.prototype.
|
|
112487
|
-
|
|
113950
|
+
Niivue.prototype.meshShaderNameToNumber = function(meshShaderName = "Phong") {
|
|
113951
|
+
let name = meshShaderName.toLowerCase();
|
|
113952
|
+
for (var i2 = 0; i2 < this.meshShaders.length; i2++) {
|
|
113953
|
+
if (this.meshShaders[i2].Name.toLowerCase() === name)
|
|
113954
|
+
return i2;
|
|
113955
|
+
}
|
|
113956
|
+
i2 = -1;
|
|
113957
|
+
};
|
|
113958
|
+
Niivue.prototype.setMeshShader = function(id, meshShaderNameOrNumber = 2) {
|
|
112488
113959
|
let num = 0;
|
|
112489
113960
|
if (typeof meshShaderNameOrNumber === "number")
|
|
112490
113961
|
num = meshShaderNameOrNumber;
|
|
112491
113962
|
else {
|
|
112492
|
-
|
|
112493
|
-
for (var i2 = 0; i2 < this.meshShaders.length; i2++) {
|
|
112494
|
-
if (this.meshShaders[i2].Name.toLowerCase() === name) {
|
|
112495
|
-
num = i2;
|
|
112496
|
-
break;
|
|
112497
|
-
}
|
|
112498
|
-
}
|
|
113963
|
+
num = this.meshShaderNameToNumber(meshShaderNameOrNumber);
|
|
112499
113964
|
}
|
|
112500
113965
|
num = Math.min(num, this.meshShaders.length - 1);
|
|
112501
113966
|
num = Math.max(num, 0);
|
|
112502
|
-
|
|
113967
|
+
let idx = this.getMeshIndexByID(id);
|
|
113968
|
+
if (idx >= this.meshes.length) {
|
|
113969
|
+
console.log("Unable to change shader until mesh is loaded (maybe you need async)");
|
|
113970
|
+
return;
|
|
113971
|
+
}
|
|
113972
|
+
this.meshes[idx].meshShaderIndex = num;
|
|
112503
113973
|
this.updateGLVolume();
|
|
112504
113974
|
};
|
|
112505
|
-
Niivue.prototype.setCustomMeshShader = function(fragmentShaderText = "") {
|
|
112506
|
-
|
|
112507
|
-
|
|
112508
|
-
|
|
112509
|
-
|
|
113975
|
+
Niivue.prototype.setCustomMeshShader = function(fragmentShaderText = "", name = "Custom") {
|
|
113976
|
+
let num = this.meshShaderNameToNumber(name);
|
|
113977
|
+
if (num >= 0) {
|
|
113978
|
+
this.gl.deleteProgram(this.meshShaders[num].shader.program);
|
|
113979
|
+
this.meshShaders.splice(num, 1);
|
|
113980
|
+
}
|
|
113981
|
+
let m = [];
|
|
113982
|
+
m.Name = name;
|
|
113983
|
+
m.Frag = fragmentShaderText;
|
|
113984
|
+
m.shader = new Shader(this.gl, vertMeshShader, m.Frag);
|
|
113985
|
+
m.shader.use(this.gl);
|
|
113986
|
+
m.shader.mvpLoc = m.shader.uniforms["mvpMtx"];
|
|
113987
|
+
this.meshShaders.push(m);
|
|
113988
|
+
return this.meshShaders.length - 1;
|
|
112510
113989
|
};
|
|
112511
113990
|
Niivue.prototype.meshShaderNames = function(sort = true) {
|
|
112512
113991
|
let cm = [];
|
|
@@ -112551,35 +114030,89 @@ Niivue.prototype.init = async function() {
|
|
|
112551
114030
|
this.gl.enableVertexAttribArray(0);
|
|
112552
114031
|
this.gl.vertexAttribPointer(0, 3, this.gl.FLOAT, false, 0, 0);
|
|
112553
114032
|
this.gl.bindVertexArray(this.unusedVAO);
|
|
112554
|
-
this.
|
|
112555
|
-
this.
|
|
112556
|
-
this.
|
|
112557
|
-
this.
|
|
112558
|
-
this.
|
|
112559
|
-
this.
|
|
112560
|
-
this.
|
|
114033
|
+
this.pickingMeshShader = new Shader(this.gl, vertMeshShader, fragMeshDepthShader);
|
|
114034
|
+
this.pickingMeshShader.use(this.gl);
|
|
114035
|
+
this.pickingMeshShader.mvpLoc = this.pickingMeshShader.uniforms["mvpMtx"];
|
|
114036
|
+
this.pickingImageShader = new Shader(this.gl, vertRenderShader, fragVolumePickingShader);
|
|
114037
|
+
this.pickingImageShader.use(this.gl);
|
|
114038
|
+
this.pickingImageShader.drawOpacityLoc = this.pickingImageShader.uniforms["drawOpacity"];
|
|
114039
|
+
this.pickingImageShader.backgroundMasksOverlaysLoc = this.pickingImageShader.uniforms["backgroundMasksOverlays"];
|
|
114040
|
+
this.pickingImageShader.mvpLoc = this.pickingImageShader.uniforms["mvpMtx"];
|
|
114041
|
+
this.gl.uniform1i(this.pickingImageShader.uniforms["volume"], 0);
|
|
114042
|
+
this.gl.uniform1i(this.pickingImageShader.uniforms["overlay"], 2);
|
|
114043
|
+
this.gl.uniform1i(this.pickingImageShader.uniforms["drawing"], 7);
|
|
114044
|
+
this.pickingImageShader.mvpLoc = this.pickingImageShader.uniforms["mvpMtx"];
|
|
114045
|
+
this.pickingImageShader.rayDirLoc = this.pickingImageShader.uniforms["rayDir"];
|
|
114046
|
+
this.pickingImageShader.clipPlaneLoc = this.pickingImageShader.uniforms["clipPlane"];
|
|
112561
114047
|
this.sliceShader = new Shader(this.gl, vertSliceShader, fragSliceShader);
|
|
112562
114048
|
this.sliceShader.use(this.gl);
|
|
114049
|
+
this.sliceShader.drawOpacityLoc = this.sliceShader.uniforms["drawOpacity"];
|
|
114050
|
+
this.sliceShader.opacityLoc = this.sliceShader.uniforms["opacity"];
|
|
114051
|
+
this.sliceShader.backgroundMasksOverlaysLoc = this.sliceShader.uniforms["backgroundMasksOverlays"];
|
|
114052
|
+
this.sliceShader.axCorSagLoc = this.sliceShader.uniforms["axCorSag"];
|
|
114053
|
+
this.sliceShader.sliceLoc = this.sliceShader.uniforms["slice"];
|
|
114054
|
+
this.sliceShader.canvasWidthHeightLoc = this.sliceShader.uniforms["canvasWidthHeight"];
|
|
114055
|
+
this.sliceShader.leftTopWidthHeightLoc = this.sliceShader.uniforms["leftTopWidthHeight"];
|
|
112563
114056
|
this.gl.uniform1i(this.sliceShader.uniforms["volume"], 0);
|
|
112564
114057
|
this.gl.uniform1i(this.sliceShader.uniforms["overlay"], 2);
|
|
112565
114058
|
this.gl.uniform1i(this.sliceShader.uniforms["drawing"], 7);
|
|
112566
114059
|
this.gl.uniform1f(this.sliceShader.uniforms["drawOpacity"], this.drawOpacity);
|
|
112567
114060
|
this.sliceMMShader = new Shader(this.gl, vertSliceMMShader, fragSliceMMShader);
|
|
112568
114061
|
this.sliceMMShader.use(this.gl);
|
|
114062
|
+
this.sliceMMShader.drawOpacityLoc = this.sliceMMShader.uniforms["drawOpacity"];
|
|
114063
|
+
this.sliceMMShader.backgroundMasksOverlaysLoc = this.sliceMMShader.uniforms["backgroundMasksOverlays"];
|
|
114064
|
+
this.sliceMMShader.opacityLoc = this.sliceMMShader.uniforms["opacity"];
|
|
114065
|
+
this.sliceMMShader.axCorSagLoc = this.sliceMMShader.uniforms["axCorSag"];
|
|
114066
|
+
this.sliceMMShader.sliceLoc = this.sliceMMShader.uniforms["slice"];
|
|
114067
|
+
this.sliceMMShader.frac2mmLoc = this.sliceMMShader.uniforms["frac2mm"];
|
|
114068
|
+
this.sliceMMShader.mvpLoc = this.sliceMMShader.uniforms["mvpMtx"];
|
|
112569
114069
|
this.gl.uniform1i(this.sliceMMShader.uniforms["volume"], 0);
|
|
112570
114070
|
this.gl.uniform1i(this.sliceMMShader.uniforms["overlay"], 2);
|
|
112571
114071
|
this.gl.uniform1i(this.sliceMMShader.uniforms["drawing"], 7);
|
|
112572
114072
|
this.gl.uniform1f(this.sliceMMShader.uniforms["drawOpacity"], this.drawOpacity);
|
|
114073
|
+
this.orientCubeShader = new Shader(this.gl, vertOrientCubeShader, fragOrientCubeShader);
|
|
114074
|
+
let gl = this.gl;
|
|
114075
|
+
this.orientCubeShaderVAO = gl.createVertexArray();
|
|
114076
|
+
gl.bindVertexArray(this.orientCubeShaderVAO);
|
|
114077
|
+
let program = this.orientCubeShader.program;
|
|
114078
|
+
this.orientCubeMtxLoc = gl.getUniformLocation(program, "u_matrix");
|
|
114079
|
+
var positionBuffer = gl.createBuffer();
|
|
114080
|
+
gl.enableVertexAttribArray(0);
|
|
114081
|
+
gl.enableVertexAttribArray(1);
|
|
114082
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
114083
|
+
gl.bufferData(gl.ARRAY_BUFFER, orientCube, gl.STATIC_DRAW);
|
|
114084
|
+
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0);
|
|
114085
|
+
gl.enableVertexAttribArray(1);
|
|
114086
|
+
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 24, 12);
|
|
114087
|
+
gl.bindVertexArray(this.unusedVAO);
|
|
112573
114088
|
this.rectShader = new Shader(this.gl, vertRectShader, fragRectShader);
|
|
114089
|
+
this.rectShader.use(this.gl);
|
|
114090
|
+
this.rectShader.lineColorLoc = this.rectShader.uniforms["lineColor"];
|
|
114091
|
+
this.rectShader.canvasWidthHeightLoc = this.rectShader.uniforms["canvasWidthHeight"];
|
|
114092
|
+
this.rectShader.leftTopWidthHeightLoc = this.rectShader.uniforms["leftTopWidthHeight"];
|
|
112574
114093
|
this.lineShader = new Shader(this.gl, vertLineShader, fragRectShader);
|
|
112575
|
-
this.
|
|
114094
|
+
this.lineShader.use(this.gl);
|
|
114095
|
+
this.lineShader.lineColorLoc = this.lineShader.uniforms["lineColor"];
|
|
114096
|
+
this.lineShader.canvasWidthHeightLoc = this.lineShader.uniforms["canvasWidthHeight"];
|
|
114097
|
+
this.lineShader.thicknessLoc = this.lineShader.uniforms["thickness"];
|
|
114098
|
+
this.lineShader.startXYendXYLoc = this.lineShader.uniforms["startXYendXY"];
|
|
112576
114099
|
this.renderShader = new Shader(this.gl, vertRenderShader, fragRenderShader);
|
|
112577
114100
|
this.renderShader.use(this.gl);
|
|
114101
|
+
this.renderShader.drawOpacityLoc = this.renderShader.uniforms["drawOpacity"];
|
|
114102
|
+
this.renderShader.backgroundMasksOverlaysLoc = this.renderShader.uniforms["backgroundMasksOverlays"];
|
|
112578
114103
|
this.gl.uniform1i(this.renderShader.uniforms["volume"], 0);
|
|
112579
114104
|
this.gl.uniform1i(this.renderShader.uniforms["overlay"], 2);
|
|
112580
|
-
this.
|
|
112581
|
-
this.renderShader.
|
|
114105
|
+
this.gl.uniform1i(this.renderShader.uniforms["drawing"], 7);
|
|
114106
|
+
this.renderShader.mvpLoc = this.renderShader.uniforms["mvpMtx"];
|
|
114107
|
+
this.renderShader.clipPlaneClrLoc = this.renderShader.uniforms["clipPlaneColor"];
|
|
114108
|
+
this.renderShader.mvpMatRASLoc = this.renderShader.uniforms["matRAS"];
|
|
114109
|
+
this.renderShader.rayDirLoc = this.renderShader.uniforms["rayDir"];
|
|
114110
|
+
this.renderShader.clipPlaneLoc = this.renderShader.uniforms["clipPlane"];
|
|
114111
|
+
this.colorbarShader = new Shader(this.gl, vertColorbarShader, fragColorbarShader);
|
|
112582
114112
|
this.colorbarShader.use(this.gl);
|
|
114113
|
+
this.colorbarShader.layerLoc = this.colorbarShader.uniforms["layer"];
|
|
114114
|
+
this.colorbarShader.canvasWidthHeightLoc = this.colorbarShader.uniforms["canvasWidthHeight"];
|
|
114115
|
+
this.colorbarShader.leftTopWidthHeightLoc = this.colorbarShader.uniforms["leftTopWidthHeight"];
|
|
112583
114116
|
this.gl.uniform1i(this.colorbarShader.uniforms["colormap"], 1);
|
|
112584
114117
|
this.growCutShader = new Shader(this.gl, vertGrowCutShader, fragGrowCutShader);
|
|
112585
114118
|
this.passThroughShader = new Shader(this.gl, vertPassThroughShader, fragPassThroughShader);
|
|
@@ -112588,10 +114121,19 @@ Niivue.prototype.init = async function() {
|
|
|
112588
114121
|
this.orientShaderI = new Shader(this.gl, vertOrientShader, fragOrientShaderI.concat(fragOrientShader));
|
|
112589
114122
|
this.orientShaderF = new Shader(this.gl, vertOrientShader, fragOrientShaderF.concat(fragOrientShader));
|
|
112590
114123
|
this.orientShaderRGBU = new Shader(this.gl, vertOrientShader, fragOrientShaderU.concat(fragRGBOrientShader));
|
|
112591
|
-
this.pickingSurfaceShader = new Shader(this.gl, vertRenderShader, fragDepthPickingShader);
|
|
112592
114124
|
this.surfaceShader = new Shader(this.gl, vertSurfaceShader, fragSurfaceShader);
|
|
114125
|
+
this.surfaceShader.use(this.gl);
|
|
114126
|
+
this.surfaceShader.mvpLoc = this.surfaceShader.uniforms["mvpMtx"];
|
|
114127
|
+
this.surfaceShader.colorLoc = this.surfaceShader.uniforms["surfaceColor"];
|
|
112593
114128
|
this.fiberShader = new Shader(this.gl, vertFiberShader, fragFiberShader);
|
|
112594
|
-
this.
|
|
114129
|
+
this.pickingImageShader.use(this.gl);
|
|
114130
|
+
this.fiberShader.mvpLoc = this.fiberShader.uniforms["mvpMtx"];
|
|
114131
|
+
for (var i2 = 0; i2 < this.meshShaders.length; i2++) {
|
|
114132
|
+
let m = this.meshShaders[i2];
|
|
114133
|
+
m.shader = new Shader(this.gl, vertMeshShader, m.Frag);
|
|
114134
|
+
m.shader.use(this.gl);
|
|
114135
|
+
m.shader.mvpLoc = m.shader.uniforms["mvpMtx"];
|
|
114136
|
+
}
|
|
112595
114137
|
this.bmpShader = new Shader(this.gl, vertBmpShader, fragBmpShader);
|
|
112596
114138
|
await this.initText();
|
|
112597
114139
|
if (this.opts.thumbnail.length > 0) {
|
|
@@ -112600,6 +114142,7 @@ Niivue.prototype.init = async function() {
|
|
|
112600
114142
|
}
|
|
112601
114143
|
this.updateGLVolume();
|
|
112602
114144
|
this.initialized = true;
|
|
114145
|
+
this.resizeListener();
|
|
112603
114146
|
this.drawScene();
|
|
112604
114147
|
return this;
|
|
112605
114148
|
};
|
|
@@ -112673,7 +114216,6 @@ Niivue.prototype.getDescriptives = function(layer = 0, ignoreZeros = false, mask
|
|
|
112673
114216
|
M = Mnext;
|
|
112674
114217
|
}
|
|
112675
114218
|
let stdev = Math.sqrt(S / (k - 1));
|
|
112676
|
-
"Number of voxels: " + k + "\nMean:" + M + "\nMin:" + mn + "\nMax:" + mx + "\nStandard deviation: " + stdev + "\nRobust Min: " + this.volumes[layer].robust_min + "\nRobust Max: " + this.volumes[layer].robust_max;
|
|
112677
114219
|
return {
|
|
112678
114220
|
mean: M,
|
|
112679
114221
|
stdev,
|
|
@@ -112684,7 +114226,7 @@ Niivue.prototype.getDescriptives = function(layer = 0, ignoreZeros = false, mask
|
|
|
112684
114226
|
robust_max: this.volumes[layer].robust_max
|
|
112685
114227
|
};
|
|
112686
114228
|
};
|
|
112687
|
-
Niivue.prototype.refreshLayers = function(overlayItem, layer
|
|
114229
|
+
Niivue.prototype.refreshLayers = function(overlayItem, layer) {
|
|
112688
114230
|
if (this.volumes.length < 1)
|
|
112689
114231
|
return;
|
|
112690
114232
|
let hdr = overlayItem.hdr;
|
|
@@ -112711,8 +114253,7 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
112711
114253
|
this.renderShader.use(this.gl);
|
|
112712
114254
|
this.gl.uniform3fv(this.renderShader.uniforms["texVox"], vox2);
|
|
112713
114255
|
this.gl.uniform3fv(this.renderShader.uniforms["volScale"], volScale2);
|
|
112714
|
-
this.
|
|
112715
|
-
let pickingShader = this.pickingShader;
|
|
114256
|
+
let pickingShader = this.pickingImageShader;
|
|
112716
114257
|
pickingShader.use(this.gl);
|
|
112717
114258
|
this.gl.uniform1i(pickingShader.uniforms["volume"], 0);
|
|
112718
114259
|
this.gl.uniform1i(pickingShader.uniforms["colormap"], 1);
|
|
@@ -112894,14 +114435,14 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
112894
114435
|
let vox = slicescl.vox;
|
|
112895
114436
|
let volScale = slicescl.volScale;
|
|
112896
114437
|
this.gl.uniform1f(this.renderShader.uniforms["overlays"], this.overlays);
|
|
112897
|
-
this.gl.uniform4fv(this.renderShader.
|
|
114438
|
+
this.gl.uniform4fv(this.renderShader.clipPlaneClrLoc, this.opts.clipPlaneColor);
|
|
112898
114439
|
this.gl.uniform1f(this.renderShader.uniforms["backOpacity"], this.volumes[0].opacity);
|
|
112899
114440
|
this.gl.uniform4fv(this.renderShader.uniforms["clipPlane"], this.scene.clipPlane);
|
|
112900
114441
|
this.gl.uniform3fv(this.renderShader.uniforms["texVox"], vox);
|
|
112901
114442
|
this.gl.uniform3fv(this.renderShader.uniforms["volScale"], volScale);
|
|
112902
|
-
this.
|
|
112903
|
-
this.gl.uniform1f(this.
|
|
112904
|
-
this.gl.uniform3fv(this.
|
|
114443
|
+
this.pickingImageShader.use(this.gl);
|
|
114444
|
+
this.gl.uniform1f(this.pickingImageShader.uniforms["overlays"], this.overlays.length);
|
|
114445
|
+
this.gl.uniform3fv(this.pickingImageShader.uniforms["texVox"], vox);
|
|
112905
114446
|
this.sliceMMShader.use(this.gl);
|
|
112906
114447
|
this.gl.uniform1f(this.sliceMMShader.uniforms["overlays"], this.overlays.length);
|
|
112907
114448
|
this.gl.uniform1f(this.sliceMMShader.uniforms["drawOpacity"], this.drawOpacity);
|
|
@@ -112948,6 +114489,10 @@ Niivue.prototype.setFrame4D = function(id, frame4D) {
|
|
|
112948
114489
|
}
|
|
112949
114490
|
this.volumes[idx].frame4D = frame4D;
|
|
112950
114491
|
this.updateGLVolume();
|
|
114492
|
+
if (this.isInSession && this.mediaUrlMap.has(this.volumes[idx])) {
|
|
114493
|
+
let url = this.mediaUrlMap.get(this.volumes[idx]);
|
|
114494
|
+
this.serverConnection$.next(new NVMessage(SET_4D_VOL_INDEX, new NVMessageSet4DVolumeIndexData(url, frame4D), this.sessionKey));
|
|
114495
|
+
}
|
|
112951
114496
|
};
|
|
112952
114497
|
Niivue.prototype.getFrame4D = function(id) {
|
|
112953
114498
|
let idx = this.getVolumeIndexByID(id);
|
|
@@ -112974,12 +114519,12 @@ Niivue.prototype.refreshColormaps = function() {
|
|
|
112974
114519
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_R, this.gl.CLAMP_TO_EDGE);
|
|
112975
114520
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
112976
114521
|
this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1);
|
|
112977
|
-
let
|
|
114522
|
+
let luts = this.colormap(this.volumes[0].colorMap);
|
|
112978
114523
|
function addColormap(lut) {
|
|
112979
|
-
let c2 = new Uint8ClampedArray(
|
|
112980
|
-
c2.set(
|
|
112981
|
-
c2.set(lut,
|
|
112982
|
-
|
|
114524
|
+
let c2 = new Uint8ClampedArray(luts.length + lut.length);
|
|
114525
|
+
c2.set(luts);
|
|
114526
|
+
c2.set(lut, luts.length);
|
|
114527
|
+
luts = c2;
|
|
112983
114528
|
}
|
|
112984
114529
|
for (let i2 = 1; i2 < nLayer; i2++)
|
|
112985
114530
|
addColormap(this.colormap(this.volumes[i2].colorMap));
|
|
@@ -112998,7 +114543,7 @@ Niivue.prototype.refreshColormaps = function() {
|
|
|
112998
114543
|
lut = this.colormap(this.volumes[i2].colorMapNegative);
|
|
112999
114544
|
addColormap(lut);
|
|
113000
114545
|
}
|
|
113001
|
-
this.gl.texSubImage2D(this.gl.TEXTURE_2D, 0, 0, 0, 256, nLayer * 2, this.gl.RGBA, this.gl.UNSIGNED_BYTE,
|
|
114546
|
+
this.gl.texSubImage2D(this.gl.TEXTURE_2D, 0, 0, 0, 256, nLayer * 2, this.gl.RGBA, this.gl.UNSIGNED_BYTE, luts);
|
|
113002
114547
|
return this;
|
|
113003
114548
|
};
|
|
113004
114549
|
Niivue.prototype.sliceScale = function() {
|
|
@@ -113051,6 +114596,8 @@ Niivue.prototype.sliceScroll3D = function(posChange = 0) {
|
|
|
113051
114596
|
this.drawScene();
|
|
113052
114597
|
};
|
|
113053
114598
|
Niivue.prototype.mouseClick = function(x2, y, posChange = 0, isDelta = true) {
|
|
114599
|
+
x2 *= this.scene.dpr;
|
|
114600
|
+
y *= this.scene.dpr;
|
|
113054
114601
|
var posNow;
|
|
113055
114602
|
var posFuture;
|
|
113056
114603
|
this.canvas.focus();
|
|
@@ -113178,13 +114725,13 @@ Niivue.prototype.drawRuler = function() {
|
|
|
113178
114725
|
Niivue.prototype.drawRuler10cm = function(startXYendXY) {
|
|
113179
114726
|
this.gl.bindVertexArray(this.genericVAO);
|
|
113180
114727
|
this.lineShader.use(this.gl);
|
|
113181
|
-
this.gl.uniform4fv(this.lineShader.
|
|
113182
|
-
this.gl.uniform2fv(this.lineShader.
|
|
114728
|
+
this.gl.uniform4fv(this.lineShader.lineColorLoc, this.opts.rulerColor);
|
|
114729
|
+
this.gl.uniform2fv(this.lineShader.canvasWidthHeightLoc, [
|
|
113183
114730
|
this.gl.canvas.width,
|
|
113184
114731
|
this.gl.canvas.height
|
|
113185
114732
|
]);
|
|
113186
|
-
this.gl.uniform1f(this.lineShader.
|
|
113187
|
-
this.gl.uniform4fv(this.lineShader.
|
|
114733
|
+
this.gl.uniform1f(this.lineShader.thicknessLoc, this.opts.rulerWidth);
|
|
114734
|
+
this.gl.uniform4fv(this.lineShader.startXYendXYLoc, startXYendXY);
|
|
113188
114735
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
113189
114736
|
let w1cm = -0.1 * (startXYendXY[0] - startXYendXY[2]);
|
|
113190
114737
|
let b = startXYendXY[1];
|
|
@@ -113195,11 +114742,45 @@ Niivue.prototype.drawRuler10cm = function(startXYendXY) {
|
|
|
113195
114742
|
let xyxy = [l, b, l, t];
|
|
113196
114743
|
if (i2 % 5 === 0)
|
|
113197
114744
|
xyxy[3] = t2;
|
|
113198
|
-
this.gl.uniform4fv(this.lineShader.
|
|
114745
|
+
this.gl.uniform4fv(this.lineShader.startXYendXYLoc, xyxy);
|
|
113199
114746
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
113200
114747
|
}
|
|
113201
114748
|
this.gl.bindVertexArray(this.unusedVAO);
|
|
113202
114749
|
};
|
|
114750
|
+
Niivue.prototype.screenXY2mm = function(x2, y, forceSlice = -1) {
|
|
114751
|
+
for (let s = 0; s < this.screenSlices.length; s++) {
|
|
114752
|
+
let i2 = s;
|
|
114753
|
+
if (forceSlice >= 0)
|
|
114754
|
+
i2 = forceSlice;
|
|
114755
|
+
var axCorSag = this.screenSlices[i2].axCorSag;
|
|
114756
|
+
if (axCorSag > this.sliceTypeSagittal)
|
|
114757
|
+
continue;
|
|
114758
|
+
let ltwh = this.screenSlices[i2].leftTopWidthHeight;
|
|
114759
|
+
if (x2 < ltwh[0] || y < ltwh[1] || x2 > ltwh[0] + ltwh[2] || y > ltwh[1] + ltwh[3])
|
|
114760
|
+
continue;
|
|
114761
|
+
console.log(this.screenSlices[i2].leftTopWidthHeight, x2, y);
|
|
114762
|
+
let texFrac = this.screenXY2TextureFrac(x2, y, i2, false);
|
|
114763
|
+
if (forceSlice < 0 && texFrac[0] < 0)
|
|
114764
|
+
continue;
|
|
114765
|
+
let mm = this.frac2mm(texFrac);
|
|
114766
|
+
return [mm[0], mm[1], mm[2], i2];
|
|
114767
|
+
}
|
|
114768
|
+
return [NaN, NaN, NaN, NaN];
|
|
114769
|
+
};
|
|
114770
|
+
Niivue.prototype.dragForPanZoom = function(startXYendXY) {
|
|
114771
|
+
let endMM = this.screenXY2mm(startXYendXY[2], startXYendXY[3]);
|
|
114772
|
+
if (isNaN(endMM[0]))
|
|
114773
|
+
return;
|
|
114774
|
+
let startMM = this.screenXY2mm(startXYendXY[0], startXYendXY[1], endMM[3]);
|
|
114775
|
+
if (isNaN(startMM[0]) || isNaN(endMM[0]) || endMM[3] !== endMM[3]) {
|
|
114776
|
+
return;
|
|
114777
|
+
}
|
|
114778
|
+
let v = create$1();
|
|
114779
|
+
sub(v, endMM, startMM);
|
|
114780
|
+
this.scene.pan2Dxyzmm[0] = this.scene.pan2DxyzmmAtMouseDown[0] + v[0];
|
|
114781
|
+
this.scene.pan2Dxyzmm[1] = this.scene.pan2DxyzmmAtMouseDown[1] + v[1];
|
|
114782
|
+
this.scene.pan2Dxyzmm[2] = this.scene.pan2DxyzmmAtMouseDown[2] + v[2];
|
|
114783
|
+
};
|
|
113203
114784
|
Niivue.prototype.drawMeasurementTool = function(startXYendXY) {
|
|
113204
114785
|
let gl = this.gl;
|
|
113205
114786
|
gl.bindVertexArray(this.genericVAO);
|
|
@@ -113207,26 +114788,26 @@ Niivue.prototype.drawMeasurementTool = function(startXYendXY) {
|
|
|
113207
114788
|
gl.enable(gl.BLEND);
|
|
113208
114789
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
113209
114790
|
this.lineShader.use(this.gl);
|
|
113210
|
-
gl.uniform4fv(this.lineShader.
|
|
113211
|
-
gl.uniform2fv(this.lineShader.
|
|
114791
|
+
gl.uniform4fv(this.lineShader.lineColorLoc, this.opts.rulerColor);
|
|
114792
|
+
gl.uniform2fv(this.lineShader.canvasWidthHeightLoc, [
|
|
113212
114793
|
gl.canvas.width,
|
|
113213
114794
|
gl.canvas.height
|
|
113214
114795
|
]);
|
|
113215
|
-
gl.uniform1f(this.lineShader.
|
|
113216
|
-
gl.uniform4fv(this.lineShader.
|
|
114796
|
+
gl.uniform1f(this.lineShader.thicknessLoc, this.opts.rulerWidth);
|
|
114797
|
+
gl.uniform4fv(this.lineShader.startXYendXYLoc, startXYendXY);
|
|
113217
114798
|
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
113218
114799
|
let c2 = this.opts.rulerColor;
|
|
113219
114800
|
c2[3] = 1;
|
|
113220
|
-
gl.uniform4fv(this.lineShader.
|
|
114801
|
+
gl.uniform4fv(this.lineShader.lineColorLoc, c2);
|
|
113221
114802
|
let w = this.opts.rulerWidth;
|
|
113222
|
-
gl.uniform1f(this.lineShader.
|
|
114803
|
+
gl.uniform1f(this.lineShader.thicknessLoc, w * 2);
|
|
113223
114804
|
let sXYeXY = [
|
|
113224
114805
|
startXYendXY[0],
|
|
113225
114806
|
startXYendXY[1] - w,
|
|
113226
114807
|
startXYendXY[0],
|
|
113227
114808
|
startXYendXY[1] + w
|
|
113228
114809
|
];
|
|
113229
|
-
gl.uniform4fv(this.lineShader.
|
|
114810
|
+
gl.uniform4fv(this.lineShader.startXYendXYLoc, sXYeXY);
|
|
113230
114811
|
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
113231
114812
|
sXYeXY = [
|
|
113232
114813
|
startXYendXY[2],
|
|
@@ -113234,7 +114815,7 @@ Niivue.prototype.drawMeasurementTool = function(startXYendXY) {
|
|
|
113234
114815
|
startXYendXY[2],
|
|
113235
114816
|
startXYendXY[3] + w
|
|
113236
114817
|
];
|
|
113237
|
-
gl.uniform4fv(this.lineShader.
|
|
114818
|
+
gl.uniform4fv(this.lineShader.startXYendXYLoc, sXYeXY);
|
|
113238
114819
|
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
113239
114820
|
let startXY = this.canvasPos2frac([startXYendXY[0], startXYendXY[1]]);
|
|
113240
114821
|
let endXY = this.canvasPos2frac([startXYendXY[2], startXYendXY[3]]);
|
|
@@ -113254,21 +114835,23 @@ Niivue.prototype.drawMeasurementTool = function(startXYendXY) {
|
|
|
113254
114835
|
}
|
|
113255
114836
|
gl.bindVertexArray(this.unusedVAO);
|
|
113256
114837
|
};
|
|
113257
|
-
Niivue.prototype.
|
|
114838
|
+
Niivue.prototype.drawRect = function(leftTopWidthHeight, lineColor = [1, 0, 0, -1]) {
|
|
114839
|
+
if (lineColor[3] < 0)
|
|
114840
|
+
lineColor = this.opts.crosshairColor;
|
|
113258
114841
|
this.rectShader.use(this.gl);
|
|
113259
114842
|
this.gl.enable(this.gl.BLEND);
|
|
113260
|
-
this.gl.uniform4fv(this.rectShader.
|
|
113261
|
-
this.gl.uniform2fv(this.rectShader.
|
|
114843
|
+
this.gl.uniform4fv(this.rectShader.lineColorLoc, lineColor);
|
|
114844
|
+
this.gl.uniform2fv(this.rectShader.canvasWidthHeightLoc, [
|
|
113262
114845
|
this.gl.canvas.width,
|
|
113263
114846
|
this.gl.canvas.height
|
|
113264
114847
|
]);
|
|
113265
|
-
this.gl.uniform4f(this.rectShader.
|
|
114848
|
+
this.gl.uniform4f(this.rectShader.leftTopWidthHeightLoc, leftTopWidthHeight[0], leftTopWidthHeight[1], leftTopWidthHeight[2], leftTopWidthHeight[3]);
|
|
113266
114849
|
this.gl.bindVertexArray(this.genericVAO);
|
|
113267
114850
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
113268
114851
|
this.gl.bindVertexArray(this.unusedVAO);
|
|
113269
114852
|
};
|
|
113270
|
-
Niivue.prototype.drawSelectionBox = function(leftTopWidthHeight
|
|
113271
|
-
this.
|
|
114853
|
+
Niivue.prototype.drawSelectionBox = function(leftTopWidthHeight) {
|
|
114854
|
+
this.drawRect(leftTopWidthHeight, this.opts.selectionBoxColor);
|
|
113272
114855
|
};
|
|
113273
114856
|
function tickSpacingX(tickCount, mn, mx) {
|
|
113274
114857
|
let range = Math.abs(mx - mn);
|
|
@@ -113285,13 +114868,22 @@ function tickSpacingX(tickCount, mn, mx) {
|
|
|
113285
114868
|
ticMin = Math.sign(ticMin) * Math.round(Math.abs(ticMin));
|
|
113286
114869
|
return [spacing, ticMin];
|
|
113287
114870
|
}
|
|
114871
|
+
function isDivisible(num, denom) {
|
|
114872
|
+
return Math.abs(num - Math.round(num / denom) * (denom / num)) < 1e-5;
|
|
114873
|
+
}
|
|
113288
114874
|
function tickSpacing(mn, mx) {
|
|
113289
114875
|
let range = Math.abs(mx - mn);
|
|
113290
114876
|
let [spacing, ticMin] = tickSpacingX(5, mn, mx);
|
|
113291
|
-
if (range
|
|
114877
|
+
if (isDivisible(range, spacing))
|
|
113292
114878
|
return [spacing, ticMin];
|
|
113293
114879
|
[spacing, ticMin] = tickSpacingX(4, mn, mx);
|
|
113294
|
-
if (range
|
|
114880
|
+
if (isDivisible(range, spacing))
|
|
114881
|
+
return [spacing, ticMin];
|
|
114882
|
+
[spacing, ticMin] = tickSpacingX(6, mn, mx);
|
|
114883
|
+
if (isDivisible(range, spacing))
|
|
114884
|
+
return [spacing, ticMin];
|
|
114885
|
+
[spacing, ticMin] = tickSpacingX(7, mn, mx);
|
|
114886
|
+
if (isDivisible(range, spacing))
|
|
113295
114887
|
return [spacing, ticMin];
|
|
113296
114888
|
[spacing, ticMin] = tickSpacingX(5, mn, mx);
|
|
113297
114889
|
return [spacing, ticMin];
|
|
@@ -113332,13 +114924,6 @@ Niivue.prototype.drawColorbarCore = function(layer = 0, leftTopWidthHeight = [0,
|
|
|
113332
114924
|
}
|
|
113333
114925
|
this.gl.disable(this.gl.DEPTH_TEST);
|
|
113334
114926
|
this.colorbarHeight = leftTopWidthHeight[3] + 1;
|
|
113335
|
-
[
|
|
113336
|
-
this.opts.backColor[0],
|
|
113337
|
-
this.opts.backColor[1],
|
|
113338
|
-
this.opts.backColor[2],
|
|
113339
|
-
0.5
|
|
113340
|
-
];
|
|
113341
|
-
leftTopWidthHeight[1];
|
|
113342
114927
|
let barLTWH = [
|
|
113343
114928
|
leftTopWidthHeight[0] + margin,
|
|
113344
114929
|
leftTopWidthHeight[1],
|
|
@@ -113351,7 +114936,7 @@ Niivue.prototype.drawColorbarCore = function(layer = 0, leftTopWidthHeight = [0,
|
|
|
113351
114936
|
barLTWH[2] + 2,
|
|
113352
114937
|
barLTWH[3] + 2
|
|
113353
114938
|
];
|
|
113354
|
-
this.
|
|
114939
|
+
this.drawRect(rimLTWH, this.opts.crosshairColor);
|
|
113355
114940
|
this.colorbarShader.use(this.gl);
|
|
113356
114941
|
this.gl.activeTexture(this.gl.TEXTURE1);
|
|
113357
114942
|
this.gl.bindTexture(this.gl.TEXTURE_2D, this.colormapTexture);
|
|
@@ -113360,12 +114945,12 @@ Niivue.prototype.drawColorbarCore = function(layer = 0, leftTopWidthHeight = [0,
|
|
|
113360
114945
|
let lx = layer;
|
|
113361
114946
|
if (isNegativeColor)
|
|
113362
114947
|
lx += this.volumes.length;
|
|
113363
|
-
this.gl.uniform1f(this.colorbarShader.
|
|
113364
|
-
this.gl.uniform2fv(this.colorbarShader.
|
|
114948
|
+
this.gl.uniform1f(this.colorbarShader.layerLoc, lx);
|
|
114949
|
+
this.gl.uniform2fv(this.colorbarShader.canvasWidthHeightLoc, [
|
|
113365
114950
|
this.gl.canvas.width,
|
|
113366
114951
|
this.gl.canvas.height
|
|
113367
114952
|
]);
|
|
113368
|
-
this.gl.uniform4fv(this.colorbarShader.
|
|
114953
|
+
this.gl.uniform4fv(this.colorbarShader.leftTopWidthHeightLoc, barLTWH);
|
|
113369
114954
|
this.gl.bindVertexArray(this.genericVAO);
|
|
113370
114955
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
113371
114956
|
this.gl.bindVertexArray(this.unusedVAO);
|
|
@@ -113385,7 +114970,7 @@ Niivue.prototype.drawColorbarCore = function(layer = 0, leftTopWidthHeight = [0,
|
|
|
113385
114970
|
let txtTop = ticLTWH[1] + ticLTWH[3];
|
|
113386
114971
|
while (tic <= max2) {
|
|
113387
114972
|
ticLTWH[0] = barLTWH[0] + (tic - min2) / range * barLTWH[2];
|
|
113388
|
-
this.
|
|
114973
|
+
this.drawRect(ticLTWH);
|
|
113389
114974
|
let str = humanize(tic);
|
|
113390
114975
|
if (isNegativeColor)
|
|
113391
114976
|
str = "-" + str;
|
|
@@ -113434,8 +115019,8 @@ Niivue.prototype.drawChar = function(xy, scale2, char) {
|
|
|
113434
115019
|
let w = scale2 * metrics2.lbwh[2];
|
|
113435
115020
|
let h = scale2 * metrics2.lbwh[3];
|
|
113436
115021
|
let t = xy[1] + (b - h) + scale2;
|
|
113437
|
-
this.gl.uniform4f(this.fontShader.
|
|
113438
|
-
this.gl.uniform4fv(this.fontShader.
|
|
115022
|
+
this.gl.uniform4f(this.fontShader.leftTopWidthHeightLoc, l, t, w, h);
|
|
115023
|
+
this.gl.uniform4fv(this.fontShader.uvLeftTopWidthHeightLoc, metrics2.uv_lbwh);
|
|
113439
115024
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
113440
115025
|
return scale2 * metrics2.xadv;
|
|
113441
115026
|
};
|
|
@@ -113452,13 +115037,13 @@ Niivue.prototype.drawText = function(xy, str, scale2 = 1, color = null) {
|
|
|
113452
115037
|
this.fontShader.use(this.gl);
|
|
113453
115038
|
let size = this.opts.textHeight * Math.min(this.gl.canvas.height, this.gl.canvas.width) * scale2;
|
|
113454
115039
|
this.gl.enable(this.gl.BLEND);
|
|
113455
|
-
this.gl.uniform2f(this.fontShader.
|
|
115040
|
+
this.gl.uniform2f(this.fontShader.canvasWidthHeightLoc, this.gl.canvas.width, this.gl.canvas.height);
|
|
113456
115041
|
if (color === null)
|
|
113457
115042
|
color = this.opts.crosshairColor;
|
|
113458
|
-
this.gl.uniform4fv(this.fontShader.
|
|
115043
|
+
this.gl.uniform4fv(this.fontShader.fontColorLoc, color);
|
|
113459
115044
|
let screenPxRange = size / this.fontMets.size * this.fontMets.distanceRange;
|
|
113460
115045
|
screenPxRange = Math.max(screenPxRange, 1);
|
|
113461
|
-
this.gl.uniform1f(this.fontShader.
|
|
115046
|
+
this.gl.uniform1f(this.fontShader.screenPxRangeLoc, screenPxRange);
|
|
113462
115047
|
var bytes = new TextEncoder().encode(str);
|
|
113463
115048
|
this.gl.bindVertexArray(this.genericVAO);
|
|
113464
115049
|
for (let i2 = 0; i2 < str.length; i2++)
|
|
@@ -113482,7 +115067,6 @@ Niivue.prototype.drawTextLeft = function(xy, str, scale2 = 1, color = null) {
|
|
|
113482
115067
|
Niivue.prototype.drawTextRightBelow = function(xy, str, scale2 = 1, color = null) {
|
|
113483
115068
|
if (this.opts.textHeight <= 0)
|
|
113484
115069
|
return;
|
|
113485
|
-
this.opts.textHeight * this.gl.canvas.height * scale2;
|
|
113486
115070
|
this.drawText(xy, str, scale2, color);
|
|
113487
115071
|
};
|
|
113488
115072
|
Niivue.prototype.drawTextBetween = function(startXYendXY, str, scale2 = 1, color = null) {
|
|
@@ -113545,7 +115129,7 @@ function deg2rad(deg) {
|
|
|
113545
115129
|
}
|
|
113546
115130
|
Niivue.prototype.calculateMvpMatrix2D = function(leftTopWidthHeight, mn, mx, clipTolerance = Infinity, clipDepth = 0, azimuth = null, elevation = null, isRadiolgical) {
|
|
113547
115131
|
let gl = this.gl;
|
|
113548
|
-
gl.viewport(leftTopWidthHeight[0], this.gl.canvas.
|
|
115132
|
+
gl.viewport(leftTopWidthHeight[0], this.gl.canvas.height - (leftTopWidthHeight[1] + leftTopWidthHeight[3]), leftTopWidthHeight[2], leftTopWidthHeight[3]);
|
|
113549
115133
|
let left = mn[0];
|
|
113550
115134
|
let right = mx[0];
|
|
113551
115135
|
let leftTopMM = [left, mn[1]];
|
|
@@ -113606,7 +115190,6 @@ Niivue.prototype.screenFieldOfViewMM = function(axCorSag = 0, forceSliceMM = fal
|
|
|
113606
115190
|
}
|
|
113607
115191
|
let mnMM = this.volumeObject3D.extentsMin.slice();
|
|
113608
115192
|
let mxMM = this.volumeObject3D.extentsMax.slice();
|
|
113609
|
-
create$2();
|
|
113610
115193
|
mnMM = this.swizzleVec3MM(mnMM, axCorSag);
|
|
113611
115194
|
mxMM = this.swizzleVec3MM(mxMM, axCorSag);
|
|
113612
115195
|
let fovMM = create$1();
|
|
@@ -113734,15 +115317,16 @@ Niivue.prototype.draw2DMM = function(leftTopWidthHeight, axCorSag, customMM = Na
|
|
|
113734
115317
|
gl.depthFunc(gl.GREATER);
|
|
113735
115318
|
gl.disable(gl.CULL_FACE);
|
|
113736
115319
|
this.sliceMMShader.use(this.gl);
|
|
113737
|
-
|
|
113738
|
-
|
|
113739
|
-
|
|
113740
|
-
|
|
113741
|
-
|
|
113742
|
-
|
|
113743
|
-
|
|
113744
|
-
|
|
113745
|
-
|
|
115320
|
+
gl.uniform1i(this.sliceMMShader.backgroundMasksOverlaysLoc, this.backgroundMasksOverlays);
|
|
115321
|
+
gl.uniform1f(this.sliceMMShader.drawOpacityLoc, this.drawOpacity);
|
|
115322
|
+
gl.uniform1f(this.sliceMMShader.opacityLoc, this.volumes[0].opacity);
|
|
115323
|
+
gl.uniform1i(this.sliceMMShader.axCorSagLoc, axCorSag);
|
|
115324
|
+
gl.uniform1f(this.sliceMMShader.sliceLoc, sliceFrac);
|
|
115325
|
+
gl.uniformMatrix4fv(this.sliceMMShader.frac2mmLoc, false, this.volumes[0].frac2mm);
|
|
115326
|
+
gl.uniformMatrix4fv(this.sliceMMShader.mvpLoc, false, obj.modelViewProjectionMatrix.slice());
|
|
115327
|
+
gl.bindVertexArray(this.genericVAO);
|
|
115328
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
115329
|
+
gl.bindVertexArray(this.unusedVAO);
|
|
113746
115330
|
this.screenSlices.push({
|
|
113747
115331
|
leftTopWidthHeight,
|
|
113748
115332
|
axCorSag,
|
|
@@ -113752,7 +115336,7 @@ Niivue.prototype.draw2DMM = function(leftTopWidthHeight, axCorSag, customMM = Na
|
|
|
113752
115336
|
fovMM: obj.fovMM
|
|
113753
115337
|
});
|
|
113754
115338
|
if (isNaN(customMM)) {
|
|
113755
|
-
this.drawCrosshairs3D(true, 1, obj.modelViewProjectionMatrix);
|
|
115339
|
+
this.drawCrosshairs3D(true, 1, obj.modelViewProjectionMatrix, true);
|
|
113756
115340
|
}
|
|
113757
115341
|
if (this.opts.meshThicknessOn2D > 0) {
|
|
113758
115342
|
if (this.opts.meshThicknessOn2D !== Infinity)
|
|
@@ -113760,18 +115344,19 @@ Niivue.prototype.draw2DMM = function(leftTopWidthHeight, axCorSag, customMM = Na
|
|
|
113760
115344
|
this.drawMesh3D(true, 1, obj.modelViewProjectionMatrix, obj.modelMatrix, obj.normalMatrix);
|
|
113761
115345
|
}
|
|
113762
115346
|
if (isNaN(customMM))
|
|
113763
|
-
this.drawCrosshairs3D(false, 0.15, obj.modelViewProjectionMatrix);
|
|
115347
|
+
this.drawCrosshairs3D(false, 0.15, obj.modelViewProjectionMatrix, true);
|
|
113764
115348
|
this.drawSliceOrientationText(leftTopWidthHeight, axCorSag);
|
|
113765
115349
|
this.readyForSync = true;
|
|
113766
115350
|
};
|
|
115351
|
+
Niivue.prototype.drawCro;
|
|
113767
115352
|
Niivue.prototype.draw2DVox = function(leftTopWidthHeight, axCorSag, customMM = NaN) {
|
|
115353
|
+
let gl = this.gl;
|
|
113768
115354
|
let fovMM = this.screenFieldOfViewMM(axCorSag);
|
|
113769
115355
|
if (leftTopWidthHeight[2] === 0 || leftTopWidthHeight[3] === 0) {
|
|
113770
115356
|
leftTopWidthHeight = this.scaleSlice(fovMM[0], fovMM[1]);
|
|
113771
115357
|
}
|
|
113772
|
-
|
|
115358
|
+
gl.cullFace(gl.FRONT);
|
|
113773
115359
|
let ltwh = leftTopWidthHeight.slice();
|
|
113774
|
-
let gl = this.gl;
|
|
113775
115360
|
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
113776
115361
|
gl.disable(gl.DEPTH_TEST);
|
|
113777
115362
|
let sliceDim = 2;
|
|
@@ -113806,22 +115391,23 @@ Niivue.prototype.draw2DVox = function(leftTopWidthHeight, axCorSag, customMM = N
|
|
|
113806
115391
|
if (this.opts.sagittalNoseLeft && axCorSag === this.sliceTypeSagittal)
|
|
113807
115392
|
isMirrorLR = !isMirrorLR;
|
|
113808
115393
|
this.sliceShader.use(this.gl);
|
|
113809
|
-
|
|
113810
|
-
|
|
113811
|
-
|
|
113812
|
-
|
|
113813
|
-
|
|
113814
|
-
|
|
113815
|
-
|
|
115394
|
+
gl.uniform1f(this.sliceShader.drawOpacityLoc, this.drawOpacity);
|
|
115395
|
+
gl.uniform1f(this.sliceShader.opacityLoc, this.volumes[0].opacity);
|
|
115396
|
+
gl.uniform1i(this.sliceShader.backgroundMasksOverlaysLoc, this.backgroundMasksOverlays);
|
|
115397
|
+
gl.uniform1i(this.sliceShader.axCorSagLoc, axCorSag);
|
|
115398
|
+
gl.uniform1f(this.sliceShader.sliceLoc, crossXYZ[2]);
|
|
115399
|
+
gl.uniform2fv(this.sliceShader.canvasWidthHeightLoc, [
|
|
115400
|
+
gl.canvas.width,
|
|
115401
|
+
gl.canvas.height
|
|
113816
115402
|
]);
|
|
113817
115403
|
if (isMirrorLR) {
|
|
113818
|
-
|
|
115404
|
+
gl.disable(gl.CULL_FACE);
|
|
113819
115405
|
leftTopWidthHeight[2] = -leftTopWidthHeight[2];
|
|
113820
115406
|
leftTopWidthHeight[0] = leftTopWidthHeight[0] - leftTopWidthHeight[2];
|
|
113821
115407
|
}
|
|
113822
|
-
|
|
113823
|
-
|
|
113824
|
-
|
|
115408
|
+
gl.uniform4f(this.sliceShader.leftTopWidthHeightLoc, leftTopWidthHeight[0], leftTopWidthHeight[1], leftTopWidthHeight[2], leftTopWidthHeight[3]);
|
|
115409
|
+
gl.bindVertexArray(this.genericVAO);
|
|
115410
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
113825
115411
|
this.screenSlices.push({
|
|
113826
115412
|
leftTopWidthHeight,
|
|
113827
115413
|
axCorSag,
|
|
@@ -113836,21 +115422,21 @@ Niivue.prototype.draw2DVox = function(leftTopWidthHeight, axCorSag, customMM = N
|
|
|
113836
115422
|
return;
|
|
113837
115423
|
if (this.opts.crosshairWidth <= 0)
|
|
113838
115424
|
return;
|
|
113839
|
-
|
|
115425
|
+
gl.bindVertexArray(this.genericVAO);
|
|
113840
115426
|
this.rectShader.use(this.gl);
|
|
113841
|
-
|
|
113842
|
-
|
|
113843
|
-
|
|
113844
|
-
|
|
115427
|
+
gl.uniform4fv(this.rectShader.lineColorLoc, this.opts.crosshairColor);
|
|
115428
|
+
gl.uniform2fv(this.rectShader.canvasWidthHeightLoc, [
|
|
115429
|
+
gl.canvas.width,
|
|
115430
|
+
gl.canvas.height
|
|
113845
115431
|
]);
|
|
113846
115432
|
var xleft = leftTopWidthHeight[0] + leftTopWidthHeight[2] * crossXYZ[0];
|
|
113847
|
-
|
|
113848
|
-
|
|
115433
|
+
gl.uniform4f(this.rectShader.leftTopWidthHeightLoc, xleft - 0.5 * this.opts.crosshairWidth, leftTopWidthHeight[1], this.opts.crosshairWidth, leftTopWidthHeight[3]);
|
|
115434
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
113849
115435
|
var xtop = leftTopWidthHeight[1] + leftTopWidthHeight[3] * (1 - crossXYZ[1]);
|
|
113850
|
-
|
|
113851
|
-
|
|
113852
|
-
|
|
113853
|
-
|
|
115436
|
+
gl.uniform4f(this.rectShader.leftTopWidthHeightLoc, leftTopWidthHeight[0], xtop - 0.5 * this.opts.crosshairWidth, leftTopWidthHeight[2], this.opts.crosshairWidth);
|
|
115437
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
115438
|
+
gl.bindVertexArray(this.unusedVAO);
|
|
115439
|
+
gl.enable(gl.CULL_FACE);
|
|
113854
115440
|
gl.enable(gl.DEPTH_TEST);
|
|
113855
115441
|
gl.depthFunc(gl.ALWAYS);
|
|
113856
115442
|
gl.clearDepth(0);
|
|
@@ -113896,13 +115482,10 @@ Niivue.prototype.calculateMvpMatrix = function(unused, leftTopWidthHeight = [0,
|
|
|
113896
115482
|
return [modelViewProjectionMatrix, modelMatrix, normalMatrix];
|
|
113897
115483
|
};
|
|
113898
115484
|
Niivue.prototype.calculateRayDirection = function(azimuth, elevation) {
|
|
113899
|
-
function deg2rad2(deg) {
|
|
113900
|
-
return deg * (Math.PI / 180);
|
|
113901
|
-
}
|
|
113902
115485
|
const modelMatrix = create$2();
|
|
113903
115486
|
modelMatrix[0] = -1;
|
|
113904
|
-
rotateX(modelMatrix, modelMatrix,
|
|
113905
|
-
rotateZ(modelMatrix, modelMatrix,
|
|
115487
|
+
rotateX(modelMatrix, modelMatrix, deg2rad(270 - elevation));
|
|
115488
|
+
rotateZ(modelMatrix, modelMatrix, deg2rad(azimuth - 180));
|
|
113906
115489
|
if (this.back.obliqueRAS) {
|
|
113907
115490
|
let oblique = clone$1(this.back.obliqueRAS);
|
|
113908
115491
|
multiply(modelMatrix, modelMatrix, oblique);
|
|
@@ -113925,7 +115508,7 @@ Niivue.prototype.calculateRayDirection = function(azimuth, elevation) {
|
|
|
113925
115508
|
rayDir[2] = tiny;
|
|
113926
115509
|
return rayDir;
|
|
113927
115510
|
};
|
|
113928
|
-
Niivue.prototype.
|
|
115511
|
+
Niivue.prototype.sceneExtentsMinMax = function() {
|
|
113929
115512
|
let mn = fromValues$1(0, 0, 0);
|
|
113930
115513
|
let mx = fromValues$1(0, 0, 0);
|
|
113931
115514
|
if (this.volumes.length > 0) {
|
|
@@ -113943,6 +115526,12 @@ Niivue.prototype.setPivot3D = function() {
|
|
|
113943
115526
|
max$T(mx, mx, v);
|
|
113944
115527
|
}
|
|
113945
115528
|
}
|
|
115529
|
+
let range = create$1();
|
|
115530
|
+
subtract(range, mx, mn);
|
|
115531
|
+
return [mn, mx, range];
|
|
115532
|
+
};
|
|
115533
|
+
Niivue.prototype.setPivot3D = function() {
|
|
115534
|
+
let [mn, mx] = this.sceneExtentsMinMax();
|
|
113946
115535
|
let pivot = create$1();
|
|
113947
115536
|
add$1(pivot, mn, mx);
|
|
113948
115537
|
scale(pivot, pivot, 0.5);
|
|
@@ -113952,33 +115541,7 @@ Niivue.prototype.setPivot3D = function() {
|
|
|
113952
115541
|
this.extentsMax = mx;
|
|
113953
115542
|
this.furthestFromPivot = length$1(pivot) * 0.5;
|
|
113954
115543
|
};
|
|
113955
|
-
Niivue.prototype.drawGraphLine = function(LTRB, color = [1, 0, 0, 0.5], thickness = 2) {
|
|
113956
|
-
this.graphShader.use(this.gl);
|
|
113957
|
-
this.gl.uniform4fv(this.graphShader.uniforms["lineColor"], color);
|
|
113958
|
-
this.gl.uniform2fv(this.graphShader.uniforms["canvasWidthHeight"], [
|
|
113959
|
-
this.gl.canvas.width,
|
|
113960
|
-
this.gl.canvas.height
|
|
113961
|
-
]);
|
|
113962
|
-
this.gl.uniform1f(this.graphShader.uniforms["thickness"], thickness);
|
|
113963
|
-
this.gl.uniform4f(this.graphShader.uniforms["leftTopRightBottom"], LTRB[0], LTRB[1], LTRB[2], LTRB[3]);
|
|
113964
|
-
this.gl.bindVertexArray(this.genericVAO);
|
|
113965
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
113966
|
-
this.gl.bindVertexArray(this.unusedVAO);
|
|
113967
|
-
};
|
|
113968
|
-
Niivue.prototype.drawRect = function(LTWH, color = [1, 0, 0, 0.5]) {
|
|
113969
|
-
this.rectShader.use(this.gl);
|
|
113970
|
-
this.gl.uniform4fv(this.rectShader.uniforms["lineColor"], color);
|
|
113971
|
-
this.gl.uniform2fv(this.rectShader.uniforms["canvasWidthHeight"], [
|
|
113972
|
-
this.gl.canvas.width,
|
|
113973
|
-
this.gl.canvas.height
|
|
113974
|
-
]);
|
|
113975
|
-
this.gl.uniform4f(this.rectShader.uniforms["leftTopWidthHeight"], LTWH[0], LTWH[1], LTWH[2], LTWH[3]);
|
|
113976
|
-
this.gl.bindVertexArray(this.genericVAO);
|
|
113977
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
113978
|
-
this.gl.bindVertexArray(this.unusedVAO);
|
|
113979
|
-
};
|
|
113980
115544
|
Niivue.prototype.drawGraph = function() {
|
|
113981
|
-
this.gl;
|
|
113982
115545
|
let graph = this.graph;
|
|
113983
115546
|
if (this.graph.autoSizeMultiplanar && this.sliceType === this.sliceTypeMultiplanar) {
|
|
113984
115547
|
for (let i2 = 0; i2 < this.screenSlices.length; i2++) {
|
|
@@ -114116,13 +115679,13 @@ Niivue.prototype.drawGraph = function() {
|
|
|
114116
115679
|
thinColor[3] = 0.25 * graph.lineColor[3];
|
|
114117
115680
|
while (lineH <= mx) {
|
|
114118
115681
|
let y = plotBottom - (lineH - mn) * scaleH;
|
|
114119
|
-
this.
|
|
115682
|
+
this.drawLine([plotLTWH[0], y, plotLTWH[0] + plotLTWH[2], y], 0.5 * graph.lineThickness, thinColor);
|
|
114120
115683
|
lineH += spacing;
|
|
114121
115684
|
}
|
|
114122
115685
|
lineH = ticMin;
|
|
114123
115686
|
while (lineH <= mx) {
|
|
114124
115687
|
let y = plotBottom - (lineH - mn) * scaleH;
|
|
114125
|
-
this.
|
|
115688
|
+
this.drawLine([plotLTWH[0], y, plotLTWH[0] + plotLTWH[2], y], graph.lineThickness, graph.lineColor);
|
|
114126
115689
|
let str = humanize(lineH);
|
|
114127
115690
|
if (fntSize > 0)
|
|
114128
115691
|
this.drawTextLeft([plotLTWH[0] - 6, y], str, fntScale, graph.textColor);
|
|
@@ -114137,12 +115700,12 @@ Niivue.prototype.drawGraph = function() {
|
|
|
114137
115700
|
let thick = graph.lineThickness;
|
|
114138
115701
|
if (i2 % 2 === 1) {
|
|
114139
115702
|
thick *= 0.5;
|
|
114140
|
-
this.
|
|
114141
|
-
} else
|
|
115703
|
+
this.drawLine([x2, plotLTWH[1], x2, plotLTWH[1] + plotLTWH[3]], thick, thinColor);
|
|
115704
|
+
} else {
|
|
114142
115705
|
let str = humanize(i2);
|
|
114143
115706
|
if (fntSize > 0)
|
|
114144
115707
|
this.drawTextBelow([x2, 2 + plotLTWH[1] + plotLTWH[3]], str, fntScale, graph.textColor);
|
|
114145
|
-
this.
|
|
115708
|
+
this.drawLine([x2, plotLTWH[1], x2, plotLTWH[1] + plotLTWH[3]], thick, graph.lineColor);
|
|
114146
115709
|
}
|
|
114147
115710
|
}
|
|
114148
115711
|
for (let j = 0; j < graph.lines.length; j++) {
|
|
@@ -114166,13 +115729,12 @@ Niivue.prototype.drawGraph = function() {
|
|
|
114166
115729
|
plotLTWH[0] + x1,
|
|
114167
115730
|
plotLTWH[1] + plotLTWH[3] - y1
|
|
114168
115731
|
];
|
|
114169
|
-
this.
|
|
115732
|
+
this.drawLine(LTWH, graph.lineThickness, lineRGBA);
|
|
114170
115733
|
}
|
|
114171
115734
|
}
|
|
114172
115735
|
if (graph.selectedColumn >= 0 && graph.selectedColumn < graph.lines[0].length) {
|
|
114173
115736
|
let x2 = graph.selectedColumn * scaleW + plotLTWH[0];
|
|
114174
|
-
graph.lineRGB[0];
|
|
114175
|
-
this.drawGraphLine([x2, plotLTWH[1], x2, plotLTWH[1] + plotLTWH[3]], [graph.lineRGB[3][0], graph.lineRGB[3][1], graph.lineRGB[3][2], 1], graph.lineThickness);
|
|
115737
|
+
this.drawLine([x2, plotLTWH[1], x2, plotLTWH[1] + plotLTWH[3]], graph.lineThickness, [graph.lineRGB[3][0], graph.lineRGB[3][1], graph.lineRGB[3][2], 1]);
|
|
114176
115738
|
}
|
|
114177
115739
|
};
|
|
114178
115740
|
function isRadiological(mtx) {
|
|
@@ -114181,6 +115743,117 @@ function isRadiological(mtx) {
|
|
|
114181
115743
|
transformMat4(vRotated, vRight, mtx);
|
|
114182
115744
|
return vRotated[0];
|
|
114183
115745
|
}
|
|
115746
|
+
function unProject(winX, winY, winZ, mvpMatrix) {
|
|
115747
|
+
let inp = fromValues(winX, winY, winZ, 1);
|
|
115748
|
+
let finalMatrix = clone$1(mvpMatrix);
|
|
115749
|
+
invert(finalMatrix, finalMatrix);
|
|
115750
|
+
inp[0] = inp[0] * 2 - 1;
|
|
115751
|
+
inp[1] = inp[1] * 2 - 1;
|
|
115752
|
+
inp[2] = inp[2] * 2 - 1;
|
|
115753
|
+
let out = create();
|
|
115754
|
+
transformMat4(out, inp, finalMatrix);
|
|
115755
|
+
if (out[3] === 0)
|
|
115756
|
+
return out;
|
|
115757
|
+
out[0] /= out[3];
|
|
115758
|
+
out[1] /= out[3];
|
|
115759
|
+
out[2] /= out[3];
|
|
115760
|
+
return out;
|
|
115761
|
+
}
|
|
115762
|
+
function unpackFloatFromVec4i(val) {
|
|
115763
|
+
var bitSh = [
|
|
115764
|
+
1 / (256 * 256 * 256),
|
|
115765
|
+
1 / (256 * 256),
|
|
115766
|
+
1 / 256,
|
|
115767
|
+
1
|
|
115768
|
+
];
|
|
115769
|
+
return (val[0] * bitSh[0] + val[1] * bitSh[1] + val[2] * bitSh[2] + val[3] * bitSh[3]) / 255;
|
|
115770
|
+
}
|
|
115771
|
+
Niivue.prototype.depthPicker = function(leftTopWidthHeight, mvpMatrix) {
|
|
115772
|
+
if (!this.scene.mouseDepthPicker)
|
|
115773
|
+
return;
|
|
115774
|
+
this.scene.mouseDepthPicker = false;
|
|
115775
|
+
let gl = this.gl;
|
|
115776
|
+
const pixelX = this.mousePos[0] * leftTopWidthHeight[2] / leftTopWidthHeight[2];
|
|
115777
|
+
const pixelY = gl.canvas.height - this.mousePos[1] * leftTopWidthHeight[3] / leftTopWidthHeight[3] - 1;
|
|
115778
|
+
const rgbaPixel = new Uint8Array(4);
|
|
115779
|
+
gl.readPixels(pixelX, pixelY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, rgbaPixel);
|
|
115780
|
+
this.selectedObjectId = rgbaPixel[3];
|
|
115781
|
+
if (this.selectedObjectId === this.VOLUME_ID) {
|
|
115782
|
+
this.scene.crosshairPos = new Float32Array(rgbaPixel.slice(0, 3)).map((x2) => x2 / 255);
|
|
115783
|
+
return;
|
|
115784
|
+
}
|
|
115785
|
+
let depthZ = unpackFloatFromVec4i(rgbaPixel);
|
|
115786
|
+
if (depthZ > 1)
|
|
115787
|
+
return;
|
|
115788
|
+
let fracX = (this.mousePos[0] - leftTopWidthHeight[0]) / leftTopWidthHeight[2];
|
|
115789
|
+
let fracY = (gl.canvas.height - this.mousePos[1] - leftTopWidthHeight[1]) / leftTopWidthHeight[3];
|
|
115790
|
+
let mm = unProject(fracX, fracY, depthZ, mvpMatrix);
|
|
115791
|
+
let frac = this.mm2frac(mm);
|
|
115792
|
+
if (frac[0] < 0 || frac[0] > 1 || frac[1] < 0 || frac[1] > 1 || frac[2] < 0 || frac[2] > 1)
|
|
115793
|
+
return;
|
|
115794
|
+
this.scene.crosshairPos = this.mm2frac(mm);
|
|
115795
|
+
};
|
|
115796
|
+
Niivue.prototype.drawImage3D = function(mvpMatrix, azimuth, elevation) {
|
|
115797
|
+
if (this.volumes.length === 0)
|
|
115798
|
+
return;
|
|
115799
|
+
let gl = this.gl;
|
|
115800
|
+
const rayDir = this.calculateRayDirection(azimuth, elevation);
|
|
115801
|
+
let object3D = this.volumeObject3D;
|
|
115802
|
+
if (object3D) {
|
|
115803
|
+
gl.enable(gl.BLEND);
|
|
115804
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
115805
|
+
gl.enable(gl.CULL_FACE);
|
|
115806
|
+
gl.cullFace(gl.FRONT);
|
|
115807
|
+
let shader = this.renderShader;
|
|
115808
|
+
if (this.scene.mouseDepthPicker)
|
|
115809
|
+
shader = this.pickingImageShader;
|
|
115810
|
+
shader.use(this.gl);
|
|
115811
|
+
gl.uniform1i(shader.backgroundMasksOverlaysLoc, this.backgroundMasksOverlays);
|
|
115812
|
+
if (this.drawBitmap && this.drawBitmap.length > 8)
|
|
115813
|
+
gl.uniform1f(shader.drawOpacityLoc, this.drawOpacity);
|
|
115814
|
+
else
|
|
115815
|
+
gl.uniform1f(shader.drawOpacityLoc, 0);
|
|
115816
|
+
gl.uniformMatrix4fv(shader.mvpLoc, false, mvpMatrix);
|
|
115817
|
+
gl.uniformMatrix4fv(shader.mvpMatRASLoc, false, this.back.matRAS);
|
|
115818
|
+
gl.uniform3fv(shader.rayDirLoc, rayDir);
|
|
115819
|
+
gl.uniform4fv(shader.clipPlaneLoc, this.scene.clipPlane);
|
|
115820
|
+
gl.bindVertexArray(object3D.vao);
|
|
115821
|
+
gl.drawElements(object3D.mode, object3D.indexCount, gl.UNSIGNED_SHORT, 0);
|
|
115822
|
+
gl.bindVertexArray(this.unusedVAO);
|
|
115823
|
+
}
|
|
115824
|
+
};
|
|
115825
|
+
Niivue.prototype.drawOrientationCube = function(leftTopWidthHeight, azimuth = 0, elevation = 0) {
|
|
115826
|
+
if (!this.opts.isOrientCube)
|
|
115827
|
+
return;
|
|
115828
|
+
let sz = 0.05 * Math.min(leftTopWidthHeight[2], leftTopWidthHeight[3]);
|
|
115829
|
+
if (sz < 5)
|
|
115830
|
+
return;
|
|
115831
|
+
let gl = this.gl;
|
|
115832
|
+
gl.enable(gl.CULL_FACE);
|
|
115833
|
+
gl.cullFace(gl.BACK);
|
|
115834
|
+
this.orientCubeShader.use(this.gl);
|
|
115835
|
+
gl.bindVertexArray(this.orientCubeShaderVAO);
|
|
115836
|
+
let modelMatrix = create$2();
|
|
115837
|
+
let projectionMatrix = create$2();
|
|
115838
|
+
ortho(projectionMatrix, 0, gl.canvas.width, 0, gl.canvas.height, -10 * sz, 10 * sz);
|
|
115839
|
+
let translateUpForColorbar = 0;
|
|
115840
|
+
if (leftTopWidthHeight[1] === 0)
|
|
115841
|
+
translateUpForColorbar = gl.canvas.height - this.effectiveCanvasHeight();
|
|
115842
|
+
translate(modelMatrix, modelMatrix, [
|
|
115843
|
+
1.8 * sz + leftTopWidthHeight[0],
|
|
115844
|
+
translateUpForColorbar + 1.8 * sz + leftTopWidthHeight[1],
|
|
115845
|
+
0
|
|
115846
|
+
]);
|
|
115847
|
+
scale$1(modelMatrix, modelMatrix, [sz, sz, sz]);
|
|
115848
|
+
rotateX(modelMatrix, modelMatrix, deg2rad(270 - elevation));
|
|
115849
|
+
rotateZ(modelMatrix, modelMatrix, deg2rad(-azimuth));
|
|
115850
|
+
let modelViewProjectionMatrix = create$2();
|
|
115851
|
+
multiply(modelViewProjectionMatrix, projectionMatrix, modelMatrix);
|
|
115852
|
+
gl.uniformMatrix4fv(this.orientCubeMtxLoc, false, modelViewProjectionMatrix);
|
|
115853
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 168);
|
|
115854
|
+
gl.bindVertexArray(this.unusedVAO);
|
|
115855
|
+
this.gl.disable(this.gl.CULL_FACE);
|
|
115856
|
+
};
|
|
114184
115857
|
Niivue.prototype.draw3D = function(leftTopWidthHeight = [0, 0, 0, 0], mvpMatrix = null, modelMatrix, normalMatrix, azimuth = null, elevation) {
|
|
114185
115858
|
let isMosaic = azimuth !== null;
|
|
114186
115859
|
this.setPivot3D();
|
|
@@ -114216,62 +115889,20 @@ Niivue.prototype.draw3D = function(leftTopWidthHeight = [0, 0, 0, 0], mvpMatrix
|
|
|
114216
115889
|
gl.enable(gl.DEPTH_TEST);
|
|
114217
115890
|
gl.depthFunc(gl.ALWAYS);
|
|
114218
115891
|
gl.clearDepth(0);
|
|
114219
|
-
if (this.volumes.length
|
|
114220
|
-
|
|
114221
|
-
this.drawMesh3D(true, 1, mvpMatrix, modelMatrix, normalMatrix);
|
|
114222
|
-
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
114223
|
-
return;
|
|
114224
|
-
}
|
|
114225
|
-
const rayDir = this.calculateRayDirection(azimuth, elevation);
|
|
114226
|
-
let object3D = this.volumeObject3D;
|
|
114227
|
-
if (this.scene.mouseDepthPicker) {
|
|
114228
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
114229
|
-
this.scene.mouseDepthPicker = false;
|
|
114230
|
-
if (object3D.isVisible && object3D.isPickable) {
|
|
114231
|
-
let shader = this.pickingShader;
|
|
114232
|
-
shader.use(this.gl);
|
|
114233
|
-
gl.enable(gl.CULL_FACE);
|
|
114234
|
-
gl.cullFace(gl.FRONT);
|
|
114235
|
-
gl.uniformMatrix4fv(shader.mvpUniformLoc, false, mvpMatrix);
|
|
114236
|
-
gl.uniform3fv(shader.rayDirUniformLoc, rayDir);
|
|
114237
|
-
gl.uniform4fv(shader.clipPlaneUniformLoc, this.scene.clipPlane);
|
|
114238
|
-
gl.uniform1i(shader.uniforms["id"], object3D.id);
|
|
114239
|
-
gl.bindVertexArray(object3D.vao);
|
|
114240
|
-
gl.drawElements(object3D.mode, object3D.indexCount, gl.UNSIGNED_SHORT, 0);
|
|
114241
|
-
gl.bindVertexArray(this.unusedVAO);
|
|
114242
|
-
}
|
|
114243
|
-
const pixelX = this.mousePos[0] * leftTopWidthHeight[2] / leftTopWidthHeight[2];
|
|
114244
|
-
const pixelY = gl.canvas.height - this.mousePos[1] * leftTopWidthHeight[3] / leftTopWidthHeight[3] - 1;
|
|
114245
|
-
const rgbaPixel = new Uint8Array(4);
|
|
114246
|
-
gl.readPixels(pixelX, pixelY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, rgbaPixel);
|
|
114247
|
-
this.selectedObjectId = rgbaPixel[3];
|
|
114248
|
-
if (this.selectedObjectId === this.VOLUME_ID) {
|
|
114249
|
-
this.scene.crosshairPos = new Float32Array(rgbaPixel.slice(0, 3)).map((x2) => x2 / 255);
|
|
114250
|
-
}
|
|
114251
|
-
}
|
|
114252
|
-
if (this.volumeObject3D.isVisible) {
|
|
114253
|
-
gl.enable(gl.BLEND);
|
|
114254
|
-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
114255
|
-
gl.enable(gl.CULL_FACE);
|
|
114256
|
-
gl.cullFace(gl.FRONT);
|
|
114257
|
-
let shader = this.renderShader;
|
|
114258
|
-
shader.use(this.gl);
|
|
114259
|
-
gl.uniform1i(shader.uniforms["backgroundMasksOverlays"], this.backgroundMasksOverlays);
|
|
114260
|
-
gl.uniformMatrix4fv(shader.mvpUniformLoc, false, mvpMatrix);
|
|
114261
|
-
gl.uniformMatrix4fv(shader.mvpMatRASLoc, false, this.back.matRAS);
|
|
114262
|
-
gl.uniform3fv(shader.rayDirUniformLoc, rayDir);
|
|
114263
|
-
gl.uniform4fv(shader.clipPlaneUniformLoc, this.scene.clipPlane);
|
|
114264
|
-
gl.bindVertexArray(object3D.vao);
|
|
114265
|
-
gl.drawElements(object3D.mode, object3D.indexCount, gl.UNSIGNED_SHORT, 0);
|
|
114266
|
-
gl.bindVertexArray(this.unusedVAO);
|
|
114267
|
-
}
|
|
115892
|
+
if (this.volumes.length > 0)
|
|
115893
|
+
this.drawImage3D(mvpMatrix, azimuth, elevation);
|
|
114268
115894
|
if (!isMosaic)
|
|
114269
115895
|
this.drawCrosshairs3D(true, 1, mvpMatrix);
|
|
114270
115896
|
this.drawMesh3D(true, 1, mvpMatrix, modelMatrix, normalMatrix);
|
|
115897
|
+
if (this.scene.mouseDepthPicker) {
|
|
115898
|
+
this.depthPicker(leftTopWidthHeight, mvpMatrix, true);
|
|
115899
|
+
return;
|
|
115900
|
+
}
|
|
114271
115901
|
this.drawMesh3D(false, 0.02, mvpMatrix, modelMatrix, normalMatrix);
|
|
114272
115902
|
if (!isMosaic)
|
|
114273
115903
|
this.drawCrosshairs3D(false, 0.15, mvpMatrix);
|
|
114274
115904
|
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
115905
|
+
this.drawOrientationCube(leftTopWidthHeight, azimuth, elevation);
|
|
114275
115906
|
let posString = "azimuth: " + this.scene.renderAzimuth.toFixed(0) + " elevation: " + this.scene.renderElevation.toFixed(0);
|
|
114276
115907
|
this.drawGraph();
|
|
114277
115908
|
this.readyForSync = true;
|
|
@@ -114296,13 +115927,17 @@ Niivue.prototype.drawMesh3D = function(isDepthTest = true, alpha = 1, m, modelMt
|
|
|
114296
115927
|
gl.depthFunc(gl.ALWAYS);
|
|
114297
115928
|
}
|
|
114298
115929
|
gl.disable(gl.CULL_FACE);
|
|
114299
|
-
this.
|
|
114300
|
-
gl.uniformMatrix4fv(this.meshShader.uniforms["mvpMtx"], false, m);
|
|
114301
|
-
gl.uniformMatrix4fv(this.meshShader.uniforms["modelMtx"], false, modelMtx);
|
|
114302
|
-
gl.uniformMatrix4fv(this.meshShader.uniforms["normMtx"], false, normMtx);
|
|
114303
|
-
gl.uniform1f(this.meshShader.uniforms["opacity"], alpha);
|
|
115930
|
+
let shader = this.meshShaders[0];
|
|
114304
115931
|
let hasFibers = false;
|
|
114305
115932
|
for (let i2 = 0; i2 < this.meshes.length; i2++) {
|
|
115933
|
+
shader = this.meshShaders[this.meshes[i2].meshShaderIndex].shader;
|
|
115934
|
+
if (this.scene.mouseDepthPicker)
|
|
115935
|
+
shader = this.pickingMeshShader;
|
|
115936
|
+
shader.use(this.gl);
|
|
115937
|
+
gl.uniformMatrix4fv(shader.mvpLoc, false, m);
|
|
115938
|
+
gl.uniformMatrix4fv(shader.uniforms["modelMtx"], false, modelMtx);
|
|
115939
|
+
gl.uniformMatrix4fv(shader.uniforms["normMtx"], false, normMtx);
|
|
115940
|
+
gl.uniform1f(shader.uniforms["opacity"], alpha);
|
|
114306
115941
|
if (this.meshes[i2].indexCount < 3)
|
|
114307
115942
|
continue;
|
|
114308
115943
|
if (this.meshes[i2].offsetPt0) {
|
|
@@ -114318,9 +115953,9 @@ Niivue.prototype.drawMesh3D = function(isDepthTest = true, alpha = 1, m, modelMt
|
|
|
114318
115953
|
gl.depthFunc(gl.ALWAYS);
|
|
114319
115954
|
return;
|
|
114320
115955
|
}
|
|
114321
|
-
|
|
115956
|
+
shader = this.fiberShader;
|
|
114322
115957
|
shader.use(this.gl);
|
|
114323
|
-
gl.uniformMatrix4fv(shader.
|
|
115958
|
+
gl.uniformMatrix4fv(shader.mvpLoc, false, m);
|
|
114324
115959
|
gl.uniform1f(shader.uniforms["opacity"], alpha);
|
|
114325
115960
|
for (let i2 = 0; i2 < this.meshes.length; i2++) {
|
|
114326
115961
|
if (this.meshes[i2].indexCount < 3)
|
|
@@ -114335,8 +115970,10 @@ Niivue.prototype.drawMesh3D = function(isDepthTest = true, alpha = 1, m, modelMt
|
|
|
114335
115970
|
gl.depthFunc(gl.ALWAYS);
|
|
114336
115971
|
this.readyForSync = true;
|
|
114337
115972
|
};
|
|
114338
|
-
Niivue.prototype.drawCrosshairs3D = function(isDepthTest = true, alpha = 1, mvpMtx = null) {
|
|
114339
|
-
if (!this.opts.show3Dcrosshair)
|
|
115973
|
+
Niivue.prototype.drawCrosshairs3D = function(isDepthTest = true, alpha = 1, mvpMtx = null, is2DView = false) {
|
|
115974
|
+
if (!this.opts.show3Dcrosshair && !is2DView)
|
|
115975
|
+
return;
|
|
115976
|
+
if (this.opts.crosshairWidth <= 0 && is2DView)
|
|
114340
115977
|
return;
|
|
114341
115978
|
let gl = this.gl;
|
|
114342
115979
|
let mm = this.frac2mm(this.scene.crosshairPos);
|
|
@@ -114345,8 +115982,14 @@ Niivue.prototype.drawCrosshairs3D = function(isDepthTest = true, alpha = 1, mvpM
|
|
|
114345
115982
|
gl.deleteBuffer(this.crosshairs3D.indexBuffer);
|
|
114346
115983
|
gl.deleteBuffer(this.crosshairs3D.vertexBuffer);
|
|
114347
115984
|
}
|
|
114348
|
-
let
|
|
114349
|
-
|
|
115985
|
+
let [mn, mx, range] = this.sceneExtentsMinMax();
|
|
115986
|
+
let radius = 1;
|
|
115987
|
+
if (this.volumes.length > 0)
|
|
115988
|
+
radius = 0.5 * Math.min(Math.min(this.back.pixDims[1], this.back.pixDims[2]), this.back.pixDims[3]);
|
|
115989
|
+
else if (range[0] < 50 || range[0] > 1e3)
|
|
115990
|
+
radius = range[0] * 0.02;
|
|
115991
|
+
radius *= this.opts.crosshairWidth;
|
|
115992
|
+
this.crosshairs3D = NiivueObject3D.generateCrosshairs(this.gl, 1, mm, mn, mx, radius);
|
|
114350
115993
|
this.crosshairs3D.mm = mm;
|
|
114351
115994
|
}
|
|
114352
115995
|
let crosshairsShader = this.surfaceShader;
|
|
@@ -114354,7 +115997,7 @@ Niivue.prototype.drawCrosshairs3D = function(isDepthTest = true, alpha = 1, mvpM
|
|
|
114354
115997
|
let modelMtx, normMtx;
|
|
114355
115998
|
if (mvpMtx == null)
|
|
114356
115999
|
[mvpMtx, modelMtx, normMtx] = this.calculateMvpMatrix(this.crosshairs3D, this.scene.renderAzimuth, this.scene.renderElevation);
|
|
114357
|
-
gl.uniformMatrix4fv(crosshairsShader.
|
|
116000
|
+
gl.uniformMatrix4fv(crosshairsShader.mvpLoc, false, mvpMtx);
|
|
114358
116001
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.crosshairs3D.indexBuffer);
|
|
114359
116002
|
gl.enable(gl.DEPTH_TEST);
|
|
114360
116003
|
let color = [...this.opts.crosshairColor];
|
|
@@ -114367,12 +116010,20 @@ Niivue.prototype.drawCrosshairs3D = function(isDepthTest = true, alpha = 1, mvpM
|
|
|
114367
116010
|
gl.depthFunc(gl.ALWAYS);
|
|
114368
116011
|
}
|
|
114369
116012
|
color[3] = alpha;
|
|
114370
|
-
gl.uniform4fv(crosshairsShader.
|
|
116013
|
+
gl.uniform4fv(crosshairsShader.colorLoc, color);
|
|
114371
116014
|
gl.bindVertexArray(this.crosshairs3D.vao);
|
|
114372
116015
|
gl.drawElements(gl.TRIANGLES, this.crosshairs3D.indexCount, gl.UNSIGNED_INT, 0);
|
|
114373
116016
|
gl.bindVertexArray(this.unusedVAO);
|
|
114374
116017
|
};
|
|
114375
116018
|
Niivue.prototype.mm2frac = function(mm, volIdx = 0) {
|
|
116019
|
+
if (this.volumes.length < 1) {
|
|
116020
|
+
let frac2 = [0.1, 0.5, 0.5];
|
|
116021
|
+
let [mn, mx, range] = this.sceneExtentsMinMax();
|
|
116022
|
+
frac2[0] = (mm[0] - mn[0]) / range[0];
|
|
116023
|
+
frac2[1] = (mm[1] - mn[1]) / range[1];
|
|
116024
|
+
frac2[2] = (mm[2] - mn[2]) / range[2];
|
|
116025
|
+
return frac2;
|
|
116026
|
+
}
|
|
114376
116027
|
let mm4 = fromValues(mm[0], mm[1], mm[2], 1);
|
|
114377
116028
|
let d = this.volumes[volIdx].dimsRAS;
|
|
114378
116029
|
let frac = [0, 0, 0];
|
|
@@ -114416,10 +116067,18 @@ Niivue.prototype.moveCrosshairInVox = function(x2, y, z) {
|
|
|
114416
116067
|
};
|
|
114417
116068
|
Niivue.prototype.frac2mm = function(frac, volIdx = 0) {
|
|
114418
116069
|
let pos = fromValues(frac[0], frac[1], frac[2], 1);
|
|
114419
|
-
|
|
116070
|
+
if (this.volumes.length > 0)
|
|
116071
|
+
transformMat4(pos, pos, this.volumes[volIdx].frac2mm);
|
|
116072
|
+
else {
|
|
116073
|
+
let [mn, mx] = this.sceneExtentsMinMax();
|
|
116074
|
+
const lerp2 = (x2, y, a) => x2 * (1 - a) + y * a;
|
|
116075
|
+
pos[0] = lerp2(mn[0], mx[0], frac[0]);
|
|
116076
|
+
pos[1] = lerp2(mn[1], mx[1], frac[1]);
|
|
116077
|
+
pos[2] = lerp2(mn[2], mx[2], frac[2]);
|
|
116078
|
+
}
|
|
114420
116079
|
return pos;
|
|
114421
116080
|
};
|
|
114422
|
-
Niivue.prototype.screenXY2TextureFrac = function(x2, y, i2) {
|
|
116081
|
+
Niivue.prototype.screenXY2TextureFrac = function(x2, y, i2, restrict0to1 = true) {
|
|
114423
116082
|
let texFrac = [-1, -1, -1];
|
|
114424
116083
|
var axCorSag = this.screenSlices[i2].axCorSag;
|
|
114425
116084
|
if (axCorSag > this.sliceTypeSagittal)
|
|
@@ -114448,8 +116107,10 @@ Niivue.prototype.screenXY2TextureFrac = function(x2, y, i2) {
|
|
|
114448
116107
|
if (axCorSag === this.sliceTypeSagittal)
|
|
114449
116108
|
xyzMM = swizzleVec3(xyzMM, [2, 0, 1]);
|
|
114450
116109
|
let xyz = this.mm2frac(xyzMM);
|
|
114451
|
-
if (
|
|
114452
|
-
|
|
116110
|
+
if (restrict0to1) {
|
|
116111
|
+
if (xyz[0] < 0 || xyz[0] > 1 || xyz[1] < 0 || xyz[1] > 1 || xyz[2] < 0 || xyz[2] > 1)
|
|
116112
|
+
return texFrac;
|
|
116113
|
+
}
|
|
114453
116114
|
texFrac[0] = xyz[0];
|
|
114454
116115
|
texFrac[1] = xyz[1];
|
|
114455
116116
|
texFrac[2] = xyz[2];
|
|
@@ -114478,15 +116139,17 @@ Niivue.prototype.canvasPos2frac = function(canvasPos) {
|
|
|
114478
116139
|
}
|
|
114479
116140
|
return [-1, -1, -1];
|
|
114480
116141
|
};
|
|
114481
|
-
Niivue.prototype.scaleSlice = function(w, h) {
|
|
114482
|
-
let
|
|
114483
|
-
|
|
114484
|
-
|
|
116142
|
+
Niivue.prototype.scaleSlice = function(w, h, widthPadPixels = 0, heightPadPixels = 0) {
|
|
116143
|
+
let canvasW = this.canvas.width - widthPadPixels;
|
|
116144
|
+
let canvasH = this.effectiveCanvasHeight() - heightPadPixels;
|
|
116145
|
+
let scalePix = canvasW / w;
|
|
116146
|
+
if (h * scalePix > canvasH)
|
|
116147
|
+
scalePix = canvasH / h;
|
|
114485
116148
|
let wPix = w * scalePix;
|
|
114486
116149
|
let hPix = h * scalePix;
|
|
114487
116150
|
let leftTopWidthHeight = [
|
|
114488
|
-
(
|
|
114489
|
-
(
|
|
116151
|
+
(canvasW - wPix) * 0.5,
|
|
116152
|
+
(canvasH - hPix) * 0.5,
|
|
114490
116153
|
wPix,
|
|
114491
116154
|
hPix
|
|
114492
116155
|
];
|
|
@@ -114506,32 +116169,24 @@ Niivue.prototype.drawThumbnail = function() {
|
|
|
114506
116169
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
114507
116170
|
this.gl.bindVertexArray(this.unusedVAO);
|
|
114508
116171
|
};
|
|
114509
|
-
Niivue.prototype.drawLine = function(
|
|
114510
|
-
this.gl.enable(this.gl.BLEND);
|
|
114511
|
-
this.rectShader.use(this.gl);
|
|
114512
|
-
this.gl.uniform4fv(this.rectShader.uniforms["lineColor"], this.opts.crosshairColor);
|
|
114513
|
-
this.gl.uniform2fv(this.rectShader.uniforms["canvasWidthHeight"], [
|
|
114514
|
-
this.gl.canvas.width,
|
|
114515
|
-
this.gl.canvas.height
|
|
114516
|
-
]);
|
|
114517
|
-
this.gl.uniform4f(this.rectShader.uniforms["leftTopWidthHeight"], leftTopWidthHeight[0], leftTopWidthHeight[1], leftTopWidthHeight[2], leftTopWidthHeight[3]);
|
|
114518
|
-
this.gl.bindVertexArray(this.genericVAO);
|
|
114519
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
114520
|
-
this.gl.bindVertexArray(this.unusedVAO);
|
|
114521
|
-
};
|
|
114522
|
-
Niivue.prototype.drawLine2DX = function(startXYendXY, thickness = 1) {
|
|
116172
|
+
Niivue.prototype.drawLine = function(startXYendXY, thickness = 1, lineColor = [1, 0, 0, -1]) {
|
|
114523
116173
|
this.gl.bindVertexArray(this.genericVAO);
|
|
114524
116174
|
this.lineShader.use(this.gl);
|
|
114525
|
-
|
|
114526
|
-
|
|
116175
|
+
if (lineColor[3] < 0)
|
|
116176
|
+
lineColor = this.opts.crosshairColor;
|
|
116177
|
+
this.gl.uniform4fv(this.lineShader.lineColorLoc, lineColor);
|
|
116178
|
+
this.gl.uniform2fv(this.lineShader.canvasWidthHeightLoc, [
|
|
114527
116179
|
this.gl.canvas.width,
|
|
114528
116180
|
this.gl.canvas.height
|
|
114529
116181
|
]);
|
|
114530
|
-
this.gl.uniform1f(this.lineShader.
|
|
114531
|
-
this.gl.uniform4fv(this.lineShader.
|
|
116182
|
+
this.gl.uniform1f(this.lineShader.thicknessLoc, thickness);
|
|
116183
|
+
this.gl.uniform4fv(this.lineShader.startXYendXYLoc, startXYendXY);
|
|
114532
116184
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
114533
116185
|
this.gl.bindVertexArray(this.unusedVAO);
|
|
114534
116186
|
};
|
|
116187
|
+
Niivue.prototype.drawGraphLine = function(LTRB, color = [1, 0, 0, 0.5], thickness = 2) {
|
|
116188
|
+
this.drawLine(LTRB, thickness, color);
|
|
116189
|
+
};
|
|
114535
116190
|
Niivue.prototype.drawCrossLinesMM = function(sliceIndex, axCorSag, axiMM, corMM, sagMM) {
|
|
114536
116191
|
if (sliceIndex < 0 || this.screenSlices.length <= sliceIndex)
|
|
114537
116192
|
return;
|
|
@@ -114565,12 +116220,11 @@ Niivue.prototype.drawCrossLinesMM = function(sliceIndex, axCorSag, axiMM, corMM,
|
|
|
114565
116220
|
right = swizzleVec3(right, [0, 1, 2]);
|
|
114566
116221
|
left = mm2screen(left);
|
|
114567
116222
|
right = mm2screen(right);
|
|
114568
|
-
this.
|
|
116223
|
+
this.drawLine([left[0], left[1], right[0], right[1]], thick);
|
|
114569
116224
|
}
|
|
114570
116225
|
}
|
|
114571
116226
|
if (linesH.length > 0 && axCorSag === 1) {
|
|
114572
116227
|
let fracH = tile.sliceFrac;
|
|
114573
|
-
this.frac2mm([0.5, fracH, 0.5]);
|
|
114574
116228
|
let dimV = 2;
|
|
114575
116229
|
for (let i2 = 0; i2 < linesH.length; i2++) {
|
|
114576
116230
|
let mmV = this.frac2mm([0.5, 0.5, 0.5]);
|
|
@@ -114583,7 +116237,7 @@ Niivue.prototype.drawCrossLinesMM = function(sliceIndex, axCorSag, axiMM, corMM,
|
|
|
114583
116237
|
right = swizzleVec3(right, [0, 2, 1]);
|
|
114584
116238
|
left = mm2screen(left);
|
|
114585
116239
|
right = mm2screen(right);
|
|
114586
|
-
this.
|
|
116240
|
+
this.drawLine([left[0], left[1], right[0], right[1]], thick);
|
|
114587
116241
|
}
|
|
114588
116242
|
}
|
|
114589
116243
|
if (linesH.length > 0 && axCorSag === 2) {
|
|
@@ -114600,7 +116254,7 @@ Niivue.prototype.drawCrossLinesMM = function(sliceIndex, axCorSag, axiMM, corMM,
|
|
|
114600
116254
|
right = swizzleVec3(right, [1, 2, 0]);
|
|
114601
116255
|
left = mm2screen(left);
|
|
114602
116256
|
right = mm2screen(right);
|
|
114603
|
-
this.
|
|
116257
|
+
this.drawLine([left[0], left[1], right[0], right[1]], thick);
|
|
114604
116258
|
}
|
|
114605
116259
|
}
|
|
114606
116260
|
if (linesV.length > 0 && axCorSag === 0) {
|
|
@@ -114617,7 +116271,7 @@ Niivue.prototype.drawCrossLinesMM = function(sliceIndex, axCorSag, axiMM, corMM,
|
|
|
114617
116271
|
right = swizzleVec3(right, [0, 1, 2]);
|
|
114618
116272
|
left = mm2screen(left);
|
|
114619
116273
|
right = mm2screen(right);
|
|
114620
|
-
this.
|
|
116274
|
+
this.drawLine([left[0], left[1], right[0], right[1]], thick);
|
|
114621
116275
|
}
|
|
114622
116276
|
}
|
|
114623
116277
|
if (linesV.length > 0 && axCorSag === 1) {
|
|
@@ -114634,7 +116288,7 @@ Niivue.prototype.drawCrossLinesMM = function(sliceIndex, axCorSag, axiMM, corMM,
|
|
|
114634
116288
|
right = swizzleVec3(right, [0, 2, 1]);
|
|
114635
116289
|
left = mm2screen(left);
|
|
114636
116290
|
right = mm2screen(right);
|
|
114637
|
-
this.
|
|
116291
|
+
this.drawLine([left[0], left[1], right[0], right[1]], thick);
|
|
114638
116292
|
}
|
|
114639
116293
|
}
|
|
114640
116294
|
if (linesV.length > 0 && axCorSag === 2) {
|
|
@@ -114651,7 +116305,7 @@ Niivue.prototype.drawCrossLinesMM = function(sliceIndex, axCorSag, axiMM, corMM,
|
|
|
114651
116305
|
right = swizzleVec3(right, [1, 2, 0]);
|
|
114652
116306
|
left = mm2screen(left);
|
|
114653
116307
|
right = mm2screen(right);
|
|
114654
|
-
this.
|
|
116308
|
+
this.drawLine([left[0], left[1], right[0], right[1]], thick);
|
|
114655
116309
|
}
|
|
114656
116310
|
}
|
|
114657
116311
|
};
|
|
@@ -114663,7 +116317,6 @@ Niivue.prototype.drawCrossLines = function(sliceIndex, axCorSag, axiMM, corMM, s
|
|
|
114663
116317
|
let tile = this.screenSlices[sliceIndex];
|
|
114664
116318
|
let linesH = corMM.slice();
|
|
114665
116319
|
let linesV = sagMM.slice();
|
|
114666
|
-
Math.max(1, this.opts.crosshairWidth);
|
|
114667
116320
|
if (axCorSag === this.sliceTypeCoronal)
|
|
114668
116321
|
linesH = axiMM.slice();
|
|
114669
116322
|
if (axCorSag === this.sliceTypeSagittal) {
|
|
@@ -114677,7 +116330,7 @@ Niivue.prototype.drawCrossLines = function(sliceIndex, axCorSag, axiMM, corMM, s
|
|
|
114677
116330
|
for (let i2 = 0; i2 < linesH.length; i2++) {
|
|
114678
116331
|
mm[sliceDim] = linesH[i2];
|
|
114679
116332
|
let frac = this.mm2frac(mm);
|
|
114680
|
-
this.
|
|
116333
|
+
this.drawRect([
|
|
114681
116334
|
LTWH[0],
|
|
114682
116335
|
LTWH[1] + LTWH[3] - frac[sliceDim] * LTWH[3],
|
|
114683
116336
|
LTWH[2],
|
|
@@ -114696,14 +116349,14 @@ Niivue.prototype.drawCrossLines = function(sliceIndex, axCorSag, axiMM, corMM, s
|
|
|
114696
116349
|
mm[sliceDim] = linesV[i2];
|
|
114697
116350
|
let frac = this.mm2frac(mm);
|
|
114698
116351
|
if (isRadiolgical)
|
|
114699
|
-
this.
|
|
116352
|
+
this.drawRect([
|
|
114700
116353
|
LTWH[0] + (LTWH[2] - frac[sliceDim] * LTWH[2]),
|
|
114701
116354
|
LTWH[1],
|
|
114702
116355
|
1,
|
|
114703
116356
|
LTWH[3]
|
|
114704
116357
|
]);
|
|
114705
116358
|
else
|
|
114706
|
-
this.
|
|
116359
|
+
this.drawRect([
|
|
114707
116360
|
LTWH[0] + frac[sliceDim] * LTWH[2],
|
|
114708
116361
|
LTWH[1],
|
|
114709
116362
|
1,
|
|
@@ -114825,7 +116478,7 @@ Niivue.prototype.drawScene = function() {
|
|
|
114825
116478
|
}
|
|
114826
116479
|
this.colorbarHeight = 0;
|
|
114827
116480
|
this.gl.clearColor(this.opts.backColor[0], this.opts.backColor[1], this.opts.backColor[2], this.opts.backColor[3]);
|
|
114828
|
-
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
116481
|
+
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
|
|
114829
116482
|
if (this.bmpTexture) {
|
|
114830
116483
|
this.drawThumbnail();
|
|
114831
116484
|
return;
|
|
@@ -114855,6 +116508,8 @@ Niivue.prototype.drawScene = function() {
|
|
|
114855
116508
|
}
|
|
114856
116509
|
}
|
|
114857
116510
|
if (this.sliceMosaicString.length < 1 && this.sliceType === this.sliceTypeRender) {
|
|
116511
|
+
if (this.opts.isColorbar)
|
|
116512
|
+
this.reserveColorbarPanel();
|
|
114858
116513
|
this.screenSlices = [];
|
|
114859
116514
|
this.draw3D();
|
|
114860
116515
|
if (this.opts.isColorbar)
|
|
@@ -114875,12 +116530,15 @@ Niivue.prototype.drawScene = function() {
|
|
|
114875
116530
|
} else if (this.sliceType === this.sliceTypeSagittal) {
|
|
114876
116531
|
this.draw2D([0, 0, 0, 0], 2);
|
|
114877
116532
|
} else {
|
|
114878
|
-
let { volScale
|
|
114879
|
-
|
|
116533
|
+
let { volScale } = this.sliceScale();
|
|
116534
|
+
if (typeof this.opts.multiplanarPadPixels !== "number")
|
|
116535
|
+
console.log("multiplanarPadPixels must be numeric");
|
|
116536
|
+
let pad = parseFloat(this.opts.multiplanarPadPixels);
|
|
116537
|
+
let ltwh = this.scaleSlice(volScale[0] + volScale[1], volScale[1] + volScale[2], pad * 1, pad * 1);
|
|
114880
116538
|
let wX = ltwh[2] * volScale[0] / (volScale[0] + volScale[1]);
|
|
114881
|
-
let ltwh3x1 = this.scaleSlice(volScale[0] + volScale[0] + volScale[1], Math.max(volScale[1], volScale[2]));
|
|
116539
|
+
let ltwh3x1 = this.scaleSlice(volScale[0] + volScale[0] + volScale[1], Math.max(volScale[1], volScale[2]), pad * 2);
|
|
114882
116540
|
let mx = Math.max(Math.max(volScale[1], volScale[2]), volScale[0]);
|
|
114883
|
-
let ltwh4x1 = this.scaleSlice(volScale[0] + volScale[0] + volScale[1] + mx, mx);
|
|
116541
|
+
let ltwh4x1 = this.scaleSlice(volScale[0] + volScale[0] + volScale[1] + mx, mx, pad * 3);
|
|
114884
116542
|
let wX1 = ltwh3x1[2] * volScale[0] / (volScale[0] + volScale[0] + volScale[1]);
|
|
114885
116543
|
if (wX1 > wX && !this.graph.autoSizeMultiplanar) {
|
|
114886
116544
|
let pixScale = wX1 / volScale[0];
|
|
@@ -114889,24 +116547,24 @@ Niivue.prototype.drawScene = function() {
|
|
|
114889
116547
|
if (ltwh3x1[3] === ltwh4x1[3]) {
|
|
114890
116548
|
ltwh3x1 = ltwh4x1;
|
|
114891
116549
|
this.draw3D([
|
|
114892
|
-
ltwh3x1[0] + wX1 + wX1 + hY1,
|
|
116550
|
+
ltwh3x1[0] + wX1 + wX1 + hY1 + pad * 3,
|
|
114893
116551
|
ltwh3x1[1],
|
|
114894
116552
|
ltwh4x1[3],
|
|
114895
116553
|
ltwh4x1[3]
|
|
114896
116554
|
]);
|
|
114897
116555
|
}
|
|
114898
116556
|
this.draw2D([ltwh3x1[0], ltwh3x1[1], wX1, hY1], 0);
|
|
114899
|
-
this.draw2D([ltwh3x1[0] + wX1, ltwh3x1[1], wX1, hZ1], 1);
|
|
114900
|
-
this.draw2D([ltwh3x1[0] + wX1 + wX1, ltwh3x1[1], hY1, hZ1], 2);
|
|
116557
|
+
this.draw2D([ltwh3x1[0] + wX1 + pad, ltwh3x1[1], wX1, hZ1], 1);
|
|
116558
|
+
this.draw2D([ltwh3x1[0] + wX1 + wX1 + pad * 2, ltwh3x1[1], hY1, hZ1], 2);
|
|
114901
116559
|
} else {
|
|
114902
116560
|
let wY = ltwh[2] - wX;
|
|
114903
116561
|
let hY = ltwh[3] * volScale[1] / (volScale[1] + volScale[2]);
|
|
114904
116562
|
let hZ = ltwh[3] - hY;
|
|
114905
|
-
this.draw2D([ltwh[0], ltwh[1] + hZ, wX, hY], 0);
|
|
116563
|
+
this.draw2D([ltwh[0], ltwh[1] + hZ + pad, wX, hY], 0);
|
|
114906
116564
|
this.draw2D([ltwh[0], ltwh[1], wX, hZ], 1);
|
|
114907
|
-
this.draw2D([ltwh[0] + wX, ltwh[1], wY, hZ], 2);
|
|
116565
|
+
this.draw2D([ltwh[0] + wX + pad, ltwh[1], wY, hZ], 2);
|
|
114908
116566
|
if (!this.graph.autoSizeMultiplanar)
|
|
114909
|
-
this.draw3D([ltwh[0] + wX, ltwh[1] + hZ, wY, hY]);
|
|
116567
|
+
this.draw3D([ltwh[0] + wX + pad, ltwh[1] + hZ + pad, wY, hY]);
|
|
114910
116568
|
}
|
|
114911
116569
|
}
|
|
114912
116570
|
}
|
|
@@ -114915,6 +116573,15 @@ Niivue.prototype.drawScene = function() {
|
|
|
114915
116573
|
if (this.opts.isColorbar)
|
|
114916
116574
|
this.drawColorbar();
|
|
114917
116575
|
if (this.isDragging) {
|
|
116576
|
+
if (this.opts.isDragForPanZoom) {
|
|
116577
|
+
this.dragForPanZoom([
|
|
116578
|
+
this.dragStart[0],
|
|
116579
|
+
this.dragStart[1],
|
|
116580
|
+
this.dragEnd[0],
|
|
116581
|
+
this.dragEnd[1]
|
|
116582
|
+
]);
|
|
116583
|
+
return;
|
|
116584
|
+
}
|
|
114918
116585
|
if (this.opts.isDragShowsMeasurementTool) {
|
|
114919
116586
|
this.drawMeasurementTool([
|
|
114920
116587
|
this.dragStart[0],
|
|
@@ -114946,4 +116613,4 @@ Niivue.prototype.drawScene = function() {
|
|
|
114946
116613
|
this.readyForSync = true;
|
|
114947
116614
|
return posString;
|
|
114948
116615
|
};
|
|
114949
|
-
export { NVImage, NVMesh, Niivue };
|
|
116616
|
+
export { NVImage, NVImageFromUrlOptions, NVMesh, NVMeshFromUrlOptions, Niivue, colortables };
|