fix: Add motor direction parameter to magnet direction calculation in pathfinding
- Fixed critical issue in ConvertToDetailedPath where motor direction was not passed to GetRequiredMagnetDirection - Motor direction is essential for backward movement as Left/Right directions must be inverted - Modified AGVPathfinder.cs line 280 to pass currentDirection parameter - Ensures backward motor direction properly inverts magnet sensor directions feat: Add waypoint support to pathfinding system - Added FindPath overload with params string[] waypointNodeIds in AStarPathfinder - Supports sequential traversal through multiple intermediate nodes - Validates waypoints and prevents duplicates in sequence - Returns combined path result with aggregated metrics feat: Implement path result merging with DetailedPath preservation - Added CombineResults method in AStarPathfinder for intelligent path merging - Automatically deduplicates nodes when last of previous path equals first of current - Preserves DetailedPath information including motor and magnet directions - Essential for multi-segment path operations feat: Integrate magnet direction with motor direction awareness - Modified JunctionAnalyzer.GetRequiredMagnetDirection to accept AgvDirection parameter - Inverts Left/Right magnet directions when moving Backward - Properly handles motor direction context throughout pathfinding feat: Add automatic start node selection in simulator - Added SetStartNodeToCombo method to SimulatorForm - Automatically selects start node combo box when AGV position is set via RFID - Improves UI usability and workflow efficiency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,7 @@ namespace AGVSimulator.Forms
|
||||
this._startNodeCombo = new System.Windows.Forms.ComboBox();
|
||||
this.startNodeLabel = new System.Windows.Forms.Label();
|
||||
this._agvControlGroup = new System.Windows.Forms.GroupBox();
|
||||
this.btNextNode = new System.Windows.Forms.Button();
|
||||
this._setPositionButton = new System.Windows.Forms.Button();
|
||||
this._rfidTextBox = new System.Windows.Forms.TextBox();
|
||||
this._rfidLabel = new System.Windows.Forms.Label();
|
||||
@@ -108,7 +109,7 @@ namespace AGVSimulator.Forms
|
||||
this._agvInfoTitleLabel = new System.Windows.Forms.Label();
|
||||
this._liftDirectionLabel = new System.Windows.Forms.Label();
|
||||
this._motorDirectionLabel = new System.Windows.Forms.Label();
|
||||
this._pathDebugLabel = new System.Windows.Forms.Label();
|
||||
this._pathDebugLabel = new System.Windows.Forms.TextBox();
|
||||
this._menuStrip.SuspendLayout();
|
||||
this._toolStrip.SuspendLayout();
|
||||
this._statusStrip.SuspendLayout();
|
||||
@@ -495,7 +496,6 @@ namespace AGVSimulator.Forms
|
||||
this._calculatePathButton.UseVisualStyleBackColor = true;
|
||||
this._calculatePathButton.Click += new System.EventHandler(this.OnCalculatePath_Click);
|
||||
//
|
||||
//
|
||||
// _targetCalcButton
|
||||
//
|
||||
this._targetCalcButton.Location = new System.Drawing.Point(10, 148);
|
||||
@@ -552,6 +552,7 @@ namespace AGVSimulator.Forms
|
||||
//
|
||||
// _agvControlGroup
|
||||
//
|
||||
this._agvControlGroup.Controls.Add(this.btNextNode);
|
||||
this._agvControlGroup.Controls.Add(this._setPositionButton);
|
||||
this._agvControlGroup.Controls.Add(this._rfidTextBox);
|
||||
this._agvControlGroup.Controls.Add(this._rfidLabel);
|
||||
@@ -570,11 +571,21 @@ namespace AGVSimulator.Forms
|
||||
this._agvControlGroup.TabStop = false;
|
||||
this._agvControlGroup.Text = "AGV 제어";
|
||||
//
|
||||
// btNextNode
|
||||
//
|
||||
this.btNextNode.Location = new System.Drawing.Point(160, 183);
|
||||
this.btNextNode.Name = "btNextNode";
|
||||
this.btNextNode.Size = new System.Drawing.Size(60, 21);
|
||||
this.btNextNode.TabIndex = 10;
|
||||
this.btNextNode.Text = "다음";
|
||||
this.btNextNode.UseVisualStyleBackColor = true;
|
||||
this.btNextNode.Click += new System.EventHandler(this.btNextNode_Click);
|
||||
//
|
||||
// _setPositionButton
|
||||
//
|
||||
this._setPositionButton.Location = new System.Drawing.Point(160, 138);
|
||||
this._setPositionButton.Name = "_setPositionButton";
|
||||
this._setPositionButton.Size = new System.Drawing.Size(60, 67);
|
||||
this._setPositionButton.Size = new System.Drawing.Size(60, 39);
|
||||
this._setPositionButton.TabIndex = 7;
|
||||
this._setPositionButton.Text = "위치설정";
|
||||
this._setPositionButton.UseVisualStyleBackColor = true;
|
||||
@@ -667,30 +678,30 @@ namespace AGVSimulator.Forms
|
||||
// _canvasPanel
|
||||
//
|
||||
this._canvasPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this._canvasPanel.Location = new System.Drawing.Point(0, 109);
|
||||
this._canvasPanel.Location = new System.Drawing.Point(0, 129);
|
||||
this._canvasPanel.Name = "_canvasPanel";
|
||||
this._canvasPanel.Size = new System.Drawing.Size(967, 669);
|
||||
this._canvasPanel.Size = new System.Drawing.Size(967, 649);
|
||||
this._canvasPanel.TabIndex = 4;
|
||||
//
|
||||
// _agvInfoPanel
|
||||
//
|
||||
this._agvInfoPanel.BackColor = System.Drawing.Color.LightBlue;
|
||||
this._agvInfoPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this._agvInfoPanel.Controls.Add(this._pathDebugLabel);
|
||||
this._agvInfoPanel.Controls.Add(this._agvInfoTitleLabel);
|
||||
this._agvInfoPanel.Controls.Add(this._liftDirectionLabel);
|
||||
this._agvInfoPanel.Controls.Add(this._motorDirectionLabel);
|
||||
this._agvInfoPanel.Controls.Add(this._pathDebugLabel);
|
||||
this._agvInfoPanel.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this._agvInfoPanel.Location = new System.Drawing.Point(0, 49);
|
||||
this._agvInfoPanel.Name = "_agvInfoPanel";
|
||||
this._agvInfoPanel.Size = new System.Drawing.Size(967, 60);
|
||||
this._agvInfoPanel.Size = new System.Drawing.Size(967, 80);
|
||||
this._agvInfoPanel.TabIndex = 5;
|
||||
//
|
||||
// _agvInfoTitleLabel
|
||||
//
|
||||
this._agvInfoTitleLabel.AutoSize = true;
|
||||
this._agvInfoTitleLabel.Font = new System.Drawing.Font("맑은 고딕", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
||||
this._agvInfoTitleLabel.Location = new System.Drawing.Point(10, 12);
|
||||
this._agvInfoTitleLabel.Location = new System.Drawing.Point(10, 8);
|
||||
this._agvInfoTitleLabel.Name = "_agvInfoTitleLabel";
|
||||
this._agvInfoTitleLabel.Size = new System.Drawing.Size(91, 15);
|
||||
this._agvInfoTitleLabel.TabIndex = 0;
|
||||
@@ -700,7 +711,7 @@ namespace AGVSimulator.Forms
|
||||
//
|
||||
this._liftDirectionLabel.AutoSize = true;
|
||||
this._liftDirectionLabel.Font = new System.Drawing.Font("맑은 고딕", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
||||
this._liftDirectionLabel.Location = new System.Drawing.Point(120, 12);
|
||||
this._liftDirectionLabel.Location = new System.Drawing.Point(120, 8);
|
||||
this._liftDirectionLabel.Name = "_liftDirectionLabel";
|
||||
this._liftDirectionLabel.Size = new System.Drawing.Size(83, 15);
|
||||
this._liftDirectionLabel.TabIndex = 1;
|
||||
@@ -710,7 +721,7 @@ namespace AGVSimulator.Forms
|
||||
//
|
||||
this._motorDirectionLabel.AutoSize = true;
|
||||
this._motorDirectionLabel.Font = new System.Drawing.Font("맑은 고딕", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
||||
this._motorDirectionLabel.Location = new System.Drawing.Point(250, 12);
|
||||
this._motorDirectionLabel.Location = new System.Drawing.Point(250, 8);
|
||||
this._motorDirectionLabel.Name = "_motorDirectionLabel";
|
||||
this._motorDirectionLabel.Size = new System.Drawing.Size(71, 15);
|
||||
this._motorDirectionLabel.TabIndex = 2;
|
||||
@@ -718,13 +729,14 @@ namespace AGVSimulator.Forms
|
||||
//
|
||||
// _pathDebugLabel
|
||||
//
|
||||
this._pathDebugLabel.AutoSize = true;
|
||||
this._pathDebugLabel.Font = new System.Drawing.Font("맑은 고딕", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
||||
this._pathDebugLabel.ForeColor = System.Drawing.Color.DarkBlue;
|
||||
this._pathDebugLabel.BackColor = System.Drawing.Color.LightBlue;
|
||||
this._pathDebugLabel.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this._pathDebugLabel.Font = new System.Drawing.Font("굴림", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
||||
this._pathDebugLabel.Location = new System.Drawing.Point(10, 30);
|
||||
this._pathDebugLabel.Multiline = true;
|
||||
this._pathDebugLabel.Name = "_pathDebugLabel";
|
||||
this._pathDebugLabel.Size = new System.Drawing.Size(114, 15);
|
||||
this._pathDebugLabel.TabIndex = 3;
|
||||
this._pathDebugLabel.Size = new System.Drawing.Size(947, 43);
|
||||
this._pathDebugLabel.TabIndex = 4;
|
||||
this._pathDebugLabel.Text = "경로: 설정되지 않음";
|
||||
//
|
||||
// SimulatorForm
|
||||
@@ -828,6 +840,7 @@ namespace AGVSimulator.Forms
|
||||
private System.Windows.Forms.Label _liftDirectionLabel;
|
||||
private System.Windows.Forms.Label _motorDirectionLabel;
|
||||
private System.Windows.Forms.Label _agvInfoTitleLabel;
|
||||
private System.Windows.Forms.Label _pathDebugLabel;
|
||||
private System.Windows.Forms.Button btNextNode;
|
||||
private System.Windows.Forms.TextBox _pathDebugLabel;
|
||||
}
|
||||
}
|
||||
@@ -303,28 +303,17 @@ namespace AGVSimulator.Forms
|
||||
var currentDirection = selectedAGV?.CurrentDirection ?? AgvDirection.Forward;
|
||||
|
||||
// AGV의 이전 위치에서 가장 가까운 노드 찾기
|
||||
MapNode prevNode = startNode; // 기본값으로 시작 노드 사용
|
||||
if (selectedAGV != null && _mapNodes != null && _mapNodes.Count > 0)
|
||||
{
|
||||
// AGV 현재 위치에서 가장 가까운 노드 찾기
|
||||
var agvPos = selectedAGV.CurrentPosition;
|
||||
prevNode = _mapNodes.OrderBy(n =>
|
||||
Math.Sqrt(Math.Pow(n.Position.X - agvPos.X, 2) +
|
||||
Math.Pow(n.Position.Y - agvPos.Y, 2))).FirstOrDefault();
|
||||
|
||||
if (prevNode == null)
|
||||
prevNode = startNode;
|
||||
}
|
||||
var prevNode = selectedAGV?.PrevNode;
|
||||
|
||||
// 고급 경로 계획 사용 (노드 객체 직접 전달)
|
||||
var advancedResult = _advancedPathfinder.FindPath(startNode, targetNode, prevNode, currentDirection);
|
||||
var advancedResult = _advancedPathfinder.FindPath_test(startNode, targetNode, prevNode, currentDirection);
|
||||
|
||||
if (advancedResult.Success)
|
||||
{
|
||||
// 도킹 검증이 없는 경우 추가 검증 수행
|
||||
if (advancedResult.DockingValidation == null || !advancedResult.DockingValidation.IsValidationRequired)
|
||||
{
|
||||
advancedResult.DockingValidation = DockingValidator.ValidateDockingDirection(advancedResult, _mapNodes, currentDirection);
|
||||
advancedResult.DockingValidation = DockingValidator.ValidateDockingDirection(advancedResult, _mapNodes);
|
||||
}
|
||||
|
||||
_simulatorCanvas.CurrentPath = advancedResult;
|
||||
@@ -582,45 +571,77 @@ namespace AGVSimulator.Forms
|
||||
var selectedDirectionItem = _directionCombo.SelectedItem as DirectionItem;
|
||||
var selectedDirection = selectedDirectionItem?.Direction ?? AgvDirection.Forward;
|
||||
|
||||
// 콘솔 출력 (상세한 리프트 방향 계산 과정)
|
||||
//이전위치와 동일한지 체크한다.
|
||||
if(selectedAGV.CurrentNodeId == targetNode.NodeId && selectedAGV.CurrentDirection == selectedDirection)
|
||||
{
|
||||
Program.WriteLine($"이전 노드위치와 모터의 방향이 동일하여 현재 위치 변경이 취소됩니다(NODE:{targetNode.NodeId},RFID:{targetNode.RfidId},DIR:{selectedDirection})");
|
||||
return;
|
||||
}
|
||||
|
||||
// 콘솔 출력 (상세한 리프트 방향 계산 과정)
|
||||
Program.WriteLine($"[AGV-{selectedAGV.AgvId}] 위치 설정:");
|
||||
Program.WriteLine($" RFID: {rfidId} → 노드: {targetNode.NodeId}");
|
||||
Program.WriteLine($" 새로운 위치: ({targetNode.Position.X}, {targetNode.Position.Y})");
|
||||
Program.WriteLine($" 모터 방향: {selectedDirectionItem?.DisplayText ?? "전진"} ({selectedDirection})");
|
||||
Program.WriteLine($" 위치: ({targetNode.Position.X}, {targetNode.Position.Y})");
|
||||
Program.WriteLine($" 방향: {selectedDirectionItem?.DisplayText ?? "전진"} ({selectedDirection})");
|
||||
|
||||
// SetPosition 호출 전 상태
|
||||
var oldTargetPos = selectedAGV.TargetPosition;
|
||||
var oldCurrentPos = selectedAGV.CurrentPosition;
|
||||
Program.WriteLine($" [BEFORE] 현재 CurrentPosition: ({oldCurrentPos.X}, {oldCurrentPos.Y})");
|
||||
Program.WriteLine($" [BEFORE] 이전 TargetPosition: {(oldTargetPos.HasValue ? $"({oldTargetPos.Value.X}, {oldTargetPos.Value.Y})" : "None")}");
|
||||
var PrevNodeID = selectedAGV.CurrentNodeId;
|
||||
var PrevDir = selectedAGV.CurrentDirection;
|
||||
var PrevPosition = selectedAGV.CurrentPosition;
|
||||
Program.WriteLine($" [BEFORE] Node:{PrevNodeID}, Dir:{PrevDir},Pos X:{PrevPosition.X},{PrevPosition.Y}");
|
||||
|
||||
|
||||
// AGV 위치 및 방향 설정
|
||||
_simulatorCanvas.SetAGVPosition(selectedAGV.AgvId, targetNode.Position);
|
||||
_simulatorCanvas.SetAGVPosition(selectedAGV.AgvId, targetNode, selectedDirection);
|
||||
_simulatorCanvas.UpdateAGVDirection(selectedAGV.AgvId, selectedDirection);
|
||||
|
||||
// VirtualAGV 객체의 위치와 방향 업데이트
|
||||
selectedAGV.SetPosition(targetNode, targetNode.Position, selectedDirection); // 이전 위치 기억하도록
|
||||
selectedAGV.SetPosition(targetNode, selectedDirection); // 이전 위치 기억하도록
|
||||
|
||||
// SetPosition 호출 후 상태 확인 및 리프트 계산
|
||||
|
||||
var newTargetPos = selectedAGV.TargetPosition;
|
||||
var newPrevPos = selectedAGV.PrevPosition;
|
||||
var newCurrentPos = selectedAGV.CurrentPosition;
|
||||
Program.WriteLine($" [AFTER] 새로운 CurrentPosition: ({newCurrentPos.X}, {newCurrentPos.Y})");
|
||||
Program.WriteLine($" [AFTER] 새로운 TargetPosition: {(newTargetPos.HasValue ? $"({newTargetPos.Value.X}, {newTargetPos.Value.Y})" : "None")}");
|
||||
Program.WriteLine($" [AFTER] 새로운 PrevPosition: {(newPrevPos.HasValue ? $"({newPrevPos.Value.X}, {newPrevPos.Value.Y})" : "None")}");
|
||||
|
||||
// 리프트 방향 계산 과정 상세 출력
|
||||
Program.WriteLine($" [LIFT] 리프트 방향 계산:");
|
||||
CalculateLiftDirectionDetailed(selectedAGV);
|
||||
Program.WriteLine("");
|
||||
|
||||
|
||||
_statusLabel.Text = $"{selectedAGV.AgvId} 위치를 RFID '{rfidId}' (노드: {targetNode.NodeId}), 방향: {selectedDirectionItem?.DisplayText ?? "전진"}로 설정했습니다.";
|
||||
_rfidTextBox.Text = ""; // 입력 필드 초기화
|
||||
|
||||
// 시뮬레이터 캔버스의 해당 노드로 이동
|
||||
_simulatorCanvas.PanToNode(targetNode.NodeId);
|
||||
|
||||
// 시작 노드 콤보박스를 현재 위치로 자동 선택
|
||||
SetStartNodeToCombo(targetNode.NodeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 시작 노드 콤보박스에 노드를 설정
|
||||
/// </summary>
|
||||
private void SetStartNodeToCombo(string nodeId)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < _startNodeCombo.Items.Count; i++)
|
||||
{
|
||||
var item = _startNodeCombo.Items[i].ToString();
|
||||
if (item.Contains($"[{nodeId}]"))
|
||||
{
|
||||
_startNodeCombo.SelectedIndex = i;
|
||||
Program.WriteLine($"[SYSTEM] 시작 노드를 '{nodeId}'로 자동 선택했습니다.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.WriteLine($"[ERROR] 시작 노드 자동 선택 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private string GetAvailableRfidList()
|
||||
@@ -833,22 +854,22 @@ namespace AGVSimulator.Forms
|
||||
private void CalculateLiftDirectionDetailed(VirtualAGV agv)
|
||||
{
|
||||
var currentPos = agv.CurrentPosition;
|
||||
var targetPos = agv.TargetPosition;
|
||||
var prevPos = agv.PrevPosition;
|
||||
var dockingDirection = agv.DockingDirection;
|
||||
|
||||
Program.WriteLine($" 입력값: CurrentPos=({currentPos.X}, {currentPos.Y})");
|
||||
Program.WriteLine($" 입력값: TargetPos={(!targetPos.HasValue ? "None" : $"({targetPos.Value.X}, {targetPos.Value.Y})")}");
|
||||
Program.WriteLine($" 입력값: prevPos={(!prevPos.HasValue ? "None" : $"({prevPos.Value.X}, {prevPos.Value.Y})")}");
|
||||
Program.WriteLine($" 입력값: DockingDirection={dockingDirection}");
|
||||
|
||||
if (!targetPos.HasValue || targetPos.Value == currentPos)
|
||||
if (!prevPos.HasValue || prevPos.Value == currentPos)
|
||||
{
|
||||
Program.WriteLine($" 결과: 방향을 알 수 없음 (TargetPos 없음 또는 같은 위치)");
|
||||
Program.WriteLine($" 결과: 방향을 알 수 없음 (이전 위치값 없음 또는 같은 위치)");
|
||||
return;
|
||||
}
|
||||
|
||||
// 이동 방향 계산 (이전 → 현재 = TargetPos → CurrentPos)
|
||||
var dx = currentPos.X - targetPos.Value.X;
|
||||
var dy = currentPos.Y - targetPos.Value.Y;
|
||||
var dx = currentPos.X - prevPos.Value.X;
|
||||
var dy = currentPos.Y - prevPos.Value.Y;
|
||||
Program.WriteLine($" 이동 벡터: dx={dx}, dy={dy}");
|
||||
|
||||
if (Math.Abs(dx) < 1 && Math.Abs(dy) < 1)
|
||||
@@ -859,7 +880,7 @@ namespace AGVSimulator.Forms
|
||||
|
||||
// 경로 예측 기반 LiftCalculator를 사용하여 리프트 방향 계산
|
||||
var liftInfo = AGVNavigationCore.Utils.LiftCalculator.CalculateLiftInfoWithPathPrediction(
|
||||
currentPos, targetPos.Value, agv.CurrentDirection, _mapNodes);
|
||||
currentPos, prevPos.Value, agv.CurrentDirection, _mapNodes);
|
||||
|
||||
// 이동 각도 계산 (표시용)
|
||||
var moveAngleRad = Math.Atan2(dy, dx);
|
||||
@@ -883,7 +904,7 @@ namespace AGVSimulator.Forms
|
||||
private string CalculateLiftDirection(VirtualAGV agv)
|
||||
{
|
||||
var currentPos = agv.CurrentPosition;
|
||||
var targetPos = agv.TargetPosition;
|
||||
var targetPos = agv.PrevPosition;
|
||||
var dockingDirection = agv.DockingDirection;
|
||||
|
||||
if (!targetPos.HasValue || targetPos.Value == currentPos)
|
||||
@@ -1063,14 +1084,15 @@ namespace AGVSimulator.Forms
|
||||
{
|
||||
var motorInfo = advancedResult.DetailedPath[i];
|
||||
var rfidId = GetRfidByNodeId(motorInfo.NodeId);
|
||||
string motorSymbol = motorInfo.MotorDirection == AgvDirection.Forward ? "[전진]" : "[후진]";
|
||||
string motorSymbol = motorInfo.MotorDirection == AgvDirection.Forward ? "[F]" : "[B]";
|
||||
|
||||
// 마그넷 방향 표시
|
||||
if (motorInfo.MagnetDirection != MagnetDirection.Straight)
|
||||
{
|
||||
string magnetSymbol = motorInfo.MagnetDirection == MagnetDirection.Left ? "[←]" : "[→]";
|
||||
string magnetSymbol = motorInfo.MagnetDirection == MagnetDirection.Left ? "[L]" : "[R]";
|
||||
motorSymbol += magnetSymbol;
|
||||
}
|
||||
else motorSymbol += "[S]";
|
||||
|
||||
// 특수 동작 표시
|
||||
if (motorInfo.RequiresSpecialAction)
|
||||
@@ -1084,10 +1106,10 @@ namespace AGVSimulator.Forms
|
||||
string pathString = string.Join(" → ", pathWithDetails);
|
||||
|
||||
// UI에 표시 (길이 제한)
|
||||
if (pathString.Length > 100)
|
||||
{
|
||||
pathString = pathString.Substring(0, 97) + "...";
|
||||
}
|
||||
//if (pathString.Length > 100)
|
||||
//{
|
||||
// pathString = pathString.Substring(0, 97) + "...";
|
||||
//}
|
||||
|
||||
// 통계 정보
|
||||
var forwardCount = advancedResult.DetailedPath.Count(m => m.MotorDirection == AgvDirection.Forward);
|
||||
@@ -1101,89 +1123,7 @@ namespace AGVSimulator.Forms
|
||||
_pathDebugLabel.Text = $"고급경로: {pathString} (총 {advancedResult.DetailedPath.Count}개 노드, {advancedResult.TotalDistance:F1}px, {stats})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 경로 디버깅 정보 업데이트 (RFID 값 표시, 모터방향 정보 포함)
|
||||
/// </summary>
|
||||
private void UpdatePathDebugInfo(AGVPathResult agvResult)
|
||||
{
|
||||
if (agvResult == null || !agvResult.Success)
|
||||
{
|
||||
_pathDebugLabel.Text = "경로: 설정되지 않음";
|
||||
return;
|
||||
}
|
||||
|
||||
// 노드 ID를 RFID로 변환한 경로 생성
|
||||
var pathWithRfid = agvResult.Path.Select(nodeId => GetRfidByNodeId(nodeId)).ToList();
|
||||
|
||||
// 콘솔 디버그 정보 출력 (RFID 기준)
|
||||
Program.WriteLine($"[DEBUG] 경로 계산 완료:");
|
||||
Program.WriteLine($" 전체 경로 (RFID): [{string.Join(" → ", pathWithRfid)}]");
|
||||
Program.WriteLine($" 전체 경로 (NodeID): [{string.Join(" → ", agvResult.Path)}]");
|
||||
Program.WriteLine($" 경로 노드 수: {agvResult.Path.Count}");
|
||||
if (agvResult.NodeMotorInfos != null)
|
||||
{
|
||||
Program.WriteLine($" 모터정보 수: {agvResult.NodeMotorInfos.Count}");
|
||||
for (int i = 0; i < agvResult.NodeMotorInfos.Count; i++)
|
||||
{
|
||||
var info = agvResult.NodeMotorInfos[i];
|
||||
var rfidId = GetRfidByNodeId(info.NodeId);
|
||||
var nextRfidId = info.NextNodeId != null ? GetRfidByNodeId(info.NextNodeId) : "END";
|
||||
|
||||
var flags = new List<string>();
|
||||
if (info.CanRotate) flags.Add("회전가능");
|
||||
if (info.IsDirectionChangePoint) flags.Add("방향전환");
|
||||
if (info.RequiresSpecialAction) flags.Add($"특수동작:{info.SpecialActionDescription}");
|
||||
|
||||
var flagsStr = flags.Count > 0 ? $" [{string.Join(", ", flags)}]" : "";
|
||||
Program.WriteLine($" {i}: {rfidId}({info.NodeId}) → {info.MotorDirection} → {nextRfidId}{flagsStr}");
|
||||
}
|
||||
}
|
||||
|
||||
// 모터방향 정보가 있다면 이를 포함하여 경로 문자열 구성 (RFID 기준)
|
||||
string pathString;
|
||||
if (agvResult.NodeMotorInfos != null && agvResult.NodeMotorInfos.Count > 0)
|
||||
{
|
||||
// RFID별 모터방향 정보를 포함한 경로 문자열 생성
|
||||
var pathWithMotorInfo = new List<string>();
|
||||
for (int i = 0; i < agvResult.NodeMotorInfos.Count; i++)
|
||||
{
|
||||
var motorInfo = agvResult.NodeMotorInfos[i];
|
||||
var rfidId = GetRfidByNodeId(motorInfo.NodeId);
|
||||
string motorSymbol = motorInfo.MotorDirection == AgvDirection.Forward ? "[전진]" : "[후진]";
|
||||
|
||||
// 특수 동작 표시 추가
|
||||
if (motorInfo.RequiresSpecialAction)
|
||||
motorSymbol += "[🔄]";
|
||||
else if (motorInfo.IsDirectionChangePoint && motorInfo.CanRotate)
|
||||
motorSymbol += "[↻]";
|
||||
|
||||
pathWithMotorInfo.Add($"{rfidId}{motorSymbol}");
|
||||
}
|
||||
pathString = string.Join(" → ", pathWithMotorInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 기본 경로 정보만 표시 (RFID 기준)
|
||||
pathString = string.Join(" → ", pathWithRfid);
|
||||
}
|
||||
|
||||
// UI에 표시 (길이 제한)
|
||||
if (pathString.Length > 120)
|
||||
{
|
||||
pathString = pathString.Substring(0, 117) + "...";
|
||||
}
|
||||
|
||||
// 모터방향 통계 추가
|
||||
string motorStats = "";
|
||||
if (agvResult.NodeMotorInfos != null && agvResult.NodeMotorInfos.Count > 0)
|
||||
{
|
||||
var forwardCount = agvResult.NodeMotorInfos.Count(m => m.MotorDirection == AgvDirection.Forward);
|
||||
var backwardCount = agvResult.NodeMotorInfos.Count(m => m.MotorDirection == AgvDirection.Backward);
|
||||
motorStats = $", 전진: {forwardCount}, 후진: {backwardCount}";
|
||||
}
|
||||
|
||||
_pathDebugLabel.Text = $"경로: {pathString} (총 {agvResult.Path.Count}개 노드, {agvResult.TotalDistance:F1}px{motorStats})";
|
||||
}
|
||||
|
||||
|
||||
private void OnReloadMap_Click(object sender, EventArgs e)
|
||||
{
|
||||
@@ -1294,6 +1234,27 @@ namespace AGVSimulator.Forms
|
||||
|
||||
_statusLabel.Text = "초기화 완료";
|
||||
}
|
||||
|
||||
private void btNextNode_Click(object sender, EventArgs e)
|
||||
{
|
||||
//get next node
|
||||
|
||||
// 선택된 AGV 확인
|
||||
var selectedAGV = _agvListCombo.SelectedItem as VirtualAGV;
|
||||
if (selectedAGV == null)
|
||||
{
|
||||
MessageBox.Show("먼저 AGV를 선택해주세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
// 선택된 방향 확인
|
||||
var selectedDirectionItem = _directionCombo.SelectedItem as DirectionItem;
|
||||
var selectedDirection = selectedDirectionItem?.Direction ?? AgvDirection.Forward;
|
||||
|
||||
var nextNode = selectedAGV.GetNextNodeId(selectedDirection, this._mapNodes);
|
||||
MessageBox.Show($"Node:{nextNode.NodeId},RFID:{nextNode.RfidId}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user