Refactor path connections structure and remove unused connection logic

This commit is contained in:
2025-03-27 14:34:36 +05:30
parent 2dfd34f27b
commit a7ec4720a4
5 changed files with 146 additions and 147 deletions

View File

@@ -12,7 +12,7 @@ interface Path {
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 }[] | []; triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] } | []; connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[]; }[];
pathPosition: [number, number, number]; pathPosition: [number, number, number];
pathRotation: [number, number, number]; pathRotation: [number, number, number];
@@ -45,7 +45,7 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
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: false }], actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
triggers: [], triggers: [],
connections: [], connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
}, },
{ {
uuid: middlePointUUID, uuid: middlePointUUID,
@@ -53,7 +53,7 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
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: false }], actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
triggers: [], triggers: [],
connections: [], connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
}, },
{ {
uuid: point2UUID, uuid: point2UUID,
@@ -61,7 +61,7 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
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: false }], actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
triggers: [], triggers: [],
connections: [], connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
}, },
], ],
pathPosition: [...item.position], pathPosition: [...item.position],

View File

@@ -2,21 +2,100 @@ import { useFrame, useThree } from '@react-three/fiber';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import * as THREE from 'three'; import * as THREE from 'three';
import { QuadraticBezierLine } from '@react-three/drei'; import { QuadraticBezierLine } from '@react-three/drei';
import { useConnections, useIsConnecting, useSimulationPaths } from '../../../store/store'; import { useIsConnecting, useSimulationPaths } from '../../../store/store';
import useModuleStore from '../../../store/useModuleStore'; import useModuleStore from '../../../store/useModuleStore';
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 { connections, setConnections, addConnection } = useConnections(); const { setIsConnecting } = useIsConnecting();
const { isConnecting, setIsConnecting } = useIsConnecting();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const [firstSelected, setFirstSelected] = useState<{ pathUUID: string; sphereUUID: string; position: THREE.Vector3; isCorner: boolean; } | null>(null); const [firstSelected, setFirstSelected] = useState<{
pathUUID: string;
sphereUUID: string;
position: THREE.Vector3;
isCorner: boolean;
} | null>(null);
const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3, end: THREE.Vector3, mid: THREE.Vector3 } | null>(null); const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3, end: THREE.Vector3, mid: THREE.Vector3 } | null>(null);
const [hoveredSphere, setHoveredSphere] = useState<{ sphereUUID: string, position: THREE.Vector3 } | null>(null);
const [helperlineColor, setHelperLineColor] = useState<string>('red'); const [helperlineColor, setHelperLineColor] = useState<string>('red');
const updatePathConnections = (
fromPathUUID: string,
fromPointUUID: string,
toPathUUID: string,
toPointUUID: string
) => {
const updatedPaths = simulationPaths.map(path => {
if (path.modeluuid === fromPathUUID) {
return {
...path,
points: path.points.map(point => {
if (point.uuid === fromPointUUID) {
const newTarget = {
pathUUID: toPathUUID,
pointUUID: toPointUUID
};
const existingTargets = point.connections.targets || [];
if (!existingTargets.some(target =>
target.pathUUID === newTarget.pathUUID &&
target.pointUUID === newTarget.pointUUID
)) {
return {
...point,
connections: {
...point.connections,
targets: [...existingTargets, newTarget]
}
};
}
}
return point;
})
};
}
else if (path.modeluuid === toPathUUID) {
return {
...path,
points: path.points.map(point => {
if (point.uuid === toPointUUID) {
const reverseTarget = {
pathUUID: fromPathUUID,
pointUUID: fromPointUUID
};
const existingTargets = point.connections.targets || [];
if (!existingTargets.some(target =>
target.pathUUID === reverseTarget.pathUUID &&
target.pointUUID === reverseTarget.pointUUID
)) {
return {
...point,
connections: {
...point.connections,
targets: [...existingTargets, reverseTarget]
}
};
}
}
return point;
})
};
}
return path;
});
setSimulationPaths(updatedPaths);
};
const handleAddConnection = (fromPathUUID: string, fromUUID: string, toPathUUID: string, toUUID: string) => {
updatePathConnections(fromPathUUID, fromUUID, toPathUUID, toUUID);
setFirstSelected(null);
setCurrentLine(null);
setIsConnecting(false);
};
useEffect(() => { useEffect(() => {
const canvasElement = gl.domElement; const canvasElement = gl.domElement;
let drag = false; let drag = false;
@@ -59,9 +138,12 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
); );
if (pathUUID) { if (pathUUID) {
const isAlreadyConnected = connections.some((connection) => // Check if sphere is already connected
connection.fromUUID === sphereUUID || const isAlreadyConnected = simulationPaths.some(path =>
connection.toConnections.some(conn => conn.toUUID === sphereUUID) path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
)
); );
if (isAlreadyConnected) { if (isAlreadyConnected) {
@@ -89,16 +171,12 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
return; return;
} }
addConnection({ handleAddConnection(
fromPathUUID: firstSelected.pathUUID, firstSelected.pathUUID,
fromUUID: firstSelected.sphereUUID, firstSelected.sphereUUID,
toConnections: [{ toPathUUID: pathUUID, toUUID: sphereUUID }] pathUUID,
}); sphereUUID
);
setFirstSelected(null);
setCurrentLine(null);
setIsConnecting(false);
setHoveredSphere(null);
} }
} }
} }
@@ -106,7 +184,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
setFirstSelected(null); setFirstSelected(null);
setCurrentLine(null); setCurrentLine(null);
setIsConnecting(false); setIsConnecting(false);
setHoveredSphere(null);
} }
}; };
@@ -119,7 +196,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
setFirstSelected(null); setFirstSelected(null);
setCurrentLine(null); setCurrentLine(null);
setIsConnecting(false); setIsConnecting(false);
setHoveredSphere(null);
} }
return () => { return () => {
@@ -128,7 +204,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, connections]); }, [camera, scene, raycaster, firstSelected, simulationPaths]);
useFrame(() => { useFrame(() => {
if (firstSelected) { if (firstSelected) {
@@ -168,9 +244,11 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
sphereUUID === sphere.userData.path.points[sphere.userData.path.points.length - 1].uuid sphereUUID === sphere.userData.path.points[sphere.userData.path.points.length - 1].uuid
); );
const isAlreadyConnected = connections.some((connection) => const isAlreadyConnected = simulationPaths.some(path =>
connection.fromUUID === sphereUUID || path.points.some(point =>
connection.toConnections.some(conn => conn.toUUID === sphereUUID) point.uuid === sphereUUID &&
point.connections.targets.length > 0
)
); );
if ( if (
@@ -186,10 +264,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
if (snappedSphere) { if (snappedSphere) {
setHoveredSphere(snappedSphere);
point = snappedSphere.position; point = snappedSphere.position;
} else {
setHoveredSphere(null);
} }
if (point) { if (point) {
@@ -224,50 +299,48 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
}); });
// Render connections from simulationPaths
useEffect(() => {
console.log('connections: ', connections);
}, [connections]);
return ( return (
<> <>
{connections.map((connection, index) => { {simulationPaths.flatMap(path =>
if (!pathsGroupRef.current) return; path.points.flatMap(point =>
const fromSphere = pathsGroupRef.current.getObjectByProperty('uuid', connection.fromUUID); point.connections.targets.map((target, index) => {
const toSphere = pathsGroupRef.current.getObjectByProperty('uuid', connection.toConnections[0].toUUID); const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
if (fromSphere && toSphere) { if (fromSphere && toSphere) {
const fromWorldPosition = new THREE.Vector3(); const fromWorldPosition = new THREE.Vector3();
const toWorldPosition = new THREE.Vector3(); const toWorldPosition = new THREE.Vector3();
fromSphere.getWorldPosition(fromWorldPosition); fromSphere.getWorldPosition(fromWorldPosition);
toSphere.getWorldPosition(toWorldPosition); toSphere.getWorldPosition(toWorldPosition);
const distance = fromWorldPosition.distanceTo(toWorldPosition); const distance = fromWorldPosition.distanceTo(toWorldPosition);
const heightFactor = Math.max(0.5, distance * 0.2); const heightFactor = Math.max(0.5, distance * 0.2);
const midPoint = new THREE.Vector3( const midPoint = new THREE.Vector3(
(fromWorldPosition.x + toWorldPosition.x) / 2, (fromWorldPosition.x + toWorldPosition.x) / 2,
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor, Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
(fromWorldPosition.z + toWorldPosition.z) / 2 (fromWorldPosition.z + toWorldPosition.z) / 2
); );
return ( return (
<QuadraticBezierLine <QuadraticBezierLine
key={index} key={`${point.uuid}-${target.pointUUID}-${index}`}
start={fromWorldPosition.toArray()} start={fromWorldPosition.toArray()}
end={toWorldPosition.toArray()} end={toWorldPosition.toArray()}
mid={midPoint.toArray()} mid={midPoint.toArray()}
color="white" color="white"
lineWidth={4} lineWidth={4}
dashed dashed
dashSize={1} dashSize={1}
dashScale={20} dashScale={20}
userData={connection} />
/> );
); }
} return null;
return null; })
})} )
)}
{currentLine && ( {currentLine && (
<QuadraticBezierLine <QuadraticBezierLine

View File

@@ -14,7 +14,7 @@ interface Path {
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 }[] | []; triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] } | []; connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[]; }[];
pathPosition: [number, number, number]; pathPosition: [number, number, number];
pathRotation: [number, number, number]; pathRotation: [number, number, number];

View File

@@ -1,5 +1,5 @@
import { useState, useEffect, useRef } from 'react'; import { useState, useEffect, useRef } from 'react';
import { useConnections, useFloorItems, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store'; import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store';
import { useThree } from '@react-three/fiber'; import { useThree } from '@react-three/fiber';
import * as THREE from 'three'; import * as THREE from 'three';
import Behaviour from './behaviour/behaviour'; import Behaviour from './behaviour/behaviour';
@@ -11,7 +11,6 @@ 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 { simulationPaths, setSimulationPaths } = useSimulationPaths();
const { connections, setConnections, addConnection, removeConnection } = useConnections();
const [processes, setProcesses] = useState([]); const [processes, setProcesses] = useState([]);
useEffect(() => { useEffect(() => {

View File

@@ -307,7 +307,7 @@ interface Path {
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 }[] | []; triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] } | []; connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[]; }[];
pathPosition: [number, number, number]; pathPosition: [number, number, number];
pathRotation: [number, number, number]; pathRotation: [number, number, number];
@@ -321,80 +321,7 @@ interface SimulationPathsStore {
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({ export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
simulationPaths: [], simulationPaths: [],
setSimulationPaths: (paths) => set({ simulationPaths: paths }), setSimulationPaths: (paths: Path[]) => set({ simulationPaths: paths }),
}));
// interface Point {
// uuid: string;
// position: [number, number, number];
// rotation: [number, number, number];
// event: {
// uuid: string;
// type: string;
// material: string;
// delay: number | string;
// spawnInterval: number | string;
// isUsed: boolean;
// };
// trigger: {
// uuid: string;
// type: string;
// isUsed: boolean;
// };
// }
// interface Process {
// processId: string;
// processName: string;
// points: Point[];
// pathPosition: [number, number, number];
// pathRotation: [number, number, number];
// speed: number;
// isUsed: boolean;
// }
// interface Path {
// modeluuid: string;
// processes: Process[];
// }
// interface SimulationPathsStore {
// simulationPaths: Path[];
// setSimulationPaths: (paths: Path[]) => void;
// }
// export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
// simulationPaths: [],
// setSimulationPaths: (paths) => set({ simulationPaths: paths }),
// }));
export const useConnections = create<Types.ConnectionStore>((set) => ({
connections: [],
setConnections: (connections) => set({ connections }),
addConnection: (newConnection) =>
set((state) => ({
connections: [...state.connections, newConnection],
})),
removeConnection: (fromUUID, toUUID) =>
set((state) => ({
connections: state.connections
.map((connection) =>
connection.fromUUID === fromUUID
? {
...connection,
toConnections: connection.toConnections.filter(
(to) => to.toUUID !== toUUID
),
}
: connection
)
.filter((connection) => connection.toConnections.length > 0),
})),
})); }));
export const useIsConnecting = create<any>((set: any) => ({ export const useIsConnecting = create<any>((set: any) => ({