@fideus-labs/fidnii 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BufferManager.d.ts.map +1 -1
- package/dist/BufferManager.js +2 -5
- package/dist/BufferManager.js.map +1 -1
- package/dist/ClipPlanes.d.ts.map +1 -1
- package/dist/ClipPlanes.js +11 -15
- package/dist/ClipPlanes.js.map +1 -1
- package/dist/OMEZarrNVImage.d.ts +33 -3
- package/dist/OMEZarrNVImage.d.ts.map +1 -1
- package/dist/OMEZarrNVImage.js +129 -50
- package/dist/OMEZarrNVImage.js.map +1 -1
- package/dist/RegionCoalescer.d.ts.map +1 -1
- package/dist/RegionCoalescer.js +1 -1
- package/dist/RegionCoalescer.js.map +1 -1
- package/dist/ResolutionSelector.d.ts.map +1 -1
- package/dist/ResolutionSelector.js +2 -4
- package/dist/ResolutionSelector.js.map +1 -1
- package/dist/ViewportBounds.d.ts.map +1 -1
- package/dist/ViewportBounds.js +7 -5
- package/dist/ViewportBounds.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -16
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/affine.d.ts +1 -1
- package/dist/utils/affine.d.ts.map +1 -1
- package/dist/utils/affine.js.map +1 -1
- package/dist/utils/coordinates.d.ts +1 -1
- package/dist/utils/coordinates.d.ts.map +1 -1
- package/dist/utils/coordinates.js.map +1 -1
- package/package.json +1 -1
- package/src/BufferManager.ts +45 -45
- package/src/ClipPlanes.ts +131 -130
- package/src/OMEZarrNVImage.ts +685 -606
- package/src/RegionCoalescer.ts +48 -47
- package/src/ResolutionSelector.ts +66 -67
- package/src/ViewportBounds.ts +120 -118
- package/src/events.ts +36 -35
- package/src/index.ts +59 -69
- package/src/types.ts +95 -94
- package/src/utils/affine.ts +65 -65
- package/src/utils/coordinates.ts +70 -70
package/src/utils/affine.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import type { NgffImage } from "@fideus-labs/ngff-zarr"
|
|
5
|
+
import { mat4 } from "gl-matrix"
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Create a 4x4 affine transformation matrix from OME-Zarr scale and translation.
|
|
@@ -27,50 +27,50 @@ export function createAffineFromOMEZarr(
|
|
|
27
27
|
scale: Record<string, number>,
|
|
28
28
|
translation: Record<string, number>,
|
|
29
29
|
): mat4 {
|
|
30
|
-
const affine = mat4.create()
|
|
30
|
+
const affine = mat4.create()
|
|
31
31
|
|
|
32
32
|
// NIfTI expects the matrix in a specific orientation
|
|
33
33
|
// The affine maps from (i, j, k) voxel indices to (x, y, z) world coordinates
|
|
34
34
|
// For OME-Zarr with [z, y, x] ordering, we need to handle the axis mapping
|
|
35
35
|
|
|
36
36
|
// Extract scale and translation for each axis
|
|
37
|
-
const sx = scale.x ?? scale.X ?? 1
|
|
38
|
-
const sy = scale.y ?? scale.Y ?? 1
|
|
39
|
-
const sz = scale.z ?? scale.Z ?? 1
|
|
37
|
+
const sx = scale.x ?? scale.X ?? 1
|
|
38
|
+
const sy = scale.y ?? scale.Y ?? 1
|
|
39
|
+
const sz = scale.z ?? scale.Z ?? 1
|
|
40
40
|
|
|
41
|
-
const tx = translation.x ?? translation.X ?? 0
|
|
42
|
-
const ty = translation.y ?? translation.Y ?? 0
|
|
43
|
-
const tz = translation.z ?? translation.Z ?? 0
|
|
41
|
+
const tx = translation.x ?? translation.X ?? 0
|
|
42
|
+
const ty = translation.y ?? translation.Y ?? 0
|
|
43
|
+
const tz = translation.z ?? translation.Z ?? 0
|
|
44
44
|
|
|
45
45
|
// Build affine matrix
|
|
46
46
|
// NIfTI convention: first index (i) -> x, second (j) -> y, third (k) -> z
|
|
47
47
|
// OME-Zarr stores data as [z, y, x], so we need to account for this
|
|
48
48
|
|
|
49
49
|
// Column 0: x direction (from third array index in [z,y,x])
|
|
50
|
-
affine[0] = sx
|
|
51
|
-
affine[1] = 0
|
|
52
|
-
affine[2] = 0
|
|
53
|
-
affine[3] = 0
|
|
50
|
+
affine[0] = sx
|
|
51
|
+
affine[1] = 0
|
|
52
|
+
affine[2] = 0
|
|
53
|
+
affine[3] = 0
|
|
54
54
|
|
|
55
55
|
// Column 1: y direction (from second array index in [z,y,x])
|
|
56
|
-
affine[4] = 0
|
|
57
|
-
affine[5] = sy
|
|
58
|
-
affine[6] = 0
|
|
59
|
-
affine[7] = 0
|
|
56
|
+
affine[4] = 0
|
|
57
|
+
affine[5] = sy
|
|
58
|
+
affine[6] = 0
|
|
59
|
+
affine[7] = 0
|
|
60
60
|
|
|
61
61
|
// Column 2: z direction (from first array index in [z,y,x])
|
|
62
|
-
affine[8] = 0
|
|
63
|
-
affine[9] = 0
|
|
64
|
-
affine[10] = sz
|
|
65
|
-
affine[11] = 0
|
|
62
|
+
affine[8] = 0
|
|
63
|
+
affine[9] = 0
|
|
64
|
+
affine[10] = sz
|
|
65
|
+
affine[11] = 0
|
|
66
66
|
|
|
67
67
|
// Column 3: translation
|
|
68
|
-
affine[12] = tx
|
|
69
|
-
affine[13] = ty
|
|
70
|
-
affine[14] = tz
|
|
71
|
-
affine[15] = 1
|
|
68
|
+
affine[12] = tx
|
|
69
|
+
affine[13] = ty
|
|
70
|
+
affine[14] = tz
|
|
71
|
+
affine[15] = 1
|
|
72
72
|
|
|
73
|
-
return affine
|
|
73
|
+
return affine
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/**
|
|
@@ -80,7 +80,7 @@ export function createAffineFromOMEZarr(
|
|
|
80
80
|
* @returns 4x4 affine matrix
|
|
81
81
|
*/
|
|
82
82
|
export function createAffineFromNgffImage(ngffImage: NgffImage): mat4 {
|
|
83
|
-
return createAffineFromOMEZarr(ngffImage.scale, ngffImage.translation)
|
|
83
|
+
return createAffineFromOMEZarr(ngffImage.scale, ngffImage.translation)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
@@ -91,9 +91,9 @@ export function createAffineFromNgffImage(ngffImage: NgffImage): mat4 {
|
|
|
91
91
|
* @returns Object with srow_x, srow_y, srow_z arrays
|
|
92
92
|
*/
|
|
93
93
|
export function affineToNiftiSrows(affine: mat4): {
|
|
94
|
-
srow_x: [number, number, number, number]
|
|
95
|
-
srow_y: [number, number, number, number]
|
|
96
|
-
srow_z: [number, number, number, number]
|
|
94
|
+
srow_x: [number, number, number, number]
|
|
95
|
+
srow_y: [number, number, number, number]
|
|
96
|
+
srow_z: [number, number, number, number]
|
|
97
97
|
} {
|
|
98
98
|
// gl-matrix uses column-major order
|
|
99
99
|
// Row 0 (srow_x): elements 0, 4, 8, 12
|
|
@@ -103,7 +103,7 @@ export function affineToNiftiSrows(affine: mat4): {
|
|
|
103
103
|
srow_x: [affine[0], affine[4], affine[8], affine[12]],
|
|
104
104
|
srow_y: [affine[1], affine[5], affine[9], affine[13]],
|
|
105
105
|
srow_z: [affine[2], affine[6], affine[10], affine[14]],
|
|
106
|
-
}
|
|
106
|
+
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
/**
|
|
@@ -114,11 +114,11 @@ export function affineToNiftiSrows(affine: mat4): {
|
|
|
114
114
|
*/
|
|
115
115
|
export function getPixelDimensions(affine: mat4): [number, number, number] {
|
|
116
116
|
// The pixel dimensions are the lengths of the column vectors
|
|
117
|
-
const dx = Math.sqrt(affine[0] ** 2 + affine[1] ** 2 + affine[2] ** 2)
|
|
118
|
-
const dy = Math.sqrt(affine[4] ** 2 + affine[5] ** 2 + affine[6] ** 2)
|
|
119
|
-
const dz = Math.sqrt(affine[8] ** 2 + affine[9] ** 2 + affine[10] ** 2)
|
|
117
|
+
const dx = Math.sqrt(affine[0] ** 2 + affine[1] ** 2 + affine[2] ** 2)
|
|
118
|
+
const dy = Math.sqrt(affine[4] ** 2 + affine[5] ** 2 + affine[6] ** 2)
|
|
119
|
+
const dz = Math.sqrt(affine[8] ** 2 + affine[9] ** 2 + affine[10] ** 2)
|
|
120
120
|
|
|
121
|
-
return [dx, dy, dz]
|
|
121
|
+
return [dx, dy, dz]
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/**
|
|
@@ -137,33 +137,33 @@ export function updateAffineForRegion(
|
|
|
137
137
|
regionStart: [number, number, number],
|
|
138
138
|
scaleFactor: [number, number, number],
|
|
139
139
|
): mat4 {
|
|
140
|
-
const result = mat4.clone(originalAffine)
|
|
140
|
+
const result = mat4.clone(originalAffine)
|
|
141
141
|
|
|
142
142
|
// Scale the voxel dimensions
|
|
143
143
|
// Column 0 (x direction)
|
|
144
|
-
result[0] *= scaleFactor[2]
|
|
145
|
-
result[1] *= scaleFactor[2]
|
|
146
|
-
result[2] *= scaleFactor[2]
|
|
144
|
+
result[0] *= scaleFactor[2] // x scale factor
|
|
145
|
+
result[1] *= scaleFactor[2]
|
|
146
|
+
result[2] *= scaleFactor[2]
|
|
147
147
|
|
|
148
148
|
// Column 1 (y direction)
|
|
149
|
-
result[4] *= scaleFactor[1]
|
|
150
|
-
result[5] *= scaleFactor[1]
|
|
151
|
-
result[6] *= scaleFactor[1]
|
|
149
|
+
result[4] *= scaleFactor[1] // y scale factor
|
|
150
|
+
result[5] *= scaleFactor[1]
|
|
151
|
+
result[6] *= scaleFactor[1]
|
|
152
152
|
|
|
153
153
|
// Column 2 (z direction)
|
|
154
|
-
result[8] *= scaleFactor[0]
|
|
155
|
-
result[9] *= scaleFactor[0]
|
|
156
|
-
result[10] *= scaleFactor[0]
|
|
154
|
+
result[8] *= scaleFactor[0] // z scale factor
|
|
155
|
+
result[9] *= scaleFactor[0]
|
|
156
|
+
result[10] *= scaleFactor[0]
|
|
157
157
|
|
|
158
158
|
// Update translation for region offset
|
|
159
159
|
// New origin = original_origin + regionStart * original_voxel_size
|
|
160
|
-
const originalPixelDims = getPixelDimensions(originalAffine)
|
|
160
|
+
const originalPixelDims = getPixelDimensions(originalAffine)
|
|
161
161
|
|
|
162
|
-
result[12] += regionStart[2] * originalPixelDims[0]
|
|
163
|
-
result[13] += regionStart[1] * originalPixelDims[1]
|
|
164
|
-
result[14] += regionStart[0] * originalPixelDims[2]
|
|
162
|
+
result[12] += regionStart[2] * originalPixelDims[0] // x offset
|
|
163
|
+
result[13] += regionStart[1] * originalPixelDims[1] // y offset
|
|
164
|
+
result[14] += regionStart[0] * originalPixelDims[2] // z offset
|
|
165
165
|
|
|
166
|
-
return result
|
|
166
|
+
return result
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/**
|
|
@@ -178,7 +178,7 @@ export function calculateWorldBounds(
|
|
|
178
178
|
dimensions: [number, number, number],
|
|
179
179
|
): { min: [number, number, number]; max: [number, number, number] } {
|
|
180
180
|
// Calculate all 8 corners of the volume in world space
|
|
181
|
-
const [dimZ, dimY, dimX] = dimensions
|
|
181
|
+
const [dimZ, dimY, dimX] = dimensions
|
|
182
182
|
const corners = [
|
|
183
183
|
[0, 0, 0],
|
|
184
184
|
[dimX, 0, 0],
|
|
@@ -188,31 +188,31 @@ export function calculateWorldBounds(
|
|
|
188
188
|
[dimX, 0, dimZ],
|
|
189
189
|
[0, dimY, dimZ],
|
|
190
190
|
[dimX, dimY, dimZ],
|
|
191
|
-
]
|
|
191
|
+
]
|
|
192
192
|
|
|
193
193
|
let minX = Infinity,
|
|
194
194
|
minY = Infinity,
|
|
195
|
-
minZ = Infinity
|
|
195
|
+
minZ = Infinity
|
|
196
196
|
let maxX = -Infinity,
|
|
197
197
|
maxY = -Infinity,
|
|
198
|
-
maxZ = -Infinity
|
|
198
|
+
maxZ = -Infinity
|
|
199
199
|
|
|
200
200
|
for (const [i, j, k] of corners) {
|
|
201
201
|
// Apply affine: world = affine * [i, j, k, 1]^T
|
|
202
|
-
const wx = affine[0] * i + affine[4] * j + affine[8] * k + affine[12]
|
|
203
|
-
const wy = affine[1] * i + affine[5] * j + affine[9] * k + affine[13]
|
|
204
|
-
const wz = affine[2] * i + affine[6] * j + affine[10] * k + affine[14]
|
|
205
|
-
|
|
206
|
-
minX = Math.min(minX, wx)
|
|
207
|
-
minY = Math.min(minY, wy)
|
|
208
|
-
minZ = Math.min(minZ, wz)
|
|
209
|
-
maxX = Math.max(maxX, wx)
|
|
210
|
-
maxY = Math.max(maxY, wy)
|
|
211
|
-
maxZ = Math.max(maxZ, wz)
|
|
202
|
+
const wx = affine[0] * i + affine[4] * j + affine[8] * k + affine[12]
|
|
203
|
+
const wy = affine[1] * i + affine[5] * j + affine[9] * k + affine[13]
|
|
204
|
+
const wz = affine[2] * i + affine[6] * j + affine[10] * k + affine[14]
|
|
205
|
+
|
|
206
|
+
minX = Math.min(minX, wx)
|
|
207
|
+
minY = Math.min(minY, wy)
|
|
208
|
+
minZ = Math.min(minZ, wz)
|
|
209
|
+
maxX = Math.max(maxX, wx)
|
|
210
|
+
maxY = Math.max(maxY, wy)
|
|
211
|
+
maxZ = Math.max(maxZ, wz)
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
return {
|
|
215
215
|
min: [minX, minY, minZ],
|
|
216
216
|
max: [maxX, maxY, maxZ],
|
|
217
|
-
}
|
|
217
|
+
}
|
|
218
218
|
}
|
package/src/utils/coordinates.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import type { NgffImage } from "@fideus-labs/ngff-zarr"
|
|
5
|
+
import { mat4, vec4 } from "gl-matrix"
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Convert a world coordinate to pixel indices.
|
|
@@ -15,26 +15,26 @@ export function worldToPixel(
|
|
|
15
15
|
worldCoord: [number, number, number],
|
|
16
16
|
ngffImage: NgffImage,
|
|
17
17
|
): [number, number, number] {
|
|
18
|
-
const scale = ngffImage.scale
|
|
19
|
-
const translation = ngffImage.translation
|
|
18
|
+
const scale = ngffImage.scale
|
|
19
|
+
const translation = ngffImage.translation
|
|
20
20
|
|
|
21
21
|
// world = scale * pixel + translation
|
|
22
22
|
// pixel = (world - translation) / scale
|
|
23
23
|
|
|
24
|
-
const sx = scale.x ?? scale.X ?? 1
|
|
25
|
-
const sy = scale.y ?? scale.Y ?? 1
|
|
26
|
-
const sz = scale.z ?? scale.Z ?? 1
|
|
24
|
+
const sx = scale.x ?? scale.X ?? 1
|
|
25
|
+
const sy = scale.y ?? scale.Y ?? 1
|
|
26
|
+
const sz = scale.z ?? scale.Z ?? 1
|
|
27
27
|
|
|
28
|
-
const tx = translation.x ?? translation.X ?? 0
|
|
29
|
-
const ty = translation.y ?? translation.Y ?? 0
|
|
30
|
-
const tz = translation.z ?? translation.Z ?? 0
|
|
28
|
+
const tx = translation.x ?? translation.X ?? 0
|
|
29
|
+
const ty = translation.y ?? translation.Y ?? 0
|
|
30
|
+
const tz = translation.z ?? translation.Z ?? 0
|
|
31
31
|
|
|
32
|
-
const px = (worldCoord[0] - tx) / sx
|
|
33
|
-
const py = (worldCoord[1] - ty) / sy
|
|
34
|
-
const pz = (worldCoord[2] - tz) / sz
|
|
32
|
+
const px = (worldCoord[0] - tx) / sx
|
|
33
|
+
const py = (worldCoord[1] - ty) / sy
|
|
34
|
+
const pz = (worldCoord[2] - tz) / sz
|
|
35
35
|
|
|
36
36
|
// Return in [z, y, x] order to match OME-Zarr array indexing
|
|
37
|
-
return [pz, py, px]
|
|
37
|
+
return [pz, py, px]
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
@@ -48,25 +48,25 @@ export function pixelToWorld(
|
|
|
48
48
|
pixelCoord: [number, number, number],
|
|
49
49
|
ngffImage: NgffImage,
|
|
50
50
|
): [number, number, number] {
|
|
51
|
-
const scale = ngffImage.scale
|
|
52
|
-
const translation = ngffImage.translation
|
|
51
|
+
const scale = ngffImage.scale
|
|
52
|
+
const translation = ngffImage.translation
|
|
53
53
|
|
|
54
54
|
// world = scale * pixel + translation
|
|
55
55
|
|
|
56
|
-
const sx = scale.x ?? scale.X ?? 1
|
|
57
|
-
const sy = scale.y ?? scale.Y ?? 1
|
|
58
|
-
const sz = scale.z ?? scale.Z ?? 1
|
|
56
|
+
const sx = scale.x ?? scale.X ?? 1
|
|
57
|
+
const sy = scale.y ?? scale.Y ?? 1
|
|
58
|
+
const sz = scale.z ?? scale.Z ?? 1
|
|
59
59
|
|
|
60
|
-
const tx = translation.x ?? translation.X ?? 0
|
|
61
|
-
const ty = translation.y ?? translation.Y ?? 0
|
|
62
|
-
const tz = translation.z ?? translation.Z ?? 0
|
|
60
|
+
const tx = translation.x ?? translation.X ?? 0
|
|
61
|
+
const ty = translation.y ?? translation.Y ?? 0
|
|
62
|
+
const tz = translation.z ?? translation.Z ?? 0
|
|
63
63
|
|
|
64
64
|
// pixelCoord is [z, y, x]
|
|
65
|
-
const wx = sx * pixelCoord[2] + tx
|
|
66
|
-
const wy = sy * pixelCoord[1] + ty
|
|
67
|
-
const wz = sz * pixelCoord[0] + tz
|
|
65
|
+
const wx = sx * pixelCoord[2] + tx
|
|
66
|
+
const wy = sy * pixelCoord[1] + ty
|
|
67
|
+
const wz = sz * pixelCoord[0] + tz
|
|
68
68
|
|
|
69
|
-
return [wx, wy, wz]
|
|
69
|
+
return [wx, wy, wz]
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
@@ -81,20 +81,20 @@ export function worldToPixelAffine(
|
|
|
81
81
|
affine: mat4,
|
|
82
82
|
): [number, number, number] {
|
|
83
83
|
// Invert the affine to go from world to pixel
|
|
84
|
-
const inverseAffine = mat4.create()
|
|
85
|
-
mat4.invert(inverseAffine, affine)
|
|
84
|
+
const inverseAffine = mat4.create()
|
|
85
|
+
mat4.invert(inverseAffine, affine)
|
|
86
86
|
|
|
87
87
|
const worldVec = vec4.fromValues(
|
|
88
88
|
worldCoord[0],
|
|
89
89
|
worldCoord[1],
|
|
90
90
|
worldCoord[2],
|
|
91
91
|
1,
|
|
92
|
-
)
|
|
93
|
-
const pixelVec = vec4.create()
|
|
94
|
-
vec4.transformMat4(pixelVec, worldVec, inverseAffine)
|
|
92
|
+
)
|
|
93
|
+
const pixelVec = vec4.create()
|
|
94
|
+
vec4.transformMat4(pixelVec, worldVec, inverseAffine)
|
|
95
95
|
|
|
96
96
|
// Return in [z, y, x] order
|
|
97
|
-
return [pixelVec[2], pixelVec[1], pixelVec[0]]
|
|
97
|
+
return [pixelVec[2], pixelVec[1], pixelVec[0]]
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
@@ -114,11 +114,11 @@ export function pixelToWorldAffine(
|
|
|
114
114
|
pixelCoord[1], // y
|
|
115
115
|
pixelCoord[0], // z
|
|
116
116
|
1,
|
|
117
|
-
)
|
|
118
|
-
const worldVec = vec4.create()
|
|
119
|
-
vec4.transformMat4(worldVec, pixelVec, affine)
|
|
117
|
+
)
|
|
118
|
+
const worldVec = vec4.create()
|
|
119
|
+
vec4.transformMat4(worldVec, pixelVec, affine)
|
|
120
120
|
|
|
121
|
-
return [worldVec[0], worldVec[1], worldVec[2]]
|
|
121
|
+
return [worldVec[0], worldVec[1], worldVec[2]]
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/**
|
|
@@ -132,24 +132,24 @@ export function normalizedToWorld(
|
|
|
132
132
|
normalizedCoord: [number, number, number],
|
|
133
133
|
ngffImage: NgffImage,
|
|
134
134
|
): [number, number, number] {
|
|
135
|
-
const shape = ngffImage.data.shape
|
|
136
|
-
const dims = ngffImage.dims
|
|
135
|
+
const shape = ngffImage.data.shape
|
|
136
|
+
const dims = ngffImage.dims
|
|
137
137
|
|
|
138
138
|
// Find z, y, x indices in dims
|
|
139
|
-
const zIdx = dims.indexOf("z")
|
|
140
|
-
const yIdx = dims.indexOf("y")
|
|
141
|
-
const xIdx = dims.indexOf("x")
|
|
139
|
+
const zIdx = dims.indexOf("z")
|
|
140
|
+
const yIdx = dims.indexOf("y")
|
|
141
|
+
const xIdx = dims.indexOf("x")
|
|
142
142
|
|
|
143
|
-
let dimX: number, dimY: number, dimZ: number
|
|
143
|
+
let dimX: number, dimY: number, dimZ: number
|
|
144
144
|
if (zIdx === -1 || yIdx === -1 || xIdx === -1) {
|
|
145
|
-
const n = shape.length
|
|
146
|
-
dimZ = shape[n - 3] || 1
|
|
147
|
-
dimY = shape[n - 2] || 1
|
|
148
|
-
dimX = shape[n - 1] || 1
|
|
145
|
+
const n = shape.length
|
|
146
|
+
dimZ = shape[n - 3] || 1
|
|
147
|
+
dimY = shape[n - 2] || 1
|
|
148
|
+
dimX = shape[n - 1] || 1
|
|
149
149
|
} else {
|
|
150
|
-
dimZ = shape[zIdx]
|
|
151
|
-
dimY = shape[yIdx]
|
|
152
|
-
dimX = shape[xIdx]
|
|
150
|
+
dimZ = shape[zIdx]
|
|
151
|
+
dimY = shape[yIdx]
|
|
152
|
+
dimX = shape[xIdx]
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// Convert normalized to pixel
|
|
@@ -157,9 +157,9 @@ export function normalizedToWorld(
|
|
|
157
157
|
normalizedCoord[2] * dimZ, // z
|
|
158
158
|
normalizedCoord[1] * dimY, // y
|
|
159
159
|
normalizedCoord[0] * dimX, // x
|
|
160
|
-
]
|
|
160
|
+
]
|
|
161
161
|
|
|
162
|
-
return pixelToWorld(pixelCoord, ngffImage)
|
|
162
|
+
return pixelToWorld(pixelCoord, ngffImage)
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
/**
|
|
@@ -173,35 +173,35 @@ export function worldToNormalized(
|
|
|
173
173
|
worldCoord: [number, number, number],
|
|
174
174
|
ngffImage: NgffImage,
|
|
175
175
|
): [number, number, number] {
|
|
176
|
-
const shape = ngffImage.data.shape
|
|
177
|
-
const dims = ngffImage.dims
|
|
176
|
+
const shape = ngffImage.data.shape
|
|
177
|
+
const dims = ngffImage.dims
|
|
178
178
|
|
|
179
179
|
// Find z, y, x indices in dims
|
|
180
|
-
const zIdx = dims.indexOf("z")
|
|
181
|
-
const yIdx = dims.indexOf("y")
|
|
182
|
-
const xIdx = dims.indexOf("x")
|
|
180
|
+
const zIdx = dims.indexOf("z")
|
|
181
|
+
const yIdx = dims.indexOf("y")
|
|
182
|
+
const xIdx = dims.indexOf("x")
|
|
183
183
|
|
|
184
|
-
let dimX: number, dimY: number, dimZ: number
|
|
184
|
+
let dimX: number, dimY: number, dimZ: number
|
|
185
185
|
if (zIdx === -1 || yIdx === -1 || xIdx === -1) {
|
|
186
|
-
const n = shape.length
|
|
187
|
-
dimZ = shape[n - 3] || 1
|
|
188
|
-
dimY = shape[n - 2] || 1
|
|
189
|
-
dimX = shape[n - 1] || 1
|
|
186
|
+
const n = shape.length
|
|
187
|
+
dimZ = shape[n - 3] || 1
|
|
188
|
+
dimY = shape[n - 2] || 1
|
|
189
|
+
dimX = shape[n - 1] || 1
|
|
190
190
|
} else {
|
|
191
|
-
dimZ = shape[zIdx]
|
|
192
|
-
dimY = shape[yIdx]
|
|
193
|
-
dimX = shape[xIdx]
|
|
191
|
+
dimZ = shape[zIdx]
|
|
192
|
+
dimY = shape[yIdx]
|
|
193
|
+
dimX = shape[xIdx]
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
// Convert world to pixel
|
|
197
|
-
const pixelCoord = worldToPixel(worldCoord, ngffImage)
|
|
197
|
+
const pixelCoord = worldToPixel(worldCoord, ngffImage)
|
|
198
198
|
|
|
199
199
|
// Convert pixel to normalized
|
|
200
200
|
return [
|
|
201
201
|
pixelCoord[2] / dimX, // x normalized
|
|
202
202
|
pixelCoord[1] / dimY, // y normalized
|
|
203
203
|
pixelCoord[0] / dimZ, // z normalized
|
|
204
|
-
]
|
|
204
|
+
]
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
/**
|
|
@@ -219,7 +219,7 @@ export function clampPixelCoord(
|
|
|
219
219
|
Math.max(0, Math.min(pixelCoord[0], shape[0] - 1)),
|
|
220
220
|
Math.max(0, Math.min(pixelCoord[1], shape[1] - 1)),
|
|
221
221
|
Math.max(0, Math.min(pixelCoord[2], shape[2] - 1)),
|
|
222
|
-
]
|
|
222
|
+
]
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
/**
|
|
@@ -235,7 +235,7 @@ export function roundPixelCoord(
|
|
|
235
235
|
Math.round(pixelCoord[0]),
|
|
236
236
|
Math.round(pixelCoord[1]),
|
|
237
237
|
Math.round(pixelCoord[2]),
|
|
238
|
-
]
|
|
238
|
+
]
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
/**
|
|
@@ -251,7 +251,7 @@ export function floorPixelCoord(
|
|
|
251
251
|
Math.floor(pixelCoord[0]),
|
|
252
252
|
Math.floor(pixelCoord[1]),
|
|
253
253
|
Math.floor(pixelCoord[2]),
|
|
254
|
-
]
|
|
254
|
+
]
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
/**
|
|
@@ -267,5 +267,5 @@ export function ceilPixelCoord(
|
|
|
267
267
|
Math.ceil(pixelCoord[0]),
|
|
268
268
|
Math.ceil(pixelCoord[1]),
|
|
269
269
|
Math.ceil(pixelCoord[2]),
|
|
270
|
-
]
|
|
270
|
+
]
|
|
271
271
|
}
|