update assetID

This commit is contained in:
2025-06-12 09:31:51 +05:30
parent 9b0842ed14
commit c7cc5cf2ca
59 changed files with 1039 additions and 1029 deletions

View File

@@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react'
import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store';
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
import { useProductContext } from '../../products/productContext';
import { useProductStore } from '../../../../store/simulation/useProductStore';
export default function ROIData() {
const { selectedProductStore } = useProductContext();
@@ -10,6 +11,9 @@ export default function ROIData() {
const { selectedProduct } = selectedProductStore();
const { isPlaying } = usePlayButtonStore();
const { setRoiSummaryData } = useROISummaryData();
const { products, getProductById } = useProductStore();
const [compareProducts, setCompareProducts] = useState<any[]>([]);
useEffect(() => {
if (!isPlaying) {
setRoiSummaryData({
@@ -43,47 +47,36 @@ export default function ROIData() {
!isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) {
const totalHoursPerYear = shiftLength * shiftsPerDay * workingDaysPerYear;
// Total good units produced per year
const annualProductionUnits = productionCapacityData * totalHoursPerYear;
// Revenue for a year
const annualRevenue = annualProductionUnits * sellingPrice;
// Costs
const totalMaterialCost = annualProductionUnits * materialCost;
const totalLaborCost = laborCost * totalHoursPerYear;
const totalEnergyCost = electricityCost * totalHoursPerYear;
const totalMaintenanceCost = maintenanceCost + fixedCost;
const totalAnnualCost = totalMaterialCost + totalLaborCost + totalEnergyCost + totalMaintenanceCost;
// Annual Profit
const annualProfit = annualRevenue - totalAnnualCost;
console.log('annualProfit: ', annualProfit);
// Net Profit over production period
const netProfit = annualProfit * productionPeriod;
// ROI
const roiPercentage = ((netProfit + salvageValue - initialInvestment) / initialInvestment) * 100;
// Payback Period
const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0
console.log('paybackPeriod: ', paybackPeriod);
// console.log("--- ROI Breakdown ---");
// console.log("Annual Production Units:", annualProductionUnits.toFixed(2));
// console.log("Annual Revenue:", annualRevenue.toFixed(2));
// console.log("Total Annual Cost:", totalAnnualCost.toFixed(2));
// console.log("Annual Profit:", annualProfit.toFixed(2));
// console.log("Net Profit:", netProfit.toFixed(2));
// console.log("ROI %:", roiPercentage.toFixed(2));
// console.log("Payback Period (years):", paybackPeriod.toFixed(2));
//
//
//
//
//
//
//
//
setRoiSummaryData({
productName: selectedProduct.productName,
@@ -107,13 +100,48 @@ export default function ROIData() {
const netProfitForTarget = profitForTargetUnits > 0 ? profitForTargetUnits : 0;
const netLossForTarget = profitForTargetUnits < 0 ? -profitForTargetUnits : 0;
// console.log("--- Fixed Product Count (" + productCount + ") ---");
// console.log("Cost per Unit:", costPerUnit.toFixed(2));
// console.log("Total Cost for " + productCount + " Units:", costForTargetUnits.toFixed(2));
// console.log("Revenue for " + productCount + " Units:", revenueForTargetUnits.toFixed(2));
// console.log("Profit:", netProfitForTarget.toFixed(2));
// console.log("Loss:", netLossForTarget.toFixed(2));
//
//
//
//
//
//
const productData = getProductById(selectedProduct.productUuid);
setCompareProducts(prev => {
const newData = {
productUuid: productData?.productUuid,
productName: productData?.productName,
costPerUnit: parseFloat(costPerUnit.toFixed(2)),
workingDaysPerYear: parseFloat(workingDaysPerYear.toFixed(2)),
shiftLength: parseFloat(shiftLength.toFixed(2)),
shiftsPerDay: parseFloat(shiftsPerDay.toFixed(2)),
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)),
paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
totalCost: parseFloat(totalAnnualCost.toFixed(2)),
revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0,
netLoss: netProfit < 0 ? parseFloat((-netProfit).toFixed(2)) : 0
};
const existingIndex = prev.findIndex(
item => item.productUuid === productData?.productUuid
);
if (existingIndex !== -1) {
// Replace the existing item
const updated = [...prev];
updated[existingIndex] = newData;
return updated;
} else {
// Add as new item
return [...prev, newData];
}
});
// console.log('compareProducts: ', compareProducts);
}
}, [inputValues, productionCapacityData]);

View File

@@ -36,7 +36,7 @@ export default function ThroughPutData() {
setMaterialCycleTime(0);
setProcessBar([]);
setThroughputData(0);
return;
return;
} else {
let process: any = [];
const fetchProductSequenceData = async () => {
@@ -190,9 +190,6 @@ export default function ThroughPutData() {
useEffect(() => {
if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) {
const utilization = machineActiveTime / 3600; // Active time per hour
const unitsPerMachinePerHour = 3600 / materialCycleTime;
const throughput = unitsPerMachinePerHour * machineCount * utilization;

View File

@@ -1,7 +1,7 @@
import * as THREE from "three";
import { useMemo, useRef, useState } from "react";
import { useThree } from "@react-three/fiber";
import { useDeleteTool } from "../../../../store/builder/store";
import { useToolMode } from "../../../../store/builder/store";
interface ConnectionLine {
id: string;
@@ -14,7 +14,7 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
const [hoveredLineKey, setHoveredLineKey] = useState<string | null>(null);
const groupRef = useRef<THREE.Group>(null);
const { scene } = useThree();
const { deleteTool } = useDeleteTool();
const { toolMode } = useToolMode();
const getWorldPositionFromScene = (uuid: string): THREE.Vector3 | null => {
const obj = scene.getObjectByProperty("uuid", uuid);
@@ -61,7 +61,7 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
onPointerOut={() => setHoveredLineKey(null)}
>
<meshStandardMaterial
color={deleteTool && hoveredLineKey === key ? "red" : "#42a5f5"}
color={toolMode === '2D-Delete' && hoveredLineKey === key ? "red" : "#42a5f5"}
/>
</mesh>
<mesh
@@ -72,7 +72,7 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
onPointerOut={() => setHoveredLineKey(null)}
>
<meshStandardMaterial
color={deleteTool && hoveredLineKey === key ? "red" : "#42a5f5"}
color={toolMode === '2D-Delete' && hoveredLineKey === key ? "red" : "#42a5f5"}
/>
</mesh>
</group>

View File

@@ -11,6 +11,7 @@ import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore";
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../products/productContext";
import { useParams } from "react-router-dom";
import { useToolMode } from "../../../../../store/builder/store";
function PointsCreator() {
const { gl, raycaster, scene, pointer, camera } = useThree();
@@ -26,7 +27,7 @@ function PointsCreator() {
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
const { isPlaying } = usePlayButtonStore();
const { toolMode } = useToolMode();
const { projectId } = useParams();
const updateBackend = (
@@ -204,9 +205,11 @@ function PointsCreator() {
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
if (toolMode === 'cursor') {
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
}
}}
key={`${index}-${point.uuid}`}
position={new THREE.Vector3(...point.position)}
@@ -235,9 +238,11 @@ function PointsCreator() {
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
if (toolMode === 'cursor') {
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
}
}}
position={new THREE.Vector3(...point.position)}
userData={{
@@ -264,9 +269,11 @@ function PointsCreator() {
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
if (toolMode === 'cursor') {
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
}
}}
position={new THREE.Vector3(...point.position)}
userData={{
@@ -293,9 +300,11 @@ function PointsCreator() {
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
if (toolMode === 'cursor') {
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
}
}}
position={new THREE.Vector3(...point.position)}
userData={{
@@ -322,9 +331,11 @@ function PointsCreator() {
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
if (toolMode === 'cursor') {
setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
}
}}
position={new THREE.Vector3(...point.position)}
userData={{

View File

@@ -8,11 +8,11 @@ import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { handleAddEventToProduct } from "../points/functions/handleAddEventToProduct";
import { QuadraticBezierLine } from "@react-three/drei";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { useDeleteTool } from "../../../../store/builder/store";
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
import { ArrowOnQuadraticBezier, Arrows } from "../arrows/arrows";
import { useProductContext } from "../../products/productContext";
import { useParams } from "react-router-dom";
import { useToolMode } from "../../../../store/builder/store";
interface ConnectionLine {
id: string;
@@ -32,7 +32,7 @@ function TriggerConnector() {
const groupRefs = useRef<Record<string, any>>({});
const [helperlineColor, setHelperLineColor] = useState<string>("red");
const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3; end: THREE.Vector3; mid: THREE.Vector3; } | null>(null);
const { deleteTool } = useDeleteTool();
const { toolMode } = useToolMode();
const { isPlaying } = usePlayButtonStore();
const { selectedAction } = useSelectedAction();
const { projectId } = useParams();
@@ -344,7 +344,7 @@ function TriggerConnector() {
}
};
if (subModule === 'mechanics' && !deleteTool && selectedAction.actionId && selectedAction.actionName) {
if (subModule === 'mechanics' && toolMode === 'cursor' && selectedAction.actionId && selectedAction.actionName) {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
@@ -360,7 +360,7 @@ function TriggerConnector() {
canvasElement.removeEventListener('contextmenu', handleRightClick);
};
}, [gl, subModule, selectedProduct, firstSelectedPoint, deleteTool, selectedAction]);
}, [gl, subModule, selectedProduct, firstSelectedPoint, toolMode, selectedAction]);
useFrame(() => {
if (firstSelectedPoint) {
@@ -477,15 +477,15 @@ function TriggerConnector() {
start={startPoint.toArray()}
end={endPoint.toArray()}
mid={midPoint.toArray()}
color={deleteTool && hoveredLineKey === connection.id ? "red" : "#42a5f5"}
color={toolMode === '3D-Delete' && hoveredLineKey === connection.id ? "red" : "#42a5f5"}
lineWidth={4}
dashed={deleteTool && hoveredLineKey === connection.id ? false : true}
dashed={toolMode === '3D-Delete' && hoveredLineKey === connection.id ? false : true}
dashSize={0.75}
dashScale={20}
onPointerOver={() => setHoveredLineKey(connection.id)}
onPointerOut={() => setHoveredLineKey(null)}
onClick={() => {
if (deleteTool) {
if (toolMode === '3D-Delete') {
setHoveredLineKey(null);
setCurrentLine(null);
removeConnection(connection);

View File

@@ -259,10 +259,9 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
}
});
//Helper to Visible the Circle and Curve
return (
<>
{customCurvePoints && customCurvePoints?.length >= 2 && currentPath && isPlaying && (
{/* {customCurvePoints && customCurvePoints?.length >= 2 && currentPath && isPlaying && (
<mesh rotation={armBot.rotation} position={armBot.position} visible={false}>
<Line
points={customCurvePoints.map((p) => [p.x, p.y, p.z] as [number, number, number])}
@@ -277,19 +276,16 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
rotation={[armBot.rotation[0], armBot.rotation[1], armBot.rotation[2]]}
visible={false}
>
{/* Green ring */}
<mesh rotation={[-Math.PI / 2, 0, 0]} visible={false}>
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.02, 64]} />
<meshBasicMaterial color="green" side={THREE.DoubleSide} />
</mesh>
{/* Markers at 90°, 180°, 270°, 360° */}
{[90, 180, 270, 360].map((degree, index) => {
const rad = ((degree) * Math.PI) / 180;
const x = CIRCLE_RADIUS * Math.cos(rad);
const z = CIRCLE_RADIUS * Math.sin(rad);
const y = 0; // same plane as the ring (Y axis)
const y = 0;
return (
<mesh key={index} position={[x, y, z]}>
<sphereGeometry args={[0.05, 16, 16]} />
@@ -302,7 +298,7 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
const rad = ((degree) * Math.PI) / 180;
const x = CIRCLE_RADIUS * Math.cos(rad);
const z = CIRCLE_RADIUS * Math.sin(rad);
const y = 0.15; // lift the text slightly above the ring
const y = 0.15;
return (
<Text
@@ -317,9 +313,7 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
</Text>
);
})}
</group>
</group> */}
</>
);

View File

@@ -10,6 +10,7 @@ import { useProductStore } from '../../../../../store/simulation/useProductStore
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useProductContext } from '../../../products/productContext';
import { Preload } from '@react-three/drei';
function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) {
@@ -45,7 +46,7 @@ function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) {
const animationFrameIdRef = useRef<number | null>(null);
const previousTimeRef = useRef<number | null>(null);
const lastRemoved = useRef<{ type: string, materialId: string } | null>(null);
const lastRemoved = useRef<{ type: string, materialId: string, modelId: string } | null>(null);
function firstFrame() {
startTime = performance.now();
@@ -72,7 +73,7 @@ function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) {
removeLastStorageMaterial(previousModel.modelUuid);
updateCurrentLoad(previousModel.modelUuid, -1)
}
lastRemoved.current = { type: previousModel.type, materialId: armBot.currentAction.materialId };
lastRemoved.current = { type: previousModel.type, materialId: armBot.currentAction.materialId, modelId: previousModel.modelUuid };
} else {
setIsVisible(armBot.currentAction.materialId, false);
}
@@ -104,13 +105,13 @@ function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) {
removeCurrentAction(armBot.modelUuid)
}
if (lastRemoved.current) {
if (lastRemoved.current.type === 'transfer') {
setIsPaused(lastRemoved.current.materialId, true)
} else {
setIsPaused(lastRemoved.current.materialId, false)
}
}
// if (lastRemoved.current) {
// if (lastRemoved.current.type === 'transfer') {
// setIsPaused(lastRemoved.current.materialId, true)
// } else {
// setIsPaused(lastRemoved.current.materialId, false)
// }
// }
}
}
@@ -392,7 +393,7 @@ function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) {
<>
{!isReset && isPlaying && (
<>
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} armBot={armBot} groupRef={groupRef} />
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} armBot={armBot} groupRef={groupRef} />
<RoboticArmAnimator
HandleCallback={HandleCallback}
restPosition={restPosition}

View File

@@ -1,21 +1,19 @@
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { useEffect, useMemo } from 'react'
import * as THREE from "three";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { clone } from "three/examples/jsm/utils/SkeletonUtils";
import { useLoader, useThree } from "@react-three/fiber";
import { CCDIKSolver, CCDIKHelper, } from "three/examples/jsm/animation/CCDIKSolver";
import { TransformControls } from '@react-three/drei';
import { useLoader } from "@react-three/fiber";
import { CCDIKSolver, CCDIKHelper } from "three/examples/jsm/animation/CCDIKSolver";
type IKInstanceProps = {
modelUrl: string;
ikSolver: any;
setIkSolver: any
armBot: ArmBotStatus;
groupRef: any;
};
function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKInstanceProps) {
const { scene } = useThree()
function IKInstance({ modelUrl, setIkSolver, armBot, groupRef }: IKInstanceProps) {
const gltf = useLoader(GLTFLoader, modelUrl, (loader) => {
const draco = new DRACOLoader();
draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/");
@@ -24,7 +22,6 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns
const cloned = useMemo(() => clone(gltf?.scene), [gltf]);
const targetBoneName = "Target";
const skinnedMeshName = "link_0";
const [selectedArm, setSelectedArm] = useState<THREE.Group>();
useEffect(() => {
if (!gltf) return;
@@ -66,28 +63,21 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns
const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks);
setIkSolver(solver);
const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05)
setSelectedArm(OOI.Target_Bone);
// const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05)
// scene.add(helper);
}, [cloned, gltf, setIkSolver]);
}, [cloned, gltf]);
return (
<>
<group ref={groupRef} position={armBot.position} rotation={armBot.rotation} onClick={() => {
setSelectedArm(groupRef.current?.getObjectByName(targetBoneName))
}}>
<primitive
uuid={`${armBot.modelUuid}_IK`}
object={cloned}
scale={[1, 1, 1]}
name={armBot.modelName}
/>
</group>
{/* {selectedArm && <TransformControls object={selectedArm} />} */}
</>
<group ref={groupRef} position={armBot.position} rotation={armBot.rotation}>
<primitive
uuid={`${armBot.modelUuid}_IK`}
object={cloned}
scale={[1, 1, 1]}
name={armBot.modelName}
/>
</group>
)
}

View File

@@ -1,18 +1,20 @@
import { useViewSceneStore } from "../../../../store/builder/store";
import { useSceneContext } from "../../../scene/sceneContext";
import RoboticArmInstance from "./armInstance/roboticArmInstance";
// import RoboticArmContentUi from "../../ui3d/RoboticArmContentUi";
import RoboticArmContentUi from "../../ui3d/RoboticArmContentUi";
import React from "react";
function RoboticArmInstances() {
const {armBotStore} = useSceneContext();
const { armBotStore } = useSceneContext();
const { armBots } = armBotStore();
const { viewSceneLabels } = useViewSceneStore();
return (
<>
{armBots?.map((robot: ArmBotStatus) => (
<React.Fragment key={robot.modelUuid}>
<RoboticArmInstance armBot={robot} />
{/* <RoboticArmContentUi roboticArm={robot} /> */}
{viewSceneLabels && <RoboticArmContentUi roboticArm={robot} />}
</React.Fragment>
))}
</>

View File

@@ -604,6 +604,7 @@ export function useTriggerHandler() {
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid,
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid,
})
setIsPaused(material.materialId, false); // New
handleAction(action, material.materialId);
}
} else {

View File

@@ -48,14 +48,24 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
const computePath = useCallback(
(start: any, end: any) => {
console.log('end: ', end);
try {
const navMeshQuery = new NavMeshQuery(navMesh);
const { path: segmentPath } = navMeshQuery.computePath(start, end);
return (
segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || []
);
if (
segmentPath.length > 0 &&
Math.round(segmentPath[segmentPath.length - 1].x) == Math.round(end.x) &&
Math.round(segmentPath[segmentPath.length - 1].z) == Math.round(end.z)
) {
console.log('if ', segmentPath);
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
} else {
console.log("There is no path here...Choose valid path")
const { path: segmentPaths } = navMeshQuery.computePath(start, start);
return segmentPaths.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
}
} catch {
echo.error("Failed to compute path");
console.error("Failed to compute path");
return [];
}
},
@@ -96,6 +106,10 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]),
agvDetail?.point?.action?.pickUpPoint?.position
);
// const toPickupPath = computePath(
// new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]),
// new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2])
// );
setPath(toPickupPath);
setCurrentPhase('stationed-pickup');
setVehicleState(agvDetail.modelUuid, 'running');