diff --git a/app/src/modules/builder/asset/functions/assetBoundingBox.tsx b/app/src/modules/builder/asset/functions/assetBoundingBox.tsx
index da08edf..7736e29 100644
--- a/app/src/modules/builder/asset/functions/assetBoundingBox.tsx
+++ b/app/src/modules/builder/asset/functions/assetBoundingBox.tsx
@@ -3,8 +3,15 @@ import { useMemo } from "react";
import { Cylinder } from "@react-three/drei";
export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth, }: { name: string; boundingBox: Box3 | null; color: string; lineWidth: number; }) => {
- const { edgeCylinders, center, size } = useMemo(() => {
- if (!boundingBox) return { edgeCylinders: [], center: new Vector3(), size: new Vector3() };
+ const { edgeCylinders, cornerSpheres, center, size } = useMemo(() => {
+ if (!boundingBox) {
+ return {
+ edgeCylinders: [],
+ cornerSpheres: [],
+ center: new Vector3(),
+ size: new Vector3(),
+ };
+ }
const min = boundingBox.min;
const max = boundingBox.max;
@@ -50,7 +57,13 @@ export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth, }: { nam
};
});
- return { edgeCylinders, center, size };
+ const cornerSpheres = corners.map((corner, i) => ({
+ key: `corner-sphere-${i}`,
+ position: corner.clone(),
+ radius: radius * 1.5,
+ }));
+
+ return { edgeCylinders, cornerSpheres, center, size };
}, [boundingBox, lineWidth]);
if (!boundingBox) return null;
@@ -58,11 +71,18 @@ export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth, }: { nam
return (
{edgeCylinders.map(({ key, position, rotation, length, radius }) => (
-
+
))}
+ {cornerSpheres.map(({ key, position, radius }) => (
+
+
+
+
+ ))}
+
diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx
index 16f37ee..96076f9 100644
--- a/app/src/modules/builder/asset/models/model/model.tsx
+++ b/app/src/modules/builder/asset/models/model/model.tsx
@@ -449,7 +449,11 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
>
) : (
-
+ <>
+ {!isSelected &&
+
+ }
+ >
)}
{isSelected &&
diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts
index 0373fd0..ebe01ff 100644
--- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts
+++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts
@@ -6,12 +6,13 @@ import { useProductContext } from "../../../products/productContext";
import { useHumanEventManager } from "../../../human/eventManager/useHumanEventManager";
export function useRetrieveHandler() {
- const { materialStore, armBotStore, machineStore, vehicleStore, storageUnitStore, productStore, humanStore, assetStore } = useSceneContext();
+ const { materialStore, armBotStore, machineStore, vehicleStore, storageUnitStore, conveyorStore, productStore, humanStore, assetStore } = useSceneContext();
const { selectedProductStore } = useProductContext();
const { addMaterial } = materialStore();
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore();
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
+ const { getConveyorById } = conveyorStore();
const { getHumanById, incrementHumanLoad, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
const { getAssetById, setCurrentAnimation } = assetStore();
const { selectedProduct } = selectedProductStore();
@@ -60,9 +61,9 @@ export function useRetrieveHandler() {
actionUuid: action.actionUuid
},
current: {
- modelUuid: action.triggers[0]?.triggeredAsset.triggeredModel.modelUuid,
- pointUuid: action.triggers[0]?.triggeredAsset.triggeredPoint.pointUuid,
- actionUuid: action.triggers[0]?.triggeredAsset.triggeredAction.actionUuid
+ modelUuid: modelUuid,
+ pointUuid: pointUuid,
+ actionUuid: action.actionUuid
},
};
@@ -371,6 +372,32 @@ export function useRetrieveHandler() {
}
return;
}
+ } else if (triggeredModel?.type === 'transfer') {
+ const model = getConveyorById(triggeredModel.modelUuid);
+ if (model && !model.isPaused) {
+ if (humanAsset?.animationState?.current === 'idle') {
+ setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
+ } else if (humanAsset?.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) {
+ const lastMaterial = getLastMaterial(storageUnit.modelUuid);
+ if (lastMaterial) {
+ const material = createNewMaterial(
+ lastMaterial.materialId,
+ lastMaterial.materialType,
+ storageUnit.point.action
+ );
+ if (material) {
+ removeLastMaterial(storageUnit.modelUuid);
+ updateCurrentLoad(storageUnit.modelUuid, -1);
+ incrementHumanLoad(human.modelUuid, 1);
+ addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
+ retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);
+
+ retrievalCountRef.current.set(actionUuid, currentCount + 1);
+ }
+ }
+ }
+ return;
+ }
} else if (triggeredModel?.type === 'machine') {
const machine = getMachineById(triggeredModel.modelUuid);
if (machine && !machine.isActive && machine.state === 'idle' && !machine.currentAction) {
diff --git a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx
index 236ab55..1469d7f 100644
--- a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx
+++ b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx
@@ -182,31 +182,23 @@ function TriggerConnector() {
const canvasElement = gl.domElement;
let drag = false;
- let isRightMouseDown = false;
+ let isLeftMouseDown = false;
const onMouseDown = (evt: MouseEvent) => {
if (selectedAsset) {
clearSelectedAsset();
}
- if (evt.button === 2) {
- isRightMouseDown = true;
+ if (evt.button === 0) {
+ isLeftMouseDown = true;
drag = false;
}
};
const onMouseUp = (evt: MouseEvent) => {
- if (evt.button === 2) {
- isRightMouseDown = false;
+ if (evt.button === 0) {
+ isLeftMouseDown = false;
}
- }
- const onMouseMove = () => {
- if (isRightMouseDown) {
- drag = true;
- }
- };
-
- const handleRightClick = (evt: MouseEvent) => {
if (drag) return;
evt.preventDefault();
@@ -368,13 +360,16 @@ function TriggerConnector() {
} else if (firstSelectedPoint) {
setFirstSelectedPoint(null);
}
+ }
+
+ const onMouseMove = () => {
+ drag = true;
};
if (subModule === 'mechanics' && toolMode === 'cursor' && selectedAction.actionId && selectedAction.actionName) {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
- canvasElement.addEventListener('contextmenu', handleRightClick);
} else {
setFirstSelectedPoint(null);
}
@@ -383,7 +378,6 @@ function TriggerConnector() {
canvasElement.removeEventListener("mousedown", onMouseDown);
canvasElement.removeEventListener("mouseup", onMouseUp);
canvasElement.removeEventListener("mousemove", onMouseMove);
- canvasElement.removeEventListener('contextmenu', handleRightClick);
};
}, [gl, subModule, selectedProduct, firstSelectedPoint, toolMode, selectedAction]);
diff --git a/app/src/modules/simulation/human/instances/instance/humanUi.tsx b/app/src/modules/simulation/human/instances/instance/humanUi.tsx
index 17335b1..043811a 100644
--- a/app/src/modules/simulation/human/instances/instance/humanUi.tsx
+++ b/app/src/modules/simulation/human/instances/instance/humanUi.tsx
@@ -1,5 +1,6 @@
import { useEffect, useRef, useState } from 'react'
-import { useGLTF } from '@react-three/drei';
+import * as THREE from 'three'
+import { Tube, useGLTF } from '@react-three/drei';
import { useFrame, useThree } from '@react-three/fiber';
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
import { useProductContext } from '../../../products/productContext';
@@ -27,7 +28,7 @@ function HumanUi() {
const { humanStore, productStore } = useSceneContext();
const { selectedProduct } = selectedProductStore();
const { humans, getHumanById } = humanStore();
- const { updateEvent, updateAction, getActionByUuid } = productStore();
+ const { updateEvent, getActionByUuid } = productStore();
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 1, 0]);
const [assemblyPosition, setAssemblyPosition] = useState<[number, number, number]>([0, 1, 0]);
@@ -313,64 +314,49 @@ function HumanUi() {
rotation={[0, Math.PI, 0]}
>
{isAssembly ? (
- {
- if (e.object.parent.name === "handle") {
- handlePointerDown(e, "assembly", "assembly");
- } else {
- handlePointerDown(e, "assembly", "assembly");
- }
- }}
- onPointerMissed={() => {
- setIsDragging(null);
- setIsRotating(null);
- if (controls) (controls as any).enabled = true;
- }}
+ outerGroupRef={outerGroup}
+ type="assembly"
+ subtype="assembly"
+ color="#0f87f7"
+ setIsDragging={setIsDragging}
+ setIsRotating={setIsRotating}
+ handlePointerDown={handlePointerDown}
/>
) : (
<>
- {
- if (e.object.parent.name === "handle") {
- handlePointerDown(e, "start", "start");
- } else {
- handlePointerDown(e, "start", "start");
- }
- }}
- onPointerMissed={() => {
- setIsDragging(null);
- setIsRotating(null);
- if (controls) (controls as any).enabled = true;
- }}
+ outerGroupRef={outerGroup}
+ type="start"
+ subtype="start"
+ color="lightgreen"
+ setIsDragging={setIsDragging}
+ setIsRotating={setIsRotating}
+ handlePointerDown={handlePointerDown}
/>
-
- {
- if (e.object.parent.name === "handle") {
- handlePointerDown(e, "end", "end");
- } else {
- handlePointerDown(e, "end", "end");
- }
- }}
- onPointerMissed={() => {
- setIsDragging(null);
- setIsRotating(null);
- if (controls) (controls as any).enabled = true;
- }}
+ outerGroupRef={outerGroup}
+ type="end"
+ subtype="end"
+ color="darkorange"
+ setIsDragging={setIsDragging}
+ setIsRotating={setIsRotating}
+ handlePointerDown={handlePointerDown}
/>
>
)}
@@ -380,4 +366,101 @@ function HumanUi() {
);
}
-export default HumanUi;
\ No newline at end of file
+export default HumanUi;
+
+const MarkerPrimitive = ({
+ name,
+ refProp,
+ object,
+ position,
+ rotation,
+ outerGroupRef,
+ type,
+ subtype,
+ color,
+ setIsDragging,
+ setIsRotating,
+ handlePointerDown,
+}: {
+ name: string;
+ refProp: any;
+ object: THREE.Object3D;
+ position: [number, number, number];
+ rotation: [number, number, number];
+ outerGroupRef: React.RefObject;
+ type: string;
+ subtype: string;
+ color: string;
+ setIsDragging: (val: any) => void;
+ setIsRotating: (val: any) => void;
+ handlePointerDown: any;
+}) => {
+ const { controls, scene, camera } = useThree();
+ const [hitPoint, setHitPoint] = useState(null);
+ const [curve, setCurve] = useState(null);
+
+ useFrame(() => {
+ if (!refProp.current || !outerGroupRef.current || !scene) return;
+
+ const worldPos = new THREE.Vector3();
+ refProp.current.getWorldPosition(worldPos);
+ const localMarkerPos = outerGroupRef.current.worldToLocal(worldPos.clone());
+
+ const rayOrigin = worldPos.clone();
+ const direction = new THREE.Vector3(0, -1, 0);
+ const raycaster = new THREE.Raycaster(rayOrigin, direction, 0.1, 1000);
+ raycaster.camera = camera;
+ const intersects = raycaster.intersectObjects(scene.children, true);
+
+ const hit = intersects.find(i => i.object.name !== name);
+
+ if (hit) {
+ const localHit = outerGroupRef.current.worldToLocal(hit.point.clone());
+ setHitPoint(localHit);
+
+ const newCurve = new THREE.CatmullRomCurve3([
+ localMarkerPos.clone(),
+ localHit.clone(),
+ ]);
+ setCurve(newCurve);
+ } else {
+ setHitPoint(null);
+ setCurve(null);
+ }
+ });
+
+ return (
+ <>
+ {
+ handlePointerDown(e, type, subtype);
+ }}
+ onPointerMissed={() => {
+ setIsDragging(null);
+ setIsRotating(null);
+ if (controls) (controls as any).enabled = true;
+ }}
+ />
+
+ {hitPoint && (
+ <>
+
+
+
+
+
+ {curve && (
+
+
+
+ )}
+ >
+ )}
+ >
+ );
+};
\ No newline at end of file
diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx
index 72cd5fe..318759a 100644
--- a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx
+++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx
@@ -61,30 +61,12 @@ function MaterialInstance({ material }: { readonly material: MaterialSchema }) {
function getCurrentSpeed(productUuid: string, modelUuid: string) {
const event = getEventByModelUuid(productUuid, modelUuid)
if (event) {
- if (event.type === 'transfer') {
- return event.speed;
- }
-
- if (event.type === 'vehicle') {
- return event.speed;
- }
-
- if (event.type === 'machine') {
+ if (event.type === 'transfer' || event.type === 'machine' || event.type === 'storageUnit') {
return 1;
}
-
- if (event.type === 'roboticArm') {
+ if (event.type === 'vehicle' || event.type === 'roboticArm' || event.type === 'human') {
return event.speed;
}
-
- if (event.type === 'storageUnit') {
- return 1;
- }
-
- if (event.type === 'human') {
- return event.speed;
- }
-
} else {
return 1;
}
diff --git a/app/src/modules/simulation/materials/instances/materialInstances.tsx b/app/src/modules/simulation/materials/instances/materialInstances.tsx
index 88b127f..35bdaef 100644
--- a/app/src/modules/simulation/materials/instances/materialInstances.tsx
+++ b/app/src/modules/simulation/materials/instances/materialInstances.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react'
+import { useEffect } from 'react'
import MaterialInstance from './instance/materialInstance'
import { useSceneContext } from '../../../scene/sceneContext';
diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
index 1f81c2d..be3a452 100644
--- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
+++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
@@ -33,8 +33,8 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
const [customCurvePoints, setCustomCurvePoints] = useState(null);
const { armBotStore, productStore, materialStore } = useSceneContext();
const { getArmBotById } = armBotStore();
- const { getMaterialById } = materialStore();
- const { getEventByModelUuid } = productStore();
+ const { getMaterialById, getMaterialPosition } = materialStore();
+ const { getEventByModelUuid, getActionByUuid, getPointByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { scene } = useThree();
@@ -167,13 +167,18 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
let start = currentPath[0];
let end = currentPath[currentPath.length - 1];
+ const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
const armbotStatus = getArmBotById(armBot.modelUuid);
const currentMaterial = armbotStatus?.currentAction?.materialId;
- if (armbotStatus && currentMaterial && (currentPhase === 'rest-to-start' || currentPhase === 'start-to-end')) {
+ const currentAction = getActionByUuid(selectedProduct.productUuid, armbotStatus?.currentAction?.actionUuid || '');
+
+ if (armbotStatus && currentMaterial && currentAction && (currentPhase === 'rest-to-start' || currentPhase === 'start-to-end' || currentPhase === 'end-to-rest')) {
const materialData = getMaterialById(currentMaterial);
if (materialData) {
const prevModel = getEventByModelUuid(selectedProduct.productUuid, materialData.current.modelUuid);
+ const nextModel = getEventByModelUuid(selectedProduct.productUuid, currentAction?.triggers[0]?.triggeredAsset?.triggeredModel?.modelUuid || '');
+ const nextPoint = getPointByUuid(selectedProduct.productUuid, currentAction?.triggers[0]?.triggeredAsset?.triggeredModel?.modelUuid || '', currentAction?.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid || '');
if (prevModel && prevModel.type === 'transfer') {
const material = scene.getObjectByProperty("uuid", currentMaterial);
@@ -194,7 +199,69 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
start = [materialLocalPos.x, materialLocalPos.y + 0.35, materialLocalPos.z];
}
}
+ } else if (prevModel && prevModel.type === 'storageUnit') {
+ const position = getMaterialPosition(prevModel.modelUuid, currentMaterial);
+ const armbotModel = scene.getObjectByProperty("uuid", armBot.modelUuid);
+
+ if (armbotModel) {
+ const armbotWorldPos = new THREE.Vector3();
+
+ let materialWorldPos = new THREE.Vector3();
+
+ if (position) {
+ materialWorldPos.copy(position);
+ } else {
+ materialWorldPos.copy(bone.getWorldPosition(armbotWorldPos));
+ }
+
+ const materialLocalPos = materialWorldPos.clone();
+ armbotModel.worldToLocal(materialLocalPos);
+
+ if (currentPhase === 'rest-to-start') {
+ end = [materialLocalPos.x, materialLocalPos.y + 0.35, materialLocalPos.z];
+ } else if (currentPhase === 'start-to-end') {
+ start = [materialLocalPos.x, materialLocalPos.y + 0.35, materialLocalPos.z];
+ } else if (currentPhase === 'end-to-rest') {
+ start = [materialLocalPos.x, materialLocalPos.y + 0.35, materialLocalPos.z];
+ }
+ }
}
+
+ if (nextModel && nextPoint && nextModel.type === 'transfer') {
+ const conveyorModel = scene.getObjectByProperty("uuid", nextModel.modelUuid);
+ const armbotModel = scene.getObjectByProperty("uuid", armBot.modelUuid);
+ if (conveyorModel && armbotModel) {
+ const localPoint = new THREE.Vector3(
+ nextPoint.position[0],
+ nextPoint.position[1],
+ nextPoint.position[2]
+ );
+
+ const worldPoint = conveyorModel.localToWorld(localPoint);
+
+ armbotModel.worldToLocal(worldPoint);
+
+ if (currentPhase === 'start-to-end') {
+ end = [worldPoint.x, worldPoint.y + 0.35, worldPoint.z];
+ }
+ }
+ }
+ }
+
+ }
+
+ if (currentPhase === 'end-to-rest') {
+ console.log('currentPhase: ', currentPhase);
+ const armbotModel = scene.getObjectByProperty("uuid", armBot.modelUuid);
+ const armbotWorldPos = new THREE.Vector3();
+
+ if (armbotModel) {
+ let materialWorldPos = new THREE.Vector3();
+ materialWorldPos.copy(bone.getWorldPosition(armbotWorldPos));
+
+ const materialLocalPos = materialWorldPos.clone();
+ armbotModel.worldToLocal(materialLocalPos);
+ start = [materialLocalPos.x, materialLocalPos.y + 0.35, materialLocalPos.z];
}
}
diff --git a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx
index 1f4dee8..dfd500a 100644
--- a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx
+++ b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx
@@ -173,13 +173,16 @@ const ArmBotUI = () => {
const targetMesh = scene?.getObjectByProperty("uuid", selectedArmBotData?.modelUuid || '');
+ const iks = targetMesh?.userData?.iks;
+ const firstIK = Array.isArray(iks) && iks.length > 0 ? iks[0] : {};
+
const { handlePointerDown } = useDraggableGLTF(
updatePointToState,
{
- minDistance: targetMesh?.userData?.iks[0]?.minDistance || 1.2,
- maxDistance: targetMesh?.userData?.iks[0]?.maxDistance || 2,
- maxheight: targetMesh?.userData?.iks[0]?.maxheight || 0.6,
- minheight: targetMesh?.userData?.iks[0]?.minheight || 1.9,
+ minDistance: firstIK.minDistance ?? 1.2,
+ maxDistance: firstIK.maxDistance ?? 2,
+ maxheight: firstIK.maxheight ?? 0.6,
+ minheight: firstIK.minheight ?? 1.9,
}
);
diff --git a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx
index 9bd36b5..e287b8e 100644
--- a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx
+++ b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx
@@ -1,6 +1,7 @@
import { useEffect, useRef, useState } from "react";
import * as Types from "../../../../types/world/worldTypes";
-import { useGLTF } from "@react-three/drei";
+import { Tube, useGLTF } from "@react-three/drei";
+import * as THREE from "three";
import { useFrame, useThree } from "@react-three/fiber";
import { useSelectedEventSphere, useIsDragging, useIsRotating, } from "../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
@@ -16,8 +17,6 @@ import { useVersionContext } from "../../../builder/version/versionContext";
const VehicleUI = () => {
const { scene: startScene } = useGLTF(startPoint) as any;
const { scene: endScene } = useGLTF(startEnd) as any;
- const startMarker = useRef(null);
- const endMarker = useRef(null);
const prevMousePos = useRef({ x: 0, y: 0 });
const { selectedEventSphere } = useSelectedEventSphere();
const { selectedProductStore } = useProductContext();
@@ -162,7 +161,7 @@ const VehicleUI = () => {
let globalStartPosition = null;
let globalEndPosition = null;
- if (outerGroup.current && startMarker.current && endMarker.current) {
+ if (outerGroup.current) {
const worldPosStart = new Vector3(...startPosition);
globalStartPosition = outerGroup.current.localToWorld(
worldPosStart.clone()
@@ -277,24 +276,19 @@ const VehicleUI = () => {
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,
- ]);
- }
+ const rotationSpeed = 10;
+ if (isRotating === "start") {
+ setStartRotation([
+ startRotation[0],
+ startRotation[1] + deltaX * rotationSpeed,
+ startRotation[2],
+ ]);
+ } else {
+ setEndRotation([
+ endRotation[0],
+ endRotation[1] + deltaX * rotationSpeed,
+ endRotation[2],
+ ]);
}
});
@@ -342,41 +336,130 @@ const VehicleUI = () => {
{/* Start Marker */}
- {
- e.stopPropagation();
- handlePointerDown(e, "start", "start");
- }}
+ outerGroupRef={outerGroup}
+ color="green"
+ handlePointerDown={handlePointerDown}
+ setIsDragging={setIsDragging}
+ setIsRotating={setIsRotating}
+ />
+
+ {/* End Marker */}
+
+
+ ) : null;
+};
+
+export default VehicleUI;
+
+export const VehicleMarkerPrimitive = ({
+ name,
+ object,
+ position,
+ rotation,
+ outerGroupRef,
+ color,
+ handlePointerDown,
+ setIsDragging,
+ setIsRotating,
+}: {
+ name: string;
+ object: THREE.Object3D;
+ position: [number, number, number];
+ rotation: [number, number, number];
+ outerGroupRef: React.RefObject;
+ color: string;
+ handlePointerDown: (e: any, type: "start" | "end", rotation: "start" | "end") => void;
+ setIsDragging: (val: any) => void;
+ setIsRotating: (val: any) => void;
+}) => {
+ const { scene, camera } = useThree();
+ const markerRef = useRef(null);
+ const [hitPoint, setHitPoint] = useState(null);
+ const [curve, setCurve] = useState(null);
+
+ useFrame(() => {
+ if (!markerRef.current || !outerGroupRef.current) return;
+
+ const worldPos = new THREE.Vector3();
+ markerRef.current.getWorldPosition(worldPos);
+ const localMarkerPos = outerGroupRef.current.worldToLocal(worldPos.clone());
+
+ const rayOrigin = worldPos.clone();
+ const direction = new THREE.Vector3(0, -1, 0);
+ const raycaster = new THREE.Raycaster(rayOrigin, direction, 0.1, 1000);
+ raycaster.camera = camera;
+ const intersects = raycaster.intersectObjects(scene.children, true);
+
+ const hit = intersects.find(i => i.object.name !== name);
+ if (hit) {
+ const localHit = outerGroupRef.current.worldToLocal(hit.point.clone());
+ setHitPoint(localHit);
+
+ const newCurve = new THREE.CatmullRomCurve3([
+ localMarkerPos.clone(),
+ localHit.clone(),
+ ]);
+ setCurve(newCurve);
+ } else {
+ setHitPoint(null);
+ setCurve(null);
+ }
+ });
+
+ return (
+ <>
+
+ handlePointerDown(
+ e,
+ name === "startMarker" ? "start" : "end",
+ name === "startMarker" ? "start" : "end"
+ )
+ }
onPointerMissed={() => {
- controls.enabled = true;
setIsDragging(null);
setIsRotating(null);
}}
/>
- {/* End Marker */}
- {
- e.stopPropagation();
- handlePointerDown(e, "end", "end");
- }}
- onPointerMissed={() => {
- controls.enabled = true;
- setIsDragging(null);
- setIsRotating(null);
- }}
- />
-
- ) : null;
-};
-export default VehicleUI;
+ {hitPoint && (
+ <>
+
+
+
+
+
+ {curve && (
+
+
+
+ )}
+ >
+ )}
+ >
+ );
+};
\ No newline at end of file
diff --git a/app/src/modules/simulation/storageUnit/instances/animator/MaterialAnimator.tsx b/app/src/modules/simulation/storageUnit/instances/animator/MaterialAnimator.tsx
index 2a95262..87ffd32 100644
--- a/app/src/modules/simulation/storageUnit/instances/animator/MaterialAnimator.tsx
+++ b/app/src/modules/simulation/storageUnit/instances/animator/MaterialAnimator.tsx
@@ -1,72 +1,84 @@
-import { useRef, useMemo } from "react";
-import { MaterialModel } from "../../../materials/instances/material/materialModel";
+import { useEffect, useMemo } from "react";
import { Object3D, Box3, Vector3 } from "three";
import { useThree } from "@react-three/fiber";
import { useLoadingProgress } from "../../../../../store/builder/store";
+import { MaterialModel } from "../../../materials/instances/material/materialModel";
+import { useSceneContext } from "../../../../scene/sceneContext";
const MaterialAnimator = ({
- storage,
+ storage,
}: Readonly<{ storage: StorageUnitStatus }>) => {
- const meshRef = useRef(null!);
- const { scene } = useThree();
- const padding = 0.1;
- const { loadingProgress } = useLoadingProgress();
+ const { scene } = useThree();
+ const padding = 0.1;
+ const { loadingProgress } = useLoadingProgress();
+ const { materialStore } = useSceneContext();
+ const { materialPositions, setMaterialPositions } = materialStore();
- const storageModel = useMemo(() => {
- return scene.getObjectByProperty("uuid", storage.modelUuid) as Object3D;
- }, [scene, storage.modelUuid, loadingProgress]);
+ const storageModel = useMemo(() => {
+ return scene.getObjectByProperty("uuid", storage.modelUuid) as Object3D;
+ }, [scene, storage.modelUuid, loadingProgress]);
- const materialPositions = useMemo(() => {
- if (!storageModel || storage.currentMaterials.length === 0) return [];
+ useEffect(() => {
+ if (!storageModel || storage.currentMaterials.length === 0) {
+ setMaterialPositions(storage.modelUuid, []);
+ return;
+ }
- const box = new Box3().setFromObject(storageModel);
- const size = new Vector3();
- box.getSize(size);
+ const box = new Box3().setFromObject(storageModel);
+ const size = new Vector3();
+ box.getSize(size);
- const matCount = storage.currentMaterials.length;
+ const materialWidth = 0.45;
+ const materialDepth = 0.45;
+ const materialHeight = 0.3;
+ const cols = Math.floor(size.x / materialWidth);
+ const rows = Math.floor(size.z / materialDepth);
+ const itemsPerLayer = cols * rows;
- // Assumed size each material needs in world units
- const materialWidth = 0.45;
- const materialDepth = 0.45;
- const materialHeight = 0.3;
+ const origin = new Vector3(
+ box.min.x + materialWidth / 2,
+ box.max.y + padding,
+ box.min.z + materialDepth / 2
+ );
- const cols = Math.floor(size.x / materialWidth);
- const rows = Math.floor(size.z / materialDepth);
- const itemsPerLayer = cols * rows;
+ const newMaterials = storage.currentMaterials.map((mat, i) => {
+ const layer = Math.floor(i / itemsPerLayer);
+ const layerIndex = i % itemsPerLayer;
+ const row = Math.floor(layerIndex / cols);
+ const col = layerIndex % cols;
- const origin = new Vector3(
- box.min.x + materialWidth / 2,
- box.max.y + padding, // slightly above the surface
- box.min.z + materialDepth / 2
+ const position = new Vector3(
+ origin.x + col * materialWidth,
+ origin.y + layer * (materialHeight + padding),
+ origin.z + row * materialDepth
+ );
+
+ return {
+ materialId: mat.materialId,
+ position,
+ };
+ });
+
+ setMaterialPositions(storage.modelUuid, newMaterials);
+ }, [storageModel, storage.currentMaterials]);
+
+ return (
+
+ {(materialPositions[storage.modelUuid] || []).map(({ materialId, position }) => {
+ const mat = storage.currentMaterials.find((m) => m.materialId === materialId);
+ return (
+
+ );
+ })}
+
);
- return Array.from({ length: matCount }, (_, i) => {
- const layer = Math.floor(i / itemsPerLayer);
- const layerIndex = i % itemsPerLayer;
- const row = Math.floor(layerIndex / cols);
- const col = layerIndex % cols;
-
- return new Vector3(
- origin.x + col * materialWidth,
- origin.y + layer * (materialHeight + padding),
- origin.z + row * materialDepth
- );
- });
- }, [storageModel, storage.currentMaterials]);
-
- return (
-
- {storage.currentMaterials.map((mat, index) => (
-
- ))}
-
- );
};
export default MaterialAnimator;
diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx
index d9faf29..cebc4f9 100644
--- a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx
+++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx
@@ -7,7 +7,6 @@ import { useViewSceneStore } from "../../../../store/builder/store";
function StorageUnitInstances() {
const { storageUnitStore } = useSceneContext();
const { storageUnits } = storageUnitStore();
- // console.log('storageUnits: ', storageUnits);
const { viewSceneLabels } = useViewSceneStore();
return (
diff --git a/app/src/modules/simulation/storageUnit/storageUnit.tsx b/app/src/modules/simulation/storageUnit/storageUnit.tsx
index eee0875..8d7f1b1 100644
--- a/app/src/modules/simulation/storageUnit/storageUnit.tsx
+++ b/app/src/modules/simulation/storageUnit/storageUnit.tsx
@@ -1,4 +1,3 @@
-import React from 'react'
import StorageUnitInstances from './instances/storageUnitInstances'
function StorageUnit() {
diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts
index 04e7fa7..b98a527 100644
--- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts
+++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts
@@ -370,40 +370,18 @@ export function useTriggerHandler() {
}
}
} else {
- if (human.isActive === false && human.state === 'idle') {
-
- // Handle current action from arm bot
- setIsPaused(materialId, true);
- handleAction(action, materialId);
-
- } else {
-
- // Handle current action using Event Manager
- setHumanScheduled(human.modelUuid, true);
- setIsPaused(materialId, true);
- addHumanToMonitor(human.modelUuid, () => {
- handleAction(action, materialId)
- }, action.actionUuid);
-
- }
- }
- } else {
- if (human.isActive === false && human.state === 'idle') {
-
- // Handle current action from arm bot
- setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
- handleAction(action, materialId);
-
- } else {
-
- // Handle current action using Event Manager
setIsPaused(materialId, true);
- setHumanScheduled(human.modelUuid, true);
addHumanToMonitor(human.modelUuid, () => {
handleAction(action, materialId)
}, action.actionUuid);
}
+ } else {
+ setHumanScheduled(human.modelUuid, true);
+ setIsPaused(materialId, true);
+ addHumanToMonitor(human.modelUuid, () => {
+ handleAction(action, materialId)
+ }, action.actionUuid);
}
}
}
@@ -1260,12 +1238,6 @@ export function useTriggerHandler() {
actionUuid: material.current.actionUuid,
})
- setCurrentLocation(material.materialId, {
- modelUuid: material.current.modelUuid,
- pointUuid: material.current.pointUuid,
- actionUuid: material.current.actionUuid,
- });
-
setIsPaused(material.materialId, true);
setIsVisible(material.materialId, true);
@@ -1279,6 +1251,13 @@ export function useTriggerHandler() {
if (model?.type === 'roboticArm') {
addArmBotToMonitor(model.modelUuid, () => {
+
+ 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 || '',
@@ -1288,6 +1267,13 @@ export function useTriggerHandler() {
})
} else if (model?.type === 'vehicle') {
addVehicleToMonitor(model.modelUuid, () => {
+
+ 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 || '',
@@ -1296,6 +1282,13 @@ export function useTriggerHandler() {
setIsPaused(material.materialId, false);
})
} else if (model?.type === 'transfer') {
+
+ 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 || '',
@@ -1303,15 +1296,48 @@ export function useTriggerHandler() {
setIsPaused(material.materialId, false);
} else if (model?.type === 'human') {
- addHumanToMonitor(model.modelUuid, () => {
- setNextLocation(material.materialId, {
- modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
- pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
- })
-
+ if (fromEvent.modelUuid === model.modelUuid) {
setIsPaused(material.materialId, false);
- }, action.actionUuid)
+
+ setCurrentLocation(material.materialId, {
+ modelUuid: material.current.modelUuid,
+ pointUuid: material.current.pointUuid,
+ actionUuid: material.current.actionUuid,
+ });
+
+ setTimeout(() => {
+ setIsPaused(material.materialId, false);
+ setNextLocation(material.materialId, {
+ modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
+ pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
+ })
+ }, 0)
+
+ } else {
+ addHumanToMonitor(model.modelUuid, () => {
+
+ 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);
+ }, action.actionUuid)
+ }
} else {
+
+ 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 || '',
diff --git a/app/src/store/simulation/useMaterialStore.ts b/app/src/store/simulation/useMaterialStore.ts
index 98a0928..68839a7 100644
--- a/app/src/store/simulation/useMaterialStore.ts
+++ b/app/src/store/simulation/useMaterialStore.ts
@@ -1,15 +1,29 @@
+import * as THREE from 'three';
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
+
+interface MaterialPosition {
+ materialId: string;
+ position: THREE.Vector3;
+}
+
+type MaterialPositionsMap = Record;
+
type MaterialsStore = {
materials: MaterialsSchema;
materialHistory: MaterialHistorySchema;
+ materialPositions: MaterialPositionsMap;
+
addMaterial: (material: MaterialSchema) => MaterialSchema | undefined;
removeMaterial: (materialId: string) => MaterialSchema | undefined;
clearMaterials: () => void;
updateMaterial: (materialId: string, updates: Partial) => MaterialSchema | undefined;
+ setMaterialPositions: (modelUuid: string, materialPositions: MaterialPosition[]) => void;
+ getMaterialPosition: (modelUuid: string, materialId: string) => THREE.Vector3 | undefined;
+
setPreviousLocation: (
materialId: string,
location: {
@@ -61,6 +75,7 @@ export const createMaterialStore = () => {
immer((set, get) => ({
materials: [],
materialHistory: [],
+ materialPositions: {},
addMaterial: (material) => {
let updatedMaterial: MaterialSchema | undefined;
@@ -262,6 +277,16 @@ export const createMaterialStore = () => {
return updatedMaterial;
},
+ setMaterialPositions: (modelUuid, positions) => {
+ set((state) => {
+ state.materialPositions[modelUuid] = positions;
+ });
+ },
+
+ getMaterialPosition: (modelUuid, materialId) => {
+ return get().materialPositions[modelUuid]?.find(p => p.materialId === materialId)?.position;
+ },
+
getMaterialById: (materialId) => {
return get().materials.find(m => m.materialId === materialId);
},