using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using AGVNavigationCore.Models;
using AGVNavigationCore.PathFinding;
namespace AGVMapEditor.Models
{
///
/// AGV 전용 경로 계산기 (AGVNavigationCore 래퍼)
/// AGVMapEditor와 AGVNavigationCore 간의 호환성 제공
/// RFID 기반 경로 계산을 우선 사용
///
public class PathCalculator
{
private AGVPathfinder _agvPathfinder;
private AStarPathfinder _astarPathfinder;
private RfidBasedPathfinder _rfidPathfinder;
///
/// 생성자
///
public PathCalculator()
{
_agvPathfinder = new AGVPathfinder();
_astarPathfinder = new AStarPathfinder();
_rfidPathfinder = new RfidBasedPathfinder();
}
///
/// 맵 노드 설정
///
/// 맵 노드 목록
public void SetMapNodes(List mapNodes)
{
_agvPathfinder.SetMapNodes(mapNodes);
_astarPathfinder.SetMapNodes(mapNodes);
}
///
/// 맵 데이터 설정
///
/// 맵 노드 목록
public void SetMapData(List mapNodes)
{
_agvPathfinder.SetMapNodes(mapNodes);
_astarPathfinder.SetMapNodes(mapNodes);
// RfidPathfinder는 MapNode의 RFID 정보를 직접 사용
_rfidPathfinder.SetMapNodes(mapNodes);
// 도킹 조건 검색용 내부 노드 목록 업데이트
UpdateInternalMapNodes(mapNodes);
}
///
/// AGV 경로 계산
///
/// 시작 노드 ID
/// 목적지 노드 ID
/// 목적지 도착 방향
/// AGV 경로 계산 결과
public AGVPathResult FindAGVPath(string startNodeId, string endNodeId, AgvDirection? targetDirection = null)
{
return _agvPathfinder.FindAGVPath(startNodeId, endNodeId, targetDirection);
}
///
/// AGV 경로 계산 (옵션 지정 가능)
///
/// 시작 노드 ID
/// 목적지 노드 ID
/// 목적지 도착 방향
/// 경로 탐색 옵션
/// AGV 경로 계산 결과
public AGVPathResult FindAGVPath(string startNodeId, string endNodeId, AgvDirection? targetDirection, PathfindingOptions options)
{
return _agvPathfinder.FindAGVPath(startNodeId, endNodeId, targetDirection, options);
}
///
/// AGV 경로 계산 (현재 방향 및 PathfindingOptions 지원)
///
/// 시작 노드 ID
/// 목적지 노드 ID
/// 현재 AGV 방향
/// 목적지 도착 방향
/// 경로 탐색 옵션
/// AGV 경로 계산 결과
public AGVPathResult FindAGVPath(string startNodeId, string endNodeId, AgvDirection? currentDirection, AgvDirection? targetDirection, PathfindingOptions options)
{
return _agvPathfinder.FindAGVPath(startNodeId, endNodeId, currentDirection, targetDirection, options);
}
///
/// 충전 스테이션으로의 경로 찾기
///
/// 시작 노드 ID
/// AGV 경로 계산 결과
public AGVPathResult FindPathToChargingStation(string startNodeId)
{
return _agvPathfinder.FindPathToChargingStation(startNodeId);
}
///
/// 도킹 스테이션으로의 경로 찾기
///
/// 시작 노드 ID
/// 장비 타입
/// AGV 경로 계산 결과
public AGVPathResult FindPathToDockingStation(string startNodeId, StationType stationType)
{
return _agvPathfinder.FindPathToDockingStation(startNodeId, stationType);
}
///
/// 여러 목적지 중 가장 가까운 노드로의 경로 찾기
///
/// 시작 노드 ID
/// 목적지 후보 노드 ID 목록
/// 경로 계산 결과
public PathResult FindNearestPath(string startNodeId, List targetNodeIds)
{
return _astarPathfinder.FindNearestPath(startNodeId, targetNodeIds);
}
///
/// 두 노드가 연결되어 있는지 확인
///
/// 노드 1 ID
/// 노드 2 ID
/// 연결 여부
public bool AreNodesConnected(string nodeId1, string nodeId2)
{
return _astarPathfinder.AreNodesConnected(nodeId1, nodeId2);
}
///
/// 경로 유효성 검증
///
/// 검증할 경로
/// 유효성 검증 결과
public bool ValidatePath(List path)
{
return _agvPathfinder.ValidatePath(path);
}
///
/// 네비게이션 가능한 노드 목록 반환
///
/// 노드 ID 목록
public List GetNavigationNodes()
{
return _astarPathfinder.GetNavigationNodes();
}
///
/// AGV 현재 방향 설정
///
/// 현재 방향
public void SetCurrentDirection(AgvDirection direction)
{
_agvPathfinder.CurrentDirection = direction;
}
///
/// 회전 비용 가중치 설정
///
/// 회전 비용 가중치
public void SetRotationCostWeight(float weight)
{
_agvPathfinder.RotationCostWeight = weight;
}
///
/// 휴리스틱 가중치 설정
///
/// 휴리스틱 가중치
public void SetHeuristicWeight(float weight)
{
_astarPathfinder.HeuristicWeight = weight;
}
///
/// 최대 탐색 노드 수 설정
///
/// 최대 탐색 노드 수
public void SetMaxSearchNodes(int maxNodes)
{
_astarPathfinder.MaxSearchNodes = maxNodes;
}
// ==================== RFID 기반 경로 계산 메서드들 ====================
///
/// RFID 기반 AGV 경로 계산
///
/// 시작 RFID
/// 목적지 RFID
/// 목적지 도착 방향
/// RFID 기반 AGV 경로 계산 결과
public RfidPathResult FindAGVPathByRfid(string startRfidId, string endRfidId, AgvDirection? targetDirection = null)
{
return _rfidPathfinder.FindAGVPath(startRfidId, endRfidId, targetDirection);
}
///
/// RFID 기반 충전소 경로 찾기
///
/// 시작 RFID
/// RFID 기반 경로 계산 결과
public RfidPathResult FindPathToChargingStationByRfid(string startRfidId)
{
return _rfidPathfinder.FindPathToChargingStation(startRfidId);
}
///
/// RFID 기반 도킹 스테이션 경로 찾기
///
/// 시작 RFID
/// 장비 타입
/// RFID 기반 경로 계산 결과
public RfidPathResult FindPathToDockingStationByRfid(string startRfidId, StationType stationType)
{
return _rfidPathfinder.FindPathToDockingStation(startRfidId, stationType);
}
///
/// 여러 RFID 목적지 중 가장 가까운 곳으로의 경로 찾기
///
/// 시작 RFID
/// 목적지 후보 RFID 목록
/// RFID 기반 경로 계산 결과
public RfidPathResult FindNearestPathByRfid(string startRfidId, List targetRfidIds)
{
return _rfidPathfinder.FindNearestPath(startRfidId, targetRfidIds);
}
///
/// RFID 매핑 정보 조회 (MapNode 반환)
///
/// RFID
/// MapNode 또는 null
public MapNode GetRfidMapping(string rfidId)
{
return _rfidPathfinder.GetRfidMapping(rfidId);
}
///
/// RFID로 NodeId 조회
///
/// RFID
/// NodeId 또는 null
public string GetNodeIdByRfid(string rfidId)
{
return _rfidPathfinder.GetNodeIdByRfid(rfidId);
}
///
/// NodeId로 RFID 조회
///
/// NodeId
/// RFID 또는 null
public string GetRfidByNodeId(string nodeId)
{
return _rfidPathfinder.GetRfidByNodeId(nodeId);
}
///
/// 활성화된 RFID 목록 반환
///
/// 활성화된 RFID 목록
public List GetActiveRfidList()
{
return _rfidPathfinder.GetActiveRfidList();
}
///
/// RFID pathfinder의 AGV 현재 방향 설정
///
/// 현재 방향
public void SetRfidPathfinderCurrentDirection(AgvDirection direction)
{
_rfidPathfinder.CurrentDirection = direction;
}
///
/// RFID pathfinder의 회전 비용 가중치 설정
///
/// 회전 비용 가중치
public void SetRfidPathfinderRotationCostWeight(float weight)
{
_rfidPathfinder.RotationCostWeight = weight;
}
#region 도킹 조건 검색 기능
// 내부 노드 목록 저장
private List _mapNodes;
///
/// 맵 노드 설정 (도킹 조건 검색용)
///
private void UpdateInternalMapNodes(List mapNodes)
{
_mapNodes = mapNodes;
}
///
/// 도킹 방향 기반 노드 검색
///
/// 도킹 방향
/// 해당 도킹 방향의 노드 목록
public List GetNodesByDockingDirection(DockingDirection dockingDirection)
{
if (_mapNodes == null) return new List();
var result = new List();
foreach (var node in _mapNodes)
{
if (!node.IsActive) continue;
var nodeDockingDirection = GetNodeDockingDirection(node);
if (nodeDockingDirection == dockingDirection)
{
result.Add(node);
}
}
return result;
}
///
/// 노드의 도킹 방향 결정
///
/// 노드
/// 도킹 방향
public DockingDirection GetNodeDockingDirection(MapNode node)
{
switch (node.Type)
{
case NodeType.Charging:
return DockingDirection.Forward; // 충전기: 전진 도킹
case NodeType.Docking:
return DockingDirection.Backward; // 장비: 후진 도킹
default:
return DockingDirection.Forward; // 기본값: 전진
}
}
///
/// 도킹 방향과 장비 타입에 맞는 노드들로의 경로 검색
///
/// 시작 RFID
/// 필요한 도킹 방향
/// 장비 타입 (선택사항)
/// 경로 계산 결과 목록 (거리 순 정렬)
public List FindPathsByDockingCondition(string startRfidId, DockingDirection dockingDirection, StationType? stationType = null)
{
var targetNodes = GetNodesByDockingDirection(dockingDirection);
var results = new List();
// 장비 타입 필터링 (필요시)
if (stationType.HasValue && dockingDirection == DockingDirection.Backward)
{
// 후진 도킹이면서 특정 장비 타입이 지정된 경우
// 이 부분은 추후 StationMapping 정보가 있을 때 구현
// 현재는 모든 도킹 노드를 대상으로 함
}
foreach (var targetNode in targetNodes)
{
if (!targetNode.HasRfid()) continue;
try
{
var pathResult = _rfidPathfinder.FindAGVPath(startRfidId, targetNode.RfidId);
if (pathResult.Success)
{
results.Add(pathResult);
}
}
catch (Exception ex)
{
// 개별 경로 계산 실패는 무시하고 계속 진행
System.Diagnostics.Debug.WriteLine($"Path calculation failed from {startRfidId} to {targetNode.RfidId}: {ex.Message}");
}
}
// 거리 순으로 정렬
return results.OrderBy(r => r.TotalDistance).ToList();
}
///
/// 가장 가까운 충전기 경로 찾기 (전진 도킹)
///
/// 시작 RFID
/// 가장 가까운 충전기로의 경로
public RfidPathResult FindNearestChargingStationPath(string startRfidId)
{
var chargingPaths = FindPathsByDockingCondition(startRfidId, DockingDirection.Forward);
var chargingNodes = chargingPaths.Where(p => p.Success).ToList();
return chargingNodes.FirstOrDefault() ?? new RfidPathResult
{
Success = false,
ErrorMessage = "충전 가능한 충전기를 찾을 수 없습니다."
};
}
///
/// 가장 가까운 장비 도킹 경로 찾기 (후진 도킹)
///
/// 시작 RFID
/// 장비 타입 (선택사항)
/// 가장 가까운 장비로의 경로
public RfidPathResult FindNearestEquipmentPath(string startRfidId, StationType? stationType = null)
{
var equipmentPaths = FindPathsByDockingCondition(startRfidId, DockingDirection.Backward, stationType);
var equipmentNodes = equipmentPaths.Where(p => p.Success).ToList();
return equipmentNodes.FirstOrDefault() ?? new RfidPathResult
{
Success = false,
ErrorMessage = $"도킹 가능한 장비를 찾을 수 없습니다. ({stationType?.ToString() ?? "모든 타입"})"
};
}
#endregion
}
}