From da4d15f97c9d8e2b37ec4f161bf0afc74efbe230 Mon Sep 17 00:00:00 2001 From: Orion Reed Date: Mon, 2 Dec 2024 06:29:30 -0500 Subject: [PATCH] RotatedDOMRect --- src/distance-field.ts | 24 +------------------- src/folk-shape.ts | 51 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/distance-field.ts b/src/distance-field.ts index 1ae2a95..a9f3908 100644 --- a/src/distance-field.ts +++ b/src/distance-field.ts @@ -153,29 +153,7 @@ export class DistanceField extends HTMLElement { // Collect positions and assign unique IDs to all shapes this.shapes.forEach((geometry, index) => { const rect = geometry.getClientRect(); - const rotation = (geometry.rotation * Math.PI) / 180; // Convert to radians - - // Calculate the center of the rectangle - const centerX = (rect.left + rect.right) / 2; - const centerY = (rect.top + rect.bottom) / 2; - - // Function to rotate a point around the center - const rotatePoint = (x: number, y: number) => { - const dx = x - centerX; - const dy = y - centerY; - const cos = Math.cos(rotation); - const sin = Math.sin(rotation); - return { - x: centerX + dx * cos - dy * sin, - y: centerY + dx * sin + dy * cos, - }; - }; - - // Rotate each corner of the rectangle - const topLeft = rotatePoint(rect.left, rect.top); - const topRight = rotatePoint(rect.right, rect.top); - const bottomLeft = rotatePoint(rect.left, rect.bottom); - const bottomRight = rotatePoint(rect.right, rect.bottom); + const [topLeft, topRight, bottomRight, bottomLeft] = rect.corners(); // Convert rotated coordinates to NDC const x1 = (topLeft.x / windowWidth) * 2 - 1; diff --git a/src/folk-shape.ts b/src/folk-shape.ts index d6dd859..ca996e3 100644 --- a/src/folk-shape.ts +++ b/src/folk-shape.ts @@ -1,12 +1,24 @@ import { css, html } from './common/tags'; import { ResizeObserverManager } from './common/resize-observer'; +import type { Vector2 } from './common/Vector2'; const resizeObserver = new ResizeObserverManager(); export type Shape = 'rectangle' | 'circle' | 'triangle'; -type RotatedDOMRect = DOMRect & { rotation: number }; +type RotatedDOMRect = DOMRect & { + // In degrees + rotation: number; + // Returns the center point in worldspace coordinates + center(): Vector2; + + // Returns the four corners in worldspace coordinates, in clockwise order + corners(): [Vector2, Vector2, Vector2, Vector2]; + + // Returns all the vertices in worldspace coordinates + vertices(): Vector2[]; +}; export type MoveEventDetail = { movementX: number; movementY: number }; export class MoveEvent extends CustomEvent { @@ -286,6 +298,7 @@ export class FolkShape extends HTMLElement { getClientRect(): RotatedDOMRect { const { x, y, width, height, rotation } = this; + const radians = (rotation * Math.PI) / 180; return { x, @@ -297,9 +310,43 @@ export class FolkShape extends HTMLElement { right: x + width, bottom: y + height, rotation, + + center(): Vector2 { + return { + x: this.x + this.width / 2, + y: this.y + this.height / 2, + }; + }, + vertices(): Vector2[] { + // TODO: Implement + return []; + }, + + corners(): [Vector2, Vector2, Vector2, Vector2] { + const center = this.center(); + const cos = Math.cos(radians); + const sin = Math.sin(radians); + + const halfWidth = this.width / 2; + const halfHeight = this.height / 2; + + // Helper to rotate a point around the center + const rotatePoint = (dx: number, dy: number): Vector2 => ({ + x: center.x + dx * cos - dy * sin, + y: center.y + dx * sin + dy * cos, + }); + + // Return vertices in clockwise order: top-left, top-right, bottom-right, bottom-left + return [ + rotatePoint(-halfWidth, -halfHeight), // Top-left + rotatePoint(halfWidth, -halfHeight), // Top-right + rotatePoint(halfWidth, halfHeight), // Bottom-right + rotatePoint(-halfWidth, halfHeight), // Bottom-left + ]; + }, + toJSON: undefined as any, }; - // return DOMRectReadOnly.fromRect({ x: this.x, y: this.y, width: this.width, height: this.height }); } // Similar to `Element.getClientBoundingRect()`, but returns an SVG path that precisely outlines the shape.