Unify preview-aware transforms across scene drawing, labels, selection and input. Give live property and creation edits explicit preview ownership, preserve cancellation and one-step undo, and reuse bounded text preparation resources. Include retained device-grid handling, worktree HMR coverage, and nested/reflected interaction regressions in this cohesive progress checkpoint. Validation: full check passes; 734 scoped unit tests and 53 targeted browser tests pass. This is NOT merge-ready: the unchanged exact nested filled-section held/released regression still fails with 63 differing pixels (maximum channel delta 5/255). The browser pass count excludes that separately run failure and the previously classified paint-field-width baseline. Raster-origin investigation and broader acceptance remain outstanding.
60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
import type { SceneGraph, SceneNode, Vector } from '@open-pencil/scene-graph'
|
|
|
|
type FixtureNode = Pick<
|
|
SceneNode,
|
|
'type' | 'name' | 'x' | 'y' | 'width' | 'height' | 'rotation' | 'flipX' | 'flipY'
|
|
>
|
|
|
|
export function nestedGeometryData(flipX = false, flipY = false) {
|
|
const section: FixtureNode = {
|
|
type: 'SECTION',
|
|
name: 'Rotated section',
|
|
x: 140,
|
|
y: 140,
|
|
width: 500,
|
|
height: 350,
|
|
rotation: 25,
|
|
flipX,
|
|
flipY: false
|
|
}
|
|
const frame: FixtureNode = {
|
|
type: 'FRAME',
|
|
name: 'Nested frame',
|
|
x: 100,
|
|
y: 100,
|
|
width: 220,
|
|
height: 120,
|
|
rotation: -55,
|
|
flipX: false,
|
|
flipY
|
|
}
|
|
return { section, frame }
|
|
}
|
|
|
|
export function nestedGeometryFixture(
|
|
graph: SceneGraph,
|
|
parentId: string,
|
|
flipX = false,
|
|
flipY = false
|
|
) {
|
|
const data = nestedGeometryData(flipX, flipY)
|
|
const section = graph.createNode('SECTION', parentId, data.section)
|
|
const frame = graph.createNode('FRAME', section.id, data.frame)
|
|
return { section, frame }
|
|
}
|
|
|
|
/** Independent scalar oracle, not the production matrix/geometry implementation. */
|
|
export function applyFixtureTransform(node: FixtureNode, point: Vector): Vector {
|
|
const pivotX = node.type === 'LINE' ? 0 : node.width / 2
|
|
const pivotY = node.type === 'LINE' ? 0 : node.height / 2
|
|
const x = point.x - pivotX
|
|
const y = point.y - pivotY
|
|
const angle = (node.rotation * Math.PI) / 180
|
|
const rotatedX = pivotX + x * Math.cos(angle) - y * Math.sin(angle)
|
|
const rotatedY = pivotY + x * Math.sin(angle) + y * Math.cos(angle)
|
|
return {
|
|
x: node.x + (node.flipX ? node.width - rotatedX : rotatedX),
|
|
y: node.y + (node.flipY ? node.height - rotatedY : rotatedY)
|
|
}
|
|
}
|