added 2d point select delete and move
This commit is contained in:
@@ -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;
|
||||
Reference in New Issue
Block a user