updated realTimeViz panel style
This commit is contained in:
commit
4a05bb8cdf
2
app/.env
2
app/.env
|
@ -11,7 +11,7 @@ REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000
|
||||||
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011
|
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011
|
||||||
|
|
||||||
# Base URL for the asset library server, used for asset library images and model blob id.
|
# Base URL for the asset library server, used for asset library images and model blob id.
|
||||||
REACT_APP_SERVER_ASSET_LIBRARY_URL=192.168.0.111:3501
|
REACT_APP_SERVER_ASSET_LIBRARY_URL=185.100.212.76:50011
|
||||||
|
|
||||||
# base url for IoT socket server
|
# base url for IoT socket server
|
||||||
REACT_APP_IOT_SOCKET_SERVER_URL =185.100.212.76:5010
|
REACT_APP_IOT_SOCKET_SERVER_URL =185.100.212.76:5010
|
||||||
|
|
Binary file not shown.
|
@ -30,14 +30,13 @@ interface ProductionCapacityProps {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
onContextMenu?: (event: React.MouseEvent) => void;
|
onContextMenu?: (event: React.MouseEvent) => void;
|
||||||
// onPointerDown:any
|
// onPointerDown:any
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, position, onContextMenu }) => {
|
const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, position, rotation, onContextMenu }) => {
|
||||||
|
|
||||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
const [measurements, setmeasurements] = useState<any>({});
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
const [duration, setDuration] = useState("1h")
|
const [duration, setDuration] = useState("1h")
|
||||||
|
@ -158,10 +157,10 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, posit
|
||||||
setDuration(response.data.Data.duration)
|
setDuration(response.data.Data.duration)
|
||||||
setName(response.data.widgetName)
|
setName(response.data.widgetName)
|
||||||
} else {
|
} else {
|
||||||
console.log("Unexpected response:", response);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("There was an error!", error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,15 +176,42 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, posit
|
||||||
}
|
}
|
||||||
, [chartMeasurements, chartDuration, widgetName])
|
, [chartMeasurements, chartDuration, widgetName])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
|
||||||
|
}, [rotation])
|
||||||
|
const rotationDegrees = {
|
||||||
|
x: (rotation[0] * 180) / Math.PI,
|
||||||
|
y: (rotation[1] * 180) / Math.PI,
|
||||||
|
z: (rotation[2] * 180) / Math.PI,
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformStyle = {
|
||||||
|
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html position={[position[0], position[1], position[2]]}
|
<Html position={position}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
zIndexRange={[1, 0]}
|
|
||||||
transform
|
transform
|
||||||
sprite>
|
sprite
|
||||||
|
zIndexRange={[1,0]}
|
||||||
|
// center
|
||||||
|
// distanceFactor={10} // Adjusted for visual balance
|
||||||
|
style={{
|
||||||
|
transform: transformStyle.transform,
|
||||||
|
transformStyle: 'preserve-3d',
|
||||||
|
transition: 'transform 0.1s ease-out'
|
||||||
|
}}>
|
||||||
<div className="productionCapacity-wrapper card"
|
<div className="productionCapacity-wrapper card"
|
||||||
onClick={() => setSelectedChartId({ id: id, type: type })}
|
onClick={() => setSelectedChartId({ id: id, type: type })}
|
||||||
onContextMenu={onContextMenu}
|
onContextMenu={onContextMenu}
|
||||||
|
style={{
|
||||||
|
width: '300px', // Original width
|
||||||
|
height: '300px', // Original height
|
||||||
|
transform: transformStyle.transform,
|
||||||
|
transformStyle: 'preserve-3d'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="headeproductionCapacityr-wrapper">
|
<div className="headeproductionCapacityr-wrapper">
|
||||||
<div className="header">Production Capacity</div>
|
<div className="header">Production Capacity</div>
|
||||||
|
|
|
@ -43,9 +43,10 @@ interface ReturnOfInvestmentProps {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
onContextMenu?: (event: React.MouseEvent) => void;
|
onContextMenu?: (event: React.MouseEvent) => void;
|
||||||
}
|
}
|
||||||
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, position, onContextMenu }) => {
|
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, position, rotation, onContextMenu }) => {
|
||||||
|
|
||||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||||
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
|
@ -203,13 +204,29 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, [chartMeasurements, chartDuration, widgetName])
|
, [chartMeasurements, chartDuration, widgetName])
|
||||||
|
const rotationDegrees = {
|
||||||
|
x: (rotation[0] * 180) / Math.PI,
|
||||||
|
y: (rotation[1] * 180) / Math.PI,
|
||||||
|
z: (rotation[2] * 180) / Math.PI,
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformStyle = {
|
||||||
|
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html position={[position[0], position[1], position[2]]}
|
<Html position={[position[0], position[1], position[2]]}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
transform
|
transform
|
||||||
zIndexRange={[1, 0]}
|
zIndexRange={[1, 0]}
|
||||||
sprite>
|
sprite
|
||||||
|
style={{
|
||||||
|
transform: transformStyle.transform,
|
||||||
|
transformStyle: 'preserve-3d',
|
||||||
|
transition: 'transform 0.1s ease-out'
|
||||||
|
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="returnOfInvestment card"
|
<div className="returnOfInvestment card"
|
||||||
onClick={() => setSelectedChartId({ id: id, type: type })}
|
onClick={() => setSelectedChartId({ id: id, type: type })}
|
||||||
onContextMenu={onContextMenu}
|
onContextMenu={onContextMenu}
|
||||||
|
|
|
@ -10,9 +10,10 @@ interface StateWorkingProps {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
onContextMenu?: (event: React.MouseEvent) => void;
|
onContextMenu?: (event: React.MouseEvent) => void;
|
||||||
}
|
}
|
||||||
const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onContextMenu }) => {
|
const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotation, onContextMenu }) => {
|
||||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||||
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
const [measurements, setmeasurements] = useState<any>({});
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
|
@ -45,7 +46,7 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onConte
|
||||||
socket.on("connect", startStream);
|
socket.on("connect", startStream);
|
||||||
socket.on("lastOutput", (response) => {
|
socket.on("lastOutput", (response) => {
|
||||||
const responseData = response;
|
const responseData = response;
|
||||||
console.log("responceeeeeeeeeee", response);
|
|
||||||
|
|
||||||
setDatas(responseData);
|
setDatas(responseData);
|
||||||
});
|
});
|
||||||
|
@ -75,7 +76,7 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onConte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("dataaaaa", datas);
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -89,13 +90,28 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onConte
|
||||||
}
|
}
|
||||||
, [chartMeasurements, chartDuration, widgetName])
|
, [chartMeasurements, chartDuration, widgetName])
|
||||||
|
|
||||||
|
const rotationDegrees = {
|
||||||
|
x: (rotation[0] * 180) / Math.PI,
|
||||||
|
y: (rotation[1] * 180) / Math.PI,
|
||||||
|
z: (rotation[2] * 180) / Math.PI,
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformStyle = {
|
||||||
|
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Html position={[position[0], position[1], position[2]]}
|
<Html position={[position[0], position[1], position[2]]}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
transform
|
transform
|
||||||
zIndexRange={[1, 0]}
|
zIndexRange={[1, 0]}
|
||||||
sprite>
|
sprite
|
||||||
|
style={{
|
||||||
|
transform: transformStyle.transform,
|
||||||
|
transformStyle: 'preserve-3d',
|
||||||
|
transition: 'transform 0.1s ease-out'
|
||||||
|
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="stateWorking-wrapper card"
|
<div className="stateWorking-wrapper card"
|
||||||
onClick={() => setSelectedChartId({ id: id, type: type })}
|
onClick={() => setSelectedChartId({ id: id, type: type })}
|
||||||
onContextMenu={onContextMenu}
|
onContextMenu={onContextMenu}
|
||||||
|
|
|
@ -45,10 +45,11 @@ interface ThroughputProps {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
onContextMenu?: (event: React.MouseEvent) => void;
|
onContextMenu?: (event: React.MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Throughput: React.FC<ThroughputProps> = ({ id, type, position, onContextMenu }) => {
|
const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, onContextMenu }) => {
|
||||||
|
|
||||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||||
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
|
@ -183,13 +184,29 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, onContextMe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, [chartMeasurements, chartDuration, widgetName])
|
, [chartMeasurements, chartDuration, widgetName])
|
||||||
|
const rotationDegrees = {
|
||||||
|
x: (rotation[0] * 180) / Math.PI,
|
||||||
|
y: (rotation[1] * 180) / Math.PI,
|
||||||
|
z: (rotation[2] * 180) / Math.PI,
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformStyle = {
|
||||||
|
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html position={[position[0], position[1], position[2]]}
|
<Html position={[position[0], position[1], position[2]]}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
transform
|
transform
|
||||||
zIndexRange={[1, 0]}
|
zIndexRange={[1, 0]}
|
||||||
sprite>
|
sprite
|
||||||
|
style={{
|
||||||
|
transform: transformStyle.transform,
|
||||||
|
transformStyle: 'preserve-3d',
|
||||||
|
transition: 'transform 0.1s ease-out'
|
||||||
|
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="throughput-wrapper"
|
<div className="throughput-wrapper"
|
||||||
onClick={() => setSelectedChartId({ id: id, type: type })}
|
onClick={() => setSelectedChartId({ id: id, type: type })}
|
||||||
onContextMenu={onContextMenu}
|
onContextMenu={onContextMenu}
|
||||||
|
|
|
@ -13,7 +13,8 @@ import {
|
||||||
useFloorItems,
|
useFloorItems,
|
||||||
useSelectedActionSphere,
|
useSelectedActionSphere,
|
||||||
useSelectedPath,
|
useSelectedPath,
|
||||||
useSimulationPaths,
|
useSimulationStates,
|
||||||
|
useSocketStore,
|
||||||
} from "../../../../store/store";
|
} 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";
|
||||||
|
@ -24,44 +25,53 @@ import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAss
|
||||||
const ConveyorMechanics: React.FC = () => {
|
const ConveyorMechanics: React.FC = () => {
|
||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
const { selectedActionSphere } = useSelectedActionSphere();
|
||||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
|
||||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const selectedPoint = useMemo(() => {
|
const selectedPoint = useMemo(() => {
|
||||||
if (!selectedActionSphere) return null;
|
if (!selectedActionSphere) return null;
|
||||||
return simulationPaths
|
return simulationStates
|
||||||
.filter(
|
.filter(
|
||||||
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
|
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
|
||||||
)
|
)
|
||||||
.flatMap((path) => path.points)
|
.flatMap((path) => path.points)
|
||||||
.find((point) => point.uuid === selectedActionSphere.point.uuid);
|
.find((point) => point.uuid === selectedActionSphere.points.uuid);
|
||||||
}, [selectedActionSphere, simulationPaths]);
|
}, [selectedActionSphere, simulationStates]);
|
||||||
|
|
||||||
const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => {
|
const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => {
|
||||||
if (!updatedPath) return;
|
if (!updatedPath) return;
|
||||||
// const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
// const organization = email ? email.split("@")[1].split(".")[0] : "";
|
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||||
// console.log('updatedPath: ', updatedPath);
|
|
||||||
// const a = await setEventApi(
|
// await setEventApi(
|
||||||
// organization,
|
// organization,
|
||||||
// updatedPath.modeluuid,
|
// updatedPath.modeluuid,
|
||||||
// updatedPath.points
|
// { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
|
||||||
// );
|
// );
|
||||||
// console.log('a: ', a);
|
|
||||||
|
const data = {
|
||||||
|
organization: organization,
|
||||||
|
modeluuid: updatedPath.modeluuid,
|
||||||
|
eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v2:model-asset:updateEventData', data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAddAction = () => {
|
const handleAddAction = () => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => {
|
const updatedPaths = simulationStates.map((path) => {
|
||||||
if (path.type === "Conveyor") {
|
if (path.type === "Conveyor") {
|
||||||
return {
|
return {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) => {
|
points: path.points.map((point) => {
|
||||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
if (point.uuid === selectedActionSphere.points.uuid) {
|
||||||
const actionIndex = point.actions.length;
|
const actionIndex = point.actions.length;
|
||||||
const newAction = {
|
const newAction = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -86,23 +96,23 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteAction = (uuid: string) => {
|
const handleDeleteAction = (uuid: string) => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.filter(
|
actions: point.actions.filter(
|
||||||
|
@ -119,23 +129,23 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(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 = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) =>
|
actions: point.actions.map((action) =>
|
||||||
|
@ -167,12 +177,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
|
|
||||||
// Update the selected item to reflect changes
|
// Update the selected item to reflect changes
|
||||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||||
|
@ -181,7 +191,7 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
|
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
|
||||||
)
|
)
|
||||||
.flatMap((path) => path.points)
|
.flatMap((path) => path.points)
|
||||||
.find((p) => p.uuid === selectedActionSphere.point.uuid)
|
.find((p) => p.uuid === selectedActionSphere.points.uuid)
|
||||||
?.actions.find((a) => a.uuid === uuid);
|
?.actions.find((a) => a.uuid === uuid);
|
||||||
|
|
||||||
if (updatedAction) {
|
if (updatedAction) {
|
||||||
|
@ -197,12 +207,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
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 = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) =>
|
actions: point.actions.map((action) =>
|
||||||
|
@ -222,12 +232,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
|
|
||||||
// Update selected item if it's the current action
|
// Update selected item if it's the current action
|
||||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||||
|
@ -244,12 +254,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
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 = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) =>
|
actions: point.actions.map((action) =>
|
||||||
|
@ -266,12 +276,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSpawnIntervalChange = (
|
const handleSpawnIntervalChange = (
|
||||||
|
@ -280,12 +290,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
) => {
|
) => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) =>
|
actions: point.actions.map((action) =>
|
||||||
|
@ -304,18 +314,18 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSpeedChange = (speed: number | string) => {
|
const handleSpeedChange = (speed: number | string) => {
|
||||||
if (!selectedPath) return;
|
if (!selectedPath) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationStates.map((path) =>
|
||||||
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -323,24 +333,24 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(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 = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) => {
|
points: path.points.map((point) => {
|
||||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
if (point.uuid === selectedActionSphere.points.uuid) {
|
||||||
const triggerIndex = point.triggers.length;
|
const triggerIndex = point.triggers.length;
|
||||||
const newTrigger = {
|
const newTrigger = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -362,23 +372,23 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteTrigger = (uuid: string) => {
|
const handleDeleteTrigger = (uuid: string) => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
triggers: point.triggers.filter(
|
triggers: point.triggers.filter(
|
||||||
|
@ -395,23 +405,23 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(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 = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
triggers: point.triggers.map((trigger) =>
|
triggers: point.triggers.map((trigger) =>
|
||||||
|
@ -430,12 +440,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
|
|
||||||
// Ensure the selectedItem is updated immediately
|
// Ensure the selectedItem is updated immediately
|
||||||
const updatedTrigger = updatedPaths
|
const updatedTrigger = updatedPaths
|
||||||
|
@ -451,12 +461,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
// Update the toggle handlers to immediately update the selected item
|
// Update the toggle handlers to immediately update the selected item
|
||||||
const handleActionToggle = (uuid: string) => {
|
const handleActionToggle = (uuid: string) => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) => ({
|
actions: point.actions.map((action) => ({
|
||||||
|
@ -474,12 +484,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
|
|
||||||
// Immediately update the selected item if it's the one being toggled
|
// Immediately update the selected item if it's the one being toggled
|
||||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||||
|
@ -497,12 +507,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const handleTriggerToggle = (uuid: string) => {
|
const handleTriggerToggle = (uuid: string) => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
triggers: point.triggers.map((trigger) => ({
|
triggers: point.triggers.map((trigger) => ({
|
||||||
|
@ -520,12 +530,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
|
|
||||||
// Immediately update the selected item if it's the one being toggled
|
// Immediately update the selected item if it's the one being toggled
|
||||||
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
|
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
|
||||||
|
@ -542,12 +552,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => {
|
const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationStates.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
triggers: point.triggers.map((trigger) =>
|
triggers: point.triggers.map((trigger) =>
|
||||||
|
@ -566,12 +576,12 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
(path): path is Types.ConveyorEventsSchema =>
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
path.type === "Conveyor" &&
|
path.type === "Conveyor" &&
|
||||||
path.points.some(
|
path.points.some(
|
||||||
(point) => point.uuid === selectedActionSphere.point.uuid
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
updateBackend(updatedPath);
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
|
|
||||||
// Immediately update selectedItem if it's the currently selected trigger
|
// Immediately update selectedItem if it's the currently selected trigger
|
||||||
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
|
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
|
||||||
|
|
|
@ -1,56 +1,79 @@
|
||||||
import React, { useRef, useMemo } from "react";
|
import React, { useRef, useMemo } from "react";
|
||||||
import { InfoIcon } from "../../../icons/ExportCommonIcons";
|
import { InfoIcon } from "../../../icons/ExportCommonIcons";
|
||||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||||
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
|
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store";
|
||||||
import * as Types from '../../../../types/world/worldTypes';
|
import * as Types from '../../../../types/world/worldTypes';
|
||||||
import PositionInput from "../customInput/PositionInputs";
|
import PositionInput from "../customInput/PositionInputs";
|
||||||
|
import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
|
||||||
|
|
||||||
const VehicleMechanics: React.FC = () => {
|
const VehicleMechanics: React.FC = () => {
|
||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
const { selectedActionSphere } = useSelectedActionSphere();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
||||||
const { editingPoint, setEditingPoint } = useEditingPoint();
|
const { editingPoint, setEditingPoint } = useEditingPoint();
|
||||||
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
|
||||||
const propertiesContainerRef = useRef<HTMLDivElement>(null);
|
const propertiesContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { selectedPoint, connectedPointUuids } = useMemo(() => {
|
const { selectedPoint, connectedPointUuids } = useMemo(() => {
|
||||||
if (!selectedActionSphere?.point?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
|
if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
|
||||||
|
|
||||||
const vehiclePaths = simulationPaths.filter(
|
const vehiclePaths = simulationStates.filter(
|
||||||
(path): path is Types.VehicleEventsSchema => path.type === "Vehicle"
|
(path): path is Types.VehicleEventsSchema => path.type === "Vehicle"
|
||||||
);
|
);
|
||||||
|
|
||||||
const point = vehiclePaths.find(
|
const points = vehiclePaths.find(
|
||||||
(path) => path.point.uuid === selectedActionSphere.point.uuid
|
(path) => path.points.uuid === selectedActionSphere.points.uuid
|
||||||
)?.point;
|
)?.points;
|
||||||
|
|
||||||
if (!point) return { selectedPoint: null, connectedPointUuids: [] };
|
if (!points) return { selectedPoint: null, connectedPointUuids: [] };
|
||||||
|
|
||||||
const connectedUuids: string[] = [];
|
const connectedUuids: string[] = [];
|
||||||
if (point.connections?.targets) {
|
if (points.connections?.targets) {
|
||||||
point.connections.targets.forEach(target => {
|
points.connections.targets.forEach(target => {
|
||||||
connectedUuids.push(target.pointUUID);
|
connectedUuids.push(target.pointUUID);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedPoint: point,
|
selectedPoint: points,
|
||||||
connectedPointUuids: connectedUuids
|
connectedPointUuids: connectedUuids
|
||||||
};
|
};
|
||||||
}, [selectedActionSphere, simulationPaths]);
|
}, [selectedActionSphere, simulationStates]);
|
||||||
|
|
||||||
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['point']['actions']>) => {
|
const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => {
|
||||||
if (!selectedActionSphere?.point?.uuid) return;
|
if (!updatedPath) return;
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => {
|
// await setEventApi(
|
||||||
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
|
// organization,
|
||||||
|
// updatedPath.modeluuid,
|
||||||
|
// { type: "Vehicle", points: updatedPath.points }
|
||||||
|
// );
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization: organization,
|
||||||
|
modeluuid: updatedPath.modeluuid,
|
||||||
|
eventData: { type: "Vehicle", points: updatedPath.points }
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v2:model-asset:updateEventData', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['points']['actions']>) => {
|
||||||
|
if (!selectedActionSphere?.points?.uuid) return;
|
||||||
|
|
||||||
|
const updatedPaths = simulationStates.map((path) => {
|
||||||
|
if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
|
||||||
return {
|
return {
|
||||||
...path,
|
...path,
|
||||||
point: {
|
points: {
|
||||||
...path.point,
|
...path.points,
|
||||||
actions: {
|
actions: {
|
||||||
...path.point.actions,
|
...path.points.actions,
|
||||||
...updatedAction
|
...updatedAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,14 +82,15 @@ const VehicleMechanics: React.FC = () => {
|
||||||
return path;
|
return path;
|
||||||
});
|
});
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
const updatedPath = updatedPaths.find(
|
||||||
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
|
(path): path is Types.VehicleEventsSchema =>
|
||||||
|
path.type === "Vehicle" &&
|
||||||
|
path.points.uuid === selectedActionSphere.points.uuid
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
const handleStartPointChange = React.useCallback((position: { x: number, y: number }) => {
|
setSimulationStates(updatedPaths);
|
||||||
}, [handleActionUpdate]);
|
}, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
|
||||||
|
|
||||||
const handleEndPointChange = React.useCallback((position: { x: number, y: number }) => {
|
|
||||||
}, [handleActionUpdate]);
|
|
||||||
|
|
||||||
const handleHitCountChange = React.useCallback((hitCount: number) => {
|
const handleHitCountChange = React.useCallback((hitCount: number) => {
|
||||||
handleActionUpdate({ hitCount });
|
handleActionUpdate({ hitCount });
|
||||||
|
@ -77,14 +101,14 @@ const VehicleMechanics: React.FC = () => {
|
||||||
}, [handleActionUpdate]);
|
}, [handleActionUpdate]);
|
||||||
|
|
||||||
const handleSpeedChange = React.useCallback((speed: number) => {
|
const handleSpeedChange = React.useCallback((speed: number) => {
|
||||||
if (!selectedActionSphere?.point?.uuid) return;
|
if (!selectedActionSphere?.points?.uuid) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => {
|
const updatedPaths = simulationStates.map((path) => {
|
||||||
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
|
if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
|
||||||
return {
|
return {
|
||||||
...path,
|
...path,
|
||||||
point: {
|
points: {
|
||||||
...path.point,
|
...path.points,
|
||||||
speed: speed
|
speed: speed
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -92,8 +116,15 @@ const VehicleMechanics: React.FC = () => {
|
||||||
return path;
|
return path;
|
||||||
});
|
});
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
const updatedPath = updatedPaths.find(
|
||||||
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
|
(path): path is Types.VehicleEventsSchema =>
|
||||||
|
path.type === "Vehicle" &&
|
||||||
|
path.points.uuid === selectedActionSphere.points.uuid
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
|
setSimulationStates(updatedPaths);
|
||||||
|
}, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
|
||||||
|
|
||||||
const handleStartEyeDropClick = () => {
|
const handleStartEyeDropClick = () => {
|
||||||
setEditingPoint('start');
|
setEditingPoint('start');
|
||||||
|
|
|
@ -33,7 +33,7 @@ const GlobalProperties: React.FC = () => {
|
||||||
const { setPlaneValue, setGridValue, planeValue, gridValue } =
|
const { setPlaneValue, setGridValue, planeValue, gridValue } =
|
||||||
useTileDistance();
|
useTileDistance();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log(gridValue, planeValue, "values");
|
|
||||||
}, [gridValue, planeValue]);
|
}, [gridValue, planeValue]);
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { limitDistance, setLimitDistance } = useLimitDistance();
|
const { limitDistance, setLimitDistance } = useLimitDistance();
|
||||||
|
|
|
@ -45,7 +45,7 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log(response.data);
|
|
||||||
|
|
||||||
setSelections(response.data.Data.measurements)
|
setSelections(response.data.Data.measurements)
|
||||||
setDuration(response.data.Data.duration)
|
setDuration(response.data.Data.duration)
|
||||||
|
|
|
@ -45,7 +45,7 @@ const FlotingWidgetInput = (props: Props) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log(response.data);
|
|
||||||
|
|
||||||
setSelections(response.data.Data.measurements)
|
setSelections(response.data.Data.measurements)
|
||||||
setDuration(response.data.Data.duration)
|
setDuration(response.data.Data.duration)
|
||||||
|
|
|
@ -45,7 +45,7 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log(response.data);
|
|
||||||
|
|
||||||
setSelections(response.data.Data.measurements)
|
setSelections(response.data.Data.measurements)
|
||||||
setDuration(response.data.Data.duration)
|
setDuration(response.data.Data.duration)
|
||||||
|
|
|
@ -42,16 +42,19 @@ const Design = () => {
|
||||||
const [elementColor, setElementColor] = useState("#6f42c1");
|
const [elementColor, setElementColor] = useState("#6f42c1");
|
||||||
const [showColorPicker, setShowColorPicker] = useState(false);
|
const [showColorPicker, setShowColorPicker] = useState(false);
|
||||||
const [chartElements, setChartElements] = useState<ChartElement[]>([]);
|
const [chartElements, setChartElements] = useState<ChartElement[]>([]);
|
||||||
const [selectedElementToStyle, setSelectedElementToStyle] = useState<string | null>(null);
|
const [selectedElementToStyle, setSelectedElementToStyle] = useState<
|
||||||
|
string | null
|
||||||
|
>(null);
|
||||||
const [nameInput, setNameInput] = useState("");
|
const [nameInput, setNameInput] = useState("");
|
||||||
const chartRef = useRef<HTMLDivElement>(null);
|
const chartRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { selectedChartId, setSelectedChartId, widgets, setWidgets } = useWidgetStore();
|
const { selectedChartId, setSelectedChartId, widgets, setWidgets } =
|
||||||
|
useWidgetStore();
|
||||||
|
|
||||||
// Initialize name input and extract elements when selectedChartId changes
|
// Initialize name input and extract elements when selectedChartId changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNameInput(selectedChartId?.header || selectedChartId?.title || "");
|
setNameInput(selectedChartId?.header || selectedChartId?.title || "");
|
||||||
|
|
||||||
if (!chartRef.current) return;
|
if (!chartRef.current) return;
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
|
@ -65,13 +68,16 @@ const Design = () => {
|
||||||
})
|
})
|
||||||
.map((el, index) => {
|
.map((el, index) => {
|
||||||
const tagName = el.tagName.toLowerCase();
|
const tagName = el.tagName.toLowerCase();
|
||||||
const className = typeof el.className === "string" ? el.className : "";
|
const className =
|
||||||
|
typeof el.className === "string" ? el.className : "";
|
||||||
const textContent = el.textContent?.trim() || "";
|
const textContent = el.textContent?.trim() || "";
|
||||||
|
|
||||||
let selector = tagName;
|
let selector = tagName;
|
||||||
|
|
||||||
if (className && typeof className === "string") {
|
if (className && typeof className === "string") {
|
||||||
const classList = className.split(/\s+/).filter((c) => c.length > 0);
|
const classList = className
|
||||||
|
.split(/\s+/)
|
||||||
|
.filter((c) => c.length > 0);
|
||||||
if (classList.length > 0) {
|
if (classList.length > 0) {
|
||||||
selector += "." + classList.join(".");
|
selector += "." + classList.join(".");
|
||||||
}
|
}
|
||||||
|
@ -126,7 +132,13 @@ const Design = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
applyStyles();
|
applyStyles();
|
||||||
}, [selectedFont, selectedSize, selectedWeight, elementColor, selectedElementToStyle]);
|
}, [
|
||||||
|
selectedFont,
|
||||||
|
selectedSize,
|
||||||
|
selectedWeight,
|
||||||
|
elementColor,
|
||||||
|
selectedElementToStyle,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
|
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
|
||||||
if (!selectedChartId) return;
|
if (!selectedChartId) return;
|
||||||
|
@ -138,7 +150,9 @@ const Design = () => {
|
||||||
setSelectedChartId(updatedChartId);
|
setSelectedChartId(updatedChartId);
|
||||||
|
|
||||||
const updatedWidgets = widgets.map((widget) =>
|
const updatedWidgets = widgets.map((widget) =>
|
||||||
widget.id === selectedChartId.id ? { ...widget, ...updatedProperties } : widget
|
widget.id === selectedChartId.id
|
||||||
|
? { ...widget, ...updatedProperties }
|
||||||
|
: widget
|
||||||
);
|
);
|
||||||
setWidgets(updatedWidgets);
|
setWidgets(updatedWidgets);
|
||||||
};
|
};
|
||||||
|
@ -146,7 +160,7 @@ const Design = () => {
|
||||||
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const newName = e.target.value;
|
const newName = e.target.value;
|
||||||
setNameInput(newName);
|
setNameInput(newName);
|
||||||
|
|
||||||
if (selectedChartId?.title) {
|
if (selectedChartId?.title) {
|
||||||
handleUpdateWidget({ title: newName });
|
handleUpdateWidget({ title: newName });
|
||||||
} else if (selectedChartId?.header) {
|
} else if (selectedChartId?.header) {
|
||||||
|
@ -155,12 +169,12 @@ const Design = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultChartData = {
|
const defaultChartData = {
|
||||||
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
data: [65, 59, 80, 81, 56, 55, 40],
|
data: [65, 59, 80, 81, 56, 55, 40],
|
||||||
backgroundColor: elementColor,
|
backgroundColor: "#6f42c1",
|
||||||
borderColor: "#ffffff",
|
borderColor: "#b392f0",
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -311,4 +325,4 @@ const Design = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Design;
|
export default Design;
|
||||||
|
|
|
@ -438,7 +438,6 @@ const Tools: React.FC = () => {
|
||||||
}`}
|
}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsPlaying(!isPlaying);
|
setIsPlaying(!isPlaying);
|
||||||
setActiveTool("play");
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlayIcon isActive={activeTool === "play"} />
|
<PlayIcon isActive={activeTool === "play"} />
|
||||||
|
|
|
@ -96,16 +96,16 @@ export const DraggableWidget = ({
|
||||||
let deleteWidget = {
|
let deleteWidget = {
|
||||||
zoneId: selectedZone.zoneId,
|
zoneId: selectedZone.zoneId,
|
||||||
widgetID: widget.id,
|
widgetID: widget.id,
|
||||||
organization: organization
|
organization: organization,
|
||||||
}
|
};
|
||||||
console.log('deleteWidget: ', deleteWidget);
|
console.log("deleteWidget: ", deleteWidget);
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget)
|
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget);
|
||||||
}
|
}
|
||||||
const updatedWidgets = selectedZone.widgets.filter(
|
const updatedWidgets = selectedZone.widgets.filter(
|
||||||
(w: Widget) => w.id !== widget.id
|
(w: Widget) => w.id !== widget.id
|
||||||
);
|
);
|
||||||
console.log('updatedWidgets: ', updatedWidgets);
|
console.log("updatedWidgets: ", updatedWidgets);
|
||||||
setSelectedZone((prevZone: any) => ({
|
setSelectedZone((prevZone: any) => ({
|
||||||
...prevZone,
|
...prevZone,
|
||||||
widgets: updatedWidgets,
|
widgets: updatedWidgets,
|
||||||
|
@ -168,10 +168,10 @@ export const DraggableWidget = ({
|
||||||
let duplicateWidget = {
|
let duplicateWidget = {
|
||||||
organization: organization,
|
organization: organization,
|
||||||
zoneId: selectedZone.zoneId,
|
zoneId: selectedZone.zoneId,
|
||||||
widget: duplicatedWidget
|
widget: duplicatedWidget,
|
||||||
}
|
};
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget)
|
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget);
|
||||||
}
|
}
|
||||||
setSelectedZone((prevZone: any) => ({
|
setSelectedZone((prevZone: any) => ({
|
||||||
...prevZone,
|
...prevZone,
|
||||||
|
@ -239,29 +239,95 @@ export const DraggableWidget = ({
|
||||||
onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop
|
onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
console.log("widget.type", widget.type);
|
|
||||||
|
|
||||||
// useClickOutside(chartWidget, () => {
|
// useClickOutside(chartWidget, () => {
|
||||||
// setSelectedChartId(null);
|
// setSelectedChartId(null);
|
||||||
// });
|
// });
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
|
||||||
console.log('isPanelHidden: ', isPanelHidden);
|
const [canvasDimensions, setCanvasDimensions] = useState({
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
});
|
||||||
|
// Track canvas dimensions
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = document.getElementById("real-time-vis-canvas");
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const updateCanvasDimensions = () => {
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
setCanvasDimensions({
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial measurement
|
||||||
|
updateCanvasDimensions();
|
||||||
|
|
||||||
|
// Set up ResizeObserver to track changes
|
||||||
|
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
|
||||||
|
resizeObserver.observe(canvas);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
resizeObserver.unobserve(canvas);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = document.getElementById("real-time-vis-canvas");
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const updateCanvasDimensions = () => {
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
setCanvasDimensions({
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial measurement
|
||||||
|
updateCanvasDimensions();
|
||||||
|
|
||||||
|
// Set up ResizeObserver to track changes
|
||||||
|
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
|
||||||
|
resizeObserver.observe(canvas);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
resizeObserver.unobserve(canvas);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
console.log("selectedChartId: ", widget);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<style>
|
||||||
|
{`
|
||||||
|
:root {
|
||||||
|
--realTimeViz-container-width: ${canvasDimensions.width * 0.25}px;
|
||||||
|
--realTimeViz-container-height: ${canvasDimensions.height}px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
<div
|
<div
|
||||||
draggable
|
draggable
|
||||||
key={widget.id}
|
key={widget.id}
|
||||||
className={`chart-container ${(selectedChartId?.id === widget.id) && !isPlaying && "activeChart"
|
className={`chart-container ${
|
||||||
}`}
|
selectedChartId?.id === widget.id && !isPlaying && "activeChart"
|
||||||
|
}`}
|
||||||
onPointerDown={handlePointerDown}
|
onPointerDown={handlePointerDown}
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
onDragEnter={handleDragEnter}
|
onDragEnter={handleDragEnter}
|
||||||
onDragOver={handleDragOver}
|
onDragOver={handleDragOver}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
style={{
|
style={{
|
||||||
// pointerEvents: isPanelHidden ? "none" : "auto",
|
// Apply styles based on panel position
|
||||||
// opacity: isPanelHidden ? "0.1" : "0",
|
width: ["top", "bottom"].includes(widget.panel)
|
||||||
|
? `calc(${canvasDimensions.width * 0.16}px - 2px)` // For top/bottom panels, set width
|
||||||
|
: undefined, // Don't set width if it's left or right
|
||||||
|
height: ["left", "right"].includes(widget.panel)
|
||||||
|
? `calc(${canvasDimensions.height * 0.3}px - 2px)` // For left/right panels, set height
|
||||||
|
: undefined, // Don't set height if it's top or bottom
|
||||||
}}
|
}}
|
||||||
ref={chartWidget}
|
ref={chartWidget}
|
||||||
onClick={() => setSelectedChartId(widget)}
|
onClick={() => setSelectedChartId(widget)}
|
||||||
|
@ -275,8 +341,9 @@ export const DraggableWidget = ({
|
||||||
{openKebabId === widget.id && (
|
{openKebabId === widget.id && (
|
||||||
<div className="kebab-options" ref={widgetRef}>
|
<div className="kebab-options" ref={widgetRef}>
|
||||||
<div
|
<div
|
||||||
className={`edit btn ${isPanelFull(widget.panel) ? "btn-blur" : ""
|
className={`edit btn ${
|
||||||
}`}
|
isPanelFull(widget.panel) ? "btn-blur" : ""
|
||||||
|
}`}
|
||||||
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
|
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
|
||||||
>
|
>
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
|
@ -350,3 +417,5 @@ export const DraggableWidget = ({
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// in style if widget .panel is top or bottom set width if left or right set height
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store";
|
import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
import { ThreeState } from "../../../types/world/worldTypes";
|
import { ThreeState } from "../../../types/world/worldTypes";
|
||||||
|
@ -13,9 +13,19 @@ import { generateUniqueId } from "../../../functions/generateUniqueId";
|
||||||
import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget";
|
import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget";
|
||||||
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
|
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
|
||||||
import { use3DWidget } from "../../../store/useDroppedObjectsStore";
|
import { use3DWidget } from "../../../store/useDroppedObjectsStore";
|
||||||
import { useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../store/useZone3DWidgetStore";
|
import { useEditWidgetOptionsStore, useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../store/useZone3DWidgetStore";
|
||||||
import { useWidgetStore } from "../../../store/useWidgetStore";
|
import { useWidgetStore } from "../../../store/useWidgetStore";
|
||||||
import EditWidgetOption from "../menu/EditWidgetOption";
|
import EditWidgetOption from "../menu/EditWidgetOption";
|
||||||
|
import { delete3dWidgetApi } from "../../../services/realTimeVisulization/zoneData/delete3dWidget";
|
||||||
|
import { update3dWidget, update3dWidgetRotation } from "../../../services/realTimeVisulization/zoneData/update3dWidget";
|
||||||
|
type WidgetData = {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation?: [number, number, number];
|
||||||
|
tempPosition?: [number, number, number];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export default function Dropped3dWidgets() {
|
export default function Dropped3dWidgets() {
|
||||||
const { widgetSelect } = useAsset3dWidget();
|
const { widgetSelect } = useAsset3dWidget();
|
||||||
|
@ -23,22 +33,23 @@ export default function Dropped3dWidgets() {
|
||||||
const { raycaster, gl, scene, mouse, camera }: ThreeState = useThree();
|
const { raycaster, gl, scene, mouse, camera }: ThreeState = useThree();
|
||||||
const { widgetSubOption } = useWidgetSubOption();
|
const { widgetSubOption } = useWidgetSubOption();
|
||||||
const { selectedZone } = useSelectedZoneStore();
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
const { top, setTop } = useTopData()
|
const { top, setTop } = useTopData();
|
||||||
const { left, setLeft } = useLeftData()
|
const { left, setLeft } = useLeftData();
|
||||||
const { rightSelect, setRightSelect } = useRightSelected()
|
const { rightSelect, setRightSelect } = useRightSelected();
|
||||||
|
const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore()
|
||||||
// ✅ Use Zustand Store instead of useState
|
const { zoneWidgetData, setZoneWidgetData, addWidget, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore();
|
||||||
const { zoneWidgetData, setZoneWidgetData, addWidget, updateWidgetPosition } = useZoneWidgetStore();
|
|
||||||
const { setWidgets3D } = use3DWidget();
|
const { setWidgets3D } = use3DWidget();
|
||||||
const { visualizationSocket } = useSocketStore();
|
const { visualizationSocket } = useSocketStore();
|
||||||
const { rightClickSelected, setRightClickSelected } = useRightClickSelected()
|
const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
|
||||||
|
|
||||||
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move
|
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move
|
||||||
const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move
|
const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move
|
||||||
const planeIntersect = useRef(new THREE.Vector3());
|
const planeIntersect = useRef(new THREE.Vector3());
|
||||||
// let [verticalPlane, setFloorPlanesVertical] = useState(
|
// const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
||||||
// new THREE.Plane(new THREE.Vector3(0, 1, 0))
|
// const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
|
||||||
// );
|
// const planeIntersect = useRef(new THREE.Vector3());
|
||||||
|
const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]);
|
||||||
|
const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeModule !== "visualization") return;
|
if (activeModule !== "visualization") return;
|
||||||
|
@ -48,16 +59,18 @@ export default function Dropped3dWidgets() {
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
async function get3dWidgetData() {
|
async function get3dWidgetData() {
|
||||||
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
|
const result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
|
||||||
|
console.log('result: ', result);
|
||||||
setWidgets3D(result);
|
setWidgets3D(result);
|
||||||
|
|
||||||
const formattedWidgets = result.map((widget: any) => ({
|
const formattedWidgets = result.map((widget: WidgetData) => ({
|
||||||
id: widget.id,
|
id: widget.id,
|
||||||
type: widget.type,
|
type: widget.type,
|
||||||
position: widget.position,
|
position: widget.position,
|
||||||
|
rotation: widget.rotation || [0, 0, 0],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
setZoneWidgetData(selectedZone.zoneId, formattedWidgets);
|
setZoneWidgetData(selectedZone.zoneId, formattedWidgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,28 +104,24 @@ export default function Dropped3dWidgets() {
|
||||||
|
|
||||||
if (intersects.length > 0) {
|
if (intersects.length > 0) {
|
||||||
const { x, y, z } = intersects[0].point;
|
const { x, y, z } = intersects[0].point;
|
||||||
const newWidget = {
|
const newWidget: WidgetData = {
|
||||||
id: generateUniqueId(),
|
id: generateUniqueId(),
|
||||||
type: widgetSelect,
|
type: widgetSelect,
|
||||||
position: [x, y, z] as [number, number, number],
|
position: [x, y, z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
};
|
};
|
||||||
|
|
||||||
let add3dWidget = {
|
const add3dWidget = {
|
||||||
organization: organization,
|
organization: organization,
|
||||||
widget: newWidget,
|
widget: newWidget,
|
||||||
zoneId: selectedZone.zoneId
|
zoneId: selectedZone.zoneId
|
||||||
}
|
};
|
||||||
|
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget)
|
visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget);
|
|
||||||
//
|
|
||||||
|
|
||||||
// if (response.message === "Widget created successfully") {
|
|
||||||
addWidget(selectedZone.zoneId, newWidget);
|
addWidget(selectedZone.zoneId, newWidget);
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,63 +137,101 @@ export default function Dropped3dWidgets() {
|
||||||
if (!rightClickSelected) return;
|
if (!rightClickSelected) return;
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
if (rightSelect === "Duplicate") {
|
if (rightSelect === "Duplicate") {
|
||||||
const widgetToDuplicate = activeZoneWidgets.find(w => w.id === rightClickSelected);
|
async function duplicateWidget() {
|
||||||
if (!widgetToDuplicate) return;
|
const widgetToDuplicate = activeZoneWidgets.find((w: WidgetData) => w.id === rightClickSelected);
|
||||||
const newWidget = {
|
if (!widgetToDuplicate) return;
|
||||||
id: generateUniqueId(),
|
const newWidget: WidgetData = {
|
||||||
type: widgetToDuplicate.type,
|
id: generateUniqueId(),
|
||||||
position: [
|
type: widgetToDuplicate.type,
|
||||||
widgetToDuplicate.position[0] + 0.5, // Slightly shift position
|
position: [
|
||||||
widgetToDuplicate.position[1],
|
widgetToDuplicate.position[0] + 0.5,
|
||||||
widgetToDuplicate.position[2] + 0.5,
|
widgetToDuplicate.position[1],
|
||||||
] as [number, number, number],
|
widgetToDuplicate.position[2] + 0.5,
|
||||||
};
|
],
|
||||||
let add3dWidget = {
|
rotation: widgetToDuplicate.rotation || [0, 0, 0],
|
||||||
organization,
|
};
|
||||||
widget: newWidget,
|
const adding3dWidget = {
|
||||||
zoneId: selectedZone.zoneId
|
organization: organization,
|
||||||
};
|
widget: newWidget,
|
||||||
// if (visualizationSocket) {
|
zoneId: selectedZone.zoneId
|
||||||
// visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget);
|
};
|
||||||
// }
|
if (visualizationSocket) {
|
||||||
addWidget(selectedZone.zoneId, newWidget);
|
visualizationSocket.emit("v2:viz-3D-widget:add", adding3dWidget);
|
||||||
setRightSelect(null);
|
}
|
||||||
setRightClickSelected(null);
|
// let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget)
|
||||||
|
// console.log('response: ', response);
|
||||||
|
|
||||||
|
addWidget(selectedZone.zoneId, newWidget);
|
||||||
|
setRightSelect(null);
|
||||||
|
setRightClickSelected(null);
|
||||||
|
}
|
||||||
|
duplicateWidget()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rightSelect === "Delete") {
|
if (rightSelect === "Delete") {
|
||||||
let deleteWidget = {
|
const deleteWidgetApi = async () => {
|
||||||
organization,
|
try {
|
||||||
widgetId: rightClickSelected,
|
const deleteWidget = {
|
||||||
zoneId: selectedZone.zoneId
|
organization,
|
||||||
|
id: rightClickSelected,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('deleteWidget: ', deleteWidget);
|
||||||
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget);
|
||||||
|
}
|
||||||
|
// Call the API to delete the widget
|
||||||
|
// const response = await delete3dWidgetApi(selectedZone.zoneId, organization, rightClickSelected);
|
||||||
|
setZoneWidgetData(
|
||||||
|
selectedZone.zoneId,
|
||||||
|
activeZoneWidgets.filter((w: WidgetData) => w.id !== rightClickSelected)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error deleting widget:", error);
|
||||||
|
} finally {
|
||||||
|
setRightClickSelected(null);
|
||||||
|
setRightSelect(null);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// if (visualizationSocket) {
|
|
||||||
// visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget);
|
|
||||||
// }
|
|
||||||
setZoneWidgetData(selectedZone.zoneId, activeZoneWidgets.filter(w => w.id !== rightClickSelected));
|
|
||||||
setRightClickSelected(null);
|
|
||||||
setRightSelect(null);
|
|
||||||
}
|
|
||||||
if (rightSelect === "Horizontal Move") {
|
|
||||||
|
|
||||||
|
deleteWidgetApi();
|
||||||
}
|
}
|
||||||
if (rightSelect === "Vertical Move") {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [rightSelect, rightClickSelected]);
|
}, [rightSelect, rightClickSelected]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleMouseMove = (event: MouseEvent) => {
|
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
const handleMouseDown = (event: MouseEvent) => {
|
||||||
if (!rightClickSelected || !rightSelect) return;
|
if (!rightClickSelected || !rightSelect) return;
|
||||||
|
|
||||||
|
if (rightSelect === "RotateX" || rightSelect === "RotateY") {
|
||||||
|
mouseStartRef.current = { x: event.clientX, y: event.clientY };
|
||||||
|
|
||||||
const selectedZone = Object.keys(zoneWidgetData).find(zoneId =>
|
const selectedZone = Object.keys(zoneWidgetData).find((zoneId: string) =>
|
||||||
zoneWidgetData[zoneId].some(widget => widget.id === rightClickSelected)
|
zoneWidgetData[zoneId].some((widget: WidgetData) => widget.id === rightClickSelected)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!selectedZone) return;
|
||||||
|
|
||||||
|
const selectedWidget = zoneWidgetData[selectedZone].find((widget: WidgetData) => widget.id === rightClickSelected);
|
||||||
|
if (selectedWidget) {
|
||||||
|
rotationStartRef.current = selectedWidget.rotation || [0, 0, 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseMove = (event: MouseEvent) => {
|
||||||
|
if (!rightClickSelected || !rightSelect) return;
|
||||||
|
const selectedZone = Object.keys(zoneWidgetData).find((zoneId: string) =>
|
||||||
|
zoneWidgetData[zoneId].some((widget: WidgetData) => widget.id === rightClickSelected)
|
||||||
);
|
);
|
||||||
if (!selectedZone) return;
|
if (!selectedZone) return;
|
||||||
|
|
||||||
const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected);
|
const selectedWidget = zoneWidgetData[selectedZone].find((widget: WidgetData) => widget.id === rightClickSelected);
|
||||||
if (!selectedWidget) return;
|
if (!selectedWidget) return;
|
||||||
|
|
||||||
const rect = gl.domElement.getBoundingClientRect();
|
const rect = gl.domElement.getBoundingClientRect();
|
||||||
|
@ -194,72 +241,200 @@ export default function Dropped3dWidgets() {
|
||||||
raycaster.setFromCamera(mouse, camera);
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
if (rightSelect === "Horizontal Move" && raycaster.ray.intersectPlane(plane.current, planeIntersect.current)) {
|
if (rightSelect === "Horizontal Move" && raycaster.ray.intersectPlane(plane.current, planeIntersect.current)) {
|
||||||
|
const newPosition: [number, number, number] = [
|
||||||
updateWidgetPosition(selectedZone, rightClickSelected, [
|
|
||||||
planeIntersect.current.x,
|
planeIntersect.current.x,
|
||||||
selectedWidget.position[1],
|
selectedWidget.position[1],
|
||||||
planeIntersect.current.z
|
planeIntersect.current.z
|
||||||
]);
|
];
|
||||||
|
updateWidgetPosition(selectedZone, rightClickSelected, newPosition);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rightSelect === "Vertical Move") {
|
if (rightSelect === "Vertical Move") {
|
||||||
if (raycaster.ray.intersectPlane(verticalPlane.current, planeIntersect.current)) {
|
if (raycaster.ray.intersectPlane(verticalPlane.current, planeIntersect.current)) {
|
||||||
updateWidgetPosition(selectedZone, rightClickSelected, [
|
updateWidgetPosition(selectedZone, rightClickSelected, [
|
||||||
selectedWidget.position[0],
|
selectedWidget.position[0],
|
||||||
planeIntersect.current.y, // Ensure Y value updates correctly
|
planeIntersect.current.y,
|
||||||
selectedWidget.position[2]
|
selectedWidget.position[2]
|
||||||
]);
|
]);
|
||||||
} else {
|
|
||||||
console.log("No Intersection with Vertical Plane");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rightSelect === "RotateX") {
|
||||||
|
const deltaX = event.clientX - mouseStartRef.current.x;
|
||||||
|
const rotationSpeed = 0.03;
|
||||||
|
const newRotation: [number, number, number] = [
|
||||||
|
rotationStartRef.current[0] + deltaX * rotationSpeed,
|
||||||
|
rotationStartRef.current[1],
|
||||||
|
rotationStartRef.current[2]
|
||||||
|
];
|
||||||
|
updateWidgetRotation(selectedZone, rightClickSelected, newRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightSelect === "RotateY") {
|
||||||
|
const deltaY = event.clientY - mouseStartRef.current.y;
|
||||||
|
const rotationSpeed = 0.03;
|
||||||
|
const newRotation: [number, number, number] = [
|
||||||
|
rotationStartRef.current[0],
|
||||||
|
rotationStartRef.current[1] + deltaY * rotationSpeed,
|
||||||
|
rotationStartRef.current[2]
|
||||||
|
];
|
||||||
|
updateWidgetRotation(selectedZone, rightClickSelected, newRotation);
|
||||||
|
}
|
||||||
|
if (rightSelect === "RotateZ") {
|
||||||
|
const deltaX = event.movementX;
|
||||||
|
const rotationSpeed = 0.03;
|
||||||
|
const currentRotation = selectedWidget.rotation || [0, 0, 0];
|
||||||
|
const newRotation: [number, number, number] = [
|
||||||
|
currentRotation[0],
|
||||||
|
currentRotation[1],
|
||||||
|
currentRotation[2] + deltaX * rotationSpeed
|
||||||
|
];
|
||||||
|
updateWidgetRotation(selectedZone, rightClickSelected, newRotation);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseUp = () => {
|
const handleMouseUp = () => {
|
||||||
|
if (!rightClickSelected || !rightSelect) return;
|
||||||
|
const selectedZone = Object.keys(zoneWidgetData).find(zoneId =>
|
||||||
|
zoneWidgetData[zoneId].some(widget => widget.id === rightClickSelected)
|
||||||
|
);
|
||||||
|
if (!selectedZone) return;
|
||||||
|
|
||||||
if (rightClickSelected && (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move")) {
|
const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected);
|
||||||
|
if (!selectedWidget) return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Format values to 2 decimal places
|
||||||
|
const formatValues = (vals: number[]) => vals.map(val => parseFloat(val.toFixed(2)));
|
||||||
|
|
||||||
|
if (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move") {
|
||||||
|
console.log(`${rightSelect} Completed - Full Position:`, formatValues(selectedWidget.position));
|
||||||
|
let lastPosition = formatValues(selectedWidget.position) as [number, number, number];
|
||||||
|
// (async () => {
|
||||||
|
// let response = await update3dWidget(selectedZone, organization, rightClickSelected, lastPosition);
|
||||||
|
// console.log('response: ', response);
|
||||||
|
// if (response) {
|
||||||
|
// console.log("Widget position updated in API:", response);
|
||||||
|
// }
|
||||||
|
// })();
|
||||||
|
let updatingPosition = {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone,
|
||||||
|
id: rightClickSelected,
|
||||||
|
position: lastPosition,
|
||||||
|
}
|
||||||
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-3D-widget:modifyPositionRotation", updatingPosition);
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
setRightClickSelected(null);
|
|
||||||
setRightSelect(null);
|
|
||||||
}, 50);
|
|
||||||
}
|
}
|
||||||
};
|
else if (rightSelect.includes("Rotate")) {
|
||||||
|
const rotation = selectedWidget.rotation || [0, 0, 0];
|
||||||
|
console.log(`${rightSelect} Completed - Full Rotation:`, formatValues(rotation));
|
||||||
|
let lastRotation = formatValues(rotation) as [number, number, number];
|
||||||
|
// (async () => {
|
||||||
|
// let response = await update3dWidgetRotation(selectedZone, organization, rightClickSelected, lastRotation);
|
||||||
|
// console.log('response: ', response);
|
||||||
|
// if (response) {
|
||||||
|
// console.log("Widget position updated in API:", response);
|
||||||
|
// }
|
||||||
|
// })();
|
||||||
|
let updatingRotation = {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone,
|
||||||
|
id: rightClickSelected,
|
||||||
|
rotation: lastRotation,
|
||||||
|
}
|
||||||
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-3D-widget:modifyPositionRotation", updatingRotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Attach events to window instead of gl.domElement
|
// Reset selection
|
||||||
|
setTimeout(() => {
|
||||||
|
setRightClickSelected(null);
|
||||||
|
setRightSelect(null);
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
|
window.addEventListener("mousedown", handleMouseDown);
|
||||||
window.addEventListener("mousemove", handleMouseMove);
|
window.addEventListener("mousemove", handleMouseMove);
|
||||||
window.addEventListener("mouseup", handleMouseUp);
|
window.addEventListener("mouseup", handleMouseUp);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
window.removeEventListener("mousedown", handleMouseDown);
|
||||||
window.removeEventListener("mousemove", handleMouseMove);
|
window.removeEventListener("mousemove", handleMouseMove);
|
||||||
window.removeEventListener("mouseup", handleMouseUp);
|
window.removeEventListener("mouseup", handleMouseUp);
|
||||||
};
|
};
|
||||||
}, [rightClickSelected, rightSelect, zoneWidgetData, gl]);
|
}, [rightClickSelected, rightSelect, zoneWidgetData, gl]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{activeZoneWidgets.map(({ id, type, position }) => {
|
{activeZoneWidgets.map(({ id, type, position, rotation = [0, 0, 0] }: WidgetData) => {
|
||||||
const handleRightClick = (event: React.MouseEvent) => {
|
const handleRightClick = (event: React.MouseEvent, id: string) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setRightClickSelected(id)
|
const canvasElement = document.getElementById("real-time-vis-canvas");
|
||||||
|
if (!canvasElement) throw new Error("Canvas element not found");
|
||||||
|
const canvasRect = canvasElement.getBoundingClientRect();
|
||||||
|
const relativeX = event.clientX - canvasRect.left;
|
||||||
|
const relativeY = event.clientY - canvasRect.top;
|
||||||
|
setEditWidgetOptions(true);
|
||||||
|
setRightClickSelected(id);
|
||||||
|
setTop(relativeY);
|
||||||
|
setLeft(relativeX);
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "ui-Widget 1":
|
case "ui-Widget 1":
|
||||||
return <ProductionCapacity key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />;
|
return (
|
||||||
|
<ProductionCapacity
|
||||||
|
key={id}
|
||||||
|
id={id}
|
||||||
|
type={type}
|
||||||
|
position={position}
|
||||||
|
rotation={rotation}
|
||||||
|
onContextMenu={(e) => handleRightClick(e, id)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case "ui-Widget 2":
|
case "ui-Widget 2":
|
||||||
return <ReturnOfInvestment key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />;
|
return (
|
||||||
|
<ReturnOfInvestment
|
||||||
|
key={id}
|
||||||
|
id={id}
|
||||||
|
type={type}
|
||||||
|
position={position}
|
||||||
|
rotation={rotation}
|
||||||
|
onContextMenu={(e) => handleRightClick(e, id)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case "ui-Widget 3":
|
case "ui-Widget 3":
|
||||||
return <StateWorking key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />;
|
return (
|
||||||
|
<StateWorking
|
||||||
|
key={id}
|
||||||
|
id={id}
|
||||||
|
type={type}
|
||||||
|
position={position}
|
||||||
|
rotation={rotation}
|
||||||
|
onContextMenu={(e) => handleRightClick(e, id)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case "ui-Widget 4":
|
case "ui-Widget 4":
|
||||||
return <Throughput key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />;
|
return (
|
||||||
|
<Throughput
|
||||||
|
key={id}
|
||||||
|
id={id}
|
||||||
|
type={type}
|
||||||
|
position={position}
|
||||||
|
rotation={rotation}
|
||||||
|
onContextMenu={(e) => handleRightClick(e, id)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -126,11 +126,12 @@ const DroppedObjects: React.FC = () => {
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
|
|
||||||
let deleteFloatingWidget = {
|
let deleteFloatingWidget = {
|
||||||
floatWidgetID: id,
|
floatWidgetID: id,
|
||||||
organization: organization,
|
organization: organization,
|
||||||
zoneId: zone.zoneId,
|
zoneId: zone.zoneId
|
||||||
};
|
}
|
||||||
|
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget);
|
visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget);
|
||||||
|
@ -143,7 +144,9 @@ const DroppedObjects: React.FC = () => {
|
||||||
// if (res.message === "FloatingWidget deleted successfully") {
|
// if (res.message === "FloatingWidget deleted successfully") {
|
||||||
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store
|
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store
|
||||||
// }
|
// }
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
||||||
|
@ -458,15 +461,15 @@ const DroppedObjects: React.FC = () => {
|
||||||
position: boundedPosition,
|
position: boundedPosition,
|
||||||
},
|
},
|
||||||
index: draggingIndex.index,
|
index: draggingIndex.index,
|
||||||
zoneId: zone.zoneId,
|
zoneId: zone.zoneId
|
||||||
};
|
}
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget);
|
visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (response.message === "Widget updated successfully") {
|
// if (response.message === "Widget updated successfully") {
|
||||||
|
|
||||||
console.log("boundedPosition: ", boundedPosition);
|
console.log('boundedPosition: ', boundedPosition);
|
||||||
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
|
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -509,43 +512,37 @@ const DroppedObjects: React.FC = () => {
|
||||||
{zone.objects.map((obj, index) => (
|
{zone.objects.map((obj, index) => (
|
||||||
<div
|
<div
|
||||||
key={`${zoneName}-${index}`}
|
key={`${zoneName}-${index}`}
|
||||||
className={`${obj.className} ${
|
className={`${obj.className} ${selectedChartId?.id === obj.id && "activeChart"}`}
|
||||||
selectedChartId?.id === obj.id && !isPlaying && "activeChart"
|
|
||||||
}`}
|
|
||||||
ref={chartWidget}
|
ref={chartWidget}
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top:
|
top:
|
||||||
typeof obj.position.top === "number"
|
typeof obj.position.top === "number"
|
||||||
? `calc(${obj.position.top}px + ${
|
? `calc(${obj.position.top}px + ${isPlaying && selectedZone.activeSides.includes("top")
|
||||||
isPlaying && selectedZone.activeSides.includes("top")
|
? 90
|
||||||
? 90
|
: 0
|
||||||
: 0
|
}px)`
|
||||||
}px)`
|
|
||||||
: "auto",
|
: "auto",
|
||||||
left:
|
left:
|
||||||
typeof obj.position.left === "number"
|
typeof obj.position.left === "number"
|
||||||
? `calc(${obj.position.left}px + ${
|
? `calc(${obj.position.left}px + ${isPlaying && selectedZone.activeSides.includes("left")
|
||||||
isPlaying && selectedZone.activeSides.includes("left")
|
? 90
|
||||||
? 90
|
: 0
|
||||||
: 0
|
}px)`
|
||||||
}px)`
|
|
||||||
: "auto",
|
: "auto",
|
||||||
right:
|
right:
|
||||||
typeof obj.position.right === "number"
|
typeof obj.position.right === "number"
|
||||||
? `calc(${obj.position.right}px + ${
|
? `calc(${obj.position.right}px + ${isPlaying && selectedZone.activeSides.includes("right")
|
||||||
isPlaying && selectedZone.activeSides.includes("right")
|
? 90
|
||||||
? 90
|
: 0
|
||||||
: 0
|
}px)`
|
||||||
}px)`
|
|
||||||
: "auto",
|
: "auto",
|
||||||
bottom:
|
bottom:
|
||||||
typeof obj.position.bottom === "number"
|
typeof obj.position.bottom === "number"
|
||||||
? `calc(${obj.position.bottom}px + ${
|
? `calc(${obj.position.bottom}px + ${isPlaying && selectedZone.activeSides.includes("bottom")
|
||||||
isPlaying && selectedZone.activeSides.includes("bottom")
|
? 90
|
||||||
? 90
|
: 0
|
||||||
: 0
|
}px)`
|
||||||
}px)`
|
|
||||||
: "auto",
|
: "auto",
|
||||||
}}
|
}}
|
||||||
onPointerDown={(event) => {
|
onPointerDown={(event) => {
|
||||||
|
|
|
@ -64,6 +64,59 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { visualizationSocket } = useSocketStore();
|
const { visualizationSocket } = useSocketStore();
|
||||||
|
|
||||||
|
const [canvasDimensions, setCanvasDimensions] = useState({
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
});
|
||||||
|
// Track canvas dimensions
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = document.getElementById("real-time-vis-canvas");
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const updateCanvasDimensions = () => {
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
setCanvasDimensions({
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial measurement
|
||||||
|
updateCanvasDimensions();
|
||||||
|
|
||||||
|
// Set up ResizeObserver to track changes
|
||||||
|
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
|
||||||
|
resizeObserver.observe(canvas);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
resizeObserver.unobserve(canvas);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = document.getElementById("real-time-vis-canvas");
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const updateCanvasDimensions = () => {
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
setCanvasDimensions({
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial measurement
|
||||||
|
updateCanvasDimensions();
|
||||||
|
|
||||||
|
// Set up ResizeObserver to track changes
|
||||||
|
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
|
||||||
|
resizeObserver.observe(canvas);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
resizeObserver.unobserve(canvas);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const getPanelStyle = useMemo(
|
const getPanelStyle = useMemo(
|
||||||
() => (side: Side) => {
|
() => (side: Side) => {
|
||||||
const currentIndex = selectedZone.panelOrder.indexOf(side);
|
const currentIndex = selectedZone.panelOrder.indexOf(side);
|
||||||
|
@ -72,36 +125,50 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
const rightActive = previousPanels.includes("right");
|
const rightActive = previousPanels.includes("right");
|
||||||
const topActive = previousPanels.includes("top");
|
const topActive = previousPanels.includes("top");
|
||||||
const bottomActive = previousPanels.includes("bottom");
|
const bottomActive = previousPanels.includes("bottom");
|
||||||
const panelSize = isPlaying ? 300 : 210;
|
|
||||||
|
// Dynamic panel sizes based on canvas width
|
||||||
|
const panelSizeWidth = Math.max(canvasDimensions.width * 0.165, 200); // Ensure minimum width of 200px
|
||||||
|
const panelSizeHeight = Math.max(canvasDimensions.width * 0.13, 200); // Ensure minimum height of 200px
|
||||||
|
|
||||||
switch (side) {
|
switch (side) {
|
||||||
case "top":
|
case "top":
|
||||||
case "bottom":
|
case "bottom":
|
||||||
return {
|
return {
|
||||||
|
minWidth: "200px", // Minimum width constraint
|
||||||
width: `calc(100% - ${
|
width: `calc(100% - ${
|
||||||
(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
|
(leftActive ? panelSizeWidth : 0) + (rightActive ? panelSizeWidth : 0)
|
||||||
}px)`,
|
}px)`,
|
||||||
height: `${panelSize - 2}px`,
|
minHeight: "200px", // Minimum height constraint
|
||||||
left: leftActive ? `${panelSize}px` : "0",
|
height: `${panelSizeHeight - 2}px`, // Subtracting for border or margin
|
||||||
right: rightActive ? `${panelSize}px` : "0",
|
left: leftActive ? `${panelSizeWidth}px` : "0",
|
||||||
|
right: rightActive ? `${panelSizeWidth}px` : "0",
|
||||||
[side]: "0",
|
[side]: "0",
|
||||||
};
|
};
|
||||||
|
|
||||||
case "left":
|
case "left":
|
||||||
case "right":
|
case "right":
|
||||||
return {
|
return {
|
||||||
width: `${panelSize - 2}px`,
|
minWidth: "200px", // Minimum width constraint
|
||||||
|
width: `${panelSizeWidth - 2}px`, // Subtracting for border or margin
|
||||||
|
minHeight: "200px", // Minimum height constraint
|
||||||
height: `calc(100% - ${
|
height: `calc(100% - ${
|
||||||
(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
|
(topActive ? panelSizeHeight : 0) + (bottomActive ? panelSizeHeight : 0)
|
||||||
}px)`,
|
}px)`,
|
||||||
top: topActive ? `${panelSize}px` : "0",
|
top: topActive ? `${panelSizeHeight}px` : "0",
|
||||||
bottom: bottomActive ? `${panelSize}px` : "0",
|
bottom: bottomActive ? `${panelSizeHeight}px` : "0",
|
||||||
[side]: "0",
|
[side]: "0",
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[selectedZone.panelOrder, isPlaying]
|
[
|
||||||
|
selectedZone.panelOrder,
|
||||||
|
isPlaying,
|
||||||
|
canvasDimensions.width,
|
||||||
|
canvasDimensions.height,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
||||||
|
@ -153,10 +220,10 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
let addWidget = {
|
let addWidget = {
|
||||||
organization: organization,
|
organization: organization,
|
||||||
zoneId: selectedZone.zoneId,
|
zoneId: selectedZone.zoneId,
|
||||||
widget: newWidget
|
widget: newWidget,
|
||||||
}
|
};
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-widget:add", addWidget)
|
visualizationSocket.emit("v2:viz-widget:add", addWidget);
|
||||||
}
|
}
|
||||||
setSelectedZone((prev) => ({
|
setSelectedZone((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
@ -165,7 +232,6 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
|
// let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
|
||||||
|
|
||||||
// if (response.message === "Widget created successfully") {
|
// if (response.message === "Widget created successfully") {
|
||||||
// setSelectedZone((prev) => ({
|
// setSelectedZone((prev) => ({
|
||||||
// ...prev,
|
// ...prev,
|
||||||
|
@ -175,7 +241,6 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error adding widget:", error);
|
console.error("Error adding widget:", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -281,3 +346,5 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Panel;
|
export default Panel;
|
||||||
|
|
||||||
|
// canvasDimensions.width as percent
|
||||||
|
|
|
@ -7,7 +7,6 @@ import DisplayZone from "./DisplayZone";
|
||||||
import Scene from "../../../modules/scene/scene";
|
import Scene from "../../../modules/scene/scene";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
|
|
||||||
|
|
||||||
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
||||||
import {
|
import {
|
||||||
useAsset3dWidget,
|
useAsset3dWidget,
|
||||||
|
@ -24,7 +23,11 @@ import RenderOverlay from "../../templates/Overlay";
|
||||||
import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup";
|
import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup";
|
||||||
import DroppedObjects from "./DroppedFloatingWidgets";
|
import DroppedObjects from "./DroppedFloatingWidgets";
|
||||||
import EditWidgetOption from "../menu/EditWidgetOption";
|
import EditWidgetOption from "../menu/EditWidgetOption";
|
||||||
import { useRightClickSelected } from "../../../store/useZone3DWidgetStore";
|
import {
|
||||||
|
useEditWidgetOptionsStore,
|
||||||
|
useRightClickSelected,
|
||||||
|
useRightSelected,
|
||||||
|
} from "../../../store/useZone3DWidgetStore";
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
|
@ -58,8 +61,10 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
|
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
|
|
||||||
|
const { rightSelect, setRightSelect } = useRightSelected();
|
||||||
const { rightClickSelected, setRightClickSelected } = useRightClickSelected()
|
const { editWidgetOptions, setEditWidgetOptions } =
|
||||||
|
useEditWidgetOptionsStore();
|
||||||
|
const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
|
||||||
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
|
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
|
||||||
|
|
||||||
const [floatingWidgets, setFloatingWidgets] = useState<
|
const [floatingWidgets, setFloatingWidgets] = useState<
|
||||||
|
@ -69,6 +74,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||||
const { visualizationSocket } = useSocketStore();
|
const { visualizationSocket } = useSocketStore();
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function GetZoneData() {
|
async function GetZoneData() {
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
|
@ -96,7 +102,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
setZonesData(formattedData);
|
setZonesData(formattedData);
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
GetZoneData();
|
GetZoneData();
|
||||||
|
@ -142,8 +148,8 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
const relativeX = event.clientX - canvasRect.left;
|
const relativeX = event.clientX - canvasRect.left;
|
||||||
const relativeY = event.clientY - canvasRect.top;
|
const relativeY = event.clientY - canvasRect.top;
|
||||||
|
|
||||||
const newPosition = determinePosition(canvasRect, relativeX, relativeY)
|
const newPosition = determinePosition(canvasRect, relativeX, relativeY);
|
||||||
console.log('newPosition: ', newPosition);
|
console.log("newPosition: ", newPosition);
|
||||||
const newObject = {
|
const newObject = {
|
||||||
...droppedData,
|
...droppedData,
|
||||||
id: generateUniqueId(),
|
id: generateUniqueId(),
|
||||||
|
@ -162,12 +168,12 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
let addFloatingWidget = {
|
let addFloatingWidget = {
|
||||||
organization: organization,
|
organization: organization,
|
||||||
widget: newObject,
|
widget: newObject,
|
||||||
zoneId: selectedZone.zoneId
|
zoneId: selectedZone.zoneId,
|
||||||
}
|
};
|
||||||
console.log('newObject: ', newObject);
|
console.log("newObject: ", newObject);
|
||||||
|
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget)
|
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// let response = await addingFloatingWidgets(
|
// let response = await addingFloatingWidgets(
|
||||||
|
@ -194,76 +200,134 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
const editWidgetOptions = document.querySelector(
|
||||||
|
".editWidgetOptions-wrapper"
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
editWidgetOptions &&
|
||||||
|
!editWidgetOptions.contains(event.target as Node)
|
||||||
|
) {
|
||||||
|
setRightClickSelected(null);
|
||||||
|
setRightSelect(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
};
|
||||||
|
}, [setRightClickSelected]);
|
||||||
|
|
||||||
|
// Add this useEffect hook to your component
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
const editWidgetOptions = document.querySelector(
|
||||||
|
".editWidgetOptions-wrapper"
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
editWidgetOptions &&
|
||||||
|
!editWidgetOptions.contains(event.target as Node)
|
||||||
|
) {
|
||||||
|
setRightClickSelected(null);
|
||||||
|
setRightSelect(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
};
|
||||||
|
}, [setRightClickSelected]);
|
||||||
|
|
||||||
function handleRightClickSel(){}
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
ref={containerRef}
|
|
||||||
id="real-time-vis-canvas"
|
|
||||||
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
|
|
||||||
style={{
|
|
||||||
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
|
||||||
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
|
||||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{openConfirmationPopup && (
|
|
||||||
<RenderOverlay>
|
|
||||||
<ConfirmationPopup
|
|
||||||
message={"Are you sure want to delete?"}
|
|
||||||
onConfirm={() => console.log("confirm")}
|
|
||||||
onCancel={() => setOpenConfirmationPopup(false)}
|
|
||||||
/>
|
|
||||||
</RenderOverlay>
|
|
||||||
)}
|
|
||||||
<div
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
id="real-time-vis-canvas"
|
||||||
|
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
|
||||||
|
style={{
|
||||||
|
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
||||||
|
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
||||||
|
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="realTime-viz-wrapper">
|
||||||
|
{openConfirmationPopup && (
|
||||||
|
<RenderOverlay>
|
||||||
|
<ConfirmationPopup
|
||||||
|
message={"Are you sure want to delete?"}
|
||||||
|
onConfirm={() => console.log("confirm")}
|
||||||
|
onCancel={() => setOpenConfirmationPopup(false)}
|
||||||
|
/>
|
||||||
|
</RenderOverlay>
|
||||||
|
)}
|
||||||
|
{/* <div
|
||||||
className="scene-container"
|
className="scene-container"
|
||||||
style={{
|
style={{
|
||||||
height: "100%",
|
height: "100%",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
borderRadius:
|
borderRadius:
|
||||||
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
||||||
}}
|
}}
|
||||||
onDrop={(event) => handleDrop(event)}
|
onDrop={(event) => handleDrop(event)}
|
||||||
onDragOver={(event) => event.preventDefault()}
|
onDragOver={(event) => event.preventDefault()}
|
||||||
>
|
>
|
||||||
<Scene />
|
<Scene />
|
||||||
</div>
|
</div> */}
|
||||||
{activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />}
|
{activeModule === "visualization" && selectedZone.zoneName !== "" && (
|
||||||
{activeModule === "visualization" && <SocketRealTimeViz />}
|
<DroppedObjects />
|
||||||
|
|
||||||
{activeModule === "visualization" && widgetSubOption === "3D" && rightClickSelected && <EditWidgetOption
|
|
||||||
options={["Duplicate", "Vertical Move", "Horizontal Move", "Delete"]}
|
|
||||||
/>}
|
|
||||||
|
|
||||||
{activeModule === "visualization" && (
|
|
||||||
<>
|
|
||||||
<DisplayZone
|
|
||||||
zonesData={zonesData}
|
|
||||||
selectedZone={selectedZone}
|
|
||||||
setSelectedZone={setSelectedZone}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{!isPlaying && selectedZone?.zoneName !== "" && (
|
|
||||||
<AddButtons
|
|
||||||
hiddenPanels={hiddenPanels}
|
|
||||||
setHiddenPanels={setHiddenPanels}
|
|
||||||
selectedZone={selectedZone}
|
|
||||||
setSelectedZone={setSelectedZone}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
{activeModule === "visualization" && <SocketRealTimeViz />}
|
||||||
|
|
||||||
<Panel
|
{activeModule === "visualization" &&
|
||||||
selectedZone={selectedZone}
|
editWidgetOptions &&
|
||||||
setSelectedZone={setSelectedZone}
|
rightClickSelected && (
|
||||||
hiddenPanels={hiddenPanels}
|
<EditWidgetOption
|
||||||
setZonesData={setZonesData}
|
options={[
|
||||||
/>
|
"Duplicate",
|
||||||
</>
|
"Vertical Move",
|
||||||
)}
|
"Horizontal Move",
|
||||||
</div>
|
"RotateX",
|
||||||
|
"RotateY",
|
||||||
|
"Delete",
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{activeModule === "visualization" && (
|
||||||
|
<>
|
||||||
|
<DisplayZone
|
||||||
|
zonesData={zonesData}
|
||||||
|
selectedZone={selectedZone}
|
||||||
|
setSelectedZone={setSelectedZone}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!isPlaying && selectedZone?.zoneName !== "" && (
|
||||||
|
<AddButtons
|
||||||
|
hiddenPanels={hiddenPanels}
|
||||||
|
setHiddenPanels={setHiddenPanels}
|
||||||
|
selectedZone={selectedZone}
|
||||||
|
setSelectedZone={setSelectedZone}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Panel
|
||||||
|
selectedZone={selectedZone}
|
||||||
|
setSelectedZone={setSelectedZone}
|
||||||
|
hiddenPanels={hiddenPanels}
|
||||||
|
setZonesData={setZonesData}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ interface ListProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
console.log("items: ", items);
|
|
||||||
const { activeModule, setActiveModule } = useModuleStore();
|
const { activeModule, setActiveModule } = useModuleStore();
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
const { setSubModule } = useSubModuleStore();
|
const { setSubModule } = useSubModuleStore();
|
||||||
|
|
|
@ -1,26 +1,48 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useLeftData, useRightSelected, useTopData } from "../../../store/useZone3DWidgetStore";
|
import {
|
||||||
|
useEditWidgetOptionsStore,
|
||||||
|
useLeftData,
|
||||||
|
useRightClickSelected,
|
||||||
|
useRightSelected,
|
||||||
|
useTopData,
|
||||||
|
} from "../../../store/useZone3DWidgetStore";
|
||||||
|
|
||||||
interface EditWidgetOptionProps {
|
interface EditWidgetOptionProps {
|
||||||
options: string[];
|
options: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({ options }) => {
|
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
|
||||||
const { top, setTop } = useTopData()
|
options,
|
||||||
const { left, setLeft } = useLeftData()
|
}) => {
|
||||||
const { rightSelect, setRightSelect } = useRightSelected()
|
const { top } = useTopData();
|
||||||
|
const { left } = useLeftData();
|
||||||
|
const { setRightSelect } = useRightSelected();
|
||||||
|
const { setEditWidgetOptions } = useEditWidgetOptionsStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
console.log('left: ', left);
|
}, [top, left]);
|
||||||
console.log('top: ', top);
|
|
||||||
}, [top, left])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="editWidgetOptions-wrapper" style={{ top: top + "px", left: left + "px" }}>
|
<div
|
||||||
|
className="editWidgetOptions-wrapper"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: `${top}px`,
|
||||||
|
left: `${left}px`,
|
||||||
|
zIndex: 10000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="editWidgetOptions">
|
<div className="editWidgetOptions">
|
||||||
{options.map((option, index) => (
|
{options.map((option, index) => (
|
||||||
<div className="option" key={index} onClick={(e) => setRightSelect(option)}>
|
<div
|
||||||
|
className="option"
|
||||||
|
key={index}
|
||||||
|
onClick={(e) => {
|
||||||
|
setRightSelect(option);
|
||||||
|
setEditWidgetOptions(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{option}
|
{option}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -238,7 +238,7 @@ const BarGraphComponent = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("titleeeeeeeeeeeeeeeeeee",title);
|
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
// Memoize Theme Colors
|
// Memoize Theme Colors
|
||||||
|
|
|
@ -51,7 +51,7 @@ const DoughnutGraphComponent = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("titleeeeeeeeeeeeeeeeeee",title);
|
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
// Memoize Theme Colors
|
// Memoize Theme Colors
|
||||||
|
|
|
@ -51,7 +51,7 @@ const LineGraphComponent = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("titleeeeeeeeeeeeeeeeeee",title);
|
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
// Memoize Theme Colors
|
// Memoize Theme Colors
|
||||||
|
|
|
@ -237,7 +237,7 @@ const PieChartComponent = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("titleeeeeeeeeeeeeeeeeee",title);
|
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
// Memoize Theme Colors
|
// Memoize Theme Colors
|
||||||
|
|
|
@ -51,7 +51,7 @@ const PolarAreaGraphComponent = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("titleeeeeeeeeeeeeeeeeee",title);
|
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
// Memoize Theme Colors
|
// Memoize Theme Colors
|
||||||
|
|
|
@ -1,24 +1,36 @@
|
||||||
import React, { useState, useRef, useEffect } from "react";
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons";
|
import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons";
|
||||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
import { useActiveTool } from "../../../store/store";
|
||||||
|
import {
|
||||||
|
useAnimationPlaySpeed,
|
||||||
|
usePauseButtonStore,
|
||||||
|
usePlayButtonStore,
|
||||||
|
useResetButtonStore,
|
||||||
|
} from "../../../store/usePlayButtonStore";
|
||||||
|
|
||||||
const SimulationPlayer: React.FC = () => {
|
const SimulationPlayer: React.FC = () => {
|
||||||
const [speed, setSpeed] = useState<number>(1);
|
const { speed, setSpeed } = useAnimationPlaySpeed();
|
||||||
const [playSimulation, setPlaySimulation] = useState(false);
|
const [playSimulation, setPlaySimulation] = useState(false);
|
||||||
const { setIsPlaying } = usePlayButtonStore();
|
const { setIsPlaying } = usePlayButtonStore();
|
||||||
const sliderRef = useRef<HTMLDivElement>(null);
|
const sliderRef = useRef<HTMLDivElement>(null);
|
||||||
const isDragging = useRef(false);
|
const isDragging = useRef(false);
|
||||||
|
const { setActiveTool } = useActiveTool();
|
||||||
|
const { isPaused, setIsPaused } = usePauseButtonStore();
|
||||||
|
const { isReset, setReset } = useResetButtonStore();
|
||||||
|
|
||||||
// Button functions
|
// Button functions
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
|
setReset(true);
|
||||||
setSpeed(1);
|
setSpeed(1);
|
||||||
};
|
};
|
||||||
const handlePlayStop = () => {
|
const handlePlayStop = () => {
|
||||||
|
setIsPaused(!isPaused);
|
||||||
setPlaySimulation(!playSimulation);
|
setPlaySimulation(!playSimulation);
|
||||||
};
|
};
|
||||||
const handleExit = () => {
|
const handleExit = () => {
|
||||||
setPlaySimulation(false);
|
setPlaySimulation(false);
|
||||||
setIsPlaying(false);
|
setIsPlaying(false);
|
||||||
|
setActiveTool("cursor")
|
||||||
};
|
};
|
||||||
|
|
||||||
// Slider functions starts
|
// Slider functions starts
|
||||||
|
@ -27,7 +39,7 @@ const SimulationPlayer: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const calculateHandlePosition = () => {
|
const calculateHandlePosition = () => {
|
||||||
return ((speed - 0.5) / (50 - 0.5)) * 100;
|
return ((speed - 0.5) / (8 - 0.5)) * 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseDown = () => {
|
const handleMouseDown = () => {
|
||||||
|
@ -115,7 +127,7 @@ const SimulationPlayer: React.FC = () => {
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
min="0.5"
|
min="0.5"
|
||||||
max="50"
|
max="8"
|
||||||
step="0.1"
|
step="0.1"
|
||||||
value={speed}
|
value={speed}
|
||||||
onChange={handleSpeedChange}
|
onChange={handleSpeedChange}
|
||||||
|
@ -123,7 +135,7 @@ const SimulationPlayer: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="max-value">50x</div>
|
<div className="max-value">8x</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,111 +1,68 @@
|
||||||
import PolygonGenerator from "./polygonGenerator";
|
import { useEffect, useState } from "react";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { Line } from "@react-three/drei";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useNavMesh, useSimulationStates } from "../../../store/store";
|
||||||
import * as THREE from "three";
|
|
||||||
import * as Types from "../../../types/world/worldTypes";
|
|
||||||
import PathNavigator from "./pathNavigator";
|
import PathNavigator from "./pathNavigator";
|
||||||
import NavMeshDetails from "./navMeshDetails";
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
import {
|
|
||||||
useSelectedActionSphere,
|
|
||||||
useSimulationPaths,
|
|
||||||
} from "../../../store/store";
|
|
||||||
|
|
||||||
const Agv = ({
|
type PathPoints = {
|
||||||
lines,
|
modelUuid: string;
|
||||||
plane,
|
modelSpeed: number;
|
||||||
}: {
|
bufferTime: number;
|
||||||
lines: Types.RefLines;
|
points: { x: number; y: number; z: number }[];
|
||||||
plane: Types.RefMesh;
|
hitCount: number;
|
||||||
}) => {
|
};
|
||||||
const [pathPoints, setPathPoints] = useState<
|
|
||||||
{
|
|
||||||
uuid: string;
|
|
||||||
points: { x: number; y: number; z: number }[];
|
|
||||||
}[]
|
|
||||||
>([]);
|
|
||||||
const { simulationPaths } = useSimulationPaths();
|
|
||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
|
||||||
useEffect(() => {
|
|
||||||
if (!Array.isArray(simulationPaths)) {
|
|
||||||
} else {
|
|
||||||
let agvModels = simulationPaths.filter(
|
|
||||||
(val: any) => val.modelName === "agv"
|
|
||||||
);
|
|
||||||
|
|
||||||
let findMesh = agvModels.filter(
|
const Agv = () => {
|
||||||
(val: any) =>
|
const [pathPoints, setPathPoints] = useState<PathPoints[]>([]);
|
||||||
val.modeluuid === selectedActionSphere?.path?.modeluuid &&
|
const { simulationStates } = useSimulationStates();
|
||||||
val.type === "Vehicle"
|
const { navMesh } = useNavMesh();
|
||||||
);
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
|
||||||
const result =
|
useEffect(() => {
|
||||||
findMesh.length > 0 &&
|
if (simulationStates.length > 0) {
|
||||||
findMesh[0].type === "Vehicle" &&
|
|
||||||
typeof findMesh[0].point?.actions.start === "object" &&
|
|
||||||
typeof findMesh[0].point?.actions.end === "object" &&
|
|
||||||
"x" in findMesh[0].point.actions.start &&
|
|
||||||
"y" in findMesh[0].point.actions.start &&
|
|
||||||
"x" in findMesh[0].point.actions.end &&
|
|
||||||
"y" in findMesh[0].point.actions.end
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
uuid: findMesh[0].modeluuid, // Ensure it's a number
|
|
||||||
|
|
||||||
points: [
|
const agvModels = simulationStates.filter((val) => val.modelName === "agv" && val.type === "Vehicle");
|
||||||
{
|
|
||||||
x: findMesh[0].position[0],
|
|
||||||
y: findMesh[0].position[1],
|
|
||||||
z: findMesh[0].position[2],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: findMesh[0].point.actions.start.x,
|
|
||||||
y: 0,
|
|
||||||
z: findMesh[0].point.actions.start.y,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: findMesh[0].point.actions.end.x,
|
|
||||||
y: 0,
|
|
||||||
z: findMesh[0].point.actions.end.y,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [];
|
|
||||||
if (result.length > 0) {
|
|
||||||
setPathPoints((prev) => {
|
|
||||||
const existingUUIDs = new Set(prev.map((item) => item.uuid));
|
|
||||||
const newItems = result.filter(
|
|
||||||
(item) => !existingUUIDs.has(item.uuid)
|
|
||||||
);
|
|
||||||
return [...prev, ...newItems];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [simulationPaths, selectedActionSphere]);
|
|
||||||
|
|
||||||
let groupRef = useRef() as Types.RefGroup;
|
const newPathPoints = agvModels.filter((model: any) => model.points && model.points.actions && typeof model.points.actions.start === "object" && typeof model.points.actions.end === "object" && "x" in model.points.actions.start && "y" in model.points.actions.start && "x" in model.points.actions.end && "y" in model.points.actions.end)
|
||||||
const [navMesh, setNavMesh] = useState();
|
.map((model: any) => ({
|
||||||
|
modelUuid: model.modeluuid,
|
||||||
|
modelSpeed: model.points.speed,
|
||||||
|
bufferTime: model.points.actions.buffer,
|
||||||
|
hitCount: model.points.actions.hitCount,
|
||||||
|
points: [
|
||||||
|
{ x: model.position[0], y: model.position[1], z: model.position[2] },
|
||||||
|
{ x: model.points.actions.start.x, y: 0, z: model.points.actions.start.y },
|
||||||
|
{ x: model.points.actions.end.x, y: 0, z: model.points.actions.end.y },
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
setPathPoints(newPathPoints);
|
||||||
<>
|
}
|
||||||
<PolygonGenerator groupRef={groupRef} lines={lines} plane={plane} />
|
}, [simulationStates]);
|
||||||
<NavMeshDetails
|
|
||||||
lines={lines}
|
return (
|
||||||
setNavMesh={setNavMesh}
|
<>
|
||||||
groupRef={groupRef}
|
{pathPoints.map((pair, i) => (
|
||||||
plane={plane}
|
<group key={i} visible={!isPlaying}>
|
||||||
/>
|
<PathNavigator
|
||||||
{pathPoints.map((pair, i) => (
|
navMesh={navMesh}
|
||||||
<PathNavigator
|
pathPoints={pair.points}
|
||||||
navMesh={navMesh}
|
id={pair.modelUuid}
|
||||||
selectedPoints={pair.points}
|
speed={pair.modelSpeed}
|
||||||
id={pair.uuid}
|
bufferTime={pair.bufferTime}
|
||||||
key={i}
|
hitCount={pair.hitCount}
|
||||||
/>
|
/>
|
||||||
))}
|
|
||||||
<group ref={groupRef} visible={false} name="Meshes"></group>
|
{pair.points.slice(1).map((point, idx) => (
|
||||||
</>
|
<mesh position={[point.x, point.y, point.z]} key={idx}>
|
||||||
);
|
<sphereGeometry args={[0.3, 15, 15]} />
|
||||||
|
<meshStandardMaterial color="red" />
|
||||||
|
</mesh>
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Agv;
|
export default Agv;
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { useRef } from "react";
|
||||||
|
import { useNavMesh } from "../../../store/store";
|
||||||
|
import PolygonGenerator from "./polygonGenerator";
|
||||||
|
import NavMeshDetails from "./navMeshDetails";
|
||||||
|
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
|
|
||||||
|
type NavMeshCreatorProps = {
|
||||||
|
lines: Types.RefLines
|
||||||
|
};
|
||||||
|
|
||||||
|
function NavMeshCreator({ lines }: NavMeshCreatorProps) {
|
||||||
|
let groupRef = useRef() as Types.RefGroup;
|
||||||
|
const { setNavMesh } = useNavMesh();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PolygonGenerator groupRef={groupRef} lines={lines} />
|
||||||
|
<NavMeshDetails lines={lines} setNavMesh={setNavMesh} groupRef={groupRef} />
|
||||||
|
|
||||||
|
<group ref={groupRef} visible={false} name="Meshes">
|
||||||
|
<mesh rotation-x={CONSTANTS.planeConfig.rotation} position={CONSTANTS.planeConfig.position3D} name="Plane" receiveShadow>
|
||||||
|
<planeGeometry args={[300, 300]} />
|
||||||
|
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
|
||||||
|
</mesh>
|
||||||
|
</group>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NavMeshCreator
|
|
@ -10,14 +10,12 @@ interface NavMeshDetailsProps {
|
||||||
setNavMesh: (navMesh: any) => void;
|
setNavMesh: (navMesh: any) => void;
|
||||||
groupRef: React.MutableRefObject<THREE.Group | null>;
|
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||||
lines: Types.RefLines;
|
lines: Types.RefLines;
|
||||||
plane: Types.RefMesh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NavMeshDetails({
|
export default function NavMeshDetails({
|
||||||
lines,
|
lines,
|
||||||
setNavMesh,
|
setNavMesh,
|
||||||
groupRef,
|
groupRef,
|
||||||
plane,
|
|
||||||
}: NavMeshDetailsProps) {
|
}: NavMeshDetailsProps) {
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
|
|
||||||
|
@ -34,14 +32,13 @@ export default function NavMeshDetails({
|
||||||
|
|
||||||
const [positions, indices] = getPositionsAndIndices(meshes);
|
const [positions, indices] = getPositionsAndIndices(meshes);
|
||||||
|
|
||||||
const cs = 0.25;
|
const cellSize = 0.35;
|
||||||
const ch = 0.69;
|
const cellHeight = 0.7;
|
||||||
const walkableRadius = 0.5;
|
const walkableRadius = 0.5;
|
||||||
|
|
||||||
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
|
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
|
||||||
cs,
|
cs: cellSize,
|
||||||
ch,
|
ch: cellHeight,
|
||||||
walkableRadius: Math.round(walkableRadius / ch),
|
walkableRadius: Math.round(walkableRadius / cellHeight),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!success || !navMesh) {
|
if (!success || !navMesh) {
|
||||||
|
@ -50,10 +47,14 @@ export default function NavMeshDetails({
|
||||||
|
|
||||||
setNavMesh(navMesh);
|
setNavMesh(navMesh);
|
||||||
|
|
||||||
|
scene.children
|
||||||
|
.filter((child) => child instanceof DebugDrawer)
|
||||||
|
.forEach((child) => scene.remove(child));
|
||||||
|
|
||||||
const debugDrawer = new DebugDrawer();
|
const debugDrawer = new DebugDrawer();
|
||||||
debugDrawer.drawNavMesh(navMesh);
|
debugDrawer.drawNavMesh(navMesh);
|
||||||
// scene.add(debugDrawer);
|
// scene.add(debugDrawer);
|
||||||
} catch (error) {}
|
} catch (error) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
initializeNavigation();
|
initializeNavigation();
|
||||||
|
|
|
@ -3,147 +3,207 @@ import * as THREE from "three";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { NavMeshQuery } from "@recast-navigation/core";
|
import { NavMeshQuery } from "@recast-navigation/core";
|
||||||
import { Line } from "@react-three/drei";
|
import { Line } from "@react-three/drei";
|
||||||
import { useTh } from "leva/dist/declarations/src/styles";
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
import { useActiveTool } from "../../../store/store";
|
|
||||||
|
|
||||||
// Define interface for props
|
|
||||||
interface PathNavigatorProps {
|
interface PathNavigatorProps {
|
||||||
navMesh: any;
|
navMesh: any;
|
||||||
selectedPoints: any;
|
pathPoints: any;
|
||||||
id: string;
|
id: string;
|
||||||
|
speed: number;
|
||||||
|
bufferTime: number;
|
||||||
|
hitCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PathNavigator({
|
export default function PathNavigator({
|
||||||
navMesh,
|
navMesh,
|
||||||
selectedPoints,
|
pathPoints,
|
||||||
id,
|
id,
|
||||||
|
speed,
|
||||||
|
bufferTime,
|
||||||
|
hitCount
|
||||||
}: PathNavigatorProps) {
|
}: PathNavigatorProps) {
|
||||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
const progressRef = useRef(0);
|
const [currentPhase, setCurrentPhase] = useState<'initial' | 'loop'>('initial');
|
||||||
const distancesRef = useRef<number[]>([]);
|
const [toPickupPath, setToPickupPath] = useState<[number, number, number][]>([]);
|
||||||
const totalDistanceRef = useRef(0);
|
const [pickupDropPath, setPickupDropPath] = useState<[number, number, number][]>([]);
|
||||||
const currentSegmentIndex = useRef(0);
|
const [dropPickupPath, setDropPickupPath] = useState<[number, number, number][]>([]);
|
||||||
const { scene } = useThree();
|
const [initialPosition, setInitialPosition] = useState<THREE.Vector3 | null>(null);
|
||||||
const { activeTool } = useActiveTool();
|
const [initialRotation, setInitialRotation] = useState<THREE.Euler | null>(null);
|
||||||
const [startPoint, setStartPoint] = useState(new THREE.Vector3());
|
|
||||||
const meshRef = useRef<THREE.Mesh | null>(null);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!scene || !id || path.length < 2) return;
|
|
||||||
|
|
||||||
let totalDistance = 0;
|
const distancesRef = useRef<number[]>([]);
|
||||||
const distances: number[] = [];
|
const totalDistanceRef = useRef(0);
|
||||||
for (let i = 0; i < path.length - 1; i++) {
|
const progressRef = useRef(0);
|
||||||
const start = new THREE.Vector3(...path[i]);
|
const isWaiting = useRef(false);
|
||||||
const end = new THREE.Vector3(...path[i + 1]);
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const segmentDistance = start.distanceTo(end);
|
|
||||||
distances.push(segmentDistance);
|
|
||||||
totalDistance += segmentDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
distancesRef.current = distances;
|
const { scene } = useThree();
|
||||||
totalDistanceRef.current = totalDistance;
|
const { isPlaying } = usePlayButtonStore();
|
||||||
progressRef.current = 0; // Reset progress when the path changes
|
|
||||||
}, [path]);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!navMesh || selectedPoints.length === 0) return;
|
|
||||||
|
|
||||||
// Flatten the selectedPoints array into a single list of points
|
useEffect(() => {
|
||||||
const allPoints = selectedPoints.flat();
|
const object = scene.getObjectByProperty("uuid", id);
|
||||||
|
if (object) {
|
||||||
|
setInitialPosition(object.position.clone());
|
||||||
|
setInitialRotation(object.rotation.clone());
|
||||||
|
}
|
||||||
|
}, [scene, id]);
|
||||||
|
|
||||||
// Compute paths between consecutive points
|
const computePath = (start: any, end: any) => {
|
||||||
const computedPath: [number, number, number][] = [];
|
try {
|
||||||
for (let i = 0; i < allPoints.length - 1; i++) {
|
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||||
const start = allPoints[i];
|
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
||||||
setStartPoint(
|
return segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [];
|
||||||
new THREE.Vector3(allPoints[0].x, allPoints[0].y, allPoints[0].z)
|
} catch {
|
||||||
);
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const end = allPoints[i + 1];
|
const resetState = () => {
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
timeoutRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
setPath([]);
|
||||||
const navMeshQuery = new NavMeshQuery(navMesh);
|
setCurrentPhase('initial');
|
||||||
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
setPickupDropPath([]);
|
||||||
|
setDropPickupPath([]);
|
||||||
|
distancesRef.current = [];
|
||||||
|
totalDistanceRef.current = 0;
|
||||||
|
progressRef.current = 0;
|
||||||
|
isWaiting.current = false;
|
||||||
|
|
||||||
if (segmentPath && segmentPath.length > 0) {
|
if (initialPosition && initialRotation) {
|
||||||
computedPath.push(
|
const object = scene.getObjectByProperty("uuid", id);
|
||||||
...segmentPath.map(({ x, y, z }): [number, number, number] => [
|
if (object) {
|
||||||
x,
|
object.position.copy(initialPosition);
|
||||||
y + 0.1,
|
object.rotation.copy(initialRotation);
|
||||||
z,
|
}
|
||||||
])
|
}
|
||||||
);
|
};
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the full computed path
|
useEffect(() => {
|
||||||
|
if (!isPlaying) {
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
|
||||||
if (computedPath.length > 0) {
|
if (!navMesh || pathPoints.length < 2) return;
|
||||||
setPath(computedPath);
|
|
||||||
currentSegmentIndex.current = 0; // Reset to the first segment
|
|
||||||
}
|
|
||||||
}, [selectedPoints, navMesh, path]);
|
|
||||||
|
|
||||||
useFrame((_, delta) => {
|
const [pickup, drop] = pathPoints.slice(-2);
|
||||||
if (!scene || !id || path.length < 2) return;
|
const object = scene.getObjectByProperty("uuid", id);
|
||||||
|
if (!object) return;
|
||||||
|
|
||||||
// Find the object in the scene
|
const currentPosition = { x: object.position.x, y: object.position.y, z: object.position.z };
|
||||||
const findObject = scene.getObjectByProperty("uuid", id);
|
|
||||||
if (activeTool === "play") {
|
|
||||||
if (!findObject) return;
|
|
||||||
|
|
||||||
const speed = 5;
|
const toPickupPath = computePath(currentPosition, pickup);
|
||||||
progressRef.current += delta * speed;
|
const pickupToDropPath = computePath(pickup, drop);
|
||||||
|
const dropToPickupPath = computePath(drop, pickup);
|
||||||
|
|
||||||
let coveredDistance = progressRef.current;
|
if (toPickupPath.length && pickupToDropPath.length && dropToPickupPath.length) {
|
||||||
let accumulatedDistance = 0;
|
setPickupDropPath(pickupToDropPath);
|
||||||
let index = 0;
|
setDropPickupPath(dropToPickupPath);
|
||||||
|
setToPickupPath(toPickupPath);
|
||||||
|
setPath(toPickupPath);
|
||||||
|
setCurrentPhase('initial');
|
||||||
|
}
|
||||||
|
}, [navMesh, pathPoints, hitCount, isPlaying]);
|
||||||
|
|
||||||
// Determine the current segment of the path
|
useEffect(() => {
|
||||||
while (
|
if (path.length < 2) return;
|
||||||
index < distancesRef.current.length &&
|
|
||||||
coveredDistance > accumulatedDistance + distancesRef.current[index]
|
|
||||||
) {
|
|
||||||
accumulatedDistance += distancesRef.current[index];
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the object has reached the end of the path, stop moving
|
let total = 0;
|
||||||
if (index >= distancesRef.current.length) {
|
const segmentDistances = path.slice(0, -1).map((point, i) => {
|
||||||
progressRef.current = totalDistanceRef.current;
|
const dist = new THREE.Vector3(...point).distanceTo(new THREE.Vector3(...path[i + 1]));
|
||||||
return;
|
total += dist;
|
||||||
}
|
return dist;
|
||||||
|
});
|
||||||
|
|
||||||
// Interpolate position within the current segment
|
distancesRef.current = segmentDistances;
|
||||||
const start = new THREE.Vector3(...path[index]);
|
totalDistanceRef.current = total;
|
||||||
const end = new THREE.Vector3(...path[index + 1]);
|
progressRef.current = 0;
|
||||||
const segmentDistance = distancesRef.current[index];
|
isWaiting.current = false;
|
||||||
|
}, [path]);
|
||||||
|
|
||||||
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
useFrame((_, delta) => {
|
||||||
const position = start.clone().lerp(end, t);
|
if (!isPlaying || path.length < 2 || !scene || !id) return;
|
||||||
findObject.position.copy(position);
|
|
||||||
|
|
||||||
// Rotate the object to face the direction of movement
|
const object = scene.getObjectByProperty("uuid", id);
|
||||||
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
if (!object) return;
|
||||||
const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(
|
|
||||||
new THREE.Vector3(0, 0, 1), // Assuming forward direction is (0, 0, 1)
|
|
||||||
direction
|
|
||||||
);
|
|
||||||
findObject.quaternion.slerp(targetQuaternion, 0.1); // Smoothly interpolate rotation
|
|
||||||
} else if (activeTool === "cursor") {
|
|
||||||
findObject?.position.copy(startPoint);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
const speedFactor = speed;
|
||||||
<>
|
progressRef.current += delta * speedFactor;
|
||||||
{path.length > 0 && <Line points={path} color="blue" lineWidth={3} />}
|
|
||||||
{/* {path.length > 0 && (
|
let covered = progressRef.current;
|
||||||
<mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}>
|
let accumulated = 0;
|
||||||
<boxGeometry args={[1, 1, 1]} />
|
let index = 0;
|
||||||
<meshNormalMaterial />
|
|
||||||
</mesh>
|
while (
|
||||||
)} */}
|
index < distancesRef.current.length &&
|
||||||
</>
|
covered > accumulated + distancesRef.current[index]
|
||||||
);
|
) {
|
||||||
}
|
accumulated += distancesRef.current[index];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= distancesRef.current.length) {
|
||||||
|
progressRef.current = totalDistanceRef.current;
|
||||||
|
|
||||||
|
if (!isWaiting.current) {
|
||||||
|
isWaiting.current = true;
|
||||||
|
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
if (currentPhase === 'initial') {
|
||||||
|
setPath(pickupDropPath);
|
||||||
|
setCurrentPhase('loop');
|
||||||
|
} else {
|
||||||
|
setPath(prevPath =>
|
||||||
|
prevPath === pickupDropPath ? dropPickupPath : pickupDropPath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
progressRef.current = 0;
|
||||||
|
isWaiting.current = false;
|
||||||
|
}, bufferTime * 1000);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = new THREE.Vector3(...path[index]);
|
||||||
|
const end = new THREE.Vector3(...path[index + 1]);
|
||||||
|
const dist = distancesRef.current[index];
|
||||||
|
const t = THREE.MathUtils.clamp((covered - accumulated) / dist, 0, 1);
|
||||||
|
const position = start.clone().lerp(end, t);
|
||||||
|
|
||||||
|
object.position.copy(position);
|
||||||
|
|
||||||
|
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
||||||
|
const targetRotationY = Math.atan2(direction.x, direction.z);
|
||||||
|
|
||||||
|
let angleDifference = targetRotationY - object.rotation.y;
|
||||||
|
angleDifference = ((angleDifference + Math.PI) % (Math.PI * 2)) - Math.PI;
|
||||||
|
object.rotation.y += angleDifference * 0.1;
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group name="path-navigator-lines" visible={!isPlaying} >
|
||||||
|
{toPickupPath.length > 0 && (
|
||||||
|
<Line points={toPickupPath} color="blue" lineWidth={3} dashed dashSize={0.75} dashScale={2} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{pickupDropPath.length > 0 && (
|
||||||
|
<Line points={pickupDropPath} color="red" lineWidth={3} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{dropPickupPath.length > 0 && (
|
||||||
|
<Line points={dropPickupPath} color="red" lineWidth={3} />
|
||||||
|
)}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
|
@ -6,21 +6,12 @@ import arrayLinesToObject from "../geomentries/lines/lineConvertions/arrayLinesT
|
||||||
interface PolygonGeneratorProps {
|
interface PolygonGeneratorProps {
|
||||||
groupRef: React.MutableRefObject<THREE.Group | null>;
|
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||||
lines: Types.RefLines;
|
lines: Types.RefLines;
|
||||||
plane: Types.RefMesh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PolygonGenerator({
|
export default function PolygonGenerator({
|
||||||
groupRef,
|
groupRef,
|
||||||
lines,
|
lines,
|
||||||
plane,
|
|
||||||
}: PolygonGeneratorProps) {
|
}: PolygonGeneratorProps) {
|
||||||
// const [rooms, setRooms] = useState<THREE.Vector3[][]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (groupRef.current && plane.current) {
|
|
||||||
groupRef.current.add(plane.current.clone());
|
|
||||||
}
|
|
||||||
}, [groupRef, plane]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let allLines = arrayLinesToObject(lines.current);
|
let allLines = arrayLinesToObject(lines.current);
|
||||||
|
@ -37,13 +28,14 @@ export default function PolygonGenerator({
|
||||||
uuid: point.uuid,
|
uuid: point.uuid,
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result || result.some((line) => !line)) {
|
if (!result || result.some((line) => !line)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lineFeatures = result?.map((line: any) =>
|
const lineFeatures = result?.map((line: any) =>
|
||||||
turf.lineString(line.map((p: any) => p?.position))
|
turf.lineString(line.map((p: any) => p?.position))
|
||||||
);
|
);
|
||||||
|
|
||||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
||||||
renderWallGeometry(wallPoints);
|
renderWallGeometry(wallPoints);
|
||||||
|
@ -79,8 +71,8 @@ export default function PolygonGenerator({
|
||||||
groupRef.current?.add(mesh);
|
groupRef.current?.add(mesh);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [lines.current]);
|
}, [lines.current]);
|
||||||
|
|
||||||
const renderWallGeometry = (walls: THREE.Vector3[][]) => {
|
const renderWallGeometry = (walls: THREE.Vector3[][]) => {
|
||||||
|
|
|
@ -24,7 +24,7 @@ async function addAssetModel(
|
||||||
socket: Socket<any>,
|
socket: Socket<any>,
|
||||||
selectedItem: any,
|
selectedItem: any,
|
||||||
setSelectedItem: any,
|
setSelectedItem: any,
|
||||||
setSimulationPaths: any,
|
setSimulationStates: any,
|
||||||
plane: Types.RefMesh,
|
plane: Types.RefMesh,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ async function addAssetModel(
|
||||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||||
if (cachedModel) {
|
if (cachedModel) {
|
||||||
// console.log(`[Cache] Fetching ${selectedItem.name}`);
|
// console.log(`[Cache] Fetching ${selectedItem.name}`);
|
||||||
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||||
|
@ -78,7 +78,7 @@ async function addAssetModel(
|
||||||
URL.revokeObjectURL(blobUrl);
|
URL.revokeObjectURL(blobUrl);
|
||||||
THREE.Cache.remove(blobUrl);
|
THREE.Cache.remove(blobUrl);
|
||||||
THREE.Cache.add(selectedItem.id, gltf);
|
THREE.Cache.add(selectedItem.id, gltf);
|
||||||
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
||||||
|
@ -90,7 +90,7 @@ async function addAssetModel(
|
||||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||||
await storeGLTF(selectedItem.id, modelBlob);
|
await storeGLTF(selectedItem.id, modelBlob);
|
||||||
THREE.Cache.add(selectedItem.id, gltf);
|
THREE.Cache.add(selectedItem.id, gltf);
|
||||||
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
||||||
|
@ -113,7 +113,7 @@ async function handleModelLoad(
|
||||||
tempLoader: Types.RefMesh,
|
tempLoader: Types.RefMesh,
|
||||||
isTempLoader: Types.RefBoolean,
|
isTempLoader: Types.RefBoolean,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
setSimulationPaths: any,
|
setSimulationStates: any,
|
||||||
socket: Socket<any>
|
socket: Socket<any>
|
||||||
) {
|
) {
|
||||||
const model = gltf.scene.clone();
|
const model = gltf.scene.clone();
|
||||||
|
@ -136,7 +136,7 @@ async function handleModelLoad(
|
||||||
tempLoader.current = undefined;
|
tempLoader.current = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newFloorItem: Types.FloorItemType = {
|
const newFloorItem: Types.EventData = {
|
||||||
modeluuid: model.uuid,
|
modeluuid: model.uuid,
|
||||||
modelname: selectedItem.name,
|
modelname: selectedItem.name,
|
||||||
modelfileID: selectedItem.id,
|
modelfileID: selectedItem.id,
|
||||||
|
@ -154,7 +154,7 @@ async function handleModelLoad(
|
||||||
if (res.type === "Conveyor") {
|
if (res.type === "Conveyor") {
|
||||||
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
|
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
|
||||||
|
|
||||||
const backendEventData: Extract<Types.FloorItemType['eventData'], { type: 'Conveyor' }> = {
|
const backendEventData: Extract<Types.EventData['eventData'], { type: 'Conveyor' }> = {
|
||||||
type: 'Conveyor',
|
type: 'Conveyor',
|
||||||
points: res.points.map((point: any, index: number) => ({
|
points: res.points.map((point: any, index: number) => ({
|
||||||
uuid: pointUUIDs[index],
|
uuid: pointUUIDs[index],
|
||||||
|
@ -167,11 +167,11 @@ async function handleModelLoad(
|
||||||
material: 'Inherit',
|
material: 'Inherit',
|
||||||
delay: 'Inherit',
|
delay: 'Inherit',
|
||||||
spawnInterval: 'Inherit',
|
spawnInterval: 'Inherit',
|
||||||
isUsed: false
|
isUsed: true
|
||||||
}],
|
}],
|
||||||
triggers: [],
|
triggers: [],
|
||||||
connections: {
|
connections: {
|
||||||
source: { pathUUID: model.uuid, pointUUID: pointUUIDs[index] },
|
source: { modelUUID: model.uuid, pointUUID: pointUUIDs[index] },
|
||||||
targets: []
|
targets: []
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
|
@ -189,7 +189,7 @@ async function handleModelLoad(
|
||||||
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||||
// false,
|
// false,
|
||||||
// true,
|
// true,
|
||||||
// newFloorItem.eventData
|
// { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
@ -206,8 +206,7 @@ async function handleModelLoad(
|
||||||
eventData: backendEventData,
|
eventData: backendEventData,
|
||||||
socketId: socket.id
|
socketId: socket.id
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('data: ', data);
|
|
||||||
setFloorItems((prevItems) => {
|
setFloorItems((prevItems) => {
|
||||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
@ -220,9 +219,71 @@ async function handleModelLoad(
|
||||||
eventData.position = newFloorItem.position;
|
eventData.position = newFloorItem.position;
|
||||||
eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
|
eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
...(prevEvents || []),
|
...(prevEvents || []),
|
||||||
eventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
eventData as Types.ConveyorEventsSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
} else if (res.type === "Vehicle") {
|
||||||
|
|
||||||
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
|
|
||||||
|
const backendEventData: Extract<Types.EventData['eventData'], { type: 'Vehicle' }> = {
|
||||||
|
type: "Vehicle",
|
||||||
|
points: {
|
||||||
|
uuid: pointUUID,
|
||||||
|
position: res.points.position as [number, number, number],
|
||||||
|
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: '', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||||
|
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
|
||||||
|
speed: 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// newFloorItem.modeluuid,
|
||||||
|
// newFloorItem.modelname,
|
||||||
|
// newFloorItem.modelfileID,
|
||||||
|
// newFloorItem.position,
|
||||||
|
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// { type: backendEventData.type, points: backendEventData.points }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: { type: backendEventData.type, points: backendEventData.points },
|
||||||
|
socketId: socket.id
|
||||||
|
};
|
||||||
|
|
||||||
|
const eventData: any = backendEventData;
|
||||||
|
eventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
eventData.modelName = newFloorItem.modelname;
|
||||||
|
eventData.position = newFloorItem.position;
|
||||||
|
|
||||||
|
setFloorItems((prevItems) => {
|
||||||
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
|
||||||
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
eventData as Types.VehicleEventsSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
@ -239,7 +300,7 @@ async function handleModelLoad(
|
||||||
// newFloorItem.position,
|
// newFloorItem.position,
|
||||||
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||||
// false,
|
// false,
|
||||||
// true
|
// true,
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
@ -255,7 +316,8 @@ async function handleModelLoad(
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
socketId: socket.id
|
socketId: socket.id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
setFloorItems((prevItems) => {
|
setFloorItems((prevItems) => {
|
||||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
@ -263,7 +325,6 @@ async function handleModelLoad(
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
||||||
|
|
|
@ -10,7 +10,7 @@ async function DeleteFloorItems(
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
hoveredDeletableFloorItem: Types.RefMesh,
|
hoveredDeletableFloorItem: Types.RefMesh,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
setSimulationPaths: any,
|
setSimulationStates: any,
|
||||||
socket: Socket<any>
|
socket: Socket<any>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ async function DeleteFloorItems(
|
||||||
}
|
}
|
||||||
setFloorItems(updatedItems);
|
setFloorItems(updatedItems);
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
|
||||||
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== removedItem.modeluuid);
|
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== removedItem.modeluuid);
|
||||||
return updatedEvents;
|
return updatedEvents;
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
useRenderDistance,
|
useRenderDistance,
|
||||||
useselectedFloorItem,
|
useselectedFloorItem,
|
||||||
useSelectedItem,
|
useSelectedItem,
|
||||||
useSimulationPaths,
|
useSimulationStates,
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useTransformMode,
|
useTransformMode,
|
||||||
|
@ -65,7 +65,7 @@ const FloorItemsGroup = ({
|
||||||
const { setselectedFloorItem } = useselectedFloorItem();
|
const { setselectedFloorItem } = useselectedFloorItem();
|
||||||
const { activeTool } = useActiveTool();
|
const { activeTool } = useActiveTool();
|
||||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const { setLoadingProgress } = useLoadingProgress();
|
const { setLoadingProgress } = useLoadingProgress();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
|
@ -110,9 +110,8 @@ const FloorItemsGroup = ({
|
||||||
}
|
}
|
||||||
gltfLoaderWorker.postMessage({ floorItems: data });
|
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||||
} else {
|
} else {
|
||||||
console.log('data: ', data);
|
|
||||||
gltfLoaderWorker.postMessage({ floorItems: [] });
|
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths);
|
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -131,7 +130,7 @@ const FloorItemsGroup = ({
|
||||||
updateLoadingProgress(progress);
|
updateLoadingProgress(progress);
|
||||||
|
|
||||||
if (loadedAssets === totalAssets) {
|
if (loadedAssets === totalAssets) {
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths);
|
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -249,7 +248,7 @@ const FloorItemsGroup = ({
|
||||||
itemsGroup,
|
itemsGroup,
|
||||||
hoveredDeletableFloorItem,
|
hoveredDeletableFloorItem,
|
||||||
setFloorItems,
|
setFloorItems,
|
||||||
setSimulationPaths,
|
setSimulationStates,
|
||||||
socket
|
socket
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -375,7 +374,7 @@ const FloorItemsGroup = ({
|
||||||
socket,
|
socket,
|
||||||
selectedItem,
|
selectedItem,
|
||||||
setSelectedItem,
|
setSelectedItem,
|
||||||
setSimulationPaths,
|
setSimulationStates,
|
||||||
plane
|
plane
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,203 +12,189 @@ import CollabUserIcon from "./collabUserIcon";
|
||||||
import { getAvatarColor } from "./users/functions/getAvatarColor";
|
import { getAvatarColor } from "./users/functions/getAvatarColor";
|
||||||
|
|
||||||
const CamModelsGroup = () => {
|
const CamModelsGroup = () => {
|
||||||
let navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const { activeUsers, setActiveUsers } = useActiveUsers();
|
const { activeUsers, setActiveUsers } = useActiveUsers();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const loader = new GLTFLoader();
|
|
||||||
const dracoLoader = new DRACOLoader();
|
|
||||||
const [cams, setCams] = useState<any[]>([]);
|
|
||||||
const [models, setModels] = useState<Record<string, { targetPosition: THREE.Vector3; targetRotation: THREE.Euler }>>({});
|
|
||||||
|
|
||||||
dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
|
const loader = new GLTFLoader();
|
||||||
loader.setDRACOLoader(dracoLoader);
|
const dracoLoader = new DRACOLoader();
|
||||||
|
dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
|
||||||
|
loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
useEffect(() => {
|
const [cams, setCams] = useState<any[]>([]);
|
||||||
if (!email) {
|
const [models, setModels] = useState<Record<string, { targetPosition: THREE.Vector3; targetRotation: THREE.Euler }>>({});
|
||||||
navigate("/");
|
|
||||||
}
|
|
||||||
if (!socket) return;
|
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
|
||||||
|
|
||||||
socket.on("userConnectResponse", (data: any) => {
|
const dedupeCams = (cams: any[]) => {
|
||||||
if (!groupRef.current) return;
|
const seen = new Set();
|
||||||
if (data.data.userData.email === email) return;
|
return cams.filter((cam) => {
|
||||||
if (socket.id === data.socketId || organization !== data.organization)
|
if (seen.has(cam.uuid)) return false;
|
||||||
return;
|
seen.add(cam.uuid);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const model = groupRef.current.getObjectByProperty(
|
const dedupeUsers = (users: any[]) => {
|
||||||
"uuid",
|
const seen = new Set();
|
||||||
data.data.userData._id
|
return users.filter((user) => {
|
||||||
);
|
if (seen.has(user._id)) return false;
|
||||||
if (model) {
|
seen.add(user._id);
|
||||||
groupRef.current.remove(model);
|
return true;
|
||||||
}
|
});
|
||||||
loader.load(camModel, (gltf) => {
|
};
|
||||||
const newModel = gltf.scene.clone();
|
|
||||||
newModel.uuid = data.data.userData._id;
|
|
||||||
newModel.position.set(
|
|
||||||
data.data.position.x,
|
|
||||||
data.data.position.y,
|
|
||||||
data.data.position.z
|
|
||||||
);
|
|
||||||
newModel.rotation.set(
|
|
||||||
data.data.rotation.x,
|
|
||||||
data.data.rotation.y,
|
|
||||||
data.data.rotation.z
|
|
||||||
);
|
|
||||||
newModel.userData = data.data.userData;
|
|
||||||
setCams((prev) => [...prev, newModel]);
|
|
||||||
setActiveUsers([...activeUsers, data.data.userData]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// socket.on("users:online", (data: any) => {
|
useEffect(() => {
|
||||||
// console.log('users online: ', data);
|
if (!email) navigate("/");
|
||||||
// })
|
|
||||||
|
|
||||||
socket.on("userDisConnectResponse", (data: any) => {
|
if (!socket) return;
|
||||||
if (!groupRef.current) return;
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
if (socket.id === data.socketId || organization !== data.organization)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setCams((prev) =>
|
socket.on("userConnectResponse", (data: any) => {
|
||||||
prev.filter((cam) => cam.uuid !== data.data.userData._id)
|
if (!groupRef.current) return;
|
||||||
);
|
if (data.data.userData.email === email) return;
|
||||||
setActiveUsers(
|
if (socket.id === data.socketId || organization !== data.organization) return;
|
||||||
activeUsers.filter((user: any) => user._id !== data.data.userData._id)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("cameraUpdateResponse", (data: any) => {
|
const model = groupRef.current.getObjectByProperty("uuid", data.data.userData._id);
|
||||||
if (
|
if (model) {
|
||||||
!groupRef.current ||
|
groupRef.current.remove(model);
|
||||||
socket.id === data.socketId ||
|
}
|
||||||
organization !== data.organization
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setModels((prev) => ({
|
loader.load(camModel, (gltf) => {
|
||||||
...prev,
|
const newModel = gltf.scene.clone();
|
||||||
[data.data.userId]: {
|
newModel.uuid = data.data.userData._id;
|
||||||
targetPosition: new THREE.Vector3(
|
newModel.position.set(
|
||||||
data.data.position.x,
|
data.data.position.x,
|
||||||
data.data.position.y,
|
data.data.position.y,
|
||||||
data.data.position.z
|
data.data.position.z
|
||||||
),
|
);
|
||||||
targetRotation: new THREE.Euler(
|
newModel.rotation.set(
|
||||||
data.data.rotation.x,
|
data.data.rotation.x,
|
||||||
data.data.rotation.y,
|
data.data.rotation.y,
|
||||||
data.data.rotation.z
|
data.data.rotation.z
|
||||||
),
|
);
|
||||||
},
|
newModel.userData = data.data.userData;
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
setCams((prev) => dedupeCams([...prev, newModel]));
|
||||||
socket.off("userConnectRespones");
|
setActiveUsers((prev: any) =>
|
||||||
socket.off("userDisConnectRespones");
|
dedupeUsers([...prev, data.data.userData])
|
||||||
socket.off("cameraUpdateResponse");
|
);
|
||||||
};
|
});
|
||||||
}, [socket, activeUsers]);
|
});
|
||||||
|
|
||||||
|
socket.on("userDisConnectResponse", (data: any) => {
|
||||||
|
if (!groupRef.current) return;
|
||||||
|
if (socket.id === data.socketId || organization !== data.organization) return;
|
||||||
|
|
||||||
// useEffect(() => {
|
setCams((prev) =>
|
||||||
// console.log(activeUsers);
|
prev.filter((cam) => cam.uuid !== data.data.userData._id)
|
||||||
// }, [activeUsers])
|
);
|
||||||
|
setActiveUsers((prev: any) =>
|
||||||
|
prev.filter((user: any) => user._id !== data.data.userData._id)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// useEffect(() => {
|
socket.on("cameraUpdateResponse", (data: any) => {
|
||||||
// console.log(models);
|
if (
|
||||||
// }, [models])
|
!groupRef.current ||
|
||||||
|
socket.id === data.socketId ||
|
||||||
|
organization !== data.organization
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
useFrame(() => {
|
setModels((prev) => ({
|
||||||
if (!groupRef.current) return;
|
...prev,
|
||||||
Object.keys(models).forEach((uuid) => {
|
[data.data.userId]: {
|
||||||
const model = groupRef.current!.getObjectByProperty("uuid", uuid);
|
targetPosition: new THREE.Vector3(
|
||||||
if (!model) return;
|
data.data.position.x,
|
||||||
|
data.data.position.y,
|
||||||
|
data.data.position.z
|
||||||
|
),
|
||||||
|
targetRotation: new THREE.Euler(
|
||||||
|
data.data.rotation.x,
|
||||||
|
data.data.rotation.y,
|
||||||
|
data.data.rotation.z
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
const { targetPosition, targetRotation } = models[uuid];
|
return () => {
|
||||||
model.position.lerp(targetPosition, 0.1);
|
socket.off("userConnectResponse");
|
||||||
model.rotation.x = THREE.MathUtils.lerp(
|
socket.off("userDisConnectResponse");
|
||||||
model.rotation.x,
|
socket.off("cameraUpdateResponse");
|
||||||
targetRotation.x,
|
};
|
||||||
0.1
|
}, [socket]);
|
||||||
);
|
|
||||||
model.rotation.y = THREE.MathUtils.lerp(
|
|
||||||
model.rotation.y,
|
|
||||||
targetRotation.y,
|
|
||||||
0.1
|
|
||||||
);
|
|
||||||
model.rotation.z = THREE.MathUtils.lerp(
|
|
||||||
model.rotation.z,
|
|
||||||
targetRotation.z,
|
|
||||||
0.1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useFrame(() => {
|
||||||
if (!groupRef.current) return;
|
if (!groupRef.current) return;
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
Object.keys(models).forEach((uuid) => {
|
||||||
getActiveUsersData(organization).then((data) => {
|
const model = groupRef.current!.getObjectByProperty("uuid", uuid);
|
||||||
const filteredData = data.cameraDatas.filter(
|
if (!model) return;
|
||||||
(camera: any) => camera.userData.email !== email
|
|
||||||
);
|
|
||||||
let a: any = [];
|
|
||||||
if (filteredData.length > 0) {
|
|
||||||
loader.load(camModel, (gltf) => {
|
|
||||||
const newCams = filteredData.map((cam: any) => {
|
|
||||||
const newModel = gltf.scene.clone();
|
|
||||||
newModel.uuid = cam.userData._id;
|
|
||||||
newModel.position.set(
|
|
||||||
cam.position.x,
|
|
||||||
cam.position.y,
|
|
||||||
cam.position.z
|
|
||||||
);
|
|
||||||
newModel.rotation.set(
|
|
||||||
cam.rotation.x,
|
|
||||||
cam.rotation.y,
|
|
||||||
cam.rotation.z
|
|
||||||
);
|
|
||||||
newModel.userData = cam.userData;
|
|
||||||
a.push(cam.userData);
|
|
||||||
return newModel;
|
|
||||||
});
|
|
||||||
setActiveUsers(a);
|
|
||||||
setCams((prev) => [...prev, ...newCams]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
const { targetPosition, targetRotation } = models[uuid];
|
||||||
<group ref={groupRef} name="Cam-Model-Group">
|
model.position.lerp(targetPosition, 0.1);
|
||||||
{cams.map((cam, index) => (
|
model.rotation.x = THREE.MathUtils.lerp(model.rotation.x, targetRotation.x, 0.1);
|
||||||
<primitive key={index} object={cam}>
|
model.rotation.y = THREE.MathUtils.lerp(model.rotation.y, targetRotation.y, 0.1);
|
||||||
<Html
|
model.rotation.z = THREE.MathUtils.lerp(model.rotation.z, targetRotation.z, 0.1);
|
||||||
as="div"
|
});
|
||||||
center
|
});
|
||||||
zIndexRange={[1, 0]}
|
|
||||||
sprite
|
useEffect(() => {
|
||||||
style={{
|
if (!groupRef.current) return;
|
||||||
color: "white",
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
textAlign: "center",
|
|
||||||
fontFamily: "Arial, sans-serif",
|
getActiveUsersData(organization).then((data) => {
|
||||||
}}
|
const filteredData = data.cameraDatas.filter(
|
||||||
position={[-0.015, 0, 0.7]}
|
(camera: any) => camera.userData.email !== email
|
||||||
>
|
);
|
||||||
<CollabUserIcon
|
|
||||||
userImage={""}
|
if (filteredData.length > 0) {
|
||||||
userName={cam.userData.userName}
|
loader.load(camModel, (gltf) => {
|
||||||
index={index}
|
const newCams = filteredData.map((cam: any) => {
|
||||||
color={getAvatarColor(index)}
|
const newModel = gltf.scene.clone();
|
||||||
/>
|
newModel.uuid = cam.userData._id;
|
||||||
</Html>
|
newModel.position.set(cam.position.x, cam.position.y, cam.position.z);
|
||||||
</primitive>
|
newModel.rotation.set(cam.rotation.x, cam.rotation.y, cam.rotation.z);
|
||||||
))}
|
newModel.userData = cam.userData;
|
||||||
</group>
|
return newModel;
|
||||||
);
|
});
|
||||||
|
|
||||||
|
const users = filteredData.map((cam: any) => cam.userData);
|
||||||
|
setActiveUsers((prev: any) => dedupeUsers([...prev, ...users]));
|
||||||
|
setCams((prev) => dedupeCams([...prev, ...newCams]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group ref={groupRef} name="Cam-Model-Group">
|
||||||
|
{cams.map((cam, index) => (
|
||||||
|
<primitive key={cam.uuid} object={cam}>
|
||||||
|
<Html
|
||||||
|
as="div"
|
||||||
|
center
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
sprite
|
||||||
|
style={{
|
||||||
|
color: "white",
|
||||||
|
textAlign: "center",
|
||||||
|
fontFamily: "Arial, sans-serif",
|
||||||
|
}}
|
||||||
|
position={[-0.015, 0, 0.7]}
|
||||||
|
>
|
||||||
|
<CollabUserIcon
|
||||||
|
userImage={""}
|
||||||
|
userName={cam.userData.userName}
|
||||||
|
index={index}
|
||||||
|
color={getAvatarColor(index)}
|
||||||
|
/>
|
||||||
|
</Html>
|
||||||
|
</primitive>
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CamModelsGroup;
|
export default CamModelsGroup;
|
||||||
|
|
|
@ -20,7 +20,24 @@ const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
||||||
{userImage ? (
|
{userImage ? (
|
||||||
<img className="user-image" src={userImage} alt={userName} />
|
<img className="user-image" src={userImage} alt={userName} />
|
||||||
) : (
|
) : (
|
||||||
<CustomAvatar name={userName} index={index} />
|
<CustomAvatar name={userName} index={index} color={color} />
|
||||||
|
// <div
|
||||||
|
// className="user-image"
|
||||||
|
// style={{
|
||||||
|
// lineHeight: "30px",
|
||||||
|
// textTransform: "uppercase",
|
||||||
|
// textAlign: "center",
|
||||||
|
// fontSize: "16px",
|
||||||
|
// borderRadius: "50%",
|
||||||
|
// backgroundColor: color,
|
||||||
|
// overflow: "hidden",
|
||||||
|
// backgroundSize: "cover",
|
||||||
|
// backgroundPosition: "center",
|
||||||
|
// color: "white",
|
||||||
|
// fontWeight: "bold",
|
||||||
|
// }}>
|
||||||
|
// {userName[0]}
|
||||||
|
// </div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="user-name" style={{ backgroundColor: color }}>
|
<div className="user-name" style={{ backgroundColor: color }}>
|
||||||
|
|
|
@ -143,10 +143,6 @@ export default function SocketResponses({
|
||||||
isVisible: data.data.isVisible,
|
isVisible: data.data.isVisible,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data.data.eventData) {
|
|
||||||
newFloorItem.eventData = data.data.eventData;
|
|
||||||
}
|
|
||||||
|
|
||||||
setFloorItems((prevItems: any) => {
|
setFloorItems((prevItems: any) => {
|
||||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
@ -221,10 +217,6 @@ export default function SocketResponses({
|
||||||
isVisible: data.data.isVisible,
|
isVisible: data.data.isVisible,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data.data.eventData) {
|
|
||||||
newFloorItem.eventData = data.data.eventData;
|
|
||||||
}
|
|
||||||
|
|
||||||
setFloorItems((prevItems: any) => {
|
setFloorItems((prevItems: any) => {
|
||||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
@ -241,7 +233,7 @@ export default function SocketResponses({
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (data.message === "Model updated successfully") {
|
} else if (data.message === "Model updated successfully") {
|
||||||
itemsGroup.current.children.forEach((item: THREE.Group) => {
|
itemsGroup.current?.children.forEach((item: THREE.Group) => {
|
||||||
if (item.uuid === data.data.modeluuid) {
|
if (item.uuid === data.data.modeluuid) {
|
||||||
item.position.set(...data.data.position as [number, number, number]);
|
item.position.set(...data.data.position as [number, number, number]);
|
||||||
item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
||||||
|
|
|
@ -7,6 +7,7 @@ interface AvatarProps {
|
||||||
size?: number;
|
size?: number;
|
||||||
index?: number;
|
index?: number;
|
||||||
textColor?: string;
|
textColor?: string;
|
||||||
|
color?: string; // Optional color prop for future use
|
||||||
}
|
}
|
||||||
|
|
||||||
const CustomAvatar: React.FC<AvatarProps> = ({
|
const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
|
@ -14,6 +15,7 @@ const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
size = 100,
|
size = 100,
|
||||||
index = 0,
|
index = 0,
|
||||||
textColor = "#ffffff",
|
textColor = "#ffffff",
|
||||||
|
color, // Optional color prop for future use
|
||||||
}) => {
|
}) => {
|
||||||
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
||||||
|
|
||||||
|
@ -26,7 +28,7 @@ const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
const initials = getInitials(name); // Convert name to initials if needed
|
const initials = getInitials(name); // Convert name to initials if needed
|
||||||
|
|
||||||
// Draw background
|
// Draw background
|
||||||
ctx.fillStyle = getAvatarColor(index);
|
ctx.fillStyle = color || getAvatarColor(index); // Use color prop or generate color based on index
|
||||||
ctx.fillRect(0, 0, size, size);
|
ctx.fillRect(0, 0, size, size);
|
||||||
|
|
||||||
// Draw initials
|
// Draw initials
|
||||||
|
@ -40,7 +42,7 @@ const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
const dataURL = canvas.toDataURL("image/png");
|
const dataURL = canvas.toDataURL("image/png");
|
||||||
setImageSrc(dataURL);
|
setImageSrc(dataURL);
|
||||||
}
|
}
|
||||||
}, [name, size, textColor]);
|
}, [name, size, textColor, index]);
|
||||||
|
|
||||||
if (!imageSrc) {
|
if (!imageSrc) {
|
||||||
return null; // Return null while the image is being generated
|
return null; // Return null while the image is being generated
|
||||||
|
@ -53,6 +55,18 @@ const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
alt="User Avatar"
|
alt="User Avatar"
|
||||||
style={{ width: "100%", height: "100%" }}
|
style={{ width: "100%", height: "100%" }}
|
||||||
/>
|
/>
|
||||||
|
// <div
|
||||||
|
// className="user-image"
|
||||||
|
// style={{
|
||||||
|
// width: size,
|
||||||
|
// height: size,
|
||||||
|
// borderRadius: "50%",
|
||||||
|
// overflow: "hidden",
|
||||||
|
// backgroundSize: "cover",
|
||||||
|
// backgroundPosition: "center",
|
||||||
|
// }}>
|
||||||
|
// {name[0]}
|
||||||
|
// </div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAss
|
||||||
async function loadInitialFloorItems(
|
async function loadInitialFloorItems(
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void
|
setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!itemsGroup.current) return;
|
if (!itemsGroup.current) return;
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
@ -23,10 +23,10 @@ async function loadInitialFloorItems(
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(items));
|
localStorage.setItem("FloorItems", JSON.stringify(items));
|
||||||
await initializeDB();
|
await initializeDB();
|
||||||
|
|
||||||
if (items.message === "floorItems not found") return;
|
if (items.message === "floorItems not found") return;
|
||||||
|
|
||||||
if (items) {
|
if (items) {
|
||||||
const storedFloorItems: Types.FloorItems = items;
|
const storedFloorItems: Types.EventData[] = items;
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
const dracoLoader = new DRACOLoader();
|
const dracoLoader = new DRACOLoader();
|
||||||
|
|
||||||
|
@ -53,7 +53,6 @@ async function loadInitialFloorItems(
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const item of storedFloorItems) {
|
for (const item of storedFloorItems) {
|
||||||
console.log('item: ', item);
|
|
||||||
if (!item.modelfileID) return;
|
if (!item.modelfileID) return;
|
||||||
const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
|
const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
|
||||||
let storedPosition;
|
let storedPosition;
|
||||||
|
@ -72,7 +71,7 @@ async function loadInitialFloorItems(
|
||||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||||
if (cachedModel) {
|
if (cachedModel) {
|
||||||
// console.log(`[Cache] Fetching ${item.modelname}`);
|
// console.log(`[Cache] Fetching ${item.modelname}`);
|
||||||
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
|
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
return;
|
return;
|
||||||
|
@ -89,7 +88,7 @@ async function loadInitialFloorItems(
|
||||||
URL.revokeObjectURL(blobUrl);
|
URL.revokeObjectURL(blobUrl);
|
||||||
THREE.Cache.remove(blobUrl);
|
THREE.Cache.remove(blobUrl);
|
||||||
THREE.Cache.add(item.modelfileID!, gltf);
|
THREE.Cache.add(item.modelfileID!, gltf);
|
||||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
|
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
},
|
},
|
||||||
|
@ -112,7 +111,7 @@ async function loadInitialFloorItems(
|
||||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||||
await storeGLTF(item.modelfileID!, modelBlob);
|
await storeGLTF(item.modelfileID!, modelBlob);
|
||||||
THREE.Cache.add(item.modelfileID!, gltf);
|
THREE.Cache.add(item.modelfileID!, gltf);
|
||||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
|
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
},
|
},
|
||||||
|
@ -138,8 +137,8 @@ async function loadInitialFloorItems(
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (item.eventData) {
|
if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') {
|
||||||
processEventData(item, setSimulationPaths);
|
processEventData(item, setSimulationStates);
|
||||||
}
|
}
|
||||||
|
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
|
@ -155,10 +154,10 @@ async function loadInitialFloorItems(
|
||||||
|
|
||||||
function processLoadedModel(
|
function processLoadedModel(
|
||||||
gltf: any,
|
gltf: any,
|
||||||
item: Types.FloorItemType,
|
item: Types.EventData,
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void
|
setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void
|
||||||
) {
|
) {
|
||||||
const model = gltf;
|
const model = gltf;
|
||||||
model.uuid = item.modeluuid;
|
model.uuid = item.modeluuid;
|
||||||
|
@ -193,15 +192,15 @@ function processLoadedModel(
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (item.eventData || item.modelfileID === '67e3da19c2e8f37134526e6a') {
|
if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') {
|
||||||
processEventData(item, setSimulationPaths);
|
processEventData(item, setSimulationStates);
|
||||||
}
|
}
|
||||||
|
|
||||||
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
||||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
||||||
}
|
}
|
||||||
|
|
||||||
function processEventData(item: Types.FloorItemType, setSimulationPaths: any) {
|
function processEventData(item: Types.EventData, setSimulationStates: any) {
|
||||||
|
|
||||||
if (item.eventData?.type === 'Conveyor') {
|
if (item.eventData?.type === 'Conveyor') {
|
||||||
|
|
||||||
|
@ -211,32 +210,45 @@ function processEventData(item: Types.FloorItemType, setSimulationPaths: any) {
|
||||||
data.position = item.position;
|
data.position = item.position;
|
||||||
data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
|
data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
...(prevEvents || []),
|
...(prevEvents || []),
|
||||||
data as Types.ConveyorEventsSchema
|
data as Types.ConveyorEventsSchema
|
||||||
]);
|
]);
|
||||||
} else {
|
|
||||||
|
} else if (item.eventData?.type === 'Vehicle') {
|
||||||
|
|
||||||
|
const data: any = item.eventData;
|
||||||
|
data.modeluuid = item.modeluuid;
|
||||||
|
data.modelName = item.modelname;
|
||||||
|
data.position = item.position;
|
||||||
|
|
||||||
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
data as Types.VehicleEventsSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else if (item.modelfileID === '67e3db95c2e8f37134526fb2') {
|
||||||
|
|
||||||
const pointUUID = THREE.MathUtils.generateUUID();
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
const pointPosition = new THREE.Vector3(0, 1.3, 0);
|
const pointPosition = new THREE.Vector3(0, 1.75, 0);
|
||||||
|
|
||||||
const newVehiclePath: Types.VehicleEventsSchema = {
|
const staticMachine: Types.StaticMachineEventsSchema = {
|
||||||
modeluuid: item.modeluuid,
|
modeluuid: item.modeluuid,
|
||||||
modelName: item.modelname,
|
modelName: item.modelname,
|
||||||
type: 'Vehicle',
|
type: "StaticMachine",
|
||||||
point: {
|
points: {
|
||||||
uuid: pointUUID,
|
uuid: pointUUID,
|
||||||
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
||||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', buffer: 'Inherit', material: 'Inherit', isUsed: false },
|
||||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
|
||||||
speed: 2,
|
connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||||
},
|
},
|
||||||
position: [...item.position],
|
position: item.position
|
||||||
};
|
};
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.VehicleEventsSchema)[]) => [
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
...(prevEvents || []),
|
...(prevEvents || []),
|
||||||
newVehiclePath as Types.VehicleEventsSchema
|
staticMachine as Types.StaticMachineEventsSchema
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
@ -10,7 +10,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { socket } = useSocketStore()
|
const { socket } = useSocketStore()
|
||||||
|
@ -151,7 +151,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
return updatedItems;
|
return updatedItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||||
|
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||||
|
@ -183,7 +183,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
: [defaultAction],
|
: [defaultAction],
|
||||||
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
|
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
|
||||||
connections: {
|
connections: {
|
||||||
source: { pathUUID: obj.uuid, pointUUID },
|
source: { modelUUID: obj.uuid, pointUUID },
|
||||||
targets: []
|
targets: []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -224,22 +224,102 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
eventData: backendEventData,
|
eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const newEventData: any = backendEventData;
|
const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed };
|
||||||
newEventData.modeluuid = newFloorItem.modeluuid;
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
newEventData.modelName = newFloorItem.modelname;
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
newEventData.position = newFloorItem.position;
|
newEventData.position = newFloorItem.position;
|
||||||
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
...(prevEvents || []),
|
...(prevEvents || []),
|
||||||
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
newEventData as Types.ConveyorEventsSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
} else if (eventData.type === 'Vehicle' && eventData) {
|
||||||
|
const createVehiclePoint = () => {
|
||||||
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
|
const vehiclePoint = (eventData as Types.VehicleEventsSchema)?.points;
|
||||||
|
const hasActions = vehiclePoint?.actions !== undefined;
|
||||||
|
|
||||||
|
const defaultAction = {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
name: 'Action 1',
|
||||||
|
type: 'Inherit',
|
||||||
|
start: {},
|
||||||
|
hitCount: 0,
|
||||||
|
end: {},
|
||||||
|
buffer: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
uuid: pointUUID,
|
||||||
|
position: vehiclePoint?.position,
|
||||||
|
actions: hasActions
|
||||||
|
? {
|
||||||
|
...vehiclePoint.actions,
|
||||||
|
uuid: THREE.MathUtils.generateUUID()
|
||||||
|
}
|
||||||
|
: defaultAction,
|
||||||
|
connections: {
|
||||||
|
source: { modelUUID: obj.uuid, pointUUID },
|
||||||
|
targets: []
|
||||||
|
},
|
||||||
|
speed: vehiclePoint?.speed || 1
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const backendEventData = {
|
||||||
|
type: 'Vehicle',
|
||||||
|
points: createVehiclePoint(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// { type: backendEventData.type, points: backendEventData.points }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: { type: backendEventData.type, points: backendEventData.points },
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
|
||||||
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
|
newEventData.position = newFloorItem.position;
|
||||||
|
|
||||||
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
newEventData as Types.VehicleEventsSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||||
|
|
||||||
const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
|
const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
|
@ -131,7 +132,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
return updatedItems;
|
return updatedItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||||
|
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||||
|
@ -164,7 +165,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
: [defaultAction],
|
: [defaultAction],
|
||||||
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
|
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
|
||||||
connections: {
|
connections: {
|
||||||
source: { pathUUID: obj.uuid, pointUUID },
|
source: { modelUUID: newFloorItem.modeluuid, pointUUID },
|
||||||
targets: []
|
targets: []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -182,16 +183,16 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
|
|
||||||
//REST
|
//REST
|
||||||
|
|
||||||
// await setFloorItemApi(
|
// setFloorItemApi(
|
||||||
// organization,
|
// organization,
|
||||||
// obj.uuid,
|
// obj.uuid,
|
||||||
// obj.userData.name,
|
// obj.userData.name,
|
||||||
|
// obj.userData.modelId,
|
||||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
// obj.userData.modelId,
|
|
||||||
// false,
|
// false,
|
||||||
// true,
|
// true,
|
||||||
// backendEventData
|
// { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
|
||||||
// );
|
// );
|
||||||
|
|
||||||
//SOCKET
|
//SOCKET
|
||||||
|
@ -205,22 +206,102 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
eventData: backendEventData,
|
eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const newEventData: any = backendEventData;
|
const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed };
|
||||||
newEventData.modeluuid = newFloorItem.modeluuid;
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
newEventData.modelName = newFloorItem.modelname;
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
newEventData.position = newFloorItem.position;
|
newEventData.position = newFloorItem.position;
|
||||||
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
...(prevEvents || []),
|
...(prevEvents || []),
|
||||||
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
newEventData as Types.ConveyorEventsSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
} else if (eventData.type === 'Vehicle' && eventData) {
|
||||||
|
const createVehiclePoint = () => {
|
||||||
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
|
const vehiclePoint = (eventData as Types.VehicleEventsSchema)?.points;
|
||||||
|
const hasActions = vehiclePoint?.actions !== undefined;
|
||||||
|
|
||||||
|
const defaultAction = {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
name: 'Action 1',
|
||||||
|
type: 'Inherit',
|
||||||
|
start: {},
|
||||||
|
hitCount: 0,
|
||||||
|
end: {},
|
||||||
|
buffer: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
uuid: pointUUID,
|
||||||
|
position: vehiclePoint?.position,
|
||||||
|
actions: hasActions
|
||||||
|
? {
|
||||||
|
...vehiclePoint.actions,
|
||||||
|
uuid: THREE.MathUtils.generateUUID()
|
||||||
|
}
|
||||||
|
: defaultAction,
|
||||||
|
connections: {
|
||||||
|
source: { modelUUID: obj.uuid, pointUUID },
|
||||||
|
targets: []
|
||||||
|
},
|
||||||
|
speed: vehiclePoint?.speed || 2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const backendEventData = {
|
||||||
|
type: 'Vehicle',
|
||||||
|
points: createVehiclePoint()
|
||||||
|
};
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// { type: backendEventData.type, points: backendEventData.points }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: { type: backendEventData.type, points: backendEventData.points },
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
|
||||||
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
|
newEventData.position = newFloorItem.position;
|
||||||
|
|
||||||
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
newEventData as Types.VehicleEventsSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
@ -12,7 +12,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
||||||
|
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const itemsData = useRef<Types.FloorItems>([]);
|
const itemsData = useRef<Types.FloorItems>([]);
|
||||||
|
@ -180,12 +180,12 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
||||||
return updatedItems;
|
return updatedItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||||
|
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||||
|
|
||||||
if (eventData) {
|
if (eventData && eventData.type !== 'StaticMachine') {
|
||||||
if (eventData.type === 'Conveyor' && eventData) {
|
if (eventData.type === 'Conveyor' && eventData) {
|
||||||
|
|
||||||
const backendEventData = {
|
const backendEventData = {
|
||||||
|
@ -205,7 +205,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
||||||
// obj.userData.modelId,
|
// obj.userData.modelId,
|
||||||
// false,
|
// false,
|
||||||
// true,
|
// true,
|
||||||
// backendEventData
|
// { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
|
||||||
// );
|
// );
|
||||||
|
|
||||||
//SOCKET
|
//SOCKET
|
||||||
|
@ -219,17 +219,17 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
eventData: backendEventData,
|
eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const newEventData: any = backendEventData;
|
const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed };
|
||||||
newEventData.modeluuid = newFloorItem.modeluuid;
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
newEventData.modelName = newFloorItem.modelname;
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
newEventData.position = newFloorItem.position;
|
newEventData.position = newFloorItem.position;
|
||||||
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
|
||||||
const updatedEvents = (prevEvents || []).map(event =>
|
const updatedEvents = (prevEvents || []).map(event =>
|
||||||
event.modeluuid === newFloorItem.modeluuid
|
event.modeluuid === newFloorItem.modeluuid
|
||||||
? { ...event, ...newEventData }
|
? { ...event, ...newEventData }
|
||||||
|
@ -238,7 +238,59 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
||||||
return updatedEvents;
|
return updatedEvents;
|
||||||
});
|
});
|
||||||
|
|
||||||
// socket.emit("v2:model-asset:add", data);
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
} else if (eventData.type === 'Vehicle' && eventData) {
|
||||||
|
|
||||||
|
const backendEventData = {
|
||||||
|
type: 'Vehicle',
|
||||||
|
points: eventData.points
|
||||||
|
};
|
||||||
|
|
||||||
|
// REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// { type: backendEventData.type, points: backendEventData.points }
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: { type: backendEventData.type, points: backendEventData.points },
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
|
||||||
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
|
newEventData.position = newFloorItem.position;
|
||||||
|
|
||||||
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
|
||||||
|
const updatedEvents = (prevEvents || []).map(event =>
|
||||||
|
event.modeluuid === newFloorItem.modeluuid
|
||||||
|
? { ...event, ...newEventData }
|
||||||
|
: event
|
||||||
|
);
|
||||||
|
return updatedEvents;
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||||
|
|
||||||
function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
|
function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
|
@ -12,7 +13,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
||||||
|
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const itemsData = useRef<Types.FloorItems>([]);
|
const itemsData = useRef<Types.FloorItems>([]);
|
||||||
|
@ -183,12 +184,12 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
||||||
return updatedItems;
|
return updatedItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||||
|
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||||
|
|
||||||
if (eventData) {
|
if (eventData && eventData.type !== 'StaticMachine') {
|
||||||
if (eventData.type === 'Conveyor' && eventData) {
|
if (eventData.type === 'Conveyor' && eventData) {
|
||||||
|
|
||||||
const backendEventData = {
|
const backendEventData = {
|
||||||
|
@ -197,18 +198,18 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
||||||
speed: (eventData as Types.ConveyorEventsSchema)?.speed
|
speed: (eventData as Types.ConveyorEventsSchema)?.speed
|
||||||
};
|
};
|
||||||
|
|
||||||
//REST
|
// REST
|
||||||
|
|
||||||
// await setFloorItemApi(
|
// await setFloorItemApi(
|
||||||
// organization,
|
// organization,
|
||||||
// obj.uuid,
|
// obj.uuid,
|
||||||
// obj.userData.name,
|
// obj.userData.name,
|
||||||
|
// obj.userData.modelId,
|
||||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
// obj.userData.modelId,
|
|
||||||
// false,
|
// false,
|
||||||
// true,
|
// true,
|
||||||
// backendEventData
|
// { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
|
||||||
// );
|
// );
|
||||||
|
|
||||||
//SOCKET
|
//SOCKET
|
||||||
|
@ -222,17 +223,17 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
eventData: backendEventData,
|
eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const newEventData: any = backendEventData;
|
const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed };
|
||||||
newEventData.modeluuid = newFloorItem.modeluuid;
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
newEventData.modelName = newFloorItem.modelname;
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
newEventData.position = newFloorItem.position;
|
newEventData.position = newFloorItem.position;
|
||||||
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
|
||||||
const updatedEvents = (prevEvents || []).map(event =>
|
const updatedEvents = (prevEvents || []).map(event =>
|
||||||
event.modeluuid === newFloorItem.modeluuid
|
event.modeluuid === newFloorItem.modeluuid
|
||||||
? { ...event, ...newEventData }
|
? { ...event, ...newEventData }
|
||||||
|
@ -241,11 +242,63 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
||||||
return updatedEvents;
|
return updatedEvents;
|
||||||
});
|
});
|
||||||
|
|
||||||
// socket.emit("v2:model-asset:add", data);
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
} else if (eventData.type === 'Vehicle' && eventData) {
|
||||||
|
|
||||||
|
const backendEventData = {
|
||||||
|
type: 'Vehicle',
|
||||||
|
points: eventData.points
|
||||||
|
};
|
||||||
|
|
||||||
|
// REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// { type: backendEventData.type, points: backendEventData.points }
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: { type: backendEventData.type, points: backendEventData.points },
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
|
||||||
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
|
newEventData.position = newFloorItem.position;
|
||||||
|
|
||||||
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
|
||||||
|
const updatedEvents = (prevEvents || []).map(event =>
|
||||||
|
event.modeluuid === newFloorItem.modeluuid
|
||||||
|
? { ...event, ...newEventData }
|
||||||
|
: event
|
||||||
|
);
|
||||||
|
return updatedEvents;
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
||||||
//REST
|
//REST
|
||||||
|
|
||||||
// await setFloorItemApi(
|
// await setFloorItemApi(
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
|
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
|
||||||
import { SelectionHelper } from "./selectionHelper";
|
import { SelectionHelper } from "./selectionHelper";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
import BoundingBox from "./boundingBoxHelper";
|
import BoundingBox from "./boundingBoxHelper";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
|
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
|
||||||
|
@ -20,7 +20,7 @@ const SelectionControls: React.FC = () => {
|
||||||
const itemsGroupRef = useRef<THREE.Group | undefined>(undefined);
|
const itemsGroupRef = useRef<THREE.Group | undefined>(undefined);
|
||||||
const selectionGroup = useRef() as Types.RefGroup;
|
const selectionGroup = useRef() as Types.RefGroup;
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { setSimulationPaths } = useSimulationPaths();
|
const { setSimulationStates } = useSimulationStates();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
|
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
|
||||||
const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]);
|
const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]);
|
||||||
|
@ -240,7 +240,7 @@ const SelectionControls: React.FC = () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
|
||||||
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid);
|
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid);
|
||||||
return updatedEvents;
|
return updatedEvents;
|
||||||
});
|
});
|
||||||
|
|
|
@ -91,7 +91,7 @@ export default function PostProcessing() {
|
||||||
)}
|
)}
|
||||||
{selectedActionSphere && (
|
{selectedActionSphere && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={[selectedActionSphere.point]}
|
selection={[selectedActionSphere.points]}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={1000}
|
width={1000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
|
|
|
@ -53,8 +53,8 @@ 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";
|
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
|
import NavMeshCreator from "../../builder/agv/navMeshCreator";
|
||||||
|
|
||||||
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.
|
||||||
|
@ -367,7 +367,9 @@ export default function World() {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* <DrieHtmlTemp itemsGroup={itemsGroup} /> */}
|
{/* <DrieHtmlTemp itemsGroup={itemsGroup} /> */}
|
||||||
{activeModule === "simulation" && <Agv lines={lines} plane={plane} />}
|
|
||||||
|
<NavMeshCreator lines={lines} />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { useFloorItems, useSimulationPaths } from '../../../store/store';
|
import { useFloorItems, useSimulationStates } 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';
|
||||||
|
|
||||||
function Behaviour() {
|
function Behaviour() {
|
||||||
const { setSimulationPaths } = useSimulationPaths();
|
const { setSimulationStates } = useSimulationStates();
|
||||||
const { floorItems } = useFloorItems();
|
const { floorItems } = useFloorItems();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
|
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] = [];
|
||||||
|
|
||||||
// floorItems.forEach((item: Types.FloorItemType) => {
|
// floorItems.forEach((item: Types.FloorItemType) => {
|
||||||
// if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
|
// if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
|
||||||
|
@ -31,7 +31,7 @@ function Behaviour() {
|
||||||
// rotation: [0, 0, 0],
|
// rotation: [0, 0, 0],
|
||||||
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
||||||
// triggers: [],
|
// triggers: [],
|
||||||
// connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
|
// connections: { source: { modelUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// uuid: middlePointUUID,
|
// uuid: middlePointUUID,
|
||||||
|
@ -39,7 +39,7 @@ function Behaviour() {
|
||||||
// rotation: [0, 0, 0],
|
// rotation: [0, 0, 0],
|
||||||
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
||||||
// triggers: [],
|
// triggers: [],
|
||||||
// connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
|
// connections: { source: { modelUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// uuid: point2UUID,
|
// uuid: point2UUID,
|
||||||
|
@ -47,7 +47,7 @@ function Behaviour() {
|
||||||
// rotation: [0, 0, 0],
|
// rotation: [0, 0, 0],
|
||||||
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
||||||
// triggers: [],
|
// triggers: [],
|
||||||
// connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
|
// connections: { source: { modelUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
|
||||||
// },
|
// },
|
||||||
// ],
|
// ],
|
||||||
// position: [...item.position],
|
// position: [...item.position],
|
||||||
|
@ -68,7 +68,7 @@ function Behaviour() {
|
||||||
// uuid: pointUUID,
|
// uuid: pointUUID,
|
||||||
// position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
// position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
||||||
// actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
// actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||||
// connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
// connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||||
// speed: 2,
|
// speed: 2,
|
||||||
// },
|
// },
|
||||||
// position: [...item.position],
|
// position: [...item.position],
|
||||||
|
@ -78,7 +78,7 @@ function Behaviour() {
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// setSimulationPaths(newPaths);
|
// setSimulationStates(newPaths);
|
||||||
// console.log('floorItems: ', floorItems);
|
// console.log('floorItems: ', floorItems);
|
||||||
}, [floorItems]);
|
}, [floorItems]);
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,21 @@ import React, { useEffect, useState } from 'react';
|
||||||
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 { QuadraticBezierLine } from '@react-three/drei';
|
import { QuadraticBezierLine } from '@react-three/drei';
|
||||||
import { useIsConnecting, useSimulationPaths } from '../../../store/store';
|
import { useIsConnecting, useSimulationStates, useSocketStore } from '../../../store/store';
|
||||||
import useModuleStore from '../../../store/useModuleStore';
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
|
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
||||||
|
import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/setEventsApt';
|
||||||
|
|
||||||
function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
|
function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { gl, raycaster, scene, pointer, camera } = useThree();
|
const { gl, raycaster, scene, pointer, camera } = useThree();
|
||||||
const { setIsConnecting } = useIsConnecting();
|
const { setIsConnecting } = useIsConnecting();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
|
||||||
const [firstSelected, setFirstSelected] = useState<{
|
const [firstSelected, setFirstSelected] = useState<{
|
||||||
pathUUID: string;
|
modelUUID: string;
|
||||||
sphereUUID: string;
|
sphereUUID: string;
|
||||||
position: THREE.Vector3;
|
position: THREE.Vector3;
|
||||||
isCorner: boolean;
|
isCorner: boolean;
|
||||||
|
@ -22,26 +26,26 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
const [helperlineColor, setHelperLineColor] = useState<string>('red');
|
const [helperlineColor, setHelperLineColor] = useState<string>('red');
|
||||||
|
|
||||||
const updatePathConnections = (
|
const updatePathConnections = (
|
||||||
fromPathUUID: string,
|
fromModelUUID: string,
|
||||||
fromPointUUID: string,
|
fromPointUUID: string,
|
||||||
toPathUUID: string,
|
toModelUUID: string,
|
||||||
toPointUUID: string
|
toPointUUID: string
|
||||||
) => {
|
) => {
|
||||||
const updatedPaths = simulationPaths.map(path => {
|
const updatedPaths = simulationStates.map(path => {
|
||||||
if (path.type === 'Conveyor') {
|
if (path.type === 'Conveyor') {
|
||||||
if (path.modeluuid === fromPathUUID) {
|
if (path.modeluuid === fromModelUUID) {
|
||||||
return {
|
return {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map(point => {
|
points: path.points.map(point => {
|
||||||
if (point.uuid === fromPointUUID) {
|
if (point.uuid === fromPointUUID) {
|
||||||
const newTarget = {
|
const newTarget = {
|
||||||
pathUUID: toPathUUID,
|
modelUUID: toModelUUID,
|
||||||
pointUUID: toPointUUID
|
pointUUID: toPointUUID
|
||||||
};
|
};
|
||||||
const existingTargets = point.connections.targets || [];
|
const existingTargets = point.connections.targets || [];
|
||||||
|
|
||||||
if (!existingTargets.some(target =>
|
if (!existingTargets.some(target =>
|
||||||
target.pathUUID === newTarget.pathUUID &&
|
target.modelUUID === newTarget.modelUUID &&
|
||||||
target.pointUUID === newTarget.pointUUID
|
target.pointUUID === newTarget.pointUUID
|
||||||
)) {
|
)) {
|
||||||
return {
|
return {
|
||||||
|
@ -57,19 +61,19 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (path.modeluuid === toPathUUID) {
|
else if (path.modeluuid === toModelUUID) {
|
||||||
return {
|
return {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map(point => {
|
points: path.points.map(point => {
|
||||||
if (point.uuid === toPointUUID) {
|
if (point.uuid === toPointUUID) {
|
||||||
const reverseTarget = {
|
const reverseTarget = {
|
||||||
pathUUID: fromPathUUID,
|
modelUUID: fromModelUUID,
|
||||||
pointUUID: fromPointUUID
|
pointUUID: fromPointUUID
|
||||||
};
|
};
|
||||||
const existingTargets = point.connections.targets || [];
|
const existingTargets = point.connections.targets || [];
|
||||||
|
|
||||||
if (!existingTargets.some(target =>
|
if (!existingTargets.some(target =>
|
||||||
target.pathUUID === reverseTarget.pathUUID &&
|
target.modelUUID === reverseTarget.modelUUID &&
|
||||||
target.pointUUID === reverseTarget.pointUUID
|
target.pointUUID === reverseTarget.pointUUID
|
||||||
)) {
|
)) {
|
||||||
return {
|
return {
|
||||||
|
@ -86,18 +90,17 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// In the updatePathConnections function, modify the Vehicle handling section:
|
|
||||||
else if (path.type === 'Vehicle') {
|
else if (path.type === 'Vehicle') {
|
||||||
// Handle outgoing connections from Vehicle
|
// Handle outgoing connections from Vehicle
|
||||||
if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) {
|
if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
|
||||||
const newTarget = {
|
const newTarget = {
|
||||||
pathUUID: toPathUUID,
|
modelUUID: toModelUUID,
|
||||||
pointUUID: toPointUUID
|
pointUUID: toPointUUID
|
||||||
};
|
};
|
||||||
const existingTargets = path.point.connections.targets || [];
|
const existingTargets = path.points.connections.targets || [];
|
||||||
|
|
||||||
// Check if target is a Conveyor
|
// Check if target is a Conveyor
|
||||||
const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID);
|
const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
|
||||||
if (toPath?.type !== 'Conveyor') {
|
if (toPath?.type !== 'Conveyor') {
|
||||||
console.log("Vehicle can only connect to Conveyors");
|
console.log("Vehicle can only connect to Conveyors");
|
||||||
return path;
|
return path;
|
||||||
|
@ -110,15 +113,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!existingTargets.some(target =>
|
if (!existingTargets.some(target =>
|
||||||
target.pathUUID === newTarget.pathUUID &&
|
target.modelUUID === newTarget.modelUUID &&
|
||||||
target.pointUUID === newTarget.pointUUID
|
target.pointUUID === newTarget.pointUUID
|
||||||
)) {
|
)) {
|
||||||
return {
|
return {
|
||||||
...path,
|
...path,
|
||||||
point: {
|
points: {
|
||||||
...path.point,
|
...path.points,
|
||||||
connections: {
|
connections: {
|
||||||
...path.point.connections,
|
...path.points.connections,
|
||||||
targets: [...existingTargets, newTarget]
|
targets: [...existingTargets, newTarget]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,15 +129,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Handle incoming connections to Vehicle
|
// Handle incoming connections to Vehicle
|
||||||
else if (path.modeluuid === toPathUUID && path.point.uuid === toPointUUID) {
|
else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
|
||||||
const reverseTarget = {
|
const reverseTarget = {
|
||||||
pathUUID: fromPathUUID,
|
modelUUID: fromModelUUID,
|
||||||
pointUUID: fromPointUUID
|
pointUUID: fromPointUUID
|
||||||
};
|
};
|
||||||
const existingTargets = path.point.connections.targets || [];
|
const existingTargets = path.points.connections.targets || [];
|
||||||
|
|
||||||
// Check if source is a Conveyor
|
// Check if source is a Conveyor
|
||||||
const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID);
|
const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
|
||||||
if (fromPath?.type !== 'Conveyor') {
|
if (fromPath?.type !== 'Conveyor') {
|
||||||
console.log("Vehicle can only connect to Conveyors");
|
console.log("Vehicle can only connect to Conveyors");
|
||||||
return path;
|
return path;
|
||||||
|
@ -147,15 +150,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!existingTargets.some(target =>
|
if (!existingTargets.some(target =>
|
||||||
target.pathUUID === reverseTarget.pathUUID &&
|
target.modelUUID === reverseTarget.modelUUID &&
|
||||||
target.pointUUID === reverseTarget.pointUUID
|
target.pointUUID === reverseTarget.pointUUID
|
||||||
)) {
|
)) {
|
||||||
return {
|
return {
|
||||||
...path,
|
...path,
|
||||||
point: {
|
points: {
|
||||||
...path.point,
|
...path.points,
|
||||||
connections: {
|
connections: {
|
||||||
...path.point.connections,
|
...path.points.connections,
|
||||||
targets: [...existingTargets, reverseTarget]
|
targets: [...existingTargets, reverseTarget]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,14 +167,139 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
// else if (path.type === 'StaticMachine') {
|
||||||
|
// if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
|
||||||
|
// const newTarget = {
|
||||||
|
// modelUUID: toModelUUID,
|
||||||
|
// pointUUID: toPointUUID
|
||||||
|
// };
|
||||||
|
// const existingTargets = path.points.connections.targets || [];
|
||||||
|
|
||||||
|
// // Check if target is an ArmBot
|
||||||
|
// const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
|
||||||
|
// if (toPath?.type !== 'ArmBot') {
|
||||||
|
// console.log("StaticMachine can only connect to ArmBot");
|
||||||
|
// return path;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Check if already has a connection
|
||||||
|
// if (existingTargets.length >= 1) {
|
||||||
|
// console.log("StaticMachine can have only one connection");
|
||||||
|
// return path;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!existingTargets.some(target =>
|
||||||
|
// target.modelUUID === newTarget.modelUUID &&
|
||||||
|
// target.pointUUID === newTarget.pointUUID
|
||||||
|
// )) {
|
||||||
|
// return {
|
||||||
|
// ...path,
|
||||||
|
// points: {
|
||||||
|
// ...path.points,
|
||||||
|
// connections: {
|
||||||
|
// ...path.points.connections,
|
||||||
|
// targets: [...existingTargets, newTarget]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // Handle incoming connections to StaticMachine
|
||||||
|
// else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
|
||||||
|
// const reverseTarget = {
|
||||||
|
// modelUUID: fromModelUUID,
|
||||||
|
// pointUUID: fromPointUUID
|
||||||
|
// };
|
||||||
|
// const existingTargets = path.points.connections.targets || [];
|
||||||
|
|
||||||
|
// // Check if source is an ArmBot
|
||||||
|
// const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
|
||||||
|
// if (fromPath?.type !== 'ArmBot') {
|
||||||
|
// console.log("StaticMachine can only connect to ArmBot");
|
||||||
|
// return path;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Check if already has a connection
|
||||||
|
// if (existingTargets.length >= 1) {
|
||||||
|
// console.log("StaticMachine can have only one connection");
|
||||||
|
// return path;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!existingTargets.some(target =>
|
||||||
|
// target.modelUUID === reverseTarget.modelUUID &&
|
||||||
|
// target.pointUUID === reverseTarget.pointUUID
|
||||||
|
// )) {
|
||||||
|
// return {
|
||||||
|
// ...path,
|
||||||
|
// points: {
|
||||||
|
// ...path.points,
|
||||||
|
// connections: {
|
||||||
|
// ...path.points.connections,
|
||||||
|
// targets: [...existingTargets, reverseTarget]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return path;
|
||||||
|
// }
|
||||||
return path;
|
return path;
|
||||||
});
|
});
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
|
|
||||||
|
const updatedPathDetails = updatedPaths.filter(path =>
|
||||||
|
path.modeluuid === fromModelUUID || path.modeluuid === toModelUUID
|
||||||
|
);
|
||||||
|
|
||||||
|
updateBackend(updatedPathDetails);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddConnection = (fromPathUUID: string, fromUUID: string, toPathUUID: string, toUUID: string) => {
|
const updateBackend = async (updatedPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
|
||||||
updatePathConnections(fromPathUUID, fromUUID, toPathUUID, toUUID);
|
if (updatedPaths.length === 0) return;
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||||
|
|
||||||
|
updatedPaths.forEach(async (updatedPath) => {
|
||||||
|
if (updatedPath.type === 'Conveyor') {
|
||||||
|
|
||||||
|
// await setEventApi(
|
||||||
|
// organization,
|
||||||
|
// updatedPath.modeluuid,
|
||||||
|
// { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
|
||||||
|
// );
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization: organization,
|
||||||
|
modeluuid: updatedPath.modeluuid,
|
||||||
|
eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v2:model-asset:updateEventData', data);
|
||||||
|
|
||||||
|
} else if (updatedPath.type === 'Vehicle') {
|
||||||
|
|
||||||
|
// await setEventApi(
|
||||||
|
// organization,
|
||||||
|
// updatedPath.modeluuid,
|
||||||
|
// { type: "Vehicle", points: updatedPath.points }
|
||||||
|
// );
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization: organization,
|
||||||
|
modeluuid: updatedPath.modeluuid,
|
||||||
|
eventData: { type: "Vehicle", points: updatedPath.points }
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v2:model-asset:updateEventData', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddConnection = (fromModelUUID: string, fromUUID: string, toModelUUID: string, toUUID: string) => {
|
||||||
|
updatePathConnections(fromModelUUID, fromUUID, toModelUUID, toUUID);
|
||||||
setFirstSelected(null);
|
setFirstSelected(null);
|
||||||
setCurrentLine(null);
|
setCurrentLine(null);
|
||||||
setIsConnecting(false);
|
setIsConnecting(false);
|
||||||
|
@ -208,25 +336,25 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
const intersected = intersects[0].object;
|
const intersected = intersects[0].object;
|
||||||
|
|
||||||
if (intersected.name.includes("events-sphere")) {
|
if (intersected.name.includes("events-sphere")) {
|
||||||
const pathUUID = intersected.userData.path.modeluuid;
|
const modelUUID = 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);
|
||||||
|
|
||||||
let isStartOrEnd = false;
|
let isStartOrEnd = false;
|
||||||
|
|
||||||
if (intersected.userData.path.points) {
|
if (intersected.userData.path.points && intersected.userData.path.points.length > 1) {
|
||||||
isStartOrEnd = intersected.userData.path.points.length > 0 && (
|
isStartOrEnd = intersected.userData.path.points.length > 0 && (
|
||||||
sphereUUID === intersected.userData.path.points[0].uuid ||
|
sphereUUID === intersected.userData.path.points[0].uuid ||
|
||||||
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
|
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
|
||||||
);
|
);
|
||||||
} else if (intersected.userData.path.point) {
|
} else if (intersected.userData.path.points) {
|
||||||
isStartOrEnd = sphereUUID === intersected.userData.path.point.uuid;
|
isStartOrEnd = sphereUUID === intersected.userData.path.points.uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pathUUID) {
|
if (modelUUID) {
|
||||||
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID);
|
const firstPath = simulationStates.find(p => p.modeluuid === firstSelected?.modelUUID);
|
||||||
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
|
const secondPath = simulationStates.find(p => p.modeluuid === modelUUID);
|
||||||
|
|
||||||
// Prevent vehicle-to-vehicle connections
|
// Prevent vehicle-to-vehicle connections
|
||||||
if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
|
if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
|
||||||
|
@ -238,23 +366,23 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
if (firstPath && secondPath &&
|
if (firstPath && secondPath &&
|
||||||
firstPath.type === 'Conveyor' &&
|
firstPath.type === 'Conveyor' &&
|
||||||
secondPath.type === 'Conveyor' &&
|
secondPath.type === 'Conveyor' &&
|
||||||
!firstSelected?.isCorner) {
|
(!firstSelected?.isCorner || !isStartOrEnd)) {
|
||||||
console.log("Conveyor middle points can only connect to non-conveyor paths");
|
console.log("Conveyor connections must be between start/end points");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this specific connection already exists
|
// Check if this specific connection already exists
|
||||||
const isDuplicateConnection = firstSelected
|
const isDuplicateConnection = firstSelected
|
||||||
? simulationPaths.some(path => {
|
? simulationStates.some(path => {
|
||||||
if (path.modeluuid === firstSelected.pathUUID) {
|
if (path.modeluuid === firstSelected.modelUUID) {
|
||||||
if (path.type === 'Conveyor') {
|
if (path.type === 'Conveyor') {
|
||||||
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
|
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
|
||||||
return point?.connections.targets.some(t =>
|
return point?.connections.targets.some(t =>
|
||||||
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
|
t.modelUUID === modelUUID && t.pointUUID === sphereUUID
|
||||||
);
|
);
|
||||||
} else if (path.type === 'Vehicle') {
|
} else if (path.type === 'Vehicle') {
|
||||||
return path.point.connections.targets.some(t =>
|
return path.points.connections.targets.some(t =>
|
||||||
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
|
t.modelUUID === modelUUID && t.pointUUID === sphereUUID
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,7 +397,8 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
|
|
||||||
// For Vehicles, check if they're already connected to anything
|
// For Vehicles, check if they're already connected to anything
|
||||||
if (intersected.userData.path.type === 'Vehicle') {
|
if (intersected.userData.path.type === 'Vehicle') {
|
||||||
const vehicleConnections = intersected.userData.path.point.connections.targets.length;
|
console.log('intersected: ', intersected);
|
||||||
|
const vehicleConnections = intersected.userData.path.points.connections.targets.length;
|
||||||
if (vehicleConnections >= 1) {
|
if (vehicleConnections >= 1) {
|
||||||
console.log("Vehicle can only have one connection");
|
console.log("Vehicle can only have one connection");
|
||||||
return;
|
return;
|
||||||
|
@ -278,7 +407,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
|
|
||||||
// For non-Vehicle paths, check if already connected
|
// For non-Vehicle paths, check if already connected
|
||||||
if (intersected.userData.path.type !== 'Vehicle') {
|
if (intersected.userData.path.type !== 'Vehicle') {
|
||||||
const isAlreadyConnected = simulationPaths.some(path => {
|
const isAlreadyConnected = simulationStates.some(path => {
|
||||||
if (path.type === 'Conveyor') {
|
if (path.type === 'Conveyor') {
|
||||||
return path.points.some(point =>
|
return path.points.some(point =>
|
||||||
point.uuid === sphereUUID &&
|
point.uuid === sphereUUID &&
|
||||||
|
@ -303,7 +432,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent same-path connections
|
// Prevent same-path connections
|
||||||
if (firstSelected.pathUUID === pathUUID) {
|
if (firstSelected.modelUUID === modelUUID) {
|
||||||
console.log("Cannot connect spheres on the same path.");
|
console.log("Cannot connect spheres on the same path.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -316,15 +445,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
|
|
||||||
// All checks passed - make the connection
|
// All checks passed - make the connection
|
||||||
handleAddConnection(
|
handleAddConnection(
|
||||||
firstSelected.pathUUID,
|
firstSelected.modelUUID,
|
||||||
firstSelected.sphereUUID,
|
firstSelected.sphereUUID,
|
||||||
pathUUID,
|
modelUUID,
|
||||||
sphereUUID
|
sphereUUID
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// First selection - just store it
|
// First selection - just store it
|
||||||
setFirstSelected({
|
setFirstSelected({
|
||||||
pathUUID,
|
modelUUID,
|
||||||
sphereUUID,
|
sphereUUID,
|
||||||
position: worldPosition,
|
position: worldPosition,
|
||||||
isCorner: isStartOrEnd
|
isCorner: isStartOrEnd
|
||||||
|
@ -358,7 +487,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||||
};
|
};
|
||||||
}, [camera, scene, raycaster, firstSelected, simulationPaths]);
|
}, [camera, scene, raycaster, firstSelected, simulationStates]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (firstSelected) {
|
if (firstSelected) {
|
||||||
|
@ -372,7 +501,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
);
|
);
|
||||||
|
|
||||||
let point: THREE.Vector3 | null = null;
|
let point: THREE.Vector3 | null = null;
|
||||||
let snappedSphere: { sphereUUID: string, position: THREE.Vector3, pathUUID: string, isCorner: boolean } | null = null;
|
let snappedSphere: { sphereUUID: string, position: THREE.Vector3, modelUUID: string, isCorner: boolean } | null = null;
|
||||||
let isInvalidConnection = false;
|
let isInvalidConnection = false;
|
||||||
|
|
||||||
if (intersects.length > 0) {
|
if (intersects.length > 0) {
|
||||||
|
@ -392,10 +521,10 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
const spherePosition = new THREE.Vector3();
|
const spherePosition = new THREE.Vector3();
|
||||||
sphere.getWorldPosition(spherePosition);
|
sphere.getWorldPosition(spherePosition);
|
||||||
const pathData = sphere.userData.path;
|
const pathData = sphere.userData.path;
|
||||||
const pathUUID = pathData.modeluuid;
|
const modelUUID = pathData.modeluuid;
|
||||||
|
|
||||||
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected.pathUUID);
|
const firstPath = simulationStates.find(p => p.modeluuid === firstSelected.modelUUID);
|
||||||
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
|
const secondPath = simulationStates.find(p => p.modeluuid === modelUUID);
|
||||||
const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';
|
const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';
|
||||||
|
|
||||||
// Inside the useFrame hook, where we check for snapped spheres:
|
// Inside the useFrame hook, where we check for snapped spheres:
|
||||||
|
@ -410,16 +539,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
!firstSelected.isCorner);
|
!firstSelected.isCorner);
|
||||||
|
|
||||||
// Check for duplicate connection (regardless of path type)
|
// Check for duplicate connection (regardless of path type)
|
||||||
const isDuplicateConnection = simulationPaths.some(path => {
|
const isDuplicateConnection = simulationStates.some(path => {
|
||||||
if (path.modeluuid === firstSelected.pathUUID) {
|
if (path.modeluuid === firstSelected.modelUUID) {
|
||||||
if (path.type === 'Conveyor') {
|
if (path.type === 'Conveyor') {
|
||||||
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
|
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
|
||||||
return point?.connections.targets.some(t =>
|
return point?.connections.targets.some(t =>
|
||||||
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
|
t.modelUUID === modelUUID && t.pointUUID === sphereUUID
|
||||||
);
|
);
|
||||||
} else if (path.type === 'Vehicle') {
|
} else if (path.type === 'Vehicle') {
|
||||||
return path.point.connections.targets.some(t =>
|
return path.points.connections.targets.some(t =>
|
||||||
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
|
t.modelUUID === modelUUID && t.pointUUID === sphereUUID
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,7 +557,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
|
|
||||||
// For non-Vehicle paths, check if already connected
|
// For non-Vehicle paths, check if already connected
|
||||||
const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' &&
|
const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' &&
|
||||||
simulationPaths.some(path => {
|
simulationStates.some(path => {
|
||||||
if (path.type === 'Conveyor') {
|
if (path.type === 'Conveyor') {
|
||||||
return path.points.some(point =>
|
return path.points.some(point =>
|
||||||
point.uuid === sphereUUID &&
|
point.uuid === sphereUUID &&
|
||||||
|
@ -440,7 +569,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
|
|
||||||
// Check vehicle connection rules
|
// Check vehicle connection rules
|
||||||
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
|
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
|
||||||
pathData.point.connections.targets.length >= 1;
|
pathData.points.connections.targets.length >= 1;
|
||||||
const isVehicleConnectingToNonConveyor =
|
const isVehicleConnectingToNonConveyor =
|
||||||
(firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
|
(firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
|
||||||
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');
|
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');
|
||||||
|
@ -452,13 +581,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
!isVehicleAtMaxConnections &&
|
!isVehicleAtMaxConnections &&
|
||||||
!isVehicleConnectingToNonConveyor &&
|
!isVehicleConnectingToNonConveyor &&
|
||||||
firstSelected.sphereUUID !== sphereUUID &&
|
firstSelected.sphereUUID !== sphereUUID &&
|
||||||
firstSelected.pathUUID !== pathUUID &&
|
firstSelected.modelUUID !== modelUUID &&
|
||||||
(firstSelected.isCorner || isConnectable)
|
(firstSelected.isCorner || isConnectable) &&
|
||||||
|
!(firstPath?.type === 'Conveyor' &&
|
||||||
|
pathData.type === 'Conveyor' &&
|
||||||
|
!(firstSelected.isCorner && isConnectable))
|
||||||
) {
|
) {
|
||||||
snappedSphere = {
|
snappedSphere = {
|
||||||
sphereUUID,
|
sphereUUID,
|
||||||
position: spherePosition,
|
position: spherePosition,
|
||||||
pathUUID,
|
modelUUID,
|
||||||
isCorner: isConnectable
|
isCorner: isConnectable
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -501,12 +633,12 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<group name='simulationConnectionGroup' visible={!isPlaying} >
|
||||||
{simulationPaths.flatMap(path => {
|
{simulationStates.flatMap(path => {
|
||||||
if (path.type === 'Conveyor') {
|
if (path.type === 'Conveyor') {
|
||||||
return path.points.flatMap(point =>
|
return path.points.flatMap(point =>
|
||||||
point.connections.targets.map((target, index) => {
|
point.connections.targets.map((target, index) => {
|
||||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
|
||||||
if (targetPath?.type === 'Vehicle') return null;
|
if (targetPath?.type === 'Vehicle') return null;
|
||||||
|
|
||||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
|
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
|
||||||
|
@ -545,8 +677,8 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else if (path.type === 'Vehicle') {
|
} else if (path.type === 'Vehicle') {
|
||||||
return path.point.connections.targets.map((target, index) => {
|
return path.points.connections.targets.map((target, index) => {
|
||||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.point.uuid);
|
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid);
|
||||||
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
||||||
|
|
||||||
if (fromSphere && toSphere) {
|
if (fromSphere && toSphere) {
|
||||||
|
@ -566,7 +698,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QuadraticBezierLine
|
<QuadraticBezierLine
|
||||||
key={`${path.point.uuid}-${target.pointUUID}-${index}`}
|
key={`${path.points.uuid}-${target.pointUUID}-${index}`}
|
||||||
start={fromWorldPosition.toArray()}
|
start={fromWorldPosition.toArray()}
|
||||||
end={toWorldPosition.toArray()}
|
end={toWorldPosition.toArray()}
|
||||||
mid={midPoint.toArray()}
|
mid={midPoint.toArray()}
|
||||||
|
@ -596,7 +728,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
dashScale={20}
|
dashScale={20}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,362 +3,340 @@ import * as Types from "../../../types/world/worldTypes";
|
||||||
import { useRef, useState, useEffect, useMemo } from "react";
|
import { useRef, useState, useEffect, useMemo } from "react";
|
||||||
import { Sphere, TransformControls } from "@react-three/drei";
|
import { Sphere, TransformControls } from "@react-three/drei";
|
||||||
import {
|
import {
|
||||||
useEditingPoint,
|
useEditingPoint,
|
||||||
useEyeDropMode,
|
useEyeDropMode,
|
||||||
useIsConnecting,
|
useIsConnecting,
|
||||||
usePreviewPosition,
|
usePreviewPosition,
|
||||||
useRenderDistance,
|
useRenderDistance,
|
||||||
useSelectedActionSphere,
|
useSelectedActionSphere,
|
||||||
useSelectedPath,
|
useSelectedPath,
|
||||||
useSimulationPaths,
|
useSimulationStates,
|
||||||
} from "../../../store/store";
|
} 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 { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
|
import { setEventApi } from "../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
|
||||||
|
|
||||||
function PathCreation({
|
function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObject<THREE.Group>; }) {
|
||||||
pathsGroupRef,
|
const { isPlaying } = usePlayButtonStore();
|
||||||
}: {
|
const { renderDistance } = useRenderDistance();
|
||||||
pathsGroupRef: React.MutableRefObject<THREE.Group>;
|
const { setSubModule } = useSubModuleStore();
|
||||||
}) {
|
const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
||||||
const { renderDistance } = useRenderDistance();
|
const { editingPoint, setEditingPoint } = useEditingPoint();
|
||||||
const { setSubModule } = useSubModuleStore();
|
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
||||||
const { setSelectedActionSphere, selectedActionSphere } =
|
const { raycaster, camera, pointer, gl } = useThree();
|
||||||
useSelectedActionSphere();
|
const { setSelectedPath } = useSelectedPath();
|
||||||
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const { editingPoint, setEditingPoint } = useEditingPoint();
|
const { isConnecting } = useIsConnecting();
|
||||||
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const { raycaster, camera, pointer, gl } = useThree();
|
|
||||||
const plane = useMemo(
|
|
||||||
() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
const { setSelectedPath } = useSelectedPath();
|
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
|
||||||
const { isConnecting } = useIsConnecting();
|
|
||||||
|
|
||||||
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
||||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||||
const isMovingRef = useRef(false);
|
const isMovingRef = useRef(false);
|
||||||
const transformRef = useRef<any>(null);
|
const transformRef = useRef<any>(null);
|
||||||
const [transformMode, setTransformMode] = useState<
|
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
||||||
"translate" | "rotate" | null
|
|
||||||
>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTransformMode(null);
|
setTransformMode(null);
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
if (e.key === "g") {
|
if (e.key === "g") {
|
||||||
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
||||||
}
|
}
|
||||||
if (e.key === "r") {
|
if (e.key === "r") {
|
||||||
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("keydown", handleKeyDown);
|
window.addEventListener("keydown", handleKeyDown);
|
||||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||||
}, [selectedActionSphere]);
|
}, [selectedActionSphere]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
Object.values(groupRefs.current).forEach((group) => {
|
Object.values(groupRefs.current).forEach((group) => {
|
||||||
if (group) {
|
if (group) {
|
||||||
const distance = new THREE.Vector3(
|
const distance = new THREE.Vector3(
|
||||||
...group.position.toArray()
|
...group.position.toArray()
|
||||||
).distanceTo(camera.position);
|
).distanceTo(camera.position);
|
||||||
group.visible = ((distance <= renderDistance) && !isPlaying);
|
group.visible = ((distance <= renderDistance) && !isPlaying);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateSimulationPaths = () => {
|
const updateSimulationPaths = () => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => {
|
const updatedPaths = simulationStates.map((path) => {
|
||||||
if (path.type === "Conveyor") {
|
if (path.type === "Conveyor") {
|
||||||
return {
|
return {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.points.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
position: [
|
position: [
|
||||||
selectedActionSphere.point.position.x,
|
selectedActionSphere.points.position.x,
|
||||||
selectedActionSphere.point.position.y,
|
selectedActionSphere.points.position.y,
|
||||||
selectedActionSphere.point.position.z,
|
selectedActionSphere.points.position.z,
|
||||||
],
|
],
|
||||||
rotation: [
|
rotation: [
|
||||||
selectedActionSphere.point.rotation.x,
|
selectedActionSphere.points.rotation.x,
|
||||||
selectedActionSphere.point.rotation.y,
|
selectedActionSphere.points.rotation.y,
|
||||||
selectedActionSphere.point.rotation.z,
|
selectedActionSphere.points.rotation.z,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
} else {
|
||||||
return path;
|
return path;
|
||||||
}) as Types.ConveyorEventsSchema[];
|
}
|
||||||
|
}) as Types.ConveyorEventsSchema[];
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
const updatedPath = updatedPaths.find(
|
||||||
};
|
(path) => path.type === "Conveyor" && path.points.some((point) => point.uuid === selectedActionSphere.points.uuid)
|
||||||
|
);
|
||||||
|
|
||||||
useFrame(() => {
|
// console.log("Updated Path:", updatedPath);
|
||||||
if (eyeDropMode) {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
|
|
||||||
if (point) {
|
setSimulationStates(updatedPaths);
|
||||||
setPreviewPosition({ x: point.x, y: point.z });
|
};
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setPreviewPosition(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useFrame(() => {
|
||||||
if (!camera) return;
|
if (eyeDropMode) {
|
||||||
const canvasElement = gl.domElement;
|
raycaster.setFromCamera(pointer, camera);
|
||||||
canvasElement.tabIndex = 0;
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
const onPointerDown = () => {
|
if (point) {
|
||||||
isMovingRef.current = false;
|
setPreviewPosition({ x: point.x, y: point.z });
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
setPreviewPosition(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const onPointerMove = () => {
|
useEffect(() => {
|
||||||
isMovingRef.current = true;
|
if (!camera) return;
|
||||||
};
|
const canvasElement = gl.domElement;
|
||||||
|
canvasElement.tabIndex = 0;
|
||||||
|
|
||||||
const onPointerUp = (event: PointerEvent) => {
|
const onPointerDown = () => {
|
||||||
if (
|
isMovingRef.current = false;
|
||||||
!isMovingRef.current &&
|
};
|
||||||
eyeDropMode &&
|
|
||||||
event.button === 0 &&
|
|
||||||
previewPosition
|
|
||||||
) {
|
|
||||||
event.preventDefault();
|
|
||||||
if (editingPoint) {
|
|
||||||
handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y);
|
|
||||||
setEditingPoint(null);
|
|
||||||
setEyeDropMode(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (eyeDropMode) {
|
const onPointerMove = () => {
|
||||||
canvasElement.addEventListener("pointerdown", onPointerDown);
|
isMovingRef.current = true;
|
||||||
canvasElement.addEventListener("pointermove", onPointerMove);
|
};
|
||||||
canvasElement.addEventListener("pointerup", onPointerUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
if (
|
||||||
canvasElement.removeEventListener("pointermove", onPointerMove);
|
!isMovingRef.current &&
|
||||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
eyeDropMode &&
|
||||||
};
|
event.button === 0 &&
|
||||||
}, [eyeDropMode, editingPoint, previewPosition]);
|
previewPosition
|
||||||
|
) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (editingPoint) {
|
||||||
|
handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y);
|
||||||
|
setEditingPoint(null);
|
||||||
|
setEyeDropMode(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handlePointUpdate = (
|
if (eyeDropMode) {
|
||||||
pointType: "start" | "end",
|
canvasElement.addEventListener("pointerdown", onPointerDown);
|
||||||
x: number,
|
canvasElement.addEventListener("pointermove", onPointerMove);
|
||||||
z: number
|
canvasElement.addEventListener("pointerup", onPointerUp);
|
||||||
) => {
|
}
|
||||||
if (!selectedActionSphere?.point?.uuid) return;
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => {
|
return () => {
|
||||||
if (
|
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
||||||
path.type === "Vehicle" &&
|
canvasElement.removeEventListener("pointermove", onPointerMove);
|
||||||
path.point.uuid === selectedActionSphere.point.uuid
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||||
) {
|
};
|
||||||
return {
|
}, [eyeDropMode, editingPoint, previewPosition]);
|
||||||
...path,
|
|
||||||
point: {
|
|
||||||
...path.point,
|
|
||||||
actions: {
|
|
||||||
...path.point.actions,
|
|
||||||
[pointType]: {
|
|
||||||
...path.point.actions[pointType],
|
|
||||||
x: x,
|
|
||||||
y: z,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
});
|
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => {
|
||||||
};
|
if (!updatedPath) return;
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||||
|
await setEventApi(
|
||||||
|
organization,
|
||||||
|
updatedPath.modeluuid,
|
||||||
|
{ type: "Vehicle", points: updatedPath.points }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
const handlePointUpdate = (pointType: "start" | "end", x: number, z: number) => {
|
||||||
<group visible={!isPlaying} name="simulation-simulationPaths-group" ref={pathsGroupRef}>
|
if (!selectedActionSphere?.points?.uuid) return;
|
||||||
{simulationPaths.map((path) => {
|
const updatedPaths = simulationStates.map((path) => {
|
||||||
if (path.type === "Conveyor") {
|
|
||||||
const points = path.points.map(
|
|
||||||
(point) => new THREE.Vector3(...point.position)
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
|
||||||
<group
|
return {
|
||||||
name={`${path.modeluuid}-event-path`}
|
...path,
|
||||||
key={path.modeluuid}
|
points: {
|
||||||
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
...path.points,
|
||||||
position={path.position}
|
actions: {
|
||||||
rotation={path.rotation}
|
...path.points.actions,
|
||||||
onClick={(e) => {
|
[pointType]: { ...path.points.actions[pointType], x: x, y: z, },
|
||||||
if (isConnecting || eyeDropMode) return;
|
},
|
||||||
e.stopPropagation();
|
},
|
||||||
setSelectedPath({
|
};
|
||||||
path,
|
}
|
||||||
group: groupRefs.current[path.modeluuid],
|
return path;
|
||||||
});
|
});
|
||||||
setSelectedActionSphere(null);
|
|
||||||
setTransformMode(null);
|
|
||||||
setSubModule("mechanics");
|
|
||||||
}}
|
|
||||||
onPointerMissed={() => {
|
|
||||||
if (eyeDropMode) return;
|
|
||||||
setSelectedPath(null);
|
|
||||||
setSubModule("properties");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{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 || eyeDropMode) return;
|
|
||||||
e.stopPropagation();
|
|
||||||
setSelectedActionSphere({
|
|
||||||
path,
|
|
||||||
point: sphereRefs.current[point.uuid],
|
|
||||||
});
|
|
||||||
setSubModule("mechanics");
|
|
||||||
setSelectedPath(null);
|
|
||||||
}}
|
|
||||||
userData={{ point, path }}
|
|
||||||
onPointerMissed={() => {
|
|
||||||
if (eyeDropMode) return;
|
|
||||||
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 updatedPath = updatedPaths.find((path): path is Types.VehicleEventsSchema => path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid);
|
||||||
const nextPoint = points[index + 1];
|
updateBackend(updatedPath);
|
||||||
const segmentCurve = new THREE.CatmullRomCurve3([
|
|
||||||
point,
|
|
||||||
nextPoint,
|
|
||||||
]);
|
|
||||||
const tubeGeometry = new THREE.TubeGeometry(
|
|
||||||
segmentCurve,
|
|
||||||
20,
|
|
||||||
0.1,
|
|
||||||
16,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
setSimulationStates(updatedPaths);
|
||||||
<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.position}
|
|
||||||
onClick={(e) => {
|
|
||||||
if (isConnecting || eyeDropMode) return;
|
|
||||||
e.stopPropagation();
|
|
||||||
setSelectedPath({
|
|
||||||
path,
|
|
||||||
group: groupRefs.current[path.modeluuid],
|
|
||||||
});
|
|
||||||
setSelectedActionSphere(null);
|
|
||||||
setTransformMode(null);
|
|
||||||
setSubModule("mechanics");
|
|
||||||
}}
|
|
||||||
onPointerMissed={() => {
|
|
||||||
if (eyeDropMode) return;
|
|
||||||
setSelectedPath(null);
|
|
||||||
setSubModule("properties");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Sphere
|
|
||||||
key={path.point.uuid}
|
|
||||||
uuid={path.point.uuid}
|
|
||||||
position={path.point.position}
|
|
||||||
args={[0.15, 32, 32]}
|
|
||||||
name="events-sphere"
|
|
||||||
ref={(el) => (sphereRefs.current[path.point.uuid] = el!)}
|
|
||||||
onClick={(e) => {
|
|
||||||
if (isConnecting || eyeDropMode) return;
|
|
||||||
e.stopPropagation();
|
|
||||||
setSelectedActionSphere({
|
|
||||||
path,
|
|
||||||
point: sphereRefs.current[path.point.uuid],
|
|
||||||
});
|
|
||||||
setSubModule("mechanics");
|
|
||||||
setSelectedPath(null);
|
|
||||||
}}
|
|
||||||
userData={{ point: path.point, path }}
|
|
||||||
onPointerMissed={() => {
|
|
||||||
if (eyeDropMode) return;
|
|
||||||
setSubModule("properties");
|
|
||||||
setSelectedActionSphere(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<meshStandardMaterial color="purple" />
|
|
||||||
</Sphere>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})}
|
|
||||||
|
|
||||||
{selectedActionSphere && transformMode && (
|
return (
|
||||||
<TransformControls
|
<group visible={!isPlaying} name="simulation-simulationStates-group" ref={pathsGroupRef}>
|
||||||
ref={transformRef}
|
{simulationStates.map((path) => {
|
||||||
object={selectedActionSphere.point}
|
if (path.type === "Conveyor") {
|
||||||
mode={transformMode}
|
const points = path.points.map(
|
||||||
onMouseUp={updateSimulationPaths}
|
(point) => new THREE.Vector3(...point.position)
|
||||||
/>
|
);
|
||||||
)}
|
|
||||||
</group>
|
return (
|
||||||
);
|
<group
|
||||||
|
name={`${path.modeluuid}-${path.type}-path`}
|
||||||
|
key={path.modeluuid}
|
||||||
|
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
||||||
|
position={path.position}
|
||||||
|
rotation={path.rotation}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (isConnecting || eyeDropMode) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedPath({
|
||||||
|
path,
|
||||||
|
group: groupRefs.current[path.modeluuid],
|
||||||
|
});
|
||||||
|
setSelectedActionSphere(null);
|
||||||
|
setTransformMode(null);
|
||||||
|
setSubModule("mechanics");
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
if (eyeDropMode) return;
|
||||||
|
setSelectedPath(null);
|
||||||
|
setSubModule("properties");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{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 || eyeDropMode) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedActionSphere({
|
||||||
|
path,
|
||||||
|
points: sphereRefs.current[point.uuid],
|
||||||
|
});
|
||||||
|
setSubModule("mechanics");
|
||||||
|
setSelectedPath(null);
|
||||||
|
}}
|
||||||
|
userData={{ points, path }}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
if (eyeDropMode) return;
|
||||||
|
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" || path.type === "StaticMachine") {
|
||||||
|
return (
|
||||||
|
<group
|
||||||
|
name={`${path.modeluuid}-${path.type}-path`}
|
||||||
|
key={path.modeluuid}
|
||||||
|
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
||||||
|
position={path.position}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (isConnecting || eyeDropMode) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedPath({
|
||||||
|
path,
|
||||||
|
group: groupRefs.current[path.modeluuid],
|
||||||
|
});
|
||||||
|
setSelectedActionSphere(null);
|
||||||
|
setTransformMode(null);
|
||||||
|
setSubModule("mechanics");
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
if (eyeDropMode) return;
|
||||||
|
setSelectedPath(null);
|
||||||
|
setSubModule("properties");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Sphere
|
||||||
|
key={path.points.uuid}
|
||||||
|
uuid={path.points.uuid}
|
||||||
|
position={path.points.position}
|
||||||
|
args={[0.15, 32, 32]}
|
||||||
|
name="events-sphere"
|
||||||
|
ref={(el) => (sphereRefs.current[path.points.uuid] = el!)}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (isConnecting || eyeDropMode) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedActionSphere({
|
||||||
|
path,
|
||||||
|
points: sphereRefs.current[path.points.uuid],
|
||||||
|
});
|
||||||
|
setSubModule("mechanics");
|
||||||
|
setSelectedPath(null);
|
||||||
|
}}
|
||||||
|
userData={{ points: path.points, path }}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
if (eyeDropMode) return;
|
||||||
|
setSubModule("properties");
|
||||||
|
setSelectedActionSphere(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<meshStandardMaterial color="purple" />
|
||||||
|
</Sphere>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})}
|
||||||
|
|
||||||
|
{selectedActionSphere && transformMode && (
|
||||||
|
<TransformControls
|
||||||
|
ref={transformRef}
|
||||||
|
object={selectedActionSphere.points}
|
||||||
|
mode={transformMode}
|
||||||
|
onMouseUp={updateSimulationPaths}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PathCreation;
|
export default PathCreation;
|
||||||
|
|
|
@ -1,916 +0,0 @@
|
||||||
// // animation-worker.js
|
|
||||||
// // This web worker handles animation calculations off the main thread
|
|
||||||
|
|
||||||
// /* eslint-disable no-restricted-globals */
|
|
||||||
// // The above disables the ESLint rule for this file since 'self' is valid in web workers
|
|
||||||
|
|
||||||
// // Store process data, animation states, and objects
|
|
||||||
// let processes = [];
|
|
||||||
// let animationStates = {};
|
|
||||||
// let lastTimestamp = 0;
|
|
||||||
|
|
||||||
// // Message handler for communication with main thread
|
|
||||||
// self.onmessage = function (event) {
|
|
||||||
// const { type, data } = event.data;
|
|
||||||
|
|
||||||
// switch (type) {
|
|
||||||
// case "initialize":
|
|
||||||
// processes = data.processes;
|
|
||||||
// initializeAnimationStates();
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case "update":
|
|
||||||
// const { timestamp, isPlaying } = data;
|
|
||||||
// if (isPlaying) {
|
|
||||||
// const delta = (timestamp - lastTimestamp) / 1000; // Convert to seconds
|
|
||||||
// updateAnimations(delta, timestamp);
|
|
||||||
// }
|
|
||||||
// lastTimestamp = timestamp;
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case "reset":
|
|
||||||
// resetAnimations();
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case "togglePlay":
|
|
||||||
// // If resuming from pause, recalculate the time delta
|
|
||||||
// lastTimestamp = data.timestamp;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Initialize animation states for all processes
|
|
||||||
// function initializeAnimationStates() {
|
|
||||||
// animationStates = {};
|
|
||||||
|
|
||||||
// processes.forEach((process) => {
|
|
||||||
// animationStates[process.id] = {
|
|
||||||
// spawnedObjects: {},
|
|
||||||
// nextSpawnTime: 0,
|
|
||||||
// objectIdCounter: 0,
|
|
||||||
// };
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Send initial states back to main thread
|
|
||||||
// self.postMessage({
|
|
||||||
// type: "statesInitialized",
|
|
||||||
// data: { animationStates },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Reset all animations
|
|
||||||
// function resetAnimations() {
|
|
||||||
// initializeAnimationStates();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Find spawn point in a process
|
|
||||||
// function findSpawnPoint(process) {
|
|
||||||
// for (const path of process.paths || []) {
|
|
||||||
// for (const point of path.points || []) {
|
|
||||||
// const spawnAction = point.actions?.find(
|
|
||||||
// (a) => a.isUsed && a.type === "Spawn"
|
|
||||||
// );
|
|
||||||
// if (spawnAction) {
|
|
||||||
// return { point, path };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Create a new spawned object with proper initial position
|
|
||||||
// function createSpawnedObject(process, spawnPoint, currentTime, materialType) {
|
|
||||||
// // Extract spawn position from the actual spawn point
|
|
||||||
// const position = spawnPoint.point.position
|
|
||||||
// ? [...spawnPoint.point.position]
|
|
||||||
// : [0, 0, 0];
|
|
||||||
|
|
||||||
// // Get the path position and add it to the spawn point position
|
|
||||||
// const pathPosition = spawnPoint.path.pathPosition || [0, 0, 0];
|
|
||||||
// const absolutePosition = [
|
|
||||||
// position[0] + pathPosition[0],
|
|
||||||
// position[1] + pathPosition[1],
|
|
||||||
// position[2] + pathPosition[2],
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// id: `obj-${process.id}-${animationStates[process.id].objectIdCounter}`,
|
|
||||||
// position: absolutePosition,
|
|
||||||
// state: {
|
|
||||||
// currentIndex: 0,
|
|
||||||
// progress: 0,
|
|
||||||
// isAnimating: true,
|
|
||||||
// speed: process.speed || 1,
|
|
||||||
// isDelaying: false,
|
|
||||||
// delayStartTime: 0,
|
|
||||||
// currentDelayDuration: 0,
|
|
||||||
// delayComplete: false,
|
|
||||||
// currentPathIndex: 0,
|
|
||||||
// // Store the spawn point index to start animation from correct path point
|
|
||||||
// spawnPointIndex: getPointIndexInProcess(process, spawnPoint.point),
|
|
||||||
// },
|
|
||||||
// visible: true,
|
|
||||||
// materialType: materialType || "Default",
|
|
||||||
// spawnTime: currentTime,
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Get the index of a point within the process animation path
|
|
||||||
// function getPointIndexInProcess(process, point) {
|
|
||||||
// if (!process.paths) return 0;
|
|
||||||
|
|
||||||
// let cumulativePoints = 0;
|
|
||||||
// for (const path of process.paths) {
|
|
||||||
// for (let i = 0; i < (path.points?.length || 0); i++) {
|
|
||||||
// if (path.points[i].uuid === point.uuid) {
|
|
||||||
// return cumulativePoints + i;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// cumulativePoints += path.points?.length || 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Get point data for current animation index
|
|
||||||
// function getPointDataForAnimationIndex(process, index) {
|
|
||||||
// if (!process.paths) return null;
|
|
||||||
|
|
||||||
// let cumulativePoints = 0;
|
|
||||||
// for (const path of process.paths) {
|
|
||||||
// const pointCount = path.points?.length || 0;
|
|
||||||
|
|
||||||
// if (index < cumulativePoints + pointCount) {
|
|
||||||
// const pointIndex = index - cumulativePoints;
|
|
||||||
// return path.points?.[pointIndex] || null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// cumulativePoints += pointCount;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Convert process paths to Vector3 format
|
|
||||||
// function getProcessPath(process) {
|
|
||||||
// return process.animationPath?.map((p) => ({ x: p.x, y: p.y, z: p.z })) || [];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Handle material swap for an object
|
|
||||||
// function handleMaterialSwap(processId, objectId, materialType) {
|
|
||||||
// const processState = animationStates[processId];
|
|
||||||
// if (!processState || !processState.spawnedObjects[objectId]) return;
|
|
||||||
|
|
||||||
// processState.spawnedObjects[objectId].materialType = materialType;
|
|
||||||
|
|
||||||
// // Notify main thread about material change
|
|
||||||
// self.postMessage({
|
|
||||||
// type: "materialChanged",
|
|
||||||
// data: {
|
|
||||||
// processId,
|
|
||||||
// objectId,
|
|
||||||
// materialType,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Handle point actions for an object
|
|
||||||
// function handlePointActions(processId, objectId, actions = [], currentTime) {
|
|
||||||
// let shouldStopAnimation = false;
|
|
||||||
// const processState = animationStates[processId];
|
|
||||||
|
|
||||||
// if (!processState || !processState.spawnedObjects[objectId]) return false;
|
|
||||||
|
|
||||||
// const objectState = processState.spawnedObjects[objectId];
|
|
||||||
|
|
||||||
// actions.forEach((action) => {
|
|
||||||
// if (!action.isUsed) return;
|
|
||||||
|
|
||||||
// switch (action.type) {
|
|
||||||
// case "Delay":
|
|
||||||
// if (objectState.state.isDelaying) return;
|
|
||||||
|
|
||||||
// const delayDuration =
|
|
||||||
// typeof action.delay === "number"
|
|
||||||
// ? action.delay
|
|
||||||
// : parseFloat(action.delay || "0");
|
|
||||||
|
|
||||||
// if (delayDuration > 0) {
|
|
||||||
// objectState.state.isDelaying = true;
|
|
||||||
// objectState.state.delayStartTime = currentTime;
|
|
||||||
// objectState.state.currentDelayDuration = delayDuration;
|
|
||||||
// objectState.state.delayComplete = false;
|
|
||||||
// shouldStopAnimation = true;
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case "Despawn":
|
|
||||||
// delete processState.spawnedObjects[objectId];
|
|
||||||
// shouldStopAnimation = true;
|
|
||||||
|
|
||||||
// // Notify main thread about despawn
|
|
||||||
// self.postMessage({
|
|
||||||
// type: "objectDespawned",
|
|
||||||
// data: {
|
|
||||||
// processId,
|
|
||||||
// objectId,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case "Swap":
|
|
||||||
// if (action.material) {
|
|
||||||
// handleMaterialSwap(processId, objectId, action.material);
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// default:
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return shouldStopAnimation;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Check if point has non-inherit actions
|
|
||||||
// function hasNonInheritActions(actions = []) {
|
|
||||||
// return actions.some((action) => action.isUsed && action.type !== "Inherit");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Calculate vector lerp (linear interpolation)
|
|
||||||
// function lerpVectors(v1, v2, alpha) {
|
|
||||||
// return {
|
|
||||||
// x: v1.x + (v2.x - v1.x) * alpha,
|
|
||||||
// y: v1.y + (v2.y - v1.y) * alpha,
|
|
||||||
// z: v1.z + (v2.z - v1.z) * alpha,
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Calculate vector distance
|
|
||||||
// function distanceBetweenVectors(v1, v2) {
|
|
||||||
// const dx = v2.x - v1.x;
|
|
||||||
// const dy = v2.y - v1.y;
|
|
||||||
// const dz = v2.z - v1.z;
|
|
||||||
// return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Process spawn logic
|
|
||||||
// function processSpawns(currentTime) {
|
|
||||||
// processes.forEach((process) => {
|
|
||||||
// const processState = animationStates[process.id];
|
|
||||||
// if (!processState) return;
|
|
||||||
|
|
||||||
// const spawnPointData = findSpawnPoint(process);
|
|
||||||
// if (!spawnPointData || !spawnPointData.point.actions) return;
|
|
||||||
|
|
||||||
// const spawnAction = spawnPointData.point.actions.find(
|
|
||||||
// (a) => a.isUsed && a.type === "Spawn"
|
|
||||||
// );
|
|
||||||
// if (!spawnAction) return;
|
|
||||||
|
|
||||||
// const spawnInterval =
|
|
||||||
// typeof spawnAction.spawnInterval === "number"
|
|
||||||
// ? spawnAction.spawnInterval
|
|
||||||
// : parseFloat(spawnAction.spawnInterval || "0");
|
|
||||||
|
|
||||||
// if (currentTime >= processState.nextSpawnTime) {
|
|
||||||
// const newObject = createSpawnedObject(
|
|
||||||
// process,
|
|
||||||
// spawnPointData,
|
|
||||||
// currentTime,
|
|
||||||
// spawnAction.material || "Default"
|
|
||||||
// );
|
|
||||||
|
|
||||||
// processState.spawnedObjects[newObject.id] = newObject;
|
|
||||||
// processState.objectIdCounter++;
|
|
||||||
// processState.nextSpawnTime = currentTime + spawnInterval;
|
|
||||||
|
|
||||||
// // Notify main thread about new object
|
|
||||||
// self.postMessage({
|
|
||||||
// type: "objectSpawned",
|
|
||||||
// data: {
|
|
||||||
// processId: process.id,
|
|
||||||
// object: newObject,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Update all animations
|
|
||||||
// function updateAnimations(delta, currentTime) {
|
|
||||||
// // First handle spawning of new objects
|
|
||||||
// processSpawns(currentTime);
|
|
||||||
|
|
||||||
// // Then animate existing objects
|
|
||||||
// processes.forEach((process) => {
|
|
||||||
// const processState = animationStates[process.id];
|
|
||||||
// if (!processState) return;
|
|
||||||
|
|
||||||
// const path = getProcessPath(process);
|
|
||||||
// if (path.length < 2) return;
|
|
||||||
|
|
||||||
// const updatedObjects = {};
|
|
||||||
// let hasChanges = false;
|
|
||||||
|
|
||||||
// Object.entries(processState.spawnedObjects).forEach(([objectId, obj]) => {
|
|
||||||
// if (!obj.visible || !obj.state.isAnimating) return;
|
|
||||||
|
|
||||||
// const stateRef = obj.state;
|
|
||||||
|
|
||||||
// // Use the spawnPointIndex as starting point if it's the initial movement
|
|
||||||
// if (stateRef.currentIndex === 0 && stateRef.progress === 0) {
|
|
||||||
// stateRef.currentIndex = stateRef.spawnPointIndex || 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Get current point data
|
|
||||||
// const currentPointData = getPointDataForAnimationIndex(
|
|
||||||
// process,
|
|
||||||
// stateRef.currentIndex
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // Execute actions when arriving at a new point
|
|
||||||
// if (stateRef.progress === 0 && currentPointData?.actions) {
|
|
||||||
// const shouldStop = handlePointActions(
|
|
||||||
// process.id,
|
|
||||||
// objectId,
|
|
||||||
// currentPointData.actions,
|
|
||||||
// currentTime
|
|
||||||
// );
|
|
||||||
// if (shouldStop) return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Handle delays
|
|
||||||
// if (stateRef.isDelaying) {
|
|
||||||
// if (
|
|
||||||
// currentTime - stateRef.delayStartTime >=
|
|
||||||
// stateRef.currentDelayDuration
|
|
||||||
// ) {
|
|
||||||
// stateRef.isDelaying = false;
|
|
||||||
// stateRef.delayComplete = true;
|
|
||||||
// } else {
|
|
||||||
// updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
|
||||||
// return; // Keep waiting
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const nextPointIdx = stateRef.currentIndex + 1;
|
|
||||||
// const isLastPoint = nextPointIdx >= path.length;
|
|
||||||
|
|
||||||
// if (isLastPoint) {
|
|
||||||
// if (currentPointData?.actions) {
|
|
||||||
// const shouldStop = !hasNonInheritActions(currentPointData.actions);
|
|
||||||
// if (shouldStop) {
|
|
||||||
// // Reached the end of path with no more actions
|
|
||||||
// delete processState.spawnedObjects[objectId];
|
|
||||||
|
|
||||||
// // Notify main thread to remove the object
|
|
||||||
// self.postMessage({
|
|
||||||
// type: "objectCompleted",
|
|
||||||
// data: {
|
|
||||||
// processId: process.id,
|
|
||||||
// objectId,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!isLastPoint) {
|
|
||||||
// const currentPos = path[stateRef.currentIndex];
|
|
||||||
// const nextPos = path[nextPointIdx];
|
|
||||||
// const distance = distanceBetweenVectors(currentPos, nextPos);
|
|
||||||
// const movement = stateRef.speed * delta;
|
|
||||||
|
|
||||||
// // Update progress based on distance and speed
|
|
||||||
// const oldProgress = stateRef.progress;
|
|
||||||
// stateRef.progress += movement / distance;
|
|
||||||
|
|
||||||
// if (stateRef.progress >= 1) {
|
|
||||||
// // Reached next point
|
|
||||||
// stateRef.currentIndex = nextPointIdx;
|
|
||||||
// stateRef.progress = 0;
|
|
||||||
// stateRef.delayComplete = false;
|
|
||||||
// obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
|
||||||
// } else {
|
|
||||||
// // Interpolate position
|
|
||||||
// const lerpedPos = lerpVectors(currentPos, nextPos, stateRef.progress);
|
|
||||||
// obj.position = [lerpedPos.x, lerpedPos.y, lerpedPos.z];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Only send updates when there's meaningful movement
|
|
||||||
// if (Math.abs(oldProgress - stateRef.progress) > 0.01) {
|
|
||||||
// hasChanges = true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Update animation state with modified objects
|
|
||||||
// if (Object.keys(updatedObjects).length > 0) {
|
|
||||||
// processState.spawnedObjects = {
|
|
||||||
// ...processState.spawnedObjects,
|
|
||||||
// ...updatedObjects,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Only send position updates when there are meaningful changes
|
|
||||||
// if (hasChanges) {
|
|
||||||
// self.postMessage({
|
|
||||||
// type: "positionsUpdated",
|
|
||||||
// data: {
|
|
||||||
// processId: process.id,
|
|
||||||
// objects: updatedObjects,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// animation-worker.js
|
|
||||||
// This web worker handles animation calculations off the main thread
|
|
||||||
|
|
||||||
/* eslint-disable no-restricted-globals */
|
|
||||||
// The above disables the ESLint rule for this file since 'self' is valid in web workers
|
|
||||||
|
|
||||||
// Store process data, animation states, and objects
|
|
||||||
let processes = [];
|
|
||||||
let animationStates = {};
|
|
||||||
let lastTimestamp = 0;
|
|
||||||
let debugMode = true;
|
|
||||||
|
|
||||||
// Logger function for debugging
|
|
||||||
function log(...args) {
|
|
||||||
if (debugMode) {
|
|
||||||
self.postMessage({
|
|
||||||
type: "debug",
|
|
||||||
data: { message: args.join(' ') }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message handler for communication with main thread
|
|
||||||
self.onmessage = function (event) {
|
|
||||||
const { type, data } = event.data;
|
|
||||||
log(`Worker received message: ${type}`);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case "initialize":
|
|
||||||
processes = data.processes;
|
|
||||||
log(`Initialized with ${processes.length} processes`);
|
|
||||||
initializeAnimationStates();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "update":
|
|
||||||
const { timestamp, isPlaying } = data;
|
|
||||||
if (isPlaying) {
|
|
||||||
const delta = lastTimestamp === 0 ? 0.016 : (timestamp - lastTimestamp) / 1000; // Convert to seconds
|
|
||||||
updateAnimations(delta, timestamp);
|
|
||||||
}
|
|
||||||
lastTimestamp = timestamp;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "reset":
|
|
||||||
log("Resetting animations");
|
|
||||||
resetAnimations();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "togglePlay":
|
|
||||||
// If resuming from pause, recalculate the time delta
|
|
||||||
log(`Toggle play: ${data.isPlaying}`);
|
|
||||||
lastTimestamp = data.timestamp;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "setDebug":
|
|
||||||
debugMode = data.enabled;
|
|
||||||
log(`Debug mode: ${debugMode}`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize animation states for all processes
|
|
||||||
function initializeAnimationStates() {
|
|
||||||
animationStates = {};
|
|
||||||
|
|
||||||
processes.forEach((process) => {
|
|
||||||
if (!process || !process.id) {
|
|
||||||
log("Invalid process found:", process);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
animationStates[process.id] = {
|
|
||||||
spawnedObjects: {},
|
|
||||||
nextSpawnTime: 0,
|
|
||||||
objectIdCounter: 0,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Send initial states back to main thread
|
|
||||||
self.postMessage({
|
|
||||||
type: "statesInitialized",
|
|
||||||
data: { animationStates },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset all animations
|
|
||||||
function resetAnimations() {
|
|
||||||
initializeAnimationStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find spawn point in a process
|
|
||||||
function findSpawnPoint(process) {
|
|
||||||
if (!process || !process.paths) {
|
|
||||||
log(`No paths found for process ${process?.id}`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const path of process.paths) {
|
|
||||||
if (!path || !path.points) continue;
|
|
||||||
|
|
||||||
for (const point of path.points) {
|
|
||||||
if (!point || !point.actions) continue;
|
|
||||||
|
|
||||||
const spawnAction = point.actions.find(
|
|
||||||
(a) => a && a.isUsed && a.type === "Spawn"
|
|
||||||
);
|
|
||||||
if (spawnAction) {
|
|
||||||
return { point, path };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log(`No spawn points found for process ${process.id}`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new spawned object with proper initial position
|
|
||||||
function createSpawnedObject(process, spawnPoint, currentTime, materialType) {
|
|
||||||
// Extract spawn position from the actual spawn point
|
|
||||||
const position = spawnPoint.point.position
|
|
||||||
? [...spawnPoint.point.position]
|
|
||||||
: [0, 0, 0];
|
|
||||||
|
|
||||||
// Get the path position and add it to the spawn point position
|
|
||||||
const pathPosition = spawnPoint.path.pathPosition || [0, 0, 0];
|
|
||||||
const absolutePosition = [
|
|
||||||
position[0] + pathPosition[0],
|
|
||||||
position[1] + pathPosition[1],
|
|
||||||
position[2] + pathPosition[2],
|
|
||||||
];
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: `obj-${process.id}-${animationStates[process.id].objectIdCounter}`,
|
|
||||||
position: absolutePosition,
|
|
||||||
state: {
|
|
||||||
currentIndex: 0,
|
|
||||||
progress: 0,
|
|
||||||
isAnimating: true,
|
|
||||||
speed: process.speed || 1,
|
|
||||||
isDelaying: false,
|
|
||||||
delayStartTime: 0,
|
|
||||||
currentDelayDuration: 0,
|
|
||||||
delayComplete: false,
|
|
||||||
currentPathIndex: 0,
|
|
||||||
// Store the spawn point index to start animation from correct path point
|
|
||||||
spawnPointIndex: getPointIndexInProcess(process, spawnPoint.point),
|
|
||||||
},
|
|
||||||
visible: true,
|
|
||||||
materialType: materialType || "Default",
|
|
||||||
spawnTime: currentTime,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the index of a point within the process animation path
|
|
||||||
function getPointIndexInProcess(process, point) {
|
|
||||||
if (!process.paths) return 0;
|
|
||||||
|
|
||||||
let cumulativePoints = 0;
|
|
||||||
for (const path of process.paths) {
|
|
||||||
for (let i = 0; i < (path.points?.length || 0); i++) {
|
|
||||||
if (path.points[i].uuid === point.uuid) {
|
|
||||||
return cumulativePoints + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cumulativePoints += path.points?.length || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get point data for current animation index
|
|
||||||
function getPointDataForAnimationIndex(process, index) {
|
|
||||||
if (!process.paths) return null;
|
|
||||||
|
|
||||||
let cumulativePoints = 0;
|
|
||||||
for (const path of process.paths) {
|
|
||||||
const pointCount = path.points?.length || 0;
|
|
||||||
|
|
||||||
if (index < cumulativePoints + pointCount) {
|
|
||||||
const pointIndex = index - cumulativePoints;
|
|
||||||
return path.points?.[pointIndex] || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
cumulativePoints += pointCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert process paths to Vector3 format
|
|
||||||
function getProcessPath(process) {
|
|
||||||
if (!process.animationPath) {
|
|
||||||
log(`No animation path for process ${process.id}`);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return process.animationPath.map((p) => ({ x: p.x, y: p.y, z: p.z })) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle material swap for an object
|
|
||||||
function handleMaterialSwap(processId, objectId, materialType) {
|
|
||||||
const processState = animationStates[processId];
|
|
||||||
if (!processState || !processState.spawnedObjects[objectId]) return;
|
|
||||||
|
|
||||||
processState.spawnedObjects[objectId].materialType = materialType;
|
|
||||||
|
|
||||||
// Notify main thread about material change
|
|
||||||
self.postMessage({
|
|
||||||
type: "materialChanged",
|
|
||||||
data: {
|
|
||||||
processId,
|
|
||||||
objectId,
|
|
||||||
materialType,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle point actions for an object
|
|
||||||
function handlePointActions(processId, objectId, actions = [], currentTime) {
|
|
||||||
let shouldStopAnimation = false;
|
|
||||||
const processState = animationStates[processId];
|
|
||||||
|
|
||||||
if (!processState || !processState.spawnedObjects[objectId]) return false;
|
|
||||||
|
|
||||||
const objectState = processState.spawnedObjects[objectId];
|
|
||||||
|
|
||||||
actions.forEach((action) => {
|
|
||||||
if (!action || !action.isUsed) return;
|
|
||||||
|
|
||||||
switch (action.type) {
|
|
||||||
case "Delay":
|
|
||||||
if (objectState.state.isDelaying) return;
|
|
||||||
|
|
||||||
const delayDuration =
|
|
||||||
typeof action.delay === "number"
|
|
||||||
? action.delay
|
|
||||||
: parseFloat(action.delay || "0");
|
|
||||||
|
|
||||||
if (delayDuration > 0) {
|
|
||||||
objectState.state.isDelaying = true;
|
|
||||||
objectState.state.delayStartTime = currentTime;
|
|
||||||
objectState.state.currentDelayDuration = delayDuration;
|
|
||||||
objectState.state.delayComplete = false;
|
|
||||||
shouldStopAnimation = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "Despawn":
|
|
||||||
delete processState.spawnedObjects[objectId];
|
|
||||||
shouldStopAnimation = true;
|
|
||||||
|
|
||||||
// Notify main thread about despawn
|
|
||||||
self.postMessage({
|
|
||||||
type: "objectDespawned",
|
|
||||||
data: {
|
|
||||||
processId,
|
|
||||||
objectId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "Swap":
|
|
||||||
if (action.material) {
|
|
||||||
handleMaterialSwap(processId, objectId, action.material);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return shouldStopAnimation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if point has non-inherit actions
|
|
||||||
function hasNonInheritActions(actions = []) {
|
|
||||||
return actions.some((action) => action && action.isUsed && action.type !== "Inherit");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate vector lerp (linear interpolation)
|
|
||||||
function lerpVectors(v1, v2, alpha) {
|
|
||||||
return {
|
|
||||||
x: v1.x + (v2.x - v1.x) * alpha,
|
|
||||||
y: v1.y + (v2.y - v1.y) * alpha,
|
|
||||||
z: v1.z + (v2.z - v1.z) * alpha,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate vector distance
|
|
||||||
function distanceBetweenVectors(v1, v2) {
|
|
||||||
const dx = v2.x - v1.x;
|
|
||||||
const dy = v2.y - v1.y;
|
|
||||||
const dz = v2.z - v1.z;
|
|
||||||
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process spawn logic
|
|
||||||
function processSpawns(currentTime) {
|
|
||||||
processes.forEach((process) => {
|
|
||||||
const processState = animationStates[process.id];
|
|
||||||
if (!processState) return;
|
|
||||||
|
|
||||||
const spawnPointData = findSpawnPoint(process);
|
|
||||||
if (!spawnPointData || !spawnPointData.point.actions) return;
|
|
||||||
|
|
||||||
const spawnAction = spawnPointData.point.actions.find(
|
|
||||||
(a) => a.isUsed && a.type === "Spawn"
|
|
||||||
);
|
|
||||||
if (!spawnAction) return;
|
|
||||||
|
|
||||||
const spawnInterval =
|
|
||||||
typeof spawnAction.spawnInterval === "number"
|
|
||||||
? spawnAction.spawnInterval
|
|
||||||
: parseFloat(spawnAction.spawnInterval || "2"); // Default to 2 seconds if not specified
|
|
||||||
|
|
||||||
if (currentTime >= processState.nextSpawnTime) {
|
|
||||||
const newObject = createSpawnedObject(
|
|
||||||
process,
|
|
||||||
spawnPointData,
|
|
||||||
currentTime,
|
|
||||||
spawnAction.material || "Default"
|
|
||||||
);
|
|
||||||
|
|
||||||
processState.spawnedObjects[newObject.id] = newObject;
|
|
||||||
processState.objectIdCounter++;
|
|
||||||
processState.nextSpawnTime = currentTime + spawnInterval;
|
|
||||||
|
|
||||||
log(`Spawned object ${newObject.id} for process ${process.id}`);
|
|
||||||
|
|
||||||
// Notify main thread about new object
|
|
||||||
self.postMessage({
|
|
||||||
type: "objectSpawned",
|
|
||||||
data: {
|
|
||||||
processId: process.id,
|
|
||||||
object: newObject,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update all animations
|
|
||||||
function updateAnimations(delta, currentTime) {
|
|
||||||
// First handle spawning of new objects
|
|
||||||
processSpawns(currentTime);
|
|
||||||
|
|
||||||
// Then animate existing objects
|
|
||||||
processes.forEach((process) => {
|
|
||||||
const processState = animationStates[process.id];
|
|
||||||
if (!processState) return;
|
|
||||||
|
|
||||||
const path = getProcessPath(process);
|
|
||||||
if (path.length < 2) {
|
|
||||||
log(`Path too short for process ${process.id}, length: ${path.length}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedObjects = {};
|
|
||||||
let hasChanges = false;
|
|
||||||
|
|
||||||
Object.entries(processState.spawnedObjects).forEach(([objectId, obj]) => {
|
|
||||||
if (!obj.visible || !obj.state.isAnimating) return;
|
|
||||||
|
|
||||||
const stateRef = obj.state;
|
|
||||||
|
|
||||||
// Use the spawnPointIndex as starting point if it's the initial movement
|
|
||||||
if (stateRef.currentIndex === 0 && stateRef.progress === 0) {
|
|
||||||
stateRef.currentIndex = stateRef.spawnPointIndex || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current point data
|
|
||||||
const currentPointData = getPointDataForAnimationIndex(
|
|
||||||
process,
|
|
||||||
stateRef.currentIndex
|
|
||||||
);
|
|
||||||
|
|
||||||
// Execute actions when arriving at a new point
|
|
||||||
if (stateRef.progress === 0 && currentPointData?.actions) {
|
|
||||||
const shouldStop = handlePointActions(
|
|
||||||
process.id,
|
|
||||||
objectId,
|
|
||||||
currentPointData.actions,
|
|
||||||
currentTime
|
|
||||||
);
|
|
||||||
if (shouldStop) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle delays
|
|
||||||
if (stateRef.isDelaying) {
|
|
||||||
if (
|
|
||||||
currentTime - stateRef.delayStartTime >=
|
|
||||||
stateRef.currentDelayDuration
|
|
||||||
) {
|
|
||||||
stateRef.isDelaying = false;
|
|
||||||
stateRef.delayComplete = true;
|
|
||||||
} else {
|
|
||||||
updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
|
||||||
return; // Keep waiting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextPointIdx = stateRef.currentIndex + 1;
|
|
||||||
const isLastPoint = nextPointIdx >= path.length;
|
|
||||||
|
|
||||||
if (isLastPoint) {
|
|
||||||
if (currentPointData?.actions) {
|
|
||||||
const shouldStop = !hasNonInheritActions(currentPointData.actions);
|
|
||||||
if (shouldStop) {
|
|
||||||
// Reached the end of path with no more actions
|
|
||||||
delete processState.spawnedObjects[objectId];
|
|
||||||
log(`Object ${objectId} completed path`);
|
|
||||||
|
|
||||||
// Notify main thread to remove the object
|
|
||||||
self.postMessage({
|
|
||||||
type: "objectCompleted",
|
|
||||||
data: {
|
|
||||||
processId: process.id,
|
|
||||||
objectId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isLastPoint) {
|
|
||||||
const currentPos = path[stateRef.currentIndex];
|
|
||||||
const nextPos = path[nextPointIdx];
|
|
||||||
const distance = distanceBetweenVectors(currentPos, nextPos);
|
|
||||||
|
|
||||||
// Ensure we don't divide by zero
|
|
||||||
if (distance > 0) {
|
|
||||||
const movement = stateRef.speed * delta;
|
|
||||||
|
|
||||||
// Update progress based on distance and speed
|
|
||||||
const oldProgress = stateRef.progress;
|
|
||||||
stateRef.progress += movement / distance;
|
|
||||||
|
|
||||||
if (stateRef.progress >= 1) {
|
|
||||||
// Reached next point
|
|
||||||
stateRef.currentIndex = nextPointIdx;
|
|
||||||
stateRef.progress = 0;
|
|
||||||
stateRef.delayComplete = false;
|
|
||||||
obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
|
||||||
} else {
|
|
||||||
// Interpolate position
|
|
||||||
const lerpedPos = lerpVectors(currentPos, nextPos, stateRef.progress);
|
|
||||||
obj.position = [lerpedPos.x, lerpedPos.y, lerpedPos.z];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only send updates when there's meaningful movement
|
|
||||||
if (Math.abs(oldProgress - stateRef.progress) > 0.01) {
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Skip to next point if distance is zero
|
|
||||||
stateRef.currentIndex = nextPointIdx;
|
|
||||||
stateRef.progress = 0;
|
|
||||||
obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update animation state with modified objects
|
|
||||||
if (Object.keys(updatedObjects).length > 0) {
|
|
||||||
processState.spawnedObjects = {
|
|
||||||
...processState.spawnedObjects,
|
|
||||||
...updatedObjects,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only send position updates when there are meaningful changes
|
|
||||||
if (hasChanges) {
|
|
||||||
self.postMessage({
|
|
||||||
type: "positionsUpdated",
|
|
||||||
data: {
|
|
||||||
processId: process.id,
|
|
||||||
objects: updatedObjects,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@
|
||||||
// useCallback,
|
// useCallback,
|
||||||
// useRef,
|
// useRef,
|
||||||
// } from "react";
|
// } from "react";
|
||||||
// import { useSimulationPaths } from "../../../store/store";
|
// import { useSimulationStates } from "../../../store/store";
|
||||||
// import * as THREE from "three";
|
// import * as THREE from "three";
|
||||||
// import { useThree } from "@react-three/fiber";
|
// import { useThree } from "@react-three/fiber";
|
||||||
// import {
|
// import {
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
// position: [number, number, number];
|
// position: [number, number, number];
|
||||||
// actions: PointAction[];
|
// actions: PointAction[];
|
||||||
// connections: {
|
// connections: {
|
||||||
// targets: Array<{ pathUUID: string }>;
|
// targets: Array<{ modelUUID: string }>;
|
||||||
// };
|
// };
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
// actions: point.actions.map(normalizeAction), // Preserve exact actions
|
// actions: point.actions.map(normalizeAction), // Preserve exact actions
|
||||||
// connections: {
|
// connections: {
|
||||||
// targets: point.connections.targets.map((target) => ({
|
// targets: point.connections.targets.map((target) => ({
|
||||||
// pathUUID: target.pathUUID,
|
// modelUUID: target.modelUUID,
|
||||||
// })),
|
// })),
|
||||||
// },
|
// },
|
||||||
// })),
|
// })),
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
// : [normalizeAction(path.point.actions)],
|
// : [normalizeAction(path.point.actions)],
|
||||||
// connections: {
|
// connections: {
|
||||||
// targets: path.point.connections.targets.map((target) => ({
|
// targets: path.point.connections.targets.map((target) => ({
|
||||||
// pathUUID: target.pathUUID,
|
// modelUUID: target.modelUUID,
|
||||||
// })),
|
// })),
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
|
@ -137,18 +137,18 @@
|
||||||
// // Check if current last connects to next last (requires reversal)
|
// // Check if current last connects to next last (requires reversal)
|
||||||
// const connectsToLast = currentLastPoint.connections.targets.some(
|
// const connectsToLast = currentLastPoint.connections.targets.some(
|
||||||
// (target) =>
|
// (target) =>
|
||||||
// target.pathUUID === nextPath.modeluuid &&
|
// target.modelUUID === nextPath.modeluuid &&
|
||||||
// nextLastPoint.connections.targets.some(
|
// nextLastPoint.connections.targets.some(
|
||||||
// (t) => t.pathUUID === currentPath.modeluuid
|
// (t) => t.modelUUID === currentPath.modeluuid
|
||||||
// )
|
// )
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// // Check if current last connects to next first (no reversal needed)
|
// // Check if current last connects to next first (no reversal needed)
|
||||||
// const connectsToFirst = currentLastPoint.connections.targets.some(
|
// const connectsToFirst = currentLastPoint.connections.targets.some(
|
||||||
// (target) =>
|
// (target) =>
|
||||||
// target.pathUUID === nextPath.modeluuid &&
|
// target.modelUUID === nextPath.modeluuid &&
|
||||||
// nextFirstPoint.connections.targets.some(
|
// nextFirstPoint.connections.targets.some(
|
||||||
// (t) => t.pathUUID === currentPath.modeluuid
|
// (t) => t.modelUUID === currentPath.modeluuid
|
||||||
// )
|
// )
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
@ -249,10 +249,10 @@
|
||||||
// // Process outgoing connections
|
// // Process outgoing connections
|
||||||
// for (const point of currentPath.points) {
|
// for (const point of currentPath.points) {
|
||||||
// for (const target of point.connections.targets) {
|
// for (const target of point.connections.targets) {
|
||||||
// if (!visited.has(target.pathUUID)) {
|
// if (!visited.has(target.modelUUID)) {
|
||||||
// const targetPath = pathMap.get(target.pathUUID);
|
// const targetPath = pathMap.get(target.modelUUID);
|
||||||
// if (targetPath) {
|
// if (targetPath) {
|
||||||
// visited.add(target.pathUUID);
|
// visited.add(target.modelUUID);
|
||||||
// queue.push(targetPath);
|
// queue.push(targetPath);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
@ -264,7 +264,7 @@
|
||||||
// if (!visited.has(uuid)) {
|
// if (!visited.has(uuid)) {
|
||||||
// const hasConnectionToCurrent = path.points.some((point) =>
|
// const hasConnectionToCurrent = path.points.some((point) =>
|
||||||
// point.connections.targets.some(
|
// point.connections.targets.some(
|
||||||
// (t) => t.pathUUID === currentPath.modeluuid
|
// (t) => t.modelUUID === currentPath.modeluuid
|
||||||
// )
|
// )
|
||||||
// );
|
// );
|
||||||
// if (hasConnectionToCurrent) {
|
// if (hasConnectionToCurrent) {
|
||||||
|
@ -312,19 +312,19 @@
|
||||||
|
|
||||||
// const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
// const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
||||||
// ({ onProcessesCreated }) => {
|
// ({ onProcessesCreated }) => {
|
||||||
// const { simulationPaths } = useSimulationPaths();
|
// const { simulationStates } = useSimulationStates();
|
||||||
// const { createProcessesFromPaths } = useProcessCreation();
|
// const { createProcessesFromPaths } = useProcessCreation();
|
||||||
// const prevPathsRef = useRef<SimulationPath[]>([]);
|
// const prevPathsRef = useRef<SimulationPath[]>([]);
|
||||||
// const prevProcessesRef = useRef<Process[]>([]);
|
// const prevProcessesRef = useRef<Process[]>([]);
|
||||||
|
|
||||||
// const convertedPaths = useMemo((): SimulationPath[] => {
|
// const convertedPaths = useMemo((): SimulationPath[] => {
|
||||||
// if (!simulationPaths) return [];
|
// if (!simulationStates) return [];
|
||||||
// return simulationPaths.map((path) =>
|
// return simulationStates.map((path) =>
|
||||||
// convertToSimulationPath(
|
// convertToSimulationPath(
|
||||||
// path as ConveyorEventsSchema | VehicleEventsSchema
|
// path as ConveyorEventsSchema | VehicleEventsSchema
|
||||||
// )
|
// )
|
||||||
// );
|
// );
|
||||||
// }, [simulationPaths]);
|
// }, [simulationStates]);
|
||||||
|
|
||||||
// const pathsDependency = useMemo(() => {
|
// const pathsDependency = useMemo(() => {
|
||||||
// if (!convertedPaths) return null;
|
// if (!convertedPaths) return null;
|
||||||
|
@ -335,7 +335,7 @@
|
||||||
// ),
|
// ),
|
||||||
// connections: path.points
|
// connections: path.points
|
||||||
// .flatMap((p: PathPoint) =>
|
// .flatMap((p: PathPoint) =>
|
||||||
// p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
|
// p.connections.targets.map((t: { modelUUID: string }) => t.modelUUID)
|
||||||
// )
|
// )
|
||||||
// .join(","),
|
// .join(","),
|
||||||
// }));
|
// }));
|
||||||
|
@ -404,7 +404,7 @@ import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
useRef,
|
useRef,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { useSimulationPaths } from "../../../store/store";
|
import { useSimulationStates } from "../../../store/store";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import {
|
import {
|
||||||
|
@ -428,11 +428,12 @@ export interface PathPoint {
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
actions: PointAction[];
|
actions: PointAction[];
|
||||||
connections: {
|
connections: {
|
||||||
targets: Array<{ pathUUID: string }>;
|
targets: Array<{ modelUUID: string }>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimulationPath {
|
export interface SimulationPath {
|
||||||
|
type: string;
|
||||||
modeluuid: string;
|
modeluuid: string;
|
||||||
points: PathPoint[];
|
points: PathPoint[];
|
||||||
pathPosition: [number, number, number];
|
pathPosition: [number, number, number];
|
||||||
|
@ -464,6 +465,7 @@ function convertToSimulationPath(
|
||||||
|
|
||||||
if (path.type === "Conveyor") {
|
if (path.type === "Conveyor") {
|
||||||
return {
|
return {
|
||||||
|
type: path.type,
|
||||||
modeluuid,
|
modeluuid,
|
||||||
points: path.points.map((point) => ({
|
points: path.points.map((point) => ({
|
||||||
uuid: point.uuid,
|
uuid: point.uuid,
|
||||||
|
@ -471,7 +473,7 @@ function convertToSimulationPath(
|
||||||
actions: point.actions.map(normalizeAction), // Preserve exact actions
|
actions: point.actions.map(normalizeAction), // Preserve exact actions
|
||||||
connections: {
|
connections: {
|
||||||
targets: point.connections.targets.map((target) => ({
|
targets: point.connections.targets.map((target) => ({
|
||||||
pathUUID: target.pathUUID,
|
modelUUID: target.modelUUID,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
|
@ -483,23 +485,24 @@ function convertToSimulationPath(
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
type: path.type,
|
||||||
modeluuid,
|
modeluuid,
|
||||||
points: [
|
points: [
|
||||||
{
|
{
|
||||||
uuid: path.point.uuid,
|
uuid: path.points.uuid,
|
||||||
position: path.point.position,
|
position: path.points.position,
|
||||||
actions: Array.isArray(path.point.actions)
|
actions: Array.isArray(path.points.actions)
|
||||||
? path.point.actions.map(normalizeAction)
|
? path.points.actions.map(normalizeAction)
|
||||||
: [normalizeAction(path.point.actions)],
|
: [normalizeAction(path.points.actions)],
|
||||||
connections: {
|
connections: {
|
||||||
targets: path.point.connections.targets.map((target) => ({
|
targets: path.points.connections.targets.map((target) => ({
|
||||||
pathUUID: target.pathUUID,
|
modelUUID: target.modelUUID,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
pathPosition: path.position,
|
pathPosition: path.position,
|
||||||
speed: path.point.speed || 1,
|
speed: path.points.speed || 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -536,18 +539,18 @@ function shouldReverseNextPath(
|
||||||
// Check if current last connects to next last (requires reversal)
|
// Check if current last connects to next last (requires reversal)
|
||||||
const connectsToLast = currentLastPoint.connections.targets.some(
|
const connectsToLast = currentLastPoint.connections.targets.some(
|
||||||
(target) =>
|
(target) =>
|
||||||
target.pathUUID === nextPath.modeluuid &&
|
target.modelUUID === nextPath.modeluuid &&
|
||||||
nextLastPoint.connections.targets.some(
|
nextLastPoint.connections.targets.some(
|
||||||
(t) => t.pathUUID === currentPath.modeluuid
|
(t) => t.modelUUID === currentPath.modeluuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check if current last connects to next first (no reversal needed)
|
// Check if current last connects to next first (no reversal needed)
|
||||||
const connectsToFirst = currentLastPoint.connections.targets.some(
|
const connectsToFirst = currentLastPoint.connections.targets.some(
|
||||||
(target) =>
|
(target) =>
|
||||||
target.pathUUID === nextPath.modeluuid &&
|
target.modelUUID === nextPath.modeluuid &&
|
||||||
nextFirstPoint.connections.targets.some(
|
nextFirstPoint.connections.targets.some(
|
||||||
(t) => t.pathUUID === currentPath.modeluuid
|
(t) => t.modelUUID === currentPath.modeluuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -614,6 +617,7 @@ export function useProcessCreation() {
|
||||||
const [processes, setProcesses] = useState<Process[]>([]);
|
const [processes, setProcesses] = useState<Process[]>([]);
|
||||||
|
|
||||||
const hasSpawnAction = useCallback((path: SimulationPath): boolean => {
|
const hasSpawnAction = useCallback((path: SimulationPath): boolean => {
|
||||||
|
if (path.type !== "Conveyor") return false;
|
||||||
return path.points.some((point) =>
|
return path.points.some((point) =>
|
||||||
point.actions.some((action) => action.type.toLowerCase() === "spawn")
|
point.actions.some((action) => action.type.toLowerCase() === "spawn")
|
||||||
);
|
);
|
||||||
|
@ -674,10 +678,10 @@ export function useProcessCreation() {
|
||||||
// Process outgoing connections
|
// Process outgoing connections
|
||||||
for (const point of currentPath.points) {
|
for (const point of currentPath.points) {
|
||||||
for (const target of point.connections.targets) {
|
for (const target of point.connections.targets) {
|
||||||
if (!visited.has(target.pathUUID)) {
|
if (!visited.has(target.modelUUID)) {
|
||||||
const targetPath = pathMap.get(target.pathUUID);
|
const targetPath = pathMap.get(target.modelUUID);
|
||||||
if (targetPath) {
|
if (targetPath) {
|
||||||
visited.add(target.pathUUID);
|
visited.add(target.modelUUID);
|
||||||
queue.push(targetPath);
|
queue.push(targetPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -689,7 +693,7 @@ export function useProcessCreation() {
|
||||||
if (!visited.has(uuid)) {
|
if (!visited.has(uuid)) {
|
||||||
const hasConnectionToCurrent = path.points.some((point) =>
|
const hasConnectionToCurrent = path.points.some((point) =>
|
||||||
point.connections.targets.some(
|
point.connections.targets.some(
|
||||||
(t) => t.pathUUID === currentPath.modeluuid
|
(t) => t.modelUUID === currentPath.modeluuid
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (hasConnectionToCurrent) {
|
if (hasConnectionToCurrent) {
|
||||||
|
@ -737,19 +741,19 @@ export function useProcessCreation() {
|
||||||
|
|
||||||
const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
||||||
({ onProcessesCreated }) => {
|
({ onProcessesCreated }) => {
|
||||||
const { simulationPaths } = useSimulationPaths();
|
const { simulationStates } = useSimulationStates();
|
||||||
const { createProcessesFromPaths } = useProcessCreation();
|
const { createProcessesFromPaths } = useProcessCreation();
|
||||||
const prevPathsRef = useRef<SimulationPath[]>([]);
|
const prevPathsRef = useRef<SimulationPath[]>([]);
|
||||||
const prevProcessesRef = useRef<Process[]>([]);
|
const prevProcessesRef = useRef<Process[]>([]);
|
||||||
|
|
||||||
const convertedPaths = useMemo((): SimulationPath[] => {
|
const convertedPaths = useMemo((): SimulationPath[] => {
|
||||||
if (!simulationPaths) return [];
|
if (!simulationStates) return [];
|
||||||
return simulationPaths.map((path) =>
|
return simulationStates.map((path) =>
|
||||||
convertToSimulationPath(
|
convertToSimulationPath(
|
||||||
path as ConveyorEventsSchema | VehicleEventsSchema
|
path as ConveyorEventsSchema | VehicleEventsSchema
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}, [simulationPaths]);
|
}, [simulationStates]);
|
||||||
|
|
||||||
// Enhanced dependency tracking that includes action types
|
// Enhanced dependency tracking that includes action types
|
||||||
const pathsDependency = useMemo(() => {
|
const pathsDependency = useMemo(() => {
|
||||||
|
@ -764,7 +768,7 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
||||||
.join(","),
|
.join(","),
|
||||||
connections: path.points
|
connections: path.points
|
||||||
.flatMap((p: PathPoint) =>
|
.flatMap((p: PathPoint) =>
|
||||||
p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
|
p.connections.targets.map((t: { modelUUID: string }) => t.modelUUID)
|
||||||
)
|
)
|
||||||
.join(","),
|
.join(","),
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
import React, { useRef, useEffect } from "react";
|
||||||
|
import { useFrame } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { GLTF } from "three-stdlib";
|
||||||
|
import { Box3Helper } from "three";
|
||||||
|
import { SpawnedObject, ProcessData } from "./types";
|
||||||
|
|
||||||
|
interface ProcessObjectRendererProps {
|
||||||
|
objectId: string;
|
||||||
|
object: SpawnedObject;
|
||||||
|
process: ProcessData;
|
||||||
|
gltf: GLTF;
|
||||||
|
showBoundingBox?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProcessObjectRenderer: React.FC<ProcessObjectRendererProps> = ({
|
||||||
|
objectId,
|
||||||
|
object,
|
||||||
|
process,
|
||||||
|
gltf,
|
||||||
|
showBoundingBox = false,
|
||||||
|
}) => {
|
||||||
|
const meshRef = useRef<THREE.Mesh>(null);
|
||||||
|
const boxHelperRef = useRef<THREE.Box3Helper | null>(null);
|
||||||
|
const boundingBoxRef = useRef<THREE.Box3>(new THREE.Box3());
|
||||||
|
|
||||||
|
// Issue 1: Can't assign to ref.current as it's read-only
|
||||||
|
useEffect(() => {
|
||||||
|
if (object.ref && meshRef.current) {
|
||||||
|
// Instead of direct assignment, we need to store the mesh reference another way
|
||||||
|
// Option 1: If you can modify the SpawnedObject interface, add a setMesh method
|
||||||
|
if (typeof (object as any).setMesh === 'function') {
|
||||||
|
(object as any).setMesh(meshRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option 2: Store the mesh in a property that isn't ref.current
|
||||||
|
// This requires modifying your SpawnedObject interface to include this property
|
||||||
|
(object as any).meshInstance = meshRef.current;
|
||||||
|
|
||||||
|
// Option 3: If you need to maintain compatibility, you could use Object.defineProperty
|
||||||
|
// But this is a hack and not recommended
|
||||||
|
// Object.defineProperty(object.ref, 'current', { value: meshRef.current, writable: true });
|
||||||
|
}
|
||||||
|
}, [object.ref]);
|
||||||
|
|
||||||
|
// Create a bounding box helper for visualization
|
||||||
|
useFrame(() => {
|
||||||
|
if (meshRef.current && showBoundingBox) {
|
||||||
|
// Update the bounding box to match the mesh position
|
||||||
|
if (!boxHelperRef.current) {
|
||||||
|
// Get the size of the mesh
|
||||||
|
const size = new THREE.Vector3(1, 1, 1);
|
||||||
|
|
||||||
|
// If the mesh has geometry, use its dimensions
|
||||||
|
if (meshRef.current.geometry) {
|
||||||
|
const box = new THREE.Box3().setFromObject(meshRef.current);
|
||||||
|
box.getSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new bounding box centered on the mesh
|
||||||
|
boundingBoxRef.current = new THREE.Box3().setFromCenterAndSize(
|
||||||
|
meshRef.current.position,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a helper to visualize the box
|
||||||
|
boxHelperRef.current = new Box3Helper(
|
||||||
|
boundingBoxRef.current,
|
||||||
|
new THREE.Color(0xff0000)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add the helper to the scene
|
||||||
|
meshRef.current.parent?.add(boxHelperRef.current);
|
||||||
|
} else {
|
||||||
|
// Update the box position to match the mesh
|
||||||
|
boundingBoxRef.current.setFromCenterAndSize(
|
||||||
|
meshRef.current.position,
|
||||||
|
boundingBoxRef.current.getSize(new THREE.Vector3())
|
||||||
|
);
|
||||||
|
|
||||||
|
// Force the helper to update
|
||||||
|
boxHelperRef.current.updateMatrixWorld(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (gltf?.scene) {
|
||||||
|
return (
|
||||||
|
<primitive
|
||||||
|
ref={meshRef}
|
||||||
|
object={gltf.scene.clone()}
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
material={object.material}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue 2: Material color type problem
|
||||||
|
return (
|
||||||
|
<mesh ref={meshRef}>
|
||||||
|
<boxGeometry args={[1, 1, 1]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
// Fix the color property access
|
||||||
|
color={
|
||||||
|
object.material && 'color' in object.material
|
||||||
|
? (object.material as THREE.MeshStandardMaterial).color
|
||||||
|
: "#00ff00"
|
||||||
|
}
|
||||||
|
metalness={0.5}
|
||||||
|
roughness={0.3}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,79 @@
|
||||||
|
import * as THREE from "three";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export interface ProcessPoint {
|
||||||
|
uuid: string;
|
||||||
|
position: number[];
|
||||||
|
actions?: PointAction[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PointAction {
|
||||||
|
type: string;
|
||||||
|
isUsed: boolean;
|
||||||
|
spawnInterval?: number | string;
|
||||||
|
material?: string;
|
||||||
|
delay?: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProcessData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
paths?: {
|
||||||
|
points?: ProcessPoint[];
|
||||||
|
}[];
|
||||||
|
animationPath?: { x: number; y: number; z: number }[];
|
||||||
|
speed?: number;
|
||||||
|
customMaterials?: Record<string, THREE.Material>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProcessAnimationState {
|
||||||
|
spawnedObjects: Record<string, SpawnedObject | SpawnedObjectWithCollision>;
|
||||||
|
nextSpawnTime: number;
|
||||||
|
objectIdCounter: number;
|
||||||
|
isProcessDelaying: boolean;
|
||||||
|
processDelayStartTime: number;
|
||||||
|
processDelayDuration: number;
|
||||||
|
isCollisionPaused?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SpawnedObject {
|
||||||
|
ref: React.RefObject<THREE.Object3D>;
|
||||||
|
state: {
|
||||||
|
currentIndex: number;
|
||||||
|
progress: number;
|
||||||
|
isAnimating: boolean;
|
||||||
|
speed: number;
|
||||||
|
isDelaying: boolean;
|
||||||
|
delayStartTime: number;
|
||||||
|
currentDelayDuration: number;
|
||||||
|
delayComplete: boolean;
|
||||||
|
currentPathIndex: number;
|
||||||
|
};
|
||||||
|
visible: boolean;
|
||||||
|
material: THREE.Material;
|
||||||
|
currentMaterialType: string;
|
||||||
|
spawnTime: number;
|
||||||
|
position: THREE.Vector3;
|
||||||
|
collision?: {
|
||||||
|
boundingBox: THREE.Box3;
|
||||||
|
isColliding: boolean;
|
||||||
|
colliding: boolean; // Added this property
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// For use in your processAnimator.tsx
|
||||||
|
// Update the CollisionState interface to include all required properties
|
||||||
|
interface CollisionState {
|
||||||
|
boundingBox: THREE.Box3;
|
||||||
|
isColliding: boolean;
|
||||||
|
colliding: boolean; // This was missing
|
||||||
|
collidingWith: string[];
|
||||||
|
}
|
||||||
|
export interface SpawnedObjectWithCollision extends SpawnedObject {
|
||||||
|
collision: {
|
||||||
|
boundingBox: THREE.Box3;
|
||||||
|
isColliding: boolean;
|
||||||
|
colliding: boolean;
|
||||||
|
collidingWith: string[];
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import { useState, useEffect, useRef, useMemo } from "react";
|
||||||
import {
|
import {
|
||||||
useSelectedActionSphere,
|
useSelectedActionSphere,
|
||||||
useSelectedPath,
|
useSelectedPath,
|
||||||
useSimulationPaths,
|
useSimulationStates,
|
||||||
} from "../../store/store";
|
} from "../../store/store";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import Behaviour from "./behaviour/behaviour";
|
import Behaviour from "./behaviour/behaviour";
|
||||||
|
@ -15,12 +15,12 @@ import Agv from "../builder/agv/agv";
|
||||||
function Simulation() {
|
function Simulation() {
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const pathsGroupRef = useRef() as React.MutableRefObject<THREE.Group>;
|
const pathsGroupRef = useRef() as React.MutableRefObject<THREE.Group>;
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
const [processes, setProcesses] = useState([]);
|
const [processes, setProcesses] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('simulationPaths: ', simulationPaths);
|
// console.log('simulationStates: ', simulationStates);
|
||||||
}, [simulationPaths]);
|
}, [simulationStates]);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// if (selectedActionSphere) {
|
// if (selectedActionSphere) {
|
||||||
|
@ -42,7 +42,7 @@ function Simulation() {
|
||||||
<PathCreation pathsGroupRef={pathsGroupRef} />
|
<PathCreation pathsGroupRef={pathsGroupRef} />
|
||||||
<PathConnector pathsGroupRef={pathsGroupRef} />
|
<PathConnector pathsGroupRef={pathsGroupRef} />
|
||||||
<ProcessContainer />
|
<ProcessContainer />
|
||||||
{/* <Agv /> */}
|
<Agv />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// import { useMemo, useState } from 'react';
|
// import { useMemo, useState } from 'react';
|
||||||
// import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
|
// import { useSelectedActionSphere, useToggleView, useSimulationStates, 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';
|
||||||
|
|
||||||
|
@ -9,17 +9,17 @@
|
||||||
// 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 { simulationStates, setSimulationStates } = useSimulationStates();
|
||||||
// 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 = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) => {
|
// points: path.points.map((point) => {
|
||||||
// if (point.uuid === selectedActionSphere.point.uuid) {
|
// if (point.uuid === selectedActionSphere.points.uuid) {
|
||||||
// const actionIndex = point.actions.length;
|
// const actionIndex = point.actions.length;
|
||||||
// const newAction = {
|
// const newAction = {
|
||||||
// uuid: THREE.MathUtils.generateUUID(),
|
// uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -37,31 +37,31 @@
|
||||||
// }),
|
// }),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(updatedPaths);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// const handleDeleteAction = (uuid: string) => {
|
// const handleDeleteAction = (uuid: string) => {
|
||||||
// if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
// const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
// ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
||||||
// : point
|
// : point
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(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 = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? {
|
// ? {
|
||||||
// ...point,
|
// ...point,
|
||||||
// actions: point.actions.map((action) =>
|
// actions: point.actions.map((action) =>
|
||||||
|
@ -72,16 +72,16 @@
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(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 = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? {
|
// ? {
|
||||||
// ...point,
|
// ...point,
|
||||||
// actions: point.actions.map((action) =>
|
// actions: point.actions.map((action) =>
|
||||||
|
@ -92,16 +92,16 @@
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(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 = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? {
|
// ? {
|
||||||
// ...point,
|
// ...point,
|
||||||
// actions: point.actions.map((action) =>
|
// actions: point.actions.map((action) =>
|
||||||
|
@ -112,16 +112,16 @@
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(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 = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? {
|
// ? {
|
||||||
// ...point,
|
// ...point,
|
||||||
// actions: point.actions.map((action) =>
|
// actions: point.actions.map((action) =>
|
||||||
|
@ -132,27 +132,27 @@
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(updatedPaths);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// const handleSpeedChange = (speed: number) => {
|
// const handleSpeedChange = (speed: number) => {
|
||||||
// if (!selectedPath) return;
|
// if (!selectedPath) return;
|
||||||
|
|
||||||
// const updatedPaths = simulationPaths.map((path) =>
|
// const updatedPaths = simulationStates.map((path) =>
|
||||||
// path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
// path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(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 = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) => {
|
// points: path.points.map((point) => {
|
||||||
// if (point.uuid === selectedActionSphere.point.uuid) {
|
// if (point.uuid === selectedActionSphere.points.uuid) {
|
||||||
// const triggerIndex = point.triggers.length;
|
// const triggerIndex = point.triggers.length;
|
||||||
// const newTrigger = {
|
// const newTrigger = {
|
||||||
// uuid: THREE.MathUtils.generateUUID(),
|
// uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -167,31 +167,31 @@
|
||||||
// }),
|
// }),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(updatedPaths);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// const handleDeleteTrigger = (uuid: string) => {
|
// const handleDeleteTrigger = (uuid: string) => {
|
||||||
// if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
// const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
// ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
||||||
// : point
|
// : point
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(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 = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? {
|
// ? {
|
||||||
// ...point,
|
// ...point,
|
||||||
// triggers: point.triggers.map((trigger) =>
|
// triggers: point.triggers.map((trigger) =>
|
||||||
|
@ -202,7 +202,7 @@
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(updatedPaths);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// const handleResetPath = () => {
|
// const handleResetPath = () => {
|
||||||
|
@ -214,10 +214,10 @@
|
||||||
// const handleActionToggle = (uuid: string) => {
|
// const handleActionToggle = (uuid: string) => {
|
||||||
// if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
// const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? {
|
// ? {
|
||||||
// ...point,
|
// ...point,
|
||||||
// actions: point.actions.map((action) => ({
|
// actions: point.actions.map((action) => ({
|
||||||
|
@ -229,16 +229,16 @@
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(updatedPaths);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// const handleTriggerToggle = (uuid: string) => {
|
// const handleTriggerToggle = (uuid: string) => {
|
||||||
// if (!selectedActionSphere) return;
|
// if (!selectedActionSphere) return;
|
||||||
|
|
||||||
// const updatedPaths = simulationPaths.map((path) => ({
|
// const updatedPaths = simulationStates.map((path) => ({
|
||||||
// ...path,
|
// ...path,
|
||||||
// points: path.points.map((point) =>
|
// points: path.points.map((point) =>
|
||||||
// point.uuid === selectedActionSphere.point.uuid
|
// point.uuid === selectedActionSphere.points.uuid
|
||||||
// ? {
|
// ? {
|
||||||
// ...point,
|
// ...point,
|
||||||
// triggers: point.triggers.map((trigger) => ({
|
// triggers: point.triggers.map((trigger) => ({
|
||||||
|
@ -250,13 +250,13 @@
|
||||||
// ),
|
// ),
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
// setSimulationPaths(updatedPaths);
|
// setSimulationStates(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 simulationStates.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.points.uuid);
|
||||||
// }, [selectedActionSphere, simulationPaths]);
|
// }, [selectedActionSphere, simulationStates]);
|
||||||
|
|
||||||
// const createPath = () => {
|
// const createPath = () => {
|
||||||
// setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
|
// setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
|
||||||
|
|
|
@ -11,13 +11,13 @@ type PathPoint = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type PathCreatorProps = {
|
type PathCreatorProps = {
|
||||||
simulationPaths: PathPoint[][];
|
simulationStates: PathPoint[][];
|
||||||
setSimulationPaths: React.Dispatch<React.SetStateAction<PathPoint[][]>>;
|
setSimulationStates: React.Dispatch<React.SetStateAction<PathPoint[][]>>;
|
||||||
connections: { start: PathPoint; end: PathPoint }[];
|
connections: { start: PathPoint; end: PathPoint }[];
|
||||||
setConnections: React.Dispatch<React.SetStateAction<{ start: PathPoint; end: PathPoint }[]>>
|
setConnections: React.Dispatch<React.SetStateAction<{ start: PathPoint; end: PathPoint }[]>>
|
||||||
};
|
};
|
||||||
|
|
||||||
const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConnections }: PathCreatorProps) => {
|
const PathCreator = ({ simulationStates, setSimulationStates, connections, setConnections }: PathCreatorProps) => {
|
||||||
const { camera, scene, raycaster, pointer, gl } = useThree();
|
const { camera, scene, raycaster, pointer, gl } = useThree();
|
||||||
const { drawMaterialPath } = useDrawMaterialPath();
|
const { drawMaterialPath } = useDrawMaterialPath();
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (drag || e.button === 0) return;
|
if (drag || e.button === 0) return;
|
||||||
if (currentPath.length > 1) {
|
if (currentPath.length > 1) {
|
||||||
setSimulationPaths((prevPaths) => [...prevPaths, currentPath]);
|
setSimulationStates((prevPaths) => [...prevPaths, currentPath]);
|
||||||
}
|
}
|
||||||
setCurrentPath([]);
|
setCurrentPath([]);
|
||||||
setTemporaryPoint(null);
|
setTemporaryPoint(null);
|
||||||
|
@ -125,7 +125,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
|
||||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||||
} else {
|
} else {
|
||||||
if (currentPath.length > 1) {
|
if (currentPath.length > 1) {
|
||||||
setSimulationPaths((prevPaths) => [...prevPaths, currentPath]);
|
setSimulationStates((prevPaths) => [...prevPaths, currentPath]);
|
||||||
}
|
}
|
||||||
setCurrentPath([]);
|
setCurrentPath([]);
|
||||||
setTemporaryPoint(null);
|
setTemporaryPoint(null);
|
||||||
|
@ -179,25 +179,25 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
|
||||||
if (selectedPoint) {
|
if (selectedPoint) {
|
||||||
const updatedPosition = e.target.object.position.clone();
|
const updatedPosition = e.target.object.position.clone();
|
||||||
const updatedRotation = e.target.object.quaternion.clone();
|
const updatedRotation = e.target.object.quaternion.clone();
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationStates.map((path) =>
|
||||||
path.map((p) =>
|
path.map((p) =>
|
||||||
p.uuid === selectedPoint.uuid ? { ...p, position: updatedPosition, rotation: updatedRotation } : p
|
p.uuid === selectedPoint.uuid ? { ...p, position: updatedPosition, rotation: updatedRotation } : p
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationStates(updatedPaths);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const meshContext = (uuid: string) => {
|
const meshContext = (uuid: string) => {
|
||||||
const pathIndex = simulationPaths.findIndex(path => path.some(point => point.uuid === uuid));
|
const pathIndex = simulationStates.findIndex(path => path.some(point => point.uuid === uuid));
|
||||||
if (pathIndex === -1) return;
|
if (pathIndex === -1) return;
|
||||||
|
|
||||||
const clickedPoint = simulationPaths[pathIndex].find(point => point.uuid === uuid);
|
const clickedPoint = simulationStates[pathIndex].find(point => point.uuid === uuid);
|
||||||
if (!clickedPoint) return;
|
if (!clickedPoint) return;
|
||||||
|
|
||||||
const isStart = simulationPaths[pathIndex][0].uuid === uuid;
|
const isStart = simulationStates[pathIndex][0].uuid === uuid;
|
||||||
const isEnd = simulationPaths[pathIndex][simulationPaths[pathIndex].length - 1].uuid === uuid;
|
const isEnd = simulationStates[pathIndex][simulationStates[pathIndex].length - 1].uuid === uuid;
|
||||||
|
|
||||||
if (pathIndex === 0 && isStart) {
|
if (pathIndex === 0 && isStart) {
|
||||||
console.log("The first-ever point is not connectable.");
|
console.log("The first-ever point is not connectable.");
|
||||||
|
@ -285,8 +285,8 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<group name='pathObjects'>
|
<group name='pathObjects'>
|
||||||
{/* Render finalized simulationPaths */}
|
{/* Render finalized simulationStates */}
|
||||||
{simulationPaths.map((path, pathIndex) => (
|
{simulationStates.map((path, pathIndex) => (
|
||||||
<group key={`path-line-${pathIndex}`}>
|
<group key={`path-line-${pathIndex}`}>
|
||||||
<Line
|
<Line
|
||||||
name={`path-line-${pathIndex}`}
|
name={`path-line-${pathIndex}`}
|
||||||
|
@ -299,7 +299,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Render finalized points */}
|
{/* Render finalized points */}
|
||||||
{simulationPaths.map((path) =>
|
{simulationStates.map((path) =>
|
||||||
path.map((point) => (
|
path.map((point) => (
|
||||||
<mesh
|
<mesh
|
||||||
key={`path-point-${point.uuid}`}
|
key={`path-point-${point.uuid}`}
|
||||||
|
|
|
@ -10,13 +10,13 @@ type PathPoint = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function Simulation() {
|
function Simulation() {
|
||||||
const [simulationPaths, setSimulationPaths] = useState<{ position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string }[][]>([]);
|
const [simulationStates, setSimulationStates] = useState<{ position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string }[][]>([]);
|
||||||
const [connections, setConnections] = useState<{ start: PathPoint; end: PathPoint }[]>([]);
|
const [connections, setConnections] = useState<{ start: PathPoint; end: PathPoint }[]>([]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PathCreator simulationPaths={simulationPaths} setSimulationPaths={setSimulationPaths} connections={connections} setConnections={setConnections} />
|
<PathCreator simulationStates={simulationStates} setSimulationStates={setSimulationStates} connections={connections} setConnections={setConnections} />
|
||||||
{simulationPaths.map((path, index) => (
|
{simulationStates.map((path, index) => (
|
||||||
<PathFlow key={index} path={path} connections={connections} />
|
<PathFlow key={index} path={path} connections={connections} />
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -5,6 +5,14 @@ import { useDroppedObjectsStore } from "../../store/useDroppedObjectsStore";
|
||||||
import { useZoneWidgetStore } from "../../store/useZone3DWidgetStore";
|
import { useZoneWidgetStore } from "../../store/useZone3DWidgetStore";
|
||||||
import useTemplateStore from "../../store/useTemplateStore";
|
import useTemplateStore from "../../store/useTemplateStore";
|
||||||
|
|
||||||
|
type WidgetData = {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation?: [number, number, number];
|
||||||
|
tempPosition?: [number, number, number];
|
||||||
|
};
|
||||||
|
|
||||||
export default function SocketRealTimeViz() {
|
export default function SocketRealTimeViz() {
|
||||||
const { visualizationSocket } = useSocketStore();
|
const { visualizationSocket } = useSocketStore();
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
|
@ -14,6 +22,7 @@ export default function SocketRealTimeViz() {
|
||||||
const { addWidget } = useZoneWidgetStore()
|
const { addWidget } = useZoneWidgetStore()
|
||||||
const { templates, removeTemplate } = useTemplateStore();
|
const { templates, removeTemplate } = useTemplateStore();
|
||||||
const { setTemplates } = useTemplateStore();
|
const { setTemplates } = useTemplateStore();
|
||||||
|
const { zoneWidgetData, setZoneWidgetData, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
|
@ -132,14 +141,36 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//add 3D Widget response
|
//add 3D Widget response
|
||||||
visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => {
|
visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => {
|
||||||
console.log('add3DWidget: ', add3DWidget);
|
|
||||||
|
|
||||||
|
console.log('add3DWidget: ', add3DWidget);
|
||||||
if (add3DWidget.success) {
|
if (add3DWidget.success) {
|
||||||
|
console.log('add3DWidget: ', add3DWidget);
|
||||||
if (add3DWidget.message === "Widget created successfully") {
|
if (add3DWidget.message === "Widget created successfully") {
|
||||||
addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget);
|
addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
//delete 3D Widget response
|
||||||
|
visualizationSocket.on("viz-widget3D:response:delete", (delete3DWidget: any) => {
|
||||||
|
console.log('delete3DWidget: ', delete3DWidget);
|
||||||
|
// "3DWidget delete unsuccessfull"
|
||||||
|
if (delete3DWidget.success && delete3DWidget.message === "3DWidget delete successfull") {
|
||||||
|
const activeZoneWidgets = zoneWidgetData[delete3DWidget.data.zoneId] || [];
|
||||||
|
setZoneWidgetData(
|
||||||
|
delete3DWidget.data.zoneId,
|
||||||
|
activeZoneWidgets.filter((w: WidgetData) => w.id !== delete3DWidget.data.id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//update3D widget response
|
||||||
|
visualizationSocket.on("viz-widget3D:response:modifyPositionRotation", (update3DWidget: any) => {
|
||||||
|
console.log('update3DWidget: ', update3DWidget);
|
||||||
|
|
||||||
|
if (update3DWidget.success && update3DWidget.message==="widget update successfully") {
|
||||||
|
updateWidgetPosition(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.position);
|
||||||
|
updateWidgetRotation(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.rotation);
|
||||||
|
}
|
||||||
|
});
|
||||||
// add Template response
|
// add Template response
|
||||||
visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => {
|
visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => {
|
||||||
console.log('addingTemplate: ', addingTemplate);
|
console.log('addingTemplate: ', addingTemplate);
|
||||||
|
|
|
@ -56,7 +56,7 @@ const Project: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="project-main">
|
<div className="project-main">
|
||||||
{loadingProgress && <LoadingPage progress={loadingProgress} />}
|
{/* {loadingProgress && <LoadingPage progress={loadingProgress} />} */}
|
||||||
{!isPlaying && (
|
{!isPlaying && (
|
||||||
<>
|
<>
|
||||||
{toggleThreeD && <ModuleToggle />}
|
{toggleThreeD && <ModuleToggle />}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_ASSET_LIBRARY_URL}`;
|
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
export const getCategoryAsset = async (categoryName: any) => {
|
export const getCategoryAsset = async (categoryName: any) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${BackEnd_url}/api/v2/getCatagoryAssets/${categoryName}`,
|
`${BackEnd_url}/api/v2/getCategoryAssets/${categoryName}`,
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const setEventApi = async (
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Failed to set or update Floor Item");
|
throw new Error("Failed to set or Update Event Data");
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
|
@ -26,7 +26,7 @@ export const findEnvironment = async (organization: string, userId: string) => {
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
0,
|
40,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
return userpos;
|
return userpos;
|
||||||
|
|
|
@ -5,9 +5,6 @@ export const adding3dWidgets = async (
|
||||||
organization: string,
|
organization: string,
|
||||||
widget: {}
|
widget: {}
|
||||||
) => {
|
) => {
|
||||||
console.log('widget: ', widget);
|
|
||||||
console.log('organization: ', organization);
|
|
||||||
console.log('zoneId: ', zoneId);
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${url_Backend_dwinzo}/api/v2/3dwidget/save`,
|
`${url_Backend_dwinzo}/api/v2/3dwidget/save`,
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||||
|
|
||||||
|
export const delete3dWidgetApi = async (
|
||||||
|
zoneId: string,
|
||||||
|
organization: string,
|
||||||
|
id: string
|
||||||
|
) => {
|
||||||
|
console.log("zoneId: ", zoneId);
|
||||||
|
console.log("organization: ", organization);
|
||||||
|
console.log("id: ", id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${url_Backend_dwinzo}/api/v2/widget3D/delete`,
|
||||||
|
{
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ organization, zoneId, id }),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to delete floating widget in the zone");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,81 @@
|
||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||||
|
export const update3dWidget = async (
|
||||||
|
zoneId: string,
|
||||||
|
organization: string,
|
||||||
|
id: string,
|
||||||
|
position?: [number, number, number]
|
||||||
|
) => {
|
||||||
|
console.log("organization: ", organization);
|
||||||
|
console.log("zoneId: ", zoneId);
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`,
|
||||||
|
{
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
organization,
|
||||||
|
zoneId,
|
||||||
|
id,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to add 3dwidget in the zone");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const update3dWidgetRotation = async (
|
||||||
|
zoneId: string,
|
||||||
|
organization: string,
|
||||||
|
id: string,
|
||||||
|
rotation?: [number, number, number]
|
||||||
|
) => {
|
||||||
|
console.log("organization: ", organization);
|
||||||
|
console.log("zoneId: ", zoneId);
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`,
|
||||||
|
{
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
organization,
|
||||||
|
zoneId,
|
||||||
|
id,
|
||||||
|
rotation,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to add 3dwidget in the zone");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -14,7 +14,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
|
||||||
const socket = io(
|
const socket = io(
|
||||||
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`,
|
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`,
|
||||||
{
|
{
|
||||||
reconnection: false,
|
reconnection: true,
|
||||||
auth: { email, organization },
|
auth: { email, organization },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -22,7 +22,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
|
||||||
const visualizationSocket = io(
|
const visualizationSocket = io(
|
||||||
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
|
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
|
||||||
{
|
{
|
||||||
reconnection: false,
|
reconnection: true,
|
||||||
auth: { email, organization },
|
auth: { email, organization },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -302,7 +302,13 @@ export const useDrieTemp = create<any>((set: any) => ({
|
||||||
|
|
||||||
export const useActiveUsers = create<any>((set: any) => ({
|
export const useActiveUsers = create<any>((set: any) => ({
|
||||||
activeUsers: [],
|
activeUsers: [],
|
||||||
setActiveUsers: (x: any) => set({ activeUsers: x }),
|
setActiveUsers: (callback: (prev: any[]) => any[] | any[]) =>
|
||||||
|
set((state: { activeUsers: any[] }) => ({
|
||||||
|
activeUsers:
|
||||||
|
typeof callback === "function"
|
||||||
|
? callback(state.activeUsers)
|
||||||
|
: callback,
|
||||||
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useDrieUIValue = create<any>((set: any) => ({
|
export const useDrieUIValue = create<any>((set: any) => ({
|
||||||
|
@ -341,24 +347,29 @@ export const useSelectedPath = create<any>((set: any) => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface SimulationPathsStore {
|
interface SimulationPathsStore {
|
||||||
simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[];
|
simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[];
|
||||||
setSimulationPaths: (
|
setSimulationStates: (
|
||||||
paths:
|
paths:
|
||||||
| (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]
|
| (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]
|
||||||
| ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]
|
| ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]
|
||||||
) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[])
|
) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[])
|
||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
export const useSimulationStates = create<SimulationPathsStore>((set) => ({
|
||||||
simulationPaths: [],
|
simulationStates: [],
|
||||||
setSimulationPaths: (paths) =>
|
setSimulationStates: (paths) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
simulationPaths:
|
simulationStates:
|
||||||
typeof paths === "function" ? paths(state.simulationPaths) : paths,
|
typeof paths === "function" ? paths(state.simulationStates) : paths,
|
||||||
})),
|
})),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
export const useNavMesh = create<any>((set: any) => ({
|
||||||
|
navMesh: null,
|
||||||
|
setNavMesh: (x: any) => set({ navMesh: x }),
|
||||||
|
}));
|
||||||
|
|
||||||
export const useIsConnecting = create<any>((set: any) => ({
|
export const useIsConnecting = create<any>((set: any) => ({
|
||||||
isConnecting: false,
|
isConnecting: false,
|
||||||
setIsConnecting: (x: any) => set({ isConnecting: x }),
|
setIsConnecting: (x: any) => set({ isConnecting: x }),
|
||||||
|
|
|
@ -4,8 +4,32 @@ type PlayButtonStore = {
|
||||||
isPlaying: boolean; // Updated state name to reflect the play/pause status more clearly
|
isPlaying: boolean; // Updated state name to reflect the play/pause status more clearly
|
||||||
setIsPlaying: (value: boolean) => void; // Updated setter function name for clarity
|
setIsPlaying: (value: boolean) => void; // Updated setter function name for clarity
|
||||||
};
|
};
|
||||||
|
type PauseButtonStore = {
|
||||||
|
isPaused: boolean; // Updated state name to reflect the play/pause status more clearly
|
||||||
|
setIsPaused: (value: boolean) => void; // Updated setter function name for clarity
|
||||||
|
};
|
||||||
|
type ResetButtonStore = {
|
||||||
|
isReset: boolean; // Updated state name to reflect the play/pause status more clearly
|
||||||
|
setReset: (value: boolean) => void; // Updated setter function name for clarity
|
||||||
|
};
|
||||||
|
interface AnimationSpeedState {
|
||||||
|
speed: number;
|
||||||
|
setSpeed: (value: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
export const usePlayButtonStore = create<PlayButtonStore>((set) => ({
|
export const usePlayButtonStore = create<PlayButtonStore>((set) => ({
|
||||||
isPlaying: false, // Default state for play/pause
|
isPlaying: false, // Default state for play/pause
|
||||||
setIsPlaying: (value) => set({ isPlaying: value }), // Update isPlaying state
|
setIsPlaying: (value) => set({ isPlaying: value }), // Update isPlaying state
|
||||||
}));
|
}));
|
||||||
|
export const useResetButtonStore = create<ResetButtonStore>((set) => ({
|
||||||
|
isReset: false, // Default state for play/pause
|
||||||
|
setReset: (value) => set({ isReset: value }), // Update isPlaying state
|
||||||
|
}));
|
||||||
|
export const usePauseButtonStore = create<PauseButtonStore>((set) => ({
|
||||||
|
isPaused: false, // Default state for play/pause
|
||||||
|
setIsPaused: (value) => set({ isPaused: value }), // Update isPlaying state
|
||||||
|
}));
|
||||||
|
export const useAnimationPlaySpeed = create<AnimationSpeedState>((set) => ({
|
||||||
|
speed: 1,
|
||||||
|
setSpeed: (value) => set({ speed: value }),
|
||||||
|
}));
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
|
||||||
type WidgetData = {
|
type WidgetData = {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
|
rotation?: [number, number, number];
|
||||||
tempPosition?: [number, number, number];
|
tempPosition?: [number, number, number];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,38 +13,59 @@ type ZoneWidgetStore = {
|
||||||
setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) => void;
|
setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) => void;
|
||||||
addWidget: (zoneId: string, widget: WidgetData) => void;
|
addWidget: (zoneId: string, widget: WidgetData) => void;
|
||||||
updateWidgetPosition: (zoneId: string, widgetId: string, newPosition: [number, number, number]) => void;
|
updateWidgetPosition: (zoneId: string, widgetId: string, newPosition: [number, number, number]) => void;
|
||||||
|
updateWidgetRotation: (zoneId: string, widgetId: string, newRotation: [number, number, number]) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useZoneWidgetStore = create<ZoneWidgetStore>((set) => ({
|
export const useZoneWidgetStore = create<ZoneWidgetStore>((set) => ({
|
||||||
zoneWidgetData: {},
|
zoneWidgetData: {},
|
||||||
|
|
||||||
setZoneWidgetData: (zoneId, widgets) =>
|
setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) =>
|
||||||
set((state) => ({
|
set((state: ZoneWidgetStore) => ({
|
||||||
zoneWidgetData: { ...state.zoneWidgetData, [zoneId]: widgets },
|
zoneWidgetData: { ...state.zoneWidgetData, [zoneId]: widgets },
|
||||||
})),
|
})),
|
||||||
|
|
||||||
addWidget: (zoneId, widget) =>
|
addWidget: (zoneId: string, widget: WidgetData) =>
|
||||||
set((state) => ({
|
set((state: ZoneWidgetStore) => ({
|
||||||
zoneWidgetData: {
|
zoneWidgetData: {
|
||||||
...state.zoneWidgetData,
|
...state.zoneWidgetData,
|
||||||
[zoneId]: [...(state.zoneWidgetData[zoneId] || []), widget],
|
[zoneId]: [...(state.zoneWidgetData[zoneId] || []), { ...widget, rotation: widget.rotation || [0, 0, 0] }],
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
|
|
||||||
updateWidgetPosition: (zoneId, widgetId, newPosition) =>
|
updateWidgetPosition: (zoneId: string, widgetId: string, newPosition: [number, number, number]) =>
|
||||||
set((state) => {
|
set((state: ZoneWidgetStore) => {
|
||||||
const widgets = state.zoneWidgetData[zoneId] || [];
|
const widgets = state.zoneWidgetData[zoneId] || [];
|
||||||
return {
|
return {
|
||||||
zoneWidgetData: {
|
zoneWidgetData: {
|
||||||
...state.zoneWidgetData,
|
...state.zoneWidgetData,
|
||||||
[zoneId]: widgets.map((widget) =>
|
[zoneId]: widgets.map((widget: WidgetData) =>
|
||||||
widget.id === widgetId ? { ...widget, position: newPosition } : widget
|
widget.id === widgetId ? { ...widget, position: newPosition } : widget
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
updateWidgetRotation: (zoneId: string, widgetId: string, newRotation: [number, number, number]) =>
|
||||||
|
set((state: ZoneWidgetStore) => {
|
||||||
|
const widgets = state.zoneWidgetData[zoneId] || [];
|
||||||
|
return {
|
||||||
|
zoneWidgetData: {
|
||||||
|
...state.zoneWidgetData,
|
||||||
|
[zoneId]: widgets.map((widget: WidgetData) =>
|
||||||
|
widget.id === widgetId ? { ...widget, rotation: newRotation } : widget
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// export type WidgetData = {
|
||||||
|
// id: string;
|
||||||
|
// type: string;
|
||||||
|
// position: [number, number, number];
|
||||||
|
// rotation?: [number, number, number];
|
||||||
|
// tempPosition?: [number, number, number];
|
||||||
|
// };
|
||||||
|
|
||||||
interface RightClickStore {
|
interface RightClickStore {
|
||||||
rightClickSelected: string | null;
|
rightClickSelected: string | null;
|
||||||
|
@ -75,3 +96,13 @@ export const useRightSelected = create<RightSelectStore>((set) => ({
|
||||||
rightSelect: null, // Default state is null
|
rightSelect: null, // Default state is null
|
||||||
setRightSelect: (x) => set({ rightSelect: x }),
|
setRightSelect: (x) => set({ rightSelect: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
interface EditWidgetOptionsStore {
|
||||||
|
editWidgetOptions: boolean;
|
||||||
|
setEditWidgetOptions: (value: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useEditWidgetOptionsStore = create<EditWidgetOptionsStore>((set) => ({
|
||||||
|
editWidgetOptions: false, // Initial state
|
||||||
|
setEditWidgetOptions: (value: boolean) => set({ editWidgetOptions: value }),
|
||||||
|
}));
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
.tools-container {
|
.tools-container {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 50px;
|
bottom: 32px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
|
|
@ -472,6 +472,15 @@
|
||||||
font-size: var(--font-weight-regular);
|
font-size: var(--font-weight-regular);
|
||||||
color: #4a4a4a;
|
color: #4a4a4a;
|
||||||
|
|
||||||
|
.reviewChart {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.floating {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.selectedWidget {
|
.selectedWidget {
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid var(--border-color);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
box-shadow: $box-shadow-medium;
|
box-shadow: $box-shadow-medium;
|
||||||
width: calc(100% - (320px + 270px + 90px));
|
width: calc(100% - (320px + 270px + 90px));
|
||||||
height: calc(100% - (200px + 80px));
|
height: calc(100% - (250px));
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: calc(270px + 45px);
|
left: calc(270px + 45px);
|
||||||
|
@ -16,6 +16,13 @@
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
z-index: #{$z-index-default};
|
z-index: #{$z-index-default};
|
||||||
|
|
||||||
|
.realTime-viz-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
.floating {
|
.floating {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
|
@ -109,7 +116,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.zone-wrapper.bottom {
|
.zone-wrapper.bottom {
|
||||||
bottom: 210px;
|
bottom: calc(var(--realTimeViz-container-height) * 0.27);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-container {
|
.content-container {
|
||||||
|
@ -182,6 +189,7 @@
|
||||||
.panel-content {
|
.panel-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -194,7 +202,6 @@
|
||||||
|
|
||||||
.chart-container {
|
.chart-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 25% !important;
|
|
||||||
min-height: 150px;
|
min-height: 150px;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
// border: 1px dashed var(--background-color-gray);
|
// border: 1px dashed var(--background-color-gray);
|
||||||
|
@ -203,6 +210,7 @@
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
.kebab {
|
.kebab {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
|
@ -287,15 +295,17 @@
|
||||||
&.bottom-panel {
|
&.bottom-panel {
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
min-height: 150px;
|
||||||
|
|
||||||
.panel-content {
|
.panel-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 150px;
|
||||||
|
|
||||||
.chart-container {
|
.chart-container {
|
||||||
height: 100% !important;
|
|
||||||
width: 20%;
|
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,17 +324,42 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
||||||
.chart-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 180px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.right-panel {
|
&.right-panel {
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
&.left-panel,
|
||||||
|
&.right-panel {
|
||||||
|
min-width: 150px;
|
||||||
|
|
||||||
|
.panel-content {
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
|
||||||
|
min-height: 150px;
|
||||||
|
max-height: 100%;
|
||||||
|
// border: 1px dashed var(--background-color-gray);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: var(--box-shadow-medium);
|
||||||
|
padding: 6px 0;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +370,7 @@
|
||||||
|
|
||||||
.playingFlase {
|
.playingFlase {
|
||||||
.zone-wrapper.bottom {
|
.zone-wrapper.bottom {
|
||||||
bottom: 300px;
|
bottom: calc(var(--realTimeViz-container-height) * 0.25);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,9 +767,9 @@
|
||||||
|
|
||||||
.editWidgetOptions {
|
.editWidgetOptions {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
// top: 50%;
|
||||||
left: 50%;
|
// left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
// transform: translate(-50%, -50%);
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -742,6 +777,8 @@
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
min-width: 150px;
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
|
|
|
@ -201,27 +201,6 @@ export type FloorItemType = {
|
||||||
modelfileID: string;
|
modelfileID: string;
|
||||||
isLocked: boolean;
|
isLocked: boolean;
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
eventData?: {
|
|
||||||
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; bufferTime: number }[] | [];
|
|
||||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
|
||||||
}[];
|
|
||||||
speed: number | string;
|
|
||||||
} | {
|
|
||||||
type: 'Vehicle';
|
|
||||||
point: {
|
|
||||||
uuid: string;
|
|
||||||
position: [number, number, number];
|
|
||||||
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
|
||||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
|
||||||
speed: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Array of floor items for managing multiple objects on the floor
|
// Array of floor items for managing multiple objects on the floor
|
||||||
|
@ -292,10 +271,10 @@ export type RefCSM = React.MutableRefObject<CSM>;
|
||||||
export type RefCSMHelper = React.MutableRefObject<CSMHelper>;
|
export type RefCSMHelper = React.MutableRefObject<CSMHelper>;
|
||||||
|
|
||||||
interface PathConnection {
|
interface PathConnection {
|
||||||
fromPathUUID: string;
|
fromModelUUID: string;
|
||||||
fromUUID: string;
|
fromUUID: string;
|
||||||
toConnections: {
|
toConnections: {
|
||||||
toPathUUID: string;
|
toModelUUID: string;
|
||||||
toUUID: string;
|
toUUID: string;
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
@ -317,7 +296,7 @@ interface ConveyorEventsSchema {
|
||||||
rotation: [number, number, number];
|
rotation: [number, number, number];
|
||||||
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
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; bufferTime: number }[] | [];
|
triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
|
||||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||||
}[];
|
}[];
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
rotation: [number, number, number];
|
rotation: [number, number, number];
|
||||||
|
@ -328,12 +307,71 @@ interface VehicleEventsSchema {
|
||||||
modeluuid: string;
|
modeluuid: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
type: 'Vehicle';
|
type: 'Vehicle';
|
||||||
point: {
|
points: {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
||||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||||
speed: number;
|
speed: number;
|
||||||
};
|
};
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StaticMachineEventsSchema {
|
||||||
|
modeluuid: string;
|
||||||
|
modelName: string;
|
||||||
|
type: 'StaticMachine';
|
||||||
|
points: {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
actions: { uuid: string; name: string; buffer: number | string; material: string; isUsed: boolean };
|
||||||
|
triggers: { uuid: string; name: string; type: string };
|
||||||
|
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||||
|
};
|
||||||
|
position: [number, number, number];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArmBotEventsSchema {
|
||||||
|
modeluuid: string;
|
||||||
|
modelName: string;
|
||||||
|
type: 'ArmBot';
|
||||||
|
points: {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] };
|
||||||
|
triggers: { uuid: string; name: string; type: string };
|
||||||
|
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||||
|
};
|
||||||
|
position: [number, number, number];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EventData = {
|
||||||
|
modeluuid: string;
|
||||||
|
modelname: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: { x: number; y: number; z: number };
|
||||||
|
modelfileID: string;
|
||||||
|
isLocked: boolean;
|
||||||
|
isVisible: boolean;
|
||||||
|
eventData?: {
|
||||||
|
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; bufferTime: number }[] | [];
|
||||||
|
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||||
|
}[];
|
||||||
|
speed: number | string;
|
||||||
|
} | {
|
||||||
|
type: 'Vehicle';
|
||||||
|
points: {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
||||||
|
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||||
|
speed: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue