From 75f77c4204f4c2a382ad131bf1f94d60f09154f4 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 14 Aug 2025 13:59:24 +0530 Subject: [PATCH] added direction movement to asset during move and duplication --- .../selection3D/duplicationControls3D.tsx | 53 ++++++++++++++++++- .../selection3D/moveControls3D.tsx | 41 +++++++++++++- .../utils/shortcutkeys/handleShortcutKeys.ts | 5 +- 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx index 344ae4e..e5ca7ab 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx @@ -35,6 +35,7 @@ const DuplicationControls3D = ({ const { selectedVersion } = selectedVersionStore(); const { userId, organization } = getUserData(); + const [axisConstraint, setAxisConstraint] = useState<"x" | "z" | null>(null); const [dragOffset, setDragOffset] = useState(null); const [initialPositions, setInitialPositions] = useState>({}); const [isDuplicating, setIsDuplicating] = useState(false); @@ -82,6 +83,19 @@ const DuplicationControls3D = ({ const onKeyDown = (event: KeyboardEvent) => { const keyCombination = detectModifierKeys(event); + if (isDuplicating && duplicatedObjects.length > 0) { + if (event.key.toLowerCase() === 'x') { + setAxisConstraint(prev => prev === 'x' ? null : 'x'); + event.preventDefault(); + return; + } + if (event.key.toLowerCase() === 'z') { + setAxisConstraint(prev => prev === 'z' ? null : 'z'); + event.preventDefault(); + return; + } + } + if (keyCombination === "Ctrl+D" && movedObjects.length === 0 && rotatedObjects.length === 0) { duplicateSelection(); } @@ -127,7 +141,28 @@ const DuplicationControls3D = ({ } if (dragOffset) { - const adjustedHit = new THREE.Vector3().addVectors(intersectionPoint, dragOffset); + let adjustedHit = new THREE.Vector3().addVectors(intersectionPoint, dragOffset); + + if (axisConstraint) { + const model = scene.getObjectByProperty("uuid", duplicatedObjects[0].userData.modelUuid); + if (model) { + + const currentBasePosition = model.position.clone(); + if (axisConstraint === 'x') { + adjustedHit = new THREE.Vector3( + adjustedHit.x, + currentBasePosition.y, + currentBasePosition.z + ); + } else if (axisConstraint === 'z') { + adjustedHit = new THREE.Vector3( + currentBasePosition.x, + currentBasePosition.y, + adjustedHit.z + ); + } + } + } duplicatedObjects.forEach((duplicatedObject: THREE.Object3D) => { if (duplicatedObject.userData.modelUuid) { @@ -154,6 +189,21 @@ const DuplicationControls3D = ({ } }); + useEffect(() => { + if (duplicatedObjects.length > 0) { + const intersectionPoint = new THREE.Vector3(); + raycaster.setFromCamera(pointer, camera); + const hit = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (hit) { + const model = scene.getObjectByProperty("uuid", duplicatedObjects[0].userData.modelUuid); + if (model) { + const newOffset = calculateDragOffset(model, intersectionPoint); + setDragOffset(newOffset); + } + } + } + }, [axisConstraint, camera, duplicatedObjects]) + const duplicateSelection = useCallback(() => { if (selectedAssets.length > 0 && duplicatedObjects.length === 0) { const positions: Record = {}; @@ -585,6 +635,7 @@ const DuplicationControls3D = ({ setSelectedAssets([]); setIsDuplicating(false); setDragOffset(null); + setAxisConstraint(null); }; return null; diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx index 4916886..865deea 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx @@ -43,6 +43,7 @@ function MoveControls3D({ const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); + const [axisConstraint, setAxisConstraint] = useState<"x" | "z" | null>(null); const [dragOffset, setDragOffset] = useState(null); const [initialPositions, setInitialPositions] = useState>({}); const [initialStates, setInitialStates] = useState>({}); @@ -114,6 +115,19 @@ function MoveControls3D({ if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return; + if (isMoving && movedObjects.length > 0) { + if (event.key.toLowerCase() === 'x') { + setAxisConstraint(prev => prev === 'x' ? null : 'x'); + event.preventDefault(); + return; + } + if (event.key.toLowerCase() === 'z') { + setAxisConstraint(prev => prev === 'z' ? null : 'z'); + event.preventDefault(); + return; + } + } + if (keyCombination !== keyEvent) { if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") { setKeyEvent(keyCombination); @@ -184,9 +198,22 @@ function MoveControls3D({ } } }); - }, 0) + setAxisConstraint(null); + }, 100) }, [movedObjects, initialStates, updateAsset]); + useEffect(() => { + if (movedObjects.length > 0) { + const intersectionPoint = new THREE.Vector3(); + raycaster.setFromCamera(pointer, camera); + const hit = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (hit) { + const newOffset = calculateDragOffset(movedObjects[0], intersectionPoint); + setDragOffset(newOffset); + } + } + }, [axisConstraint, camera, movedObjects]) + useFrame(() => { if (!isMoving || movedObjects.length === 0) return; @@ -204,7 +231,16 @@ function MoveControls3D({ } if (dragOffset) { - const rawBasePosition = new THREE.Vector3().addVectors(intersectionPoint, dragOffset); + let rawBasePosition = new THREE.Vector3().addVectors(intersectionPoint, dragOffset); + + if (axisConstraint) { + const currentBasePosition = movedObjects[0].position.clone(); + if (axisConstraint === 'x') { + rawBasePosition = new THREE.Vector3(rawBasePosition.x, currentBasePosition.y, currentBasePosition.z); + } else if (axisConstraint === 'z') { + rawBasePosition = new THREE.Vector3(currentBasePosition.x, currentBasePosition.y, rawBasePosition.z); + } + } let moveDistance = keyEvent.includes("Shift") ? 0.05 : 1; @@ -422,6 +458,7 @@ function MoveControls3D({ echo.success("Object moved!"); setIsMoving(false); clearSelection(); + setAxisConstraint(null); }; const clearSelection = () => { diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 7abbe2f..2a0d437 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -11,6 +11,7 @@ import useVersionHistoryVisibleStore, { useDfxUpload, useRenameModeStore, useSaveVersion, + useSelectedAssets, useSelectedComment, useSelectedFloorItem, useSelectedWallItem, @@ -40,6 +41,7 @@ const KeyPressListener: React.FC = () => { const { toggleView, setToggleView } = useToggleView(); const { setAddAction } = useAddAction(); const { setSelectedWallItem } = useSelectedWallItem(); + const { selectedAssets } = useSelectedAssets(); const { setActiveTool } = useActiveTool(); const { clearSelectedZone } = useSelectedZoneStore(); const { showShortcuts, setShowShortcuts } = useShortcutStore(); @@ -82,7 +84,7 @@ const KeyPressListener: React.FC = () => { H: "free-hand", }; const tool = toolMap[key]; - if (tool) { + if (tool && selectedAssets.length === 0) { setActiveTool(tool); setActiveSubTool(tool); } @@ -278,6 +280,7 @@ const KeyPressListener: React.FC = () => { hidePlayer, selectedFloorItem, isRenameMode, + selectedAssets ]); return null;