"refactor:Improve-map-loading-and-use-canvas-nodes"
This commit is contained in:
@@ -108,7 +108,6 @@ namespace AGVSimulator.Forms
|
||||
}
|
||||
|
||||
private UnifiedAGVCanvas _simulatorCanvas;
|
||||
private List<MapNode> _mapNodes;
|
||||
private AGVPathfinder _advancedPathfinder;
|
||||
private List<VirtualAGV> _agvList;
|
||||
private SimulationState _simulationState;
|
||||
@@ -158,7 +157,7 @@ namespace AGVSimulator.Forms
|
||||
_config = SimulatorConfig.Load();
|
||||
|
||||
// 데이터 초기화
|
||||
_mapNodes = new List<MapNode>();
|
||||
|
||||
_agvList = new List<VirtualAGV>();
|
||||
_simulationState = new SimulationState();
|
||||
_currentMapFilePath = string.Empty;
|
||||
@@ -305,14 +304,14 @@ namespace AGVSimulator.Forms
|
||||
|
||||
private void OnAddAGV_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_mapNodes == null || _mapNodes.Count == 0)
|
||||
if (_simulatorCanvas.Nodes == null || _simulatorCanvas.Nodes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("먼저 맵을 로드해주세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
var agvId = $"AGV{_agvList.Count + 1:D2}";
|
||||
var startPosition = _mapNodes.First().Position; // 첫 번째 노드에서 시작
|
||||
var startPosition = _simulatorCanvas.Nodes.First().Position; // 첫 번째 노드에서 시작
|
||||
|
||||
var newAGV = new VirtualAGV(agvId, startPosition);
|
||||
_agvList.Add(newAGV);
|
||||
@@ -396,7 +395,7 @@ namespace AGVSimulator.Forms
|
||||
|
||||
if (_advancedPathfinder == null)
|
||||
{
|
||||
_advancedPathfinder = new AGVPathfinder(_mapNodes);
|
||||
_advancedPathfinder = new AGVPathfinder(_simulatorCanvas.Nodes);
|
||||
}
|
||||
|
||||
// 현재 AGV 방향 가져오기
|
||||
@@ -420,11 +419,11 @@ namespace AGVSimulator.Forms
|
||||
// 도킹 검증이 없는 경우 추가 검증 수행
|
||||
if (advancedResult.DockingValidation == null || !advancedResult.DockingValidation.IsValidationRequired)
|
||||
{
|
||||
advancedResult.DockingValidation = DockingValidator.ValidateDockingDirection(advancedResult, _mapNodes);
|
||||
advancedResult.DockingValidation = DockingValidator.ValidateDockingDirection(advancedResult, _simulatorCanvas.Nodes);
|
||||
}
|
||||
|
||||
//마지막대상이 버퍼라면 시퀀스처리를 해야한다
|
||||
if(targetNode.Type == NodeType.Buffer)
|
||||
if(targetNode.StationType == StationType.Buffer)
|
||||
{
|
||||
var lastDetailPath = advancedResult.DetailedPath.Last();
|
||||
if(lastDetailPath.NodeId == targetNode.Id) //마지막노드 재확인
|
||||
@@ -598,13 +597,13 @@ namespace AGVSimulator.Forms
|
||||
/// </summary>
|
||||
private MapNode FindClosestNode(Point position)
|
||||
{
|
||||
if (_mapNodes == null || _mapNodes.Count == 0)
|
||||
if (_simulatorCanvas.Nodes == null || _simulatorCanvas.Nodes.Count == 0)
|
||||
return null;
|
||||
|
||||
MapNode closestNode = null;
|
||||
double closestDistance = double.MaxValue;
|
||||
|
||||
foreach (var node in _mapNodes)
|
||||
foreach (var node in _simulatorCanvas.Nodes)
|
||||
{
|
||||
var distance = Math.Sqrt(Math.Pow(node.Position.X - position.X, 2) +
|
||||
Math.Pow(node.Position.Y - position.Y, 2));
|
||||
@@ -645,7 +644,7 @@ namespace AGVSimulator.Forms
|
||||
var currentDirection = directionItem?.Direction ?? AgvDirection.Forward;
|
||||
|
||||
// 중복 RFID 확인
|
||||
var existingNode = _mapNodes?.FirstOrDefault(n => n.RfidId.Equals(rfidId, StringComparison.OrdinalIgnoreCase));
|
||||
var existingNode = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.RfidId.Equals(rfidId, StringComparison.OrdinalIgnoreCase));
|
||||
if (existingNode != null)
|
||||
{
|
||||
// 이미 존재하는 노드로 이동
|
||||
@@ -723,15 +722,14 @@ namespace AGVSimulator.Forms
|
||||
Id = newNodeId,
|
||||
RfidId = rfidId,
|
||||
Position = new Point(newX, newY),
|
||||
Type = NodeType.Normal,
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
// 맵에 추가
|
||||
if (_mapNodes == null)
|
||||
_mapNodes = new List<MapNode>();
|
||||
if (_simulatorCanvas.Nodes == null)
|
||||
_simulatorCanvas.Nodes = new List<MapNode>();
|
||||
|
||||
_mapNodes.Add(newNode);
|
||||
_simulatorCanvas.Nodes.Add(newNode);
|
||||
|
||||
// 이전 노드와 연결 생성
|
||||
if (_lastScannedNode != null)
|
||||
@@ -748,7 +746,7 @@ namespace AGVSimulator.Forms
|
||||
selectedAGV.SetPosition(newNode, currentDirection);
|
||||
|
||||
// 캔버스 업데이트
|
||||
_simulatorCanvas.Nodes = _mapNodes;
|
||||
_simulatorCanvas.Nodes = _simulatorCanvas.Nodes;
|
||||
|
||||
// 화면을 새 노드 위치로 이동
|
||||
_simulatorCanvas.PanToNode(newNode.Id);
|
||||
@@ -763,7 +761,7 @@ namespace AGVSimulator.Forms
|
||||
// UI 업데이트
|
||||
UpdateNodeComboBoxes();
|
||||
|
||||
_statusLabel.Text = $"노드 생성: {newNode.Id} (RFID: {rfidId}) [{GetDirectionSymbol(currentDirection)}] - 총 {_mapNodes.Count}개";
|
||||
_statusLabel.Text = $"노드 생성: {newNode.Id} (RFID: {rfidId}) [{GetDirectionSymbol(currentDirection)}] - 총 {_simulatorCanvas.Nodes.Count}개";
|
||||
_rfidTextBox.Text = "";
|
||||
|
||||
Program.WriteLine($"[맵 스캔] 노드 생성 완료: {newNode.Id} (RFID: {rfidId}) at ({newX}, {newY}), 방향: {currentDirection}");
|
||||
@@ -864,7 +862,7 @@ namespace AGVSimulator.Forms
|
||||
}
|
||||
|
||||
// RFID에 해당하는 노드 직접 찾기
|
||||
var targetNode = _mapNodes?.FirstOrDefault(n => n.RfidId.Equals(rfidId, StringComparison.OrdinalIgnoreCase));
|
||||
var targetNode = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.RfidId.Equals(rfidId, StringComparison.OrdinalIgnoreCase));
|
||||
if (targetNode == null)
|
||||
{
|
||||
MessageBox.Show($"RFID '{rfidId}'에 해당하는 노드를 찾을 수 없습니다.\n\n사용 가능한 RFID 목록:\n{GetAvailableRfidList()}",
|
||||
@@ -947,10 +945,10 @@ namespace AGVSimulator.Forms
|
||||
|
||||
private string GetAvailableRfidList()
|
||||
{
|
||||
if (_mapNodes == null || _mapNodes.Count == 0)
|
||||
if (_simulatorCanvas.Nodes == null || _simulatorCanvas.Nodes.Count == 0)
|
||||
return "매핑된 RFID가 없습니다.";
|
||||
|
||||
var nodesWithRfid = _mapNodes.Where(n => n.HasRfid()).ToList();
|
||||
var nodesWithRfid = _simulatorCanvas.Nodes.Where(n => n.HasRfid()).ToList();
|
||||
if (nodesWithRfid.Count == 0)
|
||||
return "RFID가 할당된 노드가 없습니다.";
|
||||
|
||||
@@ -977,13 +975,13 @@ namespace AGVSimulator.Forms
|
||||
{
|
||||
Console.WriteLine($"Map File Load : {filePath}");
|
||||
|
||||
_mapNodes = result.Nodes;
|
||||
_simulatorCanvas.Nodes = result.Nodes;
|
||||
_currentMapFilePath = filePath;
|
||||
|
||||
// RFID 자동 할당 제거 - 에디터에서 설정한 값 그대로 사용
|
||||
|
||||
// 시뮬레이터 캔버스에 맵 설정
|
||||
_simulatorCanvas.Nodes = _mapNodes;
|
||||
_simulatorCanvas.SetMapLoadResult(result);//.Nodes = _simulatorCanvas.Nodes;
|
||||
|
||||
// 맵 설정 적용 (배경색, 그리드 표시)
|
||||
if (result.Settings != null)
|
||||
@@ -1051,9 +1049,9 @@ namespace AGVSimulator.Forms
|
||||
_startNodeCombo.Items.Clear();
|
||||
_targetNodeCombo.Items.Clear();
|
||||
|
||||
if (_mapNodes != null)
|
||||
if (_simulatorCanvas.Nodes != null)
|
||||
{
|
||||
foreach (var node in _mapNodes)
|
||||
foreach (var node in _simulatorCanvas.Nodes)
|
||||
{
|
||||
if (node.IsActive && node.HasRfid())
|
||||
{
|
||||
@@ -1109,7 +1107,7 @@ namespace AGVSimulator.Forms
|
||||
|
||||
// RFID 위치 설정 관련
|
||||
var hasSelectedAGV = _agvListCombo.SelectedItem != null;
|
||||
var hasRfidNodes = _mapNodes != null && _mapNodes.Any(n => n.HasRfid());
|
||||
var hasRfidNodes = _simulatorCanvas.Nodes != null && _simulatorCanvas.Nodes.Any(n => n.HasRfid());
|
||||
|
||||
_setPositionButton.Enabled = hasSelectedAGV && hasRfidNodes;
|
||||
_rfidTextBox.Enabled = hasSelectedAGV && hasRfidNodes;
|
||||
@@ -1182,7 +1180,7 @@ namespace AGVSimulator.Forms
|
||||
|
||||
// 경로 예측 기반 LiftCalculator를 사용하여 리프트 방향 계산
|
||||
var liftInfo = AGVNavigationCore.Utils.LiftCalculator.CalculateLiftInfoWithPathPrediction(
|
||||
currentPos, prevPos.Value, agv.CurrentDirection, _mapNodes);
|
||||
currentPos, prevPos.Value, agv.CurrentDirection, _simulatorCanvas.Nodes);
|
||||
|
||||
// 이동 각도 계산 (표시용)
|
||||
var moveAngleRad = Math.Atan2(dy, dx);
|
||||
@@ -1226,7 +1224,7 @@ namespace AGVSimulator.Forms
|
||||
|
||||
// 경로 예측 기반 LiftCalculator를 사용하여 리프트 방향 계산
|
||||
var liftInfo = AGVNavigationCore.Utils.LiftCalculator.CalculateLiftInfoWithPathPrediction(
|
||||
currentPos, targetPos.Value, agv.CurrentDirection, _mapNodes);
|
||||
currentPos, targetPos.Value, agv.CurrentDirection, _simulatorCanvas.Nodes);
|
||||
|
||||
// 도킹 방향 정보 추가
|
||||
string dockingInfo = dockingDirection == DockingDirection.Forward ? "전진도킹" : "후진도킹";
|
||||
@@ -1259,7 +1257,7 @@ namespace AGVSimulator.Forms
|
||||
/// </summary>
|
||||
private string GetRfidByNodeId(string nodeId)
|
||||
{
|
||||
var node = _mapNodes?.FirstOrDefault(n => n.Id == nodeId);
|
||||
var node = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.Id == nodeId);
|
||||
return node?.HasRfid() == true ? node.RfidId : nodeId;
|
||||
}
|
||||
|
||||
@@ -1268,7 +1266,7 @@ namespace AGVSimulator.Forms
|
||||
/// </summary>
|
||||
private string GetDisplayName(string nodeId)
|
||||
{
|
||||
var node = _mapNodes?.FirstOrDefault(n => n.Id == nodeId);
|
||||
var node = _simulatorCanvas.Nodes?.FirstOrDefault(n => n.Id == nodeId);
|
||||
if (node != null && !string.IsNullOrEmpty(node.RfidId))
|
||||
{
|
||||
return node.RfidId;
|
||||
@@ -1541,7 +1539,7 @@ namespace AGVSimulator.Forms
|
||||
private async void toolStripButton1_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 맵과 AGV 확인
|
||||
if (_mapNodes == null || _mapNodes.Count == 0)
|
||||
if (_simulatorCanvas.Nodes == null || _simulatorCanvas.Nodes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("맵 데이터가 없습니다. 먼저 맵을 로드해주세요.", "알림",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
@@ -1557,8 +1555,7 @@ namespace AGVSimulator.Forms
|
||||
}
|
||||
|
||||
// 도킹 타겟 노드 찾기
|
||||
var dockingTargets = _mapNodes.Where(n =>
|
||||
n.Type == NodeType.Charging || n.Type == NodeType.Loader || n.Type == NodeType.UnLoader || n.Type == NodeType.Clearner || n.Type == NodeType.Buffer).ToList();
|
||||
var dockingTargets = _simulatorCanvas.Nodes.Where(n => n.isDockingNode).ToList();
|
||||
|
||||
if (dockingTargets.Count == 0)
|
||||
{
|
||||
@@ -1666,7 +1663,7 @@ namespace AGVSimulator.Forms
|
||||
private PathTestLogItem CreateTestResultFromUI(MapNode prevNode, MapNode targetNode,
|
||||
string directionName, (bool result, string message) calcResult)
|
||||
{
|
||||
var currentNode = _mapNodes.FirstOrDefault(n => n.Id ==
|
||||
var currentNode = _simulatorCanvas.Nodes.FirstOrDefault(n => n.Id ==
|
||||
(_agvListCombo.SelectedItem as VirtualAGV)?.CurrentNodeId);
|
||||
|
||||
var logItem = new PathTestLogItem
|
||||
@@ -1675,7 +1672,7 @@ namespace AGVSimulator.Forms
|
||||
MotorDirection = directionName,
|
||||
CurrentPosition = GetNodeDisplayName(currentNode),
|
||||
TargetPosition = GetNodeDisplayName(targetNode),
|
||||
DockingPosition = targetNode.Type == NodeType.Charging ? "충전기" : "장비"
|
||||
DockingPosition = targetNode.StationType == StationType.Charger ? "충전기" : "장비"
|
||||
};
|
||||
|
||||
if (calcResult.result)
|
||||
@@ -1685,7 +1682,7 @@ namespace AGVSimulator.Forms
|
||||
if (currentPath != null && currentPath.Success)
|
||||
{
|
||||
// 도킹 검증
|
||||
var dockingValidation = DockingValidator.ValidateDockingDirection(currentPath, _mapNodes);
|
||||
var dockingValidation = DockingValidator.ValidateDockingDirection(currentPath, _simulatorCanvas.Nodes);
|
||||
|
||||
if (dockingValidation.IsValid)
|
||||
{
|
||||
@@ -1726,7 +1723,7 @@ namespace AGVSimulator.Forms
|
||||
var pairs = new List<(MapNode, MapNode)>();
|
||||
var processedPairs = new HashSet<string>();
|
||||
|
||||
foreach (var nodeA in _mapNodes)
|
||||
foreach (var nodeA in _simulatorCanvas.Nodes)
|
||||
{
|
||||
if (nodeA.ConnectedMapNodes == null || nodeA.ConnectedMapNodes.Count == 0)
|
||||
continue;
|
||||
@@ -1952,9 +1949,9 @@ namespace AGVSimulator.Forms
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
// 기존 맵 데이터 삭제
|
||||
_mapNodes?.Clear();
|
||||
_mapNodes = new List<MapNode>();
|
||||
_simulatorCanvas.Nodes = _mapNodes;
|
||||
_simulatorCanvas.Nodes?.Clear();
|
||||
_simulatorCanvas.Nodes = new List<MapNode>();
|
||||
_simulatorCanvas.Nodes = _simulatorCanvas.Nodes;
|
||||
_currentMapFilePath = string.Empty;
|
||||
UpdateNodeComboBoxes();
|
||||
_statusLabel.Text = "맵 초기화 완료 - 스캔 모드 시작";
|
||||
@@ -1978,16 +1975,16 @@ namespace AGVSimulator.Forms
|
||||
_isMapScanMode = false;
|
||||
btMakeMap.Text = "맵 생성";
|
||||
btMakeMap.BackColor = SystemColors.Control;
|
||||
_statusLabel.Text = $"맵 스캔 완료 - {_mapNodes?.Count ?? 0}개 노드 생성됨";
|
||||
_statusLabel.Text = $"맵 스캔 완료 - {_simulatorCanvas.Nodes?.Count ?? 0}개 노드 생성됨";
|
||||
|
||||
Program.WriteLine($"[맵 스캔] 스캔 모드 종료 - 총 {_mapNodes?.Count ?? 0}개 노드");
|
||||
Program.WriteLine($"[맵 스캔] 스캔 모드 종료 - 총 {_simulatorCanvas.Nodes?.Count ?? 0}개 노드");
|
||||
|
||||
// 맵 저장 권장
|
||||
if (_mapNodes != null && _mapNodes.Count > 0)
|
||||
if (_simulatorCanvas.Nodes != null && _simulatorCanvas.Nodes.Count > 0)
|
||||
{
|
||||
var saveResult = MessageBox.Show(
|
||||
$"맵 스캔이 완료되었습니다.\n\n" +
|
||||
$"생성된 노드: {_mapNodes.Count}개\n\n" +
|
||||
$"생성된 노드: {_simulatorCanvas.Nodes.Count}개\n\n" +
|
||||
"맵을 저장하시겠습니까?",
|
||||
"맵 저장",
|
||||
MessageBoxButtons.YesNo,
|
||||
@@ -2011,11 +2008,11 @@ namespace AGVSimulator.Forms
|
||||
try
|
||||
{
|
||||
// MapLoader의 표준 저장 메서드 사용 (AGVMapEditor와 동일한 형식)
|
||||
bool success = MapLoader.SaveMapToFile(filePath, _mapNodes);
|
||||
bool success = MapLoader.SaveMapToFile(filePath, _simulatorCanvas.Nodes);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Program.WriteLine($"[맵 저장] 파일 저장 완료: {filePath} ({_mapNodes.Count}개 노드)");
|
||||
Program.WriteLine($"[맵 저장] 파일 저장 완료: {filePath} ({_simulatorCanvas.Nodes.Count}개 노드)");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2032,7 +2029,7 @@ namespace AGVSimulator.Forms
|
||||
private void btMapSaveAs_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 맵 데이터 확인
|
||||
if (_mapNodes == null || _mapNodes.Count == 0)
|
||||
if (_simulatorCanvas.Nodes == null || _simulatorCanvas.Nodes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("저장할 맵 데이터가 없습니다.", "알림",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
|
||||
Reference in New Issue
Block a user