using System; using System.Collections.Generic; using System.Linq; using AGVNavigationCore.Models; namespace AGVNavigationCore.PathFinding { /// /// RFID 기반 AGV 경로 탐색기 /// 실제 현장에서 AGV가 RFID를 읽어서 위치를 파악하는 방식에 맞춤 /// public class RfidBasedPathfinder { private AGVPathfinder _agvPathfinder; private AStarPathfinder _astarPathfinder; private Dictionary _rfidToNodeMap; // RFID -> NodeId private Dictionary _nodeToRfidMap; // NodeId -> RFID private List _mapNodes; /// /// AGV 현재 방향 /// public AgvDirection CurrentDirection { get => _agvPathfinder.CurrentDirection; set => _agvPathfinder.CurrentDirection = value; } /// /// 회전 비용 가중치 /// public float RotationCostWeight { get => _agvPathfinder.RotationCostWeight; set => _agvPathfinder.RotationCostWeight = value; } /// /// 생성자 /// public RfidBasedPathfinder() { _agvPathfinder = new AGVPathfinder(); _astarPathfinder = new AStarPathfinder(); _rfidToNodeMap = new Dictionary(); _nodeToRfidMap = new Dictionary(); _mapNodes = new List(); } /// /// 맵 노드 설정 (MapNode의 RFID 정보 직접 사용) /// /// 맵 노드 목록 public void SetMapNodes(List mapNodes) { // 기존 pathfinder에 맵 노드 설정 _agvPathfinder.SetMapNodes(mapNodes); _astarPathfinder.SetMapNodes(mapNodes); // MapNode의 RFID 정보로 매핑 구성 _mapNodes = mapNodes ?? new List(); _rfidToNodeMap.Clear(); _nodeToRfidMap.Clear(); foreach (var node in _mapNodes.Where(n => n.IsActive && n.HasRfid())) { _rfidToNodeMap[node.RfidId] = node.NodeId; _nodeToRfidMap[node.NodeId] = node.RfidId; } } /// /// RFID 기반 AGV 경로 계산 /// /// 시작 RFID /// 목적지 RFID /// 목적지 도착 방향 /// RFID 기반 AGV 경로 계산 결과 public RfidPathResult FindAGVPath(string startRfidId, string endRfidId, AgvDirection? targetDirection = null) { try { // RFID를 NodeId로 변환 if (!_rfidToNodeMap.TryGetValue(startRfidId, out string startNodeId)) { return RfidPathResult.CreateFailure($"시작 RFID를 찾을 수 없습니다: {startRfidId}", 0); } if (!_rfidToNodeMap.TryGetValue(endRfidId, out string endNodeId)) { return RfidPathResult.CreateFailure($"목적지 RFID를 찾을 수 없습니다: {endRfidId}", 0); } // NodeId 기반으로 경로 계산 var nodeResult = _agvPathfinder.FindAGVPath(startNodeId, endNodeId, targetDirection); // 결과를 RFID 기반으로 변환 return ConvertToRfidResult(nodeResult, startRfidId, endRfidId); } catch (Exception ex) { return RfidPathResult.CreateFailure($"RFID 기반 경로 계산 중 오류: {ex.Message}", 0); } } /// /// 가장 가까운 충전소로의 RFID 기반 경로 찾기 /// /// 시작 RFID /// RFID 기반 경로 계산 결과 public RfidPathResult FindPathToChargingStation(string startRfidId) { try { if (!_rfidToNodeMap.TryGetValue(startRfidId, out string startNodeId)) { return RfidPathResult.CreateFailure($"시작 RFID를 찾을 수 없습니다: {startRfidId}", 0); } var nodeResult = _agvPathfinder.FindPathToChargingStation(startNodeId); return ConvertToRfidResult(nodeResult, startRfidId, null); } catch (Exception ex) { return RfidPathResult.CreateFailure($"충전소 경로 계산 중 오류: {ex.Message}", 0); } } /// /// 특정 장비 타입의 도킹 스테이션으로의 RFID 기반 경로 찾기 /// /// 시작 RFID /// 장비 타입 /// RFID 기반 경로 계산 결과 public RfidPathResult FindPathToDockingStation(string startRfidId, StationType stationType) { try { if (!_rfidToNodeMap.TryGetValue(startRfidId, out string startNodeId)) { return RfidPathResult.CreateFailure($"시작 RFID를 찾을 수 없습니다: {startRfidId}", 0); } var nodeResult = _agvPathfinder.FindPathToDockingStation(startNodeId, stationType); return ConvertToRfidResult(nodeResult, startRfidId, null); } catch (Exception ex) { return RfidPathResult.CreateFailure($"도킹 스테이션 경로 계산 중 오류: {ex.Message}", 0); } } /// /// 여러 RFID 목적지 중 가장 가까운 곳으로의 경로 찾기 /// /// 시작 RFID /// 목적지 후보 RFID 목록 /// RFID 기반 경로 계산 결과 public RfidPathResult FindNearestPath(string startRfidId, List targetRfidIds) { try { if (!_rfidToNodeMap.TryGetValue(startRfidId, out string startNodeId)) { return RfidPathResult.CreateFailure($"시작 RFID를 찾을 수 없습니다: {startRfidId}", 0); } // RFID 목록을 NodeId 목록으로 변환 var targetNodeIds = new List(); foreach (var rfidId in targetRfidIds) { if (_rfidToNodeMap.TryGetValue(rfidId, out string nodeId)) { targetNodeIds.Add(nodeId); } } if (targetNodeIds.Count == 0) { return RfidPathResult.CreateFailure("유효한 목적지 RFID가 없습니다", 0); } var pathResult = _astarPathfinder.FindNearestPath(startNodeId, targetNodeIds); if (!pathResult.Success) { return RfidPathResult.CreateFailure(pathResult.ErrorMessage, pathResult.CalculationTimeMs); } // AGV 명령어 생성을 위해 AGV pathfinder 사용 var endNodeId = pathResult.Path.Last(); var agvResult = _agvPathfinder.FindAGVPath(startNodeId, endNodeId); return ConvertToRfidResult(agvResult, startRfidId, null); } catch (Exception ex) { return RfidPathResult.CreateFailure($"최근접 경로 계산 중 오류: {ex.Message}", 0); } } /// /// RFID 매핑 상태 확인 (MapNode 기반) /// /// 확인할 RFID /// MapNode 또는 null public MapNode GetRfidMapping(string rfidId) { return _mapNodes.FirstOrDefault(n => n.RfidId == rfidId && n.IsActive && n.HasRfid()); } /// /// RFID로 NodeId 조회 /// /// RFID /// NodeId 또는 null public string GetNodeIdByRfid(string rfidId) { return _rfidToNodeMap.TryGetValue(rfidId, out string nodeId) ? nodeId : null; } /// /// NodeId로 RFID 조회 /// /// NodeId /// RFID 또는 null public string GetRfidByNodeId(string nodeId) { return _nodeToRfidMap.TryGetValue(nodeId, out string rfidId) ? rfidId : null; } /// /// 활성화된 RFID 목록 반환 /// /// 활성화된 RFID 목록 public List GetActiveRfidList() { return _mapNodes.Where(n => n.IsActive && n.HasRfid()).Select(n => n.RfidId).ToList(); } /// /// NodeId 기반 결과를 RFID 기반 결과로 변환 /// private RfidPathResult ConvertToRfidResult(AGVPathResult nodeResult, string startRfidId, string endRfidId) { if (!nodeResult.Success) { return RfidPathResult.CreateFailure(nodeResult.ErrorMessage, nodeResult.CalculationTimeMs); } // NodeId 경로를 RFID 경로로 변환 var rfidPath = new List(); foreach (var nodeId in nodeResult.Path) { if (_nodeToRfidMap.TryGetValue(nodeId, out string rfidId)) { rfidPath.Add(rfidId); } else { // 매핑이 없는 경우 NodeId를 그대로 사용 (경고 로그 필요) rfidPath.Add($"[{nodeId}]"); } } return RfidPathResult.CreateSuccess( rfidPath, nodeResult.Commands, nodeResult.TotalDistance, nodeResult.CalculationTimeMs, nodeResult.EstimatedTimeSeconds, nodeResult.RotationCount ); } } }