Merge remote-tracking branch 'origin/main-dev' into feature/agv-edit
This commit is contained in:
@@ -6,146 +6,128 @@ import PositionInput from "../customInput/PositionInputs";
|
|||||||
import RotationInput from "../customInput/RotationInput";
|
import RotationInput from "../customInput/RotationInput";
|
||||||
import { useSelectedFloorItem, useObjectPosition, useObjectRotation } from "../../../../store/builder/store";
|
import { useSelectedFloorItem, useObjectPosition, useObjectRotation } from "../../../../store/builder/store";
|
||||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||||
|
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||||
|
|
||||||
interface UserData {
|
interface UserData {
|
||||||
id: number; // Unique identifier for the user data
|
id: number;
|
||||||
label: string; // Label of the user data field
|
label: string;
|
||||||
value: string; // Value of the user data field
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AssetProperties: React.FC = () => {
|
const AssetProperties: React.FC = () => {
|
||||||
const [userData, setUserData] = useState<UserData[]>([]); // State to track user data
|
const [userData, setUserData] = useState<UserData[]>([]);
|
||||||
const [nextId, setNextId] = useState(1); // Unique ID for new entries
|
const { selectedFloorItem } = useSelectedFloorItem();
|
||||||
const { selectedFloorItem } = useSelectedFloorItem();
|
const { objectPosition } = useObjectPosition();
|
||||||
const { objectPosition } = useObjectPosition();
|
const { objectRotation } = useObjectRotation();
|
||||||
const { objectRotation } = useObjectRotation();
|
const { assetStore } = useSceneContext();
|
||||||
const { assetStore } = useSceneContext();
|
const { assets, setCurrentAnimation } = assetStore();
|
||||||
const { assets, setCurrentAnimation } = assetStore()
|
const { loopAnimation } = useBuilderStore();
|
||||||
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
|
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
|
||||||
const [isPlaying, setIsplaying] = useState(false);
|
|
||||||
// Function to handle adding new user data
|
const handleAddUserData = () => {
|
||||||
const handleAddUserData = () => {
|
|
||||||
const newUserData: UserData = {
|
|
||||||
id: nextId,
|
|
||||||
label: `Property ${nextId}`,
|
|
||||||
value: "",
|
|
||||||
};
|
};
|
||||||
setUserData([...userData, newUserData]);
|
|
||||||
setNextId(nextId + 1); // Increment the ID for the next entry
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to update the value of a user data entry
|
const handleUserDataChange = (id: number, newValue: string) => {
|
||||||
const handleUserDataChange = (id: number, newValue: string) => {
|
};
|
||||||
setUserData((prevUserData) =>
|
|
||||||
prevUserData.map((data) =>
|
|
||||||
data.id === id ? { ...data, value: newValue } : data
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove user data
|
const handleRemoveUserData = (id: number) => {
|
||||||
const handleRemoveUserData = (id: number) => {
|
};
|
||||||
setUserData((prevUserData) =>
|
|
||||||
prevUserData.filter((data) => data.id !== id)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAnimationClick = (animation: string) => {
|
const handleAnimationClick = (animation: string) => {
|
||||||
if (selectedFloorItem && selectedFloorItem.animationState) {
|
if (selectedFloorItem) {
|
||||||
const isPlaying = selectedFloorItem.animationState?.playing || false;
|
setCurrentAnimation(selectedFloorItem.uuid, animation, true, loopAnimation, true);
|
||||||
setCurrentAnimation(selectedFloorItem.uuid, animation, !isPlaying);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedFloorItem) return null;
|
if (!selectedFloorItem) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="asset-properties-container">
|
<div className="asset-properties-container">
|
||||||
{/* Name */}
|
{/* Name */}
|
||||||
<div className="header">{selectedFloorItem.userData.modelName}</div>
|
<div className="header">{selectedFloorItem.userData.modelName}</div>
|
||||||
<section>
|
<section>
|
||||||
{objectPosition.x && objectPosition.z &&
|
{objectPosition &&
|
||||||
<PositionInput
|
<PositionInput
|
||||||
onChange={() => { }}
|
onChange={() => { }}
|
||||||
value1={parseFloat(objectPosition.x.toFixed(5))}
|
value1={parseFloat(objectPosition.x.toFixed(5))}
|
||||||
value2={parseFloat(objectPosition.z.toFixed(5))}
|
value2={parseFloat(objectPosition.z.toFixed(5))}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{objectRotation.y &&
|
{objectRotation &&
|
||||||
<RotationInput
|
<RotationInput
|
||||||
onChange={() => { }}
|
onChange={() => { }}
|
||||||
value={parseFloat(objectRotation.y.toFixed(5))}
|
value={parseFloat(objectRotation.y.toFixed(5))}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div className="header">Render settings</div>
|
<div className="header">Render settings</div>
|
||||||
<InputToggle inputKey="visible" label="Visible" />
|
<InputToggle inputKey="visible" label="Visible" />
|
||||||
<InputToggle inputKey="frustumCull" label="Frustum cull" />
|
<InputToggle inputKey="frustumCull" label="Frustum cull" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div className="header">User Data</div>
|
<div className="header">User Data</div>
|
||||||
{userData.map((data) => (
|
{userData.map((data) => (
|
||||||
<div className="input-container">
|
<div className="input-container">
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
key={data.id}
|
key={data.id}
|
||||||
label={data.label}
|
label={data.label}
|
||||||
value={data.value}
|
value={data.value}
|
||||||
editableLabel
|
editableLabel
|
||||||
onChange={(newValue) => handleUserDataChange(data.id, newValue)} // Pass the change handler
|
onChange={(newValue) => handleUserDataChange(data.id, newValue)}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="remove-button"
|
className="remove-button"
|
||||||
onClick={() => handleRemoveUserData(data.id)}
|
onClick={() => handleRemoveUserData(data.id)}
|
||||||
>
|
>
|
||||||
<RemoveIcon />
|
<RemoveIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Add new user data */}
|
{/* Add new user data */}
|
||||||
<div className="optimize-button" onClick={handleAddUserData}>
|
<div className="optimize-button" onClick={handleAddUserData}>
|
||||||
+ Add
|
+ Add
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<div style={{ display: "flex", flexDirection: "column", outline: "1px solid var(--border-color)" }}>
|
|
||||||
{selectedFloorItem.uuid && <div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>Animations</div>}
|
|
||||||
{assets.map((asset) => (
|
|
||||||
<div key={asset.modelUuid} className="asset-item">
|
|
||||||
{asset.modelUuid === selectedFloorItem.uuid &&
|
|
||||||
asset.animations &&
|
|
||||||
asset.animations.length > 0 &&
|
|
||||||
asset.animations.map((animation, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
style={{ gap: "15px", cursor: "pointer", padding: "5px" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
onClick={() => handleAnimationClick(animation)}
|
|
||||||
onMouseEnter={() => setHoveredIndex(index)}
|
|
||||||
onMouseLeave={() => setHoveredIndex(null)}
|
|
||||||
style={{
|
|
||||||
height: "20px",
|
|
||||||
width: "100%",
|
|
||||||
borderRadius: "5px",
|
|
||||||
background:
|
|
||||||
hoveredIndex === index
|
|
||||||
? "#7b4cd3"
|
|
||||||
: "transparent",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{animation.charAt(0).toUpperCase() +
|
|
||||||
animation.slice(1).toLowerCase()}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
</section>
|
||||||
</div>
|
<div style={{ display: "flex", flexDirection: "column", outline: "1px solid var(--border-color)" }}>
|
||||||
))}
|
{selectedFloorItem.uuid && <div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>Animations</div>}
|
||||||
</div>
|
{assets.map((asset) => (
|
||||||
</div>
|
<div key={asset.modelUuid} className="asset-item">
|
||||||
);
|
{asset.modelUuid === selectedFloorItem.uuid &&
|
||||||
|
asset.animations &&
|
||||||
|
asset.animations.length > 0 &&
|
||||||
|
asset.animations.map((animation, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
style={{ gap: "15px", cursor: "pointer", padding: "5px" }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
onClick={() => handleAnimationClick(animation)}
|
||||||
|
onMouseEnter={() => setHoveredIndex(index)}
|
||||||
|
onMouseLeave={() => setHoveredIndex(null)}
|
||||||
|
style={{
|
||||||
|
height: "20px",
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: "5px",
|
||||||
|
background:
|
||||||
|
hoveredIndex === index
|
||||||
|
? "#7b4cd3"
|
||||||
|
: "transparent",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{animation.charAt(0).toUpperCase() +
|
||||||
|
animation.slice(1).toLowerCase()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AssetProperties;
|
export default AssetProperties;
|
||||||
|
|||||||
@@ -12,13 +12,17 @@ import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCam
|
|||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { getUserData } from "../../../../functions/getUserData";
|
import { getUserData } from "../../../../functions/getUserData";
|
||||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||||
|
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||||
|
|
||||||
const ZoneProperties: React.FC = () => {
|
const ZoneProperties: React.FC = () => {
|
||||||
const { Edit, setEdit } = useEditPosition();
|
const { Edit, setEdit } = useEditPosition();
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
const { zonePosition, setZonePosition } = usezonePosition();
|
const { zonePosition, setZonePosition } = usezonePosition();
|
||||||
const { zoneTarget, setZoneTarget } = usezoneTarget();
|
const { zoneTarget, setZoneTarget } = usezoneTarget();
|
||||||
const { zones, setZones } = useZones();
|
// const { zones, setZones } = useZones();
|
||||||
|
const { assetStore, zoneStore } = useSceneContext();
|
||||||
|
const { zones, setZoneName } = zoneStore()
|
||||||
|
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { userName, userId, organization, email } = getUserData();
|
const { userName, userId, organization, email } = getUserData();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
@@ -34,10 +38,11 @@ const ZoneProperties: React.FC = () => {
|
|||||||
|
|
||||||
let zonesdata = {
|
let zonesdata = {
|
||||||
zoneUuid: selectedZone.zoneUuid,
|
zoneUuid: selectedZone.zoneUuid,
|
||||||
viewPortposition: zonePosition,
|
viewPortPosition: zonePosition,
|
||||||
viewPortCenter: zoneTarget,
|
viewPortTarget: zoneTarget,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
let response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
||||||
// console.log('response: ', response);
|
// console.log('response: ', response);
|
||||||
if (response.message === "zone updated") {
|
if (response.message === "zone updated") {
|
||||||
@@ -63,13 +68,14 @@ const ZoneProperties: React.FC = () => {
|
|||||||
let response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
let response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
||||||
if (response.message === "zone updated") {
|
if (response.message === "zone updated") {
|
||||||
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
||||||
setZones((prevZones: any[]) =>
|
setZoneName(selectedZone.zoneUuid, newName)
|
||||||
prevZones.map((zone) =>
|
// setZones((prevZones: any[]) =>
|
||||||
zone.zoneUuid === selectedZone.zoneUuid
|
// prevZones.map((zone) =>
|
||||||
? { ...zone, zoneName: newName }
|
// zone.zoneUuid === selectedZone.zoneUuid
|
||||||
: zone
|
// ? { ...zone, zoneName: newName }
|
||||||
)
|
// : zone
|
||||||
);
|
// )
|
||||||
|
// );
|
||||||
} else {
|
} else {
|
||||||
// console.log(response?.message);
|
// console.log(response?.message);
|
||||||
}
|
}
|
||||||
@@ -81,6 +87,7 @@ const ZoneProperties: React.FC = () => {
|
|||||||
setSelectedZone((prev) => ({ ...prev, [key]: newValue }));
|
setSelectedZone((prev) => ({ ...prev, [key]: newValue }));
|
||||||
}
|
}
|
||||||
const checkZoneNameDuplicate = (name: string) => {
|
const checkZoneNameDuplicate = (name: string) => {
|
||||||
|
console.log('zones: ', zones);
|
||||||
return zones.some(
|
return zones.some(
|
||||||
(zone: any) =>
|
(zone: any) =>
|
||||||
zone.zoneName?.trim().toLowerCase() === name?.trim().toLowerCase() &&
|
zone.zoneName?.trim().toLowerCase() === name?.trim().toLowerCase() &&
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import VehicleMechanics from "./mechanics/vehicleMechanics";
|
|||||||
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
|
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
|
||||||
import MachineMechanics from "./mechanics/machineMechanics";
|
import MachineMechanics from "./mechanics/machineMechanics";
|
||||||
import StorageMechanics from "./mechanics/storageMechanics";
|
import StorageMechanics from "./mechanics/storageMechanics";
|
||||||
|
import HumanMechanics from "./mechanics/humanMechanics";
|
||||||
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 { useProductContext } from "../../../../../modules/simulation/products/productContext";
|
import { useProductContext } from "../../../../../modules/simulation/products/productContext";
|
||||||
@@ -60,6 +61,8 @@ const EventProperties: React.FC = () => {
|
|||||||
return "machine";
|
return "machine";
|
||||||
case "storageUnit":
|
case "storageUnit":
|
||||||
return "storageUnit";
|
return "storageUnit";
|
||||||
|
case "human":
|
||||||
|
return "human";
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -79,6 +82,7 @@ const EventProperties: React.FC = () => {
|
|||||||
{assetType === "roboticArm" && <RoboticArmMechanics />}
|
{assetType === "roboticArm" && <RoboticArmMechanics />}
|
||||||
{assetType === "machine" && <MachineMechanics />}
|
{assetType === "machine" && <MachineMechanics />}
|
||||||
{assetType === "storageUnit" && <StorageMechanics />}
|
{assetType === "storageUnit" && <StorageMechanics />}
|
||||||
|
{assetType === "human" && <HumanMechanics />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!currentEventData && selectedEventSphere && (
|
{!currentEventData && selectedEventSphere && (
|
||||||
|
|||||||
@@ -1,95 +1,70 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
|
||||||
|
|
||||||
interface TravelActionProps {
|
interface TravelActionProps {
|
||||||
loadCapacity: {
|
loadCapacity: {
|
||||||
value: string;
|
value: string;
|
||||||
min: number;
|
min: number;
|
||||||
max: number;
|
max: number;
|
||||||
defaultValue: string;
|
defaultValue: string;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
};
|
};
|
||||||
unloadDuration: {
|
unloadDuration: {
|
||||||
value: string;
|
value: string;
|
||||||
min: number;
|
min: number;
|
||||||
max: number;
|
max: number;
|
||||||
defaultValue: string;
|
defaultValue: string;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
};
|
};
|
||||||
pickPoint?: {
|
clearPoints: () => void;
|
||||||
value: string;
|
|
||||||
onChange: (value: string) => void;
|
|
||||||
};
|
|
||||||
unloadPoint?: {
|
|
||||||
value: string;
|
|
||||||
onChange: (value: string) => void;
|
|
||||||
};
|
|
||||||
clearPoints: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TravelAction: React.FC<TravelActionProps> = ({
|
const TravelAction: React.FC<TravelActionProps> = ({
|
||||||
loadCapacity,
|
loadCapacity,
|
||||||
unloadDuration,
|
unloadDuration,
|
||||||
pickPoint,
|
clearPoints,
|
||||||
unloadPoint,
|
|
||||||
clearPoints,
|
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Load Capacity"
|
label="Load Capacity"
|
||||||
value={loadCapacity.value}
|
value={loadCapacity.value}
|
||||||
min={loadCapacity.min}
|
min={loadCapacity.min}
|
||||||
max={loadCapacity.max}
|
max={loadCapacity.max}
|
||||||
defaultValue={loadCapacity.defaultValue}
|
defaultValue={loadCapacity.defaultValue}
|
||||||
step={1}
|
step={1}
|
||||||
activeOption="s"
|
activeOption="unit"
|
||||||
onClick={() => {}}
|
onClick={() => { }}
|
||||||
onChange={loadCapacity.onChange}
|
onChange={loadCapacity.onChange}
|
||||||
/>
|
/>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Unload Duration"
|
label="Unload Duration"
|
||||||
value={unloadDuration.value}
|
value={unloadDuration.value}
|
||||||
min={unloadDuration.min}
|
min={unloadDuration.min}
|
||||||
max={unloadDuration.max}
|
max={unloadDuration.max}
|
||||||
defaultValue={unloadDuration.defaultValue}
|
defaultValue={unloadDuration.defaultValue}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
activeOption="s"
|
activeOption="s"
|
||||||
onClick={() => {}}
|
onClick={() => { }}
|
||||||
onChange={unloadDuration.onChange}
|
onChange={unloadDuration.onChange}
|
||||||
/>
|
/>
|
||||||
<div className="selected-actions-list">
|
<div className="selected-actions-list">
|
||||||
<div className="value-field-container">
|
<div className="value-field-container">
|
||||||
<div className="label">Reset</div>
|
<div className="label">Reset</div>
|
||||||
<button
|
<button
|
||||||
id="rest-button"
|
id="rest-button"
|
||||||
type="button"
|
type="button"
|
||||||
className="regularDropdown-container"
|
className="regularDropdown-container"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clearPoints();
|
clearPoints();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{pickPoint && (
|
</>
|
||||||
<EyeDropInput
|
);
|
||||||
label="Pick Point"
|
|
||||||
value={pickPoint.value}
|
|
||||||
onChange={pickPoint.onChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{unloadPoint && (
|
|
||||||
<EyeDropInput
|
|
||||||
label="Unload Point"
|
|
||||||
value={unloadPoint.value}
|
|
||||||
onChange={unloadPoint.onChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TravelAction;
|
export default TravelAction;
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import React from "react";
|
||||||
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
|
|
||||||
|
interface WorkerActionProps {
|
||||||
|
loadCapacity: {
|
||||||
|
value: string;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
step: number;
|
||||||
|
defaultValue: string;
|
||||||
|
disabled?: boolean,
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
};
|
||||||
|
clearPoints: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WorkerAction: React.FC<WorkerActionProps> = ({
|
||||||
|
loadCapacity,
|
||||||
|
clearPoints,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Load Capacity"
|
||||||
|
value={loadCapacity.value}
|
||||||
|
min={loadCapacity.min}
|
||||||
|
max={loadCapacity.max}
|
||||||
|
disabled={loadCapacity.disabled}
|
||||||
|
defaultValue={loadCapacity.defaultValue}
|
||||||
|
step={loadCapacity.step}
|
||||||
|
activeOption="unit"
|
||||||
|
onClick={() => { }}
|
||||||
|
onChange={loadCapacity.onChange}
|
||||||
|
/>
|
||||||
|
<div className="selected-actions-list">
|
||||||
|
<div className="value-field-container">
|
||||||
|
<div className="label">Reset</div>
|
||||||
|
<button
|
||||||
|
id="rest-button"
|
||||||
|
type="button"
|
||||||
|
className="regularDropdown-container"
|
||||||
|
onClick={() => {
|
||||||
|
clearPoints();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorkerAction;
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { MathUtils } from "three";
|
||||||
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
import Trigger from "../trigger/Trigger";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
import { useSelectedEventData, useSelectedAction, useSelectedAnimation } from "../../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
|
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
|
||||||
|
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
|
||||||
|
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import WorkerAction from "../actions/workerAction";
|
||||||
|
|
||||||
|
function HumanMechanics() {
|
||||||
|
const [activeOption, setActiveOption] = useState<"worker">("worker");
|
||||||
|
const [speed, setSpeed] = useState("0.5");
|
||||||
|
const [loadCapacity, setLoadCapacity] = useState("1");
|
||||||
|
const [currentAction, setCurrentAction] = useState<HumanAction | undefined>();
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<HumanPointSchema | undefined>();
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { productStore } = useSceneContext();
|
||||||
|
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction, getEventByModelUuid } = productStore();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventData && selectedEventData.data.type === "human") {
|
||||||
|
const point = getPointByUuid(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
|
selectedEventData.selectedPoint
|
||||||
|
) as HumanPointSchema | undefined;
|
||||||
|
|
||||||
|
if (point?.action) {
|
||||||
|
setSelectedPointData(point);
|
||||||
|
setCurrentAction(point.action);
|
||||||
|
setSelectedAction(point.action.actionUuid, point.action.actionName);
|
||||||
|
setSpeed((
|
||||||
|
getEventByModelUuid(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedEventData?.data.modelUuid || ""
|
||||||
|
) as HumanEventSchema | undefined
|
||||||
|
)?.speed?.toString() || "1");
|
||||||
|
setLoadCapacity(point.action.loadCapacity.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearSelectedAction();
|
||||||
|
}
|
||||||
|
}, [selectedEventData, selectedProduct]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventData && selectedProduct.productUuid) {
|
||||||
|
const point = getPointByUuid(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
|
selectedEventData.selectedPoint
|
||||||
|
) as HumanPointSchema | undefined;
|
||||||
|
|
||||||
|
if (point?.action) {
|
||||||
|
setSelectedPointData(point);
|
||||||
|
setCurrentAction(point.action);
|
||||||
|
setActiveOption(point.action.actionType);
|
||||||
|
setSelectedAction(point.action.actionUuid, point.action.actionName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearSelectedAction();
|
||||||
|
setCurrentAction(undefined);
|
||||||
|
setSpeed("0.5");
|
||||||
|
setLoadCapacity("1");
|
||||||
|
}
|
||||||
|
}, [selectedEventData, selectedProduct, selectedAction]);
|
||||||
|
|
||||||
|
const updateBackend = (
|
||||||
|
productName: string,
|
||||||
|
productUuid: string,
|
||||||
|
projectId: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName,
|
||||||
|
productUuid,
|
||||||
|
projectId,
|
||||||
|
eventDatas: eventData,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectActionType = (actionType: string) => {
|
||||||
|
if (!selectedAction.actionId || !currentAction || !selectedPointData) return;
|
||||||
|
|
||||||
|
const updatedAction = { ...currentAction, actionType: actionType as "worker" };
|
||||||
|
const updatedPoint = { ...selectedPointData, action: updatedAction };
|
||||||
|
|
||||||
|
const event = updateAction(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedAction.actionId,
|
||||||
|
updatedAction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentAction(updatedAction);
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSpeedChange = (value: string) => {
|
||||||
|
if (!selectedEventData) return;
|
||||||
|
|
||||||
|
const numericValue = parseFloat(value);
|
||||||
|
if (isNaN(numericValue)) return;
|
||||||
|
|
||||||
|
const updatedEvent = {
|
||||||
|
...selectedEventData.data,
|
||||||
|
speed: numericValue
|
||||||
|
} as HumanEventSchema;
|
||||||
|
|
||||||
|
const event = updateEvent(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
|
updatedEvent
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSpeed(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLoadCapacityChange = (value: string) => {
|
||||||
|
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
|
||||||
|
|
||||||
|
const updatedAction = { ...currentAction };
|
||||||
|
updatedAction.loadCapacity = parseInt(value)
|
||||||
|
|
||||||
|
const updatedPoint = { ...selectedPointData, action: updatedAction };
|
||||||
|
|
||||||
|
const event = updateAction(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedAction.actionId,
|
||||||
|
updatedAction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentAction(updatedAction);
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
setLoadCapacity(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClearPoints = () => {
|
||||||
|
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
|
||||||
|
|
||||||
|
const updatedAction = { ...currentAction };
|
||||||
|
delete updatedAction.pickUpPoint;
|
||||||
|
delete updatedAction.dropPoint;
|
||||||
|
|
||||||
|
const updatedPoint = { ...selectedPointData, action: updatedAction };
|
||||||
|
|
||||||
|
const event = updateAction(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedAction.actionId,
|
||||||
|
updatedAction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentAction(updatedAction);
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddAction = () => {
|
||||||
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
|
|
||||||
|
const newAction: HumanAction = {
|
||||||
|
actionUuid: MathUtils.generateUUID(),
|
||||||
|
actionName: `Action`,
|
||||||
|
actionType: "worker",
|
||||||
|
loadCapacity: 1,
|
||||||
|
triggers: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const event = addAction(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
|
selectedEventData.selectedPoint,
|
||||||
|
newAction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedPoint = { ...selectedPointData, action: newAction };
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
setSelectedAction(newAction.actionUuid, newAction.actionName);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteAction = () => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
|
||||||
|
const event = removeAction(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedPointData.action.actionUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedPoint = { ...selectedPointData, action: undefined as any };
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
clearSelectedAction();
|
||||||
|
setCurrentAction(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="global-props section">
|
||||||
|
<div className="property-list-container">
|
||||||
|
<div className="property-item">
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Speed"
|
||||||
|
value={speed}
|
||||||
|
min={0}
|
||||||
|
step={0.1}
|
||||||
|
defaultValue="0.5"
|
||||||
|
max={10}
|
||||||
|
activeOption="m/s"
|
||||||
|
onClick={() => { }}
|
||||||
|
onChange={handleSpeedChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<section>
|
||||||
|
<ActionsList
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
multipleAction={false}
|
||||||
|
handleAddAction={handleAddAction}
|
||||||
|
handleDeleteAction={handleDeleteAction}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{selectedAction.actionId && currentAction && (
|
||||||
|
<div className="selected-actions-details">
|
||||||
|
<div className="selected-actions-header">
|
||||||
|
<RenameInput value={selectedAction.actionName || ""} canEdit={false} />
|
||||||
|
</div>
|
||||||
|
<div className="selected-actions-list">
|
||||||
|
<LabledDropdown
|
||||||
|
label="Action Type"
|
||||||
|
defaultOption={activeOption}
|
||||||
|
options={["worker"]}
|
||||||
|
onSelect={handleSelectActionType}
|
||||||
|
disabled={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<WorkerAction
|
||||||
|
loadCapacity={{
|
||||||
|
value: loadCapacity,
|
||||||
|
min: 1,
|
||||||
|
max: 5,
|
||||||
|
step: 1,
|
||||||
|
defaultValue: "1",
|
||||||
|
disabled: true,
|
||||||
|
onChange: handleLoadCapacityChange,
|
||||||
|
}}
|
||||||
|
clearPoints={handleClearPoints}
|
||||||
|
/>
|
||||||
|
<div className="tirgger">
|
||||||
|
<Trigger selectedPointData={selectedPointData as any} type="Human" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HumanMechanics;
|
||||||
@@ -274,14 +274,6 @@ function VehicleMechanics() {
|
|||||||
onChange: handleUnloadDurationChange,
|
onChange: handleUnloadDurationChange,
|
||||||
}}
|
}}
|
||||||
clearPoints={handleClearPoints}
|
clearPoints={handleClearPoints}
|
||||||
// pickPoint={{
|
|
||||||
// value: currentPickPoint,
|
|
||||||
// onChange: handlePickPointChange,
|
|
||||||
// }}
|
|
||||||
// unloadPoint={{
|
|
||||||
// value: currentUnloadPoint,
|
|
||||||
// onChange: handleUnloadPointChange,
|
|
||||||
// }}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
|||||||
|
|
||||||
type TriggerProps = {
|
type TriggerProps = {
|
||||||
selectedPointData?: PointsScheme | undefined;
|
selectedPointData?: PointsScheme | undefined;
|
||||||
type?: "Conveyor" | "Vehicle" | "RoboticArm" | "Machine" | "StorageUnit";
|
type?: "Conveyor" | "Vehicle" | "RoboticArm" | "Machine" | "StorageUnit" | "Human";
|
||||||
};
|
};
|
||||||
|
|
||||||
const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
||||||
@@ -38,7 +38,7 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
|||||||
|
|
||||||
if (type === "Conveyor" || type === "Vehicle" || type === "Machine" || type === "StorageUnit") {
|
if (type === "Conveyor" || type === "Vehicle" || type === "Machine" || type === "StorageUnit") {
|
||||||
actionUuid = (selectedPointData as | ConveyorPointSchema | VehiclePointSchema | MachinePointSchema | StoragePointSchema).action?.actionUuid;
|
actionUuid = (selectedPointData as | ConveyorPointSchema | VehiclePointSchema | MachinePointSchema | StoragePointSchema).action?.actionUuid;
|
||||||
} else if (type === "RoboticArm" && selectedAction.actionId) {
|
} else if ((type === "RoboticArm" || type === "Human") && selectedAction.actionId) {
|
||||||
actionUuid = selectedAction.actionId;
|
actionUuid = selectedAction.actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,18 +365,16 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
{triggers.length > 1 && (
|
<button
|
||||||
<button
|
id="remove-trigger-button"
|
||||||
id="remove-trigger-button"
|
className="remove-button"
|
||||||
className="remove-button"
|
onClick={(e) => {
|
||||||
onClick={(e) => {
|
e.stopPropagation();
|
||||||
e.stopPropagation();
|
handleRemoveTrigger(trigger.triggerUuid);
|
||||||
handleRemoveTrigger(trigger.triggerUuid);
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<RemoveIcon />
|
||||||
<RemoveIcon />
|
</button>
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ const VersionHistory = () => {
|
|||||||
const handleSelectVersion = (version: Version) => {
|
const handleSelectVersion = (version: Version) => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
|
|
||||||
getVersionDataApi(projectId, version.versionId).then((verdionData) => {
|
getVersionDataApi(projectId, version.versionId).then((versionData) => {
|
||||||
setSelectedVersion(version);
|
setSelectedVersion(version);
|
||||||
// console.log(verdionData);
|
// console.log(versionData);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
// console.log(err);
|
// console.log(err);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ type InputWithDropDownProps = {
|
|||||||
max?: number;
|
max?: number;
|
||||||
step?: number;
|
step?: number;
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
|
disabled?: boolean;
|
||||||
options?: string[]; // Array of dropdown options
|
options?: string[]; // Array of dropdown options
|
||||||
activeOption?: string; // The currently active dropdown option
|
activeOption?: string; // The currently active dropdown option
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
@@ -23,6 +24,7 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
|||||||
max,
|
max,
|
||||||
step,
|
step,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
|
disabled = false,
|
||||||
options,
|
options,
|
||||||
activeOption,
|
activeOption,
|
||||||
onClick,
|
onClick,
|
||||||
@@ -54,6 +56,7 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
|||||||
type="number"
|
type="number"
|
||||||
defaultValue={value}
|
defaultValue={value}
|
||||||
// value={value}
|
// value={value}
|
||||||
|
disabled={disabled}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ interface RenameInputProps {
|
|||||||
value: string;
|
value: string;
|
||||||
onRename?: (newText: string) => void;
|
onRename?: (newText: string) => void;
|
||||||
checkDuplicate?: (name: string) => boolean;
|
checkDuplicate?: (name: string) => boolean;
|
||||||
|
canEdit?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplicate }) => {
|
const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplicate, canEdit = true }) => {
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const [text, setText] = useState(value);
|
const [text, setText] = useState(value);
|
||||||
const [isDuplicate, setIsDuplicate] = useState(false);
|
const [isDuplicate, setIsDuplicate] = useState(false);
|
||||||
@@ -28,13 +29,15 @@ const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplica
|
|||||||
}, [text, checkDuplicate]);
|
}, [text, checkDuplicate]);
|
||||||
|
|
||||||
const handleDoubleClick = () => {
|
const handleDoubleClick = () => {
|
||||||
setIsEditing(true);
|
if (canEdit) {
|
||||||
setTimeout(() => inputRef.current?.focus(), 0);
|
setIsEditing(true);
|
||||||
|
setTimeout(() => inputRef.current?.focus(), 0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
|
|
||||||
if(isDuplicate) return
|
if (isDuplicate) return
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
if (onRename && !isDuplicate) {
|
if (onRename && !isDuplicate) {
|
||||||
onRename(text);
|
onRename(text);
|
||||||
|
|||||||
@@ -44,16 +44,19 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
|||||||
remove,
|
remove,
|
||||||
}) => {
|
}) => {
|
||||||
const [isOpen, setIsOpen] = useState<boolean>(defaultOpen);
|
const [isOpen, setIsOpen] = useState<boolean>(defaultOpen);
|
||||||
const { zones } = useZones();
|
// const { zones } = useZones();
|
||||||
|
|
||||||
const handleToggle = () => {
|
const handleToggle = () => {
|
||||||
setIsOpen((prev) => !prev); // Toggle the state
|
setIsOpen((prev) => !prev); // Toggle the state
|
||||||
};
|
};
|
||||||
|
|
||||||
const [zoneDataList, setZoneDataList] = useState<ZoneData[]>([]);
|
const [zoneDataList, setZoneDataList] = useState<ZoneData[]>([]);
|
||||||
const { assetStore } = useSceneContext();
|
// const { assetStore } = useSceneContext();
|
||||||
|
const { assetStore, zoneStore } = useSceneContext();
|
||||||
const { assets } = assetStore();
|
const { assets } = assetStore();
|
||||||
|
const { zones } = zoneStore()
|
||||||
|
|
||||||
|
|
||||||
const isPointInsidePolygon = (
|
const isPointInsidePolygon = (
|
||||||
point: [number, number],
|
point: [number, number],
|
||||||
polygon: [number, number][]
|
polygon: [number, number][]
|
||||||
@@ -76,7 +79,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updatedZoneList: ZoneData[] = zones?.map((zone: Zone) => {
|
const updatedZoneList: ZoneData[] = zones?.map((zone: any) => {
|
||||||
const polygon2D = zone.points.map((p: [number, number, number]) => [
|
const polygon2D = zone.points.map((p: [number, number, number]) => [
|
||||||
p[0],
|
p[0],
|
||||||
p[2],
|
p[2],
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
||||||
const { zones, setZones } = useZones();
|
|
||||||
const { setSubModule } = useSubModuleStore();
|
const { setSubModule } = useSubModuleStore();
|
||||||
const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>({});
|
const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>({});
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
@@ -55,6 +55,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||||||
const { organization } = getUserData();
|
const { organization } = getUserData();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { zoneStore } = useSceneContext();
|
||||||
|
const { zones, setZoneName } = zoneStore()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
useSelectedZoneStore.getState().setSelectedZone({
|
useSelectedZoneStore.getState().setSelectedZone({
|
||||||
@@ -92,8 +94,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||||||
lockedPanels: response?.lockedPanels ?? [],
|
lockedPanels: response?.lockedPanels ?? [],
|
||||||
widgets: response?.widgets ?? [],
|
widgets: response?.widgets ?? [],
|
||||||
zoneUuid: response?.zoneUuid,
|
zoneUuid: response?.zoneUuid,
|
||||||
zoneViewPortTarget: response?.viewPortCenter ?? [],
|
zoneViewPortTarget: response?.viewPortTarget ?? [],
|
||||||
zoneViewPortPosition: response?.viewPortposition ?? [],
|
zoneViewPortPosition: response?.viewPortPosition ?? [],
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
echo.error("Failed to select zone");
|
echo.error("Failed to select zone");
|
||||||
@@ -123,13 +125,14 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||||||
const response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
const response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
||||||
if (response.message === "zone updated") {
|
if (response.message === "zone updated") {
|
||||||
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
||||||
setZones((prevZones: any[]) =>
|
setZoneName(selectedZone.zoneUuid, newName)
|
||||||
prevZones.map((zone) =>
|
// setZones((prevZones: any[]) =>
|
||||||
zone.zoneUuid === selectedZone.zoneUuid
|
// prevZones.map((zone) =>
|
||||||
? { ...zone, zoneName: newName }
|
// zone.zoneUuid === selectedZone.zoneUuid
|
||||||
: zone
|
// ? { ...zone, zoneName: newName }
|
||||||
)
|
// : zone
|
||||||
);
|
// )
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
|||||||
import { useThree } from '@react-three/fiber';
|
import { useThree } from '@react-three/fiber';
|
||||||
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||||
import { upsertAisleApi } from '../../../../services/factoryBuilder/aisle/upsertAisleApi';
|
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useVersionContext } from '../../version/versionContext';
|
import { useVersionContext } from '../../version/versionContext';
|
||||||
import { useSceneContext } from '../../../scene/sceneContext';
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
import ReferenceAisle from './referenceAisle';
|
import ReferenceAisle from './referenceAisle';
|
||||||
import ReferencePoint from '../../point/reference/referencePoint';
|
import ReferencePoint from '../../point/reference/referencePoint';
|
||||||
|
import { getUserData } from '../../../../functions/getUserData';
|
||||||
|
|
||||||
|
// import { upsertAisleApi } from '../../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||||
|
|
||||||
function AisleCreator() {
|
function AisleCreator() {
|
||||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||||
@@ -23,6 +25,7 @@ function AisleCreator() {
|
|||||||
const isLeftMouseDown = useRef(false);
|
const isLeftMouseDown = useRef(false);
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
|
|
||||||
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||||
@@ -106,7 +109,22 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
points: aisle.points,
|
||||||
|
type: aisle.type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -129,7 +147,22 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
points: aisle.points,
|
||||||
|
type: aisle.type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -151,7 +184,22 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
points: aisle.points,
|
||||||
|
type: aisle.type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -172,7 +220,22 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
points: aisle.points,
|
||||||
|
type: aisle.type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -195,7 +258,22 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
points: aisle.points,
|
||||||
|
type: aisle.type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -217,7 +295,22 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
points: aisle.points,
|
||||||
|
type: aisle.type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -238,7 +331,22 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
points: aisle.points,
|
||||||
|
type: aisle.type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -260,7 +368,22 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
points: aisle.points,
|
||||||
|
type: aisle.type
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as THREE from "three"
|
import * as THREE from "three"
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
|
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
|
||||||
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
||||||
@@ -226,7 +226,8 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
|||||||
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], state: "idle",
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
type: "storageUnit",
|
type: "storageUnit",
|
||||||
point: {
|
point: {
|
||||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||||
@@ -242,6 +243,30 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
addEvent(storageEvent);
|
addEvent(storageEvent);
|
||||||
|
} else if (item.eventData.type === 'Human') {
|
||||||
|
const humanEvent: HumanEventSchema = {
|
||||||
|
modelUuid: item.modelUuid,
|
||||||
|
modelName: item.modelName,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "human",
|
||||||
|
speed: 1,
|
||||||
|
point: {
|
||||||
|
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||||
|
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||||
|
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Action 1",
|
||||||
|
actionType: "worker",
|
||||||
|
loadCapacity: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addEvent(humanEvent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assets.push({
|
assets.push({
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ async function handleModelLoad(
|
|||||||
|
|
||||||
if (!data || !data.points) return;
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
const eventData: any = { type: selectedItem.type, };
|
const eventData: any = { type: selectedItem.type };
|
||||||
|
|
||||||
if (selectedItem.type === "Conveyor") {
|
if (selectedItem.type === "Conveyor") {
|
||||||
const ConveyorEvent: ConveyorEventSchema = {
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
@@ -360,6 +360,35 @@ async function handleModelLoad(
|
|||||||
position: storageEvent.point.position,
|
position: storageEvent.point.position,
|
||||||
rotation: storageEvent.point.rotation,
|
rotation: storageEvent.point.rotation,
|
||||||
};
|
};
|
||||||
|
} else if (selectedItem.type === "Human") {
|
||||||
|
const humanEvent: HumanEventSchema = {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: newFloorItem.rotation,
|
||||||
|
state: "idle",
|
||||||
|
type: "human",
|
||||||
|
speed: 1,
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Action 1",
|
||||||
|
actionType: "worker",
|
||||||
|
loadCapacity: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addEvent(humanEvent);
|
||||||
|
eventData.point = {
|
||||||
|
uuid: humanEvent.point.uuid,
|
||||||
|
position: humanEvent.point.position,
|
||||||
|
rotation: humanEvent.point.rotation,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const completeData = {
|
const completeData = {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
|||||||
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||||
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||||
import { CameraControls, Html } from '@react-three/drei';
|
import { CameraControls } from '@react-three/drei';
|
||||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||||
import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore';
|
import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore';
|
||||||
import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore';
|
import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore';
|
||||||
@@ -15,6 +15,8 @@ import { useParams } from 'react-router-dom';
|
|||||||
import { getUserData } from '../../../../../functions/getUserData';
|
import { getUserData } from '../../../../../functions/getUserData';
|
||||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||||
import { useVersionContext } from '../../../version/versionContext';
|
import { useVersionContext } from '../../../version/versionContext';
|
||||||
|
import { SkeletonUtils } from 'three-stdlib';
|
||||||
|
import { useAnimationPlaySpeed } from '../../../../../store/usePlayButtonStore';
|
||||||
|
|
||||||
function Model({ asset }: { readonly asset: Asset }) {
|
function Model({ asset }: { readonly asset: Asset }) {
|
||||||
const { camera, controls, gl } = useThree();
|
const { camera, controls, gl } = useThree();
|
||||||
@@ -22,8 +24,9 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { subModule } = useSubModuleStore();
|
const { subModule } = useSubModuleStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
|
const { speed } = useAnimationPlaySpeed();
|
||||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||||
const { assets, removeAsset, setAnimations } = assetStore();
|
const { removeAsset, setAnimations, resetAnimation, setAnimationComplete, setCurrentAnimation: setAnmationAnimation } = assetStore();
|
||||||
const { setTop } = useTopData();
|
const { setTop } = useTopData();
|
||||||
const { setLeft } = useLeftData();
|
const { setLeft } = useLeftData();
|
||||||
const { getIsEventInProduct } = productStore();
|
const { getIsEventInProduct } = productStore();
|
||||||
@@ -33,7 +36,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
const { limitDistance } = useLimitDistance();
|
const { limitDistance } = useLimitDistance();
|
||||||
const { renderDistance } = useRenderDistance();
|
const { renderDistance } = useRenderDistance();
|
||||||
const [isRendered, setIsRendered] = useState(false);
|
const [isRendered, setIsRendered] = useState(false);
|
||||||
@@ -46,13 +49,18 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const [animationNames, setAnimationNames] = useState<string[]>([]);
|
|
||||||
const mixerRef = useRef<THREE.AnimationMixer>();
|
const mixerRef = useRef<THREE.AnimationMixer>();
|
||||||
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
||||||
|
const [previousAnimation, setPreviousAnimation] = useState<string | null>(null);
|
||||||
|
const blendFactor = useRef(0);
|
||||||
|
const blendDuration = 0.5;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDeletableFloorItem(null);
|
setDeletableFloorItem(null);
|
||||||
}, [activeModule, toolMode])
|
if (selectedFloorItem === null) {
|
||||||
|
resetAnimation(asset.modelUuid);
|
||||||
|
}
|
||||||
|
}, [activeModule, toolMode, selectedFloorItem])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
@@ -62,40 +70,21 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
loader.setDRACOLoader(dracoLoader);
|
loader.setDRACOLoader(dracoLoader);
|
||||||
const loadModel = async () => {
|
const loadModel = async () => {
|
||||||
try {
|
try {
|
||||||
// Check Cache
|
|
||||||
// const assetId = asset.assetId;
|
|
||||||
// const cachedModel = THREE.Cache.get(assetId);
|
|
||||||
// if (cachedModel) {
|
|
||||||
// setGltfScene(cachedModel.scene.clone());
|
|
||||||
// calculateBoundingBox(cachedModel.scene);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Check Cache
|
// Check Cache
|
||||||
// const assetId = asset.assetId;
|
|
||||||
// console.log('assetId: ', assetId);
|
|
||||||
// const cachedModel = THREE.Cache.get(assetId);
|
|
||||||
// console.log('cachedModel: ', cachedModel);
|
|
||||||
// if (cachedModel) {
|
|
||||||
// setGltfScene(cachedModel.scene.clone());
|
|
||||||
// calculateBoundingBox(cachedModel.scene);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const assetId = asset.assetId;
|
const assetId = asset.assetId;
|
||||||
const cachedModel = THREE.Cache.get(assetId);
|
const cachedModel = THREE.Cache.get(assetId);
|
||||||
if (cachedModel) {
|
if (cachedModel) {
|
||||||
const clonedScene = cachedModel.scene.clone();
|
const clone: any = SkeletonUtils.clone(cachedModel.scene);
|
||||||
clonedScene.animations = cachedModel.animations || [];
|
clone.animations = cachedModel.animations || [];
|
||||||
setGltfScene(clonedScene);
|
setGltfScene(clone);
|
||||||
calculateBoundingBox(clonedScene);
|
calculateBoundingBox(clone);
|
||||||
if (cachedModel.animations && clonedScene.animations.length > 0) {
|
if (cachedModel.animations && clone.animations.length > 0) {
|
||||||
const animationName = clonedScene.animations.map((clip: any) => clip.name);
|
const animationName = clone.animations.map((clip: any) => clip.name);
|
||||||
setAnimationNames(animationName)
|
|
||||||
setAnimations(asset.modelUuid, animationName)
|
setAnimations(asset.modelUuid, animationName)
|
||||||
mixerRef.current = new THREE.AnimationMixer(clonedScene);
|
mixerRef.current = new THREE.AnimationMixer(clone);
|
||||||
|
|
||||||
clonedScene.animations.forEach((animation: any) => {
|
clone.animations.forEach((animation: any) => {
|
||||||
const action = mixerRef.current!.clipAction(animation);
|
const action = mixerRef.current!.clipAction(animation);
|
||||||
actions.current[animation.name] = action;
|
actions.current[animation.name] = action;
|
||||||
});
|
});
|
||||||
@@ -293,28 +282,50 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
clearSelectedAsset()
|
clearSelectedAsset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleAnimationComplete = useCallback(() => {
|
||||||
|
if (asset.animationState) {
|
||||||
|
setAnimationComplete(asset.modelUuid, true);
|
||||||
|
}
|
||||||
|
}, [asset.animationState]);
|
||||||
|
|
||||||
useFrame((_, delta) => {
|
useFrame((_, delta) => {
|
||||||
if (mixerRef.current) {
|
if (mixerRef.current) {
|
||||||
mixerRef.current.update(delta);
|
mixerRef.current.update(delta * speed);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handlePlay = (clipName: string) => {
|
if (!asset.animationState || !mixerRef.current) return;
|
||||||
if (!mixerRef.current) return;
|
|
||||||
|
|
||||||
|
const { current, loopAnimation, isPlaying } = asset.animationState;
|
||||||
|
const currentAction = actions.current[current];
|
||||||
|
const previousAction = previousAnimation ? actions.current[previousAnimation] : null;
|
||||||
|
|
||||||
|
if (isPlaying && currentAction) {
|
||||||
|
blendFactor.current = 0;
|
||||||
|
|
||||||
|
currentAction.reset();
|
||||||
|
currentAction.setLoop(loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce, loopAnimation ? Infinity : 1);
|
||||||
|
currentAction.clampWhenFinished = true;
|
||||||
|
|
||||||
|
if (previousAction && previousAction !== currentAction) {
|
||||||
|
previousAction.crossFadeTo(currentAction, blendDuration, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentAction.play();
|
||||||
|
mixerRef.current.addEventListener('finished', handleAnimationComplete);
|
||||||
|
setPreviousAnimation(current);
|
||||||
|
} else {
|
||||||
Object.values(actions.current).forEach((action) => action.stop());
|
Object.values(actions.current).forEach((action) => action.stop());
|
||||||
|
}
|
||||||
|
|
||||||
const action = actions.current[clipName];
|
return () => {
|
||||||
if (action && asset.animationState?.playing) {
|
if (mixerRef.current) {
|
||||||
action.reset().setLoop(THREE.LoopOnce, 1).play();
|
mixerRef.current.removeEventListener('finished', handleAnimationComplete);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}, [asset.animationState?.current, asset.animationState?.isPlaying]);
|
||||||
handlePlay(asset.animationState?.current || '');
|
|
||||||
|
|
||||||
}, [asset])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<group
|
||||||
@@ -362,17 +373,6 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
<AssetBoundingBox boundingBox={boundingBox} />
|
<AssetBoundingBox boundingBox={boundingBox} />
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
{/* <group >
|
|
||||||
<Html>
|
|
||||||
<div style={{ position: 'absolute', }}>
|
|
||||||
{animationNames.map((name) => (
|
|
||||||
<button key={name} onClick={() => handlePlay(name)} style={{ margin: 4 }}>
|
|
||||||
{name}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</Html>
|
|
||||||
</group> */}
|
|
||||||
</group >
|
</group >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { useParams } from 'react-router-dom';
|
|||||||
import { useVersionContext } from '../version/versionContext';
|
import { useVersionContext } from '../version/versionContext';
|
||||||
import { useSceneContext } from '../../scene/sceneContext';
|
import { useSceneContext } from '../../scene/sceneContext';
|
||||||
|
|
||||||
import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAisleApi';
|
// import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||||
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
// import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
||||||
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||||
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||||
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||||
@@ -159,7 +159,22 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
const updatedAisles = getAislesByPointId(point.pointUuid);
|
const updatedAisles = getAislesByPointId(point.pointUuid);
|
||||||
if (updatedAisles.length > 0 && projectId) {
|
if (updatedAisles.length > 0 && projectId) {
|
||||||
updatedAisles.forEach((updatedAisle) => {
|
updatedAisles.forEach((updatedAisle) => {
|
||||||
upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:add', {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: updatedAisle.aisleUuid,
|
||||||
|
points: updatedAisle.points,
|
||||||
|
type: updatedAisle.type
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if (point.pointType === 'Wall') {
|
} else if (point.pointType === 'Wall') {
|
||||||
@@ -238,7 +253,22 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
if (removedAisles.length > 0) {
|
if (removedAisles.length > 0) {
|
||||||
removedAisles.forEach(aisle => {
|
removedAisles.forEach(aisle => {
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '')
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '');
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-aisle:delete', data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setHoveredPoint(null);
|
setHoveredPoint(null);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ function ZoneCreator() {
|
|||||||
const { activeLayer } = useActiveLayer();
|
const { activeLayer } = useActiveLayer();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { zoneStore } = useSceneContext();
|
const { zoneStore } = useSceneContext();
|
||||||
const { addZone, getZonePointById, getZoneByPoints } = zoneStore();
|
const { zones, addZone, getZonePointById, getZoneByPoints } = zoneStore();
|
||||||
const drag = useRef(false);
|
const drag = useRef(false);
|
||||||
const isLeftMouseDown = useRef(false);
|
const isLeftMouseDown = useRef(false);
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
@@ -32,6 +32,7 @@ function ZoneCreator() {
|
|||||||
const [isCreating, setIsCreating] = useState(false);
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
const { zoneColor, zoneHeight, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore();
|
const { zoneColor, zoneHeight, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore();
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ function ZoneCreator() {
|
|||||||
if (tempPoints.length > 2 && isCreating && snappedPoint && snappedPoint.pointUuid === tempPoints[0].pointUuid) {
|
if (tempPoints.length > 2 && isCreating && snappedPoint && snappedPoint.pointUuid === tempPoints[0].pointUuid) {
|
||||||
const zone: Zone = {
|
const zone: Zone = {
|
||||||
zoneUuid: THREE.MathUtils.generateUUID(),
|
zoneUuid: THREE.MathUtils.generateUUID(),
|
||||||
zoneName: "Zone",
|
zoneName: `Zone `,
|
||||||
points: tempPoints,
|
points: tempPoints,
|
||||||
zoneColor,
|
zoneColor,
|
||||||
zoneHeight,
|
zoneHeight,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export default function SocketResponses() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
socket.on("v1:model-asset:response:add", (data: any) => {
|
socket.on("v1:model-asset:response:add", (data: any) => {
|
||||||
console.log('data: ', data);
|
// console.log('data: ', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -332,6 +332,34 @@ const CopyPasteControls = ({
|
|||||||
position: storageEvent.point.position,
|
position: storageEvent.point.position,
|
||||||
rotation: storageEvent.point.rotation
|
rotation: storageEvent.point.rotation
|
||||||
};
|
};
|
||||||
|
} else if (obj.userData.eventData.type === "Human") {
|
||||||
|
const humanEvent: HumanEventSchema = {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "human",
|
||||||
|
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: "worker",
|
||||||
|
loadCapacity: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addEvent(humanEvent);
|
||||||
|
eventData.point = {
|
||||||
|
uuid: humanEvent.point.uuid,
|
||||||
|
position: humanEvent.point.position,
|
||||||
|
rotation: humanEvent.point.rotation
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
newFloorItem.eventData = eventData;
|
newFloorItem.eventData = eventData;
|
||||||
|
|||||||
@@ -306,6 +306,34 @@ const DuplicationControls = ({
|
|||||||
position: storageEvent.point.position,
|
position: storageEvent.point.position,
|
||||||
rotation: storageEvent.point.rotation
|
rotation: storageEvent.point.rotation
|
||||||
};
|
};
|
||||||
|
} else if (obj.userData.eventData.type === "Human") {
|
||||||
|
const humanEvent: HumanEventSchema = {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "human",
|
||||||
|
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: "worker",
|
||||||
|
loadCapacity: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addEvent(humanEvent);
|
||||||
|
eventData.point = {
|
||||||
|
uuid: humanEvent.point.uuid,
|
||||||
|
position: humanEvent.point.position,
|
||||||
|
rotation: humanEvent.point.rotation
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
newFloorItem.eventData = eventData;
|
newFloorItem.eventData = eventData;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { createMachineStore, MachineStoreType } from '../../store/simulation/use
|
|||||||
import { createConveyorStore, ConveyorStoreType } from '../../store/simulation/useConveyorStore';
|
import { createConveyorStore, ConveyorStoreType } from '../../store/simulation/useConveyorStore';
|
||||||
import { createVehicleStore, VehicleStoreType } from '../../store/simulation/useVehicleStore';
|
import { createVehicleStore, VehicleStoreType } from '../../store/simulation/useVehicleStore';
|
||||||
import { createStorageUnitStore, StorageUnitStoreType } from '../../store/simulation/useStorageUnitStore';
|
import { createStorageUnitStore, StorageUnitStoreType } from '../../store/simulation/useStorageUnitStore';
|
||||||
|
import { createHumanStore, HumanStoreType } from '../../store/simulation/useHumanStore';
|
||||||
|
|
||||||
type SceneContextValue = {
|
type SceneContextValue = {
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ type SceneContextValue = {
|
|||||||
conveyorStore: ConveyorStoreType;
|
conveyorStore: ConveyorStoreType;
|
||||||
vehicleStore: VehicleStoreType;
|
vehicleStore: VehicleStoreType;
|
||||||
storageUnitStore: StorageUnitStoreType;
|
storageUnitStore: StorageUnitStoreType;
|
||||||
|
humanStore: HumanStoreType;
|
||||||
|
|
||||||
clearStores: () => void;
|
clearStores: () => void;
|
||||||
|
|
||||||
@@ -67,6 +69,7 @@ export function SceneProvider({
|
|||||||
const conveyorStore = useMemo(() => createConveyorStore(), []);
|
const conveyorStore = useMemo(() => createConveyorStore(), []);
|
||||||
const vehicleStore = useMemo(() => createVehicleStore(), []);
|
const vehicleStore = useMemo(() => createVehicleStore(), []);
|
||||||
const storageUnitStore = useMemo(() => createStorageUnitStore(), []);
|
const storageUnitStore = useMemo(() => createStorageUnitStore(), []);
|
||||||
|
const humanStore = useMemo(() => createHumanStore(), []);
|
||||||
|
|
||||||
const clearStores = useMemo(() => () => {
|
const clearStores = useMemo(() => () => {
|
||||||
assetStore.getState().clearAssets();
|
assetStore.getState().clearAssets();
|
||||||
@@ -83,7 +86,8 @@ export function SceneProvider({
|
|||||||
conveyorStore.getState().clearConveyors();
|
conveyorStore.getState().clearConveyors();
|
||||||
vehicleStore.getState().clearVehicles();
|
vehicleStore.getState().clearVehicles();
|
||||||
storageUnitStore.getState().clearStorageUnits();
|
storageUnitStore.getState().clearStorageUnits();
|
||||||
}, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]);
|
humanStore.getState().clearHumans();
|
||||||
|
}, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore]);
|
||||||
|
|
||||||
const contextValue = useMemo(() => (
|
const contextValue = useMemo(() => (
|
||||||
{
|
{
|
||||||
@@ -101,10 +105,11 @@ export function SceneProvider({
|
|||||||
conveyorStore,
|
conveyorStore,
|
||||||
vehicleStore,
|
vehicleStore,
|
||||||
storageUnitStore,
|
storageUnitStore,
|
||||||
|
humanStore,
|
||||||
clearStores,
|
clearStores,
|
||||||
layout
|
layout
|
||||||
}
|
}
|
||||||
), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]);
|
), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, clearStores, layout]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SceneContext.Provider value={contextValue}>
|
<SceneContext.Provider value={contextValue}>
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { useCallback } from "react";
|
||||||
|
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||||
|
import { useProductContext } from "../../../products/productContext";
|
||||||
|
|
||||||
|
export function useWorkerHandler() {
|
||||||
|
const { materialStore, humanStore, productStore } = useSceneContext();
|
||||||
|
const { getMaterialById } = materialStore();
|
||||||
|
const { getModelUuidByActionUuid } = productStore();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
const { incrementHumanLoad, addCurrentMaterial } = humanStore();
|
||||||
|
|
||||||
|
const workerLogStatus = (materialUuid: string, status: string) => {
|
||||||
|
echo.info(`${materialUuid}, ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleWorker = useCallback((action: HumanAction, materialId?: string) => {
|
||||||
|
if (!action || action.actionType !== 'worker' || !materialId) return;
|
||||||
|
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (!material) return;
|
||||||
|
|
||||||
|
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||||
|
if (!modelUuid) return;
|
||||||
|
|
||||||
|
incrementHumanLoad(modelUuid, 1);
|
||||||
|
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
|
||||||
|
|
||||||
|
workerLogStatus(material.materialName, `performing worker action`);
|
||||||
|
|
||||||
|
}, [getMaterialById]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleWorker,
|
||||||
|
};
|
||||||
|
}
|
||||||
36
app/src/modules/simulation/actions/human/useHumanActions.ts
Normal file
36
app/src/modules/simulation/actions/human/useHumanActions.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { useEffect, useCallback } from 'react';
|
||||||
|
import { useWorkerHandler } from './actionHandler/useWorkerHandler';
|
||||||
|
|
||||||
|
export function useHumanActions() {
|
||||||
|
const { handleWorker } = useWorkerHandler();
|
||||||
|
|
||||||
|
const handleWorkerAction = useCallback((action: HumanAction, materialId: string) => {
|
||||||
|
handleWorker(action, materialId);
|
||||||
|
}, [handleWorker]);
|
||||||
|
|
||||||
|
const handleHumanAction = useCallback((action: HumanAction, materialId: string) => {
|
||||||
|
if (!action) return;
|
||||||
|
|
||||||
|
switch (action.actionType) {
|
||||||
|
case 'worker':
|
||||||
|
handleWorkerAction(action, materialId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Unknown Human action type: ${action.actionType}`);
|
||||||
|
}
|
||||||
|
}, [handleWorkerAction]);
|
||||||
|
|
||||||
|
const cleanup = useCallback(() => {
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
cleanup();
|
||||||
|
};
|
||||||
|
}, [cleanup]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleHumanAction,
|
||||||
|
cleanup
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ export function useStorageActions() {
|
|||||||
default:
|
default:
|
||||||
console.warn(`Unknown storage action type: ${action.actionType}`);
|
console.warn(`Unknown storage action type: ${action.actionType}`);
|
||||||
}
|
}
|
||||||
}, [handleStoreAction]);
|
}, [handleStoreAction, handleRetrieveAction]);
|
||||||
|
|
||||||
const cleanup = useCallback(() => {
|
const cleanup = useCallback(() => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { useMachineActions } from "./machine/useMachineActions";
|
|||||||
import { useRoboticArmActions } from "./roboticArm/useRoboticArmActions";
|
import { useRoboticArmActions } from "./roboticArm/useRoboticArmActions";
|
||||||
import { useStorageActions } from "./storageUnit/useStorageUnitActions";
|
import { useStorageActions } from "./storageUnit/useStorageUnitActions";
|
||||||
import { useVehicleActions } from "./vehicle/useVehicleActions";
|
import { useVehicleActions } from "./vehicle/useVehicleActions";
|
||||||
|
import { useHumanActions } from "./human/useHumanActions";
|
||||||
import { useCallback, useEffect } from "react";
|
import { useCallback, useEffect } from "react";
|
||||||
|
|
||||||
export function useActionHandler() {
|
export function useActionHandler() {
|
||||||
@@ -17,6 +18,7 @@ export function useActionHandler() {
|
|||||||
const { handleRoboticArmAction, cleanup: cleanupRoboticArm } = useRoboticArmActions();
|
const { handleRoboticArmAction, cleanup: cleanupRoboticArm } = useRoboticArmActions();
|
||||||
const { handleMachineAction, cleanup: cleanupMachine } = useMachineActions();
|
const { handleMachineAction, cleanup: cleanupMachine } = useMachineActions();
|
||||||
const { handleStorageAction, cleanup: cleanupStorage } = useStorageActions();
|
const { handleStorageAction, cleanup: cleanupStorage } = useStorageActions();
|
||||||
|
const { handleHumanAction, cleanup: cleanupHuman } = useHumanActions();
|
||||||
|
|
||||||
const handleAction = useCallback((action: Action, materialId?: string) => {
|
const handleAction = useCallback((action: Action, materialId?: string) => {
|
||||||
if (!action) return;
|
if (!action) return;
|
||||||
@@ -37,6 +39,9 @@ export function useActionHandler() {
|
|||||||
case 'store': case 'retrieve':
|
case 'store': case 'retrieve':
|
||||||
handleStorageAction(action as StorageAction, materialId as string);
|
handleStorageAction(action as StorageAction, materialId as string);
|
||||||
break;
|
break;
|
||||||
|
case 'worker':
|
||||||
|
handleHumanAction(action as HumanAction, materialId as string);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Unknown action type: ${(action as Action).actionType}`);
|
console.warn(`Unknown action type: ${(action as Action).actionType}`);
|
||||||
}
|
}
|
||||||
@@ -44,7 +49,7 @@ export function useActionHandler() {
|
|||||||
echo.error("Failed to handle action");
|
echo.error("Failed to handle action");
|
||||||
console.error("Error handling action:", error);
|
console.error("Error handling action:", error);
|
||||||
}
|
}
|
||||||
}, [handleConveyorAction, handleVehicleAction, handleRoboticArmAction, handleMachineAction, handleStorageAction,]);
|
}, [handleConveyorAction, handleVehicleAction, handleRoboticArmAction, handleMachineAction, handleStorageAction, handleHumanAction]);
|
||||||
|
|
||||||
const cleanup = useCallback(() => {
|
const cleanup = useCallback(() => {
|
||||||
cleanupConveyor();
|
cleanupConveyor();
|
||||||
@@ -52,7 +57,8 @@ export function useActionHandler() {
|
|||||||
cleanupRoboticArm();
|
cleanupRoboticArm();
|
||||||
cleanupMachine();
|
cleanupMachine();
|
||||||
cleanupStorage();
|
cleanupStorage();
|
||||||
}, [cleanupConveyor, cleanupVehicle, cleanupRoboticArm, cleanupMachine, cleanupStorage,]);
|
cleanupHuman();
|
||||||
|
}, [cleanupConveyor, cleanupVehicle, cleanupRoboticArm, cleanupMachine, cleanupStorage, cleanupHuman]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
import React, { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store'
|
import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store'
|
||||||
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||||
import { useProductContext } from '../../products/productContext';
|
|
||||||
|
|
||||||
export default function ProductionCapacityData() {
|
export default function ProductionCapacityData() {
|
||||||
const { throughputData } = useThroughPutData()
|
const { throughputData } = useThroughPutData()
|
||||||
const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData()
|
const { setProductionCapacityData } = useProductionCapacityData()
|
||||||
const { inputValues } = useInputValues();
|
const { inputValues } = useInputValues();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
|
||||||
const { selectedProduct } = selectedProductStore();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPlaying) {
|
if (!isPlaying) {
|
||||||
|
|
||||||
setProductionCapacityData(0);
|
setProductionCapacityData(0);
|
||||||
}
|
}
|
||||||
}, [isPlaying]);
|
}, [isPlaying]);
|
||||||
@@ -26,8 +22,6 @@ export default function ProductionCapacityData() {
|
|||||||
const Monthly_working_days = workingDaysPerYear / 12;
|
const Monthly_working_days = workingDaysPerYear / 12;
|
||||||
const Production_capacity_per_month = throughputData * Monthly_working_days;
|
const Production_capacity_per_month = throughputData * Monthly_working_days;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setProductionCapacityData(Number(Production_capacity_per_month.toFixed(2)));
|
setProductionCapacityData(Number(Production_capacity_per_month.toFixed(2)));
|
||||||
}
|
}
|
||||||
}, [throughputData, inputValues, isPlaying]);
|
}, [throughputData, inputValues, isPlaying]);
|
||||||
|
|||||||
@@ -1,18 +1,9 @@
|
|||||||
import React, { useEffect } from 'react'
|
|
||||||
import { usePlayButtonStore } from '../../../store/usePlayButtonStore'
|
|
||||||
import ProductionCapacityData from './productionCapacity/productionCapacityData'
|
import ProductionCapacityData from './productionCapacity/productionCapacityData'
|
||||||
import ThroughPutData from './throughPut/throughPutData'
|
import ThroughPutData from './throughPut/throughPutData'
|
||||||
import ROIData from './ROI/roiData'
|
import ROIData from './ROI/roiData'
|
||||||
|
|
||||||
function SimulationAnalysis() {
|
function SimulationAnalysis() {
|
||||||
const { isPlaying } = usePlayButtonStore()
|
|
||||||
// useEffect(()=>{
|
|
||||||
// if (isPlaying) {
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// },[isPlaying])
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ThroughPutData />
|
<ThroughPutData />
|
||||||
|
|||||||
@@ -352,6 +352,37 @@ function PointsCreator() {
|
|||||||
</mesh>
|
</mesh>
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
|
} else if (usedEvent.type === "human") {
|
||||||
|
const point = usedEvent.point;
|
||||||
|
return (
|
||||||
|
<group
|
||||||
|
key={`${index}-${usedEvent.modelUuid}`}
|
||||||
|
position={usedEvent.position}
|
||||||
|
rotation={usedEvent.rotation}
|
||||||
|
>
|
||||||
|
<mesh
|
||||||
|
name="Event-Sphere"
|
||||||
|
uuid={point.uuid}
|
||||||
|
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (toolMode === 'cursor') {
|
||||||
|
setSelectedEventSphere(
|
||||||
|
sphereRefs.current[point.uuid]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
position={new THREE.Vector3(...point.position)}
|
||||||
|
userData={{
|
||||||
|
modelUuid: usedEvent.modelUuid,
|
||||||
|
pointUuid: point.uuid,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<sphereGeometry args={[0.1, 16, 16]} />
|
||||||
|
<meshStandardMaterial color="white" />
|
||||||
|
</mesh>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import React from 'react'
|
|
||||||
import PointsCreator from './creator/pointsCreator'
|
import PointsCreator from './creator/pointsCreator'
|
||||||
|
|
||||||
function Points() {
|
function Points() {
|
||||||
|
|||||||
@@ -152,6 +152,22 @@ function TriggerConnector() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Handle Human point
|
||||||
|
else if (event.type === "human" && 'point' in event) {
|
||||||
|
const point = event.point;
|
||||||
|
if (point.action?.triggers) {
|
||||||
|
point.action.triggers.forEach(trigger => {
|
||||||
|
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
|
||||||
|
newConnections.push({
|
||||||
|
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
|
||||||
|
startPointUuid: point.uuid,
|
||||||
|
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
trigger
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setConnections(newConnections);
|
setConnections(newConnections);
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { useFrame } from '@react-three/fiber';
|
||||||
|
import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore';
|
||||||
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
|
|
||||||
|
type HumanCallback = {
|
||||||
|
humanId: string;
|
||||||
|
callback: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useHumanEventManager() {
|
||||||
|
const { humanStore } = useSceneContext();
|
||||||
|
const { getHumanById } = humanStore();
|
||||||
|
const callbacksRef = useRef<HumanCallback[]>([]);
|
||||||
|
const isMonitoringRef = useRef(false);
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { isPaused } = usePauseButtonStore();
|
||||||
|
const { isReset } = useResetButtonStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isReset) {
|
||||||
|
callbacksRef.current = [];
|
||||||
|
}
|
||||||
|
}, [isReset])
|
||||||
|
|
||||||
|
// Add a new human to monitor
|
||||||
|
const addHumanToMonitor = (humanId: string, callback: () => void) => {
|
||||||
|
// Avoid duplicates
|
||||||
|
if (!callbacksRef.current.some((entry) => entry.humanId === humanId)) {
|
||||||
|
callbacksRef.current.push({ humanId, callback });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start monitoring if not already running
|
||||||
|
if (!isMonitoringRef.current) {
|
||||||
|
isMonitoringRef.current = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove a human from monitoring
|
||||||
|
const removeHumanFromMonitor = (humanId: string) => {
|
||||||
|
callbacksRef.current = callbacksRef.current.filter(
|
||||||
|
(entry) => entry.humanId !== humanId
|
||||||
|
);
|
||||||
|
|
||||||
|
// Stop monitoring if no more humans to track
|
||||||
|
if (callbacksRef.current.length === 0) {
|
||||||
|
isMonitoringRef.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check human states every frame
|
||||||
|
useFrame(() => {
|
||||||
|
if (!isMonitoringRef.current || callbacksRef.current.length === 0 || !isPlaying || isPaused) return;
|
||||||
|
|
||||||
|
callbacksRef.current.forEach(({ humanId, callback }) => {
|
||||||
|
const human = getHumanById(humanId);
|
||||||
|
if (human && human.isActive === false && human.state === 'idle' && human.isPicking && human.currentLoad < human.point.action.loadCapacity) {
|
||||||
|
callback();
|
||||||
|
removeHumanFromMonitor(humanId); // Remove after triggering
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cleanup on unmount
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
callbacksRef.current = [];
|
||||||
|
isMonitoringRef.current = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
addHumanToMonitor,
|
||||||
|
removeHumanFromMonitor,
|
||||||
|
};
|
||||||
|
}
|
||||||
40
app/src/modules/simulation/human/human.tsx
Normal file
40
app/src/modules/simulation/human/human.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useSelectedAnimation, useSelectedEventSphere } from '../../../store/simulation/useSimulationStore';
|
||||||
|
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
||||||
|
import { useSceneContext } from '../../scene/sceneContext';
|
||||||
|
import HumanInstances from './instances/humanInstances'
|
||||||
|
import HumanUi from './instances/instance/humanUi';
|
||||||
|
|
||||||
|
function Human() {
|
||||||
|
const { humanStore } = useSceneContext();
|
||||||
|
const { getHumanById } = humanStore();
|
||||||
|
const { selectedAnimation } = useSelectedAnimation();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const [isVehicleSelected, setIsHumanSelected] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventSphere) {
|
||||||
|
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
|
||||||
|
if (selectedHuman) {
|
||||||
|
setIsHumanSelected(true);
|
||||||
|
} else {
|
||||||
|
setIsHumanSelected(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [getHumanById, selectedEventSphere, selectedAnimation])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<HumanInstances />
|
||||||
|
|
||||||
|
{isVehicleSelected && selectedEventSphere && !isPlaying &&
|
||||||
|
<HumanUi />
|
||||||
|
}
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Human
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { Line } from '@react-three/drei';
|
||||||
|
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
|
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||||
|
|
||||||
|
interface HumanAnimatorProps {
|
||||||
|
path: [number, number, number][];
|
||||||
|
handleCallBack: () => void;
|
||||||
|
reset: () => void;
|
||||||
|
startUnloadingProcess: () => void;
|
||||||
|
currentPhase: string;
|
||||||
|
human: HumanStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, startUnloadingProcess }: Readonly<HumanAnimatorProps>) {
|
||||||
|
const { humanStore, assetStore } = useSceneContext();
|
||||||
|
const { getHumanById } = humanStore();
|
||||||
|
const { setCurrentAnimation } = assetStore();
|
||||||
|
const { isPaused } = usePauseButtonStore();
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { speed } = useAnimationPlaySpeed();
|
||||||
|
const { isReset, setReset } = useResetButtonStore();
|
||||||
|
const progressRef = useRef<number>(0);
|
||||||
|
const movingForward = useRef<boolean>(true);
|
||||||
|
const completedRef = useRef<boolean>(false);
|
||||||
|
const [objectRotation, setObjectRotation] = useState<[number, number, number] | null>(human.point?.action?.pickUpPoint?.rotation || [0, 0, 0])
|
||||||
|
const [restRotation, setRestingRotation] = useState<boolean>(true);
|
||||||
|
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
||||||
|
const { scene } = useThree();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentPhase === 'init-pickup' && path.length > 0) {
|
||||||
|
setCurrentPath(path);
|
||||||
|
setObjectRotation(human.point.action.pickUpPoint?.rotation ?? null)
|
||||||
|
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
||||||
|
setObjectRotation(human.point.action?.dropPoint?.rotation ?? null)
|
||||||
|
setCurrentPath(path);
|
||||||
|
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
|
||||||
|
setObjectRotation(human.point.action?.pickUpPoint?.rotation ?? null)
|
||||||
|
setCurrentPath(path);
|
||||||
|
}
|
||||||
|
}, [currentPhase, path, objectRotation]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
completedRef.current = false;
|
||||||
|
}, [currentPath]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isReset || !isPlaying) {
|
||||||
|
reset();
|
||||||
|
setCurrentPath([]);
|
||||||
|
completedRef.current = false;
|
||||||
|
movingForward.current = true;
|
||||||
|
progressRef.current = 0;
|
||||||
|
setReset(false);
|
||||||
|
setRestingRotation(true);
|
||||||
|
const object = scene.getObjectByProperty('uuid', human.modelUuid);
|
||||||
|
const humanData = getHumanById(human.modelUuid);
|
||||||
|
if (object && humanData) {
|
||||||
|
object.position.set(humanData.position[0], humanData.position[1], humanData.position[2]);
|
||||||
|
object.rotation.set(humanData.rotation[0], humanData.rotation[1], humanData.rotation[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isReset, isPlaying])
|
||||||
|
|
||||||
|
const lastTimeRef = useRef(performance.now());
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
const now = performance.now();
|
||||||
|
const delta = (now - lastTimeRef.current) / 1000;
|
||||||
|
lastTimeRef.current = now;
|
||||||
|
|
||||||
|
const object = scene.getObjectByProperty('uuid', human.modelUuid);
|
||||||
|
if (!object || currentPath.length < 2) return;
|
||||||
|
if (isPaused) return;
|
||||||
|
|
||||||
|
let totalDistance = 0;
|
||||||
|
const distances = [];
|
||||||
|
let accumulatedDistance = 0;
|
||||||
|
let index = 0;
|
||||||
|
const rotationSpeed = 1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (index < distances.length && progressRef.current > 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 targetQuaternion = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().lookAt(start, end, new THREE.Vector3(0, 1, 0)));
|
||||||
|
const y180 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);
|
||||||
|
targetQuaternion.multiply(y180);
|
||||||
|
|
||||||
|
const angle = object.quaternion.angleTo(targetQuaternion);
|
||||||
|
if (angle < 0.01) {
|
||||||
|
object.quaternion.copy(targetQuaternion);
|
||||||
|
} else {
|
||||||
|
object.quaternion.slerp(targetQuaternion, delta * rotationSpeed * speed * human.speed * 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAligned = angle < 0.01;
|
||||||
|
|
||||||
|
if (isAligned) {
|
||||||
|
progressRef.current += delta * (speed * human.speed);
|
||||||
|
const t = (progressRef.current - accumulatedDistance) / segmentDistance;
|
||||||
|
const position = start.clone().lerp(end, t);
|
||||||
|
object.position.copy(position);
|
||||||
|
if (human.currentMaterials.length > 0) {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
|
||||||
|
} else {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (human.currentMaterials.length > 0) {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'idle_with_box', true, true, true);
|
||||||
|
} else {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progressRef.current >= totalDistance) {
|
||||||
|
if (restRotation && objectRotation) {
|
||||||
|
const targetEuler = new THREE.Euler(0, objectRotation[1], 0);
|
||||||
|
|
||||||
|
const baseQuaternion = new THREE.Quaternion().setFromEuler(targetEuler);
|
||||||
|
const y180 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);
|
||||||
|
const targetQuaternion = baseQuaternion.multiply(y180);
|
||||||
|
|
||||||
|
const angle = object.quaternion.angleTo(targetQuaternion);
|
||||||
|
if (angle < 0.01) {
|
||||||
|
object.quaternion.copy(targetQuaternion);
|
||||||
|
setRestingRotation(false);
|
||||||
|
} else {
|
||||||
|
object.quaternion.slerp(targetQuaternion, delta * rotationSpeed * speed * human.speed * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (human.currentMaterials.length > 0) {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'idle_with_box', true, true, true);
|
||||||
|
} else {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progressRef.current >= totalDistance) {
|
||||||
|
setRestingRotation(true);
|
||||||
|
progressRef.current = 0;
|
||||||
|
movingForward.current = !movingForward.current;
|
||||||
|
setCurrentPath([]);
|
||||||
|
handleCallBack();
|
||||||
|
if (currentPhase === 'pickup-drop') {
|
||||||
|
requestAnimationFrame(startUnloadingProcess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{currentPath.length > 0 && (
|
||||||
|
// helper
|
||||||
|
<group visible={false}>
|
||||||
|
<Line points={currentPath} color="blue" lineWidth={3} />
|
||||||
|
{currentPath.map((point, index) => (
|
||||||
|
<mesh key={index} position={point}>
|
||||||
|
<sphereGeometry args={[0.1, 16, 16]} />
|
||||||
|
<meshStandardMaterial color="red" />
|
||||||
|
</mesh>
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HumanAnimator
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { useThree } from '@react-three/fiber';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { MaterialModel } from '../../../materials/instances/material/materialModel';
|
||||||
|
|
||||||
|
const MaterialAnimator = ({ human }: { human: HumanStatus }) => {
|
||||||
|
const meshRef = useRef<any>(null!);
|
||||||
|
const [hasLoad, setHasLoad] = useState(false);
|
||||||
|
const { scene } = useThree();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasLoad(human.currentLoad > 0);
|
||||||
|
}, [human.currentLoad]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasLoad || !meshRef.current) return;
|
||||||
|
|
||||||
|
const humanModel = scene.getObjectByProperty("uuid", human.modelUuid) as THREE.Object3D;
|
||||||
|
if (!humanModel) return;
|
||||||
|
|
||||||
|
const bone = humanModel.getObjectByName('PlaceObjectRefBone') as THREE.Bone;
|
||||||
|
if (bone) {
|
||||||
|
bone.add(meshRef.current);
|
||||||
|
|
||||||
|
meshRef.current.position.set(0, 0, 0);
|
||||||
|
meshRef.current.rotation.set(0, 0, 0);
|
||||||
|
meshRef.current.scale.set(1, 1, 1);
|
||||||
|
}
|
||||||
|
}, [hasLoad, human.modelUuid]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{hasLoad && human.currentMaterials.length > 0 && (
|
||||||
|
<MaterialModel
|
||||||
|
matRef={meshRef}
|
||||||
|
materialId={human.currentMaterials[0].materialId || ''}
|
||||||
|
materialType={human.currentMaterials[0].materialType || 'Default material'}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MaterialAnimator;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import HumanInstance from './instance/humanInstance';
|
||||||
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
|
|
||||||
|
function HumanInstances() {
|
||||||
|
const { humanStore } = useSceneContext();
|
||||||
|
const { humans } = humanStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{humans.map((human: HumanStatus) => (
|
||||||
|
<React.Fragment key={human.modelUuid}>
|
||||||
|
<HumanInstance human={human} />
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HumanInstances
|
||||||
@@ -0,0 +1,688 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { useThree } from '@react-three/fiber';
|
||||||
|
import { NavMeshQuery } from '@recast-navigation/core';
|
||||||
|
import { useNavMesh } from '../../../../../store/builder/store';
|
||||||
|
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
|
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
|
||||||
|
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||||
|
import { useProductContext } from '../../../products/productContext';
|
||||||
|
|
||||||
|
import HumanAnimator from '../animator/humanAnimator';
|
||||||
|
import MaterialAnimator from '../animator/materialAnimator';
|
||||||
|
|
||||||
|
function HumanInstance({ human }: { human: HumanStatus }) {
|
||||||
|
const { navMesh } = useNavMesh();
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { scene } = useThree();
|
||||||
|
const { assetStore, materialStore, armBotStore, conveyorStore, machineStore, vehicleStore, humanStore, storageUnitStore, productStore } = useSceneContext();
|
||||||
|
const { removeMaterial, setEndTime } = materialStore();
|
||||||
|
const { getStorageUnitById } = storageUnitStore();
|
||||||
|
const { getArmBotById } = armBotStore();
|
||||||
|
const { getConveyorById } = conveyorStore();
|
||||||
|
const { getVehicleById } = vehicleStore();
|
||||||
|
const { getMachineById } = machineStore();
|
||||||
|
const { triggerPointActions } = useTriggerHandler();
|
||||||
|
const { setCurrentAnimation, resetAnimation, getAssetById } = assetStore();
|
||||||
|
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
const { setHumanActive, setHumanState, setHumanPicking, clearCurrentMaterials, setHumanLoad, decrementHumanLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = humanStore();
|
||||||
|
|
||||||
|
const [currentPhase, setCurrentPhase] = useState<string>('init');
|
||||||
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
|
const pauseTimeRef = useRef<number | null>(null);
|
||||||
|
const idleTimeRef = useRef<number>(0);
|
||||||
|
const activeTimeRef = useRef<number>(0);
|
||||||
|
const isPausedRef = useRef<boolean>(false);
|
||||||
|
const isSpeedRef = useRef<number>(0);
|
||||||
|
const { speed } = useAnimationPlaySpeed();
|
||||||
|
const { isPaused } = usePauseButtonStore();
|
||||||
|
const previousTimeRef = useRef<number | null>(null);
|
||||||
|
const animationFrameIdRef = useRef<number | null>(null);
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
isPausedRef.current = isPaused;
|
||||||
|
}, [isPaused]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
isSpeedRef.current = speed;
|
||||||
|
}, [speed]);
|
||||||
|
|
||||||
|
const computePath = useCallback(
|
||||||
|
(start: any, end: any) => {
|
||||||
|
try {
|
||||||
|
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||||
|
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
||||||
|
if (
|
||||||
|
segmentPath.length > 0 &&
|
||||||
|
Math.round(segmentPath[segmentPath.length - 1].x) == Math.round(end.x) &&
|
||||||
|
Math.round(segmentPath[segmentPath.length - 1].z) == Math.round(end.z)
|
||||||
|
) {
|
||||||
|
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
|
||||||
|
} else {
|
||||||
|
console.log("There is no path here...Choose valid path")
|
||||||
|
const { path: segmentPaths } = navMeshQuery.computePath(start, start);
|
||||||
|
return segmentPaths.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
console.error("Failed to compute path");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}, [navMesh]);
|
||||||
|
|
||||||
|
function humanStatus(modelId: string, status: string) {
|
||||||
|
// console.log(`${modelId} , ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
setCurrentPhase('init');
|
||||||
|
setHumanActive(human.modelUuid, false);
|
||||||
|
setHumanPicking(human.modelUuid, false);
|
||||||
|
setHumanState(human.modelUuid, 'idle');
|
||||||
|
setHumanLoad(human.modelUuid, 0);
|
||||||
|
resetAnimation(human.modelUuid);
|
||||||
|
setPath([]);
|
||||||
|
isPausedRef.current = false;
|
||||||
|
pauseTimeRef.current = 0;
|
||||||
|
resetTime(human.modelUuid)
|
||||||
|
activeTimeRef.current = 0
|
||||||
|
idleTimeRef.current = 0
|
||||||
|
previousTimeRef.current = null
|
||||||
|
if (animationFrameIdRef.current !== null) {
|
||||||
|
cancelAnimationFrame(animationFrameIdRef.current)
|
||||||
|
animationFrameIdRef.current = null
|
||||||
|
}
|
||||||
|
const object = scene.getObjectByProperty('uuid', human.modelUuid);
|
||||||
|
if (object && human) {
|
||||||
|
object.position.set(human.position[0], human.position[1], human.position[2]);
|
||||||
|
object.rotation.set(human.rotation[0], human.rotation[1], human.rotation[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isPlaying) {
|
||||||
|
if (!human.point.action.pickUpPoint || !human.point.action.dropPoint) return;
|
||||||
|
|
||||||
|
if (!human.isActive && human.state === 'idle' && currentPhase === 'init') {
|
||||||
|
const toPickupPath = computePath(
|
||||||
|
new THREE.Vector3(human?.position[0], human?.position[1], human?.position[2]),
|
||||||
|
new THREE.Vector3(
|
||||||
|
human?.point?.action?.pickUpPoint?.position?.[0] ?? 0,
|
||||||
|
human?.point?.action?.pickUpPoint?.position?.[1] ?? 0,
|
||||||
|
human?.point?.action?.pickUpPoint?.position?.[2] ?? 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setPath(toPickupPath);
|
||||||
|
setCurrentPhase('init-pickup');
|
||||||
|
setHumanState(human.modelUuid, 'running');
|
||||||
|
setHumanPicking(human.modelUuid, false);
|
||||||
|
setHumanActive(human.modelUuid, true);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
|
||||||
|
humanStatus(human.modelUuid, 'Started from init, heading to pickup');
|
||||||
|
return;
|
||||||
|
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'picking') {
|
||||||
|
if (humanAsset && human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) {
|
||||||
|
if (human.point.action.pickUpPoint && human.point.action.dropPoint) {
|
||||||
|
const toDrop = computePath(
|
||||||
|
new THREE.Vector3(
|
||||||
|
human.point.action.pickUpPoint.position?.[0] ?? 0,
|
||||||
|
human.point.action.pickUpPoint.position?.[1] ?? 0,
|
||||||
|
human.point.action.pickUpPoint.position?.[2] ?? 0
|
||||||
|
),
|
||||||
|
new THREE.Vector3(
|
||||||
|
human.point.action.dropPoint.position?.[0] ?? 0,
|
||||||
|
human.point.action.dropPoint.position?.[1] ?? 0,
|
||||||
|
human.point.action.dropPoint.position?.[2] ?? 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setPath(toDrop);
|
||||||
|
setCurrentPhase('pickup-drop');
|
||||||
|
setHumanState(human.modelUuid, 'running');
|
||||||
|
setHumanPicking(human.modelUuid, false);
|
||||||
|
setHumanPicking(human.modelUuid, true);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
|
||||||
|
humanStatus(human.modelUuid, 'Started from pickup point, heading to drop point');
|
||||||
|
}
|
||||||
|
} else if (human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0) {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
|
||||||
|
}
|
||||||
|
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'dropping' && human.currentLoad === 0) {
|
||||||
|
if (human.point.action.pickUpPoint && human.point.action.dropPoint) {
|
||||||
|
const dropToPickup = computePath(
|
||||||
|
new THREE.Vector3(
|
||||||
|
human.point.action.dropPoint.position?.[0] ?? 0,
|
||||||
|
human.point.action.dropPoint.position?.[1] ?? 0,
|
||||||
|
human.point.action.dropPoint.position?.[2] ?? 0
|
||||||
|
),
|
||||||
|
new THREE.Vector3(
|
||||||
|
human.point.action.pickUpPoint.position?.[0] ?? 0,
|
||||||
|
human.point.action.pickUpPoint.position?.[1] ?? 0,
|
||||||
|
human.point.action.pickUpPoint.position?.[2] ?? 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setPath(dropToPickup);
|
||||||
|
setCurrentPhase('drop-pickup');
|
||||||
|
setHumanState(human.modelUuid, 'running');
|
||||||
|
setHumanPicking(human.modelUuid, false);
|
||||||
|
setHumanActive(human.modelUuid, true);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
|
||||||
|
humanStatus(human.modelUuid, 'Started from dropping point, heading to pickup point');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [human, currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
|
||||||
|
|
||||||
|
function handleCallBack() {
|
||||||
|
if (currentPhase === 'init-pickup') {
|
||||||
|
setCurrentPhase('picking');
|
||||||
|
setHumanState(human.modelUuid, 'idle');
|
||||||
|
setHumanPicking(human.modelUuid, true);
|
||||||
|
setHumanActive(human.modelUuid, false);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||||
|
humanStatus(human.modelUuid, 'Reached pickup point, waiting for material');
|
||||||
|
setPath([]);
|
||||||
|
} else if (currentPhase === 'pickup-drop') {
|
||||||
|
setCurrentPhase('dropping');
|
||||||
|
setHumanState(human.modelUuid, 'idle');
|
||||||
|
setHumanPicking(human.modelUuid, false);
|
||||||
|
setHumanActive(human.modelUuid, false);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
humanStatus(human.modelUuid, 'Reached drop point');
|
||||||
|
setPath([]);
|
||||||
|
} else if (currentPhase === 'drop-pickup') {
|
||||||
|
setCurrentPhase('picking');
|
||||||
|
setHumanState(human.modelUuid, 'idle');
|
||||||
|
setHumanPicking(human.modelUuid, true);
|
||||||
|
setHumanActive(human.modelUuid, false);
|
||||||
|
setPath([]);
|
||||||
|
clearCurrentMaterials(human.modelUuid);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||||
|
humanStatus(human.modelUuid, 'Reached pickup point again, cycle complete');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate(currentTime: number) {
|
||||||
|
if (previousTimeRef.current === null) {
|
||||||
|
previousTimeRef.current = currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deltaTime = (currentTime - previousTimeRef.current) / 1000;
|
||||||
|
previousTimeRef.current = currentTime;
|
||||||
|
|
||||||
|
if (human.isActive) {
|
||||||
|
if (!isPausedRef.current) {
|
||||||
|
activeTimeRef.current += deltaTime * isSpeedRef.current;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isPausedRef.current) {
|
||||||
|
idleTimeRef.current += deltaTime * isSpeedRef.current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
animationFrameIdRef.current = requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isPlaying) return
|
||||||
|
if (!human.isActive) {
|
||||||
|
const roundedActiveTime = Math.round(activeTimeRef.current);
|
||||||
|
incrementActiveTime(human.modelUuid, roundedActiveTime);
|
||||||
|
activeTimeRef.current = 0;
|
||||||
|
} else {
|
||||||
|
const roundedIdleTime = Math.round(idleTimeRef.current);
|
||||||
|
incrementIdleTime(human.modelUuid, roundedIdleTime);
|
||||||
|
idleTimeRef.current = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animationFrameIdRef.current === null) {
|
||||||
|
animationFrameIdRef.current = requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (animationFrameIdRef.current !== null) {
|
||||||
|
cancelAnimationFrame(animationFrameIdRef.current);
|
||||||
|
animationFrameIdRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [human, isPlaying]);
|
||||||
|
|
||||||
|
function startUnloadingProcess() {
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||||
|
if (human.point.action.triggers.length > 0) {
|
||||||
|
const trigger = getTriggerByUuid(selectedProduct.productUuid, human.point.action.triggers[0]?.triggerUuid);
|
||||||
|
const model = getEventByModelUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredModel?.modelUuid || '');
|
||||||
|
|
||||||
|
if (trigger && model) {
|
||||||
|
if (model.type === 'transfer') {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||||
|
if (action) {
|
||||||
|
handleMaterialDropToConveyor(model);
|
||||||
|
}
|
||||||
|
} else if (model.type === 'machine') {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||||
|
if (action) {
|
||||||
|
handleMaterialDropToMachine(model);
|
||||||
|
}
|
||||||
|
} else if (model.type === 'roboticArm') {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||||
|
if (action) {
|
||||||
|
handleMaterialDropToArmBot(model);
|
||||||
|
}
|
||||||
|
} else if (model.type === 'storageUnit') {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||||
|
if (action) {
|
||||||
|
handleMaterialDropToStorageUnit(model);
|
||||||
|
}
|
||||||
|
} else if (model.type === 'vehicle') {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||||
|
if (action) {
|
||||||
|
handleMaterialDropToVehicle(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const droppedMaterial = human.currentLoad;
|
||||||
|
handleMaterialDropByDefault(droppedMaterial);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const droppedMaterial = human.currentLoad;
|
||||||
|
handleMaterialDropByDefault(droppedMaterial);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(startUnloadingProcess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaterialDropToStorageUnit(model: StorageEventSchema) {
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
if (model && humanAsset?.animationState?.current !== 'drop') {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkAnimation = () => {
|
||||||
|
if (humanAsset?.animationState?.isCompleted) {
|
||||||
|
if (model.point.action.actionType === 'store') {
|
||||||
|
loopMaterialDropToStorage(
|
||||||
|
human.modelUuid,
|
||||||
|
human.currentLoad,
|
||||||
|
model.modelUuid,
|
||||||
|
model.point.action.storageCapacity,
|
||||||
|
human.point.action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(checkAnimation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loopMaterialDropToStorage(
|
||||||
|
humanId: string,
|
||||||
|
humanCurrentLoad: number,
|
||||||
|
storageUnitId: string,
|
||||||
|
storageMaxCapacity: number,
|
||||||
|
action: HumanAction
|
||||||
|
) {
|
||||||
|
const storageUnit = getStorageUnitById(storageUnitId);
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
|
||||||
|
if (!storageUnit || humanCurrentLoad <= 0 || storageUnit.currentLoad >= storageMaxCapacity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrementHumanLoad(humanId, 1);
|
||||||
|
humanCurrentLoad -= 1;
|
||||||
|
|
||||||
|
const material = removeLastMaterial(humanId);
|
||||||
|
if (material) {
|
||||||
|
triggerPointActions(action, material.materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humanCurrentLoad > 0 && storageUnit.currentLoad < storageMaxCapacity) {
|
||||||
|
resetAnimation(human.modelUuid);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
|
||||||
|
const waitForNextDrop = () => {
|
||||||
|
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||||
|
loopMaterialDropToStorage(
|
||||||
|
humanId,
|
||||||
|
humanCurrentLoad,
|
||||||
|
storageUnitId,
|
||||||
|
storageMaxCapacity,
|
||||||
|
action
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextDrop);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForNextDrop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaterialDropToConveyor(model: ConveyorEventSchema) {
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
if (humanAsset?.animationState?.current !== 'drop') {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkAnimation = () => {
|
||||||
|
if (humanAsset?.animationState?.isCompleted) {
|
||||||
|
const conveyor = getConveyorById(model.modelUuid);
|
||||||
|
if (conveyor) {
|
||||||
|
loopMaterialDropToConveyor(
|
||||||
|
human.modelUuid,
|
||||||
|
human.currentLoad,
|
||||||
|
conveyor.modelUuid,
|
||||||
|
human.point.action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(checkAnimation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loopMaterialDropToConveyor(
|
||||||
|
humanId: string,
|
||||||
|
humanCurrentLoad: number,
|
||||||
|
conveyorId: string,
|
||||||
|
action: HumanAction
|
||||||
|
) {
|
||||||
|
const conveyor = getConveyorById(conveyorId);
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
|
||||||
|
if (!conveyor || humanCurrentLoad <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrementHumanLoad(humanId, 1);
|
||||||
|
humanCurrentLoad -= 1;
|
||||||
|
|
||||||
|
const material = removeLastMaterial(humanId);
|
||||||
|
if (material) {
|
||||||
|
triggerPointActions(action, material.materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humanCurrentLoad > 0) {
|
||||||
|
resetAnimation(human.modelUuid);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
|
||||||
|
const waitForNextDrop = () => {
|
||||||
|
if (humanAsset?.animationState?.isCompleted) {
|
||||||
|
loopMaterialDropToConveyor(
|
||||||
|
humanId,
|
||||||
|
humanCurrentLoad,
|
||||||
|
conveyorId,
|
||||||
|
action
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextDrop);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForNextDrop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaterialDropToArmBot(model: RoboticArmEventSchema) {
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
if (humanAsset?.animationState?.current !== 'drop') {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkAnimation = () => {
|
||||||
|
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||||
|
const armBot = getArmBotById(model.modelUuid);
|
||||||
|
if (armBot && armBot.state === 'idle' && !armBot.isActive) {
|
||||||
|
loopMaterialDropToArmBot(
|
||||||
|
human.modelUuid,
|
||||||
|
human.currentLoad,
|
||||||
|
model.modelUuid,
|
||||||
|
human.point.action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(checkAnimation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loopMaterialDropToArmBot(
|
||||||
|
humanId: string,
|
||||||
|
humanCurrentLoad: number,
|
||||||
|
armBotId: string,
|
||||||
|
action: HumanAction
|
||||||
|
) {
|
||||||
|
const armBot = getArmBotById(armBotId);
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
|
||||||
|
if (!armBot || armBot.state !== 'idle' || armBot.isActive || humanCurrentLoad <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrementHumanLoad(humanId, 1);
|
||||||
|
humanCurrentLoad -= 1;
|
||||||
|
|
||||||
|
const material = removeLastMaterial(humanId);
|
||||||
|
if (material) {
|
||||||
|
triggerPointActions(action, material.materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humanCurrentLoad > 0) {
|
||||||
|
resetAnimation(human.modelUuid);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
|
||||||
|
const waitForNextTransfer = () => {
|
||||||
|
const currentArmBot = getArmBotById(armBotId);
|
||||||
|
if (currentArmBot && currentArmBot.state === 'idle' && !currentArmBot.isActive) {
|
||||||
|
if (humanAsset?.animationState?.isCompleted) {
|
||||||
|
loopMaterialDropToArmBot(
|
||||||
|
humanId,
|
||||||
|
humanCurrentLoad,
|
||||||
|
armBotId,
|
||||||
|
action
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextTransfer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextTransfer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForNextTransfer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaterialDropToVehicle(model: VehicleEventSchema) {
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
if (humanAsset?.animationState?.current !== 'drop') {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkAnimation = () => {
|
||||||
|
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||||
|
const vehicle = getVehicleById(model.modelUuid);
|
||||||
|
if (vehicle && vehicle.state === 'idle' && !vehicle.isActive) {
|
||||||
|
loopMaterialDropToVehicle(
|
||||||
|
human.modelUuid,
|
||||||
|
human.currentLoad,
|
||||||
|
model.modelUuid,
|
||||||
|
human.point.action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(checkAnimation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loopMaterialDropToVehicle(
|
||||||
|
humanId: string,
|
||||||
|
humanCurrentLoad: number,
|
||||||
|
vehicleId: string,
|
||||||
|
action: HumanAction
|
||||||
|
) {
|
||||||
|
const vehicle = getVehicleById(vehicleId);
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
|
||||||
|
if (!vehicle || vehicle.state !== 'idle' || vehicle.isActive || humanCurrentLoad <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrementHumanLoad(humanId, 1);
|
||||||
|
humanCurrentLoad -= 1;
|
||||||
|
|
||||||
|
const material = removeLastMaterial(humanId);
|
||||||
|
if (material) {
|
||||||
|
triggerPointActions(action, material.materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humanCurrentLoad > 0) {
|
||||||
|
resetAnimation(human.modelUuid);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
|
||||||
|
const waitForNextTransfer = () => {
|
||||||
|
const currentVehicle = getVehicleById(vehicleId);
|
||||||
|
if (currentVehicle && currentVehicle.state === 'idle' && !currentVehicle.isActive) {
|
||||||
|
if (humanAsset?.animationState?.isCompleted) {
|
||||||
|
loopMaterialDropToVehicle(
|
||||||
|
humanId,
|
||||||
|
humanCurrentLoad,
|
||||||
|
vehicleId,
|
||||||
|
action
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextTransfer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextTransfer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForNextTransfer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaterialDropToMachine(model: MachineEventSchema) {
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
if (humanAsset?.animationState?.current !== 'drop') {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkAnimation = () => {
|
||||||
|
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||||
|
const machine = getMachineById(model.modelUuid);
|
||||||
|
if (machine && machine.state === 'idle' && !machine.isActive) {
|
||||||
|
loopMaterialDropToMachine(
|
||||||
|
human.modelUuid,
|
||||||
|
human.currentLoad,
|
||||||
|
model.modelUuid,
|
||||||
|
human.point.action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(checkAnimation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loopMaterialDropToMachine(
|
||||||
|
humanId: string,
|
||||||
|
humanCurrentLoad: number,
|
||||||
|
machineId: string,
|
||||||
|
action: HumanAction
|
||||||
|
) {
|
||||||
|
const machine = getMachineById(machineId);
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
|
||||||
|
if (!machine || machine.state !== 'idle' || machine.isActive || humanCurrentLoad <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrementHumanLoad(humanId, 1);
|
||||||
|
humanCurrentLoad -= 1;
|
||||||
|
|
||||||
|
const material = removeLastMaterial(humanId);
|
||||||
|
if (material) {
|
||||||
|
triggerPointActions(action, material.materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humanCurrentLoad > 0) {
|
||||||
|
resetAnimation(human.modelUuid);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
|
||||||
|
const waitForNextTransfer = () => {
|
||||||
|
const currentMachine = getMachineById(machineId);
|
||||||
|
if (currentMachine && currentMachine.state === 'idle' && !currentMachine.isActive) {
|
||||||
|
if (humanAsset?.animationState?.isCompleted) {
|
||||||
|
loopMaterialDropToMachine(
|
||||||
|
humanId,
|
||||||
|
humanCurrentLoad,
|
||||||
|
machineId,
|
||||||
|
action
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextTransfer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(waitForNextTransfer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForNextTransfer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaterialDropByDefault(droppedMaterial: number) {
|
||||||
|
const humanAsset = getAssetById(human.modelUuid);
|
||||||
|
if (humanAsset?.animationState?.current !== 'drop') {
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humanAsset?.animationState?.isCompleted) {
|
||||||
|
const remainingMaterials = droppedMaterial - 1;
|
||||||
|
decrementHumanLoad(human.modelUuid, 1);
|
||||||
|
const material = removeLastMaterial(human.modelUuid);
|
||||||
|
|
||||||
|
if (material) {
|
||||||
|
setEndTime(material.materialId, performance.now());
|
||||||
|
removeMaterial(material.materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainingMaterials > 0) {
|
||||||
|
resetAnimation(human.modelUuid);
|
||||||
|
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||||
|
|
||||||
|
requestAnimationFrame(() => handleMaterialDropByDefault(remainingMaterials));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(() => handleMaterialDropByDefault(droppedMaterial));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<HumanAnimator
|
||||||
|
path={path}
|
||||||
|
handleCallBack={handleCallBack}
|
||||||
|
currentPhase={currentPhase}
|
||||||
|
human={human}
|
||||||
|
reset={reset}
|
||||||
|
startUnloadingProcess={startUnloadingProcess}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MaterialAnimator human={human} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HumanInstance
|
||||||
263
app/src/modules/simulation/human/instances/instance/humanUi.tsx
Normal file
263
app/src/modules/simulation/human/instances/instance/humanUi.tsx
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
import { useGLTF } from '@react-three/drei';
|
||||||
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
|
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
||||||
|
import { useProductContext } from '../../../products/productContext';
|
||||||
|
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||||
|
import { Group, Plane, Vector3 } from 'three';
|
||||||
|
import { useVersionContext } from '../../../../builder/version/versionContext';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import startPoint from "../../../../../assets/gltf-glb/ui/arrow_green.glb";
|
||||||
|
import startEnd from "../../../../../assets/gltf-glb/ui/arrow_red.glb";
|
||||||
|
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||||
|
|
||||||
|
function HumanUi() {
|
||||||
|
const { scene: startScene } = useGLTF(startPoint) as any;
|
||||||
|
const { scene: endScene } = useGLTF(startEnd) as any;
|
||||||
|
const startMarker = useRef<Group>(null);
|
||||||
|
const endMarker = useRef<Group>(null);
|
||||||
|
const outerGroup = useRef<Group>(null);
|
||||||
|
const prevMousePos = useRef({ x: 0, y: 0 });
|
||||||
|
const { controls, raycaster } = useThree();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { humanStore, productStore } = useSceneContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
const { humans, getHumanById } = humanStore();
|
||||||
|
const { updateEvent } = productStore();
|
||||||
|
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||||
|
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||||
|
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||||
|
const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||||
|
const { isDragging, setIsDragging } = useIsDragging();
|
||||||
|
const { isRotating, setIsRotating } = useIsRotating();
|
||||||
|
const plane = useRef(new Plane(new Vector3(0, 1, 0), 0));
|
||||||
|
|
||||||
|
const [selectedHumanData, setSelectedHumanData] = useState<{
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
}>({ position: [0, 0, 0], rotation: [0, 0, 0] });
|
||||||
|
|
||||||
|
const { selectedAction } = useSelectedAction();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
const updateBackend = (
|
||||||
|
productName: string,
|
||||||
|
productUuid: string,
|
||||||
|
projectId: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productUuid: productUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
eventDatas: eventData,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedEventSphere) return;
|
||||||
|
|
||||||
|
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
|
||||||
|
if (!selectedHuman || !selectedHuman.point?.action) return;
|
||||||
|
|
||||||
|
setSelectedHumanData({
|
||||||
|
position: selectedHuman.position,
|
||||||
|
rotation: selectedHuman.rotation,
|
||||||
|
});
|
||||||
|
|
||||||
|
const action = selectedHuman.point.action;
|
||||||
|
|
||||||
|
if (action.pickUpPoint?.position && outerGroup.current) {
|
||||||
|
const worldPos = new Vector3(...action.pickUpPoint.position);
|
||||||
|
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||||
|
setStartPosition([localPosition.x, 0.5, localPosition.z]);
|
||||||
|
setStartRotation(action.pickUpPoint.rotation || [0, 0, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.dropPoint?.position && outerGroup.current) {
|
||||||
|
const worldPos = new Vector3(...action.dropPoint.position);
|
||||||
|
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||||
|
setEndPosition([localPosition.x, 0.5, localPosition.z]);
|
||||||
|
setEndRotation(action.dropPoint.rotation || [0, 0, 0]);
|
||||||
|
}
|
||||||
|
}, [selectedEventSphere, outerGroup.current, selectedAction, humans]);
|
||||||
|
|
||||||
|
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 as any).enabled = false;
|
||||||
|
setIsDragging(null);
|
||||||
|
} else {
|
||||||
|
setIsDragging(state);
|
||||||
|
setIsRotating(null);
|
||||||
|
if (controls) (controls as any).enabled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePointerUp = () => {
|
||||||
|
(controls as any).enabled = true;
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
|
||||||
|
if (selectedEventSphere?.userData.modelUuid && selectedAction.actionId) {
|
||||||
|
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
|
||||||
|
|
||||||
|
if (selectedHuman && outerGroup.current && startMarker.current && endMarker.current) {
|
||||||
|
const worldPosStart = new Vector3(...startPosition);
|
||||||
|
const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());
|
||||||
|
|
||||||
|
const worldPosEnd = new Vector3(...endPosition);
|
||||||
|
const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());
|
||||||
|
|
||||||
|
const updatedAction = {
|
||||||
|
...selectedHuman.point.action,
|
||||||
|
pickUpPoint: {
|
||||||
|
position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number],
|
||||||
|
rotation: startRotation
|
||||||
|
},
|
||||||
|
dropPoint: {
|
||||||
|
position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number],
|
||||||
|
rotation: endRotation
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const event = updateEvent(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedEventSphere.userData.modelUuid,
|
||||||
|
{
|
||||||
|
...selectedHuman,
|
||||||
|
point: {
|
||||||
|
...selectedHuman.point,
|
||||||
|
action: updatedAction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
event
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (!isDragging || !plane.current || !raycaster || !outerGroup.current) return;
|
||||||
|
const intersectPoint = new Vector3();
|
||||||
|
const intersects = raycaster.ray.intersectPlane(
|
||||||
|
plane.current,
|
||||||
|
intersectPoint
|
||||||
|
);
|
||||||
|
if (!intersects) return;
|
||||||
|
const localPoint = outerGroup?.current.worldToLocal(intersectPoint.clone());
|
||||||
|
if (isDragging === "start") {
|
||||||
|
setStartPosition([localPoint.x, 0.5, localPoint.z]);
|
||||||
|
} else if (isDragging === "end") {
|
||||||
|
setEndPosition([localPoint.x, 0.5, localPoint.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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleGlobalPointerUp = () => {
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
if (controls) (controls as any).enabled = true;
|
||||||
|
handlePointerUp();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isDragging || isRotating) {
|
||||||
|
window.addEventListener("pointerup", handleGlobalPointerUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("pointerup", handleGlobalPointerUp);
|
||||||
|
};
|
||||||
|
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{selectedHumanData && (
|
||||||
|
<group
|
||||||
|
position={selectedHumanData.position}
|
||||||
|
ref={outerGroup}
|
||||||
|
>
|
||||||
|
<primitive
|
||||||
|
name="startMarker"
|
||||||
|
object={startScene}
|
||||||
|
ref={startMarker}
|
||||||
|
position={startPosition}
|
||||||
|
rotation={startRotation}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(e, "start", "start");
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
(controls as any).enabled = true;
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<primitive
|
||||||
|
name="endMarker"
|
||||||
|
object={endScene}
|
||||||
|
ref={endMarker}
|
||||||
|
position={endPosition}
|
||||||
|
rotation={endRotation}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(e, "end", "end");
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
(controls as any).enabled = true;
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HumanUi
|
||||||
@@ -10,7 +10,7 @@ import { useParams } from 'react-router-dom';
|
|||||||
import { useVersionContext } from '../../builder/version/versionContext';
|
import { useVersionContext } from '../../builder/version/versionContext';
|
||||||
|
|
||||||
function Products() {
|
function Products() {
|
||||||
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout, productStore } = useSceneContext();
|
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, layout, productStore } = useSceneContext();
|
||||||
const { products, getProductById, addProduct, setProducts } = productStore();
|
const { products, getProductById, addProduct, setProducts } = productStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { setMainProduct } = useMainProduct();
|
const { setMainProduct } = useMainProduct();
|
||||||
@@ -20,6 +20,7 @@ function Products() {
|
|||||||
const { addMachine, clearMachines } = machineStore();
|
const { addMachine, clearMachines } = machineStore();
|
||||||
const { addConveyor, clearConveyors } = conveyorStore();
|
const { addConveyor, clearConveyors } = conveyorStore();
|
||||||
const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore();
|
const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore();
|
||||||
|
const { addHuman, clearHumans } = humanStore();
|
||||||
const { isReset } = useResetButtonStore();
|
const { isReset } = useResetButtonStore();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { mainProduct } = useMainProduct();
|
const { mainProduct } = useMainProduct();
|
||||||
@@ -153,6 +154,20 @@ function Products() {
|
|||||||
}
|
}
|
||||||
}, [selectedProduct, products, isReset, isPlaying]);
|
}, [selectedProduct, products, isReset, isPlaying]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedProduct.productUuid) {
|
||||||
|
const product = getProductById(selectedProduct.productUuid);
|
||||||
|
if (product) {
|
||||||
|
clearHumans();
|
||||||
|
product.eventDatas.forEach(events => {
|
||||||
|
if (events.type === 'human') {
|
||||||
|
addHuman(selectedProduct.productUuid, events);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedProduct, products, isReset, isPlaying]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import Vehicles from './vehicle/vehicles';
|
import Vehicles from './vehicle/vehicles';
|
||||||
import Points from './events/points/points';
|
import Points from './events/points/points';
|
||||||
import Conveyor from './conveyor/conveyor';
|
import Conveyor from './conveyor/conveyor';
|
||||||
@@ -6,6 +6,7 @@ import RoboticArm from './roboticArm/roboticArm';
|
|||||||
import Materials from './materials/materials';
|
import Materials from './materials/materials';
|
||||||
import Machine from './machine/machine';
|
import Machine from './machine/machine';
|
||||||
import StorageUnit from './storageUnit/storageUnit';
|
import StorageUnit from './storageUnit/storageUnit';
|
||||||
|
import Human from './human/human';
|
||||||
import Simulator from './simulator/simulator';
|
import Simulator from './simulator/simulator';
|
||||||
import Products from './products/products';
|
import Products from './products/products';
|
||||||
import Trigger from './triggers/trigger';
|
import Trigger from './triggers/trigger';
|
||||||
@@ -52,6 +53,8 @@ function Simulation() {
|
|||||||
|
|
||||||
<StorageUnit />
|
<StorageUnit />
|
||||||
|
|
||||||
|
<Human />
|
||||||
|
|
||||||
<Simulator />
|
<Simulator />
|
||||||
|
|
||||||
<SimulationAnalysis />
|
<SimulationAnalysis />
|
||||||
|
|||||||
@@ -124,7 +124,8 @@ function determineExecutionMachineSequences(products: productsSchema): EventsSch
|
|||||||
event.type === 'vehicle' ||
|
event.type === 'vehicle' ||
|
||||||
event.type === 'machine' ||
|
event.type === 'machine' ||
|
||||||
event.type === 'storageUnit' ||
|
event.type === 'storageUnit' ||
|
||||||
event.type === 'roboticArm'
|
event.type === 'roboticArm' ||
|
||||||
|
event.type === 'human'
|
||||||
) {
|
) {
|
||||||
pointToEventMap.set(event.point.uuid, event);
|
pointToEventMap.set(event.point.uuid, event);
|
||||||
allPoints.push(event.point);
|
allPoints.push(event.point);
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ export async function determineExecutionMachineSequences(products: productsSchem
|
|||||||
event.type === 'vehicle' ||
|
event.type === 'vehicle' ||
|
||||||
event.type === 'machine' ||
|
event.type === 'machine' ||
|
||||||
event.type === 'storageUnit' ||
|
event.type === 'storageUnit' ||
|
||||||
event.type === 'roboticArm'
|
event.type === 'roboticArm' ||
|
||||||
|
event.type === 'human'
|
||||||
) {
|
) {
|
||||||
pointToEventMap.set(event.point.uuid, event);
|
pointToEventMap.set(event.point.uuid, event);
|
||||||
allPoints.push(event.point);
|
allPoints.push(event.point);
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ export function determineExecutionOrder(products: productsSchema): PointsScheme[
|
|||||||
} else if (event.type === 'vehicle' ||
|
} else if (event.type === 'vehicle' ||
|
||||||
event.type === 'machine' ||
|
event.type === 'machine' ||
|
||||||
event.type === 'storageUnit' ||
|
event.type === 'storageUnit' ||
|
||||||
event.type === 'roboticArm') {
|
event.type === 'roboticArm' ||
|
||||||
|
event.type === 'human'
|
||||||
|
) {
|
||||||
pointMap.set(event.point.uuid, event.point);
|
pointMap.set(event.point.uuid, event.point);
|
||||||
allPoints.push(event.point);
|
allPoints.push(event.point);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ export async function determineExecutionSequences(products: productsSchema): Pro
|
|||||||
} else if (event.type === 'vehicle' ||
|
} else if (event.type === 'vehicle' ||
|
||||||
event.type === 'machine' ||
|
event.type === 'machine' ||
|
||||||
event.type === 'storageUnit' ||
|
event.type === 'storageUnit' ||
|
||||||
event.type === 'roboticArm') {
|
event.type === 'roboticArm' ||
|
||||||
|
event.type === 'human'
|
||||||
|
) {
|
||||||
pointMap.set(event.point.uuid, event.point);
|
pointMap.set(event.point.uuid, event.point);
|
||||||
allPoints.push(event.point);
|
allPoints.push(event.point);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ function determineExecutionMachineSequences(products: productsSchema): EventsSch
|
|||||||
event.type === 'vehicle' ||
|
event.type === 'vehicle' ||
|
||||||
event.type === 'machine' ||
|
event.type === 'machine' ||
|
||||||
event.type === 'storageUnit' ||
|
event.type === 'storageUnit' ||
|
||||||
event.type === 'roboticArm'
|
event.type === 'roboticArm' ||
|
||||||
|
event.type === 'human'
|
||||||
) {
|
) {
|
||||||
pointToEventMap.set(event.point.uuid, event);
|
pointToEventMap.set(event.point.uuid, event);
|
||||||
allPoints.push(event.point);
|
allPoints.push(event.point);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayB
|
|||||||
import { determineExecutionOrder } from './functions/determineExecutionOrder';
|
import { determineExecutionOrder } from './functions/determineExecutionOrder';
|
||||||
import { useProductContext } from '../products/productContext';
|
import { useProductContext } from '../products/productContext';
|
||||||
import { useSceneContext } from '../../scene/sceneContext';
|
import { useSceneContext } from '../../scene/sceneContext';
|
||||||
import { useCompareProductDataStore } from '../../../store/builder/store';
|
|
||||||
|
|
||||||
function Simulator() {
|
function Simulator() {
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const VehicleUI = () => {
|
|||||||
const outerGroup = useRef<Group>(null);
|
const outerGroup = useRef<Group>(null);
|
||||||
const state: Types.ThreeState = useThree();
|
const state: Types.ThreeState = useThree();
|
||||||
const controls: any = state.controls;
|
const controls: any = state.controls;
|
||||||
const [selectedVehicleData, setSelectedVechicleData] = useState<{ position: [number, number, number]; rotation: [number, number, number]; }>({ position: [0, 0, 0], rotation: [0, 0, 0] });
|
const [selectedVehicleData, setSelectedVehicleData] = useState<{ position: [number, number, number]; rotation: [number, number, number]; }>({ position: [0, 0, 0], rotation: [0, 0, 0] });
|
||||||
const CIRCLE_RADIUS = 0.8;
|
const CIRCLE_RADIUS = 0.8;
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
@@ -71,7 +71,7 @@ const VehicleUI = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (selectedVehicle) {
|
if (selectedVehicle) {
|
||||||
setSelectedVechicleData({
|
setSelectedVehicleData({
|
||||||
position: selectedVehicle.position,
|
position: selectedVehicle.position,
|
||||||
rotation: selectedVehicle.rotation,
|
rotation: selectedVehicle.rotation,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import { useVehicleEventManager } from '../../vehicle/eventManager/useVehicleEve
|
|||||||
import { useMachineEventManager } from '../../machine/eventManager/useMachineEventManager';
|
import { useMachineEventManager } from '../../machine/eventManager/useMachineEventManager';
|
||||||
import { useSceneContext } from '../../../scene/sceneContext';
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
import { useProductContext } from '../../products/productContext';
|
import { useProductContext } from '../../products/productContext';
|
||||||
|
import { useHumanEventManager } from '../../human/eventManager/useHumanEventManager';
|
||||||
|
|
||||||
export function useTriggerHandler() {
|
export function useTriggerHandler() {
|
||||||
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, productStore } = useSceneContext();
|
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, humanStore, storageUnitStore, productStore } = useSceneContext();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { handleAction } = useActionHandler();
|
const { handleAction } = useActionHandler();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
@@ -19,7 +20,9 @@ export function useTriggerHandler() {
|
|||||||
const { addConveyorToMonitor } = useConveyorEventManager();
|
const { addConveyorToMonitor } = useConveyorEventManager();
|
||||||
const { addVehicleToMonitor } = useVehicleEventManager();
|
const { addVehicleToMonitor } = useVehicleEventManager();
|
||||||
const { addMachineToMonitor } = useMachineEventManager();
|
const { addMachineToMonitor } = useMachineEventManager();
|
||||||
|
const { addHumanToMonitor } = useHumanEventManager();
|
||||||
const { getVehicleById } = vehicleStore();
|
const { getVehicleById } = vehicleStore();
|
||||||
|
const { getHumanById } = humanStore();
|
||||||
const { getMachineById } = machineStore();
|
const { getMachineById } = machineStore();
|
||||||
const { getStorageUnitById } = storageUnitStore();
|
const { getStorageUnitById } = storageUnitStore();
|
||||||
const { getMaterialById, setCurrentLocation, setNextLocation, setPreviousLocation, setIsPaused, setIsVisible, setEndTime } = materialStore();
|
const { getMaterialById, setCurrentLocation, setNextLocation, setPreviousLocation, setIsPaused, setIsVisible, setEndTime } = materialStore();
|
||||||
@@ -149,23 +152,51 @@ export function useTriggerHandler() {
|
|||||||
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
if (model?.type === 'vehicle') {
|
if (model?.type === 'vehicle') {
|
||||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
const armBot = getArmBotById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
if (vehicle) {
|
if (armBot) {
|
||||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
if (armBot.isActive === false && armBot.state === 'idle') {
|
||||||
// Handle current action from vehicle
|
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
setIsPaused(materialId, true);
|
if (vehicle) {
|
||||||
handleAction(action, materialId);
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
// Handle current action from vehicle
|
||||||
} else {
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
// Handle current action using Event Manager
|
|
||||||
setIsPaused(materialId, true);
|
|
||||||
|
|
||||||
addVehicleToMonitor(vehicle.modelUuid,
|
|
||||||
() => {
|
|
||||||
handleAction(action, materialId);
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addVehicleToMonitor(vehicle.modelUuid,
|
||||||
|
() => {
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
} else {
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
addArmBotToMonitor(armBot.modelUuid, () => {
|
||||||
|
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (vehicle) {
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
// Handle current action from vehicle
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addVehicleToMonitor(vehicle.modelUuid,
|
||||||
|
() => {
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (model?.type === 'machine') {
|
} else if (model?.type === 'machine') {
|
||||||
@@ -191,26 +222,25 @@ export function useTriggerHandler() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setIsPaused(materialId, true);
|
setIsPaused(materialId, true);
|
||||||
addArmBotToMonitor(armBot.modelUuid,
|
addArmBotToMonitor(armBot.modelUuid, () => {
|
||||||
() => {
|
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
if (machine) {
|
||||||
if (machine) {
|
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||||
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
setIsPaused(materialId, true);
|
||||||
setIsPaused(materialId, true);
|
handleAction(action, materialId);
|
||||||
handleAction(action, materialId);
|
} else {
|
||||||
} else {
|
|
||||||
|
|
||||||
// Handle current action using Event Manager
|
// Handle current action using Event Manager
|
||||||
setIsPaused(materialId, true);
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
addMachineToMonitor(machine.modelUuid,
|
addMachineToMonitor(machine.modelUuid,
|
||||||
() => {
|
() => {
|
||||||
handleAction(action, materialId);
|
handleAction(action, materialId);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,6 +286,242 @@ export function useTriggerHandler() {
|
|||||||
} else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
// Transfer to Storage Unit
|
// Transfer to Storage Unit
|
||||||
|
|
||||||
|
} else if (toEvent?.type === 'human') {
|
||||||
|
// Transfer to Human
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
|
||||||
|
// Handle current action of the material
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
if (material.next) {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.next.modelUuid,
|
||||||
|
pointUuid: material.next.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
if (action) {
|
||||||
|
|
||||||
|
if (human) {
|
||||||
|
if (action && action.triggers.length > 0 &&
|
||||||
|
action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
|
||||||
|
action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid &&
|
||||||
|
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid) {
|
||||||
|
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
if (model?.type === 'vehicle') {
|
||||||
|
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
if (human) {
|
||||||
|
if (human.isActive === false && human.state === 'idle') {
|
||||||
|
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
if (vehicle) {
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
// Handle current action from vehicle
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addVehicleToMonitor(vehicle.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
addHumanToMonitor(human.modelUuid, () => {
|
||||||
|
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (vehicle) {
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
// Handle current action from vehicle
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addVehicleToMonitor(vehicle.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (model?.type === 'transfer') {
|
||||||
|
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
if (human) {
|
||||||
|
if (human.isActive === false && human.state === 'idle') {
|
||||||
|
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
if (conveyor) {
|
||||||
|
if (!conveyor.isPaused) {
|
||||||
|
// Handle current action from vehicle
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addConveyorToMonitor(conveyor.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
addHumanToMonitor(human.modelUuid, () => {
|
||||||
|
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (conveyor) {
|
||||||
|
if (!conveyor.isPaused) {
|
||||||
|
// Handle current action from vehicle
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addConveyorToMonitor(conveyor.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (model?.type === 'machine') {
|
||||||
|
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
if (human) {
|
||||||
|
if (human.isActive === false && human.state === 'idle') {
|
||||||
|
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
if (machine) {
|
||||||
|
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addMachineToMonitor(machine.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
addHumanToMonitor(human.modelUuid, () => {
|
||||||
|
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (machine) {
|
||||||
|
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addMachineToMonitor(machine.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (human.isActive === false && human.state === 'idle') {
|
||||||
|
|
||||||
|
// Handle current action from arm bot
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
addHumanToMonitor(human.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (human.isActive === false && human.state === 'idle') {
|
||||||
|
|
||||||
|
// Handle current action from arm bot
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
addHumanToMonitor(human.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (fromEvent?.type === 'vehicle') {
|
} else if (fromEvent?.type === 'vehicle') {
|
||||||
if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
@@ -322,18 +588,25 @@ export function useTriggerHandler() {
|
|||||||
|
|
||||||
setNextLocation(material.materialId, null);
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
setIsVisible(materialId, false);
|
|
||||||
|
|
||||||
if (action && armBot) {
|
if (action && armBot) {
|
||||||
|
|
||||||
if (armBot.isActive === false && armBot.state === 'idle') {
|
if (armBot.isActive === false && armBot.state === 'idle') {
|
||||||
|
|
||||||
// Handle current action from arm bot
|
// Handle current action from arm bot
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
handleAction(action, materialId);
|
handleAction(action, materialId);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Event Manager Needed
|
addArmBotToMonitor(armBot.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,6 +652,52 @@ export function useTriggerHandler() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (toEvent?.type === 'human') {
|
||||||
|
// Vehicle to Human
|
||||||
|
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
|
||||||
|
if (action && human) {
|
||||||
|
|
||||||
|
if (human.isActive === false && human.state === 'idle') {
|
||||||
|
|
||||||
|
// Handle current action from arm bot
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
addHumanToMonitor(human.modelUuid,
|
||||||
|
() => {
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (fromEvent?.type === 'machine') {
|
} else if (fromEvent?.type === 'machine') {
|
||||||
if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
@@ -485,6 +804,135 @@ export function useTriggerHandler() {
|
|||||||
} else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
// Machine to Storage Unit
|
// Machine to Storage Unit
|
||||||
|
|
||||||
|
} else if (toEvent?.type === 'human') {
|
||||||
|
// Machine to Human
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
if (material) {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
if (action && human) {
|
||||||
|
|
||||||
|
if (human.isActive === false && human.state === 'idle') {
|
||||||
|
|
||||||
|
// Handle current action from arm bot
|
||||||
|
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (model?.type === 'transfer') {
|
||||||
|
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (conveyor) {
|
||||||
|
const previousModel = getEventByModelUuid(selectedProduct.productUuid, material.previous?.modelUuid || '');
|
||||||
|
if (previousModel) {
|
||||||
|
if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) {
|
||||||
|
handleAction(action, materialId)
|
||||||
|
} else {
|
||||||
|
addConveyorToMonitor(conveyor.modelUuid,
|
||||||
|
() => {
|
||||||
|
handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
// handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
} else if (model?.type === 'vehicle') {
|
||||||
|
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (vehicle) {
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
// Handle current action from vehicle
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addVehicleToMonitor(vehicle.modelUuid,
|
||||||
|
() => {
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
|
||||||
|
addHumanToMonitor(human.modelUuid, () => {
|
||||||
|
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (model?.type === 'transfer') {
|
||||||
|
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (conveyor) {
|
||||||
|
const previousModel = getEventByModelUuid(selectedProduct.productUuid, material.previous?.modelUuid || '');
|
||||||
|
if (previousModel) {
|
||||||
|
if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) {
|
||||||
|
handleAction(action, materialId)
|
||||||
|
} else {
|
||||||
|
addConveyorToMonitor(conveyor.modelUuid,
|
||||||
|
() => {
|
||||||
|
handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (model?.type === 'vehicle') {
|
||||||
|
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
if (vehicle) {
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
// Handle current action from vehicle
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addVehicleToMonitor(vehicle.modelUuid,
|
||||||
|
() => {
|
||||||
|
handleAction(action, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleAction(action, materialId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (fromEvent?.type === 'roboticArm') {
|
} else if (fromEvent?.type === 'roboticArm') {
|
||||||
if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
@@ -758,6 +1206,53 @@ export function useTriggerHandler() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (toEvent?.type === 'human') {
|
||||||
|
// Robotic Arm to Human
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
|
||||||
|
setIsPaused(material.materialId, false);
|
||||||
|
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
if (action) {
|
||||||
|
|
||||||
|
if (human) {
|
||||||
|
|
||||||
|
if (human.isActive === false && human.state === 'idle' && human.isPicking && human.currentLoad < human.point.action.loadCapacity) {
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle current action from human
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Event Manager Needed
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (fromEvent?.type === 'storageUnit') {
|
} else if (fromEvent?.type === 'storageUnit') {
|
||||||
if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
@@ -775,6 +1270,326 @@ export function useTriggerHandler() {
|
|||||||
} else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
// Storage Unit to Storage Unit
|
// Storage Unit to Storage Unit
|
||||||
|
|
||||||
|
} else if (toEvent?.type === 'human') {
|
||||||
|
// Storage Unit to Human
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (fromEvent?.type === 'human') {
|
||||||
|
if (toEvent?.type === 'transfer') {
|
||||||
|
// Human to Transfer
|
||||||
|
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
|
||||||
|
if (action && action.triggers.length > 0 &&
|
||||||
|
action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
|
||||||
|
action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid &&
|
||||||
|
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid) {
|
||||||
|
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
if (model?.type === 'roboticArm') {
|
||||||
|
|
||||||
|
handleAction(action, material.materialId);
|
||||||
|
|
||||||
|
} else if (model?.type === 'vehicle') {
|
||||||
|
const nextAction = getActionByUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredAction.actionUuid);
|
||||||
|
|
||||||
|
if (action) {
|
||||||
|
handleAction(action, material.materialId);
|
||||||
|
|
||||||
|
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
if (nextAction) {
|
||||||
|
|
||||||
|
if (vehicle) {
|
||||||
|
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||||
|
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||||
|
actionUuid: action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || '',
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
setIsPaused(materialId, false);
|
||||||
|
|
||||||
|
// Handle current action from vehicle
|
||||||
|
handleAction(nextAction, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Handle current action using Event Manager
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
addVehicleToMonitor(vehicle.modelUuid,
|
||||||
|
() => {
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||||
|
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||||
|
actionUuid: action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || '',
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
setIsPaused(materialId, false);
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
handleAction(nextAction, materialId);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (model?.type === 'transfer') {
|
||||||
|
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
if (conveyor) {
|
||||||
|
setNextLocation(material.materialId, {
|
||||||
|
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid,
|
||||||
|
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid,
|
||||||
|
})
|
||||||
|
setIsPaused(material.materialId, false);
|
||||||
|
setIsVisible(material.materialId, true);
|
||||||
|
handleAction(action, material.materialId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setNextLocation(material.materialId, {
|
||||||
|
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid,
|
||||||
|
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
handleAction(action, material.materialId);
|
||||||
|
}
|
||||||
|
} else if (action) {
|
||||||
|
setNextLocation(material.materialId, null)
|
||||||
|
|
||||||
|
handleAction(action, material.materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
|
// Human to Vehicle
|
||||||
|
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
|
||||||
|
setIsPaused(material.materialId, false);
|
||||||
|
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const vehicle = getVehicleById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
if (action) {
|
||||||
|
|
||||||
|
if (vehicle) {
|
||||||
|
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle current action from vehicle
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Event Manager Needed
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (toEvent?.type === 'machine') {
|
||||||
|
// Human to Machine
|
||||||
|
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
|
||||||
|
// setIsPaused(material.materialId, false);
|
||||||
|
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const machine = getMachineById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
if (action) {
|
||||||
|
|
||||||
|
if (machine) {
|
||||||
|
|
||||||
|
if (machine.isActive === false && machine.state === 'idle') {
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle current action from machine
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Event Manager Needed
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (toEvent?.type === 'roboticArm') {
|
||||||
|
// Human to Robotic Arm
|
||||||
|
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const armBot = getArmBotById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
if (action && armBot) {
|
||||||
|
|
||||||
|
if (armBot.isActive === false && armBot.state === 'idle') {
|
||||||
|
|
||||||
|
// Handle current action from arm bot
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Event Manager Needed
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
|
// Human to Storage Unit
|
||||||
|
|
||||||
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const storageUnit = getStorageUnitById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setPreviousLocation(material.materialId, {
|
||||||
|
modelUuid: material.current.modelUuid,
|
||||||
|
pointUuid: material.current.pointUuid,
|
||||||
|
actionUuid: material.current.actionUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
if (action && storageUnit) {
|
||||||
|
|
||||||
|
if (storageUnit.currentLoad < storageUnit.point.action.storageCapacity) {
|
||||||
|
|
||||||
|
// Handle current action from vehicle
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Event Manager Needed
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (toEvent?.type === 'human') {
|
||||||
|
// Human to Human
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,7 @@ import { useThree, useFrame } from '@react-three/fiber';
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { MaterialModel } from '../../../materials/instances/material/materialModel';
|
import { MaterialModel } from '../../../materials/instances/material/materialModel';
|
||||||
|
|
||||||
type MaterialAnimatorProps = {
|
const MaterialAnimator = ({ agvDetail }: { agvDetail: VehicleStatus }) => {
|
||||||
agvDetail: VehicleStatus;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const MaterialAnimator = ({ agvDetail }: MaterialAnimatorProps) => {
|
|
||||||
const meshRef = useRef<any>(null!);
|
const meshRef = useRef<any>(null!);
|
||||||
const [hasLoad, setHasLoad] = useState(false);
|
const [hasLoad, setHasLoad] = useState(false);
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
|||||||
}
|
}
|
||||||
}, [isReset, isPlaying])
|
}, [isReset, isPlaying])
|
||||||
|
|
||||||
|
|
||||||
const lastTimeRef = useRef(performance.now());
|
const lastTimeRef = useRef(performance.now());
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
@@ -283,88 +282,6 @@ function DraggableSphere({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// function DraggableLineSegment({
|
|
||||||
// index,
|
|
||||||
// start,
|
|
||||||
// end,
|
|
||||||
// updatePoints,
|
|
||||||
// isAnyDragging,
|
|
||||||
// setIsAnyDragging,
|
|
||||||
// }: {
|
|
||||||
// index: number;
|
|
||||||
// start: THREE.Vector3;
|
|
||||||
// end: THREE.Vector3;
|
|
||||||
// updatePoints: (i0: number, p0: THREE.Vector3, i1: number, p1: THREE.Vector3) => void;
|
|
||||||
// isAnyDragging: string;
|
|
||||||
// setIsAnyDragging: (val: string) => void;
|
|
||||||
// }) {
|
|
||||||
// const meshRef = useRef<THREE.Mesh>(null);
|
|
||||||
// const { gl, raycaster, controls } = useThree();
|
|
||||||
// const { activeTool } = useActiveTool();
|
|
||||||
// const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
|
||||||
// const dragStart = useRef<THREE.Vector3 | null>(null);
|
|
||||||
|
|
||||||
|
|
||||||
// const onPointerDown = () => {
|
|
||||||
// if (activeTool !== 'pen' || isAnyDragging) return; // <-- Skip if dragging sphere
|
|
||||||
// setIsAnyDragging("line");
|
|
||||||
// gl.domElement.style.cursor = 'grabbing';
|
|
||||||
// if (controls) (controls as any).enabled = false;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
|
|
||||||
// if (isAnyDragging !== "line" || activeTool !== 'pen') return;
|
|
||||||
|
|
||||||
// const intersect = new THREE.Vector3();
|
|
||||||
// if (raycaster.ray.intersectPlane(plane, intersect)) {
|
|
||||||
// if (!dragStart.current) dragStart.current = intersect.clone();
|
|
||||||
|
|
||||||
// const offset = new THREE.Vector3().subVectors(intersect, dragStart.current);
|
|
||||||
// const newStart = start.clone().add(offset);
|
|
||||||
// const newEnd = end.clone().add(offset);
|
|
||||||
// updatePoints(index, newStart, index + 1, newEnd);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onPointerUp = () => {
|
|
||||||
// if (activeTool !== 'pen') return;
|
|
||||||
// setIsAnyDragging("");
|
|
||||||
// dragStart.current = null;
|
|
||||||
// gl.domElement.style.cursor = 'default';
|
|
||||||
// if (controls) (controls as any).enabled = true;
|
|
||||||
// };
|
|
||||||
// const noopRaycast = (raycaster: THREE.Raycaster, intersects: THREE.Intersection[]) => { };
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <mesh
|
|
||||||
// ref={meshRef}
|
|
||||||
// onPointerDown={onPointerDown}
|
|
||||||
// onPointerMove={onPointerMove}
|
|
||||||
// onPointerUp={onPointerUp}
|
|
||||||
// onPointerMissed={onPointerUp}
|
|
||||||
// raycast={isAnyDragging === "point" ? noopRaycast : undefined} // ✅ Safe
|
|
||||||
// >
|
|
||||||
// <Line points={[start, end]} color="blue" lineWidth={5} />
|
|
||||||
// </mesh>
|
|
||||||
// );
|
|
||||||
|
|
||||||
|
|
||||||
// // return (
|
|
||||||
// // <mesh
|
|
||||||
// // ref={meshRef}
|
|
||||||
// // onPointerDown={onPointerDown}
|
|
||||||
// // onPointerMove={onPointerMove}
|
|
||||||
// // onPointerUp={onPointerUp}
|
|
||||||
// // onPointerMissed={onPointerUp}
|
|
||||||
// // // raycast={isAnyDragging === 'point' ? () => null : undefined}
|
|
||||||
// // raycast={isAnyDragging === "point" ? () => { } : undefined}
|
|
||||||
// // // pointerEvents={isAnyDragging === "point" ? "none" : "auto"} // ✅ the correct way
|
|
||||||
// // >
|
|
||||||
// // <Line points={[start, end]} color="blue" lineWidth={5} />
|
|
||||||
// // </mesh>
|
|
||||||
// // );
|
|
||||||
// }
|
|
||||||
|
|
||||||
function DraggableLineSegment({
|
function DraggableLineSegment({
|
||||||
index,
|
index,
|
||||||
start,
|
start,
|
||||||
@@ -426,207 +343,3 @@ function DraggableLineSegment({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are recently edited files. Do not suggest code that has been deleted.
|
|
||||||
// function DraggableSphere({
|
|
||||||
// index,
|
|
||||||
// position,
|
|
||||||
// onMove,
|
|
||||||
// isAnyDragging,
|
|
||||||
// setIsAnyDragging,
|
|
||||||
// }: {
|
|
||||||
// index: number;
|
|
||||||
// position: THREE.Vector3;
|
|
||||||
// onMove: (index: number, pos: THREE.Vector3) => void;
|
|
||||||
// isAnyDragging: boolean;
|
|
||||||
// setIsAnyDragging: (val: boolean) => void;
|
|
||||||
// }) {
|
|
||||||
// const meshRef = useRef<THREE.Mesh>(null);
|
|
||||||
// const { gl, controls, raycaster } = useThree();
|
|
||||||
// const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); // XZ plane
|
|
||||||
// const isDragging = useRef(false);
|
|
||||||
// const { activeTool } = useActiveTool();
|
|
||||||
|
|
||||||
// const onPointerDown = (e: ThreeEvent<PointerEvent>) => {
|
|
||||||
// if (activeTool !== 'pen') return;
|
|
||||||
|
|
||||||
// isDragging.current = true;
|
|
||||||
// gl.domElement.style.cursor = 'grabbing';
|
|
||||||
|
|
||||||
// if (controls) {
|
|
||||||
// (controls as any).enabled = false;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
|
|
||||||
// if (!isDragging.current || activeTool !== 'pen') return;
|
|
||||||
|
|
||||||
// const intersect = new THREE.Vector3();
|
|
||||||
// if (raycaster.ray.intersectPlane(plane, intersect)) {
|
|
||||||
// meshRef.current!.position.copy(intersect);
|
|
||||||
// onMove(index, intersect);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onPointerUp = () => {
|
|
||||||
// if (activeTool !== 'pen') return;
|
|
||||||
|
|
||||||
// isDragging.current = false;
|
|
||||||
// gl.domElement.style.cursor = 'default';
|
|
||||||
// if (controls) {
|
|
||||||
// (controls as any).enabled = true;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <mesh
|
|
||||||
// ref={meshRef}
|
|
||||||
// position={position}
|
|
||||||
// onPointerDown={onPointerDown}
|
|
||||||
// onPointerMove={onPointerMove}
|
|
||||||
// onPointerUp={onPointerUp}
|
|
||||||
// onPointerMissed={onPointerUp}
|
|
||||||
// >
|
|
||||||
// <sphereGeometry args={[0.2, 16, 16]} />
|
|
||||||
// <meshStandardMaterial color="red" />
|
|
||||||
// </mesh>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function DraggableLineSegment({
|
|
||||||
// index,
|
|
||||||
// start,
|
|
||||||
// end,
|
|
||||||
// updatePoints,
|
|
||||||
// isAnyDragging,
|
|
||||||
// setIsAnyDragging,
|
|
||||||
// }: {
|
|
||||||
// index: number;
|
|
||||||
// start: THREE.Vector3;
|
|
||||||
// end: THREE.Vector3;
|
|
||||||
// updatePoints: (i0: number, p0: THREE.Vector3, i1: number, p1: THREE.Vector3) => void;
|
|
||||||
// isAnyDragging: boolean;
|
|
||||||
// setIsAnyDragging: (val: boolean) => void;
|
|
||||||
// }) {
|
|
||||||
// const meshRef = useRef<THREE.Mesh>(null);
|
|
||||||
// const { gl, camera, controls, raycaster } = useThree();
|
|
||||||
// const { activeTool } = useActiveTool(); // 👈 Get active tool
|
|
||||||
// const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
|
||||||
// const isDragging = useRef(false);
|
|
||||||
// const dragStart = useRef<THREE.Vector3 | null>(null);
|
|
||||||
|
|
||||||
// const onPointerDown = () => {
|
|
||||||
// if (activeTool !== 'pen') return; // 👈 Only allow when tool is 'pen'
|
|
||||||
|
|
||||||
// isDragging.current = true;
|
|
||||||
// gl.domElement.style.cursor = 'grabbing';
|
|
||||||
// if (controls) (controls as any).enabled = false;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
|
|
||||||
// if (!isDragging.current || activeTool !== 'pen') return;
|
|
||||||
|
|
||||||
// const intersect = new THREE.Vector3();
|
|
||||||
// if (raycaster.ray.intersectPlane(plane, intersect)) {
|
|
||||||
// if (!dragStart.current) {
|
|
||||||
// dragStart.current = intersect.clone();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const offset = new THREE.Vector3().subVectors(intersect, dragStart.current);
|
|
||||||
// const newStart = start.clone().add(offset);
|
|
||||||
// const newEnd = end.clone().add(offset);
|
|
||||||
// updatePoints(index, newStart, index + 1, newEnd);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onPointerUp = () => {
|
|
||||||
// if (activeTool !== 'pen') return;
|
|
||||||
|
|
||||||
// isDragging.current = false;
|
|
||||||
// dragStart.current = null;
|
|
||||||
// gl.domElement.style.cursor = 'default';
|
|
||||||
// if (controls) (controls as any).enabled = true;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <mesh
|
|
||||||
// ref={meshRef}
|
|
||||||
// onPointerDown={onPointerDown}
|
|
||||||
// onPointerMove={onPointerMove}
|
|
||||||
// onPointerUp={onPointerUp}
|
|
||||||
// onPointerMissed={onPointerUp}
|
|
||||||
// >
|
|
||||||
// <Line points={[start, end]} color="blue" lineWidth={10} />
|
|
||||||
// </mesh>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <>
|
|
||||||
// {selectedPath === "auto" && <group>
|
|
||||||
// {/* {currentPath.map((pos, i) => {
|
|
||||||
// if (i < currentPath.length - 1) {
|
|
||||||
// return (
|
|
||||||
// <DraggableLineSegment
|
|
||||||
// key={i}
|
|
||||||
// index={i}
|
|
||||||
// start={new THREE.Vector3(...currentPath[i])}
|
|
||||||
// end={new THREE.Vector3(...currentPath[i + 1])}
|
|
||||||
// updatePoints={(i0, p0, i1, p1) => {
|
|
||||||
// const updated = [...currentPath];
|
|
||||||
// updated[i0] = p0.toArray() as [number, number, number];
|
|
||||||
// updated[i1] = p1.toArray() as [number, number, number];
|
|
||||||
// setCurrentPath(updated);
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// })} */}
|
|
||||||
// {currentPath.length > 0 && (
|
|
||||||
// <group onPointerMissed={() => { if (controls) (controls as any).enabled = true; }}>
|
|
||||||
// <Line points={currentPath} color="blue" lineWidth={3} />
|
|
||||||
// {currentPath.map((pos, i) => {
|
|
||||||
// if (i < currentPath.length - 1) {
|
|
||||||
// return (
|
|
||||||
// <React.Fragment key={i}>
|
|
||||||
// <DraggableSphere
|
|
||||||
// key={i}
|
|
||||||
// index={i}
|
|
||||||
// position={new THREE.Vector3(...pos)}
|
|
||||||
// onMove={updatePoint}
|
|
||||||
// />
|
|
||||||
// {/* <DraggableLineSegment
|
|
||||||
// key={i}
|
|
||||||
// index={i}
|
|
||||||
// start={new THREE.Vector3(...currentPath[i])}
|
|
||||||
// end={new THREE.Vector3(...currentPath[i + 1])}
|
|
||||||
// updatePoints={(i0, p0, i1, p1) => {
|
|
||||||
// const updated = [...currentPath];
|
|
||||||
// updated[i0] = p0.toArray() as [number, number, number];
|
|
||||||
// updated[i1] = p1.toArray() as [number, number, number];
|
|
||||||
// setCurrentPath(updated);
|
|
||||||
// }}
|
|
||||||
// /> */}
|
|
||||||
// </React.Fragment>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// )}
|
|
||||||
// </group >
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// </group >
|
|
||||||
// }
|
|
||||||
// </>
|
|
||||||
// );
|
|
||||||
@@ -1,21 +1,23 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
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, useSelectedPath } from '../../../../../store/builder/store';
|
import { useNavMesh, useSelectedPath } from '../../../../../store/builder/store';
|
||||||
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
|
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
|
||||||
import MaterialAnimator from '../animator/materialAnimator';
|
|
||||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||||
import { useProductContext } from '../../../products/productContext';
|
import { useProductContext } from '../../../products/productContext';
|
||||||
import InteractivePoints from '../animator/interactivePoint';
|
import InteractivePoints from '../animator/interactivePoint';
|
||||||
|
|
||||||
|
import MaterialAnimator from '../animator/materialAnimator';
|
||||||
|
import VehicleAnimator from '../animator/vehicleAnimator';
|
||||||
|
|
||||||
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
|
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
|
||||||
const { navMesh } = useNavMesh();
|
const { navMesh } = useNavMesh();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, productStore } = useSceneContext();
|
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore } = useSceneContext();
|
||||||
const { removeMaterial, setEndTime } = materialStore();
|
const { removeMaterial, setEndTime } = materialStore();
|
||||||
const { getStorageUnitById } = storageUnitStore();
|
const { getStorageUnitById } = storageUnitStore();
|
||||||
|
const { getHumanById } = humanStore();
|
||||||
const { getArmBotById } = armBotStore();
|
const { getArmBotById } = armBotStore();
|
||||||
const { getConveyorById } = conveyorStore();
|
const { getConveyorById } = conveyorStore();
|
||||||
const { triggerPointActions } = useTriggerHandler();
|
const { triggerPointActions } = useTriggerHandler();
|
||||||
@@ -149,7 +151,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
|||||||
}
|
}
|
||||||
}, [vehicles, currentPhase, path, isPlaying, selectedPath]);
|
}, [vehicles, currentPhase, path, isPlaying, selectedPath]);
|
||||||
|
|
||||||
|
|
||||||
function animate(currentTime: number) {
|
function animate(currentTime: number) {
|
||||||
if (previousTimeRef.current === null) {
|
if (previousTimeRef.current === null) {
|
||||||
previousTimeRef.current = currentTime;
|
previousTimeRef.current = currentTime;
|
||||||
@@ -196,7 +197,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
|||||||
};
|
};
|
||||||
}, [agvDetail, isPlaying]);
|
}, [agvDetail, isPlaying]);
|
||||||
|
|
||||||
|
|
||||||
function handleCallBack() {
|
function handleCallBack() {
|
||||||
if (currentPhase === 'stationed-pickup') {
|
if (currentPhase === 'stationed-pickup') {
|
||||||
setCurrentPhase('picking');
|
setCurrentPhase('picking');
|
||||||
@@ -246,6 +246,11 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
|||||||
if (action) {
|
if (action) {
|
||||||
handleMaterialDropToStorageUnit(model);
|
handleMaterialDropToStorageUnit(model);
|
||||||
}
|
}
|
||||||
|
} else if (model.type === 'human') {
|
||||||
|
const action = getActionByUuid(selectedProduct.productUuid, agvDetail.point.action.actionUuid);
|
||||||
|
if (action) {
|
||||||
|
handleMaterialDropToHuman(model);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const droppedMaterial = agvDetail.currentLoad;
|
const droppedMaterial = agvDetail.currentLoad;
|
||||||
@@ -259,6 +264,79 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleMaterialDropToHuman(model: HumanEventSchema) {
|
||||||
|
if (model) {
|
||||||
|
if (model.point.action.actionType === 'worker') {
|
||||||
|
loopMaterialDropToHuman(
|
||||||
|
agvDetail.modelUuid,
|
||||||
|
agvDetail.currentLoad,
|
||||||
|
agvDetail.point.action.unLoadDuration,
|
||||||
|
model.modelUuid,
|
||||||
|
model.point.action.loadCapacity,
|
||||||
|
agvDetail.point.action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loopMaterialDropToHuman(
|
||||||
|
vehicleId: string,
|
||||||
|
vehicleCurrentLoad: number,
|
||||||
|
unLoadDuration: number,
|
||||||
|
humanId: string,
|
||||||
|
storageMaxCapacity: number,
|
||||||
|
action: VehicleAction
|
||||||
|
) {
|
||||||
|
startTime = performance.now();
|
||||||
|
const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / isSpeedRef.current));
|
||||||
|
|
||||||
|
const unloadLoop = () => {
|
||||||
|
if (isPausedRef.current) {
|
||||||
|
pauseTimeRef.current ??= performance.now();
|
||||||
|
requestAnimationFrame(unloadLoop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pauseTimeRef.current) {
|
||||||
|
const pauseDuration = performance.now() - pauseTimeRef.current;
|
||||||
|
startTime += pauseDuration;
|
||||||
|
pauseTimeRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elapsedTime = performance.now() - startTime;
|
||||||
|
const human = getHumanById(humanId);
|
||||||
|
|
||||||
|
if (elapsedTime >= fixedInterval) {
|
||||||
|
if (human && agvDetail &&
|
||||||
|
human.currentLoad < storageMaxCapacity &&
|
||||||
|
vehicleCurrentLoad > 0) {
|
||||||
|
|
||||||
|
decrementVehicleLoad(vehicleId, 1);
|
||||||
|
vehicleCurrentLoad -= 1;
|
||||||
|
|
||||||
|
const material = removeLastMaterial(vehicleId);
|
||||||
|
if (material) {
|
||||||
|
|
||||||
|
triggerPointActions(action, material.materialId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vehicleCurrentLoad > 0 && human.currentLoad < storageMaxCapacity) {
|
||||||
|
startTime = performance.now();
|
||||||
|
requestAnimationFrame(unloadLoop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(unloadLoop);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const human = getHumanById(humanId);
|
||||||
|
if (human && vehicleCurrentLoad > 0 && human?.currentLoad < storageMaxCapacity) {
|
||||||
|
unloadLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleMaterialDropToStorageUnit(model: StorageEventSchema) {
|
function handleMaterialDropToStorageUnit(model: StorageEventSchema) {
|
||||||
if (model) {
|
if (model) {
|
||||||
if (model.point.action.actionType === 'store') {
|
if (model.point.action.actionType === 'store') {
|
||||||
@@ -527,10 +605,4 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VehicleInstance;
|
export default VehicleInstance;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -5,20 +5,20 @@ import { useSceneContext } from "../../../scene/sceneContext";
|
|||||||
import { useViewSceneStore } from "../../../../store/builder/store";
|
import { useViewSceneStore } from "../../../../store/builder/store";
|
||||||
|
|
||||||
function VehicleInstances() {
|
function VehicleInstances() {
|
||||||
const { vehicleStore } = useSceneContext();
|
const { vehicleStore } = useSceneContext();
|
||||||
const { vehicles } = vehicleStore();
|
const { vehicles } = vehicleStore();
|
||||||
const { viewSceneLabels } = useViewSceneStore();
|
const { viewSceneLabels } = useViewSceneStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{vehicles.map((vehicle: VehicleStatus) => (
|
{vehicles.map((vehicle: VehicleStatus) => (
|
||||||
<React.Fragment key={vehicle.modelUuid}>
|
<React.Fragment key={vehicle.modelUuid}>
|
||||||
<VehicleInstance agvDetail={vehicle} />
|
<VehicleInstance agvDetail={vehicle} />
|
||||||
{viewSceneLabels && <VehicleContentUi vehicle={vehicle} />}
|
{viewSceneLabels && <VehicleContentUi vehicle={vehicle} />}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VehicleInstances;
|
export default VehicleInstances;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { useWidgetStore } from "../../store/useWidgetStore";
|
|||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { getUserData } from "../../functions/getUserData";
|
import { getUserData } from "../../functions/getUserData";
|
||||||
import { useVersionContext } from "../builder/version/versionContext";
|
import { useVersionContext } from "../builder/version/versionContext";
|
||||||
|
import { useSceneContext } from "../scene/sceneContext";
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ type FormattedZoneData = Record<
|
|||||||
points: [];
|
points: [];
|
||||||
lockedPanels: Side[];
|
lockedPanels: Side[];
|
||||||
zoneUuid: string;
|
zoneUuid: string;
|
||||||
|
zoneName: string;
|
||||||
zoneViewPortTarget: number[];
|
zoneViewPortTarget: number[];
|
||||||
zoneViewPortPosition: number[];
|
zoneViewPortPosition: number[];
|
||||||
widgets: Widget[];
|
widgets: Widget[];
|
||||||
@@ -64,6 +66,9 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { zoneStore } = useSceneContext();
|
||||||
|
const { zones } = zoneStore();
|
||||||
|
|
||||||
|
|
||||||
OuterClick({
|
OuterClick({
|
||||||
contextClassName: [
|
contextClassName: [
|
||||||
@@ -82,6 +87,7 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!projectId || !selectedVersion) return;
|
if (!projectId || !selectedVersion) return;
|
||||||
getZone2dData(organization, projectId, selectedVersion?.versionId || '').then((response) => {
|
getZone2dData(organization, projectId, selectedVersion?.versionId || '').then((response) => {
|
||||||
|
// console.log('response: ', response);
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
// if (response.status === 401) {
|
// if (response.status === 401) {
|
||||||
// console.log("force logout");
|
// console.log("force logout");
|
||||||
@@ -94,19 +100,21 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
const formattedData = response.reduce<FormattedZoneData>(
|
const formattedData = response.reduce<FormattedZoneData>(
|
||||||
(acc, zone) => {
|
(acc, zone) => {
|
||||||
|
|
||||||
acc[zone.zoneName] = {
|
acc[zone.zoneUuid] = {
|
||||||
activeSides: [],
|
activeSides: [],
|
||||||
panelOrder: [],
|
panelOrder: [],
|
||||||
lockedPanels: [],
|
lockedPanels: [],
|
||||||
points: zone.points,
|
points: zone.points,
|
||||||
zoneUuid: zone.zoneUuid,
|
zoneUuid: zone.zoneUuid,
|
||||||
zoneViewPortTarget: zone.viewPortCenter,
|
zoneName: zone.zoneName,
|
||||||
zoneViewPortPosition: zone.viewPortposition,
|
zoneViewPortTarget: zone.viewPortTarget,
|
||||||
|
zoneViewPortPosition: zone.viewPortPosition,
|
||||||
widgets: [],
|
widgets: [],
|
||||||
};
|
};
|
||||||
return acc;
|
return acc;
|
||||||
}, {}
|
}, {}
|
||||||
);
|
);
|
||||||
|
// console.log('formattedData: ', formattedData);
|
||||||
setZonesData(formattedData);
|
setZonesData(formattedData);
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -119,13 +127,14 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
if (!selectedZone) return prev;
|
if (!selectedZone) return prev;
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
[selectedZone.zoneName]: {
|
[selectedZone.zoneUuid]: {
|
||||||
...prev[selectedZone.zoneName], // Keep existing properties
|
...prev[selectedZone.zoneUuid], // Keep existing properties
|
||||||
activeSides: selectedZone.activeSides || [],
|
activeSides: selectedZone.activeSides || [],
|
||||||
panelOrder: selectedZone.panelOrder || [],
|
panelOrder: selectedZone.panelOrder || [],
|
||||||
lockedPanels: selectedZone.lockedPanels || [],
|
lockedPanels: selectedZone.lockedPanels || [],
|
||||||
points: selectedZone.points || [],
|
points: selectedZone.points || [],
|
||||||
zoneUuid: selectedZone.zoneUuid || "",
|
zoneUuid: selectedZone.zoneUuid || "",
|
||||||
|
zoneName: selectedZone.zoneName || "",
|
||||||
zoneViewPortTarget: selectedZone.zoneViewPortTarget || [],
|
zoneViewPortTarget: selectedZone.zoneViewPortTarget || [],
|
||||||
zoneViewPortPosition: selectedZone.zoneViewPortPosition || [],
|
zoneViewPortPosition: selectedZone.zoneViewPortPosition || [],
|
||||||
widgets: selectedZone.widgets || [],
|
widgets: selectedZone.widgets || [],
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ interface DisplayZoneProps {
|
|||||||
points: [];
|
points: [];
|
||||||
widgets: Widget[];
|
widgets: Widget[];
|
||||||
zoneUuid: string;
|
zoneUuid: string;
|
||||||
|
zoneName: string;
|
||||||
zoneViewPortTarget: number[];
|
zoneViewPortTarget: number[];
|
||||||
zoneViewPortPosition: number[];
|
zoneViewPortPosition: number[];
|
||||||
};
|
};
|
||||||
@@ -111,8 +112,8 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||||||
setShowLeftArrow(isOverflowing && canScrollLeft);
|
setShowLeftArrow(isOverflowing && canScrollLeft);
|
||||||
setShowRightArrow(isOverflowing && canScrollRight);
|
setShowRightArrow(isOverflowing && canScrollRight);
|
||||||
|
|
||||||
// console.log('canScrollRight: ', canScrollRight);
|
//
|
||||||
// console.log('isOverflowing: ', isOverflowing);
|
//
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -180,9 +181,10 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||||||
// setSelectedChartId(null);
|
// setSelectedChartId(null);
|
||||||
|
|
||||||
let response = await getSelect2dZoneData(zoneUuid, organization, projectId, selectedVersion?.versionId || '');
|
let response = await getSelect2dZoneData(zoneUuid, organization, projectId, selectedVersion?.versionId || '');
|
||||||
// console.log('response2d: ', response);
|
|
||||||
|
//
|
||||||
let res = await getFloatingZoneData(zoneUuid, organization, projectId, selectedVersion?.versionId || '');
|
let res = await getFloatingZoneData(zoneUuid, organization, projectId, selectedVersion?.versionId || '');
|
||||||
// console.log("resFloating: ", res);
|
//
|
||||||
|
|
||||||
setFloatingWidget(res);
|
setFloatingWidget(res);
|
||||||
// Set the selected zone in the store
|
// Set the selected zone in the store
|
||||||
@@ -201,8 +203,8 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||||||
widgets: response.widgets || [],
|
widgets: response.widgets || [],
|
||||||
points: response.points || [],
|
points: response.points || [],
|
||||||
zoneUuid: zoneUuid,
|
zoneUuid: zoneUuid,
|
||||||
zoneViewPortTarget: response.viewPortCenter || {},
|
zoneViewPortTarget: response.viewPortTarget || [],
|
||||||
zoneViewPortPosition: response.viewPortposition || {},
|
zoneViewPortPosition: response.viewPortPosition || [],
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
echo.error("Failed to select zone");
|
echo.error("Failed to select zone");
|
||||||
@@ -238,20 +240,22 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||||||
>
|
>
|
||||||
{Object.keys(zonesData).length !== 0 ? (
|
{Object.keys(zonesData).length !== 0 ? (
|
||||||
<>
|
<>
|
||||||
{Object.keys(zonesData).map((zoneName, index) => (
|
{Object.values(zonesData).map((zone, index) => (
|
||||||
<div
|
<>
|
||||||
key={index}
|
{ }
|
||||||
className={`zone ${selectedZone.zoneName === zoneName ? "active" : ""
|
<div
|
||||||
}`}
|
key={index}
|
||||||
onClick={() => {
|
className={`zone ${selectedZone.zoneUuid === zone.zoneUuid ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
|
||||||
console.log('zonesData: ', zonesData);
|
handleSelect2dZoneData(zonesData[zone.zoneUuid]?.zoneUuid, zone.zoneName)
|
||||||
handleSelect2dZoneData(zonesData[zoneName]?.zoneUuid, zoneName)
|
}
|
||||||
}
|
}
|
||||||
}
|
>
|
||||||
>
|
{zone.zoneName}
|
||||||
{zoneName}
|
</div>
|
||||||
</div>
|
</>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
|
|
||||||
export default function ZoneCentreTarget() {
|
export default function ZoneCentreTarget() {
|
||||||
const { selectedZone } = useSelectedZoneStore();
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
//
|
||||||
const [previousZoneCentre, setPreviousZoneCentre] = useState<number[] | null>(
|
const [previousZoneCentre, setPreviousZoneCentre] = useState<number[] | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ const UserAuth: React.FC = () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const projects = await recentlyViewed(organization, res.message.userId);
|
const projects = await recentlyViewed(organization, res.message.userId);
|
||||||
console.log('projects: ', projects);
|
|
||||||
if (res.message.isShare) {
|
if (res.message.isShare) {
|
||||||
if (Object.values(projects.RecentlyViewed).length > 0) {
|
if (Object.values(projects.RecentlyViewed).length > 0) {
|
||||||
const firstId = (Object.values(projects?.RecentlyViewed || {})[0] as any)?._id;
|
const firstId = (Object.values(projects?.RecentlyViewed || {})[0] as any)?._id;
|
||||||
|
|||||||
@@ -1,9 +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 getZonesApi = async (
|
export const getZonesApi = async (projectId: string, versionId: string,) => {
|
||||||
projectId: string,
|
|
||||||
versionId: string,
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/V1/zones/${projectId}/${versionId}`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/V1/zones/${projectId}/${versionId}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|||||||
@@ -1,38 +1,37 @@
|
|||||||
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 upsertProductOrEventApi = async (body: any) => {
|
export const upsertProductOrEventApi = async (body: any) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${url_Backend_dwinzo}/api/V1/ProductUpsert`,
|
`${url_Backend_dwinzo}/api/V1/ProductUpsert`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer <access_token>",
|
Authorization: "Bearer <access_token>",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
token: localStorage.getItem("token") || "",
|
token: localStorage.getItem("token") || "",
|
||||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const newAccessToken = response.headers.get("x-access-token");
|
const newAccessToken = response.headers.get("x-access-token");
|
||||||
if (newAccessToken) {
|
if (newAccessToken) {
|
||||||
//console.log("New token received:", newAccessToken);
|
localStorage.setItem("token", newAccessToken);
|
||||||
localStorage.setItem("token", newAccessToken);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
console.error("Failed to add product or event");
|
console.error("Failed to add product or event");
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
echo.error("Failed to upsert product Or eventApi");
|
echo.error("Failed to upsert product Or eventApi");
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
console.log(error.message);
|
console.log(error.message);
|
||||||
} else {
|
} else {
|
||||||
console.log("An unknown error occurred");
|
console.log("An unknown error occurred");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR
|
|||||||
|
|
||||||
export const zoneCameraUpdate = async (zoneData: {}, organization: string, projectId?: string, versionId?: string) => {
|
export const zoneCameraUpdate = async (zoneData: {}, organization: string, projectId?: string, versionId?: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/V1/zones`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/V1/upsertZone`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer <access_token>", // Replace with actual token
|
Authorization: "Bearer <access_token>", // Replace with actual token
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ interface AssetsStore {
|
|||||||
|
|
||||||
// Animation controls
|
// Animation controls
|
||||||
setAnimations: (modelUuid: string, animations: string[]) => void;
|
setAnimations: (modelUuid: string, animations: string[]) => void;
|
||||||
setCurrentAnimation: (modelUuid: string, current: string, isPlaying: boolean) => void;
|
setCurrentAnimation: (modelUuid: string, current: string, isPlaying: boolean, loopAnimation: boolean, isCompleted: boolean) => void;
|
||||||
|
setAnimationComplete: (modelUuid: string, isCompleted: boolean) => void;
|
||||||
|
resetAnimation: (modelUuid: string) => void;
|
||||||
addAnimation: (modelUuid: string, animation: string) => void;
|
addAnimation: (modelUuid: string, animation: string) => void;
|
||||||
removeAnimation: (modelUuid: string, animation: string) => void;
|
removeAnimation: (modelUuid: string, animation: string) => void;
|
||||||
|
|
||||||
@@ -149,22 +151,44 @@ export const createAssetStore = () => {
|
|||||||
if (asset) {
|
if (asset) {
|
||||||
asset.animations = animations;
|
asset.animations = animations;
|
||||||
if (!asset.animationState) {
|
if (!asset.animationState) {
|
||||||
asset.animationState = { current: '', playing: false };
|
asset.animationState = { current: '', isPlaying: false, loopAnimation: true, isCompleted: true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setCurrentAnimation: (modelUuid, current, isPlaying) => {
|
setCurrentAnimation: (modelUuid, current, isPlaying, loopAnimation, isCompleted) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const asset = state.assets.find(a => a.modelUuid === modelUuid);
|
const asset = state.assets.find(a => a.modelUuid === modelUuid);
|
||||||
if (asset?.animationState) {
|
if (asset?.animationState) {
|
||||||
asset.animationState.current = current;
|
asset.animationState.current = current;
|
||||||
asset.animationState.playing = isPlaying;
|
asset.animationState.isPlaying = isPlaying;
|
||||||
|
asset.animationState.loopAnimation = loopAnimation;
|
||||||
|
asset.animationState.isCompleted = isCompleted;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setAnimationComplete: (modelUuid, isCompleted) => {
|
||||||
|
set((state) => {
|
||||||
|
const asset = state.assets.find(a => a.modelUuid === modelUuid);
|
||||||
|
if (asset?.animationState) {
|
||||||
|
asset.animationState.isCompleted = isCompleted;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
resetAnimation: (modelUuid) => {
|
||||||
|
set((state) => {
|
||||||
|
const asset = state.assets.find(a => a.modelUuid === modelUuid);
|
||||||
|
if (asset?.animationState) {
|
||||||
|
asset.animationState.current = '';
|
||||||
|
asset.animationState.isPlaying = true;
|
||||||
|
asset.animationState.loopAnimation = true;
|
||||||
|
asset.animationState.isCompleted = true; }
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
addAnimation: (modelUuid, animation) => {
|
addAnimation: (modelUuid, animation) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const asset = state.assets.find(a => a.modelUuid === modelUuid);
|
const asset = state.assets.find(a => a.modelUuid === modelUuid);
|
||||||
@@ -184,7 +208,7 @@ export const createAssetStore = () => {
|
|||||||
if (asset?.animations) {
|
if (asset?.animations) {
|
||||||
asset.animations = asset.animations.filter(a => a !== animation);
|
asset.animations = asset.animations.filter(a => a !== animation);
|
||||||
if (asset.animationState?.current === animation) {
|
if (asset.animationState?.current === animation) {
|
||||||
asset.animationState.playing = false;
|
asset.animationState.isPlaying = false;
|
||||||
asset.animationState.current = '';
|
asset.animationState.current = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ interface BuilderState {
|
|||||||
|
|
||||||
// Floor Asset
|
// Floor Asset
|
||||||
selectedFloorAsset: Object3D | null;
|
selectedFloorAsset: Object3D | null;
|
||||||
|
loopAnimation: boolean;
|
||||||
|
|
||||||
// Wall Settings
|
// Wall Settings
|
||||||
selectedWall: Object3D | null;
|
selectedWall: Object3D | null;
|
||||||
@@ -64,6 +65,7 @@ interface BuilderState {
|
|||||||
|
|
||||||
// Setters - Floor Asset
|
// Setters - Floor Asset
|
||||||
setSelectedFloorAsset: (asset: Object3D | null) => void;
|
setSelectedFloorAsset: (asset: Object3D | null) => void;
|
||||||
|
setLoopAnimation: (loop: boolean) => void;
|
||||||
|
|
||||||
// Setters - Wall
|
// Setters - Wall
|
||||||
setSelectedWall: (wall: Object3D | null) => void;
|
setSelectedWall: (wall: Object3D | null) => void;
|
||||||
@@ -118,6 +120,7 @@ export const useBuilderStore = create<BuilderState>()(
|
|||||||
deletableWallAsset: null,
|
deletableWallAsset: null,
|
||||||
|
|
||||||
selectedFloorAsset: null,
|
selectedFloorAsset: null,
|
||||||
|
loopAnimation: true,
|
||||||
|
|
||||||
selectedWall: null,
|
selectedWall: null,
|
||||||
wallThickness: 0.5,
|
wallThickness: 0.5,
|
||||||
@@ -197,6 +200,12 @@ export const useBuilderStore = create<BuilderState>()(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLoopAnimation(loopAnimation: boolean) {
|
||||||
|
set((state) => {
|
||||||
|
state.loopAnimation = loopAnimation;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// === Setters: Wall ===
|
// === Setters: Wall ===
|
||||||
|
|
||||||
setSelectedWall: (wall: Object3D | null) => {
|
setSelectedWall: (wall: Object3D | null) => {
|
||||||
|
|||||||
238
app/src/store/simulation/useHumanStore.ts
Normal file
238
app/src/store/simulation/useHumanStore.ts
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
import { immer } from "zustand/middleware/immer";
|
||||||
|
|
||||||
|
interface HumansStore {
|
||||||
|
humans: HumanStatus[];
|
||||||
|
|
||||||
|
addHuman: (productUuid: string, event: HumanEventSchema) => void;
|
||||||
|
removeHuman: (modelUuid: string) => void;
|
||||||
|
updateHuman: (
|
||||||
|
modelUuid: string,
|
||||||
|
updates: Partial<Omit<HumanStatus, "modelUuid" | "productUuid">>
|
||||||
|
) => void;
|
||||||
|
clearHumans: () => void;
|
||||||
|
|
||||||
|
setHumanActive: (modelUuid: string, isActive: boolean) => void;
|
||||||
|
setHumanPicking: (modelUuid: string, isPicking: boolean) => void;
|
||||||
|
setHumanLoad: (modelUuid: string, load: number) => void;
|
||||||
|
setHumanState: (
|
||||||
|
modelUuid: string,
|
||||||
|
newState: HumanStatus["state"]
|
||||||
|
) => void;
|
||||||
|
incrementHumanLoad: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
decrementHumanLoad: (modelUuid: string, decrementBy: number) => void;
|
||||||
|
|
||||||
|
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
|
||||||
|
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void;
|
||||||
|
removeLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
|
||||||
|
getLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
|
||||||
|
clearCurrentMaterials: (modelUuid: string) => void;
|
||||||
|
|
||||||
|
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
incrementDistanceTraveled: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
resetTime: (modelUuid: string) => void;
|
||||||
|
|
||||||
|
getHumanById: (modelUuid: string) => HumanStatus | undefined;
|
||||||
|
getHumansByProduct: (productUuid: string) => HumanStatus[];
|
||||||
|
getActiveHumans: () => HumanStatus[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createHumanStore = () => {
|
||||||
|
return create<HumansStore>()(
|
||||||
|
immer((set, get) => ({
|
||||||
|
humans: [],
|
||||||
|
|
||||||
|
addHuman: (productUuid, event) => {
|
||||||
|
set((state) => {
|
||||||
|
const exists = state.humans.some(h => h.modelUuid === event.modelUuid);
|
||||||
|
if (!exists) {
|
||||||
|
state.humans.push({
|
||||||
|
...event,
|
||||||
|
productUuid,
|
||||||
|
isActive: false,
|
||||||
|
isPicking: false,
|
||||||
|
idleTime: 0,
|
||||||
|
activeTime: 0,
|
||||||
|
currentLoad: 0,
|
||||||
|
currentMaterials: [],
|
||||||
|
distanceTraveled: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeHuman: (modelUuid) => {
|
||||||
|
set((state) => {
|
||||||
|
state.humans = state.humans.filter(h => h.modelUuid !== modelUuid);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateHuman: (modelUuid, updates) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
Object.assign(human, updates);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clearHumans: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.humans = [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setHumanActive: (modelUuid, isActive) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.isActive = isActive;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setHumanPicking: (modelUuid, isPicking) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.isPicking = isPicking;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setHumanLoad: (modelUuid, load) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.currentLoad = load;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setHumanState: (modelUuid, newState) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.state = newState;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
incrementHumanLoad: (modelUuid, incrementBy) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.currentLoad += incrementBy;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
decrementHumanLoad: (modelUuid, decrementBy) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.currentLoad -= decrementBy;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
addCurrentMaterial: (modelUuid, materialType, materialId) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.currentMaterials.push({ materialType, materialId });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setCurrentMaterials: (modelUuid, materials) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.currentMaterials = materials;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeLastMaterial: (modelUuid) => {
|
||||||
|
let removed;
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human && human.currentMaterials.length > 0) {
|
||||||
|
removed = JSON.parse(JSON.stringify(human.currentMaterials.pop()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return removed;
|
||||||
|
},
|
||||||
|
|
||||||
|
getLastMaterial: (modelUuid) => {
|
||||||
|
const human = get().humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human && human.currentMaterials.length > 0) {
|
||||||
|
return human.currentMaterials[human.currentMaterials.length - 1];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearCurrentMaterials: (modelUuid) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.currentMaterials = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.activeTime += incrementBy;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.idleTime += incrementBy;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
incrementDistanceTraveled: (modelUuid, incrementBy) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.distanceTraveled += incrementBy;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
resetTime: (modelUuid) => {
|
||||||
|
set((state) => {
|
||||||
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
if (human) {
|
||||||
|
human.activeTime = 0;
|
||||||
|
human.idleTime = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getHumanById: (modelUuid) => {
|
||||||
|
return get().humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
},
|
||||||
|
|
||||||
|
getHumansByProduct: (productUuid) => {
|
||||||
|
return get().humans.filter(h => h.productUuid === productUuid);
|
||||||
|
},
|
||||||
|
|
||||||
|
getActiveHumans: () => {
|
||||||
|
return get().humans.filter(h => h.isActive);
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HumanStoreType = ReturnType<typeof createHumanStore>;
|
||||||
@@ -32,13 +32,13 @@ type ProductsStore = {
|
|||||||
productUuid: string,
|
productUuid: string,
|
||||||
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'] | HumanPointSchema['action']
|
||||||
) => EventsSchema | undefined;
|
) => EventsSchema | undefined;
|
||||||
removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
|
removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
|
||||||
updateAction: (
|
updateAction: (
|
||||||
productUuid: string,
|
productUuid: string,
|
||||||
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'] | HumanPointSchema['action']>
|
||||||
) => EventsSchema | undefined;
|
) => EventsSchema | undefined;
|
||||||
|
|
||||||
// Trigger-level actionss
|
// Trigger-level actionss
|
||||||
@@ -276,6 +276,15 @@ export const createProductStore = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (event.type === "human") {
|
||||||
|
if ('actions' in point) {
|
||||||
|
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) {
|
||||||
point.action = undefined;
|
point.action = undefined;
|
||||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||||
|
|||||||
@@ -146,6 +146,40 @@ export const useSelectedAction = create<SelectedActionState>()(
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
interface SelectedAnimationState {
|
||||||
|
selectedAnimation: {
|
||||||
|
animationUuid: string;
|
||||||
|
animationName: string;
|
||||||
|
animationType: "behaviour" | "animatedTravel";
|
||||||
|
animation: string | null;
|
||||||
|
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; }
|
||||||
|
} | null;
|
||||||
|
setSelectedAnimation: (animation: {
|
||||||
|
animationUuid: string;
|
||||||
|
animationName: string;
|
||||||
|
animationType: "behaviour" | "animatedTravel";
|
||||||
|
animation: string | null;
|
||||||
|
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; }
|
||||||
|
}) => void;
|
||||||
|
clearSelectedAnimation: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedAnimation = create<SelectedAnimationState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
selectedAnimation: null,
|
||||||
|
setSelectedAnimation: (animation) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedAnimation = animation;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedAnimation: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedAnimation = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
interface IsDraggingState {
|
interface IsDraggingState {
|
||||||
isDragging: "start" | "end" | null;
|
isDragging: "start" | "end" | null;
|
||||||
setIsDragging: (state: "start" | "end" | null) => void;
|
setIsDragging: (state: "start" | "end" | null) => void;
|
||||||
|
|||||||
4
app/src/types/builderTypes.d.ts
vendored
4
app/src/types/builderTypes.d.ts
vendored
@@ -26,7 +26,9 @@ interface Asset {
|
|||||||
animations?: string[];
|
animations?: string[];
|
||||||
animationState?: {
|
animationState?: {
|
||||||
current: string;
|
current: string;
|
||||||
playing: boolean;
|
isPlaying: boolean;
|
||||||
|
loopAnimation: boolean;
|
||||||
|
isCompleted: boolean;
|
||||||
};
|
};
|
||||||
eventData?: {
|
eventData?: {
|
||||||
type: string;
|
type: string;
|
||||||
|
|||||||
190
app/src/types/simulationTypes.d.ts
vendored
190
app/src/types/simulationTypes.d.ts
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
// Base Types
|
||||||
interface AssetEventSchema {
|
interface AssetEventSchema {
|
||||||
modelUuid: string;
|
modelUuid: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
@@ -18,69 +19,7 @@ interface TriggerSchema {
|
|||||||
} | null;
|
} | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConveyorPointSchema {
|
// Actions
|
||||||
uuid: string;
|
|
||||||
position: [number, number, number];
|
|
||||||
rotation: [number, number, number];
|
|
||||||
action: ConveyorAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VehiclePointSchema {
|
|
||||||
uuid: string;
|
|
||||||
position: [number, number, number];
|
|
||||||
rotation: [number, number, number];
|
|
||||||
action: VehicleAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RoboticArmPointSchema {
|
|
||||||
uuid: string;
|
|
||||||
position: [number, number, number];
|
|
||||||
rotation: [number, number, number];
|
|
||||||
actions: RoboticArmAction[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MachinePointSchema {
|
|
||||||
uuid: string;
|
|
||||||
position: [number, number, number];
|
|
||||||
rotation: [number, number, number];
|
|
||||||
action: MachineAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface StoragePointSchema {
|
|
||||||
uuid: string;
|
|
||||||
position: [number, number, number];
|
|
||||||
rotation: [number, number, number];
|
|
||||||
action: StorageAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ConveyorEventSchema extends AssetEventSchema {
|
|
||||||
type: "transfer";
|
|
||||||
speed: number;
|
|
||||||
points: ConveyorPointSchema[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VehicleEventSchema extends AssetEventSchema {
|
|
||||||
type: "vehicle";
|
|
||||||
speed: number;
|
|
||||||
point: VehiclePointSchema;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RoboticArmEventSchema extends AssetEventSchema {
|
|
||||||
type: "roboticArm";
|
|
||||||
speed: number;
|
|
||||||
point: RoboticArmPointSchema;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MachineEventSchema extends AssetEventSchema {
|
|
||||||
type: "machine";
|
|
||||||
point: MachinePointSchema;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface StorageEventSchema extends AssetEventSchema {
|
|
||||||
type: "storageUnit";
|
|
||||||
point: StoragePointSchema;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ConveyorAction {
|
interface ConveyorAction {
|
||||||
actionUuid: string;
|
actionUuid: string;
|
||||||
actionName: string;
|
actionName: string;
|
||||||
@@ -130,19 +69,101 @@ interface StorageAction {
|
|||||||
triggers: TriggerSchema[];
|
triggers: TriggerSchema[];
|
||||||
}
|
}
|
||||||
|
|
||||||
type Action = ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction;
|
interface HumanAction {
|
||||||
|
actionUuid: string;
|
||||||
|
actionName: string;
|
||||||
|
actionType: "worker";
|
||||||
|
pickUpPoint?: { position: [number, number, number] | null; rotation: [number, number, number] | null; }
|
||||||
|
dropPoint?: { position: [number, number, number] | null; rotation: [number, number, number] | null; }
|
||||||
|
loadCapacity: number;
|
||||||
|
triggers: TriggerSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
type PointsScheme = ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema;
|
type Action = ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction | HumanAction;
|
||||||
|
|
||||||
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema;
|
// Points
|
||||||
|
interface ConveyorPointSchema {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
action: ConveyorAction;
|
||||||
|
}
|
||||||
|
|
||||||
type productsSchema = {
|
interface VehiclePointSchema {
|
||||||
productName: string;
|
uuid: string;
|
||||||
productUuid: string;
|
position: [number, number, number];
|
||||||
eventDatas: EventsSchema[];
|
rotation: [number, number, number];
|
||||||
}[]
|
action: VehicleAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RoboticArmPointSchema {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
actions: RoboticArmAction[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MachinePointSchema {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
action: MachineAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StoragePointSchema {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
action: StorageAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HumanPointSchema {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
action: HumanAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PointsScheme = | ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema;
|
||||||
|
|
||||||
|
// Events
|
||||||
|
interface ConveyorEventSchema extends AssetEventSchema {
|
||||||
|
type: "transfer";
|
||||||
|
speed: number;
|
||||||
|
points: ConveyorPointSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VehicleEventSchema extends AssetEventSchema {
|
||||||
|
type: "vehicle";
|
||||||
|
speed: number;
|
||||||
|
point: VehiclePointSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RoboticArmEventSchema extends AssetEventSchema {
|
||||||
|
type: "roboticArm";
|
||||||
|
speed: number;
|
||||||
|
point: RoboticArmPointSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MachineEventSchema extends AssetEventSchema {
|
||||||
|
type: "machine";
|
||||||
|
point: MachinePointSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StorageEventSchema extends AssetEventSchema {
|
||||||
|
type: "storageUnit";
|
||||||
|
point: StoragePointSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HumanEventSchema extends AssetEventSchema {
|
||||||
|
type: "human";
|
||||||
|
speed: number;
|
||||||
|
point: HumanPointSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventsSchema = | ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema | HumanEventSchema;
|
||||||
|
|
||||||
|
// Statuses
|
||||||
interface ConveyorStatus extends ConveyorEventSchema {
|
interface ConveyorStatus extends ConveyorEventSchema {
|
||||||
productUuid: string;
|
productUuid: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
@@ -197,6 +218,25 @@ interface StorageUnitStatus extends StorageEventSchema {
|
|||||||
currentMaterials: { materialType: string; materialId: string; }[];
|
currentMaterials: { materialType: string; materialId: string; }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface HumanStatus extends HumanEventSchema {
|
||||||
|
productUuid: string;
|
||||||
|
isActive: boolean;
|
||||||
|
isPicking: boolean;
|
||||||
|
idleTime: number;
|
||||||
|
activeTime: number;
|
||||||
|
currentLoad: number;
|
||||||
|
currentMaterials: { materialType: string; materialId: string; }[];
|
||||||
|
distanceTraveled: number;
|
||||||
|
currentAction?: {
|
||||||
|
actionUuid: string;
|
||||||
|
actionName: string;
|
||||||
|
animationUuid: string;
|
||||||
|
materialType?: string | null;
|
||||||
|
materialId?: string | null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Materials
|
||||||
interface MaterialSchema {
|
interface MaterialSchema {
|
||||||
materialId: string;
|
materialId: string;
|
||||||
materialName: string;
|
materialName: string;
|
||||||
@@ -230,6 +270,14 @@ interface MaterialSchema {
|
|||||||
|
|
||||||
type MaterialsSchema = MaterialSchema[];
|
type MaterialsSchema = MaterialSchema[];
|
||||||
|
|
||||||
|
// Products
|
||||||
|
type productsSchema = {
|
||||||
|
productName: string;
|
||||||
|
productUuid: string;
|
||||||
|
eventDatas: EventsSchema[];
|
||||||
|
}[];
|
||||||
|
|
||||||
|
// Material History
|
||||||
interface MaterialHistoryEntry {
|
interface MaterialHistoryEntry {
|
||||||
material: MaterialSchema;
|
material: MaterialSchema;
|
||||||
removedAt: string;
|
removedAt: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user