Merge remote-tracking branch 'origin/main' into simulation-agv

This commit is contained in:
Poovizhi99 2025-04-04 09:46:48 +05:30
commit bb4f846528
50 changed files with 3905 additions and 978 deletions

View File

@ -8,7 +8,7 @@ import StateWorking from "./cards/StateWorking";
const CardsScene = () => {
return (
<div className="cards-scene" style={{ width: "100%", height: "100%" }}>
<Canvas>
{/* <Canvas> */}
{/* 3d-cards */}
{/* <ProductionCapacity /> */}
@ -16,8 +16,8 @@ const CardsScene = () => {
{/* <StateWorking /> */}
{/* <Throughput /> */}
<OrbitControls />
</Canvas>
{/* <OrbitControls /> */}
{/* </Canvas> */}
</div>
);
};

View File

@ -30,11 +30,13 @@ interface ProductionCapacityProps {
id: string;
type: string;
position: [number, number, number];
onContextMenu?: (event: React.MouseEvent) => void;
// onPointerDown:any
}
const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ id, type, position }) => {
const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, position, onContextMenu }) => {
const { selectedChartId,setSelectedChartId } = useWidgetStore();
const { selectedChartId, setSelectedChartId } = useWidgetStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
@ -111,7 +113,7 @@ const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ id, type, posi
};
const startStream = () => {
const startStream = () => {
socket.emit("lineInput", inputData);
};
@ -146,8 +148,8 @@ const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ id, type, posi
};
}, [measurements, duration, iotApiUrl]);
const fetchSavedInputes = async() => {
const fetchSavedInputes = async () => {
if (id !== "") {
try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
@ -173,20 +175,18 @@ const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ id, type, posi
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration, widgetName])
, [chartMeasurements, chartDuration, widgetName])
return (
<Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]}
transform
sprite>
<Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]}
zIndexRange={[1, 0]}
transform
sprite>
<div className="productionCapacity-wrapper card"
onClick={
() => setSelectedChartId({
id: id,
type: type
})
}>
onClick={() => setSelectedChartId({ id: id, type: type })}
onContextMenu={onContextMenu}
>
<div className="headeproductionCapacityr-wrapper">
<div className="header">Production Capacity</div>
<div className="production-capacity">
@ -207,7 +207,7 @@ const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ id, type, posi
</div>{" "}
<div className="bar-chart charts">
{/* Bar Chart */}
<Bar data={Object.keys(measurements).length > 0 ? chartData : defaultChartData } options={chartOptions} />
<Bar data={Object.keys(measurements).length > 0 ? chartData : defaultChartData} options={chartOptions} />
</div>
</div>
</Html>

View File

@ -43,10 +43,11 @@ interface ReturnOfInvestmentProps {
id: string;
type: string;
position: [number, number, number];
onContextMenu?: (event: React.MouseEvent) => void;
}
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, position }) => {
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, position, onContextMenu }) => {
const { selectedChartId,setSelectedChartId } = useWidgetStore();
const { selectedChartId, setSelectedChartId } = useWidgetStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h")
@ -138,7 +139,7 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
};
const startStream = () => {
const startStream = () => {
socket.emit("lineInput", inputData);
};
@ -155,8 +156,8 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
return {
label: datasetKey,
data: responseData[datasetKey]?.values ?? [],
borderColor: index === 0 ? "rgba(75, 192, 192, 1)": "rgba(255, 99, 132, 1)", // Light blue color
backgroundColor: index === 0 ? "rgba(75, 192, 192, 0.2)": "rgba(255, 99, 132, 0.2)",
borderColor: index === 0 ? "rgba(75, 192, 192, 1)" : "rgba(255, 99, 132, 1)", // Light blue color
backgroundColor: index === 0 ? "rgba(75, 192, 192, 0.2)" : "rgba(255, 99, 132, 0.2)",
fill: true,
tension: 0.4, // Smooth curve effect
pointRadius: 0, // Hide dots
@ -174,8 +175,8 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
};
}, [measurements, duration, iotApiUrl]);
const fetchSavedInputes = async() => {
const fetchSavedInputes = async () => {
if (id !== "") {
try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
@ -201,21 +202,18 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration, widgetName])
, [chartMeasurements, chartDuration, widgetName])
return (
<Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]}
transform
zIndexRange={[1,0]}
zIndexRange={[1, 0]}
sprite>
<div className="returnOfInvestment card"
onClick={
() => setSelectedChartId({
id: id,
type: type
})
}>
onClick={() => setSelectedChartId({ id: id, type: type })}
onContextMenu={onContextMenu}
>
<div className="header">Return of Investment</div>
<div className="lineGraph charts">
{/* Smooth curve graph with two datasets */}

View File

