Merge remote-tracking branch 'origin/dev-simulation/human' into main-demo
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { useCallback } from "react";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
|
||||
export function useAssemblyHandler() {
|
||||
const { materialStore, humanStore, productStore } = useSceneContext();
|
||||
const { getMaterialById } = materialStore();
|
||||
const { getModelUuidByActionUuid } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { incrementHumanLoad, addCurrentMaterial } = humanStore();
|
||||
|
||||
const assemblyLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handleAssembly = useCallback((action: HumanAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'assembly' || !materialId) return;
|
||||
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
if (!modelUuid) return;
|
||||
|
||||
incrementHumanLoad(modelUuid, 1);
|
||||
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
|
||||
|
||||
assemblyLogStatus(material.materialName, `performing assembly action`);
|
||||
|
||||
}, [getMaterialById]);
|
||||
|
||||
return {
|
||||
handleAssembly,
|
||||
};
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { useWorkerHandler } from './actionHandler/useWorkerHandler';
|
||||
import { useAssemblyHandler } from './actionHandler/useAssemblyHandler';
|
||||
|
||||
export function useHumanActions() {
|
||||
const { handleWorker } = useWorkerHandler();
|
||||
const { handleAssembly } = useAssemblyHandler();
|
||||
|
||||
const handleWorkerAction = useCallback((action: HumanAction, materialId: string) => {
|
||||
handleWorker(action, materialId);
|
||||
}, [handleWorker]);
|
||||
|
||||
const handleAssemblyAction = useCallback((action: HumanAction, materialId: string) => {
|
||||
handleAssembly(action, materialId);
|
||||
}, [handleAssembly]);
|
||||
|
||||
const handleHumanAction = useCallback((action: HumanAction, materialId: string) => {
|
||||
if (!action) return;
|
||||
|
||||
@@ -15,10 +21,13 @@ export function useHumanActions() {
|
||||
case 'worker':
|
||||
handleWorkerAction(action, materialId);
|
||||
break;
|
||||
case 'assembly':
|
||||
handleAssemblyAction(action, materialId);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown Human action type: ${action.actionType}`);
|
||||
}
|
||||
}, [handleWorkerAction]);
|
||||
}, [handleWorkerAction, handleAssemblyAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
}, []);
|
||||
|
||||
@@ -39,7 +39,7 @@ export function useActionHandler() {
|
||||
case 'store': case 'retrieve':
|
||||
handleStorageAction(action as StorageAction, materialId as string);
|
||||
break;
|
||||
case 'worker':
|
||||
case 'worker': case 'assembly':
|
||||
handleHumanAction(action as HumanAction, materialId as string);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -6,6 +6,7 @@ import { MaterialModel } from '../../../materials/instances/material/materialMod
|
||||
const MaterialAnimator = ({ human }: { human: HumanStatus }) => {
|
||||
const meshRef = useRef<any>(null!);
|
||||
const [hasLoad, setHasLoad] = useState(false);
|
||||
const [isAttached, setIsAttached] = useState(false);
|
||||
const { scene } = useThree();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -13,32 +14,45 @@ const MaterialAnimator = ({ human }: { human: HumanStatus }) => {
|
||||
}, [human.currentLoad]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasLoad || !meshRef.current) return;
|
||||
if (!hasLoad || !meshRef.current) {
|
||||
setIsAttached(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const humanModel = scene.getObjectByProperty("uuid", human.modelUuid) as THREE.Object3D;
|
||||
if (!humanModel) return;
|
||||
|
||||
meshRef.current.visible = false;
|
||||
|
||||
const bone = humanModel.getObjectByName('PlaceObjectRefBone') as THREE.Bone;
|
||||
if (bone) {
|
||||
if (meshRef.current.parent) {
|
||||
meshRef.current.parent.remove(meshRef.current);
|
||||
}
|
||||
|
||||
bone.add(meshRef.current);
|
||||
|
||||
meshRef.current.position.set(0, 0, 0);
|
||||
meshRef.current.rotation.set(0, 0, 0);
|
||||
meshRef.current.scale.set(1, 1, 1);
|
||||
|
||||
meshRef.current.visible = true;
|
||||
setIsAttached(true);
|
||||
}
|
||||
}, [hasLoad, human.modelUuid]);
|
||||
}, [hasLoad, human.modelUuid, scene]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{hasLoad && human.currentMaterials.length > 0 && (
|
||||
{hasLoad && human.point.action.actionType === 'worker' && human.currentMaterials.length > 0 && (
|
||||
<MaterialModel
|
||||
matRef={meshRef}
|
||||
materialId={human.currentMaterials[0].materialId || ''}
|
||||
materialType={human.currentMaterials[0].materialType || 'Default material'}
|
||||
visible={isAttached}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MaterialAnimator;
|
||||
export default MaterialAnimator;
|
||||
@@ -16,7 +16,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { scene } = useThree();
|
||||
const { assetStore, materialStore, armBotStore, conveyorStore, machineStore, vehicleStore, humanStore, storageUnitStore, productStore } = useSceneContext();
|
||||
const { removeMaterial, setEndTime } = materialStore();
|
||||
const { removeMaterial, setEndTime, setMaterial } = materialStore();
|
||||
const { getStorageUnitById } = storageUnitStore();
|
||||
const { getArmBotById } = armBotStore();
|
||||
const { getConveyorById } = conveyorStore();
|
||||
@@ -41,6 +41,13 @@ function HumanInstance({ human }: { human: HumanStatus }) {
|
||||
const previousTimeRef = useRef<number | null>(null);
|
||||
const animationFrameIdRef = useRef<number | null>(null);
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
const processStartTimeRef = useRef<number | null>(null);
|
||||
const processTimeRef = useRef<number>(0);
|
||||
const processAnimationIdRef = useRef<number | null>(null);
|
||||
const accumulatedPausedTimeRef = useRef<number>(0);
|
||||
const lastPauseTimeRef = useRef<number | null>(null);
|
||||
const hasLoggedHalfway = useRef(false);
|
||||
const hasLoggedCompleted = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
isPausedRef.current = isPaused;
|
||||
@@ -94,6 +101,16 @@ function HumanInstance({ human }: { human: HumanStatus }) {
|
||||
cancelAnimationFrame(animationFrameIdRef.current)
|
||||
animationFrameIdRef.current = null
|
||||
}
|
||||
if (processAnimationIdRef.current) {
|
||||
cancelAnimationFrame(processAnimationIdRef.current);
|
||||
processAnimationIdRef.current = null;
|
||||
}
|
||||
processStartTimeRef.current = null;
|
||||
processTimeRef.current = 0;
|
||||
accumulatedPausedTimeRef.current = 0;
|
||||
lastPauseTimeRef.current = null;
|
||||
hasLoggedHalfway.current = false;
|
||||
hasLoggedCompleted.current = false;
|
||||
const object = scene.getObjectByProperty('uuid', human.modelUuid);
|
||||
if (object && human) {
|
||||
object.position.set(human.position[0], human.position[1], human.position[2]);
|
||||
@@ -103,7 +120,103 @@ function HumanInstance({ human }: { human: HumanStatus }) {
|
||||
|
||||
useEffect(() => {
|
||||
if (isPlaying) {
|
||||
if (!human.point.action.pickUpPoint || !human.point.action.dropPoint) return;
|
||||
if (!human.point.action.assemblyPoint || human.point.action.actionType === 'worker') return;
|
||||
|
||||
if (!human.isActive && human.state === 'idle' && currentPhase === 'init') {
|
||||
setHumanState(human.modelUuid, 'idle');
|
||||
setCurrentPhase('waiting');
|
||||
setHumanPicking(human.modelUuid, false);
|
||||
setHumanActive(human.modelUuid, false);
|
||||
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||
humanStatus(human.modelUuid, 'Human is waiting for material in assembly');
|
||||
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'waiting') {
|
||||
if (human.currentMaterials.length > 0 && humanAsset && humanAsset.animationState?.current !== 'working_standing') {
|
||||
setCurrentAnimation(human.modelUuid, 'working_standing', true, true, false);
|
||||
setHumanState(human.modelUuid, 'running');
|
||||
setCurrentPhase('assembling');
|
||||
setHumanPicking(human.modelUuid, true);
|
||||
setHumanActive(human.modelUuid, true);
|
||||
|
||||
processStartTimeRef.current = performance.now();
|
||||
processTimeRef.current = human.point.action.processTime || 0;
|
||||
accumulatedPausedTimeRef.current = 0;
|
||||
lastPauseTimeRef.current = null;
|
||||
hasLoggedHalfway.current = false;
|
||||
hasLoggedCompleted.current = false;
|
||||
|
||||
if (!processAnimationIdRef.current) {
|
||||
processAnimationIdRef.current = requestAnimationFrame(trackAssemblyProcess);
|
||||
}
|
||||
}
|
||||
} else if (human.isActive && human.state === 'running' && human.currentMaterials.length > 0 && humanAsset && humanAsset.animationState?.current === 'working_standing' && humanAsset.animationState?.isCompleted) {
|
||||
if (human.point.action.assemblyPoint && currentPhase === 'assembling') {
|
||||
setHumanState(human.modelUuid, 'idle');
|
||||
setCurrentPhase('waiting');
|
||||
setHumanPicking(human.modelUuid, false);
|
||||
setHumanActive(human.modelUuid, false);
|
||||
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||
humanStatus(human.modelUuid, 'Human is waiting for material in assembly');
|
||||
|
||||
decrementHumanLoad(human.modelUuid, 1);
|
||||
const material = removeLastMaterial(human.modelUuid);
|
||||
if (material) {
|
||||
triggerPointActions(human.point.action, material.materialId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
reset()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [human, currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
|
||||
|
||||
const trackAssemblyProcess = useCallback(() => {
|
||||
const now = performance.now();
|
||||
|
||||
if (!processStartTimeRef.current || !human.point.action.processTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPausedRef.current) {
|
||||
if (!lastPauseTimeRef.current) {
|
||||
lastPauseTimeRef.current = now;
|
||||
}
|
||||
processAnimationIdRef.current = requestAnimationFrame(trackAssemblyProcess);
|
||||
return;
|
||||
} else if (lastPauseTimeRef.current) {
|
||||
accumulatedPausedTimeRef.current += now - lastPauseTimeRef.current;
|
||||
lastPauseTimeRef.current = null;
|
||||
}
|
||||
|
||||
const elapsed = (now - processStartTimeRef.current - accumulatedPausedTimeRef.current) * isSpeedRef.current;
|
||||
const totalProcessTimeMs = human.point.action.processTime * 1000;
|
||||
|
||||
if (elapsed >= totalProcessTimeMs / 2 && !hasLoggedHalfway.current) {
|
||||
hasLoggedHalfway.current = true;
|
||||
if (human.currentMaterials.length > 0) {
|
||||
setMaterial(human.currentMaterials[0].materialId, human.point.action.swapMaterial || 'Default Material');
|
||||
}
|
||||
humanStatus(human.modelUuid, `🟡 Human ${human.modelUuid} reached halfway in assembly.`);
|
||||
}
|
||||
|
||||
if (elapsed >= totalProcessTimeMs && !hasLoggedCompleted.current) {
|
||||
hasLoggedCompleted.current = true;
|
||||
setCurrentAnimation(human.modelUuid, 'working_standing', true, true, true);
|
||||
if (processAnimationIdRef.current) {
|
||||
cancelAnimationFrame(processAnimationIdRef.current);
|
||||
processAnimationIdRef.current = null;
|
||||
}
|
||||
humanStatus(human.modelUuid, `✅ Human ${human.modelUuid} completed assembly process.`);
|
||||
return;
|
||||
}
|
||||
|
||||
processAnimationIdRef.current = requestAnimationFrame(trackAssemblyProcess);
|
||||
}, [human.modelUuid, human.point.action.processTime, human.currentMaterials]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPlaying) {
|
||||
if (!human.point.action.pickUpPoint || !human.point.action.dropPoint || human.point.action.actionType === 'assembly') return;
|
||||
|
||||
if (!human.isActive && human.state === 'idle' && currentPhase === 'init') {
|
||||
const toPickupPath = computePath(
|
||||
@@ -145,7 +258,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
|
||||
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
|
||||
humanStatus(human.modelUuid, 'Started from pickup point, heading to drop point');
|
||||
}
|
||||
} else if (human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0) {
|
||||
} else if (human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0 && humanAsset?.animationState?.current !== 'pickup') {
|
||||
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
|
||||
}
|
||||
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'dropping' && human.currentLoad === 0) {
|
||||
@@ -253,6 +366,9 @@ function HumanInstance({ human }: { human: HumanStatus }) {
|
||||
|
||||
function startUnloadingProcess() {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (humanAsset?.animationState?.current !== 'drop') {
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
}
|
||||
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||
if (human.point.action.triggers.length > 0) {
|
||||
const trigger = getTriggerByUuid(selectedProduct.productUuid, human.point.action.triggers[0]?.triggerUuid);
|
||||
|
||||
@@ -4,21 +4,24 @@ import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
||||
import { useProductContext } from '../../../products/productContext';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { Group, Plane, Vector3 } from 'three';
|
||||
import { Group, Plane, Vector2, Vector3 } from 'three';
|
||||
import { useVersionContext } from '../../../../builder/version/versionContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import startPoint from "../../../../../assets/gltf-glb/ui/arrow_green.glb";
|
||||
import startEnd from "../../../../../assets/gltf-glb/ui/arrow_red.glb";
|
||||
import startPoint from "../../../../../assets/gltf-glb/ui/human-ui-green.glb";
|
||||
import startEnd from "../../../../../assets/gltf-glb/ui/human-ui-orange.glb";
|
||||
import assembly from "../../../../../assets/gltf-glb/ui/human-ui-assembly.glb";
|
||||
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
|
||||
function HumanUi() {
|
||||
const { scene: startScene } = useGLTF(startPoint) as any;
|
||||
const { scene: endScene } = useGLTF(startEnd) as any;
|
||||
const { scene: assemblyScene } = useGLTF(assembly) as any;
|
||||
const startMarker = useRef<Group>(null);
|
||||
const endMarker = useRef<Group>(null);
|
||||
const assemblyMarker = useRef<Group>(null);
|
||||
const outerGroup = useRef<Group>(null);
|
||||
const prevMousePos = useRef({ x: 0, y: 0 });
|
||||
const { controls, raycaster } = useThree();
|
||||
const { controls, raycaster, camera } = useThree();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { humanStore, productStore } = useSceneContext();
|
||||
@@ -27,11 +30,13 @@ function HumanUi() {
|
||||
const { updateEvent } = productStore();
|
||||
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, Math.PI, 0]);
|
||||
const [assemblyRotation, setAssemblyRotation] = 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 plane = useRef(new Plane(new Vector3(0, 1, 0), 0));
|
||||
const dragOffset = useRef(new Vector3());
|
||||
|
||||
const [selectedHumanData, setSelectedHumanData] = useState<{
|
||||
position: [number, number, number];
|
||||
@@ -43,6 +48,10 @@ function HumanUi() {
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const selectedHuman = selectedEventSphere ? getHumanById(selectedEventSphere.userData.modelUuid) : null;
|
||||
const actionType = selectedHuman?.point?.action?.actionType || null;
|
||||
const isAssembly = actionType === 'assembly';
|
||||
|
||||
const updateBackend = (
|
||||
productName: string,
|
||||
productUuid: string,
|
||||
@@ -69,21 +78,42 @@ function HumanUi() {
|
||||
rotation: selectedHuman.rotation,
|
||||
});
|
||||
|
||||
if (outerGroup.current) {
|
||||
outerGroup.current.position.set(
|
||||
selectedHuman.position[0],
|
||||
selectedHuman.position[1],
|
||||
selectedHuman.position[2]
|
||||
);
|
||||
}
|
||||
|
||||
const action = selectedHuman.point.action;
|
||||
|
||||
if (action.pickUpPoint?.position && outerGroup.current) {
|
||||
const worldPos = new Vector3(...action.pickUpPoint.position);
|
||||
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||
setStartPosition([localPosition.x, 0.5, localPosition.z]);
|
||||
setStartPosition([localPosition.x, 1, localPosition.z]);
|
||||
setStartRotation(action.pickUpPoint.rotation || [0, 0, 0]);
|
||||
} else {
|
||||
setStartPosition([0, 1, 0]);
|
||||
setStartRotation([0, Math.PI, 0]);
|
||||
}
|
||||
|
||||
if (action.dropPoint?.position && outerGroup.current) {
|
||||
const worldPos = new Vector3(...action.dropPoint.position);
|
||||
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||
setEndPosition([localPosition.x, 0.5, localPosition.z]);
|
||||
setEndRotation(action.dropPoint.rotation || [0, 0, 0]);
|
||||
setEndPosition([localPosition.x, 1, localPosition.z]);
|
||||
setEndRotation(action.dropPoint.rotation || [0, Math.PI, 0]);
|
||||
} else {
|
||||
setEndPosition([0, 1, 0]);
|
||||
setEndRotation([0, 0, 0]);
|
||||
}
|
||||
|
||||
if (action.assemblyPoint?.rotation) {
|
||||
setAssemblyRotation(action.assemblyPoint.rotation);
|
||||
} else {
|
||||
setAssemblyRotation([0, 0, 0]);
|
||||
}
|
||||
|
||||
}, [selectedEventSphere, outerGroup.current, selectedAction, humans]);
|
||||
|
||||
const handlePointerDown = (
|
||||
@@ -91,84 +121,117 @@ function HumanUi() {
|
||||
state: "start" | "end",
|
||||
rotation: "start" | "end"
|
||||
) => {
|
||||
if (e.object.name === "handle") {
|
||||
if (isAssembly) return;
|
||||
e.stopPropagation();
|
||||
const intersection = new Vector3();
|
||||
const pointer = new Vector2((e.clientX / window.innerWidth) * 2 - 1, -(e.clientY / window.innerHeight) * 2 + 1);
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.ray.intersectPlane(plane.current, intersection);
|
||||
|
||||
if (e.object.parent.name === "handle") {
|
||||
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 as any).enabled = false;
|
||||
setIsDragging(null);
|
||||
} else {
|
||||
setIsDragging(state);
|
||||
setIsRotating(null);
|
||||
if (controls) (controls as any).enabled = false;
|
||||
}
|
||||
|
||||
if (intersects) {
|
||||
let localPoint: Vector3 | null = null;
|
||||
if (outerGroup.current) {
|
||||
localPoint = outerGroup.current.worldToLocal(intersection.clone());
|
||||
}
|
||||
const marker = state === "start" ? startMarker.current : endMarker.current;
|
||||
if (marker && localPoint) {
|
||||
const markerPos = new Vector3().copy(marker.position);
|
||||
dragOffset.current.copy(markerPos.sub(localPoint));
|
||||
}
|
||||
}
|
||||
|
||||
if (controls) (controls as any).enabled = false;
|
||||
};
|
||||
|
||||
|
||||
const handlePointerUp = () => {
|
||||
(controls as any).enabled = true;
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
|
||||
if (selectedEventSphere?.userData.modelUuid && selectedAction.actionId) {
|
||||
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
|
||||
if (!selectedEventSphere?.userData.modelUuid || !selectedAction?.actionId) return;
|
||||
|
||||
if (selectedHuman && outerGroup.current && startMarker.current && endMarker.current) {
|
||||
const worldPosStart = new Vector3(...startPosition);
|
||||
const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());
|
||||
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
|
||||
if (!selectedHuman || !outerGroup.current) return;
|
||||
|
||||
const worldPosEnd = new Vector3(...endPosition);
|
||||
const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());
|
||||
const isAssembly = selectedHuman.point?.action?.actionType === 'assembly';
|
||||
|
||||
const updatedAction = {
|
||||
...selectedHuman.point.action,
|
||||
pickUpPoint: {
|
||||
position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number],
|
||||
rotation: startRotation
|
||||
},
|
||||
dropPoint: {
|
||||
position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number],
|
||||
rotation: endRotation
|
||||
}
|
||||
};
|
||||
let updatedAction;
|
||||
|
||||
const event = updateEvent(
|
||||
selectedProduct.productUuid,
|
||||
selectedEventSphere.userData.modelUuid,
|
||||
{
|
||||
...selectedHuman,
|
||||
point: {
|
||||
...selectedHuman.point,
|
||||
action: updatedAction
|
||||
}
|
||||
}
|
||||
);
|
||||
if (isAssembly) {
|
||||
updatedAction = {
|
||||
...selectedHuman.point.action,
|
||||
assemblyPoint: {
|
||||
rotation: assemblyRotation
|
||||
},
|
||||
};
|
||||
} else {
|
||||
if (!startMarker.current || !endMarker.current) return;
|
||||
|
||||
if (event) {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
const worldPosStart = new Vector3(...startPosition);
|
||||
const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());
|
||||
|
||||
const worldPosEnd = new Vector3(...endPosition);
|
||||
const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());
|
||||
|
||||
updatedAction = {
|
||||
...selectedHuman.point.action,
|
||||
pickUpPoint: {
|
||||
position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number],
|
||||
rotation: startRotation,
|
||||
},
|
||||
dropPoint: {
|
||||
position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number],
|
||||
rotation: endRotation,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const event = updateEvent(
|
||||
selectedProduct.productUuid,
|
||||
selectedEventSphere.userData.modelUuid,
|
||||
{
|
||||
...selectedHuman,
|
||||
point: {
|
||||
...selectedHuman.point,
|
||||
action: updatedAction,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (event) {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useFrame(() => {
|
||||
if (!isDragging || !plane.current || !raycaster || !outerGroup.current) return;
|
||||
if (isAssembly || !isDragging || !plane.current || !raycaster || !outerGroup.current) return;
|
||||
const intersectPoint = new Vector3();
|
||||
const intersects = raycaster.ray.intersectPlane(
|
||||
plane.current,
|
||||
intersectPoint
|
||||
);
|
||||
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
|
||||
if (!intersects) return;
|
||||
const localPoint = outerGroup?.current.worldToLocal(intersectPoint.clone());
|
||||
|
||||
const localPoint = outerGroup.current.worldToLocal(intersectPoint.clone()).add(dragOffset.current);
|
||||
|
||||
if (isDragging === "start") {
|
||||
setStartPosition([localPoint.x, 0.5, localPoint.z]);
|
||||
setStartPosition([localPoint.x, 1, localPoint.z]);
|
||||
} else if (isDragging === "end") {
|
||||
setEndPosition([localPoint.x, 0.5, localPoint.z]);
|
||||
setEndPosition([localPoint.x, 1, localPoint.z]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -177,11 +240,17 @@ function HumanUi() {
|
||||
const currentPointerX = state.pointer.x;
|
||||
const deltaX = currentPointerX - prevMousePos.current.x;
|
||||
prevMousePos.current.x = currentPointerX;
|
||||
const marker =isRotating === "start" ? startMarker.current : endMarker.current;
|
||||
const marker = isRotating === "start" ? isAssembly ? assemblyMarker.current : startMarker.current : isAssembly ? assemblyMarker.current : endMarker.current;
|
||||
if (marker) {
|
||||
const rotationSpeed = 10;
|
||||
marker.rotation.y += deltaX * rotationSpeed;
|
||||
if (isRotating === "start") {
|
||||
if (isAssembly && isRotating === "start") {
|
||||
setAssemblyRotation([
|
||||
marker.rotation.x,
|
||||
marker.rotation.y,
|
||||
marker.rotation.z,
|
||||
]);
|
||||
} else if (isRotating === "start") {
|
||||
setStartRotation([
|
||||
marker.rotation.x,
|
||||
marker.rotation.y,
|
||||
@@ -212,7 +281,7 @@ function HumanUi() {
|
||||
return () => {
|
||||
window.removeEventListener("pointerup", handleGlobalPointerUp);
|
||||
};
|
||||
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]);
|
||||
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation, assemblyRotation]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -220,44 +289,71 @@ function HumanUi() {
|
||||
<group
|
||||
position={selectedHumanData.position}
|
||||
ref={outerGroup}
|
||||
rotation={[0, Math.PI, 0]}
|
||||
>
|
||||
<primitive
|
||||
name="startMarker"
|
||||
object={startScene}
|
||||
ref={startMarker}
|
||||
position={startPosition}
|
||||
rotation={startRotation}
|
||||
onPointerDown={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handlePointerDown(e, "start", "start");
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
(controls as any).enabled = true;
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
}}
|
||||
/>
|
||||
{isAssembly ? (
|
||||
<primitive
|
||||
ref={assemblyMarker}
|
||||
object={assemblyScene}
|
||||
position={[0, 1, 0]}
|
||||
rotation={assemblyRotation}
|
||||
onPointerDown={(e: any) => {
|
||||
if (e.object.parent.name === "handle") {
|
||||
e.stopPropagation();
|
||||
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
|
||||
prevMousePos.current.x = normalizedX;
|
||||
setIsRotating("start");
|
||||
setIsDragging(null);
|
||||
if (controls) (controls as any).enabled = false;
|
||||
}
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
if (controls) (controls as any).enabled = true;
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<primitive
|
||||
name="startMarker"
|
||||
object={startScene}
|
||||
ref={startMarker}
|
||||
position={startPosition}
|
||||
rotation={startRotation}
|
||||
onPointerDown={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handlePointerDown(e, "start", "start");
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
if (controls) (controls as any).enabled = true;
|
||||
}}
|
||||
/>
|
||||
|
||||
<primitive
|
||||
name="endMarker"
|
||||
object={endScene}
|
||||
ref={endMarker}
|
||||
position={endPosition}
|
||||
rotation={endRotation}
|
||||
onPointerDown={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handlePointerDown(e, "end", "end");
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
(controls as any).enabled = true;
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
}}
|
||||
/>
|
||||
<primitive
|
||||
name="endMarker"
|
||||
object={endScene}
|
||||
ref={endMarker}
|
||||
position={endPosition}
|
||||
rotation={endRotation}
|
||||
onPointerDown={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handlePointerDown(e, "end", "end");
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
if (controls) (controls as any).enabled = true;
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</group>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default HumanUi
|
||||
@@ -301,7 +301,6 @@ const VehicleUI = () => {
|
||||
return selectedVehicleData ? (
|
||||
<group
|
||||
position={selectedVehicleData.position}
|
||||
rotation={selectedVehicleData.rotation}
|
||||
ref={outerGroup}
|
||||
>
|
||||
<group
|
||||
|
||||
@@ -299,6 +299,10 @@ export function useTriggerHandler() {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
if (human && human.modelUuid === "cc62adae-7000-447b-b845-6d4910de503a") {
|
||||
console.log(human);
|
||||
}
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
@@ -330,7 +334,9 @@ export function useTriggerHandler() {
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
@@ -341,7 +347,9 @@ export function useTriggerHandler() {
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
@@ -354,7 +362,9 @@ export function useTriggerHandler() {
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
@@ -365,7 +375,9 @@ export function useTriggerHandler() {
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
@@ -382,7 +394,9 @@ export function useTriggerHandler() {
|
||||
if (conveyor) {
|
||||
if (!conveyor.isPaused) {
|
||||
// Handle current action from vehicle
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
@@ -393,7 +407,9 @@ export function useTriggerHandler() {
|
||||
|
||||
addConveyorToMonitor(conveyor.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
@@ -406,7 +422,9 @@ export function useTriggerHandler() {
|
||||
if (conveyor) {
|
||||
if (!conveyor.isPaused) {
|
||||
// Handle current action from vehicle
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
@@ -417,7 +435,9 @@ export function useTriggerHandler() {
|
||||
|
||||
addConveyorToMonitor(conveyor.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
@@ -434,7 +454,9 @@ export function useTriggerHandler() {
|
||||
if (machine) {
|
||||
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||
setIsPaused(materialId, true);
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
} else {
|
||||
|
||||
@@ -443,7 +465,9 @@ export function useTriggerHandler() {
|
||||
|
||||
addMachineToMonitor(machine.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
@@ -456,7 +480,9 @@ export function useTriggerHandler() {
|
||||
if (machine) {
|
||||
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||
setIsPaused(materialId, true);
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
} else {
|
||||
|
||||
@@ -465,7 +491,9 @@ export function useTriggerHandler() {
|
||||
|
||||
addMachineToMonitor(machine.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
@@ -480,7 +508,9 @@ export function useTriggerHandler() {
|
||||
|
||||
// Handle current action from arm bot
|
||||
setIsPaused(materialId, true);
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
@@ -489,7 +519,9 @@ export function useTriggerHandler() {
|
||||
setIsPaused(materialId, true);
|
||||
addHumanToMonitor(human.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
);
|
||||
@@ -501,7 +533,9 @@ export function useTriggerHandler() {
|
||||
|
||||
// Handle current action from arm bot
|
||||
setIsPaused(materialId, true);
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
@@ -510,7 +544,9 @@ export function useTriggerHandler() {
|
||||
setIsPaused(materialId, true);
|
||||
addHumanToMonitor(human.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
if (action.actionType === 'worker') {
|
||||
setIsVisible(materialId, false);
|
||||
}
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
);
|
||||
@@ -1280,7 +1316,7 @@ export function useTriggerHandler() {
|
||||
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
if (material && action.actionType === 'worker') {
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
@@ -1410,6 +1446,28 @@ export function useTriggerHandler() {
|
||||
handleAction(action, material.materialId);
|
||||
}
|
||||
|
||||
} else if (material && action.actionType === 'assembly') {
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, {
|
||||
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid,
|
||||
})
|
||||
|
||||
setIsPaused(material.materialId, false);
|
||||
setIsVisible(material.materialId, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,40 +6,53 @@ import { MaterialModel } from '../../../materials/instances/material/materialMod
|
||||
const MaterialAnimator = ({ agvDetail }: { agvDetail: VehicleStatus }) => {
|
||||
const meshRef = useRef<any>(null!);
|
||||
const [hasLoad, setHasLoad] = useState(false);
|
||||
const [isAttached, setIsAttached] = useState(false);
|
||||
const { scene } = useThree();
|
||||
const offset = new THREE.Vector3(0, 0.85, 0);
|
||||
|
||||
useEffect(() => {
|
||||
setHasLoad(agvDetail.currentLoad > 0);
|
||||
const loadState = agvDetail.currentLoad > 0;
|
||||
setHasLoad(loadState);
|
||||
|
||||
if (!loadState) {
|
||||
setIsAttached(false);
|
||||
if (meshRef.current?.parent) {
|
||||
meshRef.current.parent.remove(meshRef.current);
|
||||
}
|
||||
}
|
||||
}, [agvDetail.currentLoad]);
|
||||
|
||||
useFrame(() => {
|
||||
if (!hasLoad || !meshRef.current) return;
|
||||
if (!hasLoad || !meshRef.current || isAttached) return;
|
||||
|
||||
const agvModel = scene.getObjectByProperty("uuid", agvDetail.modelUuid) as THREE.Object3D;
|
||||
if (agvModel) {
|
||||
const worldPosition = offset.clone().applyMatrix4(agvModel.matrixWorld);
|
||||
meshRef.current.position.copy(worldPosition);
|
||||
meshRef.current.rotation.copy(agvModel.rotation);
|
||||
if (agvModel && !isAttached) {
|
||||
if (meshRef.current.parent) {
|
||||
meshRef.current.parent.remove(meshRef.current);
|
||||
}
|
||||
|
||||
agvModel.add(meshRef.current);
|
||||
|
||||
meshRef.current.position.copy(offset);
|
||||
meshRef.current.rotation.set(0, 0, 0);
|
||||
meshRef.current.scale.set(1, 1, 1);
|
||||
|
||||
setIsAttached(true);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{hasLoad && (
|
||||
<>
|
||||
{agvDetail.currentMaterials.length > 0 &&
|
||||
<MaterialModel
|
||||
matRef={meshRef}
|
||||
materialId={agvDetail.currentMaterials[0].materialId || ''}
|
||||
materialType={agvDetail.currentMaterials[0].materialType || 'Default material'}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
{hasLoad && agvDetail.currentMaterials.length > 0 && (
|
||||
<MaterialModel
|
||||
matRef={meshRef}
|
||||
materialId={agvDetail.currentMaterials[0].materialId || ''}
|
||||
materialType={agvDetail.currentMaterials[0].materialType || 'Default material'}
|
||||
visible={isAttached}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default MaterialAnimator;
|
||||
export default MaterialAnimator;
|
||||
@@ -87,7 +87,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||
const distances = [];
|
||||
let accumulatedDistance = 0;
|
||||
let index = 0;
|
||||
const rotationSpeed = 1;
|
||||
const rotationSpeed = 0.75;
|
||||
|
||||
for (let i = 0; i < currentPath.length - 1; i++) {
|
||||
const start = new THREE.Vector3(...currentPath[i]);
|
||||
@@ -107,17 +107,25 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||
const end = new THREE.Vector3(...currentPath[index + 1]);
|
||||
const segmentDistance = distances[index];
|
||||
|
||||
const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
|
||||
const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
|
||||
const currentAngle = object.rotation.y;
|
||||
const targetQuaternion = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().lookAt(start, end, new THREE.Vector3(0, 1, 0)));
|
||||
const y180 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);
|
||||
targetQuaternion.multiply(y180);
|
||||
|
||||
let angleDifference = targetAngle - currentAngle;
|
||||
if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI;
|
||||
if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI;
|
||||
const angle = object.quaternion.angleTo(targetQuaternion);
|
||||
if (angle < 0.01) {
|
||||
object.quaternion.copy(targetQuaternion);
|
||||
} else {
|
||||
const step = rotationSpeed * delta * speed * agvDetail.speed;
|
||||
const angle = object.quaternion.angleTo(targetQuaternion);
|
||||
|
||||
const maxRotationStep = (rotationSpeed * speed * agvDetail.speed) * delta;
|
||||
object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep);
|
||||
const isAligned = Math.abs(angleDifference) < 0.01;
|
||||
if (angle < step) {
|
||||
object.quaternion.copy(targetQuaternion);
|
||||
} else {
|
||||
object.quaternion.rotateTowards(targetQuaternion, step);
|
||||
}
|
||||
}
|
||||
|
||||
const isAligned = angle < 0.01;
|
||||
|
||||
if (isAligned) {
|
||||
progressRef.current += delta * (speed * agvDetail.speed);
|
||||
@@ -129,17 +137,25 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||
|
||||
if (progressRef.current >= totalDistance) {
|
||||
if (restRotation && objectRotation) {
|
||||
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 * (rotationSpeed * speed * agvDetail.speed));
|
||||
if (object.quaternion.angleTo(targetQuaternion) < 0.01) {
|
||||
const targetEuler = new THREE.Euler(0, objectRotation.y - agvDetail.point.action.steeringAngle, 0);
|
||||
|
||||
const baseQuaternion = new THREE.Quaternion().setFromEuler(targetEuler);
|
||||
const y180 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);
|
||||
const targetQuaternion = baseQuaternion.multiply(y180);
|
||||
|
||||
const angle = object.quaternion.angleTo(targetQuaternion);
|
||||
if (angle < 0.01) {
|
||||
object.quaternion.copy(targetQuaternion);
|
||||
object.rotation.copy(targetEuler);
|
||||
setRestingRotation(false);
|
||||
} else {
|
||||
const step = rotationSpeed * delta * speed * agvDetail.speed;
|
||||
const angle = object.quaternion.angleTo(targetQuaternion);
|
||||
|
||||
if (angle < step) {
|
||||
object.quaternion.copy(targetQuaternion);
|
||||
} else {
|
||||
object.quaternion.rotateTowards(targetQuaternion, step);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user