merged with orgin/v2

This commit is contained in:
Poovizhi99 2025-04-25 19:31:46 +05:30
commit f1e55d9abc
85 changed files with 3776 additions and 494 deletions

View File

@ -73,7 +73,7 @@ const Assets: React.FC = () => {
try {
const filt = await fetchAssets();
setFiltereredAssets(filt);
} catch { }
} catch {}
};
filteredAssets();
}, [categoryAssets]);
@ -135,7 +135,7 @@ const Assets: React.FC = () => {
const res = await getCategoryAsset(asset);
setCategoryAssets(res);
setFiltereredAssets(res);
} catch (error) { }
} catch (error) {}
}
};
return (
@ -151,7 +151,12 @@ const Assets: React.FC = () => {
<div className="assets-container">
{categoryAssets &&
categoryAssets?.map((asset: any, index: number) => (
<div key={index} className="assets" id={asset.filename}>
<div
key={index}
className="assets"
id={asset.filename}
title={asset.filename}
>
<img
src={asset?.thumbnail}
alt={asset.filename}
@ -187,7 +192,12 @@ const Assets: React.FC = () => {
<div className="assets-container">
{categoryAssets &&
categoryAssets?.map((asset: any, index: number) => (
<div key={index} className="assets" id={asset.filename}>
<div
key={index}
className="assets"
id={asset.filename}
title={asset.filename}
>
<img
src={asset?.thumbnail}
alt={asset.filename}
@ -196,8 +206,9 @@ const Assets: React.FC = () => {
setSelectedItem({
name: asset.filename,
id: asset.AssetID,
type: asset.type === "undefined" ? undefined : asset.type
})
type:
asset.type === "undefined" ? undefined : asset.type,
});
}}
/>

View File

@ -5,8 +5,8 @@ import Header from "./Header";
import useToggleStore from "../../../store/useUIToggleStore";
import Assets from "./Assets";
import useModuleStore from "../../../store/useModuleStore";
import Widgets from ".//visualization/widgets/Widgets";
import Templates from "../../../modules//visualization/template/Templates";
import Widgets from "./visualization/widgets/Widgets";
import Templates from "../../../modules/visualization/template/Templates";
import Search from "../../ui/inputs/Search";
const SideBarLeft: React.FC = () => {

View File

@ -5,11 +5,11 @@ import {
GlobeIcon,
WalletIcon,
} from "../../../../icons/3dChartIcons";
import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard";
import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
import WarehouseThroughput from "../../../../../modules//visualization/widgets/floating/cards/WarehouseThroughput";
import ProductivityDashboard from "../../../../../modules//visualization/widgets/floating/cards/ProductivityDashboard";
import FleetEfficiency from "../../../../../modules//visualization/widgets/floating/cards/FleetEfficiency";
import WarehouseThroughput from "../../../../../modules/visualization/widgets/floating/cards/WarehouseThroughput";
import ProductivityDashboard from "../../../../../modules/visualization/widgets/floating/cards/ProductivityDashboard";
import FleetEfficiency from "../../../../../modules/visualization/widgets/floating/cards/FleetEfficiency";
interface Widget {
id: string;

View File

@ -1,138 +1,148 @@
import React, { useEffect, useState } from "react";
import React, { useEffect } from "react";
import Header from "./Header";
import useModuleStore, {
useSubModuleStore,
useSubModuleStore,
} from "../../../store/useModuleStore";
import {
AnalysisIcon,
MechanicsIcon,
PropertiesIcon,
SimulationIcon,
AnalysisIcon,
MechanicsIcon,
PropertiesIcon,
SimulationIcon,
} from "../../icons/SimulationIcons";
import useToggleStore from "../../../store/useUIToggleStore";
import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
import {
useSelectedFloorItem,
} from "../../../store/store";
import { useSelectedFloorItem } from "../../../store/store";
import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties";
import EventProperties from "./properties/eventProperties/EventProperties";
const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore();
const { toggleUI } = useToggleStore();
const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem();
// Reset activeList whenever activeModule changes
useEffect(() => {
if (activeModule !== "simulation") setSubModule("properties");
if (activeModule === "simulation") setSubModule("mechanics");
}, [activeModule]);
const { activeModule } = useModuleStore();
const { toggleUI } = useToggleStore();
const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere();
return (
<div className="sidebar-right-wrapper">
<Header />
{toggleUI && (
<div className="sidebar-actions-container">
{/* {activeModule === "builder" && ( */}
<div
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
}`}
onClick={() => setSubModule("properties")}
>
<PropertiesIcon isActive={subModule === "properties"} />
</div>
{/* )} */}
{activeModule === "simulation" && (
<>
<div
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
}`}
onClick={() => setSubModule("mechanics")}
>
<MechanicsIcon isActive={subModule === "mechanics"} />
</div>
<div
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
}`}
onClick={() => setSubModule("simulations")}
>
<SimulationIcon isActive={subModule === "simulations"} />
</div>
<div
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
}`}
onClick={() => setSubModule("analysis")}
>
<AnalysisIcon isActive={subModule === "analysis"} />
</div>
</>
)}
// Reset activeList whenever activeModule changes
useEffect(() => {
if (activeModule !== "simulation") setSubModule("properties");
if (activeModule === "simulation") setSubModule("simulations");
}, [activeModule]);
useEffect(() => {
if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) {
setSubModule("mechanics");
} else if (!selectedEventData && !selectedEventSphere) {
if (activeModule === 'simulation') {
setSubModule("simulations");
}
};
}, [activeModule, selectedEventData, selectedEventSphere])
return (
<div className="sidebar-right-wrapper">
<Header />
{toggleUI && (
<div className="sidebar-actions-container">
<div
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
}`}
onClick={() => setSubModule("properties")}
>
<PropertiesIcon isActive={subModule === "properties"} />
</div>
{activeModule === "simulation" && (
<>
<div
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
}`}
onClick={() => setSubModule("mechanics")}
>
<MechanicsIcon isActive={subModule === "mechanics"} />
</div>
<div
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
}`}
onClick={() => setSubModule("simulations")}
>
<SimulationIcon isActive={subModule === "simulations"} />
</div>
<div
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
}`}
onClick={() => setSubModule("analysis")}
>
<AnalysisIcon isActive={subModule === "analysis"} />
</div>
</>
)}
</div>
)}
{/* process builder */}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" &&
!selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<GlobalProperties />
</div>
</div>
)}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" &&
selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<AsstePropertiies />
</div>
</div>
)}
{toggleUI &&
subModule === "zoneProperties" &&
(activeModule === "builder" || activeModule === "simulation") && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<ZoneProperties />
</div>
</div>
)}
{/* simulation */}
{toggleUI && activeModule === "simulation" && (
<>
{subModule === "simulations" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Simulations />
</div>
</div>
)}
{subModule === "mechanics" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<EventProperties />
</div>
</div>
)}
{subModule === "analysis" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Analysis />
</div>
</div>
)}
</>
)}
{/* realtime visualization */}
{toggleUI && activeModule === "visualization" && <Visualization />}
</div>
)}
{/* process builder */}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" &&
!selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<GlobalProperties />
</div>
</div>
)}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" &&
selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<AsstePropertiies />
</div>
</div>
)}
{toggleUI &&
subModule === "zoneProperties" &&
(activeModule === "builder" || activeModule === "simulation") && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<ZoneProperties />
</div>
</div>
)}
{/* simulation */}
{toggleUI && activeModule === "simulation" && (
<>
{subModule === "mechanics" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
</div>
</div>
)}
{subModule === "analysis" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Analysis />
</div>
</div>
)}
{subModule === "simulations" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Simulations />
</div>
</div>
)}
</>
)}
{/* realtime visualization */}
{toggleUI && activeModule === "visualization" && <Visualization />}
</div>
);
);
};
export default SideBarRight;
export default SideBarRight;

View File

@ -0,0 +1,64 @@
import React, { useEffect, useRef, useState } from "react";
import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../store/simulation/useProductStore";
import ConveyorMechanics from "./mechanics/conveyorMechanics";
import VehicleMechanics from "./mechanics/vehicleMechanics";
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
import MachineMechanics from "./mechanics/machineMechanics";
import StorageMechanics from "./mechanics/storageMechanics";
const EventProperties: React.FC = () => {
const { selectedEventData } = useSelectedEventData();
const { getEventByModelUuid } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(null);
const [assetType, setAssetType] = useState<string | null>(null);
useEffect(() => {
const event = getCurrentEventData();
setCurrentEventData(event);
const type = determineAssetType(event);
setAssetType(type);
}, [selectedEventData, selectedProduct]);
const getCurrentEventData = () => {
if (!selectedEventData?.data || !selectedProduct) return null;
return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null;
};
const determineAssetType = (event: EventsSchema | null) => {
if (!event) return null;
switch (event.type) {
case 'transfer': return 'conveyor';
case 'vehicle': return 'vehicle';
case 'roboticArm': return 'roboticArm';
case 'machine': return 'machine';
case 'storageUnit': return 'storageUnit';
default: return null;
}
};
return (
<>
<div className="event-proprties-wrapper">
{currentEventData &&
<>
<div className="header">
<div className="header-value">{selectedEventData?.data.modelName}</div>
</div>
{assetType === 'conveyor' && <ConveyorMechanics />}
{assetType === 'vehicle' && <VehicleMechanics />}
{assetType === 'roboticArm' && <RoboticArmMechanics />}
{assetType === 'machine' && <MachineMechanics />}
{assetType === 'storageUnit' && <StorageMechanics />}
</>
}
</div>
</>
);
};
export default EventProperties;

View File

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

View File

@ -0,0 +1,30 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
interface DelayActionProps {
value: string;
defaultValue: string;
min: number;
max: number;
onChange: (value: string) => void;
}
const DelayAction: React.FC<DelayActionProps> = ({ value, defaultValue, min, max, onChange }) => {
return (
<>
<InputWithDropDown
label="Delay"
value={value}
min={min}
step={0.1}
defaultValue={defaultValue}
max={max}
activeOption="s"
onClick={() => { }}
onChange={onChange}
/>
</>
);
};
export default DelayAction;

View File

@ -0,0 +1,11 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
const DespawnAction: React.FC = () => {
return (
<>
</>
);
};
export default DespawnAction;

View File

@ -0,0 +1,25 @@
import React from "react";
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
interface PickAndPlaceActionProps {
pickPointValue: string;
pickPointOnChange: (value: string) => void;
placePointValue: string;
placePointOnChange: (value: string) => void;
}
const PickAndPlaceAction: React.FC<PickAndPlaceActionProps> = ({
pickPointValue,
pickPointOnChange,
placePointValue,
placePointOnChange,
}) => {
return (
<>
<EyeDropInput label="Pick Point" value={pickPointValue} onChange={pickPointOnChange} />
<EyeDropInput label="Unload Point" value={placePointValue} onChange={placePointOnChange} />
</>
);
};
export default PickAndPlaceAction;

View File

@ -0,0 +1,48 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import SwapAction from "./SwapAction";
interface ProcessActionProps {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
swapOptions: string[];
swapDefaultOption: string;
onSwapSelect: (value: string) => void;
}
const ProcessAction: React.FC<ProcessActionProps> = ({
value,
min,
max,
defaultValue,
onChange,
swapOptions,
swapDefaultOption,
onSwapSelect,
}) => {
return (
<>
<InputWithDropDown
label="Process Time"
value={value}
min={min}
step={1}
max={max}
defaultValue={defaultValue}
activeOption="s"
onClick={() => { }}
onChange={onChange}
/>
<SwapAction
options={swapOptions}
defaultOption={swapDefaultOption}
onSelect={onSwapSelect}
/>
</>
);
};
export default ProcessAction;

View File

@ -0,0 +1,72 @@
import React from "react";
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
interface SpawnActionProps {
onChangeInterval: (value: string) => void;
onChangeCount: (value: string) => void;
defaultOption: string;
options: string[];
onSelect: (option: string) => void;
intervalValue: string;
countValue: string;
intervalMin: number;
intervalMax: number;
intervalDefaultValue: string;
countMin: number;
countMax: number;
countDefaultValue: string;
}
const SpawnAction: React.FC<SpawnActionProps> = ({
onChangeInterval,
onChangeCount,
defaultOption,
options,
onSelect,
intervalValue,
countValue,
intervalMin,
intervalMax,
intervalDefaultValue,
countMin,
countMax,
countDefaultValue,
}) => {
return (
<>
<InputWithDropDown
label="Spawn interval"
value={intervalValue}
min={intervalMin}
step={1}
defaultValue={intervalDefaultValue}
max={intervalMax}
activeOption="s"
onClick={() => { }}
onChange={onChangeInterval}
/>
<InputWithDropDown
label="Spawn count"
value={countValue}
min={countMin}
step={1}
defaultValue={countDefaultValue}
max={countMax}
activeOption="s"
onClick={() => { }}
onChange={onChangeCount}
/>
{/* <PreviewSelectionWithUpload /> */}
<LabledDropdown
label="Presets"
defaultOption={defaultOption}
options={options}
onSelect={onSelect}
/>
</>
);
};
export default SpawnAction;

View File

@ -0,0 +1,28 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
interface StorageActionProps {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
}
const StorageAction: React.FC<StorageActionProps> = ({ value, min, max, defaultValue, onChange }) => {
return (
<InputWithDropDown
label="Storage Capacity"
value={value}
min={min}
step={1}
max={max}
defaultValue={defaultValue}
activeOption="s"
onClick={() => { }}
onChange={onChange}
/>
);
};
export default StorageAction;

View File

@ -0,0 +1,27 @@
import React from "react";
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
interface SwapActionProps {
onSelect: (option: string) => void;
defaultOption: string;
options: string[];
}
const SwapAction: React.FC<SwapActionProps> = ({ onSelect, defaultOption, options }) => {
return (
<>
{/* <PreviewSelectionWithUpload /> */}
<LabledDropdown
label="Presets"
defaultOption={defaultOption}
options={options}
onSelect={onSelect}
/>
</>
);
};
export default SwapAction;

View File

@ -0,0 +1,78 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
interface TravelActionProps {
loadCapacity: {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
};
unloadDuration: {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
};
pickPoint?: {
value: string;
onChange: (value: string) => void;
};
unloadPoint?: {
value: string;
onChange: (value: string) => void;
};
}
const TravelAction: React.FC<TravelActionProps> = ({
loadCapacity,
unloadDuration,
pickPoint,
unloadPoint,
}) => {
return (
<>
<InputWithDropDown
label="Load Capacity"
value={loadCapacity.value}
min={loadCapacity.min}
max={loadCapacity.max}
defaultValue={loadCapacity.defaultValue}
step={0.1}
activeOption="s"
onClick={() => { }}
onChange={loadCapacity.onChange}
/>
<InputWithDropDown
label="Unload Duration"
value={unloadDuration.value}
min={unloadDuration.min}
max={unloadDuration.max}
defaultValue={unloadDuration.defaultValue}
step={0.1}
activeOption="s"
onClick={() => { }}
onChange={unloadDuration.onChange}
/>
{pickPoint && (
<EyeDropInput
label="Pick Point"
value={pickPoint.value}
onChange={pickPoint.onChange}
/>
)}
{unloadPoint && (
<EyeDropInput
label="Unload Point"
value={unloadPoint.value}
onChange={unloadPoint.onChange}
/>
)}
</>
);
};
export default TravelAction;

View File

@ -0,0 +1,6 @@
export function handleActionToggle(uuid: string) {
// This function handles the action toggle for the event properties.
// It updates the selected action and its properties based on the provided UUID.
// The function is currently empty and needs to be implemented.
// You can add your logic here to handle the action toggle.
}

View File

@ -0,0 +1,6 @@
export function handleDeleteAction(uuid: string) {
// This function handles the action toggle for the event properties.
// It updates the selected action and its properties based on the provided UUID.
// The function is currently empty and needs to be implemented.
// You can add your logic here to handle the action toggle.
}

View File

@ -0,0 +1,212 @@
import { useEffect, useState } from 'react'
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown'
import DelayAction from '../actions/DelayAction'
import RenameInput from '../../../../../ui/inputs/RenameInput'
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
import DespawnAction from '../actions/DespawnAction'
import SwapAction from '../actions/SwapAction'
import SpawnAction from '../actions/SpawnAction'
import DefaultAction from '../actions/DefaultAction'
import Trigger from '../trigger/Trigger'
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
function ConveyorMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default");
const [selectedPointData, setSelectedPointData] = useState<ConveyorPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productId,
selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint
) as ConveyorPointSchema | undefined;
if (point && 'action' in point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "default" | "spawn" | "swap" | "delay" | "despawn");
}
}
}, [selectedProduct, selectedEventData])
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
updateEvent(
selectedProduct.productId,
selectedEventData.data.modelUuid,
{ speed: parseFloat(value) }
);
};
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "default" | "spawn" | "swap" | "delay" | "despawn";
setActiveOption(validOption);
updateAction(
selectedPointData.action.actionUuid,
{ actionType: validOption }
);
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ actionName: newName }
);
};
const handleSpawnCountChange = (value: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ spawnCount: value === "inherit" ? "inherit" : parseFloat(value) }
);
};
const handleSpawnIntervalChange = (value: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ spawnInterval: value === "inherit" ? "inherit" : parseFloat(value) }
);
};
const handleMaterialSelect = (material: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ material }
);
};
const handleDelayChange = (value: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ delay: value === "inherit" ? "inherit" : parseFloat(value) }
);
};
const availableActions = {
defaultOption: "default",
options: ["default", "spawn", "swap", "delay", "despawn"],
};
// Get current values from store
const currentSpeed = selectedEventData?.data.type === "transfer"
? selectedEventData.data.speed.toString()
: "0.5";
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentMaterial = selectedPointData
? selectedPointData.action.material
: "Default material";
const currentSpawnCount = selectedPointData
? selectedPointData.action.spawnCount?.toString() || "1"
: "1";
const currentSpawnInterval = selectedPointData
? selectedPointData.action.spawnInterval?.toString() || "1"
: "1";
const currentDelay = selectedPointData
? selectedPointData.action.delay?.toString() || "0"
: "0";
return (
<>
{selectedEventData &&
<>
<div key={selectedPointData?.uuid} className="global-props">
<div className="property-list-container">
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
min={0}
step={0.1}
defaultValue={"0.5"}
max={10}
activeOption="m/s"
onClick={() => { }}
onChange={handleSpeedChange}
/>
</div>
</div>
</div>
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption={selectedPointData
? selectedPointData.action.actionType
: "default"}
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
{activeOption === "default" &&
<DefaultAction />
}
{activeOption === "spawn" &&
<SpawnAction
onChangeCount={handleSpawnCountChange}
options={["Default material", "Material 1", "Material 2"]}
defaultOption={currentMaterial}
onSelect={handleMaterialSelect}
onChangeInterval={handleSpawnIntervalChange}
intervalValue={currentSpawnInterval}
countValue={currentSpawnCount}
intervalMin={1}
intervalMax={60}
intervalDefaultValue="1"
countMin={1}
countMax={100}
countDefaultValue="1"
/>
}
{activeOption === "swap" &&
<SwapAction
options={["Default material", "Material 1", "Material 2"]}
defaultOption={currentMaterial}
onSelect={handleMaterialSelect}
/>
}
{activeOption === "despawn" &&
<DespawnAction />
}
{activeOption === "delay" &&
<DelayAction
value={currentDelay}
defaultValue="0"
min={0}
max={60}
onChange={handleDelayChange}
/>
}
</div>
</div>
<div className="tirgger">
<Trigger />
</div>
</>
}
</>
)
}
export default ConveyorMechanics

View File

@ -0,0 +1,123 @@
import { useEffect, useState } from 'react'
import RenameInput from '../../../../../ui/inputs/RenameInput'
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
import Trigger from '../trigger/Trigger'
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ProcessAction from '../actions/ProcessAction'
function MachineMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "process">("default");
const [selectedPointData, setSelectedPointData] = useState<MachinePointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productId,
selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint
) as MachinePointSchema | undefined;
if (point && 'action' in point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "process");
}
}
}, [selectedProduct, selectedEventData])
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "process";
setActiveOption(validOption);
updateAction(
selectedPointData.action.actionUuid,
{ actionType: validOption }
);
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ actionName: newName }
);
};
const handleProcessTimeChange = (value: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ processTime: parseFloat(value) }
);
};
const handleMaterialSelect = (material: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ swapMaterial: material }
);
};
// Get current values from store
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentProcessTime = selectedPointData
? selectedPointData.action.processTime.toString()
: "1";
const currentMaterial = selectedPointData
? selectedPointData.action.swapMaterial
: "Default material";
const availableActions = {
defaultOption: "process",
options: ["process"],
};
return (
<>
{selectedEventData &&
<>
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption="process"
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
{activeOption === "process" &&
<ProcessAction
value={currentProcessTime}
min={0.1}
max={60}
defaultValue="1"
onChange={handleProcessTimeChange}
swapOptions={["Default material", "Material 1", "Material 2"]}
swapDefaultOption={currentMaterial}
onSwapSelect={handleMaterialSelect}
/>
}
</div>
</div>
<div className="tirgger">
<Trigger />
</div>
</>
}
</>
)
}
export default MachineMechanics

View File

@ -0,0 +1,276 @@
import { useEffect, useRef, useState } from 'react'
import * as THREE from 'three';
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown'
import RenameInput from '../../../../../ui/inputs/RenameInput'
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
import Trigger from '../trigger/Trigger'
import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons'
import { handleResize } from '../../../../../../functions/handleResizePannel'
import PickAndPlaceAction from '../actions/PickAndPlaceAction'
function RoboticArmMechanics() {
const actionsContainerRef = useRef<HTMLDivElement>(null);
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default");
const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productId,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint
) as RoboticArmPointSchema | undefined;
if (point) {
setSelectedPointData(point);
setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace");
if (point.actions.length > 0 && !selectedAction.actionId) {
setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName);
}
}
} else {
clearSelectedAction();
}
}, [selectedEventData, selectedProduct]);
const handleActionSelect = (actionUuid: string, actionName: string) => {
setSelectedAction(actionUuid, actionName);
};
const handleAddAction = () => {
if (!selectedEventData || !selectedPointData) return;
const newAction = {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: `Action ${selectedPointData.actions.length + 1}`,
actionType: "pickAndPlace" as "pickAndPlace",
process: {
startPoint: null,
endPoint: null
},
triggers: [] as TriggerSchema[]
};
addAction(
selectedProduct.productId,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint,
newAction
);
const updatedPoint = {
...selectedPointData,
actions: [...selectedPointData.actions, newAction]
};
setSelectedPointData(updatedPoint);
setSelectedAction(newAction.actionUuid, newAction.actionName);
};
const handleDeleteAction = (actionUuid: string) => {
if (!selectedPointData) return;
removeAction(actionUuid);
const newActions = selectedPointData.actions.filter(a => a.actionUuid !== actionUuid);
const updatedPoint = {
...selectedPointData,
actions: newActions
};
setSelectedPointData(updatedPoint);
if (selectedAction.actionId === actionUuid) {
if (newActions.length > 0) {
setSelectedAction(newActions[0].actionUuid, newActions[0].actionName);
} else {
clearSelectedAction();
}
}
};
const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return;
updateAction(
selectedAction.actionId,
{ actionName: newName }
);
if (selectedPointData) {
const updatedActions = selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId
? { ...action, actionName: newName }
: action
);
setSelectedPointData({
...selectedPointData,
actions: updatedActions
});
}
};
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
updateEvent(
selectedProduct.productId,
selectedEventData.data.modelUuid,
{ speed: parseFloat(value) }
);
};
const handlePickPointChange = (value: string) => {
if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(',').map(Number);
updateAction(
selectedAction.actionId,
{
process: {
startPoint: [x, y, z] as [number, number, number],
endPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.endPoint || null
}
}
);
};
const handlePlacePointChange = (value: string) => {
if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(',').map(Number);
updateAction(
selectedAction.actionId,
{
process: {
startPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.startPoint || null,
endPoint: [x, y, z] as [number, number, number]
}
}
);
};
const availableActions = {
defaultOption: "pickAndPlace",
options: ["pickAndPlace"],
};
const currentSpeed = selectedEventData?.data.type === "roboticArm"
? selectedEventData.data.speed.toString()
: "0.5";
const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId);
const currentPickPoint = currentAction?.process.startPoint
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
: "";
const currentPlacePoint = currentAction?.process.endPoint
? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}`
: "";
return (
<>
{selectedEventData && selectedPointData && (
<>
<div className="global-props">
<div className="property-list-container">
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
min={0}
step={0.1}
defaultValue={"0.5"}
max={10}
activeOption="m/s"
onClick={() => { }}
onChange={handleSpeedChange}
/>
</div>
</div>
</div>
<div className="actions-list-container">
<div className="actions">
<div className="header">
<div className="header-value">Actions</div>
<div className="add-button" onClick={handleAddAction}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={actionsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{selectedPointData.actions.map((action) => (
<div
key={action.actionUuid}
className={`list-item ${selectedAction.actionId === action.actionUuid ? "active" : ""}`}
>
<div
className="value"
onClick={() => handleActionSelect(action.actionUuid, action.actionName)}
>
<RenameInput
value={action.actionName}
onRename={handleRenameAction}
/>
</div>
{selectedPointData.actions.length > 1 && (
<div
className="remove-button"
onClick={() => handleDeleteAction(action.actionUuid)}
>
<RemoveIcon />
</div>
)}
</div>
))}
</div>
<div
className="resize-icon"
id="action-resize"
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
</div>
{selectedAction.actionId && currentAction && (
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={selectedAction.actionName}
onRename={handleRenameAction}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption={activeOption}
options={availableActions.options}
onSelect={() => { }}
disabled={true}
/>
<PickAndPlaceAction
pickPointValue={currentPickPoint}
pickPointOnChange={handlePickPointChange}
placePointValue={currentPlacePoint}
placePointOnChange={handlePlacePointChange}
/>
</div>
<div className="tirgger">
<Trigger />
</div>
</div>
)}
</>
)}
</>
)
}
export default RoboticArmMechanics

View File

@ -0,0 +1,113 @@
import { useEffect, useState } from 'react'
import RenameInput from '../../../../../ui/inputs/RenameInput'
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
import Trigger from '../trigger/Trigger'
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import StorageAction from '../actions/StorageAction';
function StorageMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default");
const [selectedPointData, setSelectedPointData] = useState<StoragePointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productId,
selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint
) as StoragePointSchema | undefined;
if (point && 'action' in point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "store" | "spawn");
}
}
}, [selectedProduct, selectedEventData])
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "store" | "spawn";
setActiveOption(validOption);
updateAction(
selectedPointData.action.actionUuid,
{ actionType: validOption }
);
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ actionName: newName }
);
};
const handleCapacityChange = (value: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ storageCapacity: parseInt(value) }
);
};
// Get current values from store
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentCapacity = selectedPointData
? selectedPointData.action.storageCapacity.toString()
: "0";
const availableActions = {
defaultOption: "store",
options: ["store", "spawn"],
};
return (
<>
{selectedEventData &&
<>
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption={activeOption}
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
{activeOption === "store" &&
<StorageAction
value={currentCapacity}
defaultValue="0"
min={0}
max={20}
onChange={handleCapacityChange}
/>
}
{activeOption === "spawn" && (
<div className="spawn-options">
<p>Spawn configuration options would go here</p>
</div>
)}
</div>
</div>
<div className="tirgger">
<Trigger />
</div>
</>
}
</>
)
}
export default StorageMechanics

View File

@ -0,0 +1,197 @@
import { useEffect, useState } from 'react'
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown'
import RenameInput from '../../../../../ui/inputs/RenameInput'
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
import Trigger from '../trigger/Trigger'
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import TravelAction from '../actions/TravelAction'
function VehicleMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "travel">("default");
const [selectedPointData, setSelectedPointData] = useState<VehiclePointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productId,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint
) as VehiclePointSchema | undefined;
if (point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "travel");
}
}
}, [selectedProduct, selectedEventData])
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
updateEvent(
selectedProduct.productId,
selectedEventData.data.modelUuid,
{ speed: parseFloat(value) }
);
};
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "travel";
setActiveOption(validOption);
updateAction(
selectedPointData.action.actionUuid,
{ actionType: validOption }
);
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ actionName: newName }
);
};
const handleLoadCapacityChange = (value: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ loadCapacity: parseFloat(value) }
);
};
const handleUnloadDurationChange = (value: string) => {
if (!selectedPointData) return;
updateAction(
selectedPointData.action.actionUuid,
{ unLoadDuration: parseFloat(value) }
);
};
const handlePickPointChange = (value: string) => {
if (!selectedPointData) return;
const [x, y, z] = value.split(',').map(Number);
updateAction(
selectedPointData.action.actionUuid,
{ pickUpPoint: { x, y, z } }
);
};
const handleUnloadPointChange = (value: string) => {
if (!selectedPointData) return;
const [x, y, z] = value.split(',').map(Number);
updateAction(
selectedPointData.action.actionUuid,
{ unLoadPoint: { x, y, z } }
);
};
// Get current values from store
const currentSpeed = selectedEventData?.data.type === "vehicle"
? selectedEventData.data.speed.toString()
: "0.5";
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentLoadCapacity = selectedPointData
? selectedPointData.action.loadCapacity.toString()
: "1";
const currentUnloadDuration = selectedPointData
? selectedPointData.action.unLoadDuration.toString()
: "1";
const currentPickPoint = selectedPointData?.action.pickUpPoint
? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}`
: "";
const currentUnloadPoint = selectedPointData?.action.unLoadPoint
? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}`
: "";
const availableActions = {
defaultOption: "travel",
options: ["travel"],
};
return (
<>
{selectedEventData &&
<>
<div className="global-props">
<div className="property-list-container">
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
min={0}
step={0.1}
defaultValue={"0.5"}
max={10}
activeOption="m/s"
onClick={() => { }}
onChange={handleSpeedChange}
/>
</div>
</div>
</div>
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption="travel"
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
{activeOption === 'travel' &&
<TravelAction
loadCapacity={{
value: currentLoadCapacity,
min: 1,
max: 100,
defaultValue: "1",
onChange: handleLoadCapacityChange,
}}
unloadDuration={{
value: currentUnloadDuration,
min: 1,
max: 60,
defaultValue: "1",
onChange: handleUnloadDurationChange,
}}
// pickPoint={{
// value: currentPickPoint,
// onChange: handlePickPointChange,
// }}
// unloadPoint={{
// value: currentUnloadPoint,
// onChange: handleUnloadPointChange,
// }}
/>
}
</div>
</div>
<div className="tirgger">
<Trigger />
</div>
</>
}
</>
)
}
export default VehicleMechanics

View File

@ -0,0 +1,107 @@
import React, { useState } from "react";
import { AddIcon, RemoveIcon } from "../../../../../icons/ExportCommonIcons";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
const Trigger: React.FC = () => {
// State to hold the list of triggers
const [triggers, setTriggers] = useState<string[]>([]);
const [activeOption, setActiveOption] = useState("onComplete");
// States for dropdowns
const [triggeredModel, setTriggeredModel] = useState<string[]>([]);
const [triggeredPoint, setTriggeredPoint] = useState<string[]>([]);
const [triggeredAction, setTriggeredAction] = useState<string[]>([]);
// Function to handle adding a new trigger
const addTrigger = (): void => {
const newTrigger = `Trigger ${triggers.length + 1}`;
setTriggers([...triggers, newTrigger]); // Add new trigger to the state
// Initialize the states for the new trigger
setTriggeredModel([...triggeredModel, ""]);
setTriggeredPoint([...triggeredPoint, ""]);
setTriggeredAction([...triggeredAction, ""]);
};
// Function to handle removing a trigger
const removeTrigger = (index: number): void => {
setTriggers(triggers.filter((_, i) => i !== index)); // Remove trigger by index
setTriggeredModel(triggeredModel.filter((_, i) => i !== index));
setTriggeredPoint(triggeredPoint.filter((_, i) => i !== index));
setTriggeredAction(triggeredAction.filter((_, i) => i !== index));
};
return (
<div className="trigger-wrapper">
<div className="header">
<div className="title">Trigger</div>
<div
className="add-button"
onClick={addTrigger}
style={{ cursor: "pointer" }}
>
<AddIcon /> Add
</div>
</div>
<div className="trigger-list">
{/* Map over triggers and render them */}
{triggers.map((trigger, index) => (
<div key={index} className="trigger-item">
<div className="trigger-name">
{trigger}
<div
className="remove-button"
onClick={() => removeTrigger(index)}
style={{ cursor: "pointer" }}
>
<RemoveIcon />
</div>
</div>
<LabledDropdown
defaultOption={activeOption}
options={["onComplete", "onStart", "onStop", "delay"]}
onSelect={(option) => setActiveOption(option)}
/>
<div className="trigger-options">
<div>
<LabledDropdown
defaultOption={triggeredModel[index] || "Select Model"}
options={["Model 1", "Model 2", "Model 3"]}
onSelect={(option) => {
const newModel = [...triggeredModel];
newModel[index] = option;
setTriggeredModel(newModel);
}}
/>
</div>
<div>
<LabledDropdown
defaultOption={triggeredPoint[index] || "Select Point"}
options={["Point 1", "Point 2", "Point 3"]}
onSelect={(option) => {
const newPoint = [...triggeredPoint];
newPoint[index] = option;
setTriggeredPoint(newPoint);
}}
/>
</div>
<div>
<LabledDropdown
defaultOption={triggeredAction[index] || "Select Action"}
options={["Action 1", "Action 2", "Action 3"]}
onSelect={(option) => {
const newAction = [...triggeredAction];
newAction[index] = option;
setTriggeredAction(newAction);
}}
/>
</div>
</div>
</div>
))}
</div>
</div>
);
};
export default Trigger;

View File

@ -1,147 +1,198 @@
import React, { useRef, useState } from "react";
import React, { useEffect, useRef } from "react";
import {
AddIcon,
ArrowIcon,
RemoveIcon,
ResizeHeightIcon,
AddIcon,
ArrowIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../functions/handleResizePannel";
import { useSelectedAsset, useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { generateUUID } from "three/src/math/MathUtils";
import RenderOverlay from "../../../templates/Overlay";
import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
interface Path {
pathName: string; // Represents the name of the path
Children: string[]; // Represents the list of child points
interface Event {
pathName: string;
}
interface DropListProps {
val: Path; // Use the Path interface for the val prop
interface ListProps {
val: Event;
}
const DropList: React.FC<DropListProps> = ({ val }) => {
const [openDrop, setOpenDrop] = useState(false);
return (
<div className="process-container">
<div
className="value"
onClick={() => {
setOpenDrop(!openDrop);
}}
>
{val.pathName}
<div className={`arrow-container${openDrop ? " active" : ""}`}>
<ArrowIcon />
</div>
</div>
{val.Children && openDrop && (
<div className="children-drop">
{val.Children.map((child, index) => (
<div key={index} className="value">
{child}
const List: React.FC<ListProps> = ({ val }) => {
return (
<div className="process-container">
<div className="value">
{val.pathName}
</div>
))}
</div>
)}
</div>
);
);
};
const Simulations: React.FC = () => {
const productsContainerRef = useRef<HTMLDivElement>(null);
const [productsList, setProductsList] = useState<string[]>([]);
const [selectedItem, setSelectedItem] = useState<string>();
const productsContainerRef = useRef<HTMLDivElement>(null);
const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent } = useProductStore();
const { selectedProduct, setSelectedProduct } = useSelectedProduct();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const handleAddAction = () => {
setProductsList([...productsList, `Product ${productsList.length + 1}`]);
};
const handleAddProduct = () => {
addProduct(`Product ${products.length + 1}`, generateUUID());
};
const handleRemoveAction = (index: number) => {
setProductsList(productsList.filter((_, i) => i !== index));
if (selectedItem === productsList[index]) {
setSelectedItem("");
}
};
const handleRemoveProduct = (productId: string) => {
const currentIndex = products.findIndex(p => p.productId === productId);
const isSelected = selectedProduct.productId === productId;
const Value = [
{ pathName: "Path 1", Children: ["Point 1", "Point 2"] },
{ pathName: "Path 2", Children: ["Point 1", "Point 2"] },
{ pathName: "Path 3", Children: ["Point 1", "Point 2"] },
];
const updatedProducts = products.filter(p => p.productId !== productId);
return (
<div className="simulations-container">
<div className="header">Simulations</div>
<div className="add-product-container">
<div className="actions">
<div className="header">
<div className="header-value">Products</div>
<div className="add-button" onClick={handleAddAction}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={productsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{productsList.map((action, index) => (
<div
key={index}
className={`list-item ${
selectedItem === action ? "active" : ""
}`}
>
<div
className="value"
onClick={() => setSelectedItem(action)}
>
<input type="radio" name="products" id="products" />
<RenameInput value={action} />
</div>
<div
className="remove-button"
onClick={() => handleRemoveAction(index)}
>
<RemoveIcon />
</div>
if (isSelected) {
if (updatedProducts.length > 0) {
let newSelectedIndex = currentIndex;
if (currentIndex >= updatedProducts.length) {
newSelectedIndex = updatedProducts.length - 1;
}
setSelectedProduct(
updatedProducts[newSelectedIndex].productId,
updatedProducts[newSelectedIndex].productName
);
} else {
setSelectedProduct('', '');
}
}
removeProduct(productId);
};
const handleRenameProduct = (productId: string, newName: string) => {
renameProduct(productId, newName);
if (selectedProduct.productId === productId) {
setSelectedProduct(productId, newName);
}
};
const handleAddEventToProduct = () => {
if (selectedAsset) {
addEvent(selectedProduct.productId, selectedAsset);
clearSelectedAsset();
}
};
const handleRemoveEventFromProduct = () => {
if (selectedAsset) {
removeEvent(selectedProduct.productId, selectedAsset.modelUuid);
clearSelectedAsset();
}
};
const selectedProductData = products.find(
(product) => product.productId === selectedProduct.productId
);
const events: Event[] = selectedProductData?.eventDatas.map((event) => ({
pathName: event.modelName,
})) || [];
return (
<div className="simulations-container">
<div className="header">Simulations</div>
<div className="add-product-container">
<div className="actions">
<div className="header">
<div className="header-value">Products</div>
<div className="add-button" onClick={handleAddProduct}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={productsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{products.map((product, index) => (
<div
key={product.productId}
className={`list-item ${selectedProduct.productId === product.productId ? "active" : ""}`}
>
<div
className="value"
onClick={() => setSelectedProduct(product.productId, product.productName)}
>
<input
type="radio"
name="products"
checked={selectedProduct.productId === product.productId}
readOnly
/>
<RenameInput
value={product.productName}
onRename={(newName) => handleRenameProduct(product.productId, newName)}
/>
</div>
{products.length > 1 && (
<div
className="remove-button"
onClick={() => handleRemoveProduct(product.productId)}
>
<RemoveIcon />
</div>
)}
</div>
))}
</div>
<div
className="resize-icon"
id="action-resize"
onMouseDown={(e) => handleResize(e, productsContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
<div className="simulation-process">
<div className="collapse-header-container">
<div className="header">Events</div>
<div className="arrow-container">
<ArrowIcon />
</div>
</div>
{events.map((event, index) => (
<List key={index} val={event} />
))}
</div>
<div className="compare-simulations-container">
<div className="compare-simulations-header">
Need to Compare Layout?
</div>
<div className="content">
Click <span>'Compare'</span> to review and analyze the layout differences between them.
</div>
<div className="input">
<input type="button" value={"Compare"} className="submit" />
</div>
</div>
))}
</div>
<div
className="resize-icon"
id="action-resize"
onMouseDown={(e) => handleResize(e, productsContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
{selectedAsset &&
<RenderOverlay>
<EditWidgetOption
options={['Add to Product', 'Remove from Product']}
onClick={(option) => {
if (option === 'Add to Product') {
handleAddEventToProduct();
} else {
handleRemoveEventFromProduct();
}
}}
/>
</RenderOverlay>
}
</div>
<div className="simulation-process">
<div className="collapse-header-container">
<div className="header">Operations</div>
<div className="arrow-container">
<ArrowIcon />
</div>
</div>
{Value.map((val, index) => (
<DropList key={index} val={val} />
))}
</div>
<div className="compare-simulations-container">
<div className="compare-simulations-header">
Need to Compare Layout?
</div>
<div className="content">
Click <span>'Compare'</span> to review and analyze the layout
differences between them.
</div>
<div className="input">
<input type="button" value={"Compare"} className="submit" />
</div>
</div>
</div>
</div>
);
);
};
export default Simulations;

View File

@ -1,9 +1,9 @@
import { useState, useEffect, useRef } from "react";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import ChartComponent from "../../../sidebarLeft//visualization/widgets/ChartComponent";
import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import { WalletIcon } from "../../../../icons/3dChartIcons";
import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard";
import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
interface Widget {
id: string;

View File

@ -15,7 +15,7 @@ import {
} from "../icons/ExportToolsIcons";
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
import { handleSaveTemplate } from "../../modules//visualization/functions/handleSaveTemplate";
import { handleSaveTemplate } from "../../modules/visualization/functions/handleSaveTemplate";
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useTemplateStore from "../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";

View File

@ -5,6 +5,7 @@ type InputWithDropDownProps = {
label: string;
value: string;
min?: number;
max?: number;
step?: number;
defaultValue?: string;
options?: string[]; // Array of dropdown options
@ -19,6 +20,7 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
label,
value,
min,
max,
step,
defaultValue,
options,
@ -47,6 +49,7 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
<div className="input default" id={separatedWords}>
<input
min={min}
max={max}
step={step}
type="number"
defaultValue={value}

View File

@ -0,0 +1,43 @@
import React, { useState } from "react";
import LabledDropdown from "./LabledDropdown";
import { ArrowIcon } from "../../icons/ExportCommonIcons";
const PreviewSelectionWithUpload: React.FC = () => {
const [showPreview, setSetshowPreview] = useState(false);
return (
<div className="preview-selection-with-upload-wrapper">
<div
className="input-header-container"
onClick={() => setSetshowPreview(!showPreview)}
>
<div className="input-header">Preview</div>
<div
className="arrow-container"
style={{ rotate: showPreview ? "0deg" : "90deg" }}
>
<ArrowIcon />
</div>
</div>
{showPreview && (
<div className="canvas-wrapper">
<div className="canvas-container"></div>
</div>
)}
<div className="asset-selection-container">
<div className="upload-custom-asset-button">
<div className="title">Upload Product</div>
<input
type="file"
accept=".glb, .gltf"
id="simulation-product-upload"
/>
<label className="upload-button" htmlFor="simulation-product-upload">
Upload here
</label>
</div>
</div>
</div>
);
};
export default PreviewSelectionWithUpload;

View File

@ -142,9 +142,6 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
)
);
}
console.log('newName: ', newName);
}
const checkZoneNameDuplicate = (name: string) => {
return zones.some(

View File

@ -1,23 +1,20 @@
import React, { useEffect } from "react";
import {
useEditWidgetOptionsStore,
useLeftData,
useRightClickSelected,
useRightSelected,
useTopData,
} from "../../../store/visualization/useZone3DWidgetStore";
interface EditWidgetOptionProps {
options: string[];
onClick: (option: string) => void;
}
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
options,
onClick
}) => {
const { top } = useTopData();
const { left } = useLeftData();
const { setRightSelect } = useRightSelected();
const { setEditWidgetOptions } = useEditWidgetOptionsStore();
useEffect(() => {
@ -38,10 +35,7 @@ const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
<div
className="option"
key={index}
onClick={(e) => {
setRightSelect(option);
setEditWidgetOptions(false);
}}
onClick={() => onClick(option)}
>
{option}
</div>

View File

@ -8,10 +8,12 @@ import * as Types from "../../../types/world/worldTypes";
import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
import PointsCalculator from '../../simulation/events/points/functions/pointsCalculator';
async function loadInitialFloorItems(
itemsGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState,
addEvent: (event: EventsSchema) => void,
): Promise<void> {
if (!itemsGroup.current) return;
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
@ -70,7 +72,7 @@ async function loadInitialFloorItems(
const cachedModel = THREE.Cache.get(item.modelfileID!);
if (cachedModel) {
// console.log(`[Cache] Fetching ${item.modelname}`);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
return;
@ -85,7 +87,7 @@ async function loadInitialFloorItems(
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
},
@ -106,7 +108,7 @@ async function loadInitialFloorItems(
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
await storeGLTF(item.modelfileID!, modelBlob);
THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
},
@ -148,8 +150,9 @@ function processLoadedModel(
item: Types.FloorItemType,
itemsGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState,
addEvent: (event: EventsSchema) => void,
) {
const model = gltf;
const model = gltf.clone();
model.uuid = item.modeluuid;
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
@ -182,6 +185,243 @@ function processLoadedModel(
},
]);
if (item.modelfileID === "a1ee92554935007b10b3eb05") {
const data = PointsCalculator(
'Vehicle',
gltf.clone(),
new THREE.Vector3(...model.rotation)
);
if (!data || !data.points) return;
const vehicleEvent: VehicleEventSchema = {
modelUuid: item.modeluuid,
modelName: item.modelname,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "vehicle",
speed: 1,
point: {
uuid: THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z],
rotation: [0, 0, 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Vehicle Action",
actionType: "travel",
material: null,
unLoadDuration: 5,
loadCapacity: 10,
pickUpPoint: null,
unLoadPoint: null,
triggers: []
}
}
};
addEvent(vehicleEvent);
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") {
const data = PointsCalculator(
'Conveyor',
gltf.clone(),
new THREE.Vector3(...model.rotation)
);
if (!data || !data.points) return;
const ConveyorEvent: ConveyorEventSchema = {
modelUuid: item.modeluuid,
modelName: item.modelname,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "transfer",
speed: 1,
points: data.points.map((point: THREE.Vector3, index: number) => ({
uuid: THREE.MathUtils.generateUUID(),
position: [point.x, point.y, point.z],
rotation: [0, 0, 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: `Action ${index + 1}`,
actionType: 'default',
material: 'Default material',
delay: 0,
spawnInterval: 5,
spawnCount: 1,
triggers: []
}
}))
};
addEvent(ConveyorEvent);
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") {
// const data = PointsCalculator(
// 'Conveyor',
// gltf.clone(),
// new THREE.Vector3(...model.rotation)
// );
// if (!data || !data.points) return;
// const points: ConveyorPointSchema[] = data.points.map((point: THREE.Vector3, index: number) => {
// const actionUuid = THREE.MathUtils.generateUUID();
// return {
// uuid: THREE.MathUtils.generateUUID(),
// position: [point.x, point.y, point.z],
// rotation: [0, 0, 0],
// action: {
// actionUuid,
// actionName: `Action ${index}`,
// actionType: 'default',
// material: 'inherit',
// delay: 0,
// spawnInterval: 5,
// spawnCount: 1,
// triggers: []
// }
// };
// });
// points.forEach((point, index) => {
// if (index < points.length - 1) {
// const nextPoint = points[index + 1];
// point.action.triggers.push({
// triggerUuid: THREE.MathUtils.generateUUID(),
// triggerName: `Trigger 1`,
// triggerType: "onComplete",
// delay: 0,
// triggeredAsset: {
// triggeredModel: {
// modelName: item.modelname,
// modelUuid: item.modeluuid
// },
// triggeredPoint: {
// pointName: `Point ${index + 1}`,
// pointUuid: nextPoint.uuid
// },
// triggeredAction: {
// actionName: nextPoint.action.actionName,
// actionUuid: nextPoint.action.actionUuid
// }
// }
// });
// }
// });
// const ConveyorEvent: ConveyorEventSchema = {
// modelUuid: item.modeluuid,
// modelName: item.modelname,
// position: item.position,
// rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
// state: "idle",
// type: "transfer",
// speed: 1,
// points
// };
// addEvent(ConveyorEvent);
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") {
const data = PointsCalculator(
'Conveyor',
gltf.clone(),
new THREE.Vector3(...model.rotation)
);
if (!data || !data.points) return;
const ConveyorEvent: ConveyorEventSchema = {
modelUuid: item.modeluuid,
modelName: item.modelname,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "transfer",
speed: 1,
points: data.points.map((point: THREE.Vector3, index: number) => ({
uuid: THREE.MathUtils.generateUUID(),
position: [point.x, point.y, point.z],
rotation: [0, 0, 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: `Action ${index}`,
actionType: 'default',
material: 'inherit',
delay: 0,
spawnInterval: 5,
spawnCount: 1,
triggers: []
}
}))
};
addEvent(ConveyorEvent);
} else if (item.modelfileID === "29dee78715ad5b853f5c346d") {
const data = PointsCalculator(
'StaticMachine',
gltf.clone(),
new THREE.Vector3(...model.rotation)
);
if (!data || !data.points) return;
const machineEvent: MachineEventSchema = {
modelUuid: item.modeluuid,
modelName: item.modelname,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "machine",
point: {
uuid: THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z],
rotation: [0, 0, 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Process Action",
actionType: "process",
processTime: 10,
swapMaterial: "material-id",
triggers: []
}
}
};
addEvent(machineEvent);
} else if (item.modelfileID === "52e6681fbb743a890d96c914") {
const data = PointsCalculator(
'ArmBot',
gltf.clone(),
new THREE.Vector3(...model.rotation)
);
if (!data || !data.points) return;
const roboticArmEvent: RoboticArmEventSchema = {
modelUuid: item.modeluuid,
modelName: item.modelname,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "roboticArm",
speed: 1,
point: {
uuid: THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z],
rotation: [0, 0, 0],
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Pick and Place",
actionType: "pickAndPlace",
process: {
startPoint: [0, 0, 0],
endPoint: [0, 0, 0]
},
triggers: []
}
]
}
};
addEvent(roboticArmEvent);
}
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
}

View File

@ -51,7 +51,7 @@ import Ground from "../scene/environment/ground";
// import ZoneGroup from "../groups/zoneGroup1";
import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment";
import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
import DrieHtmlTemp from "..//visualization/mqttTemp/drieHtmlTemp";
import DrieHtmlTemp from "../visualization/mqttTemp/drieHtmlTemp";
import ZoneGroup from "./groups/zoneGroup";
import useModuleStore from "../../store/useModuleStore";
import MeasurementTool from "../scene/tools/measurementTool";

View File

@ -10,7 +10,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
import { Socket } from 'socket.io-client';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import PointsCalculator from '../../../simulation/events/points/pointsCalculator';
import PointsCalculator from '../../../simulation/events/points/functions/pointsCalculator';
async function addAssetModel(
raycaster: THREE.Raycaster,
@ -184,24 +184,9 @@ async function handleModelLoad(
);
if (!data || !data.points) return;
console.log('data: ', data);
const createMarker = (point: THREE.Vector3) => {
const sphere = new THREE.SphereGeometry(0.1, 15);
const material = new THREE.MeshStandardMaterial();
const mesh = new THREE.Mesh(sphere, material);
mesh.position.copy(point);
return mesh;
};
if (data.points && data.points.length > 0) {
data.points.forEach((Point) => {
model.add(createMarker(Point));
});
}
if (selectedItem.type === "Conveyor") {
const event: ConveyorEventSchema = {
const ConveyorEvent: ConveyorEventSchema = {
modelUuid: newFloorItem.modeluuid,
modelName: newFloorItem.modelname,
position: newFloorItem.position,
@ -225,7 +210,85 @@ async function handleModelLoad(
}
}))
}
addEvent(event);
addEvent(ConveyorEvent);
} else if (selectedItem.type === "Vehicle") {
const vehicleEvent: VehicleEventSchema = {
modelUuid: newFloorItem.modeluuid,
modelName: newFloorItem.modelname,
position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle",
type: "vehicle",
speed: 1,
point: {
uuid: THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z],
rotation: [0, 0, 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Vehicle Action",
actionType: "travel",
material: null,
unLoadDuration: 5,
loadCapacity: 10,
pickUpPoint: null,
unLoadPoint: null,
triggers: []
}
}
};
addEvent(vehicleEvent);
} else if (selectedItem.type === "ArmBot") {
const roboticArmEvent: RoboticArmEventSchema = {
modelUuid: newFloorItem.modeluuid,
modelName: newFloorItem.modelname,
position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle",
type: "roboticArm",
speed: 1,
point: {
uuid: THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z],
rotation: [0, 0, 0],
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Pick and Place",
actionType: "pickAndPlace",
process: {
startPoint: [0, 0, 0],
endPoint: [0, 0, 0]
},
triggers: []
}
]
}
};
addEvent(roboticArmEvent);
} else if (selectedItem.type === "StaticMachine") {
const machineEvent: MachineEventSchema = {
modelUuid: newFloorItem.modeluuid,
modelName: newFloorItem.modelname,
position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle",
type: "machine",
point: {
uuid: THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z],
rotation: [0, 0, 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Process Action",
actionType: "process",
processTime: 10,
swapMaterial: "material-id",
triggers: []
}
}
};
addEvent(machineEvent);
}
}

View File

@ -16,8 +16,8 @@ import addAssetModel from "../geomentries/assets/addAssetModel";
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
import useModuleStore from "../../../store/useModuleStore";
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
import { useEventsStore } from "../../../store/simulation/useEventsStore";
const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url));
const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
@ -75,7 +75,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
gltfLoaderWorker.postMessage({ floorItems: data });
} else {
gltfLoaderWorker.postMessage({ floorItems: [] });
loadInitialFloorItems(itemsGroup, setFloorItems);
loadInitialFloorItems(itemsGroup, setFloorItems, addEvent);
updateLoadingProgress(100);
}
});
@ -94,7 +94,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
updateLoadingProgress(progress);
if (loadedAssets === totalAssets) {
loadInitialFloorItems(itemsGroup, setFloorItems);
loadInitialFloorItems(itemsGroup, setFloorItems, addEvent);
updateLoadingProgress(100);
}
});

View File

@ -2,90 +2,107 @@ import * as THREE from "three";
import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing";
import { BlendFunction } from "postprocessing";
import {
useDeletableFloorItem,
useSelectedWallItem,
useSelectedFloorItem,
useDeletableFloorItem,
useSelectedWallItem,
useSelectedFloorItem,
} from "../../../store/store";
import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from "../../../types/world/worldConstants";
import { useEffect } from "react";
import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
export default function PostProcessing() {
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
const { selectedEventSphere } = useSelectedEventSphere();
function flattenChildren(children: any[]) {
const allChildren: any[] = [];
children.forEach((child) => {
allChildren.push(child);
if (child.children && child.children.length > 0) {
allChildren.push(...flattenChildren(child.children));
}
});
return allChildren;
}
function flattenChildren(children: any[]) {
const allChildren: any[] = [];
children.forEach((child) => {
allChildren.push(child);
if (child.children && child.children.length > 0) {
allChildren.push(...flattenChildren(child.children));
}
});
return allChildren;
}
return (
<>
<EffectComposer autoClear={false}>
<N8AO
color="black"
aoRadius={20}
intensity={7}
distanceFalloff={4}
aoSamples={32}
denoiseRadius={6}
denoiseSamples={16}
/>
{deletableFloorItem && (
<Outline
selection={flattenChildren(deletableFloorItem.children)}
selectionLayer={10}
width={3000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={5}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
hiddenEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
blur={true}
xRay={true}
/>
)}
{selectedWallItem && (
<Outline
selection={selectedWallItem.children[1].children[0].children.filter(
(child: Types.Mesh) => child.name !== "CSG_REF"
)}
selectionLayer={10}
width={3000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={5}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
blur={true}
xRay={true}
/>
)}
{selectedFloorItem && (
<Outline
selection={flattenChildren(selectedFloorItem.children)}
selectionLayer={10}
width={3000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={5}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
blur={true}
xRay={true}
/>
)}
</EffectComposer>
</>
);
return (
<>
<EffectComposer autoClear={false}>
<N8AO
color="black"
aoRadius={20}
intensity={7}
distanceFalloff={4}
aoSamples={32}
denoiseRadius={6}
denoiseSamples={16}
/>
{deletableFloorItem && (
<Outline
selection={flattenChildren(deletableFloorItem.children)}
selectionLayer={10}
width={3000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={5}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
hiddenEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
blur={true}
xRay={true}
/>
)}
{selectedWallItem && (
<Outline
selection={selectedWallItem.children[1].children[0].children.filter(
(child: Types.Mesh) => child.name !== "CSG_REF"
)}
selectionLayer={10}
width={3000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={5}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
blur={true}
xRay={true}
/>
)}
{selectedFloorItem && (
<Outline
selection={flattenChildren(selectedFloorItem.children)}
selectionLayer={10}
width={3000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={5}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
blur={true}
xRay={true}
/>
)}
{selectedEventSphere && (
<Outline
selection={[selectedEventSphere]}
selectionLayer={10}
width={1000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={10}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={0x6f42c1}
hiddenEdgeColor={0x6f42c1}
blur={true}
xRay={true}
/>
)}
</EffectComposer>
</>
);
}

View File

@ -0,0 +1,14 @@
import React from 'react'
import ConveyorInstances from './instances/conveyorInstances'
function Conveyor() {
return (
<>
<ConveyorInstances />
</>
)
}
export default Conveyor

View File

@ -0,0 +1,10 @@
import React from 'react'
function ConveyorInstance() {
return (
<>
</>
)
}
export default ConveyorInstance

View File

@ -0,0 +1,14 @@
import React from 'react'
import ConveyorInstance from './conveyorInstance/conveyorInstance'
function ConveyorInstances() {
return (
<>
<ConveyorInstance />
</>
)
}
export default ConveyorInstances

View File

@ -0,0 +1,169 @@
import React, { useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import { useEventsStore } from '../../../../../store/simulation/useEventsStore';
import useModuleStore from '../../../../../store/useModuleStore';
import { TransformControls } from '@react-three/drei';
import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys';
import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore';
function PointsCreator() {
const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore();
const { activeModule } = useModuleStore();
const transformRef = useRef<any>(null);
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere();
const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
useEffect(() => {
if (selectedEventSphere) {
const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid);
if (eventData) {
setSelectedEventData(
eventData,
selectedEventSphere.userData.pointUuid
);
} else {
clearSelectedEventData();
}
} else {
clearSelectedEventData();
}
}, [selectedEventSphere]);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const keyCombination = detectModifierKeys(e);
if (!selectedEventSphere) return;
if (keyCombination === "G") {
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
}
if (keyCombination === "R") {
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [selectedEventSphere]);
const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid)));
if (point) {
point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z];
updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point)
}
}
return (
<>
{activeModule === 'simulation' &&
<>
<group name='EventPointsGroup' >
{events.map((event, i) => {
if (event.type === 'transfer') {
return (
<group key={i} position={new THREE.Vector3(...event.position)}>
{event.points.map((point, j) => (
<mesh
uuid={point.uuid}
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(sphereRefs.current[point.uuid]);
}}
onPointerMissed={() => {
clearSelectedEventSphere();
setTransformMode(null);
}}
key={`${i}-${j}`}
position={new THREE.Vector3(...point.position)}
userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }}
>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="orange" />
</mesh>
))}
</group>
);
} else if (event.type === 'vehicle') {
return (
<group key={i} position={new THREE.Vector3(...event.position)}>
<mesh
uuid={event.point.uuid}
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
}}
onPointerMissed={() => {
clearSelectedEventSphere();
setTransformMode(null);
}}
position={new THREE.Vector3(...event.point.position)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="blue" />
</mesh>
</group>
);
} else if (event.type === 'roboticArm') {
return (
<group key={i} position={new THREE.Vector3(...event.position)}>
<mesh
uuid={event.point.uuid}
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
}}
onPointerMissed={() => {
clearSelectedEventSphere();
setTransformMode(null);
}}
position={new THREE.Vector3(...event.point.position)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="green" />
</mesh>
</group>
);
} else if (event.type === 'machine') {
return (
<group key={i} position={new THREE.Vector3(...event.position)}>
<mesh
uuid={event.point.uuid}
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
onClick={(e) => {
e.stopPropagation();
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
}}
onPointerMissed={() => {
clearSelectedEventSphere();
setTransformMode(null);
}}
position={new THREE.Vector3(...event.point.position)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="purple" />
</mesh>
</group>
);
} else {
return null;
}
})}
</group>
{(selectedEventSphere && transformMode) &&
<TransformControls ref={transformRef} object={selectedEventSphere} mode={transformMode} onMouseUp={(e) => { updatePointToState(selectedEventSphere) }} />
}
</>
}
</>
);
}
export default PointsCreator;

View File

@ -1,5 +1,5 @@
import * as THREE from 'three';
import { Group } from '../../../../types/world/worldTypes';
import { Group } from '../../../../../types/world/worldTypes';
function PointsCalculator(
type: string,

View File

@ -0,0 +1,12 @@
import React from 'react'
import PointsCreator from './creator/pointsCreator'
function Points() {
return (
<>
<PointsCreator />
</>
)
}
export default Points

View File

@ -0,0 +1,10 @@
import React from 'react'
function MachineInstance() {
return (
<>
</>
)
}
export default MachineInstance

View File

@ -0,0 +1,14 @@
import React from 'react'
import MachineInstance from './machineInstance/machineInstance'
function MachineInstances() {
return (
<>
<MachineInstance />
</>
)
}
export default MachineInstances

View File

@ -0,0 +1,14 @@
import React from 'react'
import MachineInstances from './instances/machineInstances'
function Machine() {
return (
<>
<MachineInstances />
</>
)
}
export default Machine

View File

@ -0,0 +1,9 @@
import React from 'react'
function MaterialAnimator() {
return (
<></>
)
}
export default MaterialAnimator

View File

@ -0,0 +1,9 @@
import React from 'react'
function MaterialInstance() {
return (
<></>
)
}
export default MaterialInstance

View File

@ -0,0 +1,17 @@
import React from 'react'
import MaterialInstance from './instance/materialInstance'
import MaterialAnimator from './animator/materialAnimator'
function MaterialInstances() {
return (
<>
<MaterialInstance />
<MaterialAnimator />
</>
)
}
export default MaterialInstances

View File

@ -0,0 +1,14 @@
import React from 'react'
import MaterialInstances from './instances/materialInstances'
function Materials() {
return (
<>
<MaterialInstances />
</>
)
}
export default Materials

View File

@ -0,0 +1,25 @@
import React, { useEffect } from 'react'
import { useProductStore } from '../../../store/simulation/useProductStore'
import * as THREE from 'three';
import { useSelectedProduct } from '../../../store/simulation/useSimulationStore';
function Products() {
const { products, addProduct } = useProductStore();
const { setSelectedProduct } = useSelectedProduct();
useEffect(() => {
if (products.length === 0) {
const id = THREE.MathUtils.generateUUID();
const name = 'Product 1';
addProduct(name, id);
setSelectedProduct(id, name);
}
}, [products])
return (
<>
</>
)
}
export default Products

View File

@ -0,0 +1,9 @@
import React from 'react'
function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase }: any) {
return (
<></>
)
}
export default RoboticArmAnimator;

View File

@ -0,0 +1,61 @@
import React, { useEffect, useState } from 'react'
import IKInstance from '../ikInstance/ikInstance';
import RoboticArmAnimator from '../animator/roboticArmAnimator';
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
function RoboticArmInstance({ armBot }: any) {
const { isPlaying } = usePlayButtonStore();
const [currentPhase, setCurrentPhase] = useState<(string)>("init");
// console.log('currentPhase: ', currentPhase);
const { armBots, addArmBot, addCurrentAction } = useArmBotStore();
useEffect(() => {
// console.log('isPlaying: ', isPlaying);
if (isPlaying) {
//Moving armBot from initial point to rest position.
if (armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") {
addCurrentAction(armBot.modelUuid, 'action-001');
setCurrentPhase("moving-to-rest");
}
//Waiting for trigger.
if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "moving-to-rest") {
setCurrentPhase("rest");
}
// Moving armBot from rest position to pick up point.
if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "rest") {
}
//Moving arm from start point to end point.
if (armBot?.isActive && armBot?.state == "running " && currentPhase == "rest-to-start ") {
}
//Moving arm from end point to idle.
if (armBot?.isActive && armBot?.state == "running" && currentPhase == "end-to-start") {
}
}
}, [currentPhase, armBot, isPlaying])
const HandleCallback = () => {
if (armBot.isActive && armBot.state == "idle" && currentPhase == "init") {
addCurrentAction('armbot-xyz-001', 'action-001');
}
}
return (
<>
<IKInstance />
<RoboticArmAnimator armUuid={armBot?.modelUuid} HandleCallback={HandleCallback} currentPhase={currentPhase} />
</>
)
}
export default RoboticArmInstance;

View File

@ -0,0 +1,9 @@
import React from 'react'
function IKInstance() {
return (
<></>
)
}
export default IKInstance;

View File

@ -0,0 +1,20 @@
import React from 'react'
import RoboticArmInstance from './armInstance/roboticArmInstance';
import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
function RoboticArmInstances() {
const { armBots } = useArmBotStore();
return (
<>
{armBots?.map((robot) => (
<RoboticArmInstance key={robot.modelUuid} armdetals={robot} />
))}
</>
)
}
export default RoboticArmInstances;

View File

@ -0,0 +1,103 @@
import { useEffect } from "react";
import RoboticArmInstances from "./instances/roboticArmInstances";
import { useArmBotStore } from "../../../store/simulation/useArmBotStore";
function RoboticArm() {
const { armBots, addArmBot, addCurrentAction } = useArmBotStore();
const armBotStatusSample: RoboticArmEventSchema[] = [
{
state: "idle",
// currentAction: {
// actionUuid: "action-001",
// actionName: "Pick Component",
// },
modelUuid: "armbot-xyz-001",
modelName: "ArmBot-X200",
position: [0, 0, 0],
rotation: [91.94347308985614, 0, 6.742905194869091],
type: "roboticArm",
speed: 1.5,
point: {
uuid: "point-123",
position: [0, 1.5, 0],
rotation: [0, 0, 0],
actions: [
{
actionUuid: "action-001",
actionName: "Pick Component",
actionType: "pickAndPlace",
process: {
startPoint: [1.2, 0.3, 0.5],
endPoint: [-0.8, 1.1, 0.7],
},
triggers: [
{
triggerUuid: "trigger-001",
triggerName: "Start Trigger",
triggerType: "onStart",
delay: 0,
triggeredAsset: {
triggeredModel: {
modelName: "Conveyor A1",
modelUuid: "conveyor-01",
},
triggeredPoint: {
pointName: "Start Point",
pointUuid: "conveyor-01-point-001",
},
triggeredAction: {
actionName: "Move Forward",
actionUuid: "conveyor-action-01",
},
},
},
{
triggerUuid: "trigger-002",
triggerName: "Complete Trigger",
triggerType: "onComplete",
delay: 0,
triggeredAsset: {
triggeredModel: {
modelName: "StaticMachine B2",
modelUuid: "machine-02",
},
triggeredPoint: {
pointName: "Receive Point",
pointUuid: "machine-02-point-001",
},
triggeredAction: {
actionName: "Process Part",
actionUuid: "machine-action-01",
},
},
},
],
},
],
},
},
];
useEffect(() => {
addArmBot('123', armBotStatusSample[0]);
// addCurrentAction('armbot-xyz-001', 'action-001');
}, []);
useEffect(() => {
// console.log('armBots: ', armBots);
}, [armBots]);
return (
<>
<RoboticArmInstances />
<></>
</>
);
}
export default RoboticArm;

View File

@ -2,13 +2,24 @@ import React, { useEffect } from 'react';
import { useEventsStore } from '../../store/simulation/useEventsStore';
import { useProductStore } from '../../store/simulation/useProductStore';
import Vehicles from './vehicle/vehicles';
import Points from './events/points/points';
import Conveyor from './conveyor/conveyor';
import RoboticArm from './roboticArm/roboticArm';
import Materials from './materials/materials';
import Machine from './machine/machine';
import StorageUnit from './storageUnit/storageUnit';
import Simulator from './simulator/simulator';
import Products from './products/products';
import Trigger from './triggers/trigger';
import useModuleStore from '../../store/useModuleStore';
function Simulation() {
const { activeModule } = useModuleStore();
const { events } = useEventsStore();
const { products } = useProductStore();
useEffect(() => {
console.log('events: ', events);
// console.log('events: ', events);
}, [events])
useEffect(() => {
@ -17,9 +28,37 @@ function Simulation() {
return (
<>
<Vehicles />
{activeModule === 'simulation' &&
<>
<Points />
<Products />
<Materials />
<Trigger />
<Conveyor />
<Vehicles />
<RoboticArm />
<Machine />
<StorageUnit />
<Simulator />
</>
}
</>
)
);
}
export default Simulation
export default Simulation;

View File

@ -0,0 +1,11 @@
import React from 'react'
function Simulator() {
return (
<>
</>
)
}
export default Simulator

View File

@ -0,0 +1,10 @@
import React from 'react'
function storageUnitInstance() {
return (
<>
</>
)
}
export default storageUnitInstance

View File

@ -0,0 +1,14 @@
import React from 'react'
import StorageUnitInstance from './storageUnitInstance/storageUnitInstance'
function StorageUnitInstances() {
return (
<>
<StorageUnitInstance />
</>
)
}
export default StorageUnitInstances

View File

@ -0,0 +1,14 @@
import React from 'react'
import StorageUnitInstances from './instances/storageUnitInstances'
function StorageUnit() {
return (
<>
<StorageUnitInstances />
</>
)
}
export default StorageUnit

View File

@ -0,0 +1,126 @@
import { useThree } from '@react-three/fiber'
import React, { useEffect } from 'react'
import { Object3D } from 'three';
import { useSubModuleStore } from '../../../../store/useModuleStore';
import { useLeftData, useTopData } from '../../../../store/visualization/useZone3DWidgetStore';
import { useEventsStore } from '../../../../store/simulation/useEventsStore';
import { useProductStore } from '../../../../store/simulation/useProductStore';
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
function TriggerConnector() {
const { gl, raycaster, scene } = useThree();
const { subModule } = useSubModuleStore();
const { setTop } = useTopData();
const { setLeft } = useLeftData();
const { getIsEventInProduct } = useProductStore();
const { getEventByModelUuid } = useEventsStore();
const { selectedProduct } = useSelectedProduct();
const { selectedAsset, setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
useEffect(() => {
const canvasElement = gl.domElement;
let drag = false;
let isRightMouseDown = false;
const onMouseDown = (evt: MouseEvent) => {
if (selectedAsset) {
clearSelectedAsset();
}
if (evt.button === 2) {
isRightMouseDown = true;
drag = false;
}
};
const onMouseUp = (evt: MouseEvent) => {
if (evt.button === 2) {
isRightMouseDown = false;
}
}
const onMouseMove = () => {
if (isRightMouseDown) {
drag = true;
}
};
const handleRightClick = (evt: MouseEvent) => {
if (drag) return;
evt.preventDefault();
const canvasElement = gl.domElement;
if (!canvasElement) return;
let intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
let currentObject = intersects[0].object;
while (currentObject) {
if (currentObject.name === "Scene") {
break;
}
currentObject = currentObject.parent as Object3D;
}
if (currentObject) {
const isInProduct = getIsEventInProduct(selectedProduct.productId, currentObject.uuid);
if (isInProduct) {
const event = getEventByModelUuid(currentObject.uuid);
if (event) {
setSelectedAsset(event)
const canvasRect = canvasElement.getBoundingClientRect();
const relativeX = evt.clientX - canvasRect.left;
const relativeY = evt.clientY - canvasRect.top;
setTop(relativeY);
setLeft(relativeX);
} else {
clearSelectedAsset()
}
} else {
const event = getEventByModelUuid(currentObject.uuid);
if (event) {
setSelectedAsset(event)
const canvasRect = canvasElement.getBoundingClientRect();
const relativeX = evt.clientX - canvasRect.left;
const relativeY = evt.clientY - canvasRect.top;
setTop(relativeY);
setLeft(relativeX);
} else {
clearSelectedAsset()
}
}
}
} else {
clearSelectedAsset()
}
};
if (subModule === 'simulations') {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
canvasElement.addEventListener('contextmenu', handleRightClick);
}
return () => {
canvasElement.removeEventListener("mousedown", onMouseDown);
canvasElement.removeEventListener("mouseup", onMouseUp);
canvasElement.removeEventListener("mousemove", onMouseMove);
canvasElement.removeEventListener('contextmenu', handleRightClick);
};
}, [gl, subModule, selectedProduct, selectedAsset]);
return (
<>
</>
)
}
export default TriggerConnector

View File

@ -0,0 +1,14 @@
import React from 'react'
import TriggerConnector from './connector/triggerConnector'
function Trigger() {
return (
<>
<TriggerConnector />
</>
)
}
export default Trigger

View File

@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react'
import { useFrame, useThree } from '@react-three/fiber';
import React, { useEffect, useRef, useState } from 'react';
import { useFloorItems } from '../../../../../store/store';
import * as THREE from 'three';
import { Line } from '@react-three/drei';
@ -15,7 +15,7 @@ interface VehicleAnimatorProps {
}
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail }: VehicleAnimatorProps) {
const { updateVehicleLoad, vehicles } = useVehicleStore();
const { decrementVehicleLoad, vehicles } = useVehicleStore();
const { isPaused } = usePauseButtonStore();
const { speed } = useAnimationPlaySpeed();
const { isReset } = useResetButtonStore();
@ -132,30 +132,23 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
const unLoadDuration = agvDetail.point.action.unLoadDuration;
const droppedMaterial = agvDetail.currentLoad;
fixedInterval = (unLoadDuration / droppedMaterial) * 1000;
if (!isPaused) {
step(droppedMaterial);
} else {
pausedTime = performance.now();
step(droppedMaterial);
}
startTime = performance.now();
step(droppedMaterial);
}
function step(droppedMaterial: number) {
if (!isPaused) {
const elapsedTime = performance.now() - startTime;
if (elapsedTime >= fixedInterval) {
console.log('fixedInterval: ', fixedInterval);
console.log('elapsedTime: ', elapsedTime);
let droppedMat = droppedMaterial - 1;
decrementVehicleLoad(agvDetail.modelUuid, 1);
if (droppedMat === 0) return;
startTime = performance.now();
const elapsedTime = performance.now() - startTime - pausedTime;
if (elapsedTime >= fixedInterval) {
let droppedMat = droppedMaterial - 1;
updateVehicleLoad(agvDetail.modelUuid, droppedMat);
if (droppedMat === 0) return;
startTime = performance.now();
pausedTime = 0;
requestAnimationFrame(() => step(droppedMat));
} else {
requestAnimationFrame(() => step(droppedMaterial));
}
requestAnimationFrame(() => step(droppedMat));
} else {
requestAnimationFrame(() => firstFrame);
requestAnimationFrame(() => step(droppedMaterial));
}
}

View File

@ -9,7 +9,7 @@ import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore
function VehicleInstance({ agvDetail }: any) {
const { navMesh } = useNavMesh();
const { isPlaying } = usePlayButtonStore();
const { vehicles, setVehicleActive, setVehicleState, updateVehicleLoad } = useVehicleStore();
const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore();
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
const [path, setPath] = useState<[number, number, number][]>([]);
@ -50,8 +50,9 @@ function VehicleInstance({ agvDetail }: any) {
agvDetail.state === 'idle' &&
currentPhase === 'picking'
) {
setTimeout(() => {
updateVehicleLoad(agvDetail.modelUuid, 2);
incrementVehicleLoad(agvDetail.modelUuid, 2);
}, 5000);
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) {

View File

@ -17,7 +17,7 @@ export default function PolygonGenerator({
useEffect(() => {
let allLines = arrayLinesToObject(lines.current);
const wallLines = allLines?.filter((line) => line?.type === "WallLine");
const aisleLines = allLines?.filter((line) => line?.type === "AisleLine");
const aisleLines = allLines?.filter((line) => line?.type === "AisleLine")
const wallPoints = wallLines
.map((pair) => pair?.line.map((vals) => vals.position))
@ -39,9 +39,10 @@ export default function PolygonGenerator({
);
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
renderWallGeometry(wallPoints);
if (polygons.features.length > 1) {
if (polygons.features.length > 0) {
polygons.features.forEach((feature) => {
if (feature.geometry.type === "Polygon") {

View File

@ -146,7 +146,7 @@ function Vehicles() {
useEffect(() => {
addVehicle('123', vehicleStatusSample[0]);
addVehicle('123', vehicleStatusSample[1]);
// addVehicle('123', vehicleStatusSample[1]);
// addVehicle('123', vehicleStatusSample[2]);
}, [])

View File

@ -125,7 +125,7 @@ const RealTimeVisulization: React.FC = () => {
{}
);
setZonesData(formattedData);
} catch (error) {}
} catch (error) { }
}
GetZoneData();
@ -362,6 +362,10 @@ const RealTimeVisulization: React.FC = () => {
"RotateY",
"Delete",
]}
onClick={(e) => {
setRightSelect(e);
setEditWidgetOptions(false);
}}
/>
)}

View File

@ -0,0 +1,26 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const addProductOrEventApi = async (body: any) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v2/UpsertProductOrEvent`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error("Failed to add product or event");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,26 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const deleteEventDataApi = async (body: any) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v2/EventDataDelete`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error("Failed to delete event data");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,25 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const deleteProductDataApi = async (productId: string, organization: string) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDataDelete?productId=${productId}&organization=${organization}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error("Failed to delete product data");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,25 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const getProductApi = async (productId: string, organization: string) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDatas?productId=${productId}&organization=${organization}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error("Failed to fetch product data");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,25 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const getAllProductsApi = async ( organization: string) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v2/AllProducts/${organization}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error("Failed to fetch all products data");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -7,7 +7,7 @@ export const getSelect2dZoneData = async (
) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v2/Zone/visualization/${ZoneId}?organization=${organization}`,
`${url_Backend_dwinzo}/api/v2/ZoneVisualization/${ZoneId}?organization=${organization}`,
{
method: "GET",
headers: {

View File

@ -1,17 +1,6 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
interface ArmBotStatus extends RoboticArmEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
currentAction?: {
actionUuid: string;
actionName: string;
};
}
interface ArmBotStore {
armBots: ArmBotStatus[];
@ -22,9 +11,14 @@ interface ArmBotStore {
updates: Partial<Omit<ArmBotStatus, 'modelUuid' | 'productId'>>
) => void;
startAction: (modelUuid: string, actionUuid: string) => void;
completeAction: (modelUuid: string) => void;
cancelAction: (modelUuid: string) => void;
addCurrentAction: (modelUuid: string, actionUuid: string) => void;
removeCurrentAction: (modelUuid: string) => void;
addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void;
removeAction: (modelUuid: string, actionUuid: string) => void;
updateStartPoint: (modelUuid: string, actionUuid: string, startPoint: [number, number, number] | null) => void;
updateEndPoint: (modelUuid: string, actionUuid: string, endPoint: [number, number, number] | null) => void;
setArmBotActive: (modelUuid: string, isActive: boolean) => void;
@ -71,7 +65,7 @@ export const useArmBotStore = create<ArmBotStore>()(
});
},
startAction: (modelUuid, actionUuid) => {
addCurrentAction: (modelUuid, actionUuid) => {
set((state) => {
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
if (armBot) {
@ -87,22 +81,54 @@ export const useArmBotStore = create<ArmBotStore>()(
});
},
completeAction: (modelUuid) => {
removeCurrentAction: (modelUuid) => {
set((state) => {
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
if (armBot && armBot.currentAction) {
if (armBot) {
armBot.currentAction = undefined;
armBot.isActive = false;
}
});
},
cancelAction: (modelUuid) => {
addAction: (modelUuid, action) => {
set((state) => {
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
if (armBot) {
armBot.currentAction = undefined;
armBot.isActive = false;
armBot.point.actions.push(action);
}
});
},
removeAction: (modelUuid, actionUuid) => {
set((state) => {
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
if (armBot) {
armBot.point.actions = armBot.point.actions.filter(a => a.actionUuid !== actionUuid);
}
});
},
updateStartPoint: (modelUuid, actionUuid, startPoint) => {
set((state) => {
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
if (armBot) {
const action = armBot.point.actions.find(a => a.actionUuid === actionUuid);
if (action) {
action.process.startPoint = startPoint;
}
}
});
},
updateEndPoint: (modelUuid, actionUuid, endPoint) => {
set((state) => {
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
if (armBot) {
const action = armBot.point.actions.find(a => a.actionUuid === actionUuid);
if (action) {
action.process.endPoint = endPoint;
}
}
});
},

View File

@ -1,13 +1,6 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
interface ConveyorStatus extends ConveyorEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
}
interface ConveyorStore {
conveyors: ConveyorStatus[];

View File

@ -1,13 +1,6 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
interface MachineStatus extends MachineEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
}
interface MachineStore {
machines: MachineStatus[];

View File

@ -0,0 +1,76 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
type MaterialsStore = {
materials: MaterialsSchema;
addMaterial: (material: MaterialSchema) => void;
removeMaterial: (materialId: string) => void;
updateMaterial: (materialId: string, updates: Partial<MaterialSchema>) => void;
setStartTime: (materialId: string, startTime: string) => void;
setEndTime: (materialId: string, endTime: string) => void;
setCost: (materialId: string, cost: number) => void;
setWeight: (materialId: string, weight: number) => void;
getMaterialById: (materialId: string) => MaterialSchema | undefined;
};
export const useMaterialStore = create<MaterialsStore>()(
immer((set, get) => ({
materials: [],
addMaterial: (material) => {
set((state) => {
state.materials.push(material);
});
},
removeMaterial: (materialId) => {
set((state) => {
state.materials = state.materials.filter(m => m.materialId !== materialId);
});
},
updateMaterial: (materialId, updates) => {
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
if (material) {
Object.assign(material, updates);
}
});
},
setStartTime: (materialId, startTime) => {
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
if (material) material.startTime = startTime;
});
},
setEndTime: (materialId, endTime) => {
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
if (material) material.endTime = endTime;
});
},
setCost: (materialId, cost) => {
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
if (material) material.cost = cost;
});
},
setWeight: (materialId, weight) => {
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
if (material) material.weight = weight;
});
},
getMaterialById: (materialId) => {
return get().materials.find(m => m.materialId === materialId);
},
}))
);

View File

@ -7,7 +7,7 @@ type ProductsStore = {
// Product-level actions
addProduct: (productName: string, productId: string) => void;
removeProduct: (productId: string) => void;
updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void;
updateProduct: (productId: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void;
// Event-level actions
addEvent: (productId: string, event: EventsSchema) => void;
@ -48,8 +48,18 @@ type ProductsStore = {
updates: Partial<TriggerSchema>
) => void;
// Renaming functions
renameProduct: (productId: string, newName: string) => void;
renameAction: (actionUuid: string, newName: string) => void;
renameTrigger: (triggerUuid: string, newName: string) => void;
// Helper functions
getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined;
getProductById: (productId: string) => { productName: string; productId: string; eventDatas: EventsSchema[] } | undefined;
getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | undefined;
getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
getActionByUuid: (productId: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
getTriggerByUuid: (productId: string, triggerUuid: string) => TriggerSchema | undefined;
getIsEventInProduct: (productId: string, modelUuid: string) => boolean;
};
export const useProductStore = create<ProductsStore>()(
@ -62,7 +72,7 @@ export const useProductStore = create<ProductsStore>()(
const newProduct = {
productName,
productId: productId,
eventsData: []
eventDatas: []
};
state.products.push(newProduct);
});
@ -88,7 +98,7 @@ export const useProductStore = create<ProductsStore>()(
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
product.eventsData.push(event);
product.eventDatas.push(event);
}
});
},
@ -97,7 +107,7 @@ export const useProductStore = create<ProductsStore>()(
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
product.eventsData = product.eventsData.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
}
});
},
@ -106,7 +116,7 @@ export const useProductStore = create<ProductsStore>()(
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event) {
Object.assign(event, updates);
}
@ -119,7 +129,7 @@ export const useProductStore = create<ProductsStore>()(
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
} else if (event && 'point' in event) {
@ -133,7 +143,7 @@ export const useProductStore = create<ProductsStore>()(
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
(event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
@ -147,7 +157,7 @@ export const useProductStore = create<ProductsStore>()(
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
if (point) {
@ -165,7 +175,7 @@ export const useProductStore = create<ProductsStore>()(
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
if (point) {
@ -185,7 +195,7 @@ export const useProductStore = create<ProductsStore>()(
removeAction: (actionUuid: string) => {
set((state) => {
for (const product of state.products) {
for (const event of product.eventsData) {
for (const event of product.eventDatas) {
if ('points' in event) {
// Handle ConveyorEventSchema
for (const point of (event as ConveyorEventSchema).points) {
@ -209,7 +219,7 @@ export const useProductStore = create<ProductsStore>()(
updateAction: (actionUuid, updates) => {
set((state) => {
for (const product of state.products) {
for (const event of product.eventsData) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
@ -239,7 +249,7 @@ export const useProductStore = create<ProductsStore>()(
addTrigger: (actionUuid, trigger) => {
set((state) => {
for (const product of state.products) {
for (const event of product.eventsData) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
@ -268,7 +278,7 @@ export const useProductStore = create<ProductsStore>()(
removeTrigger: (triggerUuid) => {
set((state) => {
for (const product of state.products) {
for (const event of product.eventsData) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && 'triggers' in point.action) {
@ -295,7 +305,7 @@ export const useProductStore = create<ProductsStore>()(
updateTrigger: (triggerUuid, updates) => {
set((state) => {
for (const product of state.products) {
for (const event of product.eventsData) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && 'triggers' in point.action) {
@ -331,9 +341,170 @@ export const useProductStore = create<ProductsStore>()(
});
},
// Renaming functions
renameProduct: (productId, newName) => {
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
product.productName = newName;
}
});
},
renameAction: (actionUuid, newName) => {
set((state) => {
for (const product of state.products) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
point.action.actionName = newName;
return;
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && point.action.actionUuid === actionUuid) {
point.action.actionName = newName;
return;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) {
action.actionName = newName;
return;
}
}
}
}
}
});
},
renameTrigger: (triggerUuid, newName) => {
set((state) => {
for (const product of state.products) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && 'triggers' in point.action) {
const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
if (trigger) {
trigger.triggerName = newName;
return;
}
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && 'triggers' in point.action) {
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) {
trigger.triggerName = newName;
return;
}
} else if ('actions' in point) {
for (const action of point.actions) {
if ('triggers' in action) {
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) {
trigger.triggerName = newName;
return;
}
}
}
}
}
}
}
});
},
// Helper functions
getProductById: (productId) => {
return get().products.find(p => p.productId === productId);
},
getEventByModelUuid: (productId, modelUuid) => {
const product = get().getProductById(productId);
if (!product) return undefined;
return product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
},
getPointByUuid: (productId, modelUuid, pointUuid) => {
const event = get().getEventByModelUuid(productId, modelUuid);
if (!event) return undefined;
if ('points' in event) {
return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
} else if ('point' in event && (event as any).point.uuid === pointUuid) {
return (event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point;
}
return undefined;
},
getActionByUuid: (productId, actionUuid) => {
const product = get().products.find(p => p.productId === productId);
if (!product) return undefined;
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action?.actionUuid === actionUuid) {
return point.action;
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && point.action?.actionUuid === actionUuid) {
return point.action;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) return action;
}
}
}
return undefined;
},
getTriggerByUuid: (productId, triggerUuid) => {
const product = get().products.find(p => p.productId === productId);
if (!product) return undefined;
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
for (const trigger of point.action?.triggers || []) {
if (trigger.triggerUuid === triggerUuid) {
return trigger;
}
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point) {
for (const trigger of point.action?.triggers || []) {
if (trigger.triggerUuid === triggerUuid) {
return trigger;
}
}
} else if ('actions' in point) {
for (const action of point.actions) {
for (const trigger of action.triggers || []) {
if (trigger.triggerUuid === triggerUuid) {
return trigger;
}
}
}
}
}
}
return undefined;
},
getIsEventInProduct: (productId, modelUuid) => {
const product = get().getProductById(productId);
if (!product) return false;
return product.eventDatas.some(e => 'modelUuid' in e && e.modelUuid === modelUuid);
}
}))
);

View File

@ -0,0 +1,117 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import * as THREE from 'three';
interface SelectedEventSphereState {
selectedEventSphere: THREE.Mesh | null;
setSelectedEventSphere: (mesh: THREE.Mesh | null) => void;
clearSelectedEventSphere: () => void;
}
export const useSelectedEventSphere = create<SelectedEventSphereState>()(
immer((set) => ({
selectedEventSphere: null,
setSelectedEventSphere: (mesh) => {
set((state) => {
state.selectedEventSphere = mesh;
});
},
clearSelectedEventSphere: () => {
set((state) => {
state.selectedEventSphere = null;
});
},
}))
);
interface SelectedEventDataState {
selectedEventData: { data: EventsSchema; selectedPoint: string } | undefined;
setSelectedEventData: (data: EventsSchema, selectedPoint: string) => void;
clearSelectedEventData: () => void;
}
export const useSelectedEventData = create<SelectedEventDataState>()(
immer((set) => ({
selectedEventData: undefined,
setSelectedEventData: (data, selectedPoint) => {
set((state) => {
state.selectedEventData = { data, selectedPoint };
});
},
clearSelectedEventData: () => {
set((state) => {
state.selectedEventData = undefined;
});
},
}))
);
interface SelectedAssetState {
selectedAsset: EventsSchema | undefined;
setSelectedAsset: (EventData: EventsSchema) => void;
clearSelectedAsset: () => void;
}
export const useSelectedAsset = create<SelectedAssetState>()(
immer((set) => ({
selectedAsset: undefined,
setSelectedAsset: (EventData) => {
set((state) => {
state.selectedAsset = EventData;
});
},
clearSelectedAsset: () => {
set((state) => {
state.selectedAsset = undefined;
});
},
}))
);
interface SelectedProductState {
selectedProduct: { productId: string; productName: string };
setSelectedProduct: (productId: string, productName: string) => void;
clearSelectedProduct: () => void;
}
export const useSelectedProduct = create<SelectedProductState>()(
immer((set) => ({
selectedProduct: { productId: '', productName: '' },
setSelectedProduct: (productId, productName) => {
set((state) => {
state.selectedProduct.productId = productId;
state.selectedProduct.productName = productName;
});
},
clearSelectedProduct: () => {
set((state) => {
state.selectedProduct.productId = '';
state.selectedProduct.productName = '';
});
},
}))
);
interface SelectedActionState {
selectedAction: { actionId: string; actionName: string };
setSelectedAction: (actionId: string, actionName: string) => void;
clearSelectedAction: () => void;
}
export const useSelectedAction = create<SelectedActionState>()(
immer((set) => ({
selectedAction: { actionId: '', actionName: '' },
setSelectedAction: (actionId, actionName) => {
set((state) => {
state.selectedAction.actionId = actionId;
state.selectedAction.actionName = actionName;
});
},
clearSelectedAction: () => {
set((state) => {
state.selectedAction.actionId = '';
state.selectedAction.actionName = '';
});
},
}))
);

View File

@ -1,14 +1,6 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
interface StorageUnitStatus extends StorageEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
currentLoad: number;
}
interface StorageUnitStore {
storageUnits: StorageUnitStatus[];

View File

@ -21,7 +21,8 @@ interface VehiclesStore {
) => void;
setVehicleActive: (modelUuid: string, isActive: boolean) => void;
updateVehicleLoad: (modelUuid: string, load: number) => void;
incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void;
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
@ -74,11 +75,20 @@ export const useVehicleStore = create<VehiclesStore>()(
});
},
updateVehicleLoad: (modelUuid, load) => {
incrementVehicleLoad: (modelUuid, incrementBy) => {
set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
if (vehicle) {
vehicle.currentLoad = load;
vehicle.currentLoad += incrementBy;
}
});
},
decrementVehicleLoad: (modelUuid, decrementBy) => {
set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
if (vehicle) {
vehicle.currentLoad -= decrementBy;
}
});
},

View File

@ -13,14 +13,17 @@ const useModuleStore = create<ModuleStore>((set) => ({
export default useModuleStore;
// New store for subModule
type SubModule = 'properties' | 'simulations' | 'mechanics' | 'analysis' | 'zoneProperties';
interface SubModuleStore {
subModule: string;
setSubModule: (subModule: string) => void;
subModule: SubModule;
setSubModule: (subModule: SubModule) => void;
}
const useSubModuleStore = create<SubModuleStore>((set) => ({
subModule: "properties", // Initial subModule state
setSubModule: (subModule) => set({ subModule }), // Update subModule state
setSubModule: (value) => set({ subModule: value }), // Update subModule state
}));
export { useSubModuleStore };

View File

@ -7,8 +7,8 @@ input {
width: 100%;
padding: 2px 4px;
border-radius: #{$border-radius-small};
outline: 2px solid var(--border-color);
outline-offset: -2px;
outline: 1px solid var(--border-color);
outline-offset: -1px;
border: none;
background: transparent;
color: var(--input-text-color);
@ -30,6 +30,24 @@ input {
background-color: var(--background-color) !important;
-webkit-box-shadow: 0 0 0px 1000px var(--background-color) inset !important;
}
// File input specific style adjustments
&::file-selector-button {
font-size: 14px;
color: var(--accent-color);
background-color: var(--background-color-secondary);
border: none;
outline: none;
border-radius: #{$border-radius-small};
padding: 2px;
cursor: pointer;
// Hover effect for the file button
&:hover {
color: var(--primary-color);
background-color: var(--accent-color);
}
}
}
.input-value {
@ -712,3 +730,47 @@ input {
border: 1px solid var(--accent-color);
}
}
.preview-selection-with-upload-wrapper {
.input-header-container {
padding: 6px 12px;
@include flex-space-between;
.arrow-container {
transition: all 0.2s;
@include flex-center;
}
}
.upload-custom-asset-button{
padding: 6px 12px;
@include flex-space-between;
.title{
white-space: nowrap;
width: 40%;
}
input{
display: none;
}
.upload-button{
width: 60%;
background: var(--highlight-accent-color);
color: var(--accent-color);
padding: 3px 6px;
border-radius: #{$border-radius-small};
text-align: center;
}
}
.canvas-wrapper {
height: 150px;
width: 100%;
padding: 8px;
padding-right: 4px;
overflow: hidden;
position: relative;
.canvas-container {
width: 100%;
height: 100%;
border-radius: #{$border-radius-small};
background-color: var(--background-color-gray);
}
}
}

View File

@ -7,6 +7,7 @@
top: 32px;
left: 8px;
background-color: var(--background-color);
backdrop-filter: blur(150px);
border-radius: #{$border-radius-extra-large};
box-shadow: #{$box-shadow-medium};
z-index: #{$z-index-tools};
@ -131,15 +132,12 @@
}
.widgets-wrapper {
min-height: 50vh;
max-height: 60vh;
overflow: auto;
}
.widget-left-sideBar {
.widget2D {
overflow: auto;
@ -246,6 +244,7 @@
top: 32px;
right: 8px;
background-color: var(--background-color);
backdrop-filter: blur(150px);
border-radius: #{$border-radius-extra-large};
box-shadow: #{$box-shadow-medium};
z-index: #{$z-index-tools};
@ -643,7 +642,7 @@
path {
stroke: var(--accent-color);
strokewidth: 1.5px;
stroke-width: 1.5px;
}
&:hover {
@ -658,7 +657,8 @@
}
.machine-mechanics-content-container,
.simulations-container {
.simulations-container,
.event-proprties-wrapper {
max-height: calc(60vh - (47px - 35px));
overflow: auto;
overflow-y: scroll;
@ -682,6 +682,52 @@
}
}
.global-props {
.property-list-container {
.property-item {
.value-field-container {
margin: 0;
input {
padding: 5px 4px;
}
.dropdown {
top: 4px;
right: 4px;
}
}
}
}
}
.selected-actions-details {
.selected-actions-header .input-value {
padding: 8px 12px;
color: var(--accent-color);
}
.selected-actions-list {
margin-bottom: 8px;
.eye-dropper-input-container{
padding: 6px 12px;
.regularDropdown-container {
padding: 5px 8px;
outline: 2px solid var(--border-color);
outline-offset: -2px;
border: none;
}
}
.value-field-container {
margin: 0;
input {
padding: 5px 4px;
}
.dropdown {
top: 4px;
right: 4px;
}
}
}
}
.lists-main-container {
margin: 2px 8px;
width: calc(100% - 12px);
@ -712,6 +758,7 @@
input {
width: fit-content;
outline: none;
accent-color: var(--accent-color);
}
}
@ -1183,25 +1230,21 @@
z-index: 3;
padding: 8px;
width: 100%;
max-height: 38px;
font-size: var(--font-size-regular);
background: color-mix(in srgb,
var(--background-color) 40%,
transparent);
background: color-mix(
in srgb,
var(--background-color) 40%,
transparent
);
backdrop-filter: blur(5px);
opacity: 0;
transition: opacity 0.3s ease;
/* Added properties for ellipsis */
display: -webkit-box;
/* Necessary for multiline truncation */
-webkit-line-clamp: 2;
/* Number of lines to show */
-webkit-box-orient: vertical;
/* Box orientation for the ellipsis */
overflow: hidden;
/* Hide overflowing content */
text-overflow: ellipsis;
/* Add ellipsis for truncated content */
}
.asset-image {
@ -1271,4 +1314,4 @@
.assets-wrapper {
margin: 0;
}
}
}

View File

@ -25,7 +25,7 @@ interface ConveyorPointSchema {
action: {
actionUuid: string;
actionName: string;
actionType: "default" | "spawn" | "swap" | "despawn";
actionType: "default" | "spawn" | "swap" | "delay" | "despawn";
material: string;
delay: number | "inherit";
spawnInterval: number | "inherit";
@ -59,7 +59,7 @@ interface RoboticArmPointSchema {
actionUuid: string;
actionName: string;
actionType: "pickAndPlace";
process: { startPoint: string; endPoint: string };
process: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; };
triggers: TriggerSchema[];
}[];
}
@ -85,7 +85,7 @@ interface StoragePointSchema {
action: {
actionUuid: string;
actionName: string;
actionType: "storage";
actionType: "store";
materials: { materialName: string; materialId: string; }[];
storageCapacity: number;
};
@ -119,14 +119,43 @@ interface StorageEventSchema extends AssetEventSchema {
point: StoragePointSchema;
}
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema | [];
type PointsScheme = ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema;
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema;
type productsSchema = {
productName: string;
productId: string;
eventsData: EventsSchema[];
eventDatas: EventsSchema[];
}[]
interface ConveyorStatus extends ConveyorEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
}
interface MachineStatus extends MachineEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
}
interface ArmBotStatus extends RoboticArmEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
currentAction?: {
actionUuid: string;
actionName: string;
};
}
interface VehicleStatus extends VehicleEventSchema {
productId: string;
isActive: boolean;
@ -134,4 +163,25 @@ interface VehicleStatus extends VehicleEventSchema {
activeTime: number;
currentLoad: number;
distanceTraveled: number;
}
}
interface StorageUnitStatus extends StorageEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
currentLoad: number;
}
interface MaterialSchema {
materialId: string;
materialName: string;
materialType: string;
isActive: boolean;
startTime?: string;
endTime?: string;
cost?: number;
weight?: number;
}
type MaterialsSchema = MaterialSchema[];