From c51c6631e12cbddd0c28e47d5e1a9fbd3d2e8fa6 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Sun, 6 Jun 2021 20:34:27 +0100 Subject: [PATCH] improves hit testing for draw shapes --- lib/shape-utils/draw.tsx | 57 ++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/lib/shape-utils/draw.tsx b/lib/shape-utils/draw.tsx index 074e4e926..c906416a0 100644 --- a/lib/shape-utils/draw.tsx +++ b/lib/shape-utils/draw.tsx @@ -3,16 +3,19 @@ import * as vec from 'utils/vec' import { DashStyle, DrawShape, ShapeStyles, ShapeType } from 'types' import { registerShapeUtils } from './index' import { intersectPolylineBounds } from 'utils/intersections' -import { boundsContainPolygon } from 'utils/bounds' +import { boundsContain, boundsContainPolygon } from 'utils/bounds' import getStroke from 'perfect-freehand' import { getBoundsCenter, getBoundsFromPoints, + getRotatedCorners, getSvgPathFromStroke, + rotateBounds, translateBounds, } from 'utils/utils' import { defaultStyle, getShapeStyle } from 'lib/shape-styles' +const rotatedCache = new WeakMap([]) const pathCache = new WeakMap([]) const draw = registerShapeUtils({ @@ -69,20 +72,16 @@ const draw = registerShapeUtils({ }, getRotatedBounds(shape) { - const bounds = - this.boundsCache.get(shape) || getBoundsFromPoints(shape.points) - - const center = getBoundsCenter(bounds) - - const rotatedPts = shape.points.map((pt) => - vec.rotWith(pt, center, shape.rotation) - ) - const rotatedBounds = translateBounds( - getBoundsFromPoints(rotatedPts), + const rBounds = translateBounds( + getBoundsFromPoints(shape.points, shape.rotation), shape.point ) - return rotatedBounds + const bounds = this.getBounds(shape) + + const delta = vec.sub(getBoundsCenter(bounds), getBoundsCenter(rBounds)) + + return translateBounds(rBounds, delta) }, getCenter(shape) { @@ -100,22 +99,30 @@ const draw = registerShapeUtils({ }, hitTestBounds(this, shape, brushBounds) { - const b = this.getBounds(shape) - const center = [b.minX + b.width / 2, b.minY + b.height / 2] + // Test axis-aligned shape + if (shape.rotation === 0) { + return ( + boundsContain(brushBounds, this.getBounds(shape)) || + intersectPolylineBounds(shape.points, brushBounds).length > 0 + ) + } - const rotatedCorners = [ - [b.minX, b.minY], - [b.maxX, b.minY], - [b.maxX, b.maxY], - [b.minX, b.maxY], - ].map((point) => vec.rotWith(point, center, shape.rotation)) + // Test rotated shape + const rBounds = this.getRotatedBounds(shape) + + if (!rotatedCache.has(shape)) { + const c = getBoundsCenter(rBounds) + rotatedCache.set( + shape, + shape.points.map((pt) => + vec.rotWith(vec.add(pt, shape.point), c, shape.rotation) + ) + ) + } return ( - boundsContainPolygon(brushBounds, rotatedCorners) || - intersectPolylineBounds( - shape.points.map((point) => vec.add(point, shape.point)), - brushBounds - ).length > 0 + boundsContain(brushBounds, rBounds) || + intersectPolylineBounds(rotatedCache.get(shape), brushBounds).length > 0 ) },