Merge pull request 'Added and modifies vehicle mechanics state, added connection between conveyors and vehicles, Added UI integeration for vehicles events addition.' (#25) from simulation into main

Reviewed-on: http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev/pulls/25
This commit is contained in:
Vishnu 2025-03-29 13:30:30 +00:00
commit c7b438fa98
33 changed files with 944 additions and 777 deletions

View File

@ -636,3 +636,32 @@ export function SaveTemplateIcon({ isActive }: { isActive: boolean }) {
</svg>
);
}
export function MeasureToolIcon({ isActive }: { isActive: boolean }) {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.07495 10.248C7.58308 10.3976 8.18027 10.4818 8.82142 10.4821C9.67666 10.4811 10.4522 10.3335 11.0449 10.0758C11.341 9.94594 11.5943 9.78867 11.7886 9.5888C11.9812 9.39173 12.1201 9.13327 12.1197 8.84166C12.1201 8.55 11.9812 8.29125 11.7886 8.09447C11.4962 7.79625 11.0754 7.58705 10.5676 7.43531C10.0598 7.28569 9.46267 7.20117 8.82147 7.20117C7.96628 7.20183 7.19069 7.34939 6.59767 7.60748C6.30152 7.73737 6.0483 7.89459 5.854 8.09447C5.66144 8.29125 5.5225 8.55 5.52283 8.84166C5.5225 9.13327 5.66139 9.39169 5.854 9.5888C6.14627 9.88669 6.56748 10.0962 7.07495 10.248ZM6.36348 8.58806C6.51831 8.42423 6.84391 8.241 7.27586 8.11561C7.70744 7.98811 8.24336 7.9102 8.82142 7.91058C9.59177 7.9095 10.288 8.0498 10.7608 8.25764C10.9971 8.36016 11.1755 8.48002 11.2787 8.58811C11.384 8.69859 11.41 8.77795 11.4103 8.8417C11.41 8.90508 11.384 8.98477 11.2787 9.09525C11.1242 9.25875 10.7986 9.44231 10.3667 9.5677C9.93508 9.6952 9.39953 9.77278 8.82142 9.77278C8.05075 9.77344 7.35452 9.63351 6.88169 9.42572C6.64544 9.32316 6.46703 9.20334 6.36353 9.09525C6.25825 8.98477 6.23256 8.90508 6.23223 8.8417C6.23251 8.77791 6.2582 8.69855 6.36348 8.58806Z"
fill={isActive ? "var(--highlight-accent-color)" : "var(--text-color)"}
/>
<path
d="M13.5094 5.1167C13.5115 5.1174 13.5139 5.11806 13.516 5.11876L13.5433 5.12673L13.5094 5.1167Z"
fill={isActive ? "var(--highlight-accent-color)" : "var(--text-color)"}
/>
<path
d="M4.13305 18.8834C4.13028 18.8827 4.12747 18.8817 4.12471 18.8806L4.09039 18.8706L4.13305 18.8834Z"
fill={isActive ? "var(--highlight-accent-color)" : "var(--text-color)"}
/>
<path
d="M17.4073 11.4456V8.97325C17.4077 8.60876 17.3207 8.25954 17.1727 7.94355C17.0242 7.62686 16.8165 7.34174 16.5698 7.08811C15.8326 6.33495 14.751 5.79382 13.4528 5.40542L13.4458 5.40345C12.1412 5.01874 10.604 4.80163 8.9538 4.80127C6.75295 4.80325 4.75594 5.18436 3.23696 5.84525L3.23628 5.84561C2.47778 6.17821 1.82951 6.58256 1.33717 7.08842C1.0909 7.34174 0.883095 7.62686 0.734718 7.94355C0.586655 8.25958 0.499642 8.6088 0.500001 8.9733V15.0268C0.499642 15.3912 0.586655 15.7402 0.734718 16.0562C0.883095 16.3729 1.0909 16.658 1.33721 16.9116C2.07451 17.6648 3.15529 18.2059 4.4529 18.5939L4.46153 18.5966C5.76646 18.9814 7.30337 19.1981 8.95385 19.1988H23.5V11.4457H17.4073V11.4456ZM2.19167 7.91665C2.70288 7.38486 3.62108 6.88991 4.79849 6.54437C5.97562 6.19681 7.4093 5.99067 8.95385 5.99098C11.013 5.98999 12.8759 6.35844 14.1944 6.93573C14.8537 7.22319 15.3745 7.56311 15.7157 7.91665C16.0586 8.27283 16.2173 8.62367 16.2177 8.97325C16.2173 9.32243 16.0586 9.67368 15.7157 10.0299C15.2045 10.5613 14.2863 11.0562 13.1089 11.4018C11.9318 11.7497 10.4984 11.9555 8.9538 11.9555C6.89436 11.9562 5.0315 11.5878 3.71295 11.0108C3.05367 10.7233 2.53285 10.3834 2.19162 10.0299C1.84869 9.67368 1.69003 9.32243 1.68967 8.97325C1.69007 8.62372 1.84874 8.27283 2.19167 7.91665ZM16.2176 10.488V11.9555H13.6018C13.9049 11.8566 14.1973 11.751 14.4665 11.6335C15.1832 11.3198 15.7758 10.9441 16.2043 10.5026L16.2176 10.488ZM22.3103 18.009H20.2707V15.0058H19.5909V18.009H18.0898V16.3824H17.4099V18.009H15.9085V15.0058H15.2287V18.009H13.7272V16.3824H13.0474V18.009H11.5463V15.0058H10.8665V18.009H9.36542V16.3824H8.68558V18.003C8.16938 17.9951 7.66778 17.9645 7.18415 17.9128V15.0058H6.5043V17.8251C5.43642 17.6624 4.48039 17.4002 3.71295 17.0643C3.05367 16.7768 2.53285 16.4369 2.19162 16.0834C1.84869 15.7271 1.69003 15.3759 1.68967 15.0267V10.488L1.70296 10.5026C2.34598 11.1632 3.35609 11.683 4.60586 12.0538C5.85604 12.4229 7.34848 12.6351 8.95376 12.6354H22.3102V18.009H22.3103Z"
fill={isActive ? "var(--highlight-accent-color)" : "var(--text-color)"}
/>
</svg>
);
}

View File

