@@ -10,43 +10,46 @@ import {
1010 RelativePoint ,
1111 Size ,
1212 State ,
13+ ViewportNumber ,
1314 ViewportPattern ,
14- ViewportPoint
15+ ViewportPoint ,
1516} from './types'
1617
17- function minPatternNumber < N extends PatternNumber > ( a : N , b : N ) : N {
18- return Math . min ( a , b ) as N
19- }
20-
21- function maxPatternNumber < N extends PatternNumber > ( a : N , b : N ) : N {
22- return Math . max ( a , b ) as N
23- }
24-
2518/**
2619 * This function mutates the boundaries object in place.
27- *
20+ *
2821 * This is a performance optimization to avoid creating new objects, since this function is called very frequently
2922 * during rendering.
3023 */
31- export function mutateBoundariesFromPattern < N extends PatternNumber > ( pattern : Pattern < N > , boundaries : Boundaries < N > ) : void {
32- const [ x1 , y1 ] = pattern . anchor
33- const [ x2 , y2 ] = pattern . target
34-
35- boundaries . xMin = minPatternNumber ( x1 , x2 )
36- boundaries . xMax = maxPatternNumber ( x1 , x2 )
37- boundaries . yMin = minPatternNumber ( y1 , y2 )
38- boundaries . yMax = maxPatternNumber ( y1 , y2 )
39- }
40-
24+ export const mutateBoundariesFromPattern = ( ( ) => {
25+ let x1 : PatternNumber
26+ let y1 : PatternNumber
27+ let x2 : PatternNumber
28+ let y2 : PatternNumber
29+
30+ return function < N extends PatternNumber > ( pattern : Pattern < N > , boundaries : Boundaries < N > ) : void {
31+ x1 = pattern . anchor [ 0 ]
32+ y1 = pattern . anchor [ 1 ]
33+ x2 = pattern . target [ 0 ]
34+ y2 = pattern . target [ 1 ]
35+
36+ boundaries . xMin = Math . min ( x1 , x2 ) as N
37+ boundaries . xMax = Math . max ( x1 , x2 ) as N
38+ boundaries . yMin = Math . min ( y1 , y2 ) as N
39+ boundaries . yMax = Math . max ( y1 , y2 ) as N
40+ }
41+ } ) ( )
4142
42- const getBoundariesFromPattern = < N extends PatternNumber > ( pattern : Pattern < N > ) : Boundaries < N > => {
43+ const getBoundariesFromPattern = < N extends PatternNumber > ( pattern : Pattern < N > ) : Boundaries < N > => {
4344 const obj : Boundaries < N > = { xMin : 0 as N , xMax : 0 as N , yMin : 0 as N , yMax : 0 as N }
4445 mutateBoundariesFromPattern ( pattern , obj )
4546 return obj
4647}
4748
48-
49- const pointIsInBoundaries = < N extends PatternNumber > ( point : Point < N > , boundaries : Boundaries < N > ) : boolean => {
49+ const pointIsInBoundaries = < N extends PatternNumber > (
50+ point : Point < N > ,
51+ boundaries : Boundaries < N >
52+ ) : boolean => {
5053 const { xMin, xMax, yMin, yMax } = boundaries
5154 const [ pointX , pointY ] = point
5255
@@ -61,10 +64,9 @@ const mapPointToViewportSpace = (
6164 [ x , y ] : AbsolutePoint ,
6265 [ viewportWidth , viewportHeight ] : Size
6366) : ViewportPoint => {
64- return [ Math . round ( x * viewportWidth ) , Math . round ( y * viewportHeight ) ] satisfies NumberPair as ViewportPoint
67+ return [ x * viewportWidth , y * viewportHeight ] satisfies NumberPair as ViewportPoint
6568}
6669
67-
6870// ts-unused-exports:disable-next-line
6971export const mapPatternToViewportSpace = ( pattern : AbsolutePattern , screenSize : Size ) : ViewportPattern => ( {
7072 anchor : mapPointToViewportSpace ( pattern . anchor , screenSize ) ,
@@ -93,7 +95,10 @@ export const mapPointFromViewportSpace = (
9395 return [ x / viewportWidth , y / viewportHeight ] satisfies NumberPair as AbsolutePoint
9496}
9597
96- function getRelativePointPosition ( point : RelativePoint , pattern : AbsolutePattern | RelativePattern ) : RelativePoint {
98+ function getRelativePointPosition (
99+ point : RelativePoint ,
100+ pattern : AbsolutePattern | RelativePattern
101+ ) : RelativePoint {
97102 const [ x1 , y1 ] = pattern . anchor
98103 const [ x2 , y2 ] = pattern . target
99104 const [ x , y ] = point
@@ -104,22 +109,50 @@ function getRelativePointPosition(point: RelativePoint, pattern: AbsolutePattern
104109 return [ relativeX , relativeY ] satisfies NumberPair as RelativePoint
105110}
106111
107- export function getRelativePatternPosition ( pattern : RelativePattern , basePattern : AbsolutePattern | RelativePattern ) : RelativePattern {
112+ export function getRelativePatternPosition (
113+ pattern : RelativePattern ,
114+ basePattern : AbsolutePattern | RelativePattern
115+ ) : RelativePattern {
108116 return {
109117 anchor : getRelativePointPosition ( pattern . anchor , basePattern ) ,
110118 target : getRelativePointPosition ( pattern . target , basePattern ) ,
111119 }
112120}
113121
114- const resolveRelativePointPosition = < N extends PatternNumber > ( relativePoint : RelativePoint , pattern : Pattern < N > ) : Point < N > => {
115- const [ x1 , y1 ] = pattern . anchor
116- const [ x2 , y2 ] = pattern . target
117- const [ x , y ] = relativePoint
122+ const resolveRelativePointPositionInPlace = ( ( ) => {
123+ let x1 : PatternNumber
124+ let y1 : PatternNumber
125+ let x2 : PatternNumber
126+ let y2 : PatternNumber
127+ let x : PatternNumber
128+ let y : PatternNumber
129+
130+ return function < N extends PatternNumber > (
131+ relativePoint : RelativePoint ,
132+ pattern : Pattern < N > ,
133+ newPoint : Point < N >
134+ ) : void {
135+ x1 = pattern . anchor [ 0 ]
136+ y1 = pattern . anchor [ 1 ]
137+ x2 = pattern . target [ 0 ]
138+ y2 = pattern . target [ 1 ]
139+ x = relativePoint [ 0 ]
140+ y = relativePoint [ 1 ]
141+
142+ newPoint [ 0 ] = ( x1 + x * ( x2 - x1 ) ) as N
143+ newPoint [ 1 ] = ( y1 + y * ( y2 - y1 ) ) as N
144+ }
145+ } ) ( )
118146
119- const resolvedX = x1 + x * ( x2 - x1 )
120- const resolvedY = y1 + y * ( y2 - y1 )
147+ const resolveRelativePointPosition = < N extends PatternNumber > (
148+ relativePoint : RelativePoint ,
149+ pattern : Pattern < N >
150+ ) : Point < N > => {
151+ const newPoint = [ 0 , 0 ] satisfies NumberPair as Point < N >
152+
153+ resolveRelativePointPositionInPlace ( relativePoint , pattern , newPoint )
121154
122- return [ resolvedX , resolvedY ] satisfies NumberPair as Point < N >
155+ return newPoint
123156}
124157
125158export const getScreenSize = ( ctx : CanvasRenderingContext2D ) : Size => [ ctx . canvas . width , ctx . canvas . height ]
@@ -133,11 +166,28 @@ export const getMousePoint = (
133166 return mapPointFromViewportSpace ( mousePosition , getScreenSize ( ctx ) )
134167}
135168
136- export function combinePatterns < ParentNumber extends PatternNumber > ( parent : Pattern < ParentNumber > , child : RelativePattern ) : Pattern < ParentNumber > {
169+ export function combinePatterns < ParentNumber extends PatternNumber > (
170+ parent : Pattern < ParentNumber > ,
171+ child : RelativePattern
172+ ) : Pattern < ParentNumber > {
137173 return {
138174 anchor : resolveRelativePointPosition ( child . anchor , parent ) ,
139175 target : resolveRelativePointPosition ( child . target , parent ) ,
140- }
176+ }
177+ }
178+
179+ /**
180+ * Rounds coordinates of the pattern to the nearest integer. NOTE: Mutates the pattern in place.
181+ *
182+ * This is a performance optimization to avoid anti-aliasing.
183+ */
184+ // ts-unused-exports:disable-next-line
185+ export function roundViewportPatternInPlace ( pattern : ViewportPattern ) : ViewportPattern {
186+ pattern . anchor [ 0 ] = Math . round ( pattern . anchor [ 0 ] ) as ViewportNumber
187+ pattern . anchor [ 1 ] = Math . round ( pattern . anchor [ 1 ] ) as ViewportNumber
188+ pattern . target [ 0 ] = Math . round ( pattern . target [ 0 ] ) as ViewportNumber
189+ pattern . target [ 1 ] = Math . round ( pattern . target [ 1 ] ) as ViewportNumber
190+ return pattern
141191}
142192
143193type NestedPath = number [ ]
0 commit comments