@ -7,11 +7,12 @@ import io from "socket.io-client";
// import image from "../../../../assets/image/temp/image.png";
interface StateWorkingProps {
id:string;
id: string;
type: string;
position: [number, number, number];
onContextMenu?: (event: React.MouseEvent) => void;
}
const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position }) => {
const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onContextMenu }) => {
const { selectedChartId, setSelectedChartId } = useWidgetStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
@ -38,14 +39,14 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position }) => {
duration,
interval: 1000,
};
const startStream = () => {
const startStream = () => {
socket.emit("lastInput", inputData);
};
socket.on("connect", startStream);
socket.on("lastOutput", (response) => {
const responseData = response;
console.log("responceeeeeeeeeee",response);
console.log("responceeeeeeeeeee", response);
setDatas(responseData);
});
@ -56,8 +57,8 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position }) => {
};
}, [measurements, duration, iotApiUrl]);
const fetchSavedInputes = async() => {
const fetchSavedInputes = async () => {
if (id !== "") {
try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
@ -74,8 +75,8 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position }) => {
}
}
console.log("dataaaaa",datas);
console.log("dataaaaa", datas);
useEffect(() => {
fetchSavedInputes();
@ -86,27 +87,24 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position }) => {
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration, widgetName])
, [chartMeasurements, chartDuration, widgetName])
return (
<Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]}
transform
zIndexRange={[1,0]}
zIndexRange={[1, 0]}
sprite>
<div className="stateWorking-wrapper card"
onClick={
() => setSelectedChartId({
id: id,
type: type
})
}>
onClick={() => setSelectedChartId({ id: id, type: type })}
onContextMenu={onContextMenu}
>
<div className="header-wrapper">
<div className="header">
<span>State</span>
<span>
{datas?.input1 ? datas.input1 : 'input1'} <span>.</span>
{datas?.input1 ? datas.input1 : 'input1'} <span>.</span>
</span>
</div>
<div className="img">
@ -126,24 +124,24 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position }) => {
<div className="key">{datas?.input2 ? datas.input2 : 'data'}</div>
</div>
<div className="data-table">
<div className="data">{measurements?.input3?.fields ? measurements.input3.fields : 'input3'}</div>
<div className="key">{datas?.input3 ? datas.input3 : 'data'}</div>
<div className="data">{measurements?.input3?.fields ? measurements.input3.fields : 'input3'}</div>
<div className="key">{datas?.input3 ? datas.input3 : 'data'}</div>
</div>
<div className="data-table">
<div className="data">{measurements?.input4?.fields ? measurements.input4.fields : 'input4'}</div>
<div className="key">{datas?.input4 ? datas.input4 : 'data'}</div>
<div className="data">{measurements?.input4?.fields ? measurements.input4.fields : 'input4'}</div>
<div className="key">{datas?.input4 ? datas.input4 : 'data'}</div>
</div>
<div className="data-table">
<div className="data">{measurements?.input5?.fields ? measurements.input5.fields : 'input5'}</div>
<div className="key">{datas?.input5 ? datas.input5 : 'data'}</div>
<div className="data">{measurements?.input5?.fields ? measurements.input5.fields : 'input5'}</div>
<div className="key">{datas?.input5 ? datas.input5 : 'data'}</div>
</div>
<div className="data-table">
<div className="data">{measurements?.input6?.fields ? measurements.input6.fields : 'input6'}</div>
<div className="key">{datas?.input6 ? datas.input6 : 'data'}</div>
<div className="data">{measurements?.input6?.fields ? measurements.input6.fields : 'input6'}</div>
<div className="key">{datas?.input6 ? datas.input6 : 'data'}</div>
</div>
<div className="data-table">
<div className="data">{measurements?.input7?.fields ? measurements.input7.fields : 'input7'}</div>
<div className="key">{datas?.input7 ? datas.input7 : 'data'}</div>
<div className="data">{measurements?.input7?.fields ? measurements.input7.fields : 'input7'}</div>
<div className="key">{datas?.input7 ? datas.input7 : 'data'}</div>
</div>
</div>
</div>

View File

@ -45,11 +45,12 @@ interface ThroughputProps {
id: string;
type: string;
position: [number, number, number];
onContextMenu?: (event: React.MouseEvent) => void;
}
const Throughput: React.FC<ThroughputProps> = ({ id, type, position }) => {
const Throughput: React.FC<ThroughputProps> = ({ id, type, position, onContextMenu }) => {
const { selectedChartId,setSelectedChartId } = useWidgetStore();
const { selectedChartId, setSelectedChartId } = useWidgetStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h")
@ -121,7 +122,7 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position }) => {
};
const startStream = () => {
const startStream = () => {
socket.emit("lineInput", inputData);
};
@ -154,8 +155,8 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position }) => {
};
}, [measurements, duration, iotApiUrl]);
const fetchSavedInputes = async() => {
const fetchSavedInputes = async () => {
if (id !== "") {
try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
@ -181,7 +182,7 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position }) => {
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration, widgetName])
, [chartMeasurements, chartDuration, widgetName])
return (
<Html position={[position[0], position[1], position[2]]}
@ -189,13 +190,10 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position }) => {
transform
zIndexRange={[1, 0]}
sprite>
<div className="throughput-wrapper"
onClick={
() => setSelectedChartId({
id: id,
type: type
})
}>
<div className="throughput-wrapper"
onClick={() => setSelectedChartId({ id: id, type: type })}
onContextMenu={onContextMenu}
>
<div className="header">{name}</div>
<div className="display-value">
<div className="left">

View File

@ -101,7 +101,6 @@ const ProgressBarWidget = ({
</div>
);
};
console.log(chartTypes, "chartTypes");
const Widgets2D = () => {
return (

View File

@ -10,6 +10,7 @@ import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import { handleResize } from "../../../../functions/handleResizePannel";
import {
useFloorItems,
useSelectedActionSphere,
useSelectedPath,
useSimulationPaths,
@ -17,11 +18,14 @@ import {
import * as THREE from "three";
import * as Types from "../../../../types/world/worldTypes";
import InputToggle from "../../../ui/inputs/InputToggle";
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
const ConveyorMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
const { selectedPath, setSelectedPath } = useSelectedPath();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const { floorItems, setFloorItems } = useFloorItems();
const actionsContainerRef = useRef<HTMLDivElement>(null);
const triggersContainerRef = useRef<HTMLDivElement>(null);
@ -36,6 +40,19 @@ const ConveyorMechanics: React.FC = () => {
.find((point) => point.uuid === selectedActionSphere.point.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(
// organization,
// updatedPath.modeluuid,
// updatedPath.points
// );
// console.log('a: ', a);
}
const handleAddAction = () => {
if (!selectedActionSphere) return;
@ -65,6 +82,15 @@ const ConveyorMechanics: React.FC = () => {
return path;
});
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
};
@ -74,21 +100,30 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.filter(
(action) => action.uuid !== uuid
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.filter(
(action) => action.uuid !== uuid
),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
};
@ -98,36 +133,45 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? {
...action,
type: actionType,
material:
actionType === "Spawn" || actionType === "Swap"
? "Inherit"
: action.material,
delay:
actionType === "Delay" ? "Inherit" : action.delay,
spawnInterval:
actionType === "Spawn"
? "Inherit"
: action.spawnInterval,
}
: action
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? {
...action,
type: actionType,
material:
actionType === "Spawn" || actionType === "Swap"
? "Inherit"
: action.material,
delay:
actionType === "Delay" ? "Inherit" : action.delay,
spawnInterval:
actionType === "Spawn"
? "Inherit"
: action.spawnInterval,
}
: action
),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
// Update the selected item to reflect changes
@ -156,24 +200,33 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid &&
(action.type === "Spawn" || action.type === "Swap")
? { ...action, material }
: action
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid &&
(action.type === "Spawn" || action.type === "Swap")
? { ...action, material }
: action
),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
// Update selected item if it's the current action
@ -194,21 +247,30 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, delay } : action
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, delay } : action
),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
};
@ -221,23 +283,32 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? { ...action, spawnInterval }
: action
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? { ...action, spawnInterval }
: action
),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
};
@ -248,6 +319,15 @@ const ConveyorMechanics: React.FC = () => {
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
};
@ -258,26 +338,35 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) {
const triggerIndex = point.triggers.length;
const newTrigger = {
uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`,
type: "",
bufferTime: 0,
isUsed: false,
};
...path,
points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) {
const triggerIndex = point.triggers.length;
const newTrigger = {
uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`,
type: "",
bufferTime: 0,
isUsed: false,
};
return { ...point, triggers: [...point.triggers, newTrigger] };
}
return point;
}),
}
return { ...point, triggers: [...point.triggers, newTrigger] };
}
return point;
}),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
};
@ -287,21 +376,30 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.filter(
(trigger) => trigger.uuid !== uuid
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.filter(
(trigger) => trigger.uuid !== uuid
),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
};
@ -311,23 +409,32 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid
? { ...trigger, type: triggerType }
: trigger
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid
? { ...trigger, type: triggerType }
: trigger
),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
// Ensure the selectedItem is updated immediately
@ -347,22 +454,31 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) => ({
...action,
isUsed: action.uuid === uuid ? !action.isUsed : false,
})),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) => ({
...action,
isUsed: action.uuid === uuid ? !action.isUsed : false,
})),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
// Immediately update the selected item if it's the one being toggled
@ -384,22 +500,31 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) => ({
...trigger,
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
})),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) => ({
...trigger,
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
})),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
// Immediately update the selected item if it's the one being toggled
@ -420,23 +545,32 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid
? { ...trigger, bufferTime }
: trigger
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid
? { ...trigger, bufferTime }
: trigger
),
}
: point
),
}
: path
);
const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" &&
path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid
)
);
updateBackend(updatedPath);
setSimulationPaths(updatedPaths);
// Immediately update selectedItem if it's the currently selected trigger
@ -493,12 +627,11 @@ const ConveyorMechanics: React.FC = () => {
{selectedPoint?.actions.map((action) => (
<div
key={action.uuid}
className={`list-item ${
selectedItem?.type === "action" &&
className={`list-item ${selectedItem?.type === "action" &&
selectedItem.item?.uuid === action.uuid
? "active"
: ""
}`}
? "active"
: ""
}`}
>
<div
className="value"
@ -506,7 +639,7 @@ const ConveyorMechanics: React.FC = () => {
setSelectedItem({ type: "action", item: action })
}
>
<input type="radio" name="action" id="action" defaultChecked={action.isUsed}/>
<input type="radio" name="action" id="action" defaultChecked={action.isUsed} />
<RenameInput value={action.name} />
</div>
<div
@ -543,12 +676,11 @@ const ConveyorMechanics: React.FC = () => {
{selectedPoint?.triggers.map((trigger) => (
<div
key={trigger.uuid}
className={`list-item ${
selectedItem?.type === "trigger" &&
className={`list-item ${selectedItem?.type === "trigger" &&
selectedItem.item?.uuid === trigger.uuid
? "active"
: ""
}`}
? "active"
: ""
}`}
>
<div
className="value"
@ -588,8 +720,8 @@ const ConveyorMechanics: React.FC = () => {
{selectedItem.type === "action" && (
<>
<InputToggle
inputKey="enableTrigger"
label="Enable Trigger"
inputKey="enableAction"
label="Enable Action"
value={selectedItem.item.isUsed}
onClick={() => handleActionToggle(selectedItem.item.uuid)}
/>
@ -604,19 +736,19 @@ const ConveyorMechanics: React.FC = () => {
{/* Only show material dropdown for Spawn/Swap actions */}
{(selectedItem.item.type === "Spawn" ||
selectedItem.item.type === "Swap") && (
<LabledDropdown
label={
selectedItem.item.type === "Spawn"
? "Spawn Material"
: "Swap Material"
}
defaultOption={selectedItem.item.material}
options={["Inherit", "Crate", "Box"]}
onSelect={(option) =>
handleMaterialSelect(selectedItem.item.uuid, option)
}
/>
)}
<LabledDropdown
label={
selectedItem.item.type === "Spawn"
? "Spawn Material"
: "Swap Material"
}
defaultOption={selectedItem.item.material}
options={["Inherit", "Crate", "Box"]}
onSelect={(option) =>
handleMaterialSelect(selectedItem.item.uuid, option)
}
/>
)}
{/* Only show delay input for Delay actions */}
{selectedItem.item.type === "Delay" && (

View File

@ -33,7 +33,7 @@ const GlobalProperties: React.FC = () => {
const { setPlaneValue, setGridValue, planeValue, gridValue } =
useTileDistance();
useEffect(() => {
console.log(gridValue, planeValue, "values");
// console.log(gridValue, planeValue, "values");
}, [gridValue, planeValue]);
const { socket } = useSocketStore();
const { limitDistance, setLimitDistance } = useLimitDistance();

View File

@ -25,7 +25,7 @@ const BarChartInput = (props: Props) => {
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -25,7 +25,7 @@ const FleetEfficiencyInputComponent = (props: Props) => {
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -25,7 +25,7 @@ const FlotingWidgetInput = (props: Props) => {
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -14,8 +14,6 @@ import { useWidgetStore } from '../../../../../store/useWidgetStore'
const InputSelecterComponent = () => {
const { selectedChartId } = useWidgetStore();
console.log('selectedChartId:',selectedChartId);
if (selectedChartId && selectedChartId.type && selectedChartId.type === 'bar' ) {
return (

View File

@ -144,7 +144,7 @@ const LineGrapInput = (props: Props) => {
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -25,7 +25,7 @@ const PieChartInput = (props: Props) => {
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -25,7 +25,7 @@ const Progress1Input = (props: Props) => {
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -25,7 +25,7 @@ const Progress2Input = (props: Props) => {
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -25,7 +25,7 @@ const WarehouseThroughputInputComponent = (props: Props) => {
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -21,13 +21,11 @@ const Widget2InputCard3D = (props: Props) => {
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]
console.log(selectedChartId);
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -19,9 +19,7 @@ const Widget3InputCard3D = () => {
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]
console.log(selectedChartId);
useEffect(() => {
const fetchZoneData = async () => {
try {

View File

@ -21,13 +21,11 @@ const Widget4InputCard3D = (props: Props) => {
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]
console.log(selectedChartId);
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);

View File

@ -17,6 +17,7 @@ import { duplicateWidgetApi } from "../../../services/realTimeVisulization/zoneD
import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteWidgetApi";
import { useClickOutside } from "./functions/handleWidgetsOuterClick";
import { useSocketStore } from "../../../store/store";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
type Side = "top" | "bottom" | "left" | "right";
@ -243,6 +244,7 @@ export const DraggableWidget = ({
// useClickOutside(chartWidget, () => {
// setSelectedChartId(null);
// });
const { isPlaying } = usePlayButtonStore();
console.log('isPanelHidden: ', isPanelHidden);
return (
@ -250,9 +252,8 @@ export const DraggableWidget = ({
<div
draggable
key={widget.id}
className={`chart-container ${
selectedChartId?.id === widget.id && "activeChart"
}`}
className={`chart-container ${(selectedChartId?.id === widget.id) && !isPlaying && "activeChart"
}`}
onPointerDown={handlePointerDown}
onDragStart={handleDragStart}
onDragEnter={handleDragEnter}
@ -273,9 +274,8 @@ export const DraggableWidget = ({
{openKebabId === widget.id && (
<div className="kebab-options" ref={widgetRef}>
<div
className={`edit btn ${
isPanelFull(widget.panel) ? "btn-blur" : ""
}`}
className={`edit btn ${isPanelFull(widget.panel) ? "btn-blur" : ""
}`}
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
>
<div className="icon">

View File

@ -1,5 +1,5 @@
import { useThree } from "@react-three/fiber";
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useRef } from "react";
import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store";
import useModuleStore from "../../../store/useModuleStore";
import { ThreeState } from "../../../types/world/worldTypes";
@ -13,30 +13,43 @@ import { generateUniqueId } from "../../../functions/generateUniqueId";
import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget";
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
import { use3DWidget } from "../../../store/useDroppedObjectsStore";
import { useZoneWidgetStore } from "../../../store/useZone3DWidgetStore";
import { useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../store/useZone3DWidgetStore";
import { useWidgetStore } from "../../../store/useWidgetStore";
import EditWidgetOption from "../menu/EditWidgetOption";
export default function Dropped3dWidgets() {
const { widgetSelect } = useAsset3dWidget();
const { activeModule } = useModuleStore();
const { raycaster, gl, scene }: ThreeState = useThree();
const { raycaster, gl, scene, mouse, camera }: ThreeState = useThree();
const { widgetSubOption } = useWidgetSubOption();
const { selectedZone } = useSelectedZoneStore();
const { top, setTop } = useTopData()
const { left, setLeft } = useLeftData()
const { rightSelect, setRightSelect } = useRightSelected()
// ✅ Use Zustand Store instead of useState
const { zoneWidgetData, setZoneWidgetData, addWidget } = useZoneWidgetStore();
const { zoneWidgetData, setZoneWidgetData, addWidget, updateWidgetPosition } = useZoneWidgetStore();
const { setWidgets3D } = use3DWidget();
const { visualizationSocket } = useSocketStore();
const { rightClickSelected, setRightClickSelected } = useRightClickSelected()
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move
const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move
const planeIntersect = useRef(new THREE.Vector3());
// let [verticalPlane, setFloorPlanesVertical] = useState(
// new THREE.Plane(new THREE.Vector3(0, 1, 0))
// );
useEffect(() => {
if (activeModule !== "visualization") return;
if (!selectedZone.zoneId) return;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
async function get3dWidgetData() {
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
console.log('result: ', result);
setWidgets3D(result);
const formattedWidgets = result.map((widget: any) => ({
@ -89,13 +102,13 @@ export default function Dropped3dWidgets() {
widget: newWidget,
zoneId: selectedZone.zoneId
}
console.log('add3dWidget: ', add3dWidget);
if (visualizationSocket) {
visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget)
}
// let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget);
// console.log('response: ', response);
//
// if (response.message === "Widget created successfully") {
addWidget(selectedZone.zoneId, newWidget);
@ -111,23 +124,142 @@ export default function Dropped3dWidgets() {
const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || [];
useEffect(() => {
if (!rightClickSelected) return;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
if (rightSelect === "Duplicate") {
const widgetToDuplicate = activeZoneWidgets.find(w => w.id === rightClickSelected);
if (!widgetToDuplicate) return;
const newWidget = {
id: generateUniqueId(),
type: widgetToDuplicate.type,
position: [
widgetToDuplicate.position[0] + 0.5, // Slightly shift position
widgetToDuplicate.position[1],
widgetToDuplicate.position[2] + 0.5,
] as [number, number, number],
};
let add3dWidget = {
organization,
widget: newWidget,
zoneId: selectedZone.zoneId
};
// if (visualizationSocket) {
// visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget);
// }
addWidget(selectedZone.zoneId, newWidget);
setRightSelect(null);
setRightClickSelected(null);
}
if (rightSelect === "Delete") {
let deleteWidget = {
organization,
widgetId: rightClickSelected,
zoneId: selectedZone.zoneId
};
// if (visualizationSocket) {
// visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget);
// }
setZoneWidgetData(selectedZone.zoneId, activeZoneWidgets.filter(w => w.id !== rightClickSelected));
setRightClickSelected(null);
setRightSelect(null);
}
if (rightSelect === "Horizontal Move") {
}
if (rightSelect === "Vertical Move") {
}
}, [rightSelect, rightClickSelected]);
useEffect(() => {
const handleMouseMove = (event: MouseEvent) => {
if (!rightClickSelected || !rightSelect) return;
const selectedZone = Object.keys(zoneWidgetData).find(zoneId =>
zoneWidgetData[zoneId].some(widget => widget.id === rightClickSelected)
);
if (!selectedZone) return;
const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected);
if (!selectedWidget) return;
const rect = gl.domElement.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
if (rightSelect === "Horizontal Move" && raycaster.ray.intersectPlane(plane.current, planeIntersect.current)) {
updateWidgetPosition(selectedZone, rightClickSelected, [
planeIntersect.current.x,
selectedWidget.position[1],
planeIntersect.current.z
]);
}
if (rightSelect === "Vertical Move") {
if (raycaster.ray.intersectPlane(verticalPlane.current, planeIntersect.current)) {
updateWidgetPosition(selectedZone, rightClickSelected, [
selectedWidget.position[0],
planeIntersect.current.y, // Ensure Y value updates correctly
selectedWidget.position[2]
]);
} else {
console.log("No Intersection with Vertical Plane");
}
}
};
const handleMouseUp = () => {
if (rightClickSelected && (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move")) {
setTimeout(() => {
setRightClickSelected(null);
setRightSelect(null);
}, 50);
}
};
// Attach events to window instead of gl.domElement
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
return () => {
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
};
}, [rightClickSelected, rightSelect, zoneWidgetData, gl]);
return (
<>
{activeZoneWidgets.map(({ id, type, position }) => {
console.log('Typeeeeeeeeeeee',type);
const handleRightClick = (event: React.MouseEvent) => {
event.preventDefault();
setRightClickSelected(id)
};
switch (type) {
case "ui-Widget 1":
return <ProductionCapacity key={id} id={id} type={type} position={position} />;
return <ProductionCapacity key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />;
case "ui-Widget 2":
return <ReturnOfInvestment key={id} id={id} type={type} position={position} />;
return <ReturnOfInvestment key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />;
case "ui-Widget 3":
return <StateWorking key={id} id={id} type={type} position={position} />;
return <StateWorking key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />;
case "ui-Widget 4":
return <Throughput key={id} id={id} type={type} position={position} />;
return <Throughput key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />;
default:
return null;
}
})}
</>
);
}

View File

@ -23,6 +23,8 @@ import SocketRealTimeViz from "../../../modules/visualization/realTimeVizSocket.
import RenderOverlay from "../../templates/Overlay";
import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup";
import DroppedObjects from "./DroppedFloatingWidgets";
import EditWidgetOption from "../menu/EditWidgetOption";
import { useRightClickSelected } from "../../../store/useZone3DWidgetStore";
type Side = "top" | "bottom" | "left" | "right";
@ -55,8 +57,9 @@ const RealTimeVisulization: React.FC = () => {
const [droppedObjects, setDroppedObjects] = useState<any[]>([]);
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { zones } = useZones();
const { rightClickSelected, setRightClickSelected } = useRightClickSelected()
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
const [floatingWidgets, setFloatingWidgets] = useState<
@ -93,7 +96,7 @@ const RealTimeVisulization: React.FC = () => {
{}
);
setZonesData(formattedData);
} catch (error) {}
} catch (error) { }
}
GetZoneData();
@ -178,7 +181,6 @@ const RealTimeVisulization: React.FC = () => {
.getState()
.addObject(selectedZone.zoneName, newObject);
// }
// Update floating widgets state
setFloatingWidgets((prevWidgets) => ({
...prevWidgets,
@ -192,9 +194,10 @@ const RealTimeVisulization: React.FC = () => {
],
},
}));
} catch (error) {}
} catch (error) { }
};
function handleRightClickSel(){}
return (
<div
ref={containerRef}
@ -206,11 +209,6 @@ const RealTimeVisulization: React.FC = () => {
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
}}
>
{/* <RenderOverlay>
<EditWidgetOption
options={["Dublicate", "Vertical Move", "Horizontal Move", "Delete"]}
/>
</RenderOverlay> */}
{openConfirmationPopup && (
<RenderOverlay>
<ConfirmationPopup
@ -235,12 +233,11 @@ const RealTimeVisulization: React.FC = () => {
</div>
{activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />}
{activeModule === "visualization" && <SocketRealTimeViz />}
{/* <DroppedObjects /> */}
{/* <RenderOverlay>
<EditWidgetOption
options={["Dublicate", "Vertical Move", "Horizontal Move", "Delete"]}
/>
</RenderOverlay> */}
{activeModule === "visualization" && widgetSubOption === "3D" && rightClickSelected && <EditWidgetOption
options={["Duplicate", "Vertical Move", "Horizontal Move", "Delete"]}
/>}
{activeModule === "visualization" && (
<>
<DisplayZone

View File

@ -1,29 +0,0 @@
// import { useSelectedZoneStore } from "../../../store/useZoneStore";
// type HandleDropTemplateProps = {
// templateId: string;
// };
// export const handleDropTemplate = ({ templateId }: HandleDropTemplateProps): void => {
// const { getTemplate } = useTemplateStore.getState();
// const { setSelectedZone } = useSelectedZoneStore.getState();
// // Find the template by ID
// const template: Template | undefined = getTemplate(templateId);
// if (!template) {
// console.error("Template not found!");
// return;
// }
// // Update the selected zone with the template data
// setSelectedZone((prev) => ({
// ...prev,
// panelOrder: template.panelOrder,
// activeSides: Array.from(new Set([...prev.activeSides, ...template.panelOrder])),
// widgets: template.widgets, // Keep widget structure the same
// }));
// console.log("Dropped template applied:", template);
// };

View File

@ -1,15 +1,26 @@
import React from "react";
import React, { useEffect } from "react";
import { useLeftData, useRightSelected, useTopData } from "../../../store/useZone3DWidgetStore";
interface EditWidgetOptionProps {
options: string[];
}
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({ options }) => {
const { top, setTop } = useTopData()
const { left, setLeft } = useLeftData()
const { rightSelect, setRightSelect } = useRightSelected()
useEffect(() => {
console.log('left: ', left);
console.log('top: ', top);
}, [top, left])
return (
<div className="editWidgetOptions-wrapper">
<div className="editWidgetOptions-wrapper" style={{ top: top + "px", left: left + "px" }}>
<div className="editWidgetOptions">
{options.map((option, index) => (
<div className="option" key={index}>
<div className="option" key={index} onClick={(e) => setRightSelect(option)}>
{option}
</div>
))}

View File

@ -24,6 +24,7 @@ async function addAssetModel(
socket: Socket<any>,
selectedItem: any,
setSelectedItem: any,
setSimulationPaths: any,
plane: Types.RefMesh,
): Promise<void> {
@ -64,7 +65,7 @@ async function addAssetModel(
const cachedModel = THREE.Cache.get(selectedItem.id);
if (cachedModel) {
// console.log(`[Cache] Fetching ${selectedItem.name}`);
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
return;
} else {
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
@ -77,7 +78,7 @@ async function addAssetModel(
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(selectedItem.id, gltf);
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
@ -89,7 +90,7 @@ async function addAssetModel(
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
await storeGLTF(selectedItem.id, modelBlob);
THREE.Cache.add(selectedItem.id, gltf);
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
@ -112,10 +113,11 @@ async function handleModelLoad(
tempLoader: Types.RefMesh,
isTempLoader: Types.RefBoolean,
setFloorItems: Types.setFloorItemSetState,
setSimulationPaths: any,
socket: Socket<any>
) {
const model = gltf.scene.clone();
model.userData = { name: selectedItem.name, modelId: selectedItem.id };
model.userData = { name: selectedItem.name, modelId: selectedItem.id, modeluuid: model.uuid };
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
@ -152,7 +154,7 @@ async function handleModelLoad(
if (res.type === "Conveyor") {
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
const eventData: Extract<Types.FloorItemType['eventData'], { type: 'Conveyor' }> = {
const backendEventData: Extract<Types.FloorItemType['eventData'], { type: 'Conveyor' }> = {
type: 'Conveyor',
points: res.points.map((point: any, index: number) => ({
uuid: pointUUIDs[index],
@ -176,49 +178,94 @@ async function handleModelLoad(
speed: 'Inherit'
};
// console.log('eventData: ', eventData);
newFloorItem.eventData = eventData;
// API
// await setFloorItemApi(
// organization,
// newFloorItem.modeluuid,
// newFloorItem.modelname,
// newFloorItem.modelfileID,
// newFloorItem.position,
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
// false,
// true,
// newFloorItem.eventData
// );
// SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
eventData: backendEventData,
socketId: socket.id
};
console.log('data: ', data);
setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
const eventData: any = backendEventData;
eventData.modeluuid = newFloorItem.modeluuid;
eventData.modelName = newFloorItem.modelname;
eventData.position = newFloorItem.position;
eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
...(prevEvents || []),
eventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
]);
socket.emit("v2:model-asset:add", data);
} else {
// API
// await setFloorItemApi(
// organization,
// newFloorItem.modeluuid,
// newFloorItem.modelname,
// newFloorItem.modelfileID,
// newFloorItem.position,
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
// false,
// true
// );
// SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id
};
setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
socket.emit("v2:model-asset:add", data);
}
setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
// API
// await setFloorItemApi(
// organization,
// newFloorItem.modeluuid,
// newFloorItem.modelname,
// newFloorItem.modelfileID,
// newFloorItem.position,
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
// false,
// true,
// newFloorItem.eventData
// );
// SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
eventData: newFloorItem.eventData,
socketId: socket.id
};
console.log('data: ', data);
socket.emit("v2:model-asset:add", data);
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
});

View File

@ -121,7 +121,7 @@ export default async function assetManager(
const model = gltf;
model.uuid = item.modeluuid;
model.userData = { name: item.modelname, modelId: item.modelfileID };
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.position.set(...item.position);
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);

View File

@ -10,6 +10,7 @@ async function DeleteFloorItems(
itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh,
setFloorItems: Types.setFloorItemSetState,
setSimulationPaths: any,
socket: Socket<any>
): Promise<void> {
@ -74,6 +75,12 @@ async function DeleteFloorItems(
itemsGroup.current.remove(hoveredDeletableFloorItem.current);
}
setFloorItems(updatedItems);
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== removedItem.modeluuid);
return updatedEvents;
});
toast.success("Model Removed!");
}
}

View File

@ -10,6 +10,7 @@ import {
useRenderDistance,
useselectedFloorItem,
useSelectedItem,
useSimulationPaths,
useSocketStore,
useToggleView,
useTransformMode,
@ -64,6 +65,7 @@ const FloorItemsGroup = ({
const { setselectedFloorItem } = useselectedFloorItem();
const { activeTool } = useActiveTool();
const { selectedItem, setSelectedItem } = useSelectedItem();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const { setLoadingProgress } = useLoadingProgress();
const { activeModule } = useModuleStore();
const { socket } = useSocketStore();
@ -96,16 +98,23 @@ const FloorItemsGroup = ({
};
getFloorAssets(organization).then((data) => {
const uniqueItems = (data as Types.FloorItems).filter(
(item, index, self) =>
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
);
totalAssets = uniqueItems.length;
if (totalAssets === 0) {
if (data.length > 0) {
const uniqueItems = (data as Types.FloorItems).filter(
(item, index, self) =>
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
);
totalAssets = uniqueItems.length;
if (totalAssets === 0) {
updateLoadingProgress(100);
return;
}
gltfLoaderWorker.postMessage({ floorItems: data });
} else {
console.log('data: ', data);
gltfLoaderWorker.postMessage({ floorItems: [] });
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths);
updateLoadingProgress(100);
return;
}
gltfLoaderWorker.postMessage({ floorItems: data });
});
gltfLoaderWorker.onmessage = async (event) => {
@ -122,7 +131,7 @@ const FloorItemsGroup = ({
updateLoadingProgress(progress);
if (loadedAssets === totalAssets) {
loadInitialFloorItems(itemsGroup, setFloorItems);
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths);
updateLoadingProgress(100);
}
});
@ -240,6 +249,7 @@ const FloorItemsGroup = ({
itemsGroup,
hoveredDeletableFloorItem,
setFloorItems,
setSimulationPaths,
socket
);
}
@ -365,6 +375,7 @@ const FloorItemsGroup = ({
socket,
selectedItem,
setSelectedItem,
setSimulationPaths,
plane
);
}
@ -408,7 +419,6 @@ const FloorItemsGroup = ({
activeModule,
]);
useEffect(() => {}, [floorItems]);
useFrame(() => {
if (controls)

View File

@ -105,7 +105,7 @@ export default function SocketResponses({
// console.log(`Getting ${data.data.modelname} from cache`);
const model = cachedModel.scene.clone();
model.uuid = data.data.modeluuid;
model.userData = { name: data.data.modelname, modelId: data.data.modelFileID };
model.userData = { name: data.data.modelname, modelId: data.data.modelFileID, modeluuid: data.data.modeluuid };
model.position.set(...data.data.position as [number, number, number]);
model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
@ -183,7 +183,7 @@ export default function SocketResponses({
THREE.Cache.remove(url);
const model = gltf.scene;
model.uuid = data.data.modeluuid;
model.userData = { name: data.data.modelname, modelId: data.data.modelFileID };
model.userData = { name: data.data.modelname, modelId: data.data.modelFileID, modeluuid: data.data.modeluuid };
model.position.set(...data.data.position as [number, number, number]);
model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);

View File

@ -11,7 +11,8 @@ import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAss
async function loadInitialFloorItems(
itemsGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState
setFloorItems: Types.setFloorItemSetState,
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void
): Promise<void> {
if (!itemsGroup.current) return;
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
@ -22,6 +23,8 @@ async function loadInitialFloorItems(
localStorage.setItem("FloorItems", JSON.stringify(items));
await initializeDB();
if (items.message === "floorItems not found") return;
if (items) {
const storedFloorItems: Types.FloorItems = items;
const loader = new GLTFLoader();
@ -50,6 +53,7 @@ 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;
@ -68,7 +72,7 @@ async function loadInitialFloorItems(
const cachedModel = THREE.Cache.get(item.modelfileID!);
if (cachedModel) {
// console.log(`[Cache] Fetching ${item.modelname}`);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
return;
@ -85,7 +89,7 @@ async function loadInitialFloorItems(
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
},
@ -108,7 +112,7 @@ async function loadInitialFloorItems(
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
await storeGLTF(item.modelfileID!, modelBlob);
THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
},
@ -121,34 +125,23 @@ async function loadInitialFloorItems(
});
} else {
// console.log(`Item ${item.modelname} is not near`);
setFloorItems((prevItems) => [
...(prevItems || []),
{
modeluuid: item.modeluuid,
modelname: item.modelname,
position: item.position,
rotation: item.rotation,
modelfileID: item.modelfileID,
isLocked: item.isLocked,
isVisible: item.isVisible,
},
]);
if (item.eventData) {
setFloorItems((prevItems) => [
...(prevItems || []),
{
modeluuid: item.modeluuid,
modelname: item.modelname,
position: item.position,
rotation: item.rotation,
modelfileID: item.modelfileID,
isLocked: item.isLocked,
isVisible: item.isVisible,
// eventData: item.eventData,
},
]);
} else {
setFloorItems((prevItems) => [
...(prevItems || []),
{
modeluuid: item.modeluuid,
modelname: item.modelname,
position: item.position,
rotation: item.rotation,
modelfileID: item.modelfileID,
isLocked: item.isLocked,
isVisible: item.isVisible,
},
]);
processEventData(item, setSimulationPaths);
}
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, () => { });
}
@ -164,12 +157,13 @@ function processLoadedModel(
gltf: any,
item: Types.FloorItemType,
itemsGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState
setFloorItems: Types.setFloorItemSetState,
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void
) {
const model = gltf;
model.uuid = item.modeluuid;
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.userData = { name: item.modelname, modelId: item.modelfileID };
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
model.position.set(...item.position);
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
@ -186,39 +180,67 @@ function processLoadedModel(
itemsGroup?.current?.add(model);
if (item.eventData) {
setFloorItems((prevItems) => [
...(prevItems || []),
{
modeluuid: item.modeluuid,
modelname: item.modelname,
position: item.position,
rotation: item.rotation,
modelfileID: item.modelfileID,
isLocked: item.isLocked,
isVisible: item.isVisible,
// eventData: item.eventData,
},
]);
} else {
setFloorItems((prevItems) => [
...(prevItems || []),
{
modeluuid: item.modeluuid,
modelname: item.modelname,
position: item.position,
rotation: item.rotation,
modelfileID: item.modelfileID,
isLocked: item.isLocked,
isVisible: item.isVisible,
},
]);
setFloorItems((prevItems) => [
...(prevItems || []),
{
modeluuid: item.modeluuid,
modelname: item.modelname,
position: item.position,
rotation: item.rotation,
modelfileID: item.modelfileID,
isLocked: item.isLocked,
isVisible: item.isVisible,
},
]);
if (item.eventData || item.modelfileID === '67e3da19c2e8f37134526e6a') {
processEventData(item, setSimulationPaths);
}
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
}
function processEventData(item: Types.FloorItemType, setSimulationPaths: any) {
if (item.eventData?.type === 'Conveyor') {
const data: any = item.eventData;
data.modeluuid = item.modeluuid;
data.modelName = item.modelname;
data.position = item.position;
data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
...(prevEvents || []),
data as Types.ConveyorEventsSchema
]);
} else {
const pointUUID = THREE.MathUtils.generateUUID();
const pointPosition = new THREE.Vector3(0, 1.3, 0);
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)[]) => [
...(prevEvents || []),
newVehiclePath as Types.VehicleEventsSchema
]);
}
}
function checkLoadingCompletion(
modelsLoaded: number,
modelsToLoad: number,

View File

@ -1,7 +1,7 @@
import * as THREE from "three";
import { useEffect, useMemo } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
import { toast } from "react-toastify";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import * as Types from "../../../../types/world/worldTypes";
@ -10,6 +10,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore()
@ -150,37 +151,128 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
return updatedItems;
});
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
if (eventData) {
if (eventData.type === 'Conveyor' && eventData) {
const createConveyorPoint = (index: number) => {
const pointUUID = THREE.MathUtils.generateUUID();
const hasActions = (eventData as Types.ConveyorEventsSchema)?.points[index].actions.length > 0;
//REST
const defaultAction = {
uuid: THREE.MathUtils.generateUUID(),
name: 'Action 1',
type: 'Inherit',
material: 'Inherit',
delay: 'Inherit',
spawnInterval: 'Inherit',
isUsed: true
};
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
return {
uuid: pointUUID,
position: (eventData as Types.ConveyorEventsSchema)?.points[index].position,
rotation: (eventData as Types.ConveyorEventsSchema)?.points[index].rotation,
actions: hasActions
? (eventData as Types.ConveyorEventsSchema)?.points[index].actions.map(action => ({
...action,
uuid: THREE.MathUtils.generateUUID()
}))
: [defaultAction],
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
connections: {
source: { pathUUID: obj.uuid, pointUUID },
targets: []
}
};
};
//SOCKET
const backendEventData = {
type: 'Conveyor',
points: [
createConveyorPoint(0), // point1
createConveyorPoint(1), // middlePoint
createConveyorPoint(2) // point2
],
speed: (eventData as Types.ConveyorEventsSchema)?.speed
};
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,
socketId: socket.id,
};
//REST
socket.emit("v2:model-asset:add", data);
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// 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;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
...(prevEvents || []),
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
]);
socket.emit("v2:model-asset:add", data);
}
} else {
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
//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,
socketId: socket.id,
};
socket.emit("v2:model-asset:add", data);
}
itemsGroupRef.current.add(obj);
}

View File

@ -1,7 +1,7 @@
import * as THREE from "three";
import { useEffect, useMemo } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
import { toast } from "react-toastify";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import * as Types from "../../../../types/world/worldTypes";
@ -10,11 +10,11 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore();
useEffect(() => {
if (!camera || !scene || toggleView) return;
const canvasElement = gl.domElement;
@ -131,37 +131,129 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
return updatedItems;
});
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
if (eventData) {
if (eventData.type === 'Conveyor' && eventData) {
const createConveyorPoint = (index: number) => {
const pointUUID = THREE.MathUtils.generateUUID();
const hasActions = (eventData as Types.ConveyorEventsSchema)?.points[index].actions.length > 0;
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
const defaultAction = {
uuid: THREE.MathUtils.generateUUID(),
name: 'Action 1',
type: 'Inherit',
material: 'Inherit',
delay: 'Inherit',
spawnInterval: 'Inherit',
isUsed: true
};
//SOCKET
return {
uuid: pointUUID,
position: (eventData as Types.ConveyorEventsSchema)?.points[index].position,
rotation: (eventData as Types.ConveyorEventsSchema)?.points[index].rotation,
actions: hasActions
? (eventData as Types.ConveyorEventsSchema)?.points[index].actions.map(action => ({
...action,
uuid: THREE.MathUtils.generateUUID()
}))
: [defaultAction],
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
connections: {
source: { pathUUID: obj.uuid, pointUUID },
targets: []
}
};
};
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,
socketId: socket.id,
};
const backendEventData = {
type: 'Conveyor',
points: [
createConveyorPoint(0), // point1
createConveyorPoint(1), // middlePoint
createConveyorPoint(2) // point2
],
speed: (eventData as Types.ConveyorEventsSchema)?.speed
};
socket.emit("v2:model-asset:add", data);
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// 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;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
...(prevEvents || []),
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
]);
socket.emit("v2:model-asset:add", data);
}
} else {
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
//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,
socketId: socket.id,
};
socket.emit("v2:model-asset:add", data);
}
itemsGroupRef.current.add(obj);
}

View File

@ -1,7 +1,7 @@
import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { toast } from "react-toastify";
import * as Types from "../../../../types/world/worldTypes";
@ -12,6 +12,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore();
const itemsData = useRef<Types.FloorItems>([]);
@ -179,37 +180,99 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
return updatedItems;
});
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
if (eventData) {
if (eventData.type === 'Conveyor' && eventData) {
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
const backendEventData = {
type: 'Conveyor',
points: eventData.points,
speed: (eventData as Types.ConveyorEventsSchema)?.speed
};
//SOCKET
//REST
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,
socketId: socket.id,
};
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// backendEventData
// );
socket.emit("v2:model-asset:add", data);
//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;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
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 {
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
//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,
socketId: socket.id,
};
socket.emit("v2:model-asset:add", data);
}
itemsGroupRef.current.add(obj);
}

View File

@ -1,7 +1,7 @@
import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { toast } from "react-toastify";
import * as Types from "../../../../types/world/worldTypes";
@ -12,6 +12,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore();
const itemsData = useRef<Types.FloorItems>([]);
@ -182,37 +183,99 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
return updatedItems;
});
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
if (eventData) {
if (eventData.type === 'Conveyor' && eventData) {
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
const backendEventData = {
type: 'Conveyor',
points: eventData.points,
speed: (eventData as Types.ConveyorEventsSchema)?.speed
};
//SOCKET
//REST
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,
socketId: socket.id,
};
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// backendEventData
// );
socket.emit("v2:model-asset:add", data);
//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;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
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 {
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
//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,
socketId: socket.id,
};
socket.emit("v2:model-asset:add", data);
}
itemsGroupRef.current.add(obj);
}

View File

@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
import { SelectionHelper } from "./selectionHelper";
import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
import BoundingBox from "./boundingBoxHelper";
import { toast } from "react-toastify";
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
@ -20,6 +20,7 @@ const SelectionControls: React.FC = () => {
const itemsGroupRef = useRef<THREE.Group | undefined>(undefined);
const selectionGroup = useRef() as Types.RefGroup;
const { toggleView } = useToggleView();
const { setSimulationPaths } = useSimulationPaths();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]);
@ -239,6 +240,11 @@ const SelectionControls: React.FC = () => {
}
});
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid);
return updatedEvents;
});
itemsGroupRef.current?.remove(selectedMesh);
});

View File

@ -93,13 +93,13 @@ export default function PostProcessing() {
<Outline
selection={[selectedActionSphere.point]}
selectionLayer={10}
width={750}
width={1000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={15}
edgeStrength={10}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
visibleEdgeColor={0x6f42c1}
hiddenEdgeColor={0x6f42c1}
blur={true}
xRay={true}
/>
@ -108,9 +108,9 @@ export default function PostProcessing() {
<Outline
selection={flattenChildren(selectedPath.group.children)}
selectionLayer={10}
width={750}
width={1000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={15}
edgeStrength={10}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={0x6f42c1}

View File

@ -10,76 +10,76 @@ function Behaviour() {
useEffect(() => {
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
floorItems.forEach((item: Types.FloorItemType) => {
if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
console.log('item: ', item);
const point1Position = new THREE.Vector3(0, 0.85, 2.2);
const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
const point2Position = new THREE.Vector3(0, 0.85, -2.2);
// floorItems.forEach((item: Types.FloorItemType) => {
// if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
// const point1Position = new THREE.Vector3(0, 0.85, 2.2);
// const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
// const point2Position = new THREE.Vector3(0, 0.85, -2.2);
const point1UUID = THREE.MathUtils.generateUUID();
const middlePointUUID = THREE.MathUtils.generateUUID();
const point2UUID = THREE.MathUtils.generateUUID();
// const point1UUID = THREE.MathUtils.generateUUID();
// const middlePointUUID = THREE.MathUtils.generateUUID();
// const point2UUID = THREE.MathUtils.generateUUID();
const newPath: Types.ConveyorEventsSchema = {
modeluuid: item.modeluuid,
modelName: item.modelname,
type: 'Conveyor',
points: [
{
uuid: point1UUID,
position: [point1Position.x, point1Position.y, point1Position.z],
rotation: [0, 0, 0],
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
triggers: [],
connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
},
{
uuid: middlePointUUID,
position: [middlePointPosition.x, middlePointPosition.y, middlePointPosition.z],
rotation: [0, 0, 0],
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
triggers: [],
connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
},
{
uuid: point2UUID,
position: [point2Position.x, point2Position.y, point2Position.z],
rotation: [0, 0, 0],
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
triggers: [],
connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
},
],
position: [...item.position],
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
speed: 'Inherit',
};
// const newPath: Types.ConveyorEventsSchema = {
// modeluuid: item.modeluuid,
// modelName: item.modelname,
// type: 'Conveyor',
// points: [
// {
// uuid: point1UUID,
// position: [point1Position.x, point1Position.y, point1Position.z],
// rotation: [0, 0, 0],
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
// triggers: [],
// connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
// },
// {
// uuid: middlePointUUID,
// position: [middlePointPosition.x, middlePointPosition.y, middlePointPosition.z],
// rotation: [0, 0, 0],
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
// triggers: [],
// connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
// },
// {
// uuid: point2UUID,
// position: [point2Position.x, point2Position.y, point2Position.z],
// rotation: [0, 0, 0],
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
// triggers: [],
// connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
// },
// ],
// position: [...item.position],
// rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
// speed: 'Inherit',
// };
newPaths.push(newPath);
} else if (item.modelfileID === "67e3da19c2e8f37134526e6a") {
const pointUUID = THREE.MathUtils.generateUUID();
const pointPosition = new THREE.Vector3(0, 1.3, 0);
// newPaths.push(newPath);
// } else if (item.modelfileID === "67e3da19c2e8f37134526e6a") {
// const pointUUID = THREE.MathUtils.generateUUID();
// const pointPosition = new THREE.Vector3(0, 1.3, 0);
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],
};
// 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],
// };
newPaths.push(newVehiclePath);
}
});
// newPaths.push(newVehiclePath);
// }
// });
setSimulationPaths(newPaths);
// setSimulationPaths(newPaths);
// console.log('floorItems: ', floorItems);
}, [floorItems]);
return null;

View File

@ -14,12 +14,14 @@ import {
} from "../../../store/store";
import { useFrame, useThree } from "@react-three/fiber";
import { useSubModuleStore } from "../../../store/useModuleStore";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
function PathCreation({
pathsGroupRef,
}: {
pathsGroupRef: React.MutableRefObject<THREE.Group>;
}) {
const { isPlaying } = usePlayButtonStore();
const { renderDistance } = useRenderDistance();
const { setSubModule } = useSubModuleStore();
const { setSelectedActionSphere, selectedActionSphere } =
@ -66,7 +68,7 @@ function PathCreation({
const distance = new THREE.Vector3(
...group.position.toArray()
).distanceTo(camera.position);
group.visible = distance <= renderDistance;
group.visible = ((distance <= renderDistance) && !isPlaying);
}
});
});
@ -193,7 +195,7 @@ function PathCreation({
};
return (
<group name="simulation-simulationPaths-group" ref={pathsGroupRef}>
<group visible={!isPlaying} name="simulation-simulationPaths-group" ref={pathsGroupRef}>
{simulationPaths.map((path) => {
if (path.type === "Conveyor") {
const points = path.points.map(

View File

@ -0,0 +1,916 @@
// // 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,
},
});
}
}
});
}

View File

@ -0,0 +1,7 @@
import React from "react";
const Mesh: React.FC = () => {
return <mesh></mesh>;
};
export default Mesh;

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@ const ProcessContainer: React.FC = () => {
<>
<ProcessCreator onProcessesCreated={setProcesses} />
{processes.length > 0 && <ProcessAnimator processes={processes} />}
</>
);
};

View File

@ -1,3 +1,402 @@
// import React, {
// useEffect,
// useMemo,
// useState,
// useCallback,
// useRef,
// } from "react";
// import { useSimulationPaths } from "../../../store/store";
// import * as THREE from "three";
// import { useThree } from "@react-three/fiber";
// import {
// ConveyorEventsSchema,
// VehicleEventsSchema,
// } from "../../../types/world/worldTypes";
// // Type definitions
// export interface PointAction {
// uuid: string;
// name: string;
// type: string;
// material: string;
// delay: number | string;
// spawnInterval: string | number;
// isUsed: boolean;
// }
// export interface PathPoint {
// uuid: string;
// position: [number, number, number];
// actions: PointAction[];
// connections: {
// targets: Array<{ pathUUID: string }>;
// };
// }
// export interface SimulationPath {
// modeluuid: string;
// points: PathPoint[];
// pathPosition: [number, number, number];
// speed?: number;
// }
// export interface Process {
// id: string;
// paths: SimulationPath[];
// animationPath: THREE.Vector3[];
// pointActions: PointAction[][];
// speed: number;
// }
// interface ProcessCreatorProps {
// onProcessesCreated: (processes: Process[]) => void;
// }
// // Convert event schemas to SimulationPath
// function convertToSimulationPath(
// path: ConveyorEventsSchema | VehicleEventsSchema
// ): SimulationPath {
// const { modeluuid } = path;
// // Simplified normalizeAction function that preserves exact original properties
// const normalizeAction = (action: any): PointAction => {
// return { ...action }; // Return exact copy with no modifications
// };
// if (path.type === "Conveyor") {
// return {
// modeluuid,
// points: path.points.map((point) => ({
// uuid: point.uuid,
// position: point.position,
// actions: point.actions.map(normalizeAction), // Preserve exact actions
// connections: {
// targets: point.connections.targets.map((target) => ({
// pathUUID: target.pathUUID,
// })),
// },
// })),
// pathPosition: path.position,
// speed:
// typeof path.speed === "string"
// ? parseFloat(path.speed) || 1
// : path.speed || 1,
// };
// } else {
// return {
// 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)],
// connections: {
// targets: path.point.connections.targets.map((target) => ({
// pathUUID: target.pathUUID,
// })),
// },
// },
// ],
// pathPosition: path.position,
// speed: path.point.speed || 1,
// };
// }
// }
// // Custom shallow comparison for arrays
// const areArraysEqual = (a: any[], b: any[]) => {
// if (a.length !== b.length) return false;
// for (let i = 0; i < a.length; i++) {
// if (a[i] !== b[i]) return false;
// }
// return true;
// };
// // Helper function to create an empty process
// const createEmptyProcess = (): Process => ({
// id: `process-${Math.random().toString(36).substring(2, 11)}`,
// paths: [],
// animationPath: [],
// pointActions: [],
// speed: 1,
// });
// // Enhanced connection checking function
// function shouldReverseNextPath(
// currentPath: SimulationPath,
// nextPath: SimulationPath
// ): boolean {
// if (nextPath.points.length !== 3) return false;
// const currentLastPoint = currentPath.points[currentPath.points.length - 1];
// const nextFirstPoint = nextPath.points[0];
// const nextLastPoint = nextPath.points[nextPath.points.length - 1];
// // Check if current last connects to next last (requires reversal)
// const connectsToLast = currentLastPoint.connections.targets.some(
// (target) =>
// target.pathUUID === nextPath.modeluuid &&
// nextLastPoint.connections.targets.some(
// (t) => t.pathUUID === currentPath.modeluuid
// )
// );
// // Check if current last connects to next first (no reversal needed)
// const connectsToFirst = currentLastPoint.connections.targets.some(
// (target) =>
// target.pathUUID === nextPath.modeluuid &&
// nextFirstPoint.connections.targets.some(
// (t) => t.pathUUID === currentPath.modeluuid
// )
// );
// // Only reverse if connected to last point and not to first point
// return connectsToLast && !connectsToFirst;
// }
// // Updated path adjustment function
// function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
// if (paths.length < 2) return paths;
// const adjustedPaths = [...paths];
// for (let i = 0; i < adjustedPaths.length - 1; i++) {
// const currentPath = adjustedPaths[i];
// const nextPath = adjustedPaths[i + 1];
// if (shouldReverseNextPath(currentPath, nextPath)) {
// const reversedPoints = [
// nextPath.points[2],
// nextPath.points[1],
// nextPath.points[0],
// ];
// adjustedPaths[i + 1] = {
// ...nextPath,
// points: reversedPoints,
// };
// }
// }
// return adjustedPaths;
// }
// // Main hook for process creation
// export function useProcessCreation() {
// const { scene } = useThree();
// const [processes, setProcesses] = useState<Process[]>([]);
// const hasSpawnAction = useCallback((path: SimulationPath): boolean => {
// return path.points.some((point) =>
// point.actions.some((action) => action.type.toLowerCase() === "spawn")
// );
// }, []);
// const createProcess = useCallback(
// (paths: SimulationPath[]): Process => {
// if (!paths || paths.length === 0) {
// return createEmptyProcess();
// }
// const animationPath: THREE.Vector3[] = [];
// const pointActions: PointAction[][] = [];
// const processSpeed = paths[0]?.speed || 1;
// for (const path of paths) {
// for (const point of path.points) {
// const obj = scene.getObjectByProperty("uuid", point.uuid);
// if (!obj) {
// console.warn(`Object with UUID ${point.uuid} not found in scene`);
// continue;
// }
// const position = obj.getWorldPosition(new THREE.Vector3());
// animationPath.push(position.clone());
// pointActions.push(point.actions);
// }
// }
// return {
// id: `process-${Math.random().toString(36).substring(2, 11)}`,
// paths,
// animationPath,
// pointActions,
// speed: processSpeed,
// };
// },
// [scene]
// );
// const getAllConnectedPaths = useCallback(
// (
// initialPath: SimulationPath,
// allPaths: SimulationPath[],
// visited: Set<string> = new Set()
// ): SimulationPath[] => {
// const connectedPaths: SimulationPath[] = [];
// const queue: SimulationPath[] = [initialPath];
// visited.add(initialPath.modeluuid);
// const pathMap = new Map<string, SimulationPath>();
// allPaths.forEach((path) => pathMap.set(path.modeluuid, path));
// while (queue.length > 0) {
// const currentPath = queue.shift()!;
// connectedPaths.push(currentPath);
// // Process outgoing connections
// for (const point of currentPath.points) {
// for (const target of point.connections.targets) {
// if (!visited.has(target.pathUUID)) {
// const targetPath = pathMap.get(target.pathUUID);
// if (targetPath) {
// visited.add(target.pathUUID);
// queue.push(targetPath);
// }
// }
// }
// }
// // Process incoming connections
// for (const [uuid, path] of pathMap) {
// if (!visited.has(uuid)) {
// const hasConnectionToCurrent = path.points.some((point) =>
// point.connections.targets.some(
// (t) => t.pathUUID === currentPath.modeluuid
// )
// );
// if (hasConnectionToCurrent) {
// visited.add(uuid);
// queue.push(path);
// }
// }
// }
// }
// return connectedPaths;
// },
// []
// );
// const createProcessesFromPaths = useCallback(
// (paths: SimulationPath[]): Process[] => {
// if (!paths || paths.length === 0) return [];
// const visited = new Set<string>();
// const processes: Process[] = [];
// const pathMap = new Map<string, SimulationPath>();
// paths.forEach((path) => pathMap.set(path.modeluuid, path));
// for (const path of paths) {
// if (!visited.has(path.modeluuid) && hasSpawnAction(path)) {
// const connectedPaths = getAllConnectedPaths(path, paths, visited);
// const adjustedPaths = adjustPathPointsOrder(connectedPaths);
// const process = createProcess(adjustedPaths);
// processes.push(process);
// }
// }
// return processes;
// },
// [createProcess, getAllConnectedPaths, hasSpawnAction]
// );
// return {
// processes,
// createProcessesFromPaths,
// setProcesses,
// };
// }
// const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
// ({ onProcessesCreated }) => {
// const { simulationPaths } = useSimulationPaths();
// const { createProcessesFromPaths } = useProcessCreation();
// const prevPathsRef = useRef<SimulationPath[]>([]);
// const prevProcessesRef = useRef<Process[]>([]);
// const convertedPaths = useMemo((): SimulationPath[] => {
// if (!simulationPaths) return [];
// return simulationPaths.map((path) =>
// convertToSimulationPath(
// path as ConveyorEventsSchema | VehicleEventsSchema
// )
// );
// }, [simulationPaths]);
// const pathsDependency = useMemo(() => {
// if (!convertedPaths) return null;
// return convertedPaths.map((path) => ({
// id: path.modeluuid,
// hasSpawn: path.points.some((p: PathPoint) =>
// p.actions.some((a: PointAction) => a.type.toLowerCase() === "spawn")
// ),
// connections: path.points
// .flatMap((p: PathPoint) =>
// p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
// )
// .join(","),
// }));
// }, [convertedPaths]);
// useEffect(() => {
// if (!convertedPaths || convertedPaths.length === 0) {
// if (prevProcessesRef.current.length > 0) {
// onProcessesCreated([]);
// prevProcessesRef.current = [];
// }
// return;
// }
// if (areArraysEqual(prevPathsRef.current, convertedPaths)) {
// return;
// }
// prevPathsRef.current = convertedPaths;
// const newProcesses = createProcessesFromPaths(convertedPaths);
// // console.log("--- Action Types in Paths ---");
// // convertedPaths.forEach((path) => {
// // path.points.forEach((point) => {
// // point.actions.forEach((action) => {
// // console.log(
// // `Path ${path.modeluuid}, Point ${point.uuid}: ${action.type}`
// // );
// // });
// // });
// // });
// // console.log("New processes:", newProcesses);
// if (
// newProcesses.length !== prevProcessesRef.current.length ||
// !newProcesses.every(
// (proc, i) =>
// proc.paths.length === prevProcessesRef.current[i]?.paths.length &&
// proc.paths.every(
// (path, j) =>
// path.modeluuid ===
// prevProcessesRef.current[i]?.paths[j]?.modeluuid
// )
// )
// ) {
// onProcessesCreated(newProcesses);
// // prevProcessesRef.current = newProcesses;
// }
// }, [
// pathsDependency,
// onProcessesCreated,
// convertedPaths,
// createProcessesFromPaths,
// ]);
// return null;
// }
// );
// export default ProcessCreator;
import React, {
useEffect,
useMemo,
@ -156,12 +555,38 @@ function shouldReverseNextPath(
return connectsToLast && !connectsToFirst;
}
// Check if a point has a spawn action
function hasSpawnAction(point: PathPoint): boolean {
return point.actions.some((action) => action.type.toLowerCase() === "spawn");
}
// Ensure spawn point is always at the beginning of the path
function ensureSpawnPointIsFirst(path: SimulationPath): SimulationPath {
if (path.points.length !== 3) return path;
// If the third point has spawn action and first doesn't, reverse the array
if (hasSpawnAction(path.points[2]) && !hasSpawnAction(path.points[0])) {
return {
...path,
points: [...path.points].reverse(),
};
}
return path;
}
// Updated path adjustment function
function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
if (paths.length < 2) return paths;
if (paths.length < 1) return paths;
const adjustedPaths = [...paths];
// First ensure all paths have spawn points at the beginning
for (let i = 0; i < adjustedPaths.length; i++) {
adjustedPaths[i] = ensureSpawnPointIsFirst(adjustedPaths[i]);
}
// Then handle connections between paths
for (let i = 0; i < adjustedPaths.length - 1; i++) {
const currentPath = adjustedPaths[i];
const nextPath = adjustedPaths[i + 1];
@ -326,13 +751,17 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
);
}, [simulationPaths]);
// Enhanced dependency tracking that includes action types
const pathsDependency = useMemo(() => {
if (!convertedPaths) return null;
return convertedPaths.map((path) => ({
id: path.modeluuid,
hasSpawn: path.points.some((p: PathPoint) =>
p.actions.some((a: PointAction) => a.type.toLowerCase() === "spawn")
),
// Track all action types for each point
actionSignature: path.points
.map((point, index) =>
point.actions.map((action) => `${index}-${action.type}`).join("|")
)
.join(","),
connections: path.points
.flatMap((p: PathPoint) =>
p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
@ -341,6 +770,7 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
}));
}, [convertedPaths]);
// Force process recreation when paths change
useEffect(() => {
if (!convertedPaths || convertedPaths.length === 0) {
if (prevProcessesRef.current.length > 0) {
@ -350,42 +780,16 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
return;
}
if (areArraysEqual(prevPathsRef.current, convertedPaths)) {
return;
}
prevPathsRef.current = convertedPaths;
// Always regenerate processes if the pathsDependency has changed
// This ensures action type changes will be detected
const newProcesses = createProcessesFromPaths(convertedPaths);
prevPathsRef.current = convertedPaths;
// console.log("--- Action Types in Paths ---");
// convertedPaths.forEach((path) => {
// path.points.forEach((point) => {
// point.actions.forEach((action) => {
// console.log(
// `Path ${path.modeluuid}, Point ${point.uuid}: ${action.type}`
// );
// });
// });
// });
// console.log("New processes:", newProcesses);
if (
newProcesses.length !== prevProcessesRef.current.length ||
!newProcesses.every(
(proc, i) =>
proc.paths.length === prevProcessesRef.current[i]?.paths.length &&
proc.paths.every(
(path, j) =>
path.modeluuid ===
prevProcessesRef.current[i]?.paths[j]?.modeluuid
)
)
) {
onProcessesCreated(newProcesses);
// prevProcessesRef.current = newProcesses;
}
// Always update processes when action types change
onProcessesCreated(newProcesses);
prevProcessesRef.current = newProcesses;
}, [
pathsDependency,
pathsDependency, // This now includes action types
onProcessesCreated,
convertedPaths,
createProcessesFromPaths,

View File

@ -19,7 +19,7 @@ function Simulation() {
const [processes, setProcesses] = useState([]);
useEffect(() => {
// console.log('simulationPaths: ', simulationPaths);
console.log('simulationPaths: ', simulationPaths);
}, [simulationPaths]);
// useEffect(() => {

View File

@ -0,0 +1,32 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const setEventApi = async (
organization: string,
modeluuid: string,
eventData: any
) => {
try {
const body: any = { organization, modeluuid, eventData };
const response = await fetch(`${url_Backend_dwinzo}/api/v2/eventDataUpdate`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error("Failed to set or update Floor Item");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -30,7 +30,6 @@ export const setFloorItemApi = async (
}
const result = await response.json();
console.log('result: ', result);
return result;
} catch (error) {
if (error instanceof Error) {

View File

@ -12,7 +12,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
}
const socket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`,
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`,
{
reconnection: false,
auth: { email, organization },
@ -343,14 +343,21 @@ export const useSelectedPath = create<any>((set: any) => ({
interface SimulationPathsStore {
simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[];
setSimulationPaths: (
paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]
paths:
| (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]
| ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]
) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[])
) => void;
}
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
simulationPaths: [],
setSimulationPaths: (paths) => set({ simulationPaths: paths }),
}));
setSimulationPaths: (paths) =>
set((state) => ({
simulationPaths:
typeof paths === "function" ? paths(state.simulationPaths) : paths,
})),
}))
export const useIsConnecting = create<any>((set: any) => ({
isConnecting: false,

View File

@ -1,33 +1,77 @@
import { create } from "zustand";
type WidgetData = {
id: string;
type: string;
position: [number, number, number];
id: string;
type: string;
position: [number, number, number];
tempPosition?: [number, number, number];
};
type ZoneWidgetStore = {
zoneWidgetData: Record<string, WidgetData[]>;
setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) => void;
addWidget: (zoneId: string, widget: WidgetData) => void;
zoneWidgetData: Record<string, WidgetData[]>;
setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) => void;
addWidget: (zoneId: string, widget: WidgetData) => void;
updateWidgetPosition: (zoneId: string, widgetId: string, newPosition: [number, number, number]) => void;
};
export const useZoneWidgetStore = create<ZoneWidgetStore>((set) => ({
zoneWidgetData: {},
setZoneWidgetData: (zoneId, widgets) =>
set((state) => ({
zoneWidgetData: {
...state.zoneWidgetData,
[zoneId]: widgets,
},
})),
addWidget: (zoneId, widget) =>
set((state) => ({
zoneWidgetData: {
...state.zoneWidgetData,
[zoneId]: [...(state.zoneWidgetData[zoneId] || []), widget],
},
})),
zoneWidgetData: {},
setZoneWidgetData: (zoneId, widgets) =>
set((state) => ({
zoneWidgetData: { ...state.zoneWidgetData, [zoneId]: widgets },
})),
addWidget: (zoneId, widget) =>
set((state) => ({
zoneWidgetData: {
...state.zoneWidgetData,
[zoneId]: [...(state.zoneWidgetData[zoneId] || []), widget],
},
})),
updateWidgetPosition: (zoneId, widgetId, newPosition) =>
set((state) => {
const widgets = state.zoneWidgetData[zoneId] || [];
return {
zoneWidgetData: {
...state.zoneWidgetData,
[zoneId]: widgets.map((widget) =>
widget.id === widgetId ? { ...widget, position: newPosition } : widget
),
},
};
}),
}));
interface RightClickStore {
rightClickSelected: string | null;
setRightClickSelected: (x: string | null) => void;
}
export const useRightClickSelected = create<RightClickStore>((set) => ({
rightClickSelected: null, // Default to null
setRightClickSelected: (x) => set({ rightClickSelected: x }),
}));
export const useTopData = create<any>((set: any) => ({
top: 0,
setTop: (x: any) => set({ top: x }),
}));
export const useLeftData = create<any>((set: any) => ({
left: 0,
setLeft: (x: any) => set({ left: x }),
}));
interface RightSelectStore {
rightSelect: string | null;
setRightSelect: (x: string | null) => void;
}
export const useRightSelected = create<RightSelectStore>((set) => ({
rightSelect: null, // Default state is null
setRightSelect: (x) => set({ rightSelect: x }),
}));

View File

@ -716,11 +716,6 @@
}
.editWidgetOptions-wrapper {
height: 100vh;
width: 100vw;
}
.editWidgetOptions {
position: absolute;