diff --git a/Cs_HMI/AGVLogic/AGVMapEditor/AGVMapEditor.csproj b/Cs_HMI/AGVLogic/AGVMapEditor/AGVMapEditor.csproj
index 3d7f65b..66fc387 100644
--- a/Cs_HMI/AGVLogic/AGVMapEditor/AGVMapEditor.csproj
+++ b/Cs_HMI/AGVLogic/AGVMapEditor/AGVMapEditor.csproj
@@ -49,9 +49,15 @@
+
+ UserControl
+
Form
+
+ ImageEditorForm.cs
+
@@ -86,7 +92,6 @@
-
\ No newline at end of file
diff --git a/Cs_HMI/AGVLogic/AGVMapEditor/Controls/ImageEditorCanvas.cs b/Cs_HMI/AGVLogic/AGVMapEditor/Controls/ImageEditorCanvas.cs
new file mode 100644
index 0000000..ad153f8
--- /dev/null
+++ b/Cs_HMI/AGVLogic/AGVMapEditor/Controls/ImageEditorCanvas.cs
@@ -0,0 +1,413 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+
+namespace AGVMapEditor.Controls
+{
+ ///
+ /// 이미지 편집용 사용자 정의 캔버스 컨트롤
+ /// 이미지 중앙 정렬, 크기 조정 핸들, 브러시 그리기 기능 제공
+ ///
+ public class ImageEditorCanvas : UserControl
+ {
+ private Bitmap _editingImage;
+ private Graphics _imageGraphics;
+ private Rectangle _imageRect = Rectangle.Empty;
+ private float _imageDisplayWidth = 0;
+ private float _imageDisplayHeight = 0;
+
+ // 브러시 그리기
+ private bool _isDrawing = false;
+ private Point _lastDrawPoint = Point.Empty;
+ private Color _drawColor = Color.Black;
+ private int _brushSize = 3;
+ private bool _brushModeEnabled = false;
+
+ // 크기 조정
+ private bool _isResizing = false;
+ private ResizeHandle _activeHandle = ResizeHandle.None;
+ private Point _resizeStartPoint = Point.Empty;
+ private float _resizeStartWidth = 0;
+ private float _resizeStartHeight = 0;
+ private const int HANDLE_SIZE = 8;
+
+ private enum ResizeHandle
+ {
+ None,
+ TopLeft, Top, TopRight,
+ Right, BottomRight, Bottom,
+ BottomLeft, Left
+ }
+
+ public ImageEditorCanvas()
+ {
+ this.DoubleBuffered = true;
+ this.BackColor = Color.White;
+ this.AutoScroll = true;
+ }
+
+ #region Properties
+
+ public Bitmap EditingImage
+ {
+ get => _editingImage;
+ set
+ {
+ _editingImage = value;
+ if (_editingImage != null)
+ {
+ _imageGraphics?.Dispose();
+ _imageGraphics = Graphics.FromImage(_editingImage);
+ _imageDisplayWidth = _editingImage.Width;
+ _imageDisplayHeight = _editingImage.Height;
+ UpdateImageRect();
+ }
+ Invalidate();
+ }
+ }
+
+ public Color DrawColor
+ {
+ get => _drawColor;
+ set => _drawColor = value;
+ }
+
+ public int BrushSize
+ {
+ get => _brushSize;
+ set => _brushSize = value;
+ }
+
+ public bool BrushModeEnabled
+ {
+ get => _brushModeEnabled;
+ set => _brushModeEnabled = value;
+ }
+
+ public Size ImageDisplaySize => new Size((int)_imageDisplayWidth, (int)_imageDisplayHeight);
+
+ #endregion
+
+ #region Paint
+
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ base.OnPaint(e);
+
+ if (_editingImage == null)
+ {
+ e.Graphics.Clear(BackColor);
+ return;
+ }
+
+ // 배경 채우기
+ e.Graphics.Clear(BackColor);
+
+ // 이미지 영역 업데이트
+ UpdateImageRect();
+
+ // 이미지 그리기 (고품질)
+ e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ e.Graphics.DrawImage(_editingImage, _imageRect);
+
+ // 크기 조정 핸들 그리기
+ DrawResizeHandles(e.Graphics);
+ }
+
+ private void UpdateImageRect()
+ {
+ if (_editingImage == null || Width == 0 || Height == 0)
+ {
+ _imageRect = Rectangle.Empty;
+ return;
+ }
+
+ // 이미지를 중앙 정렬
+ float x = (Width - _imageDisplayWidth) / 2f;
+ float y = (Height - _imageDisplayHeight) / 2f;
+
+ // 음수 방지
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+
+ _imageRect = new Rectangle((int)x, (int)y, (int)_imageDisplayWidth, (int)_imageDisplayHeight);
+ }
+
+ private void DrawResizeHandles(Graphics g)
+ {
+ if (_imageRect.IsEmpty)
+ return;
+
+ var handles = GetResizeHandles();
+ foreach (var handle in handles)
+ {
+ g.FillRectangle(Brushes.Blue, handle);
+ g.DrawRectangle(Pens.White, handle);
+ }
+ }
+
+ private Rectangle[] GetResizeHandles()
+ {
+ int x = _imageRect.X;
+ int y = _imageRect.Y;
+ int w = _imageRect.Width;
+ int h = _imageRect.Height;
+ int hs = HANDLE_SIZE;
+
+ return new Rectangle[]
+ {
+ new Rectangle(x - hs/2, y - hs/2, hs, hs), // TopLeft
+ new Rectangle(x + w/2 - hs/2, y - hs/2, hs, hs), // Top
+ new Rectangle(x + w - hs/2, y - hs/2, hs, hs), // TopRight
+ new Rectangle(x + w - hs/2, y + h/2 - hs/2, hs, hs), // Right
+ new Rectangle(x + w - hs/2, y + h - hs/2, hs, hs), // BottomRight
+ new Rectangle(x + w/2 - hs/2, y + h - hs/2, hs, hs), // Bottom
+ new Rectangle(x - hs/2, y + h - hs/2, hs, hs), // BottomLeft
+ new Rectangle(x - hs/2, y + h/2 - hs/2, hs, hs) // Left
+ };
+ }
+
+ #endregion
+
+ #region Mouse Events
+
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ base.OnMouseDown(e);
+
+ if (_editingImage == null || e.Button != MouseButtons.Left)
+ return;
+
+ // 크기 조정 핸들 확인
+ _activeHandle = GetHandleAtPoint(e.Location);
+ if (_activeHandle != ResizeHandle.None)
+ {
+ _isResizing = true;
+ _resizeStartPoint = e.Location;
+ _resizeStartWidth = _imageDisplayWidth;
+ _resizeStartHeight = _imageDisplayHeight;
+ return;
+ }
+
+ // 브러시 모드: 그리기
+ if (_brushModeEnabled && _imageRect.Contains(e.Location))
+ {
+ _isDrawing = true;
+ _lastDrawPoint = ImagePointFromScreen(e.Location);
+ }
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ base.OnMouseMove(e);
+
+ if (_editingImage == null)
+ return;
+
+ // 크기 조정 중
+ if (_isResizing && _activeHandle != ResizeHandle.None)
+ {
+ ResizeImageDisplay(e.Location);
+ return;
+ }
+
+ // 크기 조정 핸들 위에 마우스가 있으면 커서 변경
+ var handle = GetHandleAtPoint(e.Location);
+ if (handle != ResizeHandle.None)
+ {
+ Cursor = GetCursorForHandle(handle);
+ return;
+ }
+ else
+ {
+ Cursor = Cursors.Default;
+ }
+
+ // 브러시 모드: 그리기
+ if (_isDrawing && _lastDrawPoint != Point.Empty && _brushModeEnabled && _imageRect.Contains(e.Location))
+ {
+ Point currentImagePoint = ImagePointFromScreen(e.Location);
+ _imageGraphics.DrawLine(new Pen(_drawColor, _brushSize), _lastDrawPoint, currentImagePoint);
+ _lastDrawPoint = currentImagePoint;
+ Invalidate();
+ }
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ base.OnMouseUp(e);
+
+ if (_isResizing)
+ {
+ _isResizing = false;
+ _activeHandle = ResizeHandle.None;
+ }
+
+ if (_isDrawing)
+ {
+ _isDrawing = false;
+ _lastDrawPoint = Point.Empty;
+ }
+ }
+
+ protected override void OnResize(EventArgs e)
+ {
+ base.OnResize(e);
+ UpdateImageRect();
+ Invalidate();
+ }
+
+ #endregion
+
+ #region Helper Methods
+
+ ///
+ /// 화면 좌표를 이미지 좌표로 변환
+ ///
+ private Point ImagePointFromScreen(Point screenPoint)
+ {
+ if (_imageRect.IsEmpty || _editingImage == null)
+ return Point.Empty;
+
+ // 화면 좌표를 이미지 비율로 변환
+ float scaleX = (float)_editingImage.Width / _imageRect.Width;
+ float scaleY = (float)_editingImage.Height / _imageRect.Height;
+
+ int imageX = (int)((screenPoint.X - _imageRect.X) * scaleX);
+ int imageY = (int)((screenPoint.Y - _imageRect.Y) * scaleY);
+
+ return new Point(imageX, imageY);
+ }
+
+ private ResizeHandle GetHandleAtPoint(Point pt)
+ {
+ var handles = GetResizeHandles();
+ var handleTypes = new[]
+ {
+ ResizeHandle.TopLeft, ResizeHandle.Top, ResizeHandle.TopRight,
+ ResizeHandle.Right, ResizeHandle.BottomRight, ResizeHandle.Bottom,
+ ResizeHandle.BottomLeft, ResizeHandle.Left
+ };
+
+ for (int i = 0; i < handles.Length; i++)
+ {
+ if (handles[i].Contains(pt))
+ return handleTypes[i];
+ }
+
+ return ResizeHandle.None;
+ }
+
+ private Cursor GetCursorForHandle(ResizeHandle handle)
+ {
+ switch (handle)
+ {
+ case ResizeHandle.TopLeft:
+ case ResizeHandle.BottomRight:
+ return Cursors.SizeNWSE;
+ case ResizeHandle.TopRight:
+ case ResizeHandle.BottomLeft:
+ return Cursors.SizeNESW;
+ case ResizeHandle.Top:
+ case ResizeHandle.Bottom:
+ return Cursors.SizeNS;
+ case ResizeHandle.Left:
+ case ResizeHandle.Right:
+ return Cursors.SizeWE;
+ default:
+ return Cursors.Default;
+ }
+ }
+
+ private void ResizeImageDisplay(Point currentPoint)
+ {
+ int deltaX = currentPoint.X - _resizeStartPoint.X;
+ int deltaY = currentPoint.Y - _resizeStartPoint.Y;
+
+ float newWidth = _resizeStartWidth;
+ float newHeight = _resizeStartHeight;
+
+ switch (_activeHandle)
+ {
+ case ResizeHandle.TopLeft:
+ newWidth -= deltaX;
+ newHeight -= deltaY;
+ break;
+ case ResizeHandle.Top:
+ newHeight -= deltaY;
+ break;
+ case ResizeHandle.TopRight:
+ newWidth += deltaX;
+ newHeight -= deltaY;
+ break;
+ case ResizeHandle.Right:
+ newWidth += deltaX;
+ break;
+ case ResizeHandle.BottomRight:
+ newWidth += deltaX;
+ newHeight += deltaY;
+ break;
+ case ResizeHandle.Bottom:
+ newHeight += deltaY;
+ break;
+ case ResizeHandle.BottomLeft:
+ newWidth -= deltaX;
+ newHeight += deltaY;
+ break;
+ case ResizeHandle.Left:
+ newWidth -= deltaX;
+ break;
+ }
+
+ // 최소 크기 제한
+ if (newWidth < 50) newWidth = 50;
+ if (newHeight < 50) newHeight = 50;
+
+ _imageDisplayWidth = newWidth;
+ _imageDisplayHeight = newHeight;
+
+ UpdateImageRect();
+ Invalidate();
+ }
+
+ ///
+ /// 표시 크기로 실제 이미지 리사이즈
+ ///
+ public Bitmap GetResizedImage()
+ {
+ if (_editingImage == null)
+ return null;
+
+ int targetWidth = (int)_imageDisplayWidth;
+ int targetHeight = (int)_imageDisplayHeight;
+
+ // 크기가 같으면 원본 반환
+ if (targetWidth == _editingImage.Width && targetHeight == _editingImage.Height)
+ return new Bitmap(_editingImage);
+
+ // 리사이즈
+ var resized = new Bitmap(targetWidth, targetHeight);
+ using (var g = Graphics.FromImage(resized))
+ {
+ g.CompositingQuality = CompositingQuality.HighQuality;
+ g.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ g.SmoothingMode = SmoothingMode.HighQuality;
+ g.DrawImage(_editingImage, 0, 0, targetWidth, targetHeight);
+ }
+
+ return resized;
+ }
+
+ #endregion
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _imageGraphics?.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+ }
+}
diff --git a/Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.Designer.cs b/Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.Designer.cs
new file mode 100644
index 0000000..864a786
--- /dev/null
+++ b/Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.Designer.cs
@@ -0,0 +1,188 @@
+namespace AGVMapEditor.Forms
+{
+ partial class ImageEditorForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.toolPanel = new System.Windows.Forms.Panel();
+ this.chkBrushMode = new System.Windows.Forms.CheckBox();
+ this.btnColor = new System.Windows.Forms.Button();
+ this.trackBrush = new System.Windows.Forms.TrackBar();
+ this.lblBrush = new System.Windows.Forms.Label();
+ this.btnSave = new System.Windows.Forms.Button();
+ this.btnResize = new System.Windows.Forms.Button();
+ this.btnOpen = new System.Windows.Forms.Button();
+ this.canvasPanel = new System.Windows.Forms.Panel();
+ this.imageCanvas = new AGVMapEditor.Controls.ImageEditorCanvas();
+ this.toolPanel.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.trackBrush)).BeginInit();
+ this.canvasPanel.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // toolPanel
+ //
+ this.toolPanel.BackColor = System.Drawing.Color.LightGray;
+ this.toolPanel.Controls.Add(this.chkBrushMode);
+ this.toolPanel.Controls.Add(this.btnColor);
+ this.toolPanel.Controls.Add(this.trackBrush);
+ this.toolPanel.Controls.Add(this.lblBrush);
+ this.toolPanel.Controls.Add(this.btnSave);
+ this.toolPanel.Controls.Add(this.btnResize);
+ this.toolPanel.Controls.Add(this.btnOpen);
+ this.toolPanel.Dock = System.Windows.Forms.DockStyle.Top;
+ this.toolPanel.Location = new System.Drawing.Point(0, 0);
+ this.toolPanel.Name = "toolPanel";
+ this.toolPanel.Size = new System.Drawing.Size(800, 50);
+ this.toolPanel.TabIndex = 0;
+ //
+ // chkBrushMode
+ //
+ this.chkBrushMode.AutoSize = true;
+ this.chkBrushMode.Location = new System.Drawing.Point(590, 15);
+ this.chkBrushMode.Name = "chkBrushMode";
+ this.chkBrushMode.Size = new System.Drawing.Size(96, 16);
+ this.chkBrushMode.TabIndex = 6;
+ this.chkBrushMode.Text = "브러시 모드";
+ this.chkBrushMode.UseVisualStyleBackColor = true;
+ //
+ // btnColor
+ //
+ this.btnColor.BackColor = System.Drawing.Color.Black;
+ this.btnColor.ForeColor = System.Drawing.Color.White;
+ this.btnColor.Location = new System.Drawing.Point(520, 10);
+ this.btnColor.Name = "btnColor";
+ this.btnColor.Size = new System.Drawing.Size(60, 23);
+ this.btnColor.TabIndex = 5;
+ this.btnColor.Text = "색상";
+ this.btnColor.UseVisualStyleBackColor = false;
+ this.btnColor.Click += new System.EventHandler(this.BtnColor_Click);
+ //
+ // trackBrush
+ //
+ this.trackBrush.Location = new System.Drawing.Point(410, 10);
+ this.trackBrush.Maximum = 20;
+ this.trackBrush.Minimum = 1;
+ this.trackBrush.Name = "trackBrush";
+ this.trackBrush.Size = new System.Drawing.Size(100, 45);
+ this.trackBrush.TabIndex = 4;
+ this.trackBrush.Value = 3;
+ this.trackBrush.ValueChanged += new System.EventHandler(this.TrackBrush_ValueChanged);
+ //
+ // lblBrush
+ //
+ this.lblBrush.AutoSize = true;
+ this.lblBrush.Location = new System.Drawing.Point(350, 15);
+ this.lblBrush.Name = "lblBrush";
+ this.lblBrush.Size = new System.Drawing.Size(54, 12);
+ this.lblBrush.TabIndex = 3;
+ this.lblBrush.Text = "브러시:";
+ //
+ // btnSave
+ //
+ this.btnSave.Location = new System.Drawing.Point(230, 10);
+ this.btnSave.Name = "btnSave";
+ this.btnSave.Size = new System.Drawing.Size(100, 23);
+ this.btnSave.TabIndex = 2;
+ this.btnSave.Text = "저장 및 닫기";
+ this.btnSave.UseVisualStyleBackColor = true;
+ this.btnSave.Click += new System.EventHandler(this.BtnSave_Click);
+ //
+ // btnResize
+ //
+ this.btnResize.Location = new System.Drawing.Point(120, 10);
+ this.btnResize.Name = "btnResize";
+ this.btnResize.Size = new System.Drawing.Size(100, 23);
+ this.btnResize.TabIndex = 1;
+ this.btnResize.Text = "크기 조정";
+ this.btnResize.UseVisualStyleBackColor = true;
+ this.btnResize.Click += new System.EventHandler(this.BtnResize_Click);
+ //
+ // btnOpen
+ //
+ this.btnOpen.Location = new System.Drawing.Point(10, 10);
+ this.btnOpen.Name = "btnOpen";
+ this.btnOpen.Size = new System.Drawing.Size(100, 23);
+ this.btnOpen.TabIndex = 0;
+ this.btnOpen.Text = "이미지 열기";
+ this.btnOpen.UseVisualStyleBackColor = true;
+ this.btnOpen.Click += new System.EventHandler(this.BtnOpen_Click);
+ //
+ // canvasPanel
+ //
+ this.canvasPanel.AutoScroll = true;
+ this.canvasPanel.BackColor = System.Drawing.Color.White;
+ this.canvasPanel.Controls.Add(this.imageCanvas);
+ this.canvasPanel.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.canvasPanel.Location = new System.Drawing.Point(0, 50);
+ this.canvasPanel.Name = "canvasPanel";
+ this.canvasPanel.Size = new System.Drawing.Size(800, 550);
+ this.canvasPanel.TabIndex = 1;
+ //
+ // imageCanvas
+ //
+ this.imageCanvas.BackColor = System.Drawing.Color.White;
+ this.imageCanvas.BrushModeEnabled = false;
+ this.imageCanvas.BrushSize = 3;
+ this.imageCanvas.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.imageCanvas.DrawColor = System.Drawing.Color.Black;
+ this.imageCanvas.Location = new System.Drawing.Point(0, 0);
+ this.imageCanvas.Name = "imageCanvas";
+ this.imageCanvas.Size = new System.Drawing.Size(800, 550);
+ this.imageCanvas.TabIndex = 0;
+ //
+ // ImageEditorForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(800, 600);
+ this.Controls.Add(this.canvasPanel);
+ this.Controls.Add(this.toolPanel);
+ this.Name = "ImageEditorForm";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "이미지 편집기";
+ this.toolPanel.ResumeLayout(false);
+ this.toolPanel.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.trackBrush)).EndInit();
+ this.canvasPanel.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Panel toolPanel;
+ private System.Windows.Forms.Button btnOpen;
+ private System.Windows.Forms.Button btnResize;
+ private System.Windows.Forms.Button btnSave;
+ private System.Windows.Forms.Label lblBrush;
+ private System.Windows.Forms.TrackBar trackBrush;
+ private System.Windows.Forms.Button btnColor;
+ private System.Windows.Forms.CheckBox chkBrushMode;
+ private System.Windows.Forms.Panel canvasPanel;
+ private AGVMapEditor.Controls.ImageEditorCanvas imageCanvas;
+ }
+}
diff --git a/Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.cs b/Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.cs
index 68bfa7d..74272cc 100644
--- a/Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.cs
+++ b/Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.cs
@@ -1,7 +1,6 @@
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
-using System.Linq;
using System.Windows.Forms;
using AGVNavigationCore.Models;
using AGVNavigationCore.Utils;
@@ -14,17 +13,11 @@ namespace AGVMapEditor.Forms
///
public partial class ImageEditorForm : Form
{
- private Bitmap _editingImage;
- private Graphics _graphics;
- private bool _isDrawing = false;
- private Point _lastPoint = Point.Empty;
- private Color _drawColor = Color.Black;
- private int _brushSize = 3;
private MapNode _targetNode;
public ImageEditorForm(MapNode imageNode = null)
{
- //InitializeComponent();
+ InitializeComponent();
_targetNode = imageNode;
SetupUI();
@@ -36,64 +29,25 @@ namespace AGVMapEditor.Forms
private void SetupUI()
{
- this.Text = "이미지 편집기";
- this.Size = new Size(800, 600);
- this.StartPosition = FormStartPosition.CenterScreen;
+ // 캔버스 초기 설정
+ imageCanvas.BrushSize = trackBrush.Value;
+ imageCanvas.BrushModeEnabled = chkBrushMode.Checked;
+ imageCanvas.BackColor = Color.FromArgb(32,32,32);
- // 패널: 도구 모음
- var toolPanel = new Panel { Dock = DockStyle.Top, Height = 50, BackColor = Color.LightGray };
+ // 이벤트 연결
+ chkBrushMode.CheckedChanged += (s, e) => imageCanvas.BrushModeEnabled = chkBrushMode.Checked;
+ }
- // 버튼: 이미지 열기
- var btnOpen = new Button { Text = "이미지 열기", Width = 100, Left = 10, Top = 10 };
- btnOpen.Click += BtnOpen_Click;
- toolPanel.Controls.Add(btnOpen);
-
- // 버튼: 크기 조정
- var btnResize = new Button { Text = "크기 조정", Width = 100, Left = 120, Top = 10 };
- btnResize.Click += BtnResize_Click;
- toolPanel.Controls.Add(btnResize);
-
- // 버튼: 저장
- var btnSave = new Button { Text = "저장 및 닫기", Width = 100, Left = 230, Top = 10 };
- btnSave.Click += BtnSave_Click;
- toolPanel.Controls.Add(btnSave);
-
- // 라벨: 브러시 크기
- var lblBrush = new Label { Text = "브러시:", Left = 350, Top = 15, Width = 50 };
- toolPanel.Controls.Add(lblBrush);
-
- // 트랙바: 브러시 크기 조절
- var trackBrush = new TrackBar { Left = 410, Top = 10, Width = 100, Minimum = 1, Maximum = 20, Value = 3 };
- trackBrush.ValueChanged += (s, e) => _brushSize = trackBrush.Value;
- toolPanel.Controls.Add(trackBrush);
-
- // 버튼: 색상 선택
- var btnColor = new Button { Text = "색상", Width = 60, Left = 520, Top = 10, BackColor = Color.Black, ForeColor = Color.White };
- btnColor.Click += BtnColor_Click;
- toolPanel.Controls.Add(btnColor);
-
- // 패널: 캔버스
- var canvasPanel = new Panel { Dock = DockStyle.Fill, AutoScroll = true, BackColor = Color.White };
- var pictureBox = new PictureBox { SizeMode = PictureBoxSizeMode.AutoSize };
- pictureBox.Name = "pictureBoxCanvas";
- pictureBox.MouseDown += PictureBox_MouseDown;
- pictureBox.MouseMove += PictureBox_MouseMove;
- pictureBox.MouseUp += PictureBox_MouseUp;
- canvasPanel.Controls.Add(pictureBox);
-
- this.Controls.Add(canvasPanel);
- this.Controls.Add(toolPanel);
+ private void TrackBrush_ValueChanged(object sender, EventArgs e)
+ {
+ imageCanvas.BrushSize = trackBrush.Value;
}
private void LoadImageFromNode(MapNode node)
{
if (node.LoadedImage != null)
{
- _editingImage?.Dispose();
- _graphics?.Dispose();
- _editingImage = new Bitmap(node.LoadedImage);
- _graphics = Graphics.FromImage(_editingImage);
- UpdateCanvas();
+ imageCanvas.EditingImage = new Bitmap(node.LoadedImage);
}
}
@@ -112,25 +66,22 @@ namespace AGVMapEditor.Forms
{
try
{
- _editingImage?.Dispose();
- _graphics?.Dispose();
-
var loadedImage = Image.FromFile(filePath);
// 이미지 크기가 크면 자동 축소 (최대 512x512)
+ Bitmap finalImage;
if (loadedImage.Width > 512 || loadedImage.Height > 512)
{
- _editingImage = ResizeImage(loadedImage, 512, 512);
+ finalImage = ResizeImage(loadedImage, 512, 512);
loadedImage.Dispose();
}
else
{
- _editingImage = new Bitmap(loadedImage);
+ finalImage = new Bitmap(loadedImage);
loadedImage.Dispose();
}
- _graphics = Graphics.FromImage(_editingImage);
- UpdateCanvas();
+ imageCanvas.EditingImage = finalImage;
}
catch (Exception ex)
{
@@ -140,12 +91,14 @@ namespace AGVMapEditor.Forms
private void BtnResize_Click(object sender, EventArgs e)
{
- if (_editingImage == null)
+ if (imageCanvas.EditingImage == null)
{
MessageBox.Show("먼저 이미지를 로드하세요.");
return;
}
+ var currentSize = imageCanvas.ImageDisplaySize;
+
using (var form = new Form())
{
form.Text = "이미지 크기 조정";
@@ -153,10 +106,10 @@ namespace AGVMapEditor.Forms
form.StartPosition = FormStartPosition.CenterParent;
var lblWidth = new Label { Text = "너비:", Left = 10, Top = 10, Width = 50 };
- var txtWidth = new TextBox { Left = 70, Top = 10, Width = 100, Text = _editingImage.Width.ToString() };
+ var txtWidth = new TextBox { Left = 70, Top = 10, Width = 100, Text = currentSize.Width.ToString() };
var lblHeight = new Label { Text = "높이:", Left = 10, Top = 40, Width = 50 };
- var txtHeight = new TextBox { Left = 70, Top = 40, Width = 100, Text = _editingImage.Height.ToString() };
+ var txtHeight = new TextBox { Left = 70, Top = 40, Width = 100, Text = currentSize.Height.ToString() };
var btnOk = new Button { Text = "적용", DialogResult = DialogResult.OK, Left = 70, Top = 70, Width = 100 };
var btnCancel = new Button { Text = "취소", DialogResult = DialogResult.Cancel, Left = 180, Top = 70, Width = 70 };
@@ -174,12 +127,8 @@ namespace AGVMapEditor.Forms
{
if (width > 0 && height > 0)
{
- _graphics?.Dispose();
- var resized = new Bitmap(_editingImage, width, height);
- _editingImage.Dispose();
- _editingImage = resized;
- _graphics = Graphics.FromImage(_editingImage);
- UpdateCanvas();
+ var resized = new Bitmap(imageCanvas.EditingImage, width, height);
+ imageCanvas.EditingImage = resized;
}
}
}
@@ -188,19 +137,19 @@ namespace AGVMapEditor.Forms
private void BtnColor_Click(object sender, EventArgs e)
{
- using (var cfd = new ColorDialog { Color = _drawColor })
+ using (var cfd = new ColorDialog { Color = imageCanvas.DrawColor })
{
if (cfd.ShowDialog() == DialogResult.OK)
{
- _drawColor = cfd.Color;
- (sender as Button).BackColor = _drawColor;
+ imageCanvas.DrawColor = cfd.Color;
+ (sender as Button).BackColor = cfd.Color;
}
}
}
private void BtnSave_Click(object sender, EventArgs e)
{
- if (_editingImage == null)
+ if (imageCanvas.EditingImage == null)
{
MessageBox.Show("저장할 이미지가 없습니다.");
return;
@@ -208,10 +157,22 @@ namespace AGVMapEditor.Forms
if (_targetNode != null && _targetNode.Type == NodeType.Image)
{
+ // 표시 크기로 리사이즈된 이미지 가져오기
+ var finalImage = imageCanvas.GetResizedImage();
+
+ if (finalImage == null)
+ {
+ MessageBox.Show("이미지 처리 중 오류가 발생했습니다.");
+ return;
+ }
+
+ var displaySize = imageCanvas.ImageDisplaySize;
+ MessageBox.Show($"이미지 크기: {displaySize.Width}x{displaySize.Height}로 저장됩니다.");
+
// 이미지를 Base64로 변환하여 저장
- _targetNode.ImageBase64 = ImageConverterUtil.ImageToBase64(_editingImage, System.Drawing.Imaging.ImageFormat.Png);
+ _targetNode.ImageBase64 = ImageConverterUtil.ImageToBase64(finalImage, System.Drawing.Imaging.ImageFormat.Png);
_targetNode.LoadedImage?.Dispose();
- _targetNode.LoadedImage = new Bitmap(_editingImage);
+ _targetNode.LoadedImage = finalImage;
MessageBox.Show("이미지가 저장되었습니다.");
this.DialogResult = DialogResult.OK;
@@ -219,41 +180,6 @@ namespace AGVMapEditor.Forms
}
}
- private void PictureBox_MouseDown(object sender, MouseEventArgs e)
- {
- if (_editingImage != null && e.Button == MouseButtons.Left)
- {
- _isDrawing = true;
- _lastPoint = e.Location;
- }
- }
-
- private void PictureBox_MouseMove(object sender, MouseEventArgs e)
- {
- if (_isDrawing && _lastPoint != Point.Empty)
- {
- _graphics.DrawLine(new Pen(_drawColor, _brushSize), _lastPoint, e.Location);
- _lastPoint = e.Location;
- UpdateCanvas();
- }
- }
-
- private void PictureBox_MouseUp(object sender, MouseEventArgs e)
- {
- _isDrawing = false;
- _lastPoint = Point.Empty;
- }
-
- private void UpdateCanvas()
- {
- var pictureBox = this.Controls.Find("pictureBoxCanvas", true).FirstOrDefault() as PictureBox;
- if (pictureBox != null)
- {
- pictureBox.Image?.Dispose();
- pictureBox.Image = new Bitmap(_editingImage);
- }
- }
-
private Bitmap ResizeImage(Image image, int maxWidth, int maxHeight)
{
double ratioX = (double)maxWidth / image.Width;
@@ -273,15 +199,5 @@ namespace AGVMapEditor.Forms
}
return resized;
}
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- _editingImage?.Dispose();
- _graphics?.Dispose();
- }
- base.Dispose(disposing);
- }
}
}
diff --git a/Cs_HMI/AGVLogic/AGVMapEditor/Forms/MainForm.cs b/Cs_HMI/AGVLogic/AGVMapEditor/Forms/MainForm.cs
index 4cb133e..fa8614a 100644
--- a/Cs_HMI/AGVLogic/AGVMapEditor/Forms/MainForm.cs
+++ b/Cs_HMI/AGVLogic/AGVMapEditor/Forms/MainForm.cs
@@ -1186,14 +1186,25 @@ namespace AGVMapEditor.Forms
if (fromNode != null && toNode != null)
{
- // 단일 연결 삭제 (어느 방향에 저장되어 있는지 확인 후 삭제)
+ // 양방향 연결 삭제 (양쪽 방향 모두 제거)
+ bool removed = false;
+
if (fromNode.ConnectedNodes.Contains(toNode.NodeId))
{
fromNode.RemoveConnection(toNode.NodeId);
+ removed = true;
}
- else if (toNode.ConnectedNodes.Contains(fromNode.NodeId))
+
+ if (toNode.ConnectedNodes.Contains(fromNode.NodeId))
{
toNode.RemoveConnection(fromNode.NodeId);
+ removed = true;
+ }
+
+ if (!removed)
+ {
+ MessageBox.Show("연결을 찾을 수 없습니다.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ return;
}
_hasChanges = true;
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs
index b6c4efa..aacf23f 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs
@@ -101,11 +101,10 @@ namespace AGVNavigationCore.Controls
foreach (var node in _nodes)
{
- if (node.ConnectedNodes == null) continue;
+ if (node.ConnectedMapNodes == null) continue;
- foreach (var connectedNodeId in node.ConnectedNodes)
+ foreach (var targetNode in node.ConnectedMapNodes)
{
- var targetNode = _nodes.FirstOrDefault(n => n.NodeId == connectedNodeId);
if (targetNode == null) continue;
DrawConnection(g, node, targetNode);
@@ -302,7 +301,7 @@ namespace AGVNavigationCore.Controls
if (node == null) continue;
// 교차로 판정: 3개 이상의 노드가 연결된 경우
- if (node.ConnectedNodes != null && node.ConnectedNodes.Count >= JUNCTION_CONNECTIONS)
+ if (node.ConnectedMapNodes != null && node.ConnectedMapNodes.Count >= JUNCTION_CONNECTIONS)
{
DrawJunctionHighlight(g, node);
}
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs
index a7d1387..1499fca 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs
@@ -567,15 +567,9 @@ namespace AGVNavigationCore.Controls
toNode.ConnectedNodes.Contains(fromNode.NodeId))
return;
- // 단일 연결 생성 (사전순으로 정렬하여 일관성 유지)
- if (string.Compare(fromNode.NodeId, toNode.NodeId, StringComparison.Ordinal) < 0)
- {
- fromNode.AddConnection(toNode.NodeId);
- }
- else
- {
- toNode.AddConnection(fromNode.NodeId);
- }
+ // 양방향 연결 생성 (AGV가 양쪽 방향으로 이동 가능하도록)
+ fromNode.AddConnection(toNode.NodeId);
+ toNode.AddConnection(fromNode.NodeId);
MapChanged?.Invoke(this, EventArgs.Empty);
}
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapLoader.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapLoader.cs
index f626947..d2176ec 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapLoader.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapLoader.cs
@@ -78,12 +78,13 @@ namespace AGVNavigationCore.Models
// 중복된 NodeId 정리
FixDuplicateNodeIds(result.Nodes);
- // 중복 연결 정리 (양방향 중복 제거)
- CleanupDuplicateConnections(result.Nodes);
-
// 양방향 연결 자동 설정 (A→B가 있으면 B→A도 설정)
+ // 주의: CleanupDuplicateConnections()는 제거됨 - 양방향 연결을 단방향으로 변환하는 버그가 있었음
EnsureBidirectionalConnections(result.Nodes);
+ // ConnectedMapNodes 채우기 (string ID → MapNode 객체 참조)
+ ResolveConnectedMapNodes(result.Nodes);
+
// 이미지 노드들의 이미지 로드
LoadImageNodes(result.Nodes);
@@ -145,6 +146,35 @@ namespace AGVNavigationCore.Models
}
}
+ ///
+ /// ConnectedMapNodes 채우기 (ConnectedNodes의 string ID → MapNode 객체 변환)
+ ///
+ /// 맵 노드 목록
+ private static void ResolveConnectedMapNodes(List mapNodes)
+ {
+ if (mapNodes == null || mapNodes.Count == 0) return;
+
+ // 빠른 조회를 위한 Dictionary 생성
+ var nodeDict = mapNodes.ToDictionary(n => n.NodeId, n => n);
+
+ foreach (var node in mapNodes)
+ {
+ // ConnectedMapNodes 초기화
+ node.ConnectedMapNodes.Clear();
+
+ if (node.ConnectedNodes != null && node.ConnectedNodes.Count > 0)
+ {
+ foreach (var connectedNodeId in node.ConnectedNodes)
+ {
+ if (nodeDict.TryGetValue(connectedNodeId, out var connectedNode))
+ {
+ node.ConnectedMapNodes.Add(connectedNode);
+ }
+ }
+ }
+ }
+ }
+
///
/// 기존 Description 데이터를 Name 필드로 마이그레이션
/// JSON 파일에서 Description 필드가 있는 경우 Name으로 이동
@@ -269,9 +299,12 @@ namespace AGVNavigationCore.Models
}
///
- /// 중복 연결을 정리합니다. 양방향 중복 연결을 단일 연결로 통합합니다.
+ /// [사용 중지됨] 중복 연결을 정리합니다. 양방향 중복 연결을 단일 연결로 통합합니다.
+ /// 주의: 이 함수는 버그가 있어 사용 중지됨 - 양방향 연결을 단방향으로 변환하여 경로 탐색 실패 발생
+ /// AGV 시스템에서는 모든 연결이 양방향이어야 하므로 EnsureBidirectionalConnections()만 사용
///
/// 맵 노드 목록
+ [Obsolete("이 함수는 양방향 연결을 단방향으로 변환하는 버그가 있습니다. 사용하지 마세요.")]
private static void CleanupDuplicateConnections(List mapNodes)
{
if (mapNodes == null || mapNodes.Count == 0) return;
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapNode.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapNode.cs
index 96064ba..64e2600 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapNode.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/MapNode.cs
@@ -44,6 +44,12 @@ namespace AGVNavigationCore.Models
///
public List ConnectedNodes { get; set; } = new List();
+ ///
+ /// 연결된 노드 객체 목록 (런타임 전용, JSON 무시)
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ public List ConnectedMapNodes { get; set; } = new List();
+
///
/// 회전 가능 여부 (180도 회전 가능한 지점)
///
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Analysis/JunctionAnalyzer.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Analysis/JunctionAnalyzer.cs
index f093621..5fcd92d 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Analysis/JunctionAnalyzer.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Analysis/JunctionAnalyzer.cs
@@ -92,15 +92,18 @@ namespace AGVNavigationCore.PathFinding.Analysis
var connected = new HashSet();
// 직접 연결된 노드들
- foreach (var connectedId in node.ConnectedNodes)
+ foreach (var connectedNode in node.ConnectedMapNodes)
{
- connected.Add(connectedId);
+ if (connectedNode != null)
+ {
+ connected.Add(connectedNode.NodeId);
+ }
}
// 역방향 연결된 노드들 (다른 노드에서 이 노드로 연결)
foreach (var otherNode in _mapNodes)
{
- if (otherNode.NodeId != node.NodeId && otherNode.ConnectedNodes.Contains(node.NodeId))
+ if (otherNode.NodeId != node.NodeId && otherNode.ConnectedMapNodes.Any(n => n.NodeId == node.NodeId))
{
connected.Add(otherNode.NodeId);
}
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Core/AStarPathfinder.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Core/AStarPathfinder.cs
index ed8105e..1df76c8 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Core/AStarPathfinder.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Core/AStarPathfinder.cs
@@ -66,17 +66,17 @@ namespace AGVNavigationCore.PathFinding.Core
{
var pathNode = _nodeMap[mapNode.NodeId];
- foreach (var connectedNode in mapNode.ConnectedNodes)
+ foreach (var connectedNode in mapNode.ConnectedMapNodes)
{
- if (_nodeMap.ContainsKey(connectedNode))
+ if (connectedNode != null && _nodeMap.ContainsKey(connectedNode.NodeId))
{
// 양방향 연결 생성 (단일 연결이 양방향을 의미)
- if (!pathNode.ConnectedNodes.Contains(connectedNode))
+ if (!pathNode.ConnectedNodes.Contains(connectedNode.NodeId))
{
- pathNode.ConnectedNodes.Add(connectedNode);
+ pathNode.ConnectedNodes.Add(connectedNode.NodeId);
}
- var connectedPathNode = _nodeMap[connectedNode];
+ var connectedPathNode = _nodeMap[connectedNode.NodeId];
if (!connectedPathNode.ConnectedNodes.Contains(mapNode.NodeId))
{
connectedPathNode.ConnectedNodes.Add(mapNode.NodeId);
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs
index aebb94c..177ec0f 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs
@@ -22,7 +22,7 @@ namespace AGVNavigationCore.PathFinding.Planning
private readonly JunctionAnalyzer _junctionAnalyzer;
private readonly DirectionChangePlanner _directionChangePlanner;
-
+
public AGVPathfinder(List mapNodes)
{
@@ -50,9 +50,13 @@ namespace AGVNavigationCore.PathFinding.Planning
n.IsNavigationNode() &&
n.ConnectedNodes != null &&
n.ConnectedNodes.Count >= 3 &&
+ n.ConnectedMapNodes.Where(t => t.Type == NodeType.Docking || t.Type == NodeType.Charging).Any() == false &&
n.NodeId != startNode.NodeId
).ToList();
+ // docking 포인트가 연결된 노드는 제거한다.
+
+
if (junctions.Count == 0)
return null;
@@ -96,7 +100,8 @@ namespace AGVNavigationCore.PathFinding.Planning
pathNode.IsActive &&
pathNode.IsNavigationNode() &&
pathNode.ConnectedNodes != null &&
- pathNode.ConnectedNodes.Count >= 3)
+ pathNode.ConnectedNodes.Count >= 3 &&
+ pathNode.ConnectedMapNodes.Where(t => t.Type == NodeType.Docking || t.Type == NodeType.Charging).Any() == false)
{
if (pathNode.NodeId.Equals(StartNode.NodeId) == false)
return pathNode;
@@ -107,7 +112,7 @@ namespace AGVNavigationCore.PathFinding.Planning
}
public AGVPathResult FindPath_test(MapNode startNode, MapNode targetNode,
- MapNode prevNode, AgvDirection prevDirection, AgvDirection currentDirection)
+ MapNode prevNode, AgvDirection prevDirection, AgvDirection currentDirection, bool crossignore = false)
{
// 입력 검증
if (startNode == null)
@@ -117,7 +122,7 @@ namespace AGVNavigationCore.PathFinding.Planning
if (prevNode == null)
return AGVPathResult.CreateFailure("이전위치 노드가 null입니다.", 0, 0);
if (startNode.NodeId == targetNode.NodeId && targetNode.DockDirection.MatchAGVDirection(prevDirection))
- return AGVPathResult.CreateFailure("목적지와 현재위치가 동일합니다.", 0, 0);
+ return AGVPathResult.CreateSuccess(new List { startNode,startNode }, new List(), 0, 0);
var ReverseDirection = (currentDirection == AgvDirection.Forward ? AgvDirection.Backward : AgvDirection.Forward);
@@ -203,6 +208,39 @@ namespace AGVNavigationCore.PathFinding.Planning
// return pathResult;
//}
+ //현재 내 포인트가 교차로라면.. 무조건 왓던 방향 혹은 그 반대방향으로 이동해서 경로를 계산해야한다.
+ //교차로에 멈춰있을때에는 바로 방향전환을 할 수없으니. 정/역(straight)로 이동해서 다시 계산을 해야한다
+ if (crossignore == false && startNode.ConnectedNodes.Count > 2)
+ {
+ //진행방향으로 이동했을때 나오는 노드를 사용한다.
+ if (nextNodeForward != null)
+ {
+ var Path0 = _basicPathfinder.FindPath(startNode.NodeId, nextNodeForward.NodeId);
+ Path0.PrevNode = prevNode;
+ Path0.PrevDirection = prevDirection;
+ MakeDetailData(Path0, prevDirection);
+
+ var Path1 = FindPath_test(nextNodeForward, targetNode, startNode, prevDirection, currentDirection, true);
+ Path1.PrevNode = startNode;
+ Path1.PrevDirection = prevDirection;
+ //MakeDetailData(Path1, ReverseDirection);
+
+ var combinedResult0 = Path0;
+ combinedResult0 = _basicPathfinder.CombineResults(combinedResult0, Path1);
+ MakeMagnetDirection(combinedResult0);
+ return combinedResult0;
+ }
+ else if (nextNodeBackward != null)
+ {
+ return AGVPathResult.CreateFailure("backward 처리코드가 없습니다 오류", 0, 0);
+ }
+ else
+ {
+ return AGVPathResult.CreateFailure("교차로에서 시작하는 조건중 forward/backrad 노드 검색 실패", 0, 0);
+ }
+ }
+
+
//3. 도킹방향이 일치하지 않으니 교차로에서 방향을 회전시켜야 한다
//최단거리(=minpath)경로에 속하는 교차로가 있다면 그것을 사용하고 없다면 가장 가까운 교차로를 찾는다.
var JunctionInPath = FindNearestJunctionOnPath(pathResult);
@@ -224,19 +262,23 @@ namespace AGVNavigationCore.PathFinding.Planning
path1.PrevNode = prevNode;
path1.PrevDirection = prevDirection;
- //다음좌표를 보고 교차로가 진행방향인지 반대방향인지 체크한다.(!모터의 정/역방향을 말하는것이 아님)
+ //다음좌표를 보고 교차로가 진행방향인지 반대방향인지 체크한다.
bool ReverseCheck = false;
- if (path1.Path.Count > 1 && nextNodeForward != null && nextNodeForward.NodeId.Equals(path1.Path[1].NodeId))
- {
- ReverseCheck = false; //현재 진행 방향으로 이동해야한다
- MakeDetailData(path1, currentDirection); // path1의 상세 경로 정보 채우기 (모터 방향 설정)
- }
- else if (path1.Path.Count > 1 && nextNodeBackward != null && nextNodeBackward.NodeId.Equals(path1.Path[1].NodeId))
+ //if (path1.Path.Count > 1 && nextNodeForward != null && nextNodeForward.NodeId.Equals(path1.Path[1].NodeId))
+ //{
+ // ReverseCheck = false; //현재 진행 방향으로 이동해야한다
+ // MakeDetailData(path1, currentDirection); // path1의 상세 경로 정보 채우기 (모터 방향 설정)
+ //}
+ if (path1.Path.Count > 1 && nextNodeBackward != null && nextNodeBackward.NodeId.Equals(path1.Path[1].NodeId))
{
ReverseCheck = true; //현재 방향의 반대방향으로 이동해야한다
MakeDetailData(path1, ReverseDirection); // path1의 상세 경로 정보 채우기 (모터 방향 설정)
}
- else return AGVPathResult.CreateFailure("교차로까지 계산된 경로에 현재 위치정보로 추측을 할 수 없습니다", 0, 0);
+ else
+ {
+ ReverseCheck = false; //현재 진행 방향으로 이동해야한다
+ MakeDetailData(path1, currentDirection); // path1의 상세 경로 정보 채우기 (모터 방향 설정)
+ }
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/DirectionChangePlanner.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/DirectionChangePlanner.cs
index b16a692..73c5167 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/DirectionChangePlanner.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/PathFinding/Planning/DirectionChangePlanner.cs
@@ -232,15 +232,18 @@ namespace AGVNavigationCore.PathFinding.Planning
var connected = new HashSet();
// 직접 연결
- foreach (var connectedId in node.ConnectedNodes)
+ foreach (var connectedNode in node.ConnectedMapNodes)
{
- connected.Add(connectedId);
+ if (connectedNode != null)
+ {
+ connected.Add(connectedNode.NodeId);
+ }
}
// 역방향 연결
foreach (var otherNode in _mapNodes)
{
- if (otherNode.NodeId != nodeId && otherNode.ConnectedNodes.Contains(nodeId))
+ if (otherNode.NodeId != nodeId && otherNode.ConnectedMapNodes.Any(n => n.NodeId == nodeId))
{
connected.Add(otherNode.NodeId);
}
@@ -728,9 +731,9 @@ namespace AGVNavigationCore.PathFinding.Planning
string currentNode = path[i].NodeId;
string nextNode = path[i + 1].NodeId;
- // 두 노드간 직접 연결성 확인 (맵 노드의 ConnectedNodes 리스트 사용)
+ // 두 노드간 직접 연결성 확인 (맵 노드의 ConnectedMapNodes 리스트 사용)
var currentMapNode = _mapNodes.FirstOrDefault(n => n.NodeId == currentNode);
- if (currentMapNode == null || !currentMapNode.ConnectedNodes.Contains(nextNode))
+ if (currentMapNode == null || !currentMapNode.ConnectedMapNodes.Any(n => n.NodeId == nextNode))
{
return PathValidationResult.CreateInvalid(currentNode, nextNode, $"노드 {currentNode}와 {nextNode} 사이에 연결이 없음");
}
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalHelper.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalHelper.cs
index 389b94e..55bd1b0 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalHelper.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DirectionalHelper.cs
@@ -69,22 +69,18 @@ namespace AGVNavigationCore.Utils
InitializeJunctionAnalyzer(allNodes);
// 현재 노드에 연결된 노드들 중 이전 노드가 아닌 노드들만 필터링
- var connectedNodeIds = currentNode.ConnectedNodes;
- if (connectedNodeIds == null || connectedNodeIds.Count == 0)
+ var connectedMapNodes = currentNode.ConnectedMapNodes;
+ if (connectedMapNodes == null || connectedMapNodes.Count == 0)
return null;
List candidateNodes = new List();
if (prevDirection == direction)
{
- candidateNodes = allNodes.Where(n => n.NodeId != prevNode.NodeId &&
- connectedNodeIds.Contains(n.NodeId)
- ).ToList();
+ candidateNodes = connectedMapNodes.Where(n => n.NodeId != prevNode.NodeId).ToList();
}
else
{
- candidateNodes = allNodes.Where(n =>
- connectedNodeIds.Contains(n.NodeId)
- ).ToList();
+ candidateNodes = connectedMapNodes.ToList();
}
if (candidateNodes.Count == 0)
@@ -375,13 +371,11 @@ namespace AGVNavigationCore.Utils
if (currentNode == null || prevNode == null || allNodes == null)
return (null, 0, "입력 파라미터가 null입니다");
- var connectedNodeIds = currentNode.ConnectedNodes;
- if (connectedNodeIds == null || connectedNodeIds.Count == 0)
+ var connectedMapNodes = currentNode.ConnectedMapNodes;
+ if (connectedMapNodes == null || connectedMapNodes.Count == 0)
return (null, 0, "연결된 노드가 없습니다");
- var candidateNodes = allNodes.Where(n =>
- connectedNodeIds.Contains(n.NodeId)
- ).ToList();
+ var candidateNodes = connectedMapNodes.ToList();
if (candidateNodes.Count == 0)
return (null, 0, "후보 노드가 없습니다");
diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DockingValidator.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DockingValidator.cs
index c435922..e276cf5 100644
--- a/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DockingValidator.cs
+++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Utils/DockingValidator.cs
@@ -28,6 +28,12 @@ namespace AGVNavigationCore.Utils
System.Diagnostics.Debug.WriteLine($"[DockingValidator] 도킹 검증 불필요: 경로 없음");
return DockingValidationResult.CreateNotRequired();
}
+ if (pathResult.DetailedPath.Any() == false && pathResult.Path.Any() && pathResult.Path.Count == 2 &&
+ pathResult.Path[0].NodeId == pathResult.Path[1].NodeId)
+ {
+ System.Diagnostics.Debug.WriteLine($"[DockingValidator] 도킹 검증 불필요: 동일포인트");
+ return DockingValidationResult.CreateNotRequired();
+ }
// 목적지 노드 가져오기 (Path는 이제 List)
var LastNode = pathResult.Path[pathResult.Path.Count - 1];
diff --git a/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs b/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs
index adb7be7..843d2b4 100644
--- a/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs
+++ b/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs
@@ -319,11 +319,16 @@ namespace AGVSimulator.Forms
// 고급 경로 계획 사용 (노드 객체 직접 전달)
var advancedResult = _advancedPathfinder.FindPath_test(startNode, targetNode, prevNode, prevDir, currentDirection);
+ _simulatorCanvas.FitToNodes();
if (advancedResult.Success)
{
// 도킹 검증이 없는 경우 추가 검증 수행
if (advancedResult.DockingValidation == null || !advancedResult.DockingValidation.IsValidationRequired)
{
+ if(advancedResult.Path.Count < 1)
+ {
+
+ }
advancedResult.DockingValidation = DockingValidator.ValidateDockingDirection(advancedResult, _mapNodes);
}
@@ -606,7 +611,7 @@ namespace AGVSimulator.Forms
_rfidTextBox.Text = ""; // 입력 필드 초기화
// 시뮬레이터 캔버스의 해당 노드로 이동
- _simulatorCanvas.PanToNode(targetNode.NodeId);
+ //_simulatorCanvas.PanToNode(targetNode.NodeId);
// 시작 노드 콤보박스를 현재 위치로 자동 선택
SetStartNodeToCombo(targetNode.NodeId);
@@ -1414,13 +1419,12 @@ namespace AGVSimulator.Forms
foreach (var nodeA in _mapNodes)
{
- if (nodeA.ConnectedNodes == null || nodeA.ConnectedNodes.Count == 0)
+ if (nodeA.ConnectedMapNodes == null || nodeA.ConnectedMapNodes.Count == 0)
continue;
- // 연결된 노드 ID를 실제 MapNode 객체로 변환
- foreach (var connectedNodeId in nodeA.ConnectedNodes)
+ // 연결된 노드 객체 순회
+ foreach (var nodeB in nodeA.ConnectedMapNodes)
{
- var nodeB = _mapNodes.FirstOrDefault(n => n.NodeId == connectedNodeId);
if (nodeB == null)
continue;
@@ -1428,7 +1432,7 @@ namespace AGVSimulator.Forms
var pairKey1 = $"{nodeA.NodeId}→{nodeB.NodeId}";
var pairKey2 = $"{nodeB.NodeId}→{nodeA.NodeId}";
- if (!processedPairs.Contains(pairKey1) && !processedPairs.Contains(pairKey2))
+ if (nodeA.HasRfid() && nodeB.HasRfid() && !processedPairs.Contains(pairKey1) && !processedPairs.Contains(pairKey2))
{
pairs.Add((nodeA, nodeB));
processedPairs.Add(pairKey1);
diff --git a/Cs_HMI/Data/MapData.json b/Cs_HMI/Data/MapData.json
deleted file mode 100644
index ecbac87..0000000
--- a/Cs_HMI/Data/MapData.json
+++ /dev/null
@@ -1,1050 +0,0 @@
-{
- "Nodes": [
- {
- "NodeId": "N001",
- "Name": "UNLOADER",
- "Position": "65, 229",
- "Type": 2,
- "DockDirection": 2,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:44.9548285+09:00",
- "ModifiedDate": "2025-09-15T11:19:44.6879389+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "001",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N001 - UNLOADER - [001]"
- },
- {
- "NodeId": "N002",
- "Name": "N002",
- "Position": "206, 244",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N001"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:48.2957516+09:00",
- "ModifiedDate": "2025-09-15T10:16:10.1841326+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "002",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N002 - N002 - [002]"
- },
- {
- "NodeId": "N003",
- "Name": "N003",
- "Position": "278, 278",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N002"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:49.2226656+09:00",
- "ModifiedDate": "2025-09-15T10:16:09.1753358+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "003",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N003 - N003 - [003]"
- },
- {
- "NodeId": "N004",
- "Name": "N004",
- "Position": "380, 340",
- "Type": 1,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N003",
- "N022",
- "N031"
- ],
- "CanRotate": true,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:50.1681027+09:00",
- "ModifiedDate": "2025-09-15T11:18:47.8876112+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "004",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N004 - N004 - [004]"
- },
- {
- "NodeId": "N006",
- "Name": "N006",
- "Position": "520, 220",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N007"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:51.1111368+09:00",
- "ModifiedDate": "2025-09-15T10:16:24.8315093+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "013",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N006 - N006 - [013]"
- },
- {
- "NodeId": "N007",
- "Name": "N007",
- "Position": "600, 180",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:51.9266982+09:00",
- "ModifiedDate": "2025-09-11T11:46:43.5813583+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "014",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N007 - N007 - [014]"
- },
- {
- "NodeId": "N008",
- "Name": "N008",
- "Position": "299, 456",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N009",
- "N031"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:53.9595825+09:00",
- "ModifiedDate": "2025-09-15T11:18:49.8874367+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "009",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N008 - N008 - [009]"
- },
- {
- "NodeId": "N009",
- "Name": "N009",
- "Position": "193, 477",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N010"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:54.5035702+09:00",
- "ModifiedDate": "2025-09-15T10:16:14.696211+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "010",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N009 - N009 - [010]"
- },
- {
- "NodeId": "N010",
- "Name": "TOPS",
- "Position": "52, 466",
- "Type": 2,
- "DockDirection": 2,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:55.0563237+09:00",
- "ModifiedDate": "2025-09-15T11:19:40.1582831+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "011",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N010 - TOPS - [011]"
- },
- {
- "NodeId": "N011",
- "Name": "N011",
- "Position": "460, 420",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N012",
- "N004",
- "N015"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:55.8875335+09:00",
- "ModifiedDate": "2025-09-15T10:16:28.6957855+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "005",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N011 - N011 - [005]"
- },
- {
- "NodeId": "N012",
- "Name": "N012",
- "Position": "540, 480",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N013"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:56.3678144+09:00",
- "ModifiedDate": "2025-09-11T11:46:27.9224943+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "006",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N012 - N012 - [006]"
- },
- {
- "NodeId": "N013",
- "Name": "N013",
- "Position": "620, 520",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N014"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:56.8390845+09:00",
- "ModifiedDate": "2025-09-11T11:46:29.5788308+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "007",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N013 - N013 - [007]"
- },
- {
- "NodeId": "N014",
- "Name": "LOADER",
- "Position": "720, 580",
- "Type": 2,
- "DockDirection": 2,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:34:57.2549726+09:00",
- "ModifiedDate": "2025-09-15T11:19:35.3431797+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "008",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N014 - LOADER - [008]"
- },
- {
- "NodeId": "N019",
- "Name": "CHARGER #2",
- "Position": "679, 199",
- "Type": 3,
- "DockDirection": 1,
- "ConnectedNodes": [
- "N007"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:35:56.5359098+09:00",
- "ModifiedDate": "2025-09-15T11:19:49.2931335+09:00",
- "IsActive": true,
- "DisplayColor": "Red",
- "RfidId": "015",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N019 - CHARGER #2 - [015]"
- },
- {
- "NodeId": "N022",
- "Name": "N022",
- "Position": "459, 279",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N023",
- "N006"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T08:36:48.0311551+09:00",
- "ModifiedDate": "2025-09-15T10:16:22.8799696+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "012",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N022 - N022 - [012]"
- },
- {
- "NodeId": "N023",
- "Name": "N023",
- "Position": "440, 220",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N024"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T09:41:36.8738794+09:00",
- "ModifiedDate": "2025-09-15T10:16:20.0378544+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "016",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N023 - N023 - [016]"
- },
- {
- "NodeId": "N024",
- "Name": "N024",
- "Position": "500, 160",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N025"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T09:41:37.4551853+09:00",
- "ModifiedDate": "2025-09-15T10:16:20.8801598+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "017",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N024 - N024 - [017]"
- },
- {
- "NodeId": "N025",
- "Name": "N025",
- "Position": "600, 120",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N026"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T09:41:38.0142374+09:00",
- "ModifiedDate": "2025-09-15T10:16:21.6723809+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "018",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N025 - N025 - [018]"
- },
- {
- "NodeId": "N026",
- "Name": "CHARGER #1",
- "Position": "660, 100",
- "Type": 3,
- "DockDirection": 1,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T09:41:38.5834487+09:00",
- "ModifiedDate": "2025-09-15T11:19:58.0225184+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "019",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N026 - CHARGER #1 - [019]"
- },
- {
- "NodeId": "LBL001",
- "Name": "Amkor Technology Korea",
- "Position": "58, 64",
- "Type": 4,
- "DockDirection": 0,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T11:08:22.4048927+09:00",
- "ModifiedDate": "2025-09-15T11:22:15.1196535+09:00",
- "IsActive": true,
- "DisplayColor": "Purple",
- "RfidId": "",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "Amkor Technology Korea",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "255, 255, 192",
- "ShowBackground": true,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "LBL001 - Amkor Technology Korea"
- },
- {
- "NodeId": "IMG001",
- "Name": "logo",
- "Position": "720, 371",
- "Type": 5,
- "DockDirection": 0,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-11T11:08:44.7897541+09:00",
- "ModifiedDate": "2025-09-17T15:39:07.5229808+09:00",
- "IsActive": true,
- "DisplayColor": "Brown",
- "RfidId": "",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "C:\\Data\\Users\\Pictures\\짤방\\아아악.png",
- "Scale": "0.7, 0.7",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "IMG001 - logo"
- },
- {
- "NodeId": "N015",
- "Name": "",
- "Position": "436, 485",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N016"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:47.8065756+09:00",
- "ModifiedDate": "2025-09-15T15:40:38.2050196+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "037",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N015 - [037]"
- },
- {
- "NodeId": "N016",
- "Name": "",
- "Position": "425, 524",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N017"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:48.6628848+09:00",
- "ModifiedDate": "2025-09-15T15:40:36.7952276+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "036",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N016 - [036]"
- },
- {
- "NodeId": "N017",
- "Name": "",
- "Position": "387, 557",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N018"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:49.8138877+09:00",
- "ModifiedDate": "2025-09-15T15:40:35.5342054+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "035",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N017 - [035]"
- },
- {
- "NodeId": "N018",
- "Name": "",
- "Position": "314, 549",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N005"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:50.6790623+09:00",
- "ModifiedDate": "2025-09-15T15:40:33.4719206+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "034",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N018 - [034]"
- },
- {
- "NodeId": "N005",
- "Name": "",
- "Position": "229, 553",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N020"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:51.5267199+09:00",
- "ModifiedDate": "2025-09-15T15:40:31.7321878+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "033",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N005 - [033]"
- },
- {
- "NodeId": "N020",
- "Name": "",
- "Position": "148, 545",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:52.3666114+09:00",
- "ModifiedDate": "2025-09-15T15:40:30.1486235+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "032",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N020 - [032]"
- },
- {
- "NodeId": "N021",
- "Name": "",
- "Position": "66, 547",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N020"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:53.0958619+09:00",
- "ModifiedDate": "2025-09-15T15:40:27.7345798+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "031",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N021 - [031]"
- },
- {
- "NodeId": "N027",
- "Name": "BUF1",
- "Position": "65, 644",
- "Type": 2,
- "DockDirection": 2,
- "ConnectedNodes": [
- "N021"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:54.7345704+09:00",
- "ModifiedDate": "2025-09-16T16:25:24.8062758+09:00",
- "IsActive": true,
- "DisplayColor": "Green",
- "RfidId": "041",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N027 - BUF1 - [041]"
- },
- {
- "NodeId": "N028",
- "Name": "BUF2",
- "Position": "149, 645",
- "Type": 2,
- "DockDirection": 2,
- "ConnectedNodes": [
- "N020"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:55.5263512+09:00",
- "ModifiedDate": "2025-09-16T16:25:28.6358219+09:00",
- "IsActive": true,
- "DisplayColor": "Green",
- "RfidId": "040",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N028 - BUF2 - [040]"
- },
- {
- "NodeId": "N029",
- "Name": "BUF3",
- "Position": "231, 639",
- "Type": 2,
- "DockDirection": 2,
- "ConnectedNodes": [
- "N005"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:56.6623294+09:00",
- "ModifiedDate": "2025-09-16T16:25:34.5699894+09:00",
- "IsActive": true,
- "DisplayColor": "Green",
- "RfidId": "039",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N029 - BUF3 - [039]"
- },
- {
- "NodeId": "N030",
- "Name": "BUF4",
- "Position": "314, 639",
- "Type": 2,
- "DockDirection": 2,
- "ConnectedNodes": [
- "N018"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-12T17:22:57.5510908+09:00",
- "ModifiedDate": "2025-09-16T16:25:40.3838199+09:00",
- "IsActive": true,
- "DisplayColor": "Green",
- "RfidId": "038",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N030 - BUF4 - [038]"
- },
- {
- "NodeId": "N031",
- "Name": "",
- "Position": "337, 397",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-09-15T11:18:40.5366059+09:00",
- "ModifiedDate": "2025-09-15T15:40:24.0443882+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "030",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImagePath": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N031 - [030]"
- }
- ],
- "CreatedDate": "2025-09-17T15:39:10.9736288+09:00",
- "Version": "1.0"
-}
\ No newline at end of file
diff --git a/Cs_HMI/Data/NewMap.agvmap b/Cs_HMI/Data/NewMap.agvmap
index df05d4c..6806987 100644
--- a/Cs_HMI/Data/NewMap.agvmap
+++ b/Cs_HMI/Data/NewMap.agvmap
@@ -46,7 +46,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:48.2957516+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "002",
@@ -79,7 +79,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:49.2226656+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "003",
@@ -114,7 +114,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:50.1681027+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "004",
@@ -180,7 +180,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:51.9266982+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "014",
@@ -246,7 +246,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:54.5035702+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "010",
@@ -278,7 +278,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:55.0563237+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "011",
@@ -312,7 +312,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:55.8875335+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "005",
@@ -345,7 +345,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:56.3678144+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "006",
@@ -378,7 +378,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:56.8390845+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "007",
@@ -410,7 +410,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:34:57.2549726+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "008",
@@ -442,7 +442,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:35:56.5359098+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Red",
"RfidId": "015",
@@ -476,7 +476,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T08:36:48.0311551+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "012",
@@ -509,7 +509,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T09:41:36.8738794+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "016",
@@ -542,7 +542,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T09:41:37.4551853+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "017",
@@ -575,7 +575,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T09:41:38.0142374+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "018",
@@ -607,7 +607,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-11T09:41:38.5834487+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "019",
@@ -659,7 +659,7 @@
{
"NodeId": "IMG001",
"Name": "logo",
- "Position": "720, 371",
+ "Position": "671, 333",
"Type": 5,
"DockDirection": 0,
"ConnectedNodes": [],
@@ -680,7 +680,7 @@
"ForeColor": "Black",
"BackColor": "Transparent",
"ShowBackground": false,
- "ImageBase64": "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",
+ "ImageBase64": "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",
"Scale": "0.7, 0.7",
"Opacity": 1.0,
"Rotation": 0.0,
@@ -700,7 +700,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:47.8065756+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "037",
@@ -733,7 +733,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:48.6628848+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "036",
@@ -760,14 +760,13 @@
"DockDirection": 0,
"ConnectedNodes": [
"N018",
- "N032",
"N016"
],
"CanRotate": false,
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:49.8138877+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T09:29:49.778537+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "035",
@@ -794,13 +793,14 @@
"DockDirection": 0,
"ConnectedNodes": [
"N030",
- "N017"
+ "N017",
+ "N005"
],
"CanRotate": false,
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:50.6790623+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "034",
@@ -868,7 +868,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:52.3666114+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "032",
@@ -901,7 +901,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:53.0958619+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "031",
@@ -933,7 +933,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:54.7345704+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Green",
"RfidId": "041",
@@ -965,7 +965,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:55.5263512+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Green",
"RfidId": "040",
@@ -997,7 +997,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:56.6623294+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Green",
"RfidId": "039",
@@ -1029,7 +1029,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-12T17:22:57.5510908+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Green",
"RfidId": "038",
@@ -1062,7 +1062,7 @@
"StationId": "",
"StationType": null,
"CreatedDate": "2025-09-15T11:18:40.5366059+09:00",
- "ModifiedDate": "2025-10-27T13:44:39.9998473+09:00",
+ "ModifiedDate": "2025-10-30T08:45:31.2491186+09:00",
"IsActive": true,
"DisplayColor": "Blue",
"RfidId": "030",
@@ -1080,40 +1080,8 @@
"Opacity": 1.0,
"Rotation": 0.0,
"DisplayText": "N031 - [030]"
- },
- {
- "NodeId": "N032",
- "Name": "",
- "Position": "416, 625",
- "Type": 0,
- "DockDirection": 0,
- "ConnectedNodes": [
- "N017"
- ],
- "CanRotate": false,
- "StationId": "",
- "StationType": null,
- "CreatedDate": "2025-10-27T13:44:12.9351531+09:00",
- "ModifiedDate": "2025-10-27T13:44:12.9351531+09:00",
- "IsActive": true,
- "DisplayColor": "Blue",
- "RfidId": "",
- "RfidStatus": "정상",
- "RfidDescription": "",
- "LabelText": "",
- "FontFamily": "Arial",
- "FontSize": 12.0,
- "FontStyle": 0,
- "ForeColor": "Black",
- "BackColor": "Transparent",
- "ShowBackground": false,
- "ImageBase64": "",
- "Scale": "1, 1",
- "Opacity": 1.0,
- "Rotation": 0.0,
- "DisplayText": "N032"
}
],
- "CreatedDate": "2025-10-27T13:44:45.04346+09:00",
+ "CreatedDate": "2025-10-30T09:30:01.9333244+09:00",
"Version": "1.0"
}
\ No newline at end of file