moveControls and other controls altered

This commit is contained in:
2025-07-18 14:14:34 +05:30
parent 0b9f23ba4f
commit c309af135d
9 changed files with 634 additions and 485 deletions

View File

@@ -1,5 +1,5 @@
import * as THREE from "three";
import { useEffect, useMemo, useRef } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
import * as Types from "../../../../../types/world/worldTypes";
@@ -20,11 +20,9 @@ function RotateControls3D({
pastedObjects,
setpastedObjects,
duplicatedObjects,
setDuplicatedObjects,
selectionGroup
setDuplicatedObjects
}: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
const { camera, gl, scene, pointer, raycaster } = useThree();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { toggleView } = useToggleView();
@@ -36,26 +34,33 @@ function RotateControls3D({
const { projectId } = useParams();
const { assetStore, eventStore, productStore } = useSceneContext();
const { updateAsset } = assetStore();
const AssetGroup = useRef<THREE.Group | undefined>(undefined);
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const updateBackend = (
const [initialRotations, setInitialRotations] = useState<Record<string, THREE.Euler>>({});
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
const [isRotating, setIsRotating] = useState(false);
const prevPointerPosition = useRef<THREE.Vector2 | null>(null);
const rotationCenter = useRef<THREE.Vector3 | null>(null);
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({
left: false,
right: false,
});
const updateBackend = useCallback((
productName: string,
productUuid: string,
projectId: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
productName,
productUuid,
projectId,
eventDatas: eventData,
versionId: selectedVersion?.versionId || '',
})
}
const prevPointerPosition = useRef<THREE.Vector2 | null>(null);
});
}, [selectedVersion]);
useEffect(() => {
if (!camera || !scene || toggleView) return;
@@ -63,45 +68,37 @@ function RotateControls3D({
const canvasElement = gl.domElement;
canvasElement.tabIndex = 0;
const itemsGroup: any = scene.getObjectByName("Asset Group");
AssetGroup.current = itemsGroup;
if (!AssetGroup.current) {
console.error("Asset Group not found in the scene.");
return;
}
let isMoving = false;
const onPointerDown = () => {
isMoving = false;
};
let isPointerMoving = false;
const onPointerMove = () => {
isMoving = true;
isPointerMoving = true;
};
const onPointerDown = (event: PointerEvent) => {
isPointerMoving = false;
if (event.button === 0) mouseButtonsDown.current.left = true;
if (event.button === 2) mouseButtonsDown.current.right = true;
};
const onPointerUp = (event: PointerEvent) => {
if (!isMoving && rotatedObjects.length > 0 && event.button === 0) {
if (event.button === 0) mouseButtonsDown.current.left = false;
if (event.button === 2) mouseButtonsDown.current.right = false;
if (!isPointerMoving && rotatedObjects.length > 0 && event.button === 0) {
event.preventDefault();
placeRotatedAssets();
}
if (!isMoving && rotatedObjects.length > 0 && event.button === 2) {
if (!isPointerMoving && rotatedObjects.length > 0 && event.button === 2) {
event.preventDefault();
resetToInitialRotations();
clearSelection();
rotatedObjects.forEach((asset: any) => {
if (AssetGroup.current) {
AssetGroup.current.attach(asset);
}
});
setRotatedObjects([]);
}
};
const onKeyDown = (event: KeyboardEvent) => {
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || movedObjects.length > 0) return;
if (event.key.toLowerCase() === "r") {
if (selectedAssets.length > 0) {
rotateAssets();
@@ -109,15 +106,8 @@ function RotateControls3D({
}
if (event.key.toLowerCase() === "escape") {
event.preventDefault();
resetToInitialRotations();
clearSelection();
rotatedObjects.forEach((asset: any) => {
if (AssetGroup.current) {
AssetGroup.current.attach(asset);
}
});
setRotatedObjects([]);
}
};
@@ -135,41 +125,85 @@ function RotateControls3D({
canvasElement.removeEventListener("pointerup", onPointerUp);
canvasElement.removeEventListener("keydown", onKeyDown);
};
}, [camera, controls, scene, toggleView, selectedAssets, socket, pastedObjects, duplicatedObjects, rotatedObjects, movedObjects]);
}, [camera, scene, toggleView, selectedAssets, rotatedObjects, pastedObjects, duplicatedObjects, movedObjects]);
const resetToInitialRotations = useCallback(() => {
rotatedObjects.forEach((obj: THREE.Object3D) => {
const uuid = obj.uuid;
if (obj.userData.modelUuid) {
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,];
updateAsset(obj.userData.modelUuid, {
rotation: rotationArray,
position: positionArray,
});
obj.rotation.copy(initialRotation);
obj.position.copy(initialPosition);
}
}
});
}, [rotatedObjects, initialRotations, initialPositions, updateAsset]);
useFrame(() => {
if (rotatedObjects.length > 0) {
const intersectionPoint = new THREE.Vector3();
raycaster.setFromCamera(pointer, camera);
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (!isRotating || rotatedObjects.length === 0) return;
if (point && prevPointerPosition.current) {
const box = new THREE.Box3();
rotatedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
const center = new THREE.Vector3();
box.getCenter(center);
const delta = new THREE.Vector3().subVectors(point, center);
const prevPointerPosition3D = new THREE.Vector3(prevPointerPosition.current.x, 0, prevPointerPosition.current.y);
const angle = Math.atan2(delta.z, delta.x) - Math.atan2(prevPointerPosition3D.z - center.z, prevPointerPosition3D.x - center.x);
selectionGroup.current.rotation.y += -angle;
selectionGroup.current.position.sub(center);
selectionGroup.current.position.applyAxisAngle(new THREE.Vector3(0, 1, 0), -angle);
selectionGroup.current.position.add(center);
const intersectionPoint = new THREE.Vector3();
raycaster.setFromCamera(pointer, camera);
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) {
if (point) {
prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
}
return;
}
if (point && prevPointerPosition.current && rotationCenter.current) {
const center = rotationCenter.current;
const currentAngle = Math.atan2(point.z - center.z, point.x - center.x);
const prevAngle = Math.atan2(
prevPointerPosition.current.y - center.z,
prevPointerPosition.current.x - center.x
);
const angleDelta = prevAngle - currentAngle;
rotatedObjects.forEach((obj: THREE.Object3D) => {
if (obj.userData.modelUuid) {
const relativePos = new THREE.Vector3().subVectors(obj.position, center);
relativePos.applyAxisAngle(new THREE.Vector3(0, 1, 0), angleDelta);
obj.position.copy(center).add(relativePos);
obj.rotation.y += angleDelta;
}
});
prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
}
});
const rotateAssets = () => {
const rotateAssets = useCallback(() => {
const rotations: Record<string, THREE.Euler> = {};
const positions: Record<string, THREE.Vector3> = {};
const box = new THREE.Box3();
selectedAssets.forEach((asset: any) => box.expandByObject(asset));
selectedAssets.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
const center = new THREE.Vector3();
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);
});
setInitialRotations(rotations);
setInitialPositions(positions);
const intersectionPoint = new THREE.Vector3();
raycaster.setFromCamera(pointer, camera);
@@ -179,56 +213,54 @@ function RotateControls3D({
prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
}
selectedAssets.forEach((asset: any) => {
selectionGroup.current.attach(asset);
});
setRotatedObjects(selectedAssets);
};
setIsRotating(true);
}, [selectedAssets, camera, pointer, raycaster, plane]);
const placeRotatedAssets = () => {
const placeRotatedAssets = useCallback(() => {
if (rotatedObjects.length === 0) return;
rotatedObjects.forEach(async (obj: THREE.Object3D) => {
if (obj && AssetGroup.current) {
const worldPosition = new THREE.Vector3();
const worldQuaternion = new THREE.Quaternion();
rotatedObjects.forEach((obj: THREE.Object3D) => {
if (obj && obj.userData.modelUuid) {
const rotationArray: [number, number, number] = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
obj.getWorldPosition(worldPosition);
obj.getWorldQuaternion(worldQuaternion);
selectionGroup.current.remove(obj);
obj.position.copy(worldPosition);
obj.quaternion.copy(worldQuaternion);
const positionArray: [number, number, number] = [obj.position.x, obj.position.y, obj.position.z];
const newFloorItem: Types.FloorItemType = {
modelUuid: obj.userData.modelUuid,
modelName: obj.userData.modelName,
assetId: obj.userData.assetId,
position: [worldPosition.x, worldPosition.y, worldPosition.z],
position: positionArray,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true
isVisible: true,
};
if (obj.userData.eventData) {
const eventData = eventStore.getState().getEventByModelUuid(obj.userData.modelUuid);
const productData = productStore.getState().getEventByModelUuid(selectedProductStore.getState().selectedProduct.productUuid, obj.userData.modelUuid);
const productData = productStore.getState().getEventByModelUuid(
selectedProduct.productUuid,
obj.userData.modelUuid
);
if (eventData) {
eventStore.getState().updateEvent(obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
})
position: positionArray,
rotation: rotationArray,
});
}
if (productData) {
const event = productStore.getState().updateEvent(selectedProductStore.getState().selectedProduct.productUuid, obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
})
if (event && organization) {
if (productData) {
const event = productStore.getState().updateEvent(
selectedProduct.productUuid,
obj.userData.modelUuid,
{
position: positionArray,
rotation: rotationArray,
}
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
@@ -242,8 +274,8 @@ function RotateControls3D({
}
updateAsset(obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
position: positionArray,
rotation: rotationArray,
});
//REST
@@ -267,7 +299,11 @@ 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: obj.rotation.x,
y: obj.rotation.y,
z: obj.rotation.z
},
isLocked: false,
isVisible: true,
socketId: socket.id,
@@ -276,29 +312,23 @@ function RotateControls3D({
userId
};
// console.log('data: ', data);
socket.emit("v1:model-asset:add", data);
AssetGroup.current.add(obj);
}
});
echo.success("Object rotated!");
setIsRotating(false);
clearSelection();
}
}, [rotatedObjects, eventStore, productStore, selectedProduct, updateBackend, projectId, updateAsset, organization, socket, selectedVersion, userId]);
const clearSelection = () => {
selectionGroup.current.children = [];
selectionGroup.current.position.set(0, 0, 0);
selectionGroup.current.rotation.set(0, 0, 0);
setpastedObjects([]);
setDuplicatedObjects([]);
setMovedObjects([]);
setRotatedObjects([]);
setSelectedAssets([]);
}
};
return null;
}
export default RotateControls3D
export default RotateControls3D;