diff --git a/packages/editor/src/components/editor/floorplan-panel.tsx b/packages/editor/src/components/editor/floorplan-panel.tsx index f25af51d..f9d75b8c 100644 --- a/packages/editor/src/components/editor/floorplan-panel.tsx +++ b/packages/editor/src/components/editor/floorplan-panel.tsx @@ -558,37 +558,6 @@ type SlabPolygonEntry = { path: string } -function getSlabHandlePolygon(entry: SlabPolygonEntry) { - return entry.visualPolygon.length === entry.polygon.length ? entry.visualPolygon : entry.polygon -} - -function getSlabVisualOffsets(entry: SlabPolygonEntry): Point2D[] { - const handlePolygon = getSlabHandlePolygon(entry) - - return entry.polygon.map((point) => { - const handlePoint = - handlePolygon.length > 0 - ? handlePolygon[getClosestPolygonVertexIndex(point, handlePolygon)] - : point - - return { - x: (handlePoint?.x ?? point.x) - point.x, - y: (handlePoint?.y ?? point.y) - point.y, - } - }) -} - -function getDraftSlabVisualPolygon(draft: SlabBoundaryDraft): Point2D[] { - return draft.polygon.map(([x, y], index) => { - const offset = draft.visualOffsets?.[index] - - return { - x: x + (offset?.x ?? 0), - y: y + (offset?.y ?? 0), - } - }) -} - type CeilingPolygonEntry = { ceiling: CeilingNode polygon: Point2D[] @@ -1430,42 +1399,6 @@ function crossPlanVectors(a: Point2D, b: Point2D) { return a.x * b.y - a.y * b.x } -function getRaySegmentIntersection( - origin: Point2D, - direction: Point2D, - segmentStart: Point2D, - segmentEnd: Point2D, -) { - const segmentVector = { - x: segmentEnd.x - segmentStart.x, - y: segmentEnd.y - segmentStart.y, - } - const denominator = crossPlanVectors(direction, segmentVector) - - if (Math.abs(denominator) <= 1e-9) { - return null - } - - const delta = { - x: segmentStart.x - origin.x, - y: segmentStart.y - origin.y, - } - const rayDistance = crossPlanVectors(delta, segmentVector) / denominator - const segmentT = crossPlanVectors(delta, direction) / denominator - - if (rayDistance < 0 || segmentT < 0 || segmentT > 1) { - return null - } - - return { - point: { - x: origin.x + direction.x * rayDistance, - y: origin.y + direction.y * rayDistance, - }, - rayDistance, - } -} - function getViewportBounds(): ViewportBounds { if (typeof window === 'undefined') { return { @@ -2686,378 +2619,6 @@ type WallFaceLine = { end: Point2D } -type WallMeasurementFaceContext = { - outerFace: WallFaceLine - innerFace: WallFaceLine - outwardNormal: Point2D - inwardNormal: Point2D -} - -function getWallFaceLines( - polygon: Point2D[], - wall: WallNode, -): { left: WallFaceLine; right: WallFaceLine } | null { - if (polygon.length < 4 || isCurvedWall(wall)) { - return null - } - - const startRight = polygon[0] - const endRight = polygon[1] - const hasEndCenterPoint = pointMatchesWallPlanPoint(polygon[2], wall.end) - const endLeft = polygon[hasEndCenterPoint ? 3 : 2] - const lastPoint = polygon[polygon.length - 1] - const hasStartCenterPoint = pointMatchesWallPlanPoint(lastPoint, wall.start) - const startLeft = polygon[hasStartCenterPoint ? polygon.length - 2 : polygon.length - 1] - - if (!(startRight && endRight && endLeft && startLeft)) { - return null - } - - return { - left: { - start: startLeft, - end: endLeft, - }, - right: { - start: startRight, - end: endRight, - }, - } -} - -function getLineMidpoint(line: WallFaceLine): Point2D { - return { - x: (line.start.x + line.end.x) / 2, - y: (line.start.y + line.end.y) / 2, - } -} - -function getWallMeasurementFaceContext( - selectedWallEntry: WallPolygonEntry, - wallPolygons: WallPolygonEntry[], -): WallMeasurementFaceContext | null { - let minX = Number.POSITIVE_INFINITY - let maxX = Number.NEGATIVE_INFINITY - let minY = Number.POSITIVE_INFINITY - let maxY = Number.NEGATIVE_INFINITY - - for (const { wall } of wallPolygons) { - minX = Math.min(minX, wall.start[0], wall.end[0]) - maxX = Math.max(maxX, wall.start[0], wall.end[0]) - minY = Math.min(minY, wall.start[1], wall.end[1]) - maxY = Math.max(maxY, wall.start[1], wall.end[1]) - } - - const centerX = minX === Number.POSITIVE_INFINITY ? 0 : (minX + maxX) / 2 - const centerY = minY === Number.POSITIVE_INFINITY ? 0 : (minY + maxY) / 2 - const { wall, polygon } = selectedWallEntry - const faceLines = getWallFaceLines(polygon, wall) - - if (!faceLines) { - return null - } - - const dx = wall.end[0] - wall.start[0] - const dy = wall.end[1] - wall.start[1] - const length = Math.hypot(dx, dy) - - if (length < 1e-6) { - return null - } - - const wallMidpoint = { - x: (wall.start[0] + wall.end[0]) / 2, - y: (wall.start[1] + wall.end[1]) / 2, - } - const normal = { x: -dy / length, y: dx / length } - const fromCenter = { - x: wallMidpoint.x - centerX, - y: wallMidpoint.y - centerY, - } - const outwardNormal = - fromCenter.x * normal.x + fromCenter.y * normal.y >= 0 ? normal : { x: -normal.x, y: -normal.y } - const rightMidpoint = getLineMidpoint(faceLines.right) - const leftMidpoint = getLineMidpoint(faceLines.left) - const rightScore = - (rightMidpoint.x - wallMidpoint.x) * outwardNormal.x + - (rightMidpoint.y - wallMidpoint.y) * outwardNormal.y - const leftScore = - (leftMidpoint.x - wallMidpoint.x) * outwardNormal.x + - (leftMidpoint.y - wallMidpoint.y) * outwardNormal.y - const outerFace = rightScore >= leftScore ? faceLines.right : faceLines.left - const innerFace = outerFace === faceLines.right ? faceLines.left : faceLines.right - - return { - outerFace, - innerFace, - outwardNormal, - inwardNormal: { x: -outwardNormal.x, y: -outwardNormal.y }, - } -} - -function getAdjacentOpeningBounds( - current: { - id: OpeningNode['id'] - wallId: WallNode['id'] - startDistance: number - endDistance: number - }, - openings: OpeningPolygonEntry[], -) { - let leftBoundary: number | null = null - let rightBoundary: number | null = null - - for (const { opening } of openings) { - if (opening.parentId !== current.wallId || opening.id === current.id) { - continue - } - - const startDistance = opening.position[0] - opening.width / 2 - const endDistance = opening.position[0] + opening.width / 2 - - if ( - endDistance <= current.startDistance && - (leftBoundary === null || endDistance > leftBoundary) - ) { - leftBoundary = endDistance - } - - if ( - startDistance >= current.endDistance && - (rightBoundary === null || startDistance < rightBoundary) - ) { - rightBoundary = startDistance - } - } - - return { - leftBoundary, - rightBoundary, - } -} - -function getSelectedWallMeasurementOverlays( - selectedWallEntry: WallPolygonEntry, - wallPolygons: WallPolygonEntry[], - unit: 'metric' | 'imperial', - metersPerUnit: number | null = null, -): LinearMeasurementOverlay[] { - const { wall } = selectedWallEntry - - if (isCurvedWall(wall)) { - let minX = Number.POSITIVE_INFINITY - let maxX = Number.NEGATIVE_INFINITY - let minY = Number.POSITIVE_INFINITY - let maxY = Number.NEGATIVE_INFINITY - - for (const { wall: candidateWall } of wallPolygons) { - minX = Math.min(minX, candidateWall.start[0], candidateWall.end[0]) - maxX = Math.max(maxX, candidateWall.start[0], candidateWall.end[0]) - minY = Math.min(minY, candidateWall.start[1], candidateWall.end[1]) - maxY = Math.max(maxY, candidateWall.start[1], candidateWall.end[1]) - } - - const centerX = minX === Number.POSITIVE_INFINITY ? 0 : (minX + maxX) / 2 - const centerY = minY === Number.POSITIVE_INFINITY ? 0 : (minY + maxY) / 2 - const overlay = getWallMeasurementOverlay(wall, centerX, centerY, unit, metersPerUnit) - return overlay ? [overlay] : [] - } - - const faceContext = getWallMeasurementFaceContext(selectedWallEntry, wallPolygons) - if (!faceContext) { - let minX = Number.POSITIVE_INFINITY - let maxX = Number.NEGATIVE_INFINITY - let minY = Number.POSITIVE_INFINITY - let maxY = Number.NEGATIVE_INFINITY - - for (const { wall: candidateWall } of wallPolygons) { - minX = Math.min(minX, candidateWall.start[0], candidateWall.end[0]) - maxX = Math.max(maxX, candidateWall.start[0], candidateWall.end[0]) - minY = Math.min(minY, candidateWall.start[1], candidateWall.end[1]) - maxY = Math.max(maxY, candidateWall.start[1], candidateWall.end[1]) - } - - const centerX = minX === Number.POSITIVE_INFINITY ? 0 : (minX + maxX) / 2 - const centerY = minY === Number.POSITIVE_INFINITY ? 0 : (minY + maxY) / 2 - const overlay = getWallMeasurementOverlay(wall, centerX, centerY, unit, metersPerUnit) - return overlay ? [overlay] : [] - } - - const { outerFace, innerFace, outwardNormal, inwardNormal } = faceContext - const outerLength = Math.hypot( - outerFace.end.x - outerFace.start.x, - outerFace.end.y - outerFace.start.y, - ) - const innerLength = Math.hypot( - innerFace.end.x - innerFace.start.x, - innerFace.end.y - innerFace.start.y, - ) - const overlays: LinearMeasurementOverlay[] = [] - - if (outerLength >= 0.1) { - const overlay = getLinearMeasurementOverlay( - `${wall.id}:outer-face`, - outerFace.start, - outerFace.end, - formatMeasurement(outerLength, unit, metersPerUnit), - { - offsetDistance: FLOORPLAN_WALL_OUTER_MEASUREMENT_OFFSET, - offsetVector: outwardNormal, - }, - ) - - if (overlay) { - overlays.push({ - ...overlay, - extensionStroke: FLOORPLAN_WALL_OUTER_MEASUREMENT_EXTENSION, - labelFill: FLOORPLAN_WALL_OUTER_MEASUREMENT_TEXT, - stroke: FLOORPLAN_WALL_OUTER_MEASUREMENT_STROKE, - }) - } - } - - if (innerLength >= 0.1) { - const overlay = getLinearMeasurementOverlay( - `${wall.id}:inner-face`, - innerFace.start, - innerFace.end, - formatMeasurement(innerLength, unit, metersPerUnit), - { - offsetDistance: FLOORPLAN_WALL_INNER_MEASUREMENT_OFFSET, - offsetVector: inwardNormal, - }, - ) - - if (overlay) { - overlays.push({ - ...overlay, - extensionStroke: FLOORPLAN_WALL_INNER_MEASUREMENT_EXTENSION, - labelFill: FLOORPLAN_WALL_INNER_MEASUREMENT_TEXT, - stroke: FLOORPLAN_WALL_INNER_MEASUREMENT_STROKE, - }) - } - } - - return overlays -} - -function getItemDimensionMeasurementOverlays( - itemEntry: FloorplanItemEntry, - unit: 'metric' | 'imperial', -): LinearMeasurementOverlay[] { - const itemMetadata = - typeof itemEntry.item.metadata === 'object' && - itemEntry.item.metadata !== null && - !Array.isArray(itemEntry.item.metadata) - ? (itemEntry.item.metadata as Record) - : null - - if (itemMetadata?.isTransient !== true) { - return [] - } - - const polygon = itemEntry.polygon - if (polygon.length < 4) { - return [] - } - - const centroid = polygonCentroid(polygon) - const configuredWidth = formatMeasurement( - itemEntry.item.scale[0] * itemEntry.item.asset.dimensions[0], - unit, - ) - const configuredDepth = formatMeasurement( - itemEntry.item.scale[2] * itemEntry.item.asset.dimensions[2], - unit, - ) - const buildSideOverlay = ( - id: string, - start: Point2D, - end: Point2D, - ): LinearMeasurementOverlay | null => { - const edgeVector = { - x: end.x - start.x, - y: end.y - start.y, - } - const tangent = normalizePlanVector(edgeVector) - if (!tangent) { - return null - } - - let outwardNormal: Point2D = { - x: -tangent.y, - y: tangent.x, - } - const midpoint = { - x: (start.x + end.x) / 2, - y: (start.y + end.y) / 2, - } - const centroidVector = { - x: midpoint.x - centroid.x, - y: midpoint.y - centroid.y, - } - - if (dotPlanVectors(outwardNormal, centroidVector) < 0) { - outwardNormal = { - x: -outwardNormal.x, - y: -outwardNormal.y, - } - } - - const overlay = getLinearMeasurementOverlay( - id, - start, - end, - id.includes(':width') ? configuredWidth : configuredDepth, - { - extensionOvershoot: 0, - offsetDistance: FLOORPLAN_ITEM_DIMENSION_OFFSET, - offsetVector: outwardNormal, - }, - ) - - return overlay - ? { - dashedExtensions: false, - ...overlay, - isSelected: true, - showTicks: false, - } - : null - } - - const widthCandidates: LinearMeasurementOverlay[] = [ - polygon[0] && polygon[1] - ? buildSideOverlay(`${itemEntry.item.id}:width-a`, polygon[0], polygon[1]) - : null, - polygon[2] && polygon[3] - ? buildSideOverlay(`${itemEntry.item.id}:width-b`, polygon[3], polygon[2]) - : null, - ].filter((overlay): overlay is LinearMeasurementOverlay => overlay !== null) - - const depthCandidates: LinearMeasurementOverlay[] = [ - polygon[1] && polygon[2] - ? buildSideOverlay(`${itemEntry.item.id}:depth-a`, polygon[1], polygon[2]) - : null, - polygon[0] && polygon[3] - ? buildSideOverlay(`${itemEntry.item.id}:depth-b`, polygon[0], polygon[3]) - : null, - ].filter((overlay): overlay is LinearMeasurementOverlay => overlay !== null) - - const widthOverlay = - widthCandidates.length > 0 - ? widthCandidates.reduce((best, current) => (current.labelY > best.labelY ? current : best)) - : null - const depthOverlay = - depthCandidates.length > 0 - ? depthCandidates.reduce((best, current) => (current.labelX < best.labelX ? current : best)) - : null - - return [widthOverlay, depthOverlay].filter( - (overlay): overlay is LinearMeasurementOverlay => overlay !== null, - ) -} - function getOpeningFootprint(wall: WallNode, node: WindowNode | DoorNode): Point2D[] { const [x1, z1] = wall.start const [x2, z2] = wall.end @@ -4160,26 +3721,6 @@ const FloorplanZoneLayer = memo(function FloorplanZoneLayer({ const FLOORPLAN_ZONE_LABEL_FONT_SIZE = 0.2 -/** Compute polygon centroid using the shoelace formula */ -const polygonCentroid = (polygon: Point2D[]): { x: number; y: number } => { - let signedArea = 0 - let cx = 0 - let cy = 0 - - for (let i = 0; i < polygon.length; i++) { - const p0 = polygon[i]! - const p1 = polygon[(i + 1) % polygon.length]! - const cross = p0.x * p1.y - p1.x * p0.y - signedArea += cross - cx += (p0.x + p1.x) * cross - cy += (p0.y + p1.y) * cross - } - - signedArea /= 2 - const factor = 1 / (6 * signedArea) - return { x: cx * factor, y: cy * factor } -} - function FloorplanZoneLabelInput({ centroid, svgRef, @@ -4696,11 +4237,6 @@ export function FloorplanPanel() { const wallEndpointDragRef = useRef(null) const wallCurveDragRef = useRef(null) const siteBoundaryDraftRef = useRef(null) - const slabBoundaryDraftRef = useRef(null) - const slabHoleBoundaryDraftRef = useRef(null) - const ceilingBoundaryDraftRef = useRef(null) - const ceilingHoleBoundaryDraftRef = useRef(null) - const zoneBoundaryDraftRef = useRef(null) const gestureScaleRef = useRef(1) const panelInteractionRef = useRef(null) const panelBoundsRef = useRef(null) @@ -4789,28 +4325,6 @@ export function FloorplanPanel() { const [zoneDraftPoints, setZoneDraftPoints] = useState([]) const [siteBoundaryDraft, setSiteBoundaryDraft] = useState(null) const [siteVertexDragState, setSiteVertexDragState] = useState(null) - const [slabBoundaryDraft, setSlabBoundaryDraft] = useState(null) - const [slabVertexDragState, setSlabVertexDragState] = useState(null) - const [slabHoleBoundaryDraft, setSlabHoleBoundaryDraft] = useState( - null, - ) - const [slabHoleVertexDragState, setSlabHoleVertexDragState] = - useState(null) - const [slabHoleMoveDraft, setSlabHoleMoveDraft] = useState(null) - const [ceilingBoundaryDraft, setCeilingBoundaryDraft] = useState( - null, - ) - const [ceilingVertexDragState, setCeilingVertexDragState] = - useState(null) - const [ceilingHoleBoundaryDraft, setCeilingHoleBoundaryDraft] = - useState(null) - const [ceilingHoleVertexDragState, setCeilingHoleVertexDragState] = - useState(null) - const [ceilingHoleMoveDraft, setCeilingHoleMoveDraft] = useState( - null, - ) - const [zoneBoundaryDraft, setZoneBoundaryDraft] = useState(null) - const [zoneVertexDragState, setZoneVertexDragState] = useState(null) const [guideTransformDraft, setGuideTransformDraft] = useState(null) const [referenceScaleDraft, setReferenceScaleDraft] = useState(null) const [pendingReferenceScale, setPendingReferenceScale] = useState( @@ -5592,51 +5106,7 @@ export function FloorplanPanel() { !movingFenceEndpoint && isFloorplanItemContextActive const visibleSitePolygon = phase === 'site' ? displaySitePolygon : null - const selectedSlabEditingHoleIndex = - selectedSlabEntry && editingHole?.nodeId === selectedSlabEntry.slab.id - ? editingHole.holeIndex - : null - const selectedSlabEditingHole = - selectedSlabEditingHoleIndex !== null - ? (selectedSlabEntry?.holes[selectedSlabEditingHoleIndex] ?? null) - : null - const selectedCeilingEditingHoleIndex = - selectedCeilingEntry && editingHole?.nodeId === selectedCeilingEntry.ceiling.id - ? editingHole.holeIndex - : null - const selectedCeilingEditingHole = - selectedCeilingEditingHoleIndex !== null - ? (selectedCeilingEntry?.holes[selectedCeilingEditingHoleIndex] ?? null) - : null const shouldShowSiteBoundaryHandles = isSiteEditActive && visibleSitePolygon !== null - const shouldShowSlabBoundaryHandles = - mode === 'select' && - !movingNode && - floorplanSelectionTool === 'click' && - selectedSlabEntry !== null && - selectedSlabEditingHole === null - const shouldShowCeilingBoundaryHandles = - mode === 'select' && - !movingNode && - floorplanSelectionTool === 'click' && - selectedCeilingEntry !== null && - selectedCeilingEditingHole === null - const shouldShowSlabHoleBoundaryHandles = - mode === 'select' && - !movingNode && - floorplanSelectionTool === 'click' && - selectedSlabEntry !== null && - selectedSlabEditingHole !== null && - slabHoleMoveDraft === null - const shouldShowCeilingHoleBoundaryHandles = - mode === 'select' && - !movingNode && - floorplanSelectionTool === 'click' && - selectedCeilingEntry !== null && - selectedCeilingEditingHole !== null && - ceilingHoleMoveDraft === null - const shouldShowZoneBoundaryHandles = canSelectFloorplanZones && selectedZoneEntry !== null - const showZonePolygons = true // Zone polygons always visible (labels always clickable) const visibleZonePolygons = displayZonePolygons const selectedIdSet = useMemo(() => new Set(selectedIds), [selectedIds]) const highlightedFloorplanIdSet = useMemo( @@ -5935,14 +5405,7 @@ export function FloorplanPanel() { movingFenceEndpoint != null || curvingWall != null || curvingFence != null || - ceilingVertexDragState != null || - ceilingHoleMoveDraft != null || - ceilingHoleVertexDragState != null || - slabHoleMoveDraft != null || - slabHoleVertexDragState != null || - slabVertexDragState != null || siteVertexDragState != null || - zoneVertexDragState != null || isPolygonDraftBuildActive if (!(hasUserAdjustedViewportRef.current || transientFloorplanFit)) { @@ -5959,14 +5422,7 @@ export function FloorplanPanel() { levelId, movingFenceEndpoint, movingNode, - ceilingVertexDragState, - ceilingHoleMoveDraft, - ceilingHoleVertexDragState, siteVertexDragState, - slabHoleMoveDraft, - slabHoleVertexDragState, - slabVertexDragState, - zoneVertexDragState, ]) const viewBox = useMemo(() => { @@ -6606,26 +6062,6 @@ export function FloorplanPanel() { siteBoundaryDraftRef.current = siteBoundaryDraft }, [siteBoundaryDraft]) - useEffect(() => { - slabBoundaryDraftRef.current = slabBoundaryDraft - }, [slabBoundaryDraft]) - - useEffect(() => { - slabHoleBoundaryDraftRef.current = slabHoleBoundaryDraft - }, [slabHoleBoundaryDraft]) - - useEffect(() => { - ceilingBoundaryDraftRef.current = ceilingBoundaryDraft - }, [ceilingBoundaryDraft]) - - useEffect(() => { - ceilingHoleBoundaryDraftRef.current = ceilingHoleBoundaryDraft - }, [ceilingHoleBoundaryDraft]) - - useEffect(() => { - zoneBoundaryDraftRef.current = zoneBoundaryDraft - }, [zoneBoundaryDraft]) - useEffect(() => { guideTransformDraftRef.current = guideTransformDraft }, [guideTransformDraft]) @@ -6855,35 +6291,6 @@ export function FloorplanPanel() { setSiteBoundaryDraft(null) setHoveredSiteHandleId(null) }, []) - const clearSlabBoundaryInteraction = useCallback(() => { - setSlabVertexDragState(null) - setSlabBoundaryDraft(null) - setHoveredSlabHandleId(null) - document.body.style.cursor = '' - }, []) - const clearSlabHoleBoundaryInteraction = useCallback(() => { - setSlabHoleVertexDragState(null) - setSlabHoleBoundaryDraft(null) - setHoveredSlabHandleId(null) - document.body.style.cursor = '' - }, []) - const clearCeilingBoundaryInteraction = useCallback(() => { - setCeilingVertexDragState(null) - setCeilingBoundaryDraft(null) - setHoveredCeilingHandleId(null) - document.body.style.cursor = '' - }, []) - const clearCeilingHoleBoundaryInteraction = useCallback(() => { - setCeilingHoleVertexDragState(null) - setCeilingHoleBoundaryDraft(null) - setHoveredCeilingHandleId(null) - document.body.style.cursor = '' - }, []) - const clearZoneBoundaryInteraction = useCallback(() => { - setZoneVertexDragState(null) - setZoneBoundaryDraft(null) - setHoveredZoneHandleId(null) - }, []) const clearDraft = useCallback(() => { clearWallPlacementDraft() @@ -6895,20 +6302,14 @@ export function FloorplanPanel() { clearWallEndpointDrag() clearWallCurveDrag() clearSiteBoundaryInteraction() - clearSlabBoundaryInteraction() - clearCeilingBoundaryInteraction() - clearZoneBoundaryInteraction() setCursorPoint(null) }, [ - clearCeilingBoundaryInteraction, clearFencePlacementDraft, clearCeilingPlacementDraft, clearRoofPlacementDraft, clearWallCurveDrag, clearSiteBoundaryInteraction, - clearSlabBoundaryInteraction, clearSlabPlacementDraft, - clearZoneBoundaryInteraction, clearWallEndpointDrag, clearWallPlacementDraft, clearZonePlacementDraft, @@ -7595,46 +6996,6 @@ export function FloorplanPanel() { clearSiteBoundaryInteraction() }, [clearSiteBoundaryInteraction, shouldShowSiteBoundaryHandles]) - useEffect(() => { - if (shouldShowSlabBoundaryHandles) { - return - } - - clearSlabBoundaryInteraction() - }, [clearSlabBoundaryInteraction, shouldShowSlabBoundaryHandles]) - - useEffect(() => { - if (shouldShowCeilingBoundaryHandles) { - return - } - - clearCeilingBoundaryInteraction() - }, [clearCeilingBoundaryInteraction, shouldShowCeilingBoundaryHandles]) - - useEffect(() => { - if (shouldShowSlabHoleBoundaryHandles) { - return - } - - clearSlabHoleBoundaryInteraction() - }, [clearSlabHoleBoundaryInteraction, shouldShowSlabHoleBoundaryHandles]) - - useEffect(() => { - if (shouldShowCeilingHoleBoundaryHandles) { - return - } - - clearCeilingHoleBoundaryInteraction() - }, [clearCeilingHoleBoundaryInteraction, shouldShowCeilingHoleBoundaryHandles]) - - useEffect(() => { - if (shouldShowZoneBoundaryHandles) { - return - } - - clearZoneBoundaryInteraction() - }, [clearZoneBoundaryInteraction, shouldShowZoneBoundaryHandles]) - useEffect(() => { const dragState = siteVertexDragState if (!dragState) { @@ -7739,773 +7100,6 @@ export function FloorplanPanel() { updateNode, ]) - useEffect(() => { - const dragState = slabVertexDragState - if (!dragState) { - return - } - - const handleWindowPointerMove = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - event.preventDefault() - - const planPoint = getPlanPointFromClientPoint(event.clientX, event.clientY) - if (!planPoint) { - return - } - - const snappedHandlePoint: WallPlanPoint = [snapToHalf(planPoint[0]), snapToHalf(planPoint[1])] - setCursorPoint(snappedHandlePoint) - const snappedPoint: WallPlanPoint = [ - snappedHandlePoint[0] - dragState.visualOffset.x, - snappedHandlePoint[1] - dragState.visualOffset.y, - ] - - setSlabBoundaryDraft((currentDraft) => { - if (!currentDraft || currentDraft.slabId !== dragState.slabId) { - return currentDraft - } - - if ( - dragState.mode === 'edge' && - dragState.edgeIndex !== undefined && - dragState.edgeNormal && - dragState.initialPlanPoint && - dragState.initialPolygon - ) { - const nextPolygon = moveFloorplanPolygonEdge( - dragState.initialPolygon, - dragState.edgeIndex, - dragState.edgeNormal, - dragState.initialPlanPoint, - snappedPoint, - ) - - if (polygonsEqual(currentDraft.polygon, nextPolygon)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - return { - ...currentDraft, - polygon: nextPolygon, - } - } - - const currentPoint = currentDraft.polygon[dragState.vertexIndex] - if (currentPoint && pointsEqual(currentPoint, snappedPoint)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - - const nextPolygon = [...currentDraft.polygon] - nextPolygon[dragState.vertexIndex] = snappedPoint - - return { - ...currentDraft, - polygon: nextPolygon, - } - }) - } - - const commitSlabVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - const draft = slabBoundaryDraftRef.current - const slab = slabById.get(dragState.slabId) - if (draft && slab && !polygonsEqual(draft.polygon, slab.polygon)) { - const suppressClick = (clickEvent: MouseEvent) => { - clickEvent.stopImmediatePropagation() - clickEvent.preventDefault() - window.removeEventListener('click', suppressClick, true) - } - window.addEventListener('click', suppressClick, true) - requestAnimationFrame(() => { - window.removeEventListener('click', suppressClick, true) - }) - - updateNode(draft.slabId, { - polygon: draft.polygon, - }) - sfxEmitter.emit('sfx:structure-build') - } - - clearSlabBoundaryInteraction() - setCursorPoint(null) - } - - const cancelSlabVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - clearSlabBoundaryInteraction() - setCursorPoint(null) - } - - window.addEventListener('pointermove', handleWindowPointerMove) - window.addEventListener('pointerup', commitSlabVertexDrag) - window.addEventListener('pointercancel', cancelSlabVertexDrag) - - return () => { - window.removeEventListener('pointermove', handleWindowPointerMove) - window.removeEventListener('pointerup', commitSlabVertexDrag) - window.removeEventListener('pointercancel', cancelSlabVertexDrag) - } - }, [ - clearSlabBoundaryInteraction, - getPlanPointFromClientPoint, - slabById, - slabVertexDragState, - updateNode, - ]) - - useEffect(() => { - const dragState = ceilingVertexDragState - if (!dragState) { - return - } - - const handleWindowPointerMove = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - event.preventDefault() - - const planPoint = getPlanPointFromClientPoint(event.clientX, event.clientY) - if (!planPoint) { - return - } - - const snappedPoint: WallPlanPoint = [snapToHalf(planPoint[0]), snapToHalf(planPoint[1])] - setCursorPoint(snappedPoint) - - setCeilingBoundaryDraft((currentDraft) => { - if (!currentDraft || currentDraft.ceilingId !== dragState.ceilingId) { - return currentDraft - } - - if ( - dragState.mode === 'edge' && - dragState.edgeIndex !== undefined && - dragState.edgeNormal && - dragState.initialPlanPoint && - dragState.initialPolygon - ) { - const nextPolygon = moveFloorplanPolygonEdge( - dragState.initialPolygon, - dragState.edgeIndex, - dragState.edgeNormal, - dragState.initialPlanPoint, - snappedPoint, - ) - - if (polygonsEqual(currentDraft.polygon, nextPolygon)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - return { - ...currentDraft, - polygon: nextPolygon, - } - } - - const currentPoint = currentDraft.polygon[dragState.vertexIndex] - if (currentPoint && pointsEqual(currentPoint, snappedPoint)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - - const nextPolygon = [...currentDraft.polygon] - nextPolygon[dragState.vertexIndex] = snappedPoint - - return { - ...currentDraft, - polygon: nextPolygon, - } - }) - } - - const commitCeilingVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - const draft = ceilingBoundaryDraftRef.current - const ceiling = ceilingById.get(dragState.ceilingId) - if (draft && ceiling && !polygonsEqual(draft.polygon, ceiling.polygon)) { - const suppressClick = (clickEvent: MouseEvent) => { - clickEvent.stopImmediatePropagation() - clickEvent.preventDefault() - window.removeEventListener('click', suppressClick, true) - } - window.addEventListener('click', suppressClick, true) - requestAnimationFrame(() => { - window.removeEventListener('click', suppressClick, true) - }) - - updateNode(draft.ceilingId, { - polygon: draft.polygon, - }) - sfxEmitter.emit('sfx:structure-build') - } - - clearCeilingBoundaryInteraction() - setCursorPoint(null) - } - - const cancelCeilingVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - clearCeilingBoundaryInteraction() - setCursorPoint(null) - } - - window.addEventListener('pointermove', handleWindowPointerMove) - window.addEventListener('pointerup', commitCeilingVertexDrag) - window.addEventListener('pointercancel', cancelCeilingVertexDrag) - - return () => { - window.removeEventListener('pointermove', handleWindowPointerMove) - window.removeEventListener('pointerup', commitCeilingVertexDrag) - window.removeEventListener('pointercancel', cancelCeilingVertexDrag) - } - }, [ - ceilingById, - ceilingVertexDragState, - clearCeilingBoundaryInteraction, - getPlanPointFromClientPoint, - updateNode, - ]) - - useEffect(() => { - const dragState = slabHoleVertexDragState - if (!dragState) { - return - } - - const handleWindowPointerMove = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - event.preventDefault() - - const planPoint = getPlanPointFromClientPoint(event.clientX, event.clientY) - if (!planPoint) { - return - } - - const snappedPoint: WallPlanPoint = [snapToHalf(planPoint[0]), snapToHalf(planPoint[1])] - setCursorPoint(snappedPoint) - - setSlabHoleBoundaryDraft((currentDraft) => { - if ( - !currentDraft || - currentDraft.slabId !== dragState.slabId || - currentDraft.holeIndex !== dragState.holeIndex - ) { - return currentDraft - } - - if ( - dragState.mode === 'edge' && - dragState.edgeIndex !== undefined && - dragState.edgeNormal && - dragState.initialPlanPoint && - dragState.initialPolygon - ) { - const nextPolygon = moveFloorplanPolygonEdge( - dragState.initialPolygon, - dragState.edgeIndex, - dragState.edgeNormal, - dragState.initialPlanPoint, - snappedPoint, - ) - - if (polygonsEqual(currentDraft.polygon, nextPolygon)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - return { - ...currentDraft, - polygon: nextPolygon, - } - } - - const currentPoint = currentDraft.polygon[dragState.vertexIndex] - if (currentPoint && pointsEqual(currentPoint, snappedPoint)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - - const nextPolygon = [...currentDraft.polygon] - nextPolygon[dragState.vertexIndex] = snappedPoint - - return { - ...currentDraft, - polygon: nextPolygon, - } - }) - } - - const commitSlabHoleVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - const draft = slabHoleBoundaryDraftRef.current - const slab = slabById.get(dragState.slabId) - const currentHole = slab?.holes?.[dragState.holeIndex] - if (draft && slab && currentHole && !polygonsEqual(draft.polygon, currentHole)) { - const suppressClick = (clickEvent: MouseEvent) => { - clickEvent.stopImmediatePropagation() - clickEvent.preventDefault() - window.removeEventListener('click', suppressClick, true) - } - window.addEventListener('click', suppressClick, true) - requestAnimationFrame(() => { - window.removeEventListener('click', suppressClick, true) - }) - - const nextHoles = [...(slab.holes ?? [])] - nextHoles[draft.holeIndex] = draft.polygon - updateNode(draft.slabId, { - holes: nextHoles, - }) - sfxEmitter.emit('sfx:structure-build') - } - - clearSlabHoleBoundaryInteraction() - setCursorPoint(null) - } - - const cancelSlabHoleVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - clearSlabHoleBoundaryInteraction() - setCursorPoint(null) - } - - window.addEventListener('pointermove', handleWindowPointerMove) - window.addEventListener('pointerup', commitSlabHoleVertexDrag) - window.addEventListener('pointercancel', cancelSlabHoleVertexDrag) - - return () => { - window.removeEventListener('pointermove', handleWindowPointerMove) - window.removeEventListener('pointerup', commitSlabHoleVertexDrag) - window.removeEventListener('pointercancel', cancelSlabHoleVertexDrag) - } - }, [ - clearSlabHoleBoundaryInteraction, - getPlanPointFromClientPoint, - slabById, - slabHoleVertexDragState, - updateNode, - ]) - - useEffect(() => { - const moveDraft = slabHoleMoveDraft - if (!moveDraft) { - return - } - - const updateMoveDraft = (clientX: number, clientY: number) => { - const planPoint = getPlanPointFromClientPoint(clientX, clientY) - if (!planPoint) { - return - } - - const snappedPoint: WallPlanPoint = [snapToHalf(planPoint[0]), snapToHalf(planPoint[1])] - const deltaX = snappedPoint[0] - moveDraft.startPlanPoint[0] - const deltaY = snappedPoint[1] - moveDraft.startPlanPoint[1] - const nextPolygon = moveDraft.originalPolygon.map( - ([x, y]) => [x + deltaX, y + deltaY] as WallPlanPoint, - ) - - setCursorPoint(snappedPoint) - setSlabHoleMoveDraft((currentDraft) => - currentDraft && - currentDraft.slabId === moveDraft.slabId && - currentDraft.holeIndex === moveDraft.holeIndex - ? { - ...currentDraft, - polygon: nextPolygon, - } - : currentDraft, - ) - } - - const commitSlabHoleMove = (event: PointerEvent) => { - if (event.button !== 0) { - return - } - - event.preventDefault() - event.stopPropagation() - - const slab = slabById.get(moveDraft.slabId) - const currentHole = slab?.holes?.[moveDraft.holeIndex] - if (slab && currentHole && !polygonsEqual(moveDraft.polygon, currentHole)) { - const nextHoles = [...(slab.holes ?? [])] - nextHoles[moveDraft.holeIndex] = moveDraft.polygon - updateNode(moveDraft.slabId, { - holes: nextHoles, - }) - sfxEmitter.emit('sfx:structure-build') - } - - setSlabHoleMoveDraft(null) - setCursorPoint(null) - } - - const cancelSlabHoleMove = (event: KeyboardEvent) => { - if (event.key !== 'Escape') { - return - } - - event.preventDefault() - setSlabHoleMoveDraft(null) - setCursorPoint(null) - } - - const handleWindowPointerMove = (event: PointerEvent) => { - updateMoveDraft(event.clientX, event.clientY) - } - - window.addEventListener('pointermove', handleWindowPointerMove) - window.addEventListener('pointerdown', commitSlabHoleMove, true) - window.addEventListener('keydown', cancelSlabHoleMove) - - return () => { - window.removeEventListener('pointermove', handleWindowPointerMove) - window.removeEventListener('pointerdown', commitSlabHoleMove, true) - window.removeEventListener('keydown', cancelSlabHoleMove) - } - }, [getPlanPointFromClientPoint, slabById, slabHoleMoveDraft, updateNode]) - - useEffect(() => { - const dragState = ceilingHoleVertexDragState - if (!dragState) { - return - } - - const handleWindowPointerMove = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - event.preventDefault() - - const planPoint = getPlanPointFromClientPoint(event.clientX, event.clientY) - if (!planPoint) { - return - } - - const snappedPoint: WallPlanPoint = [snapToHalf(planPoint[0]), snapToHalf(planPoint[1])] - setCursorPoint(snappedPoint) - - setCeilingHoleBoundaryDraft((currentDraft) => { - if ( - !currentDraft || - currentDraft.ceilingId !== dragState.ceilingId || - currentDraft.holeIndex !== dragState.holeIndex - ) { - return currentDraft - } - - if ( - dragState.mode === 'edge' && - dragState.edgeIndex !== undefined && - dragState.edgeNormal && - dragState.initialPlanPoint && - dragState.initialPolygon - ) { - const nextPolygon = moveFloorplanPolygonEdge( - dragState.initialPolygon, - dragState.edgeIndex, - dragState.edgeNormal, - dragState.initialPlanPoint, - snappedPoint, - ) - - if (polygonsEqual(currentDraft.polygon, nextPolygon)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - return { - ...currentDraft, - polygon: nextPolygon, - } - } - - const currentPoint = currentDraft.polygon[dragState.vertexIndex] - if (currentPoint && pointsEqual(currentPoint, snappedPoint)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - - const nextPolygon = [...currentDraft.polygon] - nextPolygon[dragState.vertexIndex] = snappedPoint - - return { - ...currentDraft, - polygon: nextPolygon, - } - }) - } - - const commitCeilingHoleVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - const draft = ceilingHoleBoundaryDraftRef.current - const ceiling = ceilingById.get(dragState.ceilingId) - const currentHole = ceiling?.holes?.[dragState.holeIndex] - if (draft && ceiling && currentHole && !polygonsEqual(draft.polygon, currentHole)) { - const suppressClick = (clickEvent: MouseEvent) => { - clickEvent.stopImmediatePropagation() - clickEvent.preventDefault() - window.removeEventListener('click', suppressClick, true) - } - window.addEventListener('click', suppressClick, true) - requestAnimationFrame(() => { - window.removeEventListener('click', suppressClick, true) - }) - - const nextHoles = [...(ceiling.holes ?? [])] - nextHoles[draft.holeIndex] = draft.polygon - updateNode(draft.ceilingId, { - holes: nextHoles, - }) - sfxEmitter.emit('sfx:structure-build') - } - - clearCeilingHoleBoundaryInteraction() - setCursorPoint(null) - } - - const cancelCeilingHoleVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - clearCeilingHoleBoundaryInteraction() - setCursorPoint(null) - } - - window.addEventListener('pointermove', handleWindowPointerMove) - window.addEventListener('pointerup', commitCeilingHoleVertexDrag) - window.addEventListener('pointercancel', cancelCeilingHoleVertexDrag) - - return () => { - window.removeEventListener('pointermove', handleWindowPointerMove) - window.removeEventListener('pointerup', commitCeilingHoleVertexDrag) - window.removeEventListener('pointercancel', cancelCeilingHoleVertexDrag) - } - }, [ - ceilingById, - ceilingHoleVertexDragState, - clearCeilingHoleBoundaryInteraction, - getPlanPointFromClientPoint, - updateNode, - ]) - - useEffect(() => { - const moveDraft = ceilingHoleMoveDraft - if (!moveDraft) { - return - } - - const updateMoveDraft = (clientX: number, clientY: number) => { - const planPoint = getPlanPointFromClientPoint(clientX, clientY) - if (!planPoint) { - return - } - - const snappedPoint: WallPlanPoint = [snapToHalf(planPoint[0]), snapToHalf(planPoint[1])] - const deltaX = snappedPoint[0] - moveDraft.startPlanPoint[0] - const deltaY = snappedPoint[1] - moveDraft.startPlanPoint[1] - const nextPolygon = moveDraft.originalPolygon.map( - ([x, y]) => [x + deltaX, y + deltaY] as WallPlanPoint, - ) - - setCursorPoint(snappedPoint) - setCeilingHoleMoveDraft((currentDraft) => - currentDraft && - currentDraft.ceilingId === moveDraft.ceilingId && - currentDraft.holeIndex === moveDraft.holeIndex - ? { - ...currentDraft, - polygon: nextPolygon, - } - : currentDraft, - ) - } - - const commitCeilingHoleMove = (event: PointerEvent) => { - if (event.button !== 0) { - return - } - - event.preventDefault() - event.stopPropagation() - - const ceiling = ceilingById.get(moveDraft.ceilingId) - const currentHole = ceiling?.holes?.[moveDraft.holeIndex] - if (ceiling && currentHole && !polygonsEqual(moveDraft.polygon, currentHole)) { - const nextHoles = [...(ceiling.holes ?? [])] - nextHoles[moveDraft.holeIndex] = moveDraft.polygon - updateNode(moveDraft.ceilingId, { - holes: nextHoles, - }) - sfxEmitter.emit('sfx:structure-build') - } - - setCeilingHoleMoveDraft(null) - setCursorPoint(null) - } - - const cancelCeilingHoleMove = (event: KeyboardEvent) => { - if (event.key !== 'Escape') { - return - } - - event.preventDefault() - setCeilingHoleMoveDraft(null) - setCursorPoint(null) - } - - const handleWindowPointerMove = (event: PointerEvent) => { - updateMoveDraft(event.clientX, event.clientY) - } - - window.addEventListener('pointermove', handleWindowPointerMove) - window.addEventListener('pointerdown', commitCeilingHoleMove, true) - window.addEventListener('keydown', cancelCeilingHoleMove) - - return () => { - window.removeEventListener('pointermove', handleWindowPointerMove) - window.removeEventListener('pointerdown', commitCeilingHoleMove, true) - window.removeEventListener('keydown', cancelCeilingHoleMove) - } - }, [ceilingById, ceilingHoleMoveDraft, getPlanPointFromClientPoint, updateNode]) - - useEffect(() => { - const dragState = zoneVertexDragState - if (!dragState) { - return - } - - const handleWindowPointerMove = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - event.preventDefault() - - const planPoint = getPlanPointFromClientPoint(event.clientX, event.clientY) - if (!planPoint) { - return - } - - const snappedPoint: WallPlanPoint = [snapToHalf(planPoint[0]), snapToHalf(planPoint[1])] - setCursorPoint(snappedPoint) - - setZoneBoundaryDraft((currentDraft) => { - if (!currentDraft || currentDraft.zoneId !== dragState.zoneId) { - return currentDraft - } - - const currentPoint = currentDraft.polygon[dragState.vertexIndex] - if (currentPoint && pointsEqual(currentPoint, snappedPoint)) { - return currentDraft - } - - sfxEmitter.emit('sfx:grid-snap') - - const nextPolygon = [...currentDraft.polygon] - nextPolygon[dragState.vertexIndex] = snappedPoint - - return { - ...currentDraft, - polygon: nextPolygon, - } - }) - } - - const commitZoneVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - const draft = zoneBoundaryDraftRef.current - const zone = zoneById.get(dragState.zoneId) - if (draft && zone && !polygonsEqual(draft.polygon, zone.polygon)) { - const suppressClick = (clickEvent: MouseEvent) => { - clickEvent.stopImmediatePropagation() - clickEvent.preventDefault() - window.removeEventListener('click', suppressClick, true) - } - window.addEventListener('click', suppressClick, true) - requestAnimationFrame(() => { - window.removeEventListener('click', suppressClick, true) - }) - - updateNode(draft.zoneId, { - polygon: draft.polygon, - }) - sfxEmitter.emit('sfx:structure-build') - } - - clearZoneBoundaryInteraction() - setCursorPoint(null) - } - - const cancelZoneVertexDrag = (event: PointerEvent) => { - if (event.pointerId !== dragState.pointerId) { - return - } - - clearZoneBoundaryInteraction() - setCursorPoint(null) - } - - window.addEventListener('pointermove', handleWindowPointerMove) - window.addEventListener('pointerup', commitZoneVertexDrag) - window.addEventListener('pointercancel', cancelZoneVertexDrag) - - return () => { - window.removeEventListener('pointermove', handleWindowPointerMove) - window.removeEventListener('pointerup', commitZoneVertexDrag) - window.removeEventListener('pointercancel', cancelZoneVertexDrag) - } - }, [ - clearZoneBoundaryInteraction, - getPlanPointFromClientPoint, - updateNode, - zoneById, - zoneVertexDragState, - ]) - useEffect(() => { return () => { setFloorplanHovered(false) @@ -8627,38 +7221,10 @@ export function FloorplanPanel() { return } - if (ceilingHoleMoveDraft) { - return - } - - if (ceilingHoleVertexDragState?.pointerId === event.pointerId) { - return - } - - if (ceilingVertexDragState?.pointerId === event.pointerId) { - return - } - - if (slabHoleMoveDraft) { - return - } - - if (slabHoleVertexDragState?.pointerId === event.pointerId) { - return - } - - if (slabVertexDragState?.pointerId === event.pointerId) { - return - } - if (siteVertexDragState?.pointerId === event.pointerId) { return } - if (zoneVertexDragState?.pointerId === event.pointerId) { - return - } - const planPoint = getPlanPointFromClientPoint(event.clientX, event.clientY) if (!planPoint) { return @@ -8874,14 +7440,8 @@ export function FloorplanPanel() { isWallBuildActive, referenceScaleDraft, roofDraftStart, - ceilingHoleMoveDraft, - ceilingHoleVertexDragState, - ceilingVertexDragState, elevatorResizeDragState, siteVertexDragState, - slabHoleMoveDraft, - slabHoleVertexDragState, - slabVertexDragState, shiftPressed, surfaceSize.height, surfaceSize.width, @@ -8890,7 +7450,6 @@ export function FloorplanPanel() { viewBox.width, viewport, walls, - zoneVertexDragState, ], ) @@ -9614,14 +8173,7 @@ export function FloorplanPanel() { !guideInteractionRef.current && !elevatorResizeDragState && !wallEndpointDragRef.current && - !ceilingVertexDragState && - !ceilingHoleMoveDraft && - !ceilingHoleVertexDragState && - !siteVertexDragState && - !slabHoleMoveDraft && - !slabHoleVertexDragState && - !slabVertexDragState && - !zoneVertexDragState + !siteVertexDragState ) { const rect = event.currentTarget.getBoundingClientRect() const nextPosition = { @@ -9643,19 +8195,7 @@ export function FloorplanPanel() { handlePointerMove(event) }, - [ - handlePointerMove, - hasFloorplanCursorIndicator, - ceilingVertexDragState, - ceilingHoleMoveDraft, - ceilingHoleVertexDragState, - elevatorResizeDragState, - siteVertexDragState, - slabHoleMoveDraft, - slabHoleVertexDragState, - slabVertexDragState, - zoneVertexDragState, - ], + [handlePointerMove, hasFloorplanCursorIndicator, elevatorResizeDragState, siteVertexDragState], ) const handleSvgPointerLeave = useCallback(() => {