..
This commit is contained in:
@@ -14,13 +14,38 @@ using AGVControl.Models;
|
||||
|
||||
namespace AGVControl
|
||||
{
|
||||
public class RFIDConnection
|
||||
{
|
||||
public uint StartRFID { get; set; }
|
||||
public uint EndRFID { get; set; }
|
||||
public bool IsBidirectional { get; set; }
|
||||
public float Distance { get; set; }
|
||||
public List<uint> IntermediateRFIDs { get; set; } = new List<uint>();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is RFIDConnection other)
|
||||
{
|
||||
return (StartRFID == other.StartRFID && EndRFID == other.EndRFID) ||
|
||||
(IsBidirectional && other.IsBidirectional &&
|
||||
StartRFID == other.EndRFID && EndRFID == other.StartRFID);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return StartRFID.GetHashCode() ^ EndRFID.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class MapControl : Control
|
||||
{
|
||||
private List<RFIDPoint> rfidPoints;
|
||||
private List<MagnetLine> magnetLines;
|
||||
private List<MapText> mapTexts;
|
||||
private List<CustomLine> customLines;
|
||||
private List<RFIDLine> rfidLines;
|
||||
private HashSet<RFIDConnection> rfidConnections;
|
||||
public AGV agv;
|
||||
private float zoom = 1.0f;
|
||||
private PointF offset = PointF.Empty;
|
||||
@@ -41,14 +66,12 @@ namespace AGVControl
|
||||
private bool isAddingText = false;
|
||||
private bool isAddingPoint = false;
|
||||
private bool isDrawingCustomLine = false;
|
||||
private bool isDrawingMagnetLine = false;
|
||||
private bool isDrawingRFIDLine = false;
|
||||
private bool isDeletingRFIDLine = false;
|
||||
private bool isDrawingLine = false;
|
||||
private MapText selectedText = null;
|
||||
private CustomLine selectedLine = null;
|
||||
private RFIDPoint selectedRFID = null;
|
||||
private MagnetLine selectedMagnetLine = null;
|
||||
private RFIDLine selectedRFIDLine = null;
|
||||
private Point? draggingPoint = null;
|
||||
private bool isDraggingPoint = false;
|
||||
@@ -61,7 +84,6 @@ namespace AGVControl
|
||||
public MapText SelectedText => selectedText;
|
||||
public CustomLine SelectedLine => selectedLine;
|
||||
public RFIDPoint SelectedRFID => selectedRFID;
|
||||
public MagnetLine SelectedMagnetLine => selectedMagnetLine;
|
||||
public RFIDLine SelectedRFIDLine => selectedRFIDLine;
|
||||
|
||||
|
||||
@@ -77,10 +99,10 @@ namespace AGVControl
|
||||
{
|
||||
this.DoubleBuffered = true;
|
||||
rfidPoints = new List<RFIDPoint>();
|
||||
magnetLines = new List<MagnetLine>();
|
||||
mapTexts = new List<MapText>();
|
||||
customLines = new List<CustomLine>();
|
||||
rfidLines = new List<RFIDLine>();
|
||||
rfidConnections = new HashSet<RFIDConnection>();
|
||||
agv = new AGV();
|
||||
|
||||
// 툴바 버튼 영역 초기화
|
||||
@@ -177,19 +199,6 @@ namespace AGVControl
|
||||
}
|
||||
}
|
||||
|
||||
// 마그넷 라인의 끝점과 근접한지 확인
|
||||
foreach (var line in magnetLines)
|
||||
{
|
||||
if (GetDistance(point, line.StartPoint) <= SNAP_DISTANCE)
|
||||
{
|
||||
return line.StartPoint;
|
||||
}
|
||||
if (GetDistance(point, line.EndPoint) <= SNAP_DISTANCE)
|
||||
{
|
||||
return line.EndPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
@@ -245,7 +254,7 @@ namespace AGVControl
|
||||
isDragging = true;
|
||||
this.Cursor = Cursors.SizeAll;
|
||||
}
|
||||
else if (e.Button == MouseButtons.Left && !isAddingText && !isDrawingCustomLine && !isDrawingRFIDLine && !isDrawingMagnetLine)
|
||||
else if (e.Button == MouseButtons.Left && !isAddingText && !isDrawingCustomLine && !isDrawingRFIDLine)
|
||||
{
|
||||
isDragging = true;
|
||||
|
||||
@@ -822,9 +831,6 @@ namespace AGVControl
|
||||
};
|
||||
rfidLines.Add(line);
|
||||
selectedRFIDLine = line;
|
||||
|
||||
// 선 근처의 RFID 포인트들을 찾아서 추가
|
||||
AddNearbyRFIDPoints(line);
|
||||
}
|
||||
// 다음 라인을 위해 현재 클릭한 RFID를 시작점으로 설정
|
||||
previewStartPoint = clickedRFID.Location;
|
||||
@@ -967,12 +973,6 @@ namespace AGVControl
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
public void SetMagnetLines(List<MagnetLine> lines)
|
||||
{
|
||||
magnetLines = lines;
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
public void SetAGV(AGV vehicle)
|
||||
{
|
||||
agv = vehicle;
|
||||
@@ -1076,7 +1076,6 @@ namespace AGVControl
|
||||
{
|
||||
isDrawingCustomLine = false;
|
||||
isDrawingLine = false;
|
||||
isDrawingMagnetLine = false;
|
||||
isDrawingRFIDLine = false;
|
||||
isAddingPoint = value;
|
||||
this.Cursor = value ? Cursors.Cross : Cursors.Default;
|
||||
@@ -1142,25 +1141,12 @@ namespace AGVControl
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedMagnetLine != null)
|
||||
if (selectedRFIDLine != null)
|
||||
{
|
||||
using (Pen pen = new Pen(Color.Magenta, 2))
|
||||
{
|
||||
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
|
||||
e.Graphics.DrawLine(pen, selectedMagnetLine.StartPoint, selectedMagnetLine.EndPoint);
|
||||
foreach (var branch in selectedMagnetLine.BranchPoints)
|
||||
{
|
||||
e.Graphics.DrawEllipse(pen, branch.X - 5, branch.Y - 5, 10, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedLine != null)
|
||||
{
|
||||
using (Pen pen = new Pen(Color.Magenta, 2))
|
||||
{
|
||||
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
|
||||
e.Graphics.DrawLine(pen, selectedLine.StartPoint, selectedLine.EndPoint);
|
||||
e.Graphics.DrawLine(pen, selectedRFIDLine.StartPoint, selectedRFIDLine.EndPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1185,23 +1171,6 @@ namespace AGVControl
|
||||
|
||||
private void DrawMap(Graphics g)
|
||||
{
|
||||
//// 마그넷 라인 그리기
|
||||
//foreach (var line in magnetLines)
|
||||
//{
|
||||
// using (Pen linePen = new Pen(Color.FromArgb(180, Color.Yellow), LINE_WIDTH))
|
||||
// {
|
||||
// g.DrawLine(linePen, line.StartPoint, line.EndPoint);
|
||||
// }
|
||||
|
||||
// // 분기점 그리기
|
||||
// foreach (var branch in line.BranchPoints)
|
||||
// {
|
||||
// g.FillEllipse(Brushes.Red, branch.X - 3, branch.Y - 3, 6, 6);
|
||||
// var direction = line.BranchDirections[branch];
|
||||
// g.DrawString(direction.ToString(), Font, Brushes.Black, branch.X + 5, branch.Y - 5);
|
||||
// }
|
||||
//}
|
||||
|
||||
// RFID 포인트 그리기
|
||||
foreach (var rfid in rfidPoints)
|
||||
{
|
||||
@@ -1297,20 +1266,23 @@ namespace AGVControl
|
||||
|
||||
private void DrawRFIDLines(Graphics g)
|
||||
{
|
||||
foreach (var line in rfidLines)
|
||||
foreach (var connection in rfidConnections)
|
||||
{
|
||||
var startPoint = rfidPoints.First(p => p.RFIDValue == connection.StartRFID).Location;
|
||||
var endPoint = rfidPoints.First(p => p.RFIDValue == connection.EndRFID).Location;
|
||||
|
||||
using (Pen linePen = new Pen(Color.FromArgb(50, Color.Wheat), 2))
|
||||
{
|
||||
if (line.IsBidirectional)
|
||||
if (connection.IsBidirectional)
|
||||
{
|
||||
// 단방향 화살표 그리기
|
||||
var arrowSize = 10;
|
||||
var angle = Math.Atan2(line.EndPoint.Y - line.StartPoint.Y, line.EndPoint.X - line.StartPoint.X);
|
||||
var angle = Math.Atan2(endPoint.Y - startPoint.Y, endPoint.X - startPoint.X);
|
||||
var arrowPoint = new PointF(
|
||||
line.EndPoint.X - (float)(arrowSize * Math.Cos(angle)),
|
||||
line.EndPoint.Y - (float)(arrowSize * Math.Sin(angle))
|
||||
endPoint.X - (float)(arrowSize * Math.Cos(angle)),
|
||||
endPoint.Y - (float)(arrowSize * Math.Sin(angle))
|
||||
);
|
||||
g.DrawLine(linePen, line.StartPoint, arrowPoint);
|
||||
g.DrawLine(linePen, startPoint, arrowPoint);
|
||||
|
||||
// 화살표 머리 그리기
|
||||
var arrowAngle = Math.PI / 6;
|
||||
@@ -1328,7 +1300,7 @@ namespace AGVControl
|
||||
}
|
||||
else
|
||||
{
|
||||
g.DrawLine(linePen, line.StartPoint, line.EndPoint);
|
||||
g.DrawLine(linePen, startPoint, endPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1368,21 +1340,6 @@ namespace AGVControl
|
||||
return rfidPoints;
|
||||
}
|
||||
|
||||
public List<MagnetLine> GetMagnetLines()
|
||||
{
|
||||
return magnetLines;
|
||||
}
|
||||
|
||||
public List<MapText> GetMapTexts()
|
||||
{
|
||||
return mapTexts;
|
||||
}
|
||||
|
||||
public List<CustomLine> GetCustomLines()
|
||||
{
|
||||
return customLines;
|
||||
}
|
||||
|
||||
public List<RFIDLine> GetRFIDLines()
|
||||
{
|
||||
return rfidLines;
|
||||
@@ -1466,7 +1423,6 @@ namespace AGVControl
|
||||
public void LoadMapData(MapData mapData)
|
||||
{
|
||||
rfidPoints = mapData.RFIDPoints ?? new List<RFIDPoint>();
|
||||
magnetLines = mapData.MagnetLines ?? new List<MagnetLine>();
|
||||
mapTexts = mapData.MapTexts ?? new List<MapText>();
|
||||
customLines = mapData.CustomLines ?? new List<CustomLine>();
|
||||
rfidLines = mapData.RFIDLines ?? new List<RFIDLine>();
|
||||
@@ -1476,7 +1432,6 @@ namespace AGVControl
|
||||
public void ClearMap()
|
||||
{
|
||||
rfidPoints.Clear();
|
||||
magnetLines.Clear();
|
||||
mapTexts.Clear();
|
||||
customLines.Clear();
|
||||
rfidLines.Clear();
|
||||
@@ -1485,7 +1440,6 @@ namespace AGVControl
|
||||
selectedText = null;
|
||||
selectedLine = null;
|
||||
selectedRFID = null;
|
||||
selectedMagnetLine = null;
|
||||
selectedRFIDLine = null;
|
||||
draggingPoint = null;
|
||||
|
||||
@@ -1509,25 +1463,6 @@ namespace AGVControl
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
public void AddMagnetLine(Point startPoint, Point endPoint, Point? branchPoint = null, BranchDirection? branchDirection = null)
|
||||
{
|
||||
// 이미 맵 좌표로 변환된 위치를 받아서 사용
|
||||
var line = new MagnetLine
|
||||
{
|
||||
StartPoint = startPoint,
|
||||
EndPoint = endPoint
|
||||
};
|
||||
|
||||
if (branchPoint.HasValue && branchDirection.HasValue)
|
||||
{
|
||||
line.BranchPoints.Add(branchPoint.Value);
|
||||
line.BranchDirections[branchPoint.Value] = branchDirection.Value;
|
||||
}
|
||||
|
||||
magnetLines.Add(line);
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
public void SaveToFile(string filename)
|
||||
{
|
||||
var lines = new List<string>();
|
||||
@@ -1541,10 +1476,12 @@ namespace AGVControl
|
||||
|
||||
// RFID 라인 저장
|
||||
lines.Add("[RFID_LINES]");
|
||||
foreach (var line in rfidLines)
|
||||
foreach (var connection in rfidConnections)
|
||||
{
|
||||
lines.Add($"{line.StartPoint.X},{line.StartPoint.Y},{line.EndPoint.X},{line.EndPoint.Y}," +
|
||||
$"{line.StartRFID},{line.EndRFID},{line.IsBidirectional},{line.Distance}");
|
||||
var startPoint = rfidPoints.First(p => p.RFIDValue == connection.StartRFID).Location;
|
||||
var endPoint = rfidPoints.First(p => p.RFIDValue == connection.EndRFID).Location;
|
||||
lines.Add($"{startPoint.X},{startPoint.Y},{endPoint.X},{endPoint.Y}," +
|
||||
$"{connection.StartRFID},{connection.EndRFID},{connection.IsBidirectional},{connection.Distance}");
|
||||
}
|
||||
|
||||
// 텍스트 저장
|
||||
@@ -1561,7 +1498,6 @@ namespace AGVControl
|
||||
lines.Add($"{line.StartPoint.X},{line.StartPoint.Y},{line.EndPoint.X},{line.EndPoint.Y},{line.LineColor.ToArgb()},{line.LineWidth}");
|
||||
}
|
||||
|
||||
|
||||
File.WriteAllLines(filename, lines);
|
||||
}
|
||||
|
||||
@@ -1614,35 +1550,6 @@ namespace AGVControl
|
||||
}
|
||||
break;
|
||||
|
||||
case "[MAGNET_LINES]":
|
||||
var lineParts = line.Split('|');
|
||||
var mainParts = lineParts[0].Split(',');
|
||||
if (mainParts.Length >= 4)
|
||||
{
|
||||
var magnetLine = new MagnetLine
|
||||
{
|
||||
StartPoint = new Point(int.Parse(mainParts[0]), int.Parse(mainParts[1])),
|
||||
EndPoint = new Point(int.Parse(mainParts[2]), int.Parse(mainParts[3]))
|
||||
};
|
||||
|
||||
// 분기점 정보 처리
|
||||
for (int i = 1; i < lineParts.Length; i++)
|
||||
{
|
||||
var branchParts = lineParts[i].Split(',');
|
||||
if (branchParts.Length >= 3)
|
||||
{
|
||||
var branchPoint = new Point(
|
||||
int.Parse(branchParts[0]),
|
||||
int.Parse(branchParts[1])
|
||||
);
|
||||
magnetLine.BranchPoints.Add(branchPoint);
|
||||
magnetLine.BranchDirections[branchPoint] = (BranchDirection)int.Parse(branchParts[2]);
|
||||
}
|
||||
}
|
||||
magnetLines.Add(magnetLine);
|
||||
}
|
||||
break;
|
||||
|
||||
case "[MAP_TEXTS]":
|
||||
var textParts = line.Split(',');
|
||||
if (textParts.Length >= 7)
|
||||
@@ -1673,16 +1580,79 @@ namespace AGVControl
|
||||
customLines.Add(customLine);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// RFID 연결 정보 처리
|
||||
ProcessRFIDConnections();
|
||||
|
||||
this.Invalidate();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private void ProcessRFIDConnections()
|
||||
{
|
||||
rfidConnections.Clear();
|
||||
var connectionSet = new HashSet<string>();
|
||||
|
||||
foreach (var line in rfidLines)
|
||||
{
|
||||
var start = line.StartPoint;
|
||||
var end = line.EndPoint;
|
||||
|
||||
// 1. 선 위의 모든 RFID 포인트(시작, 끝 포함)를 projectionRatio로 정렬
|
||||
var pointsOnThisLine = rfidPoints
|
||||
.Where(p => IsPointOnLine(p.Location, start, end, 15f)) // 오차 허용치 넉넉히
|
||||
.Select(p => new
|
||||
{
|
||||
RFID = p.RFIDValue,
|
||||
Ratio = GetProjectionRatio(p.Location, start, end)
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// 2. 시작/끝 RFID가 목록에 없으면 강제로 추가
|
||||
if (!pointsOnThisLine.Any(p => p.RFID == line.StartRFID))
|
||||
pointsOnThisLine.Add(new { RFID = line.StartRFID, Ratio = 0f });
|
||||
if (!pointsOnThisLine.Any(p => p.RFID == line.EndRFID))
|
||||
pointsOnThisLine.Add(new { RFID = line.EndRFID, Ratio = 1f });
|
||||
|
||||
// 3. 정렬
|
||||
pointsOnThisLine = pointsOnThisLine.OrderBy(p => p.Ratio).ToList();
|
||||
|
||||
// 4. 순서대로 1:1 연결
|
||||
for (int i = 0; i < pointsOnThisLine.Count - 1; i++)
|
||||
{
|
||||
var from = pointsOnThisLine[i].RFID;
|
||||
var to = pointsOnThisLine[i + 1].RFID;
|
||||
var key = $"{Math.Min(from, to)}_{Math.Max(from, to)}";
|
||||
if (connectionSet.Contains(key)) continue;
|
||||
|
||||
var fromPt = rfidPoints.FirstOrDefault(p => p.RFIDValue == from)?.Location ?? line.StartPoint;
|
||||
var toPt = rfidPoints.FirstOrDefault(p => p.RFIDValue == to)?.Location ?? line.EndPoint;
|
||||
|
||||
rfidConnections.Add(new RFIDConnection
|
||||
{
|
||||
StartRFID = from,
|
||||
EndRFID = to,
|
||||
IsBidirectional = line.IsBidirectional,
|
||||
Distance = GetDistance(fromPt, toPt)
|
||||
});
|
||||
connectionSet.Add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tolerance 인자를 받는 IsPointOnLine
|
||||
private bool IsPointOnLine(Point point, Point lineStart, Point lineEnd, float tolerance = 10.0f)
|
||||
{
|
||||
var distance = GetDistanceToLine(point, lineStart, lineEnd);
|
||||
if (distance > tolerance) return false;
|
||||
|
||||
var projectionRatio = GetProjectionRatio(point, lineStart, lineEnd);
|
||||
return projectionRatio >= 0 && projectionRatio <= 1;
|
||||
}
|
||||
|
||||
private void DeleteNearbyRFIDLine(Point clickPoint)
|
||||
{
|
||||
const float DELETE_DISTANCE = 10.0f; // 클릭 지점으로부터의 허용 거리
|
||||
|
||||
Reference in New Issue
Block a user