- Updated all instances of `simulationPaths` to `simulationStates` across multiple components including copyPasteControls, duplicationControls, moveControls, rotateControls, selectionControls, and others. - Adjusted related state management hooks in the store to reflect the change from `simulationPaths` to `simulationStates`. - Ensured that all references to simulation paths in the simulation logic and UI components are consistent with the new naming convention.
382 lines
18 KiB
TypeScript
382 lines
18 KiB
TypeScript
import * as THREE from "three";
|
|
import { useEffect, useMemo } from "react";
|
|
import { useFrame, useThree } from "@react-three/fiber";
|
|
import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
|
|
import { toast } from "react-toastify";
|
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
|
import * as Types from "../../../../types/world/worldTypes";
|
|
|
|
const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, selectionGroup, setDuplicatedObjects, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
|
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
|
const { toggleView } = useToggleView();
|
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
|
const { floorItems, setFloorItems } = useFloorItems();
|
|
const { socket } = useSocketStore()
|
|
|
|
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 && pastedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
|
event.preventDefault();
|
|
addPastedObjects();
|
|
}
|
|
};
|
|
|
|
const onKeyDown = (event: KeyboardEvent) => {
|
|
if (event.ctrlKey && event.key.toLowerCase() === "c" && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
|
copySelection();
|
|
}
|
|
if (event.ctrlKey && event.key.toLowerCase() === "v" && copiedObjects.length > 0 && pastedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
|
pasteCopiedObjects();
|
|
}
|
|
};
|
|
|
|
if (!toggleView) {
|
|
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, selectedAssets, copiedObjects, pastedObjects, movedObjects, socket, floorItems, rotatedObjects]);
|
|
|
|
useFrame(() => {
|
|
if (pastedObjects.length > 0) {
|
|
const intersectionPoint = new THREE.Vector3();
|
|
raycaster.setFromCamera(pointer, camera);
|
|
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
if (point) {
|
|
const position = new THREE.Vector3();
|
|
if (boundingBoxRef.current) {
|
|
boundingBoxRef.current?.getWorldPosition(position)
|
|
selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
|
|
} else {
|
|
const box = new THREE.Box3();
|
|
pastedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
|
|
const center = new THREE.Vector3();
|
|
box.getCenter(center);
|
|
selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
const copySelection = () => {
|
|
if (selectedAssets.length > 0) {
|
|
const newClones = selectedAssets.map((asset: any) => {
|
|
const clone = asset.clone();
|
|
clone.position.copy(asset.position);
|
|
return clone;
|
|
});
|
|
setCopiedObjects(newClones);
|
|
toast.info("Objects copied!");
|
|
}
|
|
};
|
|
|
|
const pasteCopiedObjects = () => {
|
|
if (copiedObjects.length > 0 && pastedObjects.length === 0) {
|
|
const newClones = copiedObjects.map((obj: THREE.Object3D) => {
|
|
const clone = obj.clone();
|
|
clone.position.copy(obj.position);
|
|
return clone;
|
|
});
|
|
selectionGroup.current.add(...newClones);
|
|
setpastedObjects([...newClones]);
|
|
setSelectedAssets([...newClones]);
|
|
|
|
const intersectionPoint = new THREE.Vector3();
|
|
raycaster.setFromCamera(pointer, camera);
|
|
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
|
|
if (point) {
|
|
const position = new THREE.Vector3();
|
|
if (boundingBoxRef.current) {
|
|
boundingBoxRef.current?.getWorldPosition(position)
|
|
selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
|
|
} else {
|
|
const box = new THREE.Box3();
|
|
newClones.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
|
|
const center = new THREE.Vector3();
|
|
box.getCenter(center);
|
|
selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const addPastedObjects = () => {
|
|
if (pastedObjects.length === 0) return;
|
|
pastedObjects.forEach(async (obj: THREE.Object3D) => {
|
|
const worldPosition = new THREE.Vector3();
|
|
obj.getWorldPosition(worldPosition);
|
|
obj.position.copy(worldPosition);
|
|
|
|
if (itemsGroupRef.current) {
|
|
|
|
const newFloorItem: Types.FloorItemType = {
|
|
modeluuid: obj.uuid,
|
|
modelname: obj.userData.name,
|
|
modelfileID: obj.userData.modelId,
|
|
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
|
|
isLocked: false,
|
|
isVisible: true
|
|
};
|
|
|
|
setFloorItems((prevItems: Types.FloorItems) => {
|
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
|
return updatedItems;
|
|
});
|
|
|
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
|
|
|
|
const email = localStorage.getItem("email");
|
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
|
if (eventData) {
|
|
if (eventData.type === 'Conveyor' && eventData) {
|
|
const createConveyorPoint = (index: number) => {
|
|
const pointUUID = THREE.MathUtils.generateUUID();
|
|
const hasActions = (eventData as Types.ConveyorEventsSchema)?.points[index].actions.length > 0;
|
|
|
|
const defaultAction = {
|
|
uuid: THREE.MathUtils.generateUUID(),
|
|
name: 'Action 1',
|
|
type: 'Inherit',
|
|
material: 'Inherit',
|
|
delay: 'Inherit',
|
|
spawnInterval: 'Inherit',
|
|
isUsed: true
|
|
};
|
|
|
|
return {
|
|
uuid: pointUUID,
|
|
position: (eventData as Types.ConveyorEventsSchema)?.points[index].position,
|
|
rotation: (eventData as Types.ConveyorEventsSchema)?.points[index].rotation,
|
|
actions: hasActions
|
|
? (eventData as Types.ConveyorEventsSchema)?.points[index].actions.map(action => ({
|
|
...action,
|
|
uuid: THREE.MathUtils.generateUUID()
|
|
}))
|
|
: [defaultAction],
|
|
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
|
|
connections: {
|
|
source: { pathUUID: obj.uuid, pointUUID },
|
|
targets: []
|
|
}
|
|
};
|
|
};
|
|
|
|
const backendEventData = {
|
|
type: 'Conveyor',
|
|
points: [
|
|
createConveyorPoint(0), // point1
|
|
createConveyorPoint(1), // middlePoint
|
|
createConveyorPoint(2) // point2
|
|
],
|
|
speed: (eventData as Types.ConveyorEventsSchema)?.speed
|
|
};
|
|
|
|
//REST
|
|
|
|
// await setFloorItemApi(
|
|
// organization,
|
|
// obj.uuid,
|
|
// obj.userData.name,
|
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
|
// obj.userData.modelId,
|
|
// false,
|
|
// true,
|
|
// backendEventData
|
|
// );
|
|
|
|
//SOCKET
|
|
|
|
const data = {
|
|
organization,
|
|
modeluuid: newFloorItem.modeluuid,
|
|
modelname: newFloorItem.modelname,
|
|
modelfileID: newFloorItem.modelfileID,
|
|
position: newFloorItem.position,
|
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
|
isLocked: false,
|
|
isVisible: true,
|
|
eventData: backendEventData,
|
|
socketId: socket.id,
|
|
};
|
|
|
|
const newEventData: any = backendEventData;
|
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
|
newEventData.modelName = newFloorItem.modelname;
|
|
newEventData.position = newFloorItem.position;
|
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
|
|
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
|
...(prevEvents || []),
|
|
newEventData as Types.ConveyorEventsSchema
|
|
]);
|
|
|
|
socket.emit("v2:model-asset:add", data);
|
|
|
|
} else if (eventData.type === 'Vehicle' && eventData) {
|
|
const createVehiclePoint = () => {
|
|
const pointUUID = THREE.MathUtils.generateUUID();
|
|
const vehiclePoint = (eventData as Types.VehicleEventsSchema)?.points;
|
|
const hasActions = vehiclePoint?.actions !== undefined;
|
|
|
|
const defaultAction = {
|
|
uuid: THREE.MathUtils.generateUUID(),
|
|
name: 'Action 1',
|
|
type: 'Inherit',
|
|
start: {},
|
|
hitCount: 0,
|
|
end: {},
|
|
buffer: 0
|
|
};
|
|
|
|
return {
|
|
uuid: pointUUID,
|
|
position: vehiclePoint?.position,
|
|
actions: hasActions
|
|
? {
|
|
...vehiclePoint.actions,
|
|
uuid: THREE.MathUtils.generateUUID()
|
|
}
|
|
: defaultAction,
|
|
connections: {
|
|
source: { modelUUID: obj.uuid, pointUUID },
|
|
targets: []
|
|
},
|
|
speed: vehiclePoint?.speed || 1
|
|
};
|
|
};
|
|
|
|
const backendEventData = {
|
|
type: 'Vehicle',
|
|
points: createVehiclePoint(),
|
|
speed: (eventData as Types.VehicleEventsSchema)?.points.speed
|
|
};
|
|
|
|
// API
|
|
|
|
// setFloorItemApi(
|
|
// organization,
|
|
// obj.uuid,
|
|
// obj.userData.name,
|
|
// obj.userData.modelId,
|
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
|
// false,
|
|
// true,
|
|
// { type: backendEventData.type, points: backendEventData.points }
|
|
// );
|
|
|
|
// SOCKET
|
|
|
|
const data = {
|
|
organization,
|
|
modeluuid: newFloorItem.modeluuid,
|
|
modelname: newFloorItem.modelname,
|
|
modelfileID: newFloorItem.modelfileID,
|
|
position: newFloorItem.position,
|
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
|
isLocked: false,
|
|
isVisible: true,
|
|
eventData: backendEventData,
|
|
socketId: socket.id,
|
|
};
|
|
|
|
const newEventData: any = backendEventData;
|
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
|
newEventData.modelName = newFloorItem.modelname;
|
|
newEventData.position = newFloorItem.position;
|
|
|
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
|
...(prevEvents || []),
|
|
newEventData as Types.VehicleEventsSchema
|
|
]);
|
|
|
|
socket.emit("v2:model-asset:add", data);
|
|
|
|
}
|
|
} else {
|
|
|
|
//REST
|
|
|
|
// await setFloorItemApi(
|
|
// organization,
|
|
// obj.uuid,
|
|
// obj.userData.name,
|
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
|
// obj.userData.modelId,
|
|
// false,
|
|
// true,
|
|
// );
|
|
|
|
//SOCKET
|
|
|
|
const data = {
|
|
organization,
|
|
modeluuid: newFloorItem.modeluuid,
|
|
modelname: newFloorItem.modelname,
|
|
modelfileID: newFloorItem.modelfileID,
|
|
position: newFloorItem.position,
|
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
|
isLocked: false,
|
|
isVisible: true,
|
|
socketId: socket.id,
|
|
};
|
|
|
|
socket.emit("v2:model-asset:add", data);
|
|
|
|
}
|
|
|
|
itemsGroupRef.current.add(obj);
|
|
}
|
|
});
|
|
|
|
toast.success("Object added!");
|
|
clearSelection();
|
|
};
|
|
|
|
const clearSelection = () => {
|
|
selectionGroup.current.children = [];
|
|
selectionGroup.current.position.set(0, 0, 0);
|
|
selectionGroup.current.rotation.set(0, 0, 0);
|
|
setMovedObjects([]);
|
|
setpastedObjects([]);
|
|
setDuplicatedObjects([]);
|
|
setRotatedObjects([]);
|
|
setSelectedAssets([]);
|
|
}
|
|
|
|
return (
|
|
<></>
|
|
);
|
|
};
|
|
|
|
export default CopyPasteControls; |