@ -22,7 +22,10 @@ const Header: React.FC = () => {
<div
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`}
onClick={() => {
if (activeModule !== "market") setToggleUI(!toggleUI);
if (activeModule !== "market") {
setToggleUI(!toggleUI);
localStorage.setItem("navBarUi", JSON.stringify(!toggleUI));
}
}}
>
<ToggleSidebarIcon />

View File

@ -12,7 +12,6 @@ const Header: React.FC = () => {
const guestUsers: ActiveUser[] = activeUsers.filter(
(user: ActiveUser) => user.userName !== userName
);
console.log('guestUsers: ', guestUsers);
return (
<div className="header-container">
@ -29,15 +28,13 @@ const Header: React.FC = () => {
<div className="other-guest">+{guestUsers.length - 3}</div>
)}
{guestUsers.slice(0, 3).map((user, index) => (
<>
<div
key={index}
className="user-profile"
style={{ background: getAvatarColor(index) }}
>
{user.userName[0]}
</div>
</>
<div
key={index}
className="user-profile"
style={{ background: getAvatarColor(index) }}
>
{user.userName[0]}
</div>
))}
</div>
<div className="user-profile-container">

View File

@ -14,7 +14,10 @@ import ConveyorMechanics from "./mechanics/ConveyorMechanics";
import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
import { useSelectedActionSphere } from "../../../store/store";
import {
useSelectedActionSphere,
useselectedFloorItem,
} from "../../../store/store";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties";
@ -25,6 +28,7 @@ const SideBarRight: React.FC = () => {
const { toggleUI } = useToggleStore();
const { selectedActionSphere } = useSelectedActionSphere();
const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useselectedFloorItem();
// Reset activeList whenever activeModule changes
useEffect(() => {
if (activeModule !== "simulation") setSubModule("properties");
@ -38,8 +42,9 @@ const SideBarRight: React.FC = () => {
<div className="sidebar-actions-container">
{/* {activeModule === "builder" && ( */}
<div
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
}`}
className={`sidebar-action-list ${
subModule === "properties" ? "active" : ""
}`}
onClick={() => setSubModule("properties")}
>
<PropertiesIcon isActive={subModule === "properties"} />
@ -48,22 +53,25 @@ const SideBarRight: React.FC = () => {
{activeModule === "simulation" && (
<>
<div
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
}`}
className={`sidebar-action-list ${
subModule === "mechanics" ? "active" : ""
}`}
onClick={() => setSubModule("mechanics")}
>
<MechanicsIcon isActive={subModule === "mechanics"} />
</div>
<div
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
}`}
className={`sidebar-action-list ${
subModule === "simulations" ? "active" : ""
}`}
onClick={() => setSubModule("simulations")}
>
<SimulationIcon isActive={subModule === "simulations"} />
</div>
<div
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
}`}
className={`sidebar-action-list ${
subModule === "analysis" ? "active" : ""
}`}
onClick={() => setSubModule("analysis")}
>
<AnalysisIcon isActive={subModule === "analysis"} />
@ -75,12 +83,21 @@ const SideBarRight: React.FC = () => {
{/* process builder */}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" && (
activeModule !== "visualization" &&
!selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<GlobalProperties />
{/* <ZoneProperties /> */}
{/* <AsstePropertiies /> */}
</div>
</div>
)}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" &&
selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<AsstePropertiies />
</div>
</div>
)}
@ -89,9 +106,7 @@ const SideBarRight: React.FC = () => {
activeModule === "builder" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
{/* <GlobalProperties /> */}
<ZoneProperties />
{/* <AsstePropertiies /> */}
</div>
</div>
)}
@ -99,20 +114,24 @@ const SideBarRight: React.FC = () => {
{toggleUI && activeModule === "simulation" && (
<>
{subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Conveyor" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<ConveyorMechanics />
{subModule === "mechanics" &&
selectedActionSphere &&
selectedActionSphere.path.type === "Conveyor" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<ConveyorMechanics />
</div>
</div>
</div>
)}
{subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Vehicle" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
{/* <VehicleMechanics /> */}
)}
{subModule === "mechanics" &&
selectedActionSphere &&
selectedActionSphere.path.type === "Vehicle" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<VehicleMechanics />
</div>
</div>
</div>
)}
)}
{subModule === "mechanics" && !selectedActionSphere && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">

View File

@ -4,12 +4,16 @@ interface PositionInputProps {
onChange: (value: string) => void; // Callback for value change
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
value1?: number;
value2?: number;
}
const PositionInput: React.FC<PositionInputProps> = ({
onChange,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
value1 = "number",
value2 = "number",
}) => {
return (
<div className="custom-input-container">
@ -22,6 +26,7 @@ const PositionInput: React.FC<PositionInputProps> = ({
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
value={value2}
/>
</div>
<div className="input-container">
@ -31,6 +36,7 @@ const PositionInput: React.FC<PositionInputProps> = ({
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
value={value1}
/>
</div>
</div>

View File

@ -4,17 +4,19 @@ interface RotationInputProps {
onChange: (value: string) => void; // Callback for value change
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
value?: number;
}
const RotationInput: React.FC<RotationInputProps> = ({
onChange,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
value = "number",
}) => {
return (
<div className="custom-input-container">
<div className="header">Rotation</div>
<div className="inputs-container" style={{display: "block"}}>
<div className="inputs-container" style={{ display: "block" }}>
<div className="input-container">
<div className="custom-input-label">Rotate : </div>
<input
@ -22,6 +24,7 @@ const RotationInput: React.FC<RotationInputProps> = ({
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
value={value}
/>
</div>
</div>

View File

@ -8,9 +8,7 @@ import {
import RenameInput from "../../../ui/inputs/RenameInput";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { handleResize } from "../../../../functions/handleResizePannel";
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
import * as THREE from 'three';
import * as Types from '../../../../types/world/worldTypes';
@ -218,7 +216,7 @@ const ConveyorMechanics: React.FC = () => {
setSimulationPaths(updatedPaths);
};
const handleSpeedChange = (speed: number) => {
const handleSpeedChange = (speed: number | string) => {
if (!selectedPath) return;
const updatedPaths = simulationPaths.map((path) =>
@ -243,6 +241,7 @@ const ConveyorMechanics: React.FC = () => {
uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`,
type: '',
bufferTime: 0,
isUsed: false
};
@ -298,8 +297,19 @@ const ConveyorMechanics: React.FC = () => {
);
setSimulationPaths(updatedPaths);
// Ensure the selectedItem is updated immediately
const updatedTrigger = updatedPaths
.flatMap((path) => (path.type === "Conveyor" ? path.points : []))
.flatMap((point) => point.triggers)
.find((trigger) => trigger.uuid === uuid);
if (updatedTrigger) {
setSelectedItem({ type: "trigger", item: updatedTrigger });
}
};
// Update the toggle handlers to immediately update the selected item
const handleActionToggle = (uuid: string) => {
if (!selectedActionSphere) return;
@ -373,17 +383,61 @@ const ConveyorMechanics: React.FC = () => {
}
};
const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid ? { ...trigger, bufferTime } : trigger
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
// Immediately update selectedItem if it's the currently selected trigger
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
setSelectedItem({
...selectedItem,
item: {
...selectedItem.item,
bufferTime
}
});
}
};
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null);
useEffect(() => {
setSelectedItem(null); // Reset selectedItem when selectedActionSphere changes
setSelectedItem(null);
}, [selectedActionSphere]);
return (
<div className="machine-mechanics-container">
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"}
</div>
{!selectedPath &&
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"}
</div>
}
{selectedPath &&
<div className="machine-mechanics-header">
{selectedPath.path.modelName || "path name not found"}
</div>
}
<div className="machine-mechanics-content-container">
{!selectedPath &&
@ -559,25 +613,45 @@ const ConveyorMechanics: React.FC = () => {
options={["On-Hit", "Buffer"]}
onSelect={(option) => handleTriggerSelect(selectedItem.item.uuid, option)}
/>
{selectedItem.item.type === "Buffer" && (
<InputWithDropDown
label="Buffer Time"
value={selectedItem.item.bufferTime.toString()}
onChange={(value) => {
handleTriggerBufferTimeChange(selectedItem.item.uuid, parseInt(value));
}}
/>
)}
</>
)}
</>
)}
{selectedPath && !selectedItem && (
<div className="speed-control">
<div key={selectedPath?.path.modeluuid || "none"} className="speed-control">
<InputWithDropDown
label="Conveyor Speed"
value={selectedPath.path.speed.toString()}
onChange={(value) => handleSpeedChange(parseFloat(value))}
min={0}
value={selectedPath.path.speed === "Inherit" ? "" : selectedPath.path.speed.toString()}
onChange={(value) => handleSpeedChange((value === "") ? "Inherit" : parseInt(value))}
/>
</div>
)}
</div>
<div className="footer">
<InfoIcon />
By selecting points, you can create events and triggers.
</div>
{!selectedPath && (
<div className="footer">
<InfoIcon />
Configure the point's action and trigger properties.
</div>
)}
{selectedPath && (
<div className="footer">
<InfoIcon />
Configure the path properties.
</div>
)}
</div>
</div>
);

View File

