From 3f90fbf5b074618e71ee5cb19d5de383493d629e Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Sun, 24 Dec 2023 11:53:15 +0000 Subject: [PATCH] [fix] polygon bounds (#2378) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes the bounds calculation for polygons. It solves the bug reported here: https://github.com/tldraw/tldraw/issues/2309 . Note that this may produce visual changes for hexagons and other shapes. ![Kapture 2023-12-24 at 10 35 13](https://github.com/tldraw/tldraw/assets/23072548/773e89ee-f8c3-4875-b942-30860b1cdf22) ### Change Type - [x] `patch` — Bug fix ### Test Plan 1. Create a hexagon shape with a label. 2. The label should be correctly centered. ### Release Notes - Fixed a bug with the bounds calculation for polygons. --- packages/editor/src/lib/primitives/utils.ts | 20 +++++++++++++++--- .../src/lib/shapes/geo/GeoShapeUtil.tsx | 21 ++++++++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/editor/src/lib/primitives/utils.ts b/packages/editor/src/lib/primitives/utils.ts index 83a5a9362..edca4f634 100644 --- a/packages/editor/src/lib/primitives/utils.ts +++ b/packages/editor/src/lib/primitives/utils.ts @@ -314,8 +314,11 @@ export function getPolygonVertices(width: number, height: number, sides: number) const cx = width / 2 const cy = height / 2 const pointsOnPerimeter: Vec2d[] = [] + let minX = Infinity + let maxX = -Infinity let minY = Infinity + let maxY = -Infinity for (let i = 0; i < sides; i++) { const step = PI2 / sides const t = -TAU + i * step @@ -323,14 +326,25 @@ export function getPolygonVertices(width: number, height: number, sides: number) const y = cy + cy * Math.sin(t) if (x < minX) minX = x if (y < minY) minY = y + if (x > maxX) maxX = x + if (y > maxY) maxY = y pointsOnPerimeter.push(new Vec2d(x, y)) } - if (minX !== 0 || minY !== 0) { + // Bounds of calculated points + const w = maxX - minX + const h = maxY - minY + + // Difference between input bounds and calculated bounds + const dx = width - w + const dy = height - h + + // If there's a difference, scale the points to the input bounds + if (dx !== 0 || dy !== 0) { for (let i = 0; i < pointsOnPerimeter.length; i++) { const pt = pointsOnPerimeter[i] - pt.x -= minX - pt.y -= minY + pt.x = ((pt.x - minX) / w) * width + pt.y = ((pt.y - minY) / h) * height } } diff --git a/packages/tldraw/src/lib/shapes/geo/GeoShapeUtil.tsx b/packages/tldraw/src/lib/shapes/geo/GeoShapeUtil.tsx index ad6aaf955..485b9376d 100644 --- a/packages/tldraw/src/lib/shapes/geo/GeoShapeUtil.tsx +++ b/packages/tldraw/src/lib/shapes/geo/GeoShapeUtil.tsx @@ -20,6 +20,7 @@ import { TLOnResizeHandler, TLShapeUtilCanvasSvgDef, Vec2d, + VecLike, geoShapeMigrations, geoShapeProps, getDefaultColorTheme, @@ -321,11 +322,13 @@ export class GeoShapeUtil extends BaseBoxShapeUtil { const labelSize = getLabelSize(this.editor, shape) const labelWidth = Math.min(w, Math.max(labelSize.w, Math.min(32, Math.max(1, w - 8)))) - const labelHeight = Math.min(h, Math.max(labelSize.h, Math.min(32, Math.max(1, w - 8)))) + const labelHeight = Math.min(h, Math.max(labelSize.h, Math.min(32, Math.max(1, w - 8)))) // not sure if bug const lines = getLines(shape.props, strokeWidth) const edges = lines ? lines.map((line) => new Polyline2d({ points: line })) : [] + // todo: use centroid for label position + return new Group2d({ children: [ body, @@ -1151,3 +1154,19 @@ function getCheckBoxLines(w: number, h: number) { ], ] } + +/** + * Get the centroid of a regular polygon. + * @param points - The points that make up the polygon. + * @internal + */ +export function getCentroidOfRegularPolygon(points: VecLike[]) { + const len = points.length + let x = 0 + let y = 0 + for (let i = 0; i < len; i++) { + x += points[i].x + y += points[i].y + } + return new Vec2d(x / len, y / len) +}