Skip to content

Commit 137847b

Browse files
committed
Start converting rectangle patterns to affine transformations
1 parent ddfb983 commit 137847b

8 files changed

Lines changed: 546 additions & 40 deletions

src/App.tsx

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,26 @@ import { useEffect, useMemo, useReducer, useRef, useState } from 'react'
22

33
import { drawFrameIncrementally, drawFramePreview } from './draw/draw-frame'
44
import {
5+
applyMatrixAndOffsetToRectangle,
56
ClickedPath,
7+
combineTransformations,
68
findClickedScreenOrPattern,
9+
getMatrixAndOffsetFromRectangle,
710
getMousePoint,
811
getRelativePatternPosition,
912
randomId,
1013
} from './functions'
1114
import { useStableFunction } from './hooks'
1215
import { Preview } from './preview'
13-
import { AbsolutePattern, AbsolutePoint, NumberPair, PatternId, RelativePattern, State } from './types'
16+
import {
17+
AbsolutePattern,
18+
AbsolutePoint,
19+
NumberPair,
20+
PatternId,
21+
RelativePattern,
22+
State,
23+
Transformation,
24+
} from './types'
1425

1526
const getDraftState = (state: State, draftClick: DraftClick, mousePosition: AbsolutePoint): State => {
1627
const draftPattern = {
@@ -29,12 +40,35 @@ const getDraftState = (state: State, draftClick: DraftClick, mousePosition: Abso
2940
// Re-interpret as relative pattern.
3041
const draftPatternRelative = draftPattern satisfies AbsolutePattern as unknown as RelativePattern
3142

32-
let newDraft = getRelativePatternPosition(draftPatternRelative, state.screens[screenIndex]!)
43+
let transform: Transformation = getMatrixAndOffsetFromRectangle(state.screens[screenIndex]!)
44+
3345
for (const k of nestedPath) {
34-
newDraft = getRelativePatternPosition(newDraft, state.patterns[k]!.pattern)
46+
transform = combineTransformations(
47+
transform.matrix,
48+
transform.offset,
49+
state.patterns[k]!.matrix,
50+
state.patterns[k]!.offset
51+
)
3552
}
3653

37-
return { ...state, patterns: state.patterns.concat({ id: randomId() as PatternId, pattern: newDraft }) }
54+
const newDraft = getMatrixAndOffsetFromRectangle(
55+
getRelativePatternPosition(
56+
draftPatternRelative,
57+
applyMatrixAndOffsetToRectangle(transform.matrix, transform.offset, {
58+
anchor: [0, 0],
59+
target: [1, 1],
60+
} as AbsolutePattern)
61+
)
62+
)
63+
64+
return {
65+
...state,
66+
patterns: state.patterns.concat({
67+
id: randomId() as PatternId,
68+
matrix: newDraft.matrix,
69+
offset: newDraft.offset,
70+
}),
71+
}
3872
}
3973

4074
type DraftClick = {
@@ -181,9 +215,13 @@ function App() {
181215
throw new Error(`Pattern with id ${id} not found`)
182216
}
183217

218+
const { matrix, offset } = getMatrixAndOffsetFromRectangle(pattern)
219+
184220
setState(prevState => ({
185221
...prevState,
186-
patterns: prevState.patterns.map(p => (p.id === id ? { ...p, pattern } : p)),
222+
patterns: prevState.patterns.map((p): State['patterns'][number] =>
223+
p.id === id ? { ...p, matrix, offset } : p
224+
),
187225
}))
188226
}}
189227
/>

src/draw/patterns.worker.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AbsolutePattern, PatternId, RelativePattern, State, ViewportPattern } from '../types'
1+
import { AbsolutePattern, PatternId, State, ViewportPattern } from '../types'
22
import { streamBatchedDrawablePatterns } from './stream-batched-drawable-patterns'
33

