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
);
}
}
}