agv 노드 정보 정리 세분화
This commit is contained in:
@@ -62,7 +62,6 @@
|
||||
<Compile Include="Models\ImagePathEditor.cs" />
|
||||
<Compile Include="Models\MapImage.cs" />
|
||||
<Compile Include="Models\MapLabel.cs" />
|
||||
<Compile Include="Models\NodePropertyWrapper.cs" />
|
||||
<Compile Include="Forms\MainForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
||||
@@ -64,6 +64,9 @@ namespace AGVMapEditor.Forms
|
||||
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.btnSave = new System.Windows.Forms.ToolStripButton();
|
||||
this.btnSaveAs = new System.Windows.Forms.ToolStripButton();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripButton1 = new System.Windows.Forms.ToolStripDropDownButton();
|
||||
this.allTurnLeftRightCrossOnToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
@@ -351,7 +354,9 @@ namespace AGVMapEditor.Forms
|
||||
this.btnClose,
|
||||
this.toolStripSeparator3,
|
||||
this.btnSave,
|
||||
this.btnSaveAs});
|
||||
this.btnSaveAs,
|
||||
this.toolStripSeparator2,
|
||||
this.toolStripButton1});
|
||||
this.toolStrip2.Location = new System.Drawing.Point(0, 0);
|
||||
this.toolStrip2.Name = "toolStrip2";
|
||||
this.toolStrip2.Size = new System.Drawing.Size(1200, 25);
|
||||
@@ -417,6 +422,28 @@ namespace AGVMapEditor.Forms
|
||||
this.btnSaveAs.ToolTipText = "다른 이름으로 저장";
|
||||
this.btnSaveAs.Click += new System.EventHandler(this.btnSaveAs_Click);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(6, 25);
|
||||
//
|
||||
// toolStripButton1
|
||||
//
|
||||
this.toolStripButton1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.allTurnLeftRightCrossOnToolStripMenuItem});
|
||||
this.toolStripButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton1.Image")));
|
||||
this.toolStripButton1.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.toolStripButton1.Name = "toolStripButton1";
|
||||
this.toolStripButton1.Size = new System.Drawing.Size(68, 22);
|
||||
this.toolStripButton1.Text = "Debig";
|
||||
//
|
||||
// allTurnLeftRightCrossOnToolStripMenuItem
|
||||
//
|
||||
this.allTurnLeftRightCrossOnToolStripMenuItem.Name = "allTurnLeftRightCrossOnToolStripMenuItem";
|
||||
this.allTurnLeftRightCrossOnToolStripMenuItem.Size = new System.Drawing.Size(223, 22);
|
||||
this.allTurnLeftRightCrossOnToolStripMenuItem.Text = "All TurnLeft/Right/Cross On";
|
||||
this.allTurnLeftRightCrossOnToolStripMenuItem.Click += new System.EventHandler(this.allTurnLeftRightCrossOnToolStripMenuItem_Click);
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
@@ -490,5 +517,8 @@ namespace AGVMapEditor.Forms
|
||||
private System.Windows.Forms.ToolStripButton btnAddImage;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
||||
private System.Windows.Forms.ToolStripDropDownButton toolStripButton1;
|
||||
private System.Windows.Forms.ToolStripMenuItem allTurnLeftRightCrossOnToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
@@ -221,8 +221,8 @@ namespace AGVMapEditor.Forms
|
||||
toolStripStatusLabel1.Text = $"{nodes.Count}개 노드 선택됨 - PropertyGrid에서 공통 속성 일괄 변경 가능";
|
||||
|
||||
// 다중 선택 PropertyWrapper 표시
|
||||
var multiWrapper = new MultiNodePropertyWrapper(nodes);
|
||||
_propertyGrid.SelectedObject = multiWrapper;
|
||||
//var multiWrapper = new MultiNodePropertyWrapper(nodes);
|
||||
_propertyGrid.SelectedObjects = nodes.ToArray();// multiWrapper;
|
||||
_propertyGrid.Focus();
|
||||
}
|
||||
}
|
||||
@@ -833,11 +833,10 @@ namespace AGVMapEditor.Forms
|
||||
foreColor = Color.Black;
|
||||
backColor = Color.White;
|
||||
break;
|
||||
case NodeType.Rotation:
|
||||
foreColor = Color.DarkOrange;
|
||||
backColor = Color.LightYellow;
|
||||
break;
|
||||
case NodeType.Docking:
|
||||
case NodeType.Loader:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
foreColor = Color.DarkGreen;
|
||||
backColor = Color.LightGreen;
|
||||
break;
|
||||
@@ -975,9 +974,7 @@ namespace AGVMapEditor.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
// 노드 래퍼 객체 생성 (타입에 따라 다른 래퍼 사용)
|
||||
var nodeWrapper = NodePropertyWrapperFactory.CreateWrapper(_selectedNode, _mapNodes);
|
||||
_propertyGrid.SelectedObject = nodeWrapper;
|
||||
_propertyGrid.SelectedObject = _selectedNode;
|
||||
_propertyGrid.Focus();
|
||||
|
||||
// 이미지 노드인 경우 편집 버튼 활성화
|
||||
@@ -989,8 +986,7 @@ namespace AGVMapEditor.Forms
|
||||
/// </summary>
|
||||
private void ShowCanvasProperties()
|
||||
{
|
||||
var canvasWrapper = new CanvasPropertyWrapper(_mapCanvas);
|
||||
_propertyGrid.SelectedObject = canvasWrapper;
|
||||
_propertyGrid.SelectedObject = _mapCanvas;
|
||||
DisableImageEditButton();
|
||||
}
|
||||
|
||||
@@ -1124,7 +1120,9 @@ namespace AGVMapEditor.Forms
|
||||
UpdateTitle();
|
||||
|
||||
// 🔥 다중 선택 여부 확인 및 선택된 노드들 저장
|
||||
bool isMultiSelect = _propertyGrid.SelectedObject is MultiNodePropertyWrapper;
|
||||
bool isMultiSelect = _propertyGrid.SelectedObjects is MapNode[]; // _propertyGrid.SelectedObject is MapNode[];
|
||||
|
||||
//var a = _propertyGrid.SelectedObject;
|
||||
List<MapNode> selectedNodes = null;
|
||||
if (isMultiSelect)
|
||||
{
|
||||
@@ -1146,9 +1144,9 @@ namespace AGVMapEditor.Forms
|
||||
// 🔥 다중 선택인 경우 MultiNodePropertyWrapper를 다시 생성하여 바인딩
|
||||
if (isMultiSelect && selectedNodes != null && selectedNodes.Count > 0)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"[PropertyGrid] MultiNodePropertyWrapper 재생성: {selectedNodes.Count}개");
|
||||
var multiWrapper = new MultiNodePropertyWrapper(selectedNodes);
|
||||
_propertyGrid.SelectedObject = multiWrapper;
|
||||
// System.Diagnostics.Debug.WriteLine($"[PropertyGrid] MultiNodePropertyWrapper 재생성: {selectedNodes.Count}개");
|
||||
//var multiWrapper = new MultiNodePropertyWrapper(selectedNodes);
|
||||
_propertyGrid.SelectedObjects = selectedNodes.ToArray();// multiWrapper;
|
||||
}
|
||||
|
||||
// PropertyGrid 새로고침
|
||||
@@ -1180,18 +1178,18 @@ namespace AGVMapEditor.Forms
|
||||
var selectedObject = _propertyGrid.SelectedObject;
|
||||
|
||||
// 다양한 PropertyWrapper 타입 처리
|
||||
if (selectedObject is NodePropertyWrapper nodeWrapper)
|
||||
{
|
||||
currentNodeId = nodeWrapper.WrappedNode?.NodeId;
|
||||
}
|
||||
else if (selectedObject is LabelNodePropertyWrapper labelWrapper)
|
||||
{
|
||||
currentNodeId = labelWrapper.WrappedNode?.NodeId;
|
||||
}
|
||||
else if (selectedObject is ImageNodePropertyWrapper imageWrapper)
|
||||
{
|
||||
currentNodeId = imageWrapper.WrappedNode?.NodeId;
|
||||
}
|
||||
//if (selectedObject is NodePropertyWrapper nodeWrapper)
|
||||
//{
|
||||
// currentNodeId = nodeWrapper.WrappedNode?.NodeId;
|
||||
//}
|
||||
//else if (selectedObject is LabelNodePropertyWrapper labelWrapper)
|
||||
//{
|
||||
// currentNodeId = labelWrapper.WrappedNode?.NodeId;
|
||||
//}
|
||||
//else if (selectedObject is ImageNodePropertyWrapper imageWrapper)
|
||||
//{
|
||||
// currentNodeId = imageWrapper.WrappedNode?.NodeId;
|
||||
//}
|
||||
|
||||
int duplicateCount = 0;
|
||||
foreach (var node in _mapNodes)
|
||||
@@ -1370,5 +1368,46 @@ namespace AGVMapEditor.Forms
|
||||
|
||||
#endregion
|
||||
|
||||
private void allTurnLeftRightCrossOnToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
//모든노드의 trun left/right/ cross 속성을 true로 변경합니다
|
||||
if (_mapNodes == null || _mapNodes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("맵에 노드가 없습니다.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
var result = MessageBox.Show(
|
||||
$"모든 노드({_mapNodes.Count}개)의 회전/교차 속성을 활성화하시겠습니까?\n\n" +
|
||||
"• CanTurnLeft = true\n" +
|
||||
"• CanTurnRight = true\n" +
|
||||
"• DisableCross = false",
|
||||
"일괄 속성 변경",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
foreach (var node in _mapNodes)
|
||||
{
|
||||
node.CanTurnLeft = true;
|
||||
node.CanTurnRight = true;
|
||||
node.DisableCross =false;
|
||||
node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
|
||||
_hasChanges = true;
|
||||
UpdateTitle();
|
||||
RefreshMapCanvas();
|
||||
|
||||
MessageBox.Show(
|
||||
$"{_mapNodes.Count}개 노드의 회전/교차 속성이 모두 활성화되었습니다.",
|
||||
"완료",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Information);
|
||||
|
||||
UpdateStatusBar($"모든 노드의 회전/교차 속성 활성화 완료");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,22 +120,40 @@
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>132, 17</value>
|
||||
</metadata>
|
||||
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>249, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="btNodeRemove.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="toolStrip3.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>462, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="btnSelect.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHrSURBVDhPldBNiBJhHMfx/ykKiohQ18tEhygyWGQRJwh1
|
||||
fcHAt7qJ3TOj6FJ0akP06G2RPQd1MNhKcxvCxDc2UHbXSCoWNu8dWp3ReTks/moGVnafjW33c/rPM8/3
|
||||
4eEhOoLJZ/6UvDp7l10/lNKa4+TW3AN9Hq9eC8kNW1ef1QZ3UapzRztMbs1+lVs2Qa5fLqsbtzBucE9G
|
||||
NetwVD2fYPf+07h5ZUH9koD24yG0rWdQ1kMQK2eVXzXTaXbv1Lh9dUZu2apy4xLUjSi0nxk0X0bRLd7B
|
||||
Vu0elM48xE8nIX6kJbbdZ1znFpTubTRfxaBpGiaTCdbfJaB+v4+BQN+2y3SBbaak5oxJqlqEcDiMTqcD
|
||||
VVXR6/VQexGCtvkYYplG4gfi2c6gVKzcqHKuGIvFkEwmkcvlUCgUUF6ah7b5FIMV2hFXaG1YoudsOxWN
|
||||
Ro2Y53l4vV5EIhHIayFIVSsk4Qy2S8SxzdRu7HQ64fF4YDab9SsvDt7Tjlii62KRusM3lGI7QzweRzab
|
||||
NWK32w2TyQR9XSrRDfEtCfqM13Ti9zLdZFsKBoPIZDIH4l3DZQrs/d7H5/MhnU7D4XDA5XIdiA+VSqXQ
|
||||
7/dht9sRCASOF+v0A9rtNvL5vPFg7P//8vv9j/RrWyyW48d//QFpDAsmbMS+zgAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHrSURBVDhPldBNiBJhHMfx/ykKKohQ18tEhygyWGQRJwh1
|
||||
fcHAt7qJ3TOj6FJ0akP06C1kz0EdDLbS3IbaxJdhA2V3jaRiYfPeIXPGeTss/mqElfbZ2HY/p/8883wf
|
||||
Hh6iAxh/5I+pq7M32fV9aeIcp4pzd8xZWb0UUZuOrjnrTe6s3OAOdpgqzn5WRYegNs5X9Y1rUJrcg1Hd
|
||||
PhzVTqfYvf+ktC4s6J9SML7dhbH1CNp6BMP3J7Ufdctxdu+U0r44o4qOmto8B30jDuN7Dq1ncXTLN7BV
|
||||
vwWtMw/pw1FI72iRbXdRGtyC1r2O1vMEDMPAeDzG+usU9K+38UugL4MqnWGbKbk1Y5FrNiEajaLT6UDX
|
||||
dfR6PdSfRmBs3odUpZH0lni2m9BW7Nxo5VQ5kUggnU6jUCigVCqhujgPY/MhBsu0LS3T2rBCj9l2Kh6P
|
||||
T2Ke5+H3+xGLxaCuRSDX7JCFExhUiGObqZ3Y7XbD5/PBarWaV34yeEPbUoUuS2XqDl9Shu0mkskk8vn8
|
||||
JPZ6vbBYLDDX5QpdkV6RYM54QUd+LtFVtqVwOIxcLrcn3jFcotDf37sEAgFks1m4XC54PJ498b4ymQz6
|
||||
/T6cTidCodDhYpN5QLvdRrFYnDwY+/+/gsHgPfPaNpvt8PEfvwFcBQshDC9YfwAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="btnMove.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
@@ -156,75 +174,75 @@
|
||||
<data name="btnAddLabel.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHMSURBVDhPnZJfa9pQGMb7JXa7sW9RCP1ku1lXRi+3luJa
|
||||
dteOjYi5CJhoBIPGLYkExb8zic5molPnoAO3k80ozzhHTopzq2wPhHDe8z6/5yV599rtNlqtFhqNBur1
|
||||
Omq1GqrVKiqVCn3f29ulZrOJ1Wq19QyHQwYxDONuCE2mhsFgwJKDIIghtOY4zt0QOjJtpmn0XC6XK/P5
|
||||
HFEUsToFWpb1dwhN5Y22bf80TXMQhiE+f/qOd9qU3fX7fZRKpT9DaDIfeblcgpq/TEO8OPJx8sjD2+wa
|
||||
0uv1UCgUoKrqJsRxHDKbzVjTYrFgyYknPi6f9fH6LMD5UTeG+L6PfD6/CbFt+8CyLDKdrpvc+g1Lvjq5
|
||||
hnj+cQvieR40TduEmKYpFItFMplMWFO39RWJQw+vTm8hiUMfhrq+73Q6UBQFoijeQgzDEHRdJ+PxeAvy
|
||||
JhHg5XEPF8fvEUVLNkUmk0EqlXoQA6h0XRdyuRwZjUYx5Oyxi4unXVyddvFtHsZmURQfbpi5NE0Tstks
|
||||
oZvIPlzzBpfPP+BHGO02cymKIqTTaUI3kf9ialZVdbeZS5blfVmWCV0w13X/zcwlSdK+JEnkv8xcFJJM
|
||||
Ju//Xuf6Be3RFseUK14pAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHISURBVDhPnZJfb9JgFMb3JbzV+C2WNPtk3jgXs0vdsuAW
|
||||
7zajKaEXTWjhvShpilBIA+GvtAWxIyAgJjNBW6WQx5yXtBPREX2SpnnPe57fc9KevXa7jVarhUajgXq9
|
||||
jlqthmq1ikqlQu97e7vUbDaxWq22nuFwyCGGYdwNoWQyDAYDnux5XgyhmmVZd0NoZGqmNDqXy+XKfD5H
|
||||
GIa8TkDTNP8OodRfGn8UCoVBEAT49PEbCmzK7/r9PvL5/J8hlByNvFwuQebP0wAvjlycPHLwNruG9Ho9
|
||||
6LoOVVU3IZZl+bPZjDctFguenHji4vJZH6/PPJwfdWOI67rQNG0TUiqVDkzT9KfTdZNdv+HJVycfIJ5f
|
||||
b0EcxwFjbBNSLBYFXdf9yWTCm7qtL0gcOnh1egtJHLow1PV9p9OBoigQRfEWYhiGoGmaPx6PtyBvEh5e
|
||||
HvdwcfwOYbjkU2QyGaRSqQcxgJTL5QTGmD8ajWLI2WMbF0+7uDrt4us8iM2iKD7cMEdijAnZbNanTeQf
|
||||
rnmDy+fv8T0Id5sjKYoipNNpnzYx+sVkVlV1tzmSLMv7siz7tGC2bf+bOZIkSfuSJPn/ZY5EkGQyef/3
|
||||
eqSfzGgWuCCdbTAAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="btnAddImage.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG8SURBVDhPnZLditpQFIXnJXrb0rcYCH2wXhSZwly2U0rp
|
||||
O0TMRUp+BTMaIYkERY3BH0TEalW8KEV6gp4cVjlnOBms7Ui7IITsvde3NmRfpWmKwWCAfr+PXq+HbreL
|
||||
TqeDdrvN38+uLilJEjDGzp7lcikgvu8/DeHJ3LBYLETyfD4vILwWx/HTEL4yH+Zp/LvVarX3+z0opaLO
|
||||
gWEY/h3CU+VgFEWHIAgWWZaBfv8GmjqiN5vN0Gw2/wzhyXLlPM/BzezHFrl9g/zLa9DUFr3pdIp6vQ7L
|
||||
sk4hcRyT3W4nho7Ho0jOrRKY9w6s8RHMvikgk8kEtVrtFBJF0aswDMl2u32AfO2KZHZ/B9b8fAYZj8dw
|
||||
XfcUEgSB0mg0yGazeYCsElCzBHb/4RFilUATQ/SHwyFM04Sqqo8Q3/cVz/PIer0+h/ifwNxb/DRvwXIq
|
||||
trBtG5VK5UUB4PI8T6lWq2S1WhWQo/EGzHmLrHaHA9kXZlVVX56YpVzXVRzHIfwSBWTZB/Xegx2yy2Yp
|
||||
0zQVwzAIv0T5i7nZsqzLZild1691XSf8wEaj0b+ZpTRNu9Y0jfyXWYpDyuXy89/rUr8A4v0dufOO1X4A
|
||||
AAAASUVORK5CYII=
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG6SURBVDhPnZLditpQFIXnJXrb0rcYCH2wXhSZwly2U0rp
|
||||
O0TMRUr+zkUyaUSjBEWNwR9ExGpVvCiDzAl6cljlnCGZWtuRdkEI2Xuvb23IvkiSBP1+H71eD91uF51O
|
||||
B+12G61WS7yfXZxTHMfgnJ88i8VCQoIgeBoikoVhPp/L5NlsVkBELYqipyFiZTEs0sR3s9ls7XY7MMZk
|
||||
XQDDMPw7RKT+Mriv1WrzNE3BfnwHSxzZm06nqFarf4aI5HzlLMsgzPxug8y+QvblNVhiy95kMoHv+7As
|
||||
6xgSRRHdbrdy6HA4yOTMKoF778C/fgS3rwrIeDyG67rHkEaj8SoMQ7rZbB4g3zoymd/egFc/n0BGoxEI
|
||||
IceQer2u+L5P1+v1A2QZg5kl8NsPjxCrBBYbsj8YDGCaJlRVfYQEQaC4rktXq9UpJPgETq5xb16DZ0xu
|
||||
Yds2KpXKiwIg5HmeQgihy+WygByMN+DOW6TuDfZ0V5hVVX15ZM5FCFEcx6HiEiVk0QPz3oPv0/PmXKZp
|
||||
KoZhUHGJ+S8WZsuyzptz6bp+qes6FQc2HA7/zZxL07RLTdPof5lzCUi5XH7+ez3XT8GUHaqSv5fjAAAA
|
||||
AElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="btnAddNode.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHeSURBVDhPnZLda9NgFMb3T3ir+F8Mwv6e3cgcorfToYgK
|
||||
Or/unF94ldJsZm3SJq4xTSFJDSlt09oPSilpa1sKilbfsn7wyPtCInG6og+EkHPO83sO5KxVq1VUKhWU
|
||||
y2WUSiUUi0UUCgW4rkvf59ZWyfM8LJfLU0+v12MQwzDOhtBkavB9nyV3Op0QQmuO45wNoSvTYZpGv/P5
|
||||
vDuZTDCfz1mdAi3L+juEpgaDtm2fmKbpT6dTjL50kfUOWa/dbiOXy/0ZQpODlReLBah5/PUTHia2cfdg
|
||||
E7p3wHqtVgu6rkOW5SjEcRwyHo/Z0Gw2w/BzF3uJy3j2bgcvtZt4lNgOIc1mE5lMJgqxbXvDsiwyGo3Y
|
||||
0Ef/A+4dbuL58Q280e/glXYrAmk0GlAUJQoxTZPLZrNkOByyoXq3gAfiFl4c74aQvaMtZEox1q/VapAk
|
||||
CTzP/4IYhsFpmkYGg8EpyOv3t/FUvoonR9cwX8zYFqlUCvF4/EIIoNI0jVNVlfT7/RBy/+0lPE5ewb66
|
||||
i+8/voVmnucvRsyBFEXh0uk0oZfI1vVd7KvXMT0hq82BJEnikskkoZcY/GJqlmV5tTmQKIrroigSemD1
|
||||
ev3fzIEEQVgXBIH8lzkQhcRisfO/1wP9BF1iD3Q2XAPzAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHdSURBVDhPnZLda9NgFMb3T3ir+F8Mgn/PbmQO0Vt1KKKC
|
||||
zo/dbX7hVUqzmbVJ+84lxpQ2rSGlbVr7QSklbW1LQdHqW9YPHnlfSDROV/SBEHLOeX7PgZyVSqWCcrmM
|
||||
UqmEYrGIQqGAfD4Px3HY+8zKMrmui8ViceLpdrscYprm6RCWzAye5/HkdrsdQFjNtu3TIWxlNszS2Hcu
|
||||
l3PG4zFmsxmvM6BlWX+HsNRfBo/T6bQ3mUww/NzBO3ef91qtFlKp1J8hLNlfeT6fg5lHXz7iYWwDd/fW
|
||||
YLh7vNdsNmEYBlRVDUNs26aj0YgPTadTDD51sBW7hJ031/Bcv4lHsY0A0mg0oGlaGJLNZi9YlkWHwyEf
|
||||
+uC9x739NTw9uoFXxh280G+FIPV6HYSQMCSTyQiGYdDBYMCHap08HsjreHa0GUC2DtahFSO8X61WoSgK
|
||||
RFH8CTFNU9A0jfb7/ROQl29vY1u9gicHVzGbT/kWiUQC0Wj0XABg0nVdIITQXq8XQO6/vojH8cvYPdzE
|
||||
t+9fA7MoiudDZl+EECGZTFJ2iXxdz8Hu4XVMjulysy9FUYR4PE7ZJfq/mJlVVV1u9iXL8qosy5QdWK1W
|
||||
+zezL0mSViVJov9l9sUgkUjk7O91Xz8AO/kPZbC5CrgAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="btnDelete.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGpSURBVDhP7Y87TyJRGIZR9AdYiYWFMdb+AYvNopXRWJho
|
||||
oY1aWGyzW8DuFmplobGxMxkPrVrY4f0SHJhhmBmGAYMxiIjcxkGh8ZZoeM05UWPG6w/wTZ7m5Hve8302
|
||||
23dYPB6PkxASJITgiyQ5jut+LiCExFVVRDabYORylCNGPp9kFArHMIwUDOMEsZhKSzIvC8xUKg5B8MPn
|
||||
8zF4noff70cgEIAgCAgGg5AkCaqqshKO424sBQeQJJGJVikUCkFRFCbregSmmXldkE4fQlFkiKLIRCrJ
|
||||
ssykcDiMSCQCXdexvx9DsZh7XXB6moCmqUyiv1FJ0zQmRqNRKHNj2BtswZazFrv9jVj83Xv3JGNnZxPn
|
||||
53lcXFAKKJUMlMtnj5hILE4j6mrDjXcGlfgarhb+QP7ViiX3AFjBZ3h7HLj2zgCzXYC7DphsQnHqB1Z6
|
||||
6vF8xkfZ+FlTqajLeJnyuAP03Tr7Ztbb7ZnL+WFg3IFblw0llw3pUTvWOuxZ6+yb4fsaJqSh5ru8uwnm
|
||||
v1okR6qw3Vlzv9pe/d86+274vsa/6057iq5NN3qSHwBTm6pq5+CDSAAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGvSURBVDhP7Y+/TxphGMdR4A9wKh0cNHHuP9ChKXQxsWEw
|
||||
oYMOjR06dGg6QNuhdHLQsLgZ8GVFBzcqRGtDD+447o7jwGAMIkV+ncevpa0mGr7N+0YNOX+0f0C/yWd5
|
||||
83y+7/NYLP/DEg6HnYSQNCEE/0g5FAo9vy4ghBQVRUC9XmI0GpRDRrNZZrRaR9D1CnT9BwoFhZbUhguM
|
||||
SqUInk8ikUgwOI5DMplEKpUCz/NIp9MQRRGKorCSYDB4airYhygKTDRLmUwGsiwzWdNyMIzazYJq9QCy
|
||||
LEEQBCZSSZIkJmWzWeRyOWiahr29Atrtxs2C4+MSVFVhEv2NSqqqMjGfz0Ne/YTv81PYcdrx7cU4Im9n
|
||||
z69k7O5uo9NpotultNDr6ej3Ty4xUFpfRt77GKfRAAbFGH5F3kF68wgbvjmwgr8RdTvwOxoAVmYA3xiw
|
||||
OIH20hN8cT/A9Rn3Jf7UNhgomxhO3+8AfTfP3pq4y1r7ubYA+B0481rQ81pQfW1F7Jm1bp69NZzn4Wfx
|
||||
5eR50zcB44Md5Vcj+Dptu9hyjX40z94ZzjP+Pu60VujadKMr+Q87TKpZvTdvaAAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="btnEditImage.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAL4SURBVDhPfdLfT9NXGMdx/oPdL17twmQxi97sajfTzV+b
|
||||
2Q91CxuxZGt0mWMxy3TFMhRx+hUqBVoI0FoqvxxrVSZFwHWtWuy0gy8UykAdiggMEGq/7bftkTB8L222
|
||||
TojbJ3muznNeJznPk2V39ZfZ2+RZs1NWjC3PqeaVVemQFetFuTzrn9ja5bm5R4+eqvE48YT431pQBXOR
|
||||
GDXOvkgGSL0cU+NUd0xS1hGk6PIPNPSZcQx+x7lgMVU+A5/XW/ja1oPONsJ8TGByDigZoLxFVlJ6zeVJ
|
||||
pK5uGnrNtA4dxNr7GTW3tNQG9mNwH2d/XQt6+yhzynOAWEJQ1zVFUWcT3weLqQ3spfKXPRh8HyFdz8bo
|
||||
+4pc02kKG+8wqyQxOftXAkpCYO2e5qirgbNyIRV+DdK1Dznm3cmRn3ciefLQVJRgb23idks2v186QdC2
|
||||
hWD1Ok0aiMQFtit/ILk6MftOUe7XUuTdhf6ndznqyebbH/OpbjzEjFeHMtQB6jSRofP4S7fNpoHHqsDu
|
||||
nsHcOUi+w47UfoBSz14k9ycUOL/AWJ/H/HARi5PtzFwzkAxd5M8HNxi07RNZqVmHY4IGz2waMbmCfFOs
|
||||
4aTxTSTDRs6YthEeLmQ5eYPkvTzCv37JaJOWoCVnIWB+b20aWIgK9I530LXu4OC5t7AUvErIvpvh5s08
|
||||
Dh1mWdwkMZaLeJhDbETPaN2OpwPlmzekP7GsuU8JRwW+sauZ8ofa6Ll0gJle3d+XNYiJj4kOF3Cv7m3O
|
||||
Nl5QM1MwpoHkCsB7tYSRK4dYTvoQ41qePNyDEjrM3dqtTE2MU+l4ZoxVTnkiHIkSVQXR+BMGvE381qln
|
||||
sKuCqcAHJMZzCAfzGTvzPgvT95lPr7L87ypb2+RSy/n+ntRypGRHyRsQe8Bty268+hfx127Hc/L15fpG
|
||||
l5o6r77Qr1jb5IoMsDrHtS8vLd6sYjFQSeDERlo/XaN269atX933n9n12gtCyl275D61fcldtul6R/4r
|
||||
L63ueTZ/AZ9Hi93BxLexAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAL5SURBVDhPfdLfT5tVHMdx/gPvjVcmGpPF6I033pip000X
|
||||
f+A0uGUlk0zjxCzGzbIiDpnbM6iUQiGUFqhd2YbtBo4yYMN2W4FtFR54oMimMhkDpA10fdqn7RlB9jZt
|
||||
tA4y/STfq/M9r5Oc7zfP4R2tdnTI4TqPrJraHlKu9WV2y6q9Q67J+yfNXSORcCRyX0smSabE/9ayJojE
|
||||
EjS6h2M5IPNyQkvS0D1HdbdC+fnvcY5YcI9/wymlgvqAkY9bbXzeMoC+ZYqlhKDWM6bmgJo2Wc3ojefn
|
||||
kHr7cA5baJ84gH34IxqvF2EN7sPYf4R9TScxOG4QUR8CJFKCpt55yntcnFYqsAb3Unt1N8bA+0hXCjAF
|
||||
PqOw7lvKTvxCWE1T6xldD6gpgb1vgcNeJ9/JZZiHdEiX3+Nrfz5f/ZiP5CtGZ67E0e7i5skCfjt3FKXl
|
||||
FZSGTbosEEsKWi78geTtwRI4Ts1QEeX+dzBcfJPDvgK+/KGEhhMHWfTrUSe6QVsgNnGGwaqt4SxwVxM4
|
||||
+hex9IxT4nYgde2nyrcXqX8PpZ5PMLUWszRZzspcF4uXjaRDHfx5exCl+UORl5l1NCFw+sJZpM6r8EWF
|
||||
jmOml5GMm2mu20p0soy19CDpW8VEf/qUG64iFNvO5aDlrSezwHJcYHC/gb59OwdOvYat9DlCjh1Mtm3h
|
||||
bugQa+IaqelCxJ1dJKYMTFm33x+r2fJs9hOrXSNqNC4ITF/K1VCok4Fz+1kc1v99WYeY3Ul8spRbTa/j
|
||||
cJ7VclMwZYH0OsB/qZKpCwdZSwcQM0Xcu7MbNXSIX62vMj87g9n9wBjrPfJsNBYnrgniyXuM+V383GNg
|
||||
vNfMfPBdUjO7iColTDe/zfLC7yxlV3nk31W2d8pVtjOjA5nlyMjuypcgcZubth34DY8yZN2G79gLa61O
|
||||
r5Y5rz87qto7ZXMO2JgjHzy1unKtnpVgLcGjmzm95zGtT7/pmY19/5n85x8RUuETqxePb1vtr37xSnfJ
|
||||
049v7HkwfwEdnYukisiEOQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="btnConnect.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
@@ -245,16 +263,16 @@
|
||||
<data name="btnDeleteConnection.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHwSURBVDhP7Y7Ni1JhGMVvXadgWrWzRcTQKgXJVbQQx0/w
|
||||
K7iL1FVBKdYrLW4fM9pdGCPMQpnAC+YqoY240VaTWhnouInIVubqziBFSJEGzaRN5olnIDFx/oMOvPBw
|
||||
zu8cXo77r4lsNtsJxti9eDzey2azkCSpwxi7wBhTS5KkkEcZMcT+U9ZoNMdcLlcilUqh2+1CURTUajXE
|
||||
YrFtSZLq7XZ7SF6j0QAxxFJnMqDX6y+Jovit1Wr1/H7/M4fDMQoGg5BlGdFoFHSTR1kul+sQS53pgcTa
|
||||
2tpAluWQ2+1eNBgM36vVKprNJur1OgqFAsijjBhiqTMZ0Ol0N0OhUD+dTt8VBKFiMpn27XY7BEE4eHST
|
||||
RxkxxFJnMqDVas95PJ52Mpns5/P5r8ViEZlMBqIoIhKJHNzldYZXl8/8fmlewFP74v6T5eMPJwMcx/FG
|
||||
o/G80+ncCQQCu+FweMAY++n1eq/4fD7Lo6vW4bs7FzHY3MD4fRl7+dt4E9aOXlhUt6ZHDlXJyis/NjcA
|
||||
2QOsngTWl/AlsYySmd+eZefquVk1Hr8tYlr9mBrkz7JzVbHyH3YfXwdiagxXOPRWOHRu8Cjb+I+z7Fxt
|
||||
+U49eH3t7K9Pq0v4HF2AEjiCqks1KlmP3p9lD9WW73SkYuF36Nv0o7/lP1AsGrGjxCTVAAAAAElFTkSu
|
||||
QmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHxSURBVDhP7Y7Ni1JhGMVvXadgWrWzRcS0S0FyFYHgOH4g
|
||||
fgQXQl0NRIr1SqB9zGh34XAXs7gwgRfMVUILsY22mhmlDHTcRGQrbXVnkCKkSIOmtMk88QyMmDj/QQde
|
||||
eDjndw4vx/3XWHa7/Qxj7IEkSd1sNgtRFNuMsSuMMa0oiip5lBFD7D9lnU53yu12y6lUCp1OB6qqolqt
|
||||
IplM7oqiWGu1WgPy6vU6iCGWOuMBo9F4LRqNfms2m91AILDldDqHoVAIiqIgkUiAbvIoy+VybWKpMzkg
|
||||
S5LUVxQl7PF45k0m0/dKpYJGo4FarYZCoQDyKCOGWOqMBwwGw+1wONxLp9P3BUEoWyyWA4fDAUEQDh/d
|
||||
5FFGDLHUGQ/o9fpLXq/3vSzLvXw+/7VYLCKTySAWiyEejx/epXWGV9cv/Hm5NIfnjvmDp4unH40HOI7j
|
||||
zWbzZZfLtRcMBvcjkUifMfbL5/Mt+/1+6+Nl6+Ddvavob25g1Crhx7O7eBPRDV9YNXcmR47Vto1Xf25u
|
||||
AIoXWD0LrC/gi7yILQu/O83OVHlJMxq9LWJSvaQW5E+zM1W28R/2n9wEkloMVjh0Vzi0b/Eo2fmP0+xM
|
||||
7fjPrb2+cfH3p9UFfE7MQQ2eQMWlGW7bTj6cZo/Vjv98vGzl9+jb9KOj8l/xBxqBzigbjwAAAABJRU5E
|
||||
rkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="btnToggleGrid.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
@@ -269,39 +287,18 @@
|
||||
<data name="btnFitMap.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKbSURBVDhPhZBdSFNhHMbPZURXEXQTFF2trgKpdWFZWH6c
|
||||
0vmxqUu3+bUskyyMUDqm4pxk5YwsmV1MsM3M6FA0NN1mzo+Dbec9y0ihwvmeQStGpO+xguDwxjvdzXHR
|
||||
A+/Ny/N7/s//T1GbCrjK1PyQkQVDphj/pFIOusrltw5DjOsvZrneQnXCl1SCy2AWXBVR/rERBAbOMUGH
|
||||
XjVrL1Bx/VqGs+vAbF9x1G/LMyu5uMjkODxYauXD6ABYQVoApXpBlOpCcC1nAa7u9/dorNO2/KjvNr21
|
||||
Ce8ysvygEQTDSAUgugggahJEdB2I69cEKF0VRKlUCP/YN9WtAd5OmlXyFHCZYoGBEiYUQQUAosYNWGrY
|
||||
hOuAiGoBlE55O2jG05kTU/IUP1QuB+16lSBKlxJTEyuQRgJENaTFWEuGyteVIyt5KuA0yeRgxEhAsCJd
|
||||
JmE8RBfifyKqDkGpmAR4rfTWAM5RGuMeahleXM/aaIFq43AEmYGIqgS4Vs6L6PjojdPMWHPG1hXm+rTs
|
||||
XK8OkEMJUCraBKsFca2CwAAizbvIzz2jbdm/3Y3p80qe8tty1TMPCqNvujVWfvnXXiEinSSVBSjpQhCl
|
||||
Eniqp/DPwkg99jWcwM/rU/XKDGqyK9fst2mi3ltnwER7JkP2JW+0KZ2ZvJMnL75qwpGgHS/P3MWedg1+
|
||||
UaXercygfFZaPW6h2fEOOkaO5bFky+6bmasTbWfxp8lO/PXDIP625MQfJ1rxSOUx2ZUsJJnYK2mGqe4S
|
||||
HJ614ej7AbzC3cfzjyqwNUP1+eX5lO1Kf1I9q001eCz5eMndjBfdLXj6XhEeqTn8/anu4A6l958aNh8x
|
||||
OMtS8OvWLDxcqf7i1KfsUnr+q+Gqozv7Sw5ZHKa0bYm/v22YpTjaxhhxAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>249, 17</value>
|
||||
</metadata>
|
||||
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>249, 17</value>
|
||||
</metadata>
|
||||
<data name="btNodeRemove.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKYSURBVDhPhZBfSFNRHMfvY0RPEfQSFD2tngKj9WBZmDqX
|
||||
em1t6tJtDV2WSRZGKN1ScV7JyhVZMnuYIJua0aXQ1Oamzj/DtnvuMlKocJ47aMWI9FwrCC4njrqX66Iv
|
||||
nJfD9/P9fX8/itpUyFOm5nvNHOi1JMJ9VjnkschzLlMi2FXMBTvOqpO+lBI8Jpvgtsb5HjMIdZ9jwi6j
|
||||
asapUwW79EzQaQDTncXxgKPQpuTWRSZvwKUsH0UHwDLSAyjVCKJUHYGr+fNwZX/gAc1OOQrj/rvarU14
|
||||
j5kjk8NRpAIQXQIQ1QsiugHEtesClK4JolQqRH/sm2ynga9Vyyl5CngsiVB3CROJIR2AqG4Dlmo34Wog
|
||||
oioApVO+Fi3jZfMTSp4K91rksNOoEkTpcnJqcgXSSICokrQYachW+dvyZCVPvXWbZXIwYiQgWJaukDAe
|
||||
oovrfyKqiECpmAT42NytAbOu0kTwiZ7hxTXNRgtUtQ7HkA2IqFyAq+d5ER0fvpnFjDDZW1eY7dRzsx0G
|
||||
QA4lQKloE6wQxFUrgQFE9LvYzz2vm3J/D9Vlzil5KuAoUE8/1sUn2mmWX/q1V4hJJ0llAUqGCETpBJ5w
|
||||
6P7MD9Rgf+0J/KIm3ajMoMbbCmwBBx333TkNvM05DNmXvOH6TGb8Hi0vDNbjWNiJl6bv47FmGr8sV+9W
|
||||
ZlB+Vqt+Y9dyoy25CXKsMbtGHryds+JtysOfxlvx1w89+NuiG3/0NuIB6zHZkyoklbirGabJ9hIcnXHg
|
||||
+PtuvBx8hOeeWjGbpfr86kLadqU/pZ5XpZvG7Gfw4tAtvDDUgKceFuGBysPfnxkO7lB6/6l+2xGTuywN
|
||||
jzZqcJ9V/cVtTNul9PxX/eVHd3aVHLK7LBnbkn9/ARsspRTlWFT8AAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="toolStrip2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
@@ -386,6 +383,21 @@
|
||||
8maMpXiUaCpB7aVH7Drag7TDOBxajYut0FpaD0XSzP7jfWfG6eiPsZKIYLLto83zJe2eGky2UlaTi9Rd
|
||||
CvLG4etIrxoHvigqHxh+pXIo+nLlIEWVA6KoYkCUnXUy+Ff+FYK4Nr4lkOwikO7CtWEB5mjqCvLm5zfY
|
||||
9qme1o7PBh0fmsYxmic4+v08R1pnqTJPU30uwBGzl11VN3jp427+BmRb26lRD0KdAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,825 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Design;
|
||||
using AGVNavigationCore.Models;
|
||||
using AGVNavigationCore.Controls;
|
||||
|
||||
namespace AGVMapEditor.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 노드 타입에 따른 PropertyWrapper 팩토리
|
||||
/// </summary>
|
||||
public static class NodePropertyWrapperFactory
|
||||
{
|
||||
public static object CreateWrapper(MapNode node, List<MapNode> mapNodes)
|
||||
{
|
||||
switch (node.Type)
|
||||
{
|
||||
case NodeType.Label:
|
||||
return new LabelNodePropertyWrapper(node, mapNodes);
|
||||
case NodeType.Image:
|
||||
return new ImageNodePropertyWrapper(node, mapNodes);
|
||||
default:
|
||||
return new NodePropertyWrapper(node, mapNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 라벨 노드 전용 PropertyWrapper
|
||||
/// </summary>
|
||||
public class LabelNodePropertyWrapper
|
||||
{
|
||||
private MapNode _node;
|
||||
private List<MapNode> _mapNodes;
|
||||
|
||||
public LabelNodePropertyWrapper(MapNode node, List<MapNode> mapNodes)
|
||||
{
|
||||
_node = node;
|
||||
_mapNodes = mapNodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 래핑된 MapNode 인스턴스 접근
|
||||
/// </summary>
|
||||
public MapNode WrappedNode => _node;
|
||||
|
||||
[Category("기본 정보")]
|
||||
[DisplayName("노드 ID")]
|
||||
[Description("노드의 고유 식별자")]
|
||||
[ReadOnly(true)]
|
||||
public string NodeId
|
||||
{
|
||||
get => _node.NodeId;
|
||||
}
|
||||
|
||||
[Category("기본 정보")]
|
||||
[DisplayName("노드 타입")]
|
||||
[Description("노드의 타입")]
|
||||
[ReadOnly(true)]
|
||||
public NodeType Type
|
||||
{
|
||||
get => _node.Type;
|
||||
}
|
||||
|
||||
[Category("라벨")]
|
||||
[DisplayName("텍스트")]
|
||||
[Description("표시할 텍스트")]
|
||||
public string LabelText
|
||||
{
|
||||
get => _node.LabelText;
|
||||
set
|
||||
{
|
||||
_node.LabelText = value ?? "";
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("라벨")]
|
||||
[DisplayName("폰트 패밀리")]
|
||||
[Description("폰트 패밀리")]
|
||||
public string FontFamily
|
||||
{
|
||||
get => _node.FontFamily;
|
||||
set
|
||||
{
|
||||
_node.FontFamily = value ?? "Arial";
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("라벨")]
|
||||
[DisplayName("폰트 크기")]
|
||||
[Description("폰트 크기")]
|
||||
public float FontSize
|
||||
{
|
||||
get => _node.FontSize;
|
||||
set
|
||||
{
|
||||
_node.FontSize = Math.Max(6, Math.Min(72, value));
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("라벨")]
|
||||
[DisplayName("폰트 스타일")]
|
||||
[Description("폰트 스타일")]
|
||||
public FontStyle FontStyle
|
||||
{
|
||||
get => _node.FontStyle;
|
||||
set
|
||||
{
|
||||
_node.FontStyle = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("라벨")]
|
||||
[DisplayName("전경색")]
|
||||
[Description("텍스트 색상")]
|
||||
public Color ForeColor
|
||||
{
|
||||
get => _node.ForeColor;
|
||||
set
|
||||
{
|
||||
_node.ForeColor = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("라벨")]
|
||||
[DisplayName("배경색")]
|
||||
[Description("배경 색상")]
|
||||
public Color BackColor
|
||||
{
|
||||
get => _node.BackColor;
|
||||
set
|
||||
{
|
||||
_node.BackColor = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("라벨")]
|
||||
[DisplayName("배경 표시")]
|
||||
[Description("배경을 표시할지 여부")]
|
||||
public bool ShowBackground
|
||||
{
|
||||
get => _node.ShowBackground;
|
||||
set
|
||||
{
|
||||
_node.ShowBackground = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("라벨")]
|
||||
[DisplayName("패딩")]
|
||||
[Description("텍스트 주변 여백 (픽셀 단위)")]
|
||||
public int Padding
|
||||
{
|
||||
get => _node.Padding;
|
||||
set
|
||||
{
|
||||
_node.Padding = Math.Max(0, Math.Min(50, value));
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("위치")]
|
||||
[DisplayName("X 좌표")]
|
||||
[Description("맵에서의 X 좌표")]
|
||||
public int PositionX
|
||||
{
|
||||
get => _node.Position.X;
|
||||
set
|
||||
{
|
||||
_node.Position = new Point(value, _node.Position.Y);
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("위치")]
|
||||
[DisplayName("Y 좌표")]
|
||||
[Description("맵에서의 Y 좌표")]
|
||||
public int PositionY
|
||||
{
|
||||
get => _node.Position.Y;
|
||||
set
|
||||
{
|
||||
_node.Position = new Point(_node.Position.X, value);
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("정보")]
|
||||
[DisplayName("생성 일시")]
|
||||
[Description("노드가 생성된 일시")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime CreatedDate
|
||||
{
|
||||
get => _node.CreatedDate;
|
||||
}
|
||||
|
||||
[Category("정보")]
|
||||
[DisplayName("수정 일시")]
|
||||
[Description("노드가 마지막으로 수정된 일시")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime ModifiedDate
|
||||
{
|
||||
get => _node.ModifiedDate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이미지 노드 전용 PropertyWrapper
|
||||
/// </summary>
|
||||
public class ImageNodePropertyWrapper
|
||||
{
|
||||
private MapNode _node;
|
||||
private List<MapNode> _mapNodes;
|
||||
|
||||
public ImageNodePropertyWrapper(MapNode node, List<MapNode> mapNodes)
|
||||
{
|
||||
_node = node;
|
||||
_mapNodes = mapNodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 래핑된 MapNode 인스턴스 접근
|
||||
/// </summary>
|
||||
public MapNode WrappedNode => _node;
|
||||
|
||||
[Category("기본 정보")]
|
||||
[DisplayName("노드 ID")]
|
||||
[Description("노드의 고유 식별자")]
|
||||
[ReadOnly(true)]
|
||||
public string NodeId
|
||||
{
|
||||
get => _node.NodeId;
|
||||
}
|
||||
|
||||
[Category("기본 정보")]
|
||||
[DisplayName("노드 타입")]
|
||||
[Description("노드의 타입")]
|
||||
[ReadOnly(true)]
|
||||
public NodeType Type
|
||||
{
|
||||
get => _node.Type;
|
||||
}
|
||||
|
||||
[Category("이미지")]
|
||||
[DisplayName("이미지 경로")]
|
||||
[Description("이미지 파일 경로 (... 버튼으로 파일 선택)")]
|
||||
[Editor(typeof(ImagePathEditor), typeof(UITypeEditor))]
|
||||
public string ImagePath
|
||||
{
|
||||
get => _node.ImagePath;
|
||||
set
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("이미지")]
|
||||
[DisplayName("가로 배율")]
|
||||
[Description("가로 배율 (1.0 = 원본 크기)")]
|
||||
public float ScaleWidth
|
||||
{
|
||||
get => _node.Scale.Width;
|
||||
set
|
||||
{
|
||||
_node.Scale = new SizeF(Math.Max(0.1f, Math.Min(5.0f, value)), _node.Scale.Height);
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("이미지")]
|
||||
[DisplayName("세로 배율")]
|
||||
[Description("세로 배율 (1.0 = 원본 크기)")]
|
||||
public float ScaleHeight
|
||||
{
|
||||
get => _node.Scale.Height;
|
||||
set
|
||||
{
|
||||
_node.Scale = new SizeF(_node.Scale.Width, Math.Max(0.1f, Math.Min(5.0f, value)));
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("이미지")]
|
||||
[DisplayName("투명도")]
|
||||
[Description("투명도 (0.0 = 투명, 1.0 = 불투명)")]
|
||||
public float Opacity
|
||||
{
|
||||
get => _node.Opacity;
|
||||
set
|
||||
{
|
||||
_node.Opacity = Math.Max(0.0f, Math.Min(1.0f, value));
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("이미지")]
|
||||
[DisplayName("회전각도")]
|
||||
[Description("회전 각도 (도 단위)")]
|
||||
public float Rotation
|
||||
{
|
||||
get => _node.Rotation;
|
||||
set
|
||||
{
|
||||
_node.Rotation = value % 360;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("위치")]
|
||||
[DisplayName("X 좌표")]
|
||||
[Description("맵에서의 X 좌표")]
|
||||
public int PositionX
|
||||
{
|
||||
get => _node.Position.X;
|
||||
set
|
||||
{
|
||||
_node.Position = new Point(value, _node.Position.Y);
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("위치")]
|
||||
[DisplayName("Y 좌표")]
|
||||
[Description("맵에서의 Y 좌표")]
|
||||
public int PositionY
|
||||
{
|
||||
get => _node.Position.Y;
|
||||
set
|
||||
{
|
||||
_node.Position = new Point(_node.Position.X, value);
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("정보")]
|
||||
[DisplayName("생성 일시")]
|
||||
[Description("노드가 생성된 일시")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime CreatedDate
|
||||
{
|
||||
get => _node.CreatedDate;
|
||||
}
|
||||
|
||||
[Category("정보")]
|
||||
[DisplayName("수정 일시")]
|
||||
[Description("노드가 마지막으로 수정된 일시")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime ModifiedDate
|
||||
{
|
||||
get => _node.ModifiedDate;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// PropertyGrid에서 사용할 노드 속성 래퍼 클래스
|
||||
/// </summary>
|
||||
public class NodePropertyWrapper
|
||||
{
|
||||
private MapNode _node;
|
||||
private List<MapNode> _mapNodes;
|
||||
|
||||
public NodePropertyWrapper(MapNode node, List<MapNode> mapNodes)
|
||||
{
|
||||
_node = node;
|
||||
_mapNodes = mapNodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 래핑된 MapNode 인스턴스 접근
|
||||
/// </summary>
|
||||
public MapNode WrappedNode => _node;
|
||||
|
||||
[Category("기본 정보")]
|
||||
[DisplayName("노드 ID")]
|
||||
[Description("노드의 고유 식별자")]
|
||||
[ReadOnly(true)]
|
||||
public string NodeId
|
||||
{
|
||||
get => _node.NodeId;
|
||||
set => _node.NodeId = value;
|
||||
}
|
||||
|
||||
[Category("기본 정보")]
|
||||
[DisplayName("노드 이름")]
|
||||
[Description("노드의 표시 이름")]
|
||||
public string Name
|
||||
{
|
||||
get => _node.Name;
|
||||
set
|
||||
{
|
||||
_node.Name = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Category("기본 정보")]
|
||||
[DisplayName("노드 타입")]
|
||||
[Description("노드의 타입 (Normal, Rotation, Docking, Charging)")]
|
||||
public NodeType Type
|
||||
{
|
||||
get => _node.Type;
|
||||
set
|
||||
{
|
||||
_node.Type = value;
|
||||
_node.CanRotate = value == NodeType.Rotation;
|
||||
_node.SetDefaultColorByType(value);
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("기본 정보")]
|
||||
[DisplayName("도킹 방향")]
|
||||
[Description("도킹이 필요한 노드의 경우 AGV 진입 방향 (DontCare: 방향 무관, Forward: 전진 도킹, Backward: 후진 도킹)")]
|
||||
public DockingDirection DockDirection
|
||||
{
|
||||
get => _node.DockDirection;
|
||||
set
|
||||
{
|
||||
_node.DockDirection = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[Category("위치")]
|
||||
[DisplayName("X 좌표")]
|
||||
[Description("맵에서의 X 좌표")]
|
||||
public int PositionX
|
||||
{
|
||||
get => _node.Position.X;
|
||||
set
|
||||
{
|
||||
_node.Position = new Point(value, _node.Position.Y);
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("위치")]
|
||||
[DisplayName("Y 좌표")]
|
||||
[Description("맵에서의 Y 좌표")]
|
||||
public int PositionY
|
||||
{
|
||||
get => _node.Position.Y;
|
||||
set
|
||||
{
|
||||
_node.Position = new Point(_node.Position.X, value);
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Category("고급")]
|
||||
[DisplayName("회전 가능")]
|
||||
[Description("이 노드에서 AGV가 회전할 수 있는지 여부")]
|
||||
public bool CanRotate
|
||||
{
|
||||
get => _node.CanRotate;
|
||||
set
|
||||
{
|
||||
_node.CanRotate = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("고급")]
|
||||
[DisplayName("RFID")]
|
||||
[Description("RFID ID")]
|
||||
public string RFID
|
||||
{
|
||||
get => _node.RfidId;
|
||||
set
|
||||
{
|
||||
_node.RfidId = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
[Category("고급")]
|
||||
[DisplayName("활성화")]
|
||||
[Description("노드 활성화 여부")]
|
||||
public bool IsActive
|
||||
{
|
||||
get => _node.IsActive;
|
||||
set
|
||||
{
|
||||
_node.IsActive = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("노드 배경색")]
|
||||
[Description("노드 배경 색상")]
|
||||
public Color DisplayColor
|
||||
{
|
||||
get => _node.DisplayColor;
|
||||
set
|
||||
{
|
||||
_node.DisplayColor = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("글자 색상")]
|
||||
[Description("노드 텍스트 색상 (NodeId, Name 등)")]
|
||||
public Color ForeColor
|
||||
{
|
||||
get => _node.ForeColor;
|
||||
set
|
||||
{
|
||||
_node.ForeColor = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("글자 크기")]
|
||||
[Description("노드 텍스트 크기 (픽셀)")]
|
||||
public float TextFontSize
|
||||
{
|
||||
get => _node.TextFontSize;
|
||||
set
|
||||
{
|
||||
_node.TextFontSize = Math.Max(5.0f, Math.Min(20.0f, value));
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("글자 굵게")]
|
||||
[Description("노드 텍스트 볼드 표시")]
|
||||
public bool TextFontBold
|
||||
{
|
||||
get => _node.TextFontBold;
|
||||
set
|
||||
{
|
||||
_node.TextFontBold = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("이름 말풍선 배경색")]
|
||||
[Description("노드 이름 말풍선(하단 표시) 배경색")]
|
||||
public Color NameBubbleBackColor
|
||||
{
|
||||
get => _node.NameBubbleBackColor;
|
||||
set
|
||||
{
|
||||
_node.NameBubbleBackColor = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("이름 말풍선 글자색")]
|
||||
[Description("노드 이름 말풍선(하단 표시) 글자색")]
|
||||
public Color NameBubbleForeColor
|
||||
{
|
||||
get => _node.NameBubbleForeColor;
|
||||
set
|
||||
{
|
||||
_node.NameBubbleForeColor = value;
|
||||
_node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("정보")]
|
||||
[DisplayName("생성 일시")]
|
||||
[Description("노드가 생성된 일시")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime CreatedDate
|
||||
{
|
||||
get => _node.CreatedDate;
|
||||
}
|
||||
|
||||
[Category("정보")]
|
||||
[DisplayName("수정 일시")]
|
||||
[Description("노드가 마지막으로 수정된 일시")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime ModifiedDate
|
||||
{
|
||||
get => _node.ModifiedDate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 다중 노드 선택 시 공통 속성 편집용 래퍼
|
||||
/// </summary>
|
||||
public class MultiNodePropertyWrapper
|
||||
{
|
||||
private List<MapNode> _nodes;
|
||||
|
||||
public MultiNodePropertyWrapper(List<MapNode> nodes)
|
||||
{
|
||||
_nodes = nodes ?? new List<MapNode>();
|
||||
}
|
||||
|
||||
[Category("다중 선택")]
|
||||
[DisplayName("선택된 노드 수")]
|
||||
[Description("현재 선택된 노드의 개수")]
|
||||
[ReadOnly(true)]
|
||||
public int SelectedCount => _nodes.Count;
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("노드 배경색")]
|
||||
[Description("선택된 모든 노드의 배경색을 일괄 변경")]
|
||||
public Color DisplayColor
|
||||
{
|
||||
get => _nodes.Count > 0 ? _nodes[0].DisplayColor : Color.Blue;
|
||||
set
|
||||
{
|
||||
foreach (var node in _nodes)
|
||||
{
|
||||
node.DisplayColor = value;
|
||||
node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("글자 색상")]
|
||||
[Description("선택된 모든 노드의 글자 색상을 일괄 변경")]
|
||||
public Color ForeColor
|
||||
{
|
||||
get => _nodes.Count > 0 ? _nodes[0].ForeColor : Color.Black;
|
||||
set
|
||||
{
|
||||
foreach (var node in _nodes)
|
||||
{
|
||||
node.ForeColor = value;
|
||||
node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("글자 크기")]
|
||||
[Description("선택된 모든 노드의 글자 크기를 일괄 변경 (5~20 픽셀)")]
|
||||
public float TextFontSize
|
||||
{
|
||||
get => _nodes.Count > 0 ? _nodes[0].TextFontSize : 7.0f;
|
||||
set
|
||||
{
|
||||
var validValue = Math.Max(5.0f, Math.Min(20.0f, value));
|
||||
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontSize 변경 시작: {validValue}, 노드 수: {_nodes.Count}");
|
||||
|
||||
foreach (var node in _nodes)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($" - 노드 {node.NodeId}: {node.TextFontSize} → {validValue}");
|
||||
node.TextFontSize = validValue;
|
||||
node.ModifiedDate = DateTime.Now;
|
||||
System.Diagnostics.Debug.WriteLine($" - 변경 후: {node.TextFontSize}");
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontSize 변경 완료");
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("글자 굵게")]
|
||||
[Description("선택된 모든 노드의 글자 굵기를 일괄 변경")]
|
||||
public bool TextFontBold
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = _nodes.Count > 0 ? _nodes[0].TextFontBold : true;
|
||||
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontBold GET: {result}");
|
||||
return result;
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontBold 변경 시작: {value}, 노드 수: {_nodes.Count}");
|
||||
|
||||
foreach (var node in _nodes)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($" - 노드 {node.NodeId}: {node.TextFontBold} → {value}");
|
||||
node.TextFontBold = value;
|
||||
node.ModifiedDate = DateTime.Now;
|
||||
System.Diagnostics.Debug.WriteLine($" - 변경 후: {node.TextFontBold}");
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"[MultiNode] TextFontBold 변경 완료");
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("이름 말풍선 배경색")]
|
||||
[Description("선택된 모든 노드의 이름 말풍선(하단 표시) 배경색을 일괄 변경")]
|
||||
public Color NameBubbleBackColor
|
||||
{
|
||||
get => _nodes.Count > 0 ? _nodes[0].NameBubbleBackColor : Color.Gold;
|
||||
set
|
||||
{
|
||||
foreach (var node in _nodes)
|
||||
{
|
||||
node.NameBubbleBackColor = value;
|
||||
node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Category("표시")]
|
||||
[DisplayName("이름 말풍선 글자색")]
|
||||
[Description("선택된 모든 노드의 이름 말풍선(하단 표시) 글자색을 일괄 변경")]
|
||||
public Color NameBubbleForeColor
|
||||
{
|
||||
get => _nodes.Count > 0 ? _nodes[0].NameBubbleForeColor : Color.Black;
|
||||
set
|
||||
{
|
||||
foreach (var node in _nodes)
|
||||
{
|
||||
node.NameBubbleForeColor = value;
|
||||
node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Category("고급")]
|
||||
[DisplayName("활성화")]
|
||||
[Description("선택된 모든 노드의 활성화 상태를 일괄 변경")]
|
||||
public bool IsActive
|
||||
{
|
||||
get => _nodes.Count > 0 ? _nodes[0].IsActive : true;
|
||||
set
|
||||
{
|
||||
foreach (var node in _nodes)
|
||||
{
|
||||
node.IsActive = value;
|
||||
node.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Category("정보")]
|
||||
[DisplayName("안내")]
|
||||
[Description("다중 선택 시 공통 속성만 변경할 수 있습니다")]
|
||||
[ReadOnly(true)]
|
||||
public string HelpText => "위 속성을 변경하면 선택된 모든 노드에 일괄 적용됩니다.";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 캔버스 속성 래퍼 (배경색 등 캔버스 전체 속성 편집)
|
||||
/// </summary>
|
||||
public class CanvasPropertyWrapper
|
||||
{
|
||||
private UnifiedAGVCanvas _canvas;
|
||||
|
||||
public CanvasPropertyWrapper(UnifiedAGVCanvas canvas)
|
||||
{
|
||||
_canvas = canvas;
|
||||
}
|
||||
|
||||
[Category("배경")]
|
||||
[DisplayName("배경색")]
|
||||
[Description("맵 캔버스 배경색")]
|
||||
public Color BackgroundColor
|
||||
{
|
||||
get => _canvas.BackColor;
|
||||
set
|
||||
{
|
||||
_canvas.BackColor = value;
|
||||
_canvas.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("그리드")]
|
||||
[DisplayName("그리드 표시")]
|
||||
[Description("그리드 표시 여부")]
|
||||
public bool ShowGrid
|
||||
{
|
||||
get => _canvas.ShowGrid;
|
||||
set
|
||||
{
|
||||
_canvas.ShowGrid = value;
|
||||
_canvas.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Category("정보")]
|
||||
[DisplayName("설명")]
|
||||
[Description("맵 캔버스 전체 속성")]
|
||||
[ReadOnly(true)]
|
||||
public string Description
|
||||
{
|
||||
get => "빈 공간을 클릭하면 캔버스 전체 속성을 편집할 수 있습니다.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -416,10 +416,10 @@ namespace AGVNavigationCore.Controls
|
||||
case NodeType.Normal:
|
||||
ghostBrush = new SolidBrush(Color.FromArgb(120, 100, 149, 237)); // 반투명 파란색
|
||||
break;
|
||||
case NodeType.Rotation:
|
||||
ghostBrush = new SolidBrush(Color.FromArgb(120, 255, 165, 0)); // 반투명 주황색
|
||||
break;
|
||||
case NodeType.Docking:
|
||||
case NodeType.Loader:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
ghostBrush = new SolidBrush(Color.FromArgb(120, 50, 205, 50)); // 반투명 초록색
|
||||
break;
|
||||
case NodeType.Charging:
|
||||
@@ -439,7 +439,10 @@ namespace AGVNavigationCore.Controls
|
||||
case NodeType.Image:
|
||||
DrawImageGhost(g);
|
||||
break;
|
||||
case NodeType.Docking:
|
||||
case NodeType.Loader:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
DrawPentagonGhost(g, ghostBrush);
|
||||
break;
|
||||
case NodeType.Charging:
|
||||
@@ -646,7 +649,10 @@ namespace AGVNavigationCore.Controls
|
||||
|
||||
switch (node.Type)
|
||||
{
|
||||
case NodeType.Docking:
|
||||
case NodeType.Loader:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
DrawPentagonNodeShape(g, node, brush);
|
||||
break;
|
||||
case NodeType.Charging:
|
||||
@@ -723,6 +729,13 @@ namespace AGVNavigationCore.Controls
|
||||
{
|
||||
DrawDuplicateRfidMarker(g, node);
|
||||
}
|
||||
|
||||
// CanCross 가능 노드 표시 (교차지점으로 사용 가능)
|
||||
if (node.DisableCross==true)
|
||||
{
|
||||
var crossRect = new Rectangle(rect.X - 3, rect.Y - 3, rect.Width + 6, rect.Height + 6);
|
||||
g.DrawEllipse(new Pen(Color.DeepSkyBlue, 3), crossRect);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPentagonNodeShape(Graphics g, MapNode node, Brush brush)
|
||||
@@ -826,6 +839,21 @@ namespace AGVNavigationCore.Controls
|
||||
{
|
||||
DrawDuplicateRfidMarker(g, node);
|
||||
}
|
||||
|
||||
// CanCross 가능 노드 표시 (교차지점으로 사용 가능)
|
||||
if (node.DisableCross==false)
|
||||
{
|
||||
var crossPoints = new Point[5];
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
|
||||
crossPoints[i] = new Point(
|
||||
(int)(center.X + (radius + 4) * Math.Cos(angle)),
|
||||
(int)(center.Y + (radius + 4) * Math.Sin(angle))
|
||||
);
|
||||
}
|
||||
g.DrawPolygon(new Pen(Color.Gold, 3), crossPoints);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTriangleNodeShape(Graphics g, MapNode node, Brush brush)
|
||||
@@ -929,6 +957,21 @@ namespace AGVNavigationCore.Controls
|
||||
{
|
||||
DrawDuplicateRfidMarker(g, node);
|
||||
}
|
||||
|
||||
// CanCross 가능 노드 표시 (교차지점으로 사용 가능)
|
||||
if (node.DisableCross==false)
|
||||
{
|
||||
var crossPoints = new Point[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
|
||||
crossPoints[i] = new Point(
|
||||
(int)(center.X + (radius + 4) * Math.Cos(angle)),
|
||||
(int)(center.Y + (radius + 4) * Math.Sin(angle))
|
||||
);
|
||||
}
|
||||
g.DrawPolygon(new Pen(Color.Gold, 3), crossPoints);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawNodeLabel(Graphics g, MapNode node)
|
||||
|
||||
@@ -108,8 +108,10 @@ namespace AGVNavigationCore.Controls
|
||||
switch (hitNode.Type)
|
||||
{
|
||||
case NodeType.Normal:
|
||||
case NodeType.Rotation:
|
||||
case NodeType.Docking:
|
||||
case NodeType.Loader:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
case NodeType.Charging:
|
||||
HandleNormalNodeDoubleClick(hitNode);
|
||||
break;
|
||||
@@ -429,7 +431,10 @@ namespace AGVNavigationCore.Controls
|
||||
{
|
||||
switch (node.Type)
|
||||
{
|
||||
case NodeType.Docking:
|
||||
case NodeType.Loader:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
return IsPointInPentagon(point, node);
|
||||
case NodeType.Charging:
|
||||
return IsPointInTriangle(point, node);
|
||||
|
||||
@@ -11,10 +11,20 @@ namespace AGVNavigationCore.Models
|
||||
{
|
||||
/// <summary>일반 경로 노드</summary>
|
||||
Normal,
|
||||
/// <summary>회전 가능 지점</summary>
|
||||
Rotation,
|
||||
/// <summary>도킹 스테이션</summary>
|
||||
Docking,
|
||||
/// <summary>로더</summary>
|
||||
Loader,
|
||||
/// <summary>
|
||||
/// 언로더
|
||||
/// </summary>
|
||||
UnLoader,
|
||||
/// <summary>
|
||||
/// 클리너
|
||||
/// </summary>
|
||||
Clearner,
|
||||
/// <summary>
|
||||
/// 버퍼
|
||||
/// </summary>
|
||||
Buffer,
|
||||
/// <summary>충전 스테이션</summary>
|
||||
Charging,
|
||||
/// <summary>라벨 (UI 요소)</summary>
|
||||
@@ -58,6 +68,10 @@ namespace AGVNavigationCore.Models
|
||||
/// </summary>
|
||||
public enum StationType
|
||||
{
|
||||
/// <summary>
|
||||
/// 일반노드
|
||||
/// </summary>
|
||||
Node,
|
||||
/// <summary>로더</summary>
|
||||
Loader,
|
||||
/// <summary>클리너</summary>
|
||||
@@ -70,6 +84,24 @@ namespace AGVNavigationCore.Models
|
||||
Charger
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AGV턴상태
|
||||
/// </summary>
|
||||
public enum AGVTurn
|
||||
{
|
||||
None=0,
|
||||
|
||||
/// <summary>
|
||||
/// left turn 90"
|
||||
/// </summary>
|
||||
L90,
|
||||
/// <summary>
|
||||
/// right turn 90"
|
||||
/// </summary>
|
||||
R90
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 모터 명령 열거형 (실제 AGV 제어용)
|
||||
/// </summary>
|
||||
|
||||
@@ -226,7 +226,10 @@ namespace AGVNavigationCore.Models
|
||||
case NodeType.Charging:
|
||||
node.DockDirection = DockingDirection.Forward;
|
||||
break;
|
||||
case NodeType.Docking:
|
||||
case NodeType.Loader:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
node.DockDirection = DockingDirection.Backward;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -34,6 +34,19 @@ namespace AGVNavigationCore.Models
|
||||
/// </summary>
|
||||
public NodeType Type { get; set; } = NodeType.Normal;
|
||||
|
||||
public bool CanDocking
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Type == NodeType.Buffer) return true;
|
||||
if (Type == NodeType.Loader) return true;
|
||||
if (Type == NodeType.UnLoader) return true;
|
||||
if (Type == NodeType.Clearner) return true;
|
||||
if (Type == NodeType.Charging) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 도킹 방향 (도킹/충전 노드인 경우에만 Forward/Backward, 일반 노드는 DontCare)
|
||||
/// </summary>
|
||||
@@ -53,18 +66,38 @@ namespace AGVNavigationCore.Models
|
||||
/// <summary>
|
||||
/// 회전 가능 여부 (180도 회전 가능한 지점)
|
||||
/// </summary>
|
||||
public bool CanRotate { get; set; } = false;
|
||||
public bool CanTurnLeft { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 회전 가능 여부 (180도 회전 가능한 지점)
|
||||
/// </summary>
|
||||
public bool CanTurnRight { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 교차로로 이용가능한지
|
||||
/// </summary>
|
||||
public bool DisableCross
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Type != NodeType.Normal) return true;
|
||||
return _disablecross;
|
||||
}
|
||||
set { _disablecross = value; }
|
||||
}
|
||||
|
||||
private bool _disablecross = false;
|
||||
|
||||
/// <summary>
|
||||
/// 장비 ID (도킹/충전 스테이션인 경우)
|
||||
/// 예: "LOADER1", "CLEANER1", "BUFFER1", "CHARGER1"
|
||||
/// </summary>
|
||||
public string StationId { get; set; } = string.Empty;
|
||||
public string NodeAlias { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 장비 타입 (도킹/충전 스테이션인 경우)
|
||||
/// </summary>
|
||||
public StationType? StationType { get; set; } = null;
|
||||
// public StationType? StationType { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 노드 생성 일자
|
||||
@@ -224,7 +257,7 @@ namespace AGVNavigationCore.Models
|
||||
Type = type;
|
||||
CreatedDate = DateTime.Now;
|
||||
ModifiedDate = DateTime.Now;
|
||||
|
||||
|
||||
// 타입별 기본 색상 설정
|
||||
SetDefaultColorByType(type);
|
||||
}
|
||||
@@ -240,10 +273,10 @@ namespace AGVNavigationCore.Models
|
||||
case NodeType.Normal:
|
||||
DisplayColor = Color.Blue;
|
||||
break;
|
||||
case NodeType.Rotation:
|
||||
DisplayColor = Color.Orange;
|
||||
break;
|
||||
case NodeType.Docking:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
case NodeType.Loader:
|
||||
DisplayColor = Color.Green;
|
||||
break;
|
||||
case NodeType.Charging:
|
||||
@@ -283,21 +316,20 @@ namespace AGVNavigationCore.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 도킹 스테이션 설정
|
||||
/// </summary>
|
||||
/// <param name="stationId">장비 ID</param>
|
||||
/// <param name="stationType">장비 타입</param>
|
||||
/// <param name="dockDirection">도킹 방향</param>
|
||||
public void SetDockingStation(string stationId, StationType stationType, DockingDirection dockDirection)
|
||||
{
|
||||
Type = NodeType.Docking;
|
||||
StationId = stationId;
|
||||
StationType = stationType;
|
||||
DockDirection = dockDirection;
|
||||
SetDefaultColorByType(NodeType.Docking);
|
||||
ModifiedDate = DateTime.Now;
|
||||
}
|
||||
///// <summary>
|
||||
///// 도킹 스테이션 설정
|
||||
///// </summary>
|
||||
///// <param name="stationId">장비 ID</param>
|
||||
///// <param name="stationType">장비 타입</param>
|
||||
///// <param name="dockDirection">도킹 방향</param>
|
||||
//public void SetDockingStation(string stationId, StationType stationType, DockingDirection dockDirection)
|
||||
//{
|
||||
// Type = NodeType.Docking;
|
||||
// NodeAlias = stationId;
|
||||
// DockDirection = dockDirection;
|
||||
// SetDefaultColorByType(NodeType.Docking);
|
||||
// ModifiedDate = DateTime.Now;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 충전 스테이션 설정
|
||||
@@ -306,8 +338,7 @@ namespace AGVNavigationCore.Models
|
||||
public void SetChargingStation(string stationId)
|
||||
{
|
||||
Type = NodeType.Charging;
|
||||
StationId = stationId;
|
||||
StationType = Models.StationType.Charger;
|
||||
NodeAlias = stationId;
|
||||
DockDirection = DockingDirection.Forward; // 충전기는 항상 전진 도킹
|
||||
SetDefaultColorByType(NodeType.Charging);
|
||||
ModifiedDate = DateTime.Now;
|
||||
@@ -329,17 +360,17 @@ namespace AGVNavigationCore.Models
|
||||
get
|
||||
{
|
||||
var displayText = NodeId;
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
displayText += $" - {Name}";
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(RfidId))
|
||||
{
|
||||
displayText += $" - [{RfidId}]";
|
||||
}
|
||||
|
||||
|
||||
return displayText;
|
||||
}
|
||||
}
|
||||
@@ -358,9 +389,12 @@ namespace AGVNavigationCore.Models
|
||||
Type = Type,
|
||||
DockDirection = DockDirection,
|
||||
ConnectedNodes = new List<string>(ConnectedNodes),
|
||||
CanRotate = CanRotate,
|
||||
StationId = StationId,
|
||||
StationType = StationType,
|
||||
|
||||
CanTurnLeft = CanTurnLeft,
|
||||
CanTurnRight = CanTurnRight,
|
||||
DisableCross = DisableCross,
|
||||
|
||||
NodeAlias = NodeAlias,
|
||||
CreatedDate = CreatedDate,
|
||||
ModifiedDate = ModifiedDate,
|
||||
IsActive = IsActive,
|
||||
@@ -475,7 +509,7 @@ namespace AGVNavigationCore.Models
|
||||
public Size GetDisplaySize()
|
||||
{
|
||||
if (Type != NodeType.Image || LoadedImage == null) return Size.Empty;
|
||||
|
||||
|
||||
return new Size(
|
||||
(int)(LoadedImage.Width * Scale.Width),
|
||||
(int)(LoadedImage.Height * Scale.Height)
|
||||
|
||||
@@ -61,12 +61,12 @@ namespace AGVNavigationCore.Models
|
||||
private int _currentNodeIndex;
|
||||
private MapNode _currentNode;
|
||||
private MapNode _prevNode;
|
||||
private AGVTurn _turn;
|
||||
|
||||
// 이동 관련
|
||||
private DateTime _lastUpdateTime;
|
||||
private Point _moveStartPosition;
|
||||
private Point _moveTargetPosition;
|
||||
private float _moveProgress;
|
||||
|
||||
// 도킹 관련
|
||||
private DockingDirection _dockingDirection;
|
||||
@@ -89,7 +89,6 @@ namespace AGVNavigationCore.Models
|
||||
public AgvDirection PrevDirection => _prevDirection;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AGV ID
|
||||
/// </summary>
|
||||
@@ -158,6 +157,11 @@ namespace AGVNavigationCore.Models
|
||||
/// </summary>
|
||||
public MapNode PrevNode => _prevNode;
|
||||
|
||||
/// <summary>
|
||||
/// Turn 상태값
|
||||
/// </summary>
|
||||
public AGVTurn Turn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 도킹 방향
|
||||
/// </summary>
|
||||
@@ -527,10 +531,10 @@ namespace AGVNavigationCore.Models
|
||||
_prevPosition = targetPosition;
|
||||
_moveStartPosition = _currentPosition;
|
||||
_moveTargetPosition = targetPosition;
|
||||
_moveProgress = 0;
|
||||
|
||||
SetState(AGVState.Moving);
|
||||
_isMoving = true;
|
||||
Turn = AGVTurn.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -620,7 +624,6 @@ namespace AGVNavigationCore.Models
|
||||
if (item != null)
|
||||
{
|
||||
//item.IsPass = true;
|
||||
|
||||
//이전노드는 모두 지나친걸로 한다
|
||||
CurrentPath.DetailedPath.Where(t => t.seq < item.seq).ToList().ForEach(t => t.IsPass = true);
|
||||
}
|
||||
@@ -865,7 +868,10 @@ namespace AGVNavigationCore.Models
|
||||
{
|
||||
case NodeType.Charging:
|
||||
return DockingDirection.Forward;
|
||||
case NodeType.Docking:
|
||||
case NodeType.Loader:
|
||||
case NodeType.UnLoader:
|
||||
case NodeType.Clearner:
|
||||
case NodeType.Buffer:
|
||||
return DockingDirection.Backward;
|
||||
default:
|
||||
return DockingDirection.Forward;
|
||||
@@ -880,8 +886,6 @@ namespace AGVNavigationCore.Models
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Cleanup
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
/// <param name="startNodeId">시작 노드 ID</param>
|
||||
/// <param name="endNodeId">목적지 노드 ID</param>
|
||||
/// <returns>경로 계산 결과</returns>
|
||||
public AGVPathResult FindPath(string startNodeId, string endNodeId)
|
||||
public AGVPathResult FindPathAStar(string startNodeId, string endNodeId)
|
||||
{
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
|
||||
@@ -126,7 +126,6 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
|
||||
var startNode = _nodeMap[startNodeId];
|
||||
var endNode = _nodeMap[endNodeId];
|
||||
|
||||
var openSet = new List<PathNode>();
|
||||
var closedSet = new HashSet<string>();
|
||||
var exploredCount = 0;
|
||||
@@ -199,7 +198,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
// 경유지가 없으면 기본 FindPath 호출
|
||||
if (waypointNodeIds == null || waypointNodeIds.Length == 0)
|
||||
{
|
||||
return FindPath(startNodeId, endNodeId);
|
||||
return FindPathAStar(startNodeId, endNodeId);
|
||||
}
|
||||
|
||||
// 경유지 유효성 검증
|
||||
@@ -220,7 +219,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
// 경유지가 없으면 기본 경로 계산
|
||||
if (validWaypoints.Count == 0)
|
||||
{
|
||||
return FindPath(startNodeId, endNodeId);
|
||||
return FindPathAStar(startNodeId, endNodeId);
|
||||
}
|
||||
|
||||
// 첫 번째 경유지가 시작노드와 같은지 검사
|
||||
@@ -267,7 +266,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
string waypoint = validWaypoints[i];
|
||||
|
||||
// 현재 위치에서 경유지까지의 경로 계산
|
||||
var segmentResult = FindPath(currentStart, waypoint);
|
||||
var segmentResult = FindPathAStar(currentStart, waypoint);
|
||||
|
||||
if (!segmentResult.Success)
|
||||
{
|
||||
@@ -295,7 +294,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
}
|
||||
|
||||
// 2단계: 마지막 경유지에서 최종 목적지까지의 경로 계산
|
||||
var finalSegmentResult = FindPath(currentStart, endNodeId);
|
||||
var finalSegmentResult = FindPathAStar(currentStart, endNodeId);
|
||||
|
||||
if (!finalSegmentResult.Success)
|
||||
{
|
||||
@@ -442,7 +441,7 @@ namespace AGVNavigationCore.PathFinding.Core
|
||||
AGVPathResult bestResult = null;
|
||||
foreach (var targetId in targetNodeIds)
|
||||
{
|
||||
var result = FindPath(startNodeId, targetId);
|
||||
var result = FindPathAStar(startNodeId, targetId);
|
||||
if (result.Success && (bestResult == null || result.TotalDistance < bestResult.TotalDistance))
|
||||
{
|
||||
bestResult = result;
|
||||
|
||||
@@ -22,8 +22,6 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
private readonly JunctionAnalyzer _junctionAnalyzer;
|
||||
private readonly DirectionChangePlanner _directionChangePlanner;
|
||||
|
||||
|
||||
|
||||
public AGVPathfinder(List<MapNode> mapNodes)
|
||||
{
|
||||
_mapNodes = mapNodes ?? new List<MapNode>();
|
||||
@@ -49,8 +47,9 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
n.IsActive &&
|
||||
n.IsNavigationNode() &&
|
||||
n.ConnectedNodes != null &&
|
||||
n.DisableCross == false &&
|
||||
n.ConnectedNodes.Count >= 3 &&
|
||||
n.ConnectedMapNodes.Where(t => t.Type == NodeType.Docking || t.Type == NodeType.Charging).Any() == false &&
|
||||
n.ConnectedMapNodes.Where(t => t.CanDocking).Any() == false &&
|
||||
n.NodeId != startNode.NodeId
|
||||
).ToList();
|
||||
|
||||
@@ -99,9 +98,10 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
if (pathNode != null &&
|
||||
pathNode.IsActive &&
|
||||
pathNode.IsNavigationNode() &&
|
||||
pathNode.DisableCross == false &&
|
||||
pathNode.ConnectedNodes != null &&
|
||||
pathNode.ConnectedNodes.Count >= 3 &&
|
||||
pathNode.ConnectedMapNodes.Where(t => t.Type == NodeType.Docking || t.Type == NodeType.Charging).Any() == false)
|
||||
pathNode.ConnectedMapNodes.Where(t => t.CanDocking).Any() == false)
|
||||
{
|
||||
if (pathNode.NodeId.Equals(StartNode.NodeId) == false)
|
||||
return pathNode;
|
||||
@@ -122,12 +122,12 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
if (prevNode == null)
|
||||
return AGVPathResult.CreateFailure("이전위치 노드가 null입니다.", 0, 0);
|
||||
if (startNode.NodeId == targetNode.NodeId && targetNode.DockDirection.MatchAGVDirection(prevDirection))
|
||||
return AGVPathResult.CreateSuccess(new List<MapNode> { startNode,startNode }, new List<AgvDirection>(), 0, 0);
|
||||
return AGVPathResult.CreateSuccess(new List<MapNode> { startNode, startNode }, new List<AgvDirection>(), 0, 0);
|
||||
|
||||
var ReverseDirection = (currentDirection == AgvDirection.Forward ? AgvDirection.Backward : AgvDirection.Forward);
|
||||
|
||||
//1.목적지까지의 최단거리 경로를 찾는다.
|
||||
var pathResult = _basicPathfinder.FindPath(startNode.NodeId, targetNode.NodeId);
|
||||
var pathResult = _basicPathfinder.FindPathAStar(startNode.NodeId, targetNode.NodeId);
|
||||
pathResult.PrevNode = prevNode;
|
||||
pathResult.PrevDirection = prevDirection;
|
||||
if (!pathResult.Success || pathResult.Path == null || pathResult.Path.Count == 0)
|
||||
@@ -221,7 +221,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
//진행방향으로 이동했을때 나오는 노드를 사용한다.
|
||||
if (nextNodeForward != null)
|
||||
{
|
||||
var Path0 = _basicPathfinder.FindPath(startNode.NodeId, nextNodeForward.NodeId);
|
||||
var Path0 = _basicPathfinder.FindPathAStar(startNode.NodeId, nextNodeForward.NodeId);
|
||||
Path0.PrevNode = prevNode;
|
||||
Path0.PrevDirection = prevDirection;
|
||||
MakeDetailData(Path0, prevDirection);
|
||||
@@ -267,7 +267,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
//경유지를 포함하여 경로를 다시 계산한다.
|
||||
|
||||
//1.시작위치 - 교차로(여기까지는 현재 방향으로 그대로 이동을 한다)
|
||||
var path1 = _basicPathfinder.FindPath(startNode.NodeId, JunctionInPath.NodeId);
|
||||
var path1 = _basicPathfinder.FindPathAStar(startNode.NodeId, JunctionInPath.NodeId);
|
||||
path1.PrevNode = prevNode;
|
||||
path1.PrevDirection = prevDirection;
|
||||
|
||||
@@ -295,7 +295,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
|
||||
//2.교차로 - 종료위치
|
||||
var path2 = _basicPathfinder.FindPath(JunctionInPath.NodeId, targetNode.NodeId);
|
||||
var path2 = _basicPathfinder.FindPathAStar(JunctionInPath.NodeId, targetNode.NodeId);
|
||||
path2.PrevNode = prevNode;
|
||||
path2.PrevDirection = prevDirection;
|
||||
|
||||
@@ -332,7 +332,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
//if (tempNode != null)
|
||||
{
|
||||
// 교차로 → 대체노드 경로 계산
|
||||
var pathToTemp = _basicPathfinder.FindPath(JunctionInPath.NodeId, tempNode.NodeId);
|
||||
var pathToTemp = _basicPathfinder.FindPathAStar(JunctionInPath.NodeId, tempNode.NodeId);
|
||||
pathToTemp.PrevNode = JunctionInPath;
|
||||
pathToTemp.PrevDirection = (ReverseCheck ? ReverseDirection : currentDirection);
|
||||
if (!pathToTemp.Success)
|
||||
@@ -348,7 +348,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
combinedResult = _basicPathfinder.CombineResults(combinedResult, pathToTemp);
|
||||
|
||||
// 대체노드 → 교차로 경로 계산 (역방향)
|
||||
var pathFromTemp = _basicPathfinder.FindPath(tempNode.NodeId, JunctionInPath.NodeId);
|
||||
var pathFromTemp = _basicPathfinder.FindPathAStar(tempNode.NodeId, JunctionInPath.NodeId);
|
||||
pathFromTemp.PrevNode = JunctionInPath;
|
||||
pathFromTemp.PrevDirection = (ReverseCheck ? ReverseDirection : currentDirection);
|
||||
if (!pathFromTemp.Success)
|
||||
@@ -362,7 +362,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
//현재까지 노드에서 목적지까지의 방향이 일치하면 그대로 사용한다.
|
||||
bool temp3ok = false;
|
||||
var TempCheck3 = _basicPathfinder.FindPath(combinedResult.Path.Last().NodeId, targetNode.NodeId);
|
||||
var TempCheck3 = _basicPathfinder.FindPathAStar(combinedResult.Path.Last().NodeId, targetNode.NodeId);
|
||||
if (TempCheck3.Path.First().NodeId.Equals(combinedResult.Path.Last().NodeId))
|
||||
{
|
||||
if (targetNode.DockDirection == DockingDirection.Forward && combinedResult.DetailedPath.Last().MotorDirection == AgvDirection.Forward)
|
||||
@@ -385,7 +385,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
combinedResult.Path[combinedResult.Path.Count - 2].NodeId,
|
||||
path2.Path[1].NodeId);
|
||||
|
||||
var pathToTemp2 = _basicPathfinder.FindPath(JunctionInPath.NodeId, tempNode2.NodeId);
|
||||
var pathToTemp2 = _basicPathfinder.FindPathAStar(JunctionInPath.NodeId, tempNode2.NodeId);
|
||||
if (ReverseCheck) MakeDetailData(pathToTemp2, currentDirection);
|
||||
else MakeDetailData(pathToTemp2, ReverseDirection);
|
||||
|
||||
@@ -400,7 +400,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
combinedResult.DetailedPath[combinedResult.DetailedPath.Count - 1].MotorDirection = currentDirection;
|
||||
}
|
||||
|
||||
var pathToTemp3 = _basicPathfinder.FindPath(tempNode2.NodeId, JunctionInPath.NodeId);
|
||||
var pathToTemp3 = _basicPathfinder.FindPathAStar(tempNode2.NodeId, JunctionInPath.NodeId);
|
||||
if (ReverseCheck) MakeDetailData(pathToTemp3, ReverseDirection);
|
||||
else MakeDetailData(pathToTemp3, currentDirection);
|
||||
|
||||
@@ -438,7 +438,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
string nextNodeId = (i + 1 < path1.Path.Count) ? path1.Path[i + 1].NodeId : null;
|
||||
|
||||
// 노드 정보 생성 (현재 방향 유지)
|
||||
var nodeInfo = new NodeMotorInfo(i+1,
|
||||
var nodeInfo = new NodeMotorInfo(i + 1,
|
||||
nodeId, RfidId,
|
||||
currentDirection,
|
||||
nextNodeId,
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
// 방향이 같으면 직접 경로 계산
|
||||
if (currentDirection == requiredDirection)
|
||||
{
|
||||
var directPath = _pathfinder.FindPath(startNodeId, targetNodeId);
|
||||
var directPath = _pathfinder.FindPathAStar(startNodeId, targetNodeId);
|
||||
if (directPath.Success)
|
||||
{
|
||||
return DirectionChangePlan.CreateSuccess(
|
||||
@@ -85,7 +85,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
}
|
||||
|
||||
// 방향 전환이 필요한 경우 - 먼저 간단한 직접 경로 확인
|
||||
var directPath2 = _pathfinder.FindPath(startNodeId, targetNodeId);
|
||||
var directPath2 = _pathfinder.FindPathAStar(startNodeId, targetNodeId);
|
||||
if (directPath2.Success)
|
||||
{
|
||||
// 직접 경로에 갈림길이 포함된 경우 그 갈림길에서 방향 전환
|
||||
@@ -160,7 +160,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
}
|
||||
|
||||
// 2. 직진 경로상의 갈림길들도 검색 (단, 되돌아가기 방지)
|
||||
var directPath = _pathfinder.FindPath(startNodeId, targetNodeId);
|
||||
var directPath = _pathfinder.FindPathAStar(startNodeId, targetNodeId);
|
||||
if (directPath.Success)
|
||||
{
|
||||
foreach (var node in directPath.Path.Skip(2)) // 시작점과 다음 노드는 제외
|
||||
@@ -261,7 +261,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
foreach (var junction in junctions)
|
||||
{
|
||||
var path = _pathfinder.FindPath(startNodeId, junction);
|
||||
var path = _pathfinder.FindPathAStar(startNodeId, junction);
|
||||
double distance = path.Success ? path.TotalDistance : double.MaxValue;
|
||||
distances.Add((junction, distance));
|
||||
}
|
||||
@@ -313,12 +313,12 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
var fullPath = new List<MapNode>();
|
||||
|
||||
// 1. 시작점에서 갈림길까지의 경로
|
||||
var toJunctionPath = _pathfinder.FindPath(startNodeId, junctionNodeId);
|
||||
var toJunctionPath = _pathfinder.FindPathAStar(startNodeId, junctionNodeId);
|
||||
if (!toJunctionPath.Success)
|
||||
return fullPath;
|
||||
|
||||
// 2. 인근 갈림길을 통한 우회인지, 직진 경로상 갈림길인지 판단
|
||||
var directPath = _pathfinder.FindPath(startNodeId, targetNodeId);
|
||||
var directPath = _pathfinder.FindPathAStar(startNodeId, targetNodeId);
|
||||
bool isNearbyDetour = !directPath.Success || !directPath.Path.Any(n => n.NodeId == junctionNodeId);
|
||||
|
||||
if (isNearbyDetour)
|
||||
@@ -341,7 +341,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
var fullPath = new List<MapNode>();
|
||||
|
||||
// 1. 시작점에서 갈림길까지 직진 (현재 방향 유지)
|
||||
var toJunctionPath = _pathfinder.FindPath(startNodeId, junctionNodeId);
|
||||
var toJunctionPath = _pathfinder.FindPathAStar(startNodeId, junctionNodeId);
|
||||
if (!toJunctionPath.Success)
|
||||
return fullPath;
|
||||
|
||||
@@ -349,7 +349,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
// 2. 갈림길에서 방향 전환 후 목적지로
|
||||
// 이때 마그넷 센서를 이용해 목적지 방향으로 진입
|
||||
var fromJunctionPath = _pathfinder.FindPath(junctionNodeId, targetNodeId);
|
||||
var fromJunctionPath = _pathfinder.FindPathAStar(junctionNodeId, targetNodeId);
|
||||
if (fromJunctionPath.Success && fromJunctionPath.Path.Count > 1)
|
||||
{
|
||||
fullPath.AddRange(fromJunctionPath.Path.Skip(1)); // 중복 노드 제거
|
||||
@@ -366,7 +366,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
var fullPath = new List<MapNode>();
|
||||
|
||||
// 1. 시작점에서 갈림길까지의 경로
|
||||
var toJunctionPath = _pathfinder.FindPath(startNodeId, junctionNodeId);
|
||||
var toJunctionPath = _pathfinder.FindPathAStar(startNodeId, junctionNodeId);
|
||||
if (!toJunctionPath.Success)
|
||||
return fullPath;
|
||||
|
||||
@@ -387,7 +387,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
|
||||
// 3. 갈림길에서 목표점까지의 경로
|
||||
string lastNode = fullPath.LastOrDefault()?.NodeId ?? junctionNodeId;
|
||||
var fromJunctionPath = _pathfinder.FindPath(lastNode, targetNodeId);
|
||||
var fromJunctionPath = _pathfinder.FindPathAStar(lastNode, targetNodeId);
|
||||
if (fromJunctionPath.Success && fromJunctionPath.Path.Count > 1)
|
||||
{
|
||||
fullPath.AddRange(fromJunctionPath.Path.Skip(1));
|
||||
@@ -609,7 +609,7 @@ namespace AGVNavigationCore.PathFinding.Planning
|
||||
private bool CanReachTargetViaJunction(string junctionNodeId, string targetNodeId)
|
||||
{
|
||||
// 갈림길에서 목적지까지의 경로가 존재하는지 확인
|
||||
var pathToTarget = _pathfinder.FindPath(junctionNodeId, targetNodeId);
|
||||
var pathToTarget = _pathfinder.FindPathAStar(junctionNodeId, targetNodeId);
|
||||
return pathToTarget.Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace AGVNavigationCore.Utils
|
||||
Console.WriteLine($"이름: {node.Name}");
|
||||
Console.WriteLine($"위치: {node.Position}");
|
||||
Console.WriteLine($"타입: {GetNodeTypeName(node.Type)}");
|
||||
Console.WriteLine($"회전 가능: {node.CanRotate}");
|
||||
Console.WriteLine($"TurnLeft/Right/교차로 : {(node.CanTurnLeft ? "O":"X")}/{(node.CanTurnRight ? "O" : "X")}/{(node.DisableCross ? "X" : "O")}");
|
||||
Console.WriteLine($"활성: {node.IsActive}");
|
||||
Console.WriteLine($"연결된 노드:");
|
||||
|
||||
|
||||
@@ -338,6 +338,17 @@ namespace AGVSimulator.Forms
|
||||
advancedResult.DockingValidation = DockingValidator.ValidateDockingDirection(advancedResult, _mapNodes);
|
||||
}
|
||||
|
||||
//마지막대상이 버퍼라면 시퀀스처리를 해야한다
|
||||
if(targetNode.Type == NodeType.Buffer)
|
||||
{
|
||||
var lastDetailPath = advancedResult.DetailedPath.Last();
|
||||
if(lastDetailPath.NodeId == targetNode.NodeId)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_simulatorCanvas.CurrentPath = advancedResult;
|
||||
_pathLengthLabel.Text = $"경로 길이: {advancedResult.TotalDistance:F1}";
|
||||
_statusLabel.Text = $"경로 계산 완료 ({advancedResult.CalculationTimeMs}ms)";
|
||||
@@ -1443,7 +1454,7 @@ namespace AGVSimulator.Forms
|
||||
|
||||
// 도킹 타겟 노드 찾기
|
||||
var dockingTargets = _mapNodes.Where(n =>
|
||||
n.Type == NodeType.Charging || n.Type == NodeType.Docking).ToList();
|
||||
n.Type == NodeType.Charging || n.Type == NodeType.Loader || n.Type == NodeType.UnLoader || n.Type == NodeType.Clearner || n.Type == NodeType.Buffer).ToList();
|
||||
|
||||
if (dockingTargets.Count == 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user