Merge remote-tracking branch 'origin/main-dev' into main-demo
This commit is contained in:
@@ -3,8 +3,15 @@ import { useMemo } from "react";
|
|||||||
import { Cylinder } from "@react-three/drei";
|
import { Cylinder } from "@react-three/drei";
|
||||||
|
|
||||||
export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth, }: { name: string; boundingBox: Box3 | null; color: string; lineWidth: number; }) => {
|
export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth, }: { name: string; boundingBox: Box3 | null; color: string; lineWidth: number; }) => {
|
||||||
const { edgeCylinders, center, size } = useMemo(() => {
|
const { edgeCylinders, cornerSpheres, center, size } = useMemo(() => {
|
||||||
if (!boundingBox) return { edgeCylinders: [], center: new Vector3(), size: new Vector3() };
|
if (!boundingBox) {
|
||||||
|
return {
|
||||||
|
edgeCylinders: [],
|
||||||
|
cornerSpheres: [],
|
||||||
|
center: new Vector3(),
|
||||||
|
size: new Vector3(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const min = boundingBox.min;
|
const min = boundingBox.min;
|
||||||
const max = boundingBox.max;
|
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]);
|
}, [boundingBox, lineWidth]);
|
||||||
|
|
||||||
if (!boundingBox) return null;
|
if (!boundingBox) return null;
|
||||||
@@ -58,11 +71,18 @@ export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth, }: { nam
|
|||||||
return (
|
return (
|
||||||
<group name={name}>
|
<group name={name}>
|
||||||
{edgeCylinders.map(({ key, position, rotation, length, radius }) => (
|
{edgeCylinders.map(({ key, position, rotation, length, radius }) => (
|
||||||
<Cylinder key={key} args={[radius, radius, length, 6]} position={position} quaternion={rotation} >
|
<Cylinder key={key} args={[radius, radius, length, 6]} position={position} quaternion={rotation}>
|
||||||
<meshBasicMaterial color={color} depthWrite={false} />
|
<meshBasicMaterial color={color} depthWrite={false} />
|
||||||
</Cylinder>
|
</Cylinder>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{cornerSpheres.map(({ key, position, radius }) => (
|
||||||
|
<mesh key={key} position={position}>
|
||||||
|
<sphereGeometry args={[radius, 12, 12]} />
|
||||||
|
<meshBasicMaterial color={color} depthWrite={false} />
|
||||||
|
</mesh>
|
||||||
|
))}
|
||||||
|
|
||||||
<mesh visible={false} position={center}>
|
<mesh visible={false} position={center}>
|
||||||
<boxGeometry args={[size.x, size.y, size.z]} />
|
<boxGeometry args={[size.x, size.y, size.z]} />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|||||||
@@ -449,7 +449,11 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
|||||||
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<AssetBoundingBox name='Asset Fallback' boundingBox={boundingBox} color='gray' lineWidth={2.5} />
|
<>
|
||||||
|
{!isSelected &&
|
||||||
|
<AssetBoundingBox name='Asset Fallback' boundingBox={boundingBox} color='gray' lineWidth={2.5} />
|
||||||
|
}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{isSelected &&
|
{isSelected &&
|
||||||
<AssetBoundingBox name='Asset BBox' boundingBox={boundingBox} color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"} lineWidth={2.7} />
|
<AssetBoundingBox name='Asset BBox' boundingBox={boundingBox} color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"} lineWidth={2.7} />
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import { useProductContext } from "../../../products/productContext";
|
|||||||
import { useHumanEventManager } from "../../../human/eventManager/useHumanEventManager";
|
import { useHumanEventManager } from "../../../human/eventManager/useHumanEventManager";
|
||||||
|
|
||||||
export function useRetrieveHandler() {
|
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 { selectedProductStore } = useProductContext();
|
||||||
const { addMaterial } = materialStore();
|
const { addMaterial } = materialStore();
|
||||||
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
|
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
|
||||||
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore();
|
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore();
|
||||||
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
|
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
|
||||||
|
const { getConveyorById } = conveyorStore();
|
||||||
const { getHumanById, incrementHumanLoad, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
|
const { getHumanById, incrementHumanLoad, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
|
||||||
const { getAssetById, setCurrentAnimation } = assetStore();
|
const { getAssetById, setCurrentAnimation } = assetStore();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
@@ -60,9 +61,9 @@ export function useRetrieveHandler() {
|
|||||||
actionUuid: action.actionUuid
|
actionUuid: action.actionUuid
|
||||||
},
|
},
|
||||||
current: {
|
current: {
|
||||||
modelUuid: action.triggers[0]?.triggeredAsset.triggeredModel.modelUuid,
|
modelUuid: modelUuid,
|
||||||
pointUuid: action.triggers[0]?.triggeredAsset.triggeredPoint.pointUuid,
|
pointUuid: pointUuid,
|
||||||
actionUuid: action.triggers[0]?.triggeredAsset.triggeredAction.actionUuid
|
actionUuid: action.actionUuid
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -371,6 +372,32 @@ export function useRetrieveHandler() {
|
|||||||
}
|
}
|
||||||
return;
|
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') {
|
} else if (triggeredModel?.type === 'machine') {
|
||||||
const machine = getMachineById(triggeredModel.modelUuid);
|
const machine = getMachineById(triggeredModel.modelUuid);
|
||||||
if (machine && !machine.isActive && machine.state === 'idle' && !machine.currentAction) {
|
if (machine && !machine.isActive && machine.state === 'idle' && !machine.currentAction) {
|
||||||
|
|||||||
@@ -182,31 +182,23 @@ function TriggerConnector() {
|
|||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
let drag = false;
|
let drag = false;
|
||||||
let isRightMouseDown = false;
|
let isLeftMouseDown = false;
|
||||||
|
|
||||||
const onMouseDown = (evt: MouseEvent) => {
|
const onMouseDown = (evt: MouseEvent) => {
|
||||||
if (selectedAsset) {
|
if (selectedAsset) {
|
||||||
clearSelectedAsset();
|
clearSelectedAsset();
|
||||||
}
|
}
|
||||||
if (evt.button === 2) {
|
if (evt.button === 0) {
|
||||||
isRightMouseDown = true;
|
isLeftMouseDown = true;
|
||||||
drag = false;
|
drag = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseUp = (evt: MouseEvent) => {
|
const onMouseUp = (evt: MouseEvent) => {
|
||||||
if (evt.button === 2) {
|
if (evt.button === 0) {
|
||||||
isRightMouseDown = false;
|
isLeftMouseDown = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const onMouseMove = () => {
|
|
||||||
if (isRightMouseDown) {
|
|
||||||
drag = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRightClick = (evt: MouseEvent) => {
|
|
||||||
if (drag) return;
|
if (drag) return;
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
|
||||||
@@ -368,13 +360,16 @@ function TriggerConnector() {
|
|||||||
} else if (firstSelectedPoint) {
|
} else if (firstSelectedPoint) {
|
||||||
setFirstSelectedPoint(null);
|
setFirstSelectedPoint(null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseMove = () => {
|
||||||
|
drag = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (subModule === 'mechanics' && toolMode === 'cursor' && selectedAction.actionId && selectedAction.actionName) {
|
if (subModule === 'mechanics' && toolMode === 'cursor' && selectedAction.actionId && selectedAction.actionName) {
|
||||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
canvasElement.addEventListener('contextmenu', handleRightClick);
|
|
||||||
} else {
|
} else {
|
||||||
setFirstSelectedPoint(null);
|
setFirstSelectedPoint(null);
|
||||||
}
|
}
|
||||||
@@ -383,7 +378,6 @@ function TriggerConnector() {
|
|||||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
canvasElement.removeEventListener('contextmenu', handleRightClick);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}, [gl, subModule, selectedProduct, firstSelectedPoint, toolMode, selectedAction]);
|
}, [gl, subModule, selectedProduct, firstSelectedPoint, toolMode, selectedAction]);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
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 { useFrame, useThree } from '@react-three/fiber';
|
||||||
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
||||||
import { useProductContext } from '../../../products/productContext';
|
import { useProductContext } from '../../../products/productContext';
|
||||||
@@ -27,7 +28,7 @@ function HumanUi() {
|
|||||||
const { humanStore, productStore } = useSceneContext();
|
const { humanStore, productStore } = useSceneContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { humans, getHumanById } = humanStore();
|
const { humans, getHumanById } = humanStore();
|
||||||
const { updateEvent, updateAction, getActionByUuid } = productStore();
|
const { updateEvent, getActionByUuid } = productStore();
|
||||||
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
|
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||||
const [endPosition, setEndPosition] = 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]);
|
const [assemblyPosition, setAssemblyPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||||
@@ -313,64 +314,49 @@ function HumanUi() {
|
|||||||
rotation={[0, Math.PI, 0]}
|
rotation={[0, Math.PI, 0]}
|
||||||
>
|
>
|
||||||
{isAssembly ? (
|
{isAssembly ? (
|
||||||
<primitive
|
<MarkerPrimitive
|
||||||
ref={assemblyMarker}
|
name="assemblyMarker"
|
||||||
|
refProp={assemblyMarker}
|
||||||
object={assemblyScene}
|
object={assemblyScene}
|
||||||
position={assemblyPosition}
|
position={assemblyPosition}
|
||||||
rotation={assemblyRotation}
|
rotation={assemblyRotation}
|
||||||
onPointerDown={(e: any) => {
|
outerGroupRef={outerGroup}
|
||||||
if (e.object.parent.name === "handle") {
|
type="assembly"
|
||||||
handlePointerDown(e, "assembly", "assembly");
|
subtype="assembly"
|
||||||
} else {
|
color="#0f87f7"
|
||||||
handlePointerDown(e, "assembly", "assembly");
|
setIsDragging={setIsDragging}
|
||||||
}
|
setIsRotating={setIsRotating}
|
||||||
}}
|
handlePointerDown={handlePointerDown}
|
||||||
onPointerMissed={() => {
|
|
||||||
setIsDragging(null);
|
|
||||||
setIsRotating(null);
|
|
||||||
if (controls) (controls as any).enabled = true;
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<primitive
|
<MarkerPrimitive
|
||||||
name="startMarker"
|
name="startMarker"
|
||||||
|
refProp={startMarker}
|
||||||
object={startScene}
|
object={startScene}
|
||||||
ref={startMarker}
|
|
||||||
position={startPosition}
|
position={startPosition}
|
||||||
rotation={startRotation}
|
rotation={startRotation}
|
||||||
onPointerDown={(e: any) => {
|
outerGroupRef={outerGroup}
|
||||||
if (e.object.parent.name === "handle") {
|
type="start"
|
||||||
handlePointerDown(e, "start", "start");
|
subtype="start"
|
||||||
} else {
|
color="lightgreen"
|
||||||
handlePointerDown(e, "start", "start");
|
setIsDragging={setIsDragging}
|
||||||
}
|
setIsRotating={setIsRotating}
|
||||||
}}
|
handlePointerDown={handlePointerDown}
|
||||||
onPointerMissed={() => {
|
|
||||||
setIsDragging(null);
|
|
||||||
setIsRotating(null);
|
|
||||||
if (controls) (controls as any).enabled = true;
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
<MarkerPrimitive
|
||||||
<primitive
|
|
||||||
name="endMarker"
|
name="endMarker"
|
||||||
|
refProp={endMarker}
|
||||||
object={endScene}
|
object={endScene}
|
||||||
ref={endMarker}
|
|
||||||
position={endPosition}
|
position={endPosition}
|
||||||
rotation={endRotation}
|
rotation={endRotation}
|
||||||
onPointerDown={(e: any) => {
|
outerGroupRef={outerGroup}
|
||||||
if (e.object.parent.name === "handle") {
|
type="end"
|
||||||
handlePointerDown(e, "end", "end");
|
subtype="end"
|
||||||
} else {
|
color="darkorange"
|
||||||
handlePointerDown(e, "end", "end");
|
setIsDragging={setIsDragging}
|
||||||
}
|
setIsRotating={setIsRotating}
|
||||||
}}
|
handlePointerDown={handlePointerDown}
|
||||||
onPointerMissed={() => {
|
|
||||||
setIsDragging(null);
|
|
||||||
setIsRotating(null);
|
|
||||||
if (controls) (controls as any).enabled = true;
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -380,4 +366,101 @@ function HumanUi() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HumanUi;
|
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<THREE.Group>;
|
||||||
|
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<THREE.Vector3 | null>(null);
|
||||||
|
const [curve, setCurve] = useState<THREE.CatmullRomCurve3 | null>(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 (
|
||||||
|
<>
|
||||||
|
<primitive
|
||||||
|
name={name}
|
||||||
|
ref={refProp}
|
||||||
|
object={object}
|
||||||
|
position={position}
|
||||||
|
rotation={rotation}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
handlePointerDown(e, type, subtype);
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
if (controls) (controls as any).enabled = true;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{hitPoint && (
|
||||||
|
<>
|
||||||
|
<mesh name={name} position={hitPoint} rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
|
<torusGeometry args={[0.15, 0.02, 3, 32]} />
|
||||||
|
<meshBasicMaterial color={color} depthWrite={false} />
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{curve && (
|
||||||
|
<Tube args={[curve, 20, 0.01, 8, true]} >
|
||||||
|
<meshBasicMaterial color={color} depthWrite={false} />
|
||||||
|
</Tube>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -61,30 +61,12 @@ function MaterialInstance({ material }: { readonly material: MaterialSchema }) {
|
|||||||
function getCurrentSpeed(productUuid: string, modelUuid: string) {
|
function getCurrentSpeed(productUuid: string, modelUuid: string) {
|
||||||
const event = getEventByModelUuid(productUuid, modelUuid)
|
const event = getEventByModelUuid(productUuid, modelUuid)
|
||||||
if (event) {
|
if (event) {
|
||||||
if (event.type === 'transfer') {
|
if (event.type === 'transfer' || event.type === 'machine' || event.type === 'storageUnit') {
|
||||||
return event.speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.type === 'vehicle') {
|
|
||||||
return event.speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.type === 'machine') {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (event.type === 'vehicle' || event.type === 'roboticArm' || event.type === 'human') {
|
||||||
if (event.type === 'roboticArm') {
|
|
||||||
return event.speed;
|
return event.speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === 'storageUnit') {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.type === 'human') {
|
|
||||||
return event.speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import MaterialInstance from './instance/materialInstance'
|
import MaterialInstance from './instance/materialInstance'
|
||||||
import { useSceneContext } from '../../../scene/sceneContext';
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
|
|||||||
const [customCurvePoints, setCustomCurvePoints] = useState<THREE.Vector3[] | null>(null);
|
const [customCurvePoints, setCustomCurvePoints] = useState<THREE.Vector3[] | null>(null);
|
||||||
const { armBotStore, productStore, materialStore } = useSceneContext();
|
const { armBotStore, productStore, materialStore } = useSceneContext();
|
||||||
const { getArmBotById } = armBotStore();
|
const { getArmBotById } = armBotStore();
|
||||||
const { getMaterialById } = materialStore();
|
const { getMaterialById, getMaterialPosition } = materialStore();
|
||||||
const { getEventByModelUuid } = productStore();
|
const { getEventByModelUuid, getActionByUuid, getPointByUuid } = productStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
@@ -167,13 +167,18 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
|
|||||||
|
|
||||||
let start = currentPath[0];
|
let start = currentPath[0];
|
||||||
let end = currentPath[currentPath.length - 1];
|
let end = currentPath[currentPath.length - 1];
|
||||||
|
const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
||||||
|
|
||||||
const armbotStatus = getArmBotById(armBot.modelUuid);
|
const armbotStatus = getArmBotById(armBot.modelUuid);
|
||||||
const currentMaterial = armbotStatus?.currentAction?.materialId;
|
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);
|
const materialData = getMaterialById(currentMaterial);
|
||||||
if (materialData) {
|
if (materialData) {
|
||||||
const prevModel = getEventByModelUuid(selectedProduct.productUuid, materialData.current.modelUuid);
|
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') {
|
if (prevModel && prevModel.type === 'transfer') {
|
||||||
const material = scene.getObjectByProperty("uuid", currentMaterial);
|
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];
|
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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -173,13 +173,16 @@ const ArmBotUI = () => {
|
|||||||
|
|
||||||
const targetMesh = scene?.getObjectByProperty("uuid", selectedArmBotData?.modelUuid || '');
|
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(
|
const { handlePointerDown } = useDraggableGLTF(
|
||||||
updatePointToState,
|
updatePointToState,
|
||||||
{
|
{
|
||||||
minDistance: targetMesh?.userData?.iks[0]?.minDistance || 1.2,
|
minDistance: firstIK.minDistance ?? 1.2,
|
||||||
maxDistance: targetMesh?.userData?.iks[0]?.maxDistance || 2,
|
maxDistance: firstIK.maxDistance ?? 2,
|
||||||
maxheight: targetMesh?.userData?.iks[0]?.maxheight || 0.6,
|
maxheight: firstIK.maxheight ?? 0.6,
|
||||||
minheight: targetMesh?.userData?.iks[0]?.minheight || 1.9,
|
minheight: firstIK.minheight ?? 1.9,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
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 { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useSelectedEventSphere, useIsDragging, useIsRotating, } from "../../../../store/simulation/useSimulationStore";
|
import { useSelectedEventSphere, useIsDragging, useIsRotating, } from "../../../../store/simulation/useSimulationStore";
|
||||||
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
|
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
@@ -16,8 +17,6 @@ import { useVersionContext } from "../../../builder/version/versionContext";
|
|||||||
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<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 { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
@@ -162,7 +161,7 @@ const VehicleUI = () => {
|
|||||||
let globalStartPosition = null;
|
let globalStartPosition = null;
|
||||||
let globalEndPosition = null;
|
let globalEndPosition = null;
|
||||||
|
|
||||||
if (outerGroup.current && startMarker.current && endMarker.current) {
|
if (outerGroup.current) {
|
||||||
const worldPosStart = new Vector3(...startPosition);
|
const worldPosStart = new Vector3(...startPosition);
|
||||||
globalStartPosition = outerGroup.current.localToWorld(
|
globalStartPosition = outerGroup.current.localToWorld(
|
||||||
worldPosStart.clone()
|
worldPosStart.clone()
|
||||||
@@ -277,24 +276,19 @@ const VehicleUI = () => {
|
|||||||
const currentPointerX = state.pointer.x;
|
const currentPointerX = state.pointer.x;
|
||||||
const deltaX = currentPointerX - prevMousePos.current.x;
|
const deltaX = currentPointerX - prevMousePos.current.x;
|
||||||
prevMousePos.current.x = currentPointerX;
|
prevMousePos.current.x = currentPointerX;
|
||||||
const marker =
|
const rotationSpeed = 10;
|
||||||
isRotating === "start" ? startMarker.current : endMarker.current;
|
if (isRotating === "start") {
|
||||||
if (marker) {
|
setStartRotation([
|
||||||
const rotationSpeed = 10;
|
startRotation[0],
|
||||||
marker.rotation.y += deltaX * rotationSpeed;
|
startRotation[1] + deltaX * rotationSpeed,
|
||||||
if (isRotating === "start") {
|
startRotation[2],
|
||||||
setStartRotation([
|
]);
|
||||||
marker.rotation.x,
|
} else {
|
||||||
marker.rotation.y,
|
setEndRotation([
|
||||||
marker.rotation.z,
|
endRotation[0],
|
||||||
]);
|
endRotation[1] + deltaX * rotationSpeed,
|
||||||
} else {
|
endRotation[2],
|
||||||
setEndRotation([
|
]);
|
||||||
marker.rotation.x,
|
|
||||||
marker.rotation.y,
|
|
||||||
marker.rotation.z,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -342,41 +336,130 @@ const VehicleUI = () => {
|
|||||||
</group>
|
</group>
|
||||||
|
|
||||||
{/* Start Marker */}
|
{/* Start Marker */}
|
||||||
<primitive
|
<VehicleMarkerPrimitive
|
||||||
name="startMarker"
|
name="startMarker"
|
||||||
object={startScene}
|
object={startScene}
|
||||||
ref={startMarker}
|
|
||||||
position={startPosition}
|
position={startPosition}
|
||||||
rotation={startRotation}
|
rotation={startRotation}
|
||||||
onPointerDown={(e: any) => {
|
outerGroupRef={outerGroup}
|
||||||
e.stopPropagation();
|
color="green"
|
||||||
handlePointerDown(e, "start", "start");
|
handlePointerDown={handlePointerDown}
|
||||||
}}
|
setIsDragging={setIsDragging}
|
||||||
|
setIsRotating={setIsRotating}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* End Marker */}
|
||||||
|
<VehicleMarkerPrimitive
|
||||||
|
name="endMarker"
|
||||||
|
object={endScene}
|
||||||
|
position={endPosition}
|
||||||
|
rotation={endRotation}
|
||||||
|
outerGroupRef={outerGroup}
|
||||||
|
color="orange"
|
||||||
|
handlePointerDown={handlePointerDown}
|
||||||
|
setIsDragging={setIsDragging}
|
||||||
|
setIsRotating={setIsRotating}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
) : 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<THREE.Group>;
|
||||||
|
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<THREE.Group>(null);
|
||||||
|
const [hitPoint, setHitPoint] = useState<THREE.Vector3 | null>(null);
|
||||||
|
const [curve, setCurve] = useState<THREE.CatmullRomCurve3 | null>(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 (
|
||||||
|
<>
|
||||||
|
<primitive
|
||||||
|
name={name}
|
||||||
|
ref={markerRef}
|
||||||
|
object={object}
|
||||||
|
position={position}
|
||||||
|
rotation={rotation}
|
||||||
|
onPointerDown={(e: any) =>
|
||||||
|
handlePointerDown(
|
||||||
|
e,
|
||||||
|
name === "startMarker" ? "start" : "end",
|
||||||
|
name === "startMarker" ? "start" : "end"
|
||||||
|
)
|
||||||
|
}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
controls.enabled = true;
|
|
||||||
setIsDragging(null);
|
setIsDragging(null);
|
||||||
setIsRotating(null);
|
setIsRotating(null);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* End Marker */}
|
{hitPoint && (
|
||||||
<primitive
|
<>
|
||||||
name="endMarker"
|
<mesh
|
||||||
object={endScene}
|
name={`${name}-torus`}
|
||||||
ref={endMarker}
|
position={hitPoint}
|
||||||
position={endPosition}
|
rotation={[-Math.PI / 2, 0, 0]}
|
||||||
rotation={endRotation}
|
>
|
||||||
onPointerDown={(e: any) => {
|
<torusGeometry args={[0.15, 0.02, 3, 32]} />
|
||||||
e.stopPropagation();
|
<meshBasicMaterial color={color} depthWrite={false} />
|
||||||
handlePointerDown(e, "end", "end");
|
</mesh>
|
||||||
}}
|
|
||||||
onPointerMissed={() => {
|
{curve && (
|
||||||
controls.enabled = true;
|
<Tube args={[curve, 20, 0.01, 8, true]}>
|
||||||
setIsDragging(null);
|
<meshBasicMaterial color={color} depthWrite={false} />
|
||||||
setIsRotating(null);
|
</Tube>
|
||||||
}}
|
)}
|
||||||
/>
|
</>
|
||||||
</group>
|
)}
|
||||||
) : null;
|
</>
|
||||||
};
|
);
|
||||||
export default VehicleUI;
|
};
|
||||||
@@ -1,72 +1,84 @@
|
|||||||
import { useRef, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { MaterialModel } from "../../../materials/instances/material/materialModel";
|
|
||||||
import { Object3D, Box3, Vector3 } from "three";
|
import { Object3D, Box3, Vector3 } from "three";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import { useLoadingProgress } from "../../../../../store/builder/store";
|
import { useLoadingProgress } from "../../../../../store/builder/store";
|
||||||
|
import { MaterialModel } from "../../../materials/instances/material/materialModel";
|
||||||
|
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||||
|
|
||||||
const MaterialAnimator = ({
|
const MaterialAnimator = ({
|
||||||
storage,
|
storage,
|
||||||
}: Readonly<{ storage: StorageUnitStatus }>) => {
|
}: Readonly<{ storage: StorageUnitStatus }>) => {
|
||||||
const meshRef = useRef<any>(null!);
|
const { scene } = useThree();
|
||||||
const { scene } = useThree();
|
const padding = 0.1;
|
||||||
const padding = 0.1;
|
const { loadingProgress } = useLoadingProgress();
|
||||||
const { loadingProgress } = useLoadingProgress();
|
const { materialStore } = useSceneContext();
|
||||||
|
const { materialPositions, setMaterialPositions } = materialStore();
|
||||||
|
|
||||||
const storageModel = useMemo(() => {
|
const storageModel = useMemo(() => {
|
||||||
return scene.getObjectByProperty("uuid", storage.modelUuid) as Object3D;
|
return scene.getObjectByProperty("uuid", storage.modelUuid) as Object3D;
|
||||||
}, [scene, storage.modelUuid, loadingProgress]);
|
}, [scene, storage.modelUuid, loadingProgress]);
|
||||||
|
|
||||||
const materialPositions = useMemo(() => {
|
useEffect(() => {
|
||||||
if (!storageModel || storage.currentMaterials.length === 0) return [];
|
if (!storageModel || storage.currentMaterials.length === 0) {
|
||||||
|
setMaterialPositions(storage.modelUuid, []);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const box = new Box3().setFromObject(storageModel);
|
const box = new Box3().setFromObject(storageModel);
|
||||||
const size = new Vector3();
|
const size = new Vector3();
|
||||||
box.getSize(size);
|
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 origin = new Vector3(
|
||||||
const materialWidth = 0.45;
|
box.min.x + materialWidth / 2,
|
||||||
const materialDepth = 0.45;
|
box.max.y + padding,
|
||||||
const materialHeight = 0.3;
|
box.min.z + materialDepth / 2
|
||||||
|
);
|
||||||
|
|
||||||
const cols = Math.floor(size.x / materialWidth);
|
const newMaterials = storage.currentMaterials.map((mat, i) => {
|
||||||
const rows = Math.floor(size.z / materialDepth);
|
const layer = Math.floor(i / itemsPerLayer);
|
||||||
const itemsPerLayer = cols * rows;
|
const layerIndex = i % itemsPerLayer;
|
||||||
|
const row = Math.floor(layerIndex / cols);
|
||||||
|
const col = layerIndex % cols;
|
||||||
|
|
||||||
const origin = new Vector3(
|
const position = new Vector3(
|
||||||
box.min.x + materialWidth / 2,
|
origin.x + col * materialWidth,
|
||||||
box.max.y + padding, // slightly above the surface
|
origin.y + layer * (materialHeight + padding),
|
||||||
box.min.z + materialDepth / 2
|
origin.z + row * materialDepth
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
materialId: mat.materialId,
|
||||||
|
position,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setMaterialPositions(storage.modelUuid, newMaterials);
|
||||||
|
}, [storageModel, storage.currentMaterials]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group position={[0, -padding, 0]}>
|
||||||
|
{(materialPositions[storage.modelUuid] || []).map(({ materialId, position }) => {
|
||||||
|
const mat = storage.currentMaterials.find((m) => m.materialId === materialId);
|
||||||
|
return (
|
||||||
|
<MaterialModel
|
||||||
|
key={materialId}
|
||||||
|
materialId={materialId}
|
||||||
|
matRef={null}
|
||||||
|
materialType={mat?.materialType ?? "Default material"}
|
||||||
|
position={position}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</group>
|
||||||
);
|
);
|
||||||
|
|
||||||
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 (
|
|
||||||
<group {...{ position: [0, -padding, 0] }}>
|
|
||||||
{storage.currentMaterials.map((mat, index) => (
|
|
||||||
<MaterialModel
|
|
||||||
key={`${index}-${mat.materialId}`}
|
|
||||||
materialId={mat.materialId}
|
|
||||||
matRef={meshRef}
|
|
||||||
materialType={mat.materialType ?? "Default material"}
|
|
||||||
position={materialPositions[index]}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MaterialAnimator;
|
export default MaterialAnimator;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { useViewSceneStore } from "../../../../store/builder/store";
|
|||||||
function StorageUnitInstances() {
|
function StorageUnitInstances() {
|
||||||
const { storageUnitStore } = useSceneContext();
|
const { storageUnitStore } = useSceneContext();
|
||||||
const { storageUnits } = storageUnitStore();
|
const { storageUnits } = storageUnitStore();
|
||||||
// console.log('storageUnits: ', storageUnits);
|
|
||||||
const { viewSceneLabels } = useViewSceneStore();
|
const { viewSceneLabels } = useViewSceneStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import React from 'react'
|
|
||||||
import StorageUnitInstances from './instances/storageUnitInstances'
|
import StorageUnitInstances from './instances/storageUnitInstances'
|
||||||
|
|
||||||
function StorageUnit() {
|
function StorageUnit() {
|
||||||
|
|||||||
@@ -370,40 +370,18 @@ export function useTriggerHandler() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
setHumanScheduled(human.modelUuid, true);
|
||||||
handleAction(action, materialId);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Handle current action using Event Manager
|
|
||||||
setIsPaused(materialId, true);
|
setIsPaused(materialId, true);
|
||||||
setHumanScheduled(human.modelUuid, true);
|
|
||||||
addHumanToMonitor(human.modelUuid, () => {
|
addHumanToMonitor(human.modelUuid, () => {
|
||||||
handleAction(action, materialId)
|
handleAction(action, materialId)
|
||||||
}, action.actionUuid);
|
}, 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,
|
actionUuid: material.current.actionUuid,
|
||||||
})
|
})
|
||||||
|
|
||||||
setCurrentLocation(material.materialId, {
|
|
||||||
modelUuid: material.current.modelUuid,
|
|
||||||
pointUuid: material.current.pointUuid,
|
|
||||||
actionUuid: material.current.actionUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
setIsPaused(material.materialId, true);
|
setIsPaused(material.materialId, true);
|
||||||
setIsVisible(material.materialId, true);
|
setIsVisible(material.materialId, true);
|
||||||
|
|
||||||
@@ -1279,6 +1251,13 @@ export function useTriggerHandler() {
|
|||||||
|
|
||||||
if (model?.type === 'roboticArm') {
|
if (model?.type === 'roboticArm') {
|
||||||
addArmBotToMonitor(model.modelUuid, () => {
|
addArmBotToMonitor(model.modelUuid, () => {
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
setNextLocation(material.materialId, {
|
setNextLocation(material.materialId, {
|
||||||
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||||
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||||
@@ -1288,6 +1267,13 @@ export function useTriggerHandler() {
|
|||||||
})
|
})
|
||||||
} else if (model?.type === 'vehicle') {
|
} else if (model?.type === 'vehicle') {
|
||||||
addVehicleToMonitor(model.modelUuid, () => {
|
addVehicleToMonitor(model.modelUuid, () => {
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
setNextLocation(material.materialId, {
|
setNextLocation(material.materialId, {
|
||||||
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||||
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||||
@@ -1296,6 +1282,13 @@ export function useTriggerHandler() {
|
|||||||
setIsPaused(material.materialId, false);
|
setIsPaused(material.materialId, false);
|
||||||
})
|
})
|
||||||
} else if (model?.type === 'transfer') {
|
} else if (model?.type === 'transfer') {
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
setNextLocation(material.materialId, {
|
setNextLocation(material.materialId, {
|
||||||
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||||
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||||
@@ -1303,15 +1296,48 @@ export function useTriggerHandler() {
|
|||||||
|
|
||||||
setIsPaused(material.materialId, false);
|
setIsPaused(material.materialId, false);
|
||||||
} else if (model?.type === 'human') {
|
} else if (model?.type === 'human') {
|
||||||
addHumanToMonitor(model.modelUuid, () => {
|
if (fromEvent.modelUuid === model.modelUuid) {
|
||||||
setNextLocation(material.materialId, {
|
|
||||||
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
|
||||||
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
|
||||||
})
|
|
||||||
|
|
||||||
setIsPaused(material.materialId, false);
|
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 {
|
} else {
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
setNextLocation(material.materialId, {
|
setNextLocation(material.materialId, {
|
||||||
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||||
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||||
|
|||||||
@@ -1,15 +1,29 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
|
|
||||||
|
interface MaterialPosition {
|
||||||
|
materialId: string;
|
||||||
|
position: THREE.Vector3;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MaterialPositionsMap = Record<string, MaterialPosition[]>;
|
||||||
|
|
||||||
type MaterialsStore = {
|
type MaterialsStore = {
|
||||||
materials: MaterialsSchema;
|
materials: MaterialsSchema;
|
||||||
materialHistory: MaterialHistorySchema;
|
materialHistory: MaterialHistorySchema;
|
||||||
|
materialPositions: MaterialPositionsMap;
|
||||||
|
|
||||||
|
|
||||||
addMaterial: (material: MaterialSchema) => MaterialSchema | undefined;
|
addMaterial: (material: MaterialSchema) => MaterialSchema | undefined;
|
||||||
removeMaterial: (materialId: string) => MaterialSchema | undefined;
|
removeMaterial: (materialId: string) => MaterialSchema | undefined;
|
||||||
clearMaterials: () => void;
|
clearMaterials: () => void;
|
||||||
updateMaterial: (materialId: string, updates: Partial<MaterialSchema>) => MaterialSchema | undefined;
|
updateMaterial: (materialId: string, updates: Partial<MaterialSchema>) => MaterialSchema | undefined;
|
||||||
|
|
||||||
|
setMaterialPositions: (modelUuid: string, materialPositions: MaterialPosition[]) => void;
|
||||||
|
getMaterialPosition: (modelUuid: string, materialId: string) => THREE.Vector3 | undefined;
|
||||||
|
|
||||||
setPreviousLocation: (
|
setPreviousLocation: (
|
||||||
materialId: string,
|
materialId: string,
|
||||||
location: {
|
location: {
|
||||||
@@ -61,6 +75,7 @@ export const createMaterialStore = () => {
|
|||||||
immer((set, get) => ({
|
immer((set, get) => ({
|
||||||
materials: [],
|
materials: [],
|
||||||
materialHistory: [],
|
materialHistory: [],
|
||||||
|
materialPositions: {},
|
||||||
|
|
||||||
addMaterial: (material) => {
|
addMaterial: (material) => {
|
||||||
let updatedMaterial: MaterialSchema | undefined;
|
let updatedMaterial: MaterialSchema | undefined;
|
||||||
@@ -262,6 +277,16 @@ export const createMaterialStore = () => {
|
|||||||
return updatedMaterial;
|
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) => {
|
getMaterialById: (materialId) => {
|
||||||
return get().materials.find(m => m.materialId === materialId);
|
return get().materials.find(m => m.materialId === materialId);
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user