From 7c3e9e2588012983c4719a2bbcfdf86e4ab35ff2 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 22 Sep 2025 14:42:07 +0530 Subject: [PATCH] added error handling in asset move controls and rotate controls --- .../collaboration/socket/builderResponses.tsx | 28 +++- .../selection3D/moveControls3D.tsx | 48 +++---- .../selection3D/rotateControls3D.tsx | 122 +++++++++--------- app/src/store/builder/useAssetStore.ts | 9 ++ 4 files changed, 119 insertions(+), 88 deletions(-) diff --git a/app/src/modules/collaboration/socket/builderResponses.tsx b/app/src/modules/collaboration/socket/builderResponses.tsx index 803933f..fb37660 100644 --- a/app/src/modules/collaboration/socket/builderResponses.tsx +++ b/app/src/modules/collaboration/socket/builderResponses.tsx @@ -9,7 +9,7 @@ import useAisleResponseHandler from "../responseHandler/useAisleResponseHandler" function BuilderResponses() { const { assetStore } = useSceneContext(); - const { getAssetById } = assetStore(); + const { getAssetById, movedObjects, initialStates, updateAsset, resetAsset, setInitialState } = assetStore(); const { selectedAisle, setSelectedAisle, selectedWall, setSelectedWall } = useBuilderStore(); const { builderSocket } = useSocketStore(); const { addAssetToScene, updateAssetInScene, removeAssetFromScene } = useAssetResponseHandler(); @@ -23,6 +23,17 @@ function BuilderResponses() { builderSocket.on("v1:model-asset:response:add", (data: any) => { if (!data.message || !data.data) { + setInitialState({}); + setTimeout(() => { + Object.entries(initialStates).forEach(([key, initialState]) => { + updateAsset(key, { + position: initialState.position, + rotation: initialState.rotation, + }); + + resetAsset(key); + }); + }, 50); echo.error(`Error adding or updating asset`); return; } @@ -41,6 +52,7 @@ function BuilderResponses() { }; addAssetToScene(model, () => { + setInitialState({}); echo.log(`Added asset: ${model.modelName}`); }); } else if (data.message === "Model updated successfully" && data.data) { @@ -58,10 +70,22 @@ function BuilderResponses() { }; updateAssetInScene(model, () => { + setInitialState({}); echo.log(`Updated asset: ${model.modelName}`); }); } else { removeAssetFromScene(data.data.modelUuid, () => { + setInitialState({}); + setTimeout(() => { + Object.entries(initialStates).forEach(([key, initialState]) => { + updateAsset(key, { + position: initialState.position, + rotation: initialState.rotation, + }); + + resetAsset(key); + }); + }, 50); echo.error(`Error adding or updating asset: ${data?.data?.modelName}`); }); } @@ -158,7 +182,7 @@ function BuilderResponses() { builderSocket.off("v1:model-asset:response:delete"); } }; - }, [builderSocket]); + }, [builderSocket, movedObjects, initialStates]); //#endregion //#region WallAsset diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx index 88b7400..10b2c25 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx @@ -41,6 +41,8 @@ function MoveControls3D({ boundingBoxRef }: any) { setDuplicatedObjects, rotatedObjects, setRotatedObjects, + initialStates, + setInitialState, } = assetStore(); const { updateAssetInScene } = useAssetResponseHandler(); const { selectedVersion } = versionStore(); @@ -48,8 +50,6 @@ function MoveControls3D({ boundingBoxRef }: any) { const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">(""); const [axisConstraint, setAxisConstraint] = useState<"x" | "z" | null>(null); const [dragOffset, setDragOffset] = useState(null); - const [initialPositions, setInitialPositions] = useState>({}); - const [initialStates, setInitialStates] = useState>({}); const [isMoving, setIsMoving] = useState(false); const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ left: false, right: false }); const { contextAction, setContextAction } = useContextActionStore(); @@ -204,16 +204,15 @@ function MoveControls3D({ boundingBoxRef }: any) { movedObjects.forEach((movedObject: THREE.Object3D) => { if (movedObject.userData.modelUuid && initialStates[movedObject.uuid]) { const initialState = initialStates[movedObject.uuid]; - const positionArray: [number, number, number] = [initialState.position.x, initialState.position.y, initialState.position.z]; updateAsset(movedObject.userData.modelUuid, { - position: positionArray, - rotation: [initialState.rotation?.x || 0, initialState.rotation?.y || 0, initialState.rotation?.z || 0], + position: initialState.position, + rotation: initialState.rotation, }); - movedObject.position.copy(initialState.position); + movedObject.position.set(initialState.position[0], initialState.position[1], initialState.position[2]); if (initialState.rotation) { - movedObject.rotation.copy(initialState.rotation); + movedObject.rotation.set(initialState.rotation[0], initialState.rotation[1], initialState.rotation[2]); } } }); @@ -231,16 +230,14 @@ function MoveControls3D({ boundingBoxRef }: any) { const initialState = initialStates[movedObject.uuid]; if (!initialState) return; - const positionArray: [number, number, number] = [initialState.position.x, initialState.position.y, initialState.position.z]; - updateAsset(modelUuid, { - position: positionArray, - rotation: [initialState.rotation?.x || 0, initialState.rotation?.y || 0, initialState.rotation?.z || 0], + position: initialState.position, + rotation: initialState.rotation, }); - movedObject.position.copy(initialState.position); + movedObject.position.set(initialState.position[0], initialState.position[1], initialState.position[2]); if (initialState.rotation) { - movedObject.rotation.copy(initialState.rotation); + movedObject.rotation.set(initialState.rotation[0], initialState.rotation[1], initialState.rotation[2]); } setAxisConstraint(null); @@ -287,10 +284,14 @@ function MoveControls3D({ boundingBoxRef }: any) { movedObjects.forEach((movedAsset: THREE.Object3D) => { if (movedAsset.userData.modelUuid) { - const initialPosition = initialPositions[movedAsset.userData.modelUuid]; + const initialState = initialStates[movedAsset.userData.modelUuid]; + const offsetState = initialStates[movedObjects[0].uuid]; - if (initialPosition) { - const relativeOffset = new THREE.Vector3().subVectors(initialPosition, initialPositions[movedObjects[0].uuid]); + if (initialState.position && offsetState.position) { + const relativeOffset = new THREE.Vector3().subVectors( + new THREE.Vector3(initialState.position[0], initialState.position[1], initialState.position[2]), + new THREE.Vector3(offsetState.position[0], offsetState.position[1], offsetState.position[2]) + ); const model = scene.getObjectByProperty("uuid", movedAsset.userData.modelUuid); const newPosition = new THREE.Vector3().addVectors(baseNewPosition, relativeOffset); @@ -317,19 +318,18 @@ function MoveControls3D({ boundingBoxRef }: any) { }); const moveAssets = () => { - const states: Record = {}; + const states: Record = {}; const positions: Record = {}; selectedAssets.forEach((asset: THREE.Object3D) => { states[asset.uuid] = { - position: new THREE.Vector3().copy(asset.position), - rotation: asset.rotation ? new THREE.Euler().copy(asset.rotation) : undefined, + position: asset.position.toArray(), + rotation: [asset.rotation.x, asset.rotation.y, asset.rotation.z], }; positions[asset.uuid] = new THREE.Vector3().copy(asset.position); }); - setInitialStates(states); - setInitialPositions(positions); + setInitialState(states); raycaster.setFromCamera(pointer, camera); const intersectionPoint = new THREE.Vector3(); @@ -357,15 +357,15 @@ function MoveControls3D({ boundingBoxRef }: any) { const model = scene.getObjectByProperty("uuid", movedAsset.userData.modelUuid); if (!asset || !model) return; const position = new THREE.Vector3().copy(model.position); - const initialState = initialStates[movedAsset.uuid]; + const initialState = initialStates[assetUuid]; if (initialState) { assetsToUpdate.push({ type: "Asset", assetData: { ...asset, - position: [initialState.position.x, initialState.position.y, initialState.position.z], - rotation: [initialState.rotation?.x || 0, initialState.rotation?.y || 0, initialState.rotation?.z || 0], + position: initialState.position, + rotation: initialState.rotation, }, newData: { ...asset, diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/rotateControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/rotateControls3D.tsx index 2c14d16..add9dd9 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/rotateControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/rotateControls3D.tsx @@ -27,6 +27,7 @@ function RotateControls3D() { const { push3D } = undoRedo3DStore(); const { updateAsset, + getAssetById, rotatedObjects, setRotatedObjects, selectedAssets, @@ -37,13 +38,13 @@ function RotateControls3D() { setPastedObjects, duplicatedObjects, setDuplicatedObjects, + initialStates, + setInitialState, } = assetStore(); const { updateAssetInScene } = useAssetResponseHandler(); const { selectedVersion } = versionStore(); const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">(""); - const [initialRotations, setInitialRotations] = useState>({}); - const [initialPositions, setInitialPositions] = useState>({}); const [isRotating, setIsRotating] = useState(false); const [isIndividualRotating, setIsIndividualRotating] = useState(false); const prevPointerPosition = useRef(null); @@ -168,7 +169,7 @@ function RotateControls3D() { canvasElement.removeEventListener("keydown", onKeyDown); canvasElement?.removeEventListener("keyup", onKeyUp); }; - }, [camera, scene, toggleView, toolMode, selectedAssets, rotatedObjects, pastedObjects, duplicatedObjects, movedObjects, keyEvent, initialPositions, initialRotations, isIndividualRotating]); + }, [camera, scene, toggleView, toolMode, selectedAssets, rotatedObjects, pastedObjects, duplicatedObjects, movedObjects, keyEvent, initialStates, isIndividualRotating]); useEffect(() => { if (activeModule !== "builder" || toolMode !== "cursor" || toggleView) { @@ -179,55 +180,47 @@ function RotateControls3D() { const resetToInitialRotations = useCallback(() => { setTimeout(() => { - rotatedObjects.forEach((obj: THREE.Object3D) => { - const uuid = obj.uuid; - if (obj.userData.modelUuid) { - const initialRotation = initialRotations[uuid]; - const initialPosition = initialPositions[uuid]; + rotatedObjects.forEach((rotatedObject: THREE.Object3D) => { + if (rotatedObject.userData.modelUuid && initialStates[rotatedObject.uuid]) { + const initialState = initialStates[rotatedObject.uuid]; - if (initialRotation && initialPosition) { - const rotationArray: [number, number, number] = [initialRotation.x, initialRotation.y, initialRotation.z]; - const positionArray: [number, number, number] = [initialPosition.x, initialPosition.y, initialPosition.z]; + updateAsset(rotatedObject.userData.modelUuid, { + position: initialState.position, + rotation: initialState.rotation, + }); - updateAsset(obj.userData.modelUuid, { - rotation: rotationArray, - position: positionArray, - }); - - obj.rotation.copy(initialRotation); - obj.position.copy(initialPosition); + rotatedObject.position.set(initialState.position[0], initialState.position[1], initialState.position[2]); + if (initialState.rotation) { + rotatedObject.rotation.set(initialState.rotation[0], initialState.rotation[1], initialState.rotation[2]); } } }); }, 50); - }, [rotatedObjects, initialRotations, initialPositions, updateAsset]); + }, [rotatedObjects, initialStates, updateAsset]); const resetToInitialRotation = useCallback( (modelUuid: string) => { setTimeout(() => { - const obj = rotatedObjects.find((o: THREE.Object3D) => o.userData.modelUuid === modelUuid); + const rotatedObject = rotatedObjects.find((o: THREE.Object3D) => o.userData.modelUuid === modelUuid); - if (!obj) return; + if (!rotatedObject) return; - const uuid = obj.uuid; - const initialRotation = initialRotations[uuid]; - const initialPosition = initialPositions[uuid]; - - if (initialRotation && initialPosition) { - const rotationArray: [number, number, number] = [initialRotation.x, initialRotation.y, initialRotation.z]; - const positionArray: [number, number, number] = [initialPosition.x, initialPosition.y, initialPosition.z]; + const initialState = initialStates[rotatedObject.uuid]; + if (initialState) { updateAsset(modelUuid, { - rotation: rotationArray, - position: positionArray, + position: initialState.position, + rotation: initialState.rotation, }); - obj.rotation.copy(initialRotation); - obj.position.copy(initialPosition); + rotatedObject.position.set(initialState.position[0], initialState.position[1], initialState.position[2]); + if (initialState.rotation) { + rotatedObject.rotation.set(initialState.rotation[0], initialState.rotation[1], initialState.rotation[2]); + } } }, 50); }, - [rotatedObjects, initialRotations, initialPositions, updateAsset] + [rotatedObjects, initialStates, updateAsset] ); useFrame(() => { @@ -273,7 +266,7 @@ function RotateControls3D() { }); const rotateAssets = useCallback(() => { - const rotations: Record = {}; + const states: Record = {}; const positions: Record = {}; const box = new THREE.Box3(); @@ -282,13 +275,15 @@ function RotateControls3D() { box.getCenter(center); rotationCenter.current = center; - selectedAssets.forEach((obj: THREE.Object3D) => { - rotations[obj.uuid] = new THREE.Euler().copy(obj.rotation); - positions[obj.uuid] = new THREE.Vector3().copy(obj.position); + selectedAssets.forEach((asset: THREE.Object3D) => { + states[asset.uuid] = { + position: asset.position.toArray(), + rotation: [asset.rotation.x, asset.rotation.y, asset.rotation.z], + }; + positions[asset.uuid] = new THREE.Vector3().copy(asset.position); }); - setInitialRotations(rotations); - setInitialPositions(positions); + setInitialState(states); raycaster.setFromCamera(pointer, camera); @@ -304,22 +299,24 @@ function RotateControls3D() { const undoActions: UndoRedo3DAction[] = []; const assetsToUpdate: AssetData[] = []; - rotatedObjects.forEach((obj: THREE.Object3D) => { - if (obj?.userData.modelUuid) { - const asset = assetStore.getState().getAssetById(obj.userData.modelUuid); + rotatedObjects.forEach((rotatedObject: THREE.Object3D) => { + if (rotatedObject) { + const assetUuid = rotatedObject.userData.modelUuid; + const asset = getAssetById(assetUuid); if (!asset) return; + const initialState = initialStates[assetUuid]; - const rotationArray: [number, number, number] = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; + const rotationArray: [number, number, number] = [rotatedObject.rotation.x, rotatedObject.rotation.y, rotatedObject.rotation.z]; - const positionArray: [number, number, number] = [obj.position.x, obj.position.y, obj.position.z]; + const positionArray: [number, number, number] = [rotatedObject.position.x, rotatedObject.position.y, rotatedObject.position.z]; - if (initialRotations[obj.uuid] && initialPositions[obj.uuid]) { + if (initialState) { assetsToUpdate.push({ type: "Asset", assetData: { ...asset, - position: [initialPositions[obj.uuid].x, initialPositions[obj.uuid].y, initialPositions[obj.uuid].z], - rotation: [initialRotations[obj.uuid].x, initialRotations[obj.uuid].y, initialRotations[obj.uuid].z], + position: initialState.position, + rotation: initialState.rotation, }, newData: { ...asset, @@ -331,28 +328,28 @@ function RotateControls3D() { } const newFloorItem: Types.FloorItemType = { - modelUuid: obj.userData.modelUuid, - modelName: obj.userData.modelName, - assetId: obj.userData.assetId, + modelUuid: rotatedObject.userData.modelUuid, + modelName: rotatedObject.userData.modelName, + assetId: rotatedObject.userData.assetId, position: positionArray, - rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + rotation: { x: rotatedObject.rotation.x, y: rotatedObject.rotation.y, z: rotatedObject.rotation.z }, isLocked: false, isVisible: true, }; - if (obj.userData.eventData) { - const eventData = eventStore.getState().getEventByModelUuid(obj.userData.modelUuid); - const productData = productStore.getState().getEventByModelUuid(productStore.getState().selectedProduct.productUuid, obj.userData.modelUuid); + if (rotatedObject.userData.eventData) { + const eventData = eventStore.getState().getEventByModelUuid(rotatedObject.userData.modelUuid); + const productData = productStore.getState().getEventByModelUuid(productStore.getState().selectedProduct.productUuid, rotatedObject.userData.modelUuid); if (eventData) { - eventStore.getState().updateEvent(obj.userData.modelUuid, { + eventStore.getState().updateEvent(rotatedObject.userData.modelUuid, { position: positionArray, rotation: rotationArray, }); } if (productData) { - const event = productStore.getState().updateEvent(productStore.getState().selectedProduct.productUuid, obj.userData.modelUuid, { + const event = productStore.getState().updateEvent(productStore.getState().selectedProduct.productUuid, rotatedObject.userData.modelUuid, { position: positionArray, rotation: rotationArray, }); @@ -371,7 +368,7 @@ function RotateControls3D() { modelName: newFloorItem.modelName, assetId: newFloorItem.assetId, position: newFloorItem.position, - rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + rotation: { x: rotatedObject.rotation.x, y: rotatedObject.rotation.y, z: rotatedObject.rotation.z }, isLocked: false, isVisible: true, socketId: builderSocket?.id, @@ -388,7 +385,7 @@ function RotateControls3D() { modelName: newFloorItem.modelName, assetId: newFloorItem.assetId, position: newFloorItem.position, - rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + rotation: { x: rotatedObject.rotation.x, y: rotatedObject.rotation.y, z: rotatedObject.rotation.z }, isLocked: false, isVisible: true, versionId: selectedVersion?.versionId || "", @@ -397,7 +394,7 @@ function RotateControls3D() { .then((data) => { if (!data.message || !data.data) { echo.error(`Error rotating asset: ${newFloorItem.modelUuid}`); - resetToInitialRotations(); + resetToInitialRotation(newFloorItem.modelUuid); clearSelection(); return; } @@ -421,13 +418,14 @@ function RotateControls3D() { }); } else { echo.error(`Error rotating asset: ${newFloorItem.modelUuid}`); - resetToInitialRotations(); + resetToInitialRotation(newFloorItem.modelUuid); clearSelection(); } }) .catch(() => { echo.error(`Error rotating asset: ${newFloorItem.modelUuid}`); - resetToInitialRotations(); + + resetToInitialRotation(newFloorItem.modelUuid); clearSelection(); }); } else { @@ -462,7 +460,7 @@ function RotateControls3D() { setIsRotating(false); setIsIndividualRotating(false); clearSelection(); - }, [rotatedObjects, eventStore, productStore, updateBackend, projectId, updateAsset, organization, builderSocket, selectedVersion, userId, initialPositions, initialRotations]); + }, [rotatedObjects, eventStore, productStore, updateBackend, projectId, updateAsset, organization, builderSocket, selectedVersion, userId, initialStates]); const clearSelection = () => { setPastedObjects([]); diff --git a/app/src/store/builder/useAssetStore.ts b/app/src/store/builder/useAssetStore.ts index fdffa0f..2a874b8 100644 --- a/app/src/store/builder/useAssetStore.ts +++ b/app/src/store/builder/useAssetStore.ts @@ -10,6 +10,7 @@ interface AssetsStore { copiedObjects: Object3D[]; pastedObjects: Object3D[]; duplicatedObjects: Object3D[]; + initialStates: Record; // Asset CRUD operations addAsset: (asset: Asset) => void; @@ -25,6 +26,7 @@ interface AssetsStore { setCopiedObjects: (objects: Object3D[]) => Object3D[]; setPastedObjects: (objects: Object3D[]) => Object3D[]; setDuplicatedObjects: (objects: Object3D[]) => Object3D[]; + setInitialState: (initialStates: Record) => void; // Asset properties setName: (modelUuid: string, newName: string) => void; @@ -64,6 +66,7 @@ export const createAssetStore = () => { copiedObjects: [], pastedObjects: [], duplicatedObjects: [], + initialStates: {}, // Asset CRUD operations addAsset: (asset) => { @@ -155,6 +158,12 @@ export const createAssetStore = () => { return objects; }, + setInitialState: (initialStates) => { + set((state) => { + state.initialStates = initialStates; + }); + }, + // Asset properties setName: (modelUuid, newName) => { set((state) => {