Skip to content

Commit

Permalink
WIP: test(mesh-io): browser readPointSet test
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Oct 2, 2024
1 parent b786dfd commit 6d1142c
Show file tree
Hide file tree
Showing 9 changed files with 2,064 additions and 937 deletions.
7 changes: 7 additions & 0 deletions packages/mesh-io/typescript/cypress/e2e/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ export function verifyMesh (mesh) {
cy.expect(mesh.numberOfPoints).to.equal(2903)
cy.expect(mesh.numberOfCells).to.equal(3263)
}

export function verifyPointSet (pointSet) {
cy.expect(pointSet.pointSetType.dimension).to.equal(3)
cy.expect(pointSet.pointSetType.pointComponentType).to.equal(FloatTypes.Float32)
cy.expect(pointSet.pointSetType.pointPixelType).to.equal(PixelTypes.Vector)
cy.expect(pointSet.numberOfPoints).to.equal(8)
}
90 changes: 90 additions & 0 deletions packages/mesh-io/typescript/cypress/e2e/read-point-set.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { demoServer, verifyPointSet } from "./common.ts";

describe("read-point-set", () => {
beforeEach(function () {
cy.visit(demoServer);

const testPathPrefix = "../test/data/input/";

const testImageFiles = ["box-points.obj"];
testImageFiles.forEach((fileName) => {
cy.readFile(`${testPathPrefix}${fileName}`, null).as(fileName);
});
});

it("Reads an point set File in the demo", function () {
cy.get('sl-tab[panel="readPointSet-panel"]').click();

const testFile = {
contents: new Uint8Array(this["box-points.obj"]),
fileName: "box-points.obj",
};
cy.get(
'#readPointSetInputs input[name="serialized-point-set-file"]',
).selectFile([testFile], { force: true });
cy.get("#readPointSet-serialized-point-set-details").should(
"contain",
"35,32",
);

cy.get('#readPointSetInputs sl-button[name="run"]').click();

cy.get("#readPointSet-point-set-details").should("contain", "pointSetType");
});

it("Reads an pointSet BinaryFile", function () {
cy.window().then(async (win) => {
const arrayBuffer = new Uint8Array(this["box-points.obj"]).buffer;
const { pointSet, webWorker } = await win.meshIo.readPointSet({
data: new Uint8Array(arrayBuffer),
path: "box-points.obj",
});
webWorker.terminate();
verifyPointSet(pointSet);
});
});

it("Reads an pointSet File", function () {
cy.window().then(async (win) => {
const arrayBuffer = new Uint8Array(this["box-points.obj"]).buffer;
const cowFile = new win.File([arrayBuffer], "box-points.obj");
const { pointSet, webWorker } = await win.meshIo.readPointSet(cowFile);
webWorker.terminate();
verifyPointSet(pointSet);
});
});

it("Reads re-uses a WebWorker", function () {
cy.window().then(async (win) => {
const arrayBuffer = new Uint8Array(this["box-points.obj"]).buffer;
const cowFile = new win.File([arrayBuffer], "box-points.obj");
const { webWorker } = await win.meshIo.readPointSet(cowFile);
const { pointSet } = await win.meshIo.readPointSet(cowFile, {
webWorker,
});
webWorker.terminate();
verifyPointSet(pointSet);
});
});

it(
"Throws a catchable error for an invalid file",
{ defaultCommandTimeout: 120000 },
function () {
cy.window().then(async (win) => {
const invalidArray = new Uint8Array([21, 4, 4, 4, 4, 9, 5, 0, 82, 42]);
const invalidBlob = new win.Blob([invalidArray]);
const invalidFile = new win.File([invalidBlob], "invalid.file");
try {
const { webWorker, pointSet } =
await win.meshIo.readPointSet(invalidFile);
webWorker.terminate();
} catch (error) {
cy.expect(error.message).to.equal(
"Could not find IO for: invalid.file",
);
}
});
},
);
});
2,403 changes: 1,467 additions & 936 deletions packages/mesh-io/typescript/test/browser/demo-app/index.html

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions packages/mesh-io/typescript/test/browser/demo-app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ if (!params.has('functionName')) {

import './read-mesh-controller.js'
import './write-mesh-controller.js'
import './read-point-set-controller.js'
import './write-point-set-controller.js'
// End added content
import './byu-read-mesh-controller.js'
import './byu-write-mesh-controller.js'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default async function readImageLoadSampleInputs (model, preRun=false) {
export default async function readMeshLoadSampleInputs (model, preRun=false) {
const inputButton = document.querySelector('#readMeshInputs sl-button[name=serialized-mesh-file-button]')
if (!preRun) {
inputButton.loading = true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import * as meshIo from "../../../dist/index.js";
import readPointSetLoadSampleInputs, {
usePreRun,
} from "./read-point-set-load-sample-inputs.js";

class ReadPointSetModel {
inputs: Map<string, any>;
options: Map<string, any>;
outputs: Map<string, any>;

constructor() {
this.inputs = new Map();
this.options = new Map();
this.outputs = new Map();
}
}

class ReadPointSetController {
constructor(loadSampleInputs) {
this.loadSampleInputs = loadSampleInputs;

this.model = new ReadPointSetModel();
const model = this.model;

this.webWorker = null;

if (loadSampleInputs) {
const loadSampleInputsButton = document.querySelector(
"#readPointSetInputs [name=loadSampleInputs]",
);
loadSampleInputsButton.setAttribute("style", "display: block-inline;");
loadSampleInputsButton.addEventListener("click", async (event) => {
loadSampleInputsButton.loading = true;
await loadSampleInputs(model);
loadSampleInputsButton.loading = false;
});
}

// ----------------------------------------------
// Inputs
const serializedPointSetElement = document.querySelector(
"#readPointSetInputs input[name=serialized-point-set-file]",
);
serializedPointSetElement.addEventListener("change", async (event) => {
const dataTransfer = event.dataTransfer;
const files = event.target.files || dataTransfer.files;

const arrayBuffer = await files[0].arrayBuffer();
model.inputs.set("serializedPointSet", {
data: new Uint8Array(arrayBuffer),
path: files[0].name,
});
const details = document.getElementById(
"readPointSet-serialized-pointSet-details",
);
details.innerHTML = `<pre>${globalThis.escapeHtml(model.inputs.get("serializedPointSet").data.subarray(0, 50).toString() + " ...")}</pre>`;
details.disabled = false;
});

// ----------------------------------------------
// Options
const informationOnlyElement = document.querySelector(
"#readPointSetInputs sl-checkbox[name=information-only]",
);
informationOnlyElement.addEventListener("sl-change", (event) => {
model.options.set("informationOnly", informationOnlyElement.checked);
});

// ----------------------------------------------
// Outputs
const pointSetOutputDownload = document.querySelector(
"#readPointSetOutputs sl-button[name=point-set-download]",
);
pointSetOutputDownload.addEventListener("click", async (event) => {
event.preventDefault();
event.stopPropagation();
if (model.outputs.has("pointSet")) {
const pointSetDownloadFormat = document.getElementById(
"point-set-output-format",
);
const downloadFormat = pointSetDownloadFormat.value || "nrrd";
const fileName = `pointSet.${downloadFormat}`;
const { webWorker, serializedPointSet } = await meshIo.writePointSet(
model.outputs.get("pointSet"),
fileName,
);

webWorker.terminate();
globalThis.downloadFile(serializedPointSet, fileName);
}
});

const preRun = async () => {
if (!this.webWorker && loadSampleInputs && usePreRun) {
await loadSampleInputs(model, true);
await this.run();
}
};

const onSelectTab = async (event) => {
if (event.detail.name === "readPointSet-panel") {
const params = new URLSearchParams(window.location.search);
if (
!params.has("functionName") ||
params.get("functionName") !== "readPointSet"
) {
params.set("functionName", "readPointSet");
const url = new URL(document.location);
url.search = params;
window.history.replaceState(
{ functionName: "readPointSet" },
"",
url,
);
await preRun();
}
}
};

const tabGroup = document.querySelector("sl-tab-group");
tabGroup.addEventListener("sl-tab-show", onSelectTab);
function onInit() {
const params = new URLSearchParams(window.location.search);
if (
params.has("functionName") &&
params.get("functionName") === "readPointSet"
) {
tabGroup.show("readPointSet-panel");
preRun();
}
}
onInit();

const runButton = document.querySelector(
'#readPointSetInputs sl-button[name="run"]',
);
runButton.addEventListener("click", async (event) => {
event.preventDefault();

if (!model.inputs.has("serializedPointSet")) {
globalThis.notify(
"Required input not provided",
"serializedPointSet",
"danger",
"exclamation-octagon",
);
return;
}

try {
runButton.loading = true;

const t0 = performance.now();
const { couldRead, pointSet } = await this.run();
const t1 = performance.now();
globalThis.notify(
"readPointSet successfully completed",
`in ${t1 - t0} milliseconds.`,
"success",
"rocket-fill",
);

model.outputs.set("pointSet", pointSet);
pointSetOutputDownload.variant = "success";
pointSetOutputDownload.disabled = false;
const pointSetDetails = document.getElementById(
"readPointSet-point-set-details",
);
pointSetDetails.innerHTML = `<pre>${globalThis.escapeHtml(JSON.stringify(pointSet, globalThis.interfaceTypeJsonReplacer, 2))}</pre>`;
pointSetDetails.disabled = false;
const pointSetOutput = document.getElementById(
"readPointSet-point-set-details",
);
} catch (error) {
globalThis.notify(
"Error while running pipeline",
error.toString(),
"danger",
"exclamation-octagon",
);
throw error;
} finally {
runButton.loading = false;
}
});
}

async run() {
const options = Object.fromEntries(this.model.options.entries());
options.webWorker = this.webWorker;
const { webWorker, pointSet } = await meshIo.readPointSet(
{
data: this.model.inputs.get("serializedPointSet").data.slice(),
path: this.model.inputs.get("serializedPointSet").path,
},
options,
);
this.webWorker = webWorker;

return { pointSet };
}
}

const readPointSetController = new ReadPointSetController(
readPointSetLoadSampleInputs,
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default async function readPointSetLoadSampleInputs (model, preRun=false) {
const inputButton = document.querySelector('#readPointSetInputs sl-button[name=serialized-point-set-file-button]')
if (!preRun) {
inputButton.loading = true
}
const fileName = 'box-points.obj'
const inputResponse = await fetch(`https://bafybeigniwg5zquxmw5izw22absoqvxwrrezr6wv3hc3gbrvgs6ywv4mdq.ipfs.w3s.link/ipfs/bafybeigniwg5zquxmw5izw22absoqvxwrrezr6wv3hc3gbrvgs6ywv4mdq/input/${fileName}`)
const inputData = new Uint8Array(await inputResponse.arrayBuffer())
model.inputs.set('serializedPointSet', { data: inputData, path: fileName })
if (!preRun) {
const inputElement = document.getElementById('readPointSet-serialized-point-set-details')
inputElement.innerHTML = `<pre>${globalThis.escapeHtml(inputData.subarray(0, 50).toString())}</pre>`
inputElement.disabled = false
inputButton.loading = false
}

return model
}

export const usePreRun = true
Loading

0 comments on commit 6d1142c

Please sign in to comment.