Merge remote-tracking branch 'origin/main' into rtViz
This commit is contained in:
commit
71310bdbdd
3
app/.env
3
app/.env
|
@ -9,3 +9,6 @@ REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000
|
||||||
|
|
||||||
# Base URL for the server marketplace API.
|
# Base URL for the server marketplace API.
|
||||||
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011
|
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011
|
||||||
|
|
||||||
|
# Base URL for the server mqtt.
|
||||||
|
REACT_APP_SERVER_MQTT_URL=185.100.212.76:23457
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,10 +9,12 @@
|
||||||
"@react-three/drei": "^9.113.0",
|
"@react-three/drei": "^9.113.0",
|
||||||
"@react-three/fiber": "^8.17.7",
|
"@react-three/fiber": "^8.17.7",
|
||||||
"@react-three/postprocessing": "^2.16.3",
|
"@react-three/postprocessing": "^2.16.3",
|
||||||
|
"@recast-navigation/three": "^0.39.0",
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/jest-dom": "^5.17.0",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"@turf/turf": "^7.1.0",
|
"@turf/helpers": "^7.2.0",
|
||||||
|
"@turf/turf": "^7.2.0",
|
||||||
"@types/jest": "^27.5.2",
|
"@types/jest": "^27.5.2",
|
||||||
"@types/react": "^18.3.5",
|
"@types/react": "^18.3.5",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
SimulationIcon,
|
SimulationIcon,
|
||||||
} from "../../icons/SimulationIcons";
|
} from "../../icons/SimulationIcons";
|
||||||
import useToggleStore from "../../../store/useUIToggleStore";
|
import useToggleStore from "../../../store/useUIToggleStore";
|
||||||
import MachineMechanics from "./mechanics/MachineMechanics";
|
import ConveyorMechanics from "./mechanics/ConveyorMechanics";
|
||||||
import Visualization from "./visualization/Visualization";
|
import Visualization from "./visualization/Visualization";
|
||||||
import Analysis from "./analysis/Analysis";
|
import Analysis from "./analysis/Analysis";
|
||||||
import Simulations from "./simulation/Simulations";
|
import Simulations from "./simulation/Simulations";
|
||||||
|
@ -18,6 +18,7 @@ import { useSelectedActionSphere } from "../../../store/store";
|
||||||
import GlobalProperties from "./properties/GlobalProperties";
|
import GlobalProperties from "./properties/GlobalProperties";
|
||||||
import AsstePropertiies from "./properties/AssetProperties";
|
import AsstePropertiies from "./properties/AssetProperties";
|
||||||
import ZoneProperties from "./properties/ZoneProperties";
|
import ZoneProperties from "./properties/ZoneProperties";
|
||||||
|
import VehicleMechanics from "./mechanics/VehicleMechanics";
|
||||||
|
|
||||||
const SideBarRight: React.FC = () => {
|
const SideBarRight: React.FC = () => {
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
|
@ -98,17 +99,24 @@ const SideBarRight: React.FC = () => {
|
||||||
|
|
||||||
{toggleUI && activeModule === "simulation" && (
|
{toggleUI && activeModule === "simulation" && (
|
||||||
<>
|
<>
|
||||||
{subModule === "mechanics" && selectedActionSphere && (
|
{subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Conveyor" && (
|
||||||
<div className="sidebar-right-container">
|
<div className="sidebar-right-container">
|
||||||
<div className="sidebar-right-content-container">
|
<div className="sidebar-right-content-container">
|
||||||
<MachineMechanics />
|
<ConveyorMechanics />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Vehicle" && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
{/* <VehicleMechanics /> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{subModule === "mechanics" && !selectedActionSphere && (
|
{subModule === "mechanics" && !selectedActionSphere && (
|
||||||
<div className="sidebar-right-container">
|
<div className="sidebar-right-container">
|
||||||
<div className="sidebar-right-content-container">
|
<div className="sidebar-right-content-container">
|
||||||
{/* <MachineMechanics /> */}
|
<ConveyorMechanics />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -0,0 +1,586 @@
|
||||||
|
import React, { useRef, useState, useMemo, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
AddIcon,
|
||||||
|
InfoIcon,
|
||||||
|
RemoveIcon,
|
||||||
|
ResizeHeightIcon,
|
||||||
|
} from "../../../icons/ExportCommonIcons";
|
||||||
|
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';
|
||||||
|
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
|
|
||||||
|
const ConveyorMechanics: React.FC = () => {
|
||||||
|
const { selectedActionSphere } = useSelectedActionSphere();
|
||||||
|
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||||
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
|
|
||||||
|
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const triggersContainerRef = 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);
|
||||||
|
}, [selectedActionSphere, simulationPaths]);
|
||||||
|
|
||||||
|
const handleAddAction = () => {
|
||||||
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
|
const updatedPaths = simulationPaths.map((path) => {
|
||||||
|
if (path.type === "Conveyor") {
|
||||||
|
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] };
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
});
|
||||||
|
|
||||||
|
setSimulationPaths(updatedPaths);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteAction = (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.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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
);
|
||||||
|
|
||||||
|
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]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="machine-mechanics-container">
|
||||||
|
<div className="machine-mechanics-header">
|
||||||
|
{selectedActionSphere?.path?.modelName || "point name not found"}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="machine-mechanics-content-container">
|
||||||
|
{!selectedPath &&
|
||||||
|
<>
|
||||||
|
<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">
|
||||||
|
{selectedPoint?.actions.map((action) => (
|
||||||
|
<div
|
||||||
|
key={action.uuid}
|
||||||
|
className={`list-item ${selectedItem?.type === "action" &&
|
||||||
|
selectedItem.item?.uuid === action.uuid
|
||||||
|
? "active"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="value"
|
||||||
|
onClick={() => setSelectedItem({ type: "action", item: action })}
|
||||||
|
>
|
||||||
|
<RenameInput value={action.name} />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="remove-button"
|
||||||
|
onClick={() => handleDeleteAction(action.uuid)}
|
||||||
|
>
|
||||||
|
<RemoveIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</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="properties-header">{selectedItem.item.name}</div>
|
||||||
|
|
||||||
|
{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)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 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="Conveyor Speed"
|
||||||
|
value={selectedPath.path.speed.toString()}
|
||||||
|
onChange={(value) => handleSpeedChange(parseFloat(value))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="footer">
|
||||||
|
<InfoIcon />
|
||||||
|
By selecting points, you can create events and triggers.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConveyorMechanics;
|
|
@ -1,533 +0,0 @@
|
||||||
import React, { useRef, useState, useMemo, useEffect } from "react";
|
|
||||||
import {
|
|
||||||
AddIcon,
|
|
||||||
InfoIcon,
|
|
||||||
RemoveIcon,
|
|
||||||
ResizeHeightIcon,
|
|
||||||
} from "../../../icons/ExportCommonIcons";
|
|
||||||
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 InputToggle from "../../../ui/inputs/InputToggle";
|
|
||||||
|
|
||||||
const MachineMechanics: React.FC = () => {
|
|
||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
|
||||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
|
||||||
|
|
||||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
|
||||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const selectedPoint = useMemo(() => {
|
|
||||||
if (!selectedActionSphere) return null;
|
|
||||||
return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
|
||||||
}, [selectedActionSphere, simulationPaths]);
|
|
||||||
|
|
||||||
const handleAddAction = () => {
|
|
||||||
if (!selectedActionSphere) return;
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
|
||||||
...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] };
|
|
||||||
}
|
|
||||||
return point;
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteAction = (uuid: string) => {
|
|
||||||
if (!selectedActionSphere) return;
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
|
||||||
...path,
|
|
||||||
points: path.points.map((point) =>
|
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
|
||||||
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
|
||||||
: point
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleActionSelect = (uuid: string, actionType: string) => {
|
|
||||||
if (!selectedActionSphere) return;
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
|
||||||
...path,
|
|
||||||
points: path.points.map((point) =>
|
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
|
||||||
? {
|
|
||||||
...point,
|
|
||||||
actions: point.actions.map((action) =>
|
|
||||||
action.uuid === uuid
|
|
||||||
? {
|
|
||||||
...action,
|
|
||||||
type: actionType,
|
|
||||||
// Reset dependent fields when type changes
|
|
||||||
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material,
|
|
||||||
delay: actionType === 'Delay' ? 'Inherit' : action.delay,
|
|
||||||
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval
|
|
||||||
}
|
|
||||||
: action
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: point
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
|
||||||
|
|
||||||
// Update the selected item to reflect changes
|
|
||||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
|
||||||
const updatedAction = updatedPaths
|
|
||||||
.flatMap(path => path.points)
|
|
||||||
.find(p => p.uuid === selectedActionSphere.point.uuid)
|
|
||||||
?.actions.find(a => a.uuid === uuid);
|
|
||||||
|
|
||||||
if (updatedAction) {
|
|
||||||
setSelectedItem({
|
|
||||||
type: "action",
|
|
||||||
item: updatedAction
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
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
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
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,
|
|
||||||
points: path.points.map((point) =>
|
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
|
||||||
? {
|
|
||||||
...point,
|
|
||||||
actions: point.actions.map((action) =>
|
|
||||||
action.uuid === uuid ? { ...action, delay } : action
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: point
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
|
|
||||||
if (!selectedActionSphere) return;
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
|
||||||
...path,
|
|
||||||
points: path.points.map((point) =>
|
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
|
||||||
? {
|
|
||||||
...point,
|
|
||||||
actions: point.actions.map((action) =>
|
|
||||||
action.uuid === uuid ? { ...action, spawnInterval } : action
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: point
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
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,
|
|
||||||
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;
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteTrigger = (uuid: string) => {
|
|
||||||
if (!selectedActionSphere) return;
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
|
||||||
...path,
|
|
||||||
points: path.points.map((point) =>
|
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
|
||||||
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
|
||||||
: point
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTriggerSelect = (uuid: string, triggerType: string) => {
|
|
||||||
if (!selectedActionSphere) return;
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
|
||||||
...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
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
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,
|
|
||||||
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
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
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,
|
|
||||||
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
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
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]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="machine-mechanics-container">
|
|
||||||
<div className="machine-mechanics-header">
|
|
||||||
{selectedActionSphere?.path?.modelName || "point name 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">
|
|
||||||
{selectedPoint?.actions.map((action) => (
|
|
||||||
<div
|
|
||||||
key={action.uuid}
|
|
||||||
className={`list-item ${selectedItem?.type === "action" &&
|
|
||||||
selectedItem.item?.uuid === action.uuid
|
|
||||||
? "active"
|
|
||||||
: ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="value"
|
|
||||||
onClick={() => setSelectedItem({ type: "action", item: action })}
|
|
||||||
>
|
|
||||||
<RenameInput value={action.name} />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="remove-button"
|
|
||||||
onClick={() => handleDeleteAction(action.uuid)}
|
|
||||||
>
|
|
||||||
<RemoveIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</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="properties-header">{selectedItem.item.name}</div>
|
|
||||||
|
|
||||||
{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)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 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="Path Speed"
|
|
||||||
value={selectedPath.path.speed.toString()}
|
|
||||||
onChange={(value) => handleSpeedChange(parseFloat(value))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="footer">
|
|
||||||
<InfoIcon />
|
|
||||||
By selecting points, you can create events and triggers.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default MachineMechanics;
|
|
|
@ -0,0 +1,561 @@
|
||||||
|
import React, { useRef, useState, useMemo, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
AddIcon,
|
||||||
|
InfoIcon,
|
||||||
|
RemoveIcon,
|
||||||
|
ResizeHeightIcon,
|
||||||
|
} from "../../../icons/ExportCommonIcons";
|
||||||
|
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';
|
||||||
|
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}, [selectedActionSphere, simulationPaths]);
|
||||||
|
|
||||||
|
const handleAddAction = () => {
|
||||||
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
|
const updatedPaths = simulationPaths.map((path) => {
|
||||||
|
if (path.type === "Conveyor") {
|
||||||
|
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] };
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
});
|
||||||
|
|
||||||
|
setSimulationPaths(updatedPaths);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteAction = (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.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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
);
|
||||||
|
|
||||||
|
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]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="machine-mechanics-container">
|
||||||
|
<div className="machine-mechanics-header">
|
||||||
|
{selectedActionSphere?.path?.modelName || "point name 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="properties-header">{selectedItem.item.name}</div>
|
||||||
|
|
||||||
|
{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)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 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()}
|
||||||
|
onChange={(value) => handleSpeedChange(parseFloat(value))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="footer">
|
||||||
|
<InfoIcon />
|
||||||
|
By selecting points, you can create events and triggers.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VehicleMechanics;
|
|
@ -201,18 +201,16 @@ const LineGraphComponent = ({
|
||||||
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if ( measurements.length > 0 ) {
|
|
||||||
const socket = io("http://192.168.0.192:5010");
|
|
||||||
|
|
||||||
|
const socket = io("http://192.168.0.192:5010");
|
||||||
|
|
||||||
|
if ( measurements.length > 0 ) {
|
||||||
var inputes = {
|
var inputes = {
|
||||||
measurements: measurements,
|
measurements: measurements,
|
||||||
duration: duration,
|
duration: duration,
|
||||||
interval: 1000,
|
interval: 1000,
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('graphHHHHHHHHHHHHHHHHHHHHHHHHHHHHH',inputes);
|
|
||||||
|
|
||||||
|
|
||||||
// Start stream
|
// Start stream
|
||||||
const startStream = () => {
|
const startStream = () => {
|
||||||
socket.emit("lineInput", inputes);
|
socket.emit("lineInput", inputes);
|
||||||
|
@ -226,23 +224,24 @@ const LineGraphComponent = ({
|
||||||
|
|
||||||
// Extract timestamps and values
|
// Extract timestamps and values
|
||||||
const labels = responceData.time;
|
const labels = responceData.time;
|
||||||
const datasets = data.measurements.map((measurement: any) => ({
|
const datasets = measurements.map((measurement: any) => {
|
||||||
label: `${measurement.name}.${measurement.fields}`,
|
const key = `${measurement.name}.${measurement.fields}`;
|
||||||
data: responceData[`${measurement.name}.${measurement.fields}`]?.values || [],
|
return {
|
||||||
backgroundColor: themeColor[0] || "#5c87df",
|
label: key,
|
||||||
borderColor: themeColor[1] || "#ffffff",
|
data: responceData[key]?.values ?? [], // Ensure it exists
|
||||||
borderWidth: 2,
|
backgroundColor: themeColor[0] || "#5c87df",
|
||||||
// fill: false,
|
borderColor: themeColor[1] || "#ffffff",
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
|
||||||
setChartData({ labels, datasets });
|
setChartData({ labels, datasets });
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.off("lineOutput");
|
socket.off("lineOutput");
|
||||||
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}, [measurements, duration]);
|
}, [measurements, duration]);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import PolygonGenerator from "./polygonGenerator";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
|
import { useEffect, 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 = [
|
||||||
|
[
|
||||||
|
{ 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 },
|
||||||
|
// ],
|
||||||
|
[
|
||||||
|
{ 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();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PolygonGenerator groupRef={groupRef} lines={lines} plane={plane} />
|
||||||
|
<NavMeshDetails
|
||||||
|
lines={lines}
|
||||||
|
setNavMesh={setNavMesh}
|
||||||
|
groupRef={groupRef}
|
||||||
|
plane={plane}
|
||||||
|
/>
|
||||||
|
{pathPoints.map((pair, i) => (
|
||||||
|
<PathNavigator navMesh={navMesh} selectedPoints={pair} key={i} />
|
||||||
|
))}
|
||||||
|
<group ref={groupRef} visible={false} name="Meshes"></group>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Agv;
|
|
@ -0,0 +1,59 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { init as initRecastNavigation } from "@recast-navigation/core";
|
||||||
|
import { generateSoloNavMesh } from "@recast-navigation/generators";
|
||||||
|
import { DebugDrawer, getPositionsAndIndices } from "@recast-navigation/three";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
|
|
||||||
|
interface NavMeshDetailsProps {
|
||||||
|
setNavMesh: (navMesh: any) => void;
|
||||||
|
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||||
|
lines: Types.RefLines;
|
||||||
|
plane: Types.RefMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function NavMeshDetails({
|
||||||
|
lines,
|
||||||
|
setNavMesh,
|
||||||
|
groupRef,
|
||||||
|
plane,
|
||||||
|
}: NavMeshDetailsProps) {
|
||||||
|
const { scene } = useThree();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initializeNavigation = async () => {
|
||||||
|
try {
|
||||||
|
await initRecastNavigation();
|
||||||
|
|
||||||
|
if (!groupRef.current || groupRef.current.children.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const meshes = groupRef?.current?.children as THREE.Mesh[];
|
||||||
|
|
||||||
|
const [positions, indices] = getPositionsAndIndices(meshes);
|
||||||
|
|
||||||
|
const cs = 0.25;
|
||||||
|
const ch = 0.5;
|
||||||
|
const walkableRadius = 0.5;
|
||||||
|
|
||||||
|
const { success, navMesh } = generateSoloNavMesh(positions, indices, { cs, ch, walkableRadius: Math.round(walkableRadius / ch), });
|
||||||
|
|
||||||
|
if (!success || !navMesh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNavMesh(navMesh);
|
||||||
|
|
||||||
|
const debugDrawer = new DebugDrawer();
|
||||||
|
debugDrawer.drawNavMesh(navMesh);
|
||||||
|
// scene.add(debugDrawer);
|
||||||
|
} catch (error) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
initializeNavigation();
|
||||||
|
}, [scene, groupRef, lines.current]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { useFrame } from "@react-three/fiber";
|
||||||
|
import { NavMeshQuery } from "@recast-navigation/core";
|
||||||
|
import { Line } from "@react-three/drei";
|
||||||
|
|
||||||
|
// Define interface for props
|
||||||
|
interface PathNavigatorProps {
|
||||||
|
navMesh: any;
|
||||||
|
selectedPoints: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PathNavigator({
|
||||||
|
navMesh,
|
||||||
|
selectedPoints,
|
||||||
|
}: PathNavigatorProps) {
|
||||||
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
|
const progressRef = useRef(0);
|
||||||
|
const meshRef = useRef<THREE.Mesh | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedPoints.length === 2 && navMesh) {
|
||||||
|
const [start, end] = selectedPoints;
|
||||||
|
if (!start || !end) return;
|
||||||
|
|
||||||
|
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||||
|
|
||||||
|
const { path: computedPath } = navMeshQuery.computePath(start, end);
|
||||||
|
|
||||||
|
if (computedPath.length > 0) {
|
||||||
|
setPath(computedPath.map(({ x, y, z }) => [x, y + 0.1, z]));
|
||||||
|
progressRef.current = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedPoints, navMesh]);
|
||||||
|
|
||||||
|
useFrame((_, delta) => {
|
||||||
|
if (path.length > 1 && meshRef.current) {
|
||||||
|
const speed = 3;
|
||||||
|
progressRef.current += delta * speed;
|
||||||
|
|
||||||
|
let totalDistance = 0;
|
||||||
|
const distances: number[] = [];
|
||||||
|
for (let i = 0; i < path.length - 1; i++) {
|
||||||
|
const start = new THREE.Vector3(...path[i]);
|
||||||
|
const end = new THREE.Vector3(...path[i + 1]);
|
||||||
|
const segmentDistance = start.distanceTo(end);
|
||||||
|
distances.push(segmentDistance);
|
||||||
|
totalDistance += segmentDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
let coveredDistance = progressRef.current;
|
||||||
|
let accumulatedDistance = 0;
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while (
|
||||||
|
index < distances.length &&
|
||||||
|
coveredDistance > accumulatedDistance + distances[index]
|
||||||
|
) {
|
||||||
|
accumulatedDistance += distances[index];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < distances.length) {
|
||||||
|
const start = new THREE.Vector3(...path[index]);
|
||||||
|
const end = new THREE.Vector3(...path[index + 1]);
|
||||||
|
const segmentDistance = distances[index];
|
||||||
|
|
||||||
|
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
||||||
|
const position = start.clone().lerp(end, t); // Use clone() to avoid mutating the original vector
|
||||||
|
meshRef.current.position.copy(position);
|
||||||
|
|
||||||
|
const direction = new THREE.Vector3()
|
||||||
|
.subVectors(end, start)
|
||||||
|
.normalize();
|
||||||
|
const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(
|
||||||
|
new THREE.Vector3(0, 0, 1),
|
||||||
|
direction
|
||||||
|
);
|
||||||
|
meshRef.current.quaternion.slerp(targetQuaternion, 0.1);
|
||||||
|
} else {
|
||||||
|
progressRef.current = totalDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* {path.length > 0 && <Line points={path} color="blue" lineWidth={3} />} */}
|
||||||
|
{path.length > 0 && (
|
||||||
|
<mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}>
|
||||||
|
<boxGeometry args={[1, 1, 1]} />
|
||||||
|
<meshNormalMaterial />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import * as turf from "@turf/turf";
|
||||||
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
|
import arrayLinesToObject from "../geomentries/lines/lineConvertions/arrayLinesToObject";
|
||||||
|
interface PolygonGeneratorProps {
|
||||||
|
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||||
|
lines: Types.RefLines;
|
||||||
|
plane: Types.RefMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PolygonGenerator({
|
||||||
|
groupRef,
|
||||||
|
lines,
|
||||||
|
plane,
|
||||||
|
}: PolygonGeneratorProps) {
|
||||||
|
// const [rooms, setRooms] = useState<THREE.Vector3[][]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (groupRef.current && plane.current) {
|
||||||
|
groupRef.current.add(plane.current.clone());
|
||||||
|
}
|
||||||
|
}, [groupRef, plane]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let allLines = arrayLinesToObject(lines.current);
|
||||||
|
const wallLines = allLines?.filter((line) => line?.type === "WallLine");
|
||||||
|
const aisleLines = allLines?.filter((line) => line?.type === "AisleLine");
|
||||||
|
|
||||||
|
const wallPoints = wallLines
|
||||||
|
.map((pair) => pair?.line.map((vals) => vals.position))
|
||||||
|
.filter((wall): wall is THREE.Vector3[] => !!wall);
|
||||||
|
|
||||||
|
const result = aisleLines.map((pair) =>
|
||||||
|
pair?.line.map((point) => ({
|
||||||
|
position: [point.position.x, point.position.z],
|
||||||
|
uuid: point.uuid,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
if (!result || result.some((line) => !line)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lineFeatures = result?.map((line: any) =>
|
||||||
|
turf.lineString(line.map((p: any) => p?.position))
|
||||||
|
);
|
||||||
|
|
||||||
|
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
||||||
|
renderWallGeometry(wallPoints);
|
||||||
|
|
||||||
|
if (polygons.features.length > 1) {
|
||||||
|
polygons.features.forEach((feature) => {
|
||||||
|
if (feature.geometry.type === "Polygon") {
|
||||||
|
|
||||||
|
const shape = new THREE.Shape();
|
||||||
|
const coords = feature.geometry.coordinates[0];
|
||||||
|
|
||||||
|
shape.moveTo(coords[0][0], coords[0][1]);
|
||||||
|
|
||||||
|
for (let i = 1; i < coords.length; i++) {
|
||||||
|
shape.lineTo(coords[i][0], coords[i][1]);
|
||||||
|
}
|
||||||
|
shape.lineTo(coords[0][0], coords[0][1]);
|
||||||
|
|
||||||
|
const extrudeSettings = {
|
||||||
|
depth: 5,
|
||||||
|
bevelEnabled: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||||
|
|
||||||
|
const material = new THREE.MeshBasicMaterial({ color: "blue", transparent: true, opacity: 0.5 });
|
||||||
|
const mesh = new THREE.Mesh(geometry, material);
|
||||||
|
mesh.rotateX(Math.PI / 2);
|
||||||
|
mesh.name = "agv-collider";
|
||||||
|
mesh.position.y = 5;
|
||||||
|
|
||||||
|
mesh.receiveShadow = true;
|
||||||
|
groupRef.current?.add(mesh);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [lines.current]);
|
||||||
|
|
||||||
|
const renderWallGeometry = (walls: THREE.Vector3[][]) => {
|
||||||
|
walls.forEach((wall) => {
|
||||||
|
if (wall.length < 2) return;
|
||||||
|
|
||||||
|
for (let i = 0; i < wall.length - 1; i++) {
|
||||||
|
const start = new THREE.Vector3(wall[i].x, wall[i].y, wall[i].z);
|
||||||
|
const end = new THREE.Vector3(
|
||||||
|
wall[i + 1].x,
|
||||||
|
wall[i + 1].y,
|
||||||
|
wall[i + 1].z
|
||||||
|
);
|
||||||
|
|
||||||
|
const wallHeight = 10;
|
||||||
|
const direction = new THREE.Vector3().subVectors(end, start);
|
||||||
|
const length = direction.length();
|
||||||
|
direction.normalize();
|
||||||
|
|
||||||
|
const wallGeometry = new THREE.BoxGeometry(length, wallHeight);
|
||||||
|
const wallMaterial = new THREE.MeshBasicMaterial({
|
||||||
|
color: "#aaa",
|
||||||
|
transparent: true,
|
||||||
|
opacity: 0.5,
|
||||||
|
});
|
||||||
|
|
||||||
|
const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
|
||||||
|
const midPoint = new THREE.Vector3()
|
||||||
|
.addVectors(start, end)
|
||||||
|
.multiplyScalar(0.5);
|
||||||
|
wallMesh.position.set(midPoint.x, wallHeight / 2, midPoint.z);
|
||||||
|
|
||||||
|
const quaternion = new THREE.Quaternion();
|
||||||
|
quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction);
|
||||||
|
wallMesh.quaternion.copy(quaternion);
|
||||||
|
|
||||||
|
groupRef.current?.add(wallMesh);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -78,7 +78,7 @@ const CamModelsGroup = () => {
|
||||||
socket.off('userDisConnectRespones');
|
socket.off('userDisConnectRespones');
|
||||||
socket.off('cameraUpdateResponse');
|
socket.off('cameraUpdateResponse');
|
||||||
};
|
};
|
||||||
}, [socket]);
|
}, [socket, activeUsers]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (!groupRef.current) return;
|
if (!groupRef.current) return;
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import React from "react";
|
import React, { Suspense, useEffect } from "react";
|
||||||
import assetImage from "../../assets/image/image.png";
|
import assetImage from "../../assets/image/image.png";
|
||||||
import { FiileedStarsIconSmall } from "../../components/icons/marketPlaceIcons";
|
import { FiileedStarsIconSmall } from "../../components/icons/marketPlaceIcons";
|
||||||
|
import { Canvas, useThree } from "@react-three/fiber";
|
||||||
|
import { ContactShadows, OrbitControls, Text } from "@react-three/drei";
|
||||||
|
import GltfLoader from "./GltfLoader";
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
// Define the shape of the selected card
|
// Define the shape of the selected card
|
||||||
interface SelectedCard {
|
interface SelectedCard {
|
||||||
|
@ -17,6 +21,14 @@ interface AssetPreviewProps {
|
||||||
setSelectedCard: React.Dispatch<React.SetStateAction<SelectedCard | null>>; // Type for setter function
|
setSelectedCard: React.Dispatch<React.SetStateAction<SelectedCard | null>>; // Type for setter function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Ui() {
|
||||||
|
return (
|
||||||
|
<Text color="#6f42c1" anchorX="center" anchorY="middle" scale={0.3}>
|
||||||
|
Loading your model...
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const AssetPreview: React.FC<AssetPreviewProps> = ({
|
const AssetPreview: React.FC<AssetPreviewProps> = ({
|
||||||
selectedCard,
|
selectedCard,
|
||||||
setSelectedCard,
|
setSelectedCard,
|
||||||
|
@ -27,8 +39,6 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
|
||||||
Math.min(5, isNaN(selectedCard.rating) ? 0 : selectedCard.rating)
|
Math.min(5, isNaN(selectedCard.rating) ? 0 : selectedCard.rating)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("selectedCard: ", selectedCard);
|
|
||||||
|
|
||||||
// Ensure that the rating is a valid positive integer for array length
|
// Ensure that the rating is a valid positive integer for array length
|
||||||
const starsArray = Array.from({ length: rating }, (_, index) => index);
|
const starsArray = Array.from({ length: rating }, (_, index) => index);
|
||||||
|
|
||||||
|
@ -36,8 +46,38 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
|
||||||
<div className="assetPreview-wrapper">
|
<div className="assetPreview-wrapper">
|
||||||
<div className="assetPreview">
|
<div className="assetPreview">
|
||||||
<div className="image-preview">
|
<div className="image-preview">
|
||||||
<img src={assetImage} alt="" />
|
{/* <img src={assetImage} alt="" /> */}
|
||||||
{/* Add canvas here */}
|
{/* Add canvas here */}
|
||||||
|
<div className="canvas-container" style={{ height: "100%" }}>
|
||||||
|
<Canvas
|
||||||
|
flat
|
||||||
|
shadows
|
||||||
|
color="#FFFFFF"
|
||||||
|
camera={{ fov: 75 }}
|
||||||
|
gl={{
|
||||||
|
preserveDrawingBuffer: true,
|
||||||
|
}}
|
||||||
|
onCreated={({ scene }) => {
|
||||||
|
scene.background = new THREE.Color(0xffffff);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Suspense fallback={<Ui />}>
|
||||||
|
{selectedCard.assetName && (
|
||||||
|
<GltfLoader fromServer={selectedCard.assetName} />
|
||||||
|
)}
|
||||||
|
<OrbitControls minPolarAngle={0} maxPolarAngle={Math.PI / 2} />
|
||||||
|
<ContactShadows
|
||||||
|
renderOrder={2}
|
||||||
|
frames={1}
|
||||||
|
resolution={1024}
|
||||||
|
scale={120}
|
||||||
|
blur={2}
|
||||||
|
opacity={0.4}
|
||||||
|
far={100}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
</Canvas>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="asset-details-preview">
|
<div className="asset-details-preview">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
CommentsIcon,
|
CommentsIcon,
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
|
@ -8,6 +8,7 @@ import {
|
||||||
} from "../../components/icons/marketPlaceIcons";
|
} from "../../components/icons/marketPlaceIcons";
|
||||||
|
|
||||||
import assetImage from "../../assets/image/image.png";
|
import assetImage from "../../assets/image/image.png";
|
||||||
|
import { getAssetDownload } from "../../services/marketplace/getAssetDownload";
|
||||||
|
|
||||||
interface CardProps {
|
interface CardProps {
|
||||||
assetName: string;
|
assetName: string;
|
||||||
|
@ -15,6 +16,7 @@ interface CardProps {
|
||||||
price: number;
|
price: number;
|
||||||
rating: number;
|
rating: number;
|
||||||
views: number;
|
views: number;
|
||||||
|
image: string;
|
||||||
onSelectCard: (cardData: {
|
onSelectCard: (cardData: {
|
||||||
assetName: string;
|
assetName: string;
|
||||||
uploadedOn: string;
|
uploadedOn: string;
|
||||||
|
@ -30,6 +32,7 @@ const Card: React.FC<CardProps> = ({
|
||||||
price,
|
price,
|
||||||
rating,
|
rating,
|
||||||
views,
|
views,
|
||||||
|
image,
|
||||||
onSelectCard,
|
onSelectCard,
|
||||||
}) => {
|
}) => {
|
||||||
const handleCardSelect = () => {
|
const handleCardSelect = () => {
|
||||||
|
@ -38,16 +41,23 @@ const Card: React.FC<CardProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card-container">
|
<div className="card-container">
|
||||||
<div className="icon">
|
{/* <a href={getAssetDownload(assetName)} download className="icon">
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
</div>
|
</a> */}
|
||||||
<div className="image-container">
|
<div className="image-container">
|
||||||
<img src={assetImage} alt={assetName} />
|
<img src={image} alt={assetName} />
|
||||||
</div>
|
</div>
|
||||||
<div className="assets-container">
|
<div className="assets-container">
|
||||||
<div className="name-container">
|
<div className="name-container">
|
||||||
<div className="assets-name">{assetName}</div>
|
<div className="assets-name">{assetName.split("_").join(" ")}</div>
|
||||||
<div className="assets-date">{uploadedOn}</div>
|
<div className="assets-date">
|
||||||
|
Uploaded on -{" "}
|
||||||
|
{new Date(uploadedOn).toLocaleDateString("en-GB", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
year: "2-digit",
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="details">
|
<div className="details">
|
||||||
<div className="content">
|
<div className="content">
|
||||||
|
|
|
@ -1,108 +1,26 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Card from "./Card";
|
import Card from "./Card";
|
||||||
import AssetPreview from "./AssetPreview";
|
import AssetPreview from "./AssetPreview";
|
||||||
import RenderOverlay from "../../components/templates/Overlay";
|
import RenderOverlay from "../../components/templates/Overlay";
|
||||||
|
import { fetchAssets } from "../../services/marketplace/fetchAssets";
|
||||||
|
interface ModelData {
|
||||||
|
CreatedBy: string;
|
||||||
|
animated: string | null;
|
||||||
|
category: string;
|
||||||
|
description: string;
|
||||||
|
filename: string;
|
||||||
|
isArchieve: boolean;
|
||||||
|
modelfileID: string;
|
||||||
|
tags: string;
|
||||||
|
thumbnail: string;
|
||||||
|
uploadDate: number;
|
||||||
|
_id: string;
|
||||||
|
}
|
||||||
|
interface ModelsProps {
|
||||||
|
models: ModelData[];
|
||||||
|
}
|
||||||
|
|
||||||
const CardsContainer: React.FC = () => {
|
const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
|
||||||
const array = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: "Asset 1",
|
|
||||||
uploadedOn: "12 Jan 23",
|
|
||||||
price: 36500,
|
|
||||||
rating: 4.5,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "Asset 2",
|
|
||||||
uploadedOn: "14 Jan 23",
|
|
||||||
price: 45000,
|
|
||||||
rating: 4.0,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "Asset 3",
|
|
||||||
uploadedOn: "15 Jan 23",
|
|
||||||
price: 52000,
|
|
||||||
rating: 4.8,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: "Asset 4",
|
|
||||||
uploadedOn: "18 Jan 23",
|
|
||||||
price: 37000,
|
|
||||||
rating: 3.9,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: "Asset 5",
|
|
||||||
uploadedOn: "20 Jan 23",
|
|
||||||
price: 60000,
|
|
||||||
rating: 5.0,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
name: "Asset 6",
|
|
||||||
uploadedOn: "22 Jan 23",
|
|
||||||
price: 46000,
|
|
||||||
rating: 4.2,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
name: "Asset 7",
|
|
||||||
uploadedOn: "25 Jan 23",
|
|
||||||
price: 38000,
|
|
||||||
rating: 4.3,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
name: "Asset 8",
|
|
||||||
uploadedOn: "27 Jan 23",
|
|
||||||
price: 41000,
|
|
||||||
rating: 4.1,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
name: "Asset 9",
|
|
||||||
uploadedOn: "30 Jan 23",
|
|
||||||
price: 55000,
|
|
||||||
rating: 4.6,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
name: "Asset 10",
|
|
||||||
uploadedOn: "2 Feb 23",
|
|
||||||
price: 49000,
|
|
||||||
rating: 4.4,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
name: "Asset 11",
|
|
||||||
uploadedOn: "5 Feb 23",
|
|
||||||
price: 62000,
|
|
||||||
rating: 5.0,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
name: "Asset 12",
|
|
||||||
uploadedOn: "7 Feb 23",
|
|
||||||
price: 53000,
|
|
||||||
rating: 4.7,
|
|
||||||
views: 500,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const [selectedCard, setSelectedCard] = useState<{
|
const [selectedCard, setSelectedCard] = useState<{
|
||||||
assetName: string;
|
assetName: string;
|
||||||
uploadedOn: string;
|
uploadedOn: string;
|
||||||
|
@ -125,24 +43,26 @@ const CardsContainer: React.FC = () => {
|
||||||
<div className="cards-container-container">
|
<div className="cards-container-container">
|
||||||
<div className="header">Products You May Like</div>
|
<div className="header">Products You May Like</div>
|
||||||
<div className="cards-wrapper-container">
|
<div className="cards-wrapper-container">
|
||||||
{array.map((asset) => (
|
{models.length > 0 &&
|
||||||
<Card
|
models.map((assetDetail) => (
|
||||||
key={asset.id}
|
<Card
|
||||||
assetName={asset.name}
|
key={assetDetail._id}
|
||||||
uploadedOn={asset.uploadedOn}
|
assetName={assetDetail?.filename}
|
||||||
price={asset.price}
|
uploadedOn={assetDetail.uploadDate.toString()}
|
||||||
rating={asset.rating}
|
price={36500}
|
||||||
views={asset.views}
|
rating={4.5}
|
||||||
onSelectCard={handleCardSelect}
|
views={800}
|
||||||
/>
|
onSelectCard={handleCardSelect}
|
||||||
))}
|
image={assetDetail.thumbnail}
|
||||||
{/* <RenderOverlay> */}
|
|
||||||
{selectedCard && (
|
|
||||||
<AssetPreview
|
|
||||||
selectedCard={selectedCard}
|
|
||||||
setSelectedCard={setSelectedCard}
|
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
|
{/* <RenderOverlay> */}
|
||||||
|
{selectedCard && (
|
||||||
|
<AssetPreview
|
||||||
|
selectedCard={selectedCard}
|
||||||
|
setSelectedCard={setSelectedCard}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{/* </RenderOverlay> */}
|
{/* </RenderOverlay> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,19 +1,69 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
// import RegularDropDown from "./ui/inputs/RegularDropDown";
|
// import RegularDropDown from "./ui/inputs/RegularDropDown";
|
||||||
|
|
||||||
import Search from "../../components/ui/inputs/Search";
|
import Search from "../../components/ui/inputs/Search";
|
||||||
import { StarsIcon } from "../../components/icons/marketPlaceIcons";
|
import { StarsIcon } from "../../components/icons/marketPlaceIcons";
|
||||||
import RegularDropDown from "../../components/ui/inputs/RegularDropDown";
|
import RegularDropDown from "../../components/ui/inputs/RegularDropDown";
|
||||||
|
import { getSortedAssets } from "../../services/marketplace/getSortedAssets";
|
||||||
const FilterSearch: React.FC = () => {
|
interface ModelData {
|
||||||
|
CreatedBy: string;
|
||||||
|
animated: string | null;
|
||||||
|
category: string;
|
||||||
|
description: string;
|
||||||
|
filename: string;
|
||||||
|
isArchieve: boolean;
|
||||||
|
modelfileID: string;
|
||||||
|
tags: string;
|
||||||
|
thumbnail: string;
|
||||||
|
uploadDate: number;
|
||||||
|
_id: string;
|
||||||
|
}
|
||||||
|
interface ModelsProps {
|
||||||
|
models: ModelData[];
|
||||||
|
setModels: React.Dispatch<React.SetStateAction<ModelData[]>>;
|
||||||
|
filteredModels: ModelData[];
|
||||||
|
}
|
||||||
|
const FilterSearch: React.FC<ModelsProps> = ({
|
||||||
|
models,
|
||||||
|
setModels,
|
||||||
|
filteredModels,
|
||||||
|
}) => {
|
||||||
const [activeOption, setActiveOption] = useState("Sort by"); // State for active option
|
const [activeOption, setActiveOption] = useState("Sort by"); // State for active option
|
||||||
|
console.log("filteredModels: ", filteredModels);
|
||||||
|
|
||||||
const handleSelect = (option: string) => {
|
const handleSelect = (option: string) => {
|
||||||
setActiveOption(option);
|
setActiveOption(option);
|
||||||
|
console.log("option: ", option);
|
||||||
|
// Alphabet ascending
|
||||||
|
// Alphabet descending
|
||||||
|
// All
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeOption == "Alphabet ascending") {
|
||||||
|
let ascending = models
|
||||||
|
?.slice()
|
||||||
|
.sort((a, b) => a.filename.localeCompare(b.filename))
|
||||||
|
.map((val) => val);
|
||||||
|
setModels(ascending);
|
||||||
|
} else if (activeOption == "Alphabet descending") {
|
||||||
|
let descending = models
|
||||||
|
?.slice()
|
||||||
|
.sort((a, b) => b.filename.localeCompare(a.filename))
|
||||||
|
.map((val) => val);
|
||||||
|
setModels(descending);
|
||||||
|
}
|
||||||
|
}, [activeOption]);
|
||||||
|
const handleSearch = (val: string) => {
|
||||||
|
const filteredModel = filteredModels?.filter((model) =>
|
||||||
|
model.filename.toLowerCase().includes(val.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
setModels(filteredModel);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="filter-search-container">
|
<div className="filter-search-container">
|
||||||
<Search onChange={() => {}} />
|
<Search onChange={handleSearch} />
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={activeOption}
|
header={activeOption}
|
||||||
options={["Alphabet ascending", "Alphabet descending", ""]}
|
options={["Alphabet ascending", "Alphabet descending", ""]}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { useRef, useEffect } from "react";
|
||||||
|
import { useFrame } from "@react-three/fiber";
|
||||||
|
import { Stage, useGLTF } from "@react-three/drei";
|
||||||
|
import { AnimationMixer, AnimationAction, Object3D } from "three";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { fetchGltfUrl } from "../../services/marketplace/fetchGltfUrl";
|
||||||
|
|
||||||
|
interface GltfLoaderProps {
|
||||||
|
glbdata?: boolean;
|
||||||
|
fromServer?: string;
|
||||||
|
setAnimations?: (animations?: string[]) => void;
|
||||||
|
selectedAnimation?: string;
|
||||||
|
setSelectedAnimation?: (animation: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const getGLTFUrl = (url: string) => url; // Placeholder for your actual function
|
||||||
|
|
||||||
|
const GltfLoader: React.FC<GltfLoaderProps> = ({
|
||||||
|
glbdata,
|
||||||
|
fromServer,
|
||||||
|
setAnimations,
|
||||||
|
selectedAnimation,
|
||||||
|
}) => {
|
||||||
|
const modelUrl: any = fromServer ? fetchGltfUrl(fromServer) : glbdata;
|
||||||
|
const { scene, animations } = useGLTF(modelUrl ?? "") as {
|
||||||
|
scene: Object3D;
|
||||||
|
animations: THREE.AnimationClip[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const mixer = useRef<AnimationMixer | null>(
|
||||||
|
scene ? new AnimationMixer(scene) : null
|
||||||
|
);
|
||||||
|
const actions = useRef<Record<string, AnimationAction>>({});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (animations.length > 0 && mixer.current && setAnimations) {
|
||||||
|
const animationNames = animations.map((animation) => animation.name);
|
||||||
|
setAnimations(animationNames);
|
||||||
|
|
||||||
|
animations.forEach((animation) => {
|
||||||
|
const action = mixer.current!.clipAction(animation);
|
||||||
|
actions.current[animation.name] = action;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setAnimations && setAnimations([]);
|
||||||
|
}
|
||||||
|
}, [animations, setAnimations]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (actions.current && selectedAnimation) {
|
||||||
|
const action = actions.current[selectedAnimation];
|
||||||
|
if (action) {
|
||||||
|
action.reset().fadeIn(0.5).play();
|
||||||
|
return () => {
|
||||||
|
action.fadeOut(0.5);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedAnimation]);
|
||||||
|
|
||||||
|
useFrame((_, delta) => {
|
||||||
|
if (mixer.current) {
|
||||||
|
mixer.current.update(delta);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stage
|
||||||
|
adjustCamera={false}
|
||||||
|
intensity={0.5}
|
||||||
|
shadows="contact"
|
||||||
|
environment="city"
|
||||||
|
>
|
||||||
|
<primitive object={scene} scale={1} />
|
||||||
|
</Stage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GltfLoader;
|
|
@ -1,14 +1,46 @@
|
||||||
import React from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import FilterSearch from "./FilterSearch";
|
import FilterSearch from "./FilterSearch";
|
||||||
import CardsContainer from "./CardsContainer";
|
import CardsContainer from "./CardsContainer";
|
||||||
|
import { fetchAssets } from "../../services/marketplace/fetchAssets";
|
||||||
|
import { getAssetImages } from "../../services/factoryBuilder/assest/assets/getAssetImages";
|
||||||
|
interface ModelData {
|
||||||
|
CreatedBy: string;
|
||||||
|
animated: string | null;
|
||||||
|
category: string;
|
||||||
|
description: string;
|
||||||
|
filename: string;
|
||||||
|
isArchieve: boolean;
|
||||||
|
modelfileID: string;
|
||||||
|
tags: string;
|
||||||
|
thumbnail: string;
|
||||||
|
uploadDate: number;
|
||||||
|
_id: string;
|
||||||
|
}
|
||||||
const MarketPlace = () => {
|
const MarketPlace = () => {
|
||||||
|
const [models, setModels] = useState<ModelData[]>([]);
|
||||||
|
const [filteredModels, setFilteredModels] = useState<ModelData[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const filteredAssets = async () => {
|
||||||
|
try {
|
||||||
|
const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6");
|
||||||
|
setModels(filt.items);
|
||||||
|
setFilteredModels(filt.items);
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
filteredAssets();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="marketplace-wrapper">
|
<div className="marketplace-wrapper">
|
||||||
<div className="marketplace-container">
|
<div className="marketplace-container">
|
||||||
<div className="marketPlace">
|
<div className="marketPlace">
|
||||||
<FilterSearch />
|
<FilterSearch
|
||||||
<CardsContainer />
|
models={models}
|
||||||
|
setModels={setModels}
|
||||||
|
filteredModels={filteredModels}
|
||||||
|
/>
|
||||||
|
<CardsContainer models={models} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -52,7 +52,6 @@ export default function Scene() {
|
||||||
<MeasurementTool />
|
<MeasurementTool />
|
||||||
<World />
|
<World />
|
||||||
<ZoneCentreTarget />
|
<ZoneCentreTarget />
|
||||||
{/* <Simulation /> */}
|
|
||||||
<Simulation />
|
<Simulation />
|
||||||
<PostProcessing />
|
<PostProcessing />
|
||||||
<Sun />
|
<Sun />
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
useShadows,
|
useShadows,
|
||||||
useUpdateScene,
|
useUpdateScene,
|
||||||
useWalls,
|
useWalls,
|
||||||
useToolMode
|
useToolMode,
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
|
|
||||||
////////// 3D Function Imports //////////
|
////////// 3D Function Imports //////////
|
||||||
|
@ -50,16 +50,17 @@ import { findEnvironment } from "../../../services/factoryBuilder/environment/fi
|
||||||
import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
|
import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
|
||||||
import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp";
|
import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp";
|
||||||
import ZoneGroup from "../../builder/groups/zoneGroup";
|
import ZoneGroup from "../../builder/groups/zoneGroup";
|
||||||
|
import Agv from "../../builder/agv/agv";
|
||||||
|
|
||||||
export default function World() {
|
export default function World() {
|
||||||
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
||||||
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
|
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
|
||||||
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
|
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
|
||||||
const scene = useRef() as Types.RefScene; // Reference to the scene.
|
const scene = useRef() as Types.RefScene; // Reference to the scene.
|
||||||
const camera = useRef() as Types.RefCamera; // Reference to the camera object.
|
const camera = useRef() as Types.RefCamera; // Reference to the camera object.
|
||||||
const controls = useRef<any>(); // Reference to the controls object.
|
const controls = useRef<any>(); // Reference to the controls object.
|
||||||
const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
|
const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
|
||||||
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
|
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
|
||||||
|
|
||||||
// Assigning the scene and camera from the Three.js state to the references.
|
// Assigning the scene and camera from the Three.js state to the references.
|
||||||
|
|
||||||
|
@ -68,47 +69,48 @@ export default function World() {
|
||||||
controls.current = state.controls;
|
controls.current = state.controls;
|
||||||
raycaster.current = state.raycaster;
|
raycaster.current = state.raycaster;
|
||||||
|
|
||||||
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
||||||
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
||||||
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
|
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
|
||||||
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
|
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
|
||||||
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
|
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
|
||||||
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
|
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
|
||||||
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
|
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
|
||||||
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
|
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
|
||||||
const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
|
const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
|
||||||
const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
|
const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
|
||||||
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
|
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
|
||||||
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
|
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
|
||||||
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
|
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
|
||||||
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
|
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
|
||||||
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
|
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
|
||||||
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
|
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
|
||||||
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
|
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
|
||||||
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
|
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
|
||||||
const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
|
const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
|
||||||
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
|
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
|
||||||
const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
|
const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
|
||||||
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
|
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
|
||||||
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
|
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
|
||||||
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
|
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
|
||||||
const floorGroupAisle = useRef() as Types.RefGroup;
|
const floorGroupAisle = useRef() as Types.RefGroup;
|
||||||
const zoneGroup = useRef() as Types.RefGroup;
|
const zoneGroup = useRef() as Types.RefGroup;
|
||||||
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
|
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
|
||||||
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
|
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
|
||||||
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
|
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
|
||||||
const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
|
const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
|
||||||
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
|
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
|
||||||
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
|
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
|
||||||
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
|
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
|
||||||
|
|
||||||
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
||||||
|
|
||||||
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
const [selectedItemsIndex, setSelectedItemsIndex] =
|
||||||
const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
||||||
const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
||||||
|
const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
||||||
const { toolMode, setToolMode } = useToolMode();
|
const { toolMode, setToolMode } = useToolMode();
|
||||||
const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not.
|
const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not.
|
||||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
||||||
|
@ -118,7 +120,6 @@ export default function World() {
|
||||||
const { walls, setWalls } = useWalls();
|
const { walls, setWalls } = useWalls();
|
||||||
const [RefTextupdate, setRefTextUpdate] = useState(-1000);
|
const [RefTextupdate, setRefTextUpdate] = useState(-1000);
|
||||||
|
|
||||||
|
|
||||||
// const loader = new GLTFLoader();
|
// const loader = new GLTFLoader();
|
||||||
// const dracoLoader = new DRACOLoader();
|
// const dracoLoader = new DRACOLoader();
|
||||||
|
|
||||||
|
@ -162,7 +163,14 @@ export default function World() {
|
||||||
dragPointControls.current.enabled = false;
|
dragPointControls.current.enabled = false;
|
||||||
}
|
}
|
||||||
if (toggleView) {
|
if (toggleView) {
|
||||||
Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
Layer2DVisibility(
|
||||||
|
activeLayer,
|
||||||
|
floorPlanGroup,
|
||||||
|
floorPlanGroupLine,
|
||||||
|
floorPlanGroupPoint,
|
||||||
|
currentLayerPoint,
|
||||||
|
dragPointControls
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
setToolMode(null);
|
setToolMode(null);
|
||||||
setDeletePointOrLine(false);
|
setDeletePointOrLine(false);
|
||||||
|
@ -179,11 +187,14 @@ export default function World() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const email = localStorage.getItem('email')
|
const email = localStorage.getItem("email");
|
||||||
const organization = (email!.split("@")[1]).split(".")[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
async function fetchVisibility() {
|
async function fetchVisibility() {
|
||||||
const visibility = await findEnvironment(organization, localStorage.getItem('userId')!);
|
const visibility = await findEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!
|
||||||
|
);
|
||||||
if (visibility) {
|
if (visibility) {
|
||||||
setRoofVisibility(visibility.roofVisibility);
|
setRoofVisibility(visibility.roofVisibility);
|
||||||
setWallVisibility(visibility.wallVisibility);
|
setWallVisibility(visibility.wallVisibility);
|
||||||
|
@ -191,13 +202,33 @@ export default function World() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchVisibility();
|
fetchVisibility();
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
////////// UseFrame is Here //////////
|
////////// UseFrame is Here //////////
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (toolMode) {
|
if (toolMode) {
|
||||||
Draw(state, plane, cursorPosition, floorPlanGroupPoint, floorPlanGroupLine, snappedPoint, isSnapped, isSnappedUUID, line, lines, ispreSnapped, floorPlanGroup, ReferenceLineMesh, LineCreated, setRefTextUpdate, Tube, anglesnappedPoint, isAngleSnapped, toolMode)
|
Draw(
|
||||||
|
state,
|
||||||
|
plane,
|
||||||
|
cursorPosition,
|
||||||
|
floorPlanGroupPoint,
|
||||||
|
floorPlanGroupLine,
|
||||||
|
snappedPoint,
|
||||||
|
isSnapped,
|
||||||
|
isSnappedUUID,
|
||||||
|
line,
|
||||||
|
lines,
|
||||||
|
ispreSnapped,
|
||||||
|
floorPlanGroup,
|
||||||
|
ReferenceLineMesh,
|
||||||
|
LineCreated,
|
||||||
|
setRefTextUpdate,
|
||||||
|
Tube,
|
||||||
|
anglesnappedPoint,
|
||||||
|
isAngleSnapped,
|
||||||
|
toolMode
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -304,7 +335,6 @@ export default function World() {
|
||||||
anglesnappedPoint={anglesnappedPoint}
|
anglesnappedPoint={anglesnappedPoint}
|
||||||
/> */}
|
/> */}
|
||||||
|
|
||||||
|
|
||||||
<ZoneGroup />
|
<ZoneGroup />
|
||||||
|
|
||||||
<FloorGroupAilse
|
<FloorGroupAilse
|
||||||
|
@ -327,10 +357,9 @@ export default function World() {
|
||||||
anglesnappedPoint={anglesnappedPoint}
|
anglesnappedPoint={anglesnappedPoint}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DrieHtmlTemp
|
<DrieHtmlTemp itemsGroup={itemsGroup} />
|
||||||
itemsGroup={itemsGroup}
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
<Agv lines={lines} plane={plane} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -1,43 +1,29 @@
|
||||||
import { useFloorItems } from '../../../store/store';
|
import { useFloorItems, useSimulationPaths } from '../../../store/store';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import * as Types from '../../../types/world/worldTypes';
|
import * as Types from '../../../types/world/worldTypes';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
interface Path {
|
function Behaviour() {
|
||||||
modeluuid: string;
|
const { setSimulationPaths } = useSimulationPaths();
|
||||||
modelName: string;
|
|
||||||
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 }[] };
|
|
||||||
}[];
|
|
||||||
pathPosition: [number, number, number];
|
|
||||||
pathRotation: [number, number, number];
|
|
||||||
speed: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
|
|
||||||
const { floorItems } = useFloorItems();
|
const { floorItems } = useFloorItems();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newPaths: Path[] = [];
|
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
|
||||||
|
|
||||||
floorItems.forEach((item: Types.FloorItemType) => {
|
floorItems.forEach((item: Types.FloorItemType) => {
|
||||||
if (item.modelfileID === "6633215057b31fe671145959") {
|
if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
|
||||||
const point1Position = new THREE.Vector3(0, 1.25, 3.3);
|
const point1Position = new THREE.Vector3(0, 0.85, 2.2);
|
||||||
const middlePointPosition = new THREE.Vector3(0, 1.25, 0);
|
const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
|
||||||
const point2Position = new THREE.Vector3(0, 1.25, -3.3);
|
const point2Position = new THREE.Vector3(0, 0.85, -2.2);
|
||||||
|
|
||||||
const point1UUID = THREE.MathUtils.generateUUID();
|
const point1UUID = THREE.MathUtils.generateUUID();
|
||||||
const middlePointUUID = THREE.MathUtils.generateUUID();
|
const middlePointUUID = THREE.MathUtils.generateUUID();
|
||||||
const point2UUID = THREE.MathUtils.generateUUID();
|
const point2UUID = THREE.MathUtils.generateUUID();
|
||||||
|
|
||||||
const newPath: Path = {
|
const newPath: Types.ConveyorEventsSchema = {
|
||||||
modeluuid: item.modeluuid,
|
modeluuid: item.modeluuid,
|
||||||
modelName: item.modelname,
|
modelName: item.modelname,
|
||||||
|
type: 'Conveyor',
|
||||||
points: [
|
points: [
|
||||||
{
|
{
|
||||||
uuid: point1UUID,
|
uuid: point1UUID,
|
||||||
|
@ -64,12 +50,32 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
|
||||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
|
connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
pathPosition: [...item.position],
|
assetPosition: [...item.position],
|
||||||
pathRotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
assetRotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
speed: 1,
|
speed: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
newPaths.push(newPath);
|
newPaths.push(newPath);
|
||||||
|
} else if (item.modelfileID === "67e3da19c2e8f37134526e6a") {
|
||||||
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
|
const pointPosition = new THREE.Vector3(0, 1.3, 0);
|
||||||
|
|
||||||
|
const newVehiclePath: Types.VehicleEventsSchema = {
|
||||||
|
modeluuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
type: 'Vehicle',
|
||||||
|
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: [],
|
||||||
|
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||||
|
},
|
||||||
|
assetPosition: [...item.position],
|
||||||
|
speed: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
newPaths.push(newVehiclePath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
|
import * as Types from '../../../types/world/worldTypes';
|
||||||
import { QuadraticBezierLine } from '@react-three/drei';
|
import { QuadraticBezierLine } from '@react-three/drei';
|
||||||
import { useIsConnecting, useSimulationPaths } from '../../../store/store';
|
import { useIsConnecting, useSimulationPaths } from '../../../store/store';
|
||||||
import useModuleStore from '../../../store/useModuleStore';
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
|
@ -27,61 +28,113 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
toPointUUID: string
|
toPointUUID: string
|
||||||
) => {
|
) => {
|
||||||
const updatedPaths = simulationPaths.map(path => {
|
const updatedPaths = simulationPaths.map(path => {
|
||||||
if (path.modeluuid === fromPathUUID) {
|
if (path.type === 'Conveyor') {
|
||||||
return {
|
if (path.modeluuid === fromPathUUID) {
|
||||||
...path,
|
return {
|
||||||
points: path.points.map(point => {
|
...path,
|
||||||
if (point.uuid === fromPointUUID) {
|
points: path.points.map(point => {
|
||||||
const newTarget = {
|
if (point.uuid === fromPointUUID) {
|
||||||
pathUUID: toPathUUID,
|
const newTarget = {
|
||||||
pointUUID: toPointUUID
|
pathUUID: toPathUUID,
|
||||||
};
|
pointUUID: toPointUUID
|
||||||
const existingTargets = point.connections.targets || [];
|
|
||||||
|
|
||||||
if (!existingTargets.some(target =>
|
|
||||||
target.pathUUID === newTarget.pathUUID &&
|
|
||||||
target.pointUUID === newTarget.pointUUID
|
|
||||||
)) {
|
|
||||||
return {
|
|
||||||
...point,
|
|
||||||
connections: {
|
|
||||||
...point.connections,
|
|
||||||
targets: [...existingTargets, newTarget]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
const existingTargets = point.connections.targets || [];
|
||||||
|
|
||||||
|
if (!existingTargets.some(target =>
|
||||||
|
target.pathUUID === newTarget.pathUUID &&
|
||||||
|
target.pointUUID === newTarget.pointUUID
|
||||||
|
)) {
|
||||||
|
return {
|
||||||
|
...point,
|
||||||
|
connections: {
|
||||||
|
...point.connections,
|
||||||
|
targets: [...existingTargets, newTarget]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return point;
|
||||||
return point;
|
})
|
||||||
})
|
};
|
||||||
};
|
}
|
||||||
|
else if (path.modeluuid === toPathUUID) {
|
||||||
|
return {
|
||||||
|
...path,
|
||||||
|
points: path.points.map(point => {
|
||||||
|
if (point.uuid === toPointUUID) {
|
||||||
|
const reverseTarget = {
|
||||||
|
pathUUID: fromPathUUID,
|
||||||
|
pointUUID: fromPointUUID
|
||||||
|
};
|
||||||
|
const existingTargets = point.connections.targets || [];
|
||||||
|
|
||||||
|
if (!existingTargets.some(target =>
|
||||||
|
target.pathUUID === reverseTarget.pathUUID &&
|
||||||
|
target.pointUUID === reverseTarget.pointUUID
|
||||||
|
)) {
|
||||||
|
return {
|
||||||
|
...point,
|
||||||
|
connections: {
|
||||||
|
...point.connections,
|
||||||
|
targets: [...existingTargets, reverseTarget]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (path.modeluuid === toPathUUID) {
|
else if (path.type === 'Vehicle') {
|
||||||
return {
|
// Handle outgoing connections from Vehicle
|
||||||
...path,
|
if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) {
|
||||||
points: path.points.map(point => {
|
const newTarget = {
|
||||||
if (point.uuid === toPointUUID) {
|
pathUUID: toPathUUID,
|
||||||
const reverseTarget = {
|
pointUUID: toPointUUID
|
||||||
pathUUID: fromPathUUID,
|
};
|
||||||
pointUUID: fromPointUUID
|
const existingTargets = path.point.connections.targets || [];
|
||||||
};
|
|
||||||
const existingTargets = point.connections.targets || [];
|
|
||||||
|
|
||||||
if (!existingTargets.some(target =>
|
if (!existingTargets.some(target =>
|
||||||
target.pathUUID === reverseTarget.pathUUID &&
|
target.pathUUID === newTarget.pathUUID &&
|
||||||
target.pointUUID === reverseTarget.pointUUID
|
target.pointUUID === newTarget.pointUUID
|
||||||
)) {
|
)) {
|
||||||
return {
|
return {
|
||||||
...point,
|
...path,
|
||||||
connections: {
|
point: {
|
||||||
...point.connections,
|
...path.point,
|
||||||
targets: [...existingTargets, reverseTarget]
|
connections: {
|
||||||
}
|
...path.point.connections,
|
||||||
};
|
targets: [...existingTargets, newTarget]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return point;
|
}
|
||||||
})
|
}
|
||||||
};
|
// Handle incoming connections to Vehicle
|
||||||
|
else if (path.modeluuid === toPathUUID && path.point.uuid === toPointUUID) {
|
||||||
|
const reverseTarget = {
|
||||||
|
pathUUID: fromPathUUID,
|
||||||
|
pointUUID: fromPointUUID
|
||||||
|
};
|
||||||
|
const existingTargets = path.point.connections.targets || [];
|
||||||
|
|
||||||
|
if (!existingTargets.some(target =>
|
||||||
|
target.pathUUID === reverseTarget.pathUUID &&
|
||||||
|
target.pointUUID === reverseTarget.pointUUID
|
||||||
|
)) {
|
||||||
|
return {
|
||||||
|
...path,
|
||||||
|
point: {
|
||||||
|
...path.point,
|
||||||
|
connections: {
|
||||||
|
...path.point.connections,
|
||||||
|
targets: [...existingTargets, reverseTarget]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
});
|
});
|
||||||
|
@ -126,25 +179,43 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
if (intersects.length > 0) {
|
if (intersects.length > 0) {
|
||||||
const intersected = intersects[0].object;
|
const intersected = intersects[0].object;
|
||||||
|
|
||||||
if (intersected.name.includes("action-sphere")) {
|
if (intersected.name.includes("events-sphere")) {
|
||||||
const pathUUID = intersected.userData.path.modeluuid;
|
const pathUUID = intersected.userData.path.modeluuid;
|
||||||
const sphereUUID = intersected.uuid;
|
const sphereUUID = intersected.uuid;
|
||||||
const worldPosition = new THREE.Vector3();
|
const worldPosition = new THREE.Vector3();
|
||||||
intersected.getWorldPosition(worldPosition);
|
intersected.getWorldPosition(worldPosition);
|
||||||
|
|
||||||
const isStartOrEnd = intersected.userData.path.points.length > 0 && (
|
let isStartOrEnd = false;
|
||||||
sphereUUID === intersected.userData.path.points[0].uuid ||
|
|
||||||
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
|
if (intersected.userData.path.points) {
|
||||||
);
|
isStartOrEnd = intersected.userData.path.points.length > 0 && (
|
||||||
|
sphereUUID === intersected.userData.path.points[0].uuid ||
|
||||||
|
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
|
||||||
|
);
|
||||||
|
} else if (intersected.userData.path.point) {
|
||||||
|
isStartOrEnd = sphereUUID === intersected.userData.path.point.uuid;
|
||||||
|
}
|
||||||
|
|
||||||
if (pathUUID) {
|
if (pathUUID) {
|
||||||
// Check if sphere is already connected
|
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID);
|
||||||
const isAlreadyConnected = simulationPaths.some(path =>
|
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
|
||||||
path.points.some(point =>
|
|
||||||
point.uuid === sphereUUID &&
|
if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
|
||||||
point.connections.targets.length > 0
|
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) {
|
if (isAlreadyConnected) {
|
||||||
console.log("Sphere is already connected. Ignoring.");
|
console.log("Sphere is already connected. Ignoring.");
|
||||||
|
@ -211,6 +282,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const intersects = raycaster.intersectObjects(scene.children, true).filter((intersect) =>
|
const intersects = raycaster.intersectObjects(scene.children, true).filter((intersect) =>
|
||||||
!intersect.object.name.includes("Roof") &&
|
!intersect.object.name.includes("Roof") &&
|
||||||
|
!intersect.object.name.includes("agv-collider") &&
|
||||||
!intersect.object.name.includes("MeasurementReference") &&
|
!intersect.object.name.includes("MeasurementReference") &&
|
||||||
!intersect.object.userData.isPathObject &&
|
!intersect.object.userData.isPathObject &&
|
||||||
!(intersect.object.type === "GridHelper")
|
!(intersect.object.type === "GridHelper")
|
||||||
|
@ -229,7 +301,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
}
|
}
|
||||||
|
|
||||||
const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) =>
|
const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) =>
|
||||||
obj.object.name.includes("action-sphere")
|
obj.object.name.includes("events-sphere")
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sphereIntersects.length > 0) {
|
if (sphereIntersects.length > 0) {
|
||||||
|
@ -237,27 +309,45 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
const sphereUUID = sphere.uuid;
|
const sphereUUID = sphere.uuid;
|
||||||
const spherePosition = new THREE.Vector3();
|
const spherePosition = new THREE.Vector3();
|
||||||
sphere.getWorldPosition(spherePosition);
|
sphere.getWorldPosition(spherePosition);
|
||||||
const pathUUID = sphere.userData.path.modeluuid;
|
const pathData = sphere.userData.path;
|
||||||
|
const pathUUID = pathData.modeluuid;
|
||||||
|
|
||||||
const isStartOrEnd = sphere.userData.path.points.length > 0 && (
|
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected.pathUUID);
|
||||||
sphereUUID === sphere.userData.path.points[0].uuid ||
|
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
|
||||||
sphereUUID === sphere.userData.path.points[sphere.userData.path.points.length - 1].uuid
|
const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';
|
||||||
);
|
|
||||||
|
|
||||||
const isAlreadyConnected = simulationPaths.some(path =>
|
const isConnectable = (pathData.type === 'Vehicle' ||
|
||||||
path.points.some(point =>
|
(pathData.points.length > 0 && (
|
||||||
point.uuid === sphereUUID &&
|
sphereUUID === pathData.points[0].uuid ||
|
||||||
point.connections.targets.length > 0
|
sphereUUID === pathData.points[pathData.points.length - 1].uuid
|
||||||
)
|
))) && !isVehicleToVehicle;
|
||||||
);
|
|
||||||
|
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 (
|
if (
|
||||||
!isAlreadyConnected &&
|
!isAlreadyConnected &&
|
||||||
|
!isVehicleToVehicle &&
|
||||||
firstSelected.sphereUUID !== sphereUUID &&
|
firstSelected.sphereUUID !== sphereUUID &&
|
||||||
firstSelected.pathUUID !== pathUUID &&
|
firstSelected.pathUUID !== pathUUID &&
|
||||||
(firstSelected.isCorner || isStartOrEnd)
|
(firstSelected.isCorner || isConnectable)
|
||||||
) {
|
) {
|
||||||
snappedSphere = { sphereUUID, position: spherePosition, pathUUID, isCorner: isStartOrEnd };
|
snappedSphere = {
|
||||||
|
sphereUUID,
|
||||||
|
position: spherePosition,
|
||||||
|
pathUUID,
|
||||||
|
isCorner: isConnectable
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
isInvalidConnection = true;
|
isInvalidConnection = true;
|
||||||
}
|
}
|
||||||
|
@ -281,8 +371,13 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
end: point,
|
end: point,
|
||||||
mid: midPoint,
|
mid: midPoint,
|
||||||
});
|
});
|
||||||
|
console.log({
|
||||||
|
start: firstSelected.position,
|
||||||
|
end: point,
|
||||||
|
mid: midPoint,
|
||||||
|
});
|
||||||
|
|
||||||
setIsConnecting(true);
|
// setIsConnecting(true);
|
||||||
|
|
||||||
if (sphereIntersects.length > 0) {
|
if (sphereIntersects.length > 0) {
|
||||||
setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542');
|
setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542');
|
||||||
|
@ -299,13 +394,53 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Render connections from simulationPaths
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{simulationPaths.flatMap(path =>
|
{simulationPaths.flatMap(path => {
|
||||||
path.points.flatMap(point =>
|
if (path.type === 'Conveyor') {
|
||||||
point.connections.targets.map((target, index) => {
|
return path.points.flatMap(point =>
|
||||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
|
point.connections.targets.map((target, index) => {
|
||||||
|
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
||||||
|
if (targetPath?.type === 'Vehicle') return null;
|
||||||
|
|
||||||
|
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
|
||||||
|
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
||||||
|
|
||||||
|
if (fromSphere && toSphere) {
|
||||||
|
const fromWorldPosition = new THREE.Vector3();
|
||||||
|
const toWorldPosition = new THREE.Vector3();
|
||||||
|
fromSphere.getWorldPosition(fromWorldPosition);
|
||||||
|
toSphere.getWorldPosition(toWorldPosition);
|
||||||
|
|
||||||
|
const distance = fromWorldPosition.distanceTo(toWorldPosition);
|
||||||
|
const heightFactor = Math.max(0.5, distance * 0.2);
|
||||||
|
|
||||||
|
const midPoint = new THREE.Vector3(
|
||||||
|
(fromWorldPosition.x + toWorldPosition.x) / 2,
|
||||||
|
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
|
||||||
|
(fromWorldPosition.z + toWorldPosition.z) / 2
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QuadraticBezierLine
|
||||||
|
key={`${point.uuid}-${target.pointUUID}-${index}`}
|
||||||
|
start={fromWorldPosition.toArray()}
|
||||||
|
end={toWorldPosition.toArray()}
|
||||||
|
mid={midPoint.toArray()}
|
||||||
|
color="white"
|
||||||
|
lineWidth={4}
|
||||||
|
dashed
|
||||||
|
dashSize={0.75}
|
||||||
|
dashScale={20}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else if (path.type === 'Vehicle') {
|
||||||
|
return path.point.connections.targets.map((target, index) => {
|
||||||
|
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.point.uuid);
|
||||||
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
||||||
|
|
||||||
if (fromSphere && toSphere) {
|
if (fromSphere && toSphere) {
|
||||||
|
@ -325,22 +460,23 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QuadraticBezierLine
|
<QuadraticBezierLine
|
||||||
key={`${point.uuid}-${target.pointUUID}-${index}`}
|
key={`${path.point.uuid}-${target.pointUUID}-${index}`}
|
||||||
start={fromWorldPosition.toArray()}
|
start={fromWorldPosition.toArray()}
|
||||||
end={toWorldPosition.toArray()}
|
end={toWorldPosition.toArray()}
|
||||||
mid={midPoint.toArray()}
|
mid={midPoint.toArray()}
|
||||||
color="white"
|
color="orange"
|
||||||
lineWidth={4}
|
lineWidth={4}
|
||||||
dashed
|
dashed
|
||||||
dashSize={1}
|
dashSize={0.75}
|
||||||
dashScale={20}
|
dashScale={20}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
})
|
});
|
||||||
)
|
}
|
||||||
)}
|
return [];
|
||||||
|
})}
|
||||||
|
|
||||||
{currentLine && (
|
{currentLine && (
|
||||||
<QuadraticBezierLine
|
<QuadraticBezierLine
|
||||||
|
|
|
@ -4,10 +4,12 @@ import { Sphere, TransformControls } from '@react-three/drei';
|
||||||
import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
|
import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import { useSubModuleStore } from '../../../store/useModuleStore';
|
import { useSubModuleStore } from '../../../store/useModuleStore';
|
||||||
|
import { point } from '@turf/helpers';
|
||||||
|
|
||||||
interface Path {
|
interface ConveyorEventsSchema {
|
||||||
modeluuid: string;
|
modeluuid: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
|
type: 'Conveyor';
|
||||||
points: {
|
points: {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
|
@ -16,8 +18,8 @@ interface Path {
|
||||||
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
|
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
|
||||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||||
}[];
|
}[];
|
||||||
pathPosition: [number, number, number];
|
assetPosition: [number, number, number];
|
||||||
pathRotation: [number, number, number];
|
assetRotation: [number, number, number];
|
||||||
speed: number;
|
speed: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,99 +65,154 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
const updateSimulationPaths = () => {
|
const updateSimulationPaths = () => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths: Path[] = simulationPaths.map((path) => ({
|
const updatedPaths = simulationPaths.map((path) => {
|
||||||
...path,
|
if (path.type === "Conveyor") {
|
||||||
points: path.points.map((point) =>
|
return {
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
...path,
|
||||||
? {
|
points: path.points.map((point) =>
|
||||||
...point,
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
position: [
|
? {
|
||||||
selectedActionSphere.point.position.x,
|
...point,
|
||||||
selectedActionSphere.point.position.y,
|
position: [
|
||||||
selectedActionSphere.point.position.z,
|
selectedActionSphere.point.position.x,
|
||||||
],
|
selectedActionSphere.point.position.y,
|
||||||
rotation: [
|
selectedActionSphere.point.position.z,
|
||||||
selectedActionSphere.point.rotation.x,
|
],
|
||||||
selectedActionSphere.point.rotation.y,
|
rotation: [
|
||||||
selectedActionSphere.point.rotation.z,
|
selectedActionSphere.point.rotation.x,
|
||||||
]
|
selectedActionSphere.point.rotation.y,
|
||||||
}
|
selectedActionSphere.point.rotation.z,
|
||||||
: point
|
]
|
||||||
),
|
}
|
||||||
}));
|
: point
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}) as ConveyorEventsSchema[];
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group name='simulation-simulationPaths-group' ref={pathsGroupRef} >
|
<group name='simulation-simulationPaths-group' ref={pathsGroupRef}>
|
||||||
{simulationPaths.map((path) => {
|
{simulationPaths.map((path) => {
|
||||||
const points = path.points.map(point => new THREE.Vector3(...point.position));
|
if (path.type === 'Conveyor') {
|
||||||
|
const points = path.points.map(point => new THREE.Vector3(...point.position));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<group
|
||||||
name={`${path.modeluuid}-event-path`}
|
name={`${path.modeluuid}-event-path`}
|
||||||
key={path.modeluuid}
|
key={path.modeluuid}
|
||||||
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
||||||
position={path.pathPosition}
|
position={path.assetPosition}
|
||||||
rotation={path.pathRotation}
|
rotation={path.assetRotation}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (isConnecting) return;
|
if (isConnecting) return;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||||
setSelectedActionSphere(null);
|
setSelectedActionSphere(null);
|
||||||
setTransformMode(null);
|
setTransformMode(null);
|
||||||
setSubModule('mechanics');
|
setSubModule('mechanics');
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPath(null);
|
setSelectedPath(null);
|
||||||
setSubModule('properties');
|
setSubModule('properties');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{path.points.map((point, index) => (
|
{path.points.map((point, index) => (
|
||||||
|
<Sphere
|
||||||
|
key={point.uuid}
|
||||||
|
uuid={point.uuid}
|
||||||
|
position={point.position}
|
||||||
|
args={[0.15, 32, 32]}
|
||||||
|
name='events-sphere'
|
||||||
|
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (isConnecting) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedActionSphere({
|
||||||
|
path,
|
||||||
|
point: sphereRefs.current[point.uuid]
|
||||||
|
});
|
||||||
|
setSubModule('mechanics');
|
||||||
|
setSelectedPath(null);
|
||||||
|
}}
|
||||||
|
userData={{ point, path }}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
setSubModule('properties');
|
||||||
|
setSelectedActionSphere(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<meshStandardMaterial
|
||||||
|
color={index === 0 ? 'orange' : index === path.points.length - 1 ? 'blue' : 'green'}
|
||||||
|
/>
|
||||||
|
</Sphere>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{points.slice(0, -1).map((point, index) => {
|
||||||
|
const nextPoint = points[index + 1];
|
||||||
|
const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]);
|
||||||
|
const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh name='event-connection-tube' key={`tube-${index}`} geometry={tubeGeometry}>
|
||||||
|
<meshStandardMaterial transparent opacity={0.9} color="red" />
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
} else if (path.type === 'Vehicle') {
|
||||||
|
return (
|
||||||
|
<group
|
||||||
|
name={`${path.modeluuid}-vehicle-path`}
|
||||||
|
key={path.modeluuid}
|
||||||
|
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
||||||
|
position={path.assetPosition}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (isConnecting) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||||
|
setSelectedActionSphere(null);
|
||||||
|
setTransformMode(null);
|
||||||
|
setSubModule('mechanics');
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
setSelectedPath(null);
|
||||||
|
setSubModule('properties');
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Sphere
|
<Sphere
|
||||||
key={point.uuid}
|
key={path.point.uuid}
|
||||||
uuid={point.uuid}
|
uuid={path.point.uuid}
|
||||||
position={point.position}
|
position={path.point.position}
|
||||||
args={[0.15, 32, 32]}
|
args={[0.15, 32, 32]}
|
||||||
name='action-sphere'
|
name='events-sphere'
|
||||||
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
ref={el => (sphereRefs.current[path.point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (isConnecting) return;
|
if (isConnecting) return;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedActionSphere({
|
setSelectedActionSphere({
|
||||||
path,
|
path,
|
||||||
point: sphereRefs.current[point.uuid]
|
point: sphereRefs.current[path.point.uuid]
|
||||||
});
|
});
|
||||||
setSubModule('mechanics');
|
setSubModule('mechanics');
|
||||||
setSelectedPath(null);
|
setSelectedPath(null);
|
||||||
}}
|
}}
|
||||||
userData={{ point, path }}
|
userData={{ point: path.point, path }}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSubModule('properties');
|
setSubModule('properties');
|
||||||
setSelectedActionSphere(null)
|
setSelectedActionSphere(null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial color="purple" />
|
||||||
color={index === 0 ? 'orange' : index === path.points.length - 1 ? 'blue' : 'green'}
|
|
||||||
/>
|
|
||||||
</Sphere>
|
</Sphere>
|
||||||
))}
|
</group>
|
||||||
|
);
|
||||||
{points.slice(0, -1).map((point, index) => {
|
}
|
||||||
const nextPoint = points[index + 1];
|
return null;
|
||||||
const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]);
|
|
||||||
const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<mesh name='event-connection-tube' key={`tube-${index}`} geometry={tubeGeometry}>
|
|
||||||
<meshStandardMaterial transparent opacity={0.9} color="red" />
|
|
||||||
</mesh>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{selectedActionSphere && transformMode && (
|
{selectedActionSphere && transformMode && (
|
||||||
|
@ -163,7 +220,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
ref={transformRef}
|
ref={transformRef}
|
||||||
object={selectedActionSphere.point}
|
object={selectedActionSphere.point}
|
||||||
mode={transformMode}
|
mode={transformMode}
|
||||||
onObjectChange={updateSimulationPaths}
|
onMouseUp={updateSimulationPaths}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</group>
|
</group>
|
||||||
|
|
|
@ -31,7 +31,7 @@ function Simulation() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Behaviour setSimulationPaths={setSimulationPaths} />
|
<Behaviour/>
|
||||||
{activeModule === 'simulation' && (
|
{activeModule === 'simulation' && (
|
||||||
<>
|
<>
|
||||||
<PathCreation pathsGroupRef={pathsGroupRef} />
|
<PathCreation pathsGroupRef={pathsGroupRef} />
|
||||||
|
|
|
@ -1,409 +1,409 @@
|
||||||
import { useMemo, useState } from 'react';
|
// import { useMemo, useState } from 'react';
|
||||||
import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
|
// import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
|
||||||
import * as THREE from 'three';
|
// import * as THREE from 'three';
|
||||||
import useModuleStore from '../../store/useModuleStore';
|
// import useModuleStore from '../../store/useModuleStore';
|
||||||
|
|
||||||
function SimulationUI() {
|
// function SimulationUI() {
|
||||||
const { ToggleView } = useToggleView();
|
// const { ToggleView } = useToggleView();
|
||||||
const { activeModule } = useModuleStore();
|
// const { activeModule } = useModuleStore();
|
||||||
const { startSimulation, setStartSimulation } = useStartSimulation();
|
// const { startSimulation, setStartSimulation } = useStartSimulation();
|
||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
// const { selectedActionSphere } = useSelectedActionSphere();
|
||||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
// const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
// const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath();
|
// const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath();
|
||||||
const [activeButton, setActiveButton] = useState<string | null>(null);
|
// const [activeButton, setActiveButton] = useState<string | null>(null);
|
||||||
|
|
||||||
const handleAddAction = () => {
|
// const handleAddAction = () => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) => {
|
// points: path.points.map((point) => {
|
||||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
// if (point.uuid === selectedActionSphere.point.uuid) {
|
||||||
const actionIndex = point.actions.length;
|
// const actionIndex = point.actions.length;
|
||||||
const newAction = {
|
// const newAction = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
// uuid: THREE.MathUtils.generateUUID(),
|
||||||
name: `Action ${actionIndex + 1}`, // Assign action name based on index
|
// name: `Action ${actionIndex + 1}`, // Assign action name based on index
|
||||||
type: 'Inherit',
|
// type: 'Inherit',
|
||||||
material: 'Inherit',
|
// material: 'Inherit',
|
||||||
delay: 'Inherit',
|
// delay: 'Inherit',
|
||||||
spawnInterval: 'Inherit',
|
// spawnInterval: 'Inherit',
|
||||||
isUsed: false
|
// isUsed: false
|
||||||
};
|
// };
|
||||||
|
|
||||||
return { ...point, actions: [...point.actions, newAction] };
|
// return { ...point, actions: [...point.actions, newAction] };
|
||||||
}
|
// }
|
||||||
return point;
|
// return point;
|
||||||
}),
|
// }),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleDeleteAction = (uuid: string) => {
|
// const handleDeleteAction = (uuid: string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
// ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleActionSelect = (uuid: string, actionType: string) => {
|
// const handleActionSelect = (uuid: string, actionType: string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
// ? {
|
||||||
...point,
|
// ...point,
|
||||||
actions: point.actions.map((action) =>
|
// actions: point.actions.map((action) =>
|
||||||
action.uuid === uuid ? { ...action, type: actionType } : action
|
// action.uuid === uuid ? { ...action, type: actionType } : action
|
||||||
),
|
// ),
|
||||||
}
|
// }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleMaterialSelect = (uuid: string, material: string) => {
|
// const handleMaterialSelect = (uuid: string, material: string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
// ? {
|
||||||
...point,
|
// ...point,
|
||||||
actions: point.actions.map((action) =>
|
// actions: point.actions.map((action) =>
|
||||||
action.uuid === uuid ? { ...action, material } : action
|
// action.uuid === uuid ? { ...action, material } : action
|
||||||
),
|
// ),
|
||||||
}
|
// }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleDelayChange = (uuid: string, delay: number | string) => {
|
// const handleDelayChange = (uuid: string, delay: number | string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
// ? {
|
||||||
...point,
|
// ...point,
|
||||||
actions: point.actions.map((action) =>
|
// actions: point.actions.map((action) =>
|
||||||
action.uuid === uuid ? { ...action, delay } : action
|
// action.uuid === uuid ? { ...action, delay } : action
|
||||||
),
|
// ),
|
||||||
}
|
// }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
|
// const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
// ? {
|
||||||
...point,
|
// ...point,
|
||||||
actions: point.actions.map((action) =>
|
// actions: point.actions.map((action) =>
|
||||||
action.uuid === uuid ? { ...action, spawnInterval } : action
|
// action.uuid === uuid ? { ...action, spawnInterval } : action
|
||||||
),
|
// ),
|
||||||
}
|
// }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleSpeedChange = (speed: number) => {
|
// const handleSpeedChange = (speed: number) => {
|
||||||
if (!selectedPath) return;
|
// if (!selectedPath) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
// const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
// path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||||
);
|
// );
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
// setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleAddTrigger = () => {
|
// const handleAddTrigger = () => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) => {
|
// points: path.points.map((point) => {
|
||||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
// if (point.uuid === selectedActionSphere.point.uuid) {
|
||||||
const triggerIndex = point.triggers.length;
|
// const triggerIndex = point.triggers.length;
|
||||||
const newTrigger = {
|
// const newTrigger = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
// uuid: THREE.MathUtils.generateUUID(),
|
||||||
name: `Trigger ${triggerIndex + 1}`, // Assign name based on index
|
// name: `Trigger ${triggerIndex + 1}`, // Assign name based on index
|
||||||
type: '',
|
// type: '',
|
||||||
isUsed: false
|
// isUsed: false
|
||||||
};
|
// };
|
||||||
|
|
||||||
return { ...point, triggers: [...point.triggers, newTrigger] };
|
// return { ...point, triggers: [...point.triggers, newTrigger] };
|
||||||
}
|
// }
|
||||||
return point;
|
// return point;
|
||||||
}),
|
// }),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleDeleteTrigger = (uuid: string) => {
|
// const handleDeleteTrigger = (uuid: string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
// ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleTriggerSelect = (uuid: string, triggerType: string) => {
|
// const handleTriggerSelect = (uuid: string, triggerType: string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
// ? {
|
||||||
...point,
|
// ...point,
|
||||||
triggers: point.triggers.map((trigger) =>
|
// triggers: point.triggers.map((trigger) =>
|
||||||
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
|
// trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
|
||||||
),
|
// ),
|
||||||
}
|
// }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleResetPath = () => {
|
// const handleResetPath = () => {
|
||||||
if (!selectedPath) return;
|
// if (!selectedPath) return;
|
||||||
|
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
|
||||||
const handleActionToggle = (uuid: string) => {
|
// const handleActionToggle = (uuid: string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
// ? {
|
||||||
...point,
|
// ...point,
|
||||||
actions: point.actions.map((action) => ({
|
// actions: point.actions.map((action) => ({
|
||||||
...action,
|
// ...action,
|
||||||
isUsed: action.uuid === uuid ? !action.isUsed : false,
|
// isUsed: action.uuid === uuid ? !action.isUsed : false,
|
||||||
})),
|
// })),
|
||||||
}
|
// }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleTriggerToggle = (uuid: string) => {
|
// const handleTriggerToggle = (uuid: string) => {
|
||||||
if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
// ...path,
|
||||||
points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
// ? {
|
||||||
...point,
|
// ...point,
|
||||||
triggers: point.triggers.map((trigger) => ({
|
// triggers: point.triggers.map((trigger) => ({
|
||||||
...trigger,
|
// ...trigger,
|
||||||
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
// isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
||||||
})),
|
// })),
|
||||||
}
|
// }
|
||||||
: point
|
// : point
|
||||||
),
|
// ),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
// setSimulationPaths(updatedPaths);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const selectedPoint = useMemo(() => {
|
// const selectedPoint = useMemo(() => {
|
||||||
if (!selectedActionSphere) return null;
|
// if (!selectedActionSphere) return null;
|
||||||
return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
// return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||||
}, [selectedActionSphere, simulationPaths]);
|
// }, [selectedActionSphere, simulationPaths]);
|
||||||
|
|
||||||
const createPath = () => {
|
// const createPath = () => {
|
||||||
setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
|
// setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
|
||||||
setDrawMaterialPath(!drawMaterialPath);
|
// setDrawMaterialPath(!drawMaterialPath);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<>
|
// <>
|
||||||
{activeModule === "simulation" && (
|
// {activeModule === "simulation" && (
|
||||||
<div style={{ zIndex: 10, position: "fixed", width: '260px' }}>
|
// <div style={{ zIndex: 10, position: "fixed", width: '260px' }}>
|
||||||
{!ToggleView && (
|
// {!ToggleView && (
|
||||||
<>
|
// <>
|
||||||
<button
|
// <button
|
||||||
onClick={() => setStartSimulation(!startSimulation)}
|
// onClick={() => setStartSimulation(!startSimulation)}
|
||||||
style={{
|
// style={{
|
||||||
marginTop: "10px",
|
// marginTop: "10px",
|
||||||
background: startSimulation ? '#ff320e' : '',
|
// background: startSimulation ? '#ff320e' : '',
|
||||||
padding: "10px",
|
// padding: "10px",
|
||||||
borderRadius: "5px"
|
// borderRadius: "5px"
|
||||||
}}
|
// }}
|
||||||
>
|
// >
|
||||||
{startSimulation ? 'Stop Simulation' : 'Start Simulation'}
|
// {startSimulation ? 'Stop Simulation' : 'Start Simulation'}
|
||||||
</button>
|
// </button>
|
||||||
|
|
||||||
<div style={{ zIndex: "10", position: "relative" }}>
|
// <div style={{ zIndex: "10", position: "relative" }}>
|
||||||
{!ToggleView && <button onClick={createPath} style={{ marginTop: "10px", background: activeButton === 'addMaterialPath' ? '#ff320e' : '' }}> Add Material Path</button>}
|
// {!ToggleView && <button onClick={createPath} style={{ marginTop: "10px", background: activeButton === 'addMaterialPath' ? '#ff320e' : '' }}> Add Material Path</button>}
|
||||||
</div>
|
// </div>
|
||||||
|
|
||||||
{selectedPath && (
|
// {selectedPath && (
|
||||||
<div style={{ marginTop: "10px" }}>
|
// <div style={{ marginTop: "10px" }}>
|
||||||
<label>Path Speed:</label>
|
// <label>Path Speed:</label>
|
||||||
<input
|
// <input
|
||||||
style={{ width: '50px' }}
|
// style={{ width: '50px' }}
|
||||||
type="number"
|
// type="number"
|
||||||
value={selectedPath.path.speed}
|
// value={selectedPath.path.speed}
|
||||||
min="0.1"
|
// min="0.1"
|
||||||
step="0.1"
|
// step="0.1"
|
||||||
onChange={(e) => handleSpeedChange(parseFloat(e.target.value))}
|
// onChange={(e) => handleSpeedChange(parseFloat(e.target.value))}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
|
|
||||||
{selectedActionSphere && (
|
// {selectedActionSphere && (
|
||||||
<div style={{ marginTop: "10px" }}>
|
// <div style={{ marginTop: "10px" }}>
|
||||||
<button onClick={handleAddAction}>Add Action</button>
|
// <button onClick={handleAddAction}>Add Action</button>
|
||||||
<button onClick={handleAddTrigger}>Add Trigger</button>
|
// <button onClick={handleAddTrigger}>Add Trigger</button>
|
||||||
|
|
||||||
{selectedPoint?.actions.map((action) => (
|
// {selectedPoint?.actions.map((action) => (
|
||||||
<div key={action.uuid} style={{ marginTop: "10px" }}>
|
// <div key={action.uuid} style={{ marginTop: "10px" }}>
|
||||||
<select value={action.type} onChange={(e) => handleActionSelect(action.uuid, e.target.value)}>
|
// <select value={action.type} onChange={(e) => handleActionSelect(action.uuid, e.target.value)}>
|
||||||
<option value="Inherit">Inherit</option>
|
// <option value="Inherit">Inherit</option>
|
||||||
<option value="Spawn">Spawn Point</option>
|
// <option value="Spawn">Spawn Point</option>
|
||||||
<option value="Swap">Swap Material</option>
|
// <option value="Swap">Swap Material</option>
|
||||||
<option value="Despawn">Despawn Point</option>
|
// <option value="Despawn">Despawn Point</option>
|
||||||
<option value="Delay">Delay</option>
|
// <option value="Delay">Delay</option>
|
||||||
</select>
|
// </select>
|
||||||
<button onClick={() => handleDeleteAction(action.uuid)}>Delete Action</button>
|
// <button onClick={() => handleDeleteAction(action.uuid)}>Delete Action</button>
|
||||||
<label>
|
// <label>
|
||||||
<input
|
// <input
|
||||||
type="checkbox"
|
// type="checkbox"
|
||||||
checked={action.isUsed}
|
// checked={action.isUsed}
|
||||||
onChange={() => handleActionToggle(action.uuid)}
|
// onChange={() => handleActionToggle(action.uuid)}
|
||||||
/>
|
// />
|
||||||
</label>
|
// </label>
|
||||||
|
|
||||||
{(action.type === 'Spawn' || action.type === 'Swap') && (
|
// {(action.type === 'Spawn' || action.type === 'Swap') && (
|
||||||
<div style={{ marginTop: "10px" }}>
|
// <div style={{ marginTop: "10px" }}>
|
||||||
<select value={action.material} onChange={(e) => handleMaterialSelect(action.uuid, e.target.value)}>
|
// <select value={action.material} onChange={(e) => handleMaterialSelect(action.uuid, e.target.value)}>
|
||||||
<option value="Inherit">Inherit</option>
|
// <option value="Inherit">Inherit</option>
|
||||||
<option value="Crate">Crate</option>
|
// <option value="Crate">Crate</option>
|
||||||
<option value="Box">Box</option>
|
// <option value="Box">Box</option>
|
||||||
</select>
|
// </select>
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
|
|
||||||
{action.type === 'Delay' && (
|
// {action.type === 'Delay' && (
|
||||||
<div style={{ marginTop: "10px" }}>
|
// <div style={{ marginTop: "10px" }}>
|
||||||
<label>Delay Time:</label>
|
// <label>Delay Time:</label>
|
||||||
<input
|
// <input
|
||||||
style={{ width: '50px' }}
|
// style={{ width: '50px' }}
|
||||||
type="text"
|
// type="text"
|
||||||
value={isNaN(Number(action.delay)) || action.delay === "Inherit" ? "Inherit" : action.delay}
|
// value={isNaN(Number(action.delay)) || action.delay === "Inherit" ? "Inherit" : action.delay}
|
||||||
min="1"
|
// min="1"
|
||||||
onChange={(e) => handleDelayChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
|
// onChange={(e) => handleDelayChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
|
||||||
/>
|
// />
|
||||||
|
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
|
|
||||||
{action.type === 'Spawn' && (
|
// {action.type === 'Spawn' && (
|
||||||
<div style={{ marginTop: "10px" }}>
|
// <div style={{ marginTop: "10px" }}>
|
||||||
<label>Spawn Interval:</label>
|
// <label>Spawn Interval:</label>
|
||||||
<input
|
// <input
|
||||||
style={{ width: '50px' }}
|
// style={{ width: '50px' }}
|
||||||
type="text"
|
// type="text"
|
||||||
value={isNaN(Number(action.spawnInterval)) || action.spawnInterval === "Inherit" ? "Inherit" : action.spawnInterval}
|
// value={isNaN(Number(action.spawnInterval)) || action.spawnInterval === "Inherit" ? "Inherit" : action.spawnInterval}
|
||||||
min="1"
|
// min="1"
|
||||||
onChange={(e) => handleSpawnIntervalChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
|
// onChange={(e) => handleSpawnIntervalChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
|
||||||
/>
|
// />
|
||||||
|
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
<hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
|
// <hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
|
||||||
</div>
|
// </div>
|
||||||
))}
|
// ))}
|
||||||
|
|
||||||
<hr style={{ margin: "10px 0", border: "1px solid black" }} />
|
// <hr style={{ margin: "10px 0", border: "1px solid black" }} />
|
||||||
|
|
||||||
{selectedPoint?.triggers.map((trigger) => (
|
// {selectedPoint?.triggers.map((trigger) => (
|
||||||
<div key={trigger.uuid} style={{ marginTop: "10px" }}>
|
// <div key={trigger.uuid} style={{ marginTop: "10px" }}>
|
||||||
<select value={trigger.type} onChange={(e) => handleTriggerSelect(trigger.uuid, e.target.value)}>
|
// <select value={trigger.type} onChange={(e) => handleTriggerSelect(trigger.uuid, e.target.value)}>
|
||||||
<option value="">Select Trigger Type</option>
|
// <option value="">Select Trigger Type</option>
|
||||||
<option value="On-Hit">On Hit</option>
|
// <option value="On-Hit">On Hit</option>
|
||||||
<option value="Buffer">Buffer</option>
|
// <option value="Buffer">Buffer</option>
|
||||||
</select>
|
// </select>
|
||||||
<button onClick={() => handleDeleteTrigger(trigger.uuid)}>Delete Trigger</button>
|
// <button onClick={() => handleDeleteTrigger(trigger.uuid)}>Delete Trigger</button>
|
||||||
<label>
|
// <label>
|
||||||
<input
|
// <input
|
||||||
type="checkbox"
|
// type="checkbox"
|
||||||
checked={trigger.isUsed}
|
// checked={trigger.isUsed}
|
||||||
onChange={() => handleTriggerToggle(trigger.uuid)}
|
// onChange={() => handleTriggerToggle(trigger.uuid)}
|
||||||
/>
|
// />
|
||||||
</label>
|
// </label>
|
||||||
<hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
|
// <hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
|
||||||
</div>
|
// </div>
|
||||||
))}
|
// ))}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
|
|
||||||
{selectedPath && (
|
// {selectedPath && (
|
||||||
<div style={{ marginTop: "10px" }}>
|
// <div style={{ marginTop: "10px" }}>
|
||||||
<button
|
// <button
|
||||||
onClick={handleResetPath}
|
// onClick={handleResetPath}
|
||||||
style={{ padding: "10px", borderRadius: "5px", background: "#ff0000", color: "#fff" }}
|
// style={{ padding: "10px", borderRadius: "5px", background: "#ff0000", color: "#fff" }}
|
||||||
>
|
// >
|
||||||
Reset Path
|
// Reset Path
|
||||||
</button>
|
// </button>
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
</>
|
// </>
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default SimulationUI;
|
// export default SimulationUI;
|
|
@ -64,7 +64,6 @@ const Project: React.FC = () => {
|
||||||
{activeModule === "market" && <MarketPlace />}
|
{activeModule === "market" && <MarketPlace />}
|
||||||
<RealTimeVisulization />
|
<RealTimeVisulization />
|
||||||
{activeModule !== "market" && <Tools />}
|
{activeModule !== "market" && <Tools />}
|
||||||
{/* <SimulationUI /> */}
|
|
||||||
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
|
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,10 +6,7 @@ const MqttEvents = () => {
|
||||||
const { setTouch, setTemperature, setHumidity } = useDrieUIValue();
|
const { setTouch, setTemperature, setHumidity } = useDrieUIValue();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
const client = mqtt.connect("ws://192.168.0.192:1884", {
|
const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`);
|
||||||
username: "gabby",
|
|
||||||
password: "gabby"
|
|
||||||
});
|
|
||||||
|
|
||||||
client.subscribe("touch");
|
client.subscribe("touch");
|
||||||
client.subscribe("temperature");
|
client.subscribe("temperature");
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
export const getAssetDetails = async (filename: string) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${BackEnd_url}/api/v1/assetDetails`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ filename }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to fetch asset details");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error: any) {
|
||||||
|
// console.error("Error fetching category:", error.message);
|
||||||
|
throw new Error(error.message);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,16 @@
|
||||||
|
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
export const fetchAssets = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${BackEnd_url}/api/v1/getAllAssets`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Network response was not ok");
|
||||||
|
}
|
||||||
|
const result = await response.json();
|
||||||
|
const last10Assets = result.slice(-10);
|
||||||
|
console.log('last10Assets: ', last10Assets);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error: ", error);
|
||||||
|
// throw new Error(error.message);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,7 @@
|
||||||
|
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
export const fetchGltfUrl = (filename: string) => {
|
||||||
|
if (filename) {
|
||||||
|
return `${BackEnd_url}/api/v1/getAssetFile/${filename}`;
|
||||||
|
}
|
||||||
|
return null; // or handle the case when filename is not provided
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
export const getAssetDownload = (filename: any) => {
|
||||||
|
return `${BackEnd_url}/api/v1/getAssetFile/${filename}.gltf`;
|
||||||
|
};
|
|
@ -0,0 +1,25 @@
|
||||||
|
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
export const getSortedAssets = async (category: any, orders: any) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${BackEnd_url}/api/v1/categoryWise/${category}?sortBy=${orders}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Error: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
return result; // Return the result to be used later
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error("Error fetching category:", error.message);
|
||||||
|
throw new Error(error.message);
|
||||||
|
}
|
||||||
|
};
|
|
@ -2,7 +2,6 @@ import * as THREE from "three";
|
||||||
import * as Types from "../types/world/worldTypes";
|
import * as Types from "../types/world/worldTypes";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
import { ComponentType, SVGProps } from "react";
|
|
||||||
|
|
||||||
export const useSocketStore = create<any>((set: any, get: any) => ({
|
export const useSocketStore = create<any>((set: any, get: any) => ({
|
||||||
socket: null,
|
socket: null,
|
||||||
|
@ -30,10 +29,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useLoadingProgress = create<{
|
export const useLoadingProgress = create<{ loadingProgress: number; setLoadingProgress: (x: number) => void }>((set) => ({
|
||||||
loadingProgress: number;
|
|
||||||
setLoadingProgress: (x: number) => void;
|
|
||||||
}>((set) => ({
|
|
||||||
loadingProgress: 1,
|
loadingProgress: 1,
|
||||||
setLoadingProgress: (x: number) => set({ loadingProgress: x }),
|
setLoadingProgress: (x: number) => set({ loadingProgress: x }),
|
||||||
}));
|
}));
|
||||||
|
@ -314,45 +310,14 @@ export const useSelectedPath = create<any>((set: any) => ({
|
||||||
setSelectedPath: (x: any) => set({ selectedPath: x }),
|
setSelectedPath: (x: any) => set({ selectedPath: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface Path {
|
|
||||||
modeluuid: string;
|
|
||||||
modelName: string;
|
|
||||||
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 }[];
|
|
||||||
};
|
|
||||||
}[];
|
|
||||||
pathPosition: [number, number, number];
|
|
||||||
pathRotation: [number, number, number];
|
|
||||||
speed: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SimulationPathsStore {
|
interface SimulationPathsStore {
|
||||||
simulationPaths: Path[];
|
simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[];
|
||||||
setSimulationPaths: (paths: Path[]) => void;
|
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
||||||
simulationPaths: [],
|
simulationPaths: [],
|
||||||
setSimulationPaths: (paths: Path[]) => set({ simulationPaths: paths }),
|
setSimulationPaths: (paths) => set({ simulationPaths: paths }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useIsConnecting = create<any>((set: any) => ({
|
export const useIsConnecting = create<any>((set: any) => ({
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
background-color: var(--background-color-secondary);
|
background-color: var(--background-color-secondary);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
top: 0;
|
||||||
padding: 100px 50px;
|
padding: 100px 50px;
|
||||||
padding-bottom: 32px;
|
padding-bottom: 32px;
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
|
@ -89,6 +90,7 @@
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-weight: $medium-weight;
|
font-weight: $medium-weight;
|
||||||
font-size: $xlarge;
|
font-size: $xlarge;
|
||||||
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cards-wrapper-container {
|
.cards-wrapper-container {
|
||||||
|
@ -122,7 +124,15 @@
|
||||||
.image-container {
|
.image-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
max-height: 180px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
border-radius: #{$border-radius-medium};
|
||||||
|
overflow: hidden;
|
||||||
|
img{
|
||||||
|
height: inherit;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.assets-container {
|
.assets-container {
|
||||||
|
@ -133,6 +143,9 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 3px;
|
gap: 3px;
|
||||||
|
.assets-name{
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
.asstes-container {
|
.asstes-container {
|
||||||
font-weight: #{$bold-weight};
|
font-weight: #{$bold-weight};
|
||||||
|
@ -200,7 +213,7 @@
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
z-index: 100;
|
overflow: hidden;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,3 +285,35 @@ interface ConnectionStore {
|
||||||
addConnection: (newConnection: PathConnection) => void;
|
addConnection: (newConnection: PathConnection) => void;
|
||||||
removeConnection: (fromUUID: string, toUUID: string) => void;
|
removeConnection: (fromUUID: string, toUUID: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VehicleEventsSchema {
|
||||||
|
modeluuid: string;
|
||||||
|
modelName: string;
|
||||||
|
type: 'Vehicle';
|
||||||
|
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 }[] | [];
|
||||||
|
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||||
|
};
|
||||||
|
assetPosition: [number, number, number];
|
||||||
|
speed: number;
|
||||||
|
}
|
Loading…
Reference in New Issue