refactor: PathFinding 폴더 구조 개선 및 도킹 에러 기능 추가
- PathFinding 폴더를 Core, Validation, Planning, Analysis로 세분화 - 네임스페이스 정리 및 using 문 업데이트 - UnifiedAGVCanvas에 SetDockingError 메서드 추가 - 도킹 검증 시스템 인프라 구축 - DockingValidator 유틸리티 클래스 추가 - 빌드 오류 수정 및 안정성 개선 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
37
Cs_HMI/AGVSimulator/Forms/SimulatorForm.Designer.cs
generated
37
Cs_HMI/AGVSimulator/Forms/SimulatorForm.Designer.cs
generated
@@ -86,7 +86,7 @@ namespace AGVSimulator.Forms
|
||||
this._clearPathButton = new System.Windows.Forms.Button();
|
||||
this._startPathButton = new System.Windows.Forms.Button();
|
||||
this._calculatePathButton = new System.Windows.Forms.Button();
|
||||
this._selectTargetButton = new System.Windows.Forms.Button();
|
||||
this._targetCalcButton = new System.Windows.Forms.Button();
|
||||
this._avoidRotationCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this._targetNodeCombo = new System.Windows.Forms.ComboBox();
|
||||
this.targetNodeLabel = new System.Windows.Forms.Label();
|
||||
@@ -412,7 +412,7 @@ namespace AGVSimulator.Forms
|
||||
this._statusGroup.Controls.Add(this._agvCountLabel);
|
||||
this._statusGroup.Controls.Add(this._simulationStatusLabel);
|
||||
this._statusGroup.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this._statusGroup.Location = new System.Drawing.Point(0, 404);
|
||||
this._statusGroup.Location = new System.Drawing.Point(0, 446);
|
||||
this._statusGroup.Name = "_statusGroup";
|
||||
this._statusGroup.Size = new System.Drawing.Size(233, 100);
|
||||
this._statusGroup.TabIndex = 3;
|
||||
@@ -451,7 +451,7 @@ namespace AGVSimulator.Forms
|
||||
this._pathGroup.Controls.Add(this._clearPathButton);
|
||||
this._pathGroup.Controls.Add(this._startPathButton);
|
||||
this._pathGroup.Controls.Add(this._calculatePathButton);
|
||||
this._pathGroup.Controls.Add(this._selectTargetButton);
|
||||
this._pathGroup.Controls.Add(this._targetCalcButton);
|
||||
this._pathGroup.Controls.Add(this._avoidRotationCheckBox);
|
||||
this._pathGroup.Controls.Add(this._targetNodeCombo);
|
||||
this._pathGroup.Controls.Add(this.targetNodeLabel);
|
||||
@@ -460,14 +460,14 @@ namespace AGVSimulator.Forms
|
||||
this._pathGroup.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this._pathGroup.Location = new System.Drawing.Point(0, 214);
|
||||
this._pathGroup.Name = "_pathGroup";
|
||||
this._pathGroup.Size = new System.Drawing.Size(233, 190);
|
||||
this._pathGroup.Size = new System.Drawing.Size(233, 232);
|
||||
this._pathGroup.TabIndex = 1;
|
||||
this._pathGroup.TabStop = false;
|
||||
this._pathGroup.Text = "경로 제어";
|
||||
//
|
||||
// _clearPathButton
|
||||
//
|
||||
this._clearPathButton.Location = new System.Drawing.Point(150, 148);
|
||||
this._clearPathButton.Location = new System.Drawing.Point(150, 177);
|
||||
this._clearPathButton.Name = "_clearPathButton";
|
||||
this._clearPathButton.Size = new System.Drawing.Size(70, 25);
|
||||
this._clearPathButton.TabIndex = 6;
|
||||
@@ -477,7 +477,7 @@ namespace AGVSimulator.Forms
|
||||
//
|
||||
// _startPathButton
|
||||
//
|
||||
this._startPathButton.Location = new System.Drawing.Point(80, 148);
|
||||
this._startPathButton.Location = new System.Drawing.Point(80, 177);
|
||||
this._startPathButton.Name = "_startPathButton";
|
||||
this._startPathButton.Size = new System.Drawing.Size(65, 25);
|
||||
this._startPathButton.TabIndex = 5;
|
||||
@@ -487,24 +487,25 @@ namespace AGVSimulator.Forms
|
||||
//
|
||||
// _calculatePathButton
|
||||
//
|
||||
this._calculatePathButton.Location = new System.Drawing.Point(10, 148);
|
||||
this._calculatePathButton.Location = new System.Drawing.Point(10, 177);
|
||||
this._calculatePathButton.Name = "_calculatePathButton";
|
||||
this._calculatePathButton.Size = new System.Drawing.Size(65, 25);
|
||||
this._calculatePathButton.TabIndex = 4;
|
||||
this._calculatePathButton.Text = "경로 계산";
|
||||
this._calculatePathButton.UseVisualStyleBackColor = true;
|
||||
this._calculatePathButton.Click += new System.EventHandler(this.OnCalculatePath_Click);
|
||||
//
|
||||
//
|
||||
// _selectTargetButton
|
||||
//
|
||||
this._selectTargetButton.Location = new System.Drawing.Point(80, 148);
|
||||
this._selectTargetButton.Name = "_selectTargetButton";
|
||||
this._selectTargetButton.Size = new System.Drawing.Size(70, 25);
|
||||
this._selectTargetButton.TabIndex = 8;
|
||||
this._selectTargetButton.Text = "목적지 선택";
|
||||
this._selectTargetButton.UseVisualStyleBackColor = true;
|
||||
this._selectTargetButton.Click += new System.EventHandler(this.OnSelectTarget_Click);
|
||||
//
|
||||
// _targetCalcButton
|
||||
//
|
||||
this._targetCalcButton.Location = new System.Drawing.Point(10, 148);
|
||||
this._targetCalcButton.Name = "_targetCalcButton";
|
||||
this._targetCalcButton.Size = new System.Drawing.Size(70, 25);
|
||||
this._targetCalcButton.TabIndex = 9;
|
||||
this._targetCalcButton.Text = "타겟계산";
|
||||
this._targetCalcButton.UseVisualStyleBackColor = true;
|
||||
this._targetCalcButton.Click += new System.EventHandler(this.OnTargetCalc_Click);
|
||||
//
|
||||
// _avoidRotationCheckBox
|
||||
//
|
||||
this._avoidRotationCheckBox.AutoSize = true;
|
||||
@@ -805,7 +806,7 @@ namespace AGVSimulator.Forms
|
||||
private System.Windows.Forms.Button _calculatePathButton;
|
||||
private System.Windows.Forms.Button _startPathButton;
|
||||
private System.Windows.Forms.Button _clearPathButton;
|
||||
private System.Windows.Forms.Button _selectTargetButton;
|
||||
private System.Windows.Forms.Button _targetCalcButton;
|
||||
private System.Windows.Forms.CheckBox _avoidRotationCheckBox;
|
||||
private System.Windows.Forms.GroupBox _statusGroup;
|
||||
private System.Windows.Forms.Label _simulationStatusLabel;
|
||||
|
||||
@@ -5,12 +5,14 @@ using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using AGVMapEditor.Models;
|
||||
using AGVNavigationCore.Models;
|
||||
using AGVNavigationCore.Controls;
|
||||
using AGVNavigationCore.PathFinding;
|
||||
using AGVNavigationCore.Utils;
|
||||
using AGVSimulator.Models;
|
||||
using Newtonsoft.Json;
|
||||
using AGVNavigationCore.PathFinding.Planning;
|
||||
using AGVNavigationCore.PathFinding.Core;
|
||||
|
||||
namespace AGVSimulator.Forms
|
||||
{
|
||||
@@ -23,15 +25,13 @@ namespace AGVSimulator.Forms
|
||||
|
||||
private UnifiedAGVCanvas _simulatorCanvas;
|
||||
private List<MapNode> _mapNodes;
|
||||
private NodeResolver _nodeResolver;
|
||||
private PathCalculator _pathCalculator;
|
||||
private AdvancedAGVPathfinder _advancedPathfinder;
|
||||
private AGVPathfinder _advancedPathfinder;
|
||||
private List<VirtualAGV> _agvList;
|
||||
private SimulationState _simulationState;
|
||||
private Timer _simulationTimer;
|
||||
private SimulatorConfig _config;
|
||||
private string _currentMapFilePath;
|
||||
private bool _isSelectingTarget; // 목적지 선택 모드 상태
|
||||
private bool _isTargetCalcMode; // 타겟계산 모드 상태
|
||||
|
||||
// UI Controls - Designer에서 생성됨
|
||||
|
||||
@@ -89,13 +89,10 @@ namespace AGVSimulator.Forms
|
||||
// 마지막 맵 파일 자동 로드 확인은 Form_Load에서 수행
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void CreateSimulatorCanvas()
|
||||
{
|
||||
_simulatorCanvas = new UnifiedAGVCanvas();
|
||||
_simulatorCanvas.Dock = DockStyle.Fill;
|
||||
_simulatorCanvas.Mode = UnifiedAGVCanvas.CanvasMode.ViewOnly;
|
||||
|
||||
// 목적지 선택 이벤트 구독
|
||||
_simulatorCanvas.TargetNodeSelected += OnTargetNodeSelected;
|
||||
@@ -272,6 +269,12 @@ namespace AGVSimulator.Forms
|
||||
|
||||
private void OnCalculatePath_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 시작 RFID가 없으면 AGV 현재 위치로 설정
|
||||
if (_startNodeCombo.SelectedItem == null || _startNodeCombo.Text == "선택하세요")
|
||||
{
|
||||
SetStartNodeFromAGVPosition();
|
||||
}
|
||||
|
||||
if (_startNodeCombo.SelectedItem == null || _targetNodeCombo.SelectedItem == null)
|
||||
{
|
||||
MessageBox.Show("시작 RFID와 목표 RFID를 선택해주세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
@@ -289,61 +292,40 @@ namespace AGVSimulator.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
if (_pathCalculator == null)
|
||||
{
|
||||
_pathCalculator = new PathCalculator();
|
||||
_pathCalculator.SetMapData(_mapNodes);
|
||||
}
|
||||
|
||||
if (_advancedPathfinder == null)
|
||||
{
|
||||
_advancedPathfinder = new AdvancedAGVPathfinder(_mapNodes);
|
||||
_advancedPathfinder = new AGVPathfinder(_mapNodes);
|
||||
}
|
||||
|
||||
// 현재 AGV 방향 가져오기
|
||||
var selectedAGV = _agvListCombo.SelectedItem as VirtualAGV;
|
||||
var currentDirection = selectedAGV?.CurrentDirection ?? AgvDirection.Forward;
|
||||
|
||||
// 고급 경로 계획 사용
|
||||
var advancedResult = _advancedPathfinder.FindAdvancedPath(startNode.NodeId, targetNode.NodeId, currentDirection);
|
||||
// 고급 경로 계획 사용 (단일 경로 계산 방식)
|
||||
var advancedResult = _advancedPathfinder.FindPath(startNode.NodeId, targetNode.NodeId, currentDirection);
|
||||
|
||||
if (advancedResult.Success)
|
||||
{
|
||||
// 고급 경로 결과를 기존 AGVPathResult 형태로 변환
|
||||
var agvResult1 = ConvertToAGVPathResult(advancedResult);
|
||||
// 고급 경로 결과를 AGVPathResult 형태로 변환 (도킹 검증 포함)
|
||||
var agvResult = ConvertToAGVPathResult(advancedResult, currentDirection);
|
||||
|
||||
_simulatorCanvas.CurrentPath = agvResult1.ToPathResult();
|
||||
_simulatorCanvas.CurrentPath = agvResult;
|
||||
_pathLengthLabel.Text = $"경로 길이: {advancedResult.TotalDistance:F1}";
|
||||
_statusLabel.Text = $"고급 경로 계산 완료 ({advancedResult.CalculationTimeMs}ms)";
|
||||
_statusLabel.Text = $"경로 계산 완료 ({advancedResult.CalculationTimeMs}ms)";
|
||||
|
||||
// 도킹 검증 결과 확인 및 UI 표시
|
||||
CheckAndDisplayDockingValidation(agvResult);
|
||||
|
||||
// 고급 경로 디버깅 정보 표시
|
||||
UpdateAdvancedPathDebugInfo(advancedResult);
|
||||
return;
|
||||
}
|
||||
|
||||
// 고급 경로 실패시 기존 방식으로 fallback
|
||||
// 회전 회피 옵션 설정
|
||||
var options = _avoidRotationCheckBox.Checked
|
||||
? PathfindingOptions.AvoidRotation
|
||||
: PathfindingOptions.Default;
|
||||
|
||||
var agvResult = _pathCalculator.FindAGVPath(startNode.NodeId, targetNode.NodeId, null, options);
|
||||
|
||||
if (agvResult.Success)
|
||||
{
|
||||
_simulatorCanvas.CurrentPath = agvResult.ToPathResult();
|
||||
_pathLengthLabel.Text = $"경로 길이: {agvResult.TotalDistance:F1}";
|
||||
_statusLabel.Text = $"경로 계산 완료 ({agvResult.CalculationTimeMs}ms)";
|
||||
|
||||
// 경로 디버깅 정보 표시
|
||||
UpdatePathDebugInfo(agvResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 경로 실패시 디버깅 정보 초기화
|
||||
_pathDebugLabel.Text = $"경로: 실패 - {agvResult.ErrorMessage}";
|
||||
|
||||
MessageBox.Show($"경로를 찾을 수 없습니다:\n{agvResult.ErrorMessage}", "경로 계산 실패",
|
||||
_pathDebugLabel.Text = $"경로: 실패 - {advancedResult.ErrorMessage}";
|
||||
|
||||
MessageBox.Show($"경로를 찾을 수 없습니다:\n{advancedResult.ErrorMessage}", "경로 계산 실패",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
}
|
||||
@@ -374,25 +356,25 @@ namespace AGVSimulator.Forms
|
||||
_statusLabel.Text = "경로 지움";
|
||||
}
|
||||
|
||||
private void OnSelectTarget_Click(object sender, EventArgs e)
|
||||
private void OnTargetCalc_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isSelectingTarget)
|
||||
if (_isTargetCalcMode)
|
||||
{
|
||||
// 목적지 선택 모드 해제
|
||||
_isSelectingTarget = false;
|
||||
_selectTargetButton.Text = "목적지 선택";
|
||||
_selectTargetButton.BackColor = SystemColors.Control;
|
||||
// 타겟계산 모드 해제
|
||||
_isTargetCalcMode = false;
|
||||
_targetCalcButton.Text = "타겟계산";
|
||||
_targetCalcButton.BackColor = SystemColors.Control;
|
||||
_simulatorCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Select;
|
||||
_statusLabel.Text = "목적지 선택 모드 해제";
|
||||
_statusLabel.Text = "타겟계산 모드 해제";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 목적지 선택 모드 활성화
|
||||
_isSelectingTarget = true;
|
||||
_selectTargetButton.Text = "선택 취소";
|
||||
_selectTargetButton.BackColor = Color.LightBlue;
|
||||
// 타겟계산 모드 활성화
|
||||
_isTargetCalcMode = true;
|
||||
_targetCalcButton.Text = "계산 취소";
|
||||
_targetCalcButton.BackColor = Color.LightGreen;
|
||||
_simulatorCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.SelectTarget;
|
||||
_statusLabel.Text = "맵에서 목적지 노드를 클릭하세요";
|
||||
_statusLabel.Text = "목적지 노드를 클릭하세요 (자동으로 경로 계산됨)";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,35 +382,123 @@ namespace AGVSimulator.Forms
|
||||
{
|
||||
try
|
||||
{
|
||||
// 목적지 선택 모드 해제
|
||||
_isSelectingTarget = false;
|
||||
_selectTargetButton.Text = "목적지 선택";
|
||||
_selectTargetButton.BackColor = SystemColors.Control;
|
||||
_simulatorCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Select;
|
||||
|
||||
// 목적지 콤보박스에 선택된 노드 설정
|
||||
var displayText = GetDisplayName(selectedNode.NodeId);
|
||||
for (int i = 0; i < _targetNodeCombo.Items.Count; i++)
|
||||
// 타겟계산 모드에서만 처리
|
||||
if (_isTargetCalcMode)
|
||||
{
|
||||
var item = _targetNodeCombo.Items[i].ToString();
|
||||
if (item.Contains($"[{selectedNode.NodeId}]"))
|
||||
{
|
||||
_targetNodeCombo.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
// 타겟계산 모드 해제
|
||||
//_isTargetCalcMode = false;
|
||||
//_targetCalcButton.Text = "타겟계산";
|
||||
//_targetCalcButton.BackColor = SystemColors.Control;
|
||||
//_simulatorCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Select;
|
||||
|
||||
// 목적지를 선택된 노드로 설정
|
||||
SetTargetNodeInCombo(selectedNode.NodeId);
|
||||
|
||||
var displayText = GetDisplayName(selectedNode.NodeId);
|
||||
_statusLabel.Text = $"타겟계산 - 목적지: {displayText}";
|
||||
|
||||
// 자동으로 경로 계산 수행
|
||||
OnCalculatePath_Click(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
_statusLabel.Text = $"목적지 설정: {displayText}";
|
||||
|
||||
// 자동으로 경로 계산 수행
|
||||
OnCalculatePath_Click(this, EventArgs.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_statusLabel.Text = $"목적지 선택 오류: {ex.Message}";
|
||||
_statusLabel.Text = $"노드 선택 오류: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 목적지 콤보박스에 노드 설정
|
||||
/// </summary>
|
||||
private void SetTargetNodeInCombo(string nodeId)
|
||||
{
|
||||
for (int i = 0; i < _targetNodeCombo.Items.Count; i++)
|
||||
{
|
||||
var item = _targetNodeCombo.Items[i].ToString();
|
||||
if (item.Contains($"[{nodeId}]"))
|
||||
{
|
||||
_targetNodeCombo.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AGV 현재 노드로 시작 노드 설정
|
||||
/// </summary>
|
||||
private void SetStartNodeFromAGVPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_agvList.Count > 0)
|
||||
{
|
||||
var agv = _agvList[0]; // 첫 번째 AGV 사용
|
||||
var currentNodeId = agv.CurrentNodeId;
|
||||
|
||||
// AGV가 현재 노드 정보를 가지고 있는 경우 직접 사용
|
||||
if (!string.IsNullOrEmpty(currentNodeId))
|
||||
{
|
||||
// 시작 노드 콤보박스에 설정
|
||||
for (int i = 0; i < _startNodeCombo.Items.Count; i++)
|
||||
{
|
||||
var item = _startNodeCombo.Items[i].ToString();
|
||||
if (item.Contains($"[{currentNodeId}]"))
|
||||
{
|
||||
_startNodeCombo.SelectedIndex = i;
|
||||
return; // 성공적으로 설정됨
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CurrentNodeId가 없거나 콤보박스에서 찾지 못한 경우 위치 기반으로 폴백
|
||||
var currentPos = agv.CurrentPosition;
|
||||
var closestNode = FindClosestNode(currentPos);
|
||||
if (closestNode != null)
|
||||
{
|
||||
// 시작 노드 콤보박스에 설정
|
||||
for (int i = 0; i < _startNodeCombo.Items.Count; i++)
|
||||
{
|
||||
var item = _startNodeCombo.Items[i].ToString();
|
||||
if (item.Contains($"[{closestNode.NodeId}]"))
|
||||
{
|
||||
_startNodeCombo.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_statusLabel.Text = $"시작 노드 설정 오류: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 위치에서 가장 가까운 노드 찾기
|
||||
/// </summary>
|
||||
private MapNode FindClosestNode(Point position)
|
||||
{
|
||||
if (_mapNodes == null || _mapNodes.Count == 0)
|
||||
return null;
|
||||
|
||||
MapNode closestNode = null;
|
||||
double closestDistance = double.MaxValue;
|
||||
|
||||
foreach (var node in _mapNodes)
|
||||
{
|
||||
var distance = Math.Sqrt(Math.Pow(node.Position.X - position.X, 2) +
|
||||
Math.Pow(node.Position.Y - position.Y, 2));
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
closestDistance = distance;
|
||||
closestNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
return closestNode;
|
||||
}
|
||||
|
||||
private void OnSetPosition_Click(object sender, EventArgs e)
|
||||
{
|
||||
SetAGVPositionByRfid();
|
||||
@@ -859,9 +929,66 @@ namespace AGVSimulator.Forms
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 고급 경로 결과를 기존 AGVPathResult 형태로 변환
|
||||
/// 도킹 검증 결과 확인 및 UI 표시
|
||||
/// </summary>
|
||||
private AGVPathResult ConvertToAGVPathResult(AdvancedAGVPathfinder.AdvancedPathResult advancedResult)
|
||||
private void CheckAndDisplayDockingValidation(AGVPathResult agvResult)
|
||||
{
|
||||
if (agvResult?.DockingValidation == null)
|
||||
return;
|
||||
|
||||
var validation = agvResult.DockingValidation;
|
||||
|
||||
// 도킹 검증이 필요하지 않은 경우
|
||||
if (!validation.IsValidationRequired)
|
||||
return;
|
||||
|
||||
// 도킹 검증 실패시 UI에 표시
|
||||
if (!validation.IsValid)
|
||||
{
|
||||
// 상태바에 경고 메시지 표시
|
||||
_statusLabel.Text = $"⚠️ 도킹 방향 오류: {validation.ValidationError}";
|
||||
_statusLabel.ForeColor = Color.Red;
|
||||
|
||||
// 경로는 표시하되, 목적지 노드에 X 마크 표시 요청
|
||||
_simulatorCanvas.SetDockingError(validation.TargetNodeId, true);
|
||||
|
||||
// 사용자에게 알림
|
||||
MessageBox.Show($"도킹 방향 검증 실패!\n\n" +
|
||||
$"노드: {validation.TargetNodeId} ({validation.TargetNodeType})\n" +
|
||||
$"필요 방향: {GetDirectionText(validation.RequiredDockingDirection)}\n" +
|
||||
$"계산 방향: {GetDirectionText(validation.CalculatedFinalDirection)}\n\n" +
|
||||
$"오류: {validation.ValidationError}",
|
||||
"도킹 검증 실패", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 도킹 검증 성공시 정상 표시
|
||||
if (_statusLabel.ForeColor == Color.Red)
|
||||
_statusLabel.ForeColor = Color.Black;
|
||||
_simulatorCanvas.SetDockingError(validation.TargetNodeId, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AGV 방향을 한글 텍스트로 변환
|
||||
/// </summary>
|
||||
private string GetDirectionText(AgvDirection direction)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case AgvDirection.Forward: return "전진";
|
||||
case AgvDirection.Backward: return "후진";
|
||||
case AgvDirection.Left: return "좌회전";
|
||||
case AgvDirection.Right: return "우회전";
|
||||
case AgvDirection.Stop: return "정지";
|
||||
default: return direction.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 고급 경로 결과를 기존 AGVPathResult 형태로 변환 (도킹 검증 포함)
|
||||
/// </summary>
|
||||
private AGVPathResult ConvertToAGVPathResult(AGVPathResult advancedResult, AgvDirection? currentDirection = null)
|
||||
{
|
||||
var agvResult = new AGVPathResult();
|
||||
agvResult.Success = advancedResult.Success;
|
||||
@@ -871,13 +998,25 @@ namespace AGVSimulator.Forms
|
||||
agvResult.CalculationTimeMs = advancedResult.CalculationTimeMs;
|
||||
agvResult.ExploredNodes = advancedResult.ExploredNodeCount;
|
||||
agvResult.ErrorMessage = advancedResult.ErrorMessage;
|
||||
|
||||
// 도킹 검증 수행 (AdvancedPathResult에서 이미 수행되었다면 그 결과 사용)
|
||||
if (advancedResult.DockingValidation != null && advancedResult.DockingValidation.IsValidationRequired)
|
||||
{
|
||||
agvResult.DockingValidation = advancedResult.DockingValidation;
|
||||
}
|
||||
else if (agvResult.Success && _mapNodes != null && currentDirection.HasValue)
|
||||
{
|
||||
agvResult.DockingValidation = DockingValidator.ValidateDockingDirection(agvResult, _mapNodes, currentDirection.Value);
|
||||
}
|
||||
|
||||
return agvResult;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 고급 경로 디버깅 정보 업데이트
|
||||
/// </summary>
|
||||
private void UpdateAdvancedPathDebugInfo(AdvancedAGVPathfinder.AdvancedPathResult advancedResult)
|
||||
private void UpdateAdvancedPathDebugInfo(AGVPathResult advancedResult)
|
||||
{
|
||||
if (advancedResult == null || !advancedResult.Success)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user