..
This commit is contained in:
@@ -78,6 +78,8 @@ namespace AGVNavigationCore.Controls
|
||||
// 노드 라벨 그리기 (가장 나중 - 선이 텍스트를 가리지 않게)
|
||||
DrawNodeLabels(g);
|
||||
DrawLabels(g); // 추가: 텍스트 라벨
|
||||
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -93,6 +95,12 @@ namespace AGVNavigationCore.Controls
|
||||
{
|
||||
DrawSyncScreen(g);
|
||||
}
|
||||
|
||||
//예측문자는 디버깅시에만 표시한다.
|
||||
if (string.IsNullOrEmpty(PredictMessage) == false && System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
g.DrawString(this.PredictMessage, this.Font, Brushes.White, 10, 10);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSyncScreen(Graphics g)
|
||||
|
||||
@@ -478,6 +478,17 @@ namespace AGVNavigationCore.Controls
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 상세경로가 설정되어있는가?
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool HasPath()
|
||||
{
|
||||
if (_currentPath == null) return false;
|
||||
if (_currentPath.DetailedPath == null) return false;
|
||||
return _currentPath.DetailedPath.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 경로 목록 (다중 AGV 경로 표시용)
|
||||
/// </summary>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace AGVNavigationCore.Models
|
||||
[Description("표시할 텍스트입니다.")]
|
||||
public string Text { get; set; } = "";
|
||||
|
||||
public StationType StationType { get; set; }
|
||||
public StationType StationType { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public bool CanDocking
|
||||
@@ -103,7 +103,7 @@ namespace AGVNavigationCore.Models
|
||||
{
|
||||
Type = NodeType.Normal;
|
||||
}
|
||||
|
||||
|
||||
public MapNode(string nodeId, Point position, StationType type) : base(nodeId, position)
|
||||
{
|
||||
Type = NodeType.Normal;
|
||||
@@ -152,6 +152,18 @@ namespace AGVNavigationCore.Models
|
||||
return $"RFID:{RfidId}(NODE:{Id}): AS:{AliasName} ({Type}) at ({Position.X}, {Position.Y})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RFID(*ID)
|
||||
/// </summary>
|
||||
public string ID2
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasRfid()) return $"{this.RfidId:0000}(*{this.Id})";
|
||||
else return $"(*{this.Id})";
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNavigationNode()
|
||||
{
|
||||
// 이제 MapNode는 항상 내비게이션 노드임 (Label, Image 분리됨)
|
||||
|
||||
@@ -40,13 +40,12 @@ namespace AGVNavigationCore.Models
|
||||
[JsonIgnore]
|
||||
public bool IsSelected { get; set; } = false;
|
||||
|
||||
|
||||
|
||||
[Browsable(false)]
|
||||
[JsonIgnore]
|
||||
public bool IsHovered { get; set; } = false;
|
||||
|
||||
|
||||
|
||||
|
||||
public NodeBase()
|
||||
{
|
||||
|
||||
@@ -83,9 +83,9 @@ namespace AGVNavigationCore.Models
|
||||
|
||||
// 에뮬레이터용 추가 속성
|
||||
public double Angle { get; set; } = 0; // 0 = Right, 90 = Down, 180 = Left, 270 = Up (Standard Math)
|
||||
// But AGV Direction: Forward usually means "Front of AGV".
|
||||
// Let's assume Angle is the orientation of the AGV in degrees.
|
||||
|
||||
// But AGV Direction: Forward usually means "Front of AGV".
|
||||
// Let's assume Angle is the orientation of the AGV in degrees.
|
||||
|
||||
public bool IsStopMarkOn { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
@@ -143,6 +143,11 @@ namespace AGVNavigationCore.Models
|
||||
/// </summary>
|
||||
public AGVPathResult CurrentPath => _currentPath;
|
||||
|
||||
public void ClearPath()
|
||||
{
|
||||
_currentPath = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 노드 ID
|
||||
/// </summary>
|
||||
@@ -153,6 +158,18 @@ namespace AGVNavigationCore.Models
|
||||
/// </summary>
|
||||
public string CurrentNodeId => _currentNode?.Id;
|
||||
|
||||
/// <summary>
|
||||
/// 현재노드의 RFID(id)값을 표시합니다 없는경우 (X)가 표시됩니다
|
||||
/// </summary>
|
||||
public string CurrentNodeID2
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_currentNode == null) return "(X)";
|
||||
return _currentNode.ID2;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이전 위치
|
||||
/// </summary>
|
||||
@@ -282,7 +299,7 @@ namespace AGVNavigationCore.Models
|
||||
if (_currentNode == null) return false;
|
||||
if (_currentPath == null) return false;
|
||||
var 미완료된처음노드 = _currentPath.DetailedPath.Where(t => t.IsPass == false).OrderBy(t => t.seq).FirstOrDefault();
|
||||
if (미완료된처음노드 == null) return false;
|
||||
if (미완료된처음노드 == null) return false;
|
||||
미완료된처음노드.IsPass = true;
|
||||
Console.WriteLine($"미완료된처음노드를 true러치합니다");
|
||||
return true;
|
||||
@@ -295,6 +312,7 @@ namespace AGVNavigationCore.Models
|
||||
/// <returns>다음에 수행할 모터/마그넷/속도 명령</returns>
|
||||
public AGVCommand Predict()
|
||||
{
|
||||
|
||||
// 1. 위치 미확정 상태 (RFID 2개 미만 감지)
|
||||
if (!_isPositionConfirmed)
|
||||
{
|
||||
@@ -311,12 +329,17 @@ namespace AGVNavigationCore.Models
|
||||
// 2. 위치 확정됨 + 경로 없음 → 정지 (목적지 미설정 상태)
|
||||
if (_currentPath == null || (_currentPath.DetailedPath?.Count ?? 0) < 1)
|
||||
{
|
||||
var curpos = "알수없음";
|
||||
if (_currentNode != null)
|
||||
{
|
||||
curpos = _currentNode.HasRfid() ? $"RFID #{_currentNode.RfidId} (*{_currentNode.Id})" : $"(*{_currentNode.Id})";
|
||||
}
|
||||
return new AGVCommand(
|
||||
MotorCommand.Stop,
|
||||
MagnetPosition.S,
|
||||
SpeedLevel.L,
|
||||
eAGVCommandReason.NoPath,
|
||||
$"위치 확정 완료 (목적지 미설정) - 현재:{_currentNode?.Id ?? "알수없음"}"
|
||||
$"(목적지 미설정) - 현재={curpos}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -325,6 +348,9 @@ namespace AGVNavigationCore.Models
|
||||
if (_currentPath.DetailedPath.Where(t => t.seq < lastNode.seq && t.IsPass == false).Any() == false)
|
||||
{
|
||||
// 마지막 노드에 도착했는지 확인 (현재 노드가 마지막 노드와 같은지)
|
||||
|
||||
|
||||
|
||||
if (_currentNode != null && _currentNode.Id == lastNode.NodeId)
|
||||
{
|
||||
if (lastNode.IsPass) //이미완료되었다.
|
||||
@@ -334,7 +360,7 @@ namespace AGVNavigationCore.Models
|
||||
MagnetPosition.S,
|
||||
SpeedLevel.L,
|
||||
eAGVCommandReason.Complete,
|
||||
$"목적지 도착 - 최종:{_currentNode?.Id ?? "알수없음"}"
|
||||
$"목적지 도착 - 최종:{CurrentNodeID2}"
|
||||
);
|
||||
}
|
||||
else
|
||||
@@ -345,7 +371,7 @@ namespace AGVNavigationCore.Models
|
||||
MagnetPosition.S,
|
||||
SpeedLevel.L,
|
||||
eAGVCommandReason.MarkStop,
|
||||
$"목적지 도착 전(MarkStop) - 최종:{_currentNode?.Id ?? "알수없음"}"
|
||||
$"목적지 도착 전(MarkStop) - 최종:{CurrentNodeID2}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -361,7 +387,7 @@ namespace AGVNavigationCore.Models
|
||||
MagnetPosition.S,
|
||||
SpeedLevel.L,
|
||||
eAGVCommandReason.PathOut,
|
||||
$"(재탐색요청)경로이탈 현재위치:{_currentNode.Id}"
|
||||
$"(재탐색요청)경로이탈 현재위치:{CurrentNodeID2}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -403,6 +429,18 @@ namespace AGVNavigationCore.Models
|
||||
|
||||
#region Public Methods - 경로 실행
|
||||
|
||||
/// <summary>
|
||||
/// 경로가 설정되어있는지?
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool HasPath()
|
||||
{
|
||||
if (_currentPath == null) return false;
|
||||
if (_currentPath.DetailedPath == null) return false;
|
||||
return _currentPath.DetailedPath.Any();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 경로 설정 (실제 AGV 및 시뮬레이터에서 사용)
|
||||
/// </summary>
|
||||
@@ -411,6 +449,9 @@ namespace AGVNavigationCore.Models
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
_currentPath = null;
|
||||
_remainingNodes.Clear();// = null;
|
||||
_currentNodeIndex = 0;
|
||||
OnError("경로가 null입니다.");
|
||||
return;
|
||||
}
|
||||
@@ -612,7 +653,7 @@ namespace AGVNavigationCore.Models
|
||||
PositionChanged?.Invoke(this, (_currentPosition, _currentDirection, _currentNode));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
}
|
||||
return Path?.Select(n => n.Id).ToList() ?? new List<string>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 문자열 표현
|
||||
/// </summary>
|
||||
|
||||
@@ -123,6 +123,8 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
if (RequiresSpecialAction)
|
||||
result += $" [특수동작:{SpecialActionDescription}]";
|
||||
|
||||
if (IsPass) result += "(O)";
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user