fix: Add motor direction parameter to magnet direction calculation in pathfinding
- Fixed critical issue in ConvertToDetailedPath where motor direction was not passed to GetRequiredMagnetDirection - Motor direction is essential for backward movement as Left/Right directions must be inverted - Modified AGVPathfinder.cs line 280 to pass currentDirection parameter - Ensures backward motor direction properly inverts magnet sensor directions feat: Add waypoint support to pathfinding system - Added FindPath overload with params string[] waypointNodeIds in AStarPathfinder - Supports sequential traversal through multiple intermediate nodes - Validates waypoints and prevents duplicates in sequence - Returns combined path result with aggregated metrics feat: Implement path result merging with DetailedPath preservation - Added CombineResults method in AStarPathfinder for intelligent path merging - Automatically deduplicates nodes when last of previous path equals first of current - Preserves DetailedPath information including motor and magnet directions - Essential for multi-segment path operations feat: Integrate magnet direction with motor direction awareness - Modified JunctionAnalyzer.GetRequiredMagnetDirection to accept AgvDirection parameter - Inverts Left/Right magnet directions when moving Backward - Properly handles motor direction context throughout pathfinding feat: Add automatic start node selection in simulator - Added SetStartNodeToCombo method to SimulatorForm - Automatically selects start node combo box when AGV position is set via RFID - Improves UI usability and workflow efficiency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
@@ -49,7 +49,11 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Forms\ImageEditorForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Models\EditorSettings.cs" />
|
||||
<Compile Include="Models\ImagePathEditor.cs" />
|
||||
<Compile Include="Models\MapImage.cs" />
|
||||
<Compile Include="Models\MapLabel.cs" />
|
||||
<Compile Include="Models\NodePropertyWrapper.cs" />
|
||||
|
||||
287
Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.cs
Normal file
287
Cs_HMI/AGVLogic/AGVMapEditor/Forms/ImageEditorForm.cs
Normal file
@@ -0,0 +1,287 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using AGVNavigationCore.Models;
|
||||
using AGVNavigationCore.Utils;
|
||||
|
||||
namespace AGVMapEditor.Forms
|
||||
{
|
||||
/// <summary>
|
||||
/// 이미지 노드의 이미지를 편집하기 위한 간단한 그림판
|
||||
/// 불러오기, 저장, 크기 조정, 기본 드로잉 기능 제공
|
||||
/// </summary>
|
||||
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();
|
||||
_targetNode = imageNode;
|
||||
SetupUI();
|
||||
|
||||
if (imageNode != null && imageNode.LoadedImage != null)
|
||||
{
|
||||
LoadImageFromNode(imageNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupUI()
|
||||
{
|
||||
this.Text = "이미지 편집기";
|
||||
this.Size = new Size(800, 600);
|
||||
this.StartPosition = FormStartPosition.CenterScreen;
|
||||
|
||||
// 패널: 도구 모음
|
||||
var toolPanel = new Panel { Dock = DockStyle.Top, Height = 50, BackColor = Color.LightGray };
|
||||
|
||||
// 버튼: 이미지 열기
|
||||
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 LoadImageFromNode(MapNode node)
|
||||
{
|
||||
if (node.LoadedImage != null)
|
||||
{
|
||||
_editingImage?.Dispose();
|
||||
_graphics?.Dispose();
|
||||
_editingImage = new Bitmap(node.LoadedImage);
|
||||
_graphics = Graphics.FromImage(_editingImage);
|
||||
UpdateCanvas();
|
||||
}
|
||||
}
|
||||
|
||||
private void BtnOpen_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (var ofd = new OpenFileDialog { Filter = "이미지|*.jpg;*.png;*.bmp|모든 파일|*.*" })
|
||||
{
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
LoadImageFromFile(ofd.FileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadImageFromFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
_editingImage?.Dispose();
|
||||
_graphics?.Dispose();
|
||||
|
||||
var loadedImage = Image.FromFile(filePath);
|
||||
|
||||
// 이미지 크기가 크면 자동 축소 (최대 512x512)
|
||||
if (loadedImage.Width > 512 || loadedImage.Height > 512)
|
||||
{
|
||||
_editingImage = ResizeImage(loadedImage, 512, 512);
|
||||
loadedImage.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
_editingImage = new Bitmap(loadedImage);
|
||||
loadedImage.Dispose();
|
||||
}
|
||||
|
||||
_graphics = Graphics.FromImage(_editingImage);
|
||||
UpdateCanvas();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"이미지 로드 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void BtnResize_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_editingImage == null)
|
||||
{
|
||||
MessageBox.Show("먼저 이미지를 로드하세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
using (var form = new Form())
|
||||
{
|
||||
form.Text = "이미지 크기 조정";
|
||||
form.Size = new Size(300, 150);
|
||||
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 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 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 };
|
||||
|
||||
form.Controls.Add(lblWidth);
|
||||
form.Controls.Add(txtWidth);
|
||||
form.Controls.Add(lblHeight);
|
||||
form.Controls.Add(txtHeight);
|
||||
form.Controls.Add(btnOk);
|
||||
form.Controls.Add(btnCancel);
|
||||
|
||||
if (form.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
if (int.TryParse(txtWidth.Text, out int width) && int.TryParse(txtHeight.Text, out int height))
|
||||
{
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
_graphics?.Dispose();
|
||||
var resized = new Bitmap(_editingImage, width, height);
|
||||
_editingImage.Dispose();
|
||||
_editingImage = resized;
|
||||
_graphics = Graphics.FromImage(_editingImage);
|
||||
UpdateCanvas();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BtnColor_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (var cfd = new ColorDialog { Color = _drawColor })
|
||||
{
|
||||
if (cfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
_drawColor = cfd.Color;
|
||||
(sender as Button).BackColor = _drawColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BtnSave_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_editingImage == null)
|
||||
{
|
||||
MessageBox.Show("저장할 이미지가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_targetNode != null && _targetNode.Type == NodeType.Image)
|
||||
{
|
||||
// 이미지를 Base64로 변환하여 저장
|
||||
_targetNode.ImageBase64 = ImageConverterUtil.ImageToBase64(_editingImage, System.Drawing.Imaging.ImageFormat.Png);
|
||||
_targetNode.LoadedImage?.Dispose();
|
||||
_targetNode.LoadedImage = new Bitmap(_editingImage);
|
||||
|
||||
MessageBox.Show("이미지가 저장되었습니다.");
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
double ratioY = (double)maxHeight / image.Height;
|
||||
double ratio = Math.Min(ratioX, ratioY);
|
||||
|
||||
int newWidth = (int)(image.Width * ratio);
|
||||
int newHeight = (int)(image.Height * ratio);
|
||||
|
||||
var resized = new Bitmap(newWidth, newHeight);
|
||||
using (var g = Graphics.FromImage(resized))
|
||||
{
|
||||
g.CompositingQuality = CompositingQuality.HighQuality;
|
||||
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
g.DrawImage(image, 0, 0, newWidth, newHeight);
|
||||
}
|
||||
return resized;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_editingImage?.Dispose();
|
||||
_graphics?.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using AGVMapEditor.Models;
|
||||
using AGVNavigationCore.Controls;
|
||||
using AGVNavigationCore.Models;
|
||||
using Newtonsoft.Json;
|
||||
@@ -165,52 +166,61 @@ namespace AGVMapEditor.Forms
|
||||
btnAddImage.Location = new Point(325, 3);
|
||||
btnAddImage.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.AddImage;
|
||||
|
||||
// 이미지 편집 버튼
|
||||
var btnEditImage = new Button();
|
||||
btnEditImage.Name = "btnToolbarEditImage";
|
||||
btnEditImage.Text = "이미지 편집";
|
||||
btnEditImage.Size = new Size(80, 28);
|
||||
btnEditImage.Location = new Point(420, 3);
|
||||
btnEditImage.Enabled = false; // 처음에는 비활성화
|
||||
btnEditImage.Click += BtnToolbarEditImage_Click;
|
||||
|
||||
// 연결 모드 버튼
|
||||
var btnConnect = new Button();
|
||||
btnConnect.Text = "연결 (C)";
|
||||
btnConnect.Size = new Size(70, 28);
|
||||
btnConnect.Location = new Point(420, 3);
|
||||
btnConnect.Location = new Point(505, 3);
|
||||
btnConnect.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Connect;
|
||||
|
||||
// 삭제 모드 버튼
|
||||
var btnDelete = new Button();
|
||||
btnDelete.Text = "삭제 (D)";
|
||||
btnDelete.Size = new Size(70, 28);
|
||||
btnDelete.Location = new Point(495, 3);
|
||||
btnDelete.Location = new Point(580, 3);
|
||||
btnDelete.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Delete;
|
||||
|
||||
// 연결 삭제 버튼
|
||||
var btnDeleteConnection = new Button();
|
||||
btnDeleteConnection.Text = "연결삭제 (X)";
|
||||
btnDeleteConnection.Size = new Size(80, 28);
|
||||
btnDeleteConnection.Location = new Point(570, 3);
|
||||
btnDeleteConnection.Location = new Point(655, 3);
|
||||
btnDeleteConnection.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.DeleteConnection;
|
||||
|
||||
// 구분선
|
||||
var separator1 = new Label();
|
||||
separator1.Text = "|";
|
||||
separator1.Size = new Size(10, 28);
|
||||
separator1.Location = new Point(655, 3);
|
||||
separator1.Location = new Point(740, 3);
|
||||
separator1.TextAlign = ContentAlignment.MiddleCenter;
|
||||
|
||||
// 그리드 토글 버튼
|
||||
var btnToggleGrid = new Button();
|
||||
btnToggleGrid.Text = "그리드";
|
||||
btnToggleGrid.Size = new Size(60, 28);
|
||||
btnToggleGrid.Location = new Point(670, 3);
|
||||
btnToggleGrid.Location = new Point(755, 3);
|
||||
btnToggleGrid.Click += (s, e) => _mapCanvas.ShowGrid = !_mapCanvas.ShowGrid;
|
||||
|
||||
// 맵 맞춤 버튼
|
||||
var btnFitMap = new Button();
|
||||
btnFitMap.Text = "맵 맞춤";
|
||||
btnFitMap.Size = new Size(70, 28);
|
||||
btnFitMap.Location = new Point(735, 3);
|
||||
btnFitMap.Location = new Point(820, 3);
|
||||
btnFitMap.Click += (s, e) => _mapCanvas.FitToNodes();
|
||||
|
||||
// 툴바에 버튼들 추가
|
||||
toolbarPanel.Controls.AddRange(new Control[]
|
||||
{
|
||||
btnSelect, btnMove, btnAddNode, btnAddLabel, btnAddImage, btnConnect, btnDelete, btnDeleteConnection, separator1, btnToggleGrid, btnFitMap
|
||||
btnSelect, btnMove, btnAddNode, btnAddLabel, btnAddImage, btnEditImage, btnConnect, btnDelete, btnDeleteConnection, separator1, btnToggleGrid, btnFitMap
|
||||
});
|
||||
|
||||
// 스플리터 패널에 툴바 추가 (맨 위에)
|
||||
@@ -946,11 +956,59 @@ namespace AGVMapEditor.Forms
|
||||
var nodeWrapper = NodePropertyWrapperFactory.CreateWrapper(_selectedNode, _mapNodes);
|
||||
_propertyGrid.SelectedObject = nodeWrapper;
|
||||
_propertyGrid.Focus();
|
||||
|
||||
// 이미지 노드인 경우 편집 버튼 활성화
|
||||
UpdateImageEditButton();
|
||||
}
|
||||
|
||||
private void ClearNodeProperties()
|
||||
{
|
||||
_propertyGrid.SelectedObject = null;
|
||||
DisableImageEditButton();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 선택된 노드가 이미지 노드이면 편집 버튼 활성화
|
||||
/// </summary>
|
||||
private void UpdateImageEditButton()
|
||||
{
|
||||
var btn = this.Controls.Find("btnToolbarEditImage", true).FirstOrDefault() as Button;
|
||||
if (btn != null)
|
||||
{
|
||||
btn.Enabled = (_selectedNode != null && _selectedNode.Type == NodeType.Image);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이미지 편집 버튼 비활성화
|
||||
/// </summary>
|
||||
private void DisableImageEditButton()
|
||||
{
|
||||
var btn = this.Controls.Find("btnToolbarEditImage", true).FirstOrDefault() as Button;
|
||||
if (btn != null)
|
||||
{
|
||||
btn.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 상단 툴바의 이미지 편집 버튼 클릭 이벤트
|
||||
/// </summary>
|
||||
private void BtnToolbarEditImage_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_selectedNode != null && _selectedNode.Type == NodeType.Image)
|
||||
{
|
||||
using (var editor = new ImageEditorForm(_selectedNode))
|
||||
{
|
||||
if (editor.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
_hasChanges = true;
|
||||
UpdateTitle();
|
||||
_mapCanvas.Invalidate(); // 캔버스 다시 그리기
|
||||
UpdateNodeProperties(); // 속성 업데이트
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTitle()
|
||||
|
||||
77
Cs_HMI/AGVLogic/AGVMapEditor/Models/ImagePathEditor.cs
Normal file
77
Cs_HMI/AGVLogic/AGVMapEditor/Models/ImagePathEditor.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.Design;
|
||||
|
||||
namespace AGVMapEditor.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// PropertyGrid에서 이미지 파일 경로를 선택하기 위한 커스텀 UITypeEditor
|
||||
/// PropertyGrid에 "..." 버튼을 표시하고, 클릭 시 파일 열기 대화상자를 표시
|
||||
/// </summary>
|
||||
public class ImagePathEditor : UITypeEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// PropertyGrid에서 이 에디터의 UI 스타일 반환
|
||||
/// DropDown 스타일을 사용하여 "..." 버튼을 표시
|
||||
/// </summary>
|
||||
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
|
||||
{
|
||||
return UITypeEditorEditStyle.Modal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 사용자가 "..." 버튼을 클릭할 때 호출되는 메서드
|
||||
/// </summary>
|
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
||||
{
|
||||
// IWindowsFormsEditorService를 얻어서 대화상자를 표시
|
||||
var editorService = provider?.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
|
||||
if (editorService == null)
|
||||
return value;
|
||||
|
||||
// 파일 열기 대화상자 생성
|
||||
using (var ofd = new OpenFileDialog())
|
||||
{
|
||||
ofd.Title = "이미지 파일 선택";
|
||||
ofd.Filter = "이미지 파일|*.jpg;*.jpeg;*.png;*.bmp;*.gif|모든 파일|*.*";
|
||||
ofd.CheckFileExists = true;
|
||||
|
||||
// 현재 경로가 있으면 해당 위치에서 시작
|
||||
if (!string.IsNullOrEmpty(value?.ToString()))
|
||||
{
|
||||
try
|
||||
{
|
||||
string currentPath = value.ToString();
|
||||
if (System.IO.File.Exists(currentPath))
|
||||
{
|
||||
ofd.InitialDirectory = System.IO.Path.GetDirectoryName(currentPath);
|
||||
ofd.FileName = System.IO.Path.GetFileName(currentPath);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// 대화상자 표시
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// 선택된 파일 경로를 Base64로 변환하고 반환
|
||||
string filePath = ofd.FileName;
|
||||
return filePath; // MapNode의 ConvertImageToBase64는 setter에서 호출됨
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PropertyGrid에서 이 타입의 값을 표시하는 방법
|
||||
/// 파일 경로를 파일명만 표시하도록 처리
|
||||
/// </summary>
|
||||
public override bool GetPaintValueSupported(ITypeDescriptorContext context)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Design;
|
||||
using AGVNavigationCore.Models;
|
||||
|
||||
namespace AGVMapEditor.Models
|
||||
@@ -237,15 +238,30 @@ namespace AGVMapEditor.Models
|
||||
|
||||
[Category("이미지")]
|
||||
[DisplayName("이미지 경로")]
|
||||
[Description("이미지 파일 경로")]
|
||||
// 파일 선택 에디터는 나중에 구현
|
||||
[Description("이미지 파일 경로 (... 버튼으로 파일 선택)")]
|
||||
[Editor(typeof(ImagePathEditor), typeof(UITypeEditor))]
|
||||
public string ImagePath
|
||||
{
|
||||
get => _node.ImagePath;
|
||||
set
|
||||
{
|
||||
_node.ImagePath = value ?? "";
|
||||
_node.LoadImage(); // 이미지 다시 로드
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
_node.ImagePath = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// 파일이 존재하면 Base64로 변환하여 저장
|
||||
if (System.IO.File.Exists(value))
|
||||
{
|
||||
_node.ConvertImageToBase64(value);
|
||||
_node.LoadImage(); // 이미지 다시 로드
|
||||
}
|
||||
else
|
||||
{
|
||||
_node.ImagePath = value;
|
||||
}
|
||||
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user