@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.
Files changed (58) hide show
  1. package/LICENSE.txt +9 -0
  2. package/README.md +180 -0
  3. package/dist/BufferManager.d.ts +86 -0
  4. package/dist/BufferManager.d.ts.map +1 -0
  5. package/dist/BufferManager.js +146 -0
  6. package/dist/BufferManager.js.map +1 -0
  7. package/dist/ClipPlanes.d.ts +180 -0
  8. package/dist/ClipPlanes.d.ts.map +1 -0
  9. package/dist/ClipPlanes.js +513 -0
  10. package/dist/ClipPlanes.js.map +1 -0
  11. package/dist/OMEZarrNVImage.d.ts +545 -0
  12. package/dist/OMEZarrNVImage.d.ts.map +1 -0
  13. package/dist/OMEZarrNVImage.js +1799 -0
  14. package/dist/OMEZarrNVImage.js.map +1 -0
  15. package/dist/RegionCoalescer.d.ts +75 -0
  16. package/dist/RegionCoalescer.d.ts.map +1 -0
  17. package/dist/RegionCoalescer.js +151 -0
  18. package/dist/RegionCoalescer.js.map +1 -0
  19. package/dist/ResolutionSelector.d.ts +88 -0
  20. package/dist/ResolutionSelector.d.ts.map +1 -0
  21. package/dist/ResolutionSelector.js +224 -0
  22. package/dist/ResolutionSelector.js.map +1 -0
  23. package/dist/ViewportBounds.d.ts +50 -0
  24. package/dist/ViewportBounds.d.ts.map +1 -0
  25. package/dist/ViewportBounds.js +325 -0
  26. package/dist/ViewportBounds.js.map +1 -0
  27. package/dist/events.d.ts +122 -0
  28. package/dist/events.d.ts.map +1 -0
  29. package/dist/events.js +12 -0
  30. package/dist/events.js.map +1 -0
  31. package/dist/index.d.ts +48 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +59 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/types.d.ts +273 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +126 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/utils/affine.d.ts +72 -0
  40. package/dist/utils/affine.d.ts.map +1 -0
  41. package/dist/utils/affine.js +173 -0
  42. package/dist/utils/affine.js.map +1 -0
  43. package/dist/utils/coordinates.d.ts +80 -0
  44. package/dist/utils/coordinates.d.ts.map +1 -0
  45. package/dist/utils/coordinates.js +207 -0
  46. package/dist/utils/coordinates.js.map +1 -0
  47. package/package.json +61 -0
  48. package/src/BufferManager.ts +176 -0
  49. package/src/ClipPlanes.ts +640 -0
  50. package/src/OMEZarrNVImage.ts +2286 -0
  51. package/src/RegionCoalescer.ts +217 -0
  52. package/src/ResolutionSelector.ts +325 -0
  53. package/src/ViewportBounds.ts +369 -0
  54. package/src/events.ts +146 -0
  55. package/src/index.ts +153 -0
  56. package/src/types.ts +429 -0
  57. package/src/utils/affine.ts +218 -0
  58. 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
+ }