Merge remote-tracking branch 'origin/main-dev' into main-demo

This commit is contained in:
2025-07-29 09:11:53 +05:30
10 changed files with 150 additions and 183 deletions

View File

@@ -16,12 +16,7 @@ import { getUserData } from "../../../functions/getUserData";
import { useSceneContext } from "../../scene/sceneContext"; import { useSceneContext } from "../../scene/sceneContext";
import { useVersionContext } from "../version/versionContext"; import { useVersionContext } from "../version/versionContext";
const gltfLoaderWorker = new Worker( const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
new URL(
"../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js",
import.meta.url
)
);
function AssetsGroup({ plane }: { readonly plane: RefMesh }) { function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();

View File

@@ -1,47 +1,67 @@
import { Line } from "@react-three/drei"; import { Box3, Vector3, Quaternion } from "three";
import { Box3, Vector3 } from "three";
import { useMemo } from "react"; 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; }) => { export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth, }: { name: string; boundingBox: Box3 | null; color: string; lineWidth: number; }) => {
const { points, size, center } = useMemo(() => { const { edgeCylinders, center, size } = useMemo(() => {
if (!boundingBox) { return { points: [], center: new Vector3(), size: new Vector3(), }; } if (!boundingBox) return { edgeCylinders: [], center: new Vector3(), size: new Vector3() };
const min = boundingBox.min; const min = boundingBox.min;
const max = boundingBox.max; const max = boundingBox.max;
const center = boundingBox.getCenter(new Vector3()); const center = boundingBox.getCenter(new Vector3());
const size = boundingBox.getSize(new Vector3()); const size = boundingBox.getSize(new Vector3());
const edges: Array<[number, number, number]> = [ const corners = [
[min.x, min.y, min.z], [max.x, min.y, min.z], new Vector3(min.x, min.y, min.z),
[max.x, min.y, min.z], [max.x, max.y, min.z], new Vector3(max.x, min.y, min.z),
[max.x, max.y, min.z], [min.x, max.y, min.z], new Vector3(max.x, max.y, min.z),
[min.x, max.y, min.z], [min.x, min.y, min.z], new Vector3(min.x, max.y, min.z),
new Vector3(min.x, min.y, max.z),
[min.x, min.y, max.z], [max.x, min.y, max.z], new Vector3(max.x, min.y, max.z),
[max.x, min.y, max.z], [max.x, max.y, max.z], new Vector3(max.x, max.y, max.z),
[max.x, max.y, max.z], [min.x, max.y, max.z], new Vector3(min.x, max.y, max.z),
[min.x, max.y, max.z], [min.x, min.y, max.z],
[min.x, min.y, min.z], [min.x, min.y, max.z],
[max.x, min.y, min.z], [max.x, min.y, max.z],
[max.x, max.y, min.z], [max.x, max.y, max.z],
[min.x, max.y, min.z], [min.x, max.y, max.z],
]; ];
return { points: edges, center, size }; const edgeIndices: [number, number][] = [
}, [boundingBox]); [0, 1], [1, 2], [2, 3], [3, 0],
[4, 5], [5, 6], [6, 7], [7, 4],
[0, 4], [1, 5], [2, 6], [3, 7],
];
const radius = 0.005 * lineWidth;
const edgeCylinders = edgeIndices.map(([startIdx, endIdx], i) => {
const start = corners[startIdx];
const end = corners[endIdx];
const direction = new Vector3().subVectors(end, start);
const length = direction.length();
const midPoint = new Vector3().addVectors(start, end).multiplyScalar(0.5);
const quaternion = new Quaternion().setFromUnitVectors(
new Vector3(0, 1, 0),
direction.clone().normalize()
);
return {
key: `edge-cylinder-${i}`,
position: midPoint,
rotation: quaternion,
length,
radius,
};
});
return { edgeCylinders, center, size };
}, [boundingBox, lineWidth]);
if (!boundingBox) return null; if (!boundingBox) return null;
return ( return (
<group name={name}> <group name={name}>
<Line {edgeCylinders.map(({ key, position, rotation, length, radius }) => (
segments <Cylinder key={key} args={[radius, radius, length, 6]} position={position} quaternion={rotation} >
depthWrite={false} <meshBasicMaterial color={color} depthWrite={false} />
points={points} </Cylinder>
color={color} ))}
lineWidth={lineWidth}
/>
<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]} />

View File

@@ -3,8 +3,8 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber'; import { ThreeEvent, useThree } from '@react-three/fiber';
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedAssets, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store'; import { useActiveTool, useDeletableFloorItem, useSelectedAssets, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
import { AssetBoundingBox } from '../../functions/assetBoundingBox'; import { AssetBoundingBox } from '../../functions/assetBoundingBox';
import { CameraControls } from '@react-three/drei'; import { CameraControls } from '@react-three/drei';
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore'; import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
@@ -16,23 +16,23 @@ import { getUserData } from '../../../../../functions/getUserData';
import { useSceneContext } from '../../../../scene/sceneContext'; import { useSceneContext } from '../../../../scene/sceneContext';
import { useVersionContext } from '../../../version/versionContext'; import { useVersionContext } from '../../../version/versionContext';
import { SkeletonUtils } from 'three-stdlib'; import { SkeletonUtils } from 'three-stdlib';
import { useAnimationPlaySpeed, usePauseButtonStore } from '../../../../../store/usePlayButtonStore';
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi'; import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs'; import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs';
import { ModelAnimator } from './animator/modelAnimator';
function Model({ asset }: { readonly asset: Asset }) {
function Model({ asset, isRendered }: { readonly asset: Asset, isRendered: boolean }) {
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
const savedTheme: string = localStorage.getItem("theme") || "light"; const savedTheme: string = localStorage.getItem("theme") || "light";
const { camera, controls, gl } = useThree(); const { controls, gl } = useThree();
const { activeTool } = useActiveTool(); const { activeTool } = useActiveTool();
const { toolMode } = useToolMode(); const { toolMode } = useToolMode();
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { subModule } = useSubModuleStore(); const { subModule } = useSubModuleStore();
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { speed } = useAnimationPlaySpeed();
const { isPaused } = usePauseButtonStore();
const { assetStore, eventStore, productStore } = useSceneContext(); const { assetStore, eventStore, productStore } = useSceneContext();
const { removeAsset, setAnimations, resetAnimation, setAnimationComplete } = assetStore(); const { removeAsset, resetAnimation } = assetStore();
const { setTop } = useTopData(); const { setTop } = useTopData();
const { setLeft } = useLeftData(); const { setLeft } = useLeftData();
const { getIsEventInProduct, addPoint } = productStore(); const { getIsEventInProduct, addPoint } = productStore();
@@ -43,23 +43,15 @@ function Model({ asset }: { readonly asset: Asset }) {
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
const { limitDistance } = useLimitDistance();
const { renderDistance } = useRenderDistance();
const leftDrag = useRef(false); const leftDrag = useRef(false);
const isLeftMouseDown = useRef(false); const isLeftMouseDown = useRef(false);
const rightDrag = useRef(false); const rightDrag = useRef(false);
const isRightMouseDown = useRef(false); const isRightMouseDown = useRef(false);
const [isRendered, setIsRendered] = useState(false);
const [gltfScene, setGltfScene] = useState<GLTF["scene"] | null>(null); const [gltfScene, setGltfScene] = useState<GLTF["scene"] | null>(null);
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null); const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
const [isSelected, setIsSelected] = useState(false); const [isSelected, setIsSelected] = useState(false);
const groupRef = useRef<THREE.Group>(null); const groupRef = useRef<THREE.Group>(null);
const mixerRef = useRef<THREE.AnimationMixer>();
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
const [previousAnimation, setPreviousAnimation] = useState<string | null>(null);
const [ikData, setIkData] = useState<any>(); const [ikData, setIkData] = useState<any>();
const blendFactor = useRef(0);
const blendDuration = 0.5;
const { selectedVersionStore } = useVersionContext(); const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore(); const { selectedVersion } = selectedVersionStore();
const { userId, organization } = getUserData(); const { userId, organization } = getUserData();
@@ -133,16 +125,6 @@ function Model({ asset }: { readonly asset: Asset }) {
clone.animations = cachedModel.animations || []; clone.animations = cachedModel.animations || [];
setGltfScene(clone); setGltfScene(clone);
calculateBoundingBox(clone); calculateBoundingBox(clone);
if (cachedModel.animations && clone.animations.length > 0) {
const animationName = clone.animations.map((clip: any) => clip.name);
setAnimations(asset.modelUuid, animationName)
mixerRef.current = new THREE.AnimationMixer(clone);
clone.animations.forEach((animation: any) => {
const action = mixerRef.current!.clipAction(animation);
actions.current[animation.name] = action;
});
}
return; return;
} }
@@ -202,21 +184,6 @@ function Model({ asset }: { readonly asset: Asset }) {
}, []); }, []);
useFrame(() => {
const assetPosition = new THREE.Vector3(...asset.position);
if (limitDistance) {
if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) {
setIsRendered(true);
} else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) {
setIsRendered(false);
}
} else {
if (!isRendered) {
setIsRendered(true);
}
}
})
const handleDblClick = (asset: Asset) => { const handleDblClick = (asset: Asset) => {
if (asset) { if (asset) {
if (activeTool === "cursor" && boundingBox && groupRef.current && activeModule === 'builder') { if (activeTool === "cursor" && boundingBox && groupRef.current && activeModule === 'builder') {
@@ -382,50 +349,6 @@ function Model({ asset }: { readonly asset: Asset }) {
} }
} }
const handleAnimationComplete = useCallback(() => {
if (asset.animationState) {
setAnimationComplete(asset.modelUuid, true);
}
}, [asset.animationState]);
useFrame((_, delta) => {
if (mixerRef.current) {
mixerRef.current.update(delta * (activeModule === 'simulation' ? speed : 1));
}
});
useEffect(() => {
if (!asset.animationState || !mixerRef.current) return;
const { current, loopAnimation, isPlaying } = asset.animationState;
const currentAction = actions.current[current];
const previousAction = previousAnimation ? actions.current[previousAnimation] : null;
if (isPlaying && currentAction && activeModule === 'simulation' && !isPaused) {
blendFactor.current = 0;
currentAction.reset();
currentAction.setLoop(loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce, loopAnimation ? Infinity : 1);
currentAction.clampWhenFinished = true;
if (previousAction && previousAction !== currentAction) {
previousAction.crossFadeTo(currentAction, blendDuration, false);
}
currentAction.play();
mixerRef.current.addEventListener('finished', handleAnimationComplete);
setPreviousAnimation(current);
} else {
Object.values(actions.current).forEach((action) => action.stop());
}
return () => {
if (mixerRef.current) {
mixerRef.current.removeEventListener('finished', handleAnimationComplete);
}
};
}, [asset.animationState?.current, asset.animationState?.isCompleted, asset.animationState?.isPlaying, isPaused, activeModule]);
useEffect(() => { useEffect(() => {
const canvasElement = gl.domElement; const canvasElement = gl.domElement;
@@ -526,9 +449,15 @@ function Model({ asset }: { readonly asset: Asset }) {
{gltfScene && ( {gltfScene && (
<> <>
{isRendered ? ( {isRendered ? (
<>
<primitive object={gltfScene} /> <primitive object={gltfScene} />
<ModelAnimator asset={asset} gltfScene={gltfScene} />
</>
) : ( ) : (
<AssetBoundingBox name='Asset Fallback' boundingBox={boundingBox} color='gray' lineWidth={1} /> <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} />

View File

@@ -1,17 +1,45 @@
import Model from './model/model'; import { useEffect, useRef, useState } from "react";
import { useThree } from '@react-three/fiber'; import { useThree, useFrame } from "@react-three/fiber";
import { Vector3 } from "three";
import { CameraControls } from '@react-three/drei'; import { CameraControls } from '@react-three/drei';
import { Vector3 } from 'three'; import { useLimitDistance, useRenderDistance, useSelectedFloorItem } from '../../../../store/builder/store';
import { useSelectedFloorItem } from '../../../../store/builder/store';
import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore'; import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
import { useSceneContext } from '../../../scene/sceneContext'; import { useSceneContext } from '../../../scene/sceneContext';
import Model from './model/model';
const distanceWorker = new Worker(new URL("../../../../services/factoryBuilder/webWorkers/distanceWorker.js", import.meta.url));
function Models() { function Models() {
const { controls } = useThree(); const { controls, camera } = useThree();
const { assetStore } = useSceneContext(); const { assetStore } = useSceneContext();
const { assets } = assetStore(); const { assets } = assetStore();
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const { limitDistance } = useLimitDistance();
const { renderDistance } = useRenderDistance();
const [renderMap, setRenderMap] = useState<Record<string, boolean>>({});
const cameraPos = useRef(new Vector3());
useEffect(() => {
distanceWorker.onmessage = (e) => {
const { shouldRender, modelUuid } = e.data;
setRenderMap((prev) => {
if (prev[modelUuid] === shouldRender) return prev;
return { ...prev, [modelUuid]: shouldRender };
});
};
}, []);
useFrame(() => {
camera.getWorldPosition(cameraPos.current);
for (const asset of assets) {
const isRendered = renderMap[asset.modelUuid] ?? false;
distanceWorker.postMessage({ modelUuid: asset.modelUuid, assetPosition: { x: asset.position[0], y: asset.position[1], z: asset.position[2], }, cameraPosition: cameraPos.current, limitDistance, renderDistance, isRendered, });
}
});
return ( return (
<group <group
@@ -28,11 +56,11 @@ function Models() {
} }
}} }}
> >
{assets.map((asset) => {assets.map((asset) => (
<Model key={asset.modelUuid} asset={asset} /> <Model key={asset.modelUuid} asset={asset} isRendered={renderMap[asset.modelUuid] ?? false} />
)} ))}
</group> </group>
) );
} }
export default Models export default Models;

View File

@@ -164,7 +164,7 @@ function MoveControls2D({
return new THREE.Vector3().subVectors(pointPosition, hitPoint); return new THREE.Vector3().subVectors(pointPosition, hitPoint);
}, []); }, []);
const movePoints = useCallback(() => { const movePoints = (() => {
if (selectedPoints.length === 0) return; if (selectedPoints.length === 0) return;
const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {}; const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {};
@@ -192,9 +192,9 @@ function MoveControls2D({
setMovedObjects(selectedPoints); setMovedObjects(selectedPoints);
setIsMoving(true); setIsMoving(true);
}, [selectedPoints, camera, pointer, plane, raycaster, calculateDragOffset]); });
const resetToInitialPositions = useCallback(() => { const resetToInitialPositions = () => {
setTimeout(() => { setTimeout(() => {
movedObjects.forEach((movedPoint: THREE.Object3D) => { movedObjects.forEach((movedPoint: THREE.Object3D) => {
if (movedPoint.userData.pointUuid && initialStates[movedPoint.uuid]) { if (movedPoint.userData.pointUuid && initialStates[movedPoint.uuid]) {
@@ -218,7 +218,7 @@ function MoveControls2D({
} }
}); });
}, 0) }, 0)
}, [movedObjects, initialStates, setAislePosition, setWallPosition, setFloorPosition, setZonePosition]); };
const placeMovedAssets = () => { const placeMovedAssets = () => {
if (movedObjects.length === 0) return; if (movedObjects.length === 0) return;

View File

@@ -42,8 +42,8 @@ const DuplicationControls3D = ({
right: false, right: false,
}); });
const calculateDragOffset = useCallback((point: THREE.Vector3, hitPoint: THREE.Vector3) => { const calculateDragOffset = useCallback((point: THREE.Object3D, hitPoint: THREE.Vector3) => {
const pointPosition = new THREE.Vector3().copy(point); const pointPosition = new THREE.Vector3().copy(point.position);
return new THREE.Vector3().subVectors(pointPosition, hitPoint); return new THREE.Vector3().subVectors(pointPosition, hitPoint);
}, []); }, []);
@@ -120,11 +120,9 @@ const DuplicationControls3D = ({
if (hit) { if (hit) {
if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) { if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) {
const assetUuid = duplicatedObjects[0].userData.modelUuid; const model = scene.getObjectByProperty("uuid", duplicatedObjects[0].userData.modelUuid);
const asset = getAssetById(assetUuid); if (model) {
if (!asset) return; const newOffset = calculateDragOffset(model, intersectionPoint);
if (duplicatedObjects[0]) {
const newOffset = calculateDragOffset(new THREE.Vector3(...asset.position), intersectionPoint);
setDragOffset(newOffset); setDragOffset(newOffset);
} }
return; return;
@@ -177,7 +175,7 @@ const DuplicationControls3D = ({
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint); const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit) { if (hit) {
const offset = calculateDragOffset(selectedAssets[0].position, hit); const offset = calculateDragOffset(selectedAssets[0], hit);
setDragOffset(offset); setDragOffset(offset);
} }

View File

@@ -46,10 +46,7 @@ function MoveControls3D({
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({}); const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({}); const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({});
const [isMoving, setIsMoving] = useState(false); const [isMoving, setIsMoving] = useState(false);
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ left: false, right: false, });
left: false,
right: false,
});
const updateBackend = ( const updateBackend = (
productName: string, productName: string,
@@ -79,9 +76,9 @@ function MoveControls3D({
}; };
const onKeyUp = (event: KeyboardEvent) => { const onKeyUp = (event: KeyboardEvent) => {
const isModifierKey = event.key === "Control" || event.key === "Shift"; const isModifierKey = (!event.shiftKey && !event.ctrlKey);
if (isModifierKey) { if (isModifierKey && keyEvent !== "") {
setKeyEvent(""); setKeyEvent("");
} }
}; };
@@ -196,7 +193,6 @@ function MoveControls3D({
raycaster.setFromCamera(pointer, camera); raycaster.setFromCamera(pointer, camera);
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint); const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit) { if (hit) {
if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) { if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) {
if (movedObjects[0]) { if (movedObjects[0]) {
@@ -209,18 +205,18 @@ function MoveControls3D({
if (dragOffset) { if (dragOffset) {
const rawBasePosition = new THREE.Vector3().addVectors(intersectionPoint, dragOffset); const rawBasePosition = new THREE.Vector3().addVectors(intersectionPoint, dragOffset);
let moveSpeed = keyEvent.includes("Shift") ? 0.05 : 1; let moveDistance = keyEvent.includes("Shift") ? 0.05 : 1;
const initialBasePosition = initialPositions[movedObjects[0].uuid]; const initialBasePosition = initialPositions[movedObjects[0].uuid];
const positionDifference = new THREE.Vector3().subVectors(rawBasePosition, initialBasePosition); const positionDifference = new THREE.Vector3().subVectors(rawBasePosition, initialBasePosition);
const adjustedDifference = positionDifference.multiplyScalar(moveSpeed); let adjustedDifference = positionDifference.multiplyScalar(moveDistance);
const baseNewPosition = new THREE.Vector3().addVectors(initialBasePosition, adjustedDifference); const baseNewPosition = new THREE.Vector3().addVectors(initialBasePosition, adjustedDifference);
if (keyEvent.includes("Ctrl")) { if (keyEvent.includes("Ctrl")) {
baseNewPosition.x = snapControls(baseNewPosition.x, "Ctrl"); baseNewPosition.x = snapControls(baseNewPosition.x, keyEvent);
baseNewPosition.z = snapControls(baseNewPosition.z, "Ctrl"); baseNewPosition.z = snapControls(baseNewPosition.z, keyEvent);
} }
movedObjects.forEach((movedAsset: THREE.Object3D) => { movedObjects.forEach((movedAsset: THREE.Object3D) => {

View File

@@ -3,17 +3,15 @@ import { useFrame } from "@react-three/fiber";
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore"; import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore";
import { useSceneContext } from "../../../../scene/sceneContext"; import { useSceneContext } from "../../../../scene/sceneContext";
import { useProductContext } from "../../../products/productContext"; import { useProductContext } from "../../../products/productContext";
import { useHumanEventManager } from "../../../human/eventManager/useHumanEventManager";
export function useRetrieveHandler() { export function useRetrieveHandler() {
const { materialStore, armBotStore, vehicleStore, storageUnitStore, productStore, humanStore, assetStore, humanEventManagerRef } = useSceneContext(); const { materialStore, armBotStore, vehicleStore, storageUnitStore, 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 { getHumanById, incrementHumanLoad, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore(); const { getHumanById, incrementHumanLoad, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
const { addHumanToMonitor } = useHumanEventManager();
const { getAssetById, setCurrentAnimation } = assetStore(); const { getAssetById, setCurrentAnimation } = assetStore();
const { selectedProduct } = selectedProductStore(); const { selectedProduct } = selectedProductStore();
const { getArmBotById, addCurrentAction } = armBotStore(); const { getArmBotById, addCurrentAction } = armBotStore();
@@ -303,19 +301,10 @@ export function useRetrieveHandler() {
const humanAsset = getAssetById(triggeredModel.modelUuid); const humanAsset = getAssetById(triggeredModel.modelUuid);
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
if (!action || action.actionType !== 'worker' || !humanEventManagerRef.current) return; if (!action || action.actionType !== 'worker') return;
let state = humanEventManagerRef.current.humanStates.find(h => h.humanId === triggeredModel.modelUuid);
console.log('state: ', state);
console.log('human: ', human);
const currentCount = retrievalCountRef.current.get(actionUuid) ?? 0; const currentCount = retrievalCountRef.current.get(actionUuid) ?? 0;
let conditionMet = false;
if (state) {
console.log('state.actionQueue: ', state.actionQueue);
// state.actionQueue[0].count
}
if (currentCount >= action.loadCount) { if (currentCount >= action.loadCount) {
completedActions.push(actionUuid); completedActions.push(actionUuid);
hasChanges = true; hasChanges = true;
@@ -337,12 +326,10 @@ export function useRetrieveHandler() {
removeLastMaterial(storageUnit.modelUuid); removeLastMaterial(storageUnit.modelUuid);
updateCurrentLoad(storageUnit.modelUuid, -1); updateCurrentLoad(storageUnit.modelUuid, -1);
incrementHumanLoad(human.modelUuid, 1); incrementHumanLoad(human.modelUuid, 1);
addHumanToMonitor(human.modelUuid, () => {
addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId); addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`); retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);
retrievalCountRef.current.set(actionUuid, currentCount + 1); retrievalCountRef.current.set(actionUuid, currentCount + 1);
}, actionUuid)
} }
} }
} }

View File

@@ -0,0 +1,21 @@
import { Vector3 } from "three";
onmessage = function (e) {
const { modelUuid, assetPosition, cameraPosition, limitDistance, renderDistance, isRendered, } = e.data;
const assetVec = new Vector3(assetPosition.x, assetPosition.y, assetPosition.z);
const cameraVec = new Vector3(cameraPosition.x, cameraPosition.y, cameraPosition.z);
const distance = assetVec.distanceTo(cameraVec);
if (limitDistance) {
if (!isRendered && distance <= renderDistance) {
postMessage({ shouldRender: true, modelUuid });
} else if (isRendered && distance > renderDistance) {
postMessage({ shouldRender: false, modelUuid });
}
} else {
if (!isRendered) {
postMessage({ shouldRender: true, modelUuid });
}
}
};

View File

@@ -1,12 +1,5 @@
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils'; import { retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
loader.setDRACOLoader(dracoLoader);
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
onmessage = async (event) => { onmessage = async (event) => {
@@ -18,7 +11,7 @@ onmessage = async (event) => {
for (const item of uniqueItems) { for (const item of uniqueItems) {
if (item.assetId === null || item.assetId === undefined) { if (item.assetId === null || item.assetId === undefined) {
continue; // Skip items without a valid assetId continue;
} }
const modelID = item.assetId; const modelID = item.assetId;
const indexedDBModel = await retrieveGLTF(modelID); const indexedDBModel = await retrieveGLTF(modelID);
@@ -37,5 +30,5 @@ onmessage = async (event) => {
} }
} }
postMessage({ message: 'done' }) postMessage({ message: 'done' });
}; };