using System;
using System.Collections.Generic;
using System.Linq;
namespace AGVMapEditor.Models
{
///
/// 경로 계산 결과
///
public class PathResult
{
///
/// 경로 계산 성공 여부
///
public bool Success { get; set; } = false;
///
/// 경로상의 노드 ID 시퀀스
///
public List NodeSequence { get; set; } = new List();
///
/// AGV 이동 명령 시퀀스
///
public List MovementSequence { get; set; } = new List();
///
/// 총 이동 거리 (비용)
///
public float TotalDistance { get; set; } = 0;
///
/// 총 회전 횟수
///
public int TotalRotations { get; set; } = 0;
///
/// 예상 소요 시간 (초)
///
public float EstimatedTime { get; set; } = 0;
///
/// 시작 노드 ID
///
public string StartNodeId { get; set; } = string.Empty;
///
/// 목표 노드 ID
///
public string TargetNodeId { get; set; } = string.Empty;
///
/// 시작시 AGV 방향
///
public AgvDirection StartDirection { get; set; } = AgvDirection.Forward;
///
/// 도착시 AGV 방향
///
public AgvDirection EndDirection { get; set; } = AgvDirection.Forward;
///
/// 경로 계산에 걸린 시간 (밀리초)
///
public long CalculationTime { get; set; } = 0;
///
/// 오류 메시지 (실패시)
///
public string ErrorMessage { get; set; } = string.Empty;
///
/// 경로상의 상세 정보 (디버깅용)
///
public List DetailedPath { get; set; } = new List();
///
/// 회전이 발생하는 노드들
///
public List RotationNodes { get; set; } = new List();
///
/// 기본 생성자
///
public PathResult()
{
}
///
/// 성공 결과 생성자
///
public PathResult(List path, string startNodeId, string targetNodeId, AgvDirection startDirection)
{
if (path == null || path.Count == 0)
{
Success = false;
ErrorMessage = "빈 경로입니다.";
return;
}
Success = true;
StartNodeId = startNodeId;
TargetNodeId = targetNodeId;
StartDirection = startDirection;
DetailedPath = new List(path);
// 노드 시퀀스 구성
NodeSequence = path.Select(p => p.NodeId).ToList();
// 이동 명령 시퀀스 구성
MovementSequence = new List();
for (int i = 0; i < path.Count; i++)
{
MovementSequence.AddRange(path[i].MovementSequence);
}
// 통계 계산
if (path.Count > 0)
{
TotalDistance = path[path.Count - 1].GCost;
EndDirection = path[path.Count - 1].Direction;
}
TotalRotations = MovementSequence.Count(cmd =>
cmd == AgvDirection.Left || cmd == AgvDirection.Right);
// 회전 노드 추출
var previousDirection = startDirection;
for (int i = 0; i < path.Count; i++)
{
if (path[i].Direction != previousDirection)
{
RotationNodes.Add(path[i].NodeId);
}
previousDirection = path[i].Direction;
}
// 예상 소요 시간 계산 (단순 추정)
EstimatedTime = CalculateEstimatedTime();
}
///
/// 실패 결과 생성자
///
public PathResult(string errorMessage)
{
Success = false;
ErrorMessage = errorMessage;
}
///
/// 예상 소요 시간 계산
///
private float CalculateEstimatedTime()
{
// 기본 이동 속도 및 회전 시간 가정
const float MOVE_SPEED = 1.0f; // 단위/초
const float ROTATION_TIME = 2.0f; // 초/회전
float moveTime = TotalDistance / MOVE_SPEED;
float rotationTime = TotalRotations * ROTATION_TIME;
return moveTime + rotationTime;
}
///
/// 경로 요약 정보
///
public string GetSummary()
{
if (!Success)
{
return $"경로 계산 실패: {ErrorMessage}";
}
return $"경로: {NodeSequence.Count}개 노드, " +
$"거리: {TotalDistance:F1}, " +
$"회전: {TotalRotations}회, " +
$"예상시간: {EstimatedTime:F1}초";
}
///
/// 상세 경로 정보
///
public List GetDetailedSteps()
{
var steps = new List();
if (!Success)
{
steps.Add($"경로 계산 실패: {ErrorMessage}");
return steps;
}
steps.Add($"시작: {StartNodeId} (방향: {StartDirection})");
for (int i = 0; i < DetailedPath.Count; i++)
{
var node = DetailedPath[i];
var step = $"{i + 1}. {node.NodeId}";
if (node.MovementSequence.Count > 0)
{
step += $" [명령: {string.Join(",", node.MovementSequence)}]";
}
step += $" (F:{node.FCost:F1}, 방향:{node.Direction})";
steps.Add(step);
}
steps.Add($"도착: {TargetNodeId} (최종 방향: {EndDirection})");
return steps;
}
///
/// RFID 시퀀스 추출 (실제 AGV 제어용)
///
public List GetRfidSequence(NodeResolver nodeResolver)
{
var rfidSequence = new List();
foreach (var nodeId in NodeSequence)
{
var rfidId = nodeResolver.GetRfidByNodeId(nodeId);
if (!string.IsNullOrEmpty(rfidId))
{
rfidSequence.Add(rfidId);
}
}
return rfidSequence;
}
///
/// 경로 유효성 검증
///
public bool ValidatePath(List mapNodes)
{
if (!Success || NodeSequence.Count == 0)
return false;
// 모든 노드가 존재하는지 확인
foreach (var nodeId in NodeSequence)
{
if (!mapNodes.Any(n => n.NodeId == nodeId))
{
ErrorMessage = $"존재하지 않는 노드: {nodeId}";
return false;
}
}
// 연결성 확인
for (int i = 0; i < NodeSequence.Count - 1; i++)
{
var currentNode = mapNodes.FirstOrDefault(n => n.NodeId == NodeSequence[i]);
var nextNodeId = NodeSequence[i + 1];
if (currentNode != null && !currentNode.ConnectedNodes.Contains(nextNodeId))
{
ErrorMessage = $"연결되지 않은 노드: {currentNode.NodeId} → {nextNodeId}";
return false;
}
}
return true;
}
///
/// JSON 직렬화를 위한 문자열 변환
///
public override string ToString()
{
return GetSummary();
}
}
}