"feat:Enable-hover-highlight-and-refactor"
This commit is contained in:
@@ -59,7 +59,7 @@ namespace AGVNavigationCore.PathFinding.Analysis
|
||||
if (node.IsNavigationNode())
|
||||
{
|
||||
var junctionInfo = AnalyzeNode(node);
|
||||
_junctions[node.NodeId] = junctionInfo;
|
||||
_junctions[node.Id] = junctionInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace AGVNavigationCore.PathFinding.Analysis
|
||||
/// </summary>
|
||||
private JunctionInfo AnalyzeNode(MapNode node)
|
||||
{
|
||||
var junction = new JunctionInfo(node.NodeId);
|
||||
var junction = new JunctionInfo(node.Id);
|
||||
|
||||
// 양방향 연결을 고려하여 모든 연결된 노드 찾기
|
||||
var connectedNodes = GetAllConnectedNodes(node);
|
||||
@@ -96,16 +96,16 @@ namespace AGVNavigationCore.PathFinding.Analysis
|
||||
{
|
||||
if (connectedNode != null)
|
||||
{
|
||||
connected.Add(connectedNode.NodeId);
|
||||
connected.Add(connectedNode.Id);
|
||||
}
|
||||
}
|
||||
|
||||
// 역방향 연결된 노드들 (다른 노드에서 이 노드로 연결)
|
||||
foreach (var otherNode in _mapNodes)
|
||||
{
|
||||
if (otherNode.NodeId != node.NodeId && otherNode.ConnectedMapNodes.Any(n => n.NodeId == node.NodeId))
|
||||
if (otherNode.Id != node.Id && otherNode.ConnectedMapNodes.Any(n => n.Id == node.Id))
|
||||
{
|
||||
connected.Add(otherNode.NodeId);
|
||||
connected.Add(otherNode.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace AGVNavigationCore.PathFinding.Analysis
|
||||
|
||||
foreach (var connectedId in connectedNodes)
|
||||
{
|
||||
var connectedNode = _mapNodes.FirstOrDefault(n => n.NodeId == connectedId);
|
||||
var connectedNode = _mapNodes.FirstOrDefault(n => n.Id == connectedId);
|
||||
if (connectedNode != null)
|
||||
{
|
||||
double angle = CalculateAngle(junctionNode.Position, connectedNode.Position);
|
||||
@@ -226,9 +226,9 @@ namespace AGVNavigationCore.PathFinding.Analysis
|
||||
return MagnetDirection.Straight;
|
||||
|
||||
// 실제 각도 기반으로 마그넷 방향 계산
|
||||
var fromNode = _mapNodes.FirstOrDefault(n => n.NodeId == fromNodeId);
|
||||
var currentNode = _mapNodes.FirstOrDefault(n => n.NodeId == currentNodeId);
|
||||
var toNode = _mapNodes.FirstOrDefault(n => n.NodeId == toNodeId);
|
||||
var fromNode = _mapNodes.FirstOrDefault(n => n.Id == fromNodeId);
|
||||
var currentNode = _mapNodes.FirstOrDefault(n => n.Id == currentNodeId);
|
||||
var toNode = _mapNodes.FirstOrDefault(n => n.Id == toNodeId);
|
||||
|
||||
if (fromNode == null || currentNode == null || toNode == null)
|
||||
return MagnetDirection.Straight;
|
||||
|
||||
@@ -320,7 +320,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
{
|
||||
return DetailedPath.Select(n => n.NodeId).ToList();
|
||||
}
|
||||
return Path?.Select(n => n.NodeId).ToList() ?? new List<string>();
|
||||
return Path?.Select(n => n.Id).ToList() ?? new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -50,36 +50,36 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
// 모든 네비게이션 노드를 PathNode로 변환하고 양방향 연결 생성
|
||||
foreach (var mapNode in _mapNodes)
|
||||
{
|
||||
_mapNodeLookup[mapNode.NodeId] = mapNode; // Add to lookup table
|
||||
_mapNodeLookup[mapNode.Id] = mapNode; // Add to lookup table
|
||||
|
||||
if (mapNode.IsNavigationNode())
|
||||
{
|
||||
var pathNode = new PathNode(mapNode.NodeId, mapNode.Position);
|
||||
_nodeMap[mapNode.NodeId] = pathNode;
|
||||
var pathNode = new PathNode(mapNode.Id, mapNode.Position);
|
||||
_nodeMap[mapNode.Id] = pathNode;
|
||||
}
|
||||
}
|
||||
|
||||
// 단일 연결을 양방향으로 확장
|
||||
foreach (var mapNode in _mapNodes)
|
||||
{
|
||||
if (mapNode.IsNavigationNode() && _nodeMap.ContainsKey(mapNode.NodeId))
|
||||
if (mapNode.IsNavigationNode() && _nodeMap.ContainsKey(mapNode.Id))
|
||||
{
|
||||
var pathNode = _nodeMap[mapNode.NodeId];
|
||||
var pathNode = _nodeMap[mapNode.Id];
|
||||
|
||||
foreach (var connectedNode in mapNode.ConnectedMapNodes)
|
||||
{
|
||||
if (connectedNode != null && _nodeMap.ContainsKey(connectedNode.NodeId))
|
||||
if (connectedNode != null && _nodeMap.ContainsKey(connectedNode.Id))
|
||||
{
|
||||
// 양방향 연결 생성 (단일 연결이 양방향을 의미)
|
||||
if (!pathNode.ConnectedNodes.Contains(connectedNode.NodeId))
|
||||
if (!pathNode.ConnectedNodes.Contains(connectedNode.Id))
|
||||
{
|
||||
pathNode.ConnectedNodes.Add(connectedNode.NodeId);
|
||||
pathNode.ConnectedNodes.Add(connectedNode.Id);
|
||||
}
|
||||
|
||||
var connectedPathNode = _nodeMap[connectedNode.NodeId];
|
||||
if (!connectedPathNode.ConnectedNodes.Contains(mapNode.NodeId))
|
||||
var connectedPathNode = _nodeMap[connectedNode.Id];
|
||||
if (!connectedPathNode.ConnectedNodes.Contains(mapNode.Id))
|
||||
{
|
||||
connectedPathNode.ConnectedNodes.Add(mapNode.NodeId);
|
||||
connectedPathNode.ConnectedNodes.Add(mapNode.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,8 +371,8 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
var combinedDetailedPath = new List<NodeMotorInfo>(previousResult.DetailedPath ?? new List<NodeMotorInfo>());
|
||||
|
||||
// 이전 경로의 마지막 노드와 현재 경로의 시작 노드 비교
|
||||
string lastNodeOfPrevious = previousResult.Path[previousResult.Path.Count - 1].NodeId;
|
||||
string firstNodeOfCurrent = currentResult.Path[0].NodeId;
|
||||
string lastNodeOfPrevious = previousResult.Path[previousResult.Path.Count - 1].Id;
|
||||
string firstNodeOfCurrent = currentResult.Path[0].Id;
|
||||
|
||||
if (lastNodeOfPrevious == firstNodeOfCurrent)
|
||||
{
|
||||
@@ -508,8 +508,8 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
float totalDistance = 0;
|
||||
for (int i = 0; i < path.Count - 1; i++)
|
||||
{
|
||||
var nodeId1 = path[i].NodeId;
|
||||
var nodeId2 = path[i + 1].NodeId;
|
||||
var nodeId1 = path[i].Id;
|
||||
var nodeId2 = path[i + 1].Id;
|
||||
|
||||
if (_nodeMap.ContainsKey(nodeId1) && _nodeMap.ContainsKey(nodeId2))
|
||||
{
|
||||
@@ -577,7 +577,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
return null;
|
||||
|
||||
// 교차로 노드 찾기
|
||||
var junctionNode = _mapNodes.FirstOrDefault(n => n.NodeId == junctionNodeId);
|
||||
var junctionNode = _mapNodes.FirstOrDefault(n => n.Id == junctionNodeId);
|
||||
if (junctionNode == null || junctionNode.ConnectedNodes == null || junctionNode.ConnectedNodes.Count == 0)
|
||||
return null;
|
||||
|
||||
@@ -602,7 +602,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
if (connectedNodeId == targetNodeId) continue;
|
||||
|
||||
// 조건 3, 4, 5: 존재하고, 활성 상태이고, 네비게이션 가능
|
||||
var connectedNode = _mapNodes.FirstOrDefault(n => n.NodeId == connectedNodeId);
|
||||
var connectedNode = _mapNodes.FirstOrDefault(n => n.Id == connectedNodeId);
|
||||
if (connectedNode != null && connectedNode.IsActive && connectedNode.IsNavigationNode())
|
||||
{
|
||||
alternateNodes.Add(connectedNode);
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
n.DisableCross == false &&
|
||||
n.ConnectedNodes.Count >= 3 &&
|
||||
n.ConnectedMapNodes.Where(t => t.CanDocking).Any() == false &&
|
||||
n.NodeId != startNode.NodeId
|
||||
n.Id != startNode.Id
|
||||
).ToList();
|
||||
|
||||
// docking 포인트가 연결된 노드는 제거한다.
|
||||
@@ -103,7 +103,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
pathNode.ConnectedNodes.Count >= 3 &&
|
||||
pathNode.ConnectedMapNodes.Where(t => t.CanDocking).Any() == false)
|
||||
{
|
||||
if (pathNode.NodeId.Equals(StartNode.NodeId) == false)
|
||||
if (pathNode.Id.Equals(StartNode.Id) == false)
|
||||
return pathNode;
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,12 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
return null;
|
||||
}
|
||||
|
||||
public AGVPathResult FindPath(MapNode startNode, MapNode targetNode)
|
||||
{
|
||||
// 기본값으로 경로 탐색 (이전 위치 = 현재 위치, 방향 = 전진)
|
||||
return FindPath(startNode, targetNode, startNode, AgvDirection.Forward, AgvDirection.Forward, false);
|
||||
}
|
||||
|
||||
public AGVPathResult FindPath(MapNode startNode, MapNode targetNode,
|
||||
MapNode prevNode, AgvDirection prevDirection, AgvDirection currentDirection, bool crossignore = false)
|
||||
{
|
||||
@@ -121,13 +127,17 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
return AGVPathResult.CreateFailure("목적지 노드가 null입니다.", 0, 0);
|
||||
if (prevNode == null)
|
||||
return AGVPathResult.CreateFailure("이전위치 노드가 null입니다.", 0, 0);
|
||||
if (startNode.NodeId == targetNode.NodeId && targetNode.DockDirection.MatchAGVDirection(prevDirection))
|
||||
if (targetNode.isDockingNode == false && targetNode.Type != NodeType.Normal)
|
||||
return AGVPathResult.CreateFailure("이동 가능한 노드가 아닙니다", 0, 0);
|
||||
|
||||
var tnode = targetNode as MapNode;
|
||||
if (startNode.Id == targetNode.Id && tnode.DockDirection.MatchAGVDirection(prevDirection))
|
||||
return AGVPathResult.CreateSuccess(new List<MapNode> { startNode, startNode }, new List<AgvDirection>(), 0, 0);
|
||||
|
||||
var ReverseDirection = (currentDirection == AgvDirection.Forward ? AgvDirection.Backward : AgvDirection.Forward);
|
||||
|
||||
//1.목적지까지의 최단거리 경로를 찾는다.
|
||||
var pathResult = _basicPathfinder.FindPathAStar(startNode.NodeId, targetNode.NodeId);
|
||||
var pathResult = _basicPathfinder.FindPathAStar(startNode.Id, targetNode.Id);
|
||||
pathResult.PrevNode = prevNode;
|
||||
pathResult.PrevDirection = prevDirection;
|
||||
if (!pathResult.Success || pathResult.Path == null || pathResult.Path.Count == 0)
|
||||
@@ -146,11 +156,11 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
|
||||
//2.AGV방향과 목적지에 설정된 방향이 일치하면 그대로 진행하면된다.(목적지에 방향이 없는 경우에도 그대로 진행)
|
||||
if (targetNode.DockDirection == DockingDirection.DontCare ||
|
||||
(targetNode.DockDirection == DockingDirection.Forward && currentDirection == AgvDirection.Forward) ||
|
||||
(targetNode.DockDirection == DockingDirection.Backward && currentDirection == AgvDirection.Backward))
|
||||
if (tnode.DockDirection == DockingDirection.DontCare ||
|
||||
(tnode.DockDirection == DockingDirection.Forward && currentDirection == AgvDirection.Forward) ||
|
||||
(tnode.DockDirection == DockingDirection.Backward && currentDirection == AgvDirection.Backward))
|
||||
{
|
||||
if ((nextNodeForward?.NodeId ?? string.Empty) == pathResult.Path[1].NodeId) //예측경로와 다음진행방향 경로가 일치하면 해당 방향이 맞다
|
||||
if ((nextNodeForward?.Id ?? string.Empty) == pathResult.Path[1].Id) //예측경로와 다음진행방향 경로가 일치하면 해당 방향이 맞다
|
||||
{
|
||||
MakeDetailData(pathResult, currentDirection);
|
||||
MakeMagnetDirection(pathResult);
|
||||
@@ -177,10 +187,10 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
//뒤로 이동시 경로상의 처음 만나는 노드가 같다면 그 방향으로 이동하면 된다.
|
||||
// ⚠️ 단, 현재 방향과 목적지 도킹 방향이 일치해야 함!
|
||||
if (nextNodeBackward != null && pathResult.Path.Count > 1 &&
|
||||
nextNodeBackward.NodeId == pathResult.Path[1].NodeId) // ✅ 추가: 현재도 Backward여야 함
|
||||
nextNodeBackward.Id == pathResult.Path[1].Id) // ✅ 추가: 현재도 Backward여야 함
|
||||
{
|
||||
if (targetNode.DockDirection == DockingDirection.Forward && ReverseDirection == AgvDirection.Forward ||
|
||||
targetNode.DockDirection == DockingDirection.Backward && ReverseDirection == AgvDirection.Backward)
|
||||
if (tnode.DockDirection == DockingDirection.Forward && ReverseDirection == AgvDirection.Forward ||
|
||||
tnode.DockDirection == DockingDirection.Backward && ReverseDirection == AgvDirection.Backward)
|
||||
{
|
||||
MakeDetailData(pathResult, ReverseDirection);
|
||||
MakeMagnetDirection(pathResult);
|
||||
@@ -191,12 +201,12 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
}
|
||||
|
||||
if (nextNodeForward != null && pathResult.Path.Count > 1 &&
|
||||
nextNodeForward.NodeId == pathResult.Path[1].NodeId &&
|
||||
targetNode.DockDirection == DockingDirection.Forward &&
|
||||
nextNodeForward.Id == pathResult.Path[1].Id &&
|
||||
tnode.DockDirection == DockingDirection.Forward &&
|
||||
currentDirection == AgvDirection.Forward) // ✅ 추가: 현재도 Forward여야 함
|
||||
{
|
||||
if (targetNode.DockDirection == DockingDirection.Forward && currentDirection == AgvDirection.Forward ||
|
||||
targetNode.DockDirection == DockingDirection.Backward && currentDirection == AgvDirection.Backward)
|
||||
if (tnode.DockDirection == DockingDirection.Forward && currentDirection == AgvDirection.Forward ||
|
||||
tnode.DockDirection == DockingDirection.Backward && currentDirection == AgvDirection.Backward)
|
||||
{
|
||||
MakeDetailData(pathResult, currentDirection);
|
||||
MakeMagnetDirection(pathResult);
|
||||
@@ -221,7 +231,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
//진행방향으로 이동했을때 나오는 노드를 사용한다.
|
||||
if (nextNodeForward != null)
|
||||
{
|
||||
var Path0 = _basicPathfinder.FindPathAStar(startNode.NodeId, nextNodeForward.NodeId);
|
||||
var Path0 = _basicPathfinder.FindPathAStar(startNode.Id, nextNodeForward.Id);
|
||||
Path0.PrevNode = prevNode;
|
||||
Path0.PrevDirection = prevDirection;
|
||||
MakeDetailData(Path0, prevDirection);
|
||||
@@ -259,7 +269,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
JunctionInPath = FindNearestJunction(startNode);
|
||||
|
||||
//종료노드로부터 가까운 교차로 검색
|
||||
if (JunctionInPath == null) JunctionInPath = FindNearestJunction(targetNode);
|
||||
if (JunctionInPath == null) JunctionInPath = FindNearestJunction(tnode);
|
||||
}
|
||||
if (JunctionInPath == null)
|
||||
return AGVPathResult.CreateFailure("교차로가 없어 경로계산을 할 수 없습니다", 0, 0);
|
||||
@@ -267,7 +277,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
//경유지를 포함하여 경로를 다시 계산한다.
|
||||
|
||||
//1.시작위치 - 교차로(여기까지는 현재 방향으로 그대로 이동을 한다)
|
||||
var path1 = _basicPathfinder.FindPathAStar(startNode.NodeId, JunctionInPath.NodeId);
|
||||
var path1 = _basicPathfinder.FindPathAStar(startNode.Id, JunctionInPath.Id);
|
||||
path1.PrevNode = prevNode;
|
||||
path1.PrevDirection = prevDirection;
|
||||
|
||||
@@ -278,7 +288,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
// ReverseCheck = false; //현재 진행 방향으로 이동해야한다
|
||||
// MakeDetailData(path1, currentDirection); // path1의 상세 경로 정보 채우기 (모터 방향 설정)
|
||||
//}
|
||||
if (path1.Path.Count > 1 && nextNodeBackward != null && nextNodeBackward.NodeId.Equals(path1.Path[1].NodeId))
|
||||
if (path1.Path.Count > 1 && nextNodeBackward != null && nextNodeBackward.Id.Equals(path1.Path[1].Id))
|
||||
{
|
||||
ReverseCheck = true; //현재 방향의 반대방향으로 이동해야한다
|
||||
MakeDetailData(path1, ReverseDirection); // path1의 상세 경로 정보 채우기 (모터 방향 설정)
|
||||
@@ -295,7 +305,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
|
||||
//2.교차로 - 종료위치
|
||||
var path2 = _basicPathfinder.FindPathAStar(JunctionInPath.NodeId, targetNode.NodeId);
|
||||
var path2 = _basicPathfinder.FindPathAStar(JunctionInPath.Id, targetNode.Id);
|
||||
path2.PrevNode = prevNode;
|
||||
path2.PrevDirection = prevDirection;
|
||||
|
||||
@@ -315,9 +325,9 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
|
||||
//3.방향전환을 위환 대체 노드찾기
|
||||
tempNode = _basicPathfinder.FindAlternateNodeForDirectionChange(JunctionInPath.NodeId,
|
||||
path1.Path[path1.Path.Count - 2].NodeId,
|
||||
path2.Path[1].NodeId);
|
||||
tempNode = _basicPathfinder.FindAlternateNodeForDirectionChange(JunctionInPath.Id,
|
||||
path1.Path[path1.Path.Count - 2].Id,
|
||||
path2.Path[1].Id);
|
||||
|
||||
//4. path1 + tempnode + path2 가 최종 위치가 된다.
|
||||
if (tempNode == null)
|
||||
@@ -332,7 +342,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
//if (tempNode != null)
|
||||
{
|
||||
// 교차로 → 대체노드 경로 계산
|
||||
var pathToTemp = _basicPathfinder.FindPathAStar(JunctionInPath.NodeId, tempNode.NodeId);
|
||||
var pathToTemp = _basicPathfinder.FindPathAStar(JunctionInPath.Id, tempNode.Id);
|
||||
pathToTemp.PrevNode = JunctionInPath;
|
||||
pathToTemp.PrevDirection = (ReverseCheck ? ReverseDirection : currentDirection);
|
||||
if (!pathToTemp.Success)
|
||||
@@ -348,7 +358,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
combinedResult = _basicPathfinder.CombineResults(combinedResult, pathToTemp);
|
||||
|
||||
// 대체노드 → 교차로 경로 계산 (역방향)
|
||||
var pathFromTemp = _basicPathfinder.FindPathAStar(tempNode.NodeId, JunctionInPath.NodeId);
|
||||
var pathFromTemp = _basicPathfinder.FindPathAStar(tempNode.Id, JunctionInPath.Id);
|
||||
pathFromTemp.PrevNode = JunctionInPath;
|
||||
pathFromTemp.PrevDirection = (ReverseCheck ? ReverseDirection : currentDirection);
|
||||
if (!pathFromTemp.Success)
|
||||
@@ -362,14 +372,14 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
//현재까지 노드에서 목적지까지의 방향이 일치하면 그대로 사용한다.
|
||||
bool temp3ok = false;
|
||||
var TempCheck3 = _basicPathfinder.FindPathAStar(combinedResult.Path.Last().NodeId, targetNode.NodeId);
|
||||
if (TempCheck3.Path.First().NodeId.Equals(combinedResult.Path.Last().NodeId))
|
||||
var TempCheck3 = _basicPathfinder.FindPathAStar(combinedResult.Path.Last().Id, targetNode.Id);
|
||||
if (TempCheck3.Path.First().Id.Equals(combinedResult.Path.Last().Id))
|
||||
{
|
||||
if (targetNode.DockDirection == DockingDirection.Forward && combinedResult.DetailedPath.Last().MotorDirection == AgvDirection.Forward)
|
||||
if (tnode.DockDirection == DockingDirection.Forward && combinedResult.DetailedPath.Last().MotorDirection == AgvDirection.Forward)
|
||||
{
|
||||
temp3ok = true;
|
||||
}
|
||||
else if (targetNode.DockDirection == DockingDirection.Backward && combinedResult.DetailedPath.Last().MotorDirection == AgvDirection.Backward)
|
||||
else if (tnode.DockDirection == DockingDirection.Backward && combinedResult.DetailedPath.Last().MotorDirection == AgvDirection.Backward)
|
||||
{
|
||||
temp3ok = true;
|
||||
}
|
||||
@@ -381,11 +391,11 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
if (temp3ok == false)
|
||||
{
|
||||
//목적지와 방향이 맞지 않다. 그러므로 대체노드를 추가로 더 찾아야한다.
|
||||
var tempNode2 = _basicPathfinder.FindAlternateNodeForDirectionChange(JunctionInPath.NodeId,
|
||||
combinedResult.Path[combinedResult.Path.Count - 2].NodeId,
|
||||
path2.Path[1].NodeId);
|
||||
var tempNode2 = _basicPathfinder.FindAlternateNodeForDirectionChange(JunctionInPath.Id,
|
||||
combinedResult.Path[combinedResult.Path.Count - 2].Id,
|
||||
path2.Path[1].Id);
|
||||
|
||||
var pathToTemp2 = _basicPathfinder.FindPathAStar(JunctionInPath.NodeId, tempNode2.NodeId);
|
||||
var pathToTemp2 = _basicPathfinder.FindPathAStar(JunctionInPath.Id, tempNode2.Id);
|
||||
if (ReverseCheck) MakeDetailData(pathToTemp2, currentDirection);
|
||||
else MakeDetailData(pathToTemp2, ReverseDirection);
|
||||
|
||||
@@ -400,7 +410,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
combinedResult.DetailedPath[combinedResult.DetailedPath.Count - 1].MotorDirection = currentDirection;
|
||||
}
|
||||
|
||||
var pathToTemp3 = _basicPathfinder.FindPathAStar(tempNode2.NodeId, JunctionInPath.NodeId);
|
||||
var pathToTemp3 = _basicPathfinder.FindPathAStar(tempNode2.Id, JunctionInPath.Id);
|
||||
if (ReverseCheck) MakeDetailData(pathToTemp3, ReverseDirection);
|
||||
else MakeDetailData(pathToTemp3, currentDirection);
|
||||
|
||||
@@ -420,12 +430,15 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 작업후에 MakeMagnetDirection 를 추가로 실행 하세요
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// 이 작업후에 MakeMagnetDirection 를 추가로 실행 하세요
|
||||
/// </summary>
|
||||
/// <param name="path1"></param>
|
||||
/// <param name="currentDirection"></param>
|
||||
private void MakeDetailData(AGVPathResult path1, AgvDirection currentDirection)
|
||||
public void MakeDetailData(AGVPathResult path1, AgvDirection currentDirection)
|
||||
{
|
||||
if (path1.Success && path1.Path != null && path1.Path.Count > 0)
|
||||
{
|
||||
@@ -433,9 +446,9 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
for (int i = 0; i < path1.Path.Count; i++)
|
||||
{
|
||||
var node = path1.Path[i];
|
||||
string nodeId = node.NodeId;
|
||||
string nodeId = node.Id;
|
||||
string RfidId = node.RfidId;
|
||||
string nextNodeId = (i + 1 < path1.Path.Count) ? path1.Path[i + 1].NodeId : null;
|
||||
string nextNodeId = (i + 1 < path1.Path.Count) ? path1.Path[i + 1].Id : null;
|
||||
|
||||
// 노드 정보 생성 (현재 방향 유지)
|
||||
var nodeInfo = new NodeMotorInfo(i + 1,
|
||||
@@ -446,7 +459,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
);
|
||||
|
||||
// [Speed Control] MapNode의 속도 설정 적용
|
||||
var mapNode = _mapNodes.FirstOrDefault(n => n.NodeId == nodeId);
|
||||
var mapNode = _mapNodes.FirstOrDefault(n => n.Id == nodeId);
|
||||
if (mapNode != null)
|
||||
{
|
||||
nodeInfo.Speed = mapNode.SpeedLimit;
|
||||
@@ -470,13 +483,13 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
for (int i = 0; i < path1.DetailedPath.Count; i++)
|
||||
{
|
||||
var detailPath = path1.DetailedPath[i];
|
||||
string nodeId = path1.Path[i].NodeId;
|
||||
string nextNodeId = (i + 1 < path1.Path.Count) ? path1.Path[i + 1].NodeId : null;
|
||||
string nodeId = path1.Path[i].Id;
|
||||
string nextNodeId = (i + 1 < path1.Path.Count) ? path1.Path[i + 1].Id : null;
|
||||
|
||||
// 마그넷 방향 계산 (3개 이상 연결된 교차로에서만 좌/우 가중치 적용)
|
||||
if (i > 0 && nextNodeId != null)
|
||||
{
|
||||
string prevNodeId = path1.Path[i - 1].NodeId;
|
||||
string prevNodeId = path1.Path[i - 1].Id;
|
||||
if (path1.DetailedPath[i - 1].MotorDirection != detailPath.MotorDirection)
|
||||
detailPath.MagnetDirection = MagnetDirection.Straight;
|
||||
else
|
||||
|
||||
@@ -91,14 +91,14 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
// 직접 경로에 갈림길이 포함된 경우 그 갈림길에서 방향 전환
|
||||
foreach (var node in directPath2.Path.Skip(1).Take(directPath2.Path.Count - 2)) // 시작과 끝 제외
|
||||
{
|
||||
var junctionInfo = _junctionAnalyzer.GetJunctionInfo(node.NodeId);
|
||||
var junctionInfo = _junctionAnalyzer.GetJunctionInfo(node.Id);
|
||||
if (junctionInfo != null && junctionInfo.IsJunction)
|
||||
{
|
||||
// 간단한 방향 전환: 직접 경로 사용하되 방향 전환 노드 표시
|
||||
return DirectionChangePlan.CreateSuccess(
|
||||
directPath2.Path,
|
||||
node.NodeId,
|
||||
$"갈림길 {node.NodeId}에서 방향 전환: {currentDirection} → {requiredDirection}"
|
||||
node.Id,
|
||||
$"갈림길 {node.Id}에서 방향 전환: {currentDirection} → {requiredDirection}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -165,14 +165,14 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
{
|
||||
foreach (var node in directPath.Path.Skip(2)) // 시작점과 다음 노드는 제외
|
||||
{
|
||||
var junctionInfo = _junctionAnalyzer.GetJunctionInfo(node.NodeId);
|
||||
var junctionInfo = _junctionAnalyzer.GetJunctionInfo(node.Id);
|
||||
if (junctionInfo != null && junctionInfo.IsJunction)
|
||||
{
|
||||
// 직진 경로상에서는 더 엄격한 조건 적용
|
||||
if (!suitableJunctions.Contains(node.NodeId) &&
|
||||
HasMultipleExitOptions(node.NodeId))
|
||||
if (!suitableJunctions.Contains(node.Id) &&
|
||||
HasMultipleExitOptions(node.Id))
|
||||
{
|
||||
suitableJunctions.Add(node.NodeId);
|
||||
suitableJunctions.Add(node.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,7 +226,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
/// </summary>
|
||||
private List<string> GetAllConnectedNodes(string nodeId)
|
||||
{
|
||||
var node = _mapNodes.FirstOrDefault(n => n.NodeId == nodeId);
|
||||
var node = _mapNodes.FirstOrDefault(n => n.Id == nodeId);
|
||||
if (node == null) return new List<string>();
|
||||
|
||||
var connected = new HashSet<string>();
|
||||
@@ -236,16 +236,16 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
{
|
||||
if (connectedNode != null)
|
||||
{
|
||||
connected.Add(connectedNode.NodeId);
|
||||
connected.Add(connectedNode.Id);
|
||||
}
|
||||
}
|
||||
|
||||
// 역방향 연결
|
||||
foreach (var otherNode in _mapNodes)
|
||||
{
|
||||
if (otherNode.NodeId != nodeId && otherNode.ConnectedMapNodes.Any(n => n.NodeId == nodeId))
|
||||
if (otherNode.Id != nodeId && otherNode.ConnectedMapNodes.Any(n => n.Id == nodeId))
|
||||
{
|
||||
connected.Add(otherNode.NodeId);
|
||||
connected.Add(otherNode.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
string actualDirectionChangeNode = FindActualDirectionChangeNode(changePath, junctionNodeId);
|
||||
|
||||
string description = $"갈림길 {GetDisplayName(junctionNodeId)}를 통해 {GetDisplayName(actualDirectionChangeNode)}에서 방향 전환: {currentDirection} → {requiredDirection}";
|
||||
System.Diagnostics.Debug.WriteLine($"[DirectionChangePlanner] ✅ 유효한 방향전환 경로: {string.Join(" → ", changePath.Select(n => n.NodeId))}");
|
||||
System.Diagnostics.Debug.WriteLine($"[DirectionChangePlanner] ✅ 유효한 방향전환 경로: {string.Join(" → ", changePath.Select(n => n.Id))}");
|
||||
return DirectionChangePlan.CreateSuccess(changePath, actualDirectionChangeNode, description);
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
// 2. 인근 갈림길을 통한 우회인지, 직진 경로상 갈림길인지 판단
|
||||
var directPath = _pathfinder.FindPathAStar(startNodeId, targetNodeId);
|
||||
bool isNearbyDetour = !directPath.Success || !directPath.Path.Any(n => n.NodeId == junctionNodeId);
|
||||
bool isNearbyDetour = !directPath.Success || !directPath.Path.Any(n => n.Id == junctionNodeId);
|
||||
|
||||
if (isNearbyDetour)
|
||||
{
|
||||
@@ -376,17 +376,17 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
if (currentDirection != requiredDirection)
|
||||
{
|
||||
string fromNodeId = toJunctionPath.Path.Count >= 2 ?
|
||||
toJunctionPath.Path[toJunctionPath.Path.Count - 2].NodeId : startNodeId;
|
||||
toJunctionPath.Path[toJunctionPath.Path.Count - 2].Id : startNodeId;
|
||||
|
||||
var changeSequence = GenerateDirectionChangeSequence(junctionNodeId, fromNodeId, currentDirection, requiredDirection);
|
||||
if (changeSequence.Count > 1)
|
||||
{
|
||||
fullPath.AddRange(changeSequence.Skip(1).Select(nodeId => _mapNodes.FirstOrDefault(n => n.NodeId == nodeId)).Where(n => n != null));
|
||||
fullPath.AddRange(changeSequence.Skip(1).Select(nodeId => _mapNodes.FirstOrDefault(n => n.Id == nodeId)).Where(n => n != null));
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 갈림길에서 목표점까지의 경로
|
||||
string lastNode = fullPath.LastOrDefault()?.NodeId ?? junctionNodeId;
|
||||
string lastNode = fullPath.LastOrDefault()?.Id ?? junctionNodeId;
|
||||
var fromJunctionPath = _pathfinder.FindPathAStar(lastNode, targetNodeId);
|
||||
if (fromJunctionPath.Success && fromJunctionPath.Path.Count > 1)
|
||||
{
|
||||
@@ -461,8 +461,8 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
// 왔던 길(excludeNodeId)를 제외한 노드 중에서 최적의 우회 노드 선택
|
||||
// 우선순위: 1) 막다른 길이 아닌 노드 (우회 후 복귀 가능) 2) 직진방향 3) 목적지 방향
|
||||
|
||||
var junctionNode = _mapNodes.FirstOrDefault(n => n.NodeId == junctionNodeId);
|
||||
var fromNode = _mapNodes.FirstOrDefault(n => n.NodeId == excludeNodeId);
|
||||
var junctionNode = _mapNodes.FirstOrDefault(n => n.Id == junctionNodeId);
|
||||
var fromNode = _mapNodes.FirstOrDefault(n => n.Id == excludeNodeId);
|
||||
|
||||
if (junctionNode == null || fromNode == null)
|
||||
return availableNodes.FirstOrDefault();
|
||||
@@ -478,7 +478,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
{
|
||||
if (nodeId == excludeNodeId) continue; // 왔던 길 제외
|
||||
|
||||
var candidateNode = _mapNodes.FirstOrDefault(n => n.NodeId == nodeId);
|
||||
var candidateNode = _mapNodes.FirstOrDefault(n => n.Id == nodeId);
|
||||
if (candidateNode == null) continue;
|
||||
|
||||
// 갈림길에서 후보 노드로의 방향 벡터 계산 (junctionNode → candidateNode)
|
||||
@@ -561,11 +561,11 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
return junctionNodeId; // 기본값으로 갈림길 반환
|
||||
|
||||
// 갈림길이 두 번 나타나는 위치 찾기
|
||||
int firstJunctionIndex = changePath.FindIndex(n => n.NodeId == junctionNodeId);
|
||||
int firstJunctionIndex = changePath.FindIndex(n => n.Id == junctionNodeId);
|
||||
int lastJunctionIndex = -1;
|
||||
for (int i = changePath.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (changePath[i].NodeId == junctionNodeId)
|
||||
if (changePath[i].Id == junctionNodeId)
|
||||
{
|
||||
lastJunctionIndex = i;
|
||||
break;
|
||||
@@ -577,7 +577,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
firstJunctionIndex != lastJunctionIndex && lastJunctionIndex - firstJunctionIndex == 2)
|
||||
{
|
||||
// 첫 번째와 두 번째 갈림길 사이에 있는 노드가 실제 방향전환 노드
|
||||
string detourNode = changePath[firstJunctionIndex + 1].NodeId;
|
||||
string detourNode = changePath[firstJunctionIndex + 1].Id;
|
||||
return detourNode;
|
||||
}
|
||||
|
||||
@@ -647,11 +647,11 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
}
|
||||
|
||||
string errorMessage = $"되돌아가기 패턴 검출 ({backtrackingPatterns.Count}개): {string.Join(", ", issues)}";
|
||||
System.Diagnostics.Debug.WriteLine($"[PathValidation] ❌ 경로: {string.Join(" → ", path.Select(n => n.NodeId))}");
|
||||
System.Diagnostics.Debug.WriteLine($"[PathValidation] ❌ 경로: {string.Join(" → ", path.Select(n => n.Id))}");
|
||||
System.Diagnostics.Debug.WriteLine($"[PathValidation] ❌ 되돌아가기 패턴: {errorMessage}");
|
||||
|
||||
return PathValidationResult.CreateInvalidWithBacktracking(
|
||||
path.Select(n => n.NodeId).ToList(), backtrackingPatterns, startNodeId, "", junctionNodeId, errorMessage);
|
||||
path.Select(n => n.Id).ToList(), backtrackingPatterns, startNodeId, "", junctionNodeId, errorMessage);
|
||||
}
|
||||
|
||||
// 2. 연속된 중복 노드 검증
|
||||
@@ -670,13 +670,13 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
}
|
||||
|
||||
// 4. 갈림길 포함 여부 검증
|
||||
if (!path.Any(n => n.NodeId == junctionNodeId))
|
||||
if (!path.Any(n => n.Id == junctionNodeId))
|
||||
{
|
||||
return PathValidationResult.CreateInvalid(startNodeId, "", $"갈림길 {junctionNodeId}이 경로에 포함되지 않음");
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"[PathValidation] ✅ 유효한 경로: {string.Join(" → ", path.Select(n => n.NodeId))}");
|
||||
return PathValidationResult.CreateValid(path.Select(n => n.NodeId).ToList(), startNodeId, "", junctionNodeId);
|
||||
System.Diagnostics.Debug.WriteLine($"[PathValidation] ✅ 유효한 경로: {string.Join(" → ", path.Select(n => n.Id))}");
|
||||
return PathValidationResult.CreateValid(path.Select(n => n.Id).ToList(), startNodeId, "", junctionNodeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -688,9 +688,9 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
for (int i = 0; i < path.Count - 2; i++)
|
||||
{
|
||||
string nodeA = path[i].NodeId;
|
||||
string nodeB = path[i + 1].NodeId;
|
||||
string nodeC = path[i + 2].NodeId;
|
||||
string nodeA = path[i].Id;
|
||||
string nodeB = path[i + 1].Id;
|
||||
string nodeC = path[i + 2].Id;
|
||||
|
||||
// A → B → A 패턴 검출
|
||||
if (nodeA == nodeC && nodeA != nodeB)
|
||||
@@ -712,9 +712,9 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
for (int i = 0; i < path.Count - 1; i++)
|
||||
{
|
||||
if (path[i].NodeId == path[i + 1].NodeId)
|
||||
if (path[i].Id == path[i + 1].Id)
|
||||
{
|
||||
duplicates.Add(path[i].NodeId);
|
||||
duplicates.Add(path[i].Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -728,12 +728,12 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
{
|
||||
for (int i = 0; i < path.Count - 1; i++)
|
||||
{
|
||||
string currentNode = path[i].NodeId;
|
||||
string nextNode = path[i + 1].NodeId;
|
||||
string currentNode = path[i].Id;
|
||||
string nextNode = path[i + 1].Id;
|
||||
|
||||
// 두 노드간 직접 연결성 확인 (맵 노드의 ConnectedMapNodes 리스트 사용)
|
||||
var currentMapNode = _mapNodes.FirstOrDefault(n => n.NodeId == currentNode);
|
||||
if (currentMapNode == null || !currentMapNode.ConnectedMapNodes.Any(n => n.NodeId == nextNode))
|
||||
var currentMapNode = _mapNodes.FirstOrDefault(n => n.Id == currentNode);
|
||||
if (currentMapNode == null || !currentMapNode.ConnectedMapNodes.Any(n => n.Id == nextNode))
|
||||
{
|
||||
return PathValidationResult.CreateInvalid(currentNode, nextNode, $"노드 {currentNode}와 {nextNode} 사이에 연결이 없음");
|
||||
}
|
||||
@@ -769,7 +769,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
/// <returns>표시할 이름</returns>
|
||||
private string GetDisplayName(string nodeId)
|
||||
{
|
||||
var node = _mapNodes.FirstOrDefault(n => n.NodeId == nodeId);
|
||||
var node = _mapNodes.FirstOrDefault(n => n.Id == nodeId);
|
||||
if (node != null && !string.IsNullOrEmpty(node.RfidId))
|
||||
{
|
||||
return node.RfidId;
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
// 연결된 노드 중 현재 노드가 아닌 것들만 필터링
|
||||
var candidateNodes = allNodes.Where(n =>
|
||||
connectedNodeIds.Contains(n.NodeId) && n.NodeId != currentNode.NodeId
|
||||
connectedNodeIds.Contains(n.Id) && n.Id != currentNode.Id
|
||||
).ToList();
|
||||
|
||||
if (candidateNodes.Count == 0)
|
||||
@@ -88,7 +88,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
if (movementLength < 0.001f) // 거의 이동하지 않음
|
||||
{
|
||||
return candidateNodes[0].NodeId; // 첫 번째 연결 노드 반환
|
||||
return candidateNodes[0].Id; // 첫 번째 연결 노드 반환
|
||||
}
|
||||
|
||||
var normalizedMovement = new PointF(
|
||||
@@ -138,7 +138,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
// 가장 높은 점수를 가진 노드 반환
|
||||
var bestCandidate = scoredCandidates.OrderByDescending(x => x.score).First();
|
||||
return bestCandidate.node.NodeId;
|
||||
return bestCandidate.node.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user