Merge remote-tracking branch 'origin/simulation-agv-v2' into v2
This commit is contained in:
@@ -1,232 +1,372 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
|
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
|
||||||
import * as THREE from "three";
|
|
||||||
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
|
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
|
||||||
import { useGLTF } from '@react-three/drei';
|
import { useGLTF } from "@react-three/drei";
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useSelectedEventSphere, useIsDragging, useIsRotating } from '../../../../store/simulation/useSimulationStore';
|
import {
|
||||||
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
|
useSelectedEventSphere,
|
||||||
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
useIsDragging,
|
||||||
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
|
useIsRotating,
|
||||||
import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi';
|
} from "../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useVehicleStore } from "../../../../store/simulation/useVehicleStore";
|
||||||
|
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||||
|
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
|
||||||
|
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
|
||||||
|
import { Box3, DoubleSide, Euler, Group, Mesh, Plane, Quaternion, Vector3 } from "three";
|
||||||
|
import { position } from "html2canvas/dist/types/css/property-descriptors/position";
|
||||||
|
|
||||||
const VehicleUI = () => {
|
const VehicleUI = () => {
|
||||||
const { scene: startScene } = useGLTF(startPoint) as any;
|
const { scene: startScene } = useGLTF(startPoint) as any;
|
||||||
const { scene: endScene } = useGLTF(startEnd) as any;
|
const { scene: endScene } = useGLTF(startEnd) as any;
|
||||||
const startMarker = useRef<THREE.Group>(null);
|
const startMarker = useRef<Group>(null);
|
||||||
const endMarker = useRef<THREE.Group>(null);
|
const endMarker = useRef<Group>(null);
|
||||||
const prevMousePos = useRef({ x: 0, y: 0 });
|
const prevMousePos = useRef({ x: 0, y: 0 });
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const { getVehicleById } = useVehicleStore();
|
const { getVehicleById } = useVehicleStore();
|
||||||
const { updateEvent } = useProductStore();
|
const { updateEvent } = useProductStore();
|
||||||
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 0, 0]);
|
const [startPosition, setStartPosition] = useState<[number, number, number]>([
|
||||||
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 0]);
|
0, 1, 0,
|
||||||
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
|
]);
|
||||||
const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
|
|
||||||
const { isDragging, setIsDragging } = useIsDragging();
|
|
||||||
const { isRotating, setIsRotating } = useIsRotating();
|
|
||||||
const { raycaster } = useThree();
|
|
||||||
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0));
|
|
||||||
const state: Types.ThreeState = useThree();
|
|
||||||
const controls: any = state.controls;
|
|
||||||
|
|
||||||
const email = localStorage.getItem('email')
|
|
||||||
const organization = (email!.split("@")[1]).split(".")[0];
|
|
||||||
|
|
||||||
const updateBackend = (
|
const [endPosition, setEndPosition] = useState<[number, number, number]>([
|
||||||
productName: string,
|
0, 1, 0,
|
||||||
productId: string,
|
]);
|
||||||
organization: string,
|
const [startRotation, setStartRotation] = useState<[number, number, number]>([
|
||||||
eventData: EventsSchema
|
0, 0, 0,
|
||||||
) => {
|
]);
|
||||||
upsertProductOrEventApi({
|
|
||||||
productName: productName,
|
|
||||||
productId: productId,
|
|
||||||
organization: organization,
|
|
||||||
eventDatas: eventData
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
const [endRotation, setEndRotation] = useState<[number, number, number]>([
|
||||||
if (!selectedEventSphere) return;
|
0, 0, 0,
|
||||||
const selectedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid);
|
]);
|
||||||
|
const [steeringRotation, setSteeringRotation] = useState<
|
||||||
|
[number, number, number]
|
||||||
|
>([0, 0, 0]);
|
||||||
|
|
||||||
if (selectedVehicle?.point?.action) {
|
const { isDragging, setIsDragging } = useIsDragging();
|
||||||
const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action;
|
const { isRotating, setIsRotating } = useIsRotating();
|
||||||
|
const { raycaster } = useThree();
|
||||||
|
const [point, setPoint] = useState<
|
||||||
|
[number, number, number]
|
||||||
|
>([0, 0, 0]);
|
||||||
|
const plane = useRef(new Plane(new Vector3(0, 1, 0), 0));
|
||||||
|
const [tubeRotation, setTubeRotation] = useState<boolean>(false);
|
||||||
|
const tubeRef = useRef<Group>(null);
|
||||||
|
const outerGroup = useRef<Group>(null);
|
||||||
|
const state: Types.ThreeState = useThree();
|
||||||
|
const controls: any = state.controls;
|
||||||
|
const [selectedVehicleData, setSelectedVechicleData] = useState<
|
||||||
|
{ position: [number, number, number], rotation: [number, number, number], }
|
||||||
|
>({ position: [0, 0, 0], rotation: [0, 0, 0], });
|
||||||
|
const CIRCLE_RADIUS = 0.8;
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
if (pickUpPoint) {
|
const updateBackend = (
|
||||||
setStartPosition([pickUpPoint.position.x, 0, pickUpPoint.position.z]);
|
productName: string,
|
||||||
setStartRotation([pickUpPoint.rotation.x, pickUpPoint.rotation.y, pickUpPoint.rotation.z]);
|
productId: string,
|
||||||
|
organization: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productId: productId,
|
||||||
|
organization: organization,
|
||||||
|
eventDatas: eventData,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedEventSphere) return;
|
||||||
|
const selectedVehicle = getVehicleById(
|
||||||
|
selectedEventSphere.userData.modelUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectedVehicle) {
|
||||||
|
setSelectedVechicleData({ position: selectedVehicle.position, rotation: selectedVehicle.rotation });
|
||||||
|
setPoint(selectedVehicle.point.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (selectedVehicle?.point?.action) {
|
||||||
|
const { pickUpPoint, unLoadPoint, steeringAngle } = selectedVehicle.point.action;
|
||||||
|
|
||||||
|
if (pickUpPoint && outerGroup.current) {
|
||||||
|
const worldPos = new Vector3(
|
||||||
|
pickUpPoint.position.x,
|
||||||
|
pickUpPoint.position.y,
|
||||||
|
pickUpPoint.position.z
|
||||||
|
);
|
||||||
|
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||||
|
|
||||||
|
|
||||||
|
setStartPosition([localPosition.x, selectedVehicle.point.position[1], localPosition.z,
|
||||||
|
]);
|
||||||
|
setStartRotation([pickUpPoint.rotation.x, pickUpPoint.rotation.y, pickUpPoint.rotation.z,])
|
||||||
} else {
|
} else {
|
||||||
const defaultLocal = new THREE.Vector3(0, 0, 1.5);
|
setStartPosition([0, selectedVehicle.point.position[1] + 0.1, 1.5]);
|
||||||
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
|
setStartRotation([0, 0, 0]);
|
||||||
setStartPosition([defaultWorld.x, 0, defaultWorld.z]);
|
|
||||||
setStartRotation([0, 0, 0]);
|
|
||||||
}
|
}
|
||||||
|
// end point
|
||||||
|
if (unLoadPoint && outerGroup.current) {
|
||||||
|
const worldPos = new Vector3(unLoadPoint.position.x, unLoadPoint.position.y, unLoadPoint.position.z);
|
||||||
|
const localPosition = outerGroup.current.worldToLocal(worldPos);
|
||||||
|
|
||||||
if (unLoadPoint) {
|
setEndPosition([localPosition.x, selectedVehicle.point.position[1], localPosition.z]);
|
||||||
setEndPosition([unLoadPoint.position.x, 0, unLoadPoint.position.z]);
|
setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z,
|
||||||
setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
const defaultLocal = new THREE.Vector3(0, 0, -1.5);
|
setEndPosition([0, selectedVehicle.point.position[1] + 0.1, -1.5]);
|
||||||
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
|
setEndRotation([0, 0, 0]);
|
||||||
setEndPosition([defaultWorld.x, 0, defaultWorld.z]);
|
|
||||||
setEndRotation([0, 0, 0]);
|
|
||||||
}
|
}
|
||||||
}
|
setSteeringRotation([0, steeringAngle, 0])
|
||||||
}, [selectedEventSphere]);
|
}
|
||||||
|
}, 10);
|
||||||
useFrame(() => {
|
|
||||||
if (!isDragging) return;
|
|
||||||
const intersectPoint = new THREE.Vector3();
|
|
||||||
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
|
|
||||||
|
|
||||||
if (intersects) {
|
|
||||||
if (isDragging === "start") {
|
|
||||||
setStartPosition([intersectPoint.x, 0, intersectPoint.z]);
|
|
||||||
}
|
|
||||||
if (isDragging === "end") {
|
|
||||||
setEndPosition([intersectPoint.x, 0, intersectPoint.z]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
useFrame((state) => {
|
|
||||||
if (!isRotating) return;
|
|
||||||
|
|
||||||
const currentPointerX = state.pointer.x;
|
|
||||||
const deltaX = currentPointerX - prevMousePos.current.x;
|
|
||||||
prevMousePos.current.x = currentPointerX;
|
|
||||||
|
|
||||||
const marker = isRotating === "start" ? startMarker.current : endMarker.current;
|
|
||||||
|
|
||||||
if (marker) {
|
|
||||||
const rotationSpeed = 10;
|
|
||||||
if (isRotating === 'start') {
|
|
||||||
const y = startRotation[1] + deltaX * rotationSpeed;
|
|
||||||
setStartRotation([0, y, 0]);
|
|
||||||
} else {
|
|
||||||
const y = endRotation[1] + deltaX * rotationSpeed;
|
|
||||||
setEndRotation([0, y, 0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const handlePointerDown = (e: any, state: "start" | "end", rotation: "start" | "end") => {
|
}, [selectedEventSphere, outerGroup.current]);
|
||||||
|
|
||||||
if (e.object.name === "handle") {
|
const handlePointerDown = (
|
||||||
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
|
e: any,
|
||||||
const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1;
|
state: "start" | "end",
|
||||||
prevMousePos.current = { x: normalizedX, y: normalizedY };
|
rotation: "start" | "end"
|
||||||
setIsRotating(rotation);
|
) => {
|
||||||
if (controls) controls.enabled = false;
|
if (e.object.name === "handle") {
|
||||||
setIsDragging(null);
|
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
prevMousePos.current = { x: normalizedX, y: normalizedY };
|
||||||
|
setIsRotating(rotation);
|
||||||
|
if (controls) controls.enabled = false;
|
||||||
|
setIsDragging(null);
|
||||||
|
} else {
|
||||||
|
setIsDragging(state);
|
||||||
|
setIsRotating(null);
|
||||||
|
if (controls) controls.enabled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} else {
|
const handlePointerUp = () => {
|
||||||
setIsDragging(state);
|
controls.enabled = true;
|
||||||
setIsRotating(null);
|
setIsDragging(null);
|
||||||
if (controls) controls.enabled = false;
|
setIsRotating(null);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePointerUp = () => {
|
if (selectedEventSphere?.userData.modelUuid) {
|
||||||
controls.enabled = true;
|
const updatedVehicle = getVehicleById(
|
||||||
setIsDragging(null);
|
selectedEventSphere.userData.modelUuid
|
||||||
setIsRotating(null);
|
);
|
||||||
|
|
||||||
if (selectedEventSphere?.userData.modelUuid) {
|
let globalStartPosition = null;
|
||||||
const updatedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid);
|
let globalEndPosition = null;
|
||||||
|
|
||||||
if (updatedVehicle) {
|
if (outerGroup.current && startMarker.current && endMarker.current) {
|
||||||
const event = updateEvent(selectedProduct.productId, selectedEventSphere.userData.modelUuid, {
|
const worldPosStart = new Vector3(...startPosition);
|
||||||
point: {
|
globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());
|
||||||
...updatedVehicle.point,
|
const worldPosEnd = new Vector3(...endPosition);
|
||||||
action: {
|
globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());
|
||||||
...updatedVehicle.point?.action,
|
}
|
||||||
pickUpPoint: {
|
if (updatedVehicle && globalEndPosition && globalStartPosition) {
|
||||||
position: { x: startPosition[0], y: startPosition[1], z: startPosition[2], },
|
const event = updateEvent(
|
||||||
rotation: { x: 0, y: startRotation[1], z: 0, },
|
selectedProduct.productId,
|
||||||
},
|
selectedEventSphere.userData.modelUuid,
|
||||||
unLoadPoint: {
|
{
|
||||||
position: { x: endPosition[0], y: endPosition[1], z: endPosition[2], },
|
point: {
|
||||||
rotation: { x: 0, y: endRotation[1], z: 0, },
|
...updatedVehicle.point,
|
||||||
},
|
action: {
|
||||||
|
...updatedVehicle.point?.action,
|
||||||
|
pickUpPoint: {
|
||||||
|
position: {
|
||||||
|
x: globalStartPosition.x,
|
||||||
|
y: 0,
|
||||||
|
z: globalStartPosition.z,
|
||||||
|
},
|
||||||
|
rotation: { x: 0, y: startRotation[1], z: 0 },
|
||||||
},
|
},
|
||||||
},
|
unLoadPoint: {
|
||||||
})
|
position: {
|
||||||
|
x: globalEndPosition.x,
|
||||||
|
y: 0,
|
||||||
|
z: globalEndPosition.z,
|
||||||
|
},
|
||||||
|
rotation: { x: 0, y: endRotation[1], z: 0 },
|
||||||
|
},
|
||||||
|
steeringAngle: steeringRotation[1]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (event) {
|
if (event) {
|
||||||
updateBackend(
|
updateBackend(
|
||||||
selectedProduct.productName,
|
selectedProduct.productName,
|
||||||
selectedProduct.productId,
|
selectedProduct.productId,
|
||||||
organization,
|
organization,
|
||||||
event
|
event
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useFrame(() => {
|
||||||
const handleGlobalPointerUp = () => {
|
if (!isDragging || !plane.current || !raycaster || !outerGroup.current) return;
|
||||||
setIsDragging(null);
|
const intersectPoint = new Vector3();
|
||||||
setIsRotating(null);
|
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
|
||||||
if (controls) controls.enabled = true;
|
if (!intersects) return;
|
||||||
handlePointerUp();
|
const localPoint = outerGroup?.current.worldToLocal(intersectPoint.clone());
|
||||||
};
|
if (isDragging === "start") {
|
||||||
|
if (startMarker.current) {
|
||||||
|
|
||||||
if (isDragging || isRotating) {
|
}
|
||||||
window.addEventListener("pointerup", handleGlobalPointerUp);
|
setStartPosition([localPoint.x, point[1], localPoint.z]);
|
||||||
}
|
} else if (isDragging === "end") {
|
||||||
|
setEndPosition([localPoint.x, point[1], localPoint.z]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
useEffect(() => {
|
||||||
window.removeEventListener("pointerup", handleGlobalPointerUp);
|
const handleGlobalPointerUp = () => {
|
||||||
};
|
setIsDragging(null);
|
||||||
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]);
|
setIsRotating(null);
|
||||||
|
setTubeRotation(false);
|
||||||
|
if (controls) controls.enabled = true;
|
||||||
|
handlePointerUp();
|
||||||
|
|
||||||
return (
|
};
|
||||||
startPosition.length > 0 && endPosition.length > 0 ? (
|
|
||||||
<mesh>
|
if (isDragging || isRotating || tubeRotation) {
|
||||||
<primitive
|
window.addEventListener("pointerup", handleGlobalPointerUp);
|
||||||
name="start"
|
}
|
||||||
object={startScene}
|
|
||||||
ref={startMarker}
|
return () => {
|
||||||
position={startPosition}
|
window.removeEventListener("pointerup", handleGlobalPointerUp);
|
||||||
rotation={startRotation}
|
};
|
||||||
onPointerDown={(e: any) => {
|
}, [
|
||||||
e.stopPropagation();
|
isDragging, isRotating, startPosition, startRotation, endPosition, endRotation, tubeRotation, steeringRotation, outerGroup.current, tubeRef.current
|
||||||
handlePointerDown(e, "start", "start");
|
]);
|
||||||
}}
|
|
||||||
onPointerMissed={() => {
|
|
||||||
controls.enabled = true;
|
const prevSteeringY = useRef(0);
|
||||||
setIsDragging(null);
|
useFrame((state) => {
|
||||||
setIsRotating(null);
|
if (tubeRotation) {
|
||||||
}}
|
const currentPointerX = state.pointer.x;
|
||||||
/>
|
const deltaX = currentPointerX - prevMousePos.current.x;
|
||||||
|
prevMousePos.current.x = currentPointerX;
|
||||||
|
|
||||||
|
const marker = tubeRef.current;
|
||||||
|
if (marker) {
|
||||||
|
const rotationSpeed = 2;
|
||||||
|
marker.rotation.y += deltaX * rotationSpeed;
|
||||||
|
setSteeringRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
prevSteeringY.current = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
useFrame((state) => {
|
||||||
|
if (!isRotating) return;
|
||||||
|
const currentPointerX = state.pointer.x;
|
||||||
|
const deltaX = currentPointerX - prevMousePos.current.x;
|
||||||
|
prevMousePos.current.x = currentPointerX;
|
||||||
|
const marker =
|
||||||
|
isRotating === "start" ? startMarker.current : endMarker.current;
|
||||||
|
if (marker) {
|
||||||
|
const rotationSpeed = 10;
|
||||||
|
marker.rotation.y += deltaX * rotationSpeed;
|
||||||
|
if (isRotating === "start") {
|
||||||
|
setStartRotation([
|
||||||
|
marker.rotation.x,
|
||||||
|
marker.rotation.y,
|
||||||
|
marker.rotation.z,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
setEndRotation([
|
||||||
|
marker.rotation.x,
|
||||||
|
marker.rotation.y,
|
||||||
|
marker.rotation.z,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return selectedVehicleData ? (
|
||||||
|
<group position={selectedVehicleData.position} rotation={selectedVehicleData.rotation} ref={outerGroup}>
|
||||||
|
<group
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
ref={tubeRef}
|
||||||
|
rotation={steeringRotation}
|
||||||
|
onPointerDown={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setTubeRotation(true);
|
||||||
|
prevMousePos.current.x = e.pointer.x;
|
||||||
|
controls.enabled = false;
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
controls.enabled = true;
|
||||||
|
setTubeRotation(false);
|
||||||
|
}}
|
||||||
|
onPointerUp={() => {
|
||||||
|
controls.enabled = true;
|
||||||
|
setTubeRotation(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
(
|
||||||
|
<mesh
|
||||||
|
position={[0, point[1], 0]}
|
||||||
|
rotation={[-Math.PI / 2, 0, 0]}
|
||||||
|
name="steering"
|
||||||
|
>
|
||||||
|
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.2, 36]} />
|
||||||
|
<meshBasicMaterial color="yellow" side={DoubleSide} />
|
||||||
|
|
||||||
<primitive
|
|
||||||
name="end"
|
|
||||||
object={endScene}
|
|
||||||
ref={endMarker}
|
|
||||||
position={endPosition}
|
|
||||||
rotation={endRotation}
|
|
||||||
onPointerDown={(e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handlePointerDown(e, "end", "end");
|
|
||||||
}}
|
|
||||||
onPointerMissed={() => {
|
|
||||||
controls.enabled = true;
|
|
||||||
setIsDragging(null);
|
|
||||||
setIsRotating(null);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</mesh>
|
</mesh>
|
||||||
) : null
|
<mesh position={[0, point[1], CIRCLE_RADIUS + 0.24]} rotation={[Math.PI / 2, 0, 0]}>
|
||||||
);
|
<coneGeometry args={[0.1, 0.3, 12]} />
|
||||||
}
|
<meshBasicMaterial color="yellow" side={DoubleSide} />
|
||||||
|
</mesh>
|
||||||
|
)
|
||||||
|
</group>
|
||||||
|
|
||||||
|
{/* Start Marker */}
|
||||||
|
<primitive
|
||||||
|
name="startMarker"
|
||||||
|
object={startScene}
|
||||||
|
ref={startMarker}
|
||||||
|
position={startPosition}
|
||||||
|
rotation={startRotation}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(e, "start", "start");
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
controls.enabled = true;
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* End Marker */}
|
||||||
|
<primitive
|
||||||
|
name="endMarker"
|
||||||
|
object={endScene}
|
||||||
|
ref={endMarker}
|
||||||
|
position={endPosition}
|
||||||
|
rotation={endRotation}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(e, "end", "end");
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
controls.enabled = true;
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
export default VehicleUI;
|
export default VehicleUI;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
|||||||
const completedRef = useRef<boolean>(false);
|
const completedRef = useRef<boolean>(false);
|
||||||
const isPausedRef = useRef<boolean>(false);
|
const isPausedRef = useRef<boolean>(false);
|
||||||
const pauseTimeRef = useRef<number | null>(null);
|
const pauseTimeRef = useRef<number | null>(null);
|
||||||
|
const [objectRotation, setObjectRotation] = useState<{ x: number; y: number; z: number } | undefined>(agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 })
|
||||||
const [progress, setProgress] = useState<number>(0);
|
const [progress, setProgress] = useState<number>(0);
|
||||||
const [restRotation, setRestingRotation] = useState<boolean>(true);
|
const [restRotation, setRestingRotation] = useState<boolean>(true);
|
||||||
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
||||||
@@ -32,20 +33,19 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
|||||||
let startTime: number;
|
let startTime: number;
|
||||||
let fixedInterval: number;
|
let fixedInterval: number;
|
||||||
let coveredDistance = progressRef.current;
|
let coveredDistance = progressRef.current;
|
||||||
let objectRotation = (agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) as { x: number; y: number; z: number } | undefined;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
objectRotation = agvDetail.point.action?.pickUpPoint?.rotation
|
setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation)
|
||||||
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
||||||
objectRotation = agvDetail.point.action?.unLoadPoint?.rotation
|
setObjectRotation(agvDetail.point.action?.unLoadPoint?.rotation)
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
|
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
|
||||||
objectRotation = agvDetail.point.action?.pickUpPoint?.rotation
|
setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation)
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
}
|
}
|
||||||
}, [currentPhase, path]);
|
}, [currentPhase, path, objectRotation]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
@@ -64,7 +64,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
|||||||
coveredDistance = 0;
|
coveredDistance = 0;
|
||||||
setReset(false);
|
setReset(false);
|
||||||
setRestingRotation(true);
|
setRestingRotation(true);
|
||||||
decrementVehicleLoad(agvDetail.modelUuid, 0);
|
|
||||||
isPausedRef.current = false;
|
isPausedRef.current = false;
|
||||||
pauseTimeRef.current = 0;
|
pauseTimeRef.current = 0;
|
||||||
const object = scene.getObjectByProperty('uuid', agvUuid);
|
const object = scene.getObjectByProperty('uuid', agvUuid);
|
||||||
@@ -125,26 +124,30 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
|||||||
if (isAligned) {
|
if (isAligned) {
|
||||||
progressRef.current += delta * (speed * agvDetail.speed);
|
progressRef.current += delta * (speed * agvDetail.speed);
|
||||||
coveredDistance = progressRef.current;
|
coveredDistance = progressRef.current;
|
||||||
|
|
||||||
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
||||||
const position = start.clone().lerp(end, t);
|
const position = start.clone().lerp(end, t);
|
||||||
object.position.copy(position);
|
object.position.copy(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (progressRef.current >= totalDistance) {
|
if (progressRef.current >= totalDistance) {
|
||||||
if (restRotation && objectRotation) {
|
if (restRotation && objectRotation) {
|
||||||
const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(objectRotation.x, objectRotation.y, objectRotation.z));
|
const targetEuler = new THREE.Euler(
|
||||||
|
objectRotation.x,
|
||||||
|
objectRotation.y - (agvDetail.point.action.steeringAngle),
|
||||||
|
objectRotation.z
|
||||||
|
);
|
||||||
|
const targetQuaternion = new THREE.Quaternion().setFromEuler(targetEuler);
|
||||||
object.quaternion.slerp(targetQuaternion, delta * 2);
|
object.quaternion.slerp(targetQuaternion, delta * 2);
|
||||||
const angleDiff = object.quaternion.angleTo(targetQuaternion);
|
if (object.quaternion.angleTo(targetQuaternion) < 0.01) {
|
||||||
if (angleDiff < 0.01) {
|
object.quaternion.copy(targetQuaternion);
|
||||||
object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z);
|
object.rotation.copy(targetEuler);
|
||||||
setRestingRotation(false);
|
setRestingRotation(false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progressRef.current >= totalDistance) {
|
if (progressRef.current >= totalDistance) {
|
||||||
setRestingRotation(true);
|
setRestingRotation(true);
|
||||||
progressRef.current = 0;
|
progressRef.current = 0;
|
||||||
@@ -199,7 +202,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{currentPath.length > 0 && (
|
{currentPath.length > 0 && (
|
||||||
<group visible={false}>
|
<group >
|
||||||
<Line points={currentPath} color="blue" lineWidth={3} />
|
<Line points={currentPath} color="blue" lineWidth={3} />
|
||||||
{currentPath.map((point, index) => (
|
{currentPath.map((point, index) => (
|
||||||
<mesh key={index} position={point}>
|
<mesh key={index} position={point}>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
|||||||
const { navMesh } = useNavMesh();
|
const { navMesh } = useNavMesh();
|
||||||
const vehicleRef: any = useRef();
|
const vehicleRef: any = useRef();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad, setVehicleLoad, setMaterialType } = useVehicleStore();
|
const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad, setMaterialType, setVehicleLoad } = useVehicleStore();
|
||||||
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
|
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
|
||||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
let isIncrememtable = useRef<boolean>(true);
|
let isIncrememtable = useRef<boolean>(true);
|
||||||
|
|||||||
@@ -28,15 +28,12 @@ function Vehicles() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<VehicleInstances />
|
<VehicleInstances />
|
||||||
|
{isVehicleSelected && selectedEventSphere && !isPlaying &&
|
||||||
{isVehicleSelected && !isPlaying &&
|
<VehicleUI />
|
||||||
< VehicleUI />
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vehicles;
|
export default Vehicles;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
import { create } from 'zustand';
|
import { immer } from "zustand/middleware/immer";
|
||||||
import { immer } from 'zustand/middleware/immer';
|
|
||||||
|
|
||||||
interface VehiclesStore {
|
interface VehiclesStore {
|
||||||
vehicles: VehicleStatus[];
|
vehicles: VehicleStatus[];
|
||||||
@@ -9,7 +8,7 @@ interface VehiclesStore {
|
|||||||
removeVehicle: (modelUuid: string) => void;
|
removeVehicle: (modelUuid: string) => void;
|
||||||
updateVehicle: (
|
updateVehicle: (
|
||||||
modelUuid: string,
|
modelUuid: string,
|
||||||
updates: Partial<Omit<VehicleStatus, 'modelUuid' | 'productId'>>
|
updates: Partial<Omit<VehicleStatus, "modelUuid" | "productId">>
|
||||||
) => void;
|
) => void;
|
||||||
clearvehicles: () => void;
|
clearvehicles: () => void;
|
||||||
|
|
||||||
@@ -18,7 +17,10 @@ interface VehiclesStore {
|
|||||||
incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
|
incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
|
||||||
decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
|
decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
|
||||||
setVehicleLoad: (modelUuid: string, load: number) => void;
|
setVehicleLoad: (modelUuid: string, load: number) => void;
|
||||||
setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void;
|
setVehicleState: (
|
||||||
|
modelUuid: string,
|
||||||
|
newState: VehicleStatus["state"]
|
||||||
|
) => void;
|
||||||
setMaterialType: (modelUuid: string, materialType: string | null) => void;
|
setMaterialType: (modelUuid: string, materialType: string | null) => void;
|
||||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
@@ -35,7 +37,9 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
addVehicle: (productId, event) => {
|
addVehicle: (productId, event) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const exists = state.vehicles.some(v => v.modelUuid === event.modelUuid);
|
const exists = state.vehicles.some(
|
||||||
|
(v) => v.modelUuid === event.modelUuid
|
||||||
|
);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
state.vehicles.push({
|
state.vehicles.push({
|
||||||
...event,
|
...event,
|
||||||
@@ -53,13 +57,15 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
removeVehicle: (modelUuid) => {
|
removeVehicle: (modelUuid) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.vehicles = state.vehicles.filter(v => v.modelUuid !== modelUuid);
|
state.vehicles = state.vehicles.filter(
|
||||||
|
(v) => v.modelUuid !== modelUuid
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateVehicle: (modelUuid, updates) => {
|
updateVehicle: (modelUuid, updates) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
Object.assign(vehicle, updates);
|
Object.assign(vehicle, updates);
|
||||||
}
|
}
|
||||||
@@ -74,7 +80,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
setVehicleActive: (modelUuid, isActive) => {
|
setVehicleActive: (modelUuid, isActive) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.isActive = isActive;
|
vehicle.isActive = isActive;
|
||||||
}
|
}
|
||||||
@@ -83,7 +89,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
updateSteeringAngle: (modelUuid, steeringAngle) => {
|
updateSteeringAngle: (modelUuid, steeringAngle) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.point.action.steeringAngle = steeringAngle;
|
vehicle.point.action.steeringAngle = steeringAngle;
|
||||||
}
|
}
|
||||||
@@ -92,7 +98,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
incrementVehicleLoad: (modelUuid, incrementBy) => {
|
incrementVehicleLoad: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.currentLoad += incrementBy;
|
vehicle.currentLoad += incrementBy;
|
||||||
}
|
}
|
||||||
@@ -101,7 +107,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
decrementVehicleLoad: (modelUuid, decrementBy) => {
|
decrementVehicleLoad: (modelUuid, decrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.currentLoad -= decrementBy;
|
vehicle.currentLoad -= decrementBy;
|
||||||
}
|
}
|
||||||
@@ -110,7 +116,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
setVehicleLoad: (modelUuid, load) => {
|
setVehicleLoad: (modelUuid, load) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.currentLoad = load;
|
vehicle.currentLoad = load;
|
||||||
}
|
}
|
||||||
@@ -119,7 +125,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
setVehicleState: (modelUuid, newState) => {
|
setVehicleState: (modelUuid, newState) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.state = newState;
|
vehicle.state = newState;
|
||||||
}
|
}
|
||||||
@@ -128,7 +134,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
setMaterialType: (modelUuid, materialType) => {
|
setMaterialType: (modelUuid, materialType) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.materialType = materialType;
|
vehicle.materialType = materialType;
|
||||||
}
|
}
|
||||||
@@ -137,7 +143,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.activeTime += incrementBy;
|
vehicle.activeTime += incrementBy;
|
||||||
}
|
}
|
||||||
@@ -146,7 +152,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
|
|
||||||
incrementIdleTime: (modelUuid, incrementBy) => {
|
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.idleTime += incrementBy;
|
vehicle.idleTime += incrementBy;
|
||||||
}
|
}
|
||||||
@@ -154,19 +160,19 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
getVehicleById: (modelUuid) => {
|
getVehicleById: (modelUuid) => {
|
||||||
return get().vehicles.find(v => v.modelUuid === modelUuid);
|
return get().vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
},
|
},
|
||||||
|
|
||||||
getVehiclesByProduct: (productId) => {
|
getVehiclesByProduct: (productId) => {
|
||||||
return get().vehicles.filter(v => v.productId === productId);
|
return get().vehicles.filter((v) => v.productId === productId);
|
||||||
},
|
},
|
||||||
|
|
||||||
getVehiclesByState: (state) => {
|
getVehiclesByState: (state) => {
|
||||||
return get().vehicles.filter(v => v.state === state);
|
return get().vehicles.filter((v) => v.state === state);
|
||||||
},
|
},
|
||||||
|
|
||||||
getActiveVehicles: () => {
|
getActiveVehicles: () => {
|
||||||
return get().vehicles.filter(v => v.isActive);
|
return get().vehicles.filter((v) => v.isActive);
|
||||||
}
|
},
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user