25 lines
1.1 KiB
TypeScript

import { DEFAULT_ANGLE_STEP } from '@pascal-app/core'
/**
* Shared rotation delta for the 2D corner rotate-arrow affordances (column /
* elevator / roof-segment / shelf / spawn / stair — all structurally
* identical). Measures the pointer's angular sweep from the grab bearing
* around the node center, wrapped to [-π, π] so a drag crossing ±π keeps its
* sign, then snaps it to the 15° increment unless `free` (the held Shift the
* contextual HUD advertises). The 2D twin of the 3D gizmo's
* `snapDirectRotationDelta`, so rotating a node reads the same in both views.
*/
export function rotateAffordanceDelta(args: {
center: readonly [number, number]
initialAngle: number
planPoint: readonly [number, number]
free: boolean
}): number {
const { center, initialAngle, planPoint, free } = args
const currentAngle = Math.atan2(planPoint[1] - center[1], planPoint[0] - center[0])
let delta = currentAngle - initialAngle
while (delta > Math.PI) delta -= 2 * Math.PI
while (delta < -Math.PI) delta += 2 * Math.PI
return free ? delta : Math.round(delta / DEFAULT_ANGLE_STEP) * DEFAULT_ANGLE_STEP
}