feat: add experimental polar pattern feature
This commit is contained in:
@@ -377,7 +377,7 @@ test('OCCT feature executor builds a Sketch to Pad to Pocket chain and retains t
|
||||
createCylinder: async () => shape('cylinder-shape'),
|
||||
createSphere: async () => shape('sphere-shape'),
|
||||
createCone: async () => shape('cone-shape'),
|
||||
applyPlacement: async (input) => { calls.push(`placement:${input.placement.translation.join(',')}`); return shape(`pattern-copy-${calls.filter((call) => call.startsWith('placement:')).length}`) },
|
||||
applyPlacement: async (input) => { calls.push(`placement:${input.placement.translation.join(',')}:${input.placement.rotationAxis.join(',')}:${input.placement.rotationAngle}`); return shape(`pattern-copy-${calls.filter((call) => call.startsWith('placement:')).length}`) },
|
||||
union: async (input) => { calls.push(`union:${input.shapes.map((entry) => entry.id).join(',')}`); return shape('union-shape') },
|
||||
cut: async () => shape('cut-shape'),
|
||||
intersection: async () => shape('intersection-shape'),
|
||||
@@ -447,8 +447,8 @@ test('OCCT feature executor builds a Sketch to Pad to Pocket chain and retains t
|
||||
const patternResult = await executor(linearPattern, document, context)
|
||||
assert.equal(patternResult.status, 'success')
|
||||
assert.equal(shapes.get('linear-pattern')?.id, 'union-shape')
|
||||
assert.ok(calls.includes('placement:0,10,0'))
|
||||
assert.ok(calls.includes('placement:0,20,0'))
|
||||
assert.ok(calls.includes('placement:0,10,0:0,0,1:0'))
|
||||
assert.ok(calls.includes('placement:0,20,0:0,0,1:0'))
|
||||
assert.ok(calls.includes('union:pad-shape,pattern-copy-1,pattern-copy-2'))
|
||||
assert.ok(calls.includes('release:pattern-copy-1'))
|
||||
assert.ok(calls.includes('release:pattern-copy-2'))
|
||||
@@ -458,6 +458,24 @@ test('OCCT feature executor builds a Sketch to Pad to Pocket chain and retains t
|
||||
assert.equal(invalidPatternResult.status, 'failed')
|
||||
assert.equal(invalidPatternResult.errors?.[0].code, 'PATTERN_OCCURRENCES_INVALID')
|
||||
|
||||
const polarPattern = { id: 'polar-pattern', typeId: 'PartDesign::PolarPattern', properties: [
|
||||
{ name: 'Base', label: 'Base', group: 'Pattern', scope: 'data' as const, type: 'App::PropertyLink' as const, value: 'pad' },
|
||||
{ name: 'Occurrences', label: 'Occurrences', group: 'Pattern', scope: 'data' as const, type: 'App::PropertyInteger' as const, value: 3 },
|
||||
{ name: 'Angle', label: 'Angle', group: 'Pattern', scope: 'data' as const, type: 'App::PropertyAngle' as const, value: 360, unit: 'deg' },
|
||||
{ name: 'Axis', label: 'Axis', group: 'Pattern', scope: 'data' as const, type: 'App::PropertyEnumeration' as const, value: 'Normal', options: ['Normal', 'Horizontal', 'Vertical'] },
|
||||
] }
|
||||
const polarResult = await executor(polarPattern, document, context)
|
||||
assert.equal(polarResult.status, 'success')
|
||||
assert.ok(calls.includes('placement:0,0,0:0,0,1:120'))
|
||||
assert.ok(calls.includes('placement:0,0,0:0,0,1:240'))
|
||||
assert.ok(calls.includes('union:pad-shape,pattern-copy-3,pattern-copy-4'))
|
||||
|
||||
const partialPolar = { ...polarPattern, id: 'polar-pattern-partial', properties: polarPattern.properties.map((property) => property.name === 'Angle' ? { ...property, value: 180 } : property) }
|
||||
const partialPolarResult = await executor(partialPolar, document, context)
|
||||
assert.equal(partialPolarResult.status, 'success')
|
||||
assert.ok(calls.includes('placement:0,0,0:0,0,1:90'))
|
||||
assert.ok(calls.includes('placement:0,0,0:0,0,1:180'))
|
||||
|
||||
const suppressedPad = { ...pad, properties: [...pad.properties, { name: 'Suppressed', label: 'Suppressed', group: 'Feature state', scope: 'data' as const, type: 'App::PropertyBool' as const, value: true }] }
|
||||
const suppressedResult = await executor(suppressedPad, document, context)
|
||||
assert.equal(suppressedResult.status, 'suppressed')
|
||||
@@ -642,10 +660,10 @@ test('disabled commands return a reason instead of mutating the document', () =>
|
||||
test('manifest commands without a Bitbybit executor are explicitly unsupported', () => {
|
||||
const facade = createMockFacade()
|
||||
const before = facade.getState().document.version
|
||||
const state = facade.gui.command.getState('polar-pattern')
|
||||
const state = facade.gui.command.getState('hole')
|
||||
assert.equal(state.status, 'disabled')
|
||||
assert.match(state.reason || '', /business executor/)
|
||||
facade.gui.command.execute({ commandId: 'polar-pattern' })
|
||||
facade.gui.command.execute({ commandId: 'hole' })
|
||||
assert.equal(facade.getState().diagnostics.at(-1)?.code, 'COMMAND_UNIMPLEMENTED')
|
||||
assert.equal(facade.getState().document.version, before)
|
||||
})
|
||||
@@ -919,6 +937,17 @@ test('Part Design feature tasks commit a document object and remain undoable', (
|
||||
assert.throws(() => facade.task.apply(), /between 2 and 100/)
|
||||
assert.equal(facade.app.document.getObject('linear-pattern001'), null)
|
||||
facade.task.cancel()
|
||||
|
||||
facade.gui.command.execute({ commandId: 'polar-pattern' })
|
||||
facade.task.update({ occurrences: 4, angle: 180, axis: 'Normal' })
|
||||
facade.task.apply()
|
||||
const polarPattern = facade.app.document.getObject('polar-pattern')
|
||||
assert.equal(polarPattern?.typeId, 'PartDesign::PolarPattern')
|
||||
assert.equal(polarPattern?.properties.find((property) => property.name === 'Base')?.value, 'linear-pattern')
|
||||
assert.equal(polarPattern?.properties.find((property) => property.name === 'Occurrences')?.value, 4)
|
||||
assert.equal(polarPattern?.properties.find((property) => property.name === 'Angle')?.value, 180)
|
||||
assert.equal(polarPattern?.properties.find((property) => property.name === 'Axis')?.value, 'Normal')
|
||||
assert.equal(facade.app.document.getObject('body')?.properties.find((property) => property.name === 'Tip')?.value, 'polar-pattern')
|
||||
})
|
||||
|
||||
test('Part workbench commands create primitive and boolean document objects', () => {
|
||||
|
||||
Reference in New Issue
Block a user