Skip to content

Commit

Permalink
feat(remote-machine): pull image from child viewport
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulHax committed Sep 6, 2023
1 parent 1c0bd1a commit 9660a7d
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 167 deletions.
28 changes: 0 additions & 28 deletions packages/element/src/itk-remote-viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,6 @@ import { Image } from '@itk-viewer/remote-viewport/types.js';
import { ItkViewport } from './itk-viewport.js';
import './itk-camera.js';

const makeMultiscaleImage = (image: string) => {
if (image.endsWith('.tif')) {
return {
scaleCount: 1,
scale: 0,
};
}
return {
scaleCount: 8,
scale: 7,
};
};

@customElement('itk-remote-viewport')
export class ItkRemoteViewport extends ItkViewport {
@property({ type: Object, attribute: 'server-config' })
Expand Down Expand Up @@ -127,21 +114,6 @@ export class ItkRemoteViewport extends ItkViewport {
this.startConnection();
}

if (changedProperties.has('image')) {
if (this.image) {
const multiscaleImage = makeMultiscaleImage(this.image);
this.remote.send({
type: 'setMultiscaleImage',
image: multiscaleImage,
});

this.remote.send({
type: 'updateRenderer',
props: { image: this.image },
});
}
}

if (changedProperties.has('density')) {
this.remote.send({
type: 'updateRenderer',
Expand Down
4 changes: 3 additions & 1 deletion packages/element/src/itk-viewport.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { viewportMachine } from '@itk-viewer/viewer/viewport-machine.js';
import { createViewport } from '@itk-viewer/viewer/viewport.js';
import { LitElement, css, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { ActorRefFrom } from 'xstate';

@customElement('itk-viewport')
export class ItkViewport extends LitElement {
actor = createViewport();
actor: ActorRefFrom<typeof viewportMachine> = createViewport();

constructor() {
super();
Expand Down
24 changes: 12 additions & 12 deletions packages/element/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { ZarrMultiscaleSpatialImage } from '@itk-viewer/io/ZarrMultiscaleSpatialImage.js';
import { makePlaceholderMultiscaleImage } from '@itk-viewer/io/makePlaceholderMultiscaleImage.js';
import { ItkViewport } from './itk-viewport.js';

const imagePath = '/ome-ngff-prototypes/single_image/v0.4/zyx.ome.zarr';
const url = new URL(imagePath, document.location.origin);
const image = await ZarrMultiscaleSpatialImage.fromUrl(url);
// Remote image placeholders for FPS pyramid-scale switching
const makeMultiscaleImage = (image: string) => {
if (image.endsWith('.tif')) {
return makePlaceholderMultiscaleImage(image, 1);
}
return makePlaceholderMultiscaleImage(image, 8);
};

const imagePath = import.meta.env.VITE_IMAGE;
const image = makeMultiscaleImage(imagePath);

const viewerElement = document.querySelector('itk-viewer');
if (!viewerElement) throw new Error('Could not find element');
const viewer = viewerElement.getActor();

// const leftViewport = document.querySelector(
// '#left-viewport'
// ) as ItkViewport | null;
// if (!leftViewport) throw new Error('Could not find element');
// const leftV = leftViewport.getActor();
// viewer.send({ type: 'addViewport', viewport: leftV, name: 'left' });

const rightViewport = document.querySelector(
'#right-viewport'
'#right-viewport',
) as ItkViewport | null;
if (!rightViewport) throw new Error('Could not find element');
const rightV = rightViewport.getActor();
Expand Down
51 changes: 27 additions & 24 deletions packages/io/src/MultiscaleSpatialImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import { ReadonlyMat4 } from 'gl-matrix';

const imageDataFromChunksWorker = new Worker(
new URL('./ImageDataFromChunks.worker.js', import.meta.url),
{ type: 'module' }
{ type: 'module' },
);
const imageDataFromChunksWorkerPromise = new WebworkerPromise(
imageDataFromChunksWorker
imageDataFromChunksWorker,
);

function inflate(bounds: Bounds, delta: number) {
Expand Down Expand Up @@ -93,7 +93,7 @@ const ensure3dDirection = (d: Float64Array): ReadonlyMat3 => {
d[5],
d[6],
d[7],
d[8]
d[8],
);
}
// Pad 2D with Z dimension
Expand Down Expand Up @@ -164,7 +164,7 @@ export const worldBoundsToIndexBounds = ({
const fullIndexBoundsWithZCT = ensuredDims(
[0, 1] as [number, number],
CXYZT,
fullIndexBounds
fullIndexBounds,
);
if (!bounds) {
// no bounds, return full image
Expand All @@ -187,22 +187,22 @@ export const worldBoundsToIndexBounds = ({
] as const;
});
const ctBounds = (['c', 't'] as const).map(
(dim) => [dim, fullIndexBoundsWithZCT.get(dim)!] as const
(dim) => [dim, fullIndexBoundsWithZCT.get(dim)!] as const,
);
return new Map([...spaceBounds, ...ctBounds]);
};

function isContained(
benchmarkBounds: ReadOnlyDimensionBounds,
testedBounds: ReadOnlyDimensionBounds
testedBounds: ReadOnlyDimensionBounds,
) {
return Array.from(benchmarkBounds).every(
([dim, [benchmarkMin, benchmarkMax]]) => {
const testDimBounds = testedBounds.get(dim);
if (!testDimBounds) throw new Error('Dimension not found');
const [testedMin, testedMax] = testDimBounds;
return benchmarkMin <= testedMin && testedMax <= benchmarkMax;
}
},
);
}

Expand All @@ -222,7 +222,7 @@ function findImageInBounds({
}) {
const imagesAtScale = cache.get(scale) ?? [];
return imagesAtScale.find(({ bounds: cachedBounds }) =>
isContained(cachedBounds, bounds)
isContained(cachedBounds, bounds),
)?.image;
}

Expand Down Expand Up @@ -254,7 +254,7 @@ class MultiscaleSpatialImage {
constructor(
scaleInfos: Array<ScaleInfo>,
imageType: ImageType,
name = 'Image'
name = 'Image',
) {
this.scaleInfos = scaleInfos;
this.name = name;
Expand All @@ -267,7 +267,7 @@ class MultiscaleSpatialImage {
this.pixelArrayType = pixelType;
this.spatialDims = ['x', 'y', 'z'].slice(
0,
imageType.dimension
imageType.dimension,
) as SpatialDimensions;
this.cachedImages = new Map();
}
Expand Down Expand Up @@ -332,7 +332,7 @@ class MultiscaleSpatialImage {
dimension,
d1,
d2,
infoDirection[di1][di2]
infoDirection[di1][di2],
);
}
}
Expand All @@ -347,15 +347,15 @@ class MultiscaleSpatialImage {

/* Return a promise that provides the requested chunk at a given scale and
* chunk index. */
async getChunks(scale: number, cxyztArray: Array<Array<number>>) {
protected async getChunks(scale: number, cxyztArray: Array<Array<number>>) {
return this.getChunksImpl(scale, cxyztArray);
}

async getChunksImpl(
protected async getChunksImpl(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_scale: number,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_cxyztArray: Array<Array<number>>
_cxyztArray: Array<Array<number>>,
): Promise<Array<ArrayBuffer>> {
console.error('Override me in a derived class');
return [];
Expand All @@ -370,23 +370,23 @@ class MultiscaleSpatialImage {
]);

const start = new Map(
CXYZT.map((dim) => [dim, indexBounds.get(dim)?.[0] ?? 0])
CXYZT.map((dim) => [dim, indexBounds.get(dim)?.[0] ?? 0]),
);
const end = new Map(
CXYZT.map((dim) => [dim, (indexBounds.get(dim)?.[1] ?? 0) + 1])
CXYZT.map((dim) => [dim, (indexBounds.get(dim)?.[1] ?? 0) + 1]),
);

const arrayShape = new Map(
CXYZT.map((dim) => [dim, end.get(dim)! - start.get(dim)!])
CXYZT.map((dim) => [dim, end.get(dim)! - start.get(dim)!]),
);

const startXYZ = new Float32Array(
(['x', 'y', 'z'] as const).map((dim) => start.get(dim)!)
(['x', 'y', 'z'] as const).map((dim) => start.get(dim)!),
);
const origin = Array.from(
vec3
.transformMat4(vec3.create(), startXYZ, indexToWorld)
.slice(0, this.imageType.dimension)
.slice(0, this.imageType.dimension),
);

const chunkSizeWith1 = ensuredDims(1, CXYZT, chunkSize);
Expand Down Expand Up @@ -430,7 +430,7 @@ class MultiscaleSpatialImage {
};
const { pixelArray, ranges } = await imageDataFromChunksWorkerPromise.exec(
'imageDataFromChunks',
args
args,
);

const size = (['x', 'y', 'z'] as const)
Expand Down Expand Up @@ -483,7 +483,7 @@ class MultiscaleSpatialImage {
bounds: worldBounds,
fullIndexBounds: this.getIndexBounds(scale),
worldToIndex: mat4.invert(mat4.create(), indexToWorld),
})
}),
);

const cachedImage = findImageInBounds({
Expand All @@ -501,7 +501,10 @@ class MultiscaleSpatialImage {
getIndexBounds(scale: number) {
const { arrayShape } = this.scaleInfos[scale];
return new Map(
Array.from(arrayShape).map(([dim, size]) => [dim, [0, size - 1] as const])
Array.from(arrayShape).map(([dim, size]) => [
dim,
[0, size - 1] as const,
]),
);
}

Expand All @@ -515,10 +518,10 @@ class MultiscaleSpatialImage {
const imageBounds = ensuredDims(
[0, 1],
['x', 'y', 'z'],
this.getIndexBounds(scale)
this.getIndexBounds(scale),
);
const bounds = (['x', 'y', 'z'] as const).flatMap((dim) =>
imageBounds.get(dim)
imageBounds.get(dim),
) as Bounds;
inflate(bounds, 0.5);
return extentToBounds(bounds, indexToWorld);
Expand Down
52 changes: 52 additions & 0 deletions packages/io/src/makePlaceholderMultiscaleImage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { IntTypes, PixelTypes } from 'itk-wasm';

import MultiscaleSpatialImage from './MultiscaleSpatialImage.js';
import { Dimension } from './types.js';

const makeScaleInfo = (image: string) => {
return {
dims: ['x', 'y', 'z'] as ReadonlyArray<Dimension>,
pixelArrayMetadata: {
shape: [-1],
chunks: [-1],
dtype: 'uint8',
compressor: {
cname: 'raw',
blocksize: -1,
clevel: -1,
shuffle: -1,
},
},
name: image,
pixelArrayPath: '',
coords: new Map(),
ranges: [[-1, 0]],
direction: [],
axesNames: [],
chunkCount: new Map(),
chunkSize: new Map(),
arrayShape: new Map(),
};
};

export const makePlaceholderMultiscaleImage = (
name: string,
scaleCount: number,
) => {
const scaleInfos = Array.from({ length: scaleCount }, () =>
makeScaleInfo(name),
);
const imageType = {
dimension: 2,
componentType: IntTypes.UInt8,
pixelType: PixelTypes.Scalar,
components: 0,
};

const multiscaleImage = new MultiscaleSpatialImage(
scaleInfos,
imageType,
name,
);
return multiscaleImage;
};
1 change: 1 addition & 0 deletions packages/remote-viewport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"vite": "^4.4.9"
},
"dependencies": {
"@itk-viewer/io": "workspace:^",
"@itk-viewer/viewer": "workspace:^",
"@itk-wasm/htj2k": "^1.0.0",
"gl-matrix": "^3.4.3",
Expand Down
Loading

0 comments on commit 9660a7d

Please sign in to comment.