From 9502f89a06d56e3517dd2c8ec3c15526acab00a1 Mon Sep 17 00:00:00 2001 From: Hiren Kangad Date: Fri, 13 Mar 2026 09:57:29 +0530 Subject: [PATCH] refboard: tighten rotated image hit testing --- frontend/src/canvas/SelectionManager.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/frontend/src/canvas/SelectionManager.ts b/frontend/src/canvas/SelectionManager.ts index ae541b8..975b9d8 100644 --- a/frontend/src/canvas/SelectionManager.ts +++ b/frontend/src/canvas/SelectionManager.ts @@ -13,7 +13,7 @@ import { SnapGuides } from './SnapGuides'; import { ImageSprite } from './sprites/ImageSprite'; import { VideoSprite } from './sprites/VideoSprite'; import type { ImageObject } from './scene-format'; -import { applyImageDisplayTransform } from './imageTransforms'; +import { applyImageDisplayTransform, getImageTransformedCorners } from './imageTransforms'; // --------------------------------------------------------------------------- // Constants @@ -27,6 +27,24 @@ const BAND_STROKE_WIDTH = 1; const RUBBER_BAND_THRESHOLD = 5; // px in screen space before rubber band activates const DRAG_THRESHOLD = 5; // px in screen space before object drag activates +function isPointInPolygon(wx: number, wy: number, points: Array<{ x: number; y: number }>): boolean { + if (points.length < 3) return false; + let sign = 0; + for (let i = 0; i < points.length; i++) { + const a = points[i]; + const b = points[(i + 1) % points.length]; + const cross = (b.x - a.x) * (wy - a.y) - (b.y - a.y) * (wx - a.x); + if (Math.abs(cross) < 1e-6) continue; + const nextSign = cross > 0 ? 1 : -1; + if (sign === 0) { + sign = nextSign; + } else if (sign !== nextSign) { + return false; + } + } + return true; +} + // --------------------------------------------------------------------------- // SelectionManager // --------------------------------------------------------------------------- @@ -210,6 +228,10 @@ export class SelectionManager { const { x: ix, y: iy, w: iw, h: ih } = getItemWorldBounds(item); if (ix <= wx && wx <= ix + iw && iy <= wy && wy <= iy + ih) { + if (item.type === 'image') { + const corners = getImageTransformedCorners(item.data as ImageObject); + if (!isPointInPolygon(wx, wy, corners)) continue; + } return item; } }