Merge pull request 'simulation' (#45) from simulation into main
Reviewed-on: http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev/pulls/45
This commit is contained in:
commit
42f0ae5317
2
app/.env
2
app/.env
|
@ -11,7 +11,7 @@ REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000
|
|||
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011
|
||||
|
||||
# Base URL for the asset library server, used for asset library images and model blob id.
|
||||
REACT_APP_SERVER_ASSET_LIBRARY_URL=192.168.0.111:3501
|
||||
REACT_APP_SERVER_ASSET_LIBRARY_URL=185.100.212.76:50011
|
||||
|
||||
# base url for IoT socket server
|
||||
REACT_APP_IOT_SOCKET_SERVER_URL =185.100.212.76:5010
|
||||
|
|
Binary file not shown.
|
@ -14,6 +14,7 @@ import {
|
|||
useSelectedActionSphere,
|
||||
useSelectedPath,
|
||||
useSimulationPaths,
|
||||
useSocketStore,
|
||||
} from "../../../../store/store";
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
@ -26,6 +27,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
const { floorItems, setFloorItems } = useFloorItems();
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
@ -37,20 +39,28 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
|
||||
)
|
||||
.flatMap((path) => path.points)
|
||||
.find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||
.find((point) => point.uuid === selectedActionSphere.points.uuid);
|
||||
}, [selectedActionSphere, simulationPaths]);
|
||||
|
||||
const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => {
|
||||
if (!updatedPath) return;
|
||||
// const email = localStorage.getItem("email");
|
||||
// const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||
// console.log('updatedPath: ', updatedPath);
|
||||
// const a = await setEventApi(
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||
|
||||
// await setEventApi(
|
||||
// organization,
|
||||
// updatedPath.modeluuid,
|
||||
// updatedPath.points
|
||||
// { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
|
||||
// );
|
||||
// console.log('a: ', a);
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: updatedPath.modeluuid,
|
||||
eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
|
||||
}
|
||||
|
||||
socket.emit('v2:model-asset:updateEventData', data);
|
||||
|
||||
}
|
||||
|
||||
const handleAddAction = () => {
|
||||
|
@ -61,7 +71,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
return {
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
if (point.uuid === selectedActionSphere.points.uuid) {
|
||||
const actionIndex = point.actions.length;
|
||||
const newAction = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
|
@ -86,7 +96,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -102,7 +112,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.filter(
|
||||
|
@ -119,7 +129,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -135,7 +145,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
|
@ -167,7 +177,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -181,7 +191,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
|
||||
)
|
||||
.flatMap((path) => path.points)
|
||||
.find((p) => p.uuid === selectedActionSphere.point.uuid)
|
||||
.find((p) => p.uuid === selectedActionSphere.points.uuid)
|
||||
?.actions.find((a) => a.uuid === uuid);
|
||||
|
||||
if (updatedAction) {
|
||||
|
@ -202,7 +212,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
|
@ -222,7 +232,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -249,7 +259,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
|
@ -266,7 +276,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -285,7 +295,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
|
@ -304,7 +314,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -323,7 +333,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -340,7 +350,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
if (point.uuid === selectedActionSphere.points.uuid) {
|
||||
const triggerIndex = point.triggers.length;
|
||||
const newTrigger = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
|
@ -362,7 +372,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -378,7 +388,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.filter(
|
||||
|
@ -395,7 +405,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -411,7 +421,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) =>
|
||||
|
@ -430,7 +440,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -456,7 +466,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) => ({
|
||||
|
@ -474,7 +484,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -502,7 +512,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) => ({
|
||||
|
@ -520,7 +530,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
@ -547,7 +557,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) =>
|
||||
|
@ -566,7 +576,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
(path): path is Types.ConveyorEventsSchema =>
|
||||
path.type === "Conveyor" &&
|
||||
path.points.some(
|
||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||
)
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import React, { useRef, useMemo } from "react";
|
||||
import { InfoIcon } from "../../../icons/ExportCommonIcons";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
|
||||
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationPaths, useSocketStore } from "../../../../store/store";
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import PositionInput from "../customInput/PositionInputs";
|
||||
import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
|
||||
|
||||
const VehicleMechanics: React.FC = () => {
|
||||
const { selectedActionSphere } = useSelectedActionSphere();
|
||||
|
@ -11,46 +12,68 @@ const VehicleMechanics: React.FC = () => {
|
|||
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
||||
const { editingPoint, setEditingPoint } = useEditingPoint();
|
||||
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
const propertiesContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { selectedPoint, connectedPointUuids } = useMemo(() => {
|
||||
if (!selectedActionSphere?.point?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
|
||||
if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
|
||||
|
||||
const vehiclePaths = simulationPaths.filter(
|
||||
(path): path is Types.VehicleEventsSchema => path.type === "Vehicle"
|
||||
);
|
||||
|
||||
const point = vehiclePaths.find(
|
||||
(path) => path.point.uuid === selectedActionSphere.point.uuid
|
||||
)?.point;
|
||||
const points = vehiclePaths.find(
|
||||
(path) => path.points.uuid === selectedActionSphere.points.uuid
|
||||
)?.points;
|
||||
|
||||
if (!point) return { selectedPoint: null, connectedPointUuids: [] };
|
||||
if (!points) return { selectedPoint: null, connectedPointUuids: [] };
|
||||
|
||||
const connectedUuids: string[] = [];
|
||||
if (point.connections?.targets) {
|
||||
point.connections.targets.forEach(target => {
|
||||
if (points.connections?.targets) {
|
||||
points.connections.targets.forEach(target => {
|
||||
connectedUuids.push(target.pointUUID);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
selectedPoint: point,
|
||||
selectedPoint: points,
|
||||
connectedPointUuids: connectedUuids
|
||||
};
|
||||
}, [selectedActionSphere, simulationPaths]);
|
||||
|
||||
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['point']['actions']>) => {
|
||||
if (!selectedActionSphere?.point?.uuid) return;
|
||||
const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => {
|
||||
if (!updatedPath) return;
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||
|
||||
// await setEventApi(
|
||||
// organization,
|
||||
// updatedPath.modeluuid,
|
||||
// { type: "Vehicle", points: updatedPath.points }
|
||||
// );
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: updatedPath.modeluuid,
|
||||
eventData: { type: "Vehicle", points: updatedPath.points }
|
||||
}
|
||||
|
||||
socket.emit('v2:model-asset:updateEventData', data);
|
||||
|
||||
}
|
||||
|
||||
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['points']['actions']>) => {
|
||||
if (!selectedActionSphere?.points?.uuid) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => {
|
||||
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
|
||||
if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
|
||||
return {
|
||||
...path,
|
||||
point: {
|
||||
...path.point,
|
||||
points: {
|
||||
...path.points,
|
||||
actions: {
|
||||
...path.point.actions,
|
||||
...path.points.actions,
|
||||
...updatedAction
|
||||
}
|
||||
}
|
||||
|
@ -59,14 +82,15 @@ const VehicleMechanics: React.FC = () => {
|
|||
return path;
|
||||
});
|
||||
|
||||
const updatedPath = updatedPaths.find(
|
||||
(path): path is Types.VehicleEventsSchema =>
|
||||
path.type === "Vehicle" &&
|
||||
path.points.uuid === selectedActionSphere.points.uuid
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
|
||||
|
||||
const handleStartPointChange = React.useCallback((position: { x: number, y: number }) => {
|
||||
}, [handleActionUpdate]);
|
||||
|
||||
const handleEndPointChange = React.useCallback((position: { x: number, y: number }) => {
|
||||
}, [handleActionUpdate]);
|
||||
}, [selectedActionSphere?.points?.uuid, simulationPaths, setSimulationPaths]);
|
||||
|
||||
const handleHitCountChange = React.useCallback((hitCount: number) => {
|
||||
handleActionUpdate({ hitCount });
|
||||
|
@ -77,14 +101,14 @@ const VehicleMechanics: React.FC = () => {
|
|||
}, [handleActionUpdate]);
|
||||
|
||||
const handleSpeedChange = React.useCallback((speed: number) => {
|
||||
if (!selectedActionSphere?.point?.uuid) return;
|
||||
if (!selectedActionSphere?.points?.uuid) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => {
|
||||
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
|
||||
if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
|
||||
return {
|
||||
...path,
|
||||
point: {
|
||||
...path.point,
|
||||
points: {
|
||||
...path.points,
|
||||
speed: speed
|
||||
}
|
||||
};
|
||||
|
@ -92,8 +116,15 @@ const VehicleMechanics: React.FC = () => {
|
|||
return path;
|
||||
});
|
||||
|
||||
const updatedPath = updatedPaths.find(
|
||||
(path): path is Types.VehicleEventsSchema =>
|
||||
path.type === "Vehicle" &&
|
||||
path.points.uuid === selectedActionSphere.points.uuid
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
|
||||
}, [selectedActionSphere?.points?.uuid, simulationPaths, setSimulationPaths]);
|
||||
|
||||
const handleStartEyeDropClick = () => {
|
||||
setEditingPoint('start');
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
import React, { useState, useRef, useEffect } from "react";
|
||||
import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons";
|
||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import { useActiveTool } from "../../../store/store";
|
||||
import {
|
||||
useAnimationPlaySpeed,
|
||||
usePauseButtonStore,
|
||||
usePlayButtonStore,
|
||||
useResetButtonStore,
|
||||
} from "../../../store/usePlayButtonStore";
|
||||
|
||||
const SimulationPlayer: React.FC = () => {
|
||||
const [speed, setSpeed] = useState<number>(1);
|
||||
const { speed, setSpeed } = useAnimationPlaySpeed();
|
||||
const [playSimulation, setPlaySimulation] = useState(false);
|
||||
const { setIsPlaying } = usePlayButtonStore();
|
||||
const sliderRef = useRef<HTMLDivElement>(null);
|
||||
const isDragging = useRef(false);
|
||||
const { setActiveTool } = useActiveTool();
|
||||
const { isPaused, setIsPaused } = usePauseButtonStore();
|
||||
const { isReset, setReset } = useResetButtonStore();
|
||||
|
||||
// Button functions
|
||||
const handleReset = () => {
|
||||
setReset(true);
|
||||
setSpeed(1);
|
||||
};
|
||||
const handlePlayStop = () => {
|
||||
setIsPaused(!isPaused);
|
||||
setPlaySimulation(!playSimulation);
|
||||
};
|
||||
const handleExit = () => {
|
||||
|
@ -30,7 +39,7 @@ const SimulationPlayer: React.FC = () => {
|
|||
};
|
||||
|
||||
const calculateHandlePosition = () => {
|
||||
return ((speed - 0.5) / (50 - 0.5)) * 100;
|
||||
return ((speed - 0.5) / (8 - 0.5)) * 100;
|
||||
};
|
||||
|
||||
const handleMouseDown = () => {
|
||||
|
@ -118,7 +127,7 @@ const SimulationPlayer: React.FC = () => {
|
|||
<input
|
||||
type="range"
|
||||
min="0.5"
|
||||
max="50"
|
||||
max="8"
|
||||
step="0.1"
|
||||
value={speed}
|
||||
onChange={handleSpeedChange}
|
||||
|
@ -126,7 +135,7 @@ const SimulationPlayer: React.FC = () => {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-value">50x</div>
|
||||
<div className="max-value">8x</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,13 +9,12 @@ import {
|
|||
useSelectedActionSphere,
|
||||
useSimulationPaths,
|
||||
} from "../../../store/store";
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
|
||||
const Agv = ({
|
||||
lines,
|
||||
plane,
|
||||
}: {
|
||||
lines: Types.RefLines;
|
||||
plane: Types.RefMesh;
|
||||
}) => {
|
||||
const [pathPoints, setPathPoints] = useState<
|
||||
{
|
||||
|
@ -23,6 +22,7 @@ const Agv = ({
|
|||
modelSpeed: number;
|
||||
bufferTime: number;
|
||||
points: { x: number; y: number; z: number }[];
|
||||
hitCount: number;
|
||||
}[]
|
||||
>([]);
|
||||
const { simulationPaths } = useSimulationPaths();
|
||||
|
@ -34,7 +34,7 @@ const Agv = ({
|
|||
(val: any) => val.modelName === "agv"
|
||||
);
|
||||
|
||||
console.log("agvModels: ", agvModels);
|
||||
|
||||
let findMesh = agvModels.filter(
|
||||
(val: any) =>
|
||||
val.modeluuid === selectedActionSphere?.path?.modeluuid &&
|
||||
|
@ -43,18 +43,19 @@ const Agv = ({
|
|||
|
||||
const result =
|
||||
findMesh.length > 0 &&
|
||||
findMesh[0].type === "Vehicle" &&
|
||||
typeof findMesh[0].point?.actions.start === "object" &&
|
||||
typeof findMesh[0].point?.actions.end === "object" &&
|
||||
"x" in findMesh[0].point.actions.start &&
|
||||
"y" in findMesh[0].point.actions.start &&
|
||||
"x" in findMesh[0].point.actions.end &&
|
||||
"y" in findMesh[0].point.actions.end
|
||||
findMesh[0].type === "Vehicle" &&
|
||||
typeof findMesh[0].points?.actions.start === "object" &&
|
||||
typeof findMesh[0].points?.actions.end === "object" &&
|
||||
"x" in findMesh[0].points.actions.start &&
|
||||
"y" in findMesh[0].points.actions.start &&
|
||||
"x" in findMesh[0].points.actions.end &&
|
||||
"y" in findMesh[0].points.actions.end
|
||||
? [
|
||||
{
|
||||
modelUuid: findMesh[0].modeluuid, // Ensure it's a number
|
||||
modelSpeed: findMesh[0].point.speed,
|
||||
bufferTime: findMesh[0].point.actions.buffer,
|
||||
modelSpeed: findMesh[0].points.speed,
|
||||
bufferTime: findMesh[0].points.actions.buffer,
|
||||
hitCount: findMesh[0].points.actions.hitCount,
|
||||
points: [
|
||||
{
|
||||
x: findMesh[0].position[0],
|
||||
|
@ -62,14 +63,14 @@ const Agv = ({
|
|||
z: findMesh[0].position[2],
|
||||
},
|
||||
{
|
||||
x: findMesh[0].point.actions.start.x,
|
||||
x: findMesh[0].points.actions.start.x,
|
||||
y: 0,
|
||||
z: findMesh[0].point.actions.start.y,
|
||||
z: findMesh[0].points.actions.start.y,
|
||||
},
|
||||
{
|
||||
x: findMesh[0].point.actions.end.x,
|
||||
x: findMesh[0].points.actions.end.x,
|
||||
y: 0,
|
||||
z: findMesh[0].point.actions.end.y,
|
||||
z: findMesh[0].points.actions.end.y,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -106,12 +107,11 @@ const Agv = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<PolygonGenerator groupRef={groupRef} lines={lines} plane={plane} />
|
||||
<PolygonGenerator groupRef={groupRef} lines={lines} />
|
||||
<NavMeshDetails
|
||||
lines={lines}
|
||||
setNavMesh={setNavMesh}
|
||||
groupRef={groupRef}
|
||||
plane={plane}
|
||||
/>
|
||||
{pathPoints.map((pair, i) => (
|
||||
<>
|
||||
|
@ -122,6 +122,7 @@ const Agv = ({
|
|||
key={i}
|
||||
speed={pair.modelSpeed}
|
||||
bufferTime={pair.bufferTime}
|
||||
hitCount={pair.hitCount}
|
||||
/>
|
||||
{/* {pair.points.length > 2 && (
|
||||
<>
|
||||
|
@ -149,7 +150,12 @@ const Agv = ({
|
|||
)} */}
|
||||
</>
|
||||
))}
|
||||
<group ref={groupRef} visible={false} name="Meshes"></group>
|
||||
<group ref={groupRef} visible={false} name="Meshes">
|
||||
<mesh rotation-x={CONSTANTS.planeConfig.rotation} position={CONSTANTS.planeConfig.position3D} name="Plane" receiveShadow>
|
||||
<planeGeometry args={[300, 300]} />
|
||||
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
|
||||
</mesh>
|
||||
</group>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -10,14 +10,12 @@ interface NavMeshDetailsProps {
|
|||
setNavMesh: (navMesh: any) => void;
|
||||
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||
lines: Types.RefLines;
|
||||
plane: Types.RefMesh;
|
||||
}
|
||||
|
||||
export default function NavMeshDetails({
|
||||
lines,
|
||||
setNavMesh,
|
||||
groupRef,
|
||||
plane,
|
||||
}: NavMeshDetailsProps) {
|
||||
const { scene } = useThree();
|
||||
|
||||
|
@ -34,14 +32,13 @@ export default function NavMeshDetails({
|
|||
|
||||
const [positions, indices] = getPositionsAndIndices(meshes);
|
||||
|
||||
const cs = 0.25;
|
||||
const ch = 0.69;
|
||||
const cellSize = 0.35;
|
||||
const cellHeight = 0.7;
|
||||
const walkableRadius = 0.5;
|
||||
|
||||
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
|
||||
cs,
|
||||
ch,
|
||||
walkableRadius: Math.round(walkableRadius / ch),
|
||||
cs: cellSize,
|
||||
ch: cellHeight,
|
||||
walkableRadius: Math.round(walkableRadius / cellHeight),
|
||||
});
|
||||
|
||||
if (!success || !navMesh) {
|
||||
|
@ -50,10 +47,14 @@ export default function NavMeshDetails({
|
|||
|
||||
setNavMesh(navMesh);
|
||||
|
||||
scene.children
|
||||
.filter((child) => child instanceof DebugDrawer)
|
||||
.forEach((child) => scene.remove(child));
|
||||
|
||||
const debugDrawer = new DebugDrawer();
|
||||
debugDrawer.drawNavMesh(navMesh);
|
||||
// scene.add(debugDrawer);
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
initializeNavigation();
|
||||
|
|
|
@ -12,6 +12,7 @@ interface PathNavigatorProps {
|
|||
id: string;
|
||||
speed: number;
|
||||
bufferTime: number;
|
||||
hitCount: number;
|
||||
}
|
||||
|
||||
export default function PathNavigator({
|
||||
|
@ -20,6 +21,7 @@ export default function PathNavigator({
|
|||
id,
|
||||
speed,
|
||||
bufferTime,
|
||||
hitCount,
|
||||
}: PathNavigatorProps) {
|
||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||
const progressRef = useRef(0);
|
||||
|
@ -32,7 +34,7 @@ export default function PathNavigator({
|
|||
const [startPoint, setStartPoint] = useState(new THREE.Vector3());
|
||||
const isWaiting = useRef<boolean>(false); // Flag to track waiting state
|
||||
const delayTime = bufferTime;
|
||||
|
||||
|
||||
const movingForward = useRef<boolean>(true); // Tracks whether the object is moving forward
|
||||
// Compute distances and total distance when the path changes
|
||||
useEffect(() => {
|
||||
|
@ -52,6 +54,7 @@ export default function PathNavigator({
|
|||
progressRef.current = 0;
|
||||
}, [path]);
|
||||
|
||||
// Compute the path using NavMeshQuery
|
||||
useEffect(() => {
|
||||
if (!navMesh || selectedPoints.length === 0) return;
|
||||
|
||||
|
@ -119,17 +122,22 @@ export default function PathNavigator({
|
|||
if (!isWaiting.current) {
|
||||
isWaiting.current = true; // Set waiting flag
|
||||
|
||||
setTimeout(() => {
|
||||
progressRef.current = 0; // Reset progress
|
||||
movingForward.current = !movingForward.current; // Toggle direction
|
||||
|
||||
// Reverse the path and distances arrays
|
||||
path.reverse();
|
||||
distancesRef.current.reverse();
|
||||
|
||||
// Reset the waiting flag
|
||||
isWaiting.current = false;
|
||||
}, delayTime * 1000); // Convert seconds to milliseconds
|
||||
if (movingForward.current) {
|
||||
// Moving forward: reached the end, wait for `delay`
|
||||
// console.log(
|
||||
// "Reached end position. Waiting for delay:",
|
||||
// delayTime,
|
||||
// "seconds"
|
||||
// );
|
||||
setTimeout(() => {
|
||||
// After delay, reverse direction
|
||||
movingForward.current = false;
|
||||
progressRef.current = 0; // Reset progress
|
||||
path.reverse(); // Reverse the path
|
||||
distancesRef.current.reverse();
|
||||
isWaiting.current = false; // Reset waiting flag
|
||||
}, delayTime * 1000); // Wait for `delay` seconds
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -154,7 +162,7 @@ export default function PathNavigator({
|
|||
findObject.position.copy(startPoint);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{path.length > 0 && (
|
||||
|
|
|
@ -6,21 +6,12 @@ import arrayLinesToObject from "../geomentries/lines/lineConvertions/arrayLinesT
|
|||
interface PolygonGeneratorProps {
|
||||
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||
lines: Types.RefLines;
|
||||
plane: Types.RefMesh;
|
||||
}
|
||||
|
||||
export default function PolygonGenerator({
|
||||
groupRef,
|
||||
lines,
|
||||
plane,
|
||||
}: PolygonGeneratorProps) {
|
||||
// const [rooms, setRooms] = useState<THREE.Vector3[][]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (groupRef.current && plane.current) {
|
||||
groupRef.current.add(plane.current.clone());
|
||||
}
|
||||
}, [groupRef, plane]);
|
||||
|
||||
useEffect(() => {
|
||||
let allLines = arrayLinesToObject(lines.current);
|
||||
|
@ -37,13 +28,14 @@ export default function PolygonGenerator({
|
|||
uuid: point.uuid,
|
||||
}))
|
||||
);
|
||||
|
||||
if (!result || result.some((line) => !line)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lineFeatures = result?.map((line: any) =>
|
||||
turf.lineString(line.map((p: any) => p?.position))
|
||||
);
|
||||
);
|
||||
|
||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
||||
renderWallGeometry(wallPoints);
|
||||
|
@ -79,8 +71,8 @@ export default function PolygonGenerator({
|
|||
groupRef.current?.add(mesh);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}, [lines.current]);
|
||||
|
||||
const renderWallGeometry = (walls: THREE.Vector3[][]) => {
|
||||
|
|
|
@ -136,7 +136,7 @@ async function handleModelLoad(
|
|||
tempLoader.current = undefined;
|
||||
}
|
||||
|
||||
const newFloorItem: Types.FloorItemType = {
|
||||
const newFloorItem: Types.EventData = {
|
||||
modeluuid: model.uuid,
|
||||
modelname: selectedItem.name,
|
||||
modelfileID: selectedItem.id,
|
||||
|
@ -154,7 +154,7 @@ async function handleModelLoad(
|
|||
if (res.type === "Conveyor") {
|
||||
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
|
||||
|
||||
const backendEventData: Extract<Types.FloorItemType['eventData'], { type: 'Conveyor' }> = {
|
||||
const backendEventData: Extract<Types.EventData['eventData'], { type: 'Conveyor' }> = {
|
||||
type: 'Conveyor',
|
||||
points: res.points.map((point: any, index: number) => ({
|
||||
uuid: pointUUIDs[index],
|
||||
|
@ -167,7 +167,7 @@ async function handleModelLoad(
|
|||
material: 'Inherit',
|
||||
delay: 'Inherit',
|
||||
spawnInterval: 'Inherit',
|
||||
isUsed: false
|
||||
isUsed: true
|
||||
}],
|
||||
triggers: [],
|
||||
connections: {
|
||||
|
@ -189,7 +189,7 @@ async function handleModelLoad(
|
|||
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
// false,
|
||||
// true,
|
||||
// newFloorItem.eventData
|
||||
// { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
@ -206,8 +206,7 @@ async function handleModelLoad(
|
|||
eventData: backendEventData,
|
||||
socketId: socket.id
|
||||
};
|
||||
|
||||
console.log('data: ', data);
|
||||
|
||||
setFloorItems((prevItems) => {
|
||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||
|
@ -222,12 +221,25 @@ async function handleModelLoad(
|
|||
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
eventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
||||
eventData as Types.ConveyorEventsSchema
|
||||
]);
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
} else {
|
||||
} else if (res.type === "Vehicle") {
|
||||
|
||||
const pointUUID = THREE.MathUtils.generateUUID();
|
||||
|
||||
const backendEventData: Extract<Types.EventData['eventData'], { type: 'Vehicle' }> = {
|
||||
type: "Vehicle",
|
||||
points: {
|
||||
uuid: pointUUID,
|
||||
position: res.points.position as [number, number, number],
|
||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
|
||||
speed: 2,
|
||||
}
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
|
@ -239,7 +251,8 @@ async function handleModelLoad(
|
|||
// newFloorItem.position,
|
||||
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
// false,
|
||||
// true
|
||||
// true,
|
||||
// { type: backendEventData.type, points: backendEventData.points }
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
@ -253,15 +266,26 @@ async function handleModelLoad(
|
|||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
eventData: { type: backendEventData.type, points: backendEventData.points },
|
||||
socketId: socket.id
|
||||
};
|
||||
|
||||
|
||||
const eventData: any = backendEventData;
|
||||
eventData.modeluuid = newFloorItem.modeluuid;
|
||||
eventData.modelName = newFloorItem.modelname;
|
||||
eventData.position = newFloorItem.position;
|
||||
|
||||
setFloorItems((prevItems) => {
|
||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||
return updatedItems;
|
||||
});
|
||||
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
eventData as Types.VehicleEventsSchema
|
||||
]);
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
}
|
||||
|
|
|
@ -110,7 +110,6 @@ const FloorItemsGroup = ({
|
|||
}
|
||||
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||
} else {
|
||||
console.log('data: ', data);
|
||||
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths);
|
||||
updateLoadingProgress(100);
|
||||
|
|
|
@ -111,7 +111,7 @@ const CamModelsGroup = () => {
|
|||
socket.off("userDisConnectRespones");
|
||||
socket.off("cameraUpdateResponse");
|
||||
};
|
||||
}, [socket, activeUsers]);
|
||||
}, [socket]);
|
||||
|
||||
|
||||
// useEffect(() => {
|
||||
|
|
|
@ -143,10 +143,6 @@ export default function SocketResponses({
|
|||
isVisible: data.data.isVisible,
|
||||
};
|
||||
|
||||
if (data.data.eventData) {
|
||||
newFloorItem.eventData = data.data.eventData;
|
||||
}
|
||||
|
||||
setFloorItems((prevItems: any) => {
|
||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||
|
@ -221,10 +217,6 @@ export default function SocketResponses({
|
|||
isVisible: data.data.isVisible,
|
||||
};
|
||||
|
||||
if (data.data.eventData) {
|
||||
newFloorItem.eventData = data.data.eventData;
|
||||
}
|
||||
|
||||
setFloorItems((prevItems: any) => {
|
||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||
|
|
|
@ -23,10 +23,10 @@ async function loadInitialFloorItems(
|
|||
localStorage.setItem("FloorItems", JSON.stringify(items));
|
||||
await initializeDB();
|
||||
|
||||
if (items.message === "floorItems not found") return;
|
||||
if (items.message === "floorItems not found") return;
|
||||
|
||||
if (items) {
|
||||
const storedFloorItems: Types.FloorItems = items;
|
||||
const storedFloorItems: Types.EventData[] = items;
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
|
@ -53,7 +53,6 @@ async function loadInitialFloorItems(
|
|||
});
|
||||
|
||||
for (const item of storedFloorItems) {
|
||||
console.log('item: ', item);
|
||||
if (!item.modelfileID) return;
|
||||
const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
|
||||
let storedPosition;
|
||||
|
@ -155,7 +154,7 @@ async function loadInitialFloorItems(
|
|||
|
||||
function processLoadedModel(
|
||||
gltf: any,
|
||||
item: Types.FloorItemType,
|
||||
item: Types.EventData,
|
||||
itemsGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void
|
||||
|
@ -193,7 +192,7 @@ function processLoadedModel(
|
|||
},
|
||||
]);
|
||||
|
||||
if (item.eventData || item.modelfileID === '67e3da19c2e8f37134526e6a') {
|
||||
if (item.eventData) {
|
||||
processEventData(item, setSimulationPaths);
|
||||
}
|
||||
|
||||
|
@ -201,7 +200,7 @@ function processLoadedModel(
|
|||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
||||
}
|
||||
|
||||
function processEventData(item: Types.FloorItemType, setSimulationPaths: any) {
|
||||
function processEventData(item: Types.EventData, setSimulationPaths: any) {
|
||||
|
||||
if (item.eventData?.type === 'Conveyor') {
|
||||
|
||||
|
@ -215,29 +214,19 @@ function processEventData(item: Types.FloorItemType, setSimulationPaths: any) {
|
|||
...(prevEvents || []),
|
||||
data as Types.ConveyorEventsSchema
|
||||
]);
|
||||
|
||||
} else {
|
||||
|
||||
const pointUUID = THREE.MathUtils.generateUUID();
|
||||
const pointPosition = new THREE.Vector3(0, 1.3, 0);
|
||||
const data: any = item.eventData;
|
||||
data.modeluuid = item.modeluuid;
|
||||
data.modelName = item.modelname;
|
||||
data.position = item.position;
|
||||
|
||||
const newVehiclePath: Types.VehicleEventsSchema = {
|
||||
modeluuid: item.modeluuid,
|
||||
modelName: item.modelname,
|
||||
type: 'Vehicle',
|
||||
point: {
|
||||
uuid: pointUUID,
|
||||
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||
speed: 2,
|
||||
},
|
||||
position: [...item.position],
|
||||
};
|
||||
|
||||
setSimulationPaths((prevEvents: (Types.VehicleEventsSchema)[]) => [
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
newVehiclePath as Types.VehicleEventsSchema
|
||||
data as Types.VehicleEventsSchema
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -236,10 +236,91 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
|||
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
||||
newEventData as Types.ConveyorEventsSchema
|
||||
]);
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
} else if (eventData.type === 'Vehicle' && eventData) {
|
||||
const createVehiclePoint = () => {
|
||||
const pointUUID = THREE.MathUtils.generateUUID();
|
||||
const vehiclePoint = (eventData as Types.VehicleEventsSchema)?.points;
|
||||
const hasActions = vehiclePoint?.actions !== undefined;
|
||||
|
||||
const defaultAction = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: 'Action 1',
|
||||
type: 'Inherit',
|
||||
start: {},
|
||||
hitCount: 0,
|
||||
end: {},
|
||||
buffer: 0
|
||||
};
|
||||
|
||||
return {
|
||||
uuid: pointUUID,
|
||||
position: vehiclePoint?.position,
|
||||
actions: hasActions
|
||||
? {
|
||||
...vehiclePoint.actions,
|
||||
uuid: THREE.MathUtils.generateUUID()
|
||||
}
|
||||
: defaultAction,
|
||||
connections: {
|
||||
source: { modelUUID: obj.uuid, pointUUID },
|
||||
targets: []
|
||||
},
|
||||
speed: vehiclePoint?.speed || 1
|
||||
};
|
||||
};
|
||||
|
||||
const backendEventData = {
|
||||
type: 'Vehicle',
|
||||
points: createVehiclePoint(),
|
||||
speed: (eventData as Types.VehicleEventsSchema)?.points.speed
|
||||
};
|
||||
|
||||
// API
|
||||
|
||||
// setFloorItemApi(
|
||||
// organization,
|
||||
// obj.uuid,
|
||||
// obj.userData.name,
|
||||
// obj.userData.modelId,
|
||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||
// false,
|
||||
// true,
|
||||
// { type: backendEventData.type, points: backendEventData.points }
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modeluuid: newFloorItem.modeluuid,
|
||||
modelname: newFloorItem.modelname,
|
||||
modelfileID: newFloorItem.modelfileID,
|
||||
position: newFloorItem.position,
|
||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
eventData: backendEventData,
|
||||
socketId: socket.id,
|
||||
};
|
||||
|
||||
const newEventData: any = backendEventData;
|
||||
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
newEventData as Types.VehicleEventsSchema
|
||||
]);
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, u
|
|||
import { toast } from "react-toastify";
|
||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||
|
||||
const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
|
||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||
|
@ -182,16 +183,16 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
|
||||
//REST
|
||||
|
||||
// await setFloorItemApi(
|
||||
// setFloorItemApi(
|
||||
// organization,
|
||||
// obj.uuid,
|
||||
// obj.userData.name,
|
||||
// obj.userData.modelId,
|
||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||
// obj.userData.modelId,
|
||||
// false,
|
||||
// true,
|
||||
// backendEventData
|
||||
// { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
|
||||
// );
|
||||
|
||||
//SOCKET
|
||||
|
@ -217,10 +218,90 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
||||
newEventData as Types.ConveyorEventsSchema
|
||||
]);
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
} else if (eventData.type === 'Vehicle' && eventData) {
|
||||
const createVehiclePoint = () => {
|
||||
const pointUUID = THREE.MathUtils.generateUUID();
|
||||
const vehiclePoint = (eventData as Types.VehicleEventsSchema)?.points;
|
||||
const hasActions = vehiclePoint?.actions !== undefined;
|
||||
|
||||
const defaultAction = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: 'Action 1',
|
||||
type: 'Inherit',
|
||||
start: {},
|
||||
hitCount: 0,
|
||||
end: {},
|
||||
buffer: 0
|
||||
};
|
||||
|
||||
return {
|
||||
uuid: pointUUID,
|
||||
position: vehiclePoint?.position,
|
||||
actions: hasActions
|
||||
? {
|
||||
...vehiclePoint.actions,
|
||||
uuid: THREE.MathUtils.generateUUID()
|
||||
}
|
||||
: defaultAction,
|
||||
connections: {
|
||||
source: { modelUUID: obj.uuid, pointUUID },
|
||||
targets: []
|
||||
},
|
||||
speed: vehiclePoint?.speed || 2
|
||||
};
|
||||
};
|
||||
|
||||
const backendEventData = {
|
||||
type: 'Vehicle',
|
||||
points: createVehiclePoint()
|
||||
};
|
||||
|
||||
// API
|
||||
|
||||
// setFloorItemApi(
|
||||
// organization,
|
||||
// obj.uuid,
|
||||
// obj.userData.name,
|
||||
// obj.userData.modelId,
|
||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||
// false,
|
||||
// true,
|
||||
// { type: backendEventData.type, points: backendEventData.points }
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modeluuid: newFloorItem.modeluuid,
|
||||
modelname: newFloorItem.modelname,
|
||||
modelfileID: newFloorItem.modelfileID,
|
||||
position: newFloorItem.position,
|
||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
eventData: backendEventData,
|
||||
socketId: socket.id,
|
||||
};
|
||||
|
||||
const newEventData: any = backendEventData;
|
||||
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
newEventData as Types.VehicleEventsSchema
|
||||
]);
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
|
|
|
@ -238,7 +238,59 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
|||
return updatedEvents;
|
||||
});
|
||||
|
||||
// socket.emit("v2:model-asset:add", data);
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
} else if (eventData.type === 'Vehicle' && eventData) {
|
||||
|
||||
const backendEventData = {
|
||||
type: 'Vehicle',
|
||||
points: eventData.points
|
||||
};
|
||||
|
||||
// REST
|
||||
|
||||
// await setFloorItemApi(
|
||||
// organization,
|
||||
// obj.uuid,
|
||||
// obj.userData.name,
|
||||
// obj.userData.modelId,
|
||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||
// false,
|
||||
// true,
|
||||
// backendEventData
|
||||
// );
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modeluuid: newFloorItem.modeluuid,
|
||||
modelname: newFloorItem.modelname,
|
||||
modelfileID: newFloorItem.modelfileID,
|
||||
position: newFloorItem.position,
|
||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
eventData: backendEventData,
|
||||
socketId: socket.id,
|
||||
};
|
||||
|
||||
const newEventData: any = backendEventData;
|
||||
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
||||
const updatedEvents = (prevEvents || []).map(event =>
|
||||
event.modeluuid === newFloorItem.modeluuid
|
||||
? { ...event, ...newEventData }
|
||||
: event
|
||||
);
|
||||
return updatedEvents;
|
||||
});
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, u
|
|||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||
import { toast } from "react-toastify";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||
|
||||
function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
|
||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||
|
@ -197,15 +198,15 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
|||
speed: (eventData as Types.ConveyorEventsSchema)?.speed
|
||||
};
|
||||
|
||||
//REST
|
||||
// REST
|
||||
|
||||
// await setFloorItemApi(
|
||||
// organization,
|
||||
// obj.uuid,
|
||||
// obj.userData.name,
|
||||
// obj.userData.modelId,
|
||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||
// obj.userData.modelId,
|
||||
// false,
|
||||
// true,
|
||||
// backendEventData
|
||||
|
@ -241,7 +242,60 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
|||
return updatedEvents;
|
||||
});
|
||||
|
||||
// socket.emit("v2:model-asset:add", data);
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
} else if (eventData.type === 'Vehicle' && eventData) {
|
||||
|
||||
const backendEventData = {
|
||||
type: 'Vehicle',
|
||||
points: eventData.points
|
||||
};
|
||||
|
||||
// REST
|
||||
|
||||
// await setFloorItemApi(
|
||||
// organization,
|
||||
// obj.uuid,
|
||||
// obj.userData.name,
|
||||
// obj.userData.modelId,
|
||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||
// false,
|
||||
// true,
|
||||
// backendEventData
|
||||
// );
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modeluuid: newFloorItem.modeluuid,
|
||||
modelname: newFloorItem.modelname,
|
||||
modelfileID: newFloorItem.modelfileID,
|
||||
position: newFloorItem.position,
|
||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
eventData: backendEventData,
|
||||
socketId: socket.id,
|
||||
};
|
||||
|
||||
const newEventData: any = backendEventData;
|
||||
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
|
||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
||||
const updatedEvents = (prevEvents || []).map(event =>
|
||||
event.modeluuid === newFloorItem.modeluuid
|
||||
? { ...event, ...newEventData }
|
||||
: event
|
||||
);
|
||||
return updatedEvents;
|
||||
});
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ export default function PostProcessing() {
|
|||
)}
|
||||
{selectedActionSphere && (
|
||||
<Outline
|
||||
selection={[selectedActionSphere.point]}
|
||||
selection={[selectedActionSphere.points]}
|
||||
selectionLayer={10}
|
||||
width={1000}
|
||||
blendFunction={BlendFunction.ALPHA}
|
||||
|
|
|
@ -367,7 +367,9 @@ export default function World() {
|
|||
/>
|
||||
|
||||
{/* <DrieHtmlTemp itemsGroup={itemsGroup} /> */}
|
||||
{activeModule === "simulation" && <Agv lines={lines} plane={plane} />}
|
||||
|
||||
{activeModule === "simulation" && <Agv lines={lines} />}
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,14 @@ import * as Types from '../../../types/world/worldTypes';
|
|||
import { QuadraticBezierLine } from '@react-three/drei';
|
||||
import { useIsConnecting, useSimulationPaths } from '../../../store/store';
|
||||
import useModuleStore from '../../../store/useModuleStore';
|
||||
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
||||
|
||||
function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
|
||||
const { activeModule } = useModuleStore();
|
||||
const { gl, raycaster, scene, pointer, camera } = useThree();
|
||||
const { setIsConnecting } = useIsConnecting();
|
||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
const [firstSelected, setFirstSelected] = useState<{
|
||||
pathUUID: string;
|
||||
|
@ -89,12 +91,12 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
// In the updatePathConnections function, modify the Vehicle handling section:
|
||||
else if (path.type === 'Vehicle') {
|
||||
// Handle outgoing connections from Vehicle
|
||||
if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) {
|
||||
if (path.modeluuid === fromPathUUID && path.points.uuid === fromPointUUID) {
|
||||
const newTarget = {
|
||||
pathUUID: toPathUUID,
|
||||
pointUUID: toPointUUID
|
||||
};
|
||||
const existingTargets = path.point.connections.targets || [];
|
||||
const existingTargets = path.points.connections.targets || [];
|
||||
|
||||
// Check if target is a Conveyor
|
||||
const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID);
|
||||
|
@ -115,10 +117,10 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
)) {
|
||||
return {
|
||||
...path,
|
||||
point: {
|
||||
...path.point,
|
||||
points: {
|
||||
...path.points,
|
||||
connections: {
|
||||
...path.point.connections,
|
||||
...path.points.connections,
|
||||
targets: [...existingTargets, newTarget]
|
||||
}
|
||||
}
|
||||
|
@ -126,12 +128,12 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
}
|
||||
}
|
||||
// Handle incoming connections to Vehicle
|
||||
else if (path.modeluuid === toPathUUID && path.point.uuid === toPointUUID) {
|
||||
else if (path.modeluuid === toPathUUID && path.points.uuid === toPointUUID) {
|
||||
const reverseTarget = {
|
||||
pathUUID: fromPathUUID,
|
||||
pointUUID: fromPointUUID
|
||||
};
|
||||
const existingTargets = path.point.connections.targets || [];
|
||||
const existingTargets = path.points.connections.targets || [];
|
||||
|
||||
// Check if source is a Conveyor
|
||||
const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID);
|
||||
|
@ -152,10 +154,10 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
)) {
|
||||
return {
|
||||
...path,
|
||||
point: {
|
||||
...path.point,
|
||||
points: {
|
||||
...path.points,
|
||||
connections: {
|
||||
...path.point.connections,
|
||||
...path.points.connections,
|
||||
targets: [...existingTargets, reverseTarget]
|
||||
}
|
||||
}
|
||||
|
@ -215,13 +217,13 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
|
||||
let isStartOrEnd = false;
|
||||
|
||||
if (intersected.userData.path.points) {
|
||||
if (intersected.userData.path.points && intersected.userData.path.points.length > 1) {
|
||||
isStartOrEnd = intersected.userData.path.points.length > 0 && (
|
||||
sphereUUID === intersected.userData.path.points[0].uuid ||
|
||||
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
|
||||
);
|
||||
} else if (intersected.userData.path.point) {
|
||||
isStartOrEnd = sphereUUID === intersected.userData.path.point.uuid;
|
||||
} else if (intersected.userData.path.points) {
|
||||
isStartOrEnd = sphereUUID === intersected.userData.path.points.uuid;
|
||||
}
|
||||
|
||||
if (pathUUID) {
|
||||
|
@ -253,7 +255,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
|
||||
);
|
||||
} else if (path.type === 'Vehicle') {
|
||||
return path.point.connections.targets.some(t =>
|
||||
return path.points.connections.targets.some(t =>
|
||||
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
|
||||
);
|
||||
}
|
||||
|
@ -269,7 +271,8 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
|
||||
// For Vehicles, check if they're already connected to anything
|
||||
if (intersected.userData.path.type === 'Vehicle') {
|
||||
const vehicleConnections = intersected.userData.path.point.connections.targets.length;
|
||||
console.log('intersected: ', intersected);
|
||||
const vehicleConnections = intersected.userData.path.points.connections.targets.length;
|
||||
if (vehicleConnections >= 1) {
|
||||
console.log("Vehicle can only have one connection");
|
||||
return;
|
||||
|
@ -418,7 +421,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
|
||||
);
|
||||
} else if (path.type === 'Vehicle') {
|
||||
return path.point.connections.targets.some(t =>
|
||||
return path.points.connections.targets.some(t =>
|
||||
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
|
||||
);
|
||||
}
|
||||
|
@ -440,7 +443,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
|
||||
// Check vehicle connection rules
|
||||
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
|
||||
pathData.point.connections.targets.length >= 1;
|
||||
pathData.points.connections.targets.length >= 1;
|
||||
const isVehicleConnectingToNonConveyor =
|
||||
(firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
|
||||
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');
|
||||
|
@ -501,7 +504,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<group name='simulationConnectionGroup' visible={!isPlaying} >
|
||||
{simulationPaths.flatMap(path => {
|
||||
if (path.type === 'Conveyor') {
|
||||
return path.points.flatMap(point =>
|
||||
|
@ -545,8 +548,8 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
})
|
||||
);
|
||||
} else if (path.type === 'Vehicle') {
|
||||
return path.point.connections.targets.map((target, index) => {
|
||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.point.uuid);
|
||||
return path.points.connections.targets.map((target, index) => {
|
||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid);
|
||||
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
||||
|
||||
if (fromSphere && toSphere) {
|
||||
|
@ -566,7 +569,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
|
||||
return (
|
||||
<QuadraticBezierLine
|
||||
key={`${path.point.uuid}-${target.pointUUID}-${index}`}
|
||||
key={`${path.points.uuid}-${target.pointUUID}-${index}`}
|
||||
start={fromWorldPosition.toArray()}
|
||||
end={toWorldPosition.toArray()}
|
||||
mid={midPoint.toArray()}
|
||||
|
@ -596,7 +599,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
dashScale={20}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { useSubModuleStore } from "../../../store/useModuleStore";
|
||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import { setEventApi } from "../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
|
||||
|
||||
function PathCreation({
|
||||
pathsGroupRef,
|
||||
|
@ -24,16 +25,12 @@ function PathCreation({
|
|||
const { isPlaying } = usePlayButtonStore();
|
||||
const { renderDistance } = useRenderDistance();
|
||||
const { setSubModule } = useSubModuleStore();
|
||||
const { setSelectedActionSphere, selectedActionSphere } =
|
||||
useSelectedActionSphere();
|
||||
const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
|
||||
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
||||
const { editingPoint, setEditingPoint } = useEditingPoint();
|
||||
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
||||
const { raycaster, camera, pointer, gl } = useThree();
|
||||
const plane = useMemo(
|
||||
() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
|
||||
[]
|
||||
);
|
||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||
const { setSelectedPath } = useSelectedPath();
|
||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
const { isConnecting } = useIsConnecting();
|
||||
|
@ -42,9 +39,7 @@ function PathCreation({
|
|||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||
const isMovingRef = useRef(false);
|
||||
const transformRef = useRef<any>(null);
|
||||
const [transformMode, setTransformMode] = useState<
|
||||
"translate" | "rotate" | null
|
||||
>(null);
|
||||
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setTransformMode(null);
|
||||
|
@ -81,20 +76,20 @@ function PathCreation({
|
|||
return {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
point.uuid === selectedActionSphere.points.uuid
|
||||
? {
|
||||
...point,
|
||||
position: [
|
||||
selectedActionSphere.point.position.x,
|
||||
selectedActionSphere.point.position.y,
|
||||
selectedActionSphere.point.position.z,
|
||||
],
|
||||
rotation: [
|
||||
selectedActionSphere.point.rotation.x,
|
||||
selectedActionSphere.point.rotation.y,
|
||||
selectedActionSphere.point.rotation.z,
|
||||
],
|
||||
}
|
||||
...point,
|
||||
position: [
|
||||
selectedActionSphere.points.position.x,
|
||||
selectedActionSphere.points.position.y,
|
||||
selectedActionSphere.points.position.z,
|
||||
],
|
||||
rotation: [
|
||||
selectedActionSphere.points.rotation.x,
|
||||
selectedActionSphere.points.rotation.y,
|
||||
selectedActionSphere.points.rotation.z,
|
||||
],
|
||||
}
|
||||
: point
|
||||
),
|
||||
};
|
||||
|
@ -161,26 +156,37 @@ function PathCreation({
|
|||
};
|
||||
}, [eyeDropMode, editingPoint, previewPosition]);
|
||||
|
||||
const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => {
|
||||
if (!updatedPath) return;
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||
await setEventApi(
|
||||
organization,
|
||||
updatedPath.modeluuid,
|
||||
{ type: "Vehicle", points: updatedPath.points }
|
||||
);
|
||||
}
|
||||
|
||||
const handlePointUpdate = (
|
||||
pointType: "start" | "end",
|
||||
x: number,
|
||||
z: number
|
||||
) => {
|
||||
if (!selectedActionSphere?.point?.uuid) return;
|
||||
|
||||
if (!selectedActionSphere?.points?.uuid) return;
|
||||
const updatedPaths = simulationPaths.map((path) => {
|
||||
|
||||
if (
|
||||
path.type === "Vehicle" &&
|
||||
path.point.uuid === selectedActionSphere.point.uuid
|
||||
path.points.uuid === selectedActionSphere.points.uuid
|
||||
) {
|
||||
return {
|
||||
...path,
|
||||
point: {
|
||||
...path.point,
|
||||
points: {
|
||||
...path.points,
|
||||
actions: {
|
||||
...path.point.actions,
|
||||
...path.points.actions,
|
||||
[pointType]: {
|
||||
...path.point.actions[pointType],
|
||||
...path.points.actions[pointType],
|
||||
x: x,
|
||||
y: z,
|
||||
},
|
||||
|
@ -191,6 +197,13 @@ function PathCreation({
|
|||
return path;
|
||||
});
|
||||
|
||||
const updatedPath = updatedPaths.find(
|
||||
(path): path is Types.VehicleEventsSchema =>
|
||||
path.type === "Vehicle" &&
|
||||
path.points.uuid === selectedActionSphere.points.uuid
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
|
@ -239,12 +252,12 @@ function PathCreation({
|
|||
e.stopPropagation();
|
||||
setSelectedActionSphere({
|
||||
path,
|
||||
point: sphereRefs.current[point.uuid],
|
||||
points: sphereRefs.current[point.uuid],
|
||||
});
|
||||
setSubModule("mechanics");
|
||||
setSelectedPath(null);
|
||||
}}
|
||||
userData={{ point, path }}
|
||||
userData={{ points, path }}
|
||||
onPointerMissed={() => {
|
||||
if (eyeDropMode) return;
|
||||
setSubModule("properties");
|
||||
|
@ -256,8 +269,8 @@ function PathCreation({
|
|||
index === 0
|
||||
? "orange"
|
||||
: index === path.points.length - 1
|
||||
? "blue"
|
||||
: "green"
|
||||
? "blue"
|
||||
: "green"
|
||||
}
|
||||
/>
|
||||
</Sphere>
|
||||
|
@ -318,23 +331,23 @@ function PathCreation({
|
|||
}}
|
||||
>
|
||||
<Sphere
|
||||
key={path.point.uuid}
|
||||
uuid={path.point.uuid}
|
||||
position={path.point.position}
|
||||
key={path.points.uuid}
|
||||
uuid={path.points.uuid}
|
||||
position={path.points.position}
|
||||
args={[0.15, 32, 32]}
|
||||
name="events-sphere"
|
||||
ref={(el) => (sphereRefs.current[path.point.uuid] = el!)}
|
||||
ref={(el) => (sphereRefs.current[path.points.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
if (isConnecting || eyeDropMode) return;
|
||||
e.stopPropagation();
|
||||
setSelectedActionSphere({
|
||||
path,
|
||||
point: sphereRefs.current[path.point.uuid],
|
||||
points: sphereRefs.current[path.points.uuid],
|
||||
});
|
||||
setSubModule("mechanics");
|
||||
setSelectedPath(null);
|
||||
}}
|
||||
userData={{ point: path.point, path }}
|
||||
userData={{ points: path.points, path }}
|
||||
onPointerMissed={() => {
|
||||
if (eyeDropMode) return;
|
||||
setSubModule("properties");
|
||||
|
@ -352,7 +365,7 @@ function PathCreation({
|
|||
{selectedActionSphere && transformMode && (
|
||||
<TransformControls
|
||||
ref={transformRef}
|
||||
object={selectedActionSphere.point}
|
||||
object={selectedActionSphere.points}
|
||||
mode={transformMode}
|
||||
onMouseUp={updateSimulationPaths}
|
||||
/>
|
||||
|
|
|
@ -1,916 +0,0 @@
|
|||
// // animation-worker.js
|
||||
// // This web worker handles animation calculations off the main thread
|
||||
|
||||
// /* eslint-disable no-restricted-globals */
|
||||
// // The above disables the ESLint rule for this file since 'self' is valid in web workers
|
||||
|
||||
// // Store process data, animation states, and objects
|
||||
// let processes = [];
|
||||
// let animationStates = {};
|
||||
// let lastTimestamp = 0;
|
||||
|
||||
// // Message handler for communication with main thread
|
||||
// self.onmessage = function (event) {
|
||||
// const { type, data } = event.data;
|
||||
|
||||
// switch (type) {
|
||||
// case "initialize":
|
||||
// processes = data.processes;
|
||||
// initializeAnimationStates();
|
||||
// break;
|
||||
|
||||
// case "update":
|
||||
// const { timestamp, isPlaying } = data;
|
||||
// if (isPlaying) {
|
||||
// const delta = (timestamp - lastTimestamp) / 1000; // Convert to seconds
|
||||
// updateAnimations(delta, timestamp);
|
||||
// }
|
||||
// lastTimestamp = timestamp;
|
||||
// break;
|
||||
|
||||
// case "reset":
|
||||
// resetAnimations();
|
||||
// break;
|
||||
|
||||
// case "togglePlay":
|
||||
// // If resuming from pause, recalculate the time delta
|
||||
// lastTimestamp = data.timestamp;
|
||||
// break;
|
||||
// }
|
||||
// };
|
||||
|
||||
// // Initialize animation states for all processes
|
||||
// function initializeAnimationStates() {
|
||||
// animationStates = {};
|
||||
|
||||
// processes.forEach((process) => {
|
||||
// animationStates[process.id] = {
|
||||
// spawnedObjects: {},
|
||||
// nextSpawnTime: 0,
|
||||
// objectIdCounter: 0,
|
||||
// };
|
||||
// });
|
||||
|
||||
// // Send initial states back to main thread
|
||||
// self.postMessage({
|
||||
// type: "statesInitialized",
|
||||
// data: { animationStates },
|
||||
// });
|
||||
// }
|
||||
|
||||
// // Reset all animations
|
||||
// function resetAnimations() {
|
||||
// initializeAnimationStates();
|
||||
// }
|
||||
|
||||
// // Find spawn point in a process
|
||||
// function findSpawnPoint(process) {
|
||||
// for (const path of process.paths || []) {
|
||||
// for (const point of path.points || []) {
|
||||
// const spawnAction = point.actions?.find(
|
||||
// (a) => a.isUsed && a.type === "Spawn"
|
||||
// );
|
||||
// if (spawnAction) {
|
||||
// return { point, path };
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// // Create a new spawned object with proper initial position
|
||||
// function createSpawnedObject(process, spawnPoint, currentTime, materialType) {
|
||||
// // Extract spawn position from the actual spawn point
|
||||
// const position = spawnPoint.point.position
|
||||
// ? [...spawnPoint.point.position]
|
||||
// : [0, 0, 0];
|
||||
|
||||
// // Get the path position and add it to the spawn point position
|
||||
// const pathPosition = spawnPoint.path.pathPosition || [0, 0, 0];
|
||||
// const absolutePosition = [
|
||||
// position[0] + pathPosition[0],
|
||||
// position[1] + pathPosition[1],
|
||||
// position[2] + pathPosition[2],
|
||||
// ];
|
||||
|
||||
// return {
|
||||
// id: `obj-${process.id}-${animationStates[process.id].objectIdCounter}`,
|
||||
// position: absolutePosition,
|
||||
// state: {
|
||||
// currentIndex: 0,
|
||||
// progress: 0,
|
||||
// isAnimating: true,
|
||||
// speed: process.speed || 1,
|
||||
// isDelaying: false,
|
||||
// delayStartTime: 0,
|
||||
// currentDelayDuration: 0,
|
||||
// delayComplete: false,
|
||||
// currentPathIndex: 0,
|
||||
// // Store the spawn point index to start animation from correct path point
|
||||
// spawnPointIndex: getPointIndexInProcess(process, spawnPoint.point),
|
||||
// },
|
||||
// visible: true,
|
||||
// materialType: materialType || "Default",
|
||||
// spawnTime: currentTime,
|
||||
// };
|
||||
// }
|
||||
|
||||
// // Get the index of a point within the process animation path
|
||||
// function getPointIndexInProcess(process, point) {
|
||||
// if (!process.paths) return 0;
|
||||
|
||||
// let cumulativePoints = 0;
|
||||
// for (const path of process.paths) {
|
||||
// for (let i = 0; i < (path.points?.length || 0); i++) {
|
||||
// if (path.points[i].uuid === point.uuid) {
|
||||
// return cumulativePoints + i;
|
||||
// }
|
||||
// }
|
||||
// cumulativePoints += path.points?.length || 0;
|
||||
// }
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// // Get point data for current animation index
|
||||
// function getPointDataForAnimationIndex(process, index) {
|
||||
// if (!process.paths) return null;
|
||||
|
||||
// let cumulativePoints = 0;
|
||||
// for (const path of process.paths) {
|
||||
// const pointCount = path.points?.length || 0;
|
||||
|
||||
// if (index < cumulativePoints + pointCount) {
|
||||
// const pointIndex = index - cumulativePoints;
|
||||
// return path.points?.[pointIndex] || null;
|
||||
// }
|
||||
|
||||
// cumulativePoints += pointCount;
|
||||
// }
|
||||
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// // Convert process paths to Vector3 format
|
||||
// function getProcessPath(process) {
|
||||
// return process.animationPath?.map((p) => ({ x: p.x, y: p.y, z: p.z })) || [];
|
||||
// }
|
||||
|
||||
// // Handle material swap for an object
|
||||
// function handleMaterialSwap(processId, objectId, materialType) {
|
||||
// const processState = animationStates[processId];
|
||||
// if (!processState || !processState.spawnedObjects[objectId]) return;
|
||||
|
||||
// processState.spawnedObjects[objectId].materialType = materialType;
|
||||
|
||||
// // Notify main thread about material change
|
||||
// self.postMessage({
|
||||
// type: "materialChanged",
|
||||
// data: {
|
||||
// processId,
|
||||
// objectId,
|
||||
// materialType,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// // Handle point actions for an object
|
||||
// function handlePointActions(processId, objectId, actions = [], currentTime) {
|
||||
// let shouldStopAnimation = false;
|
||||
// const processState = animationStates[processId];
|
||||
|
||||
// if (!processState || !processState.spawnedObjects[objectId]) return false;
|
||||
|
||||
// const objectState = processState.spawnedObjects[objectId];
|
||||
|
||||
// actions.forEach((action) => {
|
||||
// if (!action.isUsed) return;
|
||||
|
||||
// switch (action.type) {
|
||||
// case "Delay":
|
||||
// if (objectState.state.isDelaying) return;
|
||||
|
||||
// const delayDuration =
|
||||
// typeof action.delay === "number"
|
||||
// ? action.delay
|
||||
// : parseFloat(action.delay || "0");
|
||||
|
||||
// if (delayDuration > 0) {
|
||||
// objectState.state.isDelaying = true;
|
||||
// objectState.state.delayStartTime = currentTime;
|
||||
// objectState.state.currentDelayDuration = delayDuration;
|
||||
// objectState.state.delayComplete = false;
|
||||
// shouldStopAnimation = true;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case "Despawn":
|
||||
// delete processState.spawnedObjects[objectId];
|
||||
// shouldStopAnimation = true;
|
||||
|
||||
// // Notify main thread about despawn
|
||||
// self.postMessage({
|
||||
// type: "objectDespawned",
|
||||
// data: {
|
||||
// processId,
|
||||
// objectId,
|
||||
// },
|
||||
// });
|
||||
// break;
|
||||
|
||||
// case "Swap":
|
||||
// if (action.material) {
|
||||
// handleMaterialSwap(processId, objectId, action.material);
|
||||
// }
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// });
|
||||
|
||||
// return shouldStopAnimation;
|
||||
// }
|
||||
|
||||
// // Check if point has non-inherit actions
|
||||
// function hasNonInheritActions(actions = []) {
|
||||
// return actions.some((action) => action.isUsed && action.type !== "Inherit");
|
||||
// }
|
||||
|
||||
// // Calculate vector lerp (linear interpolation)
|
||||
// function lerpVectors(v1, v2, alpha) {
|
||||
// return {
|
||||
// x: v1.x + (v2.x - v1.x) * alpha,
|
||||
// y: v1.y + (v2.y - v1.y) * alpha,
|
||||
// z: v1.z + (v2.z - v1.z) * alpha,
|
||||
// };
|
||||
// }
|
||||
|
||||
// // Calculate vector distance
|
||||
// function distanceBetweenVectors(v1, v2) {
|
||||
// const dx = v2.x - v1.x;
|
||||
// const dy = v2.y - v1.y;
|
||||
// const dz = v2.z - v1.z;
|
||||
// return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
// }
|
||||
|
||||
// // Process spawn logic
|
||||
// function processSpawns(currentTime) {
|
||||
// processes.forEach((process) => {
|
||||
// const processState = animationStates[process.id];
|
||||
// if (!processState) return;
|
||||
|
||||
// const spawnPointData = findSpawnPoint(process);
|
||||
// if (!spawnPointData || !spawnPointData.point.actions) return;
|
||||
|
||||
// const spawnAction = spawnPointData.point.actions.find(
|
||||
// (a) => a.isUsed && a.type === "Spawn"
|
||||
// );
|
||||
// if (!spawnAction) return;
|
||||
|
||||
// const spawnInterval =
|
||||
// typeof spawnAction.spawnInterval === "number"
|
||||
// ? spawnAction.spawnInterval
|
||||
// : parseFloat(spawnAction.spawnInterval || "0");
|
||||
|
||||
// if (currentTime >= processState.nextSpawnTime) {
|
||||
// const newObject = createSpawnedObject(
|
||||
// process,
|
||||
// spawnPointData,
|
||||
// currentTime,
|
||||
// spawnAction.material || "Default"
|
||||
// );
|
||||
|
||||
// processState.spawnedObjects[newObject.id] = newObject;
|
||||
// processState.objectIdCounter++;
|
||||
// processState.nextSpawnTime = currentTime + spawnInterval;
|
||||
|
||||
// // Notify main thread about new object
|
||||
// self.postMessage({
|
||||
// type: "objectSpawned",
|
||||
// data: {
|
||||
// processId: process.id,
|
||||
// object: newObject,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// // Update all animations
|
||||
// function updateAnimations(delta, currentTime) {
|
||||
// // First handle spawning of new objects
|
||||
// processSpawns(currentTime);
|
||||
|
||||
// // Then animate existing objects
|
||||
// processes.forEach((process) => {
|
||||
// const processState = animationStates[process.id];
|
||||
// if (!processState) return;
|
||||
|
||||
// const path = getProcessPath(process);
|
||||
// if (path.length < 2) return;
|
||||
|
||||
// const updatedObjects = {};
|
||||
// let hasChanges = false;
|
||||
|
||||
// Object.entries(processState.spawnedObjects).forEach(([objectId, obj]) => {
|
||||
// if (!obj.visible || !obj.state.isAnimating) return;
|
||||
|
||||
// const stateRef = obj.state;
|
||||
|
||||
// // Use the spawnPointIndex as starting point if it's the initial movement
|
||||
// if (stateRef.currentIndex === 0 && stateRef.progress === 0) {
|
||||
// stateRef.currentIndex = stateRef.spawnPointIndex || 0;
|
||||
// }
|
||||
|
||||
// // Get current point data
|
||||
// const currentPointData = getPointDataForAnimationIndex(
|
||||
// process,
|
||||
// stateRef.currentIndex
|
||||
// );
|
||||
|
||||
// // Execute actions when arriving at a new point
|
||||
// if (stateRef.progress === 0 && currentPointData?.actions) {
|
||||
// const shouldStop = handlePointActions(
|
||||
// process.id,
|
||||
// objectId,
|
||||
// currentPointData.actions,
|
||||
// currentTime
|
||||
// );
|
||||
// if (shouldStop) return;
|
||||
// }
|
||||
|
||||
// // Handle delays
|
||||
// if (stateRef.isDelaying) {
|
||||
// if (
|
||||
// currentTime - stateRef.delayStartTime >=
|
||||
// stateRef.currentDelayDuration
|
||||
// ) {
|
||||
// stateRef.isDelaying = false;
|
||||
// stateRef.delayComplete = true;
|
||||
// } else {
|
||||
// updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
||||
// return; // Keep waiting
|
||||
// }
|
||||
// }
|
||||
|
||||
// const nextPointIdx = stateRef.currentIndex + 1;
|
||||
// const isLastPoint = nextPointIdx >= path.length;
|
||||
|
||||
// if (isLastPoint) {
|
||||
// if (currentPointData?.actions) {
|
||||
// const shouldStop = !hasNonInheritActions(currentPointData.actions);
|
||||
// if (shouldStop) {
|
||||
// // Reached the end of path with no more actions
|
||||
// delete processState.spawnedObjects[objectId];
|
||||
|
||||
// // Notify main thread to remove the object
|
||||
// self.postMessage({
|
||||
// type: "objectCompleted",
|
||||
// data: {
|
||||
// processId: process.id,
|
||||
// objectId,
|
||||
// },
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!isLastPoint) {
|
||||
// const currentPos = path[stateRef.currentIndex];
|
||||
// const nextPos = path[nextPointIdx];
|
||||
// const distance = distanceBetweenVectors(currentPos, nextPos);
|
||||
// const movement = stateRef.speed * delta;
|
||||
|
||||
// // Update progress based on distance and speed
|
||||
// const oldProgress = stateRef.progress;
|
||||
// stateRef.progress += movement / distance;
|
||||
|
||||
// if (stateRef.progress >= 1) {
|
||||
// // Reached next point
|
||||
// stateRef.currentIndex = nextPointIdx;
|
||||
// stateRef.progress = 0;
|
||||
// stateRef.delayComplete = false;
|
||||
// obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
||||
// } else {
|
||||
// // Interpolate position
|
||||
// const lerpedPos = lerpVectors(currentPos, nextPos, stateRef.progress);
|
||||
// obj.position = [lerpedPos.x, lerpedPos.y, lerpedPos.z];
|
||||
// }
|
||||
|
||||
// // Only send updates when there's meaningful movement
|
||||
// if (Math.abs(oldProgress - stateRef.progress) > 0.01) {
|
||||
// hasChanges = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
||||
// });
|
||||
|
||||
// // Update animation state with modified objects
|
||||
// if (Object.keys(updatedObjects).length > 0) {
|
||||
// processState.spawnedObjects = {
|
||||
// ...processState.spawnedObjects,
|
||||
// ...updatedObjects,
|
||||
// };
|
||||
|
||||
// // Only send position updates when there are meaningful changes
|
||||
// if (hasChanges) {
|
||||
// self.postMessage({
|
||||
// type: "positionsUpdated",
|
||||
// data: {
|
||||
// processId: process.id,
|
||||
// objects: updatedObjects,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// animation-worker.js
|
||||
// This web worker handles animation calculations off the main thread
|
||||
|
||||
/* eslint-disable no-restricted-globals */
|
||||
// The above disables the ESLint rule for this file since 'self' is valid in web workers
|
||||
|
||||
// Store process data, animation states, and objects
|
||||
let processes = [];
|
||||
let animationStates = {};
|
||||
let lastTimestamp = 0;
|
||||
let debugMode = true;
|
||||
|
||||
// Logger function for debugging
|
||||
function log(...args) {
|
||||
if (debugMode) {
|
||||
self.postMessage({
|
||||
type: "debug",
|
||||
data: { message: args.join(' ') }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Message handler for communication with main thread
|
||||
self.onmessage = function (event) {
|
||||
const { type, data } = event.data;
|
||||
log(`Worker received message: ${type}`);
|
||||
|
||||
switch (type) {
|
||||
case "initialize":
|
||||
processes = data.processes;
|
||||
log(`Initialized with ${processes.length} processes`);
|
||||
initializeAnimationStates();
|
||||
break;
|
||||
|
||||
case "update":
|
||||
const { timestamp, isPlaying } = data;
|
||||
if (isPlaying) {
|
||||
const delta = lastTimestamp === 0 ? 0.016 : (timestamp - lastTimestamp) / 1000; // Convert to seconds
|
||||
updateAnimations(delta, timestamp);
|
||||
}
|
||||
lastTimestamp = timestamp;
|
||||
break;
|
||||
|
||||
case "reset":
|
||||
log("Resetting animations");
|
||||
resetAnimations();
|
||||
break;
|
||||
|
||||
case "togglePlay":
|
||||
// If resuming from pause, recalculate the time delta
|
||||
log(`Toggle play: ${data.isPlaying}`);
|
||||
lastTimestamp = data.timestamp;
|
||||
break;
|
||||
|
||||
case "setDebug":
|
||||
debugMode = data.enabled;
|
||||
log(`Debug mode: ${debugMode}`);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize animation states for all processes
|
||||
function initializeAnimationStates() {
|
||||
animationStates = {};
|
||||
|
||||
processes.forEach((process) => {
|
||||
if (!process || !process.id) {
|
||||
log("Invalid process found:", process);
|
||||
return;
|
||||
}
|
||||
|
||||
animationStates[process.id] = {
|
||||
spawnedObjects: {},
|
||||
nextSpawnTime: 0,
|
||||
objectIdCounter: 0,
|
||||
};
|
||||
});
|
||||
|
||||
// Send initial states back to main thread
|
||||
self.postMessage({
|
||||
type: "statesInitialized",
|
||||
data: { animationStates },
|
||||
});
|
||||
}
|
||||
|
||||
// Reset all animations
|
||||
function resetAnimations() {
|
||||
initializeAnimationStates();
|
||||
}
|
||||
|
||||
// Find spawn point in a process
|
||||
function findSpawnPoint(process) {
|
||||
if (!process || !process.paths) {
|
||||
log(`No paths found for process ${process?.id}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const path of process.paths) {
|
||||
if (!path || !path.points) continue;
|
||||
|
||||
for (const point of path.points) {
|
||||
if (!point || !point.actions) continue;
|
||||
|
||||
const spawnAction = point.actions.find(
|
||||
(a) => a && a.isUsed && a.type === "Spawn"
|
||||
);
|
||||
if (spawnAction) {
|
||||
return { point, path };
|
||||
}
|
||||
}
|
||||
}
|
||||
log(`No spawn points found for process ${process.id}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create a new spawned object with proper initial position
|
||||
function createSpawnedObject(process, spawnPoint, currentTime, materialType) {
|
||||
// Extract spawn position from the actual spawn point
|
||||
const position = spawnPoint.point.position
|
||||
? [...spawnPoint.point.position]
|
||||
: [0, 0, 0];
|
||||
|
||||
// Get the path position and add it to the spawn point position
|
||||
const pathPosition = spawnPoint.path.pathPosition || [0, 0, 0];
|
||||
const absolutePosition = [
|
||||
position[0] + pathPosition[0],
|
||||
position[1] + pathPosition[1],
|
||||
position[2] + pathPosition[2],
|
||||
];
|
||||
|
||||
return {
|
||||
id: `obj-${process.id}-${animationStates[process.id].objectIdCounter}`,
|
||||
position: absolutePosition,
|
||||
state: {
|
||||
currentIndex: 0,
|
||||
progress: 0,
|
||||
isAnimating: true,
|
||||
speed: process.speed || 1,
|
||||
isDelaying: false,
|
||||
delayStartTime: 0,
|
||||
currentDelayDuration: 0,
|
||||
delayComplete: false,
|
||||
currentPathIndex: 0,
|
||||
// Store the spawn point index to start animation from correct path point
|
||||
spawnPointIndex: getPointIndexInProcess(process, spawnPoint.point),
|
||||
},
|
||||
visible: true,
|
||||
materialType: materialType || "Default",
|
||||
spawnTime: currentTime,
|
||||
};
|
||||
}
|
||||
|
||||
// Get the index of a point within the process animation path
|
||||
function getPointIndexInProcess(process, point) {
|
||||
if (!process.paths) return 0;
|
||||
|
||||
let cumulativePoints = 0;
|
||||
for (const path of process.paths) {
|
||||
for (let i = 0; i < (path.points?.length || 0); i++) {
|
||||
if (path.points[i].uuid === point.uuid) {
|
||||
return cumulativePoints + i;
|
||||
}
|
||||
}
|
||||
cumulativePoints += path.points?.length || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get point data for current animation index
|
||||
function getPointDataForAnimationIndex(process, index) {
|
||||
if (!process.paths) return null;
|
||||
|
||||
let cumulativePoints = 0;
|
||||
for (const path of process.paths) {
|
||||
const pointCount = path.points?.length || 0;
|
||||
|
||||
if (index < cumulativePoints + pointCount) {
|
||||
const pointIndex = index - cumulativePoints;
|
||||
return path.points?.[pointIndex] || null;
|
||||
}
|
||||
|
||||
cumulativePoints += pointCount;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Convert process paths to Vector3 format
|
||||
function getProcessPath(process) {
|
||||
if (!process.animationPath) {
|
||||
log(`No animation path for process ${process.id}`);
|
||||
return [];
|
||||
}
|
||||
return process.animationPath.map((p) => ({ x: p.x, y: p.y, z: p.z })) || [];
|
||||
}
|
||||
|
||||
// Handle material swap for an object
|
||||
function handleMaterialSwap(processId, objectId, materialType) {
|
||||
const processState = animationStates[processId];
|
||||
if (!processState || !processState.spawnedObjects[objectId]) return;
|
||||
|
||||
processState.spawnedObjects[objectId].materialType = materialType;
|
||||
|
||||
// Notify main thread about material change
|
||||
self.postMessage({
|
||||
type: "materialChanged",
|
||||
data: {
|
||||
processId,
|
||||
objectId,
|
||||
materialType,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Handle point actions for an object
|
||||
function handlePointActions(processId, objectId, actions = [], currentTime) {
|
||||
let shouldStopAnimation = false;
|
||||
const processState = animationStates[processId];
|
||||
|
||||
if (!processState || !processState.spawnedObjects[objectId]) return false;
|
||||
|
||||
const objectState = processState.spawnedObjects[objectId];
|
||||
|
||||
actions.forEach((action) => {
|
||||
if (!action || !action.isUsed) return;
|
||||
|
||||
switch (action.type) {
|
||||
case "Delay":
|
||||
if (objectState.state.isDelaying) return;
|
||||
|
||||
const delayDuration =
|
||||
typeof action.delay === "number"
|
||||
? action.delay
|
||||
: parseFloat(action.delay || "0");
|
||||
|
||||
if (delayDuration > 0) {
|
||||
objectState.state.isDelaying = true;
|
||||
objectState.state.delayStartTime = currentTime;
|
||||
objectState.state.currentDelayDuration = delayDuration;
|
||||
objectState.state.delayComplete = false;
|
||||
shouldStopAnimation = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Despawn":
|
||||
delete processState.spawnedObjects[objectId];
|
||||
shouldStopAnimation = true;
|
||||
|
||||
// Notify main thread about despawn
|
||||
self.postMessage({
|
||||
type: "objectDespawned",
|
||||
data: {
|
||||
processId,
|
||||
objectId,
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
||||
case "Swap":
|
||||
if (action.material) {
|
||||
handleMaterialSwap(processId, objectId, action.material);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return shouldStopAnimation;
|
||||
}
|
||||
|
||||
// Check if point has non-inherit actions
|
||||
function hasNonInheritActions(actions = []) {
|
||||
return actions.some((action) => action && action.isUsed && action.type !== "Inherit");
|
||||
}
|
||||
|
||||
// Calculate vector lerp (linear interpolation)
|
||||
function lerpVectors(v1, v2, alpha) {
|
||||
return {
|
||||
x: v1.x + (v2.x - v1.x) * alpha,
|
||||
y: v1.y + (v2.y - v1.y) * alpha,
|
||||
z: v1.z + (v2.z - v1.z) * alpha,
|
||||
};
|
||||
}
|
||||
|
||||
// Calculate vector distance
|
||||
function distanceBetweenVectors(v1, v2) {
|
||||
const dx = v2.x - v1.x;
|
||||
const dy = v2.y - v1.y;
|
||||
const dz = v2.z - v1.z;
|
||||
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
// Process spawn logic
|
||||
function processSpawns(currentTime) {
|
||||
processes.forEach((process) => {
|
||||
const processState = animationStates[process.id];
|
||||
if (!processState) return;
|
||||
|
||||
const spawnPointData = findSpawnPoint(process);
|
||||
if (!spawnPointData || !spawnPointData.point.actions) return;
|
||||
|
||||
const spawnAction = spawnPointData.point.actions.find(
|
||||
(a) => a.isUsed && a.type === "Spawn"
|
||||
);
|
||||
if (!spawnAction) return;
|
||||
|
||||
const spawnInterval =
|
||||
typeof spawnAction.spawnInterval === "number"
|
||||
? spawnAction.spawnInterval
|
||||
: parseFloat(spawnAction.spawnInterval || "2"); // Default to 2 seconds if not specified
|
||||
|
||||
if (currentTime >= processState.nextSpawnTime) {
|
||||
const newObject = createSpawnedObject(
|
||||
process,
|
||||
spawnPointData,
|
||||
currentTime,
|
||||
spawnAction.material || "Default"
|
||||
);
|
||||
|
||||
processState.spawnedObjects[newObject.id] = newObject;
|
||||
processState.objectIdCounter++;
|
||||
processState.nextSpawnTime = currentTime + spawnInterval;
|
||||
|
||||
log(`Spawned object ${newObject.id} for process ${process.id}`);
|
||||
|
||||
// Notify main thread about new object
|
||||
self.postMessage({
|
||||
type: "objectSpawned",
|
||||
data: {
|
||||
processId: process.id,
|
||||
object: newObject,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Update all animations
|
||||
function updateAnimations(delta, currentTime) {
|
||||
// First handle spawning of new objects
|
||||
processSpawns(currentTime);
|
||||
|
||||
// Then animate existing objects
|
||||
processes.forEach((process) => {
|
||||
const processState = animationStates[process.id];
|
||||
if (!processState) return;
|
||||
|
||||
const path = getProcessPath(process);
|
||||
if (path.length < 2) {
|
||||
log(`Path too short for process ${process.id}, length: ${path.length}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedObjects = {};
|
||||
let hasChanges = false;
|
||||
|
||||
Object.entries(processState.spawnedObjects).forEach(([objectId, obj]) => {
|
||||
if (!obj.visible || !obj.state.isAnimating) return;
|
||||
|
||||
const stateRef = obj.state;
|
||||
|
||||
// Use the spawnPointIndex as starting point if it's the initial movement
|
||||
if (stateRef.currentIndex === 0 && stateRef.progress === 0) {
|
||||
stateRef.currentIndex = stateRef.spawnPointIndex || 0;
|
||||
}
|
||||
|
||||
// Get current point data
|
||||
const currentPointData = getPointDataForAnimationIndex(
|
||||
process,
|
||||
stateRef.currentIndex
|
||||
);
|
||||
|
||||
// Execute actions when arriving at a new point
|
||||
if (stateRef.progress === 0 && currentPointData?.actions) {
|
||||
const shouldStop = handlePointActions(
|
||||
process.id,
|
||||
objectId,
|
||||
currentPointData.actions,
|
||||
currentTime
|
||||
);
|
||||
if (shouldStop) return;
|
||||
}
|
||||
|
||||
// Handle delays
|
||||
if (stateRef.isDelaying) {
|
||||
if (
|
||||
currentTime - stateRef.delayStartTime >=
|
||||
stateRef.currentDelayDuration
|
||||
) {
|
||||
stateRef.isDelaying = false;
|
||||
stateRef.delayComplete = true;
|
||||
} else {
|
||||
updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
||||
return; // Keep waiting
|
||||
}
|
||||
}
|
||||
|
||||
const nextPointIdx = stateRef.currentIndex + 1;
|
||||
const isLastPoint = nextPointIdx >= path.length;
|
||||
|
||||
if (isLastPoint) {
|
||||
if (currentPointData?.actions) {
|
||||
const shouldStop = !hasNonInheritActions(currentPointData.actions);
|
||||
if (shouldStop) {
|
||||
// Reached the end of path with no more actions
|
||||
delete processState.spawnedObjects[objectId];
|
||||
log(`Object ${objectId} completed path`);
|
||||
|
||||
// Notify main thread to remove the object
|
||||
self.postMessage({
|
||||
type: "objectCompleted",
|
||||
data: {
|
||||
processId: process.id,
|
||||
objectId,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLastPoint) {
|
||||
const currentPos = path[stateRef.currentIndex];
|
||||
const nextPos = path[nextPointIdx];
|
||||
const distance = distanceBetweenVectors(currentPos, nextPos);
|
||||
|
||||
// Ensure we don't divide by zero
|
||||
if (distance > 0) {
|
||||
const movement = stateRef.speed * delta;
|
||||
|
||||
// Update progress based on distance and speed
|
||||
const oldProgress = stateRef.progress;
|
||||
stateRef.progress += movement / distance;
|
||||
|
||||
if (stateRef.progress >= 1) {
|
||||
// Reached next point
|
||||
stateRef.currentIndex = nextPointIdx;
|
||||
stateRef.progress = 0;
|
||||
stateRef.delayComplete = false;
|
||||
obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
||||
} else {
|
||||
// Interpolate position
|
||||
const lerpedPos = lerpVectors(currentPos, nextPos, stateRef.progress);
|
||||
obj.position = [lerpedPos.x, lerpedPos.y, lerpedPos.z];
|
||||
}
|
||||
|
||||
// Only send updates when there's meaningful movement
|
||||
if (Math.abs(oldProgress - stateRef.progress) > 0.01) {
|
||||
hasChanges = true;
|
||||
}
|
||||
} else {
|
||||
// Skip to next point if distance is zero
|
||||
stateRef.currentIndex = nextPointIdx;
|
||||
stateRef.progress = 0;
|
||||
obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
||||
});
|
||||
|
||||
// Update animation state with modified objects
|
||||
if (Object.keys(updatedObjects).length > 0) {
|
||||
processState.spawnedObjects = {
|
||||
...processState.spawnedObjects,
|
||||
...updatedObjects,
|
||||
};
|
||||
|
||||
// Only send position updates when there are meaningful changes
|
||||
if (hasChanges) {
|
||||
self.postMessage({
|
||||
type: "positionsUpdated",
|
||||
data: {
|
||||
processId: process.id,
|
||||
objects: updatedObjects,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -486,20 +486,20 @@ function convertToSimulationPath(
|
|||
modeluuid,
|
||||
points: [
|
||||
{
|
||||
uuid: path.point.uuid,
|
||||
position: path.point.position,
|
||||
actions: Array.isArray(path.point.actions)
|
||||
? path.point.actions.map(normalizeAction)
|
||||
: [normalizeAction(path.point.actions)],
|
||||
uuid: path.points.uuid,
|
||||
position: path.points.position,
|
||||
actions: Array.isArray(path.points.actions)
|
||||
? path.points.actions.map(normalizeAction)
|
||||
: [normalizeAction(path.points.actions)],
|
||||
connections: {
|
||||
targets: path.point.connections.targets.map((target) => ({
|
||||
targets: path.points.connections.targets.map((target) => ({
|
||||
pathUUID: target.pathUUID,
|
||||
})),
|
||||
},
|
||||
},
|
||||
],
|
||||
pathPosition: path.position,
|
||||
speed: path.point.speed || 1,
|
||||
speed: path.points.speed || 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
import React, { useRef, useEffect } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import { GLTF } from "three-stdlib";
|
||||
import { Box3Helper } from "three";
|
||||
import { SpawnedObject, ProcessData } from "./types";
|
||||
|
||||
interface ProcessObjectRendererProps {
|
||||
objectId: string;
|
||||
object: SpawnedObject;
|
||||
process: ProcessData;
|
||||
gltf: GLTF;
|
||||
showBoundingBox?: boolean;
|
||||
}
|
||||
|
||||
export const ProcessObjectRenderer: React.FC<ProcessObjectRendererProps> = ({
|
||||
objectId,
|
||||
object,
|
||||
process,
|
||||
gltf,
|
||||
showBoundingBox = false,
|
||||
}) => {
|
||||
const meshRef = useRef<THREE.Mesh>(null);
|
||||
const boxHelperRef = useRef<THREE.Box3Helper | null>(null);
|
||||
const boundingBoxRef = useRef<THREE.Box3>(new THREE.Box3());
|
||||
|
||||
// Issue 1: Can't assign to ref.current as it's read-only
|
||||
useEffect(() => {
|
||||
if (object.ref && meshRef.current) {
|
||||
// Instead of direct assignment, we need to store the mesh reference another way
|
||||
// Option 1: If you can modify the SpawnedObject interface, add a setMesh method
|
||||
if (typeof (object as any).setMesh === 'function') {
|
||||
(object as any).setMesh(meshRef.current);
|
||||
}
|
||||
|
||||
// Option 2: Store the mesh in a property that isn't ref.current
|
||||
// This requires modifying your SpawnedObject interface to include this property
|
||||
(object as any).meshInstance = meshRef.current;
|
||||
|
||||
// Option 3: If you need to maintain compatibility, you could use Object.defineProperty
|
||||
// But this is a hack and not recommended
|
||||
// Object.defineProperty(object.ref, 'current', { value: meshRef.current, writable: true });
|
||||
}
|
||||
}, [object.ref]);
|
||||
|
||||
// Create a bounding box helper for visualization
|
||||
useFrame(() => {
|
||||
if (meshRef.current && showBoundingBox) {
|
||||
// Update the bounding box to match the mesh position
|
||||
if (!boxHelperRef.current) {
|
||||
// Get the size of the mesh
|
||||
const size = new THREE.Vector3(1, 1, 1);
|
||||
|
||||
// If the mesh has geometry, use its dimensions
|
||||
if (meshRef.current.geometry) {
|
||||
const box = new THREE.Box3().setFromObject(meshRef.current);
|
||||
box.getSize(size);
|
||||
}
|
||||
|
||||
// Create a new bounding box centered on the mesh
|
||||
boundingBoxRef.current = new THREE.Box3().setFromCenterAndSize(
|
||||
meshRef.current.position,
|
||||
size
|
||||
);
|
||||
|
||||
// Create a helper to visualize the box
|
||||
boxHelperRef.current = new Box3Helper(
|
||||
boundingBoxRef.current,
|
||||
new THREE.Color(0xff0000)
|
||||
);
|
||||
|
||||
// Add the helper to the scene
|
||||
meshRef.current.parent?.add(boxHelperRef.current);
|
||||
} else {
|
||||
// Update the box position to match the mesh
|
||||
boundingBoxRef.current.setFromCenterAndSize(
|
||||
meshRef.current.position,
|
||||
boundingBoxRef.current.getSize(new THREE.Vector3())
|
||||
);
|
||||
|
||||
// Force the helper to update
|
||||
boxHelperRef.current.updateMatrixWorld(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (gltf?.scene) {
|
||||
return (
|
||||
<primitive
|
||||
ref={meshRef}
|
||||
object={gltf.scene.clone()}
|
||||
position={[0, 0, 0]}
|
||||
material={object.material}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Issue 2: Material color type problem
|
||||
return (
|
||||
<mesh ref={meshRef}>
|
||||
<boxGeometry args={[1, 1, 1]} />
|
||||
<meshStandardMaterial
|
||||
// Fix the color property access
|
||||
color={
|
||||
object.material && 'color' in object.material
|
||||
? (object.material as THREE.MeshStandardMaterial).color
|
||||
: "#00ff00"
|
||||
}
|
||||
metalness={0.5}
|
||||
roughness={0.3}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
import * as THREE from "three";
|
||||
import React from "react";
|
||||
|
||||
export interface ProcessPoint {
|
||||
uuid: string;
|
||||
position: number[];
|
||||
actions?: PointAction[];
|
||||
}
|
||||
|
||||
export interface PointAction {
|
||||
type: string;
|
||||
isUsed: boolean;
|
||||
spawnInterval?: number | string;
|
||||
material?: string;
|
||||
delay?: number | string;
|
||||
}
|
||||
|
||||
export interface ProcessData {
|
||||
id: string;
|
||||
name: string;
|
||||
paths?: {
|
||||
points?: ProcessPoint[];
|
||||
}[];
|
||||
animationPath?: { x: number; y: number; z: number }[];
|
||||
speed?: number;
|
||||
customMaterials?: Record<string, THREE.Material>;
|
||||
}
|
||||
|
||||
export interface ProcessAnimationState {
|
||||
spawnedObjects: Record<string, SpawnedObject | SpawnedObjectWithCollision>;
|
||||
nextSpawnTime: number;
|
||||
objectIdCounter: number;
|
||||
isProcessDelaying: boolean;
|
||||
processDelayStartTime: number;
|
||||
processDelayDuration: number;
|
||||
isCollisionPaused?: boolean;
|
||||
}
|
||||
|
||||
export interface SpawnedObject {
|
||||
ref: React.RefObject<THREE.Object3D>;
|
||||
state: {
|
||||
currentIndex: number;
|
||||
progress: number;
|
||||
isAnimating: boolean;
|
||||
speed: number;
|
||||
isDelaying: boolean;
|
||||
delayStartTime: number;
|
||||
currentDelayDuration: number;
|
||||
delayComplete: boolean;
|
||||
currentPathIndex: number;
|
||||
};
|
||||
visible: boolean;
|
||||
material: THREE.Material;
|
||||
currentMaterialType: string;
|
||||
spawnTime: number;
|
||||
position: THREE.Vector3;
|
||||
collision?: {
|
||||
boundingBox: THREE.Box3;
|
||||
isColliding: boolean;
|
||||
colliding: boolean; // Added this property
|
||||
};
|
||||
}
|
||||
|
||||
// For use in your processAnimator.tsx
|
||||
// Update the CollisionState interface to include all required properties
|
||||
interface CollisionState {
|
||||
boundingBox: THREE.Box3;
|
||||
isColliding: boolean;
|
||||
colliding: boolean; // This was missing
|
||||
collidingWith: string[];
|
||||
}
|
||||
export interface SpawnedObjectWithCollision extends SpawnedObject {
|
||||
collision: {
|
||||
boundingBox: THREE.Box3;
|
||||
isColliding: boolean;
|
||||
colliding: boolean;
|
||||
collidingWith: string[];
|
||||
};
|
||||
}
|
|
@ -19,7 +19,7 @@ function Simulation() {
|
|||
const [processes, setProcesses] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('simulationPaths: ', simulationPaths);
|
||||
// console.log('simulationPaths: ', simulationPaths);
|
||||
}, [simulationPaths]);
|
||||
|
||||
// useEffect(() => {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) => {
|
||||
// if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
// if (point.uuid === selectedActionSphere.points.uuid) {
|
||||
// const actionIndex = point.actions.length;
|
||||
// const newAction = {
|
||||
// uuid: THREE.MathUtils.generateUUID(),
|
||||
|
@ -46,7 +46,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
||||
// : point
|
||||
// ),
|
||||
|
@ -61,7 +61,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) =>
|
||||
|
@ -81,7 +81,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) =>
|
||||
|
@ -101,7 +101,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) =>
|
||||
|
@ -121,7 +121,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) =>
|
||||
|
@ -152,7 +152,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) => {
|
||||
// if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
// if (point.uuid === selectedActionSphere.points.uuid) {
|
||||
// const triggerIndex = point.triggers.length;
|
||||
// const newTrigger = {
|
||||
// uuid: THREE.MathUtils.generateUUID(),
|
||||
|
@ -176,7 +176,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
||||
// : point
|
||||
// ),
|
||||
|
@ -191,7 +191,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// triggers: point.triggers.map((trigger) =>
|
||||
|
@ -217,7 +217,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) => ({
|
||||
|
@ -238,7 +238,7 @@
|
|||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// point.uuid === selectedActionSphere.points.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// triggers: point.triggers.map((trigger) => ({
|
||||
|
@ -255,7 +255,7 @@
|
|||
|
||||
// const selectedPoint = useMemo(() => {
|
||||
// if (!selectedActionSphere) return null;
|
||||
// return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||
// return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.points.uuid);
|
||||
// }, [selectedActionSphere, simulationPaths]);
|
||||
|
||||
// const createPath = () => {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_ASSET_LIBRARY_URL}`;
|
||||
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
export const getCategoryAsset = async (categoryName: any) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BackEnd_url}/api/v2/getCatagoryAssets/${categoryName}`,
|
||||
`${BackEnd_url}/api/v2/getCategoryAssets/${categoryName}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
|
|
|
@ -17,7 +17,7 @@ export const setEventApi = async (
|
|||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to set or update Floor Item");
|
||||
throw new Error("Failed to set or Update Event Data");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
|
|
@ -4,8 +4,32 @@ type PlayButtonStore = {
|
|||
isPlaying: boolean; // Updated state name to reflect the play/pause status more clearly
|
||||
setIsPlaying: (value: boolean) => void; // Updated setter function name for clarity
|
||||
};
|
||||
type PauseButtonStore = {
|
||||
isPaused: boolean; // Updated state name to reflect the play/pause status more clearly
|
||||
setIsPaused: (value: boolean) => void; // Updated setter function name for clarity
|
||||
};
|
||||
type ResetButtonStore = {
|
||||
isReset: boolean; // Updated state name to reflect the play/pause status more clearly
|
||||
setReset: (value: boolean) => void; // Updated setter function name for clarity
|
||||
};
|
||||
interface AnimationSpeedState {
|
||||
speed: number;
|
||||
setSpeed: (value: number) => void;
|
||||
}
|
||||
|
||||
export const usePlayButtonStore = create<PlayButtonStore>((set) => ({
|
||||
isPlaying: false, // Default state for play/pause
|
||||
setIsPlaying: (value) => set({ isPlaying: value }), // Update isPlaying state
|
||||
}));
|
||||
export const useResetButtonStore = create<ResetButtonStore>((set) => ({
|
||||
isReset: false, // Default state for play/pause
|
||||
setReset: (value) => set({ isReset: value }), // Update isPlaying state
|
||||
}));
|
||||
export const usePauseButtonStore = create<PauseButtonStore>((set) => ({
|
||||
isPaused: false, // Default state for play/pause
|
||||
setIsPaused: (value) => set({ isPaused: value }), // Update isPlaying state
|
||||
}));
|
||||
export const useAnimationPlaySpeed = create<AnimationSpeedState>((set) => ({
|
||||
speed: 1,
|
||||
setSpeed: (value) => set({ speed: value }),
|
||||
}));
|
||||
|
|
|
@ -201,27 +201,6 @@ export type FloorItemType = {
|
|||
modelfileID: string;
|
||||
isLocked: boolean;
|
||||
isVisible: boolean;
|
||||
eventData?: {
|
||||
type: 'Conveyor';
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
||||
triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
}[];
|
||||
speed: number | string;
|
||||
} | {
|
||||
type: 'Vehicle';
|
||||
point: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
speed: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Array of floor items for managing multiple objects on the floor
|
||||
|
@ -328,12 +307,43 @@ interface VehicleEventsSchema {
|
|||
modeluuid: string;
|
||||
modelName: string;
|
||||
type: 'Vehicle';
|
||||
point: {
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
speed: number;
|
||||
};
|
||||
position: [number, number, number];
|
||||
}
|
||||
}
|
||||
|
||||
export type EventData = {
|
||||
modeluuid: string;
|
||||
modelname: string;
|
||||
position: [number, number, number];
|
||||
rotation: { x: number; y: number; z: number };
|
||||
modelfileID: string;
|
||||
isLocked: boolean;
|
||||
isVisible: boolean;
|
||||
eventData?: {
|
||||
type: 'Conveyor';
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
||||
triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
}[];
|
||||
speed: number | string;
|
||||
} | {
|
||||
type: 'Vehicle';
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
||||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
speed: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue