feat: 시뮬레이터에 목적지 선택 기능 추가

- 목적지 선택 버튼을 경로 계산 그룹에 추가
- 목적지 선택 모드 상태 관리 구현 (버튼 색상 변경)
- UnifiedAGVCanvas에 SelectTarget EditMode 및 TargetNodeSelected 이벤트 추가
- 노드 클릭 시 목적지 자동 설정 및 경로 계산 기능
- 시뮬레이션 중 빠른 목적지 변경 및 테스트 지원

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ChiKyun Kim
2025-09-15 17:33:16 +09:00
parent 073ced8690
commit 06deda2956
4 changed files with 89 additions and 2 deletions

View File

@@ -63,6 +63,17 @@ namespace AGVNavigationCore.Controls
if (e.Button == MouseButtons.Left) if (e.Button == MouseButtons.Left)
{ {
// 목적지 선택 모드 처리 (시뮬레이터)
if (_editMode == EditMode.SelectTarget)
{
var hitNode = GetNodeAt(worldPoint);
if (hitNode != null)
{
TargetNodeSelected?.Invoke(this, hitNode);
return;
}
}
if (_canvasMode == CanvasMode.Edit && _editMode == EditMode.Move) if (_canvasMode == CanvasMode.Edit && _editMode == EditMode.Move)
{ {
var hitNode = GetNodeAt(worldPoint); var hitNode = GetNodeAt(worldPoint);

View File

@@ -50,7 +50,8 @@ namespace AGVNavigationCore.Controls
Delete, // 삭제 모드 Delete, // 삭제 모드
DeleteConnection, // 연결 삭제 모드 DeleteConnection, // 연결 삭제 모드
AddLabel, // 라벨 추가 모드 AddLabel, // 라벨 추가 모드
AddImage // 이미지 추가 모드 AddImage, // 이미지 추가 모드
SelectTarget // 목적지 선택 모드 (시뮬레이터 전용)
} }
#endregion #endregion
@@ -145,6 +146,9 @@ namespace AGVNavigationCore.Controls
public event EventHandler<IAGV> AGVSelected; public event EventHandler<IAGV> AGVSelected;
public event EventHandler<IAGV> AGVStateChanged; public event EventHandler<IAGV> AGVStateChanged;
// 시뮬레이터 이벤트
public event EventHandler<MapNode> TargetNodeSelected;
#endregion #endregion
#region Properties #region Properties

View File

@@ -86,6 +86,7 @@ namespace AGVSimulator.Forms
this._clearPathButton = new System.Windows.Forms.Button(); this._clearPathButton = new System.Windows.Forms.Button();
this._startPathButton = new System.Windows.Forms.Button(); this._startPathButton = new System.Windows.Forms.Button();
this._calculatePathButton = new System.Windows.Forms.Button(); this._calculatePathButton = new System.Windows.Forms.Button();
this._selectTargetButton = new System.Windows.Forms.Button();
this._avoidRotationCheckBox = new System.Windows.Forms.CheckBox(); this._avoidRotationCheckBox = new System.Windows.Forms.CheckBox();
this._targetNodeCombo = new System.Windows.Forms.ComboBox(); this._targetNodeCombo = new System.Windows.Forms.ComboBox();
this.targetNodeLabel = new System.Windows.Forms.Label(); this.targetNodeLabel = new System.Windows.Forms.Label();
@@ -450,6 +451,7 @@ namespace AGVSimulator.Forms
this._pathGroup.Controls.Add(this._clearPathButton); this._pathGroup.Controls.Add(this._clearPathButton);
this._pathGroup.Controls.Add(this._startPathButton); this._pathGroup.Controls.Add(this._startPathButton);
this._pathGroup.Controls.Add(this._calculatePathButton); this._pathGroup.Controls.Add(this._calculatePathButton);
this._pathGroup.Controls.Add(this._selectTargetButton);
this._pathGroup.Controls.Add(this._avoidRotationCheckBox); this._pathGroup.Controls.Add(this._avoidRotationCheckBox);
this._pathGroup.Controls.Add(this._targetNodeCombo); this._pathGroup.Controls.Add(this._targetNodeCombo);
this._pathGroup.Controls.Add(this.targetNodeLabel); this._pathGroup.Controls.Add(this.targetNodeLabel);
@@ -492,7 +494,17 @@ namespace AGVSimulator.Forms
this._calculatePathButton.Text = "경로 계산"; this._calculatePathButton.Text = "경로 계산";
this._calculatePathButton.UseVisualStyleBackColor = true; this._calculatePathButton.UseVisualStyleBackColor = true;
this._calculatePathButton.Click += new System.EventHandler(this.OnCalculatePath_Click); 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);
//
// _avoidRotationCheckBox // _avoidRotationCheckBox
// //
this._avoidRotationCheckBox.AutoSize = true; this._avoidRotationCheckBox.AutoSize = true;
@@ -793,6 +805,7 @@ namespace AGVSimulator.Forms
private System.Windows.Forms.Button _calculatePathButton; private System.Windows.Forms.Button _calculatePathButton;
private System.Windows.Forms.Button _startPathButton; private System.Windows.Forms.Button _startPathButton;
private System.Windows.Forms.Button _clearPathButton; private System.Windows.Forms.Button _clearPathButton;
private System.Windows.Forms.Button _selectTargetButton;
private System.Windows.Forms.CheckBox _avoidRotationCheckBox; private System.Windows.Forms.CheckBox _avoidRotationCheckBox;
private System.Windows.Forms.GroupBox _statusGroup; private System.Windows.Forms.GroupBox _statusGroup;
private System.Windows.Forms.Label _simulationStatusLabel; private System.Windows.Forms.Label _simulationStatusLabel;

View File

@@ -31,6 +31,7 @@ namespace AGVSimulator.Forms
private Timer _simulationTimer; private Timer _simulationTimer;
private SimulatorConfig _config; private SimulatorConfig _config;
private string _currentMapFilePath; private string _currentMapFilePath;
private bool _isSelectingTarget; // 목적지 선택 모드 상태
// UI Controls - Designer에서 생성됨 // UI Controls - Designer에서 생성됨
@@ -96,6 +97,9 @@ namespace AGVSimulator.Forms
_simulatorCanvas.Dock = DockStyle.Fill; _simulatorCanvas.Dock = DockStyle.Fill;
_simulatorCanvas.Mode = UnifiedAGVCanvas.CanvasMode.ViewOnly; _simulatorCanvas.Mode = UnifiedAGVCanvas.CanvasMode.ViewOnly;
// 목적지 선택 이벤트 구독
_simulatorCanvas.TargetNodeSelected += OnTargetNodeSelected;
_canvasPanel.Controls.Add(_simulatorCanvas); _canvasPanel.Controls.Add(_simulatorCanvas);
} }
@@ -370,6 +374,61 @@ namespace AGVSimulator.Forms
_statusLabel.Text = "경로 지움"; _statusLabel.Text = "경로 지움";
} }
private void OnSelectTarget_Click(object sender, EventArgs e)
{
if (_isSelectingTarget)
{
// 목적지 선택 모드 해제
_isSelectingTarget = false;
_selectTargetButton.Text = "목적지 선택";
_selectTargetButton.BackColor = SystemColors.Control;
_simulatorCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Select;
_statusLabel.Text = "목적지 선택 모드 해제";
}
else
{
// 목적지 선택 모드 활성화
_isSelectingTarget = true;
_selectTargetButton.Text = "선택 취소";
_selectTargetButton.BackColor = Color.LightBlue;
_simulatorCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.SelectTarget;
_statusLabel.Text = "맵에서 목적지 노드를 클릭하세요";
}
}
private void OnTargetNodeSelected(object sender, MapNode selectedNode)
{
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++)
{
var item = _targetNodeCombo.Items[i].ToString();
if (item.Contains($"[{selectedNode.NodeId}]"))
{
_targetNodeCombo.SelectedIndex = i;
break;
}
}
_statusLabel.Text = $"목적지 설정: {displayText}";
// 자동으로 경로 계산 수행
OnCalculatePath_Click(this, EventArgs.Empty);
}
catch (Exception ex)
{
_statusLabel.Text = $"목적지 선택 오류: {ex.Message}";
}
}
private void OnSetPosition_Click(object sender, EventArgs e) private void OnSetPosition_Click(object sender, EventArgs e)
{ {
SetAGVPositionByRfid(); SetAGVPositionByRfid();