Files
Web_FreeCAD_Bitbybit/public/chrome-native-loft-history-harness.html

37 lines
4.5 KiB
HTML

<!doctype html>
<meta charset="utf-8">
<title>Chrome native Loft history</title>
<pre id="result">running</pre>
<script type="module">
import { BitbybitGeometryRuntime } from '/src/facade/geometryRuntime.ts'
import { NativeOcctHistoryWorkerProvider } from '/src/facade/nativeHistoryWorkerClient.ts'
const output = document.querySelector('#result')
const report = { schemaVersion: 1, browserId: 'chrome', crossOriginIsolated: globalThis.crossOriginIsolated === true, status: 'running' }
let runtime, provider, first, second, result
try {
const [firstStep, secondStep] = await Promise.all([
fetch('/native-loft-first.step').then((response) => response.ok ? response.text() : Promise.reject(new Error(`First Loft fixture failed: ${response.status}`))),
fetch('/native-loft-second.step').then((response) => response.ok ? response.text() : Promise.reject(new Error(`Second Loft fixture failed: ${response.status}`))),
])
runtime = new BitbybitGeometryRuntime(); const capabilities = await runtime.initialize()
provider = new NativeOcctHistoryWorkerProvider({ moduleUrl: '/native/occt-history/bitbybit-occt-history.js' }); const nativeCapabilities = await provider.initialize(); runtime.configureNativeHistory(provider)
const context = { documentId: 'chrome-native-loft', documentVersion: 1 }
first = await runtime.importShape({ ...context, format: 'step', text: firstStep })
second = await runtime.importShape({ ...context, format: 'step', text: secondStep })
result = await runtime.loft({ ...context, sections: [
{ outer: [[0, 0, 0], [2, 0, 0], [2, 2, 0], [0, 2, 0]] },
{ outer: [[0, 0, 5], [2, 0, 5], [2, 2, 5], [0, 2, 5]] },
], mode: 'standalone', ruled: false, closed: false })
const records = await runtime.topologyHistory({ ...context, operationId: 'chrome-native-loft-history', operation: 'loft', inputs: [{ objectId: 'FirstSection', shape: first }, { objectId: 'SecondSection', shape: second }], ruled: false, result })
const [quality, mass] = await Promise.all([runtime.qualityReport(result), runtime.massProperties(result)])
const relations = { modified: records.filter((entry) => entry.relation === 'modified').length, generated: records.filter((entry) => entry.relation === 'generated').length, deleted: records.filter((entry) => entry.relation === 'deleted').length }
const directory = await navigator.storage.getDirectory(); const markerName = 'native-loft-history-marker.json'; const marker = await directory.getFileHandle(markerName, { create: true }); const writable = await marker.createWritable(); await writable.write(JSON.stringify({ operation: 'loft', sections: 2, ruled: false })); await writable.close(); const markerPayload = JSON.parse(await (await marker.getFile()).text()); await directory.removeEntry(markerName)
report.capabilities = capabilities; report.nativeCapabilities = nativeCapabilities; report.history = { recordCount: records.length, relations, sourceObjects: [...new Set(records.map((entry) => entry.sourceObjectId))].sort() }; report.result = { bitbybitStructuralValid: quality.structuralValid, bitbybitSolids: quality.solids, bitbybitVolume: mass.volume }; report.opfs = { markerPayload, markerRemoved: true }
await runtime.release(result); result = undefined; await runtime.release(second); second = undefined; await runtime.release(first); first = undefined; report.afterRelease = { shapeCount: runtime.capabilities().shapeCount, kernelReferenceCount: runtime.capabilities().kernelReferenceCount }
report.status = report.crossOriginIsolated && capabilities.status === 'ready' && nativeCapabilities.operations.includes('loft') && records.length > 0 && relations.generated > 0 && report.history.sourceObjects.includes('FirstSection') && report.history.sourceObjects.includes('SecondSection') && quality.solids === 1 && Math.abs(mass.volume - 20) < 1e-7 && markerPayload.sections === 2 && report.afterRelease.shapeCount === 0 && report.afterRelease.kernelReferenceCount === 0 ? 'pass' : 'failed'
} catch (error) { report.status = 'failed'; report.error = error instanceof Error ? error.stack || error.message : String(error) }
finally { if (result) await runtime?.release(result).catch(() => {}); if (second) await runtime?.release(second).catch(() => {}); if (first) await runtime?.release(first).catch(() => {}); provider?.dispose(); runtime?.dispose() }
output.textContent = JSON.stringify(report, null, 2); await fetch('/__native-loft-history-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }); if (report.status !== 'pass') throw new Error(report.error || 'failed')
</script>