44
type WorkerState =
@@ -77,9 +77,7 @@ self.onmessage = event => {
7777
function generatePatterns() {
7878
for (const { depth, patterns } of streamBatchedDrawablePatterns({
7979
state: {
80-
patterns: [
81-
{ id: 'debug' as PatternId, pattern: { anchor: [0, 0], target: [0.5, 0.5] } as RelativePattern },
82-
],
80+
patterns: [{ id: 'debug' as PatternId, matrix: [0.8, 0, 0, 0.8], offset: [0.1, 0.1] }],
8381
screens: [{ anchor: [0.2, 0.2], target: [0.8, 0.8] } as AbsolutePattern],
8482
},
8583
chunkSize: 5,

src/draw/stream-batched-drawable-patterns.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ export function* streamBatchedDrawablePatterns({
3636

3737
chunk = {
3838
depth: entry.depth,
39-
patterns: [entry.currentPattern],
39+
patterns: [entry.pattern],
4040
}
4141
} else {
42-
chunk.patterns.push(entry.currentPattern)
42+
chunk.patterns.push(entry.pattern)
4343

4444
if (chunk.patterns.length >= chunkSize) {
4545
yield chunk

src/draw/stream-drawable-patterns.ts

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
1-
import { combinePatterns, mapPatternToViewportSpace, mutateBoundariesFromPattern } from '../functions'
1+
import {
2+
applyMatrixAndOffsetToRectangle,
3+
combineTransformations,
4+
getMatrixAndOffsetFromRectangle,
5+
mapPatternToViewportSpace,
6+
mutateBoundariesFromPattern,
7+
} from '../functions'
28
import { Queue } from '../queue'
3-
import { Boundaries, Size, State, ViewportNumber, ViewportPattern } from '../types'
9+
import {
10+
AbsolutePoint,
11+
Boundaries,
12+
Size,
13+
State,
14+
Transformation,
15+
ViewportNumber,
16+
ViewportPattern,
17+
} from '../types'
418
import { MAX_DEPTH, MAX_QUEUE_SIZE, MIN_PATTERN_SIZE_PX } from './constants'
519

620
// We'll ignore everything that's a bit outside the viewport.
@@ -16,7 +30,12 @@ function getViewportBoundaries(screenSize: Size): Boundaries<ViewportNumber> {
1630
}
1731

1832
type QueueEntry = {
19-
currentPattern: ViewportPattern
33+
currentTransformation: Transformation
34+
depth: number
35+
}
36+
37+
type DrawablePattern = {
38+
pattern: ViewportPattern
2039
depth: number
2140
}
2241

@@ -65,7 +84,7 @@ export function* streamDrawablePatterns({
6584
}: {
6685
state: State
6786
screenSize: Size
68-
}): Generator<QueueEntry, void, void> {
87+
}): Generator<DrawablePattern, void, void> {
6988
console.log(
7089
`generateDrawQueue start. Initial screens: ${state.screens.length}, Patterns: ${state.patterns.length}`
7190
)
@@ -76,9 +95,14 @@ export function* streamDrawablePatterns({
7695

7796
for (const screen of state.screens) {
7897
patternQueue.push({
79-
currentPattern: mapPatternToViewportSpace(screen, screenSize),
98+
currentTransformation: getMatrixAndOffsetFromRectangle(screen),
8099
depth: 0,
81100
})
101+
102+
yield {
103+
pattern: mapPatternToViewportSpace(screen, screenSize),
104+
depth: 0,
105+
}
82106
}
83107

84108
let iterations = 0
@@ -87,8 +111,6 @@ export function* streamDrawablePatterns({
87111

88112
const entry = patternQueue.shift()
89113

90-
yield entry
91-
92114
// Don't add patterns that are too deep.
93115
if (entry.depth >= MAX_DEPTH) {
94116
console.log(
@@ -97,13 +119,34 @@ export function* streamDrawablePatterns({
97119
break
98120
}
99121

100-
for (const { pattern } of state.patterns) {
122+
for (const { matrix, offset } of state.patterns) {
101123
// Get new pattern
102-
const newViewportPattern = combinePatterns(entry.currentPattern, pattern)
124+
const newTransformation = combineTransformations(
125+
entry.currentTransformation.matrix,
126+
entry.currentTransformation.offset,
127+
matrix,
128+
offset
129+
)
130+
131+
const transformedUnit = applyMatrixAndOffsetToRectangle(
132+
newTransformation.matrix,
133+
newTransformation.offset,
134+
{
135+
anchor: [0, 0] as AbsolutePoint,
136+
target: [1, 1] as AbsolutePoint,
137+
}
138+
)
139+
140+
const newScreen = mapPatternToViewportSpace(transformedUnit, screenSize)
141+
142+
if (isValidPattern(newScreen, viewportBoundaries)) {
143+
yield {
144+
pattern: newScreen,
145+
depth: entry.depth + 1,
146+
}
103147

104-
if (isValidPattern(newViewportPattern, viewportBoundaries)) {
105148
patternQueue.push({
106-
currentPattern: newViewportPattern,
149+
currentTransformation: newTransformation,
107150
depth: entry.depth + 1,
108151
})
109152

0 commit comments

Comments
 (0)