@niivue/niivue 0.43.7 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.ts +48 -2
- package/build/index.js +382 -35
- package/build/index.js.map +1 -1
- package/build/index.min.js +1 -1
- package/dist/index.d.ts +48 -2
- package/dist/index.js +504 -158
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/niivue.umd.js +31 -29
- package/package.json +1 -1
- package/src/index.html +5 -1
- package/src/niivue/index.ts +165 -28
- package/src/nvdocument.ts +10 -0
- package/src/nvimage/index.ts +25 -2
- package/src/nvimage/utils.ts +2 -0
- package/src/nvmesh-loaders.ts +26 -5
- package/src/nvmesh-utilities.ts +139 -0
- package/src/nvmesh.ts +96 -0
package/build/index.js
CHANGED
|
@@ -13,7 +13,7 @@ var __publicField = (obj, key, value) => {
|
|
|
13
13
|
import { mat4 as mat46, vec2, vec3 as vec311, vec4 as vec48 } from "gl-matrix";
|
|
14
14
|
|
|
15
15
|
// package.json
|
|
16
|
-
var version = "0.
|
|
16
|
+
var version = "0.44.1";
|
|
17
17
|
|
|
18
18
|
// src/logger.ts
|
|
19
19
|
var _Log = class _Log {
|
|
@@ -11254,6 +11254,7 @@ var cmapper = new ColorTables();
|
|
|
11254
11254
|
|
|
11255
11255
|
// src/nvmesh-utilities.ts
|
|
11256
11256
|
import { vec3 as vec32 } from "gl-matrix";
|
|
11257
|
+
import { gzipSync } from "fflate/browser";
|
|
11257
11258
|
var NVMeshUtilities = class {
|
|
11258
11259
|
static getClusterBoundaryU8(u8, faces) {
|
|
11259
11260
|
const border = new Array(u8.length).fill(false);
|
|
@@ -11279,6 +11280,112 @@ var NVMeshUtilities = class {
|
|
|
11279
11280
|
}
|
|
11280
11281
|
return border;
|
|
11281
11282
|
}
|
|
11283
|
+
static createMZ3(vertices, indices, compress2 = false) {
|
|
11284
|
+
const magic = 23117;
|
|
11285
|
+
const attr = 3;
|
|
11286
|
+
const nface = indices.length / 3;
|
|
11287
|
+
const nvert = vertices.length / 3;
|
|
11288
|
+
const nskip = 0;
|
|
11289
|
+
const headerSize = 16;
|
|
11290
|
+
const indexSize = nface * 3 * 4;
|
|
11291
|
+
const vertexSize = nvert * 3 * 4;
|
|
11292
|
+
const totalSize = headerSize + indexSize + vertexSize;
|
|
11293
|
+
const buffer = new ArrayBuffer(totalSize);
|
|
11294
|
+
const writer = new DataView(buffer);
|
|
11295
|
+
writer.setUint16(0, magic, true);
|
|
11296
|
+
writer.setUint16(2, attr, true);
|
|
11297
|
+
writer.setUint32(4, nface, true);
|
|
11298
|
+
writer.setUint32(8, nvert, true);
|
|
11299
|
+
writer.setUint32(12, nskip, true);
|
|
11300
|
+
let offset = headerSize;
|
|
11301
|
+
new Uint32Array(buffer, offset, indices.length).set(indices);
|
|
11302
|
+
offset += indexSize;
|
|
11303
|
+
new Float32Array(buffer, offset, vertices.length).set(vertices);
|
|
11304
|
+
if (compress2) {
|
|
11305
|
+
return gzipSync(new Uint8Array(buffer));
|
|
11306
|
+
}
|
|
11307
|
+
return buffer;
|
|
11308
|
+
}
|
|
11309
|
+
static createOBJ(vertices, indices) {
|
|
11310
|
+
let objContent = "";
|
|
11311
|
+
for (let i = 0; i < vertices.length; i += 3) {
|
|
11312
|
+
objContent += `v ${vertices[i]} ${vertices[i + 1]} ${vertices[i + 2]}
|
|
11313
|
+
`;
|
|
11314
|
+
}
|
|
11315
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
11316
|
+
objContent += `f ${indices[i] + 1} ${indices[i + 1] + 1} ${indices[i + 2] + 1}
|
|
11317
|
+
`;
|
|
11318
|
+
}
|
|
11319
|
+
const encoder = new TextEncoder();
|
|
11320
|
+
const arrayBuffer = encoder.encode(objContent).buffer;
|
|
11321
|
+
return arrayBuffer;
|
|
11322
|
+
}
|
|
11323
|
+
static createSTL(vertices, indices) {
|
|
11324
|
+
const numTriangles = indices.length / 3;
|
|
11325
|
+
const bufferLength = 84 + numTriangles * 50;
|
|
11326
|
+
const arrayBuffer = new ArrayBuffer(bufferLength);
|
|
11327
|
+
const dataView = new DataView(arrayBuffer);
|
|
11328
|
+
for (let i = 0; i < 80; i++) {
|
|
11329
|
+
dataView.setUint8(i, 0);
|
|
11330
|
+
}
|
|
11331
|
+
dataView.setUint32(80, numTriangles, true);
|
|
11332
|
+
let offset = 84;
|
|
11333
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
11334
|
+
const i0 = indices[i] * 3;
|
|
11335
|
+
const i1 = indices[i + 1] * 3;
|
|
11336
|
+
const i2 = indices[i + 2] * 3;
|
|
11337
|
+
dataView.setFloat32(offset, 0, true);
|
|
11338
|
+
dataView.setFloat32(offset + 4, 0, true);
|
|
11339
|
+
dataView.setFloat32(offset + 8, 0, true);
|
|
11340
|
+
offset += 12;
|
|
11341
|
+
dataView.setFloat32(offset, vertices[i0], true);
|
|
11342
|
+
dataView.setFloat32(offset + 4, vertices[i0 + 1], true);
|
|
11343
|
+
dataView.setFloat32(offset + 8, vertices[i0 + 2], true);
|
|
11344
|
+
offset += 12;
|
|
11345
|
+
dataView.setFloat32(offset, vertices[i1], true);
|
|
11346
|
+
dataView.setFloat32(offset + 4, vertices[i1 + 1], true);
|
|
11347
|
+
dataView.setFloat32(offset + 8, vertices[i1 + 2], true);
|
|
11348
|
+
offset += 12;
|
|
11349
|
+
dataView.setFloat32(offset, vertices[i2], true);
|
|
11350
|
+
dataView.setFloat32(offset + 4, vertices[i2 + 1], true);
|
|
11351
|
+
dataView.setFloat32(offset + 8, vertices[i2 + 2], true);
|
|
11352
|
+
offset += 12;
|
|
11353
|
+
dataView.setUint16(offset, 0, true);
|
|
11354
|
+
offset += 2;
|
|
11355
|
+
}
|
|
11356
|
+
return arrayBuffer;
|
|
11357
|
+
}
|
|
11358
|
+
static downloadArrayBuffer(buffer, filename) {
|
|
11359
|
+
const blob = new Blob([buffer], { type: "application/octet-stream" });
|
|
11360
|
+
const url = URL.createObjectURL(blob);
|
|
11361
|
+
const a = document.createElement("a");
|
|
11362
|
+
a.href = url;
|
|
11363
|
+
a.download = filename;
|
|
11364
|
+
document.body.appendChild(a);
|
|
11365
|
+
a.style.display = "none";
|
|
11366
|
+
a.click();
|
|
11367
|
+
setTimeout(() => {
|
|
11368
|
+
document.body.removeChild(a);
|
|
11369
|
+
URL.revokeObjectURL(url);
|
|
11370
|
+
}, 0);
|
|
11371
|
+
}
|
|
11372
|
+
static saveMesh(vertices, indices, filename = ".mz3", compress2 = false) {
|
|
11373
|
+
let buff = new ArrayBuffer(0);
|
|
11374
|
+
if (/\.obj$/i.test(filename)) {
|
|
11375
|
+
buff = this.createOBJ(vertices, indices);
|
|
11376
|
+
} else if (/\.stl$/i.test(filename)) {
|
|
11377
|
+
buff = this.createSTL(vertices, indices);
|
|
11378
|
+
} else {
|
|
11379
|
+
if (!/\.mz3$/i.test(filename)) {
|
|
11380
|
+
filename += ".mz3";
|
|
11381
|
+
}
|
|
11382
|
+
buff = this.createMZ3(vertices, indices, compress2);
|
|
11383
|
+
}
|
|
11384
|
+
if (filename.length > 4) {
|
|
11385
|
+
this.downloadArrayBuffer(buff, filename);
|
|
11386
|
+
}
|
|
11387
|
+
return buff;
|
|
11388
|
+
}
|
|
11282
11389
|
static getClusterBoundary(rgba8, faces) {
|
|
11283
11390
|
const rgba32 = new Uint32Array(rgba8.buffer);
|
|
11284
11391
|
const border = new Array(rgba32.length).fill(false);
|
|
@@ -12669,7 +12776,8 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12669
12776
|
static readANNOT(buffer, n_vert, isReadColortables = false) {
|
|
12670
12777
|
const view = new DataView(buffer);
|
|
12671
12778
|
const n_vertex = view.getUint32(0, false);
|
|
12672
|
-
|
|
12779
|
+
const n_vertexDecimated = this.decimateLayerVertices(n_vertex, n_vert);
|
|
12780
|
+
if (n_vert !== n_vertexDecimated) {
|
|
12673
12781
|
throw new Error("ANNOT file has different number of vertices than mesh");
|
|
12674
12782
|
}
|
|
12675
12783
|
if (buffer.byteLength < 4 + 8 * n_vertex) {
|
|
@@ -13917,6 +14025,20 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
13917
14025
|
};
|
|
13918
14026
|
}
|
|
13919
14027
|
// readSTL()
|
|
14028
|
+
static decimateLayerVertices(nVertLayer, nVertMesh) {
|
|
14029
|
+
if (nVertLayer % nVertMesh === 0) {
|
|
14030
|
+
return nVertLayer;
|
|
14031
|
+
}
|
|
14032
|
+
const V0 = 12;
|
|
14033
|
+
const orderLayer = Math.round(Math.log((nVertLayer - 2) / (V0 - 2)) / Math.log(4));
|
|
14034
|
+
const orderMesh = Math.round(Math.log((nVertMesh - 2) / (V0 - 2)) / Math.log(4));
|
|
14035
|
+
const nVLayer = Math.pow(4, orderLayer) * (V0 - 2) + 2;
|
|
14036
|
+
const nVMesh = Math.pow(4, orderMesh) * (V0 - 2) + 2;
|
|
14037
|
+
if (nVLayer !== nVertLayer || nVMesh !== nVertMesh) {
|
|
14038
|
+
return nVertLayer;
|
|
14039
|
+
}
|
|
14040
|
+
return nVertMesh;
|
|
14041
|
+
}
|
|
13920
14042
|
// read NIfTI2 format with embedded CIfTI
|
|
13921
14043
|
// this variation very specific to connectome workbench
|
|
13922
14044
|
// https://brainder.org/2015/04/03/the-nifti-2-file-format/
|
|
@@ -14077,8 +14199,9 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14077
14199
|
);
|
|
14078
14200
|
return scalars2;
|
|
14079
14201
|
}
|
|
14202
|
+
nvert = this.decimateLayerVertices(nvert, n_vert);
|
|
14080
14203
|
if (nvert % n_vert !== 0) {
|
|
14081
|
-
throw new Error("Vertices in
|
|
14204
|
+
throw new Error("Vertices in layer (" + nvert + ") is not a multiple of number of vertices (" + n_vert + ")");
|
|
14082
14205
|
}
|
|
14083
14206
|
if (isLittleEndian) {
|
|
14084
14207
|
if (datatype === 16) {
|
|
@@ -14157,8 +14280,9 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14157
14280
|
const dim = reader.getUint16(40 + i * 2, isLittleEndian);
|
|
14158
14281
|
nvert *= Math.max(dim, 1);
|
|
14159
14282
|
}
|
|
14283
|
+
nvert = this.decimateLayerVertices(nvert, n_vert);
|
|
14160
14284
|
if (nvert % n_vert !== 0) {
|
|
14161
|
-
throw new Error("Vertices in
|
|
14285
|
+
throw new Error("Vertices in layer (" + nvert + ") is not a multiple of number of vertices (" + n_vert + ")");
|
|
14162
14286
|
}
|
|
14163
14287
|
if (isLittleEndian) {
|
|
14164
14288
|
if (datatype === 16) {
|
|
@@ -14214,10 +14338,11 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
14214
14338
|
if (version2 !== 1 || mtype < 0 || mtype > 4) {
|
|
14215
14339
|
log.warn("Not a valid MGH file");
|
|
14216
14340
|
}
|
|
14217
|
-
|
|
14341
|
+
let nvert = width * height * depth * nframes;
|
|
14218
14342
|
let scalars = [];
|
|
14343
|
+
nvert = this.decimateLayerVertices(nvert, n_vert);
|
|
14219
14344
|
if (nvert % n_vert !== 0) {
|
|
14220
|
-
log.warn("Vertices in
|
|
14345
|
+
log.warn("Vertices in layer (" + nvert + ") is not a multiple of number of vertices (" + n_vert + ")");
|
|
14221
14346
|
return scalars;
|
|
14222
14347
|
}
|
|
14223
14348
|
if (mtype === 3) {
|
|
@@ -15961,6 +16086,91 @@ var NVMesh2 = class _NVMesh {
|
|
|
15961
16086
|
}
|
|
15962
16087
|
this.updateMesh(gl);
|
|
15963
16088
|
}
|
|
16089
|
+
hierarchicalOrder() {
|
|
16090
|
+
const V0 = 12;
|
|
16091
|
+
const F0 = 20;
|
|
16092
|
+
const nF = this.tris.length / 3;
|
|
16093
|
+
const order = Math.log(nF / F0) / Math.log(4);
|
|
16094
|
+
if (nF !== Math.pow(4, order) * F0) {
|
|
16095
|
+
return NaN;
|
|
16096
|
+
}
|
|
16097
|
+
const nV = this.pts.length / 3;
|
|
16098
|
+
if (nV !== Math.pow(4, order) * (V0 - 2) + 2) {
|
|
16099
|
+
return NaN;
|
|
16100
|
+
}
|
|
16101
|
+
for (let i = 0; i < 15; i += 3) {
|
|
16102
|
+
if (this.tris[i] !== 0) {
|
|
16103
|
+
return NaN;
|
|
16104
|
+
}
|
|
16105
|
+
}
|
|
16106
|
+
for (let i = 15; i < 24; i += 3) {
|
|
16107
|
+
if (this.tris[i] !== 3) {
|
|
16108
|
+
return NaN;
|
|
16109
|
+
}
|
|
16110
|
+
}
|
|
16111
|
+
for (let i = 24; i < 30; i += 3) {
|
|
16112
|
+
if (this.tris[i] !== 4) {
|
|
16113
|
+
return NaN;
|
|
16114
|
+
}
|
|
16115
|
+
}
|
|
16116
|
+
return order;
|
|
16117
|
+
}
|
|
16118
|
+
decimateFaces(n, ntarget) {
|
|
16119
|
+
let fac = this.tris;
|
|
16120
|
+
const V0 = 12;
|
|
16121
|
+
const F0 = 20;
|
|
16122
|
+
for (let j = n - 1; j >= ntarget; j--) {
|
|
16123
|
+
const nVjprev = Math.pow(4, j + 1) * (V0 - 2) + 2;
|
|
16124
|
+
const nVj = Math.pow(4, j) * (V0 - 2) + 2;
|
|
16125
|
+
const nFjprev = fac.length / 3;
|
|
16126
|
+
const nFj = Math.pow(4, j) * F0;
|
|
16127
|
+
console.log(`order ${j + 1} -> ${j} vertices ${nVjprev} -> ${nVj} faces ${nFjprev} -> ${nFj}`);
|
|
16128
|
+
const remap = Array.from({ length: nVjprev }, (_, i) => i + 1);
|
|
16129
|
+
for (let i = 0; i < nFjprev; i++) {
|
|
16130
|
+
const v1 = fac[3 * i];
|
|
16131
|
+
const v2 = fac[3 * i + 1];
|
|
16132
|
+
const v3 = fac[3 * i + 2];
|
|
16133
|
+
remap[v1 - 1] = Math.min(remap[v1 - 1], v2, v3);
|
|
16134
|
+
}
|
|
16135
|
+
const facJ = new Uint32Array(nFj * 3);
|
|
16136
|
+
for (let i = 0; i < nFj; i++) {
|
|
16137
|
+
facJ[3 * i] = remap[fac[3 * i] - 1];
|
|
16138
|
+
facJ[3 * i + 1] = remap[fac[3 * i + 1] - 1];
|
|
16139
|
+
facJ[3 * i + 2] = remap[fac[3 * i + 2] - 1];
|
|
16140
|
+
}
|
|
16141
|
+
fac = facJ;
|
|
16142
|
+
}
|
|
16143
|
+
this.tris = new Uint32Array(fac);
|
|
16144
|
+
}
|
|
16145
|
+
// internal function simplifies FreeSurfer triangulated mesh and overlays
|
|
16146
|
+
decimateHierarchicalMesh(gl, order = 4) {
|
|
16147
|
+
const inputOrder = this.hierarchicalOrder();
|
|
16148
|
+
if (isNaN(inputOrder)) {
|
|
16149
|
+
log.warn("Unable to decimate mesh: it does not have a hierarchical structure");
|
|
16150
|
+
return false;
|
|
16151
|
+
}
|
|
16152
|
+
if (order >= inputOrder) {
|
|
16153
|
+
log.warn(`Unable to decimate mesh: input order (${inputOrder}) must be larger than downsampled order (${order})`);
|
|
16154
|
+
return false;
|
|
16155
|
+
}
|
|
16156
|
+
const inputVLength = this.pts.length / 3;
|
|
16157
|
+
const V0 = 12;
|
|
16158
|
+
const nV = Math.pow(4, order) * (V0 - 2) + 2;
|
|
16159
|
+
this.pts = new Float32Array(this.pts.slice(0, nV * 3));
|
|
16160
|
+
this.decimateFaces(inputOrder, order);
|
|
16161
|
+
if (this.layers && this.layers.length > 0) {
|
|
16162
|
+
for (let i = 0; i < this.layers.length; i++) {
|
|
16163
|
+
const layer = this.layers[i];
|
|
16164
|
+
if (layer.values instanceof Float32Array || layer.values.length !== inputVLength) {
|
|
16165
|
+
layer.values = new Float32Array(layer.values.slice(0, nV));
|
|
16166
|
+
} else {
|
|
16167
|
+
log.warn(`decimation logic needs to be updated`);
|
|
16168
|
+
}
|
|
16169
|
+
}
|
|
16170
|
+
}
|
|
16171
|
+
this.updateMesh(gl);
|
|
16172
|
+
return true;
|
|
16173
|
+
}
|
|
15964
16174
|
// adjust attributes of a mesh layer. invoked by niivue.setMeshLayerProperty()
|
|
15965
16175
|
// TODO this method is a bit too generic
|
|
15966
16176
|
setLayerProperty(id, key, val, gl) {
|
|
@@ -18016,7 +18226,7 @@ import { vec3 as vec38, vec4 as vec46 } from "gl-matrix";
|
|
|
18016
18226
|
import * as nifti from "nifti-reader-js";
|
|
18017
18227
|
import daikon from "daikon";
|
|
18018
18228
|
import { mat3, mat4 as mat44, vec3 as vec37, vec4 as vec45 } from "gl-matrix";
|
|
18019
|
-
import { Decompress, decompressSync as decompressSync3, gzipSync } from "fflate/browser";
|
|
18229
|
+
import { Decompress, decompressSync as decompressSync3, gzipSync as gzipSync2 } from "fflate/browser";
|
|
18020
18230
|
import { v4 as uuidv42 } from "@lukeed/uuid";
|
|
18021
18231
|
|
|
18022
18232
|
// src/nvimage/utils.ts
|
|
@@ -20875,7 +21085,7 @@ var NVImage = class _NVImage {
|
|
|
20875
21085
|
let saveData = null;
|
|
20876
21086
|
const compress2 = fnm.endsWith(".gz");
|
|
20877
21087
|
if (compress2) {
|
|
20878
|
-
saveData =
|
|
21088
|
+
saveData = gzipSync2(odata, {
|
|
20879
21089
|
// GZIP-specific: the filename to use when decompressed
|
|
20880
21090
|
filename: fnm,
|
|
20881
21091
|
// GZIP-specific: the modification time. Can be a Date, date string,
|
|
@@ -21338,7 +21548,7 @@ var NVImage = class _NVImage {
|
|
|
21338
21548
|
* read a 3D slab of voxels from a volume
|
|
21339
21549
|
* @param voxStart - first row, column and slice (RAS order) for selection
|
|
21340
21550
|
* @param voxEnd - final row, column and slice (RAS order) for selection
|
|
21341
|
-
* @param dataType - array data type. Options: 'same' (default), 'uint8', 'float32'
|
|
21551
|
+
* @param dataType - array data type. Options: 'same' (default), 'uint8', 'float32', 'scaled', 'normalized', 'windowed'
|
|
21342
21552
|
* @returns the an array where ret[0] is the voxel values and ret[1] is dimension of selection
|
|
21343
21553
|
* @see {@link https://niivue.github.io/niivue/features/slab_selection.html | live demo usage}
|
|
21344
21554
|
*/
|
|
@@ -21362,7 +21572,7 @@ var NVImage = class _NVImage {
|
|
|
21362
21572
|
let dt = this.hdr.datatypeCode;
|
|
21363
21573
|
if (dataType === "uint8") {
|
|
21364
21574
|
dt = 2 /* DT_UINT8 */;
|
|
21365
|
-
} else if (dataType === "float32") {
|
|
21575
|
+
} else if (dataType === "float32" || dataType === "scaled" || dataType === "normalized" || dataType === "windowed") {
|
|
21366
21576
|
dt = 16 /* DT_FLOAT32 */;
|
|
21367
21577
|
}
|
|
21368
21578
|
if (dt === 2 /* DT_UINT8 */) {
|
|
@@ -21392,6 +21602,24 @@ var NVImage = class _NVImage {
|
|
|
21392
21602
|
}
|
|
21393
21603
|
}
|
|
21394
21604
|
}
|
|
21605
|
+
if (dataType === "scaled" || dataType === "normalized" || dataType === "windowed") {
|
|
21606
|
+
for (let i2 = 0; i2 < img.length; i2++) {
|
|
21607
|
+
img[i2] = img[i2] * this.hdr.scl_slope + this.hdr.scl_inter;
|
|
21608
|
+
}
|
|
21609
|
+
}
|
|
21610
|
+
if (dataType === "normalized" || dataType === "windowed") {
|
|
21611
|
+
let mn = this.cal_min;
|
|
21612
|
+
let mx = this.cal_max;
|
|
21613
|
+
if (dataType === "normalized") {
|
|
21614
|
+
mn = this.global_min;
|
|
21615
|
+
mx = this.global_max;
|
|
21616
|
+
}
|
|
21617
|
+
const scale = 1 / (mx - mn);
|
|
21618
|
+
for (let i2 = 0; i2 < img.length; i2++) {
|
|
21619
|
+
img[i2] = (img[i2] - mn) * scale;
|
|
21620
|
+
img[i2] = Math.max(Math.min(img[i2], 1), 0);
|
|
21621
|
+
}
|
|
21622
|
+
}
|
|
21395
21623
|
return [img, slabDims];
|
|
21396
21624
|
}
|
|
21397
21625
|
// getVolumeData()
|
|
@@ -21929,6 +22157,12 @@ var SLICE_TYPE = /* @__PURE__ */ ((SLICE_TYPE2) => {
|
|
|
21929
22157
|
SLICE_TYPE2[SLICE_TYPE2["RENDER"] = 4] = "RENDER";
|
|
21930
22158
|
return SLICE_TYPE2;
|
|
21931
22159
|
})(SLICE_TYPE || {});
|
|
22160
|
+
var SHOW_RENDER = /* @__PURE__ */ ((SHOW_RENDER2) => {
|
|
22161
|
+
SHOW_RENDER2[SHOW_RENDER2["NEVER"] = 0] = "NEVER";
|
|
22162
|
+
SHOW_RENDER2[SHOW_RENDER2["ALWAYS"] = 1] = "ALWAYS";
|
|
22163
|
+
SHOW_RENDER2[SHOW_RENDER2["AUTO"] = 2] = "AUTO";
|
|
22164
|
+
return SHOW_RENDER2;
|
|
22165
|
+
})(SHOW_RENDER || {});
|
|
21932
22166
|
var MULTIPLANAR_TYPE = /* @__PURE__ */ ((MULTIPLANAR_TYPE2) => {
|
|
21933
22167
|
MULTIPLANAR_TYPE2[MULTIPLANAR_TYPE2["AUTO"] = 0] = "AUTO";
|
|
21934
22168
|
MULTIPLANAR_TYPE2[MULTIPLANAR_TYPE2["COLUMN"] = 1] = "COLUMN";
|
|
@@ -21975,7 +22209,10 @@ var DEFAULT_OPTIONS = {
|
|
|
21975
22209
|
isColorbar: false,
|
|
21976
22210
|
isOrientCube: false,
|
|
21977
22211
|
multiplanarPadPixels: 0,
|
|
22212
|
+
// @deprecated
|
|
21978
22213
|
multiplanarForceRender: false,
|
|
22214
|
+
multiplanarShowRender: 2 /* AUTO */,
|
|
22215
|
+
// auto is the same behaviour as multiplanarForceRender: false
|
|
21979
22216
|
isRadiologicalConvention: false,
|
|
21980
22217
|
meshThicknessOn2D: Infinity,
|
|
21981
22218
|
dragMode: 1 /* contrast */,
|
|
@@ -24997,6 +25234,39 @@ var Niivue = class _Niivue {
|
|
|
24997
25234
|
this.addVolume(volume);
|
|
24998
25235
|
return volume;
|
|
24999
25236
|
}
|
|
25237
|
+
async addVolumesFromUrl(imageOptionsArray) {
|
|
25238
|
+
const promises = imageOptionsArray.map(async (imageItem) => {
|
|
25239
|
+
const imageOptions = {
|
|
25240
|
+
url: imageItem.url,
|
|
25241
|
+
headers: imageItem.headers,
|
|
25242
|
+
name: imageItem.name,
|
|
25243
|
+
colormap: imageItem.colormap ? imageItem.colormap : imageItem.colorMap,
|
|
25244
|
+
colormapNegative: imageItem.colormapNegative ? imageItem.colormapNegative : imageItem.colorMapNegative,
|
|
25245
|
+
opacity: imageItem.opacity,
|
|
25246
|
+
urlImgData: imageItem.urlImgData,
|
|
25247
|
+
cal_min: imageItem.cal_min,
|
|
25248
|
+
cal_max: imageItem.cal_max,
|
|
25249
|
+
trustCalMinMax: this.opts.trustCalMinMax,
|
|
25250
|
+
isManifest: imageItem.isManifest,
|
|
25251
|
+
frame4D: imageItem.frame4D,
|
|
25252
|
+
limitFrames4D: imageItem.limitFrames4D || this.opts.limitFrames4D,
|
|
25253
|
+
colorbarVisible: imageItem.colorbarVisible
|
|
25254
|
+
};
|
|
25255
|
+
const volume = await NVImage.loadFromUrl(imageOptions);
|
|
25256
|
+
this.document.addImageOptions(volume, imageOptions);
|
|
25257
|
+
volume.onColormapChange = this.onColormapChange;
|
|
25258
|
+
this.mediaUrlMap.set(volume, imageOptions.url);
|
|
25259
|
+
if (this.onVolumeAddedFromUrl) {
|
|
25260
|
+
this.onVolumeAddedFromUrl(imageOptions, volume);
|
|
25261
|
+
}
|
|
25262
|
+
return volume;
|
|
25263
|
+
});
|
|
25264
|
+
const volumes = await Promise.all(promises);
|
|
25265
|
+
for (let i = 0; i < volumes.length; i++) {
|
|
25266
|
+
this.addVolume(volumes[i]);
|
|
25267
|
+
}
|
|
25268
|
+
return volumes;
|
|
25269
|
+
}
|
|
25000
25270
|
/**
|
|
25001
25271
|
* Find media by url
|
|
25002
25272
|
*/
|
|
@@ -25924,6 +26194,24 @@ var Niivue = class _Niivue {
|
|
|
25924
26194
|
}
|
|
25925
26195
|
return this.meshes[idx].indexNearestXYZmm(Xmm, Ymm, Zmm);
|
|
25926
26196
|
}
|
|
26197
|
+
/**
|
|
26198
|
+
* reduce complexity of FreeSurfer mesh
|
|
26199
|
+
* @param mesh - identity of mesh to change
|
|
26200
|
+
* @param order - decimation order 0..6
|
|
26201
|
+
* @example niivue.decimateHierarchicalMesh(niivue.meshes[0].id, 4)
|
|
26202
|
+
* @returns boolean false if mesh is not hierarchical or of lower order
|
|
26203
|
+
* @see {@link https://niivue.github.io/niivue/features/meshes.html | live demo usage}
|
|
26204
|
+
*/
|
|
26205
|
+
decimateHierarchicalMesh(mesh, order = 3) {
|
|
26206
|
+
const idx = this.getMeshIndexByID(mesh);
|
|
26207
|
+
if (idx < 0) {
|
|
26208
|
+
log.warn("reverseFaces() id not loaded", mesh);
|
|
26209
|
+
return;
|
|
26210
|
+
}
|
|
26211
|
+
const ret = this.meshes[idx].decimateHierarchicalMesh(this.gl, order);
|
|
26212
|
+
this.updateGLVolume();
|
|
26213
|
+
return ret;
|
|
26214
|
+
}
|
|
25927
26215
|
/**
|
|
25928
26216
|
* reverse triangle winding of mesh (swap front and back faces)
|
|
25929
26217
|
* @param id - identity of mesh to change
|
|
@@ -26422,6 +26710,9 @@ var Niivue = class _Niivue {
|
|
|
26422
26710
|
this.renderShader.use(this.gl);
|
|
26423
26711
|
this.gl.uniform3fv(this.renderShader.uniforms.clipLo, this.opts.clipVolumeLow);
|
|
26424
26712
|
this.gl.uniform3fv(this.renderShader.uniforms.clipHi, this.opts.clipVolumeHigh);
|
|
26713
|
+
this.pickingImageShader.use(this.gl);
|
|
26714
|
+
this.gl.uniform3fv(this.pickingImageShader.uniforms.clipLo, this.opts.clipVolumeLow);
|
|
26715
|
+
this.gl.uniform3fv(this.pickingImageShader.uniforms.clipHi, this.opts.clipVolumeHigh);
|
|
26425
26716
|
this.drawScene();
|
|
26426
26717
|
}
|
|
26427
26718
|
/**
|
|
@@ -26775,28 +27066,27 @@ var Niivue = class _Niivue {
|
|
|
26775
27066
|
this.volumes = [];
|
|
26776
27067
|
this.gl.clearColor(0, 0, 0, 1);
|
|
26777
27068
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
26778
|
-
|
|
26779
|
-
|
|
26780
|
-
|
|
26781
|
-
}
|
|
26782
|
-
const imageOptions = {
|
|
26783
|
-
url: volumeList[i].url,
|
|
26784
|
-
headers: volumeList[i].headers,
|
|
26785
|
-
name: volumeList[i].name,
|
|
26786
|
-
colormap: volumeList[i].colormap,
|
|
26787
|
-
colormapNegative: volumeList[i].colormapNegative,
|
|
26788
|
-
opacity: volumeList[i].opacity,
|
|
26789
|
-
urlImgData: volumeList[i].urlImgData,
|
|
26790
|
-
cal_min: volumeList[i].cal_min,
|
|
26791
|
-
cal_max: volumeList[i].cal_max,
|
|
26792
|
-
trustCalMinMax: this.opts.trustCalMinMax,
|
|
26793
|
-
isManifest: volumeList[i].isManifest,
|
|
26794
|
-
frame4D: volumeList[i].frame4D,
|
|
26795
|
-
limitFrames4D: volumeList[i].limitFrames4D || this.opts.limitFrames4D,
|
|
26796
|
-
colorbarVisible: volumeList[i].colorbarVisible
|
|
26797
|
-
};
|
|
26798
|
-
await this.addVolumeFromUrl(imageOptions);
|
|
27069
|
+
if (volumeList.length > 1) {
|
|
27070
|
+
await this.addVolumesFromUrl(volumeList);
|
|
27071
|
+
return this;
|
|
26799
27072
|
}
|
|
27073
|
+
const imageOptions = {
|
|
27074
|
+
url: volumeList[0].url,
|
|
27075
|
+
headers: volumeList[0].headers,
|
|
27076
|
+
name: volumeList[0].name,
|
|
27077
|
+
colormap: volumeList[0].colormap ? volumeList[0].colormap : volumeList[0].colorMap,
|
|
27078
|
+
colormapNegative: volumeList[0].colormapNegative ? volumeList[0].colormapNegative : volumeList[0].colorMapNegative,
|
|
27079
|
+
opacity: volumeList[0].opacity,
|
|
27080
|
+
urlImgData: volumeList[0].urlImgData,
|
|
27081
|
+
cal_min: volumeList[0].cal_min,
|
|
27082
|
+
cal_max: volumeList[0].cal_max,
|
|
27083
|
+
trustCalMinMax: this.opts.trustCalMinMax,
|
|
27084
|
+
isManifest: volumeList[0].isManifest,
|
|
27085
|
+
frame4D: volumeList[0].frame4D,
|
|
27086
|
+
limitFrames4D: volumeList[0].limitFrames4D || this.opts.limitFrames4D,
|
|
27087
|
+
colorbarVisible: volumeList[0].colorbarVisible
|
|
27088
|
+
};
|
|
27089
|
+
await this.addVolumeFromUrl(imageOptions);
|
|
26800
27090
|
return this;
|
|
26801
27091
|
}
|
|
26802
27092
|
/**
|
|
@@ -26820,6 +27110,32 @@ var Niivue = class _Niivue {
|
|
|
26820
27110
|
this.addMesh(mesh);
|
|
26821
27111
|
return mesh;
|
|
26822
27112
|
}
|
|
27113
|
+
/**
|
|
27114
|
+
* Add mesh and notify subscribers
|
|
27115
|
+
* @see {@link https://niivue.github.io/niivue/features/multiuser.meshes.html | live demo usage}
|
|
27116
|
+
*/
|
|
27117
|
+
async addMeshesFromUrl(meshOptions) {
|
|
27118
|
+
const promises = meshOptions.map(async (meshItem) => {
|
|
27119
|
+
const ext = this.getFileExt(meshItem.url);
|
|
27120
|
+
if (ext === "JCON" || ext === "JSON") {
|
|
27121
|
+
const response = await fetch(meshItem.url, {});
|
|
27122
|
+
const json = await response.json();
|
|
27123
|
+
const mesh2 = this.loadConnectomeAsMesh(json);
|
|
27124
|
+
this.mediaUrlMap.set(mesh2, meshItem.url);
|
|
27125
|
+
this.onMeshAddedFromUrl(meshItem, mesh2);
|
|
27126
|
+
return mesh2;
|
|
27127
|
+
}
|
|
27128
|
+
const mesh = await NVMesh2.loadFromUrl({ ...meshItem, gl: this.gl });
|
|
27129
|
+
this.mediaUrlMap.set(mesh, meshItem.url);
|
|
27130
|
+
this.onMeshAddedFromUrl(meshItem, mesh);
|
|
27131
|
+
return mesh;
|
|
27132
|
+
});
|
|
27133
|
+
const meshes = await Promise.all(promises);
|
|
27134
|
+
for (let i = 0; i < meshes.length; i++) {
|
|
27135
|
+
this.addMesh(meshes[i]);
|
|
27136
|
+
}
|
|
27137
|
+
return meshes;
|
|
27138
|
+
}
|
|
26823
27139
|
/**
|
|
26824
27140
|
* load an array of meshes
|
|
26825
27141
|
* @param meshList - the array of objects to load. each object must have a resolvable "url" property at a minimum
|
|
@@ -26841,9 +27157,13 @@ var Niivue = class _Niivue {
|
|
|
26841
27157
|
this.meshes = [];
|
|
26842
27158
|
this.gl.clearColor(0, 0, 0, 1);
|
|
26843
27159
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
26844
|
-
|
|
26845
|
-
await this.
|
|
27160
|
+
if (meshList.length > 1) {
|
|
27161
|
+
await this.addMeshesFromUrl(meshList);
|
|
27162
|
+
this.updateGLVolume();
|
|
27163
|
+
this.drawScene();
|
|
27164
|
+
return this;
|
|
26846
27165
|
}
|
|
27166
|
+
await this.addMeshFromUrl(meshList[0]);
|
|
26847
27167
|
this.updateGLVolume();
|
|
26848
27168
|
this.drawScene();
|
|
26849
27169
|
return this;
|
|
@@ -28694,6 +29014,8 @@ var Niivue = class _Niivue {
|
|
|
28694
29014
|
this.pickingImageShader.use(this.gl);
|
|
28695
29015
|
this.gl.uniform1f(this.pickingImageShader.uniforms.overlays, this.overlays.length);
|
|
28696
29016
|
this.gl.uniform3fv(this.pickingImageShader.uniforms.texVox, vox);
|
|
29017
|
+
this.gl.uniform3fv(this.pickingImageShader.uniforms.clipLo, this.opts.clipVolumeLow);
|
|
29018
|
+
this.gl.uniform3fv(this.pickingImageShader.uniforms.clipHi, this.opts.clipVolumeHigh);
|
|
28697
29019
|
let shader = this.sliceMMShader;
|
|
28698
29020
|
if (this.opts.isV1SliceShader) {
|
|
28699
29021
|
shader = this.sliceV1Shader;
|
|
@@ -30104,6 +30426,9 @@ var Niivue = class _Niivue {
|
|
|
30104
30426
|
width = bulletMargin + longestTextLength;
|
|
30105
30427
|
width += horizontalMargin * 2;
|
|
30106
30428
|
}
|
|
30429
|
+
if (width >= this.gl.canvas.width) {
|
|
30430
|
+
return 0;
|
|
30431
|
+
}
|
|
30107
30432
|
return width;
|
|
30108
30433
|
}
|
|
30109
30434
|
getLegendPanelHeight() {
|
|
@@ -32390,6 +32715,20 @@ var Niivue = class _Niivue {
|
|
|
32390
32715
|
} else if (this.opts.sliceType === 2 /* SAGITTAL */) {
|
|
32391
32716
|
this.draw2D([0, 0, 0, 0], 2);
|
|
32392
32717
|
} else {
|
|
32718
|
+
let isShowRender = false;
|
|
32719
|
+
if (this.opts.multiplanarForceRender) {
|
|
32720
|
+
isShowRender = true;
|
|
32721
|
+
if (this.opts.multiplanarForceRender) {
|
|
32722
|
+
this.opts.multiplanarShowRender = 1 /* ALWAYS */;
|
|
32723
|
+
} else {
|
|
32724
|
+
this.opts.multiplanarShowRender = 2 /* AUTO */;
|
|
32725
|
+
}
|
|
32726
|
+
delete this.opts.multiplanarForceRender;
|
|
32727
|
+
} else {
|
|
32728
|
+
if (this.opts.multiplanarShowRender === 1 /* ALWAYS */) {
|
|
32729
|
+
isShowRender = true;
|
|
32730
|
+
}
|
|
32731
|
+
}
|
|
32393
32732
|
const isDrawPenDown = isFinite(this.drawPenLocation[0]) && this.opts.drawingEnabled;
|
|
32394
32733
|
const { volScale } = this.sliceScale();
|
|
32395
32734
|
if (typeof this.opts.multiplanarPadPixels !== "number") {
|
|
@@ -32431,7 +32770,7 @@ var Niivue = class _Niivue {
|
|
|
32431
32770
|
}
|
|
32432
32771
|
if (isDrawColumn) {
|
|
32433
32772
|
let ltwh = ltwh1x3;
|
|
32434
|
-
if (this.opts.
|
|
32773
|
+
if (isShowRender || this.opts.multiplanarShowRender === 2 /* AUTO */ && ltwh1x4[4] >= ltwh1x3[4]) {
|
|
32435
32774
|
ltwh = ltwh1x4;
|
|
32436
32775
|
} else {
|
|
32437
32776
|
isDraw3D = false;
|
|
@@ -32448,7 +32787,7 @@ var Niivue = class _Niivue {
|
|
|
32448
32787
|
}
|
|
32449
32788
|
} else if (isDrawRow) {
|
|
32450
32789
|
let ltwh = ltwh3x1;
|
|
32451
|
-
if (this.opts.
|
|
32790
|
+
if (isShowRender || this.opts.multiplanarShowRender === 2 /* AUTO */ && ltwh4x1[4] >= ltwh3x1[4]) {
|
|
32452
32791
|
ltwh = ltwh4x1;
|
|
32453
32792
|
} else {
|
|
32454
32793
|
isDraw3D = false;
|
|
@@ -32463,6 +32802,12 @@ var Niivue = class _Niivue {
|
|
|
32463
32802
|
this.draw3D([ltwh[0] + sX + sX + sY + pad * 3, ltwh[1], ltwh[3], ltwh[3]]);
|
|
32464
32803
|
}
|
|
32465
32804
|
} else if (isDrawGrid) {
|
|
32805
|
+
if (!isShowRender) {
|
|
32806
|
+
isDraw3D = false;
|
|
32807
|
+
}
|
|
32808
|
+
if (this.opts.multiplanarShowRender === 2 /* AUTO */) {
|
|
32809
|
+
isDraw3D = true;
|
|
32810
|
+
}
|
|
32466
32811
|
const ltwh = ltwh2x2;
|
|
32467
32812
|
const sX = volScale[0] * ltwh[4];
|
|
32468
32813
|
const sY = volScale[1] * ltwh[4];
|
|
@@ -32585,8 +32930,10 @@ export {
|
|
|
32585
32930
|
NVMeshFromUrlOptions,
|
|
32586
32931
|
NVMeshLayerDefaults,
|
|
32587
32932
|
NVMeshLoaders,
|
|
32933
|
+
NVMeshUtilities,
|
|
32588
32934
|
NVUtilities,
|
|
32589
32935
|
Niivue,
|
|
32936
|
+
SHOW_RENDER,
|
|
32590
32937
|
SLICE_TYPE,
|
|
32591
32938
|
cmapper,
|
|
32592
32939
|
ColorTables as colortables
|