diff --git a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx
index 9b16186..cc0c597 100644
--- a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx
+++ b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx
@@ -3,6 +3,7 @@ import { AIIcon } from "../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { AnalysisPresetsType } from "../../../../types/analysis";
import RenderAnalysisInputs from "./RenderAnalysisInputs";
+import { useInputValues } from "../../../../store/store";
const Analysis: React.FC = () => {
const [selectedOption, setSelectedOption] = useState("Throughput time");
@@ -48,6 +49,10 @@ const Analysis: React.FC = () => {
type: "default",
inputs: { label: "Fixed costs", activeOption: "INR" },
},
+ {
+ type: "default",
+ inputs: { label: "Initial Investment", activeOption: "INR" },
+ },
{
type: "default",
inputs: { label: "Salvage value", activeOption: "Hrs" },
@@ -63,6 +68,8 @@ const Analysis: React.FC = () => {
],
};
+ const { inputValues, setInputValues, updateInputValue } = useInputValues();
+
return (
@@ -88,10 +95,14 @@ const Analysis: React.FC = () => {
presets={
AnalysisPresets[selectedOption as keyof AnalysisPresetsType]
}
+ inputValues={inputValues}
+ onInputChange={(label, value) => {
+ updateInputValue(label, value);
+ }}
/>
-
-
+ setInputValues({})} />
+ setInputValues(inputValues)} />
Create Custom Analysis
diff --git a/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx b/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx
index e14b542..0204582 100644
--- a/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx
+++ b/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx
@@ -6,12 +6,11 @@ import { AnalysisPresetsType } from "../../../../types/analysis";
interface InputRendererProps {
keyName: string;
presets: AnalysisPresetsType[keyof AnalysisPresetsType];
+ inputValues: Record
; // <-- Add this line
+ onInputChange: (label: string, value: string) => void;
}
-const RenderAnalysisInputs: React.FC = ({
- keyName,
- presets,
-}) => {
+const RenderAnalysisInputs: React.FC = ({ keyName, presets,inputValues, onInputChange }) => {
return (
{presets.map((preset, index) => {
@@ -20,9 +19,9 @@ const RenderAnalysisInputs: React.FC
= ({
{}}
+ onChange={(newValue) => onInputChange(preset.inputs.label, newValue)}
/>
);
}
diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx
index 94ab1eb..e9242f6 100644
--- a/app/src/components/ui/analysis/ProductionCapacity.tsx
+++ b/app/src/components/ui/analysis/ProductionCapacity.tsx
@@ -21,9 +21,6 @@ const ThroughputSummary:React.FC = () => {
};
const { machineActiveTime } = useMachineUptime();
-
-
-
const energyConsumption = {
energyConsumed: 456,
unit: "KWH",
diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx
index 1dfe184..a287a11 100644
--- a/app/src/components/ui/analysis/ThroughputSummary.tsx
+++ b/app/src/components/ui/analysis/ThroughputSummary.tsx
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
-import { useMachineCount, useMachineUptime, useMaterialCycle } from "../../../store/store";
+import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from "../../../store/store";
import {
ThroughputSummaryIcon,
} from "../../icons/analysis";
@@ -13,26 +13,32 @@ const ProductionCapacity = ({
}) => {
- const { machineCount } = useMachineCount();
+
const { machineActiveTime } = useMachineUptime();
const { materialCycleTime } = useMaterialCycle();
-
+ const { throughputData } = useThroughPutData()
+
+
const progressPercent = machineActiveTime;
-
-
+
+
const totalBars = 6;
const barsToFill = Math.floor((progressPercent / 100) * totalBars);
const partialFillPercent =
- ((progressPercent / 100) * totalBars - barsToFill) * 100;
-
+ ((progressPercent / 100) * totalBars - barsToFill) * 100;
+
const [isLoading, setIsLoading] = useState(false);
- // const { machineCount, setMachineCount } = useMachineCount()
- // const { machineActiveTime, setMachineActiveTime } = useMachineUptime()
+
useEffect(() => {
- setIsLoading(true);
- machineUtilization = machineActiveTime
- console.log('machineActiveTime: ', machineActiveTime);
- }, [machineActiveTime])
+ if (throughputData > 0) {
+ console.log('machineActiveTime: ', machineActiveTime);
+ console.log('materialCycleTime: ', materialCycleTime);
+ console.log('throughputData: ', throughputData);
+
+ setIsLoading(true);
+ }
+
+ }, [throughputData])
return (
@@ -52,7 +58,7 @@ const ProductionCapacity = ({
<>
- {machineActiveTime} Units/hour
+ {throughputData} Units/hour
{/* Dynamic Progress Bar */}
@@ -79,7 +85,7 @@ const ProductionCapacity = ({
Machine Utilization
- 1
+ {machineActiveTime}
{/* {machineActiveTime} */}
diff --git a/app/src/components/ui/inputs/InputWithDropDown.tsx b/app/src/components/ui/inputs/InputWithDropDown.tsx
index 3d42917..c6316d6 100644
--- a/app/src/components/ui/inputs/InputWithDropDown.tsx
+++ b/app/src/components/ui/inputs/InputWithDropDown.tsx
@@ -52,7 +52,8 @@ const InputWithDropDown: React.FC = ({
max={max}
step={step}
type="number"
- defaultValue={value}
+ // defaultValue={value}
+ value={value}
onChange={(e) => {
onChange(e.target.value);
}}
diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx
new file mode 100644
index 0000000..22b524d
--- /dev/null
+++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx
@@ -0,0 +1,84 @@
+import React, { useEffect } from 'react'
+import { useInputValues, useProductionCapacityData } from '../../../../store/store';
+
+export default function ROIData() {
+ const { inputValues } = useInputValues();
+ const { productionCapacityData } = useProductionCapacityData()
+
+ useEffect(() => {
+ if (inputValues === undefined) return;
+
+ const electricityCost = parseFloat(inputValues["Electricity cost"]);
+ const fixedCost = parseFloat(inputValues["Fixed costs"]);
+ const laborCost = parseFloat(inputValues["Labor Cost"]);
+ const maintenanceCost = parseFloat(inputValues["Maintenance cost"]); // Remove space typ
+ const materialCost = parseFloat(inputValues["Material cost"]);
+ const productionPeriod = parseFloat(inputValues["Production period"]);
+ const salvageValue = parseFloat(inputValues["Salvage value"]);
+ const sellingPrice = parseFloat(inputValues["Selling price"]);
+ const initialInvestment = parseFloat(inputValues["Initial Investment"]);
+ const shiftLength = parseFloat(inputValues["Shift length"]);
+ const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
+ const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
+
+ if (!isNaN(electricityCost) && !isNaN(fixedCost) && !isNaN(laborCost) && !isNaN(maintenanceCost) &&
+ !isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
+ !isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) {
+
+ console.log('sellingPrice: ', sellingPrice);
+ console.log('salvageValue: ', salvageValue);
+ console.log('productionPeriod: ', productionPeriod);
+ console.log('materialCost: ', materialCost);
+ console.log('maintenanceCost: ', maintenanceCost);
+ console.log('laborCost: ', laborCost);
+ console.log('fixedCost: ', fixedCost);
+ console.log('electricityCost: ', electricityCost);
+
+
+ // Revenue
+ const RevenueForYear = productionCapacityData * sellingPrice;
+ console.log('RevenueForYear: ', RevenueForYear);
+
+ //Costs
+ let MaterialCost = productionCapacityData * materialCost
+ console.log('MaterialCost: ', MaterialCost);
+ let LaborCost = laborCost * shiftLength * shiftsPerDay * workingDaysPerYear;
+ console.log('LaborCost: ', LaborCost);
+ let EnergyCost = electricityCost * shiftLength * shiftsPerDay * workingDaysPerYear;
+ console.log('EnergyCost: ', EnergyCost);
+ let MaintenceCost = maintenanceCost + fixedCost;
+ console.log('MaintenceCost: ', MaintenceCost);
+
+ //Total Anuual Cost
+ let TotalAnnualCost = MaterialCost + LaborCost + EnergyCost + MaintenceCost;
+ console.log('TotalAnnualCost: ', TotalAnnualCost);
+
+ //Profit for Year
+ let ProfitforYear = RevenueForYear - TotalAnnualCost;
+ console.log('ProfitforYear: ', ProfitforYear);
+
+ //Net Profit
+ let NetProfit = ProfitforYear * productionPeriod;
+ console.log('NetProfit: ', NetProfit);
+
+
+ //Final ROI
+ const ROIData = ((NetProfit + salvageValue - initialInvestment) / TotalAnnualCost) * 100;
+ console.log('ROIData: ', ROIData);
+
+
+ // Payback Period
+ const paybackPeriod = initialInvestment / ProfitforYear;
+ console.log('paybackPeriod: ', paybackPeriod);
+
+
+ }
+
+ }, [inputValues, productionCapacityData]);
+
+ return (
+ <>>
+ )
+}
+
+
diff --git a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx
new file mode 100644
index 0000000..b9739d3
--- /dev/null
+++ b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx
@@ -0,0 +1,48 @@
+import React, { useEffect } from 'react'
+import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/store'
+
+export default function ProductionCapacityData() {
+ const { throughputData } = useThroughPutData()
+ const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData()
+ const { inputValues } = useInputValues();
+
+ useEffect(() => {
+ if (inputValues === undefined || throughputData === undefined) return;
+
+ const shiftLength = parseFloat(inputValues["Shift length"]);
+ // console.log('shiftLength: ', shiftLength);
+ const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
+ // console.log('shiftsPerDay: ', shiftsPerDay);
+ const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
+ // console.log('workingDaysPerYear: ', workingDaysPerYear);
+ const yieldRate = parseFloat(inputValues["Yield rate"]);
+ // console.log('yieldRate: ', yieldRate);
+
+
+ if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && !isNaN(yieldRate) && throughputData > 0) {
+ //Daily Output
+ const dailyProduction = throughputData * shiftLength * shiftsPerDay;
+ console.log("DailyProduction: ", dailyProduction.toFixed(2));
+ // Good units (after Yield)
+ const afterYield = dailyProduction * (yieldRate / 100);
+ console.log('afterYield: ', afterYield.toFixed(2));
+ //Annual Output
+ const annualProduction = afterYield * workingDaysPerYear;
+ console.log('annualProduction: ', annualProduction.toFixed(2));
+ setProductionCapacityData(annualProduction);
+ }
+ }, [throughputData, inputValues]);
+
+
+
+ useEffect(() => {
+
+
+ }, [])
+
+ return (
+ <>>
+ )
+}
+
+
diff --git a/app/src/modules/simulation/analysis/simulationAnalysis.tsx b/app/src/modules/simulation/analysis/simulationAnalysis.tsx
index 531c103..db5a88b 100644
--- a/app/src/modules/simulation/analysis/simulationAnalysis.tsx
+++ b/app/src/modules/simulation/analysis/simulationAnalysis.tsx
@@ -1,10 +1,23 @@
-import React from 'react'
-import ThroughPut from './throughPut/throughPut'
+import React, { useEffect } from 'react'
+import { usePlayButtonStore } from '../../../store/usePlayButtonStore'
+import ProductionCapacityData from './productionCapacity/productionCapacityData'
+import ThroughPutData from './throughPut/throughPutData'
+import ROIData from './ROI/roiData'
function SimulationAnalysis() {
+ const { isPlaying } = usePlayButtonStore()
+ // useEffect(()=>{
+ // if (isPlaying) {
+ //
+ // } else {
+ //
+ // }
+ // },[isPlaying])
return (
<>
-
+
+
+
>
)
}
diff --git a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx
deleted file mode 100644
index 8a9e331..0000000
--- a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx
+++ /dev/null
@@ -1,239 +0,0 @@
-// import React, { useEffect, useState } from 'react';
-// import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
-// import { useProductStore } from '../../../../store/simulation/useProductStore';
-// import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences';
-// import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
-// import { useMachineCount, useMachineUptime, useMaterialCycle } from '../../../../store/store';
-// import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
-// import { useMachineStore } from '../../../../store/simulation/useMachineStore';
-// import { useConveyorStore } from '../../../../store/simulation/useConveyorStore';
-// import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore';
-// import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
-
-// export default function ThroughPut() {
-// const { selectedProduct } = useSelectedProduct();
-// const { products, getProductById } = useProductStore();
-// const { armBots } = useArmBotStore();
-// const { vehicles } = useVehicleStore();
-// const { machines } = useMachineStore();
-// const { conveyors } = useConveyorStore();
-// const { storageUnits } = useStorageUnitStore();
-// const { materials } = useMaterialStore();
-
-// const { machineCount, setMachineCount } = useMachineCount();
-// const { setMachineActiveTime } = useMachineUptime();
-// const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle();
-
-// const [totalActiveTime, setTotalActiveTime] = useState(0);
-
-// // 1. Setting static active times and counting machines
-// useEffect(() => {
-// const productData = getProductById(selectedProduct.productId);
-// if (productData) {
-// const productSequenceData = determineExecutionMachineSequences([productData]);
-// if (productSequenceData?.length > 0) {
-// let totalItems = 0;
-
-// productSequenceData.forEach((sequence) => {
-// totalItems += sequence.length;
-// sequence.forEach((item) => {
-// if (item.type === "roboticArm") {
-// armBots.filter(arm => arm.modelUuid === item.modelUuid)
-// .forEach(arm => {
-// if (arm.activeTime >= 0) {
-//
-// }
-// });
-// } else if (item.type === "vehicle") {
-// vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid)
-// .forEach(vehicle => {
-// if (vehicle.activeTime >= 0) {
-// vehicle.activeTime = 10; // static
-// }
-// });
-// } else if (item.type === "machine") {
-// machines.filter(machine => machine.modelUuid === item.modelUuid)
-// .forEach(machine => {
-// if (machine.activeTime >= 0) {
-// machine.activeTime = 12; // static
-// }
-// });
-// } else if (item.type === "transfer") {
-// conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid)
-// .forEach(conveyor => {
-// if (conveyor.activeTime >= 0) {
-// conveyor.activeTime = 5; // static
-// }
-// });
-// } else if (item.type === "storageUnit") {
-// storageUnits.filter(storage => storage.modelUuid === item.modelUuid)
-// .forEach(storage => {
-// if (storage.activeTime >= 0) {
-// storage.activeTime = 8; // static
-// }
-// });
-// }
-// });
-// });
-
-// setMachineCount(totalItems);
-// }
-// }
-// }, [products, selectedProduct, armBots, vehicles, machines, conveyors, storageUnits, getProductById, setMachineCount]);
-
-// // 2. Set material cycle time (static also)
-// useEffect(() => {
-// materials.forEach((material) => {
-// material.startTime = 50;
-// material.endTime = 100;
-// const totalCycleTime = material.endTime - material.startTime;
-// setMaterialCycleTime(totalCycleTime);
-// });
-// }, [materials, setMaterialCycleTime]);
-
-// // 3. Sum of all activeTimes after static values are set
-// useEffect(() => {
-// let sum = 0;
-// armBots.forEach(arm => { if (arm.activeTime > 0) sum += arm.activeTime; });
-// vehicles.forEach(vehicle => { if (vehicle.activeTime > 0) sum += vehicle.activeTime; });
-// machines.forEach(machine => { if (machine.activeTime > 0) sum += machine.activeTime; });
-// conveyors.forEach(conveyor => { if (conveyor.activeTime > 0) sum += conveyor.activeTime; });
-// storageUnits.forEach(storage => { if (storage.activeTime > 0) sum += storage.activeTime; });
-
-// setTotalActiveTime(sum);
-// setMachineActiveTime(sum);
-
-// }, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]);
-
-// // 4. Calculate throughput when activeTime and materialCycleTime are ready
-// useEffect(() => {
-// if (totalActiveTime > 0 && materialCycleTime > 0) {
-// const avgProcessTime = (totalActiveTime / materialCycleTime) * 100;
-//
-// }
-// }, [totalActiveTime, materialCycleTime]);
-
-// return (
-// <>
-// >
-// );
-// }
-
-
-import React, { useEffect, useState } from 'react';
-import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
-import { useProductStore } from '../../../../store/simulation/useProductStore';
-import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences';
-import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
-import { useMachineCount, useMachineUptime, useMaterialCycle } from '../../../../store/store';
-import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
-import { useMachineStore } from '../../../../store/simulation/useMachineStore';
-import { useConveyorStore } from '../../../../store/simulation/useConveyorStore';
-import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore';
-import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
-
-export default function ThroughPut() {
- const { selectedProduct } = useSelectedProduct();
- const { products, getProductById } = useProductStore();
- const { armBots } = useArmBotStore();
- const { vehicles } = useVehicleStore();
- const { machines } = useMachineStore();
- const { conveyors } = useConveyorStore();
- const { storageUnits } = useStorageUnitStore();
- const { materials } = useMaterialStore();
-
- const { setMachineCount } = useMachineCount();
- const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
- console.log('machineActiveTime: ', machineActiveTime);
- const { setMaterialCycleTime } = useMaterialCycle();
-
- const [totalActiveTime, setTotalActiveTime] = useState(0);
- const [throughputData, setThroughputData] = useState(0); // <=== ADD THIS
-
- // Setting machine count
- useEffect(() => {
- const productData = getProductById(selectedProduct.productId);
- if (productData) {
- const productSequenceData = determineExecutionMachineSequences([productData]);
- if (productSequenceData?.length > 0) {
- let totalItems = 0;
- productSequenceData.forEach((sequence) => {
- totalItems += sequence.length;
- });
- setMachineCount(totalItems);
- }
- }
- }, [products, selectedProduct, getProductById, setMachineCount]);
-
- // Setting material cycle time
- useEffect(() => {
- materials.forEach(() => {
- const staticStartTime = 50;
- const staticEndTime = 100;
- const totalCycleTime = staticEndTime - staticStartTime;
- setMaterialCycleTime(totalCycleTime);
- });
- }, [materials, setMaterialCycleTime]);
-
- // Calculate Sum, Machine Uptime and Throughput
- useEffect(() => {
- let sum = 0;
-
-
- armBots.forEach(arm => {
-
- if (arm.activeTime > 0) sum += arm.activeTime;
- });
-
- vehicles.forEach(vehicle => {
- if (vehicle.activeTime > 0) sum += 10; // static
- });
-
- machines.forEach(machine => {
- if (machine.activeTime > 0) sum += 12; // static
- });
-
- conveyors.forEach(conveyor => {
- if (conveyor.activeTime > 0) sum += 5; // static
- });
-
- storageUnits.forEach(storage => {
- if (storage.activeTime > 0) sum += 8; // static
- });
-
-
-
- const avgProcessTime = 100 - 50; // static 50
-
- const machineUptime = (sum / avgProcessTime) * 100;
- console.log('machineUptime: ', machineUptime);
-
-
-
- const machineCount = 3; // static
- const throughput = (3600 / avgProcessTime) * machineCount * (machineUptime / 100); // **IMPORTANT divide by 100 for %**
-
-
-
- setTotalActiveTime(sum);
- setMachineActiveTime(machineUptime)
- setMaterialCycleTime(throughput)
- // setMachineActiveTime(sum);
- setThroughputData(throughput); // Save it properly here
-
- }, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]);
-
- // Just display throughput when ready
- useEffect(() => {
-
- if (throughputData > 0) {
-
- }
- }, [throughputData]);
-
- return (
- <>
- >
- );
-}
-
diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx
new file mode 100644
index 0000000..b7d6130
--- /dev/null
+++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx
@@ -0,0 +1,208 @@
+import React, { useEffect, useRef, useState } from 'react';
+import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
+import { useProductStore } from '../../../../store/simulation/useProductStore';
+import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences';
+import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
+import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from '../../../../store/store';
+import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
+import { useMachineStore } from '../../../../store/simulation/useMachineStore';
+import { useConveyorStore } from '../../../../store/simulation/useConveyorStore';
+import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore';
+import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
+import { usePauseButtonStore, usePlayButtonStore } from '../../../../store/usePlayButtonStore';
+
+export default function ThroughPutData() {
+ const { selectedProduct } = useSelectedProduct();
+ const { products, getProductById } = useProductStore();
+ const { armBots, incrementActiveTime, incrementIdleTime } = useArmBotStore();
+ const { vehicles } = useVehicleStore();
+ const { machines } = useMachineStore();
+ const { conveyors } = useConveyorStore();
+ const { storageUnits } = useStorageUnitStore();
+ const { materials } = useMaterialStore();
+
+ const { machineCount, setMachineCount } = useMachineCount();
+ const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
+
+ const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle();
+
+ // const [totalActiveTime, setTotalActiveTime] = useState(0);
+ const { setThroughputData } = useThroughPutData() // <=== ADD THIS
+ const { isPlaying } = usePlayButtonStore();
+
+ // Setting machine count
+ useEffect(() => {
+ if (materialCycleTime < 0) return
+ // console.log('materialCycleTime: ', materialCycleTime);
+ const fetchProductSequenceData = async () => {
+ const productData = getProductById(selectedProduct.productId);
+ if (productData) {
+ const productSequenceData = await determineExecutionMachineSequences([productData]);
+ // console.log('productSequenceData: ', productSequenceData);
+
+ if (productSequenceData?.length > 0) {
+ let totalItems = 0;
+ let totalActiveTime = 0;
+
+ productSequenceData.forEach((sequence) => {
+ // console.log('sequence: ', sequence);
+
+ sequence.forEach((item) => {
+ if (item.type === "roboticArm") {
+ armBots.filter(arm => arm.modelUuid === item.modelUuid)
+ .forEach(arm => {
+
+ if (arm.activeTime >= 0) {
+ totalActiveTime += arm.activeTime;
+ }
+ });
+ } else if (item.type === "vehicle") {
+ vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid)
+ .forEach(vehicle => {
+
+ if (vehicle.activeTime >= 0) {
+ // totalActiveTime += vehicle.activeTime;
+ // totalActiveTime += 10;
+ }
+ });
+ } else if (item.type === "machine") {
+ machines.filter(machine => machine.modelUuid === item.modelUuid)
+ .forEach(machine => {
+ if (machine.activeTime >= 0) {
+ // totalActiveTime += machine.activeTime;
+ // totalActiveTime += 12;
+ }
+ });
+ } else if (item.type === "transfer") {
+ conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid)
+ .forEach(conveyor => {
+ if (conveyor.activeTime >= 0) {
+ // totalActiveTime += conveyor.activeTime;
+ // totalActiveTime += 7;
+ }
+ });
+ } else if (item.type === "storageUnit") {
+ storageUnits.filter(storage => storage.modelUuid === item.modelUuid)
+ .forEach(storage => {
+ if (storage.activeTime >= 0) {
+ // totalActiveTime += storage.activeTime;
+ // totalActiveTime += 9;
+ }
+ });
+ }
+ });
+
+ totalItems += sequence.length;
+ });
+
+ setMachineCount(totalItems);
+ setMachineActiveTime(totalActiveTime);
+
+ }
+ }
+ };
+
+ fetchProductSequenceData();
+ }, [products, selectedProduct, getProductById, setMachineCount, isPlaying, armBots, materialCycleTime]);
+
+ // Setting material cycle time
+ useEffect(() => {
+ materials.map((material) => {
+ // console.log('material: ', material);
+ // const totalCycleTime = material.endTime - material.startTime;//dynamic
+ const staticStartTime = 50;
+ const staticEndTime = 100;
+ const totalCycleTime = staticEndTime - staticStartTime;
+ setMaterialCycleTime(totalCycleTime)
+
+ })
+ }, [materials]);
+
+
+ useEffect(() => {
+ if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) {
+ const avgProcessTime = (machineActiveTime / materialCycleTime) * 100; // % value
+ const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); // β
division by 100
+ setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store
+
+ // console.log('---Throughput Results---');
+ // console.log('Total Active Time:', machineActiveTime);
+ // console.log('Material Cycle Time:', materialCycleTime);
+ // console.log('Machine Count:', machineCount);
+ // console.log('Average Process Time (%):', avgProcessTime);
+ // console.log('Calculated Throughput:', throughput);
+ }
+ }, [machineActiveTime, materialCycleTime, machineCount]);
+
+
+
+ return (
+ <>
+ >
+ );
+}
+
+
+
+ // useEffect(() => {
+ // if (!isPlaying) return;
+
+ // const intervalMs = 1000
+
+ // if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) {
+ // isIdleRef.current = true
+
+ // // Stop the timer
+ // // π¨ 1. Clear Active Timer
+ // if (activeTimerId.current) {
+ // clearInterval(activeTimerId.current);
+ // activeTimerId.current = null;
+ // }
+ // incrementActiveTime(armBot.modelUuid, activeSecondsElapsed.current)
+ // console.log(`β
Active Cycle completed in ${activeSecondsElapsed.current} seconds`);
+
+ // // π¨ 2. Reset active timer seconds after logging
+ // // activeSecondsElapsed.current = 0;
+
+ // // π¨ 3. Start Idle Timer (clean old idle timer first)
+ // if (idleTimerId.current) {
+ // clearInterval(idleTimerId.current);
+ // idleTimerId.current = null;
+ // }
+
+ // idleSecondsElapsed.current = 0;
+ // idleTimerId.current = setInterval(() => {
+ // if (!isPausedRef.current) {
+ // idleSecondsElapsed.current += 1;
+ // console.log(`π Idle Timer: ${idleSecondsElapsed.current} seconds`);
+ // }
+ // }, intervalMs);
+ // }
+ // if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) {
+ // isIdleRef.current = false
+
+ // if (armBot.currentAction) {
+ // // π¨ Clear Idle Timer
+ // if (idleTimerId.current) {
+ // clearInterval(idleTimerId.current);
+ // idleTimerId.current = null;
+ // }
+ // incrementIdleTime(armBot.modelUuid, idleSecondsElapsed.current)
+ // console.log(`π Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`);
+ // idleSecondsElapsed.current = 0;
+
+ // // π¨ Start Active Timer
+ // if (activeTimerId.current) {
+ // clearInterval(activeTimerId.current);
+ // }
+ // // activeSecondsElapsed.current = 0;
+ // activeTimerId.current = setInterval(() => {
+ // if (!isPausedRef.current) {
+ // activeSecondsElapsed.current += 1
+ // console.log(`π Active Timer: ${activeSecondsElapsed.current} seconds`);
+ // }
+ // }, intervalMs);
+ // }
+ // }
+
+ // }, [armBot, currentPhase, isPlaying])
\ No newline at end of file
diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
index d498783..6de5f1d 100644
--- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
+++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
@@ -29,7 +29,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
const isIdleRef = useRef(false);
let startTime: number;
- const { setArmBotActive, setArmBotState, removeCurrentAction,incrementActiveTime,incrementIdleTime } = useArmBotStore();
+ const { armBots, setArmBotActive, setArmBotState, removeCurrentAction, incrementActiveTime, incrementIdleTime } = useArmBotStore();
const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = useStorageUnitStore();
const { setIsVisible, getMaterialById } = useMaterialStore();
@@ -42,10 +42,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
const { speed } = useAnimationPlaySpeed();
const activeSecondsElapsed = useRef(0);
- const activeTimerId = useRef | null>(null);
-
const idleSecondsElapsed = useRef(0);
- const idleTimerId = useRef | null>(null);
+
+ const animationFrameIdRef = useRef(null);
+ const previousTimeRef = useRef(null);
function firstFrame() {
startTime = performance.now();
@@ -168,12 +168,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
}
useEffect(() => {
-
isPausedRef.current = isPaused;
}, [isPaused]);
useEffect(() => {
-
isSpeedRef.current = speed;
}, [speed]);
@@ -189,12 +187,13 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
isPausedRef.current = false
pauseTimeRef.current = null
startTime = 0
- clearInterval(activeTimerId.current!);
- clearInterval(idleTimerId.current!);
- activeTimerId.current = null;
activeSecondsElapsed.current = 0;
idleSecondsElapsed.current = 0;
- idleTimerId.current = null;
+ previousTimeRef.current = null;
+ if (animationFrameIdRef.current !== null) {
+ cancelAnimationFrame(animationFrameIdRef.current);
+ animationFrameIdRef.current = null;
+ }
const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone
);
if (targetBones && isPlaying) {
@@ -207,186 +206,65 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
}
}, [isReset, isPlaying])
- useEffect(() => {
- if (!isPlaying) return;
- const intervalMs = 1000
-
- if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) {
- isIdleRef.current = true
-
- // Stop the timer
- // π¨ 1. Clear Active Timer
- if (activeTimerId.current) {
- clearInterval(activeTimerId.current);
- activeTimerId.current = null;
+ function animate(currentTime: number) {
+ if (previousTimeRef.current === null) {
+ previousTimeRef.current = currentTime;
+ }
+ const deltaTime = (currentTime - previousTimeRef.current) / 1000;
+ previousTimeRef.current = currentTime;
+ if (armBot.isActive) {
+ if (!isPausedRef.current) {
+ activeSecondsElapsed.current += deltaTime * isSpeedRef.current;
+ // console.log(' activeSecondsElapsed.current: ', activeSecondsElapsed.current);
}
- incrementActiveTime(armBot.modelUuid, activeSecondsElapsed.current)
- // console.log(`β
Active Cycle completed in ${activeSecondsElapsed.current} seconds`);
-
- // π¨ 2. Reset active timer seconds after logging
- activeSecondsElapsed.current = 0;
-
- // π¨ 3. Start Idle Timer (clean old idle timer first)
- if (idleTimerId.current) {
- clearInterval(idleTimerId.current);
- idleTimerId.current = null;
- }
-
- idleSecondsElapsed.current = 0;
- idleTimerId.current = setInterval(() => {
- if (!isPausedRef.current) {
- idleSecondsElapsed.current += 1;
- // console.log(`π Idle Timer: ${idleSecondsElapsed.current} seconds`);
- }
- }, intervalMs);
- } else if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) {
- isIdleRef.current = false
-
- if (armBot.currentAction) {
- // π¨ Clear Idle Timer
- if (idleTimerId.current) {
- clearInterval(idleTimerId.current);
- idleTimerId.current = null;
- }
- incrementIdleTime(armBot.modelUuid, idleSecondsElapsed.current)
- // console.log(`π Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`);
- idleSecondsElapsed.current = 0;
-
- // π¨ Start Active Timer
- if (activeTimerId.current) {
- clearInterval(activeTimerId.current);
- }
- activeSecondsElapsed.current = 0;
- activeTimerId.current = setInterval(() => {
- if (!isPausedRef.current) {
- activeSecondsElapsed.current += 1
- // console.log(`π Active Timer: ${activeSecondsElapsed.current} seconds`);
- }
- }, intervalMs);
+ } else {
+ if (!isPausedRef.current) {
+ idleSecondsElapsed.current += deltaTime * isSpeedRef.current;
+ // console.log('idleSecondsElapsed.current: ', idleSecondsElapsed.current);
}
}
+ animationFrameIdRef.current = requestAnimationFrame(animate);
+ }
- }, [armBot, currentPhase, isPlaying])
+ useEffect(() => {
+ if (!isPlaying) return
+ if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init")) {
+ cancelAnimationFrame(animationFrameIdRef.current!);
+ animationFrameIdRef.current = null;
+ const roundedActiveTime = Math.round(activeSecondsElapsed.current); // Get the final rounded active time
+ console.log('Final Active Time:', roundedActiveTime, 'seconds');
+ incrementActiveTime(armBot.modelUuid, roundedActiveTime);
+ activeSecondsElapsed.current = 0;
- // useEffect(() => {
- // if (!isPlaying) return;
- // const now = () => performance.now();
+ } else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction) {
+ cancelAnimationFrame(animationFrameIdRef.current!);
+ animationFrameIdRef.current = null;
+ const roundedIdleTime = Math.round(idleSecondsElapsed.current); // Get the final rounded idle time
+ console.log('Final Idle Time:', roundedIdleTime, 'seconds');
+ incrementIdleTime(armBot.modelUuid, roundedIdleTime);
+ idleSecondsElapsed.current = 0;
+ }
+ if (animationFrameIdRef.current === null) {
+ animationFrameIdRef.current = requestAnimationFrame(animate);
+ }
- // const startActiveTimer = () => {
- // let lastTime = now();
+ return () => {
+ if (animationFrameIdRef.current !== null) {
+ cancelAnimationFrame(animationFrameIdRef.current);
+ animationFrameIdRef.current = null; // Reset the animation frame ID
+ }
+ };
- // const update = () => {
- // if (!isPausedRef.current) {
- // const currentTime = now();
- // const delta = currentTime - lastTime;
- // activeSecondsElapsed.current += delta / 1000;
- // console.log(`π Active Timer: ${activeSecondsElapsed.current.toFixed(2)} seconds`);
- // lastTime = currentTime;
- // } else {
+ }, [armBot.isActive, armBot.state, currentPhase])
- // lastTime = now();
- // }
+ useEffect(() => {
- // if (!isIdleRef.current) {
- // requestAnimationFrame(update);
- // }
- // };
+ console.log('armBots: ', armBots);
+ }, [armBots])
- // activeSecondsElapsed.current = 0;
- // update();
- // };
-
- // const startIdleTimer = () => {
- // let lastTime = now();
-
- // const update = () => {
- // if (!isPausedRef.current) {
- // const currentTime = now();
- // const delta = currentTime - lastTime;
- // idleSecondsElapsed.current += delta / 1000;
- // console.log(`π Idle Timer: ${idleSecondsElapsed.current.toFixed(2)} seconds`);
- // lastTime = currentTime;
- // } else {
- // lastTime = now();
- // }
-
- // if (isIdleRef.current) {
- // requestAnimationFrame(update);
- // }
- // };
-
- // idleSecondsElapsed.current = 0;
- // update();
- // };
-
- // // State transition logic
- // if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init") && !isIdleRef.current) {
- // isIdleRef.current = true;
- // console.log(`β
Active Cycle completed in ${activeSecondsElapsed.current.toFixed(2)} seconds`);
- // startIdleTimer();
- // }
- // else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) {
- // isIdleRef.current = false;
- // console.log(`π Idle Cycle completed in: ${idleSecondsElapsed.current.toFixed(2)} seconds`);
- // startActiveTimer();
- // }
-
- // }, [armBot, currentPhase, isPlaying, isIdleRef.current, isPausedRef.current]);
-
-
-
- // useEffect(() => {
- // if (!isPlaying) return;
-
- // let frameId: number | null = null;
- // let lastTime = performance.now();
-
- // const tick = (currentTime: number) => {
- // const delta = currentTime - lastTime;
- // lastTime = currentTime;
-
- // const secondsToAdd = delta / 1000; // β‘οΈREAL time passed (NO speed multiplication)
-
- // if (!isPausedRef.current) {
- // // Update Timer
- // if (isIdleRef.current) {
- // idleSecondsElapsed.current += secondsToAdd;
- // console.log(`π Idle Timer: ${idleSecondsElapsed.current.toFixed(2)} seconds (Speed: ${isSpeedRef.current}x)`);
- // } else {
- // activeSecondsElapsed.current += secondsToAdd;
- // console.log(`π Active Timer: ${activeSecondsElapsed.current.toFixed(2)} seconds (Speed: ${isSpeedRef.current}x)`);
- // }
- // }
- // frameId = requestAnimationFrame(tick);
- // };
- // // Detect mode switch
- // if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init") && !isIdleRef.current) {
- // isIdleRef.current = true;
-
- // console.log(`β
Active Cycle completed in ${activeSecondsElapsed.current.toFixed(2)} seconds`);
- // activeSecondsElapsed.current = 0;
- // idleSecondsElapsed.current = 0;
- // } else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) {
- // isIdleRef.current = false;
- // console.log(`π Idle Cycle completed in: ${idleSecondsElapsed.current.toFixed(2)} seconds`);
- // idleSecondsElapsed.current = 0;
- // activeSecondsElapsed.current = 0;
- // }
-
- // frameId = requestAnimationFrame(tick);
-
- // return () => {
- // if (frameId !== null) {
- // cancelAnimationFrame(frameId);
- // }
- // };
- // }, [armBot, currentPhase, isPlaying]);
-
-
-
useEffect(() => {
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
if (targetMesh) {
@@ -409,7 +287,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
}
//Waiting for trigger.
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) {
-
logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction")
}
//Moving to pickup point
@@ -449,12 +326,13 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
pauseTimeRef.current = null
isPausedRef.current = false
startTime = 0
- clearInterval(activeTimerId.current!);
- clearInterval(idleTimerId.current!);
- activeTimerId.current = null;
activeSecondsElapsed.current = 0;
idleSecondsElapsed.current = 0;
- idleTimerId.current = null;
+ previousTimeRef.current = null;
+ if (animationFrameIdRef.current !== null) {
+ cancelAnimationFrame(animationFrameIdRef.current);
+ animationFrameIdRef.current = null;
+ }
removeCurrentAction(armBot.modelUuid)
}
@@ -492,38 +370,13 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
}
else if (armBot.isActive && armBot.state == "running" && currentPhase == "end-to-rest") {
logStatus(armBot.modelUuid, "Callback triggered: rest, cycle completed.");
- // Stop the timer
- // π¨ 1. Clear Active Timer
- // if (activeTimerId.current) {
- // clearInterval(activeTimerId.current);
- // activeTimerId.current = null;
- // }
- // console.log(`β
Active Cycle completed in ${activeSecondsElapsed.current} seconds`);
-
- // // π¨ 2. Reset active timer seconds after logging
- // activeSecondsElapsed.current = 0;
-
- // // π¨ 3. Start Idle Timer (clean old idle timer first)
- // if (idleTimerId.current) {
- // clearInterval(idleTimerId.current);
- // idleTimerId.current = null;
- // }
-
- // idleSecondsElapsed.current = 0;
- // idleTimerId.current = setInterval(() => {
- // if (!isPausedRef.current) {
- // idleSecondsElapsed.current += 1;
- // console.log(`π Idle Timer: ${idleSecondsElapsed.current} seconds`);
- // }
- // }, 1000);
-
-
setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "idle")
setCurrentPhase("rest");
setPath([])
}
}
+
const logStatus = (id: string, status: string) => {
// console.log('status: ', status);
}
diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx
index d6ff2fa..aa0b9f6 100644
--- a/app/src/modules/simulation/simulator/simulator.tsx
+++ b/app/src/modules/simulation/simulator/simulator.tsx
@@ -3,22 +3,27 @@ import { useProductStore } from '../../../store/simulation/useProductStore';
import { useActionHandler } from '../actions/useActionHandler';
import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore';
import { determineExecutionOrder } from './functions/determineExecutionOrder';
+import { useSelectedProduct } from '../../../store/simulation/useSimulationStore';
function Simulator() {
- const { products } = useProductStore();
+ const { products, getProductById } = useProductStore();
const { handleAction } = useActionHandler();
+ const { selectedProduct } = useSelectedProduct();
const { isPlaying } = usePlayButtonStore();
const { isReset } = useResetButtonStore();
useEffect(() => {
- if (!isPlaying || isReset) return;
+ if (!isPlaying || isReset || !selectedProduct.productId) return;
- const executionOrder = determineExecutionOrder(products);
+ const product = getProductById(selectedProduct.productId);
+ if (!product) return;
+
+ const executionOrder = determineExecutionOrder([product]);
executionOrder.forEach(point => {
const action = 'actions' in point ? point.actions[0] : point.action;
handleAction(action);
});
- }, [products, isPlaying, isReset]);
+ }, [products, isPlaying, isReset, selectedProduct]);
return (
diff --git a/app/src/store/store.ts b/app/src/store/store.ts
index 226e4e7..6192bdf 100644
--- a/app/src/store/store.ts
+++ b/app/src/store/store.ts
@@ -67,8 +67,8 @@ export const useWalls = create((set: any) => ({
}));
export const useRoomsState = create((set: any) => ({
- roomsState: [],
- setRoomsState: (x: any) => set(() => ({ walls: x })),
+ roomsState: [],
+ setRoomsState: (x: any) => set(() => ({ walls: x })),
}));
export const useZones = create((set: any) => ({
@@ -448,3 +448,31 @@ export const useMaterialCycle = create((set: any) => ({
materialCycleTime: 0,
setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }),
}));
+
+export const useThroughPutData = create((set: any) => ({
+ throughputData: 0,
+ setThroughputData: (x: any) => set({ throughputData: x }),
+}));
+export const useProductionCapacityData = create((set: any) => ({
+ productionCapacityData: 0,
+ setProductionCapacityData: (x: any) => set({ productionCapacityData: x }),
+}));
+
+
+type InputValuesStore = {
+ inputValues: Record;
+ setInputValues: (values: Record) => void;
+ updateInputValue: (label: string, value: string) => void; // <- New
+};
+
+export const useInputValues = create((set) => ({
+ inputValues: {},
+ setInputValues: (values) => set({ inputValues: values }),
+ updateInputValue: (label, value) =>
+ set((state) => ({
+ inputValues: {
+ ...state.inputValues,
+ [label]: value,
+ },
+ })),
+}));
\ No newline at end of file