pillar Jig half way completed
This commit is contained in:
@@ -143,10 +143,7 @@ const Assets: React.FC = () => {
|
||||
setSelectedItem({
|
||||
name: asset.filename,
|
||||
id: asset.AssetID,
|
||||
type:
|
||||
asset.type === "undefined"
|
||||
? undefined
|
||||
: asset.type
|
||||
type: asset.type === "undefined" ? undefined : asset.type
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -200,30 +197,20 @@ const Assets: React.FC = () => {
|
||||
setSelectedItem({
|
||||
name: asset.filename,
|
||||
id: asset.AssetID,
|
||||
type:
|
||||
asset.type === "undefined"
|
||||
? undefined
|
||||
: asset.type,
|
||||
type: asset.type === "undefined" ? undefined : asset.type,
|
||||
category: asset.category,
|
||||
subCategory: asset.subCategory
|
||||
subType: asset.subType
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div className="asset-name">
|
||||
{asset.filename
|
||||
.split("_")
|
||||
.map(
|
||||
(word: any) =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
)
|
||||
.join(" ")}
|
||||
{asset.filename.split("_").map((word: any) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ")}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{categoryAssets.length === 0 && (
|
||||
<div className="no-asset">
|
||||
🚧 The asset shelf is empty. We're working on filling it
|
||||
up!
|
||||
🚧 The asset shelf is empty. We're working on filling it up!
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -119,6 +119,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
subType: item.eventData.subType as VehicleEventSchema['subType'] || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
@@ -151,6 +152,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "transfer",
|
||||
subType: item.eventData.subType || '',
|
||||
speed: 1,
|
||||
points: item.eventData.points?.map((point: any, index: number) => ({
|
||||
uuid: point.uuid || THREE.MathUtils.generateUUID(),
|
||||
@@ -177,6 +179,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
subType: item.eventData.subType || '',
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
@@ -200,6 +203,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
subType: item.eventData.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
@@ -228,6 +232,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
subType: item.eventData.subType || '',
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
@@ -250,6 +255,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "human",
|
||||
subType: item.eventData.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
@@ -270,6 +276,31 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
}
|
||||
}
|
||||
addEvent(humanEvent);
|
||||
} else if (item.eventData.type === 'Crane') {
|
||||
const craneEvent: CraneEventSchema = {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "crane",
|
||||
subType: item.eventData.subType as CraneEventSchema['subType'] || 'pillarJib',
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndDrop",
|
||||
maxPickUpCount: 1,
|
||||
triggers: []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
addEvent(craneEvent);
|
||||
}
|
||||
} else {
|
||||
assets.push({
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as THREE from "three";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
import { Socket } from "socket.io-client";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
import PointsCalculator from "../../../simulation/events/points/functions/pointsCalculator";
|
||||
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
|
||||
async function addAssetModel(
|
||||
scene: THREE.Scene,
|
||||
@@ -165,7 +165,7 @@ async function handleModelLoad(
|
||||
|
||||
if (!data || !data.points) return;
|
||||
|
||||
const eventData: any = { type: selectedItem.type };
|
||||
const eventData: any = { type: selectedItem.type, subType: selectedItem.subType };
|
||||
|
||||
if (selectedItem.type === "Conveyor") {
|
||||
const ConveyorEvent: ConveyorEventSchema = {
|
||||
@@ -175,6 +175,7 @@ async function handleModelLoad(
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "transfer",
|
||||
subType: selectedItem.subType || '',
|
||||
speed: 1,
|
||||
points: data.points.map((point: THREE.Vector3, index: number) => {
|
||||
const triggers: TriggerSchema[] = [];
|
||||
@@ -243,6 +244,7 @@ async function handleModelLoad(
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
subType: selectedItem.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -280,6 +282,7 @@ async function handleModelLoad(
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
subType: selectedItem.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -313,6 +316,7 @@ async function handleModelLoad(
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
subType: selectedItem.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
@@ -341,6 +345,7 @@ async function handleModelLoad(
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
subType: selectedItem.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
@@ -368,6 +373,7 @@ async function handleModelLoad(
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "human",
|
||||
subType: selectedItem.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -393,6 +399,36 @@ async function handleModelLoad(
|
||||
position: humanEvent.point.position,
|
||||
rotation: humanEvent.point.rotation,
|
||||
}
|
||||
} else if (selectedItem.type === "Crane") {
|
||||
const craneEvent: CraneEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "crane",
|
||||
subType: selectedItem.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndDrop",
|
||||
maxPickUpCount: 1,
|
||||
triggers: []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
addEvent(craneEvent);
|
||||
eventData.point = {
|
||||
uuid: craneEvent.point.uuid,
|
||||
position: craneEvent.point.position,
|
||||
rotation: craneEvent.point.rotation,
|
||||
}
|
||||
}
|
||||
|
||||
const completeData = {
|
||||
@@ -401,11 +437,7 @@ async function handleModelLoad(
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
@@ -422,11 +454,7 @@ async function handleModelLoad(
|
||||
modelName: completeData.modelName,
|
||||
assetId: completeData.assetId,
|
||||
position: completeData.position,
|
||||
rotation: [
|
||||
completeData.rotation.x,
|
||||
completeData.rotation.y,
|
||||
completeData.rotation.z,
|
||||
] as [number, number, number],
|
||||
rotation: [completeData.rotation.x, completeData.rotation.y, completeData.rotation.z,] as [number, number, number],
|
||||
isLocked: completeData.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: completeData.isVisible,
|
||||
@@ -442,11 +470,7 @@ async function handleModelLoad(
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
@@ -462,11 +486,7 @@ async function handleModelLoad(
|
||||
modelName: data.modelName,
|
||||
assetId: data.assetId,
|
||||
position: data.position,
|
||||
rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [
|
||||
number,
|
||||
number,
|
||||
number
|
||||
],
|
||||
rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [number, number, number],
|
||||
isLocked: data.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: data.isVisible,
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import * as THREE from 'three';
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import { ThreeEvent } from '@react-three/fiber';
|
||||
import { useCallback } from 'react';
|
||||
import { ProductStoreType } from '../../../../../../store/simulation/useProductStore';
|
||||
import { EventStoreType } from '../../../../../../store/simulation/useEventsStore';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
import { useActiveTool, useToolMode } from '../../../../../../store/builder/store';
|
||||
import { useActiveTool, useDeletableFloorItem, useSelectedFloorItem, useToggleView } from '../../../../../../store/builder/store';
|
||||
import useModuleStore, { useSubModuleStore } from '../../../../../../store/useModuleStore';
|
||||
import { useSocketStore } from '../../../../../../store/builder/store';
|
||||
import { useSceneContext } from '../../../../../scene/sceneContext';
|
||||
@@ -14,60 +11,60 @@ import { useProductContext } from '../../../../../simulation/products/productCon
|
||||
import { useVersionContext } from '../../../../version/versionContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { getUserData } from '../../../../../../functions/getUserData';
|
||||
import { useLeftData, useTopData } from '../../../../../../store/visualization/useZone3DWidgetStore';
|
||||
import { useSelectedAsset } from '../../../../../../store/simulation/useSimulationStore';
|
||||
import { upsertProductOrEventApi } from '../../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
|
||||
// import { deleteFloorItem } from '../../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi';
|
||||
|
||||
export function useModelEventHandlers({
|
||||
controls,
|
||||
boundingBox,
|
||||
groupRef,
|
||||
toggleView,
|
||||
deletableFloorItem,
|
||||
setDeletableFloorItem,
|
||||
setSelectedFloorItem,
|
||||
gl,
|
||||
setTop,
|
||||
setLeft,
|
||||
getIsEventInProduct,
|
||||
getEventByModelUuid,
|
||||
setSelectedAsset,
|
||||
clearSelectedAsset,
|
||||
removeAsset,
|
||||
updateBackend,
|
||||
leftDrag,
|
||||
rightDrag
|
||||
}: {
|
||||
controls: CameraControls | any,
|
||||
boundingBox: THREE.Box3 | null,
|
||||
groupRef: React.RefObject<THREE.Group>,
|
||||
toggleView: boolean,
|
||||
deletableFloorItem: THREE.Object3D | null,
|
||||
setDeletableFloorItem: (item: THREE.Object3D | null) => void,
|
||||
setSelectedFloorItem: (item: THREE.Object3D | null) => void,
|
||||
gl: THREE.WebGLRenderer,
|
||||
setTop: (top: number) => void,
|
||||
setLeft: (left: number) => void,
|
||||
getIsEventInProduct: (productUuid: string, modelUuid: string) => boolean,
|
||||
getEventByModelUuid: (modelUuid: string) => EventsSchema | undefined,
|
||||
setSelectedAsset: (EventData: EventsSchema) => void,
|
||||
clearSelectedAsset: () => void,
|
||||
removeAsset: (modelUuid: string) => void,
|
||||
updateBackend: (productName: string, productUuid: string, projectId: string, event: EventsSchema) => void,
|
||||
leftDrag: React.MutableRefObject<boolean>,
|
||||
rightDrag: React.MutableRefObject<boolean>
|
||||
}) {
|
||||
|
||||
const { controls, gl } = useThree();
|
||||
const { activeTool } = useActiveTool();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toggleView } = useToggleView();
|
||||
const { subModule } = useSubModuleStore();
|
||||
const { socket } = useSocketStore();
|
||||
const { eventStore, productStore } = useSceneContext();
|
||||
const { eventStore, productStore, assetStore } = useSceneContext();
|
||||
const { removeAsset } = assetStore();
|
||||
const { removeEvent } = eventStore();
|
||||
const { getIsEventInProduct, addPoint, deleteEvent } = productStore();
|
||||
const { getEventByModelUuid } = eventStore();
|
||||
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization } = getUserData();
|
||||
const leftDrag = useRef(false);
|
||||
const isLeftMouseDown = useRef(false);
|
||||
const rightDrag = useRef(false);
|
||||
const isRightMouseDown = useRef(false);
|
||||
const { setTop } = useTopData();
|
||||
const { setLeft } = useLeftData();
|
||||
|
||||
const updateBackend = (
|
||||
productName: string,
|
||||
productUuid: string,
|
||||
projectId: string,
|
||||
eventData: EventsSchema
|
||||
) => {
|
||||
upsertProductOrEventApi({
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
const handleDblClick = (asset: Asset) => {
|
||||
if (asset && activeTool === "cursor" && boundingBox && groupRef.current && activeModule === 'builder') {
|
||||
@@ -117,8 +114,8 @@ export function useModelEventHandlers({
|
||||
|
||||
const response = socket.emit('v1:model-asset:delete', data)
|
||||
|
||||
eventStore.getState().removeEvent(asset.modelUuid);
|
||||
const updatedEvents = productStore.getState().deleteEvent(asset.modelUuid);
|
||||
removeEvent(asset.modelUuid);
|
||||
const updatedEvents = deleteEvent(asset.modelUuid);
|
||||
|
||||
updatedEvents.forEach((event) => {
|
||||
updateBackend(
|
||||
@@ -157,7 +154,7 @@ export function useModelEventHandlers({
|
||||
}
|
||||
}
|
||||
|
||||
const event = productStore.getState().addPoint(selectedProduct.productUuid, asset.modelUuid, conveyorPoint);
|
||||
const event = addPoint(selectedProduct.productUuid, asset.modelUuid, conveyorPoint);
|
||||
|
||||
if (event) {
|
||||
updateBackend(
|
||||
@@ -169,7 +166,6 @@ export function useModelEventHandlers({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -228,6 +224,50 @@ export function useModelEventHandlers({
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const onPointerDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown.current = true;
|
||||
leftDrag.current = false;
|
||||
}
|
||||
if (evt.button === 2) {
|
||||
isRightMouseDown.current = true;
|
||||
rightDrag.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onPointerMove = () => {
|
||||
if (isLeftMouseDown.current) {
|
||||
leftDrag.current = true;
|
||||
}
|
||||
if (isRightMouseDown.current) {
|
||||
rightDrag.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onPointerUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown.current = false;
|
||||
}
|
||||
if (evt.button === 2) {
|
||||
isRightMouseDown.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
canvasElement.addEventListener('pointerdown', onPointerDown);
|
||||
canvasElement.addEventListener('pointermove', onPointerMove);
|
||||
canvasElement.addEventListener('pointerup', onPointerUp);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener('pointerdown', onPointerDown);
|
||||
canvasElement.removeEventListener('pointermove', onPointerMove);
|
||||
canvasElement.removeEventListener('pointerup', onPointerUp);
|
||||
}
|
||||
|
||||
}, [gl])
|
||||
|
||||
return {
|
||||
handleDblClick,
|
||||
handleClick,
|
||||
|
||||
@@ -1,76 +1,34 @@
|
||||
import * as THREE from 'three';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||
import { useActiveTool, useDeletableFloorItem, useSelectedAssets, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { useDeletableFloorItem, useSelectedAssets, useSelectedFloorItem, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||
import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore';
|
||||
import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore';
|
||||
import { useProductContext } from '../../../../simulation/products/productContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { getUserData } from '../../../../../functions/getUserData';
|
||||
import useModuleStore from '../../../../../store/useModuleStore';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { useVersionContext } from '../../../version/versionContext';
|
||||
import { SkeletonUtils } from 'three-stdlib';
|
||||
|
||||
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs';
|
||||
import { ModelAnimator } from './animator/modelAnimator';
|
||||
import { useModelEventHandlers } from './eventHandlers/useEventHandlers';
|
||||
|
||||
function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendered: boolean, loader: GLTFLoader }) {
|
||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
const savedTheme: string = localStorage.getItem("theme") || "light";
|
||||
const { controls, gl } = useThree();
|
||||
const { activeTool } = useActiveTool();
|
||||
const { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
const { subModule } = useSubModuleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||
const { removeAsset, resetAnimation } = assetStore();
|
||||
const { setTop } = useTopData();
|
||||
const { setLeft } = useLeftData();
|
||||
const { getIsEventInProduct, addPoint } = productStore();
|
||||
const { getEventByModelUuid } = eventStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
const { socket } = useSocketStore();
|
||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { resetAnimation } = assetStore();
|
||||
const { setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const leftDrag = useRef(false);
|
||||
const isLeftMouseDown = useRef(false);
|
||||
const rightDrag = useRef(false);
|
||||
const isRightMouseDown = useRef(false);
|
||||
const [gltfScene, setGltfScene] = useState<GLTF["scene"] | null>(null);
|
||||
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
|
||||
const [isSelected, setIsSelected] = useState(false);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const [ikData, setIkData] = useState<any>();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { projectId } = useParams();
|
||||
const { selectedAssets } = useSelectedAssets();
|
||||
|
||||
const updateBackend = (
|
||||
productName: string,
|
||||
productUuid: string,
|
||||
projectId: string,
|
||||
eventData: EventsSchema
|
||||
) => {
|
||||
upsertProductOrEventApi({
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!ikData && asset.eventData && asset.eventData.type === 'ArmBot') {
|
||||
getAssetIksApi(asset.assetId).then((data) => {
|
||||
@@ -82,17 +40,6 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
}
|
||||
}, [asset.modelUuid, ikData])
|
||||
|
||||
useEffect(() => {
|
||||
if (gltfScene) {
|
||||
gltfScene.traverse((child: any) => {
|
||||
if (child.isMesh) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [gltfScene]);
|
||||
|
||||
useEffect(() => {
|
||||
setDeletableFloorItem(null);
|
||||
if (selectedFloorItem === null || selectedFloorItem.userData.modelUuid !== asset.modelUuid) {
|
||||
@@ -107,8 +54,34 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
}, [isRendered, selectedFloorItem])
|
||||
|
||||
useEffect(() => {
|
||||
const loadModel = async () => {
|
||||
try {
|
||||
if (selectedAssets.length > 0) {
|
||||
if (selectedAssets.some((selectedAsset: THREE.Object3D) => selectedAsset.userData.modelUuid === asset.modelUuid)) {
|
||||
setIsSelected(true);
|
||||
} else {
|
||||
setIsSelected(false);
|
||||
}
|
||||
} else {
|
||||
setIsSelected(false);
|
||||
}
|
||||
}, [selectedAssets])
|
||||
|
||||
useEffect(() => {
|
||||
if (gltfScene) {
|
||||
gltfScene.traverse((child: any) => {
|
||||
if (child.isMesh) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [gltfScene]);
|
||||
|
||||
useEffect(() => {
|
||||
// Calculate Bounding Box
|
||||
const calculateBoundingBox = (scene: THREE.Object3D) => {
|
||||
const box = new THREE.Box3().setFromObject(scene);
|
||||
setBoundingBox(box);
|
||||
};
|
||||
|
||||
// Check Cache
|
||||
const assetId = asset.assetId;
|
||||
@@ -122,10 +95,12 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
}
|
||||
|
||||
// Check IndexedDB
|
||||
const indexedDBModel = await retrieveGLTF(assetId);
|
||||
retrieveGLTF(assetId).then((indexedDBModel) => {
|
||||
if (indexedDBModel) {
|
||||
const blobUrl = URL.createObjectURL(indexedDBModel);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
loader.load(
|
||||
blobUrl,
|
||||
(gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(assetId, gltf);
|
||||
@@ -143,259 +118,35 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
|
||||
// Fetch from Backend
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${assetId}`;
|
||||
const handleBackendLoad = async (gltf: GLTF) => {
|
||||
try {
|
||||
const response = await fetch(modelUrl);
|
||||
const modelBlob = await response.blob();
|
||||
await storeGLTF(assetId, modelBlob);
|
||||
loader.load(
|
||||
modelUrl,
|
||||
(gltf: GLTF) => {
|
||||
fetch(modelUrl)
|
||||
.then((response) => response.blob())
|
||||
.then((modelBlob) => storeGLTF(assetId, modelBlob))
|
||||
.then(() => {
|
||||
THREE.Cache.add(assetId, gltf);
|
||||
setGltfScene(gltf.scene.clone());
|
||||
calculateBoundingBox(gltf.scene);
|
||||
} catch (error) {
|
||||
console.error(`[Backend] Error storing/loading ${asset.modelName}:`, error);
|
||||
}
|
||||
};
|
||||
loader.load(modelUrl,
|
||||
handleBackendLoad,
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
`[Backend] Error storing/loading ${asset.modelName}:`,
|
||||
error
|
||||
);
|
||||
});
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
echo.error(`[Backend] Error loading ${asset.modelName}:`);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
}).catch((err) => {
|
||||
console.error("Failed to load model:", asset.assetId, err);
|
||||
}
|
||||
};
|
||||
|
||||
const calculateBoundingBox = (scene: THREE.Object3D) => {
|
||||
const box = new THREE.Box3().setFromObject(scene);
|
||||
setBoundingBox(box);
|
||||
};
|
||||
|
||||
loadModel();
|
||||
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleDblClick = (asset: Asset) => {
|
||||
if (asset) {
|
||||
if (activeTool === "cursor" && boundingBox && groupRef.current && activeModule === 'builder') {
|
||||
const size = boundingBox.getSize(new THREE.Vector3());
|
||||
const center = boundingBox.getCenter(new THREE.Vector3());
|
||||
|
||||
const front = new THREE.Vector3(0, 0, 1);
|
||||
groupRef.current.localToWorld(front);
|
||||
front.sub(groupRef.current.position).normalize();
|
||||
|
||||
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||
const newPosition = center.clone().addScaledVector(front, distance);
|
||||
|
||||
(controls as CameraControls).setPosition(
|
||||
newPosition.x,
|
||||
newPosition.y,
|
||||
newPosition.z,
|
||||
true
|
||||
);
|
||||
(controls as CameraControls).setTarget(center.x, center.y, center.z, true);
|
||||
(controls as CameraControls).fitToBox(groupRef.current, true, {
|
||||
cover: true,
|
||||
paddingTop: 5,
|
||||
paddingLeft: 5,
|
||||
paddingBottom: 5,
|
||||
paddingRight: 5,
|
||||
});
|
||||
setSelectedFloorItem(groupRef.current);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = (evt: ThreeEvent<MouseEvent>, asset: Asset) => {
|
||||
if (leftDrag.current || toggleView) return;
|
||||
if (activeTool === 'delete' && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||
|
||||
//REST
|
||||
|
||||
// const response = await deleteFloorItem(organization, asset.modelUuid, asset.modelName);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
modelName: asset.modelName,
|
||||
socketId: socket.id,
|
||||
userId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId
|
||||
}
|
||||
|
||||
const response = socket.emit('v1:model-asset:delete', data)
|
||||
|
||||
eventStore.getState().removeEvent(asset.modelUuid);
|
||||
const updatedEvents = productStore.getState().deleteEvent(asset.modelUuid);
|
||||
|
||||
updatedEvents.forEach((event) => {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
})
|
||||
|
||||
if (response) {
|
||||
|
||||
removeAsset(asset.modelUuid);
|
||||
|
||||
echo.success("Model Removed!");
|
||||
}
|
||||
|
||||
} else if (activeModule === 'simulation' && subModule === "simulations" && activeTool === 'pen') {
|
||||
if (asset.eventData && asset.eventData.type === 'Conveyor') {
|
||||
const intersectedPoint = evt.point;
|
||||
const localPosition = groupRef.current?.worldToLocal(intersectedPoint.clone());
|
||||
if (localPosition) {
|
||||
const conveyorPoint: ConveyorPointSchema = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [localPosition?.x, localPosition?.y, localPosition?.z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: `Action 1`,
|
||||
actionType: 'default',
|
||||
material: 'Default Material',
|
||||
delay: 0,
|
||||
spawnInterval: 5,
|
||||
spawnCount: 1,
|
||||
triggers: []
|
||||
}
|
||||
}
|
||||
|
||||
const event = addPoint(selectedProduct.productUuid, asset.modelUuid, conveyorPoint);
|
||||
|
||||
if (event) {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const handlePointerOver = useCallback((asset: Asset) => {
|
||||
if (activeTool === "delete" && activeModule === 'builder') {
|
||||
if (deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||
return;
|
||||
} else {
|
||||
setDeletableFloorItem(groupRef.current);
|
||||
}
|
||||
}
|
||||
}, [activeTool, activeModule, deletableFloorItem]);
|
||||
|
||||
const handlePointerOut = useCallback((evt: ThreeEvent<MouseEvent>, asset: Asset) => {
|
||||
if (evt.intersections.length === 0 && activeTool === "delete" && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
}, [activeTool, deletableFloorItem]);
|
||||
|
||||
const handleContextMenu = (asset: Asset, evt: ThreeEvent<MouseEvent>) => {
|
||||
if (rightDrag.current || toggleView) return;
|
||||
if (activeTool === "cursor" && subModule === 'simulations') {
|
||||
if (asset.modelUuid) {
|
||||
const canvasElement = gl.domElement;
|
||||
const isInProduct = getIsEventInProduct(selectedProduct.productUuid, asset.modelUuid);
|
||||
if (isInProduct) {
|
||||
const event = getEventByModelUuid(asset.modelUuid);
|
||||
if (event) {
|
||||
setSelectedAsset(event);
|
||||
const canvasRect = canvasElement.getBoundingClientRect();
|
||||
const relativeX = evt.clientX - canvasRect.left;
|
||||
const relativeY = evt.clientY - canvasRect.top;
|
||||
setTop(relativeY);
|
||||
setLeft(relativeX);
|
||||
} else {
|
||||
clearSelectedAsset();
|
||||
}
|
||||
} else {
|
||||
const event = getEventByModelUuid(asset.modelUuid);
|
||||
if (event) {
|
||||
setSelectedAsset(event)
|
||||
const canvasRect = canvasElement.getBoundingClientRect();
|
||||
const relativeX = evt.clientX - canvasRect.left;
|
||||
const relativeY = evt.clientY - canvasRect.top;
|
||||
setTop(relativeY);
|
||||
setLeft(relativeX);
|
||||
} else {
|
||||
clearSelectedAsset()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clearSelectedAsset()
|
||||
}
|
||||
} else {
|
||||
clearSelectedAsset()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const onPointerDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown.current = true;
|
||||
leftDrag.current = false;
|
||||
}
|
||||
if (evt.button === 2) {
|
||||
isRightMouseDown.current = true;
|
||||
rightDrag.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onPointerMove = () => {
|
||||
if (isLeftMouseDown.current) {
|
||||
leftDrag.current = true;
|
||||
}
|
||||
if (isRightMouseDown.current) {
|
||||
rightDrag.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onPointerUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown.current = false;
|
||||
}
|
||||
if (evt.button === 2) {
|
||||
isRightMouseDown.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
canvasElement.addEventListener('pointerdown', onPointerDown);
|
||||
canvasElement.addEventListener('pointermove', onPointerMove);
|
||||
canvasElement.addEventListener('pointerup', onPointerUp);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener('pointerdown', onPointerDown);
|
||||
canvasElement.removeEventListener('pointermove', onPointerMove);
|
||||
canvasElement.removeEventListener('pointerup', onPointerUp);
|
||||
}
|
||||
|
||||
}, [gl])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAssets.length > 0) {
|
||||
if (selectedAssets.some((selectedAsset: THREE.Object3D) => selectedAsset.userData.modelUuid === asset.modelUuid)) {
|
||||
setIsSelected(true);
|
||||
} else {
|
||||
setIsSelected(false);
|
||||
}
|
||||
} else {
|
||||
setIsSelected(false);
|
||||
}
|
||||
}, [selectedAssets])
|
||||
const { handleDblClick, handleClick, handlePointerOver, handlePointerOut, handleContextMenu } = useModelEventHandlers({ boundingBox, groupRef });
|
||||
|
||||
return (
|
||||
<group
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { useThree, useFrame } from "@react-three/fiber";
|
||||
import { Group, Vector3 } from "three";
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import { useLimitDistance, useRenderDistance, useSelectedFloorItem } from '../../../../store/builder/store';
|
||||
import { useLimitDistance, useRenderDistance, useSelectedFloorItem, useToggleView } from '../../../../store/builder/store';
|
||||
import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
@@ -12,7 +12,7 @@ import { GLTFLoader } from "three/examples/jsm/Addons";
|
||||
const distanceWorker = new Worker(new URL("../../../../services/factoryBuilder/webWorkers/distanceWorker.js", import.meta.url));
|
||||
|
||||
function Models({ loader }: { loader: GLTFLoader }) {
|
||||
const { controls, camera, raycaster, pointer, gl } = useThree();
|
||||
const { controls, camera } = useThree();
|
||||
const assetGroupRef = useRef<Group>(null);
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets } = assetStore();
|
||||
@@ -43,28 +43,6 @@ function Models({ loader }: { loader: GLTFLoader }) {
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// const canvasElement = gl.domElement;
|
||||
|
||||
// const onClick = () => {
|
||||
// if (!assetGroupRef.current || assetGroupRef.current.children.length === 0) return;
|
||||
// raycaster.setFromCamera(pointer, camera);
|
||||
|
||||
// const intersects = raycaster.intersectObjects(assetGroupRef.current.children, true);
|
||||
|
||||
// if (intersects.length > 0) {
|
||||
// console.log('intersects: ', intersects);
|
||||
// }
|
||||
// }
|
||||
|
||||
// canvasElement.addEventListener('click', onClick);
|
||||
|
||||
// return () => {
|
||||
// canvasElement.removeEventListener('click', onClick);
|
||||
// }
|
||||
|
||||
}, [camera])
|
||||
|
||||
return (
|
||||
<group
|
||||
name='Asset Group'
|
||||
|
||||
@@ -140,7 +140,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
|
||||
const updatedWallAsset = updateWallAsset(wallAsset.modelUuid, {
|
||||
wallUuid: intersect.object.userData.wallUuid,
|
||||
position: [newPoint.x, wallAsset.wallAssetType === 'fixed-move' ? 0 : intersect.point.y, newPoint.z],
|
||||
position: [newPoint.x, wallAsset.wallAssetType === 'fixedMove' ? 0 : intersect.point.y, newPoint.z],
|
||||
rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
|
||||
});
|
||||
|
||||
@@ -190,7 +190,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
|
||||
updateWallAsset(wallAsset.modelUuid, {
|
||||
wallUuid: intersect.object.userData.wallUuid,
|
||||
position: [newPoint.x, wallAsset.wallAssetType === 'fixed-move' ? 0 : intersect.point.y, newPoint.z],
|
||||
position: [newPoint.x, wallAsset.wallAssetType === 'fixedMove' ? 0 : intersect.point.y, newPoint.z],
|
||||
rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ function WallAssetCreator() {
|
||||
modelName: selectedItem.name,
|
||||
modelUuid: MathUtils.generateUUID(),
|
||||
wallUuid: wall.wallUuid,
|
||||
wallAssetType: selectedItem.subCategory,
|
||||
wallAssetType: selectedItem.subType,
|
||||
assetId: selectedItem.id,
|
||||
position: [closestPoint.x, selectedItem.subCategory === "fixed-move" ? 0 : intersect.point.y, closestPoint.z],
|
||||
position: [closestPoint.x, selectedItem.subType === "fixedMove" ? 0 : intersect.point.y, closestPoint.z],
|
||||
rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
|
||||
@@ -39,10 +39,7 @@ const CopyPasteControls3D = ({
|
||||
const [isPasting, setIsPasting] = useState(false);
|
||||
const [relativePositions, setRelativePositions] = useState<THREE.Vector3[]>([]);
|
||||
const [centerOffset, setCenterOffset] = useState<THREE.Vector3 | null>(null);
|
||||
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({
|
||||
left: false,
|
||||
right: false,
|
||||
});
|
||||
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ left: false, right: false, });
|
||||
|
||||
const calculateRelativePositions = useCallback((objects: THREE.Object3D[]) => {
|
||||
if (objects.length === 0) return { center: new THREE.Vector3(), relatives: [] };
|
||||
@@ -227,6 +224,7 @@ const CopyPasteControls3D = ({
|
||||
|
||||
const eventData: any = {
|
||||
type: pastedAsset.userData.eventData.type,
|
||||
subType: pastedAsset.userData.eventData.subType,
|
||||
};
|
||||
|
||||
if (pastedAsset.userData.eventData.type === "Conveyor") {
|
||||
@@ -237,6 +235,7 @@ const CopyPasteControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: 'transfer',
|
||||
subType: pastedAsset.userData.eventData.subType || '',
|
||||
speed: 1,
|
||||
points: updatedEventData.points.map((point: any, index: number) => ({
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -269,6 +268,7 @@ const CopyPasteControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
subType: pastedAsset.userData.eventData.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -307,6 +307,7 @@ const CopyPasteControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
subType: pastedAsset.userData.eventData.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -341,6 +342,7 @@ const CopyPasteControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
subType: pastedAsset.userData.eventData.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
|
||||
@@ -369,6 +371,7 @@ const CopyPasteControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
subType: pastedAsset.userData.eventData.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
|
||||
@@ -396,6 +399,7 @@ const CopyPasteControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "human",
|
||||
subType: pastedAsset.userData.eventData.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -421,6 +425,36 @@ const CopyPasteControls3D = ({
|
||||
position: humanEvent.point.position,
|
||||
rotation: humanEvent.point.rotation
|
||||
};
|
||||
} else if (pastedAsset.userData.eventData.type === "Crane") {
|
||||
const craneEvent: CraneEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "crane",
|
||||
subType: pastedAsset.userData.eventData.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
|
||||
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndDrop",
|
||||
maxPickUpCount: 1,
|
||||
triggers: []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
addEvent(craneEvent);
|
||||
eventData.point = {
|
||||
uuid: craneEvent.point.uuid,
|
||||
position: craneEvent.point.position,
|
||||
rotation: craneEvent.point.rotation
|
||||
};
|
||||
}
|
||||
|
||||
newFloorItem.eventData = eventData;
|
||||
|
||||
@@ -37,10 +37,7 @@ const DuplicationControls3D = ({
|
||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
||||
const [isDuplicating, setIsDuplicating] = useState(false);
|
||||
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({
|
||||
left: false,
|
||||
right: false,
|
||||
});
|
||||
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ left: false, right: false, });
|
||||
|
||||
const calculateDragOffset = useCallback((point: THREE.Object3D, hitPoint: THREE.Vector3) => {
|
||||
const pointPosition = new THREE.Vector3().copy(point.position);
|
||||
@@ -228,6 +225,7 @@ const DuplicationControls3D = ({
|
||||
|
||||
const eventData: any = {
|
||||
type: duplicatedAsset.userData.eventData.type,
|
||||
subType: duplicatedAsset.userData.eventData.subType,
|
||||
};
|
||||
|
||||
if (duplicatedAsset.userData.eventData.type === "Conveyor") {
|
||||
@@ -238,6 +236,7 @@ const DuplicationControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: 'transfer',
|
||||
subType: duplicatedAsset.userData.eventData.subType || '',
|
||||
speed: 1,
|
||||
points: updatedEventData.points.map((point: any, index: number) => ({
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -270,6 +269,7 @@ const DuplicationControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
subType: duplicatedAsset.userData.eventData.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -308,6 +308,7 @@ const DuplicationControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
subType: duplicatedAsset.userData.eventData.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -342,6 +343,7 @@ const DuplicationControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
subType: duplicatedAsset.userData.eventData.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
|
||||
@@ -370,6 +372,7 @@ const DuplicationControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
subType: duplicatedAsset.userData.eventData.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
|
||||
@@ -397,6 +400,7 @@ const DuplicationControls3D = ({
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "human",
|
||||
subType: duplicatedAsset.userData.eventData.subType || '',
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -422,6 +426,36 @@ const DuplicationControls3D = ({
|
||||
position: humanEvent.point.position,
|
||||
rotation: humanEvent.point.rotation
|
||||
};
|
||||
} else if (duplicatedAsset.userData.eventData.type === "Crane") {
|
||||
const craneEvent: CraneEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "crane",
|
||||
subType: duplicatedAsset.userData.eventData.subType || '',
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
|
||||
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndDrop",
|
||||
maxPickUpCount: 1,
|
||||
triggers: []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
addEvent(craneEvent);
|
||||
eventData.point = {
|
||||
uuid: craneEvent.point.uuid,
|
||||
position: craneEvent.point.position,
|
||||
rotation: craneEvent.point.rotation
|
||||
};
|
||||
}
|
||||
|
||||
newFloorItem.eventData = eventData;
|
||||
|
||||
@@ -19,6 +19,7 @@ import { createConveyorStore, ConveyorStoreType } from '../../store/simulation/u
|
||||
import { createVehicleStore, VehicleStoreType } from '../../store/simulation/useVehicleStore';
|
||||
import { createStorageUnitStore, StorageUnitStoreType } from '../../store/simulation/useStorageUnitStore';
|
||||
import { createHumanStore, HumanStoreType } from '../../store/simulation/useHumanStore';
|
||||
import { createCraneStore, CraneStoreType } from '../../store/simulation/useCraneStore';
|
||||
|
||||
type SceneContextValue = {
|
||||
|
||||
@@ -41,6 +42,7 @@ type SceneContextValue = {
|
||||
vehicleStore: VehicleStoreType;
|
||||
storageUnitStore: StorageUnitStoreType;
|
||||
humanStore: HumanStoreType;
|
||||
craneStore: CraneStoreType;
|
||||
|
||||
humanEventManagerRef: React.RefObject<HumanEventManagerState>;
|
||||
|
||||
@@ -78,6 +80,7 @@ export function SceneProvider({
|
||||
const vehicleStore = useMemo(() => createVehicleStore(), []);
|
||||
const storageUnitStore = useMemo(() => createStorageUnitStore(), []);
|
||||
const humanStore = useMemo(() => createHumanStore(), []);
|
||||
const craneStore = useMemo(() => createCraneStore(), []);
|
||||
|
||||
const humanEventManagerRef = useRef<HumanEventManagerState>({ humanStates: [] });
|
||||
|
||||
@@ -98,8 +101,9 @@ export function SceneProvider({
|
||||
vehicleStore.getState().clearVehicles();
|
||||
storageUnitStore.getState().clearStorageUnits();
|
||||
humanStore.getState().clearHumans();
|
||||
craneStore.getState().clearCranes();
|
||||
humanEventManagerRef.current.humanStates = [];
|
||||
}, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, undoRedo2DStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore]);
|
||||
}, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, undoRedo2DStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore]);
|
||||
|
||||
const contextValue = useMemo(() => (
|
||||
{
|
||||
@@ -119,11 +123,12 @@ export function SceneProvider({
|
||||
vehicleStore,
|
||||
storageUnitStore,
|
||||
humanStore,
|
||||
craneStore,
|
||||
humanEventManagerRef,
|
||||
clearStores,
|
||||
layout
|
||||
}
|
||||
), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, undoRedo2DStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, clearStores, layout]);
|
||||
), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, undoRedo2DStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore, clearStores, layout]);
|
||||
|
||||
return (
|
||||
<SceneContext.Provider value={contextValue}>
|
||||
|
||||
15
app/src/modules/simulation/crane/crane.tsx
Normal file
15
app/src/modules/simulation/crane/crane.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
import CraneInstances from './instances/craneInstances'
|
||||
|
||||
function Crane() {
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<CraneInstances />
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Crane
|
||||
@@ -0,0 +1,133 @@
|
||||
import * as THREE from 'three';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
|
||||
function PillarJibAnimator({ crane }: { crane: CraneStatus }) {
|
||||
const { scene } = useThree();
|
||||
|
||||
useEffect(() => {
|
||||
const model = scene.getObjectByProperty('uuid', crane.modelUuid);
|
||||
|
||||
if (model) {
|
||||
const base = model.getObjectByName('base');
|
||||
const trolley = model.getObjectByName('trolley');
|
||||
const hook = model.getObjectByName('hook');
|
||||
|
||||
if (base && trolley && hook) {
|
||||
let trolleyDir = 1;
|
||||
let hookDir = 1;
|
||||
|
||||
const trolleySpeed = 0.01;
|
||||
const hookSpeed = 0.01;
|
||||
const rotationSpeed = 0.005;
|
||||
|
||||
const trolleyMinOffset = -1;
|
||||
const trolleyMaxOffset = 1.75;
|
||||
const hookMinOffset = 0.25;
|
||||
const hookMaxOffset = -1.5;
|
||||
|
||||
const originalTrolleyX = trolley.position.x;
|
||||
const originalHookY = hook.position.y;
|
||||
|
||||
const animate = () => {
|
||||
if (base) {
|
||||
base.rotation.y += rotationSpeed;
|
||||
}
|
||||
|
||||
if (trolley) {
|
||||
trolley.position.x += trolleyDir * trolleySpeed;
|
||||
if (trolley.position.x >= originalTrolleyX + trolleyMaxOffset ||
|
||||
trolley.position.x <= originalTrolleyX + trolleyMinOffset) {
|
||||
trolleyDir *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (hook) {
|
||||
hook.position.y += hookDir * hookSpeed;
|
||||
if (hook.position.y >= originalHookY + hookMinOffset ||
|
||||
hook.position.y <= originalHookY + hookMaxOffset) {
|
||||
hookDir *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
animate();
|
||||
}
|
||||
}
|
||||
}, [crane, scene]);
|
||||
|
||||
return (
|
||||
<PillarJibHelper crane={crane} />
|
||||
);
|
||||
}
|
||||
|
||||
export default PillarJibAnimator;
|
||||
|
||||
function PillarJibHelper({ crane }: { crane: CraneStatus }) {
|
||||
const { scene } = useThree();
|
||||
|
||||
const { geometry, position } = useMemo(() => {
|
||||
const model = scene.getObjectByProperty('uuid', crane.modelUuid);
|
||||
if (!model) return { geometry: null, position: null };
|
||||
|
||||
const base = model.getObjectByName('base');
|
||||
const trolley = model.getObjectByName('trolley');
|
||||
const hook = model.getObjectByName('hook');
|
||||
|
||||
if (!base || !trolley || !hook) return { geometry: null, position: null };
|
||||
|
||||
const baseWorld = new THREE.Vector3();
|
||||
base.getWorldPosition(baseWorld);
|
||||
|
||||
const trolleyWorld = new THREE.Vector3();
|
||||
trolley.getWorldPosition(trolleyWorld);
|
||||
|
||||
const hookWorld = new THREE.Vector3();
|
||||
hook.getWorldPosition(hookWorld);
|
||||
|
||||
const distFromBase = new THREE.Vector2(trolleyWorld.x - baseWorld.x, trolleyWorld.z - baseWorld.z).length();
|
||||
const outerRadius = distFromBase + 1.75;
|
||||
const innerRadius = Math.max(distFromBase - 1, 0.05);
|
||||
const height = (0.25 - (-1.5));
|
||||
const cylinderYPosition = hookWorld.y + (height / 2) + (-1.5 + 0.25) / 2;
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
shape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false);
|
||||
|
||||
const hole = new THREE.Path();
|
||||
hole.absarc(0, 0, innerRadius, 0, Math.PI * 2, true);
|
||||
shape.holes.push(hole);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: height,
|
||||
bevelEnabled: false,
|
||||
steps: 1
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const position: [number, number, number] = [baseWorld.x, cylinderYPosition, baseWorld.z];
|
||||
|
||||
return { geometry, position };
|
||||
}, [scene, crane.modelUuid]);
|
||||
|
||||
if (!geometry || !position) return null;
|
||||
|
||||
return (
|
||||
<mesh
|
||||
geometry={geometry}
|
||||
position={position}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={0x888888}
|
||||
metalness={0.5}
|
||||
roughness={0.4}
|
||||
side={THREE.DoubleSide}
|
||||
transparent={true}
|
||||
opacity={0.3}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from 'react'
|
||||
import PillarJibInstance from './instance/pillarJibInstance';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
function CraneInstances() {
|
||||
const { craneStore } = useSceneContext();
|
||||
const { cranes } = craneStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
{cranes.map((crane: CraneStatus) => (
|
||||
<React.Fragment key={crane.modelUuid}>
|
||||
|
||||
{crane.subType === "pillarJib" &&
|
||||
<PillarJibInstance crane={crane} />
|
||||
}
|
||||
|
||||
</React.Fragment>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default CraneInstances
|
||||
@@ -0,0 +1,14 @@
|
||||
import PillarJibAnimator from '../animator/pillarJibAnimator'
|
||||
|
||||
function PillarJibInstance({ crane }: { crane: CraneStatus }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<PillarJibAnimator crane={crane} />
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PillarJibInstance
|
||||
@@ -40,7 +40,7 @@ function PointsCalculator(
|
||||
}
|
||||
|
||||
return {
|
||||
points: [worldTopMiddle]
|
||||
points: [new THREE.Vector3(worldTopMiddle.x, worldTopMiddle.y + 0.1, worldTopMiddle.z)]
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ function PointInstances() {
|
||||
machine: "purple",
|
||||
storageUnit: "red",
|
||||
human: "white",
|
||||
crane: "yellow",
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -173,6 +173,22 @@ function TriggerConnector() {
|
||||
});
|
||||
});
|
||||
}
|
||||
// Handle Human point
|
||||
else if (event.type === "crane" && 'point' in event) {
|
||||
const point = event.point;
|
||||
point.actions?.forEach(action => {
|
||||
action.triggers?.forEach(trigger => {
|
||||
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
|
||||
newConnections.push({
|
||||
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
|
||||
startPointUuid: point.uuid,
|
||||
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
trigger
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
setConnections(newConnections);
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useParams } from 'react-router-dom';
|
||||
import { useVersionContext } from '../../builder/version/versionContext';
|
||||
|
||||
function Products() {
|
||||
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, layout, productStore } = useSceneContext();
|
||||
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore, layout, productStore } = useSceneContext();
|
||||
const { products, getProductById, addProduct, setProducts } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { setMainProduct } = useMainProduct();
|
||||
@@ -20,7 +20,8 @@ function Products() {
|
||||
const { addMachine, clearMachines } = machineStore();
|
||||
const { addConveyor, clearConveyors } = conveyorStore();
|
||||
const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore();
|
||||
const { addHuman, addCurrentAction, clearHumans } = humanStore();
|
||||
const { addHuman, addCurrentAction: addCurrentActionHuman, clearHumans } = humanStore();
|
||||
const { addCrane, addCurrentAction: addCurrentActionCrane, clearCranes } = craneStore();
|
||||
const { isReset } = useResetButtonStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { mainProduct } = useMainProduct();
|
||||
@@ -164,7 +165,25 @@ function Products() {
|
||||
addHuman(selectedProduct.productUuid, events);
|
||||
|
||||
if (events.point.actions.length > 0) {
|
||||
addCurrentAction(events.modelUuid, events.point.actions[0].actionUuid);
|
||||
addCurrentActionHuman(events.modelUuid, events.point.actions[0].actionUuid);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, products, isReset, isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProduct.productUuid) {
|
||||
const product = getProductById(selectedProduct.productUuid);
|
||||
if (product) {
|
||||
clearCranes();
|
||||
product.eventDatas.forEach(events => {
|
||||
if (events.type === 'crane') {
|
||||
addCrane(selectedProduct.productUuid, events);
|
||||
|
||||
if (events.point.actions.length > 0) {
|
||||
addCurrentActionCrane(events.modelUuid, events.point.actions[0].actionUuid);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import Materials from './materials/materials';
|
||||
import Machine from './machine/machine';
|
||||
import StorageUnit from './storageUnit/storageUnit';
|
||||
import Human from './human/human';
|
||||
import Crane from './crane/crane';
|
||||
import Simulator from './simulator/simulator';
|
||||
import Products from './products/products';
|
||||
import Trigger from './triggers/trigger';
|
||||
@@ -55,6 +56,8 @@ function Simulation() {
|
||||
|
||||
<Human />
|
||||
|
||||
<Crane />
|
||||
|
||||
<Simulator />
|
||||
|
||||
<SimulationAnalysis />
|
||||
|
||||
@@ -156,7 +156,7 @@ export const useSelectedItem = create<any>((set: any) => ({
|
||||
id: "",
|
||||
type: undefined,
|
||||
category: "",
|
||||
subCatergory: "",
|
||||
subType: "",
|
||||
},
|
||||
setSelectedItem: (x: any) => set(() => ({ selectedItem: x })),
|
||||
}));
|
||||
|
||||
263
app/src/store/simulation/useCraneStore.ts
Normal file
263
app/src/store/simulation/useCraneStore.ts
Normal file
@@ -0,0 +1,263 @@
|
||||
import { create } from "zustand";
|
||||
import { immer } from "zustand/middleware/immer";
|
||||
|
||||
interface CraneStore {
|
||||
cranes: CraneStatus[];
|
||||
|
||||
addCrane: (productUuid: string, event: CraneEventSchema) => void;
|
||||
removeCrane: (modelUuid: string) => void;
|
||||
updateCrane: (
|
||||
modelUuid: string,
|
||||
updates: Partial<Omit<CraneStatus, "modelUuid" | "productUuid">>
|
||||
) => void;
|
||||
clearCranes: () => void;
|
||||
|
||||
setCurrentPhase: (modelUuid: string, phase: string) => void;
|
||||
|
||||
addCurrentAction: (modelUuid: string, actionUuid: string) => void;
|
||||
removeCurrentAction: (modelUuid: string) => void;
|
||||
|
||||
setCraneActive: (modelUuid: string, isActive: boolean) => void;
|
||||
setCraneScheduled: (modelUuid: string, isScheduled: boolean) => void;
|
||||
setCraneLoad: (modelUuid: string, load: number) => void;
|
||||
setCraneState: (modelUuid: string, newState: CraneStatus["state"]) => void;
|
||||
incrementCraneLoad: (modelUuid: string, incrementBy: number) => void;
|
||||
decrementCraneLoad: (modelUuid: string, decrementBy: number) => void;
|
||||
|
||||
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
|
||||
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void;
|
||||
removeLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
|
||||
getLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
|
||||
clearCurrentMaterials: (modelUuid: string) => void;
|
||||
|
||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||
resetTime: (modelUuid: string) => void;
|
||||
|
||||
getCraneById: (modelUuid: string) => CraneStatus | undefined;
|
||||
getCranesByProduct: (productUuid: string) => CraneStatus[];
|
||||
getActiveCranes: () => CraneStatus[];
|
||||
}
|
||||
|
||||
export const createCraneStore = () => {
|
||||
return create<CraneStore>()(
|
||||
immer((set, get) => ({
|
||||
cranes: [],
|
||||
|
||||
addCrane: (productUuid, event) => {
|
||||
set((state) => {
|
||||
const exists = state.cranes.some(c => c.modelUuid === event.modelUuid);
|
||||
if (!exists) {
|
||||
state.cranes.push({
|
||||
...event,
|
||||
productUuid,
|
||||
currentPhase: 'init',
|
||||
isActive: false,
|
||||
isScheduled: false,
|
||||
idleTime: 0,
|
||||
activeTime: 0,
|
||||
currentLoad: 0,
|
||||
currentMaterials: []
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeCrane: (modelUuid) => {
|
||||
set((state) => {
|
||||
state.cranes = state.cranes.filter(c => c.modelUuid !== modelUuid);
|
||||
});
|
||||
},
|
||||
|
||||
updateCrane: (modelUuid, updates) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
Object.assign(crane, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
clearCranes: () => {
|
||||
set((state) => {
|
||||
state.cranes = [];
|
||||
});
|
||||
},
|
||||
|
||||
setCurrentPhase: (modelUuid, phase) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.currentPhase = phase;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
addCurrentAction: (modelUuid, actionUuid) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
const action = crane.point.actions.find(a => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
crane.currentAction = {
|
||||
actionUuid: action.actionUuid,
|
||||
actionName: action.actionName
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeCurrentAction: (modelUuid) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.currentAction = undefined;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setCraneActive: (modelUuid, isActive) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.isActive = isActive;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setCraneScheduled: (modelUuid, isScheduled) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.isScheduled = isScheduled;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setCraneLoad: (modelUuid, load) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.currentLoad = load;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setCraneState: (modelUuid, newState) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.state = newState;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
incrementCraneLoad: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.currentLoad += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
decrementCraneLoad: (modelUuid, decrementBy) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.currentLoad = Math.max(0, crane.currentLoad - decrementBy);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
addCurrentMaterial: (modelUuid, materialType, materialId) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.currentMaterials.push({ materialType, materialId });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setCurrentMaterials: (modelUuid, materials) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.currentMaterials = materials;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeLastMaterial: (modelUuid) => {
|
||||
let removed;
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane && crane.currentMaterials.length > 0) {
|
||||
removed = JSON.parse(JSON.stringify(crane.currentMaterials.pop()));
|
||||
}
|
||||
});
|
||||
return removed;
|
||||
},
|
||||
|
||||
getLastMaterial: (modelUuid) => {
|
||||
const crane = get().cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane && crane.currentMaterials.length > 0) {
|
||||
return crane.currentMaterials[crane.currentMaterials.length - 1];
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
clearCurrentMaterials: (modelUuid) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.currentMaterials = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.activeTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.idleTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
resetTime: (modelUuid) => {
|
||||
set((state) => {
|
||||
const crane = state.cranes.find(c => c.modelUuid === modelUuid);
|
||||
if (crane) {
|
||||
crane.activeTime = 0;
|
||||
crane.idleTime = 0;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getCraneById: (modelUuid) => {
|
||||
return get().cranes.find(c => c.modelUuid === modelUuid);
|
||||
},
|
||||
|
||||
getCranesByProduct: (productUuid) => {
|
||||
return get().cranes.filter(c => c.productUuid === productUuid);
|
||||
},
|
||||
|
||||
getActiveCranes: () => {
|
||||
return get().cranes.filter(c => c.isActive);
|
||||
}
|
||||
}))
|
||||
);
|
||||
};
|
||||
|
||||
export type CraneStoreType = ReturnType<typeof createCraneStore>;
|
||||
@@ -11,24 +11,24 @@ type EventsStore = {
|
||||
updateEvent: (modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
|
||||
addPoint: (modelUuid: string, point: PointsScheme) => void;
|
||||
removePoint: (modelUuid: string, pointUuid: string) => void;
|
||||
updatePoint: (
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
updates: Partial<ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema>
|
||||
updates: Partial<PointsScheme>
|
||||
) => EventsSchema | undefined;
|
||||
|
||||
// Action-level actions
|
||||
addAction: (
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
|
||||
action: ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction | CraneAction
|
||||
) => void;
|
||||
removeAction: (actionUuid: string) => void;
|
||||
updateAction: (
|
||||
actionUuid: string,
|
||||
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
|
||||
updates: Partial<ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction | CraneAction>
|
||||
) => void;
|
||||
|
||||
// Trigger-level actions
|
||||
@@ -38,8 +38,8 @@ type EventsStore = {
|
||||
|
||||
// Helper functions
|
||||
getEventByModelUuid: (modelUuid: string) => EventsSchema | undefined;
|
||||
getPointByUuid: (modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
|
||||
getActionByUuid: (actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
||||
getPointByUuid: (modelUuid: string, pointUuid: string) => PointsScheme | undefined;
|
||||
getActionByUuid: (actionUuid: string) => (ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction | CraneAction) | undefined;
|
||||
getTriggerByUuid: (triggerUuid: string) => TriggerSchema | undefined;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ type ProductsStore = {
|
||||
updateEvent: (productUuid: string, modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (productUuid: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema) => EventsSchema | undefined;
|
||||
addPoint: (productUuid: string, modelUuid: string, point: PointsScheme) => EventsSchema | undefined;
|
||||
removePoint: (productUuid: string, modelUuid: string, pointUuid: string) => EventsSchema | undefined;
|
||||
updatePoint: (
|
||||
productUuid: string,
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
updates: Partial<ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema>
|
||||
updates: Partial<PointsScheme>
|
||||
) => EventsSchema | undefined;
|
||||
|
||||
// Action-level actions
|
||||
@@ -32,13 +32,13 @@ type ProductsStore = {
|
||||
productUuid: string,
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]
|
||||
action: ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction | CraneAction
|
||||
) => EventsSchema | undefined;
|
||||
removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
|
||||
updateAction: (
|
||||
productUuid: string,
|
||||
actionUuid: string,
|
||||
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]>
|
||||
updates: Partial<ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction | CraneAction>
|
||||
) => EventsSchema | undefined;
|
||||
|
||||
// Trigger-level actionss
|
||||
@@ -65,9 +65,9 @@ type ProductsStore = {
|
||||
getEventByActionUuid: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
|
||||
getEventByTriggerUuid: (productUuid: string, triggerUuid: string) => EventsSchema | undefined;
|
||||
getEventByPointUuid: (productUuid: string, pointUuid: string) => EventsSchema | undefined;
|
||||
getPointByUuid: (productUuid: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema | undefined;
|
||||
getActionByUuid: (productUuid: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]) | undefined;
|
||||
getActionByPointUuid: (productUuid: string, pointUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]) | undefined;
|
||||
getPointByUuid: (productUuid: string, modelUuid: string, pointUuid: string) => PointsScheme | undefined;
|
||||
getActionByUuid: (productUuid: string, actionUuid: string) => (ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction | CraneAction) | undefined;
|
||||
getActionByPointUuid: (productUuid: string, pointUuid: string) => (ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction | CraneAction) | undefined;
|
||||
getModelUuidByPointUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
||||
getModelUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
||||
getPointUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
||||
@@ -375,6 +375,15 @@ export const createProductStore = () => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (event.type === "crane") {
|
||||
if ('actions' in point) {
|
||||
const index = point.actions.findIndex((a: any) => a.actionUuid === actionUuid);
|
||||
if (index !== -1) {
|
||||
point.actions.splice(index, 1);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
point.action = undefined;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
|
||||
1
app/src/types/builderTypes.d.ts
vendored
1
app/src/types/builderTypes.d.ts
vendored
@@ -32,6 +32,7 @@ interface Asset {
|
||||
};
|
||||
eventData?: {
|
||||
type: string;
|
||||
subType: string;
|
||||
point?: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
|
||||
104
app/src/types/simulationTypes.d.ts
vendored
104
app/src/types/simulationTypes.d.ts
vendored
@@ -1,4 +1,5 @@
|
||||
// Base Types
|
||||
|
||||
interface AssetEventSchema {
|
||||
modelUuid: string;
|
||||
modelName: string;
|
||||
@@ -19,7 +20,9 @@ interface TriggerSchema {
|
||||
} | null;
|
||||
}
|
||||
|
||||
|
||||
// Actions
|
||||
|
||||
interface ConveyorAction {
|
||||
actionUuid: string;
|
||||
actionName: string;
|
||||
@@ -107,9 +110,19 @@ interface HumanAction {
|
||||
triggers: TriggerSchema[];
|
||||
}
|
||||
|
||||
type Action = ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction;
|
||||
interface CraneAction {
|
||||
actionUuid: string;
|
||||
actionName: string;
|
||||
actionType: "pickAndDrop";
|
||||
maxPickUpCount: number;
|
||||
triggers: TriggerSchema[];
|
||||
}
|
||||
|
||||
type Action = ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction | CraneAction;
|
||||
|
||||
|
||||
// Points
|
||||
|
||||
interface ConveyorPointSchema {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
@@ -152,46 +165,69 @@ interface HumanPointSchema {
|
||||
actions: HumanAction[];
|
||||
}
|
||||
|
||||
type PointsScheme = | ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema;
|
||||
interface CranePointSchema {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: CraneAction[];
|
||||
}
|
||||
|
||||
type PointsScheme = | ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema | CranePointSchema;
|
||||
|
||||
|
||||
// Events
|
||||
|
||||
interface ConveyorEventSchema extends AssetEventSchema {
|
||||
type: "transfer";
|
||||
subType: string;
|
||||
speed: number;
|
||||
points: ConveyorPointSchema[];
|
||||
}
|
||||
|
||||
interface VehicleEventSchema extends AssetEventSchema {
|
||||
type: "vehicle";
|
||||
subType: "manual" | "automatic" | "semiAutomatic" | '';
|
||||
speed: number;
|
||||
point: VehiclePointSchema;
|
||||
}
|
||||
|
||||
interface RoboticArmEventSchema extends AssetEventSchema {
|
||||
type: "roboticArm";
|
||||
subType: string;
|
||||
speed: number;
|
||||
point: RoboticArmPointSchema;
|
||||
}
|
||||
|
||||
interface MachineEventSchema extends AssetEventSchema {
|
||||
type: "machine";
|
||||
subType: string;
|
||||
point: MachinePointSchema;
|
||||
}
|
||||
|
||||
interface StorageEventSchema extends AssetEventSchema {
|
||||
type: "storageUnit";
|
||||
subType: string;
|
||||
point: StoragePointSchema;
|
||||
}
|
||||
|
||||
interface HumanEventSchema extends AssetEventSchema {
|
||||
type: "human";
|
||||
subType: string;
|
||||
speed: number;
|
||||
point: HumanPointSchema;
|
||||
}
|
||||
|
||||
type EventsSchema = | ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema | HumanEventSchema;
|
||||
interface CraneEventSchema extends AssetEventSchema {
|
||||
type: "crane";
|
||||
subType: "pillarJib" | '';
|
||||
point: CranePointSchema;
|
||||
}
|
||||
|
||||
type EventsSchema = | ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema | HumanEventSchema | CraneEventSchema;
|
||||
|
||||
|
||||
// Statuses
|
||||
|
||||
interface ConveyorStatus extends ConveyorEventSchema {
|
||||
productUuid: string;
|
||||
isActive: boolean;
|
||||
@@ -262,6 +298,24 @@ interface HumanStatus extends HumanEventSchema {
|
||||
};
|
||||
}
|
||||
|
||||
interface CraneStatus extends CraneEventSchema {
|
||||
productUuid: string;
|
||||
currentPhase: string;
|
||||
isActive: boolean;
|
||||
isScheduled: boolean;
|
||||
idleTime: number;
|
||||
activeTime: number;
|
||||
currentLoad: number;
|
||||
currentMaterials: { materialType: string; materialId: string; }[];
|
||||
currentAction?: {
|
||||
actionUuid: string;
|
||||
actionName: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Event Manager
|
||||
|
||||
type HumanEventState = {
|
||||
humanId: string;
|
||||
actionQueue: {
|
||||
@@ -282,7 +336,9 @@ type HumanEventManagerState = {
|
||||
humanStates: HumanEventState[];
|
||||
};
|
||||
|
||||
|
||||
// Materials
|
||||
|
||||
interface MaterialSchema {
|
||||
materialId: string;
|
||||
materialName: string;
|
||||
@@ -316,14 +372,18 @@ interface MaterialSchema {
|
||||
|
||||
type MaterialsSchema = MaterialSchema[];
|
||||
|
||||
|
||||
// Products
|
||||
|
||||
type productsSchema = {
|
||||
productName: string;
|
||||
productUuid: string;
|
||||
eventDatas: EventsSchema[];
|
||||
}[];
|
||||
|
||||
|
||||
// Material History
|
||||
|
||||
interface MaterialHistoryEntry {
|
||||
material: MaterialSchema;
|
||||
removedAt: string;
|
||||
@@ -331,7 +391,8 @@ interface MaterialHistoryEntry {
|
||||
|
||||
type MaterialHistorySchema = MaterialHistoryEntry[];
|
||||
|
||||
//IK
|
||||
|
||||
// IK Constraints
|
||||
|
||||
type Link = {
|
||||
index: number;
|
||||
@@ -350,3 +411,38 @@ type IK = {
|
||||
maxheight?: number;
|
||||
minheight?: number;
|
||||
};
|
||||
|
||||
// Conveyor Spline Points
|
||||
|
||||
type NormalConveyor = {
|
||||
type: 'normal';
|
||||
points: [number, number, number][][];
|
||||
}
|
||||
|
||||
type YJunctionConveyor = {
|
||||
type: 'y-junction';
|
||||
points: [number, number, number][][];
|
||||
}
|
||||
|
||||
type CurvedConveyor = {
|
||||
type: 'curved';
|
||||
points: [number, number, number][][];
|
||||
}
|
||||
|
||||
type ConveyorPoints = NormalConveyor | YJunctionConveyor | CurvedConveyor;
|
||||
|
||||
|
||||
// Crane Constraints
|
||||
|
||||
|
||||
type PillarJibCrane = {
|
||||
trolleySpeed: number;
|
||||
hookSpeed: number;
|
||||
rotationSpeed: number;
|
||||
trolleyMinOffset: number
|
||||
trolleyMaxOffset: number;
|
||||
hookMinOffset: number;
|
||||
hookMaxOffset: number;
|
||||
}
|
||||
|
||||
type CraneConstraints = PillarJibCrane;
|
||||
3
app/src/types/world/worldTypes.d.ts
vendored
3
app/src/types/world/worldTypes.d.ts
vendored
@@ -198,6 +198,7 @@ export type FloorItemType = {
|
||||
isVisible: boolean;
|
||||
eventData?: {
|
||||
type: string;
|
||||
subType: string;
|
||||
point?: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
@@ -221,7 +222,7 @@ export type setFloorItemSetState = React.Dispatch<React.SetStateAction<FloorItem
|
||||
|
||||
// Configuration for wall items, including model, scale, position, and rotation
|
||||
interface WallItem {
|
||||
type: "fixed-move" | "free-move" | undefined;
|
||||
type: "fixedMove" | "freeMove" | undefined;
|
||||
model?: THREE.Group;
|
||||
modelUuid?: string;
|
||||
assetId: string;
|
||||
|
||||
Reference in New Issue
Block a user