From 5564eecf76660f0e34202e4659448111e96c6886 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B <jerald@hexrfactory.com> Date: Sat, 29 Mar 2025 18:14:29 +0530 Subject: [PATCH] refactor: update VehicleMechanics to use LabledDropdown for start and end point selection; clean up unused MQTT code and improve zone data fetching logic --- .../mechanics/VehicleMechanics.tsx | 47 ++-- .../ui/componets/RealTimeVisulization.tsx | 4 +- app/src/components/ui/inputs/EyeDropInput.tsx | 8 +- app/src/modules/builder/agv/agv.tsx | 16 +- .../builder/geomentries/roofs/hideRoof.ts | 3 +- .../modules/simulation/path/pathConnector.tsx | 261 ++++++++++++++---- .../factoryBuilder/mqtt/mqttEvents.ts | 48 ++-- .../zoneData/getSelect2dZoneData.ts | 1 - 8 files changed, 279 insertions(+), 109 deletions(-) diff --git a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx index a81ce15..c611a13 100644 --- a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx @@ -1,9 +1,9 @@ import React, { useRef, useMemo } from "react"; import { InfoIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import EyeDropInput from "../../../ui/inputs/EyeDropInput"; import { useSelectedActionSphere, useSimulationPaths } from "../../../../store/store"; import * as Types from '../../../../types/world/worldTypes'; +import LabledDropdown from "../../../ui/inputs/LabledDropdown"; const VehicleMechanics: React.FC = () => { const { selectedActionSphere } = useSelectedActionSphere(); @@ -11,17 +11,31 @@ const VehicleMechanics: React.FC = () => { const propertiesContainerRef = useRef<HTMLDivElement>(null); - const selectedPoint = useMemo(() => { - if (!selectedActionSphere?.point?.uuid) return null; + const { selectedPoint, connectedPointUuids } = useMemo(() => { + if (!selectedActionSphere?.point?.uuid) return { selectedPoint: null, connectedPointUuids: [] }; const vehiclePaths = simulationPaths.filter( (path): path is Types.VehicleEventsSchema => path.type === "Vehicle" ); - return vehiclePaths.find( + const point = vehiclePaths.find( (path) => path.point.uuid === selectedActionSphere.point.uuid )?.point; - }, [selectedActionSphere, simulationPaths, selectedActionSphere?.point?.uuid]); + + if (!point) return { selectedPoint: null, connectedPointUuids: [] }; + + const connectedUuids: string[] = []; + if (point.connections?.targets) { + point.connections.targets.forEach(target => { + connectedUuids.push(target.pointUUID); + }); + } + + return { + selectedPoint: point, + connectedPointUuids: connectedUuids + }; + }, [selectedActionSphere, simulationPaths]); const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['point']['actions']>) => { if (!selectedActionSphere?.point?.uuid) return; @@ -45,12 +59,12 @@ const VehicleMechanics: React.FC = () => { setSimulationPaths(updatedPaths); }, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]); - const handleStartPointChange = React.useCallback((position: string) => { - handleActionUpdate({ start: position }); + const handleStartPointChange = React.useCallback((uuid: string) => { + handleActionUpdate({ start: uuid }); }, [handleActionUpdate]); - const handleEndPointChange = React.useCallback((position: string) => { - handleActionUpdate({ end: position }); + const handleEndPointChange = React.useCallback((uuid: string) => { + handleActionUpdate({ end: uuid }); }, [handleActionUpdate]); const handleHitCountChange = React.useCallback((hitCount: number) => { @@ -92,18 +106,20 @@ const VehicleMechanics: React.FC = () => { {selectedPoint && ( <> - <EyeDropInput + <LabledDropdown key={`start-${selectedPoint.uuid}`} label="Start Point" - value={selectedPoint.actions.start} - onChange={handleStartPointChange} + defaultOption={selectedPoint.actions.start || "Select start point"} + options={connectedPointUuids} + onSelect={handleStartPointChange} /> - <EyeDropInput + <LabledDropdown key={`end-${selectedPoint.uuid}`} label="End Point" - value={selectedPoint.actions.end} - onChange={handleEndPointChange} + defaultOption={selectedPoint.actions.end || "Select end point"} + options={connectedPointUuids} + onSelect={handleEndPointChange} /> <InputWithDropDown @@ -128,7 +144,6 @@ const VehicleMechanics: React.FC = () => { /> </> )} - </div> <div className="footer"> diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 27044b1..1948433 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -76,7 +76,7 @@ const RealTimeVisulization: React.FC = () => { } GetZoneData(); - }, []); // Removed `zones` from dependencies + }, [activeModule]); // Removed `zones` from dependencies useEffect(() => { @@ -97,7 +97,7 @@ const RealTimeVisulization: React.FC = () => { }; }); }, [selectedZone]); - + useEffect(() => { }, [floatingWidgets]) diff --git a/app/src/components/ui/inputs/EyeDropInput.tsx b/app/src/components/ui/inputs/EyeDropInput.tsx index d29613a..72c5ded 100644 --- a/app/src/components/ui/inputs/EyeDropInput.tsx +++ b/app/src/components/ui/inputs/EyeDropInput.tsx @@ -1,5 +1,6 @@ import React from "react"; import { EyeDroperIcon } from "../../icons/ExportCommonIcons"; +import RegularDropDown from "./RegularDropDown"; interface EyeDropInputProps { label: string; @@ -23,7 +24,12 @@ const EyeDropInput: React.FC<EyeDropInputProps> = ({ <div className="eye-dropper-input-container"> <div className="label">{label}</div> <div className="input-container"> - <input disabled type="text" /> + {/* <input disabled type="text" /> */} + <RegularDropDown + header="select object" + options={[]} + onSelect={() => { }} + /> <div className="eye-picker-button" onClick={handleEyeDropClick}> <EyeDroperIcon isActive={false} /> </div> diff --git a/app/src/modules/builder/agv/agv.tsx b/app/src/modules/builder/agv/agv.tsx index 749e39f..37c4f4e 100644 --- a/app/src/modules/builder/agv/agv.tsx +++ b/app/src/modules/builder/agv/agv.tsx @@ -1,24 +1,17 @@ import PolygonGenerator from "./polygonGenerator"; import { useThree } from "@react-three/fiber"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import * as THREE from "three"; import * as Types from "../../../types/world/worldTypes"; import PathNavigator from "./pathNavigator"; import NavMeshDetails from "./navMeshDetails"; -const Agv = ({ - lines, - plane, -}: { - lines: Types.RefLines; - plane: Types.RefMesh; -}) => { - let pathPoints = [ +const Agv = ({ lines, plane }: { lines: Types.RefLines; plane: Types.RefMesh; }) => { + const pathPoints = useMemo(() => [ [ { x: 8.477161935339709, y: 0, z: 17.41343083550102 }, { x: 9.175416491482693, y: 0, z: -12.361001232663693 }, ], - , // [ // { x: 13.508213355232144, y: 0, z: -15.456970649652018 }, // { x: -30.464866520869617, y: 0, z: 9.779806557688929 }, @@ -27,7 +20,8 @@ const Agv = ({ { x: 16.792040856420844, y: 0, z: 15.86281907549489 }, { x: -42.77173264503395, y: 0, z: -15.821322764400804 }, ], - ]; + ], []); + let groupRef = useRef() as Types.RefGroup; const [navMesh, setNavMesh] = useState(); diff --git a/app/src/modules/builder/geomentries/roofs/hideRoof.ts b/app/src/modules/builder/geomentries/roofs/hideRoof.ts index 8eb80f8..3dc48fe 100644 --- a/app/src/modules/builder/geomentries/roofs/hideRoof.ts +++ b/app/src/modules/builder/geomentries/roofs/hideRoof.ts @@ -22,7 +22,8 @@ function hideRoof( if (roofChild.material) { const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material]; materials.forEach(material => { - material.visible = v.dot(u) < 0.25; + // material.visible = v.dot(u) < 0.25; + material.visible = true; }); } } diff --git a/app/src/modules/simulation/path/pathConnector.tsx b/app/src/modules/simulation/path/pathConnector.tsx index 8df718c..0888966 100644 --- a/app/src/modules/simulation/path/pathConnector.tsx +++ b/app/src/modules/simulation/path/pathConnector.tsx @@ -86,6 +86,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }; } } + // In the updatePathConnections function, modify the Vehicle handling section: else if (path.type === 'Vehicle') { // Handle outgoing connections from Vehicle if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) { @@ -95,6 +96,27 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }; const existingTargets = path.point.connections.targets || []; + // Check if we're trying to add a connection to a Conveyor + const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID); + const isConnectingToConveyor = toPath?.type === 'Conveyor'; + + // Count existing connections + if (existingTargets.length >= 2) { + console.log("Vehicle can have maximum 2 connections"); + return path; + } + + // Check if we already have a Conveyor connection and trying to add another + const hasConveyorConnection = existingTargets.some(target => { + const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); + return targetPath?.type === 'Conveyor'; + }); + + if (hasConveyorConnection && isConnectingToConveyor) { + console.log("Vehicle can only have one connection to a Conveyor"); + return path; + } + if (!existingTargets.some(target => target.pathUUID === newTarget.pathUUID && target.pointUUID === newTarget.pointUUID @@ -119,6 +141,27 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }; const existingTargets = path.point.connections.targets || []; + // Check if we're receiving a connection from a Conveyor + const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID); + const isConnectingFromConveyor = fromPath?.type === 'Conveyor'; + + // Count existing connections + if (existingTargets.length >= 2) { + console.log("Vehicle can have maximum 2 connections"); + return path; + } + + // Check if we already have a Conveyor connection and trying to add another + const hasConveyorConnection = existingTargets.some(target => { + const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); + return targetPath?.type === 'Conveyor'; + }); + + if (hasConveyorConnection && isConnectingFromConveyor) { + console.log("Vehicle can only have one connection to a Conveyor"); + return path; + } + if (!existingTargets.some(target => target.pathUUID === reverseTarget.pathUUID && target.pointUUID === reverseTarget.pointUUID @@ -135,6 +178,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }; } } + return path; } return path; }); @@ -168,7 +212,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec drag = true; } }; - const onContextMenu = (evt: MouseEvent) => { evt.preventDefault(); if (drag || evt.button === 0) return; @@ -200,29 +243,126 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID); const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID); + // Prevent vehicle-to-vehicle connections if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') { console.log("Cannot connect two vehicle paths together"); return; } - const isAlreadyConnected = simulationPaths.some(path => { - if (path.type === 'Conveyor') { - return path.points.some(point => - point.uuid === sphereUUID && - point.connections.targets.length > 0 - ); - } else if (path.type === 'Vehicle') { - return path.point.uuid === sphereUUID && - path.point.connections.targets.length > 0; - } - return false; - }); - if (isAlreadyConnected) { - console.log("Sphere is already connected. Ignoring."); + // Prevent conveyor middle point to conveyor connections + if (firstPath && secondPath && + firstPath.type === 'Conveyor' && + secondPath.type === 'Conveyor' && + !firstSelected?.isCorner) { + console.log("Conveyor middle points can only connect to non-conveyor paths"); return; } - if (!firstSelected) { + // Check if this specific connection already exists + const isDuplicateConnection = firstSelected + ? simulationPaths.some(path => { + if (path.modeluuid === firstSelected.pathUUID) { + if (path.type === 'Conveyor') { + const point = path.points.find(p => p.uuid === firstSelected.sphereUUID); + return point?.connections.targets.some(t => + t.pathUUID === pathUUID && t.pointUUID === sphereUUID + ); + } else if (path.type === 'Vehicle') { + return path.point.connections.targets.some(t => + t.pathUUID === pathUUID && t.pointUUID === sphereUUID + ); + } + } + return false; + }) + : false; + + if (isDuplicateConnection) { + console.log("These points are already connected. Ignoring."); + return; + } + + // For Vehicles, skip the "already connected" check since they can have multiple connections + if (intersected.userData.path.type !== 'Vehicle') { + const isAlreadyConnected = simulationPaths.some(path => { + if (path.type === 'Conveyor') { + return path.points.some(point => + point.uuid === sphereUUID && + point.connections.targets.length > 0 + ); + } + return false; + }); + + if (isAlreadyConnected) { + console.log("Conveyor point is already connected. Ignoring."); + return; + } + } + + // Check vehicle connection limits + const checkVehicleConnections = (pathUUID: string) => { + const path = simulationPaths.find(p => p.modeluuid === pathUUID); + if (path?.type === 'Vehicle') { + return path.point.connections.targets.length >= 2; + } + return false; + }; + + if (firstSelected) { + // Check if either selected point is from a Vehicle with max connections + if (checkVehicleConnections(firstSelected.pathUUID) || + checkVehicleConnections(pathUUID)) { + console.log("Vehicle already has maximum connections"); + return; + } + + // Check if we're trying to add a second Conveyor connection to a Vehicle + if (firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor') { + const hasConveyorConnection = firstPath.point.connections.targets.some(target => { + const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); + return targetPath?.type === 'Conveyor'; + }); + + if (hasConveyorConnection) { + console.log("Vehicle can only have one connection to a Conveyor"); + return; + } + } + + if (secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor') { + const hasConveyorConnection = secondPath.point.connections.targets.some(target => { + const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); + return targetPath?.type === 'Conveyor'; + }); + + if (hasConveyorConnection) { + console.log("Vehicle can only have one connection to a Conveyor"); + return; + } + } + + // Prevent same-path connections + if (firstSelected.pathUUID === pathUUID) { + console.log("Cannot connect spheres on the same path."); + return; + } + + // At least one must be start/end point + if (!firstSelected.isCorner && !isStartOrEnd) { + console.log("At least one of the selected spheres must be a start or end point."); + return; + } + + // All checks passed - make the connection + handleAddConnection( + firstSelected.pathUUID, + firstSelected.sphereUUID, + pathUUID, + sphereUUID + ); + } else { + // First selection - just store it setFirstSelected({ pathUUID, sphereUUID, @@ -230,28 +370,11 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec isCorner: isStartOrEnd }); setIsConnecting(true); - } else { - if (firstSelected.sphereUUID === sphereUUID) return; - - if (firstSelected.pathUUID === pathUUID) { - console.log("Cannot connect spheres on the same path."); - return; - } - if (!firstSelected.isCorner && !isStartOrEnd) { - console.log("At least one of the selected spheres must be a start or end point."); - return; - } - - handleAddConnection( - firstSelected.pathUUID, - firstSelected.sphereUUID, - pathUUID, - sphereUUID - ); } } } } else { + // Clicked outside - cancel connection setFirstSelected(null); setCurrentLine(null); setIsConnecting(false); @@ -294,7 +417,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec if (intersects.length > 0) { point = intersects[0].point; - if (point.y < 0.05) { point = new THREE.Vector3(point.x, 0.05, point.z); } @@ -316,28 +438,68 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID); const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle'; + // Inside the useFrame hook, where we check for snapped spheres: const isConnectable = (pathData.type === 'Vehicle' || (pathData.points.length > 0 && ( sphereUUID === pathData.points[0].uuid || sphereUUID === pathData.points[pathData.points.length - 1].uuid - ))) && !isVehicleToVehicle; + ))) && + !isVehicleToVehicle && + !(firstPath?.type === 'Conveyor' && + pathData.type === 'Conveyor' && + !firstSelected.isCorner); - const isAlreadyConnected = simulationPaths.some(path => { - if (path.type === 'Conveyor') { - return path.points.some(point => - point.uuid === sphereUUID && - point.connections.targets.length > 0 - ); - } else if (path.type === 'Vehicle') { - return path.point.uuid === sphereUUID && - path.point.connections.targets.length > 0; + // Check for duplicate connection (regardless of path type) + const isDuplicateConnection = simulationPaths.some(path => { + if (path.modeluuid === firstSelected.pathUUID) { + if (path.type === 'Conveyor') { + const point = path.points.find(p => p.uuid === firstSelected.sphereUUID); + return point?.connections.targets.some(t => + t.pathUUID === pathUUID && t.pointUUID === sphereUUID + ); + } else if (path.type === 'Vehicle') { + return path.point.connections.targets.some(t => + t.pathUUID === pathUUID && t.pointUUID === sphereUUID + ); + } } return false; }); + // For non-Vehicle paths, check if already connected + const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' && + simulationPaths.some(path => { + if (path.type === 'Conveyor') { + return path.points.some(point => + point.uuid === sphereUUID && + point.connections.targets.length > 0 + ); + } + return false; + }); + + // Check vehicle connection limits + const isVehicleAtMaxConnections = pathData.type === 'Vehicle' && + pathData.point.connections.targets.length >= 2; + + const isVehicleConveyorConflict = + (firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor' && + firstPath.point.connections.targets.some(t => { + const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID); + return targetPath?.type === 'Conveyor'; + })) || + (secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor' && + secondPath.point.connections.targets.some(t => { + const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID); + return targetPath?.type === 'Conveyor'; + })); + if ( - !isAlreadyConnected && + !isDuplicateConnection && !isVehicleToVehicle && + !isNonVehicleAlreadyConnected && + !isVehicleAtMaxConnections && + !isVehicleConveyorConflict && firstSelected.sphereUUID !== sphereUUID && firstSelected.pathUUID !== pathUUID && (firstSelected.isCorner || isConnectable) @@ -371,13 +533,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec end: point, mid: midPoint, }); - console.log({ - start: firstSelected.position, - end: point, - mid: midPoint, - }); - - // setIsConnecting(true); if (sphereIntersects.length > 0) { setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542'); diff --git a/app/src/services/factoryBuilder/mqtt/mqttEvents.ts b/app/src/services/factoryBuilder/mqtt/mqttEvents.ts index 41175ca..34d3939 100644 --- a/app/src/services/factoryBuilder/mqtt/mqttEvents.ts +++ b/app/src/services/factoryBuilder/mqtt/mqttEvents.ts @@ -6,37 +6,37 @@ const MqttEvents = () => { const { setTouch, setTemperature, setHumidity } = useDrieUIValue(); useEffect(() => { - const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`); + // const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`); - client.subscribe("touch"); - client.subscribe("temperature"); - client.subscribe("humidity"); + // client.subscribe("touch"); + // client.subscribe("temperature"); + // client.subscribe("humidity"); - const handleMessage = (topic: string, message: any) => { - const value = message.toString(); + // const handleMessage = (topic: string, message: any) => { + // const value = message.toString(); - if (topic === "touch") { - setTouch(value); - } else if (topic === "temperature") { - setTemperature(parseFloat(value)); - } else if (topic === "humidity") { - setHumidity(parseFloat(value)); - } - }; + // if (topic === "touch") { + // setTouch(value); + // } else if (topic === "temperature") { + // setTemperature(parseFloat(value)); + // } else if (topic === "humidity") { + // setHumidity(parseFloat(value)); + // } + // }; - client.on("message", handleMessage); + // client.on("message", handleMessage); - client.on("error", (err) => { - console.error("MQTT Connection Error:", err); - }); + // client.on("error", (err) => { + // console.error("MQTT Connection Error:", err); + // }); - client.on("close", () => { - console.log("MQTT Connection Closed"); - }); + // client.on("close", () => { + // console.log("MQTT Connection Closed"); + // }); - return () => { - client.end(); - }; + // return () => { + // client.end(); + // }; }, [setTouch, setTemperature, setHumidity]); return null; diff --git a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts index 71d9c2f..26a88c5 100644 --- a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts @@ -1,5 +1,4 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -console.log("url_Backend_dwinzo: ", url_Backend_dwinzo); export const getSelect2dZoneData = async ( ZoneId?: string,