Files
Web_FreeCAD_Bitbybit/public/chrome-sketcher-bspline-harness.html

90 lines
6.2 KiB
HTML

<!doctype html>
<meta charset="utf-8">
<title>Chrome Sketcher B-spline editor harness</title>
<pre id="result">running</pre>
<script type="module">
import { createSketch, editSketchBspline, sketchGeometrySignature } from '/src/facade/sketcher.ts'
import { inspectFcstdArchive, serializeFcstdMetadataArchive } from '/src/facade/fcstd.ts'
const output = document.querySelector('#result')
const report = { schemaVersion: 1, browserId: 'chrome', crossOriginIsolated: globalThis.crossOriginIsolated === true, status: 'running' }
const source = createSketch('chrome-bspline', [{ id: 'spline', type: 'bspline', degree: 2, controlPoints: [{ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 3, y: 0 }], weights: [1, 1, 1], knots: [0, 0, 0, 1, 1, 1] }])
const errorFor = (patch) => {
try {
editSketchBspline(source, 'spline', patch)
return null
} catch (error) {
return error instanceof Error ? error.message : String(error)
}
}
try {
const edited = editSketchBspline(source, 'spline', {
degree: 1,
controlPoints: [{ x: 0, y: 0 }, { x: 2, y: 3 }, { x: 4, y: 0 }],
weights: [1, 0.5, 1],
knots: [0, 0, 0.5, 1, 1],
periodic: true,
})
const editedGeometry = edited.geometry[0]
const sourceGeometry = source.geometry[0]
const constrained = createSketch('Sketch', [{
id: 'weighted-spline', type: 'bspline', degree: 3,
controlPoints: [{ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 3, y: 2 }, { x: 4, y: 0 }],
weights: [1, 1.5, 1.25, 1], knots: [0, 0, 0, 0, 1, 1, 1, 1], periodic: false,
}], [
{ id: 'middle-weight', type: 'weight', geometryId: 'weighted-spline', controlPointIndex: 1, value: 1.5, driving: true },
{ id: 'third-alignment', type: 'internalAlignment', geometryId: 'weighted-spline', internalGeometryIndex: 2, alignmentType: 'bspline-control-point', driving: true },
{ id: 'third-weight', type: 'weight', geometryId: 'weighted-spline', controlPointIndex: 2, value: 1.25, driving: true },
])
const document = {
id: 'chrome-bspline-fcstd', label: 'B-spline round-trip', version: 1, dirty: true, readOnly: false, units: 'mm',
tree: [{ id: 'Sketch', label: 'Sketch', type: 'sketch', state: 'valid' }],
objects: [{ id: 'Sketch', typeId: 'Sketcher::SketchObject', properties: [], sketch: constrained }],
dependencies: [], recompute: { generation: 0, status: 'idle', objectStates: { Sketch: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] },
}
const archive = serializeFcstdMetadataArchive(document)
const restored = inspectFcstdArchive(archive).objects[0]?.sketch
const markerDirectory = await navigator.storage.getDirectory()
const markerName = 'sketcher-bspline-chrome-marker.json'
const marker = await markerDirectory.getFileHandle(markerName, { create: true })
const writable = await marker.createWritable()
await writable.write(JSON.stringify({ suite: 'SK-10', fields: 8 }))
await writable.close()
const markerPayload = JSON.parse(await (await marker.getFile()).text())
await markerDirectory.removeEntry(markerName)
let markerRemoved = false
try { await markerDirectory.getFileHandle(markerName) } catch (error) { markerRemoved = error?.name === 'NotFoundError' }
report.edit = {
stableId: editedGeometry?.id === 'spline',
degree: editedGeometry?.type === 'bspline' ? editedGeometry.degree : null,
poleCount: editedGeometry?.type === 'bspline' ? editedGeometry.controlPoints.length : 0,
middlePole: editedGeometry?.type === 'bspline' ? editedGeometry.controlPoints[1] : null,
weights: editedGeometry?.type === 'bspline' ? editedGeometry.weights : null,
knots: editedGeometry?.type === 'bspline' ? editedGeometry.knots : null,
periodic: editedGeometry?.type === 'bspline' ? editedGeometry.periodic === true : false,
sourceUnchanged: sketchGeometrySignature(sourceGeometry) === JSON.stringify({ id: 'spline', type: 'bspline', degree: 2, controlPoints: [{ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 3, y: 0 }], weights: [1, 1, 1], knots: [0, 0, 0, 1, 1, 1] }),
}
report.validationErrors = {
invalidWeight: errorFor({ weights: [1, 0, 1] }),
invalidKnots: errorFor({ knots: [0, 1] }),
invalidDegree: errorFor({ degree: 3 }),
}
report.roundTrip = {
archiveBytes: archive.byteLength,
geometryEqual: JSON.stringify(restored?.geometry) === JSON.stringify(constrained.geometry),
constraintsEqual: JSON.stringify(restored?.constraints) === JSON.stringify(constrained.constraints),
constraintTypes: restored?.constraints.map((constraint) => constraint.type) ?? [],
weights: restored?.geometry[0]?.type === 'bspline' ? restored.geometry[0].weights : null,
knots: restored?.geometry[0]?.type === 'bspline' ? restored.geometry[0].knots : null,
}
report.opfs = { markerSuite: markerPayload.suite, markerFields: markerPayload.fields, markerRemoved }
report.status = report.crossOriginIsolated && report.edit.stableId && report.edit.degree === 1 && report.edit.poleCount === 3 && report.edit.middlePole?.x === 2 && report.edit.middlePole?.y === 3 && JSON.stringify(report.edit.weights) === JSON.stringify([1, 0.5, 1]) && JSON.stringify(report.edit.knots) === JSON.stringify([0, 0, 0.5, 1, 1]) && report.edit.periodic && report.edit.sourceUnchanged && /weights/.test(report.validationErrors.invalidWeight ?? '') && /knots/.test(report.validationErrors.invalidKnots ?? '') && /degree \+ 1/.test(report.validationErrors.invalidDegree ?? '') && report.roundTrip.archiveBytes > 0 && report.roundTrip.geometryEqual && report.roundTrip.constraintsEqual && JSON.stringify(report.roundTrip.constraintTypes) === JSON.stringify(['weight', 'internalAlignment', 'weight']) && JSON.stringify(report.roundTrip.weights) === JSON.stringify([1, 1.5, 1.25, 1]) && JSON.stringify(report.roundTrip.knots) === JSON.stringify([0, 0, 0, 0, 1, 1, 1, 1]) && report.opfs.markerSuite === 'SK-10' && report.opfs.markerFields === 8 && report.opfs.markerRemoved ? 'pass' : 'failed'
} catch (error) {
report.status = 'failed'
report.error = error instanceof Error ? error.message : String(error)
}
output.textContent = JSON.stringify(report, null, 2)
await fetch('/__chrome-sketcher-bspline-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) })
if (report.status !== 'pass') throw new Error(report.error || 'Chrome Sketcher B-spline harness failed.')
</script>