feat: close builder mutation and roundtrip evidence gaps
This commit is contained in:
@@ -258,6 +258,56 @@ try {
|
||||
if (!shape || !primitiveResaved.shapeResources.some((resource) => resource.path === shape.path && resource.status === 'available')) fail(`FreeCAD resave did not produce an available ${objectName}.Shape resource.`)
|
||||
}
|
||||
|
||||
const throughHoleDocument: DocumentSnapshot = {
|
||||
id: 'fcstd-native-part-cut-through-hole',
|
||||
label: 'FCStd native Part Cut through hole',
|
||||
version: 1,
|
||||
dirty: false,
|
||||
readOnly: false,
|
||||
units: 'mm',
|
||||
tree: ['Base', 'HoleTool', 'CutThroughHole'].map((id) => ({ id, label: id, type: 'feature', state: 'up-to-date' })),
|
||||
objects: [
|
||||
{ id: 'Base', typeId: 'Part::Box', properties: [
|
||||
{ name: 'Length', label: 'Length', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 20 },
|
||||
{ name: 'Width', label: 'Width', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 20 },
|
||||
{ name: 'Height', label: 'Height', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 10 },
|
||||
] },
|
||||
{ id: 'HoleTool', typeId: 'Part::Cylinder', properties: [
|
||||
{ name: 'Radius', label: 'Radius', group: 'Cylinder', scope: 'data', type: 'App::PropertyLength', value: 3 },
|
||||
{ name: 'Height', label: 'Height', group: 'Cylinder', scope: 'data', type: 'App::PropertyLength', value: 12 },
|
||||
{ name: 'Angle', label: 'Angle', group: 'Cylinder', scope: 'data', type: 'App::PropertyAngle', value: 360 },
|
||||
{ name: 'Placement', label: 'Placement', group: 'Base', scope: 'data', type: 'App::PropertyPlacement', value: { position: { x: 10, y: 10, z: -1 }, rotation: { axis: { x: 0, y: 0, z: 1 }, angle: 0 } } },
|
||||
] },
|
||||
{ id: 'CutThroughHole', typeId: 'Part::Cut', properties: [
|
||||
{ name: 'Base', label: 'Base', group: 'Boolean', scope: 'data', type: 'App::PropertyLink', value: 'Base' },
|
||||
{ name: 'Tool', label: 'Tool', group: 'Boolean', scope: 'data', type: 'App::PropertyLink', value: 'HoleTool' },
|
||||
{ name: 'Refine', label: 'Refine shape', group: 'Boolean', scope: 'data', type: 'App::PropertyBool', value: false },
|
||||
] },
|
||||
],
|
||||
dependencies: [
|
||||
{ sourceId: 'CutThroughHole', targetId: 'Base', relation: 'link', propertyName: 'Base' },
|
||||
{ sourceId: 'CutThroughHole', targetId: 'HoleTool', relation: 'link', propertyName: 'Tool' },
|
||||
],
|
||||
recompute: { generation: 0, status: 'idle', objectStates: { Base: 'up-to-date', HoleTool: 'up-to-date', CutThroughHole: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] },
|
||||
}
|
||||
const throughHolePath = join(temporaryDirectory, 'native-part-cut-through-hole.fcstd')
|
||||
const throughHoleResavedPath = join(temporaryDirectory, 'native-part-cut-through-hole-resaved.fcstd')
|
||||
await writeFile(throughHolePath, serializeFcstdMetadataArchive(throughHoleDocument))
|
||||
const throughHoleResult = runFreecadProbe(throughHolePath, 'CutThroughHole', {
|
||||
FREECAD_FCSTD_RECOMPUTE: '1',
|
||||
FREECAD_FCSTD_PROPERTIES: 'Base,Tool,Refine',
|
||||
FREECAD_FCSTD_RESAVE_PATH: throughHoleResavedPath,
|
||||
})
|
||||
const throughHoleExpectedVolume = 4000 - 90 * Math.PI
|
||||
if (throughHoleResult.freecadVersion !== '1.1.1' || throughHoleResult.shapeNull !== false || throughHoleResult.shapeValid !== true || throughHoleResult.shapeError !== null || throughHoleResult.solidCount !== 1 || throughHoleResult.faceCount !== 7 || !near(throughHoleResult.volume, throughHoleExpectedVolume, 1e-8) || !throughHoleResult.boundingBox || JSON.stringify(throughHoleResult.boundingBox.min) !== '[0,0,0]' || JSON.stringify(throughHoleResult.boundingBox.max) !== '[20,20,10]') fail(`unexpected native Part::Cut through-hole result: ${JSON.stringify(throughHoleResult)}`)
|
||||
if (throughHoleResult.properties.Base !== 'Base' || throughHoleResult.properties.Tool !== 'HoleTool' || throughHoleResult.properties.Refine !== false || Object.keys(throughHoleResult.properties).length !== 3) fail(`native Part::Cut through-hole links did not restore: ${JSON.stringify(throughHoleResult.properties)}`)
|
||||
const throughHoleResaved = inspectFcstdArchive(new Uint8Array(await readFile(throughHoleResavedPath)))
|
||||
const throughHoleObject = throughHoleResaved.objects.find((object) => object.name === 'CutThroughHole') ?? fail('FreeCAD resave is missing CutThroughHole.')
|
||||
const throughHoleShape = throughHoleObject.properties.find((property) => property.name === 'Shape')?.shapeResource
|
||||
const throughHolePlacement = throughHoleResaved.objects.find((object) => object.name === 'HoleTool')?.properties.find((property) => property.name === 'Placement')
|
||||
if (!throughHoleShape || !throughHoleResaved.shapeResources.some((resource) => resource.path === throughHoleShape.path && resource.status === 'available')) fail('FreeCAD resave did not produce the CutThroughHole.Shape resource.')
|
||||
if (!throughHolePlacement || JSON.stringify(decodeFcstdPropertyValue(throughHolePlacement).value) !== '{"position":{"x":10,"y":10,"z":-1},"rotation":{"axis":{"x":0,"y":0,"z":1},"angle":0}}') fail('Web inspector did not recover the through-hole tool placement.')
|
||||
|
||||
const sphereTrimPath = join(temporaryDirectory, 'native-sphere-trim.fcstd')
|
||||
const sphereTrimResavedPath = join(temporaryDirectory, 'native-sphere-trim-resaved.fcstd')
|
||||
const sphereTrimProperties = { Radius: 5, Angle1: -45, Angle2: 45, Angle3: 120 }
|
||||
@@ -658,6 +708,18 @@ try {
|
||||
resavedShapeAvailable: primitiveResaved.shapeResources.some((resource) => resource.path === `${oracleCase.objectName}.Shape.brp` && resource.status === 'available'),
|
||||
})
|
||||
}),
|
||||
scenario('part-cut-through-hole', 'web-freecad-web', ['objectTree', 'properties', 'shape', 'resources'], {
|
||||
typeId: throughHoleObject.typeId,
|
||||
solidCount: throughHoleResult.solidCount,
|
||||
faceCount: throughHoleResult.faceCount,
|
||||
volume: throughHoleResult.volume,
|
||||
boundingBox: throughHoleResult.boundingBox,
|
||||
propertyCount: Object.keys(throughHoleResult.properties).length,
|
||||
properties: throughHoleResult.properties,
|
||||
toolPlacement: decodeFcstdPropertyValue(throughHolePlacement).value,
|
||||
refine: throughHoleResult.properties.Refine,
|
||||
resavedShapeAvailable: true,
|
||||
}),
|
||||
scenario('part-sphere-trim', 'web-freecad-web', ['properties', 'shape', 'resources'], {
|
||||
solidCount: sphereTrimResult.solidCount,
|
||||
faceCount: sphereTrimResult.faceCount,
|
||||
|
||||
Reference in New Issue
Block a user