Merge remote-tracking branch 'origin/v2' into v2-ui

This commit is contained in:
2025-04-30 16:53:54 +05:30
49 changed files with 3127 additions and 2003 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +1,5 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { import {
useSelectedAsset,
useSelectedEventData, useSelectedEventData,
useSelectedEventSphere, useSelectedEventSphere,
useSelectedProduct, useSelectedProduct,
@@ -13,19 +12,17 @@ import MachineMechanics from "./mechanics/machineMechanics";
import StorageMechanics from "./mechanics/storageMechanics"; import StorageMechanics from "./mechanics/storageMechanics";
import { AddIcon } from "../../../../icons/ExportCommonIcons"; import { AddIcon } from "../../../../icons/ExportCommonIcons";
import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
import { useEventsStore } from "../../../../../store/simulation/useEventsStore";
const EventProperties: React.FC = () => { const EventProperties: React.FC = () => {
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
const { getEventByModelUuid } = useProductStore(); const { getEventByModelUuid } = useProductStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>( const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(null);
null
);
const [assetType, setAssetType] = useState<string | null>(null); const [assetType, setAssetType] = useState<string | null>(null);
const { products, addEvent } = useProductStore(); const { products, addEvent } = useProductStore();
const { selectedEventSphere } = useSelectedEventSphere(); const { selectedEventSphere } = useSelectedEventSphere();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
useEffect(() => { useEffect(() => {
const event = getCurrentEventData(); const event = getCurrentEventData();
setCurrentEventData(event); setCurrentEventData(event);
@@ -81,7 +78,7 @@ const EventProperties: React.FC = () => {
</> </>
)} )}
{!currentEventData && selectedEventSphere && ( {!currentEventData && selectedEventSphere && (
<div className="no-event-selected section"> <div className="no-event-selected">
<p> <p>
<strong>Oops!</strong> It looks like this object doesn't have an <strong>Oops!</strong> It looks like this object doesn't have an
event assigned yet. To continue, please link it to one of the event assigned yet. To continue, please link it to one of the
@@ -92,33 +89,32 @@ const EventProperties: React.FC = () => {
<p> <p>
<strong>Here are some products you can add it to:</strong> <strong>Here are some products you can add it to:</strong>
</p> </p>
<div className="product-item"> <ul>
{products.map((product) => ( {products.map((product) => (
<div key={product.productId}> <li key={product.productId}>
<button <button
onClick={() => onClick={() => {
if (selectedEventData) {
handleAddEventToProduct({ handleAddEventToProduct({
selectedAsset, event: useEventsStore.getState().getEventByModelUuid(selectedEventData?.data.modelUuid),
addEvent, addEvent,
selectedProduct: { selectedProduct,
productId: product.productId,
productName: product.productName,
},
clearSelectedAsset,
}) })
} }
}}
> >
<AddIcon /> <AddIcon />
{product.productName} {product.productName}
</button> </button>
</div> </li>
))} ))}
</ul>
</div> </div>
</div> </div>
</div> )
)} }
{!selectedEventSphere && ( {!selectedEventSphere && (
<div className="no-event-selected section"> <div className="no-event-selected">
<p> <p>
<strong>Oops!</strong> It looks like you haven't selected an event <strong>Oops!</strong> It looks like you haven't selected an event
point yet. Please select an event to view its properties. point yet. Please select an event to view its properties.

View File

@@ -6,104 +6,44 @@ import {
} from "../../../../../icons/ExportCommonIcons"; } from "../../../../../icons/ExportCommonIcons";
import RenameInput from "../../../../../ui/inputs/RenameInput"; import RenameInput from "../../../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../../../functions/handleResizePannel"; import { handleResize } from "../../../../../../functions/handleResizePannel";
import { import { useSelectedAction, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
useSelectedAction,
useSelectedEventData,
useSelectedProduct,
} from "../../../../../../store/simulation/useSimulationStore";
import { MathUtils } from "three";
import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
interface ActionsListProps { interface ActionsListProps {
setSelectedPointData: (data: any) => void; // You can replace `any` with a more specific type if you have one selectedPointData: any;
selectedPointData: any; // You can replace `any` with a more specific type if you have one
// ui control props
multipleAction?: boolean; multipleAction?: boolean;
handleAddAction?: () => void;
handleDeleteAction?: (actionUuid: string) => void;
} }
const ActionsList: React.FC<ActionsListProps> = ({ const ActionsList: React.FC<ActionsListProps> = ({
setSelectedPointData,
selectedPointData, selectedPointData,
multipleAction = false, multipleAction = false,
handleAddAction,
handleDeleteAction,
}) => { }) => {
const actionsContainerRef = useRef<HTMLDivElement>(null); const actionsContainerRef = useRef<HTMLDivElement>(null);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
// store // store
const { selectedEventData } = useSelectedEventData(); const { renameAction } = useProductStore();
const { updateAction, addAction, removeAction } = useProductStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
const { selectedAction, setSelectedAction, clearSelectedAction } = const { selectedAction, setSelectedAction } = useSelectedAction();
useSelectedAction();
const handleAddAction = () => {
if (!selectedEventData || !selectedPointData) return;
const newAction = {
actionUuid: MathUtils.generateUUID(),
actionName: `Action ${selectedPointData.actions.length + 1}`,
actionType: "pickAndPlace" as const,
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: any) => 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) => { const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return; if (!selectedAction.actionId) return;
updateAction(selectedAction.actionId, { actionName: newName }); const event = renameAction(selectedAction.actionId, newName);
if (selectedPointData?.actions) { if (event) {
const updatedActions = selectedPointData.actions.map((action: any) => upsertProductOrEventApi({
action.actionUuid === selectedAction.actionId productName: selectedProduct.productName,
? { ...action, actionName: newName } productId: selectedProduct.productId,
: action organization: organization,
); eventDatas: event
setSelectedPointData({ })
...selectedPointData,
actions: updatedActions,
});
} else {
// write logic for single action
return;
} }
}; };
@@ -119,7 +59,11 @@ const ActionsList: React.FC<ActionsListProps> = ({
<button <button
className="add-button" className="add-button"
onClick={() => handleAddAction()} onClick={() => {
if (handleAddAction) {
handleAddAction();
}
}}
disabled={!multipleAction} disabled={!multipleAction}
> >
<AddIcon /> Add <AddIcon /> Add
@@ -131,12 +75,11 @@ const ActionsList: React.FC<ActionsListProps> = ({
style={{ height: "120px" }} style={{ height: "120px" }}
> >
<div className="list-container"> <div className="list-container">
{multipleAction && {multipleAction && selectedPointData &&
selectedPointData.actions.map((action: any) => ( selectedPointData.actions.map((action: any) => (
<div <div
key={action.actionUuid} key={action.actionUuid}
className={`list-item ${ className={`list-item ${selectedAction.actionId === action.actionUuid
selectedAction.actionId === action.actionUuid
? "active" ? "active"
: "" : ""
}`} }`}
@@ -149,13 +92,17 @@ const ActionsList: React.FC<ActionsListProps> = ({
> >
<RenameInput <RenameInput
value={action.actionName} value={action.actionName}
onRename={handleRenameAction} onRename={(value) => handleRenameAction(value)}
/> />
</button> </button>
{selectedPointData.actions.length > 1 && ( {selectedPointData.actions.length > 1 && (
<button <button
className="remove-button" className="remove-button"
onClick={() => handleDeleteAction(action.actionUuid)} onClick={() => {
if (handleDeleteAction) {
handleDeleteAction(action.actionUuid);
}
}}
> >
<RemoveIcon /> <RemoveIcon />
</button> </button>

View File

@@ -8,24 +8,21 @@ import SwapAction from "../actions/SwapAction";
import SpawnAction from "../actions/SpawnAction"; import SpawnAction from "../actions/SpawnAction";
import DefaultAction from "../actions/DefaultAction"; import DefaultAction from "../actions/DefaultAction";
import Trigger from "../trigger/Trigger"; import Trigger from "../trigger/Trigger";
import { import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
useSelectedEventData,
useSelectedProduct,
} from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ActionsList from "../components/ActionsList"; import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
function ConveyorMechanics() { function ConveyorMechanics() {
const [activeOption, setActiveOption] = useState< const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default");
"default" | "spawn" | "swap" | "delay" | "despawn" const [selectedPointData, setSelectedPointData] = useState<ConveyorPointSchema | undefined>();
>("default");
const [selectedPointData, setSelectedPointData] = useState<
ConveyorPointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
useEffect(() => { useEffect(() => {
if (selectedEventData) { if (selectedEventData) {
const point = getPointByUuid( const point = getPointByUuid(
@@ -35,69 +32,134 @@ function ConveyorMechanics() {
) as ConveyorPointSchema | undefined; ) as ConveyorPointSchema | undefined;
if (point && "action" in point) { if (point && "action" in point) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption( setActiveOption(point.action.actionType as | "default" | "spawn" | "swap" | "delay" | "despawn");
point.action.actionType as
| "default"
| "spawn"
| "swap"
| "delay"
| "despawn"
);
} }
} }
}, [selectedProduct, selectedEventData, getPointByUuid]); }, [selectedProduct, selectedEventData, getPointByUuid]);
const updateBackend = (
productName: string,
productId: string,
organization: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
const handleSpeedChange = (value: string) => { const handleSpeedChange = (value: string) => {
if (!selectedEventData) return; if (!selectedEventData) return;
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { const event = updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
speed: parseFloat(value), speed: parseFloat(value),
}); });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handleActionTypeChange = (option: string) => { const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
const validOption = option as const validOption = option as | "default" | "spawn" | "swap" | "delay" | "despawn";
| "default"
| "spawn"
| "swap"
| "delay"
| "despawn";
setActiveOption(validOption); setActiveOption(validOption);
updateAction(selectedPointData.action.actionUuid, { const event = updateAction(selectedPointData.action.actionUuid, {
actionType: validOption, actionType: validOption,
}); });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handleRenameAction = (newName: string) => { const handleRenameAction = (newName: string) => {
if (!selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, { actionName: newName }); const event = updateAction(selectedPointData.action.actionUuid, { actionName: newName });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handleSpawnCountChange = (value: string) => { const handleSpawnCountChange = (value: string) => {
if (!selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, { const event = updateAction(selectedPointData.action.actionUuid, {
spawnCount: value === "inherit" ? "inherit" : parseFloat(value), spawnCount: value === "inherit" ? "inherit" : parseFloat(value),
}); });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handleSpawnIntervalChange = (value: string) => { const handleSpawnIntervalChange = (value: string) => {
if (!selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, { const event = updateAction(selectedPointData.action.actionUuid, {
spawnInterval: value === "inherit" ? "inherit" : parseFloat(value), spawnInterval: value === "inherit" ? "inherit" : parseFloat(value),
}); });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handleMaterialSelect = (material: string) => { const handleMaterialSelect = (material: string) => {
if (!selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, { material }); const event = updateAction(selectedPointData.action.actionUuid, { material });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handleDelayChange = (value: string) => { const handleDelayChange = (value: string) => {
if (!selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, { const event = updateAction(selectedPointData.action.actionUuid, {
delay: value === "inherit" ? "inherit" : parseFloat(value), delay: value === "inherit" ? "inherit" : parseFloat(value),
}); });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const availableActions = { const availableActions = {
@@ -106,10 +168,9 @@ function ConveyorMechanics() {
}; };
// Get current values from store // Get current values from store
const currentSpeed = const currentSpeed = (getEventByModelUuid(
selectedEventData?.data.type === "transfer" selectedProduct.productId, selectedEventData?.data.modelUuid || ""
? selectedEventData.data.speed.toString() ) as ConveyorEventSchema | undefined)?.speed?.toString() || "0.5";
: "0.5";
const currentActionName = selectedPointData const currentActionName = selectedPointData
? selectedPointData.action.actionName ? selectedPointData.action.actionName
@@ -132,8 +193,6 @@ function ConveyorMechanics() {
: "0"; : "0";
return ( return (
<>
{selectedEventData && (
<> <>
<div key={selectedPointData?.uuid} className="global-props section"> <div key={selectedPointData?.uuid} className="global-props section">
<div className="property-list-container"> <div className="property-list-container">
@@ -154,7 +213,6 @@ function ConveyorMechanics() {
</div> </div>
<section> <section>
<ActionsList <ActionsList
setSelectedPointData={setSelectedPointData}
selectedPointData={selectedPointData} selectedPointData={selectedPointData}
/> />
@@ -217,8 +275,6 @@ function ConveyorMechanics() {
</div> </div>
</section> </section>
</> </>
)}
</>
); );
} }

View File

@@ -2,21 +2,14 @@ import { useEffect, useState } from "react";
import RenameInput from "../../../../../ui/inputs/RenameInput"; import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger"; import Trigger from "../trigger/Trigger";
import { import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
useSelectedEventData,
useSelectedProduct,
} from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ProcessAction from "../actions/ProcessAction"; import ProcessAction from "../actions/ProcessAction";
import ActionsList from "../components/ActionsList"; import ActionsList from "../components/ActionsList";
function MachineMechanics() { function MachineMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "process">( const [activeOption, setActiveOption] = useState<"default" | "process">("default");
"default" const [selectedPointData, setSelectedPointData] = useState<MachinePointSchema | undefined>();
);
const [selectedPointData, setSelectedPointData] = useState<
MachinePointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateAction } = useProductStore(); const { getPointByUuid, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
@@ -94,7 +87,6 @@ function MachineMechanics() {
/> />
</div> </div>
<ActionsList <ActionsList
setSelectedPointData={setSelectedPointData}
selectedPointData={selectedPointData} selectedPointData={selectedPointData}
/> />
<div className="selected-actions-list"> <div className="selected-actions-list">

View File

@@ -1,29 +1,25 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { MathUtils } from "three";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import RenameInput from "../../../../../ui/inputs/RenameInput"; import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger"; import Trigger from "../trigger/Trigger";
import { import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
useSelectedEventData,
useSelectedProduct,
useSelectedAction,
} from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import PickAndPlaceAction from "../actions/PickAndPlaceAction"; import PickAndPlaceAction from "../actions/PickAndPlaceAction";
import ActionsList from "../components/ActionsList"; import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
function RoboticArmMechanics() { function RoboticArmMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">( const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default");
"default" const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>();
);
const [selectedPointData, setSelectedPointData] = useState<
RoboticArmPointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
const { selectedAction, setSelectedAction, clearSelectedAction } = const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
useSelectedAction();
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
useEffect(() => { useEffect(() => {
if (selectedEventData) { if (selectedEventData) {
@@ -34,9 +30,7 @@ function RoboticArmMechanics() {
) as RoboticArmPointSchema | undefined; ) as RoboticArmPointSchema | undefined;
if (point?.actions) { if (point?.actions) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption( setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace");
point.actions[0].actionType as "default" | "pickAndPlace"
);
if (point.actions.length > 0 && !selectedAction.actionId) { if (point.actions.length > 0 && !selectedAction.actionId) {
setSelectedAction( setSelectedAction(
point.actions[0].actionUuid, point.actions[0].actionUuid,
@@ -47,67 +41,174 @@ function RoboticArmMechanics() {
} else { } else {
clearSelectedAction(); clearSelectedAction();
} }
}, [ }, [clearSelectedAction, getPointByUuid, selectedAction.actionId, selectedEventData, selectedProduct, setSelectedAction,]);
clearSelectedAction,
getPointByUuid, const updateBackend = (
selectedAction.actionId, productName: string,
selectedEventData, productId: string,
selectedProduct, organization: string,
setSelectedAction, eventData: EventsSchema
]); ) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
const handleRenameAction = (newName: string) => { const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return; if (!selectedAction.actionId) return;
updateAction(selectedAction.actionId, { actionName: newName }); const event = updateAction(selectedAction.actionId, { actionName: newName });
if (selectedPointData) { if (selectedPointData) {
const updatedActions = selectedPointData.actions.map((action) => const updatedActions = selectedPointData.actions.map((action) =>
action.actionUuid === selectedAction.actionId action.actionUuid === selectedAction.actionId ? { ...action, actionName: newName } : action
? { ...action, actionName: newName }
: action
); );
setSelectedPointData({ setSelectedPointData({
...selectedPointData, ...selectedPointData,
actions: updatedActions, actions: updatedActions,
}); });
} }
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handleSpeedChange = (value: string) => { const handleSpeedChange = (value: string) => {
if (!selectedEventData) return; if (!selectedEventData) return;
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { const event = updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
speed: parseFloat(value), speed: parseFloat(value),
}); });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handlePickPointChange = (value: string) => { const handlePickPointChange = (value: string) => {
if (!selectedAction.actionId || !selectedPointData) return; if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(",").map(Number); const [x, y, z] = value.split(",").map(Number);
updateAction(selectedAction.actionId, { const event = updateAction(selectedAction.actionId, {
process: { process: {
startPoint: [x, y, z] as [number, number, number], startPoint: [x, y, z] as [number, number, number],
endPoint: endPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.endPoint || null,
selectedPointData.actions.find(
(a) => a.actionUuid === selectedAction.actionId
)?.process.endPoint || null,
}, },
}); });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}; };
const handlePlacePointChange = (value: string) => { const handlePlacePointChange = (value: string) => {
if (!selectedAction.actionId || !selectedPointData) return; if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(",").map(Number); const [x, y, z] = value.split(",").map(Number);
updateAction(selectedAction.actionId, { const event = updateAction(selectedAction.actionId, {
process: { process: {
startPoint: startPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.startPoint || null,
selectedPointData.actions.find(
(a) => a.actionUuid === selectedAction.actionId
)?.process.startPoint || null,
endPoint: [x, y, z] as [number, number, number], endPoint: [x, y, z] as [number, number, number],
}, },
}); });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handleAddAction = () => {
if (!selectedEventData || !selectedPointData) return;
const newAction = {
actionUuid: MathUtils.generateUUID(),
actionName: `Action ${selectedPointData.actions.length + 1}`,
actionType: "pickAndPlace" as const,
process: {
startPoint: null,
endPoint: null,
},
triggers: [] as TriggerSchema[],
};
const event = addAction(
selectedProduct.productId,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint,
newAction
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
const updatedPoint = {
...selectedPointData,
actions: [...selectedPointData.actions, newAction],
};
setSelectedPointData(updatedPoint);
setSelectedAction(newAction.actionUuid, newAction.actionName);
};
const handleDeleteAction = (actionUuid: string) => {
if (!selectedPointData) return;
const event = removeAction(actionUuid);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
const newActions = selectedPointData.actions.filter(
(a: any) => 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 availableActions = { const availableActions = {
@@ -115,14 +216,12 @@ function RoboticArmMechanics() {
options: ["pickAndPlace"], options: ["pickAndPlace"],
}; };
const currentSpeed = const currentSpeed = (getEventByModelUuid(
selectedEventData?.data.type === "roboticArm" selectedProduct.productId, selectedEventData?.data.modelUuid || ""
? selectedEventData.data.speed.toString() ) as RoboticArmEventSchema | undefined)?.speed?.toString() || "0.5";
: "0.5";
const currentAction = selectedPointData?.actions.find((a) => a.actionUuid === selectedAction.actionId);
const currentAction = selectedPointData?.actions.find(
(a) => a.actionUuid === selectedAction.actionId
);
const currentPickPoint = currentAction?.process.startPoint const currentPickPoint = currentAction?.process.startPoint
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
: ""; : "";
@@ -131,8 +230,6 @@ function RoboticArmMechanics() {
: ""; : "";
return ( return (
<>
{selectedEventData && selectedPointData && (
<> <>
<div className="global-props section"> <div className="global-props section">
<div className="property-list-container"> <div className="property-list-container">
@@ -152,10 +249,12 @@ function RoboticArmMechanics() {
</div> </div>
</div> </div>
<section> <section>
<ActionsList <ActionsList
setSelectedPointData={setSelectedPointData}
selectedPointData={selectedPointData} selectedPointData={selectedPointData}
multipleAction multipleAction
handleAddAction={handleAddAction}
handleDeleteAction={handleDeleteAction}
/> />
{selectedAction.actionId && currentAction && ( {selectedAction.actionId && currentAction && (
@@ -187,8 +286,6 @@ function RoboticArmMechanics() {
)} )}
</section> </section>
</> </>
)}
</>
); );
} }

View File

@@ -2,21 +2,14 @@ import { useEffect, useState } from "react";
import RenameInput from "../../../../../ui/inputs/RenameInput"; import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger"; import Trigger from "../trigger/Trigger";
import { import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
useSelectedEventData,
useSelectedProduct,
} from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import StorageAction from "../actions/StorageAction"; import StorageAction from "../actions/StorageAction";
import ActionsList from "../components/ActionsList"; import ActionsList from "../components/ActionsList";
function StorageMechanics() { function StorageMechanics() {
const [activeOption, setActiveOption] = useState< const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default");
"default" | "store" | "spawn" const [selectedPointData, setSelectedPointData] = useState<StoragePointSchema | undefined>();
>("default");
const [selectedPointData, setSelectedPointData] = useState<
StoragePointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateAction } = useProductStore(); const { getPointByUuid, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
@@ -76,7 +69,6 @@ function StorageMechanics() {
{selectedEventData && ( {selectedEventData && (
<section> <section>
<ActionsList <ActionsList
setSelectedPointData={setSelectedPointData}
selectedPointData={selectedPointData} selectedPointData={selectedPointData}
/> />
<div className="selected-actions-details"> <div className="selected-actions-details">

View File

@@ -12,14 +12,10 @@ import TravelAction from "../actions/TravelAction";
import ActionsList from "../components/ActionsList"; import ActionsList from "../components/ActionsList";
function VehicleMechanics() { function VehicleMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "travel">( const [activeOption, setActiveOption] = useState<"default" | "travel">("default");
"default" const [selectedPointData, setSelectedPointData] = useState<VehiclePointSchema | undefined>();
);
const [selectedPointData, setSelectedPointData] = useState<
VehiclePointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
useEffect(() => { useEffect(() => {
@@ -82,10 +78,10 @@ function VehicleMechanics() {
}; };
// Get current values from store // Get current values from store
const currentSpeed =
selectedEventData?.data.type === "vehicle" const currentSpeed = (getEventByModelUuid(
? selectedEventData.data.speed.toString() selectedProduct.productId, selectedEventData?.data.modelUuid || ""
: "0.5"; ) as VehicleEventSchema | undefined)?.speed?.toString() || "0.5";
const currentActionName = selectedPointData const currentActionName = selectedPointData
? selectedPointData.action.actionName ? selectedPointData.action.actionName
@@ -131,7 +127,6 @@ function VehicleMechanics() {
</div> </div>
<section> <section>
<ActionsList <ActionsList
setSelectedPointData={setSelectedPointData}
selectedPointData={selectedPointData} selectedPointData={selectedPointData}
/> />
<div className="selected-actions-details"> <div className="selected-actions-details">

View File

@@ -15,8 +15,11 @@ import { useProductStore } from "../../../../store/simulation/useProductStore";
import { generateUUID } from "three/src/math/MathUtils"; import { generateUUID } from "three/src/math/MathUtils";
import RenderOverlay from "../../../templates/Overlay"; import RenderOverlay from "../../../templates/Overlay";
import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { deleteEventDataApi } from "../../../../services/simulation/deleteEventDataApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { deleteProductApi } from "../../../../services/simulation/deleteProductApi";
interface Event { interface Event {
pathName: string; pathName: string;
@@ -36,21 +39,19 @@ const List: React.FC<ListProps> = ({ val }) => {
const Simulations: React.FC = () => { const Simulations: React.FC = () => {
const productsContainerRef = useRef<HTMLDivElement>(null); const productsContainerRef = useRef<HTMLDivElement>(null);
const { const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent, } = useProductStore();
products,
addProduct,
removeProduct,
renameProduct,
addEvent,
removeEvent,
} = useProductStore();
const { selectedProduct, setSelectedProduct } = useSelectedProduct(); const { selectedProduct, setSelectedProduct } = useSelectedProduct();
const { getEventByModelUuid } = useEventsStore();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
const [openObjects, setOpenObjects] = useState(true); const [openObjects, setOpenObjects] = useState(true);
const handleAddProduct = () => { const handleAddProduct = () => {
addProduct(`Product ${products.length + 1}`, generateUUID()); const id = generateUUID();
const name = `Product ${products.length + 1}`;
addProduct(name, id);
upsertProductOrEventApi({ productName: name, productId: id, organization: organization });
}; };
const handleRemoveProduct = (productId: string) => { const handleRemoveProduct = (productId: string) => {
@@ -75,6 +76,7 @@ const Simulations: React.FC = () => {
} }
removeProduct(productId); removeProduct(productId);
deleteProductApi(productId, organization);
}; };
const handleRenameProduct = (productId: string, newName: string) => { const handleRenameProduct = (productId: string, newName: string) => {
@@ -86,6 +88,13 @@ const Simulations: React.FC = () => {
const handleRemoveEventFromProduct = () => { const handleRemoveEventFromProduct = () => {
if (selectedAsset) { if (selectedAsset) {
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
deleteEventDataApi({
productId: selectedProduct.productId,
modelUuid: selectedAsset.modelUuid,
organization: organization
});
removeEvent(selectedProduct.productId, selectedAsset.modelUuid); removeEvent(selectedProduct.productId, selectedAsset.modelUuid);
clearSelectedAsset(); clearSelectedAsset();
} }
@@ -95,8 +104,7 @@ const Simulations: React.FC = () => {
(product) => product.productId === selectedProduct.productId (product) => product.productId === selectedProduct.productId
); );
const events: Event[] = const events: Event[] = selectedProductData?.eventDatas.map((event) => ({
selectedProductData?.eventDatas.map((event) => ({
pathName: event.modelName, pathName: event.modelName,
})) || []; })) || [];
@@ -120,8 +128,7 @@ const Simulations: React.FC = () => {
{products.map((product, index) => ( {products.map((product, index) => (
<div <div
key={product.productId} key={product.productId}
className={`list-item ${ className={`list-item ${selectedProduct.productId === product.productId
selectedProduct.productId === product.productId
? "active" ? "active"
: "" : ""
}`} }`}
@@ -201,10 +208,10 @@ const Simulations: React.FC = () => {
onClick={(option) => { onClick={(option) => {
if (option === "Add to Product") { if (option === "Add to Product") {
handleAddEventToProduct({ handleAddEventToProduct({
selectedAsset, event: getEventByModelUuid(selectedAsset.modelUuid),
addEvent, addEvent,
selectedProduct, selectedProduct,
clearSelectedAsset, clearSelectedAsset
}); });
} else { } else {
handleRemoveEventFromProduct(); handleRemoveEventFromProduct();
@@ -214,7 +221,7 @@ const Simulations: React.FC = () => {
</RenderOverlay> </RenderOverlay>
)} )}
</div> </div>
); )
}; };
export default Simulations; export default Simulations;

View File

@@ -86,8 +86,8 @@ const DropDownList: React.FC<DropDownListProps> = ({
return isPointInsidePolygon([x, z], polygon2D as [number, number][]); return isPointInsidePolygon([x, z], polygon2D as [number, number][]);
}) })
.map((item: any) => ({ .map((item: any) => ({
id: item.modeluuid, id: item.modelUuid,
name: item.modelname, name: item.modelName,
position: item.position, position: item.position,
rotation: item.rotation, rotation: item.rotation,
})); }));

View File

@@ -135,8 +135,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
console.log("response: ", response); console.log("response: ", response);
setFloorItems((prevFloorItems: any[]) => setFloorItems((prevFloorItems: any[]) =>
prevFloorItems.map((floorItems) => prevFloorItems.map((floorItems) =>
floorItems.modeluuid === zoneAssetId.id floorItems.modelUuid === zoneAssetId.id
? { ...floorItems, modelname: response.modelname } ? { ...floorItems, modelName: response.modelName }
: floorItems : floorItems
) )
); );

View File

@@ -30,6 +30,7 @@ const SimulationPlayer: React.FC = () => {
// Button functions // Button functions
const handleReset = () => { const handleReset = () => {
setReset(true); setReset(true);
// setReset(!isReset);
setSpeed(1); setSpeed(1);
}; };
const handlePlayStop = () => { const handlePlayStop = () => {

View File

@@ -72,7 +72,7 @@ async function loadInitialFloorItems(
// Check Three.js Cache // Check Three.js Cache
const cachedModel = THREE.Cache.get(item.modelfileID!); const cachedModel = THREE.Cache.get(item.modelfileID!);
if (cachedModel) { if (cachedModel) {
// console.log(`[Cache] Fetching ${item.modelname}`); // console.log(`[Cache] Fetching ${item.modelName}`);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent); processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
modelsLoaded++; modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
@@ -82,7 +82,7 @@ async function loadInitialFloorItems(
// Check IndexedDB // Check IndexedDB
const indexedDBModel = await retrieveGLTF(item.modelfileID!); const indexedDBModel = await retrieveGLTF(item.modelfileID!);
if (indexedDBModel) { if (indexedDBModel) {
// console.log(`[IndexedDB] Fetching ${item.modelname}`); // console.log(`[IndexedDB] Fetching ${item.modelName}`);
const blobUrl = URL.createObjectURL(indexedDBModel); const blobUrl = URL.createObjectURL(indexedDBModel);
loader.load(blobUrl, (gltf) => { loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl); URL.revokeObjectURL(blobUrl);
@@ -94,7 +94,7 @@ async function loadInitialFloorItems(
}, },
undefined, undefined,
(error) => { (error) => {
toast.error(`[IndexedDB] Error loading ${item.modelname}:`); toast.error(`[IndexedDB] Error loading ${item.modelName}:`);
URL.revokeObjectURL(blobUrl); URL.revokeObjectURL(blobUrl);
resolve(); resolve();
} }
@@ -103,7 +103,7 @@ async function loadInitialFloorItems(
} }
// Fetch from Backend // Fetch from Backend
// console.log(`[Backend] Fetching ${item.modelname}`); // console.log(`[Backend] Fetching ${item.modelName}`);
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`;
loader.load(modelUrl, async (gltf) => { loader.load(modelUrl, async (gltf) => {
const modelBlob = await fetch(modelUrl).then((res) => res.blob()); const modelBlob = await fetch(modelUrl).then((res) => res.blob());
@@ -115,18 +115,18 @@ async function loadInitialFloorItems(
}, },
undefined, undefined,
(error) => { (error) => {
toast.error(`[Backend] Error loading ${item.modelname}:`); toast.error(`[Backend] Error loading ${item.modelName}:`);
resolve(); resolve();
} }
); );
}); });
} else { } else {
// console.log(`Item ${item.modelname} is not near`); // console.log(`Item ${item.modelName} is not near`);
setFloorItems((prevItems) => [ setFloorItems((prevItems) => [
...(prevItems || []), ...(prevItems || []),
{ {
modeluuid: item.modeluuid, modelUuid: item.modelUuid,
modelname: item.modelname, modelName: item.modelName,
position: item.position, position: item.position,
rotation: item.rotation, rotation: item.rotation,
modelfileID: item.modelfileID, modelfileID: item.modelfileID,
@@ -154,9 +154,9 @@ function processLoadedModel(
addEvent: (event: EventsSchema) => void, addEvent: (event: EventsSchema) => void,
) { ) {
const model = gltf.clone(); const model = gltf.clone();
model.uuid = item.modeluuid; model.uuid = item.modelUuid;
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid }; model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid, eventData: item.eventData };
model.position.set(...item.position); model.position.set(...item.position);
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
@@ -170,49 +170,43 @@ function processLoadedModel(
} }
}); });
itemsGroup?.current?.add(model); itemsGroup?.current?.add(model);
if (item.eventData) {
setFloorItems((prevItems) => [ setFloorItems((prevItems) => [
...(prevItems || []), ...(prevItems || []),
{ {
modeluuid: item.modeluuid, modelUuid: item.modelUuid,
modelname: item.modelname, modelName: item.modelName,
position: item.position, position: item.position,
rotation: item.rotation, rotation: item.rotation,
modelfileID: item.modelfileID, modelfileID: item.modelfileID,
isLocked: item.isLocked, isLocked: item.isLocked,
isVisible: item.isVisible, isVisible: item.isVisible,
eventData: item.eventData,
}, },
]); ]);
if (item.modelfileID === "a1ee92554935007b10b3eb05") { if (item.eventData.type === "vehicle") {
const data = PointsCalculator(
'Vehicle',
gltf.clone(),
new THREE.Vector3(...model.rotation)
);
if (!data || !data.points) return;
const vehicleEvent: VehicleEventSchema = { const vehicleEvent: VehicleEventSchema = {
modelUuid: item.modeluuid, modelUuid: item.modelUuid,
modelName: item.modelname, modelName: item.modelName,
position: item.position, position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z], rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle", state: "idle",
type: "vehicle", type: "vehicle",
speed: 1, speed: 1,
point: { point: {
uuid: THREE.MathUtils.generateUUID(), uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z], position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
rotation: [0, 0, 0], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
action: { action: {
actionUuid: THREE.MathUtils.generateUUID(), actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Vehicle Action", actionName: "Vehicle Action",
actionType: "travel", actionType: "travel",
unLoadDuration: 5, unLoadDuration: 5,
loadCapacity: 10, loadCapacity: 10,
steeringAngle:0,
pickUpPoint: null, pickUpPoint: null,
unLoadPoint: null, unLoadPoint: null,
triggers: [] triggers: []
@@ -220,27 +214,19 @@ function processLoadedModel(
} }
}; };
addEvent(vehicleEvent); addEvent(vehicleEvent);
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { } else if (item.eventData.type === "Conveyor") {
const data = PointsCalculator(
'Conveyor',
gltf.clone(),
new THREE.Vector3(...model.rotation)
);
if (!data || !data.points) return;
const ConveyorEvent: ConveyorEventSchema = { const ConveyorEvent: ConveyorEventSchema = {
modelUuid: item.modeluuid, modelUuid: item.modelUuid,
modelName: item.modelname, modelName: item.modelName,
position: item.position, position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z], rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle", state: "idle",
type: "transfer", type: "transfer",
speed: 1, speed: 1,
points: data.points.map((point: THREE.Vector3, index: number) => ({ points: item.eventData.points?.map((point: any, index: number) => ({
uuid: THREE.MathUtils.generateUUID(), uuid: point.uuid || THREE.MathUtils.generateUUID(),
position: [point.x, point.y, point.z], position: [point.position[0], point.position[1], point.position[2]],
rotation: [0, 0, 0], rotation: [point.rotation[0], point.rotation[1], point.rotation[2]],
action: { action: {
actionUuid: THREE.MathUtils.generateUUID(), actionUuid: THREE.MathUtils.generateUUID(),
actionName: `Action ${index + 1}`, actionName: `Action ${index + 1}`,
@@ -251,128 +237,21 @@ function processLoadedModel(
spawnCount: 1, spawnCount: 1,
triggers: [] triggers: []
} }
})) })) || [],
}; };
addEvent(ConveyorEvent); addEvent(ConveyorEvent);
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { } else if (item.eventData.type === "StaticMachine") {
// 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 = { const machineEvent: MachineEventSchema = {
modelUuid: item.modeluuid, modelUuid: item.modelUuid,
modelName: item.modelname, modelName: item.modelName,
position: item.position, position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z], rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle", state: "idle",
type: "machine", type: "machine",
point: { point: {
uuid: THREE.MathUtils.generateUUID(), uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z], position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
rotation: [0, 0, 0], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
action: { action: {
actionUuid: THREE.MathUtils.generateUUID(), actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Process Action", actionName: "Process Action",
@@ -384,27 +263,19 @@ function processLoadedModel(
} }
}; };
addEvent(machineEvent); addEvent(machineEvent);
} else if (item.modelfileID === "52e6681fbb743a890d96c914") { } else if (item.eventData.type === "ArmBot") {
const data = PointsCalculator(
'ArmBot',
gltf.clone(),
new THREE.Vector3(...model.rotation)
);
if (!data || !data.points) return;
const roboticArmEvent: RoboticArmEventSchema = { const roboticArmEvent: RoboticArmEventSchema = {
modelUuid: item.modeluuid, modelUuid: item.modelUuid,
modelName: item.modelname, modelName: item.modelName,
position: item.position, position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z], rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle", state: "idle",
type: "roboticArm", type: "roboticArm",
speed: 1, speed: 1,
point: { point: {
uuid: THREE.MathUtils.generateUUID(), uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z], position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
rotation: [0, 0, 0], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
actions: [ actions: [
{ {
actionUuid: THREE.MathUtils.generateUUID(), actionUuid: THREE.MathUtils.generateUUID(),
@@ -420,6 +291,21 @@ function processLoadedModel(
} }
}; };
addEvent(roboticArmEvent); addEvent(roboticArmEvent);
}
} else {
setFloorItems((prevItems) => [
...(prevItems || []),
{
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: item.rotation,
modelfileID: item.modelfileID,
isLocked: item.isLocked,
isVisible: item.isVisible,
},
]);
} }
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' }); gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });

View File

@@ -22,9 +22,9 @@ async function loadInitialWallItems(
const loadedWallItems = await Promise.all(storedWallItems.map(async (item) => { const loadedWallItems = await Promise.all(storedWallItems.map(async (item) => {
const loader = new GLTFLoader(); const loader = new GLTFLoader();
return new Promise<Types.WallItem>((resolve) => { return new Promise<Types.WallItem>((resolve) => {
loader.load(AssetConfigurations[item.modelname!].modelUrl, (gltf) => { loader.load(AssetConfigurations[item.modelName!].modelUrl, (gltf) => {
const model = gltf.scene; const model = gltf.scene;
model.uuid = item.modeluuid!; model.uuid = item.modelUuid!;
model.children[0].children.forEach((child: any) => { model.children[0].children.forEach((child: any) => {
if (child.name !== "CSG_REF") { if (child.name !== "CSG_REF") {
@@ -36,7 +36,7 @@ async function loadInitialWallItems(
resolve({ resolve({
type: item.type, type: item.type,
model: model, model: model,
modelname: item.modelname, modelName: item.modelName,
scale: item.scale, scale: item.scale,
csgscale: item.csgscale, csgscale: item.csgscale,
csgposition: item.csgposition, csgposition: item.csgposition,

View File

@@ -117,7 +117,7 @@ async function handleModelLoad(
socket: Socket<any> socket: Socket<any>
) { ) {
const model = gltf.scene.clone(); const model = gltf.scene.clone();
model.userData = { name: selectedItem.name, modelId: selectedItem.id, modeluuid: model.uuid }; model.userData = { name: selectedItem.name, modelId: selectedItem.id, modelUuid: model.uuid };
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z); model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
@@ -137,8 +137,8 @@ async function handleModelLoad(
} }
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.FloorItemType = {
modeluuid: model.uuid, modelUuid: model.uuid,
modelname: selectedItem.name, modelName: selectedItem.name,
modelfileID: selectedItem.id, modelfileID: selectedItem.id,
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
@@ -153,8 +153,8 @@ async function handleModelLoad(
// await setFloorItemApi( // await setFloorItemApi(
// organization, // organization,
// newFloorItem.modeluuid, // newFloorItem.modelUuid,
// newFloorItem.modelname, // newFloorItem.modelName,
// newFloorItem.modelfileID, // newFloorItem.modelfileID,
// newFloorItem.position, // newFloorItem.position,
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, // { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
@@ -164,18 +164,6 @@ async function handleModelLoad(
// SOCKET // SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id
};
if (selectedItem.type) { if (selectedItem.type) {
const data = PointsCalculator( const data = PointsCalculator(
selectedItem.type, selectedItem.type,
@@ -185,10 +173,14 @@ async function handleModelLoad(
if (!data || !data.points) return; if (!data || !data.points) return;
const eventData: any = {
type: selectedItem.type,
};
if (selectedItem.type === "Conveyor") { if (selectedItem.type === "Conveyor") {
const ConveyorEvent: ConveyorEventSchema = { const ConveyorEvent: ConveyorEventSchema = {
modelUuid: newFloorItem.modeluuid, modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelname, modelName: newFloorItem.modelName,
position: newFloorItem.position, position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle", state: "idle",
@@ -209,12 +201,18 @@ async function handleModelLoad(
triggers: [] triggers: []
} }
})) }))
} };
addEvent(ConveyorEvent); addEvent(ConveyorEvent);
eventData.points = ConveyorEvent.points.map(point => ({
uuid: point.uuid,
position: point.position,
rotation: point.rotation
}));
} else if (selectedItem.type === "Vehicle") { } else if (selectedItem.type === "Vehicle") {
const vehicleEvent: VehicleEventSchema = { const vehicleEvent: VehicleEventSchema = {
modelUuid: newFloorItem.modeluuid, modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelname, modelName: newFloorItem.modelName,
position: newFloorItem.position, position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle", state: "idle",
@@ -230,6 +228,7 @@ async function handleModelLoad(
actionType: "travel", actionType: "travel",
unLoadDuration: 5, unLoadDuration: 5,
loadCapacity: 10, loadCapacity: 10,
steeringAngle:0,
pickUpPoint: null, pickUpPoint: null,
unLoadPoint: null, unLoadPoint: null,
triggers: [] triggers: []
@@ -237,10 +236,16 @@ async function handleModelLoad(
} }
}; };
addEvent(vehicleEvent); addEvent(vehicleEvent);
eventData.point = {
uuid: vehicleEvent.point.uuid,
position: vehicleEvent.point.position,
rotation: vehicleEvent.point.rotation
};
} else if (selectedItem.type === "ArmBot") { } else if (selectedItem.type === "ArmBot") {
const roboticArmEvent: RoboticArmEventSchema = { const roboticArmEvent: RoboticArmEventSchema = {
modelUuid: newFloorItem.modeluuid, modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelname, modelName: newFloorItem.modelName,
position: newFloorItem.position, position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle", state: "idle",
@@ -265,10 +270,16 @@ async function handleModelLoad(
} }
}; };
addEvent(roboticArmEvent); addEvent(roboticArmEvent);
eventData.point = {
uuid: roboticArmEvent.point.uuid,
position: roboticArmEvent.point.position,
rotation: roboticArmEvent.point.rotation
};
} else if (selectedItem.type === "StaticMachine") { } else if (selectedItem.type === "StaticMachine") {
const machineEvent: MachineEventSchema = { const machineEvent: MachineEventSchema = {
modelUuid: newFloorItem.modeluuid, modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelname, modelName: newFloorItem.modelName,
position: newFloorItem.position, position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle", state: "idle",
@@ -288,8 +299,53 @@ async function handleModelLoad(
} }
}; };
addEvent(machineEvent); addEvent(machineEvent);
eventData.point = {
uuid: machineEvent.point.uuid,
position: machineEvent.point.position,
rotation: machineEvent.point.rotation
};
} }
}
const completeData = {
organization,
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
eventData: eventData
};
model.userData.eventData = eventData;
newFloorItem.eventData = eventData;
setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
socket.emit("v2:model-asset:add", completeData);
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
} else {
const data = {
organization,
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id
};
setFloorItems((prevItems) => { setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
@@ -302,5 +358,6 @@ async function handleModelLoad(
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
} }
}
export default addAssetModel; export default addAssetModel;

View File

@@ -58,7 +58,7 @@ export default async function assetManager(
// Check Three.js Cache // Check Three.js Cache
const cachedModel = THREE.Cache.get(item.modelfileID!); const cachedModel = THREE.Cache.get(item.modelfileID!);
if (cachedModel) { if (cachedModel) {
// console.log(`[Cache] Fetching ${item.modelname}`); // console.log(`[Cache] Fetching ${item.modelName}`);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve); processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve);
return; return;
} }
@@ -66,7 +66,7 @@ export default async function assetManager(
// Check IndexedDB // Check IndexedDB
const indexedDBModel = await retrieveGLTF(item.modelfileID!); const indexedDBModel = await retrieveGLTF(item.modelfileID!);
if (indexedDBModel) { if (indexedDBModel) {
// console.log(`[IndexedDB] Fetching ${item.modelname}`); // console.log(`[IndexedDB] Fetching ${item.modelName}`);
const blobUrl = URL.createObjectURL(indexedDBModel); const blobUrl = URL.createObjectURL(indexedDBModel);
loader.load( loader.load(
blobUrl, blobUrl,
@@ -78,7 +78,7 @@ export default async function assetManager(
}, },
undefined, undefined,
(error) => { (error) => {
toast.error(`[IndexedDB] Error loading ${item.modelname}:`); toast.error(`[IndexedDB] Error loading ${item.modelName}:`);
resolve(); resolve();
} }
); );
@@ -86,7 +86,7 @@ export default async function assetManager(
} }
// Fetch from Backend // Fetch from Backend
// console.log(`[Backend] Fetching ${item.modelname}`); // console.log(`[Backend] Fetching ${item.modelName}`);
loader.load( loader.load(
modelUrl, modelUrl,
async (gltf) => { async (gltf) => {
@@ -97,7 +97,7 @@ export default async function assetManager(
}, },
undefined, undefined,
(error) => { (error) => {
toast.error(`[Backend] Error loading ${item.modelname}:`); toast.error(`[Backend] Error loading ${item.modelName}:`);
resolve(); resolve();
} }
); );
@@ -112,16 +112,16 @@ export default async function assetManager(
) { ) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modeluuid); const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modelUuid);
if (existingModel) { if (existingModel) {
// console.log(`Model ${item.modelname} already exists in the scene.`); // console.log(`Model ${item.modelName} already exists in the scene.`);
resolve(); resolve();
return; return;
} }
const model = gltf; const model = gltf;
model.uuid = item.modeluuid; model.uuid = item.modelUuid;
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid }; model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid };
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.position.set(...item.position); model.position.set(...item.position);
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);

View File

@@ -5,6 +5,8 @@ import * as Types from "../../../../types/world/worldTypes";
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; // import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
import { getFloorAssets } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; import { getFloorAssets } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
async function DeleteFloorItems( async function DeleteFloorItems(
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
@@ -22,7 +24,7 @@ async function DeleteFloorItems(
const items = await getFloorAssets(organization); const items = await getFloorAssets(organization);
const removedItem = items.find( const removedItem = items.find(
(item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid (item: { modelUuid: string }) => item.modelUuid === hoveredDeletableFloorItem.current?.uuid
); );
if (!removedItem) { if (!removedItem) {
@@ -31,26 +33,29 @@ async function DeleteFloorItems(
//REST //REST
// const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname); // const response = await deleteFloorItem(organization, removedItem.modelUuid, removedItem.modelName);
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
modeluuid: removedItem.modeluuid, modelUuid: removedItem.modelUuid,
modelname: removedItem.modelname, modelName: removedItem.modelName,
socketId: socket.id socketId: socket.id
} }
const response = socket.emit('v2:model-asset:delete', data) const response = socket.emit('v2:model-asset:delete', data)
useEventsStore.getState().removeEvent(removedItem.modelUuid);
useProductStore.getState().deleteEvent(removedItem.modelUuid);
if (response) { if (response) {
const updatedItems = items.filter( const updatedItems = items.filter(
(item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid (item: { modelUuid: string }) => item.modelUuid !== hoveredDeletableFloorItem.current?.uuid
); );
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid); const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== hoveredDeletableFloorItem.current?.uuid);
localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
if (hoveredDeletableFloorItem.current) { if (hoveredDeletableFloorItem.current) {

View File

@@ -43,7 +43,7 @@ async function AddWallItems(
const newWallItem = { const newWallItem = {
type: config.type, type: config.type,
model: model, model: model,
modelname: selected, modelName: selected,
scale: config.scale, scale: config.scale,
csgscale: config.csgscale, csgscale: config.csgscale,
csgposition: config.csgposition, csgposition: config.csgposition,
@@ -59,7 +59,7 @@ async function AddWallItems(
// await setWallItem( // await setWallItem(
// organization, // organization,
// model.uuid, // model.uuid,
// newWallItem.modelname, // newWallItem.modelName,
// newWallItem.type!, // newWallItem.type!,
// newWallItem.csgposition!, // newWallItem.csgposition!,
// newWallItem.csgscale!, // newWallItem.csgscale!,
@@ -72,8 +72,8 @@ async function AddWallItems(
const data = { const data = {
organization: organization, organization: organization,
modeluuid: model.uuid, modelUuid: model.uuid,
modelname: newWallItem.modelname, modelName: newWallItem.modelName,
type: newWallItem.type!, type: newWallItem.type!,
csgposition: newWallItem.csgposition!, csgposition: newWallItem.csgposition!,
csgscale: newWallItem.csgscale!, csgscale: newWallItem.csgscale!,
@@ -92,7 +92,7 @@ async function AddWallItems(
const { model, ...rest } = item; const { model, ...rest } = item;
return { return {
...rest, ...rest,
modeluuid: model?.uuid, modelUuid: model?.uuid,
}; };
}); });

View File

@@ -28,14 +28,14 @@ function DeleteWallItems(
//REST //REST
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!) // await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelName!)
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
modeluuid: removedItem?.model?.uuid!, modelUuid: removedItem?.model?.uuid!,
modelname: removedItem?.modelname!, modelName: removedItem?.modelName!,
socketId: socket.id socketId: socket.id
} }
@@ -45,7 +45,7 @@ function DeleteWallItems(
const { model, ...rest } = item; const { model, ...rest } = item;
return { return {
...rest, ...rest,
modeluuid: model?.uuid, modelUuid: model?.uuid,
}; };
}); });

View File

@@ -91,7 +91,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
const { model, ...rest } = item; const { model, ...rest } = item;
return { return {
...rest, ...rest,
modeluuid: model?.uuid, modelUuid: model?.uuid,
}; };
}); });
@@ -110,7 +110,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
// await setWallItem( // await setWallItem(
// organization, // organization,
// currentItem?.model?.uuid, // currentItem?.model?.uuid,
// currentItem.modelname, // currentItem.modelName,
// currentItem.type!, // currentItem.type!,
// currentItem.csgposition!, // currentItem.csgposition!,
// currentItem.csgscale!, // currentItem.csgscale!,
@@ -123,8 +123,8 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
const data = { const data = {
organization: organization, organization: organization,
modeluuid: currentItem.model?.uuid!, modelUuid: currentItem.model?.uuid!,
modelname: currentItem.modelname!, modelName: currentItem.modelName!,
type: currentItem.type!, type: currentItem.type!,
csgposition: currentItem.csgposition!, csgposition: currentItem.csgposition!,
csgscale: currentItem.csgscale!, csgscale: currentItem.csgscale!,

View File

@@ -99,13 +99,13 @@ export default function SocketResponses({
try { try {
isTempLoader.current = true; isTempLoader.current = true;
const cachedModel = THREE.Cache.get(data.data.modelname); const cachedModel = THREE.Cache.get(data.data.modelName);
let url; let url;
if (cachedModel) { if (cachedModel) {
// console.log(`Getting ${data.data.modelname} from cache`); // console.log(`Getting ${data.data.modelName} from cache`);
const model = cachedModel.scene.clone(); const model = cachedModel.scene.clone();
model.uuid = data.data.modeluuid; model.uuid = data.data.modelUuid;
model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; model.userData = { name: data.data.modelName, modelId: data.data.modelfileID, modelUuid: data.data.modelUuid };
model.position.set(...data.data.position as [number, number, number]); model.position.set(...data.data.position as [number, number, number]);
model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
@@ -130,8 +130,8 @@ export default function SocketResponses({
} }
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.FloorItemType = {
modeluuid: data.data.modeluuid, modelUuid: data.data.modelUuid,
modelname: data.data.modelname, modelName: data.data.modelName,
modelfileID: data.data.modelfileID, modelfileID: data.data.modelfileID,
position: [...data.data.position as [number, number, number]], position: [...data.data.position as [number, number, number]],
rotation: { rotation: {
@@ -153,12 +153,12 @@ export default function SocketResponses({
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } });
} else { } else {
const indexedDBModel = await retrieveGLTF(data.data.modelname); const indexedDBModel = await retrieveGLTF(data.data.modelName);
if (indexedDBModel) { if (indexedDBModel) {
// console.log(`Getting ${data.data.modelname} from IndexedDB`); // console.log(`Getting ${data.data.modelName} from IndexedDB`);
url = URL.createObjectURL(indexedDBModel); url = URL.createObjectURL(indexedDBModel);
} else { } else {
// console.log(`Getting ${data.data.modelname} from Backend`); // console.log(`Getting ${data.data.modelName} from Backend`);
url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`; url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`;
const modelBlob = await fetch(url).then((res) => res.blob()); const modelBlob = await fetch(url).then((res) => res.blob());
await storeGLTF(data.data.modelfileID, modelBlob); await storeGLTF(data.data.modelfileID, modelBlob);
@@ -178,8 +178,8 @@ export default function SocketResponses({
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
THREE.Cache.remove(url); THREE.Cache.remove(url);
const model = gltf.scene; const model = gltf.scene;
model.uuid = data.data.modeluuid; model.uuid = data.data.modelUuid;
model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; model.userData = { name: data.data.modelName, modelId: data.data.modelfileID, modelUuid: data.data.modelUuid };
model.position.set(...data.data.position as [number, number, number]); model.position.set(...data.data.position as [number, number, number]);
model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
@@ -204,8 +204,8 @@ export default function SocketResponses({
} }
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.FloorItemType = {
modeluuid: data.data.modeluuid, modelUuid: data.data.modelUuid,
modelname: data.data.modelname, modelName: data.data.modelName,
modelfileID: data.data.modelfileID, modelfileID: data.data.modelfileID,
position: [...data.data.position as [number, number, number]], position: [...data.data.position as [number, number, number]],
rotation: { rotation: {
@@ -226,7 +226,7 @@ export default function SocketResponses({
gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' }); gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } });
THREE.Cache.add(data.data.modelname, gltf); THREE.Cache.add(data.data.modelName, gltf);
}, () => { }, () => {
TempLoader(new THREE.Vector3(...data.data.position), isTempLoader, tempLoader, itemsGroup); TempLoader(new THREE.Vector3(...data.data.position), isTempLoader, tempLoader, itemsGroup);
}); });
@@ -234,7 +234,7 @@ export default function SocketResponses({
} else if (data.message === "Model updated successfully") { } else if (data.message === "Model updated successfully") {
itemsGroup.current?.children.forEach((item: THREE.Group) => { itemsGroup.current?.children.forEach((item: THREE.Group) => {
if (item.uuid === data.data.modeluuid) { if (item.uuid === data.data.modelUuid) {
item.position.set(...data.data.position as [number, number, number]); item.position.set(...data.data.position as [number, number, number]);
item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
} }
@@ -246,7 +246,7 @@ export default function SocketResponses({
} }
let updatedItem: any = null; let updatedItem: any = null;
const updatedItems = prevItems.map((item) => { const updatedItems = prevItems.map((item) => {
if (item.modeluuid === data.data.modeluuid) { if (item.modelUuid === data.data.modelUuid) {
updatedItem = { updatedItem = {
...item, ...item,
position: [...data.data.position] as [number, number, number], position: [...data.data.position] as [number, number, number],
@@ -269,15 +269,15 @@ export default function SocketResponses({
return return
} }
if (data.message === "Model deleted successfully") { if (data.message === "Model deleted successfully") {
const deletedUUID = data.data.modeluuid; const deletedUUID = data.data.modelUuid;
let items = JSON.parse(localStorage.getItem("FloorItems")!); let items = JSON.parse(localStorage.getItem("FloorItems")!);
const updatedItems = items.filter( const updatedItems = items.filter(
(item: { modeluuid: string }) => item.modeluuid !== deletedUUID (item: { modelUuid: string }) => item.modelUuid !== deletedUUID
); );
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== deletedUUID); const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== deletedUUID);
localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
itemsGroup.current.children.forEach((item: any) => { itemsGroup.current.children.forEach((item: any) => {
@@ -519,7 +519,7 @@ export default function SocketResponses({
return return
} }
if (data.message === "wallitem deleted") { if (data.message === "wallitem deleted") {
const deletedUUID = data.data.modeluuid; const deletedUUID = data.data.modelUuid;
let WallItemsRef = wallItems; let WallItemsRef = wallItems;
const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID); const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID);
@@ -531,7 +531,7 @@ export default function SocketResponses({
const { model, ...rest } = item; const { model, ...rest } = item;
return { return {
...rest, ...rest,
modeluuid: model?.uuid, modelUuid: model?.uuid,
}; };
}); });
@@ -550,9 +550,9 @@ export default function SocketResponses({
} }
if (data.message === "wallIitem created") { if (data.message === "wallIitem created") {
const loader = new GLTFLoader(); const loader = new GLTFLoader();
loader.load(AssetConfigurations[data.data.modelname].modelUrl, async (gltf) => { loader.load(AssetConfigurations[data.data.modelName].modelUrl, async (gltf) => {
const model = gltf.scene; const model = gltf.scene;
model.uuid = data.data.modeluuid; model.uuid = data.data.modelUuid;
model.children[0].children.forEach((child) => { model.children[0].children.forEach((child) => {
if (child.name !== "CSG_REF") { if (child.name !== "CSG_REF") {
child.castShadow = true; child.castShadow = true;
@@ -563,7 +563,7 @@ export default function SocketResponses({
const newWallItem = { const newWallItem = {
type: data.data.type, type: data.data.type,
model: model, model: model,
modelname: data.data.modelname, modelName: data.data.modelName,
scale: data.data.scale, scale: data.data.scale,
csgscale: data.data.csgscale, csgscale: data.data.csgscale,
csgposition: data.data.csgposition, csgposition: data.data.csgposition,
@@ -578,7 +578,7 @@ export default function SocketResponses({
const { model, ...rest } = item; const { model, ...rest } = item;
return { return {
...rest, ...rest,
modeluuid: model?.uuid, modelUuid: model?.uuid,
}; };
}); });
@@ -589,7 +589,7 @@ export default function SocketResponses({
}); });
}); });
} else if (data.message === "wallIitem updated") { } else if (data.message === "wallIitem updated") {
const updatedUUID = data.data.modeluuid; const updatedUUID = data.data.modelUuid;
setWallItems((prevItems: any) => { setWallItems((prevItems: any) => {
const updatedItems = prevItems.map((item: any) => { const updatedItems = prevItems.map((item: any) => {
@@ -610,7 +610,7 @@ export default function SocketResponses({
const { model, ...rest } = item; const { model, ...rest } = item;
return { return {
...rest, ...rest,
modeluuid: model?.uuid, modelUuid: model?.uuid,
}; };
}); });

View File

@@ -6,6 +6,7 @@ import { toast } from "react-toastify";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, selectionGroup, setDuplicatedObjects, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => { const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, selectionGroup, setDuplicatedObjects, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { camera, controls, gl, scene, pointer, raycaster } = useThree();
@@ -13,7 +14,8 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { floorItems, setFloorItems } = useFloorItems(); const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore() const { socket } = useSocketStore();
const { addEvent } = useEventsStore();
useEffect(() => { useEffect(() => {
if (!camera || !scene || toggleView) return; if (!camera || !scene || toggleView) return;
@@ -138,15 +140,158 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
if (itemsGroupRef.current) { if (itemsGroupRef.current) {
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.FloorItemType = {
modeluuid: obj.uuid, modelUuid: obj.uuid,
modelname: obj.userData.name, modelName: obj.userData.name,
modelfileID: obj.userData.modelId, modelfileID: obj.userData.modelId,
position: [worldPosition.x, worldPosition.y, worldPosition.z], position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
isLocked: false, isLocked: false,
isVisible: true isVisible: true,
}; };
let updatedEventData = null;
if (obj.userData.eventData) {
updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData));
updatedEventData.modelUuid = newFloorItem.modelUuid;
const eventData: any = {
type: obj.userData.eventData.type,
};
if (obj.userData.eventData.type === "Conveyor") {
const ConveyorEvent: ConveyorEventSchema = {
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle",
type: 'transfer',
speed: 1,
points: updatedEventData.points.map((point: any, index: number) => ({
uuid: THREE.MathUtils.generateUUID(),
position: [point.position[0], point.position[1], point.position[2]],
rotation: [point.rotation[0], point.rotation[1], point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: `Action ${index}`,
actionType: 'default',
material: 'Default Material',
delay: 0,
spawnInterval: 5,
spawnCount: 1,
triggers: []
}
}))
};
addEvent(ConveyorEvent);
eventData.points = ConveyorEvent.points.map(point => ({
uuid: point.uuid,
position: point.position,
rotation: point.rotation
}));
} else if (obj.userData.eventData.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: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "travel",
unLoadDuration: 5,
loadCapacity: 10,
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
triggers: []
}
}
};
addEvent(vehicleEvent);
eventData.point = {
uuid: vehicleEvent.point.uuid,
position: vehicleEvent.point.position,
rotation: vehicleEvent.point.rotation
};
} else if (obj.userData.eventData.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: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "pickAndPlace",
process: {
startPoint: null,
endPoint: null
},
triggers: []
}
]
}
};
addEvent(roboticArmEvent);
eventData.point = {
uuid: roboticArmEvent.point.uuid,
position: roboticArmEvent.point.position,
rotation: roboticArmEvent.point.rotation
};
} else if (obj.userData.eventData.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: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "process",
processTime: 10,
swapMaterial: "Default Material",
triggers: []
}
}
};
addEvent(machineEvent);
eventData.point = {
uuid: machineEvent.point.uuid,
position: machineEvent.point.position,
rotation: machineEvent.point.rotation
};
}
obj.userData.eventData = eventData;
newFloorItem.eventData = eventData;
setFloorItems((prevItems: Types.FloorItems) => { setFloorItems((prevItems: Types.FloorItems) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@@ -173,8 +318,56 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
const data = { const data = {
organization, organization,
modeluuid: newFloorItem.modeluuid, modelUuid: newFloorItem.modelUuid,
modelname: newFloorItem.modelname, modelName: newFloorItem.modelName,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
eventData: eventData,
};
socket.emit("v2:model-asset:add", data);
obj.userData = {
name: newFloorItem.modelName,
modelId: newFloorItem.modelfileID,
modelUuid: newFloorItem.modelUuid,
};
itemsGroupRef.current.add(obj);
} else {
setFloorItems((prevItems: Types.FloorItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
//SOCKET
const data = {
organization,
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
modelfileID: newFloorItem.modelfileID, modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position, position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
@@ -185,9 +378,15 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
obj.userData.modeluuid = newFloorItem.modeluuid; obj.userData = {
name: newFloorItem.modelName,
modelId: newFloorItem.modelfileID,
modelUuid: newFloorItem.modelUuid,
};
itemsGroupRef.current.add(obj); itemsGroupRef.current.add(obj);
} }
}
}); });
toast.success("Object added!"); toast.success("Object added!");
@@ -205,7 +404,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
setSelectedAssets([]); setSelectedAssets([]);
} }
return null; // No visible output, but the component handles copy-paste functionality return null;
}; };
export default CopyPasteControls; export default CopyPasteControls;

View File

@@ -7,6 +7,7 @@ import { toast } from "react-toastify";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => { const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { camera, controls, gl, scene, pointer, raycaster } = useThree();
@@ -15,6 +16,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { floorItems, setFloorItems } = useFloorItems(); const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const { addEvent } = useEventsStore();
useEffect(() => { useEffect(() => {
if (!camera || !scene || toggleView) return; if (!camera || !scene || toggleView) return;
@@ -116,15 +118,158 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
if (itemsGroupRef.current) { if (itemsGroupRef.current) {
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.FloorItemType = {
modeluuid: obj.uuid, modelUuid: obj.uuid,
modelname: obj.userData.name, modelName: obj.userData.name,
modelfileID: obj.userData.modelId, modelfileID: obj.userData.modelId,
position: [worldPosition.x, worldPosition.y, worldPosition.z], position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
isLocked: false, isLocked: false,
isVisible: true isVisible: true,
}; };
let updatedEventData = null;
if (obj.userData.eventData) {
updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData));
updatedEventData.modelUuid = newFloorItem.modelUuid;
const eventData: any = {
type: obj.userData.eventData.type,
};
if (obj.userData.eventData.type === "Conveyor") {
const ConveyorEvent: ConveyorEventSchema = {
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
position: newFloorItem.position,
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
state: "idle",
type: 'transfer',
speed: 1,
points: updatedEventData.points.map((point: any, index: number) => ({
uuid: THREE.MathUtils.generateUUID(),
position: [point.position[0], point.position[1], point.position[2]],
rotation: [point.rotation[0], point.rotation[1], point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: `Action ${index}`,
actionType: 'default',
material: 'Default Material',
delay: 0,
spawnInterval: 5,
spawnCount: 1,
triggers: []
}
}))
};
addEvent(ConveyorEvent);
eventData.points = ConveyorEvent.points.map(point => ({
uuid: point.uuid,
position: point.position,
rotation: point.rotation
}));
} else if (obj.userData.eventData.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: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "travel",
unLoadDuration: 5,
loadCapacity: 10,
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
triggers: []
}
}
};
addEvent(vehicleEvent);
eventData.point = {
uuid: vehicleEvent.point.uuid,
position: vehicleEvent.point.position,
rotation: vehicleEvent.point.rotation
};
} else if (obj.userData.eventData.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: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "pickAndPlace",
process: {
startPoint: null,
endPoint: null
},
triggers: []
}
]
}
};
addEvent(roboticArmEvent);
eventData.point = {
uuid: roboticArmEvent.point.uuid,
position: roboticArmEvent.point.position,
rotation: roboticArmEvent.point.rotation
};
} else if (obj.userData.eventData.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: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "process",
processTime: 10,
swapMaterial: "Default Material",
triggers: []
}
}
};
addEvent(machineEvent);
eventData.point = {
uuid: machineEvent.point.uuid,
position: machineEvent.point.position,
rotation: machineEvent.point.rotation
};
}
obj.userData.eventData = eventData;
newFloorItem.eventData = eventData;
setFloorItems((prevItems: Types.FloorItems) => { setFloorItems((prevItems: Types.FloorItems) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@@ -151,8 +296,56 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
const data = { const data = {
organization, organization,
modeluuid: newFloorItem.modeluuid, modelUuid: newFloorItem.modelUuid,
modelname: newFloorItem.modelname, modelName: newFloorItem.modelName,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
eventData: eventData,
};
socket.emit("v2:model-asset:add", data);
obj.userData = {
name: newFloorItem.modelName,
modelId: newFloorItem.modelfileID,
modelUuid: newFloorItem.modelUuid,
};
itemsGroupRef.current.add(obj);
} else {
setFloorItems((prevItems: Types.FloorItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
//SOCKET
const data = {
organization,
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
modelfileID: newFloorItem.modelfileID, modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position, position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
@@ -163,9 +356,15 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
obj.userData.modeluuid = newFloorItem.modeluuid; obj.userData = {
name: newFloorItem.modelName,
modelId: newFloorItem.modelfileID,
modelUuid: newFloorItem.modelUuid,
};
itemsGroupRef.current.add(obj); itemsGroupRef.current.add(obj);
} }
}
}); });
toast.success("Object duplicated!"); toast.success("Object duplicated!");
@@ -183,7 +382,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
setSelectedAssets([]); setSelectedAssets([]);
} }
return null; // This component does not render any UI return null;
}; };
export default DuplicationControls; export default DuplicationControls;

View File

@@ -1,11 +1,14 @@
import * as THREE from "three"; import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef } from "react";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store"; import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) { function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { camera, controls, gl, scene, pointer, raycaster } = useThree();
@@ -62,7 +65,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
if (keyCombination === "G") { if (keyCombination === "G") {
if (selectedAssets.length > 0) { if (selectedAssets.length > 0) {
moveAssets(); moveAssets();
itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid));
} }
} }
if (keyCombination === "ESCAPE") { if (keyCombination === "ESCAPE") {
@@ -148,7 +151,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
const moveAssets = () => { const moveAssets = () => {
const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid));
setFloorItems(updatedItems); setFloorItems(updatedItems);
setMovedObjects(selectedAssets); setMovedObjects(selectedAssets);
selectedAssets.forEach((asset: any) => { selectionGroup.current.attach(asset); }); selectedAssets.forEach((asset: any) => { selectionGroup.current.attach(asset); });
@@ -167,8 +170,8 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
if (itemsGroupRef.current) { if (itemsGroupRef.current) {
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.FloorItemType = {
modeluuid: obj.uuid, modelUuid: obj.uuid,
modelname: obj.userData.name, modelName: obj.userData.name,
modelfileID: obj.userData.modelId, modelfileID: obj.userData.modelId,
position: [worldPosition.x, worldPosition.y, worldPosition.z], position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
@@ -176,6 +179,24 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
isVisible: true isVisible: true
}; };
if (obj.userData.eventData) {
const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid);
const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid);
if (eventData) {
useEventsStore.getState().updateEvent(obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
})
}
if (productData) {
useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
})
}
}
setFloorItems((prevItems: Types.FloorItems) => { setFloorItems((prevItems: Types.FloorItems) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@@ -202,8 +223,8 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
const data = { const data = {
organization, organization,
modeluuid: newFloorItem.modeluuid, modelUuid: newFloorItem.modelUuid,
modelname: newFloorItem.modelname, modelName: newFloorItem.modelName,
modelfileID: newFloorItem.modelfileID, modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position, position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
@@ -234,7 +255,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
setSelectedAssets([]); setSelectedAssets([]);
} }
return null; // No need to return anything, as this component is used for its side effects return null;
} }
export default MoveControls export default MoveControls

View File

@@ -1,11 +1,13 @@
import * as THREE from "three"; import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef } from "react";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store"; import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) { function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { camera, controls, gl, scene, pointer, raycaster } = useThree();
@@ -62,7 +64,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
if (event.key.toLowerCase() === "r") { if (event.key.toLowerCase() === "r") {
if (selectedAssets.length > 0) { if (selectedAssets.length > 0) {
rotateAssets(); rotateAssets();
itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid));
} }
} }
if (event.key.toLowerCase() === "escape") { if (event.key.toLowerCase() === "escape") {
@@ -126,7 +128,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
}); });
const rotateAssets = () => { const rotateAssets = () => {
const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid));
setFloorItems(updatedItems); setFloorItems(updatedItems);
const box = new THREE.Box3(); const box = new THREE.Box3();
@@ -168,8 +170,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
if (itemsGroupRef.current) { if (itemsGroupRef.current) {
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.FloorItemType = {
modeluuid: obj.uuid, modelUuid: obj.uuid,
modelname: obj.userData.name, modelName: obj.userData.name,
modelfileID: obj.userData.modelId, modelfileID: obj.userData.modelId,
position: [worldPosition.x, worldPosition.y, worldPosition.z], position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
@@ -177,6 +179,24 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
isVisible: true isVisible: true
}; };
if (obj.userData.eventData) {
const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid);
const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid);
if (eventData) {
useEventsStore.getState().updateEvent(obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
})
}
if (productData) {
useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
})
}
}
setFloorItems((prevItems: Types.FloorItems) => { setFloorItems((prevItems: Types.FloorItems) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@@ -203,8 +223,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
const data = { const data = {
organization, organization,
modeluuid: newFloorItem.modeluuid, modelUuid: newFloorItem.modelUuid,
modelname: newFloorItem.modelname, modelName: newFloorItem.modelName,
modelfileID: newFloorItem.modelfileID, modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position, position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
@@ -235,7 +255,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
setSelectedAssets([]); setSelectedAssets([]);
} }
return null; // No need to return anything, as this component is used for its side effects return null;
} }
export default RotateControls export default RotateControls

View File

@@ -14,6 +14,8 @@ import CopyPasteControls from "./copyPasteControls";
import MoveControls from "./moveControls"; import MoveControls from "./moveControls";
import RotateControls from "./rotateControls"; import RotateControls from "./rotateControls";
import useModuleStore from "../../../../store/useModuleStore"; import useModuleStore from "../../../../store/useModuleStore";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
const SelectionControls: React.FC = () => { const SelectionControls: React.FC = () => {
const { camera, controls, gl, scene, pointer } = useThree(); const { camera, controls, gl, scene, pointer } = useThree();
@@ -206,7 +208,7 @@ const SelectionControls: React.FC = () => {
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || "[]"); const storedItems = JSON.parse(localStorage.getItem("FloorItems") || "[]");
const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid); const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid);
const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid)); const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid));
localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
selectedAssets.forEach((selectedMesh: THREE.Object3D) => { selectedAssets.forEach((selectedMesh: THREE.Object3D) => {
@@ -218,13 +220,16 @@ const SelectionControls: React.FC = () => {
const data = { const data = {
organization: organization, organization: organization,
modeluuid: selectedMesh.uuid, modelUuid: selectedMesh.uuid,
modelname: selectedMesh.userData.name, modelName: selectedMesh.userData.name,
socketId: socket.id, socketId: socket.id,
}; };
socket.emit("v2:model-asset:delete", data); socket.emit("v2:model-asset:delete", data);
useEventsStore.getState().removeEvent(selectedMesh.uuid);
useProductStore.getState().deleteEvent(selectedMesh.uuid);
selectedMesh.traverse((child: THREE.Object3D) => { selectedMesh.traverse((child: THREE.Object3D) => {
if (child instanceof THREE.Mesh) { if (child instanceof THREE.Mesh) {
if (child.geometry) child.geometry.dispose(); if (child.geometry) child.geometry.dispose();
@@ -243,7 +248,7 @@ const SelectionControls: React.FC = () => {
itemsGroupRef.current?.remove(selectedMesh); itemsGroupRef.current?.remove(selectedMesh);
}); });
const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid)); const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid));
setFloorItems(updatedItems); setFloorItems(updatedItems);
} }
toast.success("Selected models removed!"); toast.success("Selected models removed!");

View File

@@ -1,10 +1,13 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from "react";
import * as THREE from 'three'; import * as THREE from "three";
import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; import { useEventsStore } from "../../../../../store/simulation/useEventsStore";
import useModuleStore from '../../../../../store/useModuleStore'; import useModuleStore from "../../../../../store/useModuleStore";
import { TransformControls } from '@react-three/drei'; import { TransformControls } from "@react-three/drei";
import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore'; import {
useSelectedEventSphere,
useSelectedEventData,
} from "../../../../../store/simulation/useSimulationStore";
function PointsCreator() { function PointsCreator() {
const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore();
@@ -12,8 +15,8 @@ function PointsCreator() {
const transformRef = useRef<any>(null); const transformRef = useRef<any>(null);
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); const { selectedEventData, setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
useEffect(() => { useEffect(() => {
if (selectedEventSphere) { if (selectedEventSphere) {
@@ -47,37 +50,57 @@ function PointsCreator() {
}, [selectedEventSphere]); }, [selectedEventSphere]);
const updatePointToState = (selectedEventSphere: THREE.Mesh) => { const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))); let point = JSON.parse(
JSON.stringify(
getPointByUuid(
selectedEventSphere.userData.modelUuid,
selectedEventSphere.userData.pointUuid
)
)
);
if (point) { if (point) {
point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z]; point.position = [
updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point) selectedEventSphere.position.x,
} selectedEventSphere.position.y,
selectedEventSphere.position.z,
];
updatePoint(
selectedEventSphere.userData.modelUuid,
selectedEventSphere.userData.pointUuid,
point
);
} }
};
return ( return (
<> <>
{activeModule === 'simulation' && {activeModule === "simulation" && (
<> <>
<group name='EventPointsGroup' > <group name="EventPointsGroup">
{events.map((event, i) => { {events.map((event, i) => {
if (event.type === 'transfer') { if (event.type === "transfer") {
return ( return (
<group key={i} position={new THREE.Vector3(...event.position)}> <group key={i} position={[...event.position]} rotation={[...event.rotation]} >
{event.points.map((point, j) => ( {event.points.map((point, j) => (
<mesh <mesh
name='Event-Sphere' name="Event-Sphere"
uuid={point.uuid} uuid={point.uuid}
ref={(el) => (sphereRefs.current[point.uuid] = el!)} ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
setSelectedEventSphere(sphereRefs.current[point.uuid]); setSelectedEventSphere(
sphereRefs.current[point.uuid]
);
}} }}
onPointerMissed={() => { onPointerMissed={() => {
if (selectedEventData?.data.type !== 'vehicle') {
clearSelectedEventSphere(); clearSelectedEventSphere();
}
setTransformMode(null); setTransformMode(null);
}} }}
key={`${i}-${j}`} key={`${i}-${j}`}
position={new THREE.Vector3(...point.position)} position={new THREE.Vector3(...point.position)}
// rotation={new THREE.Euler(...point.rotation)}
userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }} userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }}
> >
<sphereGeometry args={[0.1, 16, 16]} /> <sphereGeometry args={[0.1, 16, 16]} />
@@ -86,22 +109,25 @@ function PointsCreator() {
))} ))}
</group> </group>
); );
} else if (event.type === 'vehicle') { } else if (event.type === "vehicle") {
return ( return (
<group key={i} position={new THREE.Vector3(...event.position)}> <group key={i} position={[...event.position]} rotation={[...event.rotation]} >
<mesh <mesh
name='Event-Sphere' name="Event-Sphere"
uuid={event.point.uuid} uuid={event.point.uuid}
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
setSelectedEventSphere(sphereRefs.current[event.point.uuid]); setSelectedEventSphere(
sphereRefs.current[event.point.uuid]
);
}} }}
onPointerMissed={() => { onPointerMissed={() => {
clearSelectedEventSphere(); clearSelectedEventSphere();
setTransformMode(null); setTransformMode(null);
}} }}
position={new THREE.Vector3(...event.point.position)} position={new THREE.Vector3(...event.point.position)}
// rotation={new THREE.Euler(...event.point.rotation)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
> >
<sphereGeometry args={[0.1, 16, 16]} /> <sphereGeometry args={[0.1, 16, 16]} />
@@ -109,22 +135,25 @@ function PointsCreator() {
</mesh> </mesh>
</group> </group>
); );
} else if (event.type === 'roboticArm') { } else if (event.type === "roboticArm") {
return ( return (
<group key={i} position={new THREE.Vector3(...event.position)}> <group key={i} position={[...event.position]} rotation={[...event.rotation]} >
<mesh <mesh
name='Event-Sphere' name="Event-Sphere"
uuid={event.point.uuid} uuid={event.point.uuid}
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
setSelectedEventSphere(sphereRefs.current[event.point.uuid]); setSelectedEventSphere(
sphereRefs.current[event.point.uuid]
);
}} }}
onPointerMissed={() => { onPointerMissed={() => {
clearSelectedEventSphere(); clearSelectedEventSphere();
setTransformMode(null); setTransformMode(null);
}} }}
position={new THREE.Vector3(...event.point.position)} position={new THREE.Vector3(...event.point.position)}
// rotation={new THREE.Euler(...event.point.rotation)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
> >
<sphereGeometry args={[0.1, 16, 16]} /> <sphereGeometry args={[0.1, 16, 16]} />
@@ -132,22 +161,25 @@ function PointsCreator() {
</mesh> </mesh>
</group> </group>
); );
} else if (event.type === 'machine') { } else if (event.type === "machine") {
return ( return (
<group key={i} position={new THREE.Vector3(...event.position)}> <group key={i} position={[...event.position]} rotation={[...event.rotation]} >
<mesh <mesh
name='Event-Sphere' name="Event-Sphere"
uuid={event.point.uuid} uuid={event.point.uuid}
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
setSelectedEventSphere(sphereRefs.current[event.point.uuid]); setSelectedEventSphere(
sphereRefs.current[event.point.uuid]
);
}} }}
onPointerMissed={() => { onPointerMissed={() => {
clearSelectedEventSphere(); clearSelectedEventSphere();
setTransformMode(null); setTransformMode(null);
}} }}
position={new THREE.Vector3(...event.point.position)} position={new THREE.Vector3(...event.point.position)}
// rotation={new THREE.Euler(...event.point.rotation)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
> >
<sphereGeometry args={[0.1, 16, 16]} /> <sphereGeometry args={[0.1, 16, 16]} />
@@ -160,11 +192,18 @@ function PointsCreator() {
} }
})} })}
</group> </group>
{(selectedEventSphere && transformMode) && {selectedEventSphere && transformMode && (
<TransformControls ref={transformRef} object={selectedEventSphere} mode={transformMode} onMouseUp={(e) => { updatePointToState(selectedEventSphere) }} /> <TransformControls
} ref={transformRef}
object={selectedEventSphere}
mode={transformMode}
onMouseUp={(e) => {
updatePointToState(selectedEventSphere);
}}
/>
)}
</> </>
} )}
</> </>
); );
} }

View File

@@ -1,28 +1,38 @@
import { upsertProductOrEventApi } from "../../../../../services/simulation/UpsertProductOrEventApi";
interface HandleAddEventToProductParams { interface HandleAddEventToProductParams {
selectedAsset: any; // Replace `any` with specific type if you have it event: EventsSchema | undefined;
addEvent: (productId: string, asset: any) => void; addEvent: (productId: string, event: EventsSchema) => void;
selectedProduct: { selectedProduct: {
productId: string; productId: string;
productName: string; productName: string;
// Add other fields if needed }
}; clearSelectedAsset?: () => void;
clearSelectedAsset: () => void;
} }
export const handleAddEventToProduct = ({ export const handleAddEventToProduct = ({
selectedAsset, event,
addEvent, addEvent,
selectedProduct, selectedProduct,
clearSelectedAsset, clearSelectedAsset
}: HandleAddEventToProductParams) => { }: HandleAddEventToProductParams) => {
console.log('selectedProduct: ', selectedProduct); if (event && selectedProduct.productId) {
if (selectedAsset) { addEvent(selectedProduct.productId, event);
addEvent(selectedProduct.productId, selectedAsset);
// upsertProductOrEventApi({ const email = localStorage.getItem('email')
// productName: selectedProduct.productName, const organization = (email!.split("@")[1]).split(".")[0];
// productId: selectedProduct.productId,
// eventDatas: selectedAsset upsertProductOrEventApi({
// }); productName: selectedProduct.productName,
productId: selectedProduct.productId,
organization: organization,
eventDatas: event
}).then((data) => {
// console.log(data);
})
if (clearSelectedAsset) {
clearSelectedAsset(); clearSelectedAsset();
} }
}
}; };

View File

@@ -7,28 +7,27 @@ import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProd
import { getAllProductsApi } from '../../../services/simulation/getallProductsApi'; import { getAllProductsApi } from '../../../services/simulation/getallProductsApi';
function Products() { function Products() {
const { products, addProduct } = useProductStore(); const { products, addProduct, setProducts } = useProductStore();
const { setSelectedProduct } = useSelectedProduct(); const { setSelectedProduct } = useSelectedProduct();
useEffect(() => { useEffect(() => {
if (products.length === 0) { const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
getAllProductsApi(organization).then((data) => {
if (data.length === 0) {
const id = THREE.MathUtils.generateUUID(); const id = THREE.MathUtils.generateUUID();
const name = 'Product 1'; const name = 'Product 1';
addProduct(name, id); addProduct(name, id);
// upsertProductOrEventApi({ productName: name, productId: id }).then((data) => { upsertProductOrEventApi({ productName: name, productId: id, organization: organization })
// console.log('data: ', data);
// });
setSelectedProduct(id, name); setSelectedProduct(id, name);
} else {
setProducts(data);
setSelectedProduct(data[0].productId, data[0].productName);
} }
}, [products]) })
}, [])
useEffect(() => { useEffect(() => {
// const email = localStorage.getItem('email')
// const organization = (email!.split("@")[1]).split(".")[0];
// console.log(organization);
// getAllProductsApi(organization).then((data) => {
// console.log('data: ', data);
// })
}, []) }, [])
return ( return (

View File

@@ -36,12 +36,12 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
useEffect(() => { useEffect(() => {
let armItems = floorItems?.filter((val: any) => let armItems = floorItems?.filter((val: any) =>
val.modeluuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" val.modelUuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d"
); );
// Get the first matching item // Get the first matching item
let armItem = armItems?.[0]; let armItem = armItems?.[0];
if (armItem) { if (armItem) {
const targetMesh = scene?.getObjectByProperty("uuid", armItem.modeluuid); const targetMesh = scene?.getObjectByProperty("uuid", armItem.modelUuid);
if (targetMesh) { if (targetMesh) {
targetMesh.visible = activeModule !== "simulation" targetMesh.visible = activeModule !== "simulation"
} }

View File

@@ -1,19 +1,85 @@
import { useEffect } from "react"; import { useEffect, useRef, useState } from "react";
import { useThree } from "@react-three/fiber"; import { useThree } from "@react-three/fiber";
import * as THREE from "three";
import { useSubModuleStore } from "../../../../store/useModuleStore"; import { useSubModuleStore } from "../../../../store/useModuleStore";
import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { handleAddEventToProduct } from "../../events/points/functions/handleAddEventToProduct";
interface ConnectionLine {
id: string;
start: THREE.Vector3;
end: THREE.Vector3;
mid: THREE.Vector3;
trigger: TriggerSchema;
}
function TriggerConnector() { function TriggerConnector() {
const { gl, raycaster, scene } = useThree(); const { gl, raycaster, scene } = useThree();
const { subModule } = useSubModuleStore(); const { subModule } = useSubModuleStore();
const { getPointByUuid, getIsEventInProduct } = useProductStore(); const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, addEvent, getEventByModelUuid } = useProductStore();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
useEffect(() => { const [firstSelectedPoint, setFirstSelectedPoint] = useState<{
productId: string;
modelUuid: string;
pointUuid: string;
actionUuid?: string;
} | null>(null);
const [connections, setConnections] = useState<ConnectionLine[]>([]);
useEffect(() => {
const newConnections: ConnectionLine[] = [];
products.forEach(product => {
product.eventDatas.forEach(event => {
if ('points' in event) {
event.points.forEach(point => {
if ('action' in point && point.action?.triggers) {
point.action.triggers.forEach(trigger => {
if (trigger.triggeredAsset) {
const targetPoint = getPointByUuid(
product.productId,
trigger.triggeredAsset.triggeredModel.modelUuid,
trigger.triggeredAsset.triggeredPoint.pointUuid
);
if (targetPoint) {
const startPos = new THREE.Vector3(...point.position);
const endPos = new THREE.Vector3(...targetPoint.position);
const midPos = new THREE.Vector3()
.addVectors(startPos, endPos)
.multiplyScalar(0.5)
.add(new THREE.Vector3(0, 2, 0));
newConnections.push({
id: `${point.uuid}-${targetPoint.uuid}-${trigger.triggerUuid}`,
start: startPos,
end: endPos,
mid: midPos,
trigger
});
}
}
});
}
});
}
});
});
setConnections(newConnections);
}, [products]);
useEffect(() => {
console.log('connections: ', connections);
}, connections)
useEffect(() => {
const canvasElement = gl.domElement; const canvasElement = gl.domElement;
let drag = false; let drag = false;
@@ -44,37 +110,114 @@ function TriggerConnector() {
const handleRightClick = (evt: MouseEvent) => { const handleRightClick = (evt: MouseEvent) => {
if (drag) return; if (drag) return;
evt.preventDefault(); evt.preventDefault();
const canvasElement = gl.domElement;
if (!canvasElement) return;
let intersects = raycaster.intersectObjects(scene.children, true); const 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) { if (intersects.length === 0) return;
let currentObject = intersects[0].object;
if (currentObject && currentObject.name === 'Event-Sphere') { const currentObject = intersects[0].object;
if (!currentObject || currentObject.name !== 'Event-Sphere') return;
const isInProduct = getIsEventInProduct( const modelUuid = currentObject.userData.modelUuid;
const pointUuid = currentObject.userData.pointUuid;
if (selectedProduct && getIsEventInProduct(selectedProduct.productId, modelUuid)) {
const point = getPointByUuid(
selectedProduct.productId, selectedProduct.productId,
currentObject.userData.modelUuid modelUuid,
pointUuid
); );
// You left Here if (!point) return;
if (isInProduct) { let actionUuid: string | undefined;
if ('action' in point && point.action) {
actionUuid = point.action.actionUuid;
} else if ('actions' in point && point.actions.length === 1) {
actionUuid = point.actions[0].actionUuid;
}
const event = getPointByUuid( if (!firstSelectedPoint) {
setFirstSelectedPoint({
productId: selectedProduct.productId,
modelUuid,
pointUuid,
actionUuid
});
} else {
const trigger: TriggerSchema = {
triggerUuid: THREE.MathUtils.generateUUID(),
triggerName: `Trigger ${firstSelectedPoint.pointUuid.slice(0, 4)}${pointUuid.slice(0, 4)}`,
triggerType: "onComplete",
delay: 0,
triggeredAsset: {
triggeredModel: {
modelName: currentObject.parent?.parent?.name || 'Unknown',
modelUuid: modelUuid
},
triggeredPoint: {
pointName: currentObject.name,
pointUuid: pointUuid
},
triggeredAction: actionUuid ? {
actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action',
actionUuid: actionUuid
} : null
}
};
if (firstSelectedPoint.actionUuid) {
addTrigger(firstSelectedPoint.actionUuid, trigger);
}
setFirstSelectedPoint(null);
}
} else if (!getIsEventInProduct(selectedProduct.productId, modelUuid) && firstSelectedPoint) {
handleAddEventToProduct({
event: useEventsStore.getState().getEventByModelUuid(modelUuid),
addEvent,
selectedProduct,
})
const point = getPointByUuid(
selectedProduct.productId, selectedProduct.productId,
currentObject.userData.modelUuid, modelUuid,
currentObject.userData.pointUuid pointUuid
); );
console.log('event: ', event);
} else {
} if (!point) return;
let actionUuid: string | undefined;
if ('action' in point && point.action) {
actionUuid = point.action.actionUuid;
} else if ('actions' in point && point.actions.length === 1) {
actionUuid = point.actions[0].actionUuid;
} }
} else { const trigger: TriggerSchema = {
triggerUuid: THREE.MathUtils.generateUUID(),
triggerName: `Trigger ${firstSelectedPoint.pointUuid.slice(0, 4)}${pointUuid.slice(0, 4)}`,
triggerType: "onComplete",
delay: 0,
triggeredAsset: {
triggeredModel: {
modelName: currentObject.parent?.parent?.name || 'Unknown',
modelUuid: modelUuid
},
triggeredPoint: {
pointName: currentObject.name,
pointUuid: pointUuid
},
triggeredAction: actionUuid ? {
actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action',
actionUuid: actionUuid
} : null
}
};
if (firstSelectedPoint.actionUuid) {
addTrigger(firstSelectedPoint.actionUuid, trigger);
}
setFirstSelectedPoint(null);
} }
}; };
@@ -92,12 +235,12 @@ function TriggerConnector() {
canvasElement.removeEventListener('contextmenu', handleRightClick); canvasElement.removeEventListener('contextmenu', handleRightClick);
}; };
}, [gl, subModule]); }, [gl, subModule, selectedProduct, firstSelectedPoint]);
return ( return (
<> <>
</> </>
) );
} }
export default TriggerConnector export default TriggerConnector;

View File

@@ -0,0 +1,131 @@
import { useRef } from "react";
import * as THREE from "three";
import { ThreeEvent, useThree } from "@react-three/fiber";
type OnUpdateCallback = (object: THREE.Object3D) => void;
export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
const { camera, gl, controls, scene } = useThree();
const activeObjRef = useRef<THREE.Object3D | null>(null);
const planeRef = useRef<THREE.Plane>(
new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)
);
const offsetRef = useRef<THREE.Vector3>(new THREE.Vector3());
const initialPositionRef = useRef<THREE.Vector3>(new THREE.Vector3());
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
const handlePointerDown = (e: ThreeEvent<PointerEvent>) => {
e.stopPropagation();
let obj: THREE.Object3D | null = e.object;
// Traverse up until we find modelUuid in userData
while (obj && !obj.userData?.modelUuid) {
obj = obj.parent;
}
if (!obj) return;
// Disable orbit controls while dragging
if (controls) (controls as any).enabled = false;
activeObjRef.current = obj;
initialPositionRef.current.copy(obj.position);
// Get world position
const objectWorldPos = new THREE.Vector3();
obj.getWorldPosition(objectWorldPos);
// Set plane at the object's Y level
planeRef.current.set(new THREE.Vector3(0, 1, 0), -objectWorldPos.y);
// Convert pointer to NDC
const rect = gl.domElement.getBoundingClientRect();
pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
// Raycast to intersection
raycaster.setFromCamera(pointer, camera);
const intersection = new THREE.Vector3();
raycaster.ray.intersectPlane(planeRef.current, intersection);
// Calculate offset
offsetRef.current.copy(objectWorldPos).sub(intersection);
// Start listening for drag
gl.domElement.addEventListener("pointermove", handlePointerMove);
gl.domElement.addEventListener("pointerup", handlePointerUp);
};
const handlePointerMove = (e: PointerEvent) => {
if (!activeObjRef.current) return;
// Check if Shift key is pressed
const isShiftKeyPressed = e.shiftKey;
// Get the mouse position relative to the canvas
const rect = gl.domElement.getBoundingClientRect();
pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
// Update raycaster to point to the mouse position
raycaster.setFromCamera(pointer, camera);
// Create a vector to store intersection point
const intersection = new THREE.Vector3();
const intersects = raycaster.ray.intersectPlane(planeRef.current, intersection);
if (!intersects) return;
// Add offset for dragging
intersection.add(offsetRef.current);
console.log('intersection: ', intersection);
// Get the parent's world matrix if exists
const parent = activeObjRef.current.parent;
const targetPosition = new THREE.Vector3();
if (isShiftKeyPressed) {
console.log('isShiftKeyPressed: ', isShiftKeyPressed);
// For Y-axis only movement, maintain original X and Z
console.log('initialPositionRef: ', initialPositionRef);
console.log('intersection.y: ', intersection);
targetPosition.set(
initialPositionRef.current.x,
intersection.y,
initialPositionRef.current.z
);
} else {
// For free movement
targetPosition.copy(intersection);
}
// Convert world position to local if object is nested inside a parent
if (parent) {
parent.worldToLocal(targetPosition);
}
// Update object position
activeObjRef.current.position.copy(targetPosition);
};
const handlePointerUp = () => {
if (controls) (controls as any).enabled = true;
if (activeObjRef.current) {
// Pass the updated position to the onUpdate callback to persist it
onUpdate(activeObjRef.current);
}
gl.domElement.removeEventListener("pointermove", handlePointerMove);
gl.domElement.removeEventListener("pointerup", handlePointerUp);
activeObjRef.current = null;
};
return { handlePointerDown };
}

View File

@@ -0,0 +1,243 @@
import React, { useEffect, useRef, useState } from 'react';
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
import * as THREE from "three";
import { useGLTF } from '@react-three/drei';
import { useFrame, useThree } from '@react-three/fiber';
import { useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore';
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
import * as Types from "../../../../types/world/worldTypes";
const VehicleUI = () => {
const { scene: startScene } = useGLTF(startPoint) as any;
const { scene: endScene } = useGLTF(startEnd) as any;
const startMarker = useRef<THREE.Group>(null);
const endMarker = useRef<THREE.Group>(null);
const prevMousePos = useRef({ x: 0, y: 0 });
const { selectedEventSphere } = useSelectedEventSphere();
const { vehicles, updateVehicle } = useVehicleStore();
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 0, 0]);
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 0]);
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
const [isDragging, setIsDragging] = useState<"start" | "end" | null>(null);
const [isRotating, setIsRotating] = useState<"start" | "end" | null>(null);
const { raycaster } = useThree();
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0));
const state: Types.ThreeState = useThree();
const controls: any = state.controls;
useEffect(() => {
if (!selectedEventSphere) return;
const selectedVehicle = vehicles.find(
(vehicle: any) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid
);
if (selectedVehicle?.point?.action) {
const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action;
if (pickUpPoint) {
const pickupPosition = new THREE.Vector3(
pickUpPoint.position.x,
pickUpPoint.position.y,
pickUpPoint.position.z
);
const pickupRotation = new THREE.Vector3(
pickUpPoint.rotation.x,
pickUpPoint.rotation.y,
pickUpPoint.rotation.z
);
pickupPosition.y = 0;
setStartPosition([pickupPosition.x, 0, pickupPosition.z]);
setStartRotation([pickupRotation.x, pickupRotation.y, pickupRotation.z]);
} else {
const defaultLocal = new THREE.Vector3(0, 0, 1.5);
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
defaultWorld.y = 0;
setStartPosition([defaultWorld.x, 0, defaultWorld.z]);
setStartRotation([0, 0, 0]);
}
if (unLoadPoint) {
const unLoadPosition = new THREE.Vector3(
unLoadPoint.position.x,
unLoadPoint.position.y,
unLoadPoint.position.z
);
const unLoadRotation = new THREE.Vector3(
unLoadPoint.rotation.x,
unLoadPoint.rotation.y,
unLoadPoint.position.z
);
unLoadPosition.y = 0; // Force y to 0
setEndPosition([unLoadPosition.x, 0, unLoadPosition.z]);
setEndRotation([unLoadRotation.x, unLoadRotation.y, unLoadRotation.z]);
} else {
const defaultLocal = new THREE.Vector3(0, 0, -1.5);
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
defaultWorld.y = 0; // Force y to 0
setEndPosition([defaultWorld.x, 0, defaultWorld.z]);
setEndRotation([0, 0, 0]);
}
}
}, [selectedEventSphere]);
useFrame(() => {
if (!isDragging) return;
const intersectPoint = new THREE.Vector3();
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
if (intersects) {
intersectPoint.y = 0; // Force y to 0
if (isDragging === "start") {
setStartPosition([intersectPoint.x, 0, intersectPoint.z]);
}
if (isDragging === "end") {
setEndPosition([intersectPoint.x, 0, intersectPoint.z]);
}
}
});
useFrame((state) => {
if (!isRotating) return;
const currentPointerX = state.pointer.x;
const deltaX = currentPointerX - prevMousePos.current.x;
prevMousePos.current.x = currentPointerX;
const marker = isRotating === "start" ? startMarker.current : endMarker.current;
if (marker) {
const rotationSpeed = 10;
marker.rotation.y += deltaX * rotationSpeed;
if (isRotating === 'start') {
setStartRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z])
} else {
setEndRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z])
}
}
});
const handlePointerDown = (e: any, state: "start" | "end", rotation: "start" | "end") => {
if (e.object.name === "handle") {
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1;
prevMousePos.current = { x: normalizedX, y: normalizedY };
setIsRotating(rotation);
if (controls) controls.enabled = false;
setIsDragging(null);
} else {
setIsDragging(state);
setIsRotating(null);
if (controls) controls.enabled = false;
}
};
const handlePointerUp = () => {
controls.enabled = true;
setIsDragging(null);
setIsRotating(null);
if (selectedEventSphere?.userData.modelUuid) {
const updatedVehicle = vehicles.find(
(vehicle) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid
);
if (updatedVehicle) {
updateVehicle(selectedEventSphere.userData.modelUuid, {
point: {
...updatedVehicle.point,
action: {
...updatedVehicle.point?.action,
pickUpPoint: {
position: {
x: startPosition[0],
y: startPosition[1],
z: startPosition[2],
},
rotation: {
x: startRotation[0],
y: startRotation[1],
z: startRotation[2],
},
},
unLoadPoint: {
position: {
x: endPosition[0],
y: endPosition[1],
z: endPosition[2],
},
rotation: {
x: endRotation[0],
y: endRotation[1],
z: endRotation[2],
},
},
},
},
});
}
}
};
useEffect(() => {
const handleGlobalPointerUp = () => {
setIsDragging(null);
setIsRotating(null);
if (controls) controls.enabled = true;
handlePointerUp();
};
if (isDragging || isRotating) {
window.addEventListener("pointerup", handleGlobalPointerUp);
}
return () => {
window.removeEventListener("pointerup", handleGlobalPointerUp);
};
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]);
return (
startPosition.length > 0 && endPosition.length > 0 ? (
<mesh>
<primitive
name="start"
object={startScene}
ref={startMarker}
position={startPosition}
onPointerDown={(e: any) => {
e.stopPropagation();
handlePointerDown(e, "start", "start");
}}
onPointerMissed={() => {
controls.enabled = true;
setIsDragging(null);
setIsRotating(null);
}}
/>
<primitive
name="end"
object={endScene}
ref={endMarker}
position={endPosition}
onPointerDown={(e: any) => {
e.stopPropagation();
handlePointerDown(e, "end", "end");
}}
onPointerMissed={() => {
controls.enabled = true;
setIsDragging(null);
setIsRotating(null);
}}
/>
</mesh>
) : null
);
}
export default VehicleUI;

View File

@@ -1,9 +1,8 @@
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useFrame, useThree } from '@react-three/fiber'; import { useFrame, useThree } from '@react-three/fiber';
import { useFloorItems } from '../../../../../store/store';
import * as THREE from 'three'; import * as THREE from 'three';
import { Line } from '@react-three/drei'; import { Line } from '@react-three/drei';
import { useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
interface VehicleAnimatorProps { interface VehicleAnimatorProps {
@@ -16,27 +15,35 @@ interface VehicleAnimatorProps {
} }
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) {
const { decrementVehicleLoad, vehicles } = useVehicleStore(); const { decrementVehicleLoad } = useVehicleStore();
const { isPaused } = usePauseButtonStore(); const { isPaused } = usePauseButtonStore();
const { isPlaying } = usePlayButtonStore();
const { speed } = useAnimationPlaySpeed(); const { speed } = useAnimationPlaySpeed();
const { isReset } = useResetButtonStore(); const { isReset, setReset } = useResetButtonStore();
const [restRotation, setRestingRotation] = useState<boolean>(true);
const [progress, setProgress] = useState<number>(0);
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
const { scene } = useThree();
const progressRef = useRef<number>(0); const progressRef = useRef<number>(0);
const movingForward = useRef<boolean>(true); const movingForward = useRef<boolean>(true);
const completedRef = useRef<boolean>(false); const completedRef = useRef<boolean>(false);
const isPausedRef = useRef<boolean>(false);
const pauseTimeRef = useRef<number | null>(null);
const [restRotation, setRestingRotation] = useState<boolean>(true);
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
const [progress, setProgress] = useState<number>(0);
const { scene } = useThree();
let startTime: number; let startTime: number;
let pausedTime: number;
let fixedInterval: number; let fixedInterval: number;
let coveredDistance = progressRef.current;
let objectRotation = (agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) as { x: number; y: number; z: number };
useEffect(() => { useEffect(() => {
if (currentPhase === 'stationed-pickup' && path.length > 0) { if (currentPhase === 'stationed-pickup' && path.length > 0) {
setCurrentPath(path); setCurrentPath(path);
objectRotation = agvDetail.point.action?.pickUpPoint?.rotation
} else if (currentPhase === 'pickup-drop' && path.length > 0) { } else if (currentPhase === 'pickup-drop' && path.length > 0) {
objectRotation = agvDetail.point.action?.unLoadPoint?.rotation
setCurrentPath(path); setCurrentPath(path);
} else if (currentPhase === 'drop-pickup' && path.length > 0) { } else if (currentPhase === 'drop-pickup' && path.length > 0) {
objectRotation = agvDetail.point.action?.pickUpPoint?.rotation
setCurrentPath(path); setCurrentPath(path);
} }
}, [currentPhase, path]); }, [currentPhase, path]);
@@ -45,122 +52,42 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
setProgress(0); setProgress(0);
completedRef.current = false; completedRef.current = false;
}, [currentPath]); }, [currentPath]);
// useEffect(() => {
// console.log('isReset: ', isReset);
// if (isReset) {
// reset();
// setCurrentPath([]);
// setProgress(0);
// completedRef.current = false;
// decrementVehicleLoad(agvDetail.modelUuid, 0)
// }
// }, [isReset])
// useFrame((_, delta) => {
// const object = scene.getObjectByProperty('uuid', agvUuid);
// if (!object || currentPath.length < 2) return;
// if (isPaused) return;
// let totalDistance = 0;
// const distances = [];
// for (let i = 0; i < currentPath.length - 1; i++) {
// const start = new THREE.Vector3(...currentPath[i]);
// const end = new THREE.Vector3(...currentPath[i + 1]);
// const segmentDistance = start.distanceTo(end);
// distances.push(segmentDistance);
// totalDistance += segmentDistance;
// }
// let coveredDistance = progressRef.current;
// let accumulatedDistance = 0;
// let index = 0;
// while (
// index < distances.length &&
// coveredDistance > accumulatedDistance + distances[index]
// ) {
// accumulatedDistance += distances[index];
// index++;
// }
// if (index < distances.length) {
// const start = new THREE.Vector3(...currentPath[index]);
// const end = new THREE.Vector3(...currentPath[index + 1]);
// const segmentDistance = distances[index];
// const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
// const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
// const rotationSpeed = 2.0;
// const currentAngle = object.rotation.y;
// let angleDifference = targetAngle - currentAngle;
// if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI;
// if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI;
// const maxRotationStep = rotationSpeed * delta;
// object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep);
// const isAligned = Math.abs(angleDifference) < 0.01;
// if (isAligned) {
// progressRef.current += delta * (speed * agvDetail.speed);
// coveredDistance = progressRef.current;
// const t = (coveredDistance - accumulatedDistance) / segmentDistance;
// const position = start.clone().lerp(end, t);
// object.position.copy(position);
// }
// }
// if (progressRef.current >= totalDistance) {
// if (restRotation) {
// const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
// object.quaternion.slerp(targetQuaternion, delta * 2);
// const angleDiff = object.quaternion.angleTo(targetQuaternion);
// if (angleDiff < 0.01) {
// let objectRotation = agvDetail.point.rotation
// object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]);
// setRestingRotation(false);
// }
// return;
// }
// }
// if (progressRef.current >= totalDistance) {
// setRestingRotation(true);
// progressRef.current = 0;
// movingForward.current = !movingForward.current;
// setCurrentPath([]);
// handleCallBack();
// if (currentPhase === 'pickup-drop') {
// requestAnimationFrame(firstFrame);
// }
// }
// });
useEffect(() => { useEffect(() => {
if (isReset) { if (isReset || !isPlaying) {
reset(); reset();
setCurrentPath([]); setCurrentPath([]);
setProgress(0); setProgress(0);
progressRef.current = 0;
completedRef.current = false; completedRef.current = false;
movingForward.current = true; movingForward.current = true;
setRestingRotation(false); progressRef.current = 0;
startTime = 0;
coveredDistance = 0;
setReset(false);
setRestingRotation(true);
decrementVehicleLoad(agvDetail.modelUuid, 0); decrementVehicleLoad(agvDetail.modelUuid, 0);
const object = scene.getObjectByProperty('uuid', agvUuid);
console.log('currentPhase: ', currentPhase);
if (object) {
object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]);
object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z);
} }
}, [isReset]); }
}, [isReset, isPlaying])
useEffect(() => {
isPausedRef.current = isPaused;
}, [isPaused]);
useFrame((_, delta) => { useFrame((_, delta) => {
// If reset is active, don't run anything in frame
if (isReset) return;
const object = scene.getObjectByProperty('uuid', agvUuid); const object = scene.getObjectByProperty('uuid', agvUuid);
if (!object || currentPath.length < 2) return; if (!object || currentPath.length < 2) return;
if (isPaused) return; if (isPaused) return;
let totalDistance = 0; let totalDistance = 0;
const distances = []; const distances = [];
let accumulatedDistance = 0;
let index = 0;
for (let i = 0; i < currentPath.length - 1; i++) { for (let i = 0; i < currentPath.length - 1; i++) {
const start = new THREE.Vector3(...currentPath[i]); const start = new THREE.Vector3(...currentPath[i]);
@@ -170,10 +97,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
totalDistance += segmentDistance; totalDistance += segmentDistance;
} }
let coveredDistance = progressRef.current;
let accumulatedDistance = 0;
let index = 0;
while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) {
accumulatedDistance += distances[index]; accumulatedDistance += distances[index];
index++; index++;
@@ -186,17 +109,16 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
const rotationSpeed = speed;
const currentAngle = object.rotation.y; const currentAngle = object.rotation.y;
let angleDifference = targetAngle - currentAngle; let angleDifference = targetAngle - currentAngle;
if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI;
if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI;
const rotationSpeed = 2.0;
const maxRotationStep = rotationSpeed * delta; const maxRotationStep = rotationSpeed * delta;
const rotationStep = Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep);
object.rotation.y += rotationStep;
const isAligned = Math.abs(angleDifference) < 0.01; const isAligned = Math.abs(angleDifference) < 0.01;
if (isAligned) { if (isAligned) {
@@ -211,15 +133,18 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
if (progressRef.current >= totalDistance) { if (progressRef.current >= totalDistance) {
if (restRotation) { if (restRotation) {
const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(objectRotation.x, objectRotation.y, objectRotation.z));
object.quaternion.slerp(targetQuaternion, delta * 2); object.quaternion.slerp(targetQuaternion, delta * 2);
const angleDiff = object.quaternion.angleTo(targetQuaternion); const angleDiff = object.quaternion.angleTo(targetQuaternion);
if (angleDiff < 0.01) { if (angleDiff < 0.01) {
const objectRotation = agvDetail.point.rotation; object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z);
object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]);
setRestingRotation(false); setRestingRotation(false);
} }
} else { return;
}
}
if (progressRef.current >= totalDistance) {
setRestingRotation(true); setRestingRotation(true);
progressRef.current = 0; progressRef.current = 0;
movingForward.current = !movingForward.current; movingForward.current = !movingForward.current;
@@ -229,25 +154,42 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
requestAnimationFrame(firstFrame); requestAnimationFrame(firstFrame);
} }
} }
}
}); });
function firstFrame() { function firstFrame() {
const unLoadDuration = agvDetail.point.action.unLoadDuration;
const droppedMaterial = agvDetail.currentLoad; const droppedMaterial = agvDetail.currentLoad;
fixedInterval = (unLoadDuration / droppedMaterial) * 1000;
startTime = performance.now(); startTime = performance.now();
step(droppedMaterial); step(droppedMaterial);
} }
function step(droppedMaterial: number) { function step(droppedMaterial: number) {
const elapsedTime = (performance.now() - startTime) * speed; if (isPausedRef.current) {
if (!pauseTimeRef.current) {
pauseTimeRef.current = performance.now();
}
requestAnimationFrame(() => step(droppedMaterial));
return;
}
if (pauseTimeRef.current) {
const pauseDuration = performance.now() - pauseTimeRef.current;
startTime += pauseDuration;
pauseTimeRef.current = null;
}
const elapsedTime = performance.now() - startTime;
const unLoadDuration = agvDetail.point.action.unLoadDuration;
fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed));
if (elapsedTime >= fixedInterval) { if (elapsedTime >= fixedInterval) {
let droppedMat = droppedMaterial - 1; let droppedMat = droppedMaterial - 1;
decrementVehicleLoad(agvDetail.modelUuid, 1); decrementVehicleLoad(agvDetail.modelUuid, 1);
if (droppedMat === 0) return; if (droppedMat > 0) {
startTime = performance.now(); startTime = performance.now();
requestAnimationFrame(() => step(droppedMat)); requestAnimationFrame(() => step(droppedMat));
} else {
return;
}
} else { } else {
requestAnimationFrame(() => step(droppedMaterial)); requestAnimationFrame(() => step(droppedMaterial));
} }

View File

@@ -1,18 +1,18 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import VehicleAnimator from '../animator/vehicleAnimator'; import VehicleAnimator from '../animator/vehicleAnimator';
import * as THREE from 'three'; import * as THREE from 'three';
import { NavMeshQuery } from '@recast-navigation/core'; import { NavMeshQuery } from '@recast-navigation/core';
import { useNavMesh } from '../../../../../store/store'; import { useNavMesh } from '../../../../../store/store';
import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
function VehicleInstance({ agvDetail }: any) { function VehicleInstance({ agvDetail }: any) {
const { navMesh } = useNavMesh(); const { navMesh } = useNavMesh();
const { isPlaying, setIsPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { isReset } = useResetButtonStore();
const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore();
const [currentPhase, setCurrentPhase] = useState<string>('stationed'); const [currentPhase, setCurrentPhase] = useState<string>('stationed');
const [path, setPath] = useState<[number, number, number][]>([]); const [path, setPath] = useState<[number, number, number][]>([]);
let isIncrememtable = useRef<boolean>(true);
const computePath = useCallback( const computePath = useCallback(
(start: any, end: any) => { (start: any, end: any) => {
@@ -20,7 +20,7 @@ function VehicleInstance({ agvDetail }: any) {
const navMeshQuery = new NavMeshQuery(navMesh); const navMeshQuery = new NavMeshQuery(navMesh);
const { path: segmentPath } = navMeshQuery.computePath(start, end); const { path: segmentPath } = navMeshQuery.computePath(start, end);
return ( return (
segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || []
); );
} catch { } catch {
return []; return [];
@@ -29,77 +29,92 @@ function VehicleInstance({ agvDetail }: any) {
[navMesh] [navMesh]
); );
function vehicleStatus(modelid: string, status: string) { function vehicleStatus(modelId: string, status: string) {
// console.log(`AGV ${modelid}: ${status}`); // console.log(`${modelId} , ${status});
} }
// Function to reset everything
function reset() { function reset() {
setCurrentPhase('stationed');
setVehicleActive(agvDetail.modelUuid, false); setVehicleActive(agvDetail.modelUuid, false);
setVehicleState(agvDetail.modelUuid, 'idle'); setVehicleState(agvDetail.modelUuid, 'idle');
setPath([]); setPath([]);
setCurrentPhase('stationed') }
const increment = () => {
if (isIncrememtable.current) {
incrementVehicleLoad(agvDetail.modelUuid, 2);
isIncrememtable.current = false;
}
} }
useEffect(() => { useEffect(() => {
if (isPlaying) { if (isPlaying) {
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
const toPickupPath = computePath( const toPickupPath = computePath(
new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]),
agvDetail.point.action.pickUpPoint agvDetail?.point?.action?.pickUpPoint?.position
); );
setPath(toPickupPath); setPath(toPickupPath);
setVehicleActive(agvDetail.modelUuid, true);
setVehicleState(agvDetail.modelUuid, 'running');
setCurrentPhase('stationed-pickup'); setCurrentPhase('stationed-pickup');
setVehicleState(agvDetail.modelUuid, 'running');
setVehicleActive(agvDetail.modelUuid, true);
vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup');
return; return;
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') { } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') {
setTimeout(() => { setTimeout(() => {
incrementVehicleLoad(agvDetail.modelUuid, 2); increment();
}, 5000); }, 5000);
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) {
const toDrop = computePath( const toDrop = computePath(
agvDetail.point.action.pickUpPoint, agvDetail.point.action.pickUpPoint.position,
agvDetail.point.action.unLoadPoint agvDetail.point.action.unLoadPoint.position
); );
setPath(toDrop); setPath(toDrop);
setVehicleActive(agvDetail.modelUuid, true);
setVehicleState(agvDetail.modelUuid, 'running');
setCurrentPhase('pickup-drop'); setCurrentPhase('pickup-drop');
setVehicleState(agvDetail.modelUuid, 'running');
setVehicleActive(agvDetail.modelUuid, true);
vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point');
} }
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) { } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) {
const dropToPickup = computePath( const dropToPickup = computePath(
agvDetail.point.action.unLoadPoint, agvDetail.point.action.unLoadPoint.position,
agvDetail.point.action.pickUpPoint agvDetail.point.action.pickUpPoint.position
); );
setPath(dropToPickup); setPath(dropToPickup);
setVehicleActive(agvDetail.modelUuid, true);
setVehicleState(agvDetail.modelUuid, 'running');
setCurrentPhase('drop-pickup'); setCurrentPhase('drop-pickup');
setVehicleState(agvDetail.modelUuid, 'running');
setVehicleActive(agvDetail.modelUuid, true);
vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point');
isIncrememtable.current = true;
} }
} else {
reset()
} }
}, [vehicles, currentPhase, path, isPlaying, isReset]); }, [vehicles, currentPhase, path, isPlaying]);
function handleCallBack() { function handleCallBack() {
if (currentPhase === 'stationed-pickup') { if (currentPhase === 'stationed-pickup') {
setVehicleActive(agvDetail.modelUuid, false);
setVehicleState(agvDetail.modelUuid, 'idle');
setCurrentPhase('picking'); setCurrentPhase('picking');
setVehicleState(agvDetail.modelUuid, 'idle');
setVehicleActive(agvDetail.modelUuid, false);
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material');
setPath([]); setPath([]);
} else if (currentPhase === 'pickup-drop') { } else if (currentPhase === 'pickup-drop') {
setVehicleActive(agvDetail.modelUuid, false);
setVehicleState(agvDetail.modelUuid, 'idle');
setCurrentPhase('dropping'); setCurrentPhase('dropping');
setVehicleState(agvDetail.modelUuid, 'idle');
setVehicleActive(agvDetail.modelUuid, false);
vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); vehicleStatus(agvDetail.modelUuid, 'Reached drop point');
setPath([]); setPath([]);
} else if (currentPhase === 'drop-pickup') { } else if (currentPhase === 'drop-pickup') {
setVehicleActive(agvDetail.modelUuid, false);
setVehicleState(agvDetail.modelUuid, 'idle');
setCurrentPhase('picking'); setCurrentPhase('picking');
setVehicleState(agvDetail.modelUuid, 'idle');
setVehicleActive(agvDetail.modelUuid, false);
setPath([]); setPath([]);
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete');
} }

View File

@@ -3,12 +3,16 @@ import VehicleInstance from './instance/vehicleInstance'
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore' import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'
function VehicleInstances() { function VehicleInstances() {
const { vehicles } = useVehicleStore(); const { vehicles } = useVehicleStore();
return ( return (
<> <>
{vehicles.map((val: any, i: any) => {vehicles.map((val: any, i: any) =>
<VehicleInstance agvDetail={val} key={i} /> <VehicleInstance agvDetail={val} key={i} />
)} )}
</> </>

View File

@@ -1,15 +1,21 @@
import React, { useEffect } from 'react' import React, { useEffect, useState } from "react";
import VehicleInstances from './instances/vehicleInstances'; import VehicleInstances from "./instances/vehicleInstances";
import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; import { useVehicleStore } from "../../../store/simulation/useVehicleStore";
import { useFloorItems } from '../../../store/store'; import { useFloorItems } from "../../../store/store";
import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
import VehicleUI from "../ui/vehicle/vehicleUI";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
function Vehicles() { function Vehicles() {
const { vehicles, addVehicle } = useVehicleStore(); const { vehicles, addVehicle } = useVehicleStore();
const { selectedEventSphere } = useSelectedEventSphere();
const { selectedEventData } = useSelectedEventData();
const { floorItems } = useFloorItems(); const { floorItems } = useFloorItems();
const { isPlaying } = usePlayButtonStore();
const vehicleStatusSample: VehicleEventSchema[] = [ const [vehicleStatusSample, setVehicleStatusSample] = useState<
VehicleEventSchema[]
>([
{ {
modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74", modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74",
modelName: "AGV", modelName: "AGV",
@@ -28,6 +34,7 @@ function Vehicles() {
actionType: "travel", actionType: "travel",
unLoadDuration: 10, unLoadDuration: 10,
loadCapacity: 2, loadCapacity: 2,
steeringAngle:0,
pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } },
unLoadPoint: { position: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, unLoadPoint: { position: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } },
triggers: [ triggers: [
@@ -71,8 +78,9 @@ function Vehicles() {
actionType: "travel", actionType: "travel",
unLoadDuration: 10, unLoadDuration: 10,
loadCapacity: 2, loadCapacity: 2,
pickUpPoint: { position: { x: 90, y: 0, z: 28 }, rotation: { x: 0, y: 0, z: 0 } }, steeringAngle:0,
unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, pickUpPoint: null,
unLoadPoint: null,
triggers: [ triggers: [
{ {
triggerUuid: "trig-001", triggerUuid: "trig-001",
@@ -96,68 +104,117 @@ function Vehicles() {
} }
} }
}, },
{ // {
modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", // modelUuid: "cd7d0584-0684-42b4-b051-9e882c1914aa",
modelName: "forklift", // modelName: "AGV",
position: [98.85729337188162, 0, 38.36616546567653], // position: [105.90938758014703, 0, 31.584209911095215],
rotation: [0, 0, 0], // rotation: [0, 0, 0],
state: "idle", // state: "idle",
type: "vehicle", // type: "vehicle",
speed: 2.5, // speed: 2.5,
point: { // point: {
uuid: "point-789", // uuid: "point-789",
position: [0, 1, 0], // position: [0, 1, 0],
rotation: [0, 0, 0], // rotation: [0, 0, 0],
action: { // action: {
actionUuid: "action-456", // actionUuid: "action-456",
actionName: "Deliver to Zone A", // actionName: "Deliver to Zone A",
actionType: "travel", // actionType: "travel",
unLoadDuration: 15, // unLoadDuration: 10,
loadCapacity: 5, // loadCapacity: 2,
pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, // steeringAngle:0,
unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, // pickUpPoint: null,
triggers: [ // unLoadPoint: null,
{ // triggers: [
triggerUuid: "trig-001", // {
triggerName: "Start Travel", // triggerUuid: "trig-001",
triggerType: "onStart", // triggerName: "Start Travel",
delay: 0, // triggerType: "onStart",
triggeredAsset: { // delay: 0,
triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, // triggeredAsset: {
triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, // triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } // triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
} // triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
}, // }
{ // },
triggerUuid: "trig-002", // {
triggerName: "Complete Travel", // triggerUuid: "trig-002",
triggerType: "onComplete", // triggerName: "Complete Travel",
delay: 2, // triggerType: "onComplete",
triggeredAsset: null // delay: 2,
} // triggeredAsset: null
] // }
} // ]
} // }
} // }
]; // },
// {
// modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79",
useEffect(() => { // modelName: "forklift",
addVehicle('123', vehicleStatusSample[0]); // position: [98.85729337188162, 0, 38.36616546567653],
// addVehicle('123', vehicleStatusSample[1]); // rotation: [0, 0, 0],
// addVehicle('123', vehicleStatusSample[2]); // state: "idle",
}, []) // type: "vehicle",
// speed: 2.5,
// point: {
// uuid: "point-789",
// position: [0, 1, 0],
// rotation: [0, 0, 0],
// action: {
// actionUuid: "action-456",
// actionName: "Deliver to Zone A",
// actionType: "travel",
// unLoadDuration: 15,
// loadCapacity: 5,
// steeringAngle:0,
// pickUpPoint: null,
// unLoadPoint: null,
// triggers: [
// {
// triggerUuid: "trig-001",
// triggerName: "Start Travel",
// triggerType: "onStart",
// delay: 0,
// triggeredAsset: {
// triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
// triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
// triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
// }
// },
// {
// triggerUuid: "trig-002",
// triggerName: "Complete Travel",
// triggerType: "onComplete",
// delay: 2,
// triggeredAsset: null
// }
// ]
// }
// }
// }
]);
useEffect(() => { useEffect(() => {
// console.log('vehicles: ', vehicles); // console.log('vehicles: ', vehicles);
}, [vehicles]) }, [vehicles])
useEffect(() => {
addVehicle("123", vehicleStatusSample[0]);
addVehicle('123', vehicleStatusSample[1]);
// addVehicle('123', vehicleStatusSample[2]);
}, []);
return ( return (
<> <>
<VehicleInstances /> <VehicleInstances />
{selectedEventSphere && selectedEventData?.data.type === "vehicle" && !isPlaying &&
< VehicleUI />
}
</> </>
) );
} }
export default Vehicles; export default Vehicles;

View File

@@ -1,13 +1,13 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const deleteFloorItem = async (organization: string, modeluuid: string, modelname: string) => { export const deleteFloorItem = async (organization: string, modelUuid: string, modelName: string) => {
try { try {
const response = await fetch(`${url_Backend_dwinzo}/api/v1/deletefloorItem`, { const response = await fetch(`${url_Backend_dwinzo}/api/v1/deletefloorItem`, {
method: "DELETE", method: "DELETE",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ organization, modeluuid, modelname }), body: JSON.stringify({ organization, modelUuid, modelName }),
}); });
if (!response.ok) { if (!response.ok) {

View File

@@ -1,8 +1,8 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const setFloorItemApi = async ( export const setFloorItemApi = async (
organization: string, organization: string,
modeluuid?: string, modelUuid?: string,
modelname?: string, modelName?: string,
modelfileID?: string, modelfileID?: string,
position?: Object, position?: Object,
rotation?: Object, rotation?: Object,
@@ -10,7 +10,7 @@ export const setFloorItemApi = async (
isVisible?: boolean, isVisible?: boolean,
) => { ) => {
try { try {
const body: any = { organization, modeluuid, modelname, position, rotation, modelfileID, isLocked, isVisible }; const body: any = { organization, modelUuid, modelName, position, rotation, modelfileID, isLocked, isVisible };
const response = await fetch(`${url_Backend_dwinzo}/api/v2/setasset`, { const response = await fetch(`${url_Backend_dwinzo}/api/v2/setasset`, {
method: "POST", method: "POST",

View File

@@ -1,13 +1,13 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const deleteWallItem = async (organization: string, modeluuid: string, modelname: string) => { export const deleteWallItem = async (organization: string, modelUuid: string, modelName: string) => {
try { try {
const response = await fetch(`${url_Backend_dwinzo}/api/v1/deleteWallItem`, { const response = await fetch(`${url_Backend_dwinzo}/api/v1/deleteWallItem`, {
method: "DELETE", method: "DELETE",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ organization, modeluuid, modelname }), body: JSON.stringify({ organization, modelUuid, modelName }),
}); });
if (!response.ok) { if (!response.ok) {

View File

@@ -2,8 +2,8 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR
export const setWallItem = async ( export const setWallItem = async (
organization: string, organization: string,
modeluuid: string, modelUuid: string,
modelname: string, modelName: string,
type: string, type: string,
csgposition: Object, csgposition: Object,
csgscale: Object, csgscale: Object,
@@ -17,7 +17,7 @@ export const setWallItem = async (
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ organization, modeluuid, modelname, position, type, csgposition, csgscale, quaternion, scale }), body: JSON.stringify({ organization, modelUuid, modelName, position, type, csgposition, csgscale, quaternion, scale }),
}); });
if (!response.ok) { if (!response.ok) {

View File

@@ -21,7 +21,7 @@ onmessage = (event) => {
const itemPosition = new THREE.Vector3(...item.position); const itemPosition = new THREE.Vector3(...item.position);
const distance = cameraPos.distanceTo(itemPosition); const distance = cameraPos.distanceTo(itemPosition);
if (distance <= renderDistance && !uuids.includes(item.modeluuid)) { if (distance <= renderDistance && !uuids.includes(item.modelUuid)) {
toAdd.push(item); toAdd.push(item);
} }
}); });
@@ -35,7 +35,7 @@ onmessage = (event) => {
// Check for items to be removed // Check for items to be removed
uuids.forEach((uuid) => { uuids.forEach((uuid) => {
const floorItem = floorItems.find((item) => item.modeluuid === uuid); const floorItem = floorItems.find((item) => item.modelUuid === uuid);
if (floorItem) { if (floorItem) {
const itemPosition = new THREE.Vector3(...floorItem.position); const itemPosition = new THREE.Vector3(...floorItem.position);
const distance = cameraPos.distanceTo(itemPosition); const distance = cameraPos.distanceTo(itemPosition);

View File

@@ -1,6 +1,6 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const deleteProductDataApi = async (productId: string, organization: string) => { export const deleteProductApi = async (productId: string, organization: string) => {
try { try {
const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDataDelete?productId=${productId}&organization=${organization}`, { const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDataDelete?productId=${productId}&organization=${organization}`, {
method: "PATCH", method: "PATCH",

View File

@@ -6,13 +6,15 @@ type ProductsStore = {
// Product-level actions // Product-level actions
addProduct: (productName: string, productId: string) => void; addProduct: (productName: string, productId: string) => void;
setProducts: (products: productsSchema) => void;
removeProduct: (productId: string) => void; removeProduct: (productId: string) => void;
updateProduct: (productId: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void; updateProduct: (productId: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void;
// Event-level actions // Event-level actions
addEvent: (productId: string, event: EventsSchema) => void; addEvent: (productId: string, event: EventsSchema) => void;
removeEvent: (productId: string, modelUuid: string) => void; removeEvent: (productId: string, modelUuid: string) => void;
updateEvent: (productId: string, modelUuid: string, updates: Partial<EventsSchema>) => void; deleteEvent: (modelUuid: string) => void;
updateEvent: (productId: string, modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
// Point-level actions // Point-level actions
addPoint: (productId: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; addPoint: (productId: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
@@ -30,12 +32,12 @@ type ProductsStore = {
modelUuid: string, modelUuid: string,
pointUuid: string, pointUuid: string,
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
) => void; ) => EventsSchema | undefined;
removeAction: (actionUuid: string) => void; removeAction: (actionUuid: string) => EventsSchema | undefined;
updateAction: ( updateAction: (
actionUuid: string, actionUuid: string,
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']> updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
) => void; ) => EventsSchema | undefined;
// Trigger-level actions // Trigger-level actions
addTrigger: ( addTrigger: (
@@ -50,7 +52,7 @@ type ProductsStore = {
// Renaming functions // Renaming functions
renameProduct: (productId: string, newName: string) => void; renameProduct: (productId: string, newName: string) => void;
renameAction: (actionUuid: string, newName: string) => void; renameAction: (actionUuid: string, newName: string) => EventsSchema | undefined;
renameTrigger: (triggerUuid: string, newName: string) => void; renameTrigger: (triggerUuid: string, newName: string) => void;
// Helper functions // Helper functions
@@ -78,6 +80,12 @@ export const useProductStore = create<ProductsStore>()(
}); });
}, },
setProducts: (products) => {
set((state) => {
state.products = products;
});
},
removeProduct: (productId) => { removeProduct: (productId) => {
set((state) => { set((state) => {
state.products = state.products.filter(p => p.productId !== productId); state.products = state.products.filter(p => p.productId !== productId);
@@ -112,16 +120,27 @@ export const useProductStore = create<ProductsStore>()(
}); });
}, },
deleteEvent: (modelUuid: string) => {
set((state) => {
for (const product of state.products) {
product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
}
});
},
updateEvent: (productId, modelUuid, updates) => { updateEvent: (productId, modelUuid, updates) => {
let updatedEvent: EventsSchema | undefined;
set((state) => { set((state) => {
const product = state.products.find(p => p.productId === productId); const product = state.products.find(p => p.productId === productId);
if (product) { if (product) {
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event) { if (event) {
Object.assign(event, updates); Object.assign(event, updates);
updatedEvent = JSON.parse(JSON.stringify(event));
} }
} }
}); });
return updatedEvent;
}, },
// Point-level actions // Point-level actions
@@ -172,6 +191,7 @@ export const useProductStore = create<ProductsStore>()(
// Action-level actions // Action-level actions
addAction: (productId, modelUuid, pointUuid, action) => { addAction: (productId, modelUuid, pointUuid, action) => {
let updatedEvent: EventsSchema | undefined;
set((state) => { set((state) => {
const product = state.products.find(p => p.productId === productId); const product = state.products.find(p => p.productId === productId);
if (product) { if (product) {
@@ -180,19 +200,24 @@ export const useProductStore = create<ProductsStore>()(
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
if (point) { if (point) {
point.action = action as any; point.action = action as any;
updatedEvent = JSON.parse(JSON.stringify(event));
} }
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
if ('action' in (event as any).point) { if ('action' in (event as any).point) {
(event as any).point.action = action; (event as any).point.action = action;
updatedEvent = JSON.parse(JSON.stringify(event));
} else if ('actions' in (event as any).point) { } else if ('actions' in (event as any).point) {
(event as any).point.actions.push(action); (event as any).point.actions.push(action);
updatedEvent = JSON.parse(JSON.stringify(event));
} }
} }
} }
}); });
return updatedEvent;
}, },
removeAction: (actionUuid: string) => { removeAction: (actionUuid: string) => {
let updatedEvent: EventsSchema | undefined;
set((state) => { set((state) => {
for (const product of state.products) { for (const product of state.products) {
for (const event of product.eventDatas) { for (const event of product.eventDatas) {
@@ -203,20 +228,28 @@ export const useProductStore = create<ProductsStore>()(
} else if ('point' in event) { } else if ('point' in event) {
const point = (event as any).point; const point = (event as any).point;
if (event.type === "roboticArm") { if (event.type === "roboticArm") {
// Handle RoboticArmEventSchema
if ('actions' in point) { if ('actions' in point) {
point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid); const index = point.actions.findIndex((a: any) => a.actionUuid === actionUuid);
if (index !== -1) {
point.actions.splice(index, 1);
updatedEvent = JSON.parse(JSON.stringify(event));
return;
}
} }
} else if ('action' in point && point.action?.actionUuid === actionUuid) { } else if ('action' in point && point.action?.actionUuid === actionUuid) {
// For other schemas with a single 'action' point.action = undefined;
updatedEvent = JSON.parse(JSON.stringify(event));
return;
} }
} }
} }
} }
}); });
return updatedEvent;
}, },
updateAction: (actionUuid, updates) => { updateAction: (actionUuid, updates) => {
let updatedEvent: EventsSchema | undefined;
set((state) => { set((state) => {
for (const product of state.products) { for (const product of state.products) {
for (const event of product.eventDatas) { for (const event of product.eventDatas) {
@@ -224,6 +257,7 @@ export const useProductStore = create<ProductsStore>()(
for (const point of (event as ConveyorEventSchema).points) { for (const point of (event as ConveyorEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) { if (point.action && point.action.actionUuid === actionUuid) {
Object.assign(point.action, updates); Object.assign(point.action, updates);
updatedEvent = JSON.parse(JSON.stringify(event));
return; return;
} }
} }
@@ -231,11 +265,13 @@ export const useProductStore = create<ProductsStore>()(
const point = (event as any).point; const point = (event as any).point;
if ('action' in point && point.action.actionUuid === actionUuid) { if ('action' in point && point.action.actionUuid === actionUuid) {
Object.assign(point.action, updates); Object.assign(point.action, updates);
updatedEvent = JSON.parse(JSON.stringify(event));
return; return;
} else if ('actions' in point) { } else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid); const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) { if (action) {
Object.assign(action, updates); Object.assign(action, updates);
updatedEvent = JSON.parse(JSON.stringify(event));
return; return;
} }
} }
@@ -243,6 +279,7 @@ export const useProductStore = create<ProductsStore>()(
} }
} }
}); });
return updatedEvent;
}, },
// Trigger-level actions // Trigger-level actions
@@ -352,6 +389,7 @@ export const useProductStore = create<ProductsStore>()(
}, },
renameAction: (actionUuid, newName) => { renameAction: (actionUuid, newName) => {
let updatedEvent: EventsSchema | undefined;
set((state) => { set((state) => {
for (const product of state.products) { for (const product of state.products) {
for (const event of product.eventDatas) { for (const event of product.eventDatas) {
@@ -359,6 +397,7 @@ export const useProductStore = create<ProductsStore>()(
for (const point of (event as ConveyorEventSchema).points) { for (const point of (event as ConveyorEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) { if (point.action && point.action.actionUuid === actionUuid) {
point.action.actionName = newName; point.action.actionName = newName;
updatedEvent = JSON.parse(JSON.stringify(event));
return; return;
} }
} }
@@ -366,11 +405,13 @@ export const useProductStore = create<ProductsStore>()(
const point = (event as any).point; const point = (event as any).point;
if ('action' in point && point.action.actionUuid === actionUuid) { if ('action' in point && point.action.actionUuid === actionUuid) {
point.action.actionName = newName; point.action.actionName = newName;
updatedEvent = JSON.parse(JSON.stringify(event));
return; return;
} else if ('actions' in point) { } else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid); const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) { if (action) {
action.actionName = newName; action.actionName = newName;
updatedEvent = JSON.parse(JSON.stringify(event));
return; return;
} }
} }
@@ -378,6 +419,7 @@ export const useProductStore = create<ProductsStore>()(
} }
} }
}); });
return updatedEvent;
}, },
renameTrigger: (triggerUuid, newName) => { renameTrigger: (triggerUuid, newName) => {

View File

@@ -22,6 +22,7 @@ interface VehiclesStore {
) => void; ) => void;
setVehicleActive: (modelUuid: string, isActive: boolean) => void; setVehicleActive: (modelUuid: string, isActive: boolean) => void;
updateSteeringAngle: (modelUuid: string, steeringAngle: number) => void;
incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void; incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void; decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void; setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void;
@@ -76,6 +77,15 @@ export const useVehicleStore = create<VehiclesStore>()(
}); });
}, },
updateSteeringAngle: (modelUuid, steeringAngle) => {
set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
if (vehicle) {
vehicle.point.action.steeringAngle = steeringAngle;
}
});
},
incrementVehicleLoad: (modelUuid, incrementBy) => { incrementVehicleLoad: (modelUuid, incrementBy) => {
set((state) => { set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);

View File

@@ -14,7 +14,7 @@ interface TriggerSchema {
triggeredAsset: { triggeredAsset: {
triggeredModel: { modelName: string, modelUuid: string }; triggeredModel: { modelName: string, modelUuid: string };
triggeredPoint: { pointName: string, pointUuid: string }; triggeredPoint: { pointName: string, pointUuid: string };
triggeredAction: { actionName: string, actionUuid: string }; triggeredAction: { actionName: string, actionUuid: string } | null;
} | null; } | null;
} }
@@ -44,6 +44,7 @@ interface VehiclePointSchema {
actionType: "travel"; actionType: "travel";
unLoadDuration: number; unLoadDuration: number;
loadCapacity: number; loadCapacity: number;
steeringAngle: number;
pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
triggers: TriggerSchema[]; triggers: TriggerSchema[];

View File

@@ -189,13 +189,26 @@ export type RefTubeGeometry = React.MutableRefObject<THREE.TubeGeometry | null>;
// Type for individual items placed on the floor, with positioning and rotation metadata // Type for individual items placed on the floor, with positioning and rotation metadata
export type FloorItemType = { export type FloorItemType = {
modeluuid: string; modelUuid: string;
modelname: string; modelName: string;
position: [number, number, number]; position: [number, number, number];
rotation: { x: number; y: number; z: number }; rotation: { x: number; y: number; z: number };
modelfileID: string; modelfileID: string;
isLocked: boolean; isLocked: boolean;
isVisible: boolean; isVisible: boolean;
eventData?: {
type: string;
point?: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
}
points?: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
}[];
}
}; };
// Array of floor items for managing multiple objects on the floor // Array of floor items for managing multiple objects on the floor
@@ -225,8 +238,8 @@ export type AssetConfigurations = { [key: string]: AssetConfiguration; };
interface WallItem { interface WallItem {
type: "Fixed-Move" | "Free-Move" | undefined; type: "Fixed-Move" | "Free-Move" | undefined;
model?: THREE.Group; model?: THREE.Group;
modeluuid?: string; modelUuid?: string;
modelname?: string; modelName?: string;
scale?: [number, number, number]; scale?: [number, number, number];
csgscale?: [number, number, number]; csgscale?: [number, number, number];
csgposition?: [number, number, number]; csgposition?: [number, number, number];