improves hit testing for draw shapes

This commit is contained in:
Steve Ruiz 2021-06-06 20:34:27 +01:00
parent c52c8f4c76
commit c51c6631e1

View file

@ -3,16 +3,19 @@ import * as vec from 'utils/vec'
import { DashStyle, DrawShape, ShapeStyles, ShapeType } from 'types' import { DashStyle, DrawShape, ShapeStyles, ShapeType } from 'types'
import { registerShapeUtils } from './index' import { registerShapeUtils } from './index'
import { intersectPolylineBounds } from 'utils/intersections' import { intersectPolylineBounds } from 'utils/intersections'
import { boundsContainPolygon } from 'utils/bounds' import { boundsContain, boundsContainPolygon } from 'utils/bounds'
import getStroke from 'perfect-freehand' import getStroke from 'perfect-freehand'
import { import {
getBoundsCenter, getBoundsCenter,
getBoundsFromPoints, getBoundsFromPoints,
getRotatedCorners,
getSvgPathFromStroke, getSvgPathFromStroke,
rotateBounds,
translateBounds, translateBounds,
} from 'utils/utils' } from 'utils/utils'
import { defaultStyle, getShapeStyle } from 'lib/shape-styles' import { defaultStyle, getShapeStyle } from 'lib/shape-styles'
const rotatedCache = new WeakMap<DrawShape, number[][]>([])
const pathCache = new WeakMap<DrawShape['points'], string>([]) const pathCache = new WeakMap<DrawShape['points'], string>([])
const draw = registerShapeUtils<DrawShape>({ const draw = registerShapeUtils<DrawShape>({
@ -69,20 +72,16 @@ const draw = registerShapeUtils<DrawShape>({
}, },
getRotatedBounds(shape) { getRotatedBounds(shape) {
const bounds = const rBounds = translateBounds(
this.boundsCache.get(shape) || getBoundsFromPoints(shape.points) getBoundsFromPoints(shape.points, shape.rotation),
const center = getBoundsCenter(bounds)
const rotatedPts = shape.points.map((pt) =>
vec.rotWith(pt, center, shape.rotation)
)
const rotatedBounds = translateBounds(
getBoundsFromPoints(rotatedPts),
shape.point shape.point
) )
return rotatedBounds const bounds = this.getBounds(shape)
const delta = vec.sub(getBoundsCenter(bounds), getBoundsCenter(rBounds))
return translateBounds(rBounds, delta)
}, },
getCenter(shape) { getCenter(shape) {
@ -100,22 +99,30 @@ const draw = registerShapeUtils<DrawShape>({
}, },
hitTestBounds(this, shape, brushBounds) { hitTestBounds(this, shape, brushBounds) {
const b = this.getBounds(shape) // Test axis-aligned shape
const center = [b.minX + b.width / 2, b.minY + b.height / 2] if (shape.rotation === 0) {
return (
boundsContain(brushBounds, this.getBounds(shape)) ||
intersectPolylineBounds(shape.points, brushBounds).length > 0
)
}
const rotatedCorners = [ // Test rotated shape
[b.minX, b.minY], const rBounds = this.getRotatedBounds(shape)
[b.maxX, b.minY],
[b.maxX, b.maxY], if (!rotatedCache.has(shape)) {
[b.minX, b.maxY], const c = getBoundsCenter(rBounds)
].map((point) => vec.rotWith(point, center, shape.rotation)) rotatedCache.set(
shape,
shape.points.map((pt) =>
vec.rotWith(vec.add(pt, shape.point), c, shape.rotation)
)
)
}
return ( return (
boundsContainPolygon(brushBounds, rotatedCorners) || boundsContain(brushBounds, rBounds) ||
intersectPolylineBounds( intersectPolylineBounds(rotatedCache.get(shape), brushBounds).length > 0
shape.points.map((point) => vec.add(point, shape.point)),
brushBounds
).length > 0
) )
}, },