refactor: Consolidate RFID mapping and add bidirectional pathfinding
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>
This commit is contained in:
229
Cs_HMI/AGVNavigationCore/PathFinding/RfidPathResult.cs
Normal file
229
Cs_HMI/AGVNavigationCore/PathFinding/RfidPathResult.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user