improve rotation

This commit is contained in:
Steve Ruiz 2021-05-23 09:30:20 +01:00
parent 2a28064a68
commit 6582eb990c
4 changed files with 49 additions and 8 deletions

View file

@ -2,7 +2,7 @@ import { v4 as uuid } from "uuid"
import * as vec from "utils/vec"
import { EllipseShape, ShapeType } from "types"
import { registerShapeUtils } from "./index"
import { boundsContained } from "utils/bounds"
import { boundsContained, getRotatedEllipseBounds } from "utils/bounds"
import { intersectEllipseBounds } from "utils/intersections"
import { pointInEllipse } from "utils/hitTests"
import {
@ -47,8 +47,8 @@ const ellipse = registerShapeUtils<EllipseShape>({
const bounds = {
minX: 0,
maxX: radiusX * 2,
minY: 0,
maxX: radiusX * 2,
maxY: radiusY * 2,
width: radiusX * 2,
height: radiusY * 2,
@ -61,7 +61,13 @@ const ellipse = registerShapeUtils<EllipseShape>({
},
getRotatedBounds(shape) {
return getBoundsFromPoints(getRotatedCorners(shape))
return getRotatedEllipseBounds(
shape.point[0],
shape.point[1],
shape.radiusX,
shape.radiusY,
shape.rotation
)
},
getCenter(shape) {
@ -79,8 +85,6 @@ const ellipse = registerShapeUtils<EllipseShape>({
},
hitTestBounds(this, shape, brushBounds) {
// TODO: Account for rotation
const shapeBounds = this.getBounds(shape)
return (
@ -108,11 +112,16 @@ const ellipse = registerShapeUtils<EllipseShape>({
return shape
},
transform(shape, bounds) {
transform(shape, bounds, { scaleX, scaleY, initialShape }) {
shape.point = [bounds.minX, bounds.minY]
shape.radiusX = bounds.width / 2
shape.radiusY = bounds.height / 2
shape.rotation =
(scaleX < 0 && scaleY >= 0) || (scaleY < 0 && scaleX >= 0)
? -initialShape.rotation
: initialShape.rotation
return shape
},

View file

@ -4,6 +4,7 @@ import BaseSession from "./base-session"
import commands from "state/commands"
import { current } from "immer"
import {
clampToRotationToSegments,
getBoundsCenter,
getCommonBounds,
getPage,
@ -31,10 +32,10 @@ export default class RotateSession extends BaseSession {
const a1 = vec.angle(boundsCenter, this.origin)
const a2 = vec.angle(boundsCenter, point)
let rot = (PI2 + (a2 - a1)) % PI2
let rot = a2 - a1
if (isLocked) {
rot = Math.floor((rot + Math.PI / 8) / (Math.PI / 4)) * (Math.PI / 4)
rot = clampToRotationToSegments(rot, 24)
}
data.boundsRotation = (PI2 + (this.snapshot.boundsRotation + rot)) % PI2

View file

@ -82,3 +82,25 @@ export function boundsAreEqual(a: Bounds, b: Bounds) {
export function pointInBounds(A: number[], b: Bounds) {
return !(A[0] < b.minX || A[0] > b.maxX || A[1] < b.minY || A[1] > b.maxY)
}
export function getRotatedEllipseBounds(
x: number,
y: number,
rx: number,
ry: number,
rotation: number
) {
const c = Math.cos(rotation)
const s = Math.sin(rotation)
const w = Math.hypot(rx * c, ry * s)
const h = Math.hypot(rx * s, ry * c)
return {
minX: x + rx - w,
minY: y + ry - h,
maxX: x + rx + w,
maxY: y + ry + h,
width: w * 2,
height: h * 2,
}
}

View file

@ -1366,3 +1366,12 @@ export function getShapeBounds(shape: Shape) {
export function getBoundsCenter(bounds: Bounds) {
return [bounds.minX + bounds.width / 2, bounds.minY + bounds.height / 2]
}
export function clampRadians(r: number) {
return (Math.PI * 2 + r) % (Math.PI * 2)
}
export function clampToRotationToSegments(r: number, segments: number) {
const seg = (Math.PI * 2) / segments
return Math.floor((clampRadians(r) + seg / 2) / seg) * seg
}