From b3a4c03ba02df37def3e9f0c26144db76f7bdce6 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Fri, 5 Sep 2025 15:06:35 +0530 Subject: [PATCH] added comparsion data --- .../layout/scenes/ComparisonScene.tsx | 165 ++++++-- .../scenes/functions/simulationStorage.ts | 1 + .../ui/compareVersion/ComparisonResult.tsx | 400 +++++++++--------- .../analysis/throughPut/throughPutData.tsx | 1 + .../simulator/SimulationHandler.tsx | 167 ++++++-- .../store/rough/useSimulationManagerStore.ts | 199 +++++---- app/src/styles/layout/_compareLayout.scss | 2 +- 7 files changed, 584 insertions(+), 351 deletions(-) diff --git a/app/src/components/layout/scenes/ComparisonScene.tsx b/app/src/components/layout/scenes/ComparisonScene.tsx index b1029df..bb63015 100644 --- a/app/src/components/layout/scenes/ComparisonScene.tsx +++ b/app/src/components/layout/scenes/ComparisonScene.tsx @@ -1,15 +1,103 @@ -import { useProductContext } from '../../../modules/simulation/products/productContext' -import RegularDropDown from '../../ui/inputs/RegularDropDown'; -import { useCompareProductDataStore, useLoadingProgress, useSaveVersion } from '../../../store/builder/store'; -import useModuleStore from '../../../store/useModuleStore'; -import CompareLayOut from '../../ui/compareVersion/CompareLayOut'; -import ComparisonResult from '../../ui/compareVersion/ComparisonResult'; -import { useComparisonProduct, useMainProduct } from '../../../store/simulation/useSimulationStore'; -import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; -import { useEffect, useState } from 'react'; -import { useVersionHistoryStore } from '../../../store/builder/useVersionHistoryStore'; -import { useVersionContext } from '../../../modules/builder/version/versionContext'; -import { useSceneContext } from '../../../modules/scene/sceneContext'; +import { useProductContext } from "../../../modules/simulation/products/productContext"; +import RegularDropDown from "../../ui/inputs/RegularDropDown"; +import { useCompareProductDataStore, useLoadingProgress, useSaveVersion } from "../../../store/builder/store"; +import useModuleStore from "../../../store/useModuleStore"; +import CompareLayOut from "../../ui/compareVersion/CompareLayOut"; +import ComparisonResult from "../../ui/compareVersion/ComparisonResult"; +import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore"; +import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; +import { useEffect, useState } from "react"; +import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore"; +import { useVersionContext } from "../../../modules/builder/version/versionContext"; +import { useSceneContext } from "../../../modules/scene/sceneContext"; +import { useSimulationManager } from "../../../store/rough/useSimulationManagerStore"; +import { useParams } from "react-router-dom"; + +export interface CompareProduct { + productUuid: string; + productName: string; + simulationData: { + roiPercentage: number; + netProfit: number; + productionCapacity: number; + paybackPeriod: number; + machineIdleTime: number; + machineActiveTime: number; + throughputData: number; + simulationTime?: number; + simulationCost?: number; + efficiencyScore?: number; + }; +} + +type AssetData = { + activeTime: number; + idleTime: number; + type: string; + assetId: string; +}; + +const calculateSimulationData = (assets: AssetData[]) => { + let totalActiveTime = 0; + let totalIdleTime = 0; + let throughput = 0; + let productionCapacity = 0; + let simulationCost = 0; + + // Cost weight per type (example values, adjust as needed) + const costWeight: Record = { + roboticArm: 50, + machine: 100, + human: 30, + transfer: 20, + storageUnit: 10, + }; + + assets.forEach((asset) => { + totalActiveTime += asset.activeTime; + totalIdleTime += asset.idleTime; + + if (asset.activeTime > 0) throughput += 1; + + productionCapacity += asset.activeTime; + simulationCost += asset.activeTime * (costWeight[asset.type] || 10); + }); + + const machineActiveTime = assets.filter((a) => a.type === "machine").reduce((acc, a) => acc + a.activeTime, 0); + + const machineIdleTime = assets.filter((a) => a.type === "machine").reduce((acc, a) => acc + a.idleTime, 0); + + const simulationTime = totalActiveTime + totalIdleTime; + + // --- Efficiency Score --- + // Weighted formula: lower cost + lower time => higher score + // Example formula (normalize to 0–100): + const efficiencyScore = Math.max( + 0, + 100 - + (simulationTime / 1000) * 0.5 - // weight 0.5 for time + (simulationCost / 1000) * 0.5 // weight 0.5 for cost + ); + + return { + throughputData: throughput, + machineActiveTime, + machineIdleTime, + productionCapacity, + netProfit: 0, // placeholder + roiPercentage: 0, // placeholder + paybackPeriod: 0, // placeholder + simulationTime, + simulationCost, + efficiencyScore, + }; +}; + +export const createCompareProduct = (productUuid: string, productName: string, assets: AssetData[]): CompareProduct => ({ + productUuid, + productName, + simulationData: calculateSimulationData(assets), +}); function ComparisonScene() { const { isPlaying } = usePlayButtonStore(); @@ -27,6 +115,8 @@ function ComparisonScene() { const { versionHistory } = useVersionHistoryStore(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion, setSelectedVersion } = selectedVersionStore(); + const { simulationRecords } = useSimulationManager(); + const { projectId } = useParams(); const handleSelectVersion = (option: string) => { const version = versionHistory.find((version) => version.versionName === option); @@ -79,27 +169,53 @@ function ComparisonScene() { // ]) // }, []); + // useEffect(() => { + + // console.log('mainProduct: ', mainProduct); + // console.log('comparisonProduct: ', comparisonProduct); + // if (mainProduct && comparisonProduct) { + // // if (mainProduct && comparisonProduct && compareProductsData.length > 1) { + // // console.log('compareProductsData: ', compareProductsData); + // const hasMain = compareProductsData.some(val => val.productUuid === mainProduct.productUuid); + // const hasComparison = compareProductsData.some(val => val.productUuid === comparisonProduct.productUuid); + // console.log('hasMain: ', hasMain); + // console.log('hasComparison: ', hasComparison); + // if (hasMain && hasComparison) { + // setShouldShowComparisonResult(true); + // } else { + // setShouldShowComparisonResult(false); + // } + // } + // }, [compareProductsData, mainProduct, comparisonProduct]); useEffect(() => { - if (mainProduct && comparisonProduct && compareProductsData.length > 1) { - // console.log('compareProductsData: ', compareProductsData); - const hasMain = compareProductsData.some(val => val.productUuid === mainProduct.productUuid); - const hasComparison = compareProductsData.some(val => val.productUuid === comparisonProduct.productUuid); - if (hasMain && hasComparison && mainProduct.productUuid !== comparisonProduct.productUuid) { - setShouldShowComparisonResult(true); - } else { + if (mainProduct && comparisonProduct && selectedVersion) { + const product1 = useSimulationManager.getState().getProductById(projectId, selectedVersion?.versionId, mainProduct.productUuid); + + const product2 = useSimulationManager.getState().getProductById(projectId, selectedVersion?.versionId, comparisonProduct.productUuid); + + const compareProduct1 = createCompareProduct(product1?.productId ?? "", mainProduct.productName, product1?.data || []); + const compareProduct2 = createCompareProduct(product2?.productId ?? "", comparisonProduct.productName, product2?.data || []); + + const comparedArray = [compareProduct1, compareProduct2]; + + if (product1 == undefined || product2 === undefined) { setShouldShowComparisonResult(false); + } else if (comparedArray.length === 2) { + console.log("comparedArray: ", comparedArray); + setCompareProductsData(comparedArray); + setShouldShowComparisonResult(true); } } else { setShouldShowComparisonResult(false); } - }, [compareProductsData, mainProduct, comparisonProduct]); + }, [mainProduct, comparisonProduct, simulationRecords]); return ( <> {isVersionSaved && activeModule === "simulation" && selectedProduct && ( <> - {selectedVersion && !isPlaying && + {selectedVersion && !isPlaying && (
- } + )} - - {(shouldShowComparisonResult && !loadingProgress) && } + {shouldShowComparisonResult && !loadingProgress && compareProductsData && } )} - ) + ); } export default ComparisonScene; diff --git a/app/src/components/layout/scenes/functions/simulationStorage.ts b/app/src/components/layout/scenes/functions/simulationStorage.ts index 7eafe7c..2e4b428 100644 --- a/app/src/components/layout/scenes/functions/simulationStorage.ts +++ b/app/src/components/layout/scenes/functions/simulationStorage.ts @@ -9,5 +9,6 @@ export const saveSimulationData = ({ key, data }: SimulationData) => { export const getSimulationData = ({ key }: SimulationData) => { const data = localStorage.getItem(key); console.log("data: ", JSON.parse(data || "{}")); + return data; }; export const clearSimulationData = ({ key, data }: SimulationData) => {}; diff --git a/app/src/components/ui/compareVersion/ComparisonResult.tsx b/app/src/components/ui/compareVersion/ComparisonResult.tsx index f5c00f0..6e2b751 100644 --- a/app/src/components/ui/compareVersion/ComparisonResult.tsx +++ b/app/src/components/ui/compareVersion/ComparisonResult.tsx @@ -2,205 +2,211 @@ import React, { useEffect, useMemo, useState } from "react"; import PerformanceResult from "./result-card/PerformanceResult"; import EnergyUsage from "./result-card/EnergyUsage"; import { Bar, Line, Pie } from "react-chartjs-2"; -import { CompareProduct, useCompareProductDataStore } from "../../../store/builder/store"; +import { useCompareProductDataStore } from "../../../store/builder/store"; +// import { CompareProduct, useCompareProductDataStore } from "../../../store/builder/store"; import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore"; - +export interface CompareProduct { + productUuid: string; + productName: string; + simulationData: { + roiPercentage: number; + netProfit: number; + productionCapacity: number; + paybackPeriod: number; + machineIdleTime: number; + machineActiveTime: number; + throughputData: number; + simulationTime?: number; + simulationCost?: number; + efficiencyScore?: number; + }; +} const ComparisonResult = () => { - const { compareProductsData, setCompareProductsData } = useCompareProductDataStore(); - const { comparisonProduct, setComparisonProduct } = useComparisonProduct(); - const { mainProduct } = useMainProduct(); - const [comparedProducts, setComparedProducts] = useState<[CompareProduct, CompareProduct] | []>([]); + const { compareProductsData, setCompareProductsData } = useCompareProductDataStore(); + const { comparisonProduct, setComparisonProduct } = useComparisonProduct(); + const { mainProduct } = useMainProduct(); + const [comparedProducts, setComparedProducts] = useState<[CompareProduct, CompareProduct] | []>([]); - useEffect(() => { - if (compareProductsData.length > 0 && mainProduct && comparisonProduct) { - const mainProductData = compareProductsData.find( - (product) => product.productUuid === mainProduct.productUuid - ); - const comparisonProductData = compareProductsData.find( - (product) => product.productUuid === comparisonProduct.productUuid - ); + useEffect(() => { + if (compareProductsData.length > 0 && mainProduct && comparisonProduct) { + const mainProductData = compareProductsData.find((product) => product.productUuid === mainProduct.productUuid); + const comparisonProductData = compareProductsData.find((product) => product.productUuid === comparisonProduct.productUuid); - if (mainProductData && comparisonProductData) { - setComparedProducts([mainProductData, comparisonProductData]); - } else { - setComparedProducts([]); - } - } else { - setComparedProducts([]); - } - }, [compareProductsData, mainProduct, comparisonProduct]); + if (mainProductData && comparisonProductData) { + setComparedProducts([mainProductData, comparisonProductData]); + } else { + setComparedProducts([]); + } + } else { + setComparedProducts([]); + } + }, [compareProductsData, mainProduct, comparisonProduct]); - useEffect(() => { - if (comparedProducts.length === 2) { - - } - }, [comparedProducts]); + useEffect(() => { + if (comparedProducts.length === 2) { + } + }, [comparedProducts]); - const options = useMemo( - () => ({ - responsive: true, - maintainAspectRatio: false, - plugins: { - title: { display: false }, - legend: { display: false }, - }, - scales: { - x: { display: false, grid: { display: false } }, - y: { display: false, grid: { display: false } }, - }, - }), - [] - ); + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { display: false }, + legend: { display: false }, + }, + scales: { + x: { display: false, grid: { display: false } }, + y: { display: false, grid: { display: false } }, + }, + }), + [] + ); - // Color palette - const purpleDark = "#6a0dad"; - const purpleLight = "#b19cd9"; + // Color palette + const purpleDark = "#6a0dad"; + const purpleLight = "#b19cd9"; - const throughputData = { - labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName], - datasets: [ - { - label: "Throughput (units/hr)", - data: [comparedProducts[0]?.simulationData.throughputData, comparedProducts[1]?.simulationData.throughputData], - backgroundColor: [purpleDark, purpleLight], - borderColor: [purpleDark, purpleLight], - borderWidth: 1, - borderRadius: 10, // ✅ Rounded all corners (TypeScript-safe) - // borderSkipped: "bottom", // ✅ This is allowed by the Chart.js types - }, - ], - }; + const throughputData = { + labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName], + datasets: [ + { + label: "Throughput (units/hr)", + data: [comparedProducts[0]?.simulationData.throughputData, comparedProducts[1]?.simulationData.throughputData], + backgroundColor: [purpleDark, purpleLight], + borderColor: [purpleDark, purpleLight], + borderWidth: 1, + borderRadius: 10, // ✅ Rounded all corners (TypeScript-safe) + // borderSkipped: "bottom", // ✅ This is allowed by the Chart.js types + }, + ], + }; + const cycleTimePieData = { + labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName], + datasets: [ + { + label: "Cycle Time (sec)", + data: [comparedProducts[0]?.simulationData.machineActiveTime, comparedProducts[1]?.simulationData.machineActiveTime], + backgroundColor: [purpleDark, purpleLight], + borderColor: "#fff", + borderWidth: 2, + }, + ], + }; - const cycleTimePieData = { - labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName], - datasets: [ - { - label: "Cycle Time (sec)", - data: [comparedProducts[0]?.simulationData.machineActiveTime, comparedProducts[1]?.simulationData.machineActiveTime], - backgroundColor: [purpleDark, purpleLight], - borderColor: "#fff", - borderWidth: 2, - }, - ], - }; + const downtimeData = { + labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName], + datasets: [ + { + label: "Downtime (mins)", + data: [comparedProducts[0]?.simulationData.machineIdleTime, comparedProducts[1]?.simulationData.machineIdleTime], + backgroundColor: [purpleDark, purpleLight], + borderColor: "#fff", + borderWidth: 2, + }, + ], + }; - const downtimeData = { - labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName], - datasets: [ - { - label: "Downtime (mins)", - data: [comparedProducts[0]?.simulationData.machineIdleTime, comparedProducts[1]?.simulationData.machineIdleTime], - backgroundColor: [purpleDark, purpleLight], - borderColor: "#fff", - borderWidth: 2, - }, - ], - }; + const productionCapacityData = { + labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName], + datasets: [ + { + label: "Production Capacity (units)", + data: [comparedProducts[0]?.simulationData.productionCapacity, comparedProducts[1]?.simulationData.productionCapacity], + backgroundColor: [purpleDark, purpleLight], + borderColor: [purpleDark, purpleLight], + borderWidth: 1, + borderRadius: 10, + borderSkipped: false, + }, + ], + }; - const productionCapacityData = { - labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName], - datasets: [ - { - label: "Production Capacity (units)", - data: [comparedProducts[0]?.simulationData.productionCapacity, comparedProducts[1]?.simulationData.productionCapacity], - backgroundColor: [purpleDark, purpleLight], - borderColor: [purpleDark, purpleLight], - borderWidth: 1, - borderRadius: 10, - borderSkipped: false, - }, - ], - }; + const highestProductivityProduct = (comparedProducts[0]?.simulationData?.productionCapacity ?? 0) > (comparedProducts[1]?.simulationData?.productionCapacity ?? 0) ? comparedProducts[0] : comparedProducts[1]; - const highestProductivityProduct = (comparedProducts[0]?.simulationData?.productionCapacity ?? 0) > (comparedProducts[1]?.simulationData?.productionCapacity ?? 0) ? comparedProducts[0] : comparedProducts[1]; + const product1CyclePercentage = ((comparedProducts[0]?.simulationData?.machineActiveTime ?? 0) / ((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[0]?.simulationData?.machineIdleTime ?? 0))) * 100; + const product2CyclePercentage = ((comparedProducts[1]?.simulationData?.machineActiveTime ?? 0) / ((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100; - const product1CyclePercentage = (comparedProducts[0]?.simulationData?.machineActiveTime ?? 0) / - ((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) + - (compareProductsData[0]?.simulationData?.machineIdleTime ?? 0)) * 100; - const product2CyclePercentage = ((comparedProducts[1]?.simulationData?.machineActiveTime ?? 0) / - ((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) + - (compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100; + const product1IdlePercentage = ((comparedProducts[0]?.simulationData?.machineIdleTime ?? 0) / ((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[0]?.simulationData?.machineIdleTime ?? 0))) * 100; + const product2IdlePercentage = ((comparedProducts[1]?.simulationData?.machineIdleTime ?? 0) / ((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100; - const product1IdlePercentage = (comparedProducts[0]?.simulationData?.machineIdleTime ?? 0) / - ((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) + - (compareProductsData[0]?.simulationData?.machineIdleTime ?? 0)) * 100; - const product2IdlePercentage = ((comparedProducts[1]?.simulationData?.machineIdleTime ?? 0) / - ((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) + - (compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100; - - return ( -
-
Performance Comparison
-
- -
-

Throughput (units/hr)

-
-
-
{comparedProducts[0]?.productName}
-
{comparedProducts[0]?.simulationData.throughputData}/ hr
-
-
-
{comparedProducts[1]?.productName}
-
{comparedProducts[1]?.simulationData.throughputData}/ hr
-
-
- -
-
-
- -
-
-

Cycle Time

-
-
-
{comparedProducts[0]?.productName}
-
{compareProductsData[0]?.simulationData.machineActiveTime} Sec
-
- {(100 - product1CyclePercentage).toFixed(2)}% + return ( +
+
Performance Comparison
+
+ +
+

Throughput (units/hr)

+
+
+
{comparedProducts[0]?.productName}
+
{comparedProducts[0]?.simulationData.throughputData}/ hr
+
+
+
{comparedProducts[1]?.productName}
+
{comparedProducts[1]?.simulationData.throughputData}/ hr
+
+
+ +
+
-
-
-
{comparedProducts[1]?.productName}
-
{compareProductsData[1]?.simulationData.machineActiveTime} Sec
-
- {(100 - product2CyclePercentage).toFixed(2)}% -
-
-
-
-
- -
-
-
-
-
Overall Downtime
-
-
-
{comparedProducts[0]?.productName}
-
{compareProductsData[0]?.simulationData.machineIdleTime} Sec
-
- {(100 - product1IdlePercentage).toFixed(2)}% +
+
+

Cycle Time

+
+
+
{comparedProducts[0]?.productName}
+
{compareProductsData[0]?.simulationData.machineActiveTime} Sec
+
+ + {(100 - product1CyclePercentage).toFixed(2)}% +
+
+
+
{comparedProducts[1]?.productName}
+
{compareProductsData[1]?.simulationData.machineActiveTime} Sec
+
+ + {(100 - product2CyclePercentage).toFixed(2)}% +
+
+
+
+
+ +
-
-
-
{comparedProducts[1]?.productName}
-
{compareProductsData[1]?.simulationData.machineIdleTime} Sec
-
- {(100 - product2IdlePercentage).toFixed(2)}% + +
+
+
Overall Downtime
+
+
+
{comparedProducts[0]?.productName}
+
{compareProductsData[0]?.simulationData.machineIdleTime} Sec
+
+ + {(100 - product1IdlePercentage).toFixed(2)}% +
+
+
+
{comparedProducts[1]?.productName}
+
{compareProductsData[1]?.simulationData.machineIdleTime} Sec
+
+ + {(100 - product2IdlePercentage).toFixed(2)}% +
+
+
+
+
+ +
-
-
-
-
- -
-
-{/* + {/*

Overall Downtime

@@ -220,24 +226,24 @@ const ComparisonResult = () => {
*/} -
-

Production Capacity

-
-
-
{highestProductivityProduct?.productName}
-
Total product produced
-
{highestProductivityProduct?.simulationData.productionCapacity}
-
-
- -
-
-
+
+

Production Capacity

+
+
+
{highestProductivityProduct?.productName}
+
Total product produced
+
{highestProductivityProduct?.simulationData.productionCapacity}
+
+
+ +
+
+
- { comparedProducts.length === 2 &&} -
-
- ); + {comparedProducts.length === 2 && } +
+
+ ); }; export default ComparisonResult; diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index 38f8aae..9d37162 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -222,6 +222,7 @@ export default function ThroughPutData() { const Throughput_per_day = Units_per_shift * shiftsPerDay * (yieldRate / 100); const data = Number(Throughput_per_day.toFixed(2)) + console.log('data: ', data); saveSimulationData({ key: selectedProduct.productUuid, data: data }); setMaterialData({ ...materialData, throughput: data }); diff --git a/app/src/modules/simulation/simulator/SimulationHandler.tsx b/app/src/modules/simulation/simulator/SimulationHandler.tsx index 5da5bc0..f8c8615 100644 --- a/app/src/modules/simulation/simulator/SimulationHandler.tsx +++ b/app/src/modules/simulation/simulator/SimulationHandler.tsx @@ -1,11 +1,13 @@ -import React, { useEffect } from 'react'; -import { useSceneContext } from '../../scene/sceneContext'; -import { useProductContext } from '../products/productContext'; -import { determineExecutionMachineSequences } from './functions/determineExecutionMachineSequences'; -import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; -import { useSimulationManager } from '../../../store/rough/useSimulationManagerStore'; -import { useParams } from 'react-router-dom'; -import { useVersionContext } from '../../builder/version/versionContext'; +import React, { useEffect } from "react"; +import { useSceneContext } from "../../scene/sceneContext"; +import { useProductContext } from "../products/productContext"; +import { determineExecutionMachineSequences } from "./functions/determineExecutionMachineSequences"; +import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; +import { useSimulationManager } from "../../../store/rough/useSimulationManagerStore"; +import { useParams } from "react-router-dom"; +import { useVersionContext } from "../../builder/version/versionContext"; +import { getSimulationData, saveSimulationData } from "../../../components/layout/scenes/functions/simulationStorage"; +import { get } from "http"; interface SimulationUsageRecord { activeTime: number; isActive: boolean; @@ -38,7 +40,17 @@ interface ProjectSimulation { versions: VersionSimulation[]; } const SimulationHandler = () => { - const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, productStore, craneStore, humanStore } = useSceneContext(); + const { + materialStore, + armBotStore, + machineStore, + conveyorStore, + vehicleStore, + storageUnitStore, + productStore, + craneStore, + humanStore, + } = useSceneContext(); const { armBots, getArmBotById } = armBotStore(); const { vehicles, getVehicleById } = vehicleStore(); const { getConveyorById } = conveyorStore(); @@ -48,16 +60,106 @@ const SimulationHandler = () => { const { selectedProduct } = selectedProductStore(); const { machines, getMachineById } = machineStore(); const { getHumanById } = humanStore(); - const { getCraneById, } = craneStore(); + const { getCraneById } = craneStore(); const { getStorageUnitById } = storageUnitStore(); const { isPlaying, setIsPlaying } = usePlayButtonStore(); - const { simulationData, addData } = useSimulationManager(); + const { simulationRecords, addSimulationRecord } = useSimulationManager(); const { projectId } = useParams(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); + const COST_RATES: Record = { + roboticArm: 5, + vehicle: 2, + transfer: 1, + storageUnit: 1, + crane: 6, + human: 4, + machine: 3, + }; + // Calculate totals for one product + function calculateProductMetrics(product: ProductSimulation) { + let totalActiveTime = 0; + let totalIdleTime = 0; + let totalCost = 0; + product.data.forEach((record) => { + const resourceTime = record.activeTime + record.idleTime; + const costRate = COST_RATES[record.type] || 0; + totalActiveTime += record.activeTime; + totalIdleTime += record.idleTime; + totalCost += resourceTime * costRate; + }); + + return { + totalTime: totalActiveTime + totalIdleTime, + totalActiveTime, + totalIdleTime, + totalCost, + }; + } + + // Calculate totals for a version + function calculateVersionMetrics(version: VersionSimulation) { + return version.products.reduce( + (acc, product) => { + const metrics = calculateProductMetrics(product); + + acc.totalTime += metrics.totalTime; + acc.totalActiveTime += metrics.totalActiveTime; + acc.totalIdleTime += metrics.totalIdleTime; + acc.totalCost += metrics.totalCost; + return acc; + }, + { totalTime: 0, totalActiveTime: 0, totalIdleTime: 0, totalCost: 0 } + ); + } + + // Efficiency score (compare across versions) + function calculateEfficiencyScores(versions: VersionSimulation[]) { + const versionMetrics = versions.map((v) => ({ + versionId: v.versionId, + ...calculateVersionMetrics(v), + })); + + const minTime = Math.min(...versionMetrics.map((m) => m.totalTime)); + const minCost = Math.min(...versionMetrics.map((m) => m.totalCost)); + + return versionMetrics.map((m) => { + const timeFactor = minTime / m.totalTime; + const costFactor = minCost / m.totalCost; + + const efficiencyScore = 0.5 * timeFactor + 0.5 * costFactor; + + return { ...m, efficiencyScore }; + }); + } + + useEffect(() => { + console.log('simulationRecords: ', simulationRecords); + if (!projectId || !selectedVersion || !selectedProduct.productUuid || simulationRecords.length === 0) return; + + const project = simulationRecords[0]; + + if (project) { + const scores = calculateEfficiencyScores(project.versions); + console.log("Version Comparisons:", scores); + } + + saveSimulationData({ + key: selectedProduct.productUuid, + data: simulationRecords, + }); + }, [simulationRecords]); + + useEffect(() => { + const simData = getSimulationData({ key: selectedProduct.productUuid }); + if (simData) { + useSimulationManager.getState().setSimulationRecords(JSON.parse(simData)); + // Parse and set in the store + } else { } + }, []) useEffect(() => { let checkTimer: ReturnType; @@ -67,41 +169,43 @@ const SimulationHandler = () => { let hasActiveEntity = false; if (currentProduct) { - const executionSequences = await determineExecutionMachineSequences([currentProduct]); + const executionSequences = await determineExecutionMachineSequences([ + currentProduct, + ]); if (executionSequences?.length > 0) { - executionSequences.forEach(sequence => { - sequence.forEach(entity => { - if (entity.type === 'roboticArm') { + executionSequences.forEach((sequence) => { + sequence.forEach((entity) => { + if (entity.type === "roboticArm") { const roboticArm = getArmBotById(entity.modelUuid); if (roboticArm?.isActive) { hasActiveEntity = true; } } - if (entity.type === 'vehicle') { + if (entity.type === "vehicle") { const vehicle = getVehicleById(entity.modelUuid); if (vehicle?.isActive) { hasActiveEntity = true; } } - if (entity.type === 'machine') { + if (entity.type === "machine") { const machine = getMachineById(entity.modelUuid); if (machine?.isActive) { hasActiveEntity = true; } } - if (entity.type === 'human') { + if (entity.type === "human") { const human = getHumanById(entity.modelUuid); if (human?.isActive) { hasActiveEntity = true; } } - if (entity.type === 'crane') { + if (entity.type === "crane") { const crane = getCraneById(entity.modelUuid); if (crane?.isActive) { hasActiveEntity = true; } } - if (entity.type === 'storageUnit') { + if (entity.type === "storageUnit") { const storageUnit = getStorageUnitById(entity.modelUuid); if (storageUnit?.isActive) { hasActiveEntity = true; @@ -117,8 +221,11 @@ const SimulationHandler = () => { }); } - if (materials.length === 0 && materialHistory.length >= 0 && !hasActiveEntity) { - + if ( + materials.length === 0 && + materialHistory.length >= 0 && + !hasActiveEntity + ) { if (executionSequences?.length > 0) { executionSequences.forEach((sequence) => { sequence.forEach((entity) => { @@ -138,7 +245,7 @@ const SimulationHandler = () => { const obj = getter(entity.modelUuid); if (!obj) return; // skip if not found - addData( + addSimulationRecord( projectId, selectedVersion?.versionId || "", selectedProduct?.productUuid, @@ -154,6 +261,7 @@ const SimulationHandler = () => { | "crane" | "storageUnit" | "transfer", + assetId: entity.modelUuid, } ); }); @@ -173,9 +281,18 @@ const SimulationHandler = () => { return () => { if (checkTimer) clearTimeout(checkTimer); }; - }, [materials, materialHistory, selectedVersion, selectedProduct?.productUuid, isPlaying, armBots, vehicles, machines]); + }, [ + materials, + materialHistory, + selectedVersion, + selectedProduct?.productUuid, + isPlaying, + armBots, + vehicles, + machines, + ]); return null; -} +}; export default SimulationHandler; diff --git a/app/src/store/rough/useSimulationManagerStore.ts b/app/src/store/rough/useSimulationManagerStore.ts index c86a38a..a8c82a4 100644 --- a/app/src/store/rough/useSimulationManagerStore.ts +++ b/app/src/store/rough/useSimulationManagerStore.ts @@ -1,136 +1,129 @@ - import { create } from "zustand"; - interface SimulationUsageRecord { - activeTime: number; - isActive: boolean; - idleTime: number; - type: - | "roboticArm" - | "vehicle" - | "transfer" - | "storageUnit" - | "crane" - | "human" - | "machine"; + activeTime: number; + isActive: boolean; + idleTime: number; + type: "roboticArm" | "vehicle" | "transfer" | "storageUnit" | "crane" | "human" | "machine"; + assetId: string; } // Product → holds multiple usage records interface ProductSimulation { - productId: string; - data: SimulationUsageRecord[]; + productId: string; + data: SimulationUsageRecord[]; } // Version → holds multiple products interface VersionSimulation { - versionId: string; - products: ProductSimulation[]; + versionId: string; + products: ProductSimulation[]; } // Project → holds multiple versions interface ProjectSimulation { - projectId: string | undefined; - versions: VersionSimulation[]; + projectId: string | undefined; + versions: VersionSimulation[]; } // or same file interface SimulationManagerStore { - simulationData: ProjectSimulation[]; + simulationRecords: ProjectSimulation[]; + setSimulationRecords: (data: ProjectSimulation[]) => void; + addSimulationRecord: (projectId: string | undefined, versionId: string, productId: string, record: SimulationUsageRecord) => void; - addData: ( - projectId: string | undefined, - versionId: string, - productId: string, - record: SimulationUsageRecord - ) => void; - - resetProductData: ( - projectId: string, - versionId: string, - productId: string - ) => void; + resetProductRecords: (projectId: string, versionId: string, productId: string) => void; + getProjectById: (projectId: string | undefined) => ProjectSimulation | undefined; + getVersionById: (projectId: string | undefined, versionId: string) => VersionSimulation | undefined; + getProductById: (projectId: string | undefined, versionId: string, productId: string) => ProductSimulation | undefined; } -export const useSimulationManager = create((set) => ({ - simulationData: [], +export const useSimulationManager = create((set, get) => ({ + simulationRecords: [], - addData: (projectId, versionId, productId, record) => - set((state) => { - const projects = state.simulationData.map((project) => { - if (project.projectId !== projectId) return project; + addSimulationRecord: (projectId, versionId, productId, record) => + set((state) => { + const projects = state.simulationRecords.map((project) => { + if (project.projectId !== projectId) return project; - return { - ...project, - versions: project.versions.map((version) => { - if (version.versionId !== versionId) return version; + return { + ...project, + versions: project.versions.map((version) => { + if (version.versionId !== versionId) return version; - return { - ...version, - products: version.products.map((product) => - product.productId === productId - ? { ...product, data: [...product.data, record] } - : product - ), - }; - }), - }; - }); + return { + ...version, + products: version.products.map((product) => (product.productId === productId ? { ...product, data: [...product.data, record] } : product)), + }; + }), + }; + }); - // If project doesn't exist, create it - if (!state.simulationData.find((p) => p.projectId === projectId)) { - projects.push({ - projectId, - versions: [ - { - versionId, - products: [{ productId, data: [record] }], - }, - ], - }); - } else { - const project = projects.find((p) => p.projectId === projectId)!; - if (!project.versions.find((v) => v.versionId === versionId)) { - project.versions.push({ - versionId, - products: [{ productId, data: [record] }], - }); - } else { - const version = project.versions.find( - (v) => v.versionId === versionId - )!; - if (!version.products.find((p) => p.productId === productId)) { - version.products.push({ productId, data: [record] }); - } - } - } + // If project doesn't exist, create it + if (!state.simulationRecords.find((p) => p.projectId === projectId)) { + projects.push({ + projectId, + versions: [ + { + versionId, + products: [{ productId, data: [record] }], + }, + ], + }); + } else { + const project = projects.find((p) => p.projectId === projectId)!; + if (!project.versions.find((v) => v.versionId === versionId)) { + project.versions.push({ + versionId, + products: [{ productId, data: [record] }], + }); + } else { + const version = project.versions.find((v) => v.versionId === versionId)!; + if (!version.products.find((p) => p.productId === productId)) { + version.products.push({ productId, data: [record] }); + } + } + } - return { simulationData: projects }; - }), + return { simulationRecords: projects }; + }), - resetProductData: (projectId, versionId, productId) => - set((state) => { - const projects = state.simulationData.map((project) => { - if (project.projectId !== projectId) return project; + resetProductRecords: (projectId, versionId, productId) => + set((state) => { + const projects = state.simulationRecords.map((project) => { + if (project.projectId !== projectId) return project; - return { - ...project, - versions: project.versions.map((version) => { - if (version.versionId !== versionId) return version; + return { + ...project, + versions: project.versions.map((version) => { + if (version.versionId !== versionId) return version; - return { - ...version, - products: version.products.map((product) => - product.productId === productId - ? { ...product, data: [] } - : product - ), - }; - }), - }; - }); + return { + ...version, + products: version.products.map((product) => (product.productId === productId ? { ...product, data: [] } : product)), + }; + }), + }; + }); - return { simulationData: projects }; - }), + return { simulationRecords: projects }; + }), + setSimulationRecords: (data) => { + set({ simulationRecords: data }); + }, + getProjectById: (projectId: string | undefined) => { + return get().simulationRecords.find((p: ProjectSimulation) => p.projectId === projectId); + }, + + getVersionById: (projectId: string | undefined, versionId: string) => { + const project = get().simulationRecords.find((p: ProjectSimulation) => p.projectId === projectId); + return project?.versions.find((v: VersionSimulation) => v.versionId === versionId); + }, + + getProductById: (projectId: string | undefined, versionId: string, productId: string) => { + const project = get().simulationRecords.find((p: ProjectSimulation) => p.projectId === projectId); + const version = project?.versions.find((v: VersionSimulation) => v.versionId === versionId); + return version?.products.find((p: ProductSimulation) => p.productId === productId); + }, })); /////////////////////////// diff --git a/app/src/styles/layout/_compareLayout.scss b/app/src/styles/layout/_compareLayout.scss index 13221bc..010cd05 100644 --- a/app/src/styles/layout/_compareLayout.scss +++ b/app/src/styles/layout/_compareLayout.scss @@ -305,7 +305,7 @@ background-color: #b7b7c6; // Custom polygon shape (adjust if needed) - clipPath: polygon(96% 52%, + clip-path: polygon(96% 52%, 96% 54%, 45% 53%, 3% 100%,