@fideus-labs/fidnii 0.1.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/LICENSE.txt +9 -0
- package/README.md +180 -0
- package/dist/BufferManager.d.ts +86 -0
- package/dist/BufferManager.d.ts.map +1 -0
- package/dist/BufferManager.js +146 -0
- package/dist/BufferManager.js.map +1 -0
- package/dist/ClipPlanes.d.ts +180 -0
- package/dist/ClipPlanes.d.ts.map +1 -0
- package/dist/ClipPlanes.js +513 -0
- package/dist/ClipPlanes.js.map +1 -0
- package/dist/OMEZarrNVImage.d.ts +545 -0
- package/dist/OMEZarrNVImage.d.ts.map +1 -0
- package/dist/OMEZarrNVImage.js +1799 -0
- package/dist/OMEZarrNVImage.js.map +1 -0
- package/dist/RegionCoalescer.d.ts +75 -0
- package/dist/RegionCoalescer.d.ts.map +1 -0
- package/dist/RegionCoalescer.js +151 -0
- package/dist/RegionCoalescer.js.map +1 -0
- package/dist/ResolutionSelector.d.ts +88 -0
- package/dist/ResolutionSelector.d.ts.map +1 -0
- package/dist/ResolutionSelector.js +224 -0
- package/dist/ResolutionSelector.js.map +1 -0
- package/dist/ViewportBounds.d.ts +50 -0
- package/dist/ViewportBounds.d.ts.map +1 -0
- package/dist/ViewportBounds.js +325 -0
- package/dist/ViewportBounds.js.map +1 -0
- package/dist/events.d.ts +122 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +12 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +273 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +126 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/affine.d.ts +72 -0
- package/dist/utils/affine.d.ts.map +1 -0
- package/dist/utils/affine.js +173 -0
- package/dist/utils/affine.js.map +1 -0
- package/dist/utils/coordinates.d.ts +80 -0
- package/dist/utils/coordinates.d.ts.map +1 -0
- package/dist/utils/coordinates.js +207 -0
- package/dist/utils/coordinates.js.map +1 -0
- package/package.json +61 -0
- package/src/BufferManager.ts +176 -0
- package/src/ClipPlanes.ts +640 -0
- package/src/OMEZarrNVImage.ts +2286 -0
- package/src/RegionCoalescer.ts +217 -0
- package/src/ResolutionSelector.ts +325 -0
- package/src/ViewportBounds.ts +369 -0
- package/src/events.ts +146 -0
- package/src/index.ts +153 -0
- package/src/types.ts +429 -0
- package/src/utils/affine.ts +218 -0
- package/src/utils/coordinates.ts +271 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import { mat4, vec4 } from "gl-matrix";
|
|
5
|
+
import type { NgffImage } from "@fideus-labs/ngff-zarr";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Convert a world coordinate to pixel indices.
|
|
9
|
+
*
|
|
10
|
+
* @param worldCoord - World coordinate [x, y, z]
|
|
11
|
+
* @param ngffImage - The NgffImage containing scale and translation
|
|
12
|
+
* @returns Pixel indices [z, y, x]
|
|
13
|
+
*/
|
|
14
|
+
export function worldToPixel(
|
|
15
|
+
worldCoord: [number, number, number],
|
|
16
|
+
ngffImage: NgffImage,
|
|
17
|
+
): [number, number, number] {
|
|
18
|
+
const scale = ngffImage.scale;
|
|
19
|
+
const translation = ngffImage.translation;
|
|
20
|
+
|
|
21
|
+
// world = scale * pixel + translation
|
|
22
|
+
// pixel = (world - translation) / scale
|
|
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;
|
|
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;
|
|
31
|
+
|
|
32
|
+
const px = (worldCoord[0] - tx) / sx;
|
|
33
|
+
const py = (worldCoord[1] - ty) / sy;
|
|
34
|
+
const pz = (worldCoord[2] - tz) / sz;
|
|
35
|
+
|
|
36
|
+
// Return in [z, y, x] order to match OME-Zarr array indexing
|
|
37
|
+
return [pz, py, px];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Convert pixel indices to world coordinates.
|
|
42
|
+
*
|
|
43
|
+
* @param pixelCoord - Pixel indices [z, y, x]
|
|
44
|
+
* @param ngffImage - The NgffImage containing scale and translation
|
|
45
|
+
* @returns World coordinate [x, y, z]
|
|
46
|
+
*/
|
|
47
|
+
export function pixelToWorld(
|
|
48
|
+
pixelCoord: [number, number, number],
|
|
49
|
+
ngffImage: NgffImage,
|
|
50
|
+
): [number, number, number] {
|
|
51
|
+
const scale = ngffImage.scale;
|
|
52
|
+
const translation = ngffImage.translation;
|
|
53
|
+
|
|
54
|
+
// world = scale * pixel + translation
|
|
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;
|
|
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;
|
|
63
|
+
|
|
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;
|
|
68
|
+
|
|
69
|
+
return [wx, wy, wz];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Convert world coordinate to pixel using an affine matrix.
|
|
74
|
+
*
|
|
75
|
+
* @param worldCoord - World coordinate [x, y, z]
|
|
76
|
+
* @param affine - 4x4 affine matrix (pixel to world)
|
|
77
|
+
* @returns Pixel indices [z, y, x]
|
|
78
|
+
*/
|
|
79
|
+
export function worldToPixelAffine(
|
|
80
|
+
worldCoord: [number, number, number],
|
|
81
|
+
affine: mat4,
|
|
82
|
+
): [number, number, number] {
|
|
83
|
+
// Invert the affine to go from world to pixel
|
|
84
|
+
const inverseAffine = mat4.create();
|
|
85
|
+
mat4.invert(inverseAffine, affine);
|
|
86
|
+
|
|
87
|
+
const worldVec = vec4.fromValues(
|
|
88
|
+
worldCoord[0],
|
|
89
|
+
worldCoord[1],
|
|
90
|
+
worldCoord[2],
|
|
91
|
+
1,
|
|
92
|
+
);
|
|
93
|
+
const pixelVec = vec4.create();
|
|
94
|
+
vec4.transformMat4(pixelVec, worldVec, inverseAffine);
|
|
95
|
+
|
|
96
|
+
// Return in [z, y, x] order
|
|
97
|
+
return [pixelVec[2], pixelVec[1], pixelVec[0]];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Convert pixel indices to world using an affine matrix.
|
|
102
|
+
*
|
|
103
|
+
* @param pixelCoord - Pixel indices [z, y, x]
|
|
104
|
+
* @param affine - 4x4 affine matrix (pixel to world)
|
|
105
|
+
* @returns World coordinate [x, y, z]
|
|
106
|
+
*/
|
|
107
|
+
export function pixelToWorldAffine(
|
|
108
|
+
pixelCoord: [number, number, number],
|
|
109
|
+
affine: mat4,
|
|
110
|
+
): [number, number, number] {
|
|
111
|
+
// pixelCoord is [z, y, x], affine expects [x, y, z]
|
|
112
|
+
const pixelVec = vec4.fromValues(
|
|
113
|
+
pixelCoord[2], // x
|
|
114
|
+
pixelCoord[1], // y
|
|
115
|
+
pixelCoord[0], // z
|
|
116
|
+
1,
|
|
117
|
+
);
|
|
118
|
+
const worldVec = vec4.create();
|
|
119
|
+
vec4.transformMat4(worldVec, pixelVec, affine);
|
|
120
|
+
|
|
121
|
+
return [worldVec[0], worldVec[1], worldVec[2]];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Convert normalized volume coordinates (0-1) to world coordinates.
|
|
126
|
+
*
|
|
127
|
+
* @param normalizedCoord - Normalized coordinate [x, y, z] in range 0-1
|
|
128
|
+
* @param ngffImage - The NgffImage
|
|
129
|
+
* @returns World coordinate [x, y, z]
|
|
130
|
+
*/
|
|
131
|
+
export function normalizedToWorld(
|
|
132
|
+
normalizedCoord: [number, number, number],
|
|
133
|
+
ngffImage: NgffImage,
|
|
134
|
+
): [number, number, number] {
|
|
135
|
+
const shape = ngffImage.data.shape;
|
|
136
|
+
const dims = ngffImage.dims;
|
|
137
|
+
|
|
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");
|
|
142
|
+
|
|
143
|
+
let dimX: number, dimY: number, dimZ: number;
|
|
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;
|
|
149
|
+
} else {
|
|
150
|
+
dimZ = shape[zIdx];
|
|
151
|
+
dimY = shape[yIdx];
|
|
152
|
+
dimX = shape[xIdx];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Convert normalized to pixel
|
|
156
|
+
const pixelCoord: [number, number, number] = [
|
|
157
|
+
normalizedCoord[2] * dimZ, // z
|
|
158
|
+
normalizedCoord[1] * dimY, // y
|
|
159
|
+
normalizedCoord[0] * dimX, // x
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
return pixelToWorld(pixelCoord, ngffImage);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Convert world coordinates to normalized volume coordinates (0-1).
|
|
167
|
+
*
|
|
168
|
+
* @param worldCoord - World coordinate [x, y, z]
|
|
169
|
+
* @param ngffImage - The NgffImage
|
|
170
|
+
* @returns Normalized coordinate [x, y, z] in range 0-1
|
|
171
|
+
*/
|
|
172
|
+
export function worldToNormalized(
|
|
173
|
+
worldCoord: [number, number, number],
|
|
174
|
+
ngffImage: NgffImage,
|
|
175
|
+
): [number, number, number] {
|
|
176
|
+
const shape = ngffImage.data.shape;
|
|
177
|
+
const dims = ngffImage.dims;
|
|
178
|
+
|
|
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");
|
|
183
|
+
|
|
184
|
+
let dimX: number, dimY: number, dimZ: number;
|
|
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;
|
|
190
|
+
} else {
|
|
191
|
+
dimZ = shape[zIdx];
|
|
192
|
+
dimY = shape[yIdx];
|
|
193
|
+
dimX = shape[xIdx];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Convert world to pixel
|
|
197
|
+
const pixelCoord = worldToPixel(worldCoord, ngffImage);
|
|
198
|
+
|
|
199
|
+
// Convert pixel to normalized
|
|
200
|
+
return [
|
|
201
|
+
pixelCoord[2] / dimX, // x normalized
|
|
202
|
+
pixelCoord[1] / dimY, // y normalized
|
|
203
|
+
pixelCoord[0] / dimZ, // z normalized
|
|
204
|
+
];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Clamp pixel coordinates to valid range for a volume.
|
|
209
|
+
*
|
|
210
|
+
* @param pixelCoord - Pixel indices [z, y, x]
|
|
211
|
+
* @param shape - Volume shape [z, y, x]
|
|
212
|
+
* @returns Clamped pixel indices [z, y, x]
|
|
213
|
+
*/
|
|
214
|
+
export function clampPixelCoord(
|
|
215
|
+
pixelCoord: [number, number, number],
|
|
216
|
+
shape: [number, number, number],
|
|
217
|
+
): [number, number, number] {
|
|
218
|
+
return [
|
|
219
|
+
Math.max(0, Math.min(pixelCoord[0], shape[0] - 1)),
|
|
220
|
+
Math.max(0, Math.min(pixelCoord[1], shape[1] - 1)),
|
|
221
|
+
Math.max(0, Math.min(pixelCoord[2], shape[2] - 1)),
|
|
222
|
+
];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Round pixel coordinates to integers.
|
|
227
|
+
*
|
|
228
|
+
* @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
|
|
229
|
+
* @returns Rounded pixel indices [z, y, x]
|
|
230
|
+
*/
|
|
231
|
+
export function roundPixelCoord(
|
|
232
|
+
pixelCoord: [number, number, number],
|
|
233
|
+
): [number, number, number] {
|
|
234
|
+
return [
|
|
235
|
+
Math.round(pixelCoord[0]),
|
|
236
|
+
Math.round(pixelCoord[1]),
|
|
237
|
+
Math.round(pixelCoord[2]),
|
|
238
|
+
];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Floor pixel coordinates to integers (for region start).
|
|
243
|
+
*
|
|
244
|
+
* @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
|
|
245
|
+
* @returns Floored pixel indices [z, y, x]
|
|
246
|
+
*/
|
|
247
|
+
export function floorPixelCoord(
|
|
248
|
+
pixelCoord: [number, number, number],
|
|
249
|
+
): [number, number, number] {
|
|
250
|
+
return [
|
|
251
|
+
Math.floor(pixelCoord[0]),
|
|
252
|
+
Math.floor(pixelCoord[1]),
|
|
253
|
+
Math.floor(pixelCoord[2]),
|
|
254
|
+
];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Ceil pixel coordinates to integers (for region end).
|
|
259
|
+
*
|
|
260
|
+
* @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
|
|
261
|
+
* @returns Ceiled pixel indices [z, y, x]
|
|
262
|
+
*/
|
|
263
|
+
export function ceilPixelCoord(
|
|
264
|
+
pixelCoord: [number, number, number],
|
|
265
|
+
): [number, number, number] {
|
|
266
|
+
return [
|
|
267
|
+
Math.ceil(pixelCoord[0]),
|
|
268
|
+
Math.ceil(pixelCoord[1]),
|
|
269
|
+
Math.ceil(pixelCoord[2]),
|
|
270
|
+
];
|
|
271
|
+
}
|