@ -1,561 +1,158 @@
import React, { useRef, useState, useMemo, useEffect } from "react";
import {
AddIcon,
InfoIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import React, { useRef, useMemo } from "react";
import { InfoIcon } from "../../../icons/ExportCommonIcons";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { handleResize } from "../../../../functions/handleResizePannel";
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
import * as THREE from 'three';
import { useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
import * as Types from '../../../../types/world/worldTypes';
import InputToggle from "../../../ui/inputs/InputToggle";
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
const VehicleMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
const { selectedPath, setSelectedPath } = useSelectedPath();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const actionsContainerRef = useRef<HTMLDivElement>(null);
const triggersContainerRef = useRef<HTMLDivElement>(null);
const propertiesContainerRef = useRef<HTMLDivElement>(null);
const selectedPoint = useMemo(() => {
if (!selectedActionSphere) return null;
return simulationPaths
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
.flatMap((path) => path.points)
.find((point) => point.uuid === selectedActionSphere.point.uuid);
const { selectedPoint, connectedPointUuids } = useMemo(() => {
if (!selectedActionSphere?.point?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
const vehiclePaths = simulationPaths.filter(
(path): path is Types.VehicleEventsSchema => path.type === "Vehicle"
);
const point = vehiclePaths.find(
(path) => path.point.uuid === selectedActionSphere.point.uuid
)?.point;
if (!point) return { selectedPoint: null, connectedPointUuids: [] };
const connectedUuids: string[] = [];
if (point.connections?.targets) {
point.connections.targets.forEach(target => {
connectedUuids.push(target.pointUUID);
});
}
return {
selectedPoint: point,
connectedPointUuids: connectedUuids
};
}, [selectedActionSphere, simulationPaths]);
const handleAddAction = () => {
if (!selectedActionSphere) return;
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['point']['actions']>) => {
if (!selectedActionSphere?.point?.uuid) return;
const updatedPaths = simulationPaths.map((path) => {
if (path.type === "Conveyor") {
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
return {
...path,
points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) {
const actionIndex = point.actions.length;
const newAction = {
uuid: THREE.MathUtils.generateUUID(),
name: `Action ${actionIndex + 1}`,
type: 'Inherit',
material: 'Inherit',
delay: 'Inherit',
spawnInterval: 'Inherit',
isUsed: false
};
return { ...point, actions: [...point.actions, newAction] };
point: {
...path.point,
actions: {
...path.point.actions,
...updatedAction
}
return point;
}),
}
};
}
return path;
});
setSimulationPaths(updatedPaths);
};
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
const handleDeleteAction = (uuid: string) => {
if (!selectedActionSphere) return;
const handleStartPointChange = React.useCallback((uuid: string) => {
handleActionUpdate({ start: uuid });
}, [handleActionUpdate]);
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
const handleEndPointChange = React.useCallback((uuid: string) => {
handleActionUpdate({ end: uuid });
}, [handleActionUpdate]);
const handleHitCountChange = React.useCallback((hitCount: number) => {
handleActionUpdate({ hitCount });
}, [handleActionUpdate]);
const handleBufferChange = React.useCallback((buffer: number) => {
handleActionUpdate({ buffer });
}, [handleActionUpdate]);
const handleSpeedChange = React.useCallback((speed: number) => {
if (!selectedActionSphere?.point?.uuid) return;
const updatedPaths = simulationPaths.map((path) => {
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
return {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleActionSelect = (uuid: string, actionType: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? {
...action,
type: actionType,
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material,
delay: actionType === 'Delay' ? 'Inherit' : action.delay,
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval
}
: action
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
// Update the selected item to reflect changes
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
const updatedAction = updatedPaths
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
.flatMap(path => path.points)
.find(p => p.uuid === selectedActionSphere.point.uuid)
?.actions.find(a => a.uuid === uuid);
if (updatedAction) {
setSelectedItem({
type: "action",
item: updatedAction
});
point: {
...path.point,
speed: speed
}
};
}
}
};
// Modified handleMaterialSelect to ensure it only applies to relevant action types
const handleMaterialSelect = (uuid: string, material: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid &&
(action.type === 'Spawn' || action.type === 'Swap')
? { ...action, material }
: action
),
}
: point
),
}
: path
);
return path;
});
setSimulationPaths(updatedPaths);
// Update selected item if it's the current action
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
setSelectedItem({
...selectedItem,
item: {
...selectedItem.item,
material
}
});
}
};
const handleDelayChange = (uuid: string, delay: number | string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, delay } : action
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, spawnInterval } : action
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleSpeedChange = (speed: number) => {
if (!selectedPath) return;
const updatedPaths = simulationPaths.map((path) =>
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
);
setSimulationPaths(updatedPaths);
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
};
const handleAddTrigger = () => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) {
const triggerIndex = point.triggers.length;
const newTrigger = {
uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`,
type: '',
isUsed: false
};
return { ...point, triggers: [...point.triggers, newTrigger] };
}
return point;
}),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleDeleteTrigger = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleTriggerSelect = (uuid: string, triggerType: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
// Update the toggle handlers to immediately update the selected item
const handleActionToggle = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) => ({
...action,
isUsed: action.uuid === uuid ? !action.isUsed : false,
})),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
// Immediately update the selected item if it's the one being toggled
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
setSelectedItem({
...selectedItem,
item: {
...selectedItem.item,
isUsed: !selectedItem.item.isUsed
}
});
}
};
// Do the same for trigger toggle
const handleTriggerToggle = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) => ({
...trigger,
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
})),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
// Immediately update the selected item if it's the one being toggled
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
setSelectedItem({
...selectedItem,
item: {
...selectedItem.item,
isUsed: !selectedItem.item.isUsed
}
});
}
};
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null);
useEffect(() => {
setSelectedItem(null); // Reset selectedItem when selectedActionSphere changes
}, [selectedActionSphere]);
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
return (
<div className="machine-mechanics-container">
<div className="machine-mechanics-container" key={selectedPoint?.uuid}>
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"}
{selectedActionSphere?.path?.modelName || "Vehicle point not found"}
</div>
<div className="machine-mechanics-content-container">
<div className="actions">
<div className="header">
<div className="header-value">Actions</div>
<div className="add-button" onClick={handleAddAction}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={actionsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
<>
{console.log(selectedPoint)}
</>
</div>
<div
className="resize-icon"
id="action-resize"
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
<div className="triggers">
<div className="header">
<div className="header-value">Triggers</div>
<div className="add-button" onClick={handleAddTrigger}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={triggersContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{selectedPoint?.triggers.map((trigger) => (
<div
key={trigger.uuid}
className={`list-item ${selectedItem?.type === "trigger" &&
selectedItem.item?.uuid === trigger.uuid
? "active"
: ""
}`}
>
<div
className="value"
onClick={() => setSelectedItem({ type: "trigger", item: trigger })}
>
<RenameInput value={trigger.name} />
</div>
<div
className="remove-button"
onClick={() => handleDeleteTrigger(trigger.uuid)}
>
<RemoveIcon />
</div>
</div>
))}
</div>
<div
className="resize-icon"
id="trigger-resize"
onMouseDown={(e) => handleResize(e, triggersContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
<div className="selected-properties-container">
{selectedItem && (
<div className="selected-properties-container" ref={propertiesContainerRef}>
<div className="properties-header">Vehicle Properties</div>
{selectedPoint && (
<>
<div className="properties-header">{selectedItem.item.name}</div>
<LabledDropdown
key={`start-${selectedPoint.uuid}`}
label="Start Point"
defaultOption={selectedPoint.actions.start || "Select start point"}
options={connectedPointUuids}
onSelect={handleStartPointChange}
/>
{selectedItem.type === "action" && (
<>
<InputToggle
inputKey="enableTrigger"
label="Enable Trigger"
value={selectedItem.item.isUsed}
onClick={() => handleActionToggle(selectedItem.item.uuid)}
/>
<LabledDropdown
defaultOption={selectedItem.item.type}
options={["Inherit", "Spawn", "Swap", "Despawn", "Delay"]}
onSelect={(option) => handleActionSelect(selectedItem.item.uuid, option)}
/>
<LabledDropdown
key={`end-${selectedPoint.uuid}`}
label="End Point"
defaultOption={selectedPoint.actions.end || "Select end point"}
options={connectedPointUuids}
onSelect={handleEndPointChange}
/>
{/* Only show material dropdown for Spawn/Swap actions */}
{(selectedItem.item.type === 'Spawn' || selectedItem.item.type === 'Swap') && (
<LabledDropdown
label={selectedItem.item.type === 'Spawn' ? 'Spawn Material' : 'Swap Material'}
defaultOption={selectedItem.item.material}
options={["Inherit", "Crate", "Box"]}
onSelect={(option) => handleMaterialSelect(selectedItem.item.uuid, option)}
/>
)}
{/* Only show delay input for Delay actions */}
{selectedItem.item.type === 'Delay' && (
<InputWithDropDown
label="Delay Time"
value={selectedItem.item.delay === 'Inherit'
? undefined
: selectedItem.item.delay}
onChange={(value) => {
const numValue = parseInt(value);
handleDelayChange(
selectedItem.item.uuid,
!value ? 'Inherit' : numValue
);
}}
/>
)}
{/* Only show spawn interval for Spawn actions */}
{selectedItem.item.type === 'Spawn' && (
<InputWithDropDown
label="Spawn Interval"
min={0}
defaultValue={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
value={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
onChange={(value) => {
handleSpawnIntervalChange(selectedItem.item.uuid, (value === "") ? "Inherit" : parseInt(value));
}}
/>
)}
</>
)}
{selectedItem.type === "trigger" && (
<>
<InputToggle
inputKey="enableTrigger"
label="Enable Trigger"
value={selectedItem.item.isUsed}
onClick={() => handleTriggerToggle(selectedItem.item.uuid)}
/>
<LabledDropdown
defaultOption={selectedItem.item.type || "Select Trigger Type"}
options={["On-Hit", "Buffer"]}
onSelect={(option) => handleTriggerSelect(selectedItem.item.uuid, option)}
/>
</>
)}
</>
)}
{selectedPath && !selectedItem && (
<div className="speed-control">
<InputWithDropDown
label="ConveyorEventsSchema Speed"
value={selectedPath.path.speed.toString()}
key={`hitcount-${selectedPoint.uuid}`}
label="Hit Count"
value={selectedPoint.actions.hitCount.toString()}
onChange={(value) => handleHitCountChange(parseInt(value))}
/>
<InputWithDropDown
key={`buffer-${selectedPoint.uuid}`}
label="Buffer Time"
value={selectedPoint.actions.buffer.toString()}
onChange={(value) => handleBufferChange(parseInt(value))}
/>
<InputWithDropDown
key={`speed-${selectedPoint.uuid}`}
label="Vehicle Speed"
value={selectedPoint.speed.toString()}
onChange={(value) => handleSpeedChange(parseFloat(value))}
/>
</div>
</>
)}
</div>
<div className="footer">
<InfoIcon />
By selecting points, you can create events and triggers.
Configure vehicle's movement and interaction properties.
</div>
</div>
</div>
);
};
export default VehicleMechanics;
export default React.memo(VehicleMechanics);

View File

@ -1,9 +1,11 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import InputToggle from "../../../ui/inputs/InputToggle";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { RemoveIcon } from "../../../icons/ExportCommonIcons";
import PositionInput from "../customInput/PositionInputs";
import RotationInput from "../customInput/RotationInput";
import { useselectedFloorItem } from "../../../../store/store";
import * as THREE from "three";
interface UserData {
id: number; // Unique identifier for the user data
@ -14,7 +16,13 @@ interface UserData {
const AssetProperties: React.FC = () => {
const [userData, setUserData] = useState<UserData[]>([]); // State to track user data
const [nextId, setNextId] = useState(1); // Unique ID for new entries
const { selectedFloorItem } = useselectedFloorItem();
let xValue = selectedFloorItem.position.x;
let zValue = selectedFloorItem.position.z;
let rotationRad = selectedFloorItem.rotation.y;
let rotationDeg = THREE.MathUtils.radToDeg(rotationRad);
// useEffect(() => {}, [selectedFloorItem]);
// Function to handle adding new user data
const handleAddUserData = () => {
const newUserData: UserData = {
@ -45,12 +53,16 @@ const AssetProperties: React.FC = () => {
return (
<div className="asset-properties-container">
{/* Name */}
<div className="header">Selected Object</div>
<div className="header">{selectedFloorItem.userData.name}</div>
<div className="split"></div>
<PositionInput onChange={() => { }} />
<RotationInput onChange={() => { }} />
<PositionInput
onChange={() => {}}
value1={xValue.toFixed(5)}
value2={zValue.toFixed(5)}
/>
<RotationInput onChange={() => {}} value={rotationDeg} />
<div className="split"></div>

View File

@ -3,8 +3,31 @@ import InputRange from "../../../ui/inputs/InputRange";
import InputToggle from "../../../ui/inputs/InputToggle";
import { AI_Icon } from "../../../icons/ExportCommonIcons";
import LabeledButton from "../../../ui/inputs/LabledButton";
import {
useAzimuth,
useElevation,
useRenderDistance,
useResetCamera,
useRoofVisibility,
useSelectedWallItem,
useShadows,
useSocketStore,
useToggleView,
useWallVisibility,
} from "../../../../store/store";
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
const GlobalProperties: React.FC = () => {
const { toggleView, setToggleView } = useToggleView();
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
const { wallVisibility, setWallVisibility } = useWallVisibility();
const { shadows, setShadows } = useShadows();
const { resetCamera, setResetCamera } = useResetCamera();
const { elevation, setElevation } = useElevation();
const { azimuth, setAzimuth } = useAzimuth();
const { renderDistance, setRenderDistance } = useRenderDistance();
const { socket } = useSocketStore();
const [limitDistance, setLimitDistance] = useState(false);
const [distance, setDistance] = useState<number>(5);
@ -23,6 +46,93 @@ const GlobalProperties: React.FC = () => {
function updateGridDistance(value: number) {
setGridDistance(value);
}
// Function to toggle roof visibility
const changeRoofVisibility = async () => {
const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0];
//using REST
const data = await setEnvironment(
organization,
localStorage.getItem("userId")!,
wallVisibility,
!roofVisibility,
shadows
);
// console.log('data: ', data);
//using Socket
// const visData = {
// organization: organization,
// userId: localStorage.getItem('userId')!,
// wallVisibility: wallVisibility,
// roofVisibility: !roofVisibility,
// shadowVisibility: shadows,
// socketId: socket.id
// };
// socket.emit('v1:Environment:set', visData)
setRoofVisibility(!roofVisibility); // Toggle roof visibility
};
// Function to toggle wall visibility
const changeWallVisibility = async () => {
const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0];
//using REST
const data = await setEnvironment(
organization,
localStorage.getItem("userId")!,
!wallVisibility,
roofVisibility,
shadows
);
// console.log('data: ', data);
//using Socket
// const visData = {
// organization: organization,
// userId: localStorage.getItem('userId')!,
// wallVisibility: !wallVisibility,
// roofVisibility: roofVisibility,
// shadowVisibility: shadows,
// socketId: socket.id
// };
// socket.emit('v1:Environment:set', visData)
setWallVisibility(!wallVisibility); // Toggle wall visibility
};
const shadowVisibility = async () => {
const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0];
//using REST
const data = await setEnvironment(
organization,
localStorage.getItem("userId")!,
wallVisibility,
roofVisibility,
!shadows
);
// console.log('data: ', data);
//using Socket
// const visData = {
// organization: organization,
// userId: localStorage.getItem('userId')!,
// wallVisibility: wallVisibility,
// roofVisibility: roofVisibility,
// shadowVisibility: !shadows,
// socketId: socket.id
// };
// socket.emit('v1:Environment:set', visData)
setShadows(!shadows);
};
const toggleResetCamera = () => {
if (!toggleView) {
setResetCamera(true); // Trigger reset camera action
}
};
return (
<div className="global-properties-container">
@ -34,10 +144,29 @@ const GlobalProperties: React.FC = () => {
<div className="split"></div>
<InputToggle inputKey="1" label="Roof Visibility" />
<InputToggle inputKey="2" label="Wall Visibility" />
<InputToggle inputKey="3" label="Shadows Visibility" />
<LabeledButton label="Reset Camera" onClick={() => {}} value="Reset"/>
<InputToggle
value={roofVisibility}
inputKey="1"
label="Roof Visibility"
onClick={changeRoofVisibility}
/>
<InputToggle
value={wallVisibility}
inputKey="2"
label="Wall Visibility"
onClick={changeWallVisibility}
/>
<InputToggle
value={shadows}
inputKey="3"
label="Shadows Visibility"
onClick={shadowVisibility}
/>
<LabeledButton
label="Reset Camera"
onClick={toggleResetCamera}
value="Reset"
/>
<div className="split"></div>

View File

@ -18,7 +18,7 @@ const ModuleToggle: React.FC = () => {
className={`module-list ${activeModule === "builder" && "active"}`}
onClick={() => {
setActiveModule("builder");
setToggleUI(true);
setToggleUI(localStorage.getItem('navBarUi') ? localStorage.getItem('navBarUi') === 'true' : true)
}}
>
<div className="icon">
@ -30,7 +30,7 @@ const ModuleToggle: React.FC = () => {
className={`module-list ${activeModule === "simulation" && "active"}`}
onClick={() => {
setActiveModule("simulation");
setToggleUI(true);
setToggleUI(localStorage.getItem('navBarUi') ? localStorage.getItem('navBarUi') === 'true' : true)
}}
>
<div className="icon">
@ -39,12 +39,11 @@ const ModuleToggle: React.FC = () => {
<div className="module">Simulation</div>
</div>
<div
className={`module-list ${
activeModule === "visualization" && "active"
}`}
className={`module-list ${activeModule === "visualization" && "active"
}`}
onClick={() => {
setActiveModule("visualization");
setToggleUI(true);
setToggleUI(localStorage.getItem('navBarUi') ? localStorage.getItem('navBarUi') === 'true' : true)
}}
>
<div className="icon">

View File

@ -3,8 +3,10 @@ import {
AsileIcon,
CommentIcon,
CursorIcon,
DeleteIcon,
FloorIcon,
FreeMoveIcon,
MeasureToolIcon,
PenIcon,
PlayIcon,
SaveTemplateIcon,
@ -18,17 +20,24 @@ import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useTemplateStore from "../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../store/useZoneStore";
import {
useActiveTool,
useAddAction,
useDeleteModels,
useDeletePointOrLine,
useMovePoint,
useRefTextUpdate,
useSelectedWallItem,
useToggleView,
useToolMode,
useTransformMode,
} from "../../store/store";
import useToggleStore from "../../store/useUIToggleStore";
const Tools: React.FC = () => {
const { templates } = useTemplateStore();
const [activeTool, setActiveTool] = useState("cursor");
const [activeSubTool, setActiveSubTool] = useState("cursor");
const [toggleThreeD, setToggleThreeD] = useState(true);
const { toggleUI, setToggleUI } = useToggleStore();
const dropdownRef = useRef<HTMLDivElement>(null);
const [openDrop, setOpenDrop] = useState(false);
@ -39,12 +48,23 @@ const Tools: React.FC = () => {
const { selectedZone } = useSelectedZoneStore();
// wall options
const { setToggleView } = useToggleView();
const { toggleView, setToggleView } = useToggleView();
const { setDeleteModels } = useDeleteModels();
const { setAddAction } = useAddAction();
const { setSelectedWallItem } = useSelectedWallItem();
const { transformMode, setTransformMode } = useTransformMode();
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
const { movePoint, setMovePoint } = useMovePoint();
const { toolMode, setToolMode } = useToolMode();
const { activeTool, setActiveTool } = useActiveTool();
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
// Reset activeTool whenever activeModule changes
useEffect(() => {
setToggleUI(localStorage.getItem('navBarUi') ? localStorage.getItem('navBarUi') === 'true' : true)
}, []);
useEffect(() => {
setActiveTool(activeSubTool);
setActiveSubTool(activeSubTool);
@ -56,10 +76,14 @@ const Tools: React.FC = () => {
setDeleteModels(false);
setAddAction(null);
setToggleView(true);
// localStorage.setItem("navBarUi", JSON.stringify(!toggleThreeD));
} else {
setToggleView(false);
}
setToggleUI(localStorage.getItem('navBarUi') ? localStorage.getItem('navBarUi') === 'true' : true)
setToggleThreeD(!toggleThreeD);
setActiveSubTool("cursor");
setActiveTool("cursor");
};
useEffect(() => {
@ -84,6 +108,90 @@ const Tools: React.FC = () => {
document.removeEventListener("keydown", handleEscKeyPress); // Clean up the event listener
};
}, []);
useEffect(() => {
if (!toggleThreeD) {
setToggleUI(false);
}
}, [toggleThreeD]);
useEffect(() => {
setToolMode(null);
setDeleteModels(false);
setAddAction(null);
setTransformMode(null);
setMovePoint(false);
setDeletePointOrLine(false);
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
switch (activeTool) {
case "Move":
if (toggleView) {
setMovePoint(true);
} else {
setTransformMode("translate");
}
break;
case "Rotate":
if (!toggleView) {
setTransformMode("rotate");
}
break;
case "Scale":
if (!toggleView) {
setTransformMode("scale");
}
break;
case "draw-wall":
if (toggleView) {
setToolMode("Wall");
}
break;
case "draw-aisle":
if (toggleView) {
setToolMode("Aisle");
}
break;
case "draw-zone":
if (toggleView) {
setToolMode("Zone");
}
break;
case "draw-floor":
if (toggleView) {
setToolMode("Floor");
}
break;
case "measure":
setToolMode("MeasurementScale");
break;
case "Add pillar":
if (!toggleView) {
setAddAction("pillar");
}
break;
case "delete":
if (toggleView) {
setDeletePointOrLine(true);
} else {
setDeleteModels(true);
}
break;
default:
break;
}
setActiveTool(activeTool);
}, [activeTool]);
return (
<>
@ -94,9 +202,8 @@ const Tools: React.FC = () => {
<div className="activeDropicon">
{activeSubTool == "cursor" && (
<div
className={`tool-button ${
activeTool === "cursor" ? "active" : ""
}`}
className={`tool-button ${activeTool === "cursor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("cursor");
}}
@ -106,9 +213,8 @@ const Tools: React.FC = () => {
)}
{activeSubTool == "free-hand" && (
<div
className={`tool-button ${
activeTool === "free-hand" ? "active" : ""
}`}
className={`tool-button ${activeTool === "free-hand" ? "active" : ""
}`}
onClick={() => {
setActiveTool("free-hand");
}}
@ -116,13 +222,23 @@ const Tools: React.FC = () => {
<FreeMoveIcon isActive={activeTool === "free-hand"} />
</div>
)}
{activeSubTool == "delete" && (
<div
className={`tool-button ${activeTool === "delete" ? "active" : ""
}`}
onClick={() => {
setActiveTool("delete");
}}
>
<DeleteIcon isActive={activeTool === "delete"} />
</div>
)}
{activeModule !== "visualization" && (
<div
className="drop-down-option-button"
ref={dropdownRef}
onClick={() => {
setOpenDrop(!openDrop);
console.log(openDrop);
}}
>
<ArrowIcon />
@ -156,6 +272,20 @@ const Tools: React.FC = () => {
<FreeMoveIcon isActive={false} />
<div className="option">Free Hand</div>
</div>
<div
className="option-list"
onClick={() => {
setOpenDrop(false);
setActiveTool("delete");
setActiveSubTool("delete");
}}
>
<div className="active-option">
{activeSubTool === "delete" && <TickIcon />}
</div>
<DeleteIcon isActive={false} />
<div className="option">Delete</div>
</div>
</div>
)}
</div>
@ -167,56 +297,72 @@ const Tools: React.FC = () => {
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "draw-wall" ? "active" : ""
}`}
className={`tool-button ${activeTool === "draw-wall" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-wall");
}}
title="Wall"
>
<WallIcon isActive={activeTool === "draw-wall"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-zone" ? "active" : ""
}`}
className={`tool-button ${activeTool === "draw-zone" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-zone");
}}
title="Zone"
>
<ZoneIcon isActive={activeTool === "draw-zone"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-aisle" ? "active" : ""
}`}
className={`tool-button ${activeTool === "draw-aisle" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-aisle");
}}
title="Aisle"
>
<AsileIcon isActive={activeTool === "draw-aisle"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-floor" ? "active" : ""
}`}
className={`tool-button ${activeTool === "draw-floor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-floor");
}}
title="Floor"
>
<FloorIcon isActive={activeTool === "draw-floor"} />
</div>
</div>
</>
)}
{activeModule === "builder" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${activeTool === "measure" ? "active" : ""
}`}
onClick={() => {
setActiveTool("measure");
}}
title="Measure"
>
<MeasureToolIcon isActive={activeTool === "measure"} />
</div>
</div>
</>
)}
{activeModule === "simulation" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "pen" ? "active" : ""
}`}
className={`tool-button ${activeTool === "pen" ? "active" : ""
}`}
onClick={() => {
setActiveTool("pen");
}}
@ -248,31 +394,30 @@ const Tools: React.FC = () => {
<div className="split"></div>
<div className="general-options">
<div
className={`tool-button ${
activeTool === "comment" ? "active" : ""
}`}
className={`tool-button ${activeTool === "comment" ? "active" : ""
}`}
onClick={() => {
setActiveTool("comment");
}}
>
<CommentIcon isActive={activeTool === "comment"} />
</div>
<div
className={`tool-button ${
activeTool === "play" ? "active" : ""
}`}
onClick={() => {
setIsPlaying(!isPlaying);
}}
>
<PlayIcon isActive={activeTool === "play"} />
</div>
{toggleThreeD && (
<div
className={`tool-button ${activeTool === "play" ? "active" : ""
}`}
onClick={() => {
setIsPlaying(!isPlaying);
}}
>
<PlayIcon isActive={activeTool === "play"} />
</div>
)}
</div>
<div className="split"></div>
<div
className={`toggle-threed-button${
toggleThreeD ? " toggled" : ""
}`}
className={`toggle-threed-button${toggleThreeD ? " toggled" : ""
}`}
onClick={toggleSwitch}
>
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>

View File

@ -76,7 +76,7 @@ const RealTimeVisulization: React.FC = () => {
}
GetZoneData();
}, []); // Removed `zones` from dependencies
}, [activeModule]); // Removed `zones` from dependencies
useEffect(() => {
@ -97,7 +97,7 @@ const RealTimeVisulization: React.FC = () => {
};
});
}, [selectedZone]);
useEffect(() => {
}, [floatingWidgets])
@ -162,7 +162,6 @@ const RealTimeVisulization: React.FC = () => {
onDrop={(event) => handleDrop(event)}
onDragOver={(event) => event.preventDefault()}
>
<Scene />
</div>
<DroppedObjects />

View File

@ -1,18 +1,36 @@
import React from "react";
import RegularDropDown from "./RegularDropDown";
import { EyeDroperIcon } from "../../icons/ExportCommonIcons";
import RegularDropDown from "./RegularDropDown";
interface EyeDropInputProps {
label: string;
value: string;
onChange: (value: string) => void;
options?: string[];
}
const EyeDropInput: React.FC<EyeDropInputProps> = ({
label = "Object",
onChange,
}) => {
const handleEyeDropClick = () => {
// Here you would typically implement the eye dropper functionality
// For now, we'll just simulate selecting a value
const simulatedValue = "picked_value"; // Replace with actual eye dropper logic
onChange(simulatedValue);
};
const EyeDropInput: React.FC = () => {
return (
<div className="eye-dropper-input-container">
<div className="label">Object</div>
<div className="label">{label}</div>
<div className="input-container">
{/* <input disabled type="text" /> */}
<RegularDropDown
header="select object"
options={[]}
onSelect={() => {}}
onSelect={() => { }}
/>
<div className="eye-picker-button">
<div className="eye-picker-button" onClick={handleEyeDropClick}>
<EyeDroperIcon isActive={false} />
</div>
</div>
@ -20,4 +38,4 @@ const EyeDropInput: React.FC = () => {
);
};
export default EyeDropInput;
export default EyeDropInput;

View File

@ -1,24 +1,17 @@
import PolygonGenerator from "./polygonGenerator";
import { useThree } from "@react-three/fiber";
import { useEffect, useRef, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import * as THREE from "three";
import * as Types from "../../../types/world/worldTypes";
import PathNavigator from "./pathNavigator";
import NavMeshDetails from "./navMeshDetails";
const Agv = ({
lines,
plane,
}: {
lines: Types.RefLines;
plane: Types.RefMesh;
}) => {
let pathPoints = [
const Agv = ({ lines, plane }: { lines: Types.RefLines; plane: Types.RefMesh; }) => {
const pathPoints = useMemo(() => [
[
{ x: 8.477161935339709, y: 0, z: 17.41343083550102 },
{ x: 9.175416491482693, y: 0, z: -12.361001232663693 },
],
,
// [
// { x: 13.508213355232144, y: 0, z: -15.456970649652018 },
// { x: -30.464866520869617, y: 0, z: 9.779806557688929 },
@ -27,7 +20,8 @@ const Agv = ({
{ x: 16.792040856420844, y: 0, z: 15.86281907549489 },
{ x: -42.77173264503395, y: 0, z: -15.821322764400804 },
],
];
], []);
let groupRef = useRef() as Types.RefGroup;
const [navMesh, setNavMesh] = useState();

View File

@ -17,7 +17,7 @@ async function Draw(
floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean,
setRefTextUpdate: Types.NumberIncrementState,
setRefTextUpdate: any,
Tube: Types.RefTubeGeometry,
anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean,

View File

@ -17,7 +17,7 @@ function addRoofToScene(
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.roofConfig.defaultColor, side: THREE.DoubleSide, transparent: true, depthWrite: false });
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.roofConfig.defaultColor, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = CONSTANTS.wallConfig.height + floor;
mesh.castShadow = true;

View File

@ -193,7 +193,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
}
const Mode = transformMode;
if (Mode !== null || activeTool === "Cursor") {
if (Mode !== null || activeTool === "cursor") {
if (!itemsGroup.current) return;
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
@ -225,7 +225,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
const Mode = transformMode;
if (Mode !== null || activeTool === "Cursor") {
if (Mode !== null || activeTool === "cursor") {
if (!itemsGroup.current) return;
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {

View File

@ -20,12 +20,7 @@ const CamModelsGroup = () => {
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
const [cams, setCams] = useState<any[]>([]);
const [models, setModels] = useState<
Record<
string,
{ targetPosition: THREE.Vector3; targetRotation: THREE.Euler }
>
>({});
const [models, setModels] = useState<Record<string, { targetPosition: THREE.Vector3; targetRotation: THREE.Euler }>>({});
dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
loader.setDRACOLoader(dracoLoader);
@ -163,7 +158,6 @@ const CamModelsGroup = () => {
cam.rotation.z
);
newModel.userData = cam.userData;
console.log('cam.userData: ', cam.userData);
setActiveUsers([...activeUsers, cam.userData]);
return newModel;
});

View File

@ -13,6 +13,7 @@ interface SelectedCard {
price: number;
rating: number;
views: number;
description: string;
}
// Define the props type for AssetPreview
@ -93,19 +94,7 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
<div className="asset-details">
<div className="asset-name">{selectedCard.assetName}</div>
<div className="asset-description">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Doloremque nisi beatae facilis architecto quaerat delectus velit
aliquid assumenda cumque vitae! Tempore quibusdam ab natus in
minima voluptates, aliquid corrupti excepturi consectetur
distinctio sequi beatae odit autem? Distinctio ab, voluptatem
omnis quibusdam, incidunt eum ipsa aliquid enim eaque eveniet nisi
autem, accusantium vel! Laborum in iste voluptates ad! Harum eum
amet pariatur fugit laudantium dolorem maxime voluptates atque
molestiae modi inventore quidem maiores dolore numquam, natus
quisquam optio distinctio eveniet aliquam, aut eligendi laboriosam
eaque! Porro cumque cum distinctio ullam debitis, dolorum
similique! Harum cupiditate perferendis voluptatum molestiae,
fugiat quisquam assumenda!
{`${selectedCard.assetName} is used in factories to improve efficiency and production speed It is designed to handle heavy workloads and perform repetitive tasks with precision. Many industries rely on this machine to manufacture products quickly and accurately. It reduces human effort and minimizes errors in the production process. Regular maintenance is required to keep the machine in good working condition.With advanced technology, this machine continues to enhance industrial operations and increase productivity.`}
</div>
<div className="asset-review">
<div className="asset-rating">

View File

@ -17,12 +17,14 @@ interface CardProps {
rating: number;
views: number;
image: string;
description: string;
onSelectCard: (cardData: {
assetName: string;
uploadedOn: number;
price: number;
rating: number;
views: number;
description: string;
}) => void;
}
@ -33,10 +35,11 @@ const Card: React.FC<CardProps> = ({
rating,
views,
image,
description,
onSelectCard,
}) => {
const handleCardSelect = () => {
onSelectCard({ assetName, uploadedOn, price, rating, views });
onSelectCard({ assetName, uploadedOn, price, rating, views, description });
};
return (

View File

@ -1,8 +1,7 @@
import React, { useEffect, useState } from "react";
import Card from "./Card";
import AssetPreview from "./AssetPreview";
import RenderOverlay from "../../components/templates/Overlay";
import { fetchAssets } from "../../services/marketplace/fetchAssets";
interface ModelData {
CreatedBy: string;
animated: string | null;
@ -27,6 +26,7 @@ const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
price: number;
rating: number;
views: number;
description: string;
} | null>(null);
const handleCardSelect = (cardData: {
@ -35,6 +35,7 @@ const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
price: number;
rating: number;
views: number;
description: string;
}) => {
setSelectedCard(cardData);
};
@ -54,6 +55,7 @@ const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
views={800}
onSelectCard={handleCardSelect}
image={assetDetail.thumbnail}
description={assetDetail.description}
/>
))}
{/* <RenderOverlay> */}

View File

@ -36,7 +36,7 @@ const MeasurementTool = () => {
isLeftMouseDown = false;
if (evt.button === 0 && !drag) {
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !(intersect.object.type === "GridHelper"));
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && !(intersect.object.type === "GridHelper"));
if (intersects.length > 0) {
const intersectionPoint = intersects[0].point.clone();
@ -83,7 +83,7 @@ const MeasurementTool = () => {
useFrame(() => {
if (points.length === 1) {
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !(intersect.object.type === "GridHelper"));
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && !(intersect.object.type === "GridHelper"));
if (intersects.length > 0) {
updateMeasurement(points[0], intersects[0].point);

View File

@ -29,6 +29,7 @@ import {
useUpdateScene,
useWalls,
useToolMode,
useRefTextUpdate,
} from "../../../store/store";
////////// 3D Function Imports //////////
@ -118,7 +119,7 @@ export default function World() {
const { shadows, setShadows } = useShadows();
const { updateScene, setUpdateScene } = useUpdateScene();
const { walls, setWalls } = useWalls();
const [RefTextupdate, setRefTextUpdate] = useState(-1000);
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
// const loader = new GLTFLoader();
// const dracoLoader = new DRACOLoader();
@ -158,7 +159,7 @@ export default function World() {
////////// All Toggle's //////////
useEffect(() => {
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
if (dragPointControls.current) {
dragPointControls.current.enabled = false;
}
@ -241,7 +242,7 @@ export default function World() {
<DistanceText key={toggleView} />
<ReferenceDistanceText
key={RefTextupdate}
key={refTextupdate}
line={ReferenceLineMesh.current}
/>

View File

@ -52,7 +52,7 @@ function Behaviour() {
],
assetPosition: [...item.position],
assetRotation: [item.rotation.x, item.rotation.y, item.rotation.z],
speed: 1,
speed: 'Inherit',
};
newPaths.push(newPath);
@ -67,12 +67,11 @@ function Behaviour() {
point: {
uuid: pointUUID,
position: [pointPosition.x, pointPosition.y, pointPosition.z],
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: THREE.MathUtils.generateUUID(), hitCount: 1, end: THREE.MathUtils.generateUUID(), buffer: 0, isUsed: false }],
triggers: [],
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: '', hitCount: 1, end: '', buffer: 0 },
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
speed: 2,
},
assetPosition: [...item.position],
speed: 2,
};
newPaths.push(newVehiclePath);

View File

@ -86,6 +86,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
};
}
}
// In the updatePathConnections function, modify the Vehicle handling section:
else if (path.type === 'Vehicle') {
// Handle outgoing connections from Vehicle
if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) {
@ -95,6 +96,27 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
};
const existingTargets = path.point.connections.targets || [];
// Check if we're trying to add a connection to a Conveyor
const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID);
const isConnectingToConveyor = toPath?.type === 'Conveyor';
// Count existing connections
if (existingTargets.length >= 2) {
console.log("Vehicle can have maximum 2 connections");
return path;
}
// Check if we already have a Conveyor connection and trying to add another
const hasConveyorConnection = existingTargets.some(target => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
return targetPath?.type === 'Conveyor';
});
if (hasConveyorConnection && isConnectingToConveyor) {
console.log("Vehicle can only have one connection to a Conveyor");
return path;
}
if (!existingTargets.some(target =>
target.pathUUID === newTarget.pathUUID &&
target.pointUUID === newTarget.pointUUID
@ -119,6 +141,27 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
};
const existingTargets = path.point.connections.targets || [];
// Check if we're receiving a connection from a Conveyor
const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID);
const isConnectingFromConveyor = fromPath?.type === 'Conveyor';
// Count existing connections
if (existingTargets.length >= 2) {
console.log("Vehicle can have maximum 2 connections");
return path;
}
// Check if we already have a Conveyor connection and trying to add another
const hasConveyorConnection = existingTargets.some(target => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
return targetPath?.type === 'Conveyor';
});
if (hasConveyorConnection && isConnectingFromConveyor) {
console.log("Vehicle can only have one connection to a Conveyor");
return path;
}
if (!existingTargets.some(target =>
target.pathUUID === reverseTarget.pathUUID &&
target.pointUUID === reverseTarget.pointUUID
@ -135,6 +178,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
};
}
}
return path;
}
return path;
});
@ -168,7 +212,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
drag = true;
}
};
const onContextMenu = (evt: MouseEvent) => {
evt.preventDefault();
if (drag || evt.button === 0) return;
@ -200,29 +243,126 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID);
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
// Prevent vehicle-to-vehicle connections
if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
console.log("Cannot connect two vehicle paths together");
return;
}
const isAlreadyConnected = simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
} else if (path.type === 'Vehicle') {
return path.point.uuid === sphereUUID &&
path.point.connections.targets.length > 0;
}
return false;
});
if (isAlreadyConnected) {
console.log("Sphere is already connected. Ignoring.");
// Prevent conveyor middle point to conveyor connections
if (firstPath && secondPath &&
firstPath.type === 'Conveyor' &&
secondPath.type === 'Conveyor' &&
!firstSelected?.isCorner) {
console.log("Conveyor middle points can only connect to non-conveyor paths");
return;
}
if (!firstSelected) {
// Check if this specific connection already exists
const isDuplicateConnection = firstSelected
? simulationPaths.some(path => {
if (path.modeluuid === firstSelected.pathUUID) {
if (path.type === 'Conveyor') {
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
return point?.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
);
} else if (path.type === 'Vehicle') {
return path.point.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
);
}
}
return false;
})
: false;
if (isDuplicateConnection) {
console.log("These points are already connected. Ignoring.");
return;
}
// For Vehicles, skip the "already connected" check since they can have multiple connections
if (intersected.userData.path.type !== 'Vehicle') {
const isAlreadyConnected = simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
}
return false;
});
if (isAlreadyConnected) {
console.log("Conveyor point is already connected. Ignoring.");
return;
}
}
// Check vehicle connection limits
const checkVehicleConnections = (pathUUID: string) => {
const path = simulationPaths.find(p => p.modeluuid === pathUUID);
if (path?.type === 'Vehicle') {
return path.point.connections.targets.length >= 2;
}
return false;
};
if (firstSelected) {
// Check if either selected point is from a Vehicle with max connections
if (checkVehicleConnections(firstSelected.pathUUID) ||
checkVehicleConnections(pathUUID)) {
console.log("Vehicle already has maximum connections");
return;
}
// Check if we're trying to add a second Conveyor connection to a Vehicle
if (firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor') {
const hasConveyorConnection = firstPath.point.connections.targets.some(target => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
return targetPath?.type === 'Conveyor';
});
if (hasConveyorConnection) {
console.log("Vehicle can only have one connection to a Conveyor");
return;
}
}
if (secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor') {
const hasConveyorConnection = secondPath.point.connections.targets.some(target => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
return targetPath?.type === 'Conveyor';
});
if (hasConveyorConnection) {
console.log("Vehicle can only have one connection to a Conveyor");
return;
}
}
// Prevent same-path connections
if (firstSelected.pathUUID === pathUUID) {
console.log("Cannot connect spheres on the same path.");
return;
}
// At least one must be start/end point
if (!firstSelected.isCorner && !isStartOrEnd) {
console.log("At least one of the selected spheres must be a start or end point.");
return;
}
// All checks passed - make the connection
handleAddConnection(
firstSelected.pathUUID,
firstSelected.sphereUUID,
pathUUID,
sphereUUID
);
} else {
// First selection - just store it
setFirstSelected({
pathUUID,
sphereUUID,
@ -230,28 +370,11 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
isCorner: isStartOrEnd
});
setIsConnecting(true);
} else {
if (firstSelected.sphereUUID === sphereUUID) return;
if (firstSelected.pathUUID === pathUUID) {
console.log("Cannot connect spheres on the same path.");
return;
}
if (!firstSelected.isCorner && !isStartOrEnd) {
console.log("At least one of the selected spheres must be a start or end point.");
return;
}
handleAddConnection(
firstSelected.pathUUID,
firstSelected.sphereUUID,
pathUUID,
sphereUUID
);
}
}
}
} else {
// Clicked outside - cancel connection
setFirstSelected(null);
setCurrentLine(null);
setIsConnecting(false);
@ -294,7 +417,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
if (intersects.length > 0) {
point = intersects[0].point;
if (point.y < 0.05) {
point = new THREE.Vector3(point.x, 0.05, point.z);
}
@ -316,28 +438,68 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';
// Inside the useFrame hook, where we check for snapped spheres:
const isConnectable = (pathData.type === 'Vehicle' ||
(pathData.points.length > 0 && (
sphereUUID === pathData.points[0].uuid ||
sphereUUID === pathData.points[pathData.points.length - 1].uuid
))) && !isVehicleToVehicle;
))) &&
!isVehicleToVehicle &&
!(firstPath?.type === 'Conveyor' &&
pathData.type === 'Conveyor' &&
!firstSelected.isCorner);
const isAlreadyConnected = simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
} else if (path.type === 'Vehicle') {
return path.point.uuid === sphereUUID &&
path.point.connections.targets.length > 0;
// Check for duplicate connection (regardless of path type)
const isDuplicateConnection = simulationPaths.some(path => {
if (path.modeluuid === firstSelected.pathUUID) {
if (path.type === 'Conveyor') {
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
return point?.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
);
} else if (path.type === 'Vehicle') {
return path.point.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
);
}
}
return false;
});
// For non-Vehicle paths, check if already connected
const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' &&
simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
}
return false;
});
// Check vehicle connection limits
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
pathData.point.connections.targets.length >= 2;
const isVehicleConveyorConflict =
(firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor' &&
firstPath.point.connections.targets.some(t => {
const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID);
return targetPath?.type === 'Conveyor';
})) ||
(secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor' &&
secondPath.point.connections.targets.some(t => {
const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID);
return targetPath?.type === 'Conveyor';
}));
if (
!isAlreadyConnected &&
!isDuplicateConnection &&
!isVehicleToVehicle &&
!isNonVehicleAlreadyConnected &&
!isVehicleAtMaxConnections &&
!isVehicleConveyorConflict &&
firstSelected.sphereUUID !== sphereUUID &&
firstSelected.pathUUID !== pathUUID &&
(firstSelected.isCorner || isConnectable)
@ -371,13 +533,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
end: point,
mid: midPoint,
});
console.log({
start: firstSelected.position,
end: point,
mid: midPoint,
});
// setIsConnecting(true);
if (sphereIntersects.length > 0) {
setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542');

View File

@ -1,27 +1,10 @@
import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes';
import { useRef, useState, useEffect } from 'react';
import { Sphere, TransformControls } from '@react-three/drei';
import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
import { useFrame, useThree } from '@react-three/fiber';
import { useSubModuleStore } from '../../../store/useModuleStore';
import { point } from '@turf/helpers';
interface ConveyorEventsSchema {
modeluuid: string;
modelName: string;
type: 'Conveyor';
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[];
assetPosition: [number, number, number];
assetRotation: [number, number, number];
speed: number;
}
function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
const { renderDistance } = useRenderDistance();
@ -89,7 +72,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
};
}
return path;
}) as ConveyorEventsSchema[];
}) as Types.ConveyorEventsSchema[];
setSimulationPaths(updatedPaths);
};

View File

@ -14,7 +14,7 @@ function Simulation() {
const [processes, setProcesses] = useState([]);
useEffect(() => {
console.log('simulationPaths: ', simulationPaths);
}, [simulationPaths]);
// useEffect(() => {

View File

@ -93,6 +93,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
intersects = intersects.filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")
@ -146,6 +147,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
const intersects = raycaster.intersectObjects(scene.children, true).filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")
@ -262,6 +264,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
const intersects = raycaster.intersectObjects(scene.children, true).filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")

View File

@ -6,37 +6,37 @@ const MqttEvents = () => {
const { setTouch, setTemperature, setHumidity } = useDrieUIValue();
useEffect(() => {
const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`);
// const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`);
client.subscribe("touch");
client.subscribe("temperature");
client.subscribe("humidity");
// client.subscribe("touch");
// client.subscribe("temperature");
// client.subscribe("humidity");
const handleMessage = (topic: string, message: any) => {
const value = message.toString();
// const handleMessage = (topic: string, message: any) => {
// const value = message.toString();
if (topic === "touch") {
setTouch(value);
} else if (topic === "temperature") {
setTemperature(parseFloat(value));
} else if (topic === "humidity") {
setHumidity(parseFloat(value));
}
};
// if (topic === "touch") {
// setTouch(value);
// } else if (topic === "temperature") {
// setTemperature(parseFloat(value));
// } else if (topic === "humidity") {
// setHumidity(parseFloat(value));
// }
// };
client.on("message", handleMessage);
// client.on("message", handleMessage);
client.on("error", (err) => {
console.error("MQTT Connection Error:", err);
});
// client.on("error", (err) => {
// console.error("MQTT Connection Error:", err);
// });
client.on("close", () => {
console.log("MQTT Connection Closed");
});
// client.on("close", () => {
// console.log("MQTT Connection Closed");
// });
return () => {
client.end();
};
// return () => {
// client.end();
// };
}, [setTouch, setTemperature, setHumidity]);
return null;

View File

@ -15,6 +15,7 @@ export const deleteZonesApi = async (userId: string, organization: string, zoneI
}
const result = await response.json();
console.log('result: ', result);
return result;
} catch (error) {
if (error instanceof Error) {

View File

@ -203,6 +203,20 @@ export const useActiveLayer = create<any>((set: any) => ({
setActiveLayer: (x: any) => set({ activeLayer: x }),
}));
interface RefTextUpdateState {
refTextupdate: number;
setRefTextUpdate: (callback: (currentValue: number) => number | number) => void;
}
export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({
refTextupdate: -1000,
setRefTextUpdate: (callback) =>
set((state) => ({
refTextupdate:
typeof callback === "function" ? callback(state.refTextupdate) : callback,
})),
}));
export const useResetCamera = create<any>((set: any) => ({
resetCamera: false,
setResetCamera: (x: any) => set({ resetCamera: x }),
@ -214,7 +228,7 @@ export const useAddAction = create<any>((set: any) => ({
}));
export const useActiveTool = create<any>((set: any) => ({
activeTool: "Cursor",
activeTool: "cursor",
setActiveTool: (x: any) => set({ activeTool: x }),
}));

View File

@ -295,12 +295,12 @@ interface ConveyorEventsSchema {
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[];
assetPosition: [number, number, number];
assetRotation: [number, number, number];
speed: number;
speed: number | string;
}
interface VehicleEventsSchema {
@ -310,10 +310,9 @@ interface VehicleEventsSchema {
point: {
uuid: string;
position: [number, number, number];
actions: { uuid: string; name: string; type: string; start: string, hitCount: number, end: string, buffer: number; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
actions: { uuid: string; name: string; type: string; start: string, hitCount: number, end: string, buffer: number };
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
speed: number;
};
assetPosition: [number, number, number];
speed: number;
}