Major improvements to AGV navigation system: • Consolidated RFID management into MapNode, removing duplicate RfidMapping class • Enhanced MapNode with RFID metadata fields (RfidStatus, RfidDescription) • Added automatic bidirectional connection generation in pathfinding algorithms • Updated all components to use unified MapNode-based RFID system • Added command line argument support for AGVMapEditor auto-loading files • Fixed pathfinding failures by ensuring proper node connectivity Technical changes: - Removed RfidMapping class and dependencies across all projects - Updated AStarPathfinder with EnsureBidirectionalConnections() method - Modified MapLoader to use AssignAutoRfidIds() for RFID automation - Enhanced UnifiedAGVCanvas, SimulatorForm, and MainForm for MapNode integration - Improved data consistency and reduced memory footprint 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
229 lines
7.2 KiB
C#
229 lines
7.2 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using AGVNavigationCore.Models;
|
||
|
||
namespace AGVNavigationCore.PathFinding
|
||
{
|
||
/// <summary>
|
||
/// RFID 기반 AGV 경로 계산 결과
|
||
/// 실제 현장에서 AGV가 RFID를 기준으로 이동하는 방식에 맞춤
|
||
/// </summary>
|
||
public class RfidPathResult
|
||
{
|
||
/// <summary>
|
||
/// 경로 찾기 성공 여부
|
||
/// </summary>
|
||
public bool Success { get; set; }
|
||
|
||
/// <summary>
|
||
/// RFID 경로 목록 (시작 → 목적지 순서)
|
||
/// </summary>
|
||
public List<string> RfidPath { get; set; }
|
||
|
||
/// <summary>
|
||
/// AGV 명령어 목록 (이동 방향 시퀀스)
|
||
/// </summary>
|
||
public List<AgvDirection> Commands { get; set; }
|
||
|
||
/// <summary>
|
||
/// 총 거리
|
||
/// </summary>
|
||
public float TotalDistance { get; set; }
|
||
|
||
/// <summary>
|
||
/// 계산 소요 시간 (밀리초)
|
||
/// </summary>
|
||
public long CalculationTimeMs { get; set; }
|
||
|
||
/// <summary>
|
||
/// 예상 소요 시간 (초)
|
||
/// </summary>
|
||
public float EstimatedTimeSeconds { get; set; }
|
||
|
||
/// <summary>
|
||
/// 회전 횟수
|
||
/// </summary>
|
||
public int RotationCount { get; set; }
|
||
|
||
/// <summary>
|
||
/// 오류 메시지 (실패시)
|
||
/// </summary>
|
||
public string ErrorMessage { get; set; }
|
||
|
||
/// <summary>
|
||
/// 기본 생성자
|
||
/// </summary>
|
||
public RfidPathResult()
|
||
{
|
||
Success = false;
|
||
RfidPath = new List<string>();
|
||
Commands = new List<AgvDirection>();
|
||
TotalDistance = 0;
|
||
CalculationTimeMs = 0;
|
||
EstimatedTimeSeconds = 0;
|
||
RotationCount = 0;
|
||
ErrorMessage = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 성공 결과 생성
|
||
/// </summary>
|
||
/// <param name="rfidPath">RFID 경로</param>
|
||
/// <param name="commands">AGV 명령어 목록</param>
|
||
/// <param name="totalDistance">총 거리</param>
|
||
/// <param name="calculationTimeMs">계산 시간</param>
|
||
/// <param name="estimatedTimeSeconds">예상 소요 시간</param>
|
||
/// <param name="rotationCount">회전 횟수</param>
|
||
/// <returns>성공 결과</returns>
|
||
public static RfidPathResult CreateSuccess(
|
||
List<string> rfidPath,
|
||
List<AgvDirection> commands,
|
||
float totalDistance,
|
||
long calculationTimeMs,
|
||
float estimatedTimeSeconds,
|
||
int rotationCount)
|
||
{
|
||
return new RfidPathResult
|
||
{
|
||
Success = true,
|
||
RfidPath = new List<string>(rfidPath),
|
||
Commands = new List<AgvDirection>(commands),
|
||
TotalDistance = totalDistance,
|
||
CalculationTimeMs = calculationTimeMs,
|
||
EstimatedTimeSeconds = estimatedTimeSeconds,
|
||
RotationCount = rotationCount
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 실패 결과 생성
|
||
/// </summary>
|
||
/// <param name="errorMessage">오류 메시지</param>
|
||
/// <param name="calculationTimeMs">계산 시간</param>
|
||
/// <returns>실패 결과</returns>
|
||
public static RfidPathResult CreateFailure(string errorMessage, long calculationTimeMs)
|
||
{
|
||
return new RfidPathResult
|
||
{
|
||
Success = false,
|
||
ErrorMessage = errorMessage,
|
||
CalculationTimeMs = calculationTimeMs
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 명령어 요약 생성
|
||
/// </summary>
|
||
/// <returns>명령어 요약 문자열</returns>
|
||
public string GetCommandSummary()
|
||
{
|
||
if (!Success) return "실패";
|
||
|
||
var summary = new List<string>();
|
||
var currentCommand = AgvDirection.Stop;
|
||
var count = 0;
|
||
|
||
foreach (var command in Commands)
|
||
{
|
||
if (command == currentCommand)
|
||
{
|
||
count++;
|
||
}
|
||
else
|
||
{
|
||
if (count > 0)
|
||
{
|
||
summary.Add($"{GetCommandText(currentCommand)}×{count}");
|
||
}
|
||
currentCommand = command;
|
||
count = 1;
|
||
}
|
||
}
|
||
|
||
if (count > 0)
|
||
{
|
||
summary.Add($"{GetCommandText(currentCommand)}×{count}");
|
||
}
|
||
|
||
return string.Join(" → ", summary);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 명령어 텍스트 반환
|
||
/// </summary>
|
||
private string GetCommandText(AgvDirection command)
|
||
{
|
||
switch (command)
|
||
{
|
||
case AgvDirection.Forward: return "전진";
|
||
case AgvDirection.Backward: return "후진";
|
||
case AgvDirection.Left: return "좌회전";
|
||
case AgvDirection.Right: return "우회전";
|
||
case AgvDirection.Stop: return "정지";
|
||
default: return command.ToString();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// RFID 경로 요약 생성
|
||
/// </summary>
|
||
/// <returns>RFID 경로 요약 문자열</returns>
|
||
public string GetRfidPathSummary()
|
||
{
|
||
if (!Success || RfidPath.Count == 0) return "경로 없음";
|
||
|
||
if (RfidPath.Count <= 3)
|
||
{
|
||
return string.Join(" → ", RfidPath);
|
||
}
|
||
else
|
||
{
|
||
return $"{RfidPath[0]} → ... ({RfidPath.Count - 2}개 경유) → {RfidPath[RfidPath.Count - 1]}";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 상세 경로 정보 반환
|
||
/// </summary>
|
||
/// <returns>상세 정보 문자열</returns>
|
||
public string GetDetailedInfo()
|
||
{
|
||
if (!Success)
|
||
{
|
||
return $"RFID 경로 계산 실패: {ErrorMessage} (계산시간: {CalculationTimeMs}ms)";
|
||
}
|
||
|
||
return $"RFID 경로: {RfidPath.Count}개 지점, 거리: {TotalDistance:F1}px, " +
|
||
$"회전: {RotationCount}회, 예상시간: {EstimatedTimeSeconds:F1}초, " +
|
||
$"계산시간: {CalculationTimeMs}ms";
|
||
}
|
||
|
||
/// <summary>
|
||
/// AGV 운영자용 실행 정보 반환
|
||
/// </summary>
|
||
/// <returns>실행 정보 문자열</returns>
|
||
public string GetExecutionInfo()
|
||
{
|
||
if (!Success) return $"실행 불가: {ErrorMessage}";
|
||
|
||
return $"[실행준비] {GetRfidPathSummary()}\n" +
|
||
$"[명령어] {GetCommandSummary()}\n" +
|
||
$"[예상시간] {EstimatedTimeSeconds:F1}초";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 문자열 표현
|
||
/// </summary>
|
||
public override string ToString()
|
||
{
|
||
if (Success)
|
||
{
|
||
return $"Success: {RfidPath.Count} RFIDs, {TotalDistance:F1}px, {RotationCount} rotations, {EstimatedTimeSeconds:F1}s";
|
||
}
|
||
else
|
||
{
|
||
return $"Failed: {ErrorMessage}";
|
||
}
|
||
}
|
||
}
|
||
} |