feat: Enhance simulation event handling and material management with new components and state management
This commit is contained in:
parent
6f93fc36c2
commit
22fb00f731
|
@ -8,10 +8,12 @@ import * as Types from "../../../types/world/worldTypes";
|
||||||
import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
|
import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
|
||||||
import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
|
import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
|
||||||
import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
||||||
|
import PointsCalculator from '../../simulation/events/points/functions/pointsCalculator';
|
||||||
|
|
||||||
async function loadInitialFloorItems(
|
async function loadInitialFloorItems(
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
|
addEvent: (event: EventsSchema) => void,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!itemsGroup.current) return;
|
if (!itemsGroup.current) return;
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
@ -70,7 +72,7 @@ async function loadInitialFloorItems(
|
||||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||||
if (cachedModel) {
|
if (cachedModel) {
|
||||||
// console.log(`[Cache] Fetching ${item.modelname}`);
|
// console.log(`[Cache] Fetching ${item.modelname}`);
|
||||||
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
return;
|
return;
|
||||||
|
@ -85,7 +87,7 @@ async function loadInitialFloorItems(
|
||||||
URL.revokeObjectURL(blobUrl);
|
URL.revokeObjectURL(blobUrl);
|
||||||
THREE.Cache.remove(blobUrl);
|
THREE.Cache.remove(blobUrl);
|
||||||
THREE.Cache.add(item.modelfileID!, gltf);
|
THREE.Cache.add(item.modelfileID!, gltf);
|
||||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
},
|
},
|
||||||
|
@ -106,7 +108,7 @@ async function loadInitialFloorItems(
|
||||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||||
await storeGLTF(item.modelfileID!, modelBlob);
|
await storeGLTF(item.modelfileID!, modelBlob);
|
||||||
THREE.Cache.add(item.modelfileID!, gltf);
|
THREE.Cache.add(item.modelfileID!, gltf);
|
||||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
},
|
},
|
||||||
|
@ -148,8 +150,9 @@ function processLoadedModel(
|
||||||
item: Types.FloorItemType,
|
item: Types.FloorItemType,
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
|
addEvent: (event: EventsSchema) => void,
|
||||||
) {
|
) {
|
||||||
const model = gltf;
|
const model = gltf.clone();
|
||||||
model.uuid = item.modeluuid;
|
model.uuid = item.modeluuid;
|
||||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||||
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
|
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
|
||||||
|
@ -182,6 +185,178 @@ function processLoadedModel(
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (item.modelfileID === "a1ee92554935007b10b3eb05") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'Vehicle',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const vehicleEvent: VehicleEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "vehicle",
|
||||||
|
speed: 1,
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Vehicle Action",
|
||||||
|
actionType: "travel",
|
||||||
|
material: null,
|
||||||
|
unLoadDuration: 5,
|
||||||
|
loadCapacity: 10,
|
||||||
|
pickUpPoint: null,
|
||||||
|
unLoadPoint: null,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addEvent(vehicleEvent);
|
||||||
|
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'Conveyor',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "transfer",
|
||||||
|
speed: 1,
|
||||||
|
points: data.points.map((point: THREE.Vector3, index: number) => ({
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [point.x, point.y, point.z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: `Action ${index}`,
|
||||||
|
actionType: 'default',
|
||||||
|
material: 'inherit',
|
||||||
|
delay: 0,
|
||||||
|
spawnInterval: 5,
|
||||||
|
spawnCount: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
addEvent(ConveyorEvent);
|
||||||
|
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'Conveyor',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "transfer",
|
||||||
|
speed: 1,
|
||||||
|
points: data.points.map((point: THREE.Vector3, index: number) => ({
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [point.x, point.y, point.z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: `Action ${index}`,
|
||||||
|
actionType: 'default',
|
||||||
|
material: 'inherit',
|
||||||
|
delay: 0,
|
||||||
|
spawnInterval: 5,
|
||||||
|
spawnCount: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
addEvent(ConveyorEvent);
|
||||||
|
} else if (item.modelfileID === "29dee78715ad5b853f5c346d") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'StaticMachine',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const machineEvent: MachineEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "machine",
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Process Action",
|
||||||
|
actionType: "process",
|
||||||
|
processTime: 10,
|
||||||
|
swapMaterial: "material-id",
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addEvent(machineEvent);
|
||||||
|
} else if (item.modelfileID === "52e6681fbb743a890d96c914") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'ArmBot',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const roboticArmEvent: RoboticArmEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "roboticArm",
|
||||||
|
speed: 1,
|
||||||
|
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: "Pick and Place",
|
||||||
|
actionType: "pickAndPlace",
|
||||||
|
process: {
|
||||||
|
startPoint: [0, 0, 0],
|
||||||
|
endPoint: [0, 0, 0]
|
||||||
|
},
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addEvent(roboticArmEvent);
|
||||||
|
}
|
||||||
|
|
||||||
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
||||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
|
||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||||
import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import PointsCalculator from '../../../simulation/events/points/pointsCalculator';
|
import PointsCalculator from '../../../simulation/events/points/functions/pointsCalculator';
|
||||||
|
|
||||||
async function addAssetModel(
|
async function addAssetModel(
|
||||||
raycaster: THREE.Raycaster,
|
raycaster: THREE.Raycaster,
|
||||||
|
@ -266,7 +266,7 @@ async function handleModelLoad(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
addEvent(roboticArmEvent);
|
addEvent(roboticArmEvent);
|
||||||
} else if (selectedItem.type === "Machine") {
|
} else if (selectedItem.type === "StaticMachine") {
|
||||||
const machineEvent: MachineEventSchema = {
|
const machineEvent: MachineEventSchema = {
|
||||||
modelUuid: newFloorItem.modeluuid,
|
modelUuid: newFloorItem.modeluuid,
|
||||||
modelName: newFloorItem.modelname,
|
modelName: newFloorItem.modelname,
|
||||||
|
|
|
@ -75,7 +75,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
||||||
gltfLoaderWorker.postMessage({ floorItems: data });
|
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||||
} else {
|
} else {
|
||||||
gltfLoaderWorker.postMessage({ floorItems: [] });
|
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
loadInitialFloorItems(itemsGroup, setFloorItems, addEvent);
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -94,7 +94,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
||||||
updateLoadingProgress(progress);
|
updateLoadingProgress(progress);
|
||||||
|
|
||||||
if (loadedAssets === totalAssets) {
|
if (loadedAssets === totalAssets) {
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
loadInitialFloorItems(itemsGroup, setFloorItems, addEvent);
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,90 +2,107 @@ import * as THREE from "three";
|
||||||
import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing";
|
import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing";
|
||||||
import { BlendFunction } from "postprocessing";
|
import { BlendFunction } from "postprocessing";
|
||||||
import {
|
import {
|
||||||
useDeletableFloorItem,
|
useDeletableFloorItem,
|
||||||
useSelectedWallItem,
|
useSelectedWallItem,
|
||||||
useSelectedFloorItem,
|
useSelectedFloorItem,
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
import * as Types from "../../../types/world/worldTypes";
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
||||||
|
|
||||||
export default function PostProcessing() {
|
export default function PostProcessing() {
|
||||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
|
||||||
function flattenChildren(children: any[]) {
|
function flattenChildren(children: any[]) {
|
||||||
const allChildren: any[] = [];
|
const allChildren: any[] = [];
|
||||||
children.forEach((child) => {
|
children.forEach((child) => {
|
||||||
allChildren.push(child);
|
allChildren.push(child);
|
||||||
if (child.children && child.children.length > 0) {
|
if (child.children && child.children.length > 0) {
|
||||||
allChildren.push(...flattenChildren(child.children));
|
allChildren.push(...flattenChildren(child.children));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return allChildren;
|
return allChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<EffectComposer autoClear={false}>
|
<EffectComposer autoClear={false}>
|
||||||
<N8AO
|
<N8AO
|
||||||
color="black"
|
color="black"
|
||||||
aoRadius={20}
|
aoRadius={20}
|
||||||
intensity={7}
|
intensity={7}
|
||||||
distanceFalloff={4}
|
distanceFalloff={4}
|
||||||
aoSamples={32}
|
aoSamples={32}
|
||||||
denoiseRadius={6}
|
denoiseRadius={6}
|
||||||
denoiseSamples={16}
|
denoiseSamples={16}
|
||||||
/>
|
/>
|
||||||
{deletableFloorItem && (
|
{deletableFloorItem && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={flattenChildren(deletableFloorItem.children)}
|
selection={flattenChildren(deletableFloorItem.children)}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={3000}
|
width={3000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
edgeStrength={5}
|
edgeStrength={5}
|
||||||
resolutionScale={2}
|
resolutionScale={2}
|
||||||
pulseSpeed={0}
|
pulseSpeed={0}
|
||||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
||||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
hiddenEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
||||||
blur={true}
|
blur={true}
|
||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{selectedWallItem && (
|
{selectedWallItem && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={selectedWallItem.children[1].children[0].children.filter(
|
selection={selectedWallItem.children[1].children[0].children.filter(
|
||||||
(child: Types.Mesh) => child.name !== "CSG_REF"
|
(child: Types.Mesh) => child.name !== "CSG_REF"
|
||||||
)}
|
)}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={3000}
|
width={3000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
edgeStrength={5}
|
edgeStrength={5}
|
||||||
resolutionScale={2}
|
resolutionScale={2}
|
||||||
pulseSpeed={0}
|
pulseSpeed={0}
|
||||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
blur={true}
|
blur={true}
|
||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{selectedFloorItem && (
|
{selectedFloorItem && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={flattenChildren(selectedFloorItem.children)}
|
selection={flattenChildren(selectedFloorItem.children)}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={3000}
|
width={3000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
edgeStrength={5}
|
edgeStrength={5}
|
||||||
resolutionScale={2}
|
resolutionScale={2}
|
||||||
pulseSpeed={0}
|
pulseSpeed={0}
|
||||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
blur={true}
|
blur={true}
|
||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</EffectComposer>
|
{selectedEventSphere && (
|
||||||
</>
|
<Outline
|
||||||
);
|
selection={[selectedEventSphere]}
|
||||||
|
selectionLayer={10}
|
||||||
|
width={1000}
|
||||||
|
blendFunction={BlendFunction.ALPHA}
|
||||||
|
edgeStrength={10}
|
||||||
|
resolutionScale={2}
|
||||||
|
pulseSpeed={0}
|
||||||
|
visibleEdgeColor={0x6f42c1}
|
||||||
|
hiddenEdgeColor={0x6f42c1}
|
||||||
|
blur={true}
|
||||||
|
xRay={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</EffectComposer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,20 +4,20 @@ import { useEventsStore } from '../../../../../store/simulation/useEventsStore';
|
||||||
import useModuleStore from '../../../../../store/useModuleStore';
|
import useModuleStore from '../../../../../store/useModuleStore';
|
||||||
import { TransformControls } from '@react-three/drei';
|
import { TransformControls } from '@react-three/drei';
|
||||||
import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys';
|
import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys';
|
||||||
|
import { useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
||||||
|
|
||||||
function PointsCreator() {
|
function PointsCreator() {
|
||||||
const { events, updatePoint, getPointByUuid } = useEventsStore();
|
const { events, updatePoint, getPointByUuid } = useEventsStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const transformRef = useRef<any>(null);
|
const transformRef = useRef<any>(null);
|
||||||
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
||||||
const [selectedPoint, setSelectedPoint] = useState<THREE.Mesh | null>(null);
|
|
||||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||||
|
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTransformMode(null);
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
const keyCombination = detectModifierKeys(e);
|
const keyCombination = detectModifierKeys(e);
|
||||||
if (!selectedPoint) return;
|
if (!selectedEventSphere) return;
|
||||||
if (keyCombination === "G") {
|
if (keyCombination === "G") {
|
||||||
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,13 @@ function PointsCreator() {
|
||||||
|
|
||||||
window.addEventListener("keydown", handleKeyDown);
|
window.addEventListener("keydown", handleKeyDown);
|
||||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||||
}, [selectedPoint]);
|
}, [selectedEventSphere]);
|
||||||
|
|
||||||
const updatePointToState = (selectedPoint: THREE.Mesh) => {
|
const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
|
||||||
let point = JSON.parse(JSON.stringify(getPointByUuid(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid)));
|
let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid)));
|
||||||
if (point) {
|
if (point) {
|
||||||
point.position = [selectedPoint.position.x, selectedPoint.position.y, selectedPoint.position.z];
|
point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z];
|
||||||
updatePoint(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid, point)
|
updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,10 +53,11 @@ function PointsCreator() {
|
||||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPoint(sphereRefs.current[point.uuid]);
|
setSelectedEventSphere(sphereRefs.current[point.uuid]);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPoint(null);
|
clearSelectedEventSphere();
|
||||||
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
key={`${i}-${j}`}
|
key={`${i}-${j}`}
|
||||||
position={new THREE.Vector3(...point.position)}
|
position={new THREE.Vector3(...point.position)}
|
||||||
|
@ -76,10 +77,11 @@ function PointsCreator() {
|
||||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPoint(sphereRefs.current[event.point.uuid]);
|
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPoint(null);
|
clearSelectedEventSphere();
|
||||||
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
position={new THREE.Vector3(...event.point.position)}
|
position={new THREE.Vector3(...event.point.position)}
|
||||||
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
||||||
|
@ -97,10 +99,11 @@ function PointsCreator() {
|
||||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPoint(sphereRefs.current[event.point.uuid]);
|
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPoint(null);
|
clearSelectedEventSphere();
|
||||||
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
position={new THREE.Vector3(...event.point.position)}
|
position={new THREE.Vector3(...event.point.position)}
|
||||||
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
||||||
|
@ -118,10 +121,11 @@ function PointsCreator() {
|
||||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPoint(sphereRefs.current[event.point.uuid]);
|
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPoint(null);
|
clearSelectedEventSphere();
|
||||||
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
position={new THREE.Vector3(...event.point.position)}
|
position={new THREE.Vector3(...event.point.position)}
|
||||||
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
||||||
|
@ -136,8 +140,8 @@ function PointsCreator() {
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
{(selectedPoint && transformMode) &&
|
{(selectedEventSphere && transformMode) &&
|
||||||
<TransformControls ref={transformRef} object={selectedPoint} mode={transformMode} onMouseUp={(e) => { updatePointToState(selectedPoint) }} />
|
<TransformControls ref={transformRef} object={selectedEventSphere} mode={transformMode} onMouseUp={(e) => { updatePointToState(selectedEventSphere) }} />
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Group } from '../../../../types/world/worldTypes';
|
import { Group } from '../../../../../types/world/worldTypes';
|
||||||
|
|
||||||
function PointsCalculator(
|
function PointsCalculator(
|
||||||
type: string,
|
type: string,
|
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function MachineInstance() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MachineInstance
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import MachineInstance from './machineInstance/machineInstance'
|
||||||
|
|
||||||
|
function MachineInstances() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<MachineInstance />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MachineInstances
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import MachineInstances from './instances/machineInstances'
|
||||||
|
|
||||||
|
function Machine() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<MachineInstances />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Machine
|
|
@ -5,6 +5,9 @@ import Vehicles from './vehicle/vehicles';
|
||||||
import Points from './events/points/points';
|
import Points from './events/points/points';
|
||||||
import Conveyor from './conveyor/conveyor';
|
import Conveyor from './conveyor/conveyor';
|
||||||
import RoboticArm from './roboticArm/roboticArm';
|
import RoboticArm from './roboticArm/roboticArm';
|
||||||
|
import Materials from './materials/materials';
|
||||||
|
import Machine from './machine/machine';
|
||||||
|
import StorageUnit from './storageUnit/storageUnit';
|
||||||
|
|
||||||
function Simulation() {
|
function Simulation() {
|
||||||
const { events } = useEventsStore();
|
const { events } = useEventsStore();
|
||||||
|
@ -23,11 +26,17 @@ function Simulation() {
|
||||||
|
|
||||||
<Points />
|
<Points />
|
||||||
|
|
||||||
|
<Materials />
|
||||||
|
|
||||||
|
<Conveyor />
|
||||||
|
|
||||||
<Vehicles />
|
<Vehicles />
|
||||||
|
|
||||||
<RoboticArm />
|
<RoboticArm />
|
||||||
|
|
||||||
<Conveyor />
|
<Machine />
|
||||||
|
|
||||||
|
<StorageUnit />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function storageUnitInstance() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default storageUnitInstance
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import StorageUnitInstance from './storageUnitInstance/storageUnitInstance'
|
||||||
|
|
||||||
|
function StorageUnitInstances() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<StorageUnitInstance />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StorageUnitInstances
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import StorageUnitInstances from './instances/storageUnitInstances'
|
||||||
|
|
||||||
|
function StorageUnit() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<StorageUnitInstances />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StorageUnit
|
|
@ -0,0 +1,76 @@
|
||||||
|
import { create } from 'zustand';
|
||||||
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
|
type MaterialsStore = {
|
||||||
|
materials: MaterialsSchema;
|
||||||
|
|
||||||
|
addMaterial: (material: MaterialSchema) => void;
|
||||||
|
removeMaterial: (materialId: string) => void;
|
||||||
|
updateMaterial: (materialId: string, updates: Partial<MaterialSchema>) => void;
|
||||||
|
|
||||||
|
setStartTime: (materialId: string, startTime: string) => void;
|
||||||
|
setEndTime: (materialId: string, endTime: string) => void;
|
||||||
|
setCost: (materialId: string, cost: number) => void;
|
||||||
|
setWeight: (materialId: string, weight: number) => void;
|
||||||
|
|
||||||
|
getMaterialById: (materialId: string) => MaterialSchema | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMaterialStore = create<MaterialsStore>()(
|
||||||
|
immer((set, get) => ({
|
||||||
|
materials: [],
|
||||||
|
|
||||||
|
addMaterial: (material) => {
|
||||||
|
set((state) => {
|
||||||
|
state.materials.push(material);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMaterial: (materialId) => {
|
||||||
|
set((state) => {
|
||||||
|
state.materials = state.materials.filter(m => m.materialId !== materialId);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMaterial: (materialId, updates) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) {
|
||||||
|
Object.assign(material, updates);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setStartTime: (materialId, startTime) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) material.startTime = startTime;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setEndTime: (materialId, endTime) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) material.endTime = endTime;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setCost: (materialId, cost) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) material.cost = cost;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setWeight: (materialId, weight) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) material.weight = weight;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getMaterialById: (materialId) => {
|
||||||
|
return get().materials.find(m => m.materialId === materialId);
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { create } from 'zustand';
|
||||||
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
interface SelectedEventSphereState {
|
||||||
|
selectedEventSphere: THREE.Mesh | null;
|
||||||
|
setSelectedEventSphere: (mesh: THREE.Mesh | null) => void;
|
||||||
|
clearSelectedEventSphere: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedEventSphere = create<SelectedEventSphereState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
selectedEventSphere: null,
|
||||||
|
setSelectedEventSphere: (mesh) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedEventSphere = mesh;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedEventSphere: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedEventSphere = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
|
@ -59,7 +59,7 @@ interface RoboticArmPointSchema {
|
||||||
actionUuid: string;
|
actionUuid: string;
|
||||||
actionName: string;
|
actionName: string;
|
||||||
actionType: "pickAndPlace";
|
actionType: "pickAndPlace";
|
||||||
process: { startPoint: [number, number, number]; endPoint: [number, number, number] };
|
process: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null };
|
||||||
triggers: TriggerSchema[];
|
triggers: TriggerSchema[];
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
@ -168,4 +168,17 @@ interface StorageUnitStatus extends StorageEventSchema {
|
||||||
idleTime: number;
|
idleTime: number;
|
||||||
activeTime: number;
|
activeTime: number;
|
||||||
currentLoad: number;
|
currentLoad: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MaterialSchema {
|
||||||
|
materialId: string;
|
||||||
|
materialName: string;
|
||||||
|
materialType: string;
|
||||||
|
isActive: boolean;
|
||||||
|
startTime?: string;
|
||||||
|
endTime?: string;
|
||||||
|
cost?: number;
|
||||||
|
weight?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MaterialsSchema = MaterialSchema[];
|
Loading…
Reference in New Issue