@jax-data-science/sci-image-visualizer 0.9.0 → 0.11.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 (149) hide show
  1. package/esm2022/index.mjs +10 -1
  2. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  3. package/esm2022/lib/contracts/ports/region-io.port.mjs +1 -1
  4. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  5. package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/section-view.contract.mjs +2 -0
  7. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  8. package/esm2022/lib/contracts/viz-config.mjs +1 -1
  9. package/esm2022/lib/geometry/loft.mjs +128 -0
  10. package/esm2022/lib/geometry/polylabel.mjs +156 -0
  11. package/esm2022/lib/geometry/reconstruct.mjs +315 -0
  12. package/esm2022/lib/geometry/reslice-image.mjs +57 -0
  13. package/esm2022/lib/geometry/section.mjs +215 -0
  14. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +11 -7
  15. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +20 -3
  16. package/esm2022/lib/implementations/napari-js/napari-region-mesh-pointer.mjs +100 -0
  17. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +28 -5
  18. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
  19. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +9 -2
  20. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +5 -2
  21. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +81 -1
  22. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +129 -0
  23. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +115 -4
  24. package/esm2022/lib/implementations/napari-js/napari-volume-slice-planes.mjs +103 -0
  25. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +15 -3
  26. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +18 -2
  27. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +9 -1
  28. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +18 -7
  29. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +38 -8
  30. package/esm2022/lib/implementations/osd/osd-tile-loading.mjs +71 -0
  31. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +1 -1
  32. package/esm2022/lib/implementations/osd/slice-cache.mjs +35 -6
  33. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +1 -1
  34. package/esm2022/lib/models/class-preset.mjs +1 -1
  35. package/esm2022/lib/models/polygon-factory.mjs +17 -1
  36. package/esm2022/lib/models/region-geojson.mjs +44 -6
  37. package/esm2022/lib/models/region.mjs +1 -1
  38. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +156 -0
  39. package/esm2022/lib/region-editor/class-tree/class-tree.mjs +108 -0
  40. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +77 -13
  41. package/esm2022/lib/region-editor/region-editor.component.mjs +670 -42
  42. package/esm2022/lib/region-editor/region-metrics.mjs +20 -2
  43. package/esm2022/lib/region-editor/region-persistence.service.mjs +44 -10
  44. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +24 -8
  45. package/esm2022/lib/region-import/label-classes.mjs +149 -0
  46. package/esm2022/lib/region-import/label-volume.mjs +194 -0
  47. package/esm2022/lib/region-import/region-import.mjs +71 -0
  48. package/esm2022/lib/region-overlay/region-geometry.mjs +3 -3
  49. package/esm2022/lib/region-overlay/region-source-layer.mjs +378 -0
  50. package/esm2022/lib/region-overlay/region-style.mjs +97 -0
  51. package/esm2022/lib/region-source/http-region-source.mjs +104 -0
  52. package/esm2022/lib/region-source/region-source-ops.mjs +53 -0
  53. package/esm2022/lib/region-source/region-source-worker.mjs +10 -0
  54. package/esm2022/lib/region-source/region-source.mjs +67 -0
  55. package/esm2022/lib/region-source/region-tiles.mjs +708 -0
  56. package/esm2022/lib/region-source/worker-region-source.mjs +229 -0
  57. package/esm2022/lib/routing-visualizer.service.mjs +510 -22
  58. package/esm2022/lib/section-pane/section-pane.component.mjs +299 -0
  59. package/esm2022/lib/store/class-color.util.mjs +10 -5
  60. package/esm2022/lib/store/class-signatures.mjs +63 -0
  61. package/esm2022/lib/store/region-scope-cache.mjs +5 -1
  62. package/esm2022/lib/store/region-source-scope.mjs +186 -0
  63. package/esm2022/lib/store/region-store.service.mjs +774 -12
  64. package/esm2022/lib/store/visualizer-store.service.mjs +33 -6
  65. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +8 -2
  66. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +55 -15
  67. package/esm2022/lib/toolbar/toolbar.component.mjs +19 -5
  68. package/esm2022/lib/visualizer/region-load.mjs +67 -4
  69. package/esm2022/lib/visualizer/volume-sections.mjs +175 -0
  70. package/esm2022/lib/visualizer.component.mjs +155 -7
  71. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.mjs} +9851 -2904
  72. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.mjs.map +1 -0
  73. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-DEDSm_NL.mjs} +4 -4
  74. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-DEDSm_NL.mjs.map} +1 -1
  75. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs +12 -0
  76. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs.map +1 -0
  77. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3 -3
  78. package/fesm2022/region-source.worker.js +1067 -0
  79. package/index.d.ts +12 -0
  80. package/lib/contracts/image.contract.d.ts +4 -0
  81. package/lib/contracts/ports/region-io.port.d.ts +24 -0
  82. package/lib/contracts/region-editor-api.contract.d.ts +102 -0
  83. package/lib/contracts/region-store.contract.d.ts +22 -0
  84. package/lib/contracts/section-view.contract.d.ts +44 -0
  85. package/lib/contracts/visualizer.contract.d.ts +10 -0
  86. package/lib/contracts/viz-config.d.ts +8 -0
  87. package/lib/geometry/loft.d.ts +22 -0
  88. package/lib/geometry/polylabel.d.ts +23 -0
  89. package/lib/geometry/reconstruct.d.ts +54 -0
  90. package/lib/geometry/reslice-image.d.ts +33 -0
  91. package/lib/geometry/section.d.ts +52 -0
  92. package/lib/implementations/napari-js/napari-loading-badge.d.ts +4 -2
  93. package/lib/implementations/napari-js/napari-loading-state.d.ts +8 -1
  94. package/lib/implementations/napari-js/napari-region-mesh-pointer.d.ts +32 -0
  95. package/lib/implementations/napari-js/napari-region-overlay.d.ts +6 -1
  96. package/lib/implementations/napari-js/napari-scene.d.ts +33 -0
  97. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +3 -1
  98. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +48 -0
  99. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +66 -0
  100. package/lib/implementations/napari-js/napari-volume-scene.d.ts +45 -1
  101. package/lib/implementations/napari-js/napari-volume-slice-planes.d.ts +43 -0
  102. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +2 -0
  103. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +2 -0
  104. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +4 -3
  105. package/lib/implementations/osd/osd-region-overlay.d.ts +10 -3
  106. package/lib/implementations/osd/osd-tile-loading.d.ts +43 -0
  107. package/lib/implementations/osd/osd-viewer-like.d.ts +14 -0
  108. package/lib/implementations/osd/slice-cache.d.ts +13 -3
  109. package/lib/implementations/tile-server/tile-protocol.d.ts +3 -0
  110. package/lib/models/class-preset.d.ts +7 -0
  111. package/lib/models/polygon-factory.d.ts +5 -0
  112. package/lib/models/region-geojson.d.ts +40 -0
  113. package/lib/models/region.d.ts +19 -0
  114. package/lib/region-editor/class-tree/class-tree.component.d.ts +78 -0
  115. package/lib/region-editor/class-tree/class-tree.d.ts +31 -0
  116. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +36 -6
  117. package/lib/region-editor/region-editor.component.d.ts +159 -17
  118. package/lib/region-editor/region-metrics.d.ts +8 -0
  119. package/lib/region-editor/region-persistence.service.d.ts +17 -5
  120. package/lib/region-editor/region-table/region-table.component.d.ts +10 -4
  121. package/lib/region-import/label-classes.d.ts +39 -0
  122. package/lib/region-import/label-volume.d.ts +31 -0
  123. package/lib/region-import/region-import.d.ts +46 -0
  124. package/lib/region-overlay/region-geometry.d.ts +4 -3
  125. package/lib/region-overlay/region-source-layer.d.ts +96 -0
  126. package/lib/region-overlay/region-style.d.ts +52 -0
  127. package/lib/region-source/http-region-source.d.ts +45 -0
  128. package/lib/region-source/region-source-ops.d.ts +89 -0
  129. package/lib/region-source/region-source-worker.d.ts +7 -0
  130. package/lib/region-source/region-source.d.ts +82 -0
  131. package/lib/region-source/region-tiles.d.ts +289 -0
  132. package/lib/region-source/worker-region-source.d.ts +65 -0
  133. package/lib/routing-visualizer.service.d.ts +168 -1
  134. package/lib/section-pane/section-pane.component.d.ts +47 -0
  135. package/lib/store/class-color.util.d.ts +6 -3
  136. package/lib/store/class-signatures.d.ts +11 -0
  137. package/lib/store/region-scope-cache.d.ts +2 -0
  138. package/lib/store/region-source-scope.d.ts +74 -0
  139. package/lib/store/region-store.service.d.ts +216 -2
  140. package/lib/store/visualizer-store.service.d.ts +10 -0
  141. package/lib/toolbar/region-tools/region-tools.component.d.ts +3 -1
  142. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +20 -9
  143. package/lib/toolbar/toolbar.component.d.ts +9 -2
  144. package/lib/visualizer/region-load.d.ts +23 -4
  145. package/lib/visualizer/volume-sections.d.ts +64 -0
  146. package/lib/visualizer.component.d.ts +40 -0
  147. package/package.json +2 -2
  148. package/src/lib/assets/slice.svg +23 -0
  149. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +0 -1
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Draws a region source (see `region-source`) under the editable regions, at the level of detail
3
+ * the zoom calls for, from the tiles in view only — the way the spatial views draw cell outlines.
4
+ * Shared by the OpenSeadragon and napari overlays: both hand it their svg and their world → svg
5
+ * camera affine, as they do their {@link SvgRegionRenderer}.
6
+ *
7
+ * One `<path>` per colour (every ring of every feature of that colour, even-odd), in world
8
+ * coordinates inside one transformed group, so a camera move rewrites one attribute. The tiles in
9
+ * view are re-planned once the camera settles; while a finer tile loads its coarser parent is
10
+ * drawn instead, so zooming in sharpens the outlines rather than blanking them. Features taken
11
+ * into the working set (selected, edited) or deleted are not drawn: the region renderer draws the
12
+ * taken ones as ordinary regions.
13
+ *
14
+ * It also answers what is under a point, from the features drawn, for the overlays' selection.
15
+ */
16
+ import type { Observable } from 'rxjs';
17
+ import { RegionSourceView } from '../region-source/region-source';
18
+ import { TileFeature } from '../region-source/region-tiles';
19
+ import { Affine } from './svg-region-renderer';
20
+ /** Wait this long after the last camera change before planning tiles (ms). */
21
+ export declare const SOURCE_REPLAN_MS = 90;
22
+ /** The view is padded by this fraction on each side, so a short pan finds its tiles loaded. */
23
+ export declare const SOURCE_VIEW_MARGIN = 0.25;
24
+ /** At most this many tiles in view. */
25
+ export declare const SOURCE_MAX_TILES = 256;
26
+ /** A rubber band takes at most this many source features into the working set. */
27
+ export declare const SOURCE_MARQUEE_LIMIT = 2000;
28
+ /** The svg size (local px), for the part of the world in view. */
29
+ export type SvgSize = () => {
30
+ width: number;
31
+ height: number;
32
+ };
33
+ export declare class RegionSourceLayer {
34
+ private readonly svg;
35
+ private readonly size;
36
+ private readonly group;
37
+ private camera;
38
+ /** Class labels inside the features, in screen space over the outlines. */
39
+ private readonly labelLayer;
40
+ /** Class name → depth in the source's class hierarchy (parents draw under their children). */
41
+ private depthOf;
42
+ /** Class name → its parent class in the source's class hierarchy. */
43
+ private parentOf;
44
+ private view;
45
+ private visible;
46
+ private readonly sub;
47
+ /** Loaded tiles of the current source and plane, by id, least recently used first. */
48
+ private readonly tiles;
49
+ /** The tiles the view wants now. */
50
+ private wanted;
51
+ /** The features drawn, by id (each at the finest level loaded). */
52
+ private drawn;
53
+ private loading;
54
+ private replanTimer;
55
+ private drawFrame;
56
+ constructor(svg: SVGSVGElement, view$: Observable<RegionSourceView | null>, size?: SvgSize);
57
+ /** Follow the camera: rewrite the transform now, re-plan the tiles once it settles. */
58
+ setCamera(affine: Affine): void;
59
+ /** Show or hide the source with the regions. */
60
+ setVisible(visible: boolean): void;
61
+ /**
62
+ * The source feature under world point (x, y) — inside an area, or within `tolerancePx`
63
+ * screen pixels of a polyline — from the features drawn; the innermost of nested ones.
64
+ */
65
+ featureAt(x: number, y: number, tolerancePx?: number): TileFeature | null;
66
+ /** The drawn source features whose box meets the world box (the rubber band's rule). */
67
+ featuresInRect(x0: number, y0: number, x1: number, y1: number): TileFeature[];
68
+ destroy(): void;
69
+ private setView;
70
+ /** The layer is the svg's first child (under the regions) while it shows a source. */
71
+ private attach;
72
+ private applyCamera;
73
+ /** Screen px per world unit. */
74
+ private scale;
75
+ /** The world box in view, padded by the margin; null when the svg has no size yet. */
76
+ private viewRect;
77
+ /** Work out the tiles the view needs, draw what is loaded, and load the rest. */
78
+ private replan;
79
+ private keep;
80
+ private scheduleDraw;
81
+ /**
82
+ * Rebuild the paths from the wanted tiles that are loaded, a missing tile's nearest loaded
83
+ * ancestor standing in for it; each feature once, at the finest level loaded.
84
+ */
85
+ private draw;
86
+ /**
87
+ * The drawn features as paths: one per colour when outlined; filled, in paint order — parents
88
+ * (by the class hierarchy) and then larger features first, so what lies inside paints over
89
+ * them — one path per run of a colour.
90
+ */
91
+ private runs;
92
+ /** Class labels inside the drawn features (each part where it fits), when labels are on. */
93
+ private drawLabels;
94
+ /** The loaded tile for `key`, else its nearest loaded coarser ancestor. */
95
+ private loadedOrAncestor;
96
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * How regions are drawn, shared by the OpenSeadragon and napari overlays and the region-source
3
+ * layer, so a feature looks the same before and after it is taken into the regions.
4
+ *
5
+ * Two looks: **outlines** (the default — each region stroked in its colour, filled only while
6
+ * selected) and **filled**, an atlas's look (each region filled in its colour, with thin outlines,
7
+ * the selection in a highlight colour, labels centred inside each part).
8
+ */
9
+ import { Region } from '../models/region';
10
+ import type { Project, ScreenLayer } from './svg-region-renderer';
11
+ /** The region look (see the module doc). */
12
+ export interface RegionStyle {
13
+ /** Fill each region at this opacity; 0 draws outlines only. */
14
+ fillOpacity: number;
15
+ /** Outline colour of a filled region; null: its own colour. */
16
+ stroke: string | null;
17
+ /** Outline width of a filled region, screen px; null: 1. */
18
+ strokeWidth: number | null;
19
+ /** Fill colour of a selected filled region; null: {@link DEFAULT_HIGHLIGHT}. */
20
+ highlight: string | null;
21
+ }
22
+ export declare const DEFAULT_REGION_STYLE: RegionStyle;
23
+ /** A selected region's fill in the filled look, unless the style names one (the Allen atlas's). */
24
+ export declare const DEFAULT_HIGHLIGHT = "#a020f0";
25
+ /** Whether `style` is the filled look. */
26
+ export declare function isFilled(style: RegionStyle): boolean;
27
+ /** The paint of one region shape. */
28
+ export interface ShapePaint {
29
+ fill: string;
30
+ fillOpacity: number;
31
+ stroke: string;
32
+ strokeWidth: number;
33
+ }
34
+ /** The paint of a region of colour `color`, selected or not, in `style`. */
35
+ export declare function shapePaint(color: string, selected: boolean, style?: RegionStyle): ShapePaint;
36
+ /** Set `paint` on an SVG shape. */
37
+ export declare function applyPaint(el: SVGElement, paint: ShapePaint): void;
38
+ /** A point to label a part at, and the room around it (image px). */
39
+ export interface LabelSpot {
40
+ x: number;
41
+ y: number;
42
+ room: number;
43
+ }
44
+ /** Where to label `region`: each part's pole of inaccessibility (a rectangle's centre). */
45
+ export declare function regionLabelSpots(region: Region): LabelSpot[];
46
+ /**
47
+ * A class label centred at `spot`, shown only while it fits: the room around the spot, on screen,
48
+ * at least half the text's width (and a few pixels). Re-checked on every camera move.
49
+ */
50
+ export declare function placeInsideLabel(layer: ScreenLayer, text: string, spot: LabelSpot, color?: string): SVGTextElement;
51
+ /** Whether a label `halfWidth` px wide fits around `spot` through `project`. */
52
+ export declare function labelFits(project: Project, spot: LabelSpot, halfWidth: number): boolean;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * A {@link RegionSource} served over HTTP, by a server that tiles a region set as `region-tiles`
3
+ * does (the example tile server's `/regions/…` routes). Relative to the source's base URL:
4
+ *
5
+ * - `GET info` → {@link RegionSourceInfo}
6
+ * - `GET tile/{z}/{level}/{gx}/{gy}` → `{ features: WireTileFeature[] }`
7
+ * - `POST features` `{ ids }` → `{ features: SourceFeature[] }`
8
+ * - `POST index` `{ z, ...query }` → {@link RegionIndexPage}
9
+ * - `POST classes` `{ z, exclude }` → features per class on plane z
10
+ * - `POST outlines` `{ classes, level, exclude }` → `{ slices: [{ z, rings }] }`
11
+ * - `POST export` `{ exclude, extra }`→ a GeoJSON FeatureCollection
12
+ *
13
+ * Tile rings travel as flat `[x, y, x, y, …]` arrays, label points as flat `[x, y, room, …]`.
14
+ *
15
+ * Given the host's Angular `HttpClient` (as the visualizer passes it), every request goes through
16
+ * it, so the host's interceptors apply — its auth header above all — as for the image tiles and
17
+ * the spatial data. The library itself knows nothing of authentication.
18
+ */
19
+ import type { HttpClient } from '@angular/common/http';
20
+ import { RegionSource } from './region-source';
21
+ import type { Bbox } from './region-tiles';
22
+ /** A tile feature on the wire: rings as plain arrays. */
23
+ export interface WireTileFeature {
24
+ id: string;
25
+ label: string | null;
26
+ color: string | null;
27
+ bbox: Bbox;
28
+ rings: number[][];
29
+ open?: boolean;
30
+ labels?: number[];
31
+ }
32
+ /** Options of {@link openHttpRegionSource}. */
33
+ export interface HttpRegionSourceOptions {
34
+ /**
35
+ * The host's `HttpClient`: requests then go through it and its interceptors (the host's auth),
36
+ * not `fetch`, and `init` and `fetch` are not used.
37
+ */
38
+ http?: HttpClient;
39
+ /** Extra request options (credentials, headers) for every `fetch` request. */
40
+ init?: RequestInit;
41
+ /** The fetch to use (default the global one). */
42
+ fetch?: typeof fetch;
43
+ }
44
+ /** Open the region source at `baseUrl` (its `info` is fetched first). */
45
+ export declare function openHttpRegionSource(baseUrl: string, options?: HttpRegionSourceOptions): Promise<RegionSource>;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The region-source worker's protocol and the tables it holds, shared by the worker and the
3
+ * main-thread fallback (which runs the very same {@link RegionSourceTables} where no worker can
4
+ * start).
5
+ *
6
+ * Protocol: `{ id, op, ...args }` → `{ id, ok: true, result }` | `{ id, ok: false, error }`.
7
+ */
8
+ import { ReconstructOptions, SliceOutlines } from '../geometry/reconstruct';
9
+ import type { Mesh } from 'napari-js/geometry';
10
+ import { ClassOutlines, RegionIndexPage, RegionIndexQuery, RegionSourceInfo, RegionTile } from './region-tiles';
11
+ import type { SourceFeature } from './region-source';
12
+ export type RegionSourceRequest = {
13
+ op: 'open';
14
+ text: string;
15
+ tileSize?: number;
16
+ } | {
17
+ op: 'tile';
18
+ handle: number;
19
+ z: number;
20
+ level: number;
21
+ gx: number;
22
+ gy: number;
23
+ } | {
24
+ op: 'features';
25
+ handle: number;
26
+ ids: readonly string[];
27
+ } | {
28
+ op: 'index';
29
+ handle: number;
30
+ z: number;
31
+ query: RegionIndexQuery;
32
+ } | {
33
+ op: 'classes';
34
+ handle: number;
35
+ z: number | null;
36
+ exclude?: readonly string[];
37
+ } | {
38
+ op: 'outlines';
39
+ handle: number;
40
+ classes: readonly string[] | null;
41
+ level: number;
42
+ exclude?: readonly string[];
43
+ } | {
44
+ op: 'mesh';
45
+ slices: readonly SliceOutlines[];
46
+ options?: ReconstructOptions;
47
+ } | {
48
+ op: 'export';
49
+ handle: number;
50
+ exclude: readonly string[];
51
+ extra: readonly object[];
52
+ } | {
53
+ op: 'close';
54
+ handle: number;
55
+ };
56
+ export interface RegionSourceResults {
57
+ open: {
58
+ handle: number;
59
+ info: RegionSourceInfo;
60
+ };
61
+ tile: RegionTile;
62
+ features: SourceFeature[];
63
+ index: RegionIndexPage;
64
+ classes: Record<string, number>;
65
+ outlines: ClassOutlines[];
66
+ mesh: Mesh;
67
+ export: string;
68
+ close: null;
69
+ }
70
+ export type RegionSourceMessage = RegionSourceRequest & {
71
+ id: number;
72
+ };
73
+ export type RegionSourceReply = {
74
+ id: number;
75
+ ok: true;
76
+ result: unknown;
77
+ } | {
78
+ id: number;
79
+ ok: false;
80
+ error: string;
81
+ };
82
+ /** The open tables, by handle. */
83
+ export declare class RegionSourceTables {
84
+ private readonly tables;
85
+ private nextHandle;
86
+ run<R extends RegionSourceRequest>(request: R): RegionSourceResults[R['op']];
87
+ private dispatch;
88
+ private table;
89
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Factory for the region-source Web Worker, isolated in its own module so the `import.meta.url`
3
+ * reference — which the bundler needs in order to locate the worker — is never pulled into the
4
+ * ts-jest CommonJS compile of anything that uses it. Same arrangement as
5
+ * `workers/spatial-math-worker.ts`.
6
+ */
7
+ export declare function createRegionSourceWorker(): Worker;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * A tiled region source: one image's large region set, served as level-of-detail tiles so a view
3
+ * never holds or draws the whole set (see `region-tiles` for the levels and tiles).
4
+ *
5
+ * Two implementations behind {@link RegionSource}: a GeoJSON source parsed and tiled in a Web
6
+ * Worker (`openGeoJsonRegionSource`, the main thread only ever sees tiles), and an HTTP source
7
+ * for a server that serves the same tiles (`openHttpRegionSource`).
8
+ */
9
+ import type { ClassOutlines, GeoJsonFeatureLike, RegionIndexPage, RegionIndexQuery, RegionSourceInfo, RegionTile, RegionTileKey, TileFeature } from './region-tiles';
10
+ import type { RegionStyle } from '../region-overlay/region-style';
11
+ /** A feature's exact GeoJSON with the source's id for it. */
12
+ export interface SourceFeature {
13
+ id: string;
14
+ feature: GeoJsonFeatureLike;
15
+ }
16
+ /** One image's tiled region set. */
17
+ export interface RegionSource {
18
+ /** What the source holds; known once it is open. */
19
+ readonly info: RegionSourceInfo;
20
+ /** One tile of plane `z`. Cached: asking again for a tile in view costs nothing. */
21
+ getTile(z: number, key: RegionTileKey, signal?: AbortSignal): Promise<RegionTile>;
22
+ /** The exact features with these ids (unknown ids are skipped). */
23
+ getFeatures(ids: readonly string[]): Promise<SourceFeature[]>;
24
+ /** A page of plane `z`'s feature index. */
25
+ getIndex(z: number, query: RegionIndexQuery): Promise<RegionIndexPage>;
26
+ /**
27
+ * Every plane's outlines of the features of these classes, simplified for `level`, without the
28
+ * `exclude`d ids: what a 3D reconstruction of the classes stacks. `classes` null reads every
29
+ * class, each outline labelled with its own (what a section through the stack draws).
30
+ */
31
+ getClassOutlines(classes: readonly string[] | null, level: number, exclude?: readonly string[]): Promise<ClassOutlines[]>;
32
+ /**
33
+ * How many features of each class plane `z` has (null: every plane, the whole stack), without
34
+ * the `exclude`d ids.
35
+ */
36
+ getClassCounts(z: number | null, exclude?: readonly string[]): Promise<Record<string, number>>;
37
+ /**
38
+ * The whole set as a GeoJSON FeatureCollection string, through the working set: `exclude`d
39
+ * features (taken for editing, or deleted) left out, `extra` features appended.
40
+ */
41
+ exportGeoJson(exclude: readonly string[], extra: readonly object[]): Promise<string>;
42
+ /** Release the source (its worker table, its cache). */
43
+ dispose(): void;
44
+ }
45
+ /** What the store shows of the current slice's region source: what a source layer draws. */
46
+ export interface RegionSourceView {
47
+ source: RegionSource;
48
+ /** The source plane the slice shows. */
49
+ plane: number;
50
+ /** Ids the source no longer draws: taken into the working set, or deleted. */
51
+ taken: ReadonlySet<string>;
52
+ /** The colour a feature is drawn in (its class colour, as a region of that class gets). */
53
+ colorOf(feature: Pick<TileFeature, 'label' | 'color'>): string;
54
+ /** The region look, the regions' own (so a feature looks the same once taken). */
55
+ style: RegionStyle;
56
+ /** Whether class labels are shown. */
57
+ labels: boolean;
58
+ /** Whether a class's features are hidden (see `RegionStore.setClassesHidden`); default: none is. */
59
+ isHidden?(label: string | null | undefined): boolean;
60
+ }
61
+ /**
62
+ * ROI GeoJSON at least this many characters long loads as a tiled region source rather than as
63
+ * regions (see `VizConfig.regionSourceMinChars`).
64
+ */
65
+ export declare const REGION_SOURCE_MIN_CHARS = 1000000;
66
+ /** Tiles a source keeps, most recently used last. */
67
+ export declare const REGION_TILE_CACHE_SIZE = 384;
68
+ /** A least-recently-used cache of tile requests. A request that fails is forgotten. */
69
+ export declare class RegionTileCache {
70
+ private readonly limit;
71
+ private readonly tiles;
72
+ constructor(limit?: number);
73
+ /** The cached tile, else `load()`'s, cached. */
74
+ get(z: number, key: RegionTileKey, load: () => Promise<RegionTile>): Promise<RegionTile>;
75
+ clear(): void;
76
+ }
77
+ /** An `AbortError`, as `fetch` and the workers reject with. */
78
+ export declare function abortError(): Error;
79
+ /** True for the rejection of an aborted request. */
80
+ export declare function isAbortError(err: unknown): boolean;
81
+ /** `promise`, rejected with an `AbortError` as soon as `signal` fires (the work goes on). */
82
+ export declare function abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T>;
@@ -0,0 +1,289 @@
1
+ /** An axis-aligned box `[x0, y0, x1, y1]` in image pixels. */
2
+ export type Bbox = [number, number, number, number];
3
+ /** Edge of a level-0 tile, in image pixels. */
4
+ export declare const REGION_TILE_SIZE = 512;
5
+ /**
6
+ * One class of a class hierarchy (e.g. a brain-atlas ontology): the class name the features use,
7
+ * its long name, its parent class and its colour. A region set may carry one (a GeoJSON
8
+ * FeatureCollection's `classHierarchy` member); the Region Editor then lists the set as a tree.
9
+ */
10
+ export interface RegionClassNode {
11
+ /** The class name, as features use it (`classification.name`): an atlas acronym, say. */
12
+ name: string;
13
+ /** The long name, e.g. "Somatomotor areas, Layer 5". */
14
+ title?: string;
15
+ /** The parent class's name; absent for a root. */
16
+ parent?: string | null;
17
+ /** `#rrggbb`. */
18
+ color?: string;
19
+ /** Position among its siblings (an atlas's graph order); file order without one. */
20
+ order?: number;
21
+ }
22
+ /**
23
+ * How a region set wants to be drawn, a hint the viewer applies when the set opens (a GeoJSON
24
+ * FeatureCollection's `style` member): an atlas fills its structures and labels them.
25
+ */
26
+ export interface RegionSourceStyle {
27
+ /** Fill regions in their colour at this opacity (0 = outlines only). */
28
+ fillOpacity?: number;
29
+ /** Outline colour when filled (default: the region's colour). */
30
+ stroke?: string;
31
+ /** Outline width in screen px. */
32
+ strokeWidth?: number;
33
+ /** Show class labels inside the regions. */
34
+ labels?: boolean;
35
+ /** Fill colour of selected regions. */
36
+ highlight?: string;
37
+ }
38
+ /** What a region source holds, known once it is open. */
39
+ export interface RegionSourceInfo {
40
+ /** Features in the source, over every plane. */
41
+ featureCount: number;
42
+ /** The box around every feature's geometry; null when none has any. */
43
+ bounds: Bbox | null;
44
+ /** Edge of a level-0 tile, in image pixels. */
45
+ tileSize: number;
46
+ /** Number of levels; the last one's tiles cover {@link bounds} in a few tiles. */
47
+ levels: number;
48
+ /** The z planes features are on (QuPath's `geometry.plane.z`, 0 without one), ascending. */
49
+ planes: number[];
50
+ /** The colour the file gives each class (its first feature's), by class name. */
51
+ classColors: Record<string, string>;
52
+ /** The set's class hierarchy, when it has one. */
53
+ hierarchy?: RegionClassNode[];
54
+ /** How the set wants to be drawn, when it says. */
55
+ style?: RegionSourceStyle;
56
+ }
57
+ /** One feature as a tile carries it: identity, class and outline at the tile's level. */
58
+ export interface TileFeature {
59
+ id: string;
60
+ /** The class name. */
61
+ label: string | null;
62
+ /** The feature's own colour (`#rrggbb`), from its classification. */
63
+ color: string | null;
64
+ /** The box around the exact geometry. */
65
+ bbox: Bbox;
66
+ /** Rings as interleaved `x, y` (no repeated closing vertex): exteriors and holes of every
67
+ * part, drawn and hit-tested even-odd. For an open feature, its polylines. */
68
+ rings: Float32Array[];
69
+ /** A polyline (LineString) rather than an area. */
70
+ open: boolean;
71
+ /**
72
+ * Where to label the feature, per part big enough: `x, y, room` triples, `room` the distance
73
+ * from the point to the part's nearest edge (image px), so a label shows once it fits.
74
+ */
75
+ labels?: Float32Array;
76
+ }
77
+ /**
78
+ * A class's outlines on one plane: rings as interleaved `x, y` image px (holes included), and its
79
+ * open features' polylines, likewise (absent from a server that predates them). Read for every
80
+ * class at once, each ring's and line's class comes with it (`ringLabels`, `lineLabels`).
81
+ */
82
+ export interface ClassOutlines {
83
+ z: number;
84
+ rings: Float32Array[];
85
+ /**
86
+ * The feature each ring is part of (see SliceOutlines.ringGroups): a feature's rings fill
87
+ * even-odd, the features as their union. Absent from a server that predates them.
88
+ */
89
+ ringGroups?: number[];
90
+ lines?: Float32Array[];
91
+ ringLabels?: string[];
92
+ lineLabels?: string[];
93
+ }
94
+ /** One tile of one level of one plane. */
95
+ export interface RegionTile {
96
+ z: number;
97
+ level: number;
98
+ gx: number;
99
+ gy: number;
100
+ features: TileFeature[];
101
+ }
102
+ /** A tile's address. */
103
+ export interface RegionTileKey {
104
+ level: number;
105
+ gx: number;
106
+ gy: number;
107
+ }
108
+ /** One row of a source's feature index (the Region Editor's table). */
109
+ export interface RegionIndexRow {
110
+ id: string;
111
+ label: string | null;
112
+ color: string | null;
113
+ bbox: Bbox;
114
+ /** The area inside the exact outline (holes left out), image px²; 0 for a polyline. Absent from a
115
+ * server that predates it. */
116
+ area?: number;
117
+ }
118
+ /** A page of a plane's feature index. */
119
+ export interface RegionIndexPage {
120
+ /** Rows matching the query, over the whole plane. */
121
+ total: number;
122
+ rows: RegionIndexRow[];
123
+ }
124
+ /** Which rows a page of the index holds. */
125
+ export interface RegionIndexQuery {
126
+ offset: number;
127
+ limit: number;
128
+ /** Only rows whose class name contains this (case-insensitive). */
129
+ label?: string;
130
+ /** Leave these ids out (taken into the working set, or deleted). */
131
+ exclude?: readonly string[];
132
+ /** Only rows of exactly these classes. */
133
+ classes?: readonly string[];
134
+ }
135
+ /** The parts of a GeoJSON feature the tiler reads. Parsed from a file: nothing is guaranteed. */
136
+ export interface GeoJsonFeatureLike {
137
+ type?: string;
138
+ id?: string | number;
139
+ geometry?: {
140
+ type?: string;
141
+ coordinates?: unknown;
142
+ plane?: {
143
+ z?: number;
144
+ };
145
+ } | null;
146
+ properties?: {
147
+ id?: string | number;
148
+ classification?: unknown;
149
+ } & Record<string, unknown>;
150
+ }
151
+ /**
152
+ * The level whose tiles suit a zoom of `pxPerImagePx` screen pixels per image pixel: exact (0)
153
+ * at 1:1 and closer, else level k for zooms in [2⁻ᵏ, 2¹⁻ᵏ), where its tolerance is half to one
154
+ * screen pixel and the features it leaves out are under one or two.
155
+ */
156
+ export declare function regionLevelFor(pxPerImagePx: number, levels: number): number;
157
+ /** Simplification tolerance of a level, in image pixels (0 = exact). */
158
+ export declare function levelTolerance(level: number): number;
159
+ /** Features smaller than this (their box's longer side, image pixels) are left out of a level. */
160
+ export declare function levelMinExtent(level: number): number;
161
+ /** Tile edge of a level, in image pixels. */
162
+ export declare function levelTileSize(level: number, tileSize?: number): number;
163
+ /**
164
+ * Tiles of `level` that meet `rect`, clipped to `bounds` (none past the data), ordered from the
165
+ * rectangle's centre outward so the middle of the screen fills first. At most `limit`.
166
+ */
167
+ export declare function regionTilesInRect(rect: Bbox, level: number, tileSize: number, bounds: Bbox | null, limit?: number): RegionTileKey[];
168
+ /** `level/gx/gy`, a tile's id within one plane. */
169
+ export declare function regionTileId(k: RegionTileKey): string;
170
+ /** The tile of `level` holding image point (x, y). */
171
+ export declare function tileAt(x: number, y: number, level: number, tileSize?: number): RegionTileKey;
172
+ /** True when two boxes meet (edges included). */
173
+ export declare function bboxesMeet(a: Readonly<Bbox>, b: Readonly<Bbox>): boolean;
174
+ /**
175
+ * The feature under image point (x, y): inside an area (even-odd over its rings, so holes are
176
+ * outside) or within `tolerance` image pixels of a polyline. Of several, the one with the
177
+ * smallest box — the innermost of nested outlines. Null when none is.
178
+ */
179
+ export declare function featureAt(features: Iterable<TileFeature>, x: number, y: number, tolerance?: number): TileFeature | null;
180
+ /** Features whose box meets `rect` (the rubber band's rule for regions). */
181
+ export declare function featuresInRect(features: Iterable<TileFeature>, rect: Readonly<Bbox>): TileFeature[];
182
+ /** Even-odd containment over interleaved rings. */
183
+ export declare function insideRings(rings: readonly ArrayLike<number>[], x: number, y: number): boolean;
184
+ /** Douglas–Peucker over an open polyline (both ends kept). */
185
+ export declare function simplifyPolyline(xs: number[], ys: number[], epsilon: number): {
186
+ xs: number[];
187
+ ys: number[];
188
+ };
189
+ /**
190
+ * Rings simplified for a level: every ring through Douglas–Peucker at the level's tolerance,
191
+ * rings whose box is under the level's minimum extent dropped, and rings left with too few
192
+ * vertices to draw (3 for a closed ring, 2 for a polyline) dropped. Level 0 returns the rings
193
+ * as they are.
194
+ */
195
+ export declare function simplifyRings(rings: readonly Float64Array[], open: boolean, level: number): Float32Array[];
196
+ /**
197
+ * A parsed GeoJSON region set, indexed for tiles. Holds the raw features (for the exact
198
+ * geometry and the export), each feature's rings, box, plane and class, and builds a level's
199
+ * tile buckets the first time that level of a plane is asked for.
200
+ */
201
+ export declare class RegionFeatureTable {
202
+ readonly raw: GeoJsonFeatureLike[];
203
+ readonly tileSize: number;
204
+ readonly ids: string[];
205
+ readonly labels: Array<string | null>;
206
+ readonly colors: Array<string | null>;
207
+ readonly planes: number[];
208
+ readonly boxes: Bbox[];
209
+ readonly rings: Float64Array[][];
210
+ readonly open: boolean[];
211
+ /** Per feature, its parts as ring indices (the exterior first, then its holes). */
212
+ readonly parts: number[][][];
213
+ private readonly labelPoints;
214
+ /** Each feature's area, worked out the first time its row is asked for. */
215
+ private readonly areas;
216
+ private hierarchy?;
217
+ private style?;
218
+ private readonly byId;
219
+ private readonly buckets;
220
+ private readonly simplified;
221
+ private readonly bounds;
222
+ private readonly levels;
223
+ constructor(raw: GeoJsonFeatureLike[], tileSize?: number);
224
+ /** Parse a GeoJSON FeatureCollection string. Throws on invalid JSON or no `features`. */
225
+ static fromGeoJson(text: string, tileSize?: number): RegionFeatureTable;
226
+ /** Attach a class hierarchy and a style hint (each ignored when not well formed). */
227
+ describe(hierarchy?: unknown, style?: unknown): void;
228
+ /**
229
+ * The outlines of every feature of these classes, plane by plane, simplified for `level` (what a
230
+ * 3D reconstruction of the classes stacks), without the `exclude`d ids: closed features' rings,
231
+ * open features' polylines as `lines`, each ring with its feature (`ringGroups`). Planes without
232
+ * one are left out. `classes` null reads every labelled feature, each outline with its class
233
+ * (`ringLabels`, `lineLabels`).
234
+ */
235
+ classOutlines(classes: readonly string[] | null, level: number, exclude?: readonly string[]): ClassOutlines[];
236
+ /** Features per class on plane `z` (null: on every plane), without the `exclude`d ids. */
237
+ classCounts(z: number | null, exclude?: readonly string[]): Record<string, number>;
238
+ info(): RegionSourceInfo;
239
+ /** One tile of plane `z`. */
240
+ tile(z: number, level: number, gx: number, gy: number): RegionTile;
241
+ /** The raw GeoJSON features with these ids, in the order asked (unknown ids skipped). */
242
+ features(ids: readonly string[]): Array<{
243
+ id: string;
244
+ feature: GeoJsonFeatureLike;
245
+ }>;
246
+ /** Feature `i`'s area in px² (0 for a polyline). */
247
+ private areaOf;
248
+ /** A page of plane `z`'s features, in file order. */
249
+ index(z: number, query: RegionIndexQuery): RegionIndexPage;
250
+ /**
251
+ * The source as a GeoJSON FeatureCollection string, through the working set: features whose
252
+ * id is in `exclude` (taken for editing, or deleted) are left out, `extra` (the working set's
253
+ * features) appended. Every feature keeps an `id`; the set keeps its hierarchy and style.
254
+ */
255
+ exportGeoJson(exclude: readonly string[], extra: readonly object[]): string;
256
+ /**
257
+ * Feature `i`'s label points (one per part with room for a label at `level`: a part under the
258
+ * level's minimum extent is not drawn there), from the exact geometry, computed once.
259
+ */
260
+ private labelsAt;
261
+ /** Feature `i`'s rings at `level`, simplified once and cached. */
262
+ private ringsAt;
263
+ /** Entries in plane `z`'s level-`level` index: cell listings plus wide features (tests). */
264
+ indexEntries(z: number, level: number): number;
265
+ /**
266
+ * Plane `z`'s level-`level` index, built on first use: features by tile cell (`gx/gy` → feature
267
+ * indices), and the wide ones (more than {@link MAX_CELLS_PER_FEATURE} cells, or past the
268
+ * number range), tested against a tile when it is asked for.
269
+ */
270
+ private bucketsFor;
271
+ }
272
+ /**
273
+ * A feature spanning more tiles than this is not listed in each of them but kept aside and tested
274
+ * against a tile when one is asked for: one huge box (an outline around a whole slide, or a corrupt
275
+ * coordinate) must not make a plane's index millions of entries.
276
+ */
277
+ export declare const MAX_CELLS_PER_FEATURE = 64;
278
+ /** A feature's own id (`id`, else `properties.id`) as a string. */
279
+ export declare function featureIdOf(feature: GeoJsonFeatureLike): string | undefined;
280
+ /**
281
+ * A FeatureCollection string of `features` (each a feature's JSON), with the set's class hierarchy
282
+ * and style as its `classHierarchy` and `style` members when it has them: what
283
+ * {@link RegionFeatureTable.fromGeoJson} reads back.
284
+ */
285
+ export declare function featureCollectionJson(features: readonly string[], hierarchy?: readonly RegionClassNode[], style?: RegionSourceStyle): string;
286
+ /** A well-formed class hierarchy from a file (colours as `#rrggbb` or `[r, g, b]`), else undefined. */
287
+ export declare function readHierarchy(raw: unknown): RegionClassNode[] | undefined;
288
+ /** A well-formed style hint from a file, else undefined. */
289
+ export declare function readStyle(raw: unknown): RegionSourceStyle | undefined;