Add swing angle support for door rotation
This commit is contained in:
@@ -2841,6 +2841,21 @@ function getOpeningCenterLine(polygon: Point2D[]) {
|
||||
}
|
||||
}
|
||||
|
||||
function isOpeningPlanFlipped(rotation: [number, number, number]) {
|
||||
const normalized =
|
||||
((((rotation[1] % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2)) + 1e-6) % (Math.PI * 2)
|
||||
|
||||
return normalized > Math.PI / 2 && normalized < (Math.PI * 3) / 2
|
||||
}
|
||||
|
||||
function getFlippedHingesSide(hingesSide: DoorNode['hingesSide']) {
|
||||
return hingesSide === 'left' ? 'right' : 'left'
|
||||
}
|
||||
|
||||
function getFlippedSwingDirection(swingDirection: DoorNode['swingDirection']) {
|
||||
return swingDirection === 'inward' ? 'outward' : 'inward'
|
||||
}
|
||||
|
||||
function normalizeGridCoordinate(value: number): number {
|
||||
return Number(value.toFixed(GRID_COORDINATE_PRECISION))
|
||||
}
|
||||
@@ -4301,8 +4316,14 @@ const FloorplanGeometryLayer = memo(function FloorplanGeometryLayer({
|
||||
const px = -ny
|
||||
const py = nx
|
||||
|
||||
const hingesSide = opening.hingesSide ?? 'left'
|
||||
const swingDirection = opening.swingDirection ?? 'inward'
|
||||
const isPlanFlipped = isOpeningPlanFlipped(opening.rotation)
|
||||
const baseHingesSide = opening.hingesSide ?? 'left'
|
||||
const baseSwingDirection = opening.swingDirection ?? 'inward'
|
||||
const hingesSide = isPlanFlipped ? getFlippedHingesSide(baseHingesSide) : baseHingesSide
|
||||
const swingDirection = isPlanFlipped
|
||||
? getFlippedSwingDirection(baseSwingDirection)
|
||||
: baseSwingDirection
|
||||
const swingAngle = Math.max(0, Math.min(Math.PI / 2, opening.swingAngle ?? 0))
|
||||
const width = opening.width
|
||||
const sweepFlag =
|
||||
hingesSide === 'left'
|
||||
@@ -4345,9 +4366,16 @@ const FloorplanGeometryLayer = memo(function FloorplanGeometryLayer({
|
||||
ny * hingeTangentSign * (doorCubeSize / 2),
|
||||
}
|
||||
const swingRadius = Math.hypot(arcEnd.x - leafStart.x, arcEnd.y - leafStart.y)
|
||||
const closedLeafVector = {
|
||||
x: arcEnd.x - leafStart.x,
|
||||
y: arcEnd.y - leafStart.y,
|
||||
}
|
||||
const openAngle = swingAngle * swingSign * hingeTangentSign
|
||||
const openCos = Math.cos(openAngle)
|
||||
const openSin = Math.sin(openAngle)
|
||||
const leafEnd = {
|
||||
x: leafStart.x + px * swingSign * swingRadius,
|
||||
y: leafStart.y + py * swingSign * swingRadius,
|
||||
x: leafStart.x + closedLeafVector.x * openCos - closedLeafVector.y * openSin,
|
||||
y: leafStart.y + closedLeafVector.x * openSin + closedLeafVector.y * openCos,
|
||||
}
|
||||
const doorBackgroundPoints = [
|
||||
{
|
||||
|
||||
@@ -5,6 +5,8 @@ import { runRedo, runUndo } from '../lib/history'
|
||||
import { sfxEmitter } from '../lib/sfx-bus'
|
||||
import useEditor from '../store/use-editor'
|
||||
|
||||
const DOOR_SWING_OPEN_ANGLE = Math.PI / 2
|
||||
|
||||
// Tools call this in their onCancel handler when they have an active mid-action to cancel,
|
||||
// so that the global Escape handler knows not to also switch to select mode.
|
||||
let _toolCancelConsumed = false
|
||||
@@ -145,10 +147,19 @@ export const useKeyboard = ({
|
||||
}
|
||||
} else if ((e.key === 'r' || e.key === 'R') && !isVersionPreviewMode) {
|
||||
// Rotate selected node clockwise if it supports rotation (items, roofs, etc.)
|
||||
// Doors use R to toggle their leaf open/closed around the hinge.
|
||||
const selectedNodeIds = useViewer.getState().selection.selectedIds as AnyNodeId[]
|
||||
if (selectedNodeIds.length === 1) {
|
||||
const node = useScene.getState().nodes[selectedNodeIds[0]!]
|
||||
if (node && 'rotation' in node) {
|
||||
if (node?.type === 'door') {
|
||||
e.preventDefault()
|
||||
const currentSwingAngle = node.swingAngle ?? 0
|
||||
useScene.getState().updateNode(node.id, {
|
||||
swingAngle:
|
||||
currentSwingAngle >= DOOR_SWING_OPEN_ANGLE / 2 ? 0 : DOOR_SWING_OPEN_ANGLE,
|
||||
})
|
||||
sfxEmitter.emit('sfx:item-rotate')
|
||||
} else if (node && 'rotation' in node) {
|
||||
e.preventDefault()
|
||||
const ROTATION_STEP = Math.PI / 4
|
||||
|
||||
@@ -168,7 +179,11 @@ export const useKeyboard = ({
|
||||
const selectedNodeIds = useViewer.getState().selection.selectedIds as AnyNodeId[]
|
||||
if (selectedNodeIds.length === 1) {
|
||||
const node = useScene.getState().nodes[selectedNodeIds[0]!]
|
||||
if (node && 'rotation' in node) {
|
||||
if (node?.type === 'door') {
|
||||
e.preventDefault()
|
||||
useScene.getState().updateNode(node.id, { swingAngle: 0 })
|
||||
sfxEmitter.emit('sfx:item-rotate')
|
||||
} else if (node && 'rotation' in node) {
|
||||
e.preventDefault()
|
||||
const ROTATION_STEP = Math.PI / 4
|
||||
|
||||
|
||||
Reference in New Issue
Block a user