added 2d point select delete and move

This commit is contained in:
2025-07-11 17:40:15 +05:30
parent 4baef5fa77
commit 96216783ef
4 changed files with 364 additions and 25 deletions

View File

@@ -0,0 +1,341 @@
import * as THREE from "three";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
import { useSelectedPoints } from "../../../../../store/simulation/useSimulationStore";
import useModuleStore from "../../../../../store/useModuleStore";
// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
// import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi";
// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
function MoveControls2D({
movedObjects,
setMovedObjects,
pastedObjects,
setpastedObjects,
duplicatedObjects,
setDuplicatedObjects,
rotatedObjects,
setRotatedObjects,
}: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { toolMode } = useToolMode();
const { toggleView } = useToggleView();
const { activeModule } = useModuleStore();
const { selectedPoints, clearSelectedPoints } = useSelectedPoints();
const { socket } = useSocketStore();
const { userId, organization } = getUserData();
const { projectId } = useParams();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
const { setPosition: setAislePosition, getAislesByPointId } = aisleStore();
const { setPosition: setWallPosition, getWallsByPointId } = wallStore();
const { setPosition: setFloorPosition, getFloorsByPointId } = floorStore();
const { setPosition: setZonePosition, getZonesByPointId } = zoneStore();
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({});
const [isMoving, setIsMoving] = useState(false);
useEffect(() => {
if (!camera || !scene || !toggleView) return;
const canvasElement = gl.domElement;
canvasElement.tabIndex = 0;
let isMoving = false;
const onPointerDown = () => {
isMoving = false;
};
const onPointerMove = () => {
isMoving = true;
};
const onPointerUp = (event: PointerEvent) => {
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
event.preventDefault();
placeMovedAssets();
}
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
event.preventDefault();
clearSelection();
setMovedObjects([]);
resetToInitialPositions();
}
};
const onKeyDown = (event: KeyboardEvent) => {
const keyCombination = detectModifierKeys(event);
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return;
if (keyCombination === "G") {
if (selectedPoints.length > 0) {
moveAssets();
}
}
if (keyCombination === "ESCAPE") {
event.preventDefault();
clearSelection();
setMovedObjects([]);
resetToInitialPositions();
}
};
if (toggleView && selectedPoints.length > 0) {
canvasElement.addEventListener("pointerdown", onPointerDown);
canvasElement.addEventListener("pointermove", onPointerMove);
canvasElement.addEventListener("pointerup", onPointerUp);
canvasElement.addEventListener("keydown", onKeyDown);
}
return () => {
canvasElement.removeEventListener("pointerdown", onPointerDown);
canvasElement.removeEventListener("pointermove", onPointerMove);
canvasElement.removeEventListener("pointerup", onPointerUp);
canvasElement.removeEventListener("keydown", onKeyDown);
};
}, [camera, controls, scene, toggleView, selectedPoints, socket, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects]);
useEffect(() => {
if (toolMode !== 'move' || !toggleView) {
if (movedObjects.length > 0) {
resetToInitialPositions();
}
clearSelection();
}
}, [activeModule, toolMode, toggleView, movedObjects]);
useFrame(() => {
if (!isMoving || movedObjects.length === 0 || !dragOffset) return;
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit) {
const baseNewPosition = new THREE.Vector3().addVectors(hit, dragOffset);
movedObjects.forEach((movedPoint: THREE.Object3D) => {
if (movedPoint.userData.pointUuid) {
const point: Point = movedPoint.userData as Point;
const initialPosition = initialPositions[movedPoint.uuid];
if (initialPosition) {
const relativeOffset = new THREE.Vector3().subVectors(
initialPosition,
initialPositions[movedObjects[0].uuid]
);
const newPosition = new THREE.Vector3().addVectors(baseNewPosition, relativeOffset);
const positionArray: [number, number, number] = [newPosition.x, newPosition.y, newPosition.z];
if (point.pointType === 'Aisle') {
setAislePosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Wall') {
setWallPosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Floor') {
setFloorPosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Zone') {
setZonePosition(point.pointUuid, positionArray);
}
}
}
});
}
});
const calculateDragOffset = useCallback((point: THREE.Object3D, hitPoint: THREE.Vector3) => {
const pointPosition = new THREE.Vector3().copy(point.position);
return new THREE.Vector3().subVectors(pointPosition, hitPoint);
}, []);
const moveAssets = useCallback(() => {
if (selectedPoints.length === 0) return;
const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {};
selectedPoints.forEach((point: THREE.Object3D) => {
states[point.uuid] = {
position: new THREE.Vector3().copy(point.position),
rotation: point.rotation ? new THREE.Euler().copy(point.rotation) : undefined
};
});
setInitialStates(states);
const positions: Record<string, THREE.Vector3> = {};
selectedPoints.forEach((point: THREE.Object3D) => { positions[point.uuid] = new THREE.Vector3().copy(point.position); });
setInitialPositions(positions);
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit && selectedPoints[0]) {
const offset = calculateDragOffset(selectedPoints[0], hit);
setDragOffset(offset);
}
setMovedObjects(selectedPoints);
setIsMoving(true);
}, [selectedPoints, camera, pointer, plane, raycaster, calculateDragOffset]);
const resetToInitialPositions = useCallback(() => {
setTimeout(() => {
movedObjects.forEach((movedPoint: THREE.Object3D) => {
if (movedPoint.userData.pointUuid && initialStates[movedPoint.uuid]) {
const point: Point = movedPoint.userData as Point;
const initialState = initialStates[movedPoint.uuid];
const positionArray: [number, number, number] = [
initialState.position.x,
initialState.position.y,
initialState.position.z
];
if (point.pointType === 'Aisle') {
setAislePosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Wall') {
setWallPosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Floor') {
setFloorPosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Zone') {
setZonePosition(point.pointUuid, positionArray);
}
}
});
}, 0)
}, [movedObjects, initialStates, setAislePosition, setWallPosition, setFloorPosition, setZonePosition]);
const placeMovedAssets = () => {
if (movedObjects.length === 0) return;
movedObjects.forEach((movedObject: THREE.Object3D) => {
if (movedObject.userData.pointUuid) {
const point: Point = movedObject.userData as Point;
if (point.pointType === 'Aisle') {
const updatedAisles = getAislesByPointId(point.pointUuid);
if (updatedAisles.length > 0 && projectId) {
updatedAisles.forEach((updatedAisle) => {
// API
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
// SOCKET
socket.emit('v1:model-aisle:add', {
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization,
aisleUuid: updatedAisle.aisleUuid,
points: updatedAisle.points,
type: updatedAisle.type
})
})
}
} else if (point.pointType === 'Wall') {
const updatedWalls = getWallsByPointId(point.pointUuid);
if (updatedWalls && updatedWalls.length > 0 && projectId) {
updatedWalls.forEach((updatedWall) => {
// API
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
// SOCKET
const data = {
wallData: updatedWall,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Wall:add', data);
});
}
} else if (point.pointType === 'Floor') {
const updatedFloors = getFloorsByPointId(point.pointUuid);
if (updatedFloors && updatedFloors.length > 0 && projectId) {
updatedFloors.forEach((updatedFloor) => {
// API
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
// SOCKET
const data = {
floorData: updatedFloor,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Floor:add', data);
});
}
} else if (point.pointType === 'Zone') {
const updatedZones = getZonesByPointId(point.pointUuid);
if (updatedZones && updatedZones.length > 0 && projectId) {
updatedZones.forEach((updatedZone) => {
// API
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
// SOCKET
const data = {
zoneData: updatedZone,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:zone:add', data);
});
}
}
}
})
echo.success("Object moved!");
clearSelection();
};
const clearSelection = () => {
setpastedObjects([]);
setDuplicatedObjects([]);
setMovedObjects([]);
setRotatedObjects([]);
clearSelectedPoints();
};
return (
<>
</>
);
}
export default MoveControls2D;