Compare commits

...

63 Commits

Author SHA1 Message Date
backuppc
30e1ce41ee 경로로직 2026-03-03 17:29:27 +09:00
backuppc
1a4b8a6a54 모든 경로를 전체 정의하기 전 백업 2026-03-03 13:00:13 +09:00
backuppc
6802967cde .. 2026-02-27 17:04:09 +09:00
backuppc
46bed6eb25 턴동작 추가 2026-02-27 16:55:35 +09:00
backuppc
43e7458866 .. 2026-02-27 16:15:30 +09:00
backuppc
03a53d49bf .. 2026-02-27 11:27:30 +09:00
backuppc
71b8a589c6 acs command 창 추가 2026-02-27 09:59:36 +09:00
ChiKyun Kim
24bd2d8a7f .. 2026-02-27 08:58:39 +09:00
ChiKyun Kim
e831752e76 .. 2026-02-26 16:30:58 +09:00
backuppc
c1670ddcbe .. 2026-02-26 14:36:33 +09:00
backuppc
d57b00095c 시스템메세지, 정보메세지개념 추가 2026-02-26 14:18:41 +09:00
backuppc
2e9b7973c7 ai로그 추가 2026-02-26 11:40:57 +09:00
backuppc
1948eda7ea agv정보표시할떄 dist 추가 2026-02-26 11:28:13 +09:00
backuppc
8beaa66516 재시작관련 코드 업데이트 2026-02-26 11:27:07 +09:00
backuppc
c067a76462 속도레벨을 기본 m->l 로 변경, 턴이되어있다면 오류로 처리한다. 2026-02-26 10:34:11 +09:00
backuppc
e7cce4c201 맵 스피드 기본값을 M->L 로 변경함, 버퍼 작업중에는 버퍼외에 다른 명령은 거부하도록 함 2026-02-26 10:00:49 +09:00
backuppc
0e2b407e48 회전중입력된 태그는 무시 2026-02-26 08:45:33 +09:00
ChiKyun Kim
e2691af903 .. 2026-02-25 16:46:51 +09:00
backuppc
2590ad91de .. 2026-02-25 14:55:36 +09:00
backuppc
245749d695 일반노드이동기능 추가 2026-02-25 11:25:09 +09:00
backuppc
6a658879f1 노드정리(삭제노드 제거 및 5번노드 제거로 인한 경로 업데이트) 2026-02-25 11:07:08 +09:00
backuppc
12b3fe50c7 .. 2026-02-24 15:03:52 +09:00
backuppc
dbc53e3146 .. 2026-02-13 14:55:28 +09:00
backuppc
213467fe3f .. 2026-02-13 10:41:10 +09:00
backuppc
d6aed58516 .. 2026-02-12 09:58:01 +09:00
backuppc
2b3a9b3d1d .. 2026-02-12 09:54:14 +09:00
backuppc
a512133d52 Merge branch 'master' of file://k4fs3201n/k4bpartcenter$/Repository/K4/ENIG_AGV 2026-02-10 14:54:10 +09:00
backuppc
471b8ff9c4 .. 2026-02-10 14:53:54 +09:00
ChiKyun Kim
161ff5c3e2 .. 2026-02-09 14:17:11 +09:00
backuppc
c2cc5d67ae 작업시작전에. 현재 위치를 확인하고 진행하게 함. 2026-02-09 13:59:19 +09:00
backuppc
7409528fbd tts에.플레이하도록 수정 2026-02-09 13:21:42 +09:00
ChiKyun Kim
3d5e2bc1e6 .. 2026-02-09 13:21:00 +09:00
backuppc
bd06f59bf1 add tts 2026-02-09 13:06:47 +09:00
backuppc
839486db87 add ttsproject 2026-02-09 13:06:25 +09:00
backuppc
35a057367c acs sequence 2026-02-09 09:43:53 +09:00
ChiKyun Kim
09b1246bbd error fix 2026-02-09 08:48:21 +09:00
ChiKyun Kim
b57c61c6d8 currentnode 값으로 lasttag 값을 복원 2026-02-09 08:41:47 +09:00
ChiKyun Kim
f5f08de0b9 대기상태일때 자동멈춤기능 다시 활성화
remotecontrol 모드 추가, 원격으로 turn, manual, auto 이동시 활성화된다.. 내부코드는 없음. 상태만 추가함, idle 상태일때 자동 멈춤코드가 동작하지 않게 하기 위함이다.
2026-02-09 08:37:39 +09:00
ChiKyun Kim
ddaab0b5da acs test 프로그램에 pick on ,off 기능 추가 2026-02-05 17:18:01 +09:00
backuppc
ba542beaff test_acs 프로젝트 변경 2026-02-05 13:18:20 +09:00
backuppc
ec2af6ac1f chore: commit all remaining changes 2026-02-04 15:26:22 +09:00
backuppc
b388b1917d feat(AGVCanvas): blink error msg, debug info, setview 2026-02-04 15:23:45 +09:00
backuppc
e35dee853f 최종우치에. 이전노드정보와 다음 시작 노드 정보를 모두 추가함.
최초 실행시 선택하는 위치 다이얼로그 제거 후 바로 자동 로딩하도록 함
2026-02-03 17:15:15 +09:00
backuppc
b25be68986 agv 오류코드가 전송되도록함, 에뮬레이터에서 표시되게 함 2026-02-02 15:04:05 +09:00
backuppc
9bca8f67d1 .. 2026-02-02 14:59:48 +09:00
backuppc
02105d49a3 .. 2026-01-30 17:29:54 +09:00
backuppc
faf13f5c37 .. 2026-01-30 16:58:14 +09:00
backuppc
3a8cbd3283 buffer-out 시퀀스 테스트 중 - 리프트 작업 후 이후 동작이 이상함 2026-01-29 17:23:41 +09:00
backuppc
1dde80fa93 buffer in 시퀀스 확인 완료
- 최초 위치확인이 좀 이상하다.
2026-01-29 17:15:08 +09:00
backuppc
af0c32215b 턴 조건 변경 센서->메세지 2026-01-29 15:13:41 +09:00
backuppc
92340308be .. 2026-01-29 14:54:54 +09:00
backuppc
cce51478be .. 2026-01-29 14:53:22 +09:00
backuppc
e99edbe04d Fix oscillation in AGV movement, add command cooldown, and enhance debug logs 2026-01-29 14:51:57 +09:00
ChiKyun Kim
1da1f2de28 .. 2026-01-29 14:24:30 +09:00
ChiKyun Kim
58ca67150d 파일정리 2026-01-29 14:03:17 +09:00
backuppc
00cc0ef5b7 Refactor AGV error handling: Standardize AGVErrorCode usage and update SetRunStepError 2026-01-28 16:45:24 +09:00
backuppc
16d51a2712 refactor: Use SetRunStepError within RunStep sequences
- Refactored _SM_RUN_ENTER, _EXIT, _BUFFER_IN, _BUFFER_OUT, and _Util to use SetRunStepError helper.

- Corrected AGV_RUN_FAIL and MESSAGE_ERROR codes in _SM_RUN_ENTER, _EXIT, and _CHARGE_GO.

- Added new error codes AGV_SPEED_SET_FAIL and AGV_RUN_FAIL to EnumData.cs.
2026-01-28 15:58:42 +09:00
backuppc
5b4fdd33cf feat: Implement RunStep error reporting and refactor charge sequences
- Added RunStepErrorCode to Xbee status protocol and CResult.

- Defined detailed operational error codes in EnumData.cs.

- Updated _SM_RUN_*.cs to report specific error codes before proper error transitions.

- Renamed and refactored charge-related sequence files.
2026-01-28 15:41:03 +09:00
backuppc
ffa6c2fb23 버퍼경로내의 오동작 확인 및 재시작 관련 코드 점검 2026-01-28 10:45:57 +09:00
ChiKyun Kim
b0e75b351a nextstop 시그널을 bool변수에서 agv 으 ㅣspeed = 'L' 조건으로 변경 2026-01-27 16:27:17 +09:00
backuppc
b4d3cd8bb5 .. 2026-01-27 14:11:27 +09:00
backuppc
d8a9007791 . 2026-01-27 14:02:30 +09:00
backuppc
9ee8295489 .. 2026-01-27 14:01:30 +09:00
501 changed files with 60994 additions and 105908 deletions

2
.gitignore vendored
View File

@@ -15,3 +15,5 @@ packages
*.bak
/Cs_HMI/Data/*.agvmap
/Cs_HMI/AGVLogic/AGVMapEditor/Data/*.agvmap
/Document/~$PICkit 프로그램 다운로드 매뉴얼.pptx
/HMI/TestProject/tts/assets

View File

@@ -38,14 +38,12 @@
<ApplicationIcon>icons8-robot-80.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="arCommUtil, Version=25.11.25.2000, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\DLL\arCommUtil.dll</HintPath>
</Reference>
<Reference Include="arControl.Net4">
<HintPath>..\Cs_HMI\DLL\arControl.Net4.dll</HintPath>
</Reference>
<Reference Include="ArLog.Net4">
<HintPath>..\Cs_HMI\DLL\ArLog.Net4.dll</HintPath>
</Reference>
<Reference Include="ArSetting.Net4">
<HintPath>..\Cs_HMI\DLL\ArSetting.Net4.dll</HintPath>
<HintPath>..\DLL\arControl.Net4.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -70,16 +68,13 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RemoteStatus.cs" />
<Compile Include="RS232.cs" />
<Compile Include="RunCode\_AGV.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="RunCode\_AGV.cs" />
<Compile Include="RunCode\_XBEE.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="RunCode\_BMS.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="RunCode\_BMS.cs" />
<Compile Include="UC\SerialConn.cs">
<SubType>UserControl</SubType>
</Compile>
@@ -126,15 +121,11 @@
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Cs_HMI\AGVLogic\AGVNavigationCore\AGVNavigationCore.csproj">
<ProjectReference Include="..\AGVLogic\AGVNavigationCore\AGVNavigationCore.csproj">
<Project>{c5f7a8b2-8d3e-4a1b-9c6e-7f4d5e2a9b1c}</Project>
<Name>AGVNavigationCore</Name>
</ProjectReference>
<ProjectReference Include="..\Cs_HMI\SubProject\CommUtil\arCommUtil.csproj">
<Project>{14e8c9a5-013e-49ba-b435-ffffff7dd623}</Project>
<Name>arCommUtil</Name>
</ProjectReference>
<ProjectReference Include="..\Cs_HMI\SubProject\EnigProtocol\enigprotocol\ENIGProtocol.csproj">
<ProjectReference Include="..\AGVLogic\ENIGProtocol\enigprotocol\ENIGProtocol.csproj">
<Project>{9365803b-933d-4237-93c7-b502c855a71c}</Project>
<Name>ENIGProtocol</Name>
</ProjectReference>

View File

@@ -5,11 +5,9 @@ VisualStudioVersion = 17.14.36804.6 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVEmulator", "AGVEmulator.csproj", "{9312AB43-72F6-4365-A266-E767215FA7F5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVNavigationCore", "..\Cs_HMI\AGVLogic\AGVNavigationCore\AGVNavigationCore.csproj", "{C5F7A8B2-8D3E-4A1B-9C6E-7F4D5E2A9B1C}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVNavigationCore", "..\AGVLogic\AGVNavigationCore\AGVNavigationCore.csproj", "{C5F7A8B2-8D3E-4A1B-9C6E-7F4D5E2A9B1C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol", "..\Cs_HMI\SubProject\ENIGProtocol\enigprotocol\ENIGProtocol.csproj", "{9365803B-933D-4237-93C7-B502C855A71C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "arCommUtil", "..\Cs_HMI\SubProject\CommUtil\arCommUtil.csproj", "{14E8C9A5-013E-49BA-B435-FFFFFF7DD623}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol", "..\AGVLogic\ENIGProtocol\enigprotocol\ENIGProtocol.csproj", "{9365803B-933D-4237-93C7-B502C855A71C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@@ -1,5 +1,4 @@
using arCtl;
using System;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
@@ -37,7 +36,19 @@ namespace AGVEmulator
/// <summary>
/// 호출제어기 통신 오류
/// </summary>
controller_comm_error = 11,
controller_comm_error,
/// <summary>
/// 배터리 저전압
/// </summary>
battery_low_voltage,
spare08,
lift_timeout,
lift_driver_overcurrent,
lift_driver_emergency,
/// <summary>
/// 도착경보기 통신 오류
/// </summary>
@@ -67,13 +78,13 @@ namespace AGVEmulator
public enum esignal1
{
front_gate_out = 0,
rear_sensor_out,
rear_gte_out,
mark_sensor_1,
mark_sensor_2,
lift_down_sensor,
lift_up_sensor,
magnet_relay,
charger_align_sensor,
lift_up,
lift_down,
magnet_on
}
public enum esystemflag0
{
@@ -330,20 +341,20 @@ namespace AGVEmulator
switch(cmd2)
{
case "ON":
SetAGV(esignal1.magnet_on, true);
SetAGV(esignal1.magnet_relay, true);
break;
case "UP":
SetAGV(esignal1.lift_down, false);
SetAGV(esignal1.lift_up, true);
SetAGV(esignal1.lift_down_sensor, false);
SetAGV(esignal1.lift_up_sensor, true);
break;
case "DN":
SetAGV(esignal1.lift_up, false);
SetAGV(esignal1.lift_down, true);
SetAGV(esignal1.lift_up_sensor, false);
SetAGV(esignal1.lift_down_sensor, true);
break;
case "ST":
break;
case "OF":
SetAGV(esignal1.magnet_on, false);
SetAGV(esignal1.magnet_relay, false);
break;
}

View File

@@ -74,24 +74,48 @@ namespace AGVEmulator
/// 카트를 가지러 들어간다
/// </summary>
/// <param name="id"></param>
public void SendPickOn(byte id)
public void SendPickOnEnter(byte id)
{
var data = new List<byte>();
data.Add(id);
Send(ENIGProtocol.AGVCommandHE.PickOn, data.ToArray());
Send(ENIGProtocol.AGVCommandHE.PickOnEnter, data.ToArray());
}
/// <summary>
/// 카트를 내려놓
/// 카트를 내려놓으로 들어간
/// </summary>
/// <param name="id"></param>
public void SendPickOff(byte id)
public void SendPickOffEnter(byte id)
{
var data = new List<byte>();
data.Add(id);
Send(ENIGProtocol.AGVCommandHE.PickOff, data.ToArray());
Send(ENIGProtocol.AGVCommandHE.PickOffEnter, data.ToArray());
}
/// <summary>
/// 카트를 가지러 들어가서 나온다
/// </summary>
/// <param name="id"></param>
public void SendPickOnExit(byte id)
{
var data = new List<byte>();
data.Add(id);
Send(ENIGProtocol.AGVCommandHE.PickOnExit, data.ToArray());
}
/// <summary>
/// 카트를 내려놓으러 들어가서 나온다
/// </summary>
/// <param name="id"></param>
public void SendPickOffExit(byte id)
{
var data = new List<byte>();
data.Add(id);
Send(ENIGProtocol.AGVCommandHE.PickOffExit, data.ToArray());
}
public void SendCurrentPos(byte id, uint tag)
{
var data = new List<byte>();

View File

@@ -0,0 +1,50 @@
using System.Text;
namespace AGVEmulator
{
public class RemoteStatus
{
public byte Mode { get; set; } // 0=manual, 1=auto
public byte RunSt { get; set; } // 0=stop, 1=run, 2=error
public byte RunStep { get; set; }
public byte RunStepSeq { get; set; }
public ushort HWError { get; set; }
public byte MotorDir { get; set; } // 0=F, 1=B
public byte MagnetDir { get; set; } // 0=S, 1=L, 2=R
public byte ChargeSt { get; set; } // 0=off, 1=on
public byte CartSt { get; set; } // 0=off, 1=on, 2=unknown
public byte LiftSt { get; set; } // 0=down, 1=up, 2=unknown
public byte ErrorCode { get; set; }
public string LastTag { get; set; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Mode: {(Mode == 1 ? "Auto" : "Manual")}");
sb.AppendLine($"RunSt: {(RunSt == 0 ? "Stop" : (RunSt == 1 ? "Run" : "Error"))}");
if (HWError > 0)
{
sb.Append(" [HW ERR: ");
for (int i = 0; i < 16; i++)
{
if ((HWError & (1 << i)) != 0)
{
sb.Append($"{(DevAGV.eerror)i},");
}
}
sb.AppendLine("]");
}
sb.AppendLine($"Step: {RunStep}, Seq: {RunStepSeq}");
sb.AppendLine($"Dir: {(MotorDir == 1 ? "B" : "F")}, Mag: {(MagnetDir == 1 ? "L" : (MagnetDir == 2 ? "R" : "S"))}");
sb.AppendLine($"Charge: {(ChargeSt == 1 ? "ON" : "OFF")}");
sb.AppendLine($"Cart: {(CartSt == 1 ? "ON" : (CartSt == 0 ? "OFF" : "Unk"))}");
sb.AppendLine($"Lift: {(LiftSt == 1 ? "UP" : (LiftSt == 0 ? "DOWN" : "Unk"))}");
sb.Append($"Tag: {LastTag}");
return sb.ToString();
}
}
}

View File

@@ -80,6 +80,7 @@ namespace AGVEmulator
}
break;
}
UpdateUIStatus();
}
private void Agv_ValueChanged(object sender, DevAGV.ValueChangedArgs e)

View File

@@ -24,15 +24,44 @@ namespace AGVEmulator
}
private void CAL_ProtocReceived(object sender, ENIG.EEProtocol.DataEventArgs e)
{
//throw new NotImplementedException();
var dev = (DeviceType)e.ReceivedPacket.ID;
if (dev == DeviceType.AGV1 || dev == DeviceType.AGV2)
// HMI(Host)에서 호스트로 취급되는 HMI가 보낸 패킷은 ID가 0(ACS)임.
// 하지만 xbee.cs에서 CreatePacket 시 PUB.setting.XBE_ID를 사용함.
// 에뮬레이터에서는 이 패킷들을 수신하여 상태를 업데이트함.
var cmd = (ENIGProtocol.AGVCommandEH)e.ReceivedPacket.Command;
var data = e.ReceivedPacket.Data;
if (cmd == ENIGProtocol.AGVCommandEH.Status)
{
//agv에서 들어오는 데이터
var cmd = e.ReceivedPacket.Command;
if(cmd == 3)
if (data.Length >= 16)
{
//status
_remoteStatus.Mode = data[0];
_remoteStatus.RunSt = data[1];
_remoteStatus.HWError = BitConverter.ToUInt16(data, 2);
_remoteStatus.RunStep = data[4];
_remoteStatus.RunStepSeq = data[5];
_remoteStatus.MotorDir = data[6];
_remoteStatus.MagnetDir = data[7];
_remoteStatus.ChargeSt = data[8];
_remoteStatus.CartSt = data[9];
_remoteStatus.LiftSt = data[10];
_remoteStatus.ErrorCode = data[11];
_remoteErrorCode = (ENIGProtocol.AGVErrorCode)data[11];
_remoteErrorMessage = ENIGProtocol.AGVUtility.GetAGVErrorMessage(_remoteErrorCode);
_remoteStatus.LastTag = Encoding.ASCII.GetString(data, 12, 4);
UpdateUIStatus();
}
}
else if (cmd == ENIGProtocol.AGVCommandEH.Error)
{
if (data.Length >= 1)
{
_remoteErrorCode = (ENIGProtocol.AGVErrorCode)data[0];
// _remoteErrorMessage = ... Error 메시지 자체는 패킷에 포함되지 않으므로 유틸리티 사용 가능
_remoteErrorMessage = ENIGProtocol.AGVUtility.GetAGVErrorMessage(_remoteErrorCode);
UpdateUIStatus();
}
}
}

View File

@@ -32,35 +32,35 @@ namespace AGVEmulator
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
AGVEmulator.UC.AgvViewer.ptdata ptdata29 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata30 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata31 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata32 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata33 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata34 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata35 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata36 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata37 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata38 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata39 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata40 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata41 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata42 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata43 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata44 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata45 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata46 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata47 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata48 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata49 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata50 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata51 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata52 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata53 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata54 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata55 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata56 = new AGVEmulator.UC.AgvViewer.ptdata();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(fMain));
AGVEmulator.UC.AgvViewer.ptdata ptdata1 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata2 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata3 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata4 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata5 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata6 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata7 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata8 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata9 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata10 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata11 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata12 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata13 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata14 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata15 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata16 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata17 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata18 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata19 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata20 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata21 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata22 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata23 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata24 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata25 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata26 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata27 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata28 = new AGVEmulator.UC.AgvViewer.ptdata();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.rtBMS = new arCtl.LogTextBox();
this.panel1 = new System.Windows.Forms.Panel();
@@ -86,6 +86,7 @@ namespace AGVEmulator
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.trackBar1 = new System.Windows.Forms.TrackBar();
this.serBMS = new AGVEmulator.SerialConn();
this.rtAGV = new arCtl.LogTextBox();
this.panel4 = new System.Windows.Forms.Panel();
this.groupBox9 = new System.Windows.Forms.GroupBox();
@@ -128,6 +129,7 @@ namespace AGVEmulator
this.button4 = new System.Windows.Forms.Button();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.rtCAL = new arCtl.LogTextBox();
this.serCAL = new AGVEmulator.SerialConn();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage4 = new System.Windows.Forms.TabPage();
@@ -135,9 +137,20 @@ namespace AGVEmulator
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.rtAGVPro = new arCtl.LogTextBox();
this.panel12 = new System.Windows.Forms.Panel();
this.agvViewer1 = new AGVEmulator.UC.AgvViewer();
this.serAGV = new AGVEmulator.SerialConn();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.panel3 = new System.Windows.Forms.Panel();
this.groupBox13 = new System.Windows.Forms.GroupBox();
this.tbErCode = new System.Windows.Forms.TextBox();
this.tbErmsg = new System.Windows.Forms.TextBox();
this.groupBox12 = new System.Windows.Forms.GroupBox();
this.rtStatus = new System.Windows.Forms.RichTextBox();
this.label13 = new System.Windows.Forms.Label();
this.button6 = new System.Windows.Forms.Button();
this.button13 = new System.Windows.Forms.Button();
this.label12 = new System.Windows.Forms.Label();
this.button3 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.nudIDAgv = new System.Windows.Forms.NumericUpDown();
@@ -166,10 +179,6 @@ namespace AGVEmulator
this.sbBMS = new System.Windows.Forms.ToolStripStatusLabel();
this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel();
this.sbCAL = new System.Windows.Forms.ToolStripStatusLabel();
this.agvViewer1 = new AGVEmulator.UC.AgvViewer();
this.serAGV = new AGVEmulator.SerialConn();
this.serBMS = new AGVEmulator.SerialConn();
this.serCAL = new AGVEmulator.SerialConn();
this.groupBox1.SuspendLayout();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trbT2)).BeginInit();
@@ -196,6 +205,8 @@ namespace AGVEmulator
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.panel3.SuspendLayout();
this.groupBox13.SuspendLayout();
this.groupBox12.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.nudIDAgv)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudTagNo)).BeginInit();
@@ -504,6 +515,18 @@ namespace AGVEmulator
this.trackBar1.Value = 7000;
this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll);
//
// serBMS
//
this.serBMS.BaudRate = 9600;
this.serBMS.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.serBMS.dev = null;
this.serBMS.Dock = System.Windows.Forms.DockStyle.Top;
this.serBMS.Location = new System.Drawing.Point(3, 17);
this.serBMS.Name = "serBMS";
this.serBMS.PortName = "COM31";
this.serBMS.Size = new System.Drawing.Size(1134, 84);
this.serBMS.TabIndex = 1;
//
// rtAGV
//
this.rtAGV.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(24)))), ((int)(((byte)(24)))));
@@ -997,6 +1020,18 @@ namespace AGVEmulator
this.rtCAL.TabIndex = 2;
this.rtCAL.Text = "";
//
// serCAL
//
this.serCAL.BaudRate = 9600;
this.serCAL.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.serCAL.dev = null;
this.serCAL.Dock = System.Windows.Forms.DockStyle.Top;
this.serCAL.Location = new System.Drawing.Point(3, 17);
this.serCAL.Name = "serCAL";
this.serCAL.PortName = "COM41";
this.serCAL.Size = new System.Drawing.Size(776, 84);
this.serCAL.TabIndex = 1;
//
// timer1
//
this.timer1.Interval = 200;
@@ -1082,6 +1117,149 @@ namespace AGVEmulator
this.panel12.Size = new System.Drawing.Size(1140, 120);
this.panel12.TabIndex = 5;
//
// agvViewer1
//
this.agvViewer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.agvViewer1.FontMrk = new System.Drawing.Font("Microsoft Sans Serif", 7F);
this.agvViewer1.FontTag = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.agvViewer1.lastmark = "";
this.agvViewer1.lastmarkdir = "";
this.agvViewer1.lasttag = "";
this.agvViewer1.lasttagdir = "";
ptdata29.active = false;
ptdata29.data = "NOT";
ptdata29.pos = 30F;
ptdata30.active = false;
ptdata30.data = "QA";
ptdata30.pos = 200F;
ptdata31.active = false;
ptdata31.data = "CHG";
ptdata31.pos = 300F;
ptdata32.active = false;
ptdata32.data = "QC";
ptdata32.pos = 400F;
ptdata33.active = false;
ptdata33.data = "#FVI-1";
ptdata33.pos = 500F;
ptdata34.active = false;
ptdata34.data = "#FVI-2";
ptdata34.pos = 600F;
ptdata35.active = false;
ptdata35.data = "#FVI-3";
ptdata35.pos = 700F;
ptdata36.active = false;
ptdata36.data = "#FVI-4";
ptdata36.pos = 800F;
ptdata37.active = false;
ptdata37.data = "#FVI-5";
ptdata37.pos = 900F;
ptdata38.active = false;
ptdata38.data = "POT";
ptdata38.pos = 970F;
this.agvViewer1.listMRK = new AGVEmulator.UC.AgvViewer.ptdata[] {
ptdata29,
ptdata30,
ptdata31,
ptdata32,
ptdata33,
ptdata34,
ptdata35,
ptdata36,
ptdata37,
ptdata38};
ptdata39.active = false;
ptdata39.data = "9000";
ptdata39.pos = 80F;
ptdata40.active = false;
ptdata40.data = "9001";
ptdata40.pos = 120F;
ptdata41.active = false;
ptdata41.data = "9010";
ptdata41.pos = 180F;
ptdata42.active = false;
ptdata42.data = "9011";
ptdata42.pos = 220F;
ptdata43.active = false;
ptdata43.data = "9020";
ptdata43.pos = 280F;
ptdata44.active = false;
ptdata44.data = "9021";
ptdata44.pos = 320F;
ptdata45.active = false;
ptdata45.data = "9030";
ptdata45.pos = 380F;
ptdata46.active = false;
ptdata46.data = "9031";
ptdata46.pos = 420F;
ptdata47.active = false;
ptdata47.data = "9040";
ptdata47.pos = 480F;
ptdata48.active = false;
ptdata48.data = "9041";
ptdata48.pos = 520F;
ptdata49.active = false;
ptdata49.data = "9050";
ptdata49.pos = 580F;
ptdata50.active = false;
ptdata50.data = "9051";
ptdata50.pos = 620F;
ptdata51.active = false;
ptdata51.data = "9060";
ptdata51.pos = 680F;
ptdata52.active = false;
ptdata52.data = "9061";
ptdata52.pos = 720F;
ptdata53.active = false;
ptdata53.data = "9070";
ptdata53.pos = 780F;
ptdata54.active = false;
ptdata54.data = "9071";
ptdata54.pos = 820F;
ptdata55.active = false;
ptdata55.data = "9000";
ptdata55.pos = 10F;
ptdata56.active = false;
ptdata56.data = "9001";
ptdata56.pos = 50F;
this.agvViewer1.listTAG = new AGVEmulator.UC.AgvViewer.ptdata[] {
ptdata39,
ptdata40,
ptdata41,
ptdata42,
ptdata43,
ptdata44,
ptdata45,
ptdata46,
ptdata47,
ptdata48,
ptdata49,
ptdata50,
ptdata51,
ptdata52,
ptdata53,
ptdata54,
ptdata55,
ptdata56};
this.agvViewer1.Location = new System.Drawing.Point(241, 0);
this.agvViewer1.Name = "agvViewer1";
this.agvViewer1.Size = new System.Drawing.Size(899, 120);
this.agvViewer1.StopbyMark = false;
this.agvViewer1.TabIndex = 0;
this.agvViewer1.Text = "agvViewer1";
this.agvViewer1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.agvViewer1_MouseDown);
//
// serAGV
//
this.serAGV.BaudRate = 9600;
this.serAGV.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.serAGV.dev = null;
this.serAGV.Dock = System.Windows.Forms.DockStyle.Left;
this.serAGV.Location = new System.Drawing.Point(0, 0);
this.serAGV.Name = "serAGV";
this.serAGV.PortName = "COM21";
this.serAGV.Size = new System.Drawing.Size(241, 120);
this.serAGV.TabIndex = 0;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.groupBox1);
@@ -1106,6 +1284,12 @@ namespace AGVEmulator
//
// panel3
//
this.panel3.Controls.Add(this.groupBox13);
this.panel3.Controls.Add(this.groupBox12);
this.panel3.Controls.Add(this.label13);
this.panel3.Controls.Add(this.button6);
this.panel3.Controls.Add(this.button13);
this.panel3.Controls.Add(this.label12);
this.panel3.Controls.Add(this.button3);
this.panel3.Controls.Add(this.button2);
this.panel3.Controls.Add(this.nudIDAgv);
@@ -1126,11 +1310,96 @@ namespace AGVEmulator
this.panel3.Size = new System.Drawing.Size(364, 622);
this.panel3.TabIndex = 15;
//
// groupBox13
//
this.groupBox13.Controls.Add(this.tbErCode);
this.groupBox13.Controls.Add(this.tbErmsg);
this.groupBox13.Dock = System.Windows.Forms.DockStyle.Bottom;
this.groupBox13.Location = new System.Drawing.Point(0, 545);
this.groupBox13.Name = "groupBox13";
this.groupBox13.Size = new System.Drawing.Size(364, 77);
this.groupBox13.TabIndex = 21;
this.groupBox13.TabStop = false;
this.groupBox13.Text = "error";
//
// tbErCode
//
this.tbErCode.Location = new System.Drawing.Point(12, 18);
this.tbErCode.Name = "tbErCode";
this.tbErCode.Size = new System.Drawing.Size(287, 21);
this.tbErCode.TabIndex = 1;
//
// tbErmsg
//
this.tbErmsg.Location = new System.Drawing.Point(13, 45);
this.tbErmsg.Name = "tbErmsg";
this.tbErmsg.Size = new System.Drawing.Size(287, 21);
this.tbErmsg.TabIndex = 0;
//
// groupBox12
//
this.groupBox12.Controls.Add(this.rtStatus);
this.groupBox12.Location = new System.Drawing.Point(7, 318);
this.groupBox12.Name = "groupBox12";
this.groupBox12.Size = new System.Drawing.Size(355, 221);
this.groupBox12.TabIndex = 20;
this.groupBox12.TabStop = false;
this.groupBox12.Text = "status";
//
// rtStatus
//
this.rtStatus.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtStatus.Location = new System.Drawing.Point(3, 17);
this.rtStatus.Name = "rtStatus";
this.rtStatus.Size = new System.Drawing.Size(349, 201);
this.rtStatus.TabIndex = 0;
this.rtStatus.Text = "";
//
// label13
//
this.label13.AutoSize = true;
this.label13.Location = new System.Drawing.Point(18, 287);
this.label13.Name = "label13";
this.label13.Size = new System.Drawing.Size(26, 12);
this.label13.TabIndex = 19;
this.label13.Text = "Exit";
//
// button6
//
this.button6.Location = new System.Drawing.Point(205, 274);
this.button6.Name = "button6";
this.button6.Size = new System.Drawing.Size(133, 38);
this.button6.TabIndex = 18;
this.button6.Tag = "--";
this.button6.Text = "Pick Off";
this.button6.UseVisualStyleBackColor = true;
this.button6.Click += new System.EventHandler(this.button6_Click_1);
//
// button13
//
this.button13.Location = new System.Drawing.Point(66, 274);
this.button13.Name = "button13";
this.button13.Size = new System.Drawing.Size(133, 38);
this.button13.TabIndex = 17;
this.button13.Tag = "--";
this.button13.Text = "Pick On";
this.button13.UseVisualStyleBackColor = true;
this.button13.Click += new System.EventHandler(this.button13_Click);
//
// label12
//
this.label12.AutoSize = true;
this.label12.Location = new System.Drawing.Point(18, 243);
this.label12.Name = "label12";
this.label12.Size = new System.Drawing.Size(34, 12);
this.label12.TabIndex = 16;
this.label12.Text = "Enter";
//
// button3
//
this.button3.Location = new System.Drawing.Point(246, 339);
this.button3.Location = new System.Drawing.Point(205, 230);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(86, 38);
this.button3.Size = new System.Drawing.Size(133, 38);
this.button3.TabIndex = 15;
this.button3.Tag = "--";
this.button3.Text = "Pick Off";
@@ -1139,9 +1408,9 @@ namespace AGVEmulator
//
// button2
//
this.button2.Location = new System.Drawing.Point(246, 295);
this.button2.Location = new System.Drawing.Point(66, 230);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(86, 38);
this.button2.Size = new System.Drawing.Size(133, 38);
this.button2.TabIndex = 14;
this.button2.Tag = "--";
this.button2.Text = "Pick On";
@@ -1151,7 +1420,7 @@ namespace AGVEmulator
// nudIDAgv
//
this.nudIDAgv.Font = new System.Drawing.Font("굴림", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.nudIDAgv.Location = new System.Drawing.Point(6, 249);
this.nudIDAgv.Location = new System.Drawing.Point(7, 174);
this.nudIDAgv.Maximum = new decimal(new int[] {
9999999,
0,
@@ -1170,7 +1439,7 @@ namespace AGVEmulator
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(32, 220);
this.label7.Location = new System.Drawing.Point(33, 145);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(45, 12);
this.label7.TabIndex = 12;
@@ -1179,7 +1448,7 @@ namespace AGVEmulator
// numericUpDown2
//
this.numericUpDown2.Font = new System.Drawing.Font("굴림", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.numericUpDown2.Location = new System.Drawing.Point(110, 207);
this.numericUpDown2.Location = new System.Drawing.Point(111, 132);
this.numericUpDown2.Maximum = new decimal(new int[] {
9999999,
0,
@@ -1197,7 +1466,7 @@ namespace AGVEmulator
//
// button1
//
this.button1.Location = new System.Drawing.Point(246, 207);
this.button1.Location = new System.Drawing.Point(247, 132);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(86, 38);
this.button1.TabIndex = 10;
@@ -1209,7 +1478,7 @@ namespace AGVEmulator
// nudTagNo
//
this.nudTagNo.Font = new System.Drawing.Font("굴림", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.nudTagNo.Location = new System.Drawing.Point(110, 251);
this.nudTagNo.Location = new System.Drawing.Point(111, 176);
this.nudTagNo.Maximum = new decimal(new int[] {
9999999,
0,
@@ -1227,7 +1496,7 @@ namespace AGVEmulator
//
// btacsgoto
//
this.btacsgoto.Location = new System.Drawing.Point(246, 251);
this.btacsgoto.Location = new System.Drawing.Point(247, 176);
this.btacsgoto.Name = "btacsgoto";
this.btacsgoto.Size = new System.Drawing.Size(86, 38);
this.btacsgoto.TabIndex = 8;
@@ -1238,7 +1507,7 @@ namespace AGVEmulator
//
// button7
//
this.button7.Location = new System.Drawing.Point(83, 72);
this.button7.Location = new System.Drawing.Point(219, 12);
this.button7.Name = "button7";
this.button7.Size = new System.Drawing.Size(62, 54);
this.button7.TabIndex = 7;
@@ -1247,7 +1516,7 @@ namespace AGVEmulator
//
// button8
//
this.button8.Location = new System.Drawing.Point(83, 132);
this.button8.Location = new System.Drawing.Point(87, 72);
this.button8.Name = "button8";
this.button8.Size = new System.Drawing.Size(62, 54);
this.button8.TabIndex = 6;
@@ -1257,7 +1526,7 @@ namespace AGVEmulator
//
// button9
//
this.button9.Location = new System.Drawing.Point(15, 130);
this.button9.Location = new System.Drawing.Point(19, 70);
this.button9.Name = "button9";
this.button9.Size = new System.Drawing.Size(62, 54);
this.button9.TabIndex = 5;
@@ -1267,7 +1536,7 @@ namespace AGVEmulator
//
// button10
//
this.button10.Location = new System.Drawing.Point(15, 70);
this.button10.Location = new System.Drawing.Point(151, 10);
this.button10.Name = "button10";
this.button10.Size = new System.Drawing.Size(62, 54);
this.button10.TabIndex = 3;
@@ -1408,173 +1677,6 @@ namespace AGVEmulator
this.sbCAL.Size = new System.Drawing.Size(19, 17);
this.sbCAL.Text = "●";
//
// agvViewer1
//
this.agvViewer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.agvViewer1.FontMrk = new System.Drawing.Font("Microsoft Sans Serif", 7F);
this.agvViewer1.FontTag = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.agvViewer1.lastmark = "";
this.agvViewer1.lastmarkdir = "";
this.agvViewer1.lasttag = "";
this.agvViewer1.lasttagdir = "";
ptdata1.active = false;
ptdata1.data = "NOT";
ptdata1.pos = 30F;
ptdata2.active = false;
ptdata2.data = "QA";
ptdata2.pos = 200F;
ptdata3.active = false;
ptdata3.data = "CHG";
ptdata3.pos = 300F;
ptdata4.active = false;
ptdata4.data = "QC";
ptdata4.pos = 400F;
ptdata5.active = false;
ptdata5.data = "#FVI-1";
ptdata5.pos = 500F;
ptdata6.active = false;
ptdata6.data = "#FVI-2";
ptdata6.pos = 600F;
ptdata7.active = false;
ptdata7.data = "#FVI-3";
ptdata7.pos = 700F;
ptdata8.active = false;
ptdata8.data = "#FVI-4";
ptdata8.pos = 800F;
ptdata9.active = false;
ptdata9.data = "#FVI-5";
ptdata9.pos = 900F;
ptdata10.active = false;
ptdata10.data = "POT";
ptdata10.pos = 970F;
this.agvViewer1.listMRK = new AGVEmulator.UC.AgvViewer.ptdata[] {
ptdata1,
ptdata2,
ptdata3,
ptdata4,
ptdata5,
ptdata6,
ptdata7,
ptdata8,
ptdata9,
ptdata10};
ptdata11.active = false;
ptdata11.data = "9000";
ptdata11.pos = 80F;
ptdata12.active = false;
ptdata12.data = "9001";
ptdata12.pos = 120F;
ptdata13.active = false;
ptdata13.data = "9010";
ptdata13.pos = 180F;
ptdata14.active = false;
ptdata14.data = "9011";
ptdata14.pos = 220F;
ptdata15.active = false;
ptdata15.data = "9020";
ptdata15.pos = 280F;
ptdata16.active = false;
ptdata16.data = "9021";
ptdata16.pos = 320F;
ptdata17.active = false;
ptdata17.data = "9030";
ptdata17.pos = 380F;
ptdata18.active = false;
ptdata18.data = "9031";
ptdata18.pos = 420F;
ptdata19.active = false;
ptdata19.data = "9040";
ptdata19.pos = 480F;
ptdata20.active = false;
ptdata20.data = "9041";
ptdata20.pos = 520F;
ptdata21.active = false;
ptdata21.data = "9050";
ptdata21.pos = 580F;
ptdata22.active = false;
ptdata22.data = "9051";
ptdata22.pos = 620F;
ptdata23.active = false;
ptdata23.data = "9060";
ptdata23.pos = 680F;
ptdata24.active = false;
ptdata24.data = "9061";
ptdata24.pos = 720F;
ptdata25.active = false;
ptdata25.data = "9070";
ptdata25.pos = 780F;
ptdata26.active = false;
ptdata26.data = "9071";
ptdata26.pos = 820F;
ptdata27.active = false;
ptdata27.data = "9000";
ptdata27.pos = 10F;
ptdata28.active = false;
ptdata28.data = "9001";
ptdata28.pos = 50F;
this.agvViewer1.listTAG = new AGVEmulator.UC.AgvViewer.ptdata[] {
ptdata11,
ptdata12,
ptdata13,
ptdata14,
ptdata15,
ptdata16,
ptdata17,
ptdata18,
ptdata19,
ptdata20,
ptdata21,
ptdata22,
ptdata23,
ptdata24,
ptdata25,
ptdata26,
ptdata27,
ptdata28};
this.agvViewer1.Location = new System.Drawing.Point(241, 0);
this.agvViewer1.Name = "agvViewer1";
this.agvViewer1.Size = new System.Drawing.Size(899, 120);
this.agvViewer1.StopbyMark = false;
this.agvViewer1.TabIndex = 0;
this.agvViewer1.Text = "agvViewer1";
this.agvViewer1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.agvViewer1_MouseDown);
//
// serAGV
//
this.serAGV.BaudRate = 9600;
this.serAGV.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.serAGV.dev = null;
this.serAGV.Dock = System.Windows.Forms.DockStyle.Left;
this.serAGV.Location = new System.Drawing.Point(0, 0);
this.serAGV.Name = "serAGV";
this.serAGV.PortName = "COM21";
this.serAGV.Size = new System.Drawing.Size(241, 120);
this.serAGV.TabIndex = 0;
//
// serBMS
//
this.serBMS.BaudRate = 9600;
this.serBMS.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.serBMS.dev = null;
this.serBMS.Dock = System.Windows.Forms.DockStyle.Top;
this.serBMS.Location = new System.Drawing.Point(3, 17);
this.serBMS.Name = "serBMS";
this.serBMS.PortName = "COM31";
this.serBMS.Size = new System.Drawing.Size(1134, 84);
this.serBMS.TabIndex = 1;
//
// serCAL
//
this.serCAL.BaudRate = 9600;
this.serCAL.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.serCAL.dev = null;
this.serCAL.Dock = System.Windows.Forms.DockStyle.Top;
this.serCAL.Location = new System.Drawing.Point(3, 17);
this.serCAL.Name = "serCAL";
this.serCAL.PortName = "COM41";
this.serCAL.Size = new System.Drawing.Size(776, 84);
this.serCAL.TabIndex = 1;
//
// fMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
@@ -1623,6 +1725,9 @@ namespace AGVEmulator
this.tabPage3.ResumeLayout(false);
this.panel3.ResumeLayout(false);
this.panel3.PerformLayout();
this.groupBox13.ResumeLayout(false);
this.groupBox13.PerformLayout();
this.groupBox12.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.nudIDAgv)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown2)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudTagNo)).EndInit();
@@ -1746,6 +1851,15 @@ namespace AGVEmulator
private Button button3;
private Button button2;
private Panel panel2;
private Label label12;
private Label label13;
private Button button6;
private Button button13;
private GroupBox groupBox13;
private GroupBox groupBox12;
private TextBox tbErCode;
private TextBox tbErmsg;
private RichTextBox rtStatus;
}
}

View File

@@ -8,22 +8,26 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using static AGVEmulator.DevAGV;
using AGVNavigationCore.Controls;
using AGVNavigationCore.Models;
using System.Text;
namespace AGVEmulator
{
public partial class fMain : Form
{
arUtil.Log logAGV, logBMS, logCAL;
AR.Log logAGV, logBMS, logCAL;
DevBMS BMS;
DevAGV AGV;
DevXBE XBE;
public RemoteStatus _remoteStatus = new RemoteStatus();
public ENIGProtocol.AGVErrorCode _remoteErrorCode = ENIGProtocol.AGVErrorCode.None;
public string _remoteErrorMessage = "";
// Map Control
private UnifiedAGVCanvas _agvCanvas;
private VirtualAGV _visualAgv;
@@ -47,9 +51,9 @@ namespace AGVEmulator
InitializeComponent();
this.Text = $"{Application.ProductName} ver.{Application.ProductVersion}";
// logPLC = new arUtil.Log();
logAGV = new arUtil.Log();
logBMS = new arUtil.Log();
logCAL = new arUtil.Log();
logAGV = new AR.Log();
logBMS = new AR.Log();
logCAL = new AR.Log();
// logPLC.FileNameFormat = "{yyyyMMdd}_PLC";
logAGV.FileNameFormat = "{yyyyMMdd}_AGV";
@@ -938,21 +942,25 @@ namespace AGVEmulator
private void button2_Click(object sender, EventArgs e)
{
var target = (byte)nudIDAgv.Value;
this.XBE.SendPickOn(target);
this.XBE.SendPickOnEnter(target);
}
private void button3_Click(object sender, EventArgs e)
{
var target = (byte)nudIDAgv.Value;
this.XBE.SendPickOff(target);
this.XBE.SendPickOffEnter(target);
}
private void trbT2_Scroll(object sender, EventArgs e)
{
Temp2 = (UInt16)trbT2.Value;
label11.Text = $"{Temp2 / 10f}º";
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
serAGV.Connect();
@@ -966,8 +974,59 @@ namespace AGVEmulator
serBMS.Disconnect();
serCAL.Disconnect();
}
private void button13_Click(object sender, EventArgs e)
{
var target = (byte)nudIDAgv.Value;
this.XBE.SendPickOnExit(target);
}
private void button6_Click_1(object sender, EventArgs e)
{
var target = (byte)nudIDAgv.Value;
this.XBE.SendPickOffExit(target);
}
public void UpdateUIStatus()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(UpdateUIStatus));
return;
}
rtStatus.Text = _remoteStatus.ToString();
string errCode = _remoteErrorCode.ToString();
string errMsg = _remoteErrorMessage;
if (_remoteStatus.HWError > 0)
{
errCode = $"HW:{_remoteStatus.HWError:X4}" + (errCode == "None" ? "" : $" | {errCode}");
StringBuilder sbHw = new StringBuilder();
for (int i = 0; i < 16; i++)
{
if (((ushort)_remoteStatus.HWError & (1 << i)) != 0)
{
sbHw.Append($"{(DevAGV.eerror)i}, ");
}
}
errMsg = $"[HW] {sbHw}" + (string.IsNullOrEmpty(errMsg) ? "" : $" | {errMsg}");
}
tbErCode.Text = errCode;
tbErmsg.Text = errMsg;
if (_remoteErrorCode != ENIGProtocol.AGVErrorCode.None || _remoteStatus.HWError > 0)
{
tbErCode.BackColor = Color.Red;
tbErCode.ForeColor = Color.White;
}
else
{
tbErCode.BackColor = SystemColors.Window;
tbErCode.ForeColor = SystemColors.WindowText;
}
}
}
}

View File

@@ -1,6 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 15 for Windows Desktop
VisualStudioVersion = 15.0.36324.19
# Visual Studio Version 17
VisualStudioVersion = 17.14.36310.24
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVMapEditor", "AGVMapEditor\AGVMapEditor.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
@@ -8,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVNavigationCore", "AGVNav
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AGVSimulator", "AGVSimulator\AGVSimulator.csproj", "{B2C3D4E5-0000-0000-0000-000000000000}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol", "EnigProtocol\enigprotocol\ENIGProtocol.csproj", "{9365803B-933D-4237-93C7-B502C855A71C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -26,11 +29,15 @@ Global
{B2C3D4E5-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2C3D4E5-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2C3D4E5-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
{9365803B-933D-4237-93C7-B502C855A71C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9365803B-933D-4237-93C7-B502C855A71C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9365803B-933D-4237-93C7-B502C855A71C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9365803B-933D-4237-93C7-B502C855A71C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F2C60284-CCB5-450D-BCD0-19C693529FD6}
SolutionGuid = {638744DA-A7C8-43E2-A98E-0DE9BDB1DA35}
EndGlobalSection
EndGlobal

View File

@@ -17,7 +17,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\..\..\..\Amkor\AGV4\Test\MapEditor\</OutputPath>
<OutputPath>bin\debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>

View File

@@ -31,6 +31,7 @@ namespace AGVMapEditor.Forms
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
this.sbFile = new System.Windows.Forms.ToolStripStatusLabel();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPageNodes = new System.Windows.Forms.TabPage();
@@ -40,6 +41,20 @@ namespace AGVMapEditor.Forms
this.lstNodeConnection = new System.Windows.Forms.ListBox();
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.btNodeRemove = new System.Windows.Forms.ToolStripButton();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.lstMagnetDirection = new System.Windows.Forms.ListBox();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.toolStrip4 = new System.Windows.Forms.ToolStrip();
this.btDirDelete = new System.Windows.Forms.ToolStripButton();
this.btMakeDirdata = new System.Windows.Forms.ToolStripButton();
this.toolStripButton2 = new System.Windows.Forms.ToolStripButton();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.lstMagnet = new System.Windows.Forms.ListBox();
this.toolStrip5 = new System.Windows.Forms.ToolStrip();
this.btDelMagnet = new System.Windows.Forms.ToolStripButton();
this._propertyGrid = new System.Windows.Forms.PropertyGrid();
this.panel1 = new System.Windows.Forms.Panel();
this.toolStrip3 = new System.Windows.Forms.ToolStrip();
@@ -51,11 +66,12 @@ namespace AGVMapEditor.Forms
this.btnDelete = new System.Windows.Forms.ToolStripButton();
this.btnEditImage = new System.Windows.Forms.ToolStripButton();
this.separator1 = new System.Windows.Forms.ToolStripSeparator();
this.btnConnect = new System.Windows.Forms.ToolStripButton();
this.btnDeleteConnection = new System.Windows.Forms.ToolStripButton();
this.btnConnNode = new System.Windows.Forms.ToolStripButton();
this.btnConnDir = new System.Windows.Forms.ToolStripButton();
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.btnToggleGrid = new System.Windows.Forms.ToolStripButton();
this.btnFitMap = new System.Windows.Forms.ToolStripButton();
this.btAddMagnet = new System.Windows.Forms.ToolStripButton();
this.toolStrip2 = new System.Windows.Forms.ToolStrip();
this.btnNew = new System.Windows.Forms.ToolStripButton();
this.btnOpen = new System.Windows.Forms.ToolStripButton();
@@ -67,16 +83,7 @@ namespace AGVMapEditor.Forms
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripButton1 = new System.Windows.Forms.ToolStripDropDownButton();
this.allTurnLeftRightCrossOnToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.lstMagnetDirection = new System.Windows.Forms.ListBox();
this.toolStrip4 = new System.Windows.Forms.ToolStrip();
this.btDirDelete = new System.Windows.Forms.ToolStripButton();
this.btMakeDirdata = new System.Windows.Forms.ToolStripButton();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.toolStripButton2 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton3 = new System.Windows.Forms.ToolStripButton();
this.statusStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
this.splitContainer1.Panel1.SuspendLayout();
@@ -86,17 +93,20 @@ namespace AGVMapEditor.Forms
this.tabPageNodes.SuspendLayout();
this.tabPage1.SuspendLayout();
this.toolStrip1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.toolStrip4.SuspendLayout();
this.tabPage3.SuspendLayout();
this.toolStrip5.SuspendLayout();
this.toolStrip3.SuspendLayout();
this.toolStrip2.SuspendLayout();
this.tabPage2.SuspendLayout();
this.toolStrip4.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripStatusLabel1});
this.toolStripStatusLabel1,
this.sbFile});
this.statusStrip1.Location = new System.Drawing.Point(0, 751);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(1200, 22);
@@ -109,6 +119,12 @@ namespace AGVMapEditor.Forms
this.toolStripStatusLabel1.Size = new System.Drawing.Size(39, 17);
this.toolStripStatusLabel1.Text = "Ready";
//
// sbFile
//
this.sbFile.Name = "sbFile";
this.sbFile.Size = new System.Drawing.Size(17, 17);
this.sbFile.Text = "--";
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
@@ -134,6 +150,7 @@ namespace AGVMapEditor.Forms
this.tabControl1.Controls.Add(this.tabPageNodes);
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 0);
this.tabControl1.Name = "tabControl1";
@@ -215,6 +232,161 @@ namespace AGVMapEditor.Forms
this.btNodeRemove.Text = "Remove";
this.btNodeRemove.Click += new System.EventHandler(this.btNodeRemove_Click);
//
// tabPage2
//
this.tabPage2.Controls.Add(this.lstMagnetDirection);
this.tabPage2.Controls.Add(this.tableLayoutPanel1);
this.tabPage2.Controls.Add(this.toolStrip4);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Size = new System.Drawing.Size(292, 309);
this.tabPage2.TabIndex = 2;
this.tabPage2.Text = "방향 관리";
this.tabPage2.UseVisualStyleBackColor = true;
//
// lstMagnetDirection
//
this.lstMagnetDirection.Dock = System.Windows.Forms.DockStyle.Fill;
this.lstMagnetDirection.FormattingEnabled = true;
this.lstMagnetDirection.ItemHeight = 12;
this.lstMagnetDirection.Location = new System.Drawing.Point(0, 25);
this.lstMagnetDirection.Name = "lstMagnetDirection";
this.lstMagnetDirection.Size = new System.Drawing.Size(292, 246);
this.lstMagnetDirection.TabIndex = 3;
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.Controls.Add(this.button1, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.button2, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.button3, 2, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 271);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(292, 38);
this.tableLayoutPanel1.TabIndex = 6;
//
// button1
//
this.button1.Dock = System.Windows.Forms.DockStyle.Fill;
this.button1.Location = new System.Drawing.Point(3, 3);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(91, 32);
this.button1.TabIndex = 0;
this.button1.Text = "Left";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Dock = System.Windows.Forms.DockStyle.Fill;
this.button2.Location = new System.Drawing.Point(100, 3);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(91, 32);
this.button2.TabIndex = 0;
this.button2.Text = "Straight";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Dock = System.Windows.Forms.DockStyle.Fill;
this.button3.Location = new System.Drawing.Point(197, 3);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(92, 32);
this.button3.TabIndex = 0;
this.button3.Text = "Right";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// toolStrip4
//
this.toolStrip4.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.btDirDelete,
this.btMakeDirdata,
this.toolStripButton2});
this.toolStrip4.Location = new System.Drawing.Point(0, 0);
this.toolStrip4.Name = "toolStrip4";
this.toolStrip4.Size = new System.Drawing.Size(292, 25);
this.toolStrip4.TabIndex = 5;
this.toolStrip4.Text = "toolStrip4";
//
// btDirDelete
//
this.btDirDelete.Image = ((System.Drawing.Image)(resources.GetObject("btDirDelete.Image")));
this.btDirDelete.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btDirDelete.Name = "btDirDelete";
this.btDirDelete.Size = new System.Drawing.Size(61, 22);
this.btDirDelete.Text = "Delete";
this.btDirDelete.Click += new System.EventHandler(this.btDirDelete_Click);
//
// btMakeDirdata
//
this.btMakeDirdata.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.btMakeDirdata.Image = ((System.Drawing.Image)(resources.GetObject("btMakeDirdata.Image")));
this.btMakeDirdata.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btMakeDirdata.Name = "btMakeDirdata";
this.btMakeDirdata.Size = new System.Drawing.Size(69, 22);
this.btMakeDirdata.Text = "Remake";
this.btMakeDirdata.Click += new System.EventHandler(this.toolStripButton3_Click);
//
// toolStripButton2
//
this.toolStripButton2.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.toolStripButton2.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton2.Image")));
this.toolStripButton2.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton2.Name = "toolStripButton2";
this.toolStripButton2.Size = new System.Drawing.Size(54, 22);
this.toolStripButton2.Text = "Clear";
this.toolStripButton2.Click += new System.EventHandler(this.toolStripButton2_Click);
//
// tabPage3
//
this.tabPage3.Controls.Add(this.lstMagnet);
this.tabPage3.Controls.Add(this.toolStrip5);
this.tabPage3.Location = new System.Drawing.Point(4, 22);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(292, 309);
this.tabPage3.TabIndex = 3;
this.tabPage3.Text = "마그넷라인";
this.tabPage3.UseVisualStyleBackColor = true;
//
// lstMagnet
//
this.lstMagnet.Dock = System.Windows.Forms.DockStyle.Fill;
this.lstMagnet.FormattingEnabled = true;
this.lstMagnet.ItemHeight = 12;
this.lstMagnet.Location = new System.Drawing.Point(0, 25);
this.lstMagnet.Name = "lstMagnet";
this.lstMagnet.Size = new System.Drawing.Size(292, 284);
this.lstMagnet.TabIndex = 2;
//
// toolStrip5
//
this.toolStrip5.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.btDelMagnet,
this.toolStripButton3});
this.toolStrip5.Location = new System.Drawing.Point(0, 0);
this.toolStrip5.Name = "toolStrip5";
this.toolStrip5.Size = new System.Drawing.Size(292, 25);
this.toolStrip5.TabIndex = 6;
this.toolStrip5.Text = "toolStrip5";
//
// btDelMagnet
//
this.btDelMagnet.Image = ((System.Drawing.Image)(resources.GetObject("btDelMagnet.Image")));
this.btDelMagnet.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btDelMagnet.Name = "btDelMagnet";
this.btDelMagnet.Size = new System.Drawing.Size(61, 22);
this.btDelMagnet.Text = "Delete";
this.btDelMagnet.Click += new System.EventHandler(this.btDelMagnet_Click);
//
// _propertyGrid
//
this._propertyGrid.Dock = System.Windows.Forms.DockStyle.Bottom;
@@ -240,11 +412,12 @@ namespace AGVMapEditor.Forms
this.btnDelete,
this.btnEditImage,
this.separator1,
this.btnConnect,
this.btnDeleteConnection,
this.btnConnNode,
this.btnConnDir,
this.toolStripSeparator1,
this.btnToggleGrid,
this.btnFitMap});
this.btnFitMap,
this.btAddMagnet});
this.toolStrip3.Location = new System.Drawing.Point(0, 0);
this.toolStrip3.Name = "toolStrip3";
this.toolStrip3.Size = new System.Drawing.Size(896, 25);
@@ -278,6 +451,8 @@ namespace AGVMapEditor.Forms
this.btnAddNode.Size = new System.Drawing.Size(111, 22);
this.btnAddNode.Text = "노드 추가 (A)";
this.btnAddNode.ToolTipText = "노드 추가 (A)";
this.btnAddNode.ButtonClick += new System.EventHandler(this.btnAddNode_ButtonClick);
this.btnAddNode.BackColorChanged += new System.EventHandler(this.btnAddNode_BackColorChanged);
//
// btnAddLabel
//
@@ -322,21 +497,20 @@ namespace AGVMapEditor.Forms
this.separator1.Name = "separator1";
this.separator1.Size = new System.Drawing.Size(6, 25);
//
// btnConnect
// btnConnNode
//
this.btnConnect.Image = ((System.Drawing.Image)(resources.GetObject("btnConnect.Image")));
this.btnConnect.Name = "btnConnect";
this.btnConnect.Size = new System.Drawing.Size(95, 22);
this.btnConnect.Text = "노드연결 (C)";
this.btnConnNode.Image = ((System.Drawing.Image)(resources.GetObject("btnConnNode.Image")));
this.btnConnNode.Name = "btnConnNode";
this.btnConnNode.Size = new System.Drawing.Size(95, 22);
this.btnConnNode.Text = "노드연결 (C)";
//
// btnDeleteConnection
// btnConnDir
//
this.btnDeleteConnection.Image = ((System.Drawing.Image)(resources.GetObject("btnDeleteConnection.Image")));
this.btnDeleteConnection.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btnDeleteConnection.Name = "btnDeleteConnection";
this.btnDeleteConnection.Size = new System.Drawing.Size(94, 22);
this.btnDeleteConnection.Text = "연결삭제 (X)";
this.btnDeleteConnection.ToolTipText = "연결 삭제 (X)";
this.btnConnDir.Image = ((System.Drawing.Image)(resources.GetObject("btnConnDir.Image")));
this.btnConnDir.Name = "btnConnDir";
this.btnConnDir.Size = new System.Drawing.Size(95, 22);
this.btnConnDir.Text = "방향연결 (C)";
this.btnConnDir.Click += new System.EventHandler(this.btnConnDir_Click);
//
// toolStripSeparator1
//
@@ -359,6 +533,15 @@ namespace AGVMapEditor.Forms
this.btnFitMap.Text = "맵 맞춤";
this.btnFitMap.ToolTipText = "맵 전체 보기";
//
// btAddMagnet
//
this.btAddMagnet.Image = ((System.Drawing.Image)(resources.GetObject("btAddMagnet.Image")));
this.btAddMagnet.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btAddMagnet.Name = "btAddMagnet";
this.btAddMagnet.Size = new System.Drawing.Size(87, 22);
this.btAddMagnet.Text = "마그넷추가";
this.btAddMagnet.Click += new System.EventHandler(this.btAddMagnet_Click);
//
// toolStrip2
//
this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -458,119 +641,15 @@ namespace AGVMapEditor.Forms
this.allTurnLeftRightCrossOnToolStripMenuItem.Text = "All TurnLeft/Right/Cross On";
this.allTurnLeftRightCrossOnToolStripMenuItem.Click += new System.EventHandler(this.allTurnLeftRightCrossOnToolStripMenuItem_Click);
//
// tabPage2
// toolStripButton3
//
this.tabPage2.Controls.Add(this.lstMagnetDirection);
this.tabPage2.Controls.Add(this.tableLayoutPanel1);
this.tabPage2.Controls.Add(this.toolStrip4);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Size = new System.Drawing.Size(292, 309);
this.tabPage2.TabIndex = 2;
this.tabPage2.Text = "방향 관리";
this.tabPage2.UseVisualStyleBackColor = true;
//
// lstMagnetDirection
//
this.lstMagnetDirection.Dock = System.Windows.Forms.DockStyle.Fill;
this.lstMagnetDirection.FormattingEnabled = true;
this.lstMagnetDirection.ItemHeight = 12;
this.lstMagnetDirection.Location = new System.Drawing.Point(0, 25);
this.lstMagnetDirection.Name = "lstMagnetDirection";
this.lstMagnetDirection.Size = new System.Drawing.Size(292, 246);
this.lstMagnetDirection.TabIndex = 3;
//
// toolStrip4
//
this.toolStrip4.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.btDirDelete,
this.btMakeDirdata,
this.toolStripButton2});
this.toolStrip4.Location = new System.Drawing.Point(0, 0);
this.toolStrip4.Name = "toolStrip4";
this.toolStrip4.Size = new System.Drawing.Size(292, 25);
this.toolStrip4.TabIndex = 5;
this.toolStrip4.Text = "toolStrip4";
//
// btDirDelete
//
this.btDirDelete.Image = ((System.Drawing.Image)(resources.GetObject("btDirDelete.Image")));
this.btDirDelete.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btDirDelete.Name = "btDirDelete";
this.btDirDelete.Size = new System.Drawing.Size(61, 22);
this.btDirDelete.Text = "Delete";
this.btDirDelete.Click += new System.EventHandler(this.btDirDelete_Click);
//
// btMakeDirdata
//
this.btMakeDirdata.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.btMakeDirdata.Image = ((System.Drawing.Image)(resources.GetObject("btMakeDirdata.Image")));
this.btMakeDirdata.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btMakeDirdata.Name = "btMakeDirdata";
this.btMakeDirdata.Size = new System.Drawing.Size(69, 22);
this.btMakeDirdata.Text = "Remake";
this.btMakeDirdata.Click += new System.EventHandler(this.toolStripButton3_Click);
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.Controls.Add(this.button1, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.button2, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.button3, 2, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 271);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(292, 38);
this.tableLayoutPanel1.TabIndex = 6;
//
// button1
//
this.button1.Dock = System.Windows.Forms.DockStyle.Fill;
this.button1.Location = new System.Drawing.Point(3, 3);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(91, 32);
this.button1.TabIndex = 0;
this.button1.Text = "Left";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Dock = System.Windows.Forms.DockStyle.Fill;
this.button2.Location = new System.Drawing.Point(100, 3);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(91, 32);
this.button2.TabIndex = 0;
this.button2.Text = "Straight";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Dock = System.Windows.Forms.DockStyle.Fill;
this.button3.Location = new System.Drawing.Point(197, 3);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(92, 32);
this.button3.TabIndex = 0;
this.button3.Text = "Right";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// toolStripButton2
//
this.toolStripButton2.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.toolStripButton2.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton2.Image")));
this.toolStripButton2.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton2.Name = "toolStripButton2";
this.toolStripButton2.Size = new System.Drawing.Size(54, 22);
this.toolStripButton2.Text = "Clear";
this.toolStripButton2.Click += new System.EventHandler(this.toolStripButton2_Click);
this.toolStripButton3.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.toolStripButton3.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton3.Image")));
this.toolStripButton3.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton3.Name = "toolStripButton3";
this.toolStripButton3.Size = new System.Drawing.Size(66, 22);
this.toolStripButton3.Text = "Refresh";
this.toolStripButton3.Click += new System.EventHandler(this.toolStripButton3_Click_1);
//
// MainForm
//
@@ -599,15 +678,19 @@ namespace AGVMapEditor.Forms
this.tabPage1.PerformLayout();
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.tabPage2.ResumeLayout(false);
this.tabPage2.PerformLayout();
this.tableLayoutPanel1.ResumeLayout(false);
this.toolStrip4.ResumeLayout(false);
this.toolStrip4.PerformLayout();
this.tabPage3.ResumeLayout(false);
this.tabPage3.PerformLayout();
this.toolStrip5.ResumeLayout(false);
this.toolStrip5.PerformLayout();
this.toolStrip3.ResumeLayout(false);
this.toolStrip3.PerformLayout();
this.toolStrip2.ResumeLayout(false);
this.toolStrip2.PerformLayout();
this.tabPage2.ResumeLayout(false);
this.tabPage2.PerformLayout();
this.toolStrip4.ResumeLayout(false);
this.toolStrip4.PerformLayout();
this.tableLayoutPanel1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@@ -639,9 +722,8 @@ namespace AGVMapEditor.Forms
private System.Windows.Forms.ToolStripButton btnSelect;
private System.Windows.Forms.ToolStripButton btnMove;
private System.Windows.Forms.ToolStripButton btnEditImage;
private System.Windows.Forms.ToolStripButton btnConnect;
private System.Windows.Forms.ToolStripButton btnConnNode;
private System.Windows.Forms.ToolStripButton btnDelete;
private System.Windows.Forms.ToolStripButton btnDeleteConnection;
private System.Windows.Forms.ToolStripSeparator separator1;
private System.Windows.Forms.ToolStripButton btnToggleGrid;
private System.Windows.Forms.ToolStripButton btnFitMap;
@@ -663,5 +745,13 @@ namespace AGVMapEditor.Forms
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.ToolStripButton toolStripButton2;
private System.Windows.Forms.ToolStripButton btAddMagnet;
private System.Windows.Forms.TabPage tabPage3;
private System.Windows.Forms.ListBox lstMagnet;
private System.Windows.Forms.ToolStrip toolStrip5;
private System.Windows.Forms.ToolStripButton btDelMagnet;
private System.Windows.Forms.ToolStripStatusLabel sbFile;
private System.Windows.Forms.ToolStripButton btnConnDir;
private System.Windows.Forms.ToolStripButton toolStripButton3;
}
}

View File

@@ -115,6 +115,7 @@ namespace AGVMapEditor.Forms
_mapCanvas.NodesSelected += OnNodesSelected; // 다중 선택 이벤트
_mapCanvas.NodeMoved += OnNodeMoved;
_mapCanvas.NodeDeleted += OnNodeDeleted;
_mapCanvas.ConnectionCreated += OnConnectionCreated;
_mapCanvas.ConnectionDeleted += OnConnectionDeleted;
_mapCanvas.ImageDoubleClicked += OnImageDoubleClicked;
_mapCanvas.MapChanged += OnMapChanged;
@@ -144,9 +145,8 @@ namespace AGVMapEditor.Forms
btnAddLabel.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.AddLabel;
btnAddImage.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.AddImage;
btnConnect.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Connect;
btnConnNode.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Connect;
btnDelete.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.Delete;
btnDeleteConnection.Click += (s, e) => _mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.DeleteConnection;
// 그리드 토글 버튼
btnToggleGrid.Click += (s, e) => _mapCanvas.ShowGrid = !_mapCanvas.ShowGrid;
@@ -182,6 +182,7 @@ namespace AGVMapEditor.Forms
_hasChanges = true;
UpdateTitle();
RefreshNodeList();
RefreshMagnetList(); // 추가
// RFID 자동 할당
}
@@ -215,6 +216,20 @@ namespace AGVMapEditor.Forms
{
// 단일 선택은 기존 방식 사용
_selectedNode = nodes[0];
// Sync with lstMagnet
if (_selectedNode is MapMagnet magnet)
{
lstMagnet.SelectedItem = magnet;
}
else
{
lstMagnet.SelectedItem = null;
}
//this._mapCanvas.SelectedNode = nodes;
//this._mapCanvas.Invalidate();
UpdateNodeProperties();
UpdateImageEditButton();
}
@@ -242,17 +257,20 @@ namespace AGVMapEditor.Forms
_hasChanges = true;
UpdateTitle();
RefreshNodeList();
RefreshMagnetList(); // 추가
ClearNodeProperties();
// RFID 자동 할당
}
private void OnConnectionCreated(object sender, (MapNode From, MapNode To) connection)
{
_hasChanges = true;
UpdateTitle();
RefreshNodeConnectionList();
UpdateNodeProperties(); // 연결 정보 업데이트
}
private void OnConnectionDeleted(object sender, (MapNode From, MapNode To) connection)
{
_hasChanges = true;
@@ -261,6 +279,8 @@ namespace AGVMapEditor.Forms
UpdateNodeProperties(); // 연결 정보 업데이트
}
private void OnImageDoubleClicked(object sender, MapImage image)
{
// 이미지 노드 더블클릭 시 이미지 편집창 표시
@@ -280,6 +300,7 @@ namespace AGVMapEditor.Forms
{
_hasChanges = true;
UpdateTitle();
RefreshMagnetDirectionList(); // 방향 정보 업데이트
}
private void OnBackgroundClicked(object sender, Point location)
@@ -403,7 +424,7 @@ namespace AGVMapEditor.Forms
var nodeId = GenerateNodeId();
var position = new Point(100 + this._mapCanvas.Nodes.Count * 50, 100 + this._mapCanvas.Nodes.Count * 50);
var node = new MapNode(nodeId, position, StationType.Normal);
var node = new MapNode(nodeId, position, Station.Normal);
this._mapCanvas.Nodes.Add(node);
_hasChanges = true;
@@ -621,7 +642,7 @@ namespace AGVMapEditor.Forms
private void LoadMapFromFile(string filePath)
{
var result = MapLoader.LoadMapFromFile(filePath);
sbFile.Text = filePath;
if (result.Success)
{
// 맵 캔버스에 데이터 설정
@@ -637,6 +658,7 @@ namespace AGVMapEditor.Forms
UpdateTitle();
UpdateNodeList();
RefreshNodeConnectionList();
RefreshMagnetList(); // 추가
@@ -767,6 +789,7 @@ namespace AGVMapEditor.Forms
{
RefreshNodeList();
RefreshNodeConnectionList();
RefreshMagnetList(); // 추가
RefreshMapCanvas();
ClearNodeProperties();
}
@@ -774,7 +797,7 @@ namespace AGVMapEditor.Forms
private void RefreshNodeList()
{
listBoxNodes.DataSource = null;
listBoxNodes.DataSource = this._mapCanvas.Nodes;
listBoxNodes.DataSource = this._mapCanvas.Items;
listBoxNodes.DisplayMember = "DisplayText";
listBoxNodes.ValueMember = "Id";
@@ -790,7 +813,7 @@ namespace AGVMapEditor.Forms
private void ListBoxNodes_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBoxNodes.SelectedItem is MapNode selectedNode)
if (listBoxNodes.SelectedItem is NodeBase selectedNode)
{
_selectedNode = selectedNode;
UpdateNodeProperties();
@@ -827,9 +850,9 @@ namespace AGVMapEditor.Forms
case NodeType.Normal:
var item = node as MapNode;
if (item.StationType == StationType.Normal)
if (item.StationType == Station.Normal)
foreColor = Color.DimGray;
else if (item.StationType == StationType.Charger1 || item.StationType == StationType.Charger2)
else if (item.StationType == Station.Charger)
foreColor = Color.Red;
else
foreColor = Color.DarkGreen;
@@ -945,13 +968,21 @@ namespace AGVMapEditor.Forms
_mapCanvas?.HighlightConnection(connectionInfo.FromNodeId, connectionInfo.ToNodeId);
// 연결된 노드들을 맵에서 하이라이트 표시 (선택적)
var fromNode = this._mapCanvas.Nodes.FirstOrDefault(n => n.Id == connectionInfo.FromNodeId);
if (fromNode != null)
{
_selectedNode = fromNode;
UpdateNodeProperties();
_mapCanvas?.Invalidate();
}
//var fromNode = this._mapCanvas.Nodes.FirstOrDefault(n => n.Id == connectionInfo.FromNodeId);
//if (fromNode != null)
//{
// if (_selectedNode != fromNode)
// {
// _selectedNode = fromNode;
// _mapCanvas.SelectedNode = fromNode; // 캔버스 선택 상태 동기화
// // 속성창 업데이트 (리스트 리프레시 포함)
// // 주의: RefreshMagnetDirectionList()가 호출되어도 lstNodeConnection에는 영향이 없으므로 안전함
// UpdateNodeProperties();
// _mapCanvas?.Invalidate();
// }
//}
}
else
{
@@ -1303,9 +1334,9 @@ namespace AGVMapEditor.Forms
{
foreach (var node in this._mapCanvas.Nodes)
{
node.CanTurnLeft = true;
node.CanTurnRight = true;
node.DisableCross = false;
node.CanTurnLeft = false;
node.CanTurnRight = false;
node.DisableCross = true;
node.ModifiedDate = DateTime.Now;
}
@@ -1367,6 +1398,9 @@ namespace AGVMapEditor.Forms
private void RefreshMagnetDirectionList()
{
// 이벤트 임시 제거 (DataSource 변경 시 불필요한 이벤트 발생 방지)
lstMagnetDirection.SelectedIndexChanged -= LstMagnetDirection_SelectedIndexChanged;
// 현재 선택된 항목 기억
int selectedIndex = lstMagnetDirection.SelectedIndex;
@@ -1374,7 +1408,12 @@ namespace AGVMapEditor.Forms
lstMagnetDirection.DataSource = null;
lstMagnetDirection.Items.Clear();
if (this._mapCanvas.Nodes == null) return;
if (this._mapCanvas.Nodes == null)
{
// 이벤트 다시 연결 (빠른 리턴 시에도 연결 필요)
lstMagnetDirection.SelectedIndexChanged += LstMagnetDirection_SelectedIndexChanged;
return;
}
var directions = new List<MagnetDirectionInfo>();
@@ -1410,8 +1449,7 @@ namespace AGVMapEditor.Forms
lstMagnetDirection.DataSource = directions;
}
// 이벤트 연결
lstMagnetDirection.SelectedIndexChanged -= LstMagnetDirection_SelectedIndexChanged;
// 이벤트 다시 연결
lstMagnetDirection.SelectedIndexChanged += LstMagnetDirection_SelectedIndexChanged;
lstMagnetDirection.DoubleClick -= LstMagnetDirection_DoubleClick;
@@ -1419,9 +1457,17 @@ namespace AGVMapEditor.Forms
// 선택 항목 복원 (가능한 경우) -> 선택된 객체가 다르게 생성되므로 인덱스로 복원 시도
if (selectedIndex >= 0 && selectedIndex < lstMagnetDirection.Items.Count)
{
try
{
lstMagnetDirection.SelectedIndex = selectedIndex;
}
catch (Exception ex)
{
}
}
}
private void LstMagnetDirection_SelectedIndexChanged(object sender, EventArgs e)
@@ -1430,6 +1476,44 @@ namespace AGVMapEditor.Forms
{
// 버튼 상태 업데이트
UpdateDirectionButtons(info);
// 캔버스에서 해당 연결선 강조 표시
if (info.FromNode != null && info.ToNode != null)
{
_mapCanvas.HighlightConnection(info.FromNode.Id, info.ToNode.Id);
// FromNode 선택 (속성창 갱신 루프 방지 위해 _propertyGrid 직접 설정 고려)
// 하지만 _selectedNode 변경 시 RefreshMagnetDirectionList()가 호출되어 리스트가 재생성되면 선택이 풀릴 수 있음
// 따라서 여기서는 캔버스 상의 선택 표시만 변경하고, 전체 속성 업데이트(리스트 리프레시 포함)는 건너뛰거나
// 리스트 리프레시 로직에서 선택 상태 유지를 보완해야 함.
// 일단 _selectedNode를 변경하되, RefreshMagnetDirectionList에서 선택 인덱스 복원을 하므로 괜찮을 것으로 예상됨.
// 만약 깜빡임이나 끊김이 심하면 UpdateNodeProperties 내의 RefreshMagnetDirectionList 호출을 조건부로 변경해야 함.
if (_selectedNode != info.FromNode)
{
var prevSelected = _selectedNode;
_selectedNode = info.FromNode;
// _mapCanvas.SelectedNode 설정 (이것만으로는 PropertyGrid 갱신 안됨)
_mapCanvas.SelectedNode = info.FromNode;
// PropertyGrid 갱신 (리스트 리프레시 포함)
// 주의: 여기서 UpdateNodeProperties()를 부르면 리스트가 다시 그려지면서 선택 이벤트가 다시 발생할 수 있음.
// 하지만 인덱스 복원 로직이 있으므로 무한루프는 아닐 수 있으나, 비효율적임.
// 해결책: 리스트 리프레시 없이 속성창만 갱신
_propertyGrid.SelectedObject = _selectedNode;
UpdateImageEditButton();
// 캔버스 다시 그리기
_mapCanvas.Invalidate();
}
}
}
else
{
_mapCanvas.ClearHighlightedConnection();
}
}
@@ -1673,5 +1757,156 @@ namespace AGVMapEditor.Forms
// 현재 선택된 노드의 속성창 및 리스트 갱신
UpdateNodeProperties();
}
private void btAddMagnet_Click(object sender, EventArgs e)
{
// 마그넷 추가
var result = MessageBox.Show("곡선 마그넷(Bezier)을 추가하시겠습니까?\n(예: 베지어 곡선, 아니오: 직선, 취소: 중단)",
"마그넷 타입 선택", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (result == DialogResult.Cancel) return;
bool isBezier = (result == DialogResult.Yes);
// 화면 중앙 좌표 계산 (World Coordinate)
float zoom = _mapCanvas.ZoomFactor;
PointF pan = _mapCanvas.PanOffset;
float worldCX = (_mapCanvas.Width / 2f) / zoom - pan.X;
float worldCY = (_mapCanvas.Height / 2f) / zoom - pan.Y;
// 고유 ID 생성
string id = _mapCanvas.GenerateUniqueNodeId();
var magnet = new MapMagnet { Id = id };
// 점 생성 시 정규화(Snap) 처리
int cx = (int)worldCX;
int cy = (int)worldCY;
magnet.StartPoint = new Point(cx - 50, cy);
magnet.EndPoint = new Point(cx + 50, cy);
if (isBezier)
{
magnet.ControlPoint = new MapMagnet.MagnetPoint { X = cx, Y = cy - 50 };
}
// 캔버스에 추가
_mapCanvas.Magnets.Add(magnet);
_hasChanges = true;
UpdateTitle();
RefreshMapCanvas();
RefreshNodeList();
RefreshMagnetList(); // 추가
// 추가된 마그넷 선택
//_mapCanvas.SelectedNode = magnet;
UpdateNodeProperties();
}
private void btDelMagnet_Click(object sender, EventArgs e)
{
//선택한 마그넷라인을 삭제 (삭제 후 맵에 바로 반영되도록 업데이트필요)
if (lstMagnet.SelectedItem is MapMagnet magnet)
{
_mapCanvas.RemoveMagnet(magnet);
RefreshMagnetList();
}
}
private void RefreshMagnetList()
{
lstMagnet.DataSource = null;
lstMagnet.Items.Clear();
if (_mapCanvas.Magnets != null && _mapCanvas.Magnets.Count > 0)
{
lstMagnet.DataSource = _mapCanvas.Magnets;
}
// 이벤트 연결
lstMagnet.SelectedIndexChanged -= LstMagnet_SelectedIndexChanged;
lstMagnet.SelectedIndexChanged += LstMagnet_SelectedIndexChanged;
lstMagnet.DoubleClick -= LstMagnet_DoubleClick;
lstMagnet.DoubleClick += LstMagnet_DoubleClick;
lstMagnet.DrawMode = DrawMode.OwnerDrawFixed;
lstMagnet.DrawItem -= LstMagnet_DrawItem;
lstMagnet.DrawItem += LstMagnet_DrawItem;
}
private void LstMagnet_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
if (e.Index >= 0 && e.Index < lstMagnet.Items.Count)
{
var magnet = lstMagnet.Items[e.Index] as MapMagnet;
if (magnet != null)
{
Brush brush = Brushes.Black;
if (magnet.ControlPoint != null) // Curve
{
brush = Brushes.Blue; // Curve는 파란색
}
// 선택된 항목은 흰색 글씨 (배경이 파란색이므로)
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{
brush = Brushes.White;
}
e.Graphics.DrawString(magnet.ToString(), e.Font, brush, e.Bounds);
}
}
e.DrawFocusRectangle();
}
private void LstMagnet_SelectedIndexChanged(object sender, EventArgs e)
{
if (lstMagnet.SelectedItem is MapMagnet magnet)
{
_mapCanvas.SelectedNode = magnet;
//UpdateNodeProperties(); // SelectedNode setter에서 Invalidate 호출됨
}
}
private void LstMagnet_DoubleClick(object sender, EventArgs e)
{
if (lstMagnet.SelectedItem is MapMagnet magnet)
{
_mapCanvas.PanTo(magnet.Position);
}
}
private void btnAddNode_ButtonClick(object sender, EventArgs e)
{
}
private void btnAddNode_BackColorChanged(object sender, EventArgs e)
{
}
private void btnDeleteConnection_Click(object sender, EventArgs e)
{
_mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.DeleteConnection;
}
private void btnConnDir_Click(object sender, EventArgs e)
{
//방향연결(노드연결과 유사), 두 노드간의 방향을 생성한다 기본값 straight
_mapCanvas.CurrentEditMode = UnifiedAGVCanvas.EditMode.ConnectDirection;
}
private void toolStripButton3_Click_1(object sender, EventArgs e)
{
RefreshMagnetList();
}
}
}

View File

@@ -123,7 +123,49 @@
<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="toolStrip4.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 56</value>
</metadata>
<metadata name="toolStrip5.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>123, 56</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="btDelMagnet.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>
<data name="toolStripButton3.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>
<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
@@ -187,21 +229,18 @@
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>
<data name="btnSelect.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHrSURBVDhPldBLaBNBHMfx/0kUVBBJ0lxWPIhihBJKyAqS
pHkQIS+9hXg3RhQviicrITnmJqFnQQ8RqiamRqkhj6VCQtuIQaVQc5di3d3s61Dy0w002KnU9nP67+x8
h2GIDmD0kT+mLk/fZNf3pQkznCrM3DFnZflSRG05euast7izcpM72GGqMP1ZFRw1tXm+qq9dg9LiHgwb
dnFYP51i9/6T0r4wp39Kwfh2F8bGI2irEYjvTmo/Gpbj7N4JpXNxShUcdbV1DvpaHMb3HNrP4uiVb2Cj
cQtadxbSh6OQ3tM82+6iNLk5rXcd7ecJGIaB0WiE1dcp6F9v41eNvmxV6QzbTMjtKYtct9Wi0Si63S50
XUe/30fjaQTG+n1IVRpKb4lnuzFtyc4Nl06VE4kE0uk0CoUCSqUSqvOzMNYfYnORtqVFWhEr9JhtJ+Lx
+DjmeR5+vx+xWAzqSgRy3Q65dgJbFeLYZmIndrvd8Pl8sFqt5pWfbL6hbalCl6Uy9cSXlGG7sWQyiXw+
P469Xi8sFgvMdblCV6RXVDNnvKAjPxfoKttSOBxGLpfbE+8QFyj09/cugUAA2WwWLpcLHo9nT7yvTCaD
wWAAp9OJUCh0uNhkHtDpdFAsFscPxv7/r2AweM+8ts1mO3z8x29KrQsZMgRtMAAAAABJRU5ErkJggg==
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHsSURBVDhPldBLaBNBHMfx/0kUVBBJ0lxWPIhihBJKyAqS
pHkQIS+9hXg3RhQviicrITnmJqFnQQ8RqiamRqkhj6VCQtuIQaVQc64H6+5mX4eSn26gwU6ltp/Tf2fn
OwxDdACjj/wxdXn6Jru+L02Y4VRh5o45K8uXImrL0TNnvcWdlZvcwQ5ThenPquCoqc3zVX3tGpQW92DY
sIvD+ukUu/eflPaFOf1TCsa3uzA2HkFbjUB8d1L70bAcZ/dOKJ2LU6rgqKutc9DX4jC+59B+FkevfAMb
jVvQurOQPhyF9J7m2XYXpcnNab3raD9PwDAMjEYjrL5OQf96G79q9GWrSmfYZkJuT1nkuq0WjUbR7Xah
6zr6/T4aTyMw1u9DqtJQeks8241pS3ZuuHSqnEgkkE6nUSgUUCqVUJ2fhbH+EJuLtC0t0opYocdsOxGP
x8cxz/Pw+/2IxWJQVyKQ63bItRPYqhDHNhM7sdvths/ng9VqNa/8ZPMNbUsVuiyVqSe+pAzbjSWTSeTz
+XHs9XphsVhgrssVuiK9opo54wUd+blAV9mWwuEwcrncnniHuEChv793CQQCyGazcLlc8Hg8e+J9ZTIZ
DAYDOJ1OhEKhw8Um84BOp4NisTh+MPb/fwWDwXvmtW022+HjP34DP4sLE797GZoAAAAASUVORK5CYII=
</value>
</data>
<data name="btnMove.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
@@ -217,83 +256,83 @@
YIGDKaeH7rEGFFd1IN1M4c5nAYIcIXLXvmW+uOKfXMvpRO9rFnzJi9lqBKPZYVCedzYsH6SQ2l+Eu2SD
bfNyWeHqqhbxahSCGIM2MwSKrYzDWboBx5sxIsP6yvTPH0lk3YoGI9lhaB8NQZO+gl8Dj7SN1tpAvgAA
AABJRU5ErkJggg==
</value>
</data>
<data name="btnAddNode.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHZSURBVDhPnZJda9NwFMb3JbxV/BaD4ufZjcwhejsdiqig
8+1u8w2vUprNrE3axDWmKW1aQ0rbtPaFUkra2paCotWU9YVHzh8SidMVfSCEnHOe33MgZ61araJSqaBc
LqNUKqFYLKJQKMCyLHqfW1sl27axXC5PPb1ej0F0XT8bQslkcByHJXc6HR9CNdM0z4bQyjRMafSdz+et
yWSC+XzO6gQ0DOPvEEr1BlOp1Ekmk3Gm0ylGX7pI2Yes1263kU6n/wyhZG/lxWIBMo+/fsKj6BbuHWxA
sw9Yr9VqQdM0SJIUhJim6Y7HYzY0m80w/NzFbvQK9t5t46V6C4+jWz6k2WwimUwGIblc7pJhGO5oNGJD
H50PuH+4gefHN/FGu4tX6u0ApNFoQJblICSbzYYURXGHwyEbqncLeChs4sXxjg/ZPdpEshRm/VqtBlEU
wXHcL4iu66FEIuEOBoNTkNfv7+CZdA1Pj65jvpixLeLxOCKRyAUfQFJVlUH6/b4PefD2Mp7ErmJf2cH3
H998M8dxFwNmT7IsMwhdIlvXsbCv3MD0xF1t9iSKYigWi7l0id4vJrMkSavNngRBWBcEwaUDq9fr/2b2
xPP8Os/z7n+ZPREkHA6f/73u6SfD/w8v3D5c0gAAAABJRU5ErkJggg==
</value>
</data>
<data name="btnAddLabel.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHJSURBVDhPnZJfa9pgFMb7JXa7sW9RkH2y3awro5dbS7Et
u2vHRsRcBEw0QkTinyhB8e9MonOZ6NRZaME12YzyjPPKm+LcKtsDIbznPc/vOSRnr91uo9VqodFooF6v
o1aroVqtolKp0PvR3i41m02sVqutZzgcMoiu6w9DKJkMg8GAJbuuG0KoZprmwxAamZopjc7lcrkyn88R
BAGrE9AwjL9DKJU35vP5n4VCYeD7Pr59vUNBnbK7fr+PXC73Zwgl85GXyyXIfD31cXbo4Pi5jXxqDen1
eshms1AUZRNimqY3m81Y02KxYMnRlw4uX/fx/tTF+WE3hDiOA03TNiGlUumZYRjedLpusuo3LPnq+DOE
8y9bENu2oarqJqRYLEY0TfMmkwlr6rZuET2w8e7kHhI9cKAr6/tOpwNZliEIwj1E1/VIOp32xuPxFuRD
1MXbox4ujj4iCJZsimQyiXg8/iQEkDKZTCSVSnmj0SiEnL6wcPGqi6uTLr7P/dAsCMLTDTOXqqoMQpvI
PlzzBpdvPuGHH+w2c8myHEkkEh5tIv/FZFYUZbeZS5KkfUmSPFowy7L+zcwliuK+KIref5m5CBKLxR7/
Xuf6BYuvFpozmyYBAAAAAElFTkSuQmCC
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHGSURBVDhPnZJfa9pgFMb7JXa7sm9RkH2y3awro5dbS3Et
u2vHRsRcBEw0gqJxGiUo/q1JdDYVnVoLLbglm1GecV55U5xbZXsghPe85/k9h+TstFotNJtN1Ot11Go1
VKtVVCoVlMtlej/Z2aZGo4HlcrnxDAYDBtE07XEIJZOh3++zZMdxAgjVDMN4HEIjUzOl0blUKpVnsxl8
32d1Auq6/ncIpfLGbDb7M5/P9z3Pw83X78irE3bX6/WQy+X+DKFkPvJisQCZbyce3h3YOHph4XNiBel2
u8hkMlAUZR1iGIY7nU5Z03w+Z8nhVzbO3/Tw8cTB6UEngNi2jVQqtQ4pFovPdV13J5NVk1m7Y8kXR1cQ
Tq83IJZlQVXVdUihUAglk0l3PB6zpk7zHuF9Cx+OHyDhfRuasrpvt9uQZRmCIDxANE0LJRIJdzQabUA+
hR28P+zi7PASvr9gU8TjcUSj0d0AQEqn0wwyHA4DyMlLE2evO7g47uDbzAvMgiA8WzNzqarKILSJ7MM1
7nD+9gt+eP52M5csy6FYLObSJvJfTGZFUbabuSRJ2pMkyaUFM03z38xcoijuiaLo/peZiyCRSOTp73Wu
X1R9FoLvbSO9AAAAAElFTkSuQmCC
</value>
</data>
<data name="btnAddImage.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG7SURBVDhPnZLditpQFIXnJXrb0rcYkD5YL4pMYS7bGUrp
O0TMRUp+hWRs/IkSFDUGfxARR6viRRmkJ+jJYZVzhpPB2o60C0LI3nt9a0P2RRzH6Pf76PV66Ha76HQ6
aLfbaLVa/P3i4pyiKAJj7ORZLBYC4vv+8xCezA3z+Vwkz2azDMJrYRg+D+Er82Gexr+bzWZrt9uBUirq
HBgEwd8hPFUOVqvVfa1WmydJAvrjO2hsi950OkWlUvkzhCfLldM0BTezhw1S6wrp17egsSV6k8kE5XIZ
pmkeQ8IwJNvtVgwdDgeRnJp5MO8D2LdPYNZVBhmPx3Bd9xjSaDTeBEFANpvNI+S+I5LZ3Q1Y5csJZDQa
wXGcY0i9Xs+5rkvW6/UjZBmBGnmwu9sniJkHjXTRHwwGMAwDiqI8QXzfz5VKJbJarU4h/mcw5xo/jWuw
lIotLMtCsVh8lQG4PM/L2bZNlstlBjno78Ds90jcG+zJLjMrivL6yCzlOI6A8EsUkEUP1PsItk/Om6UM
w8jpuk74JcpfzM2maZ43S2madqlpGuEHNhwO/80sparqpaqq5L/MUhxSKBRe/l6X+gWA2x2MFEPZrwAA
AABJRU5ErkJggg==
</value>
</data>
<data name="btnAddNode.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHdSURBVDhPnZLra9NgFMb3T/hV8b8YFP+efZE5RL+qQxEV
dN6+OXfBTynNZtYmbeKSxfSS1pDSNq29UEpJW9tSULT6lvXCI+8LicTpij4QQs45z+85kLNSqVRQLpdR
KpVQLBZRKBSQz+dh2zZ9X1hZJsdxsFgszjzdbpdBDMM4H0KTqcF1XZbcbrd9CK1ZlnU+hK5Mh2ka/c7l
cvZ4PMZsNmN1CjRN8+8QmuoNplKp03Q67U4mEwy/dPDeOWS9VquFZDL5ZwhN9laez+eg5tHXT3ga3cDD
gzXozgHrNZtN6LoOSZKCEMuyyGg0YkPT6RSDzx1sRa/h1btb2NXu4ll0w4c0Gg2oqhqEZLPZK6ZpkuFw
yIY+uh/w6HANr4/v4I3+AHvavQCkXq9DluUgJJPJhFRVJYPBgA3VOnk8Edaxc7zpQ7aO1qEWw6xfrVYh
iiI4jvsFMQwjpCgK6ff7ZyD7J/fxUrqBF0c3MZtP2RbxeByRSOSSD6DSNC2USCRIr9fzIY/fXsXz2HVs
K5v4/uObb+Y47nLA7EmWZQahl8jWdW1sK7cxOSXLzZ5EUQzFYjFCL9H7xdQsSdJysydBEFYFQSD0wGq1
2r+ZPfE8v8rzPPkvsycKCYfDF3+ve/oJ+zEPR++RdtEAAAAASUVORK5CYII=
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG3SURBVDhPnZLditpQFIXnJXrb0rcYkD5YL4pMYS7bKaX0
HSLmIiW/ghmNaJSgqDH4g4hYrYoXpUgT9OSwyj7DyWBtR9oFIWTvvb61IfsqiiIMBgP0+330ej10u110
Oh202216P7u6pDAMwTk/e5bLpYB4nvc0hJLJsFgsRPJ8Ps8gVAuC4GkIrUzDlEbfrVarvd/vwRgTdQL6
vv93CKXKwWq1eqjX64skScC+fwOLbNGbzWao1Wp/hlCyXDlNU5CZ/9gitW6QfnkNFlmiN51OUalUYJrm
KSQIgni324mh4/EoklMzD+6+A69+BLduMshkMkG5XD6FNJvNV77vx9vt9gHytSuS+f0deO3zGWQ8HsNx
nFNIo9HIlUqleLPZPEBWIZiRB7//8Agx82ChLvrD4RCGYUBRlEeI53k527bj9Xp9DvE+gTu3+GncgqdM
bGFZForF4osMQHJdV0BWq1UGOepvwO23SMp3OMT7zKwoyssTs5TjOAJClyggyz6Y+x78kFw2SxmGkdN1
PaZLlL+YzKZpXjZLaZp2rWlaTAc2Go3+zSylquq1qqrxf5mlCFIoFJ7/Xpf6BUmpHXRPK0SnAAAAAElF
TkSuQmCC
</value>
</data>
<data name="btnDelete.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVDhP7Y+/TxphGMex4B/QqXQgxqGz/0CHRmw6aRhM
dGjToQ4OujiAdqidOrRhccIEXyYT26EbFmLV4MEdx91xHBCahiLy+zwUFn80oeFr3jdCyKm1f0C/yWd5
83y+7/NYLP/DEggEnISQOCEE/0jB7/dP9QsIITlFEVCt5hm1GuUXo14vMBqNQ+h6Ebp+hExGoSWVwQKj
WMyB56OIRCIMjuMQjUYRi8XA8zzi8ThEUYSiKKzE5/Ndmgp+QBQFJpqlRCIBWZaZrGkpGEblZkGp9BOy
LEEQBCZSSZIkJiWTSaRSKWiahmw2g2azdrOgXM5DVRUm0d+opKoqE9PpNOT1dzh49QTfncPYn3Vgc3G6
05Oxt7eDk5M6Tk8pDbRaOtrt42sM5D9/Qtr9FJdBL7q5EM63liAtjOGL5yVYwX0EXXZcBL3A2iTgeQh8
GEXz4zNsux6hf8bfsj1u63aVrxhMe9UO+m6evTXhCWvlbOMNsGrHb7cFLbcFpXkrQs+tVfPsreFmHr8X
X4906p5RGCvDKMwNYfeF7c+3iQdvzbN3hptxLIed1iJdm27Uk68A8qiqJzQDmt8AAAAASUVORK5CYII=
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVDhP7Y89S1thGIZToz+gk+kg4uDsH3CQJh0VB0EH
pUM7iDh1SNRBnRwqLkKGQvoGnKxDF0lV6gfxJOfk5JyT8xGJlDSmMV+nJ5osVguR3OV9MRKOae0P8IZr
eXmu+30eh+MpLMFg0E0IiRFC8J9kAoHAyH0BISSlKAIKhTSjWKR8Z5RKGUa5fAbTzMI0fyCZVGhJvrXA
ymZT4PkIwuEwg+M4RCIRRKNR8DyPWCwGURShKAor8fv9N7aCU4iiwES7FI/HIcsyk3Vdg2XlHxbkct8g
yxIEQWAilSRJYlIikYCmadB1HScnSVQqxYcF5+dpqKrCJPoblVRVZaJhGJA/LOJ4qh/77i4cTfRgY2as
3pRxePgVFxclXF5SyqhWTdRqP++wkP60CsM7iJvQGhqpXfzafAdpdgBbvkmwgscIjbpwHVoD1ocB33Ng
pQ+V90P4MtqN+zP+le2XnY2G8hmtqS25QN/ts22z53Hmrz6+AZZc+O11oOp1IDftxO4rZ8E+2zbc+Itl
8XVvveTrgzXfhczbZzjwdN7ueDoW7LN/DTfeM7fndmbp2nSjpvwHq8ip+rkEjbgAAAAASUVORK5CYII=
</value>
</data>
<data name="btnEditImage.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAL0SURBVDhPhdLdT1N3HMdx/oPdL16ZbDfGuJtll4vbfNrM
3JxzOGMbQ3SZYzHLdMUyJuL0CB3lQCFAC5xVfGCtyqQIOGzVItOKBwpFfBgOkedA7WlP258E8b202Tol
e/gk36vf9/f6Jb/vN0vx9JYqbnVadqua1fn/JbtUzXFOLcv6K3UtN2cmJief6fE48YT4z5rTBTORGNWn
b0QyQOrlmB6nqnWM0tYghRd+wnnLhqv/e04Fi6j0W/i8wc7X9V2Y6oeYjQlkd5+WAcqcqpbSqy+MIbV3
4Oyx0TSwD0fPZ1TfyKEmsAdL52H21J7ErNxhRvsHIJYQ1LaPU9jWyOlgETWBXZT/ugOLfxvS1Wys/q8w
VvxAwfF7TGtJZHfvi4CWEDg6JjjocfKjWoDcbUC6spVDvs18d2kzkjcXg1yM0tTI3ZPZ/Hb+CMH6tQSr
VhjSQCQuqL84ieRpw+Y/Rll3DoW+jzD/somD3my+/TmPquP7mfKZ0AZaQZ8gMnAGf8n66TTwWBconVPY
2vrJcylILXsp8e5C6txJvvsLrA25zA4WMj/WwtQVC8nQOZ4+vEZf7W6RlZptOCZweqfTSIUnyDdFBo5a
30GyrKauYj3hwQIWk9dIPsglfPNL7jTmELR/MhewffBqGpiLCsyu9zE1bWTfqXex579OSNnC4Ik1PA4d
YFFcJzFsRDzaTmzITKhq47O+sjWvpT+x1HlLC0cF/uHLmeoONdN1fi9TPaY/LxsQo58SHcznQe17KMpZ
PTMFaxpIvgD4LhczdHE/i0k/YiSHJ492oIUOcL9mHeOjI8iu58ZY6VZHw5EoUV0QjT+hz9fI7TYz/e0y
44GPSYxsJxzMY7juQ+Ymfmc2vcqBv1fZ0ayW2M/0dqWWIyW7it+G2EPu2rfgM79Md80GvEffXGxQPHrq
vPxsr+ZoVuUMsDSHja8szF+vZD5QTuDIak4Yl+kdphWrlvb9aza98ZKQjMsX2o9tWOgsfetqa97K5Ut7
ns8f9tyLJQW2uh8AAAAASUVORK5CYII=
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAALySURBVDhPhdLfT1tlHMdx/gPvjYnJLrxZjF7otZk63XRx
OjdFl7UxZBonZjFulhVxyNzOoFLOKAi0wLHDbdhuw9EOmNhuK0PWsQMHimwqk0FBIND1tKftM4Lsbdpo
sxF/fJLv1fN9Xk/yfL8Fim+oWvGq87JX1e3u/y/Zo+qus2pNwd9p7ry2MB2N3jNSKVJp8Z+1ZAgW4kka
Tg3E80D25aSRot4fpdqvUX7+W9zXHXhGvuCkVkFdyMb7rU4+bunD0jLOYlIge4f1PFDjVvWs3nA+itTd
g3vQQfvoPlyD79FwtYjG8B5svYfY03QCq3KDBf0fgGRa0NQ9Q3lXG6e0ChrDuzn24y5sobeQLhdiD32E
ufZLyo7/zLyeQfYOPQjoaYGrZ5aDPjdfq2XI/SakS2/weXAbn/2wDSlQjEmuRGlv4+aJQn49dxit5QW0
+vWmHBBPCVou/I7k68IROkpNfxHlwdexfr+Vg4FCPv2uhPrj+5kLWtBH/WDMEh89Tahq03wOuGMIlN45
HF0jlHgUpM69VAV2I/W+Q6n3A+ytxSyOlbMc7WTuko1M5Cx/3L7C8FfvioLsbGNJgTswn0NqfRqfVJg4
Yn8eybaB5tpNxMbKWM1cIXOrmNi1D7nRVoTmfHMp7Hj1sRywlBBYPa9gad/CvpMv4Sx9moiynbFvNnIn
coBVMUB6woyY3kly3IpWu+XecM3GJ3OfWO2+rscSgtDExXz1RzroO7eXuUHLX5dNiKm3SYyVcqvpZRTl
jJGfgj0HZB4AghcrGb+wn9VMCDFZxN3pXeiRA/zS+CIzU5PInvvGWOdVp2LxBAlDkEjdZTjYxk9dVka6
ZWbCO0hP7iSmlTDR/BpLs7+xuHaVXR1qlfP0UF92ObKyp/I5SN7mpnM7QevD9DduJnDkmdVWxWdkz+Uz
Q7qrQ5XzwNocMq9bWR6oYzl8jPDhDbjNjxg9lvVPrO3712x96iEhmR9d8R/dvNJb/exlf8nj69b23J8/
AbuKiwBr5ZOIAAAAAElFTkSuQmCC
</value>
</data>
<data name="btnConnect.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="btnConnNode.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29m
dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHrSURBVDhPY/j//z8DJRhDgFSMIUAqxhAgFcMZdnZ2
@@ -308,19 +347,19 @@
gg==
</value>
</data>
<data name="btnDeleteConnection.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="btnConnDir.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHvSURBVDhP7Y7Ni1JhGMVvXadgWrWzRQyzTEFyFa7U0Wvg
R3A3KgS1SLFeSbCPGe0uHFyMIEzgBXOVECi00VbOKGWg4yYiW4i1ujNIEVKkQVPaZJ7hGUhMnP+gAy88
nPM7h5fj/msiQRDOMMbux2KxXjabhSRJHcbYJcaYWpIkhTzKiCH2n7JGoznlcDiSqVQK3W4XiqKgVqtR
YVeSpHqr1RqS12g0QAyx1JkM6PX6K6FQ6Fu73e55vd4tQRBGfr8fsiwjGo2CbvIoy+fzHWKpMz2QjMfj
A1mWA06nc9FgMHyvVqtoNpuo1+soFAogjzJiiKXOZECn090KBAL9dDp9TxTFitlsPrDZbBBF8ejRTR5l
xBBLncmAVqu94HK53icSiX4ul/taLBaRyWQQDocRiUSO7vIGw0tx6c+LlQU8sy0ePDGdfjgZ4DiONxqN
F+12+57P59sPBoMDxtgvt9t9zePxWB5dNQ3f3jVgUNrE+F0ZP57eweugZvTcoro9PXKstq288rO0Ccgu
YO0ssLGML0kTSmZ+d5adq60V1Xj8pohp9WNqkD/LzlXFyn/Yf3wDiKkxXOXQW+XQucmjLPAfZ9m52vGc
W391fen3p7VlfI4uQPGdQPWyarRtPflglj1WO57zkYqF36Nv04/+lg8BALcaCRX7gQ0AAAAASUVORK5C
YII=
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29m
dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHrSURBVDhPY/j//z8DJRhDgFSMIUAqxhAgFcMZdnZ2
3FlZWaWtra3v5s2b97+mpuZhTk6OeU5OjkRNTc1dkBhIDqQGpBbFACMjIzYfH5+uiRMn/n/x4sX/u3fv
/j948OD/xsbGe9XV1Ydu3rz5AyR25MiR/yA1ILUgPXADDA0N/YqLiz9cvXr1XURExDZvb+8/qamp/ydN
mvS/srLyP4gNEgPJrVix4iFILUgPsgu6mpqavk+ePDnd39+fy97e/vPevXv/nzt37v+hQ4f+r1279j9I
DCQHUgNSC9IDN0BXVzczPT39/bRp00qCgoJ2Ojo6/nJzc/sfGBgIxiA2SAwkB1IDUgvSAzdAU1NT09fX
93pvb+/7VatWvV23bt3/6dOn/y8sLPxfUVEBZvcvbP1fODXmX1qf//+IJse/Lrm6E+EGqKmpMdvb2xt4
eXndT0lJ+ZKdnf09Ozv7Z3h4eFx4eLhzZm3cz8bVif+3XJn6/8KzXf/7d2f9D+/X/W+eLdmDEa/YcGy7
y/eNlyf833ht0n8Q6NmT+r9/TzrIgO8YirFhn2rD/9uuzAFrhoFNl6aCDMBUjA1b5kh/796V9L99VwJY
c/vOBNJcYJ4t2RLco/G/d1cK2GYQDeITHQZQQzrMsyU/gZwNpTtA4gBRO5Y8lpxI5AAAAABJRU5ErkJg
gg==
</value>
</data>
<data name="btnToggleGrid.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
@@ -335,18 +374,33 @@
<data name="btnFitMap.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKYSURBVDhPhZBfSFNRHMfvY0RPEfQSFD2tngqh9WBZmFOX
ess2de2Pii7LJAsjHN1ScU4yc0WWzB4m2KZmdMkSV7qZ889tuHvuMlKocJ47aMWI9FwrCC4njrqX66Iv
nJfD9/P9fX8/itrQrNek5vssLOgrTYT6LfJbr0mecZsTXHcxy3WeUSd9KSV4zVbhcXmc77WA2Z6zTNht
UE27ClVct47hXHow1VUcDzpPWZXcmsjkddjo4KNoH1hCOgClWkGUaiJwJX8OLu8N3qUdk046Hrit3dyE
91pYMjkcRSoA0QUAkU0Q0TUgrl4VoHRFECWjEP2xZ6KDBv5WLavkKeAtTcz2lDCRGCoEENWvw1LdBlwD
RFQNoHTC36JlfC35CSVPhfpMcthlUAmidDE5NbkCaSRAVEVa+Bo0qkBbrqzkKc5jlMnBiJGAYEm6RMJ4
iM6v/YmoMgKlYhLgd2g2B0y7jQnuoY7hxdWc9Raoeg2OISsQUYUAV8p4ER0duZ7F+GyazSvMdOnYmU49
IIcSoFS0AVYK4ko5gQFE9LvYz10vmnJ/D9dnhpQ8FXQWqKce0PE3HbSDX/y1W4hJx0llAUr6CETpBPa3
03/mBmtxoO4YflabblBmUONtBdagk477b50Eo83ZDNmXvBFbJjPenifPv7ThWNiFF6fu4LFmGj+vUO9U
ZlABh1b92q5lfS2aBDnWmD1LHrqZvTzalIc/jbfirx968bcFD/442ogHLUdkb6qQVGIvZ5gnOkpwdNqJ
4+978BJ3H4celWNHlurz0Lm0rUp/Sj2tTjeP2U/jheEbeH64AU/eK8KDVQe/P9Hv36b0/lMD1kNmjykN
v2rMwf1l6i8eQ9oOpee/Gqg4vL275IDdXZqxJfn3F2EzpMPWLB83AAAAAElFTkSuQmCC
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKXSURBVDhPhZBfSFNRHMfvY0RPEfQSFD2tngqh9WBZmVOX
ess23ZrzD7r+mGRhhKNbKs6JVq7IktnDBNvUjFaSuNTNnJtD3D1nGSlUOM8dtGJEeq4VBJcTR93LddEX
zsvh+/n+vr8fw2xo1lWi5PtK3aCvLDHdb5CCLr0UdBgToe5id6jzrDLpSynoMprg04o431sKZnvOcWGH
XhG0FypC3RouZNeCQFdx3G87bZJza6KT12GDlY/ifWAJawASa6Eg1kTQSv4cWt7rv89ap2xs3HdHvbkJ
7yp108nhKFYAhC8BhM1QwDeAsHodIvEaFEQDjP7YM9nBAm+r2i3nGeAqS8z26LhIDBcChOvXYbFuA64B
Aq4GSDzpbVFznpb8hJxnpvv0UtiuV0BBvJycmlyBNoIIX6AtPA0qha9dJcl5JuDUSfRg1EhBsCReoWE8
whfX/gRcFUFiMQ3wWjM3BwQdhkTosYbjhdWc9Ra4eg2OYRMQcCVEK+W8gI+O3MziPGZVihW6NO7pTi2g
h4JILNoAq6CwUkFhgDD7LvZz18um3N/D9Zkzcp7x2wqUgUds/G0Ha+UXf+2GMfE4rQyRqI0gnE7h0ba8
P3ODtcRXd4y8qE3XyzOYifYCk9/Gxr1tp8BYczZH96VvxJzJTdzNleZfm0ksbCeLgXtkvJklryqVO+UZ
jM+qVo5a1G5PiypBjzVuOSEN3c5eHmvKI58mWsnXD73k24KTfBxrJIOGI5IrVUgqua9mGCc7dCQatJH4
+x6yFHpIZp5UEGuW4vPQ+bStcn9KPa9ON45bzpCF4VtkfriBTD0oIoMXDn5/pt2/Te79pwZMh4zOkjTy
pjGH9Jcrvzj1aTvknv9qoPLw9m7dAYujLGNL8u8v3CKkjDkyCW0AAAAASUVORK5CYII=
</value>
</data>
<data name="btAddMagnet.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="toolStrip2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">

View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("26.02.10.0900")]
[assembly: AssemblyFileVersion("26.02.10.0900")]

View File

@@ -49,7 +49,7 @@
<ItemGroup>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\HMI\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -84,6 +84,7 @@
<Compile Include="Models\NodeBase.cs" />
<Compile Include="Models\MapLabel.cs" />
<Compile Include="Models\MapImage.cs" />
<Compile Include="PathFinding\Core\Utility.cs" />
<Compile Include="PathFinding\Planning\AGVPathfinder.cs" />
<Compile Include="PathFinding\Planning\DirectionChangePlanner.cs" />
<Compile Include="PathFinding\Planning\DirectionalPathfinder.cs" />
@@ -93,7 +94,7 @@
<Compile Include="PathFinding\Core\PathNode.cs" />
<Compile Include="PathFinding\Core\AStarPathfinder.cs" />
<Compile Include="PathFinding\Core\AGVPathResult.cs" />
<Compile Include="PathFinding\Planning\NodeMotorInfo.cs" />
<Compile Include="Models\NodeMotorInfo.cs" />
<Compile Include="Controls\UnifiedAGVCanvas.cs">
<SubType>UserControl</SubType>
</Compile>

View File

@@ -90,7 +90,7 @@ namespace AGVNavigationCore.Controls
}
// UI 정보 그리기 (변환 없이)
if (_showGrid)
//if (_showGrid)
DrawUIInfo(g);
// 동기화 화면 그리기 (변환 없이, 최상위)
@@ -100,11 +100,13 @@ namespace AGVNavigationCore.Controls
}
//예측문자는 디버깅시에만 표시한다.
if (string.IsNullOrEmpty(PredictMessage) == false && System.Diagnostics.Debugger.IsAttached)
if (string.IsNullOrEmpty(PredictMessage) == false)
{
g.DrawString(this.PredictMessage, this.Font, Brushes.White, 10, 100);
}
DrawSystemMessage(g);
DrawAlertMessage(g);
DrawTagIgnoreMessage(g);
}
@@ -184,7 +186,7 @@ namespace AGVNavigationCore.Controls
var textPoint = new PointF((float)(boxX - textSize.Width / 2), (float)(boxY - textSize.Height / 2));
//편집모드에서만 글자를 표시한다.
if(Mode == CanvasMode.Edit)
if (Mode == CanvasMode.Edit)
{
// 텍스트 배경 (반투명 - 선이 은은하게 보이도록 투명도 조절하거나, 가독성을 위해 불투명하게 처리)
// 사용자가 "박스를 가로지르는" 느낌을 원했으므로 선이 보여야 함. 하지만 텍스트 가독성도 필요.
@@ -207,17 +209,167 @@ namespace AGVNavigationCore.Controls
}
}
void DrawAlertMessage(Graphics g)
void DrawSystemMessage(Graphics g)
{
if (showalert == false) return;
if (!showalertsystem || String.IsNullOrEmpty(this._systemmesage)) return;
//상단에 경고 메세지를 추가한다
if (String.IsNullOrEmpty(this._alertmesage)) return;
// 상단 중앙에 반투명 빨간색 배경 바 표시
int barHeight = 40;
int barWidth = Math.Min(600, this.Width - 40); // 최대 600px, 좌우 여백 20px
int barX = (this.Width - barWidth) / 2;
int barY = 20;
// 둥근 사각형 배경
using (var path = new GraphicsPath())
{
int radius = 10;
path.AddArc(barX, barY, radius * 2, radius * 2, 180, 90);
path.AddArc(barX + barWidth - radius * 2, barY, radius * 2, radius * 2, 270, 90);
path.AddArc(barX + barWidth - radius * 2, barY + barHeight - radius * 2, radius * 2, radius * 2, 0, 90);
path.AddArc(barX, barY + barHeight - radius * 2, radius * 2, radius * 2, 90, 90);
path.CloseFigure();
g.DrawString(this._alertmesage, this.Font, Brushes.Gold, 10, 10);
using (var brush = new SolidBrush(Color.FromArgb(200, 255, 69, 58))) // 진한 붉은색 (Apple Red 계열)
{
g.FillPath(brush, path);
}
using (var pen = new Pen(Color.FromArgb(255, 255, 255), 2))
{
g.DrawPath(pen, path);
}
}
// 텍스트 깜박임 효과 (배경은 유지하고 텍스트만 깜박임)
using (var font = new Font("Malgun Gothic", 12, FontStyle.Bold))
using (var brush = new SolidBrush(Color.White))
{
var textSize = g.MeasureString(_systemmesage, font);
g.DrawString(_systemmesage, font, brush,
barX + (barWidth - textSize.Width) / 2,
barY + (barHeight - textSize.Height) / 2);
}
// 경고 아이콘 그리기 (왼쪽)
// 간단한 느낌표 아이콘
int iconX = barX + 15;
int iconY = barY + barHeight / 2;
using (var brush = new SolidBrush(Color.White))
{
g.FillEllipse(brush, iconX - 2, iconY - 8, 4, 16); // body
g.FillEllipse(brush, iconX - 2, iconY + 10, 4, 4); // dot
}
}
void DrawAlertMessage(Graphics g)
{
if (!showinfo || String.IsNullOrEmpty(this._infomessage)) return;
// 상단 중앙에 반투명 빨간색 배경 바 표시
int barHeight = 40;
int barWidth = Math.Min(600, this.Width - 40); // 최대 600px, 좌우 여백 20px
int barX = (this.Width - barWidth) / 2;
int barY = 20+50;
// 둥근 사각형 배경
using (var path = new GraphicsPath())
{
int radius = 10;
path.AddArc(barX, barY, radius * 2, radius * 2, 180, 90);
path.AddArc(barX + barWidth - radius * 2, barY, radius * 2, radius * 2, 270, 90);
path.AddArc(barX + barWidth - radius * 2, barY + barHeight - radius * 2, radius * 2, radius * 2, 0, 90);
path.AddArc(barX, barY + barHeight - radius * 2, radius * 2, radius * 2, 90, 90);
path.CloseFigure();
using (var brush = new SolidBrush(Color.FromArgb(255, Color.Lime)))
{
g.FillPath(brush, path);
}
using (var pen = new Pen(Color.FromArgb(255, 255, 255), 2))
{
g.DrawPath(pen, path);
}
}
// 텍스트 깜박임 효과 (배경은 유지하고 텍스트만 깜박임)
using (var font = new Font("Malgun Gothic", 12, FontStyle.Bold))
using (var brush = new SolidBrush(Color.Black))
{
var textSize = g.MeasureString(_infomessage, font);
g.DrawString(_infomessage, font, brush,
barX + (barWidth - textSize.Width) / 2,
barY + (barHeight - textSize.Height) / 2);
}
// 경고 아이콘 그리기 (왼쪽)
// 간단한 느낌표 아이콘
int iconX = barX + 15;
int iconY = barY + barHeight / 2;
using (var brush = new SolidBrush(Color.Black))
{
g.FillEllipse(brush, iconX - 2, iconY - 8, 4, 16); // body
g.FillEllipse(brush, iconX - 2, iconY + 10, 4, 4); // dot
}
}
void DrawTagIgnoreMessage(Graphics g)
{
if (!showtagigreno || String.IsNullOrEmpty(this._tagignoreMessage)) return;
var ts = DateTime.Now - tagignoretime;
if (ts.TotalSeconds > 5) return;
// 상단 중앙에 반투명 빨간색 배경 바 표시
int barHeight = 40;
int barWidth = Math.Min(600, this.Width - 40); // 최대 600px, 좌우 여백 20px
int barX = (this.Width - barWidth) / 2;
int barY = this.Height - barHeight-20;
// 둥근 사각형 배경
using (var path = new GraphicsPath())
{
int radius = 10;
path.AddArc(barX, barY, radius * 2, radius * 2, 180, 90);
path.AddArc(barX + barWidth - radius * 2, barY, radius * 2, radius * 2, 270, 90);
path.AddArc(barX + barWidth - radius * 2, barY + barHeight - radius * 2, radius * 2, radius * 2, 0, 90);
path.AddArc(barX, barY + barHeight - radius * 2, radius * 2, radius * 2, 90, 90);
path.CloseFigure();
using (var brush = new SolidBrush(Color.FromArgb(255, Color.Violet)))
{
g.FillPath(brush, path);
}
using (var pen = new Pen(Color.FromArgb(255, 255, 255), 2))
{
g.DrawPath(pen, path);
}
}
// 텍스트 깜박임 효과 (배경은 유지하고 텍스트만 깜박임)
using (var font = new Font("Malgun Gothic", 12, FontStyle.Bold))
using (var brush = new SolidBrush(Color.Black))
{
var textSize = g.MeasureString(_tagignoreMessage, font);
g.DrawString(_tagignoreMessage, font, brush,
barX + (barWidth - textSize.Width) / 2,
barY + (barHeight - textSize.Height) / 2);
}
// 경고 아이콘 그리기 (왼쪽)
// 간단한 느낌표 아이콘
int iconX = barX + 15;
int iconY = barY + barHeight / 2;
using (var brush = new SolidBrush(Color.Black))
{
g.FillEllipse(brush, iconX - 2, iconY - 8, 4, 16); // body
g.FillEllipse(brush, iconX - 2, iconY + 10, 4, 4); // dot
}
}
private void DrawSyncScreen(Graphics g)
{
// 반투명 검은색 배경
@@ -330,11 +482,26 @@ namespace AGVNavigationCore.Controls
foreach (var targetNode in node.ConnectedMapNodes)
{
if (targetNode == null) continue;
// 강조된 연결은 나중에 그리기 위해 건너뜀
if (IsConnectionHighlighted(node.Id, targetNode.Id)) continue;
DrawConnection(g, node, targetNode);
}
}
}
// 1.1 강조된 연결 그리기 (항상 위에 표시되도록)
if (_highlightedConnection.HasValue)
{
var n1 = _nodes.FirstOrDefault(n => n.Id == _highlightedConnection.Value.FromNodeId);
var n2 = _nodes.FirstOrDefault(n => n.Id == _highlightedConnection.Value.ToNodeId);
if (n1 != null && n2 != null)
{
DrawConnection(g, n1, n2);
}
}
// 2. 마그넷 그리기 (별도 리스트 사용)
if (_magnets != null)
{
@@ -398,10 +565,17 @@ namespace AGVNavigationCore.Controls
g.DrawLine(_magnetPen, startPoint, endPoint);
}
// 호버된 마그넷 강조
if (magnet == _hoveredNode)
// 호버되거나 선택된 마그넷 강조 (선택: Red, 호버: Orange)
bool isHovered = (magnet == _hoveredNode);
bool isSelected = (magnet == _selectedNode);
if (isHovered || isSelected)
{
using (var highlightPen = new Pen(Color.Orange, 19))
Color highlightColor = isSelected ? Color.Red : Color.Orange;
// 선택된 상태에서 호버되면? -> 선택 색상 우선 (Red) 또는 명확한 구분 필요
// 여기서는 선택이 더 중요하므로 Red 유지
using (var highlightPen = new Pen(highlightColor, 19) { StartCap = LineCap.Round, EndCap = LineCap.Round })
{
if (magnet.ControlPoint != null)
{
@@ -426,16 +600,31 @@ namespace AGVNavigationCore.Controls
g.DrawLine(highlightPen, startPoint, endPoint);
}
}
// Redraw normal to keep it on top? No, highlight is usually outer.
// If I draw highlight AFTER, it covers.
// But DrawMagnet is void. If I draw highlight after, it's fine if I want it to glow.
// Actually _magnetPen is Width 15, very thick.
// If I draw highlight Width 19 *before* normal, it acts as border.
// But this method draws normal first.
// So I should refactor to calculate path first, then draw?
// Or just draw highlight on top with alpha?
// Let's draw highlight on top with non-filled center? No, it's a line.
// I'll draw highlight on top for now, maybe with alpha.
}
// 선택된 마그넷 핸들 그리기
if (magnet == _selectedNode && _canvasMode == CanvasMode.Edit)
{
using (var handleBrush = new SolidBrush(Color.White))
using (var handlePen = new Pen(Color.Black, 1))
{
float size = HANDLE_SIZE / _zoomFactor;
float half = size / 2;
// 시작점, 끝점 핸들
g.FillRectangle(handleBrush, startPoint.X - half, startPoint.Y - half, size, size);
g.DrawRectangle(handlePen, startPoint.X - half, startPoint.Y - half, size, size);
g.FillRectangle(handleBrush, endPoint.X - half, endPoint.Y - half, size, size);
g.DrawRectangle(handlePen, endPoint.X - half, endPoint.Y - half, size, size);
// 제어점 핸들 (곡선일 경우)
if (magnet.ControlPoint != null)
{
var cp = magnet.ControlPoint;
g.FillRectangle(handleBrush, (float)cp.X - half, (float)cp.Y - half, size, size);
g.DrawRectangle(handlePen, (float)cp.X - half, (float)cp.Y - half, size, size);
}
}
}
}
@@ -444,11 +633,10 @@ namespace AGVNavigationCore.Controls
if (_marks == null) return; // _marks 리스트 사용
int sensorSize = 12; // 크기 설정
int lineLength = 20; // 선 길이 설정
int halfLength = lineLength / 2;
foreach (var mark in _marks)
{
int lineLength = (int)mark.Length; // 저장된 길이 사용
int halfLength = lineLength / 2;
Point p = mark.Position;
double radians = mark.Rotation * Math.PI / 180.0;
@@ -470,6 +658,22 @@ namespace AGVNavigationCore.Controls
g.DrawLine(highlightPen, p1, p2);
}
}
// 선택된 마크 핸들 그리기
if (mark == _selectedNode && _canvasMode == CanvasMode.Edit)
{
using (var handleBrush = new SolidBrush(Color.White))
using (var handlePen = new Pen(Color.Black, 1))
{
float size = HANDLE_SIZE / _zoomFactor;
float half = size / 2;
g.FillRectangle(handleBrush, p1.X - half, p1.Y - half, size, size);
g.DrawRectangle(handlePen, p1.X - half, p1.Y - half, size, size);
g.FillRectangle(handleBrush, p2.X - half, p2.Y - half, size, size);
g.DrawRectangle(handlePen, p2.X - half, p2.Y - half, size, size);
}
}
}
}
@@ -776,7 +980,7 @@ namespace AGVNavigationCore.Controls
{
case NodeType.Normal:
var item = _selectedNode as MapNode;
if ( item.StationType == StationType.Charger1 || item.StationType == StationType.Charger2)
if (item.StationType == Station.Charger)
DrawTriangleGhost(g, ghostBrush);
else
DrawPentagonGhost(g, ghostBrush);
@@ -965,17 +1169,16 @@ namespace AGVNavigationCore.Controls
switch (node.StationType)
{
case StationType.Loader:
case StationType.UnLoader:
case StationType.Clearner:
case StationType.Buffer:
case Station.Loder:
case Station.Cleaner:
case Station.Plating:
case Station.Buffer:
DrawPentagonNodeShape(g, node, brush);
break;
case StationType.Charger1:
case StationType.Charger2:
case Station.Charger:
DrawTriangleNodeShape(g, node, brush);
break;
case StationType.Limit:
case Station.Lmt:
DrawRectangleNodeShape(g, node, brush);
break;
default:
@@ -1387,7 +1590,7 @@ namespace AGVNavigationCore.Controls
// 🔥 노드의 폰트 설정 사용 (0 이하일 경우 기본값 7.0f 사용)
var topFont = new Font("Arial", 9, FontStyle.Bold);
var btmFont = new Font("Arial", 12, FontStyle.Bold);
var btmFont = new Font("Arial", node.NodeTextFontSize, FontStyle.Bold);
// 메인 텍스트 크기 측정
var TopSize = g.MeasureString(TopIDText, topFont);
@@ -1413,21 +1616,20 @@ namespace AGVNavigationCore.Controls
Color bgColor = Color.White;
switch (node.StationType)
{
case StationType.Charger1:
case StationType.Charger2:
case Station.Charger:
fgColor = Color.White;
bgColor = Color.Tomato;
break;
case StationType.Buffer:
case Station.Buffer:
fgColor = Color.Black;
bgColor = Color.White;
break;
case StationType.Clearner:
case Station.Plating:
fgColor = Color.Black;
bgColor = Color.DeepSkyBlue;
break;
case StationType.Loader:
case StationType.UnLoader:
case Station.Loder:
case Station.Cleaner:
fgColor = Color.Black;
bgColor = Color.Gold;
break;
@@ -1438,6 +1640,8 @@ namespace AGVNavigationCore.Controls
var rectpaddingx = 4;
var rectpaddingy = 2;
var roundRect = new Rectangle((int)(btmPoint.X - rectpaddingx),
@@ -1458,7 +1662,8 @@ namespace AGVNavigationCore.Controls
}
using (var descBrush = new SolidBrush(fgColor))
using (var descBrush = new SolidBrush(node.NodeTextForeColor))
{
g.DrawString(BottomLabelText, btmFont, descBrush, roundRect, new StringFormat
{
@@ -1710,14 +1915,18 @@ namespace AGVNavigationCore.Controls
switch (node.StationType)
{
case StationType.Normal: bgColor = Color.DeepSkyBlue; break;
case StationType.Charger1: bgColor = Color.Tomato; break;
case StationType.Charger2: bgColor = Color.Tomato; break;
case StationType.Loader:
case StationType.UnLoader: bgColor = Color.Gold; break;
case StationType.Clearner: bgColor = Color.DeepSkyBlue; break;
case StationType.Buffer: bgColor = Color.WhiteSmoke; break;
case StationType.Limit: bgColor = Color.Red; break;
case Station.Normal:
if (node.CanTurnLeft || node.CanTurnRight)
bgColor = Color.Violet;
else
bgColor = Color.DeepSkyBlue;
break;
case Station.Charger: bgColor = Color.Tomato; break;
case Station.Loder:
case Station.Cleaner: bgColor = Color.Gold; break;
case Station.Plating: bgColor = Color.DeepSkyBlue; break;
case Station.Buffer: bgColor = Color.WhiteSmoke; break;
case Station.Lmt: bgColor = Color.Red; break;
default: bgColor = Color.White; break;
}
@@ -2396,6 +2605,14 @@ namespace AGVNavigationCore.Controls
g.FillRectangle(bgBrush, scaleRect);
g.DrawRectangle(Pens.Gray, scaleRect.X, scaleRect.Y, scaleRect.Width, scaleRect.Height);
g.DrawString(scaleText, font, Brushes.Black, scaleRect.X + 5, scaleRect.Y + 2);
// 팬 정보 (스케일 정보 위에)
var panText = $"Pan: {_panOffset.X:F1}, {_panOffset.Y:F1}";
var panSize = g.MeasureString(panText, font);
var panRect = new RectangleF(10, Height - zoomSize.Height - scaleSize.Height - panSize.Height - 35, panSize.Width + 10, panSize.Height + 5);
g.FillRectangle(bgBrush, panRect);
g.DrawRectangle(Pens.Gray, panRect.X, panRect.Y, panRect.Width, panRect.Height);
g.DrawString(panText, font, Brushes.Black, panRect.X + 5, panRect.Y + 2);
}

View File

@@ -104,6 +104,10 @@ namespace AGVNavigationCore.Controls
HandleConnectClick(hitNode as MapNode);
break;
case EditMode.ConnectDirection:
HandleConnectDirectionClick(hitNode as MapNode);
break;
case EditMode.Delete:
HandleDeleteClick(hitNode);
break;
@@ -220,12 +224,45 @@ namespace AGVNavigationCore.Controls
{
if (_editMode == EditMode.Move)
{
// 0. 핸들 선택 확인 (이미 선택된 노드가 있을 때)
if (_selectedNode != null)
{
int handleIdx = GetHandleAt(worldPoint);
if (handleIdx != -1)
{
_dragHandleIndex = handleIdx;
// 핸들 드래그 시 초기 오프셋 설정 (점프 현상 방지)
if (_selectedNode is MapMagnet magnet)
{
Point handlePos = Point.Empty;
if (handleIdx == 0) handlePos = magnet.StartPoint;
else if (handleIdx == 1) handlePos = magnet.EndPoint;
else if (handleIdx == 2 && magnet.ControlPoint != null)
handlePos = new Point((int)magnet.ControlPoint.X, (int)magnet.ControlPoint.Y);
_dragOffset = new Point(worldPoint.X - handlePos.X, worldPoint.Y - handlePos.Y);
}
else
{
_dragOffset = Point.Empty; // Mark 등은 오프셋 없이 마우스 포인터 기준 계산
}
_isDragging = true;
_isPanning = false;
Capture = true;
Invalidate();
return;
}
}
// 1. 노드 선택 확인
var hitNode = GetItemAt(worldPoint);
if (hitNode != null)
{
_isDragging = true;
_isPanning = false;
_dragHandleIndex = -1; // 노드 전체 드래그
_selectedNode = hitNode;
_dragStartPosition = hitNode.Position;
_dragOffset = new Point(worldPoint.X - hitNode.Position.X, worldPoint.Y - hitNode.Position.Y);
@@ -322,8 +359,38 @@ namespace AGVNavigationCore.Controls
// 노드 드래그
if (_selectedNode != null)
{
if (_dragHandleIndex != -1)
{
// 핸들 드래그 (포인트별 수정)
if (_selectedNode is MapMagnet magnet)
{
if (_dragHandleIndex == 0) magnet.StartPoint = newPosition;
else if (_dragHandleIndex == 1) magnet.EndPoint = newPosition;
else if (_dragHandleIndex == 2 && magnet.ControlPoint != null)
{
magnet.ControlPoint.X = newPosition.X;
magnet.ControlPoint.Y = newPosition.Y;
}
}
else if (_selectedNode is MapMark mark)
{
// 마크는 중심점 대비 각도와 길이를 계산하여 수정
var dx = newPosition.X - mark.Position.X;
var dy = newPosition.Y - mark.Position.Y;
// 핸들 인덱스에 따라 각도 반전 (p1 vs p2)
if (_dragHandleIndex == 0) { dx = -dx; dy = -dy; }
mark.Rotation = Math.Atan2(dy, dx) * 180.0 / Math.PI;
mark.Length = Math.Sqrt(dx * dx + dy * dy) * 2;
}
}
else
{
// 노드 전체 드래그
_selectedNode.Position = newPosition;
NodeMoved?.Invoke(this, _selectedNode);
}
moved = true;
}
@@ -352,6 +419,7 @@ namespace AGVNavigationCore.Controls
if (_isDragging && _canvasMode == CanvasMode.Edit)
{
_isDragging = false;
_dragHandleIndex = -1;
Capture = false; // 🔥 마우스 캡처 해제
Cursor = GetCursorForMode(_editMode);
}
@@ -463,6 +531,25 @@ namespace AGVNavigationCore.Controls
}
}
if (_marks != null)
{
for (int i = _marks.Count - 1; i >= 0; i--)
{
var node = _marks[i];
if (IsPointInNode(worldPoint, node))
return node;
}
}
if (_magnets != null)
{
for (int i = _magnets.Count - 1; i >= 0; i--)
{
var node = _magnets[i];
if (IsPointInNode(worldPoint, node))
return node;
}
}
return null;
}
@@ -477,6 +564,14 @@ namespace AGVNavigationCore.Controls
{
return IsPointInImage(point, image);
}
if (node is MapMark mark)
{
return IsPointInMark(point, mark);
}
if (node is MapMagnet magnet)
{
return IsPointInMagnet(point, magnet);
}
// 라벨과 이미지는 별도 리스트로 관리되므로 여기서 처리하지 않음
// 하지만 혹시 모를 하위 호환성을 위해 타입 체크는 유지하되,
// 실제 로직은 CircularNode 등으로 분기
@@ -487,13 +582,12 @@ namespace AGVNavigationCore.Controls
{
switch (node.StationType)
{
case StationType.Loader:
case StationType.UnLoader:
case StationType.Clearner:
case StationType.Buffer:
case Station.Loder:
case Station.Cleaner:
case Station.Plating:
case Station.Buffer:
return IsPointInPentagon(point, node);
case StationType.Charger2:
case StationType.Charger1:
case Station.Charger:
return IsPointInTriangle(point, node);
default:
return IsPointInCircle(point, node);
@@ -648,6 +742,55 @@ namespace AGVNavigationCore.Controls
return imageRect.Contains(point);
}
private bool IsPointInMark(Point point, MapMark mark)
{
int lineLength = (int)mark.Length;
int halfLength = lineLength / 2;
double radians = mark.Rotation * Math.PI / 180.0;
int dx = (int)(halfLength * Math.Cos(radians));
int dy = (int)(halfLength * Math.Sin(radians));
Point p1 = new Point(mark.Position.X - dx, mark.Position.Y - dy);
Point p2 = new Point(mark.Position.X + dx, mark.Position.Y + dy);
// 마크 선택을 위해 약간 넉넉한 히트 영역 (7픽셀)
return CalculatePointToLineDistance(point, p1, p2) <= 7 / _zoomFactor;
}
private bool IsPointInMagnet(Point point, MapMagnet magnet)
{
// 마그넷은 두꺼우므로 (Pen Width 15) 절반인 7.5 정도를 히트 영역으로 잡음
float hitThreshold = Math.Max(8f, 12f / _zoomFactor);
if (magnet.ControlPoint != null)
{
// 베지어 곡선 정밀 샘플링 (10개 세그먼트)
Point prevPoint = magnet.StartPoint;
for (int i = 1; i <= 10; i++)
{
float t = i / 10f;
// Quadratic Bezier: (1-t)^2*P0 + 2(1-t)t*P1 + t^2*P2
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float x = uu * magnet.StartPoint.X + 2 * u * t * (float)magnet.ControlPoint.X + tt * magnet.EndPoint.X;
float y = uu * magnet.StartPoint.Y + 2 * u * t * (float)magnet.ControlPoint.Y + tt * magnet.EndPoint.Y;
Point currentPoint = new Point((int)x, (int)y);
if (CalculatePointToLineDistance(point, prevPoint, currentPoint) <= hitThreshold)
return true;
prevPoint = currentPoint;
}
return false;
}
else
{
return CalculatePointToLineDistance(point, magnet.StartPoint, magnet.EndPoint) <= hitThreshold;
}
}
//private MapLabel GetLabelAt(Point worldPoint)
//{
// if (_labels == null) return null;
@@ -764,7 +907,9 @@ namespace AGVNavigationCore.Controls
var newNode = new MapNode
{
Id = newNodeId,
Position = worldPoint
Position = worldPoint,
CanTurnLeft=false,
CanTurnRight= false,
};
_nodes.Add(newNode);
@@ -833,7 +978,7 @@ namespace AGVNavigationCore.Controls
/// <summary>
/// 중복되지 않는 고유한 NodeId 생성
/// </summary>
private string GenerateUniqueNodeId()
public string GenerateUniqueNodeId()
{
string nodeId;
int counter = _nodeCounter;
@@ -875,6 +1020,31 @@ namespace AGVNavigationCore.Controls
Invalidate();
}
private void HandleConnectDirectionClick(MapNode hitNode)
{
if (hitNode == null) return;
if (!_isConnectionMode)
{
// 연결 시작 (방향 설정)
_isConnectionMode = true;
_connectionStartNode = hitNode;
_selectedNode = hitNode;
}
else
{
// 연결 완료
if (_connectionStartNode != null && _connectionStartNode != hitNode)
{
// 기본값 S (Straight)로 방향 설정
SetMagnetDirection(_connectionStartNode, hitNode, MagnetPosition.S);
}
CancelConnection();
}
Invalidate();
}
private void HandleDeleteClick(MapNode hitNode)
{
if (hitNode == null) return;
@@ -902,10 +1072,46 @@ namespace AGVNavigationCore.Controls
toNode.ConnectedNodes.Contains(fromNode.Id))
return;
// 양방향 연결 생성 (AGV가 양쪽 방향으로 이동 가능하도록)
// 양방향 연결 생성 (AGV가 양쪽 방향으로 이동 가능하도록)
fromNode.AddConnection(toNode.Id);
toNode.AddConnection(fromNode.Id);
// 🔥 화면 표시용 ConnectedMapNodes 리스트도 즉시 갱신해야 함
if (!fromNode.ConnectedMapNodes.Contains(toNode))
fromNode.ConnectedMapNodes.Add(toNode);
if (!toNode.ConnectedMapNodes.Contains(fromNode))
toNode.ConnectedMapNodes.Add(fromNode);
ConnectionCreated?.Invoke(this, (fromNode, toNode));
MapChanged?.Invoke(this, EventArgs.Empty);
}
public void SetMagnetDirection(MapNode fromNode, MapNode toNode, MagnetPosition direction)
{
if (fromNode == null || toNode == null) return;
// 이미 연결된 노드인지 확인 (연결되어 있어야 방향 설정 가능)
// 이미 연결된 노드인지 확인 (연결되어 있어야 방향 설정 가능)
if (!fromNode.ConnectedNodes.Contains(toNode.Id))
{
// 연결되어 있지 않으면 자동 연결
CreateConnection(fromNode, toNode);
}
if (fromNode.MagnetDirections == null)
fromNode.MagnetDirections = new Dictionary<string, MagnetPosition>();
if (fromNode.MagnetDirections.ContainsKey(toNode.Id))
{
fromNode.MagnetDirections[toNode.Id] = direction;
}
else
{
fromNode.MagnetDirections.Add(toNode.Id, direction);
}
MapChanged?.Invoke(this, EventArgs.Empty);
}
@@ -1053,8 +1259,8 @@ namespace AGVNavigationCore.Controls
var C = lineEnd.X - lineStart.X;
var D = lineEnd.Y - lineStart.Y;
var dot = A * C + B * D;
var lenSq = C * C + D * D;
var dot = (double)A * C + (double)B * D;
var lenSq = (double)C * C + (double)D * D;
if (lenSq == 0) return CalculateDistance(point, lineStart);
@@ -1102,6 +1308,39 @@ namespace AGVNavigationCore.Controls
}
}
private int GetHandleAt(Point worldPoint)
{
if (_selectedNode == null) return -1;
float hitTolerance = (HANDLE_SIZE + 4) / _zoomFactor;
if (_selectedNode is MapMagnet magnet)
{
if (CalculateDistance(worldPoint, magnet.StartPoint) <= hitTolerance) return 0;
if (CalculateDistance(worldPoint, magnet.EndPoint) <= hitTolerance) return 1;
if (magnet.ControlPoint != null)
{
if (CalculateDistance(worldPoint, new Point((int)magnet.ControlPoint.X, (int)magnet.ControlPoint.Y)) <= hitTolerance) return 2;
}
}
else if (_selectedNode is MapMark mark)
{
int lineLength = (int)mark.Length;
int halfLength = lineLength / 2;
double radians = mark.Rotation * Math.PI / 180.0;
int dx = (int)(halfLength * Math.Cos(radians));
int dy = (int)(halfLength * Math.Sin(radians));
Point p1 = new Point(mark.Position.X - dx, mark.Position.Y - dy);
Point p2 = new Point(mark.Position.X + dx, mark.Position.Y + dy);
if (CalculateDistance(worldPoint, p1) <= hitTolerance) return 0;
if (CalculateDistance(worldPoint, p2) <= hitTolerance) return 1;
}
return -1;
}
#endregion
#region View Control Methods

View File

@@ -20,7 +20,7 @@ namespace AGVNavigationCore.Controls
{
#region Constants
private const int NODE_SIZE = 24;
private const int NODE_SIZE = 18;
private const int NODE_RADIUS = NODE_SIZE / 2;
private const int GRID_SIZE = 20;
private const float CONNECTION_WIDTH = 1.0f;
@@ -56,6 +56,7 @@ namespace AGVNavigationCore.Controls
DeleteConnection, // 연결 삭제 모드
AddLabel, // 라벨 추가 모드
AddImage, // 이미지 추가 모드
ConnectDirection, // 방향 연결 모드
}
#endregion
@@ -109,6 +110,8 @@ namespace AGVNavigationCore.Controls
private MapNode _connectionStartNode;
private Point _connectionEndPoint;
private int _mouseMoveCounter = 0; // 디버그용: MouseMove 실행 횟수
private int _dragHandleIndex = -1; // 드래그 중인 핸들 인덱스
private const int HANDLE_SIZE = 8; // 편집 핸들 크기
// 영역 선택 관련
private bool _isAreaSelecting;
@@ -135,12 +138,28 @@ namespace AGVNavigationCore.Controls
private float _syncProgress = 0.0f;
private string _syncDetail = "";
string _alertmesage = "";
bool showalert = false;
public void SetAlertMessage(string m)
string _systemmesage = "";
string _infomessage = "";
string _tagignoreMessage = "";
bool showalertsystem = false;
bool showinfo = false;
bool showtagigreno = false;
DateTime tagignoretime = DateTime.Now;
public void SetTagIgnore(string m)
{
_alertmesage = m;
showalert = !string.IsNullOrEmpty(m);
_tagignoreMessage = m;
tagignoretime = DateTime.Now;
showtagigreno = !string.IsNullOrEmpty(m);
}
public void SetInfoMessage(string m)
{
_infomessage = m;
showinfo = !string.IsNullOrEmpty(m);
}
public void SetSystemMessage(string m)
{
_systemmesage = m;
showalertsystem = !string.IsNullOrEmpty(m);
}
// 브러쉬 및 펜
@@ -185,6 +204,7 @@ namespace AGVNavigationCore.Controls
public event EventHandler<List<NodeBase>> NodesSelected; // 다중 선택 이벤트
public event EventHandler<NodeBase> NodeDeleted;
public event EventHandler<NodeBase> NodeMoved;
public event EventHandler<(MapNode From, MapNode To)> ConnectionCreated; // 연결 생성 이벤트 추가
public event EventHandler<(MapNode From, MapNode To)> ConnectionDeleted;
public event EventHandler<MapImage> ImageDoubleClicked;
public event EventHandler<MapLabel> LabelDoubleClicked;
@@ -231,6 +251,18 @@ namespace AGVNavigationCore.Controls
{
if (_nodes != null && _nodes.Contains(node))
{
// 🔥 삭제되는 노드와 연결된 다른 노드들의 연결 정보도 삭제
foreach (var otherNode in _nodes.ToList()) // ToList()로 복사본 순회 (안전장치)
{
if (otherNode == node) continue;
// 다른 노드 -> 삭제되는 노드 연결 제거
if (otherNode.ConnectedNodes.Contains(node.Id))
{
otherNode.RemoveConnection(node.Id);
}
}
_nodes.Remove(node);
Invalidate();
}
@@ -291,6 +323,34 @@ namespace AGVNavigationCore.Controls
}
}
/// <summary>
/// 외부에서 Pan(X,Y) 및 Zoom 값을 설정합니다.
/// </summary>
/// <param name="panX">Pan X 좌표</param>
/// <param name="panY">Pan Y 좌표</param>
/// <param name="zoom">Zoom Level (0.1 ~ 5.0)</param>
public void SetView(float panX, float panY, float zoom)
{
// Zoom 값 범위 제한
float newZoom = Math.Max(0.1f, Math.Min(5.0f, zoom));
_panOffset = new PointF(panX, panY);
_zoomFactor = newZoom;
Invalidate();
}
[Browsable(false)]
public PointF PanOffset
{
get => _panOffset;
set
{
_panOffset = value;
Invalidate();
}
}
/// <summary>
/// 그리드 표시 여부
/// </summary>
@@ -345,9 +405,23 @@ namespace AGVNavigationCore.Controls
/// <summary>
/// 선택된 노드 (단일)
/// </summary>
public MapNode SelectedNode
public NodeBase SelectedNode
{
get { return this._selectedNode as MapNode; }
get { return this._selectedNode; }
set
{
_selectedNode = value;
if (value != null)
{
_selectedNodes.Clear();
_selectedNodes.Add(value);
}
else
{
_selectedNodes.Clear();
}
Invalidate();
}
}
/// <summary>
@@ -392,6 +466,19 @@ namespace AGVNavigationCore.Controls
this.FitToNodes();
}
/// <summary>
/// 맵 데이터를 셋팅합니다
/// </summary>
public void SetMapData(List<MapNode> nodes, List<MapLabel> labels = null, List<MapImage> images = null, List<MapMark> marks = null, List<MapMagnet> magnets = null)
{
this.Nodes = nodes;
this.Labels = labels ?? new List<MapLabel>();
this.Images = images ?? new List<MapImage>();
this.Marks = marks ?? new List<MapMark>();
this.Magnets = magnets ?? new List<MapMagnet>();
this.FitToNodes();
}
/// <summary>
/// 노드 목록
/// </summary>
@@ -656,8 +743,8 @@ namespace AGVNavigationCore.Controls
_destinationNodePen = new Pen(Color.Orange, 4);
_pathPen = new Pen(Color.Purple, 3);
_agvPen = new Pen(Color.Red, 3);
_highlightedConnectionPen = new Pen(Color.Red, 4) { DashStyle = DashStyle.Solid };
_magnetPen = new Pen(Color.FromArgb(100, Color.LightSkyBlue), 15) { DashStyle = DashStyle.Solid };
_highlightedConnectionPen = new Pen(Color.Red, 6) { DashStyle = DashStyle.Solid };
_magnetPen = new Pen(Color.FromArgb(100, Color.LightSkyBlue), 15) { DashStyle = DashStyle.Solid, StartCap = LineCap.Round, EndCap = LineCap.Round };
_markPen = new Pen(Color.White, 3); // 마크는 흰색 선으로 표시
}
@@ -858,6 +945,7 @@ namespace AGVNavigationCore.Controls
// 이미지 정리
_companyLogo?.Dispose();
}
base.Dispose(disposing);

View File

@@ -21,6 +21,9 @@
/// <summary>명령 이유- (디버깅/로깅용)</summary>
public eAGVCommandReason Reason { get; set; }
/// <summary>방향 전환 명령 여부 (180도 Left Turn 등)</summary>
public bool IsTurn { get; set; }
/// <summary>
/// 생성자
/// </summary>

View File

@@ -58,29 +58,27 @@ namespace AGVNavigationCore.Models
/// <summary>
/// 장비 타입 열거형
/// </summary>
public enum StationType
public enum Station
{
/// <summary>
/// 일반노드
/// </summary>
Normal,
/// <summary>로더</summary>
Loader,
Loder,
/// <summary>클리너</summary>
Clearner,
Plating,
/// <summary>오프로더</summary>
UnLoader,
Cleaner,
/// <summary>버퍼</summary>
Buffer,
/// <summary>충전기1</summary>
Charger1,
/// <summary>충전기2</summary>
Charger2,
Charger,
/// <summary>
/// 끝점(더이상 이동불가)
/// </summary>
Limit,
Lmt,
}
@@ -179,4 +177,7 @@ namespace AGVNavigationCore.Models
Complete,
}
}

View File

@@ -56,17 +56,37 @@ namespace AGVNavigationCore.Models
}
/// <summary>
/// 시작점 Point 반환
/// 시작점 Point 반환 및 설정
/// </summary>
[Browsable(false)]
[JsonIgnore]
public Point StartPoint => new Point((int)P1.X, (int)P1.Y);
public Point StartPoint
{
get => new Point((int)P1.X, (int)P1.Y);
set { P1.X = value.X; P1.Y = value.Y; }
}
/// <summary>
/// 끝점 Point 반환
/// 끝점 Point 반환 및 설정
/// </summary>
[Browsable(false)]
[JsonIgnore]
public Point EndPoint => new Point((int)P2.X, (int)P2.Y);
public Point EndPoint
{
get => new Point((int)P2.X, (int)P2.Y);
set { P2.X = value.X; P2.Y = value.Y; }
}
public override string ToString()
{
if (ControlPoint == null)
{
return $"[LINE] ({P1.X:F0},{P1.Y:F0}) -> ({P2.X:F0},{P2.Y:F0})";
}
else
{
return $"[CURVE] ({P1.X:F0},{P1.Y:F0}) -> ({P2.X:F0},{P2.Y:F0})";
}
}
}
}

View File

@@ -33,5 +33,9 @@ namespace AGVNavigationCore.Models
[Category("위치 정보")]
[Description("마크의 회전 각도")]
public double Rotation { get; set; }
[Category("위치 정보")]
[Description("마크의 길이")]
public double Length { get; set; } = 20.0;
}
}

View File

@@ -15,23 +15,20 @@ namespace AGVNavigationCore.Models
{
[Category("라벨 설정")]
[Description("표시할 텍스트입니다.")]
public string Text { get; set; } = "";
public StationType StationType { get; set; }
public Station StationType { get; set; }
[Browsable(false)]
public bool CanDocking
{
get
{
if (StationType == StationType.Buffer) return true;
if (StationType == StationType.Loader) return true;
if (StationType == StationType.UnLoader) return true;
if (StationType == StationType.Clearner) return true;
if (StationType == StationType.Charger1) return true;
if (StationType == StationType.Charger2) return true;
if (StationType == Station.Buffer) return true;
if (StationType == Station.Loder) return true;
if (StationType == Station.Cleaner) return true;
if (StationType == Station.Plating) return true;
if (StationType == Station.Charger) return true;
return false;
}
}
@@ -56,11 +53,11 @@ namespace AGVNavigationCore.Models
[Category("주행 설정")]
[Description("제자리 회전(좌) 가능 여부입니다.")]
public bool CanTurnLeft { get; set; } = true;
public bool CanTurnLeft { get; set; } = false;
[Category("주행 설정")]
[Description("제자리 회전(우) 가능 여부입니다.")]
public bool CanTurnRight { get; set; } = true;
public bool CanTurnRight { get; set; } = false;
[Category("주행 설정")]
[Description("교차로 주행 가능 여부입니다.")]
@@ -73,11 +70,11 @@ namespace AGVNavigationCore.Models
}
set { _disablecross = value; }
}
private bool _disablecross = false;
private bool _disablecross = true;
[Category("주행 설정")]
[Description("노드 통과 시 제한 속도입니다.")]
public SpeedLevel SpeedLimit { get; set; } = SpeedLevel.M;
public SpeedLevel SpeedLimit { get; set; } = SpeedLevel.L;
[Category("노드 설정")]
[Description("장비 ID 또는 별칭입니다.")]
@@ -105,12 +102,16 @@ namespace AGVNavigationCore.Models
set => _textFontSize = value > 0 ? value : 7.0f;
}
[Category("노드 텍스트")]
[Description("표시할 텍스트입니다.")]
public string Text { get; set; } = "";
public MapNode() : base()
{
Type = NodeType.Normal;
}
public MapNode(string nodeId, Point position, StationType type) : base(nodeId, position)
public MapNode(string nodeId, Point position, Station type) : base(nodeId, position)
{
Type = NodeType.Normal;
}
@@ -121,9 +122,9 @@ namespace AGVNavigationCore.Models
{
get
{
if (StationType == StationType.Charger1 || StationType == StationType.Charger2 || StationType == StationType.Buffer ||
StationType == StationType.Clearner || StationType == StationType.Loader ||
StationType == StationType.UnLoader) return true;
if (StationType == Station.Charger || StationType == Station.Buffer ||
StationType == Station.Plating || StationType == Station.Loder ||
StationType == Station.Cleaner) return true;
return false;
}
}
@@ -141,6 +142,15 @@ namespace AGVNavigationCore.Models
{
if (ConnectedNodes.Remove(nodeId))
{
if (MagnetDirections != null && MagnetDirections.ContainsKey(nodeId))
{
MagnetDirections.Remove(nodeId);
}
// 🔥 ConnectedMapNodes에서도 제거 (화면 갱신용)
var target = ConnectedMapNodes.Find(n => n.Id == nodeId);
if (target != null) ConnectedMapNodes.Remove(target);
ModifiedDate = DateTime.Now;
}
}

View File

@@ -1,6 +1,4 @@
using AGVNavigationCore.Models;
namespace AGVNavigationCore.PathFinding.Planning
namespace AGVNavigationCore.Models
{
/// <summary>
/// AGV 마그넷 센서 방향 제어
@@ -82,13 +80,16 @@ namespace AGVNavigationCore.PathFinding.Planning
/// </summary>
public bool IsPass { get; set; }
public bool IsTurn { get; set; }
/// <summary>
/// 특수 동작 설명
/// </summary>
public string SpecialActionDescription { get; set; }
public NodeMotorInfo(int seqno,string nodeId,ushort rfid, AgvDirection motorDirection, MapNode nextNodeId = null, MagnetDirection magnetDirection = MagnetDirection.Straight)
public NodeMotorInfo(int seqno,string nodeId,ushort rfid,
AgvDirection motorDirection, MapNode nextNodeId = null, MagnetDirection magnetDirection = MagnetDirection.Straight,bool turn=false)
{
IsTurn = turn;
seq = seqno;
NodeId = nodeId;
RfidId = rfid;

View File

@@ -56,7 +56,7 @@ namespace AGVNavigationCore.Models
private AgvDirection _prevDirection;
private AGVState _currentState;
private float _currentSpeed;
private MapNode _targetnode = null;
// 경로 관련
private AGVPathResult _currentPath;
private List<string> _remainingNodes;
@@ -92,7 +92,6 @@ namespace AGVNavigationCore.Models
#region Properties
public bool Turn180 { get; set; } = false;
/// <summary>
/// 대상 이동시 모터 방향
@@ -312,7 +311,6 @@ namespace AGVNavigationCore.Models
/// <returns>다음에 수행할 모터/마그넷/속도 명령</returns>
public AGVCommand Predict()
{
// 1. 위치 미확정 상태 (RFID 2개 미만 감지)
if (!_isPositionConfirmed)
{
@@ -347,12 +345,11 @@ namespace AGVNavigationCore.Models
var lastNode = _currentPath.DetailedPath.Last();
if (_currentPath.DetailedPath.Where(t => t.seq < lastNode.seq && t.IsPass == false).Any() == false)
{
// 마지막 노드에 도착했는지 확인 (현재 노드가 마지막 노드와 같은지)
if (_currentNode != null && _currentNode.Id == lastNode.NodeId)
// 마지막 노드에 도착했는지 확인 (현재 노드가 마지막 노드와 같은지) -
// 모터방향오 같아야한다. 간혹 방향전환 후 MARK STOP하는경우가있다. 260127
if (_currentNode != null && _currentNode.Id == lastNode.NodeId && lastNode.MotorDirection == CurrentDirection)
{
if (lastNode.IsPass) //이미완료되었다.
{
return new AGVCommand(
@@ -365,12 +362,23 @@ namespace AGVNavigationCore.Models
}
else
{
//움직이지 않는다면 움직이게하고, 움직인다면 마크스탑하낟.i
//도킹노드라면 markstop 을 나머지는 바로 스탑한다.
eAGVCommandReason reason = eAGVCommandReason.MarkStop;
if (TargetNode.StationType == Station.Normal || TargetNode.StationType == Station.Lmt)
{
//일반노드는 마크스탑포인트가 없으니 바로 종료되도록 한다
reason = eAGVCommandReason.Complete;
}
//마지막노드는 일혔지만 완료되지 않았다. 마크스탑필요
return new AGVCommand(
MotorCommand.Stop,
MagnetPosition.S,
SpeedLevel.L,
eAGVCommandReason.MarkStop,
reason,
$"목적지 도착 전(MarkStop) - 최종:{CurrentNodeID2}"
);
}
@@ -379,8 +387,8 @@ namespace AGVNavigationCore.Models
}
// 4. 경로이탈
var TargetNode = _currentPath.DetailedPath.Where(t => t.IsPass == false && t.NodeId.Equals(_currentNode.Id)).FirstOrDefault();
if (TargetNode == null)
var checkPathOutNode = _currentPath.DetailedPath.Where(t => t.IsPass == false && t.NodeId.Equals(_currentNode.Id)).FirstOrDefault();
if (checkPathOutNode == null)
{
return new AGVCommand(
MotorCommand.Stop,
@@ -712,6 +720,15 @@ namespace AGVNavigationCore.Models
// MotorDirection → MotorCommand 변환
MotorCommand motorCmd;
eAGVCommandReason reason = eAGVCommandReason.Normal;
if (nodeInfo.IsTurn)
{
motorCmd = MotorCommand.Stop;
reason = eAGVCommandReason.MarkStop;
}
else
{
switch (nodeInfo.MotorDirection)
{
case AgvDirection.Forward:
@@ -724,18 +741,19 @@ namespace AGVNavigationCore.Models
motorCmd = MotorCommand.Stop;
break;
}
}
// MagnetDirection → MagnetPosition 변换
MagnetPosition magnetPos;
switch (nodeInfo.MagnetDirection)
{
case PathFinding.Planning.MagnetDirection.Left:
case MagnetDirection.Left:
magnetPos = MagnetPosition.L;
break;
case PathFinding.Planning.MagnetDirection.Right:
case MagnetDirection.Right:
magnetPos = MagnetPosition.R;
break;
case PathFinding.Planning.MagnetDirection.Straight:
case MagnetDirection.Straight:
default:
magnetPos = MagnetPosition.S;
break;
@@ -753,9 +771,12 @@ namespace AGVNavigationCore.Models
motorCmd,
magnetPos,
speed,
eAGVCommandReason.Normal,
reason,
$"{actionDescription} → {targetNode.Id} (Motor:{motorCmd}, Magnet:{magnetPos})"
);
)
{
IsTurn = nodeInfo.IsTurn
};
}
private void StartMovement()
@@ -827,8 +848,6 @@ namespace AGVNavigationCore.Models
public MapNode StartNode { get; set; } = null;
private MapNode _targetnode = null;
/// <summary>
/// 목적지를 설정합니다. 목적지가 변경되면 경로계산정보가 삭제 됩니다.
/// </summary>
@@ -848,6 +867,10 @@ namespace AGVNavigationCore.Models
}
}
private void ProcessNextNode()
{
if (_remainingNodes == null || _currentNodeIndex >= _remainingNodes.Count - 1)

View File

@@ -181,277 +181,6 @@ namespace AGVNavigationCore.PathFinding.Core
}
}
///// <summary>
///// 경유지를 거쳐 경로 찾기 (오버로드)
///// 여러 경유지를 순차적으로 거쳐서 최종 목적지까지의 경로를 계산합니다.
///// 기존 FindPath를 여러 번 호출하여 각 구간의 경로를 합칩니다.
///// </summary>
///// <param name="startNodeId">시작 노드 ID</param>
///// <param name="endNodeId">최종 목적지 노드 ID</param>
///// <param name="waypointNodeIds">경유지 노드 ID 배열 (선택사항)</param>
///// <returns>경로 계산 결과 (모든 경유지를 거친 전체 경로)</returns>
//public AGVPathResult FindPath(string startNodeId, string endNodeId, params string[] waypointNodeIds)
//{
// var stopwatch = System.Diagnostics.Stopwatch.StartNew();
// try
// {
// // 경유지가 없으면 기본 FindPath 호출
// if (waypointNodeIds == null || waypointNodeIds.Length == 0)
// {
// return FindPathAStar(startNodeId, endNodeId);
// }
// // 경유지 유효성 검증
// var validWaypoints = new List<string>();
// foreach (var waypointId in waypointNodeIds)
// {
// if (string.IsNullOrEmpty(waypointId))
// continue;
// if (!_nodeMap.ContainsKey(waypointId))
// {
// return AGVPathResult.CreateFailure($"경유지 노드를 찾을 수 없습니다: {waypointId}", stopwatch.ElapsedMilliseconds, 0);
// }
// validWaypoints.Add(waypointId);
// }
// // 경유지가 없으면 기본 경로 계산
// if (validWaypoints.Count == 0)
// {
// return FindPathAStar(startNodeId, endNodeId);
// }
// // 첫 번째 경유지가 시작노드와 같은지 검사
// if (validWaypoints[0] == startNodeId)
// {
// return AGVPathResult.CreateFailure(
// $"첫 번째 경유지({validWaypoints[0]})가 시작 노드({startNodeId})와 동일합니다. 경유지는 시작노드와 달라야 합니다.",
// stopwatch.ElapsedMilliseconds, 0);
// }
// // 마지막 경유지가 목적지노드와 같은지 검사
// if (validWaypoints[validWaypoints.Count - 1] == endNodeId)
// {
// return AGVPathResult.CreateFailure(
// $"마지막 경유지({validWaypoints[validWaypoints.Count - 1]})가 목적지 노드({endNodeId})와 동일합니다. 경유지는 목적지노드와 달라야 합니다.",
// stopwatch.ElapsedMilliseconds, 0);
// }
// // 연속된 중복만 제거 (순서 유지)
// // 예: [1, 2, 2, 3, 2] -> [1, 2, 3, 2] (연속 중복만 제거)
// var deduplicatedWaypoints = new List<string>();
// string lastWaypoint = null;
// foreach (var waypoint in validWaypoints)
// {
// if (waypoint != lastWaypoint)
// {
// deduplicatedWaypoints.Add(waypoint);
// lastWaypoint = waypoint;
// }
// }
// validWaypoints = deduplicatedWaypoints;
// // 최종 경로 리스트와 누적 값
// var combinedPath = new List<MapNode>();
// float totalDistance = 0;
// long totalCalculationTime = 0;
// // 현재 시작점
// string currentStart = startNodeId;
// // 1단계: 각 경유지까지의 경로 계산
// for (int i = 0; i < validWaypoints.Count; i++)
// {
// string waypoint = validWaypoints[i];
// // 현재 위치에서 경유지까지의 경로 계산
// var segmentResult = FindPathAStar(currentStart, waypoint);
// if (!segmentResult.Success)
// {
// return AGVPathResult.CreateFailure(
// $"경유지 {i + 1}({waypoint})까지의 경로 계산 실패: {segmentResult.ErrorMessage}",
// stopwatch.ElapsedMilliseconds, 0);
// }
// // 경로 합치기 (첫 번째 구간이 아니면 시작점 제거하여 중복 방지)
// if (combinedPath.Count > 0 && segmentResult.Path.Count > 0)
// {
// // 시작 노드 제거 (이전 경로의 마지막 노드와 동일)
// combinedPath.AddRange(segmentResult.Path.Skip(1));
// }
// else
// {
// combinedPath.AddRange(segmentResult.Path);
// }
// totalDistance += segmentResult.TotalDistance;
// totalCalculationTime += segmentResult.CalculationTimeMs;
// // 다음 경유지의 시작점은 현재 경유지
// currentStart = waypoint;
// }
// // 2단계: 마지막 경유지에서 최종 목적지까지의 경로 계산
// var finalSegmentResult = FindPathAStar(currentStart, endNodeId);
// if (!finalSegmentResult.Success)
// {
// return AGVPathResult.CreateFailure(
// $"최종 목적지까지의 경로 계산 실패: {finalSegmentResult.ErrorMessage}",
// stopwatch.ElapsedMilliseconds, 0);
// }
// // 최종 경로 합치기 (시작점 제거)
// if (combinedPath.Count > 0 && finalSegmentResult.Path.Count > 0)
// {
// combinedPath.AddRange(finalSegmentResult.Path.Skip(1));
// }
// else
// {
// combinedPath.AddRange(finalSegmentResult.Path);
// }
// totalDistance += finalSegmentResult.TotalDistance;
// totalCalculationTime += finalSegmentResult.CalculationTimeMs;
// stopwatch.Stop();
// // 결과 생성
// return AGVPathResult.CreateSuccess(
// combinedPath,
// new List<AgvDirection>(),
// totalDistance,
// totalCalculationTime
// );
// }
// catch (Exception ex)
// {
// return AGVPathResult.CreateFailure($"경로 계산 중 오류: {ex.Message}", stopwatch.ElapsedMilliseconds, 0);
// }
//}
/// <summary>
/// 두 경로 결과를 합치기
/// 이전 경로의 마지막 노드와 현재 경로의 시작 노드가 같으면 시작 노드를 제거하고 합침
/// </summary>
/// <param name="previousResult">이전 경로 결과</param>
/// <param name="currentResult">현재 경로 결과</param>
/// <returns>합쳐진 경로 결과</returns>
public AGVPathResult CombineResults( AGVPathResult previousResult, AGVPathResult currentResult)
{
// 입력 검증
if (previousResult == null)
return currentResult;
if (currentResult == null)
return previousResult;
if (!previousResult.Success)
return AGVPathResult.CreateFailure(
$"이전 경로 결과 실패: {previousResult.Message}",
previousResult.CalculationTimeMs);
if (!currentResult.Success)
return AGVPathResult.CreateFailure(
$"현재 경로 결과 실패: {currentResult.Message}",
currentResult.CalculationTimeMs);
// 경로가 비어있는 경우 처리
if (previousResult.Path == null || previousResult.Path.Count == 0)
return currentResult;
if (currentResult.Path == null || currentResult.Path.Count == 0)
return previousResult;
// 합친 경로 생성
var combinedPath = new List<MapNode>(previousResult.Path);
var combinedCommands = new List<AgvDirection>(previousResult.Commands);
var combinedDetailedPath = new List<NodeMotorInfo>(previousResult.DetailedPath ?? new List<NodeMotorInfo>());
// 이전 경로의 마지막 노드와 현재 경로의 시작 노드 비교
string lastNodeOfPrevious = previousResult.Path[previousResult.Path.Count - 1].Id;
string firstNodeOfCurrent = currentResult.Path[0].Id;
if (lastNodeOfPrevious == firstNodeOfCurrent)
{
// 첫 번째 노드 제거 (중복 제거)
combinedPath.RemoveAt(combinedPath.Count - 1);
combinedPath.AddRange(currentResult.Path);
// DetailedPath도 첫 번째 노드 제거
if (currentResult.DetailedPath != null && currentResult.DetailedPath.Count > 0)
{
combinedDetailedPath.RemoveAt(combinedDetailedPath.Count - 1);
combinedDetailedPath.AddRange(currentResult.DetailedPath);
}
}
else
{
// 그대로 붙임
combinedPath.AddRange(currentResult.Path);
// DetailedPath도 그대로 붙임
if (currentResult.DetailedPath != null && currentResult.DetailedPath.Count > 0)
{
combinedDetailedPath.AddRange(currentResult.DetailedPath);
}
}
// 명령어 합치기
combinedCommands.AddRange(currentResult.Commands);
// 총 거리 합산
float combinedDistance = previousResult.TotalDistance + currentResult.TotalDistance;
// 계산 시간 합산
long combinedCalculationTime = previousResult.CalculationTimeMs + currentResult.CalculationTimeMs;
// 합쳐진 결과 생성
var result = AGVPathResult.CreateSuccess(
combinedPath,
combinedCommands,
combinedDistance,
combinedCalculationTime
);
// DetailedPath 설정
result.DetailedPath = combinedDetailedPath;
result.PrevNode = previousResult.PrevNode;
result.PrevDirection = previousResult.PrevDirection;
return result;
}
///// <summary>
///// 여러 목적지 중 가장 가까운 노드로의 경로 찾기
///// </summary>
///// <param name="startNodeId">시작 노드 ID</param>
///// <param name="targetNodeIds">목적지 후보 노드 ID 목록</param>
///// <returns>경로 계산 결과</returns>
//public AGVPathResult FindNearestPath(string startNodeId, List<string> targetNodeIds)
//{
// if (targetNodeIds == null || targetNodeIds.Count == 0)
// {
// return AGVPathResult.CreateFailure("목적지 노드가 지정되지 않았습니다", 0, 0);
// }
// AGVPathResult bestResult = null;
// foreach (var targetId in targetNodeIds)
// {
// var result = FindPathAStar(startNodeId, targetId);
// if (result.Success && (bestResult == null || result.TotalDistance < bestResult.TotalDistance))
// {
// bestResult = result;
// }
// }
// return bestResult ?? AGVPathResult.CreateFailure("모든 목적지로의 경로를 찾을 수 없습니다", 0, 0);
//}
/// <summary>
/// 휴리스틱 거리 계산 (유클리드 거리)
/// </summary>

View File

@@ -0,0 +1,106 @@
using AGVNavigationCore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AGVNavigationCore.PathFinding.Core
{
public static class Utility
{
/// <summary>
/// 두 경로 결과를 합치기
/// 이전 경로의 마지막 노드와 현재 경로의 시작 노드가 같으면 시작 노드를 제거하고 합침
/// </summary>
/// <param name="previousResult">이전 경로 결과</param>
/// <param name="currentResult">현재 경로 결과</param>
/// <returns>합쳐진 경로 결과</returns>
public static AGVPathResult CombineResults(AGVPathResult previousResult, AGVPathResult currentResult)
{
// 입력 검증
if (previousResult == null)
return currentResult;
if (currentResult == null)
return previousResult;
if (!previousResult.Success)
return AGVPathResult.CreateFailure(
$"이전 경로 결과 실패: {previousResult.Message}",
previousResult.CalculationTimeMs);
if (!currentResult.Success)
return AGVPathResult.CreateFailure(
$"현재 경로 결과 실패: {currentResult.Message}",
currentResult.CalculationTimeMs);
// 경로가 비어있는 경우 처리
if (previousResult.Path == null || previousResult.Path.Count == 0)
return currentResult;
if (currentResult.Path == null || currentResult.Path.Count == 0)
return previousResult;
// 합친 경로 생성
var combinedPath = new List<MapNode>(previousResult.Path);
var combinedCommands = new List<AgvDirection>(previousResult.Commands);
var combinedDetailedPath = new List<NodeMotorInfo>(previousResult.DetailedPath ?? new List<NodeMotorInfo>());
// 이전 경로의 마지막 노드와 현재 경로의 시작 노드 비교
string lastNodeOfPrevious = previousResult.Path[previousResult.Path.Count - 1].Id;
string firstNodeOfCurrent = currentResult.Path[0].Id;
if (lastNodeOfPrevious == firstNodeOfCurrent)
{
// 첫 번째 노드 제거 (중복 제거)
combinedPath.RemoveAt(combinedPath.Count - 1);
combinedPath.AddRange(currentResult.Path);
// DetailedPath도 첫 번째 노드 제거
if (currentResult.DetailedPath != null && currentResult.DetailedPath.Count > 0)
{
combinedDetailedPath.RemoveAt(combinedDetailedPath.Count - 1);
combinedDetailedPath.AddRange(currentResult.DetailedPath);
}
}
else
{
// 그대로 붙임
combinedPath.AddRange(currentResult.Path);
// DetailedPath도 그대로 붙임
if (currentResult.DetailedPath != null && currentResult.DetailedPath.Count > 0)
{
combinedDetailedPath.AddRange(currentResult.DetailedPath);
}
}
// 명령어 합치기
combinedCommands.AddRange(currentResult.Commands);
// 총 거리 합산
float combinedDistance = previousResult.TotalDistance + currentResult.TotalDistance;
// 계산 시간 합산
long combinedCalculationTime = previousResult.CalculationTimeMs + currentResult.CalculationTimeMs;
// 합쳐진 결과 생성
var result = AGVPathResult.CreateSuccess(
combinedPath,
combinedCommands,
combinedDistance,
combinedCalculationTime
);
// DetailedPath 설정
result.DetailedPath = combinedDetailedPath;
result.PrevNode = previousResult.PrevNode;
result.PrevDirection = previousResult.PrevDirection;
return result;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\..\..\..\Amkor\AGV4\Test\Simulator\</OutputPath>
<OutputPath>bin\debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@@ -45,6 +45,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="fMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="fMain.Designer.cs">
<DependentUpon>fMain.cs</DependentUpon>
</Compile>
<Compile Include="Forms\ComboBoxItem.cs" />
<Compile Include="Forms\DirectionItem.cs" />
<Compile Include="Forms\PathTestLogItem.cs" />
@@ -56,20 +62,9 @@
</Compile>
<Compile Include="Models\SimulatorConfig.cs" />
<Compile Include="Models\SimulationState.cs" />
<Compile Include="Forms\SimulatorForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\SimulatorForm.Designer.cs">
<DependentUpon>SimulatorForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Forms\SimulatorForm.resx">
<DependentUpon>SimulatorForm.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="build.bat" />
<None Include="packages.config" />
@@ -84,5 +79,10 @@
<Name>AGVMapEditor</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="fMain.resx">
<DependentUpon>fMain.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -55,6 +55,7 @@ namespace AGVSimulator.Forms
this.ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.launchMapEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.btSelectMapEditor = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.simulationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -85,6 +86,7 @@ namespace AGVSimulator.Forms
this._statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this._coordLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.prb1 = new System.Windows.Forms.ToolStripProgressBar();
this.sbFile = new System.Windows.Forms.ToolStripStatusLabel();
this._controlPanel = new System.Windows.Forms.Panel();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.propertyNode = new System.Windows.Forms.PropertyGrid();
@@ -120,7 +122,7 @@ namespace AGVSimulator.Forms
this._liftDirectionLabel = new System.Windows.Forms.Label();
this._motorDirectionLabel = new System.Windows.Forms.Label();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.btSelectMapEditor = new System.Windows.Forms.ToolStripMenuItem();
this.button1 = new System.Windows.Forms.Button();
this._menuStrip.SuspendLayout();
this._toolStrip.SuspendLayout();
this._statusStrip.SuspendLayout();
@@ -205,6 +207,13 @@ namespace AGVSimulator.Forms
this.launchMapEditorToolStripMenuItem.Text = "MapEditor 실행(&M)";
this.launchMapEditorToolStripMenuItem.Click += new System.EventHandler(this.OnLaunchMapEditor_Click);
//
// btSelectMapEditor
//
this.btSelectMapEditor.Name = "btSelectMapEditor";
this.btSelectMapEditor.Size = new System.Drawing.Size(221, 22);
this.btSelectMapEditor.Text = "Mapeditor 선택";
this.btSelectMapEditor.Click += new System.EventHandler(this.btSelectMapEditor_Click);
//
// toolStripSeparator4
//
this.toolStripSeparator4.Name = "toolStripSeparator4";
@@ -434,7 +443,8 @@ namespace AGVSimulator.Forms
this._statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this._statusLabel,
this._coordLabel,
this.prb1});
this.prb1,
this.sbFile});
this._statusStrip.Location = new System.Drawing.Point(0, 689);
this._statusStrip.Name = "_statusStrip";
this._statusStrip.Size = new System.Drawing.Size(1248, 22);
@@ -457,6 +467,12 @@ namespace AGVSimulator.Forms
this.prb1.Name = "prb1";
this.prb1.Size = new System.Drawing.Size(200, 16);
//
// sbFile
//
this.sbFile.Name = "sbFile";
this.sbFile.Size = new System.Drawing.Size(17, 17);
this.sbFile.Text = "--";
//
// _controlPanel
//
this._controlPanel.BackColor = System.Drawing.SystemColors.Control;
@@ -531,6 +547,7 @@ namespace AGVSimulator.Forms
//
// _pathGroup
//
this._pathGroup.Controls.Add(this.button1);
this._pathGroup.Controls.Add(this.btPath2);
this._pathGroup.Controls.Add(this._clearPathButton);
this._pathGroup.Controls.Add(this._targetCalcButton);
@@ -816,12 +833,15 @@ namespace AGVSimulator.Forms
this.timer1.Interval = 500;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// btSelectMapEditor
// button1
//
this.btSelectMapEditor.Name = "btSelectMapEditor";
this.btSelectMapEditor.Size = new System.Drawing.Size(221, 22);
this.btSelectMapEditor.Text = "Mapeditor 선택";
this.btSelectMapEditor.Click += new System.EventHandler(this.btSelectMapEditor_Click);
this.button1.Location = new System.Drawing.Point(21, 201);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(106, 25);
this.button1.TabIndex = 11;
this.button1.Text = "경로 계산2";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// SimulatorForm
//
@@ -937,5 +957,7 @@ namespace AGVSimulator.Forms
private System.Windows.Forms.PropertyGrid propertyNode;
private System.Windows.Forms.Button btPath2;
private System.Windows.Forms.ToolStripMenuItem btSelectMapEditor;
private System.Windows.Forms.ToolStripStatusLabel sbFile;
private System.Windows.Forms.Button button1;
}
}

View File

@@ -876,7 +876,7 @@ namespace AGVSimulator.Forms
try
{
var result = MapLoader.LoadMapFromFile(filePath);
sbFile.Text = filePath;
if (result.Success)
{
Console.WriteLine($"Map File Load : {filePath}");
@@ -1291,7 +1291,7 @@ namespace AGVSimulator.Forms
var flags = new List<string>();
if (info.CanRotate) flags.Add("회전가능");
if (info.IsTurn) flags.Add("회전");
if (info.IsDirectionChangePoint) flags.Add("방향전환");
if (info.RequiresSpecialAction) flags.Add($"특수동작:{info.SpecialActionDescription}");
if (info.MagnetDirection != MagnetDirection.Straight) flags.Add($"마그넷:{info.MagnetDirection}");
@@ -1322,6 +1322,8 @@ namespace AGVSimulator.Forms
else if (motorInfo.IsDirectionChangePoint && motorInfo.CanRotate)
motorSymbol += "[↻]";
if (motorInfo.IsTurn) motorSymbol = "[TURN]";
pathWithDetails.Add($"{rfidId}{motorSymbol}");
}
@@ -1596,7 +1598,7 @@ namespace AGVSimulator.Forms
MotorDirection = directionName,
CurrentPosition = GetNodeDisplayName(currentNode),
TargetPosition = GetNodeDisplayName(targetNode),
DockingPosition = (targetNode.StationType == StationType.Charger1 || targetNode.StationType == StationType.Charger2) ? "충전기" : "장비"
DockingPosition = (targetNode.StationType == Station.Charger) ? "충전기" : "장비"
};
if (calcResult.Success)
@@ -1849,8 +1851,15 @@ namespace AGVSimulator.Forms
// 첫 번째 AGV의 다음 행동 예측
var agv = _agvList[0];
try
{
var command = agv.Predict();
this.lbPredict.Text = $"Motor:{command.Motor},Magnet:{command.Magnet},Speed:{command.Speed} : {command.Message}";
}catch ( Exception ex)
{
lbPredict.Text = "예측오류" + ex.Message;
}
}
@@ -2588,7 +2597,21 @@ namespace AGVSimulator.Forms
this._simulatorCanvas.HighlightNodeId = (result.Gateway?.Id ?? string.Empty);
return result;
}
/// <summary>
/// 길목(Gateway) 기반 경로 계산
/// 버퍼-버퍼 상태에서는 별도의 추가 로직을 적용합니다
/// </summary>
public AGVPathResult CalcPath_New(MapNode startNode, MapNode targetNode, List<MapNode> nodes,
MapNode prevNode, AgvDirection prevDir)
{
// Core Logic으로 이관됨
var pathFinder = new AGVPathfinder(nodes);
var result = pathFinder.CalculateScriptedPath(startNode, targetNode, prevNode, prevDir);
//게이트웨이노드를 하이라이트강조 한단
this._simulatorCanvas.HighlightNodeId = (result.Gateway?.Id ?? string.Empty);
return result;
}
private void ApplyResultToSimulator(AGVPathResult result, VirtualAGV agv)
{
_simulatorCanvas.CurrentPath = result;
@@ -2622,5 +2645,33 @@ namespace AGVSimulator.Forms
}
}
}
private void button1_Click(object sender, EventArgs e)
{
// 1. 기본 정보 획득
if (_startNodeCombo.SelectedItem == null || _startNodeCombo.Text == "선택하세요") SetStartNodeFromAGVPosition();
if (_startNodeCombo.SelectedItem == null || _targetNodeCombo.SelectedItem == null)
{
MessageBox.Show("시작/목표 노드를 확인하세요");
return;
}
//var selectedAGV = _agvListCombo.SelectedItem as VirtualAGV;
//if (selectedAGV == null) return AGVPathResult.CreateFailure("Virtual AGV 없음");
var selectedAGV = _agvListCombo.SelectedItem as VirtualAGV;
// 경로계산2 (Gateway Logic)
var startNode = (_startNodeCombo.SelectedItem as ComboBoxItem<MapNode>)?.Value;
var targetNode = (_targetNodeCombo.SelectedItem as ComboBoxItem<MapNode>)?.Value;
var rlt = CalcPath_New(startNode, targetNode, this._simulatorCanvas.Nodes, selectedAGV.PrevNode, selectedAGV.PrevDirection);
if (rlt.Success == false) MessageBox.Show(rlt.Message, "알림", MessageBoxButtons.OK, MessageBoxIcon.Information);
else
{
// 8. 적용
ApplyResultToSimulator(rlt, selectedAGV);
UpdateAdvancedPathDebugInfo(rlt);
}
}
}
}

13
AGVLogic/EnigProtocol/.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
obj
bin
*.user
*.v12
*.suo
.git
.vs
Debug
__vm
*.pdb
desktop.ini
packages
~*.xlsx

View File

@@ -0,0 +1,53 @@
using Xunit;
using ENIG;
namespace ENIGProtocol.Tests
{
public class EEProtocolTests
{
[Fact]
public void TestCRC16Calculation()
{
// 테스트 데이터
byte[] testData = new byte[] { 0x02,0x00,0xFF }; //payload에는 stx, len, ... crc,etx 는 제외한다
// CRC16 계산
var protocol = new EEProtocol();
ushort crc = protocol.CalculateCRC16(testData);
// 예상 결과와 비교
Assert.Equal(0x1789, crc);
}
[Fact]
public void TestPacketCreation()
{
// 패킷 생성 테스트
var protocol = new EEProtocol();
byte[] packet = protocol.CreatePacket(0x01, 0x02, new byte[] { 0x03, 0x04 });
// 패킷 구조 검증
Assert.Equal(0x02, packet[0]); // STX
Assert.Equal(0x04, packet[1]); // Length
Assert.Equal(0x01, packet[2]); // ID
Assert.Equal(0x02, packet[3]); // Command
Assert.Equal(0x03, packet[4]); // Data[0]
Assert.Equal(0x04, packet[5]); // Data[1]
}
[Fact]
public void TestPacketParsing()
{
// 패킷 파싱 테스트
var protocol = new EEProtocol();
//byte[] testPacket = new byte[] { 0x02, 0x04, 0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x03 };
byte[] testPacket = new byte[] { 0x02, 0x02, 0x00, 0xFF, 0x89, 0x17, 0x03 };
bool result = protocol.ParsePacket(testPacket);
Assert.True(result);
}
}
}

View File

@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\enigprotocol\enigprotocol.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
namespace ENIGProtocol.Tests;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}

View File

@@ -0,0 +1,43 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 15 for Windows Desktop
VisualStudioVersion = 15.0.28307.1000
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "솔루션 항목", "솔루션 항목", "{0A11874A-E5C6-4170-9787-1FFF7AF0D289}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
ReadMe.MD = ReadMe.MD
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleProject", "sample\SampleProject.csproj", "{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol.Tests", "ENIGProtocol.Tests\ENIGProtocol.Tests.csproj", "{3A677629-1F08-49B2-BC75-58282E439FD4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ENIGProtocol", "enigprotocol\ENIGProtocol.csproj", "{499D8912-4B96-41E5-A70D-CFE797883D65}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAB31C8A-7DCF-4152-8A82-76F3C10BABA4}.Release|Any CPU.Build.0 = Release|Any CPU
{3A677629-1F08-49B2-BC75-58282E439FD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A677629-1F08-49B2-BC75-58282E439FD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A677629-1F08-49B2-BC75-58282E439FD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A677629-1F08-49B2-BC75-58282E439FD4}.Release|Any CPU.Build.0 = Release|Any CPU
{499D8912-4B96-41E5-A70D-CFE797883D65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{499D8912-4B96-41E5-A70D-CFE797883D65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{499D8912-4B96-41E5-A70D-CFE797883D65}.Release|Any CPU.ActiveCfg = Release|Any CPU
{499D8912-4B96-41E5-A70D-CFE797883D65}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {07331835-C46C-4B93-965F-AD2714F97F88}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,246 @@
# ENIG Protocol
ENIG 프로토콜 통신 라이브러리
**Explanation of the README Content:**
1. **Title and Overview:** Clearly states the purpose of the library.
2. **Key Components:** Explains the main building blocks:
* `DeviceType` enum: Lists the device types.
* `Packet` class: Describes the packet structure.
* `EEProtocol` class: Explains its role in packet handling.
3. **Key Features:** Details the core functionalities of the `EEProtocol` class:
* Packet creation.
* Packet parsing.
* Data reception.
* Event-driven nature.
* CRC16 calculation.
4. **Usage:** Provides code examples for:
* Creating a packet.
* Parsing a packet.
* Processing received data.
5. **Error Handling:** Explains how the library handles invalid data and incomplete packets.
6. **Dependencies:** Lists any required frameworks or libraries.
7. **License:** Placeholder for the project's license.
This README provides a comprehensive overview of the `ENIGProtocol` library, making it easy for other developers to understand and use it. I hope this is helpful!
## 개발 환경
- Frameworks : .NET Standard 2.0
- Visual Studio 2022 또는 Visual Studio Code
## 프로젝트 구조
- `EEProtocol.cs`: ENIG 프로토콜 구현
- `EEProtocolTests.cs`: 단위 테스트 코드
- `Sample`: C# Winform 샘플 프로젝트
## 장비 목록
```
public enum DeviceType : byte
{
ACS = 0,
AGV1 = 10+1,
AGV2 = 10+2,
BUFFER1 = 20+1,
BUFFER2 = 20+2,
BUFFER3 = 20+3,
BUFFER4 = 20+4,
BUFFER5 = 20+5,
DOOR = 30,
}
```
public enum DeviceAlias : byte
{
B1 = 20 + 1, //BUFFER1 ~ 5
B2 = 20 + 2,
B3 = 20 + 3,
B4 = 20 + 4,
B5 = 20 + 5,
C1 = 40 + 1, //충전소 1
C2 = 40 + 2, //충전소 2
C3 = 40 + 3, //충전소 3
C4 = 40 + 4, //충전소 4
E1 = 90 + 1, //장비1 (SSOTRON Loader)
E2 = 90 + 2, //장비2 (TOPS ENIG)
E3 = 90 + 3, //장비3 (SSOTRON DIVERTER)
}
//11번 AGV야! BUFFER1로 이동해라!
//0x02 0x03 0x0B 0x6B 0x42 0x31 {CRC} 0x03
### 기본 패킷 구조
```
[STX][LEN][ID][CMD][DATA][CRC16][ETX]
```
- **STX (Start of Text)**: 0x02
- **LEN (Length)**: 데이터 길이 (1바이트) = {CMD+DATA}
- **ID (Client ID)**: 데이터 길이 (1바이트) : 디바이스식별코드(=DeviceType)
- **CMD (Command)**: 명령어 코드 (1바이트)
- **DATA**: 명령어에 따른 데이터 (가변 길이)
- **CRC16**: 데이터 무결성 검사 (2바이트)
- **ETX (End of Text)**: 0x03
### 통신 방향 (호스트=ACS, 장비=agv,buffer,door)
- H -> E: 호스트에서 장비로 전송
- E -> H: 장비에서 호스트로 전송
### 명령어 목록
1. **ACS (AGV Control System)**
2. **Buffer**
- E -> H | cmd(3): 상태 (data len=1 : 0=카트없음, 1=카트있음, 2=바쁨, 3=알수없음, 255=오류)
- H -> E | cmd(1): Lock
- Target[1] = {DeviceType}
- H -> E | cmd(2): UnLock
- Target[1] = {DeviceType}
3. **AGV**
- H -> E | Move : cmd(100) : 대상태그까지 이동(자동이동)
- Target[1] = {DeviceType}
- TagID[4] = "0000"
- H -> E | Stop : cmd(101) : 멈춤
- H -> E | Reset : cmd(102) : 오류 소거
- H -> E | SetCurrent : cmd(103) : 현재위치설정
- Target[1] = {DeviceType}
- TagID[4] = "0000"
- H -> E | MoveManual : cmd(104) : 메뉴얼이동
- Target[1] = {DeviceType}
- Direction[1] : 0=Backward, 1=Forward, 2=TurnLeft, 3=TurnRight
- Speed[1] : 0=Slow, 1=Normal, 2=Fast
- H -> E | MarkStop : cmd(105) : 마크센서스톱
- Target[1] = {DeviceType}
- H -> E | Lift Control : cmd(106) : 리프트제어
- Target[1] = {DeviceType}
- Action[1] : 0=STOP, 1=UP, 2=DOWN
- H -> E | Move : cmd(107) : 대상별칭까지 이동(자동이동)
- Target[1] = {DeviceType}
- AliasName[n] = ".....
- H -> E | MoveAuto : cmd(108) : 자동이동
- Target[1] = {DeviceType}
- MotDirection[1] : 0=Backward, 1=Forward
- MagnetDirection[1] : 0=Straight,1=Left, 2=Right
- Speed[1] : 0=Slow, 1=Normal, 2=Fast
- H -> E | Charge On: cmd(109) : 충전실행(충전기 이동 후 자동 충전 진행)
- Target[1] = {DeviceType}
- Action[1] : 0=Charge Off, 1=Charge On
- E -> H | Move Complete : cmd(1) : 목적지이동완료 후 전송
- TagID[4] : "0000"
- E -> H | TagID Received : cmd(2) : 태그값 인식시 전송
- TagID[4] : "0000"
- E -> H | Status : cmd(3)
- Mode[1] : 0=manual, 1=auto
- RunSt[1] : 0=stop, 1=run, 2=error
- Diection[1] : 0=straight, 1=left, 2=right, 3=markstop
- Inposition[1] : 0=off, 1=on : 목적위치에 도달완료 시 설정 이동 이동시 OFF됨
- ChargeSt[1] : 0=off, 1=on
- CartSt[1] : 0=off, 1=on, 2=unknown
- LiftSt[1] : 0=down , 1=up, 2=unknown
- LastTag[4] : "0000"
- CurrentPath[1] : Path ID , 0=미설정, 1~255(순차증가)
4. **Door**
- H -> E | cmd(1): 출입문 열기
- H -> E | cmd(2): 출입문 닫기
- E -> H | cmd(3): 출입문 상태 (data len=1 : 0=닫힘, 1=열림, 2=바쁨, 3=알수없음, 255=오류)
### CRC16 계산
- CRC16 다항식 사용
- 초기값: 0xFFFF
- 데이터 무결성 검증에 사용
#### CRC-16 테이블 값
```
0x0000, 0x408E, 0x73EF, 0x3361, 0x152D, 0x55A3, 0x66C2, 0x264C,
0x2A5A, 0x6AD4, 0x59B5, 0x193B, 0x3F77, 0x7FF9, 0x4C98, 0x0C16,
0x54B4, 0x143A, 0x275B, 0x67D5, 0x4199, 0x0117, 0x3276, 0x72F8,
0x7EEE, 0x3E60, 0x0D01, 0x4D8F, 0x6BC3, 0x2B4D, 0x182C, 0x58A2,
0x5B9B, 0x1B15, 0x2874, 0x68FA, 0x4EB6, 0x0E38, 0x3D59, 0x7DD7,
0x71C1, 0x314F, 0x022E, 0x42A0, 0x64EC, 0x2462, 0x1703, 0x578D,
0x0F2F, 0x4FA1, 0x7CC0, 0x3C4E, 0x1A02, 0x5A8C, 0x69ED, 0x2963,
0x2575, 0x65FB, 0x569A, 0x1614, 0x3058, 0x70D6, 0x43B7, 0x0339,
0x45C5, 0x054B, 0x362A, 0x76A4, 0x50E8, 0x1066, 0x2307, 0x6389,
0x6F9F, 0x2F11, 0x1C70, 0x5CFE, 0x7AB2, 0x3A3C, 0x095D, 0x49D3,
0x1171, 0x51FF, 0x629E, 0x2210, 0x045C, 0x44D2, 0x77B3, 0x373D,
0x3B2B, 0x7BA5, 0x48C4, 0x084A, 0x2E06, 0x6E88, 0x5DE9, 0x1D67,
0x1E5E, 0x5ED0, 0x6DB1, 0x2D3F, 0x0B73, 0x4BFD, 0x789C, 0x3812,
0x3404, 0x748A, 0x47EB, 0x0765, 0x2129, 0x61A7, 0x52C6, 0x1248,
0x4AEA, 0x0A64, 0x3905, 0x798B, 0x5FC7, 0x1F49, 0x2C28, 0x6CA6,
0x60B0, 0x203E, 0x135F, 0x53D1, 0x759D, 0x3513, 0x0672, 0x46FC,
0x7979, 0x39F7, 0x0A96, 0x4A18, 0x6C54, 0x2CDA, 0x1FBB, 0x5F35,
0x5323, 0x13AD, 0x20CC, 0x6042, 0x460E, 0x0680, 0x35E1, 0x756F,
0x2DCD, 0x6D43, 0x5E22, 0x1EAC, 0x38E0, 0x786E, 0x4B0F, 0x0B81,
0x0797, 0x4719, 0x7478, 0x34F6, 0x12BA, 0x5234, 0x6155, 0x21DB,
0x22E2, 0x626C, 0x510D, 0x1183, 0x37CF, 0x7741, 0x4420, 0x04AE,
0x08B8, 0x4836, 0x7B57, 0x3BD9, 0x1D95, 0x5D1B, 0x6E7A, 0x2EF4,
0x7656, 0x36D8, 0x05B9, 0x4537, 0x637B, 0x23F5, 0x1094, 0x501A,
0x5C0C, 0x1C82, 0x2FE3, 0x6F6D, 0x4921, 0x09AF, 0x3ACE, 0x7A40,
0x3CBC, 0x7C32, 0x4F53, 0x0FDD, 0x2991, 0x691F, 0x5A7E, 0x1AF0,
0x16E6, 0x5668, 0x6509, 0x2587, 0x03CB, 0x4345, 0x7024, 0x30AA,
0x6808, 0x2886, 0x1BE7, 0x5B69, 0x7D25, 0x3DAB, 0x0ECA, 0x4E44,
0x4252, 0x02DC, 0x31BD, 0x7133, 0x577F, 0x17F1, 0x2490, 0x641E,
0x6727, 0x27A9, 0x14C8, 0x5446, 0x720A, 0x3284, 0x01E5, 0x416B,
0x4D7D, 0x0DF3, 0x3E92, 0x7E1C, 0x5850, 0x18DE, 0x2BBF, 0x6B31,
0x3393, 0x731D, 0x407C, 0x00F2, 0x26BE, 0x6630, 0x5551, 0x15DF,
0x19C9, 0x5947, 0x6A26, 0x2AA8, 0x0CE4, 0x4C6A, 0x7F0B, 0x3F85,
```
#### CRC16 계산 테이블 생성 코드
```csharp
const ushort polynomial = 0x7979;
ushort[] CRC16_TABLE = new ushort[256];
for (ushort i = 0; i < CRC16_TABLE.Length; i++)
{
ushort value = 0;
ushort temp = i;
for (byte j = 0; j < 8; j++)
{
if (((value ^ temp) & 0x0001) != 0)
{
value = (ushort)((value >> 1) ^ polynomial);
}
else
{
value >>= 1;
}
temp >>= 1;
}
CRC16_TABLE[i] = value;
}
```
#### CRC16 계산 예시
```csharp
ushort CalculateCRC16(byte[] data)
{
ushort crc = 0xFFFF;
for (int i = 0; i < data.Length; i++)
{
byte index = (byte)(crc ^ data[i]);
crc = (ushort)((crc >> 8) ^ CRC16_TABLE[index]);
}
return crc;
}
```
## 라이센스

View File

@@ -0,0 +1,8 @@
################################################################################
# 이 .gitignore 파일은 Microsoft(R) Visual Studio에서 자동으로 만들어졌습니다.
################################################################################
/obj
/bin
/.vs
/.git

View File

@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ENIGProtocol
{
/// <summary>
/// host -> eq
/// </summary>
public enum AGVCommandHE : byte
{
Goto = 100,
Stop = 101,
Reset = 102,
SetCurrent = 103,
Manual = 104,
MarkStop = 105,
LiftControl = 106,
GotoAlias = 107,
AutoMove = 108,
ChargeControl = 109,
Charger = 112,
LTurn = 113,
RTurn = 114,
LTurn180 = 115,
RTurn180 = 116,
PickOnEnter = 117,
PickOffEnter = 118,
PickOnExit = 119,
PickOffExit = 120,
}
/// <summary>
/// eq -> host
/// </summary>
public enum AGVCommandEH : byte
{
Error = 1,
Arrived = 2,
ReadRFID = 3,
ActionComplete=4,
Status = 9,
}
public enum AGVErrorCode : byte
{
None = 0,
PredictFix,
TurnTimeout,
TurnError,
EmptyNode,
Goto,
ManualMode,
UnknownCommand,
UnknownAlias,
// Operational Errors
CART_EXIST,
MARK_TIMEOUT,
MARK_SENSOR_FAIL,
LIFT_ERROR,
AGV_SPEED_SET_FAIL,
AGV_RUN_FAIL,
AGV_STOP_FAIL,
PATH_INTEGRITY_FAIL,
TURN_FAIL,
NO_CHARGEPOINT,
NOTSET_CHARGEPOINT,
ALREADY_CHARGE,
CHARGE_RETRY_OVER,
MAGNET_ON_ERROR,
MAGNET_OF_ERROR,
BUFFER_NOT_COMPLETE,
MARK_STOP_FAIL,
LIDAR_STOP,
NOT_BUFFERPOINT,
NOT_EQUIPMENTPOINT,
PATH_COMPLETE_INTEGRITY_FAIL,
UPDATEMOTION_TIMEOUT
}
public static class AGVUtility
{
/// <summary>
/// 에러코드에 해당하는 오류메세지를 반환 합니다
/// </summary>
/// <param name="ecode"></param>
/// <returns></returns>
public static string GetAGVErrorMessage(AGVErrorCode ecode)
{
switch (ecode)
{
case AGVErrorCode.None: return "No Error";
case AGVErrorCode.PredictFix: return "이동 예측이 동작하지 않습니다";
case AGVErrorCode.TurnTimeout: return "회전작업 시간초과";
case AGVErrorCode.TurnError: return "회전작업이 완료되지 않았습니다";
case AGVErrorCode.EmptyNode: return "노드정보를 찾을 수 없습니다";
case AGVErrorCode.Goto: return "이동 명령 오류";
case AGVErrorCode.ManualMode: return "자동운전 상태가 아닙니다";
case AGVErrorCode.UnknownCommand: return "알수 없는 명령입니다";
case AGVErrorCode.UnknownAlias: return "알수 없는 별칭 입니다";
case AGVErrorCode.CART_EXIST: return "카트 감지 센서 오류";
case AGVErrorCode.MARK_TIMEOUT: return "마크 정지 신호 시간초과";
case AGVErrorCode.MARK_SENSOR_FAIL: return "마크 센서 미감지";
case AGVErrorCode.LIFT_ERROR: return "리프트 동작 오류";
case AGVErrorCode.AGV_SPEED_SET_FAIL: return "AGV 속도 설정 실패";
case AGVErrorCode.AGV_RUN_FAIL: return "AGV 구동 실패";
case AGVErrorCode.AGV_STOP_FAIL: return "AGV 정지 실패";
case AGVErrorCode.PATH_INTEGRITY_FAIL: return "경로 무결성 검증 실패";
case AGVErrorCode.TURN_FAIL: return "턴 동작 실패";
case AGVErrorCode.NO_CHARGEPOINT: return "충전 위치 아님";
case AGVErrorCode.NOTSET_CHARGEPOINT: return "충전기 노드 미설정";
case AGVErrorCode.ALREADY_CHARGE: return "이미 충전 중 상태임";
case AGVErrorCode.CHARGE_RETRY_OVER: return $"충전명령 재전송 횟수 초과";
case AGVErrorCode.NOT_BUFFERPOINT: return "현재 위치가 버퍼가 아닙니다";
case AGVErrorCode.NOT_EQUIPMENTPOINT: return "현재 위치가 장비 노드가 아닙니다";
case AGVErrorCode.PATH_COMPLETE_INTEGRITY_FAIL: return "목적지 도착 완료 했으나 노드 혹은 방향이 일치지하지 않습니다";
default: return ecode.ToString();
}
}
}
}

View File

@@ -0,0 +1,235 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ENIG
{
// 장비 타입 정의
public enum DeviceType
{
ACS = 0,
AGV1 = 10,
AGV2 = 11,
BUFFER1 = 20,
BUFFER2 = 21,
BUFFER3 = 22,
BUFFER4 = 23,
BUFFER5 = 24,
DOOR = 30,
}
public partial class EEProtocol
{
// 패킷 수신 이벤트 정의
// 데이터 수신 이벤트 정의
public event EventHandler<DataEventArgs> OnDataReceived;
public event EventHandler<MessageEventArgs> OnMessage;
// CRC16 계산을 위한 테이블
private static readonly ushort[] CRC16_TABLE = new ushort[256];
// CRC16 테이블 초기화
public EEProtocol()
{
const ushort polynomial = 0x7979;
for (ushort i = 0; i < CRC16_TABLE.Length; i++)
{
ushort value = 0;
ushort temp = i;
for (byte j = 0; j < 8; j++)
{
if (((value ^ temp) & 0x0001) != 0)
{
value = (ushort)((value >> 1) ^ polynomial);
}
else
{
value >>= 1;
}
temp >>= 1;
}
CRC16_TABLE[i] = value;
}
//// CRC 테이블 출력
//Console.WriteLine("CRC16 테이블 값:");
//for (int i = 0; i < CRC16_TABLE.Length; i++)
//{
// if (i % 8 == 0)
// {
// Console.WriteLine();
// }
// Console.Write($"0x{CRC16_TABLE[i]:X4}, ");
//}
//Console.WriteLine();
}
// CRC16 계산 메서드
public ushort CalculateCRC16(byte[] data)
{
ushort crc = 0xFFFF;
for (int i = 0; i < data.Length; i++)
{
byte index = (byte)(crc ^ data[i]);
crc = (ushort)((crc >> 8) ^ CRC16_TABLE[index]);
}
return crc;
}
// 패킷 생성 메서드
public byte[] CreatePacket(byte id, byte command, byte[] data)
{
var packet = new Packet
{
ID = id,
Command = command,
Data = data ?? new byte[0],
Length = (byte)(1 + 1 + (data?.Length ?? 0)) // ID + Command + Data 길이
};
// 패킷 조립
List<byte> packetData = new List<byte>();
packetData.Add(Packet.STX);
packetData.Add(packet.Length);
packetData.Add(packet.ID);
packetData.Add(packet.Command);
if (packet.Data != null)
packetData.AddRange(packet.Data);
// CRC16 계산
packet.CRC16 = CalculateCRC16(packetData.Skip(1).ToArray()); // STX 제외하고 계산
packetData.AddRange(BitConverter.GetBytes(packet.CRC16));
packetData.Add(Packet.ETX);
return packetData.ToArray();
}
//패킷테스트
public void PacketTest(byte[] rawData)
{
var hexstr = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage( $"TestPacket : {hexstr}");
ParsePacket(rawData);
}
//메세지 발생
public void RaiseMessage(string message, bool isError = false)
{
OnMessage?.Invoke(this, new MessageEventArgs { IsError = isError, Message = message });
}
// 패킷 파싱 메서드
public bool ParsePacket(byte[] rawData)
{
try
{
if (rawData.Length < 7) // 최소 패킷 크기
{
var hexstring = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage($"Too Short Data:{hexstring}");
return false;
}
if (rawData[0] != Packet.STX || rawData[rawData.Length - 1] != Packet.ETX)
{
var hexstring = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage($"STX/ETX Error Data:{hexstring}");
return false;
}
byte length = rawData[1];
if (length + 5 != rawData.Length) // STX + Length + CRC16(2) + ETX = 5
{
var hexstring = string.Join(" ", rawData.Select(t => t.ToString("X2")));
RaiseMessage($"Length Error ({length+5} != {rawData.Length}) Data:{hexstring}");
return false;
}
// CRC16 검증
byte[] dataForCrc = rawData.Skip(1).Take(length + 1).ToArray();
ushort calculatedCrc = CalculateCRC16(dataForCrc);
ushort receivedCrc = BitConverter.ToUInt16(rawData, rawData.Length - 3);
if (receivedCrc != 0xFFFF && calculatedCrc != receivedCrc) //FF 무시
{
RaiseMessage($"CRC Error ID:{rawData[2]:X2},CMD:{rawData[3]:X2}", true);
return false;
}
// 패킷 생성
var packet = new Packet
{
Length = length,
ID = rawData[2],
Command = rawData[3],
Data = rawData.Skip(4).Take(length - 2).ToArray(), // ID와 Command 길이(2) 제외
CRC16 = receivedCrc,
RawData = rawData,
};
// 이벤트 발생
OnDataReceived?.Invoke(this, new DataEventArgs { ReceivedPacket = packet });
return true;
}
catch(Exception ex)
{
RaiseMessage(ex.Message, true);
return false;
}
}
// 데이터 수신 처리 메서드 (시리얼 포트에서 데이터를 받았을 때 호출)
private List<byte> buffer = new List<byte>();
private int ProtocolParseError = 0;
public void ProcessReceivedData(byte[] data)
{
buffer.AddRange(data);
while (buffer.Count > 0)
{
// STX 찾기
int stxIndex = buffer.FindIndex(b => b == Packet.STX);
if (stxIndex == -1)
{
buffer.Clear();
break;
}
// 불필요한 데이터 제거
if (stxIndex > 0)
buffer.RemoveRange(0, stxIndex);
// 패킷 길이 확인을 위한 최소 데이터 확인
if (buffer.Count < 2)
break;
int expectedLength = buffer[1] + 5; // 전체 패킷 길이
if (buffer.Count < expectedLength)
break;
// 패킷 추출 및 처리
byte[] packetData = buffer.Take(expectedLength).ToArray();
buffer.RemoveRange(0, expectedLength);
var parseOK = ParsePacket(packetData);
if(parseOK==false) //분석이 실패되었다면 해당 데이터는 삭제한다.
{
ProtocolParseError += 1;
if (ProtocolParseError > 3) buffer.Clear();
} else ProtocolParseError = 0;
if(buffer.Any())
{
System.Threading.Thread.Sleep(1);
}
}
}
}
}

View File

@@ -0,0 +1,57 @@
<?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>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{9365803B-933D-4237-93C7-B502C855A71C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>enigprotocol</RootNamespace>
<AssemblyName>enigprotocol</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Commands.cs" />
<Compile Include="EEProtocol.cs" />
<Compile Include="EventArgs.cs" />
<Compile Include="Packet.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include=".gitignore" />
<None Include="ReadMe.MD" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,18 @@
using System;
namespace ENIG
{
public partial class EEProtocol
{
public class MessageEventArgs : EventArgs
{
public string Message { get; set; }
public bool IsError { get; set; }
}
public class DataEventArgs : EventArgs
{
public Packet ReceivedPacket { get; set; }
}
}
}

View File

@@ -0,0 +1,20 @@
namespace ENIG
{
// 패킷 구조체
public class Packet
{
public const byte STX = 0x02;
public const byte ETX = 0x03;
public byte Length { get; set; }
public byte ID { get; set; }
public byte Command { get; set; }
public byte[] Data { get; set; }
public ushort CRC16 { get; set; }
public byte[] RawData { get; set; }
public Packet()
{
Data = new byte[0];
}
}
}

View File

@@ -5,11 +5,11 @@ using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("ClassLibrary1")]
[assembly: AssemblyTitle("enigprotocol")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary1")]
[assembly: AssemblyProduct("enigprotocol")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("19675e19-eb91-493e-88c3-32b3c094b749")]
[assembly: Guid("9365803b-933d-4237-93c7-b502c855a71c")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//

View File

@@ -0,0 +1,236 @@
# ENIG Protocol
ENIG 프로토콜 통신 라이브러리
**Explanation of the README Content:**
1. **Title and Overview:** Clearly states the purpose of the library.
2. **Key Components:** Explains the main building blocks:
* `DeviceType` enum: Lists the device types.
* `Packet` class: Describes the packet structure.
* `EEProtocol` class: Explains its role in packet handling.
3. **Key Features:** Details the core functionalities of the `EEProtocol` class:
* Packet creation.
* Packet parsing.
* Data reception.
* Event-driven nature.
* CRC16 calculation.
4. **Usage:** Provides code examples for:
* Creating a packet.
* Parsing a packet.
* Processing received data.
5. **Error Handling:** Explains how the library handles invalid data and incomplete packets.
6. **Dependencies:** Lists any required frameworks or libraries.
7. **License:** Placeholder for the project's license.
This README provides a comprehensive overview of the `ENIGProtocol` library, making it easy for other developers to understand and use it. I hope this is helpful!
## 개발 환경
- Frameworks : .NET Standard 2.0
- Visual Studio 2022 또는 Visual Studio Code
## 프로젝트 구조
- `EEProtocol.cs`: ENIG 프로토콜 구현
- `EEProtocolTests.cs`: 단위 테스트 코드
- `Sample`: C# Winform 샘플 프로젝트
### Xbee Setting value
- **NARMI 70 : AGV No 70
- **NARMI 70 (LIFT) : P46A6,C17,DH:0,DL:FFFF,MY40
- **NARMI 70 (AGV) : P46A6,C17,DH:0,DL:FFFF,MY41
- **NARMI 77 : AGV No 71
- **NARMI 71 (LIFT) : P46A6,C17,DH:0,DL:FFFF,MY30
- **NARMI 71 (AGV) : P46A6,C17,DH:0,DL:FFFF,MY31
- **충전기04 : P46A6,C17,DH:0,DL:FFFF,MY41
- **충전기71 : P46A6,C17,DH:0,DL:FFFF,MY46
- **ACS : P46A5,C17,DH:0,DL:FFFF,MY10
- **BUFFER : P46A5,C17,DH:0,DL:FFFF,MY60~65
- **AGV1 : P46A5,C17,DH:0,DL:FFFF,MY50
- **AGV2 : P46A5,C17,DH:0,DL:FFFF,MY51
- **DOOR : P46A5,C17,DH:0,DL:FFFF,MY30
## 장비 목록
```
public enum DeviceType : byte
{
ACS = 0,
AGV1 = 10+1,
AGV2 = 10+2,
BUFFER1 = 20+1,
BUFFER2 = 20+2,
BUFFER3 = 20+3,
BUFFER4 = 20+4,
BUFFER5 = 20+5,
DOOR = 30,
}
```
### 기본 패킷 구조
```
[STX][LEN][ID][CMD][DATA][CRC16][ETX]
```
- **STX (Start of Text)**: 0x02
- **LEN (Length)**: 데이터 길이 (1바이트) = {ID+CMD+DATA}
- **ID (Client ID)**: 데이터 길이 (1바이트) : 디바이스식별코드(=DeviceType)
- **CMD (Command)**: 명령어 코드 (1바이트)
- **DATA**: 명령어에 따른 데이터 (가변 길이)
- **CRC16**: 데이터 무결성 검사 (2바이트)
- **ETX (End of Text)**: 0x03
### 통신 방향 (호스트=ACS, 장비=agv,buffer,door)
- H -> E: 호스트에서 장비로 전송
- E -> H: 장비에서 호스트로 전송
### 명령어 목록
1. **ACS (AGV Control System)**
2. **Buffer**
- E -> H | cmd('S'): 상태 (............) BIT & 1BYTE 0:CART1, 1:CART2, 2:BASKET1, 3:BASKET2, 4:OPEN, 5:CLOSE
- H -> E | cmd('L'): Lock
- Target[1] = {DeviceType}
- H -> E | cmd('U'): UnLock
- Target[1] = {DeviceType}
3. **AGV**
- H -> E | Move : cmd(100) : 대상태그까지 이동(자동이동)
- Target[1] = {DeviceType}
- TagID[4] = "0000"
- H -> E | Move : cmd(107) : 대상별칭까지 이동(자동이동)
- Target[1] = {DeviceType}
- AliasName[n] = "....."
- H -> E | Stop : cmd(101) : 멈춤
- H -> E | Reset : cmd(102) : 오류 소거
- H -> E | Charge On: cmd(103) : 충전실행(충전기 이동 후 자동 충전 진행)
- Target[1] = {DeviceType}
- Action[1] : 0=Charge Off, 1=Charge On
- H -> E | MoveManual : cmd(104) : 메뉴얼이동
- Target[1] = {DeviceType}
- Direction[1] : 0=Backward, 1=Forward, 2=TurnLeft, 3=TurnRight
- Speed[1] : 0=Slow, 1=Normal, 2=Fast
- Runtime[1] : 0 second
- H -> E | MarkStop : cmd(105) : 마크센서스톱
- Target[1] = {DeviceType}
- H -> E | Lift Control : cmd(106) : 리프트제어
- Target[1] = {DeviceType}
- Action[1] : 0=STOP, 1=UP, 2=DOWN
- E -> H | Move Complete : cmd(1) : 목적지이동완료 후 전송
- TagID[4] : "0000"
- E -> H | TagID Received : cmd(2) : 태그값 인식시 전송
- TagID[4] : "0000"
- E -> H | Status : cmd(3) - 총 12바이트
- Mode[1] : 0=manual, 1=auto
- RunSt[1] : 0=stop, 1=run, 2=error
MotDirection[1] : 0:Forward, 1:Backward, 0xFF:unknown
- MagDiection[1] : 0=straight, 1=left, 2=right , 0xFF:unknown
- Inposition[1] : 0=off, 1=on : 목적위치에 도달완료 시 설정 이동 이동시 OFF됨
- ChargeSt[1] : 0=off, 1=on
- CartSt[1] : 0=off, 1=on, 2=unknown
- LiftSt[1] : 0=down , 1=up, 2=unknown
- LastTag[4] : "0000" (ASCII 4바이트)
4. **Door**
- H -> E | cmd(1): 출입문 열기
- H -> E | cmd(2): 출입문 닫기
- E -> H | cmd(3): 출입문 상태 (data len=1 : 0=닫힘, 1=열림, 2=바쁨, 3=알수없음, 255=오류)
### CRC16 계산
- CRC16 다항식 사용
- 초기값: 0xFFFF
- 데이터 무결성 검증에 사용
#### CRC-16 테이블 값
```
0x0000, 0x408E, 0x73EF, 0x3361, 0x152D, 0x55A3, 0x66C2, 0x264C,
0x2A5A, 0x6AD4, 0x59B5, 0x193B, 0x3F77, 0x7FF9, 0x4C98, 0x0C16,
0x54B4, 0x143A, 0x275B, 0x67D5, 0x4199, 0x0117, 0x3276, 0x72F8,
0x7EEE, 0x3E60, 0x0D01, 0x4D8F, 0x6BC3, 0x2B4D, 0x182C, 0x58A2,
0x5B9B, 0x1B15, 0x2874, 0x68FA, 0x4EB6, 0x0E38, 0x3D59, 0x7DD7,
0x71C1, 0x314F, 0x022E, 0x42A0, 0x64EC, 0x2462, 0x1703, 0x578D,
0x0F2F, 0x4FA1, 0x7CC0, 0x3C4E, 0x1A02, 0x5A8C, 0x69ED, 0x2963,
0x2575, 0x65FB, 0x569A, 0x1614, 0x3058, 0x70D6, 0x43B7, 0x0339,
0x45C5, 0x054B, 0x362A, 0x76A4, 0x50E8, 0x1066, 0x2307, 0x6389,
0x6F9F, 0x2F11, 0x1C70, 0x5CFE, 0x7AB2, 0x3A3C, 0x095D, 0x49D3,
0x1171, 0x51FF, 0x629E, 0x2210, 0x045C, 0x44D2, 0x77B3, 0x373D,
0x3B2B, 0x7BA5, 0x48C4, 0x084A, 0x2E06, 0x6E88, 0x5DE9, 0x1D67,
0x1E5E, 0x5ED0, 0x6DB1, 0x2D3F, 0x0B73, 0x4BFD, 0x789C, 0x3812,
0x3404, 0x748A, 0x47EB, 0x0765, 0x2129, 0x61A7, 0x52C6, 0x1248,
0x4AEA, 0x0A64, 0x3905, 0x798B, 0x5FC7, 0x1F49, 0x2C28, 0x6CA6,
0x60B0, 0x203E, 0x135F, 0x53D1, 0x759D, 0x3513, 0x0672, 0x46FC,
0x7979, 0x39F7, 0x0A96, 0x4A18, 0x6C54, 0x2CDA, 0x1FBB, 0x5F35,
0x5323, 0x13AD, 0x20CC, 0x6042, 0x460E, 0x0680, 0x35E1, 0x756F,
0x2DCD, 0x6D43, 0x5E22, 0x1EAC, 0x38E0, 0x786E, 0x4B0F, 0x0B81,
0x0797, 0x4719, 0x7478, 0x34F6, 0x12BA, 0x5234, 0x6155, 0x21DB,
0x22E2, 0x626C, 0x510D, 0x1183, 0x37CF, 0x7741, 0x4420, 0x04AE,
0x08B8, 0x4836, 0x7B57, 0x3BD9, 0x1D95, 0x5D1B, 0x6E7A, 0x2EF4,
0x7656, 0x36D8, 0x05B9, 0x4537, 0x637B, 0x23F5, 0x1094, 0x501A,
0x5C0C, 0x1C82, 0x2FE3, 0x6F6D, 0x4921, 0x09AF, 0x3ACE, 0x7A40,
0x3CBC, 0x7C32, 0x4F53, 0x0FDD, 0x2991, 0x691F, 0x5A7E, 0x1AF0,
0x16E6, 0x5668, 0x6509, 0x2587, 0x03CB, 0x4345, 0x7024, 0x30AA,
0x6808, 0x2886, 0x1BE7, 0x5B69, 0x7D25, 0x3DAB, 0x0ECA, 0x4E44,
0x4252, 0x02DC, 0x31BD, 0x7133, 0x577F, 0x17F1, 0x2490, 0x641E,
0x6727, 0x27A9, 0x14C8, 0x5446, 0x720A, 0x3284, 0x01E5, 0x416B,
0x4D7D, 0x0DF3, 0x3E92, 0x7E1C, 0x5850, 0x18DE, 0x2BBF, 0x6B31,
0x3393, 0x731D, 0x407C, 0x00F2, 0x26BE, 0x6630, 0x5551, 0x15DF,
0x19C9, 0x5947, 0x6A26, 0x2AA8, 0x0CE4, 0x4C6A, 0x7F0B, 0x3F85,
```
#### CRC16 계산 테이블 생성 코드
```csharp
const ushort polynomial = 0x7979;
ushort[] CRC16_TABLE = new ushort[256];
for (ushort i = 0; i < CRC16_TABLE.Length; i++)
{
ushort value = 0;
ushort temp = i;
for (byte j = 0; j < 8; j++)
{
if (((value ^ temp) & 0x0001) != 0)
{
value = (ushort)((value >> 1) ^ polynomial);
}
else
{
value >>= 1;
}
temp >>= 1;
}
CRC16_TABLE[i] = value;
}
```
#### CRC16 계산 예시
```csharp
ushort CalculateCRC16(byte[] data)
{
ushort crc = 0xFFFF;
for (int i = 0; i < data.Length; i++)
{
byte index = (byte)(crc ^ data[i]);
crc = (ushort)((crc >> 8) ^ CRC16_TABLE[index]);
}
return crc;
}
```
## 라이센스

View File

@@ -0,0 +1,450 @@
namespace SampleProject
{
partial class Form1
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.rtRx = new System.Windows.Forms.RichTextBox();
this.rtTx = new System.Windows.Forms.RichTextBox();
this.tbmsg = new System.Windows.Forms.TextBox();
this.btsend = new System.Windows.Forms.Button();
this.cmbport = new System.Windows.Forms.ComboBox();
this.btconnect = new System.Windows.Forms.Button();
this.tbbaud = new System.Windows.Forms.ComboBox();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.sbPort = new System.Windows.Forms.ToolStripStatusLabel();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.cmbid = new System.Windows.Forms.ComboBox();
this.btsim = new System.Windows.Forms.Button();
this.rtMsg = new System.Windows.Forms.RichTextBox();
this.tbCmd = new System.Windows.Forms.TextBox();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.panel1 = new System.Windows.Forms.Panel();
this.label5 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.btSave = new System.Windows.Forms.Button();
this.btload = new System.Windows.Forms.Button();
this.rtCmd = new System.Windows.Forms.RichTextBox();
this.statusStrip1.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.SuspendLayout();
//
// rtRx
//
this.rtRx.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtRx.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.rtRx.Location = new System.Drawing.Point(4, 5);
this.rtRx.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rtRx.Name = "rtRx";
this.rtRx.Size = new System.Drawing.Size(462, 302);
this.rtRx.TabIndex = 0;
this.rtRx.Text = "";
//
// rtTx
//
this.rtTx.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtTx.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.rtTx.Location = new System.Drawing.Point(474, 5);
this.rtTx.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rtTx.Name = "rtTx";
this.rtTx.Size = new System.Drawing.Size(462, 302);
this.rtTx.TabIndex = 1;
this.rtTx.Text = "";
//
// tbmsg
//
this.tbmsg.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
this.tbmsg.Dock = System.Windows.Forms.DockStyle.Fill;
this.tbmsg.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.tbmsg.Location = new System.Drawing.Point(436, 5);
this.tbmsg.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.tbmsg.Name = "tbmsg";
this.tbmsg.Size = new System.Drawing.Size(273, 44);
this.tbmsg.TabIndex = 2;
this.tbmsg.Text = "mesage";
this.tbmsg.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.tbmsg.TextChanged += new System.EventHandler(this.tbmsg_TextChanged);
//
// btsend
//
this.btsend.Dock = System.Windows.Forms.DockStyle.Right;
this.btsend.Font = new System.Drawing.Font("굴림", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.btsend.Location = new System.Drawing.Point(709, 5);
this.btsend.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btsend.Name = "btsend";
this.btsend.Size = new System.Drawing.Size(120, 42);
this.btsend.TabIndex = 3;
this.btsend.Text = "Send";
this.btsend.UseVisualStyleBackColor = true;
this.btsend.Click += new System.EventHandler(this.btsend_Click);
//
// cmbport
//
this.cmbport.Dock = System.Windows.Forms.DockStyle.Left;
this.cmbport.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.cmbport.FormattingEnabled = true;
this.cmbport.Location = new System.Drawing.Point(58, 3);
this.cmbport.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.cmbport.Name = "cmbport";
this.cmbport.Size = new System.Drawing.Size(218, 40);
this.cmbport.TabIndex = 4;
//
// btconnect
//
this.btconnect.Dock = System.Windows.Forms.DockStyle.Right;
this.btconnect.Location = new System.Drawing.Point(765, 3);
this.btconnect.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btconnect.Name = "btconnect";
this.btconnect.Size = new System.Drawing.Size(186, 40);
this.btconnect.TabIndex = 5;
this.btconnect.Text = "connect";
this.btconnect.UseVisualStyleBackColor = true;
this.btconnect.Click += new System.EventHandler(this.btconnect_Click);
//
// tbbaud
//
this.tbbaud.Dock = System.Windows.Forms.DockStyle.Left;
this.tbbaud.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.tbbaud.FormattingEnabled = true;
this.tbbaud.Location = new System.Drawing.Point(331, 3);
this.tbbaud.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.tbbaud.Name = "tbbaud";
this.tbbaud.Size = new System.Drawing.Size(171, 40);
this.tbbaud.TabIndex = 6;
this.tbbaud.Text = "9600";
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.sbPort});
this.statusStrip1.Location = new System.Drawing.Point(0, 583);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 20, 0);
this.statusStrip1.Size = new System.Drawing.Size(954, 22);
this.statusStrip1.TabIndex = 7;
this.statusStrip1.Text = "statusStrip1";
//
// sbPort
//
this.sbPort.Name = "sbPort";
this.sbPort.Size = new System.Drawing.Size(121, 17);
this.sbPort.Text = "toolStripStatusLabel1";
//
// timer1
//
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// cmbid
//
this.cmbid.Dock = System.Windows.Forms.DockStyle.Left;
this.cmbid.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbid.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.cmbid.FormattingEnabled = true;
this.cmbid.Location = new System.Drawing.Point(60, 5);
this.cmbid.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.cmbid.Name = "cmbid";
this.cmbid.Size = new System.Drawing.Size(183, 40);
this.cmbid.TabIndex = 8;
//
// btsim
//
this.btsim.Dock = System.Windows.Forms.DockStyle.Right;
this.btsim.Font = new System.Drawing.Font("굴림", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.btsim.Location = new System.Drawing.Point(829, 5);
this.btsim.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.btsim.Name = "btsim";
this.btsim.Size = new System.Drawing.Size(120, 42);
this.btsim.TabIndex = 9;
this.btsim.Text = "Test";
this.btsim.UseVisualStyleBackColor = true;
this.btsim.Click += new System.EventHandler(this.btsim_Click);
//
// rtMsg
//
this.rtMsg.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
this.tableLayoutPanel1.SetColumnSpan(this.rtMsg, 2);
this.rtMsg.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtMsg.Location = new System.Drawing.Point(4, 317);
this.rtMsg.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rtMsg.Name = "rtMsg";
this.rtMsg.Size = new System.Drawing.Size(932, 124);
this.rtMsg.TabIndex = 10;
this.rtMsg.Text = "";
//
// tbCmd
//
this.tbCmd.Dock = System.Windows.Forms.DockStyle.Left;
this.tbCmd.Font = new System.Drawing.Font("굴림", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.tbCmd.Location = new System.Drawing.Point(298, 5);
this.tbCmd.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.tbCmd.Name = "tbCmd";
this.tbCmd.Size = new System.Drawing.Size(83, 44);
this.tbCmd.TabIndex = 11;
this.tbCmd.Text = "cmd";
this.tbCmd.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Controls.Add(this.rtMsg, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.rtRx, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.rtTx, 1, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 70F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 30F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(940, 446);
this.tableLayoutPanel1.TabIndex = 12;
//
// panel1
//
this.panel1.Controls.Add(this.tbmsg);
this.panel1.Controls.Add(this.label5);
this.panel1.Controls.Add(this.tbCmd);
this.panel1.Controls.Add(this.label4);
this.panel1.Controls.Add(this.cmbid);
this.panel1.Controls.Add(this.label3);
this.panel1.Controls.Add(this.btsend);
this.panel1.Controls.Add(this.btsim);
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panel1.Location = new System.Drawing.Point(0, 531);
this.panel1.Name = "panel1";
this.panel1.Padding = new System.Windows.Forms.Padding(5);
this.panel1.Size = new System.Drawing.Size(954, 52);
this.panel1.TabIndex = 13;
//
// label5
//
this.label5.Dock = System.Windows.Forms.DockStyle.Left;
this.label5.Font = new System.Drawing.Font("Arial", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label5.Location = new System.Drawing.Point(381, 5);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(55, 42);
this.label5.TabIndex = 14;
this.label5.Text = "DATA\r\n(n)";
this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label4
//
this.label4.Dock = System.Windows.Forms.DockStyle.Left;
this.label4.Font = new System.Drawing.Font("Arial", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label4.Location = new System.Drawing.Point(243, 5);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(55, 42);
this.label4.TabIndex = 13;
this.label4.Text = "CMD\r\n(1)";
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label3
//
this.label3.Dock = System.Windows.Forms.DockStyle.Left;
this.label3.Font = new System.Drawing.Font("Arial", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label3.Location = new System.Drawing.Point(5, 5);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(55, 42);
this.label3.TabIndex = 12;
this.label3.Text = "ID\r\n(1)";
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// panel2
//
this.panel2.Controls.Add(this.tbbaud);
this.panel2.Controls.Add(this.label2);
this.panel2.Controls.Add(this.cmbport);
this.panel2.Controls.Add(this.btconnect);
this.panel2.Controls.Add(this.label1);
this.panel2.Dock = System.Windows.Forms.DockStyle.Top;
this.panel2.Location = new System.Drawing.Point(0, 0);
this.panel2.Name = "panel2";
this.panel2.Padding = new System.Windows.Forms.Padding(3);
this.panel2.Size = new System.Drawing.Size(954, 46);
this.panel2.TabIndex = 14;
//
// label2
//
this.label2.Dock = System.Windows.Forms.DockStyle.Left;
this.label2.Location = new System.Drawing.Point(276, 3);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(55, 40);
this.label2.TabIndex = 8;
this.label2.Text = "baud";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label1
//
this.label1.Dock = System.Windows.Forms.DockStyle.Left;
this.label1.Location = new System.Drawing.Point(3, 3);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(55, 40);
this.label1.TabIndex = 7;
this.label1.Text = "port";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 46);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(954, 485);
this.tabControl1.TabIndex = 15;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.tableLayoutPanel1);
this.tabPage1.Location = new System.Drawing.Point(4, 29);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(946, 452);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Test";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.btSave);
this.tabPage2.Controls.Add(this.btload);
this.tabPage2.Controls.Add(this.rtCmd);
this.tabPage2.Location = new System.Drawing.Point(4, 29);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(946, 452);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Command";
this.tabPage2.UseVisualStyleBackColor = true;
//
// btSave
//
this.btSave.Location = new System.Drawing.Point(820, 50);
this.btSave.Name = "btSave";
this.btSave.Size = new System.Drawing.Size(113, 29);
this.btSave.TabIndex = 13;
this.btSave.Text = "Save";
this.btSave.UseVisualStyleBackColor = true;
this.btSave.Click += new System.EventHandler(this.btSave_Click);
//
// btload
//
this.btload.Location = new System.Drawing.Point(820, 15);
this.btload.Name = "btload";
this.btload.Size = new System.Drawing.Size(113, 29);
this.btload.TabIndex = 12;
this.btload.Text = "Load";
this.btload.UseVisualStyleBackColor = true;
this.btload.Click += new System.EventHandler(this.btload_Click);
//
// rtCmd
//
this.rtCmd.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtCmd.Location = new System.Drawing.Point(3, 3);
this.rtCmd.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.rtCmd.Name = "rtCmd";
this.rtCmd.Size = new System.Drawing.Size(940, 446);
this.rtCmd.TabIndex = 11;
this.rtCmd.Text = "";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 19F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(954, 605);
this.Controls.Add(this.tabControl1);
this.Controls.Add(this.panel2);
this.Controls.Add(this.panel1);
this.Controls.Add(this.statusStrip1);
this.Font = new System.Drawing.Font("굴림", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "!!";
this.Load += new System.EventHandler(this.Form1_Load);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.tableLayoutPanel1.ResumeLayout(false);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.panel2.ResumeLayout(false);
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.RichTextBox rtRx;
private System.Windows.Forms.RichTextBox rtTx;
private System.Windows.Forms.TextBox tbmsg;
private System.Windows.Forms.Button btsend;
private System.Windows.Forms.ComboBox cmbport;
private System.Windows.Forms.Button btconnect;
private System.Windows.Forms.ComboBox tbbaud;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel sbPort;
private System.Windows.Forms.Timer timer1;
private System.Windows.Forms.ComboBox cmbid;
private System.Windows.Forms.Button btsim;
private System.Windows.Forms.RichTextBox rtMsg;
private System.Windows.Forms.TextBox tbCmd;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.RichTextBox rtCmd;
private System.Windows.Forms.Button btSave;
private System.Windows.Forms.Button btload;
}
}

Some files were not shown because too many files have changed in this diff Show More