Refactor API imports and restructure services

- Updated import paths for `upsertProductOrEventApi`, `deleteEventDataApi`, `deleteProductApi`, `getProductApi`, `getAllProductsApi`, and `renameProductApi` to point to the new `products` directory.
- Removed old API files for `UpsertProductOrEventApi`, `deleteEventDataApi`, `deleteProductApi`, `getProductApi`, `getAllProductsApi`, and `renameProductApi`.
- Introduced new implementations for the above APIs in the `products` directory.
- Added `MaterialCollisionDetector` component to handle material collision detection using a web worker.
- Updated various components to utilize the new API structure and ensure proper functionality.
This commit is contained in:
2025-05-21 15:36:34 +05:30
parent 60a277f7f0
commit 8e01c24844
32 changed files with 191 additions and 24 deletions

View File

@@ -11,7 +11,7 @@ import {
useSelectedProduct,
} from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
interface ActionsListProps {
selectedPointData: any;

View File

@@ -11,7 +11,7 @@ import Trigger from "../trigger/Trigger";
import { useSelectedAction, useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
function ConveyorMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default");

View File

@@ -6,7 +6,7 @@ import { useSelectedAction, useSelectedEventData, useSelectedProduct } from "../
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ProcessAction from "../actions/ProcessAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
function MachineMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "process">("default");

View File

@@ -12,7 +12,7 @@ import {
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import PickAndPlaceAction from "../actions/PickAndPlaceAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
function RoboticArmMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">(

View File

@@ -4,7 +4,7 @@ import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger";
import StorageAction from "../actions/StorageAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { useStorageUnitStore } from "../../../../../../store/simulation/useStorageUnitStore";
import { useSelectedAction, useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";

View File

@@ -12,7 +12,7 @@ import {
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import TravelAction from "../actions/TravelAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useVehicleStore } from "../../../../../../store/simulation/useVehicleStore";
function VehicleMechanics() {

View File

@@ -13,7 +13,7 @@ import {
useSelectedAction,
useSelectedProduct,
} from "../../../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
type TriggerProps = {
selectedPointData?: PointsScheme | undefined;

View File

@@ -17,10 +17,10 @@ import RenderOverlay from "../../../templates/Overlay";
import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { deleteEventDataApi } from "../../../../services/simulation/deleteEventDataApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { deleteProductApi } from "../../../../services/simulation/deleteProductApi";
import { renameProductApi } from "../../../../services/simulation/renameProductApi";
import { deleteEventDataApi } from "../../../../services/simulation/products/deleteEventDataApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { deleteProductApi } from "../../../../services/simulation/products/deleteProductApi";
import { renameProductApi } from "../../../../services/simulation/products/renameProductApi";
import { determineExecutionMachineSequences } from "../../../../modules/simulation/simulator/functions/determineExecutionMachineSequences";
import ComparePopUp from "../../../ui/compareVersion/Compare";
import {

View File

@@ -13,7 +13,7 @@ import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifie
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { snapControls } from "../../../../utils/handleSnap";
import DistanceFindingControls from "./distanceFindingControls";

View File

@@ -7,7 +7,7 @@ import * as Types from "../../../../types/world/worldTypes";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree();

View File

@@ -9,7 +9,7 @@ import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifie
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
export default function TransformControl() {

View File

@@ -9,7 +9,7 @@ import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModi
import { useSelectedEventSphere, useSelectedEventData, } from "../../../../../store/simulation/useSimulationStore";
import { useThree } from "@react-three/fiber";
import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore";
import { upsertProductOrEventApi } from "../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
function PointsCreator() {
const { gl, raycaster, scene, pointer, camera } = useThree();

View File

@@ -1,4 +1,4 @@
import { upsertProductOrEventApi } from "../../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
interface HandleAddEventToProductParams {
event: EventsSchema | undefined;

View File

@@ -8,7 +8,7 @@ import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { handleAddEventToProduct } from "../points/functions/handleAddEventToProduct";
import { QuadraticBezierLine } from "@react-three/drei";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { useDeleteTool } from "../../../../store/builder/store";
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
import { ArrowOnQuadraticBezier, Arrows } from "../arrows/arrows";

View File

@@ -0,0 +1,119 @@
import { useEffect, useRef } from 'react';
import * as THREE from 'three';
import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
import { useThree, useFrame } from '@react-three/fiber';
import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore';
import { CameraControls } from '@react-three/drei';
const collisionWorker = new Worker(new URL('../../../../services/simulation/webWorkers/collisionWorker.ts', import.meta.url));
export default function MaterialCollisionDetector() {
const { materials } = useMaterialStore();
const { scene, controls, camera } = useThree();
const positionsRef = useRef<Record<string, THREE.Vector3>>({});
const sizesRef = useRef<Record<string, number>>({});
const { isPlaying } = usePlayButtonStore();
const { isPaused, setIsPaused } = usePauseButtonStore();
const { isReset } = useResetButtonStore();
const collisionStateRef = useRef<Record<string, boolean>>({});
useEffect(() => {
if (isReset) {
collisionStateRef.current = {};
}
}, [isReset])
useEffect(() => {
collisionWorker.onmessage = (e) => {
const { collisions } = e.data;
handleCollisions(collisions);
};
}, []);
useFrame(() => {
if (materials.length < 2 || !isPlaying || isPaused) return;
const { positions, sizes } = getCurrentMaterialData();
positionsRef.current = positions;
sizesRef.current = sizes;
collisionWorker.postMessage({
materials: materials,
positions: positions,
sizes: sizes
});
});
const getCurrentMaterialData = () => {
const positions: Record<string, THREE.Vector3> = {};
const sizes: Record<string, number> = {};
materials.forEach(material => {
if (material.isVisible) {
const obj = scene.getObjectByProperty('uuid', material.materialId);
if (obj) {
const position = new THREE.Vector3();
obj.getWorldPosition(position);
positions[material.materialId] = position;
const boundingBox = new THREE.Box3().setFromObject(obj);
const sizeVector = new THREE.Vector3();
boundingBox.getSize(sizeVector);
sizes[material.materialId] = Math.max(sizeVector.x, sizeVector.y, sizeVector.z) / 2;
}
}
});
return { positions, sizes };
};
const handleCollisions = (currentCollisions: Array<{
materialId1: string;
materialId2: string;
distance: number;
}>) => {
const newCollisionState: Record<string, boolean> = {};
currentCollisions.forEach(collision => {
const key = `${collision.materialId1}|-|${collision.materialId2}`;
newCollisionState[key] = true;
});
Object.keys(collisionStateRef.current).forEach(key => {
if (!newCollisionState[key]) {
const [id1, id2] = key.split('|-|');
echo.error(`Collision ended between ${id1} and ${id2}`);
}
});
currentCollisions.forEach(collision => {
const key = `${collision.materialId1}|-|${collision.materialId2}`;
if (!collisionStateRef.current[key]) {
setIsPaused(true);
echo.error(`Collision started between ${collision.materialId1} and ${collision.materialId2}`);
const obj = scene.getObjectByProperty('uuid', collision.materialId1)
if (obj) {
const collisionPos = new THREE.Vector3();
obj.getWorldPosition(collisionPos);
const currentPos = new THREE.Vector3().copy(camera.position);
const target = new THREE.Vector3();
(controls as CameraControls).getTarget(target);
const direction = new THREE.Vector3().subVectors(target, currentPos).normalize();
const offsetDistance = 5;
const newCameraPos = new THREE.Vector3().copy(collisionPos).sub(direction.multiplyScalar(offsetDistance));
camera.position.copy(newCameraPos);
(controls as CameraControls).setLookAt(newCameraPos.x, newCameraPos.y, newCameraPos.z, collisionPos.x, collisionPos.y, collisionPos.z, true);
}
}
});
collisionStateRef.current = newCollisionState;
};
return null;
}

View File

@@ -95,7 +95,7 @@ function MaterialInstance({ material }: { material: MaterialSchema }) {
<>
{material.isRendered &&
<MaterialModel matRef={matRef} materialType={material.materialType} visible={material.isVisible} position={position} />
<MaterialModel materialId={material.materialId} matRef={matRef} materialType={material.materialType} visible={material.isVisible} position={position} />
}
<MaterialAnimator

View File

@@ -17,11 +17,12 @@ const modelPaths: Record<string, string> = {
type ModelType = keyof typeof modelPaths;
interface ModelProps extends React.ComponentProps<'group'> {
materialId: string;
materialType: ModelType;
matRef: React.Ref<THREE.Group<THREE.Object3DEventMap>>
}
export function MaterialModel({ materialType, matRef, ...props }: Readonly<ModelProps>) {
export function MaterialModel({ materialId, materialType, matRef, ...props }: Readonly<ModelProps>) {
const path = modelPaths[materialType] || modelPaths['Default material'];
const gltf = useGLTF(path);
const cloned = useMemo(() => gltf?.scene.clone(), [gltf]);
@@ -29,7 +30,7 @@ export function MaterialModel({ materialType, matRef, ...props }: Readonly<Model
if (!cloned) return null;
return (
<group ref={matRef} {...props} dispose={null}>
<group uuid={materialId} ref={matRef} {...props} dispose={null}>
<primitive
object={cloned}
scale={[0.4, 0.4, 0.4]}

View File

@@ -2,6 +2,7 @@ import { useEffect } from 'react'
import MaterialInstances from './instances/materialInstances'
import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore';
import { useMaterialStore } from '../../../store/simulation/useMaterialStore';
import MaterialCollisionDetector from './collisionDetection/materialCollitionDetector';
function Materials() {
const { clearMaterials } = useMaterialStore();
@@ -23,6 +24,8 @@ function Materials() {
}
<MaterialCollisionDetector />
</>
)
}

View File

@@ -3,8 +3,8 @@ import { useEffect } from 'react';
import { useProductStore } from '../../../store/simulation/useProductStore';
import { useSelectedProduct } from '../../../store/simulation/useSimulationStore';
import AddOrRemoveEventsInProducts from './events/addOrRemoveEventsInProducts';
import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProductOrEventApi';
import { getAllProductsApi } from '../../../services/simulation/getallProductsApi';
import { upsertProductOrEventApi } from '../../../services/simulation/products/UpsertProductOrEventApi';
import { getAllProductsApi } from '../../../services/simulation/products/getallProductsApi';
import { useVehicleStore } from '../../../store/simulation/useVehicleStore';
import { useArmBotStore } from '../../../store/simulation/useArmBotStore';
import { useConveyorStore } from '../../../store/simulation/useConveyorStore';

View File

@@ -57,6 +57,7 @@ export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: Rea
<>
{isRendered && (
<MaterialModel
materialId={armBot.currentAction?.materialId ?? ''}
matRef={sphereRef}
materialType={armBot.currentAction?.materialType ?? 'Default material'}
/>

View File

@@ -10,7 +10,7 @@ import * as THREE from 'three';
import armPick from "../../../../assets/gltf-glb/ui/arm_ui_pick.glb";
import armDrop from "../../../../assets/gltf-glb/ui/arm_ui_drop.glb";
import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi';
import { upsertProductOrEventApi } from '../../../../services/simulation/products/UpsertProductOrEventApi';
type Positions = {
pick: [number, number, number];

View File

@@ -10,7 +10,7 @@ import {
} from "../../../../store/simulation/useSimulationStore";
import { useVehicleStore } from "../../../../store/simulation/useVehicleStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { DoubleSide, Group, Plane, Vector3 } from "three";
import startPoint from "../../../../assets/gltf-glb/ui/arrow_green.glb";

View File

@@ -63,6 +63,7 @@ const MaterialAnimator = ({
storage.currentMaterials.map((mat, index) => (
<MaterialModel
key={`${index}-${mat.materialId}`}
materialId={mat.materialId}
matRef={meshRef}
materialType={mat.materialType ?? "Default material"}
position={materialPositions[index]}

View File

@@ -194,6 +194,7 @@ export function useTriggerHandler() {
}
}
} else {
setIsPaused(materialId, true);
addArmBotToMonitor(armBot.modelUuid,
() => {
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');

View File

@@ -36,6 +36,7 @@ const MaterialAnimator = ({ agvDetail }: MaterialAnimatorProps) => {
{agvDetail.currentMaterials.length > 0 &&
<MaterialModel
matRef={meshRef}
materialId={agvDetail.currentMaterials[0].materialId || ''}
materialType={agvDetail.currentMaterials[0].materialType || 'Default material'}
/>
}

View File

@@ -0,0 +1,40 @@
onmessage = function (e) {
const { materials, positions, sizes } = e.data;
const collisions = [];
const allPairs = [];
for (let i = 0; i < materials.length; i++) {
for (let j = i + 1; j < materials.length; j++) {
const mat1 = materials[i];
const mat2 = materials[j];
const pos1 = positions[mat1.materialId];
const pos2 = positions[mat2.materialId];
if (!pos1 || !pos2) continue;
const size1 = sizes[mat1.materialId] || 0.2;
const size2 = sizes[mat2.materialId] || 0.2;
const distance = Math.sqrt(
Math.pow(pos1.x - pos2.x, 2) +
Math.pow(pos1.y - pos2.y, 2) +
Math.pow(pos1.z - pos2.z, 2)
);
allPairs.push({
materialId1: mat1.materialId,
materialId2: mat2.materialId
});
if (distance < (size1 + size2)) {
collisions.push({
materialId1: mat1.materialId,
materialId2: mat2.materialId,
distance: distance
});
}
}
}
postMessage({ collisions, allPairs });
};