using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D; using System.Configuration; namespace UIControl { public partial class Loader : UserControl { #region "Variable - Private" Timer tm; Boolean _ardebugmode = false; eScean _scean = eScean.Nomal; //기타 내부 변수 int AnimationStepConv = 30; //컨베어 이동 애니메이션 최대 값 //int AnimationStepPort = 9; //포트 이동 애니메이션 최대 값 Boolean bRemakeRect = true; //이값이 활성화되면 각 영역을 다시 그리게 된다 DateTime updatetime = DateTime.Now; //화면을 다시 그린 시간 Brush BRPortBg = new SolidBrush(Color.FromArgb(50, Color.DimGray)); Brush BRDetectDn = new SolidBrush(Color.FromArgb(50, Color.DimGray)); StringFormat sfCenter; StringFormat sfLeft = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center }; SolidBrush brVacOff = new SolidBrush(Color.FromArgb(150, Color.White)); SolidBrush brVacOn = new SolidBrush(Color.FromArgb(200, Color.Lime)); Pen penVacOn = new Pen(Color.Red, 5); Pen penVacOff = new Pen(Color.Black, 5); //영역(큰 그림?) (bRemakeRect 에 의 해 생성된다) RectangleF rect_main = RectangleF.Empty; RectangleF rect_frontShuttle = RectangleF.Empty; RectangleF rect_rearShuttle = RectangleF.Empty; RectangleF rect_conveyor = RectangleF.Empty; RectangleF rect_picker = RectangleF.Empty; //영역(피커) RectangleF rect_picker_rear = RectangleF.Empty; RectangleF rect_picker_front = RectangleF.Empty; RectangleF rect_picker_rear_vac1 = RectangleF.Empty; RectangleF rect_picker_rear_vac2 = RectangleF.Empty; RectangleF rect_picker_rear_vac3 = RectangleF.Empty; RectangleF rect_picker_rear_vac4 = RectangleF.Empty; RectangleF rect_picker_front_vac1 = RectangleF.Empty; RectangleF rect_picker_front_vac2 = RectangleF.Empty; RectangleF rect_picker_front_vac3 = RectangleF.Empty; RectangleF rect_picker_front_vac4 = RectangleF.Empty; //X축 포트 (F-L:0, F-R:1, R-L:2, R-R:3 //RectangleF[] rect_port = new RectangleF[4]; RectangleF[] rect_zone = new RectangleF[11]; CIcon[] icons = new CIcon[6]; List Buttons = new List(); List menuButtons = new List(); /// /// 외부에서 입력된 릴의 갯수 /// int ExtInputCount = 0; #endregion #region "Variable - Public" public double[] arMotorPosition = new double[] { 0, 0, 0, 0, 0 }; public int ConveyorRunPoint = 1; //컨베어 모터 이동시 이동 화살표의 위치값(내부 타이머에의해 증가함) public double arMcLengthW = 1460; public double arMcLengthH = 1350;// #endregion #region "Property" /// /// 현재 메뉴가 표시되어있는가? /// public Boolean HasPopupMenu { get; private set; } /// /// 현재표시된 메뉴는 사용자의 입력을 반드시 받아야 하는가? /// public Boolean PopupMenuRequireInput { get; private set; } public Font arFont_PortMessage { get; set; } public Boolean LockXF { get; set; } public Boolean LockXR { get; set; } public Boolean LockYP { get; set; } public eScean Scean { get { return _scean; } set { _scean = value; bRemakeRect = true; this.Invalidate(); } } //컨베이어에 설치된 자재 감지 센서 public Boolean[] arDI_Cv_Detect { get; set; } //컨베이어 입구 안전 센서 public Boolean arInitMOT { get; set; } public Boolean arJobEND { get; set; } public Boolean arLowDiskSpace { get; set; } //용량 부족 메세지 여부 public double arFreespace { get; set; } //남은 디스크 용량 비율 public Boolean arDI_Safty_CvIn { get; set; } public Boolean arDI_SaftyOk { get; set; } //작업을 선택하면 설정되는 작업일자와 차수이다 public string arJobDate { get; set; } public string arJobSeq { get; set; } public Boolean[] arMOT_LimUp = new bool[] { false, false, false, false, false }; public Boolean[] arMOT_LimDn = new bool[] { false, false, false, false, false }; public Boolean[] arMOT_Origin = new bool[] { false, false, false, false, false }; public Boolean[] arMOT_Alm = new bool[] { false, false, false, false, false }; public Boolean[] arMOT_HSet = new bool[] { false, false, false, false, false }; public Boolean[] arMOT_SVOn = new bool[] { false, false, false, false, false }; public Boolean arFlag_WaitPLC { get; set; } public Boolean arFlag_WaitBCD2 { get; set; } public Boolean arFlag_WaitBCD1 { get; set; } public Boolean arFlag_BusyExtIn { get { return ExtInputCount > 0; } } public Boolean arFlag_Minspace { get; set; } public byte arUnloaderSeq { get; set; } public Boolean arFlag_UnloaderBusy { get; set; } public Boolean arFlag_UnloaderErr { get; set; } public Boolean arConn_REM { get; set; } public Boolean arFG_RDY_YP_FPICKON { get; set; } public Boolean arFG_RDY_YP_FPICKOF { get; set; } public Boolean arFG_RDY_YP_RPICKON { get; set; } public Boolean arFG_RDY_YP_RPICKOF { get; set; } public Boolean arFG_CMD_YP_FPICKON { get; set; } //public Boolean arFG_CMD_YP_FPICKOF { get; set; } public Boolean arFG_CMD_YP_RPICKON { get; set; } //public Boolean arFG_CMD_YP_RPICKOF { get; set; } //컨베이어 출구 안전 센서 public Boolean arDI_Safty_CvOut { get; set; } //비상정지 센서 상태 public Boolean arDI_Emergency { get; set; } public Boolean arDIAir { get; set; } public Boolean arConn_MOT { get; set; } public Boolean arConn_DIO { get; set; } public Boolean arConn_BCD { get; set; } public Boolean arConn_PLC { get; set; } public int arLastDetectIndex { get; set; } public Boolean arDebugMode { get { return _ardebugmode; } set { this._ardebugmode = value; Invalidate(); } } public CPort[] arVar_Port { get; set; } public CPicker[] arVar_Picker { get; set; } public Boolean arConvRun { get; set; } public Boolean arIsRunning { get; set; } public Boolean arFGInputMode { get; set; } public Boolean arFGInputFL { get; set; } public Boolean arFGInputFR { get; set; } public Boolean arFGInputRL { get; set; } public Boolean arFGInputRR { get; set; } private List zitem = new List(); public long[] zonetime = new long[11]; public Font arFont_count { get; set; } public Font arFont_picker { get; set; } public double arMotorLengthY { get; set; } public double arMotorLengthXF { get; set; } public double arMotorLengthXR { get; set; } private CMenu[] _menus = null; public CMenu[] arMenus { get { return _menus; } set { _menus = value; this.Invalidate(); } } #endregion public Loader() { InitializeComponent(); // Set Optimized Double Buffer to reduce flickering this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); this.SetStyle(ControlStyles.ContainerControl, false); this.SetStyle(ControlStyles.Selectable, true); this.Resize += Loader_Resize; sfCenter = new StringFormat(); sfCenter.Alignment = StringAlignment.Center; sfCenter.LineAlignment = StringAlignment.Center; // Redraw when resized this.SetStyle(ControlStyles.ResizeRedraw, true); tm = new Timer(); tm.Interval = 50; //10frame; tm.Tick += Tm_Tick; arLastDetectIndex = -1; arFont_PortMessage = new Font("Consolas", 11, FontStyle.Bold); arFont_picker = new Font("Arial", 10, FontStyle.Bold); arUnloaderSeq = 0; arMotorLengthY = 400; arMotorLengthXF = 580; arMotorLengthXR = 590; arJobDate = string.Empty; arJobSeq = string.Empty; arDI_Cv_Detect = new bool[8]; for (int i = 0; i < arDI_Cv_Detect.Length; i++) arDI_Cv_Detect[i] = false; bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime); if (designMode == false) tm.Start(); arFont_count = new Font("Consolas", 30, FontStyle.Bold); //기본수량설정됨 arVar_Port = new CPort[4]; arVar_Picker = new CPicker[2]; for (int i = 0; i < rect_zone.Length; i++) rect_zone[i] = RectangleF.Empty; for (int i = 0; i < zonetime.Length; i++) zonetime[i] = 0; for (int i = 0; i < icons.Length; i++) icons[i] = new CIcon(); //미리 10개를 생성한다. 슬롯에 10개이상 생기기 않는다. zitem = new List(10); for (int i = 0; i < zitem.Count; i++) zitem[i] = new CItem(); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (this.icons == null || icons.Length < 1) return; var item = this.icons.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault(); //선택된 것이 잇다면 모두 해제를 해준다. icons.Where(t => t.Focus == true).ToList().ForEach(t => t.Focus = false); if (item != null) { item.Focus = true; this.Cursor = Cursors.Hand; } else { this.Cursor = Cursors.Arrow; } } public class ZoneItemClickEventargs : EventArgs { public CItem item { get; private set; } public ZoneItemClickEventargs(CItem item_) { this.item = item_; } } public class IconClickEventargs : EventArgs { public CIcon item { get; private set; } public IconClickEventargs(CIcon item_) { this.item = item_; } } public class MenuItemClickEventargs : EventArgs { public CMenuButton item { get; private set; } public MenuItemClickEventargs(CMenuButton item_) { this.item = item_; } } public event EventHandler ButtonClick; public event EventHandler IConClick; public event EventHandler ZoneItemClick; protected override void OnMouseClick(MouseEventArgs e) { base.OnMouseClick(e); if (e.Button == MouseButtons.Left) { var item = this.icons.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault(); if (item != null) { //다른 메뉴가 선택되어잇다면 동작하지 않게 한다. if (IConClick != null) IConClick(this, new IconClickEventargs(item)); } //삭제된 아이템은 선택되지 않게 한다 201013 lock (zitem) { var zitem = this.zitem.Where(t => t.Rect.Contains(e.Location) && t.Delete == false).FirstOrDefault(); if (zitem != null) { //특정 존의 아이템을 선택했다 if (ZoneItemClick != null) ZoneItemClick(this, new ZoneItemClickEventargs(zitem)); } } //메뉴의해 생성된 버튼 var zbbut = this.menuButtons.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault(); if (zbbut != null) { //특정 존의 아이템을 선택했다 if (ButtonClick != null) ButtonClick(this, new MenuItemClickEventargs(zbbut)); } //아이콘 var zbut = this.Buttons.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault(); if (zbut != null) { //특정 존의 아이템을 선택했다 if (ButtonClick != null) ButtonClick(this, new MenuItemClickEventargs(zbut)); } } } void Loader_Resize(object sender, EventArgs e) { bRemakeRect = true; } public void RemakeRect() { bRemakeRect = true; } void makeRect_Input() { rect_main = new RectangleF( DisplayRectangle.Left + DisplayRectangle.Width * 0.05f, DisplayRectangle.Top + DisplayRectangle.Height * 0.05f, DisplayRectangle.Width * 0.9f, DisplayRectangle.Height * 0.9f); //화면에 꽉차도록 전체 영역을 할당한다. var cx = rect_main.Left + rect_main.Width / 2.0f; var cy = rect_main.Top + rect_main.Height / 2.0f; var padding = (int)(rect_main.Width * 0.03); arVar_Port[2].Rect = new Rectangle( (int)rect_main.Left + padding, (int)rect_main.Top + padding, (int)((cx - rect_main.Left) - padding * 2), (int)((cy - rect_main.Top) - padding * 2)); arVar_Port[3].Rect = new Rectangle( (int)cx + padding, (int)rect_main.Top + padding, (int)((cx - rect_main.Left) - padding * 2), (int)((cy - rect_main.Top) - padding * 2)); arVar_Port[0].Rect = new Rectangle( (int)rect_main.Left + padding, (int)cy + padding, (int)((cx - rect_main.Left) - padding * 2), (int)((cy - rect_main.Top) - padding * 2)); arVar_Port[1].Rect = new Rectangle( (int)cx + padding, (int)cy + padding, (int)((cx - rect_main.Left) - padding * 2), (int)((cy - rect_main.Top) - padding * 2)); } void makeRect_MotHome() { rect_main = new RectangleF( DisplayRectangle.Left + DisplayRectangle.Width * 0.05f, DisplayRectangle.Top + DisplayRectangle.Height * 0.05f, DisplayRectangle.Width * 0.9f, DisplayRectangle.Height * 0.9f); } double CvtMMtoPX_W(double PosMM, double StartX) { //컨베어 기준으로 값을 반환한ㄷ. return StartX + rect_main.Width * (PosMM / arMcLengthW); } double CvtMMtoPX_H(double PosMM, double StartY) { //컨베어 기준으로 값을 반환한ㄷ. return StartY + rect_main.Height * (PosMM / arMcLengthH); } #region "Menu Method" public void ClearMenu() { _menus = null; this.Invalidate(); } public void AddMenu(CMenu menu) { var curCnt = 0; if (this._menus != null) curCnt = this._menus.Length; Array.Resize(ref _menus, curCnt + 1); _menus[curCnt] = menu; this.Invalidate(); } public void DelMenu(CMenu menu) { List newlist = new List(); for (int i = 0; i < _menus.Length; i++) { if (_menus[i] != menu) newlist.Add(_menus[i]); } this._menus = newlist.ToArray(); this.Invalidate(); } public void DelMenu(int idx) { List newlist = new List(); for (int i = 0; i < _menus.Length; i++) { if (i != idx) newlist.Add(_menus[i]); } this._menus = newlist.ToArray(); this.Invalidate(); } public void DelMenu() { //제거할 아이템이 없다 if (_menus == null || _menus.Length < 1) return; if (_menus.Length == 1) _menus = null; else { //마지막요소를 제거 해주낟 Array.Resize(ref _menus, _menus.Length - 1); } this.Invalidate(); } #endregion /// /// 각 영역을 현재 크기대비하여 재계산 한다 /// void makeRect_Normal() { rect_main = new RectangleF( DisplayRectangle.Left + DisplayRectangle.Width * 0.025f, DisplayRectangle.Top + DisplayRectangle.Height * 0.025f, DisplayRectangle.Width * 0.95f, DisplayRectangle.Height * 0.8f); //X축 모션(셔틀) 표시 var xPos1 = rect_main.Left + (rect_main.Width * 0.175); var xPos2 = rect_main.Right - xPos1; var yposR = rect_main.Height * 0.15; var yposF = rect_main.Height * 0.85; var h0p5 = rect_main.Height * 0.03; var w0p5 = (rect_main.Width * 0.035) * ((rect_main.Height * 1.0) / rect_main.Width); //var conv_height = rect_main.Height * 0.3; var cx = (float)(rect_main.Top + (rect_main.Width / 2.0)); var cy = (float)(rect_main.Top + (rect_main.Height / 2.0)); var conv_height = CvtMMtoPX_H(350, 0); //컨베이어 높이 var conv_width = CvtMMtoPX_W(arMcLengthW, 0); //컨베어이어너비는 장비 너비와 같다 rect_conveyor = new RectangleF(rect_main.Left, (float)(rect_main.Top + (rect_main.Height - conv_height) / 2.0f), (float)conv_width, (float)conv_height); var h10p = rect_main.Height * 0.03; var pickWidth = rect_main.Width * 0.02f; //프론트셔틀의 영역(가동 영역) - 아래서 450mm 떨어진곳 var xAxisLengthMM = arMcLengthW - 200; // 컨베어 길이에서 좌우 100mm 씩 리밋센서가 있다 var xAxisLengthPX = CvtMMtoPX_W(xAxisLengthMM, rect_conveyor.Left); rect_frontShuttle = new RectangleF( (float)(CvtMMtoPX_W(100, rect_conveyor.Left)), (float)(CvtMMtoPX_H(arMcLengthH - 410 - 10, rect_main.Top)), (float)xAxisLengthPX, (float)(CvtMMtoPX_H(20, 0))); //리어셔틀의 영역(가동 영역) - 위에서 450mm rect_rearShuttle = new RectangleF( (float)(CvtMMtoPX_W(100, rect_conveyor.Left)), (float)(CvtMMtoPX_H(410 - 10, rect_main.Top)), (float)xAxisLengthPX, (float)(CvtMMtoPX_H(20, 0))); //세로축 총길이 1400mm Y축 모터는 양끝에 100mm 의 여유가 있으며, Y축 var pickerX = CvtMMtoPX_W(750, rect_conveyor.Left); rect_picker = new RectangleF( (float)(pickerX - (pickWidth / 2.0f)), (float)(rect_rearShuttle.Top), (float)(pickWidth), (float)(rect_frontShuttle.Bottom - rect_rearShuttle.Top) ); //Y축 피커 관련 세부 영역 설정 (VAC 와 원) //전체영역의 80% 영역에 Y-로봇의 축을 그린다. //var motorMax = 400; //전체 가동 길이 400mm RectangleF rect = rect_picker; var MotPosPx = rect.Top + rect.Height * (this.arMotorPosition[0] / (this.arMotorLengthY * 1.0f)); cx = rect.Left + rect.Width / 2.0f; //상(Rear), 하(Front)로 영역을 그린다 var port_height = rect.Height * 0.25f; var port_width = port_height; //;// var port_width = rect.Width * 3f; //port_width = port_height; var port_space = CvtMMtoPX_H(350 / 2.0f, 0); var port_spacex = CvtMMtoPX_W(10, 0); ; var PickerSizeW = CvtMMtoPX_W(145, 0);// (float)(Math.Max(CvtMMtoPX_W(150, 0), CvtMMtoPX_H(15, 0))); var PickerSizeH = PickerSizeW;// CvtMMtoPX_H(130, 0);//(float)(Math.Max(CvtMMtoPX_W(150, 0), CvtMMtoPX_H(15, 0))); var PickerSpaceH = CvtMMtoPX_H(350, 0); rect_picker_rear = new RectangleF( (float)(cx + port_spacex), (float)(MotPosPx - PickerSpaceH - PickerSizeH / 2.0f), (float)PickerSizeW, (float)PickerSizeH); rect_picker_front = new RectangleF( (float)(cx + port_spacex), (float)(MotPosPx), (float)PickerSizeW, (float)PickerSizeH); var pointoffset = 5; rect_picker_rear_vac1 = new RectangleF( (float)rect_picker_rear.Left + pointoffset, (float)rect_picker_rear.Top + pointoffset, (float)rect_picker_rear.Width * 0.2f, (float)rect_picker_rear.Height * 0.2f); rect_picker_rear_vac2 = new RectangleF( (float)rect_picker_rear.Right - rect_picker_rear_vac1.Width - pointoffset, (float)rect_picker_rear_vac1.Top, (float)rect_picker_rear_vac1.Width, (float)rect_picker_rear_vac1.Height); rect_picker_rear_vac3 = new RectangleF( (float)rect_picker_rear.Left + pointoffset, (float)rect_picker_rear.Bottom - rect_picker_rear_vac1.Height - pointoffset, (float)rect_picker_rear_vac1.Width, (float)rect_picker_rear_vac1.Height); rect_picker_rear_vac4 = new RectangleF( (float)rect_picker_rear.Right - rect_picker_rear_vac1.Width - pointoffset, (float)rect_picker_rear.Bottom - rect_picker_rear_vac1.Height - pointoffset, (float)rect_picker_rear_vac1.Width, (float)rect_picker_rear_vac1.Height); rect_picker_front_vac1 = new RectangleF( (float)rect_picker_front.Left + pointoffset, (float)rect_picker_front.Top + pointoffset, (float)rect_picker_front.Width * 0.2f, (float)rect_picker_front.Height * 0.2f); rect_picker_front_vac2 = new RectangleF( (float)rect_picker_front.Right - rect_picker_front_vac1.Width - pointoffset, (float)rect_picker_front_vac1.Top, (float)rect_picker_front_vac1.Width, (float)rect_picker_front_vac1.Height); rect_picker_front_vac3 = new RectangleF( (float)rect_picker_front.Left + pointoffset, (float)rect_picker_front.Bottom - rect_picker_front_vac1.Height - pointoffset, (float)rect_picker_front_vac1.Width, (float)rect_picker_front_vac1.Height); rect_picker_front_vac4 = new RectangleF( (float)rect_picker_front.Right - rect_picker_front_vac1.Width - pointoffset, (float)rect_picker_front.Bottom - rect_picker_front_vac1.Height - pointoffset, (float)rect_picker_front_vac1.Width, (float)rect_picker_front_vac1.Height); //각 존의 영역 확인 //컨베어의 릴감지센서 위치를 표시한다 var senseW = rect_conveyor.Width * 0.02f; var senseH = rect_conveyor.Height * 0.05f; var slist = new double[] { 20, 340, 550, 890, 1110, 1440 };// new double[] { 0.02, 0.25, 0.4, 0.6, 0.75, 0.9 }; //센서의 위치정보(컨베어좌측기준) //센서가 포함된 존의 영역을 생성한다 for (int i = 0; i < slist.Length; i++) { //선으로 영역을 표시해준다. var PosMM = rect_conveyor.Width * (slist[i] / arMcLengthW); var x = (float)(rect_conveyor.Left + PosMM); var rx = x - senseW / 2.0f; rect_zone[i * 2] = new RectangleF(rx, rect_conveyor.Top, senseW, rect_conveyor.Height); } var arraylis = new int[] { 1, 3, 5, 7, 9 }; var zterm = 4; for (int i = 0; i < arraylis.Length; i++) { var idx = arraylis[i]; rect_zone[idx] = new RectangleF( rect_zone[idx - 1].Right + zterm, rect_zone[idx - 1].Top, rect_zone[idx + 1].Left - rect_zone[idx - 1].Right - zterm * 2, rect_zone[idx - 1].Height); } //아이콘영역 float ix = rect_main.Left; float iy = rect_main.Bottom + 20; Size iconSizeW = new Size(80, 80); int idxIcon = 0; ix = rect_main.Left; iy = rect_main.Bottom + 20; icons[idxIcon++] = new CIcon("bcd", new RectangleF(ix, iy, iconSizeW.Width, iconSizeW.Height)); ix += 85; icons[idxIcon++] = new CIcon("plc", new RectangleF(ix, iy, iconSizeW.Width, iconSizeW.Height)); ix += 85; icons[idxIcon++] = new CIcon("mot", new RectangleF(ix, iy, iconSizeW.Width, iconSizeW.Height)); ix += 85; icons[idxIcon++] = new CIcon("emg", new RectangleF(ix, iy, iconSizeW.Width, iconSizeW.Height)); ix += 85; icons[idxIcon++] = new CIcon("sft", new RectangleF(ix, iy, iconSizeW.Width, iconSizeW.Height)); ix += 85; icons[idxIcon++] = new CIcon("air", new RectangleF(ix, iy, iconSizeW.Width, iconSizeW.Height)); //ix += 85; //icons[idxIcon++] = new CIcon("debug", new RectangleF(ix, iy, iconSizeW.Width, iconSizeW.Height)); ////버튼 생성해준다 //var ButL = this.Buttons.Where(t => t.Tag == "INPUTL").FirstOrDefault(); //var ButR = this.Buttons.Where(t => t.Tag == "INPUTR").FirstOrDefault(); //var butWidth = 64; //var butPadding = 1; //var butHeight = butWidth;// (int)(rect_conveyor.Height - butPadding * 2); //if (ButL == null) //{ // var newbutton = new CMenuButton("투입\n출구", "INPUTL"); // newbutton.BorderSize = 1; // newbutton.Shape = eButtonType.Rectangle; // newbutton.Rect = new Rectangle((int)rect_main.Left + butPadding, (int)rect_main.Bottom - butHeight - butPadding, butWidth, butHeight); // this.Buttons.Add(newbutton); //} //else //{ // ButL.Rect = new Rectangle((int)rect_main.Left + butPadding, (int)rect_main.Bottom - butHeight - butPadding, butWidth, butHeight); // ButL.Shape = eButtonType.Rectangle; //} //if (ButR == null) //{ // var newbutton = new CMenuButton("투입\n입구", "INPUTR"); // newbutton.BorderSize = 1; // newbutton.Shape = eButtonType.Rectangle; // newbutton.Rect = new Rectangle((int)rect_main.Right - butWidth - butPadding, (int)rect_main.Bottom - butHeight - butPadding, butWidth, butHeight); // this.Buttons.Add(newbutton); //} //else //{ // ButR.Rect = new Rectangle((int)rect_main.Right - butWidth - butPadding, (int)rect_main.Bottom - butHeight - butPadding, butWidth, butHeight); // ButR.Shape = eButtonType.Rectangle; //} } protected override void OnPaint(PaintEventArgs e) { e.Graphics.CompositingQuality = CompositingQuality.HighQuality; e.Graphics.InterpolationMode = InterpolationMode.High; e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; base.OnPaint(e); if (bRemakeRect) { if (Scean == eScean.Nomal) makeRect_Normal(); else if (Scean == eScean.MotHome) makeRect_MotHome(); else if (Scean == eScean.Input) makeRect_Input(); bRemakeRect = false; } try { if (this.Scean == eScean.Nomal) Scean_Normal(e.Graphics); else if (this.Scean == eScean.MotHome) Scean_MotHome(e.Graphics); else if (this.Scean == eScean.Input) Scean_Input(e.Graphics); } catch (Exception ex) { //오류발생시 해당 오류를 표시한다 210110 e.Graphics.DrawString(ex.Message, this.Font, Brushes.Red, 100, 100); } //삭제대상 아이템을 삭제한다 ZoneItem_AutoClear(); //var str = "CAN DROP:" + isCanPickerDrop.ToString() + " : HOLD;" + zoneitemholding.ToString//() + ",TOT:" + ZoneItemCountTotal.ToString(); // e.Graphics.DrawString(str, this.Font, Brushes.White, 100, 100); } public double[] HomeProgress { get; set; } public UIControl.CItem ZoneItem_Get(int zoneIndex) { lock (zitem) return zitem.Where(t => t.ZoneIndex == zoneIndex).FirstOrDefault(); } public UIControl.CItem ZoneItem_Get(string guid) { lock (zitem) return zitem.Where(t => t.GUID == guid).FirstOrDefault(); } public UIControl.CItem ZoneItem_GetJ(string jguid) { lock (zitem) return zitem.Where(t => t.JGUID == jguid).FirstOrDefault(); } //public int CountZoneItem(int zoneIndex) //{ // return zoneitem.Where(t => t.Delete == false && t.ZoneIndex == zoneIndex).Count(); //} private void ZoneItem_AutoClear() { //삭제된 아이템을 소거한다(작업중인녀석은 삭제되지 않게한다) lock (zitem) { var delitems = this.zitem.Where(t => t.Delete == true && t.Processing == false).ToList(); for (int i = delitems.Count - 1; i >= 0; i--) { //이미 삭제된 아이템이므로 수량에는 적용하지 않는다 var item = delitems[i]; RaiseMessage("[{0}] 아이템소거 : Zone:{1},iPort:{2},Id:{3},Sid:{4},jguid:{5}", false, item.Seq, item.ZoneIndex, item.iPort, item.RID, item.SID, item.JGUID); this.zitem.Remove(delitems[i]); } } } public void ZoneItem_Clear() { RaiseMessage("ClearZoneItem", false); lock (zitem) { //직접모두 삭제하게 함 //this.zitem.ForEach((t) => { t.Delete = true; t.ZoneIndex = -1; }); this.zitem.Clear(); ExtInputCount = 0; //this.ZoneItemCountTotal = 0; } } public void ZoneItem_Delete(string itemguid) { lock (zitem) { var item = zitem.Where(t => t.GUID == itemguid).FirstOrDefault(); if (item != null) { if (item.ZoneIndex > ExitInputBusyBaseZone) ExtInputCount -= 1; item.Delete = true; item.ZoneIndex = -1; if (ExtInputCount < 0) ExtInputCount = 0; } // this.ZoneItemCountTotal -= 1; } } public void ZoneItem_Delete(UIControl.CItem item) { RaiseMessage("[{0}] Delte Item : ZONE:{1},iPORT:{2},RID:{3},SID:{4}", false, item.Seq, item.ZoneIndex, item.iPort, item.RID, item.SID); item.Delete = true; if (item.ZoneIndex > ExitInputBusyBaseZone) ExtInputCount -= 1; item.ZoneIndex = -1; if (ExtInputCount < 0) ExtInputCount = 0; } /// /// 지정된 시간을 초과한 자료를 삭제한다 /// /// public List ZoneItem_GetOldItemList(int timeSec) { var retval = new List(); var basetime = DateTime.Now.AddSeconds(-timeSec); lock (zitem) { var list = this.zitem.Where(t => t.Delete == false && t.InTime <= basetime).ToList(); foreach (var item in list) retval.Add(item.GUID); } return retval; } public void ZoneItem_Add(UIControl.CItem item) { //해당 아이템을 지정한 존에 추가한다. //만약 해당 존에 아이템이 있다면 정보를 변형만 한다 lock (zitem) { var curitems = this.zitem.Where(t => t.ZoneIndex == item.ZoneIndex && t.Delete == false).ToList(); if (curitems.Count == 0) { RaiseMessage("[{0}] ##### AddItem Zone:{1},iPort:{2},JGUID:{3}", false, item.Seq, item.ZoneIndex, item.iPort, item.JGUID); item.Delete = false; this.zitem.Add(item); if (item.ZoneIndex > ExitInputBusyBaseZone) ExtInputCount += 1; //return item.GUID; } else { //기존 정보를 업데이트 해버린다. var firstdr = curitems.FirstOrDefault(); if (firstdr != null) { if (firstdr.ZoneIndex > ExitInputBusyBaseZone) ExtInputCount -= 1; RaiseMessage("[{0}] ##### UpdateItem Zone:{1},iPort:{2},Id:{3},Sid:{4} => Zone:{5},iPort:{6},Id:{7},Sid:{8}", true, firstdr.Seq, firstdr.ZoneIndex, firstdr.iPort, firstdr.RID, firstdr.SID, item.ZoneIndex, item.iPort, item.RID, item.SID); firstdr.ZoneIndex = item.ZoneIndex; firstdr.DropTime = item.DropTime; firstdr.InTime = item.InTime; firstdr.iPort = item.iPort; firstdr.Size = item.Size; firstdr.Delete = false; if (item.ZoneIndex > ExitInputBusyBaseZone) ExtInputCount += 1; } //return item.GUID; } if (ExtInputCount < 0) ExtInputCount = 0; } } /// /// 해당 존에 아이템이 들어왔다 /// /// public CItem ZoneItem_MoveIn(int InputZoneIdx, int offset = 1) { if (InputZoneIdx < 0 || InputZoneIdx > 9) throw new Exception("zonindex 값은 0~10 입니다"); //RaiseMessage("CVItem In : 존에 아이템 투입 입력존 : {0}", false, InputZoneIdx); //해당 아이템 이후의 자재를 모두 Offset 만큼 shit 해준다 //Boolean shiftok = false; //입력하려는 존 이후의 1개 데이터를 가져와서 존을 이동시켜준다 CItem target = null; lock (zitem) { target = this.zitem.Where(t => t.Delete == false && t.ZoneIndex > InputZoneIdx && t.ZoneIndex <= InputZoneIdx + offset).OrderBy(t => t.ZoneIndex).FirstOrDefault(); if (target != null) { //RaiseMessage("CVItemIn : 아이템 존 설정 Zone:{0},iPort:{1},Id:{2},Sid:{3} => NewZone:{4}", false, target.ZoneIndex, target.iPort, target.RID, target.SID, InputZoneIdx); if (target.ZoneIndex > ExitInputBusyBaseZone) ExtInputCount -= 1; if (InputZoneIdx > ExitInputBusyBaseZone) ExtInputCount += 1; target.ZoneIndex = InputZoneIdx; target.ZoneIntime = DateTime.Now; //shiftok = true; } else RaiseMessage("아이템이동 실패 대상 존 " + InputZoneIdx.ToString() + ": 아이템이 없습니다, 현재:" + ZoneItemCountTotal.ToString() + "개 있음", true, null); } if (ExtInputCount < 0) ExtInputCount = 0; return target; } int ExitInputBusyBaseZone = 5; public Boolean isCanPickerDrop { get { //현재 존에 1개까지는 놓을수 있지만 그 이상 있다면 놓을 수없다 var tsDrop = DateTime.Now - LastDropTime; //마지막으로 놓은시간이후 3초 미만은 놓지 못하게 한다 //단 이경우는 컨베이어가 멈춰있는 경우에는 적용하지 못한다 if (tsDrop.TotalSeconds < 2) return false; //절대 2개이상은 놓지못한다 if (ZoneItemCountTotal >= 2) return false; else return zoneitemholding == 0; //return this.zoneitem.Where(t => t.Delete == false && t.ZoneIndex > 1).Count() == 0; } } public int ZoneItemCountTotal { get { int retval = -1; lock (zitem) { retval = this.zitem.Where(t => t.Delete == false && t.ZoneIndex != -1).Count(); } return retval; } } public Boolean ZoneItemDoubleError { get { int retval = 0; lock (zitem) { retval = this.zitem.Where(t => t.Delete == false && t.ZoneIndex >= 0 && t.ZoneIndex <= 1).Count(); //중복오류 } return retval > 1; } } /// /// Z축이 아이템을 내려놓은 시간(연속으로 놓는 증상이 발생하여, 일단 이것으로 2초이상 빠르게 놓는일이 없도록 한다) /// public DateTime LastDropTime = DateTime.Now; public int zoneitemholding { get { int retval = -1; lock (zitem) { //int holdCount = 2; int inch13cnt = this.zitem.Where(t => t.Delete == false && t.Size == "13").Count(); if (inch13cnt > 0) retval = this.zitem.Where(t => t.Delete == false && t.ZoneIndex >= CanDropCount13).Count(); else retval = this.zitem.Where(t => t.Delete == false && t.ZoneIndex >= CanDropCount7).Count(); } return retval; } } public int CanDropCount7 { get; set; } public int CanDropCount13 { get; set; } //private int ZoneItemCountTotal = 0;// //private int zoneitemholding = 0; /// /// 컨베이어에 아이템이 있는가? /// public Boolean CVHasItem { get { //return ZoneItemCountTotal > 0; Boolean cnt = false; lock (zitem) { cnt = this.zitem.Where(t => t.Delete == false && t.ZoneIndex != -1).Count() > 0; } return cnt; } } /// /// 바코드 존의 데이터를 변경해준다. /// /// /// /// public CItem SetBarcodeZone(string jguid, string _reelid, string _sid, string _lot, string _rawdata, int qty_, string _msg, DateTime _sTime) { //바코드 존에 있는 아이템을 확인한다 var item = ZoneItem_GetJ(jguid); if (item == null) { RaiseMessage("바코드 존 아이템 찾기 실패 GUID:{0}", true, jguid); return null; } else if (item.BarcodeDone) { if (item.RID == _reelid && item.SID == _sid) { RaiseMessage("[{0}] 바코드할당 스킵(동일 바코드값 확인) jguid:{1}", true, item.Seq, jguid); } else RaiseMessage("[{0}] 바코드할당 실패(이미 등록된 아이템) jguid:{1}", true, item.Seq, jguid); return item; } item.RID = _reelid; item.SID = _sid; item.VLOT = _lot; item.Qty = qty_; item.BarcodeRaw = _rawdata; item.BarcodeEnd = DateTime.Now; item.BarcodeMsg = _msg; item.BarcodeStart = _sTime; item.BarcodeDone = true; RaiseMessage("[{0}] SetBarcode Zone:{1},RID:{2},SID:{3},msg{4},time:{5},jguid:{6}", false, item.Seq, item.ZoneIndex, _reelid, _sid, _msg, _sTime, jguid); return item; } //public int SetBarcodeZone(string _reelid, string _sid, string _rawdata, string _msg, DateTime _sTime) //{ // RaiseMessage("SetBarcodeZone : id:{0},sid:{1},msg{2},time:{3}", false, _reelid, _sid, _msg, _sTime); // //바코드 존에 있는 아이템을 확인한다 // int[] bcdzone = new int[] { 1, 2, 3 }; //1,2,3번 존에 할당한다 // for (int i = 0; i < bcdzone.Length; i++) // { // var item = ZoneItem_Get(bcdzone[i]); // if (item == null || item.BarcodeDone) continue; // if (string.IsNullOrEmpty(item.RID)) // { // //존에서 아이템이 검출되었다 // //동일한 데이터가 있다면 // item.RID = _reelid; // item.SID = _sid; // item.BarcodeRaw = _rawdata; // item.BarcodeEnd = DateTime.Now; // item.BarcodeMsg = _msg; // item.BarcodeStart = _sTime; // item.BarcodeDone = true; // return bcdzone[i]; // } // else if (item.RID != _reelid) // { // //이미 등록된 아이템이다 (??) // RaiseMessage("SetBarcodeZone : 지금 등록하려는 바코드가 이미 등록되었다! id:{0}, 등록되어있는 존 : {1},등록시간:{2} ", true, _reelid, bcdzone[i], item.BarcodeStart); // continue; // } // else // { // //같은게 중복으로 인식되었으므로 처리하지 않아도 된다 // RaiseMessage("SetBarcodeZone : 중복건으로 처리하지 않는다", false); // return bcdzone[i]; // } // } // RaiseMessage("1~3번 존 안에서 아이템을 찾지 못해 할당할 수 없습니다", true); // return -1; //} void RaiseMessage(string m, Boolean iserr, params object[] args) { if (args != null && args.Length > 0) m = string.Format(m, args); if (Message != null) Message(this, new MessageArgs(m, iserr)); } //public void CVItemMove(int oldZoneIdx) //{ // if (oldZoneIdx < 1 || oldZoneIdx > 10) throw new Exception("zonindex 값은 1~10 입니다"); // //해당 아이템 이하의 데이터를 모두 -1 한다. // this.zoneitem.Where(t => t.Delete == false && t.ZoneIndex >= oldZoneIdx).ToList().ForEach((t) => // { // t.ZoneIndex = t.ZoneIndex - 1; // t.ZoneIntime = DateTime.Now; // }); //} /// /// 아이템을 DROP해도 되는가? 존 3번 부터 아이템이 존재하면 drop 불가능으로 한다 /// void Scean_Input(Graphics g) { //var sb = new System.Text.StringBuilder(); //sb.AppendLine("자재 투입 모드"); //for (int i = 0; i < 4; i++) //{ // var p = arVar_Port[i]; // sb.AppendLine(string.Format("P{0} A:{1},DETU:{2},ENB:{3},LIML:{4},LIMH:{5},OVR:{6},RDY:{7}" + // ",MDIR:{8},MRUN:{9},SFTY:{10} :: {11}", // i + 1, p.AlignOK, p.DetectUp, p.Enable, p.LimitLower, // p.LimitUpper, p.OverLoad, p.Ready, p.MotorDir, p.MotorRun, p.SaftyErr, p.title)); //} //g.DrawString(sb.ToString(), this.arFont_PortMessage, Brushes.White, 100, 100); //각 포트영역 테두리 그리기 for (int i = 0; i < arVar_Port.Length; i++) { var p = arVar_Port[i]; var inputActive = false; if (i == 0) inputActive = arFGInputFL; else if (i == 1) inputActive = arFGInputFR; else if (i == 2) inputActive = arFGInputRL; else if (i == 3) inputActive = arFGInputRR; p.Display(g, this.arFont_count, this.arFont_PortMessage, this.arFGInputMode, inputActive); } } void Scean_MotHome(Graphics g) { //g.DrawString("mot home", this.Font, Brushes.Black, 100, 100); g.DrawRectangle(new Pen(Color.SteelBlue, 10), this.rect_main.Left, rect_main.Top, rect_main.Width, rect_main.Height); Font f = new Font(this.Font.Name, 50f, FontStyle.Bold); var rectTitle = new RectangleF( rect_main.Left, rect_main.Top, rect_main.Width, rect_main.Height * 0.25f); g.DrawString("MOTION HOME", f, Brushes.White, rectTitle, sfCenter); ; // g.DrawRectangle(Pens.Red, rectTitle.Left, rectTitle.Top, rectTitle.Width, rectTitle.Height); var rectBody = new RectangleF( rect_main.Left, rectTitle.Bottom + 10, rect_main.Width, rect_main.Height - rectTitle.Height - 10); // g.DrawRectangle(Pens.White, rectBody.Left, rectBody.Top, rectBody.Width, rectBody.Height); var rectT = new Rectangle( (int)(rectBody.Left + 20), (int)(rectBody.Top + 10), (int)(rectBody.Width * 0.23f), (int)(rectBody.Height * 0.07)); var rectXF = new Rectangle( (int)(rectT.Right + 20), (int)(rectBody.Top + 10), (int)(rectBody.Width - rectT.Width - rectT.Left - 10), (int)(rectBody.Height * 0.07)); var titles = new string[] { "Y-PICKER", "Z-FRONT", "Z-REAR", "X-FRONT", "X-REAR" }; for (int i = 0; i < 5; i++) { var perc = HomeProgress[i]; var title = titles[i]; var offsetY = (rectBody.Height * 0.15f); rectXF.Offset(0, (int)offsetY); rectT.Offset(0, (int)offsetY); //g.DrawRectangle(Pens.Yellow, rectT.Left, rectT.Top, rectT.Width, rectT.Height); using (Font f2 = new Font(this.Font.Name, 20f, FontStyle.Bold)) { g.DrawString("* " + title, f2, Brushes.Lime, rectT, sfLeft); } LinearGradientBrush brProgr = new LinearGradientBrush(rectXF, Color.Gold, Color.Yellow, LinearGradientMode.Vertical); var rectXF_P = new Rectangle(rectXF.Left, rectXF.Top, (int)(rectXF.Width * (perc / 100.0)), rectXF.Height); g.FillRectangle(brProgr, rectXF_P); g.DrawRectangle(Pens.Gray, rectXF); brProgr.Dispose(); } f.Dispose(); } void Scean_Normal(Graphics g) { ///50mm 마다 그리드를 처리한다 //using (Font f = new Font("Consolas", 7)) //{ // for (float i = 0; i < arMcLengthW; i += 50.0f) // { // var fs = g.MeasureString(i.ToString(), f); // var px = (float)(CvtMMtoPX_W(i, rect_main.Left)); // g.DrawLine(Pens.DimGray, px, (float)rect_main.Top, px, (float)rect_main.Bottom); // g.DrawString(i.ToString(), f, Brushes.White, new PointF(px - (fs.Width / 2.0f), rect_main.Top - fs.Height)); // } // for (float i = 0; i < arMcLengthH; i += 50.0f) // { // var fs = g.MeasureString(i.ToString(), f); // var px = (float)(CvtMMtoPX_H(i, rect_main.Top)); // g.DrawLine(Pens.DimGray, (float)rect_main.Left, px, (float)rect_main.Right, px); // if (i == 0) continue; // g.DrawString(i.ToString(), f, Brushes.White, new PointF(rect_main.Left, px - (fs.Height / 2.0f))); // } //} Draw_Icon(g); //전체 영역 테두리 g.DrawRectangle(new Pen(Color.DimGray, 2), rect_main.Left, rect_main.Top, rect_main.Width, rect_main.Height); //컨베어 그리기 Draw_Conveyor(g, rect_conveyor); //셔틀표시 Draw_BallScrewRail(g, rect_frontShuttle, 50, 5, false, LockXF, this.arMOT_Origin[(int)eAxis.X_F], arMOT_LimDn[(int)eAxis.X_F], arMOT_LimUp[(int)eAxis.X_F]); Draw_BallScrewRail(g, rect_rearShuttle, 50, 5, false, LockXR, this.arMOT_Origin[(int)eAxis.X_R], arMOT_LimDn[(int)eAxis.X_R], arMOT_LimUp[(int)eAxis.X_R]); //포트표시(셔틀위에 표시됨) Draw_Port(g, arMotorPosition[3], arMotorLengthXF, rect_frontShuttle, 0); //front Draw_Port(g, arMotorPosition[4], arMotorLengthXR, rect_rearShuttle, 2); //rear //Y축 레일표시 Draw_BallScrewRail(g, rect_picker, 50, 5, true, LockYP, this.arMOT_Origin[(int)eAxis.Y_P], arMOT_LimDn[(int)eAxis.Y_P], arMOT_LimUp[(int)eAxis.Y_P]); //모터 Y축 Draw_PickerY(g, rect_picker); Draw_Zone(g); Draw_CVItem(g); Draw_Button(g); //우측상단에 작업일자와 차수를 표시한다 if (string.IsNullOrEmpty(arJobDate) == false && string.IsNullOrEmpty(arJobSeq) == false) { var msg = arJobDate + ":" + arJobSeq; var fsizeseq = g.MeasureString(msg, this.Font); var rectseqinfo = new RectangleF(rect_main.Right - fsizeseq.Width * 1.15f, rect_main.Bottom, fsizeseq.Width * 1.15f, fsizeseq.Height); g.FillRectangle(new SolidBrush(Color.FromArgb(64, 64, 64)), rectseqinfo); g.DrawString(arJobDate + ":" + arJobSeq, this.Font, Brushes.White, rectseqinfo, sfCenter); g.DrawRectangle(Pens.White, rectseqinfo.Left, rectseqinfo.Top, rectseqinfo.Width, rectseqinfo.Height); } //정보 표시 (나중에 제거해야함) 별도 인포박스형태를 취해야 함 Draw_Info(g, rect_conveyor); Draw_Error(g); //메뉴는 최상위에 표시한다 Draw_Menu(g); if (arDebugMode) { var sb = new System.Text.StringBuilder(); sb.AppendLine("Loader Control"); sb.AppendLine(string.Format("Display {0} / pickup zone count {1} / total item count {2}", DisplayRectangle, zoneitemholding, ZoneItemCountTotal)); g.DrawString(sb.ToString(), this.Font, Brushes.White, 10, 10); updatetime = DateTime.Now; //작업 수량 및 전체수량을 표시함 var sb2 = new System.Text.StringBuilder(); if (arVar_Port != null && arVar_Port.Length > 0) { //sb2.AppendLine(string.Format("입(PICKER)/출(SS:DET1)/겹침(SS:DET1) : {0}/{1}/{2}", // ar_cnt_in, ar_cnt_out, ar_cnt_outdup)); //sb2.AppendLine(string.Format("바코드 입/출:CMD/DUP/READ/ERR/중복수신/할당실패 {0}/{1}:{2}/{3}/{4}/{5}/{6}/{7}", // ar_cnt_barcodein, ar_cnt_barcodeot, ar_cnt_barcodecmd, ar_cnt_barcodedup, ar_cnt_barcoderead, ar_cnt_barcodereaderr, ar_cnt_barcodereaddup, ar_cnt_barcodeAssignErr)); //sb2.AppendLine(string.Format("언로더 입/출:CMD/DUP {0}/{1}:{2}/{3}", // ar_cnt_plcin, ar_cnt_plcot, ar_cnt_plccmd, ar_cnt_plcdup)); sb2.AppendLine(string.Format("DIO:{4},BCD:{5},PLC:{6}\n" + "YP_RDY {7},{8},{9},{10}\n" + "YP_CMD {7},{8},{9},{10}\n", arVar_Port[0].reelCount, arVar_Port[1].reelCount, arVar_Port[2].reelCount, arVar_Port[3].reelCount, arConn_DIO, arConn_BCD, arConn_PLC, arFG_RDY_YP_FPICKON, arFG_RDY_YP_FPICKOF, arFG_RDY_YP_RPICKON, arFG_RDY_YP_RPICKOF, arFG_CMD_YP_FPICKON, arFG_CMD_YP_RPICKON)); } using (var f = new Font("Consolas", 15f, FontStyle.Bold)) g.DrawString(sb.ToString(), f, Brushes.SkyBlue, rect_conveyor.Left + 20, rect_conveyor.Top + 50); } } void Draw_Zone(Graphics g) { // if (arFlag_WaitBCD2) //바코드 대기중이라면 해당 존을 강조해준다 { var zone = rect_zone[2]; g.FillRectangle(new SolidBrush(Color.FromArgb(150, Color.Violet)), zone.Left, rect_main.Top, zone.Width, rect_main.Height); } if (arFlag_WaitBCD1) //바코드 대기중이라면 해당 존을 강조해준다 { var zone = rect_zone[3]; g.FillRectangle(new SolidBrush(Color.FromArgb(150, Color.Gold)), zone.Left, zone.Top, zone.Width, zone.Height); } if (arFlag_WaitPLC) { var zone = rect_zone[0]; g.FillRectangle(new SolidBrush(Color.FromArgb(150, Color.Violet)), zone.Left, this.rect_main.Top, zone.Width, this.rect_main.Height); } } /// /// 컨베이어의 아이템을 화면에 표시한ㄷ /// /// void Draw_CVItem(Graphics g) { //lock 개체적용 210110 lock (zitem) { var items = this.zitem.Where(t => t.Delete == false).ToList(); foreach (var item in items) { var zone = rect_zone[item.ZoneIndex]; var itemwidth = rect_conveyor.Width * 0.09f; //해당 존의 중앙에 아이템을 그린다. var cx = zone.Left + zone.Width / 2.0f; var cy = zone.Top + zone.Height / 2.0f; item.Rect = new Rectangle( (int)(cx - itemwidth / 2.0f), (int)(cy - itemwidth / 2.0f), (int)itemwidth, (int)itemwidth); //원을 그리다. if (item.hasBarcode) { if (item.Size == "13") { using (LinearGradientBrush br = new LinearGradientBrush(item.Rect, Color.DeepSkyBlue, Color.LightSkyBlue, LinearGradientMode.Vertical)) { g.FillEllipse(br, item.Rect); } } else { using (LinearGradientBrush br = new LinearGradientBrush(item.Rect, Color.LightSkyBlue, Color.DeepSkyBlue, LinearGradientMode.Vertical)) { g.FillEllipse(br, item.Rect); } } } else { if (item.iPort == -1) //외부입력데이터 { using (LinearGradientBrush br = new LinearGradientBrush(item.Rect, Color.Magenta, Color.DimGray, LinearGradientMode.BackwardDiagonal)) { g.FillEllipse(br, item.Rect); } } else { using (LinearGradientBrush br = new LinearGradientBrush(item.Rect, Color.Gray, Color.DimGray, LinearGradientMode.BackwardDiagonal)) { g.FillEllipse(br, item.Rect); } } } // g.DrawRectangle(Pens.Blue, zone.Left,zone.Top,zone.Width,zone.Height); // g.DrawRectangle(Pens.Red, item.Rect); var ts = DateTime.Now - item.ZoneIntime; if (ts.TotalSeconds > 7.0) { //오류발생 너무 오래됬음 g.DrawEllipse(new Pen(Color.Black, 7), item.Rect.OffsetRect(1, 1)); g.DrawEllipse(new Pen(Color.Magenta, 7), item.Rect); } else { g.DrawEllipse(new Pen(Color.DimGray, 5), item.Rect.OffsetRect(1, 1)); g.DrawEllipse(new Pen(Color.FromArgb(240, 240, 240), 5), item.Rect); } using (Font f = new Font("Consolas", 11, FontStyle.Bold)) { var fsizet = g.MeasureString(item.SID, f); var fsizeb = g.MeasureString(item.RID, f); var itemW = Math.Max(fsizet.Width, fsizeb.Width); var itemH = Math.Max(fsizet.Height, fsizeb.Height); //padding var paddingValue = (int)((item.Rect.Top - rect_conveyor.Top - itemH) / 2.0f + 5); //상단에는 SID를 if (string.IsNullOrEmpty(item.SID) == false) { var zcx = zone.Left + zone.Width / 2.0f; var rectTop = new RectangleF(zcx - itemW / 2.0f, (float)rect_conveyor.Top, itemW, itemH); g.FillRectangle(new SolidBrush(Color.SteelBlue), rectTop); g.DrawRect(rectTop, Color.FromArgb(30, 30, 30)); g.DrawString(item.SID, f, Brushes.Black, rectTop, sfCenter); } //하단에는 RID를 if (string.IsNullOrEmpty(item.RID) == false) { var zcx = zone.Left + zone.Width / 2.0f; var rectTop = new RectangleF(zcx - itemW / 2.0f, (float)rect_conveyor.Bottom - itemH, itemW, itemH); g.FillRectangle(new SolidBrush(Color.SteelBlue), rectTop); g.DrawRect(rectTop, Color.FromArgb(30, 30, 30)); g.DrawString(item.RID, f, Brushes.Black, rectTop, sfCenter); } } if (arDebugMode) { ///크기 및 포트 drop 시간 정보를 표시한다. var sb = new System.Text.StringBuilder(); sb.AppendLine("[" + item.Seq.ToString() + "]PORT:" + item.iPort.ToString()); sb.AppendLine("SIZE:" + item.Size); sb.AppendLine("DROP:" + item.DropTime.ToString("HH:mm:ss")); sb.AppendLine("IN:" + item.InTime.ToString("HH:mm:ss")); sb.AppendLine("ZONE:" + item.ZoneIndex.ToString()); sb.AppendLine("존투입:" + item.ZoneIntime.ToString("yyyy-MM-dd HH:mmss")); sb.AppendLine("REEL:" + item.RID.ToString()); sb.AppendLine("SID:" + item.SID.ToString()); using (Font f = new Font("맑은 고딕", 12, FontStyle.Bold)) { if (item.Delete) g.DrawString(sb.ToString(), f, Brushes.Red, item.Rect.Left, item.Rect.Top); else if (item.RID.Trim() != "") g.DrawString(sb.ToString(), f, Brushes.Blue, item.Rect.Left, item.Rect.Top); else g.DrawString(sb.ToString(), f, Brushes.Black, item.Rect.Left, item.Rect.Top); } } else { //배출포트 설정전에는 크기를 중앙에 표시 //위에는 SID , 아래는 RID를 표시 var CenterString = (item.oPort == -1 ? item.Size + "\"" : "#" + item.oPort.ToString()); var fsize = item.oPort == -1 ? 40 : 30; using (Font f = new Font("Consolas", fsize, FontStyle.Bold)) { if (item.Delete) g.DrawString(CenterString, f, Brushes.Red, item.Rect, sfCenter); else if (item.RID.Trim() != "") { g.DrawString(CenterString, f, Brushes.Black, item.Rect, sfCenter); } else g.DrawString(CenterString, f, Brushes.Black, item.Rect, sfCenter); } } } } } void Draw_Icon(Graphics g) { int iconOffsetX = 19; int iconOffsetY = 20; CIcon icon; icon = this.icons[0];//.Rect; if (arConn_BCD) g.DrawImage(UIControl.Properties.Resources.bg_blue, icon.X, icon.Y); else g.DrawImage(Properties.Resources.bg_red, icon.X, icon.Y); g.DrawImage(Properties.Resources.bcd, icon.X + iconOffsetX, icon.Y + iconOffsetY); //if (icon.Focus) g.DrawRectangle(Pens.Gold, icon.X,icon.Y,icon.W,icon.H); icon = this.icons[1];//.Rect; if (arConn_PLC) g.DrawImage(Properties.Resources.bg_blue, icon.X, icon.Y); else g.DrawImage(Properties.Resources.bg_red, icon.X, icon.Y); g.DrawImage(Properties.Resources.plc, icon.X + iconOffsetX, icon.Y + iconOffsetY); //if (icon.Focus) g.DrawRectangle(Pens.Gold, icon.X, icon.Y, icon.W, icon.H); icon = this.icons[2];//.Rect; if (arConn_MOT) g.DrawImage(Properties.Resources.bg_blue, icon.X, icon.Y); else g.DrawImage(Properties.Resources.bg_red, icon.X, icon.Y); g.DrawImage(Properties.Resources.mot, icon.X + iconOffsetX, icon.Y + iconOffsetY); //if (icon.Focus) g.DrawRectangle(Pens.Gold, icon.X, icon.Y, icon.W, icon.H); icon = this.icons[3];//.Rect; if (arDI_Emergency == false) g.DrawImage(Properties.Resources.bg_blue, icon.X, icon.Y); else g.DrawImage(Properties.Resources.bg_red, icon.X, icon.Y); g.DrawImage(Properties.Resources.emg, icon.X + iconOffsetX, icon.Y + iconOffsetY); //if (icon.Focus) g.DrawRectangle(Pens.Gold, icon.X, icon.Y, icon.W, icon.H); icon = this.icons[4];//.Rect; if (this.arDI_SaftyOk) g.DrawImage(Properties.Resources.bg_blue, icon.X, icon.Y); else g.DrawImage(Properties.Resources.bg_red, icon.X, icon.Y); g.DrawImage(Properties.Resources.safty, icon.X + iconOffsetX, icon.Y + iconOffsetY); //if (icon.Focus) g.DrawRectangle(Pens.Gold, icon.X, icon.Y, icon.W, icon.H); icon = this.icons[5];//.Rect; if (arDIAir) g.DrawImage(Properties.Resources.bg_blue, icon.X, icon.Y); else g.DrawImage(Properties.Resources.bg_red, icon.X, icon.Y); g.DrawImage(Properties.Resources.air, icon.X + iconOffsetX, icon.Y + iconOffsetY); //if (icon.Focus) g.DrawRectangle(Pens.Gold, icon.X, icon.Y, icon.W, icon.H); //icon = this.icons[6];//.Rect; //if (arConn_REM) g.DrawImage(Properties.Resources.bg_blue, icon.X, icon.Y); //else g.DrawImage(Properties.Resources.bg_red, icon.X, icon.Y); //g.DrawImage(Properties.Resources.debug40, icon.X + iconOffsetX, icon.Y + iconOffsetY); ////if (icon.Focus) g.DrawRectangle(Pens.Gold, icon.X, icon.Y, icon.W, icon.H); } void Draw_Button(Graphics g) { foreach (var but in Buttons) { var font = but.Font; if (font == null) font = new Font("맑은 고딕", 15); if (NeedHomeSet() == false && arDI_Emergency == false && but.Tag == "INPUTL" && arIsRunning == false && arFGInputMode == false) { if (but.Shape == eButtonType.Rectangle) { g.FillRectangle(Brushes.White, but.Rect); g.DrawRectangle(new Pen(but.BorderColor, but.BorderSize), but.Rect); } else { g.FillEllipse(Brushes.White, but.Rect); g.DrawEllipse(new Pen(but.BorderColor, but.BorderSize), but.Rect); } g.DrawString(but.Text, font, Brushes.Black, but.Rect, sfCenter); } else if (NeedHomeSet() == false && arDI_Emergency == false && but.Tag == "INPUTR" && arIsRunning == false && arFGInputMode == false) { if (but.Shape == eButtonType.Rectangle) { g.FillRectangle(Brushes.White, but.Rect); g.DrawRectangle(new Pen(but.BorderColor, but.BorderSize), but.Rect); } else { g.FillEllipse(Brushes.White, but.Rect); g.DrawEllipse(new Pen(but.BorderColor, but.BorderSize), but.Rect); } g.DrawString(but.Text, font, Brushes.Black, but.Rect, sfCenter); } font.Dispose(); } } void Draw_Info(Graphics g, RectangleF rect) { //디자인 모드에서는 표시하지 않는다 200714 //if (DesignMode == true) return; //if (this.arFlag_UnloaderBusy) ShowPopupMessage(g, "언로더 작업 대기 중\nBUSY", Properties.Resources.info); //if (this.arIsRunning) if (arFGInputMode) { ShowPopupMessage(g, "자재 투입 모드", "투입완료 후 'Re.Start' 하세요", Properties.Resources.info, false); } else { if (this.arFlag_UnloaderErr == true) ShowPopupMessage(g, "언로더 오류 발생", "STOP된 언로더를 확인하세요", Properties.Resources.error, false); else if (this.arFlag_WaitPLC && arUnloaderSeq > 0) { if (arUnloaderSeq == 1) ShowPopupMessage(g, "언로더 작업 대기 중", "상태확인(#1)", Properties.Resources.info, false); else if (arUnloaderSeq == 2) ShowPopupMessage(g, "언로더 작업 대기 중", "BUSY(#2)", Properties.Resources.info, false); else if (arUnloaderSeq == 3) ShowPopupMessage(g, "언로더 작업 대기 중", "ITEM CHECK(#3)", Properties.Resources.info, false); else if (arUnloaderSeq == 4) ShowPopupMessage(g, "언로더 작업 대기 중", "배출포트 설정(#4)", Properties.Resources.info, false); else if (arUnloaderSeq == 5) ShowPopupMessage(g, "언로더 작업 대기 중", "릴크기 설정(#5)", Properties.Resources.info, false); else if (arUnloaderSeq == 6) ShowPopupMessage(g, "언로더 작업 대기 중", "No.ZERO CHECK(#6)", Properties.Resources.info, false); } } } void Draw_PickerRail(Graphics g, RectangleF rect) { RectangleF rectRailL = new RectangleF(rect.Left, rect.Top, rect.Width / 2.0f + 1, rect.Height); RectangleF rectRailR = new RectangleF(rect.Left + rect.Width / 2.0f, rect.Top, rect.Width / 2.0f, rect.Height); var brR = new LinearGradientBrush(rect, Color.FromArgb(60, 60, 60), Color.FromArgb(80, 80, 80), LinearGradientMode.Horizontal); var brL = new LinearGradientBrush(rect, Color.FromArgb(80, 80, 80), Color.FromArgb(60, 60, 60), LinearGradientMode.Horizontal); g.FillRectangle(brL, rectRailL); //g.FillRectangle(brR, rectRailR); brL.Dispose(); brR.Dispose(); g.DrawRectangle(Pens.DimGray, rect.Left, rect.Top, rect.Width, rect.Height); } void Draw_PickerY(Graphics g, RectangleF rect) { //전체영역의 80% 영역에 Y-로봇의 축을 그린다. //var motorMax = 400; //전체 가동 길이 400mm this.arMotorLengthY = 600; var py = rect.Top + rect.Height - (rect.Height * ((this.arMotorPosition[0] + 1) / (this.arMotorLengthY * 1.0f))); var cx = rect.Left + rect.Width / 2.0f; //상(Rear), 하(Front)로 영역을 그린다 var port_width = rect_picker_rear.Width;// * 3f; var port_height = rect_picker_rear.Height; // rect.Height * 0.2f; var port_space = (this.rect_picker_front.Top - this.rect_picker_rear.Bottom) / 2.0f; //New Rear Position var newYR = (float)(py - port_height - port_space); if (newYR != rect_picker_rear.Y) { var offset = newYR - rect_picker_rear.Y; this.rect_picker_rear.Offset(0, offset); //좌표가 변경되었다면 재계산 this.rect_picker_rear_vac1.Offset(0, offset); this.rect_picker_rear_vac2.Offset(0, offset); this.rect_picker_rear_vac3.Offset(0, offset); this.rect_picker_rear_vac4.Offset(0, offset); } //New Front Position var newYF = (float)(py + port_space); if (newYF != rect_picker_front.Y) { var offset = newYF - rect_picker_front.Y; this.rect_picker_front.Offset(0, offset); //좌표가 변경되었다면 재계산 this.rect_picker_front_vac1.Offset(0, offset); this.rect_picker_front_vac2.Offset(0, offset); this.rect_picker_front_vac3.Offset(0, offset); this.rect_picker_front_vac4.Offset(0, offset); } //피커 #1 Circle 색상 var Bg1 = Color.FromArgb(100, 100, 100); var Bg2 = Color.FromArgb(160, 160, 160); if (this.arVar_Picker[0].Overload) { Bg1 = Color.Tomato; Bg2 = Color.Red; } else { if (this.arVar_Picker[0].ItemOn) { if (this.arVar_Picker[0].isReelDetect) { Bg1 = Color.Lime; //.FromArgb(100, 100, 100); Bg2 = Color.Green;//.FromArgb(160, 160, 160); } else { Bg1 = Color.Magenta; //.FromArgb(100, 100, 100); Bg2 = Color.DarkMagenta;//.FromArgb(160, 160, 160); } } else { Bg1 = Color.FromArgb(100, 100, 100); Bg2 = Color.FromArgb(160, 160, 160); } } using (var br = new LinearGradientBrush(rect_picker_front, Bg1, Bg2, LinearGradientMode.Vertical)) { g.FillEllipse(br, rect_picker_front); } //피커 #2 Circle 색상 if (this.arVar_Picker[1].Overload) { Bg1 = Color.Tomato; Bg2 = Color.Red; } else { if (this.arVar_Picker[1].ItemOn) { //실제 아이템 체크 if (this.arVar_Picker[1].isReelDetect) { Bg1 = Color.Lime; //.FromArgb(100, 100, 100); Bg2 = Color.Green;//.FromArgb(160, 160, 160); } else { Bg1 = Color.Magenta; //.FromArgb(100, 100, 100); Bg2 = Color.DarkMagenta;//.FromArgb(160, 160, 160); } } else { Bg1 = Color.FromArgb(100, 100, 100); Bg2 = Color.FromArgb(160, 160, 160); } } using (var br = new LinearGradientBrush(rect_picker_rear, Bg1, Bg2, LinearGradientMode.Vertical)) { g.FillEllipse(br, rect_picker_rear); } //피커 테두리 using (var bgPen = new Pen(Color.Black, 3)) { g.DrawEllipse(bgPen, rect_picker_front); g.DrawEllipse(bgPen, rect_picker_rear); } //피커 내부의 진공 표현 g.FillEllipse((this.arVar_Picker[0].VacDetect[0] ? brVacOn : brVacOff), rect_picker_front_vac1); g.FillEllipse((this.arVar_Picker[0].VacDetect[1] ? brVacOn : brVacOff), rect_picker_front_vac2); g.FillEllipse((this.arVar_Picker[0].VacDetect[2] ? brVacOn : brVacOff), rect_picker_front_vac3); g.FillEllipse((this.arVar_Picker[0].VacDetect[3] ? brVacOn : brVacOff), rect_picker_front_vac4); g.FillEllipse((this.arVar_Picker[1].VacDetect[0] ? brVacOn : brVacOff), rect_picker_rear_vac1); g.FillEllipse((this.arVar_Picker[1].VacDetect[1] ? brVacOn : brVacOff), rect_picker_rear_vac2); g.FillEllipse((this.arVar_Picker[1].VacDetect[2] ? brVacOn : brVacOff), rect_picker_rear_vac3); g.FillEllipse((this.arVar_Picker[1].VacDetect[3] ? brVacOn : brVacOff), rect_picker_rear_vac4); //피커설명 표시 if (arVar_Picker[0].Overload) g.DrawString("OVL", arFont_picker, Brushes.Black, rect_picker_front, sfCenter); else g.DrawString(this.arVar_Picker[0].ReelSize, arFont_picker, Brushes.Black, rect_picker_front, sfCenter); if (arVar_Picker[1].Overload) g.DrawString("OVL", arFont_picker, Brushes.Black, rect_picker_rear, sfCenter); else g.DrawString(this.arVar_Picker[1].ReelSize, arFont_picker, Brushes.Black, rect_picker_rear, sfCenter); //피커 진공표시 테두리 (진공출력상태에 따라서 색상을 달리 함) g.DrawEllipse((this.arVar_Picker[0].VacOutput[0] ? penVacOn : penVacOff), rect_picker_front_vac1); g.DrawEllipse((this.arVar_Picker[0].VacOutput[1] ? penVacOn : penVacOff), rect_picker_front_vac2); g.DrawEllipse((this.arVar_Picker[0].VacOutput[2] ? penVacOn : penVacOff), rect_picker_front_vac3); g.DrawEllipse((this.arVar_Picker[0].VacOutput[3] ? penVacOn : penVacOff), rect_picker_front_vac4); g.DrawEllipse((this.arVar_Picker[1].VacOutput[0] ? penVacOn : penVacOff), rect_picker_rear_vac1); g.DrawEllipse((this.arVar_Picker[1].VacOutput[1] ? penVacOn : penVacOff), rect_picker_rear_vac2); g.DrawEllipse((this.arVar_Picker[1].VacOutput[2] ? penVacOn : penVacOff), rect_picker_rear_vac3); g.DrawEllipse((this.arVar_Picker[1].VacOutput[3] ? penVacOn : penVacOff), rect_picker_rear_vac4); //중앙부에 흰색구를 표시함 g.FillEllipse(Brushes.White, cx - 5, (float)(py - 5f), 10, 10); } void Draw_Screw(Graphics g, Rectangle rect) { //모터표시(X축) g.FillRectangle(new SolidBrush(Color.FromArgb(50, 150, 150, 150)), rect); //해다 영역에 사선으로그림을 그린다. var termcount = 50; var lineterm = rect.Width / termcount; var skew = rect.Width * 0.01f; Pen p = new Pen(Color.FromArgb(50, 120, 120, 120), 2); for (int i = 0; i < termcount; i++) { var pt1 = new PointF(rect.Left + i * lineterm, rect.Top); var pt2 = new PointF(pt1.X + skew, rect.Bottom); g.DrawLine(p, pt1, pt2); } p.Dispose(); //e.Graphics.DrawRectangle(Pens.Gray, motr_rect.Left, motr_rect.Top, motr_rect.Width, motr_rect.Height); //e.Graphics.DrawRectangle(Pens.Gray, motf_rect.Left, motf_rect.Top, motf_rect.Width, motf_rect.Height); //RectangleF rectRailT = new RectangleF(rect.Left, rect.Top, rect.Width, rect.Height / 2.0f + 1); //RectangleF rectRailB = new RectangleF(rect.Left, rect.Top + rect.Height / 2.0f, rect.Width, rect.Height / 2.0f); //var brR = new LinearGradientBrush(rect, Color.FromArgb(100, 60, 60, 60), Color.FromArgb(100, 80, 80, 80), LinearGradientMode.Vertical); //var brL = new LinearGradientBrush(rect, Color.FromArgb(100, 80, 80, 80), Color.FromArgb(100, 60, 60, 60), LinearGradientMode.Vertical); ////g.FillRectangle(brL, rectRailT); ////g.FillRectangle(brR, rectRailB); //brL.Dispose(); //brR.Dispose(); g.DrawRectangle(new Pen(Color.FromArgb(50, Color.Gray)), rect.Left, rect.Top, rect.Width, rect.Height); } void Draw_BallScrewRail(Graphics g, RectangleF rect, int divCount, int alpha, Boolean downDirection, Boolean MLock, Boolean Org, Boolean LimDn, Boolean LimUp) { //모터표시(X축) if (Org) g.FillRectangle(new SolidBrush(Color.FromArgb(alpha, Color.SkyBlue)), rect); else if (LimUp) g.FillRectangle(new SolidBrush(Color.FromArgb(alpha, Color.Red)), rect); else if (LimDn) g.FillRectangle(new SolidBrush(Color.FromArgb(alpha, Color.Blue)), rect); else g.FillRectangle(new SolidBrush(Color.FromArgb(alpha, 150, 150, 150)), rect); //해다 영역에 사선으로그림을 그린다. var baseSize = (downDirection == false ? rect.Width : rect.Height); var lineterm = baseSize / divCount; var skew = baseSize * 0.01f; Pen p = new Pen(Color.FromArgb(alpha, 120, 120, 120), 2); PointF pt1 = PointF.Empty; PointF pt2 = PointF.Empty; for (int i = 0; i < divCount; i++) { if (downDirection) { pt1 = new PointF(rect.Left, rect.Top + i * lineterm); pt2 = new PointF(rect.Right, pt1.Y + skew); } else { pt1 = new PointF(rect.Left + i * lineterm, rect.Top); pt2 = new PointF(pt1.X + skew, rect.Bottom); } g.DrawLine(p, pt1, pt2); } p.Dispose(); //limi이 걸려있다면 해당 영역에 적색으로 표시한다. var limwidth = 30; if (LimUp) { RectangleF rectlu; if (downDirection) rectlu = new RectangleF(rect.Left, rect.Top, rect.Width, limwidth); else rectlu = new RectangleF(rect.Right - limwidth, rect.Top, limwidth, rect.Height); g.FillRectangle(Brushes.Red, rectlu.Left, rectlu.Top, rectlu.Width, rectlu.Height); } if (LimDn) { RectangleF rectlu; if (downDirection) rectlu = new RectangleF(rect.Left, rect.Bottom - limwidth, rect.Width, limwidth); else rectlu = new RectangleF(rect.Left, rect.Top, limwidth, rect.Height); g.FillRectangle(Brushes.Red, rectlu.Left, rectlu.Top, rectlu.Width, rectlu.Height); } //전체 테두리 g.DrawRectangle(new Pen(Color.FromArgb(alpha, Color.Gray)), rect.Left, rect.Top, rect.Width, rect.Height); } Boolean NeedHomeSet() { return arConn_MOT && (this.arMOT_HSet[0] == false || this.arMOT_HSet[1] == false || this.arMOT_HSet[2] == false || this.arMOT_HSet[3] == false || this.arMOT_HSet[4] == false); } byte errstep = 0; bool errstepR = true; void Draw_Error(Graphics g) { //디자인 모드에서는 표시하지 않는다 200714 if (DesignMode == true) return; if (arConn_DIO && this.arDI_Emergency == true) ShowPopupMessage(g, "EMERGENCY BUTTON", "비상정지 확인\nEMERGENCY or POWER LOSS", Properties.Resources.error, true); else if (this.arDI_SaftyOk == false) ShowPopupMessage(g, "SAFTY SENSOR", "안전 센서 확인", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_Alm[0] == true) ShowPopupMessage(g, "SERVO ALARM", "Y-PICKER 모터 알람 발생", Properties.Resources.error, true); else if (arConn_MOT && this.arMOT_Alm[1] == true) ShowPopupMessage(g, "SERVO ALARM", "Z-FRONT 모터 알람 발생", Properties.Resources.error, true); else if (arConn_MOT && this.arMOT_Alm[2] == true) ShowPopupMessage(g, "SERVO ALARM", "Z-REAR 모터 알람 발생", Properties.Resources.error, true); else if (arConn_MOT && this.arMOT_Alm[3] == true) ShowPopupMessage(g, "SERVO ALARM", "X-FRONT 모터 알람 발생", Properties.Resources.error, true); else if (arConn_MOT && this.arMOT_Alm[4] == true) ShowPopupMessage(g, "SERVO ALARM", "X-REAR 모터 알람 발생", Properties.Resources.error, true); else if (arConn_MOT && this.arMOT_SVOn[0] == false) ShowPopupMessage(g, "SERVO ALARM", "Y-PICKER SERVO-OFF", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_SVOn[1] == false) ShowPopupMessage(g, "SERVO ALARM", "Z-FRONT SERVO-OFF", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_SVOn[2] == false) ShowPopupMessage(g, "SERVO ALARM", "Z-REAR SERVO-OFF", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_SVOn[3] == false) ShowPopupMessage(g, "SERVO ALARM", "X-FRONT SERVO-OFF", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_SVOn[4] == false) ShowPopupMessage(g, "SERVO ALARM", "X-REAR SERVO-OFF", Properties.Resources.alert, true); else if (arConn_MOT && (this.arMOT_HSet[0] == false || this.arMOT_HSet[1] == false || this.arMOT_HSet[2] == false || this.arMOT_HSet[3] == false || this.arMOT_HSet[4] == false)) { //안전오류도 표시해줘야한다 var SaftyMessage = string.Empty; if (arVar_Port[0].SaftyErr == true) SaftyMessage += "PORT-FL"; if (arVar_Port[1].SaftyErr == true) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "," : string.Empty) + "PORT-FR"; if (arVar_Port[2].SaftyErr == true) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "," : string.Empty) + "PORT-RL"; if (arVar_Port[3].SaftyErr == true) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "," : string.Empty) + "PORT-RR"; if (string.IsNullOrEmpty(SaftyMessage) == false) { ShowPopupMessage(g, "SYSTEM NOT READY", "장치 초기화가 필요 합니다\n포트안전센서 확인 필요\n" + SaftyMessage, Properties.Resources.error, true); } else ShowPopupMessage(g, "SYSTEM NOT READY", "장치 초기화가 필요 합니다\n홈 검색이 완료되지 않았습니다", Properties.Resources.error, true); } else if (arConn_MOT && this.arMOT_HSet[0] == false) ShowPopupMessage(g, "SERVO ALARM", "Y-PICKER 홈 검색 필요", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_HSet[1] == false) ShowPopupMessage(g, "SERVO ALARM", "Z-FRONT 홈 검색 필요", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_HSet[2] == false) ShowPopupMessage(g, "SERVO ALARM", "Z-REAR 홈 검색 필요", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_HSet[3] == false) ShowPopupMessage(g, "SERVO ALARM", "X-FRONT 홈 검색 필요", Properties.Resources.alert, true); else if (arConn_MOT && this.arMOT_HSet[4] == false) ShowPopupMessage(g, "SERVO ALARM", "X-REAR 홈 검색 필요", Properties.Resources.alert, true); else if (arVar_Port[0].OverLoad) ShowPopupMessage(g, "## OVERLOAD ##", "FRONT-LEFT", Properties.Resources.alert, true); else if (arVar_Port[1].OverLoad) ShowPopupMessage(g, "## OVERLOAD ##", "FRONT-RIGHT", Properties.Resources.alert, true); else if (arVar_Port[2].OverLoad) ShowPopupMessage(g, "## OVERLOAD ##", "REAR-LEFT", Properties.Resources.alert, true); else if (arVar_Port[3].OverLoad) ShowPopupMessage(g, "## OVERLOAD ##", "REAR-RIGHT", Properties.Resources.alert, true); //else if (arFlag_UnloaderBusy) ShowPopupMessage(g, "## UNLOADER ##\nBUSY", Properties.Resources.alert); //else if (arFlag_UnloaderErr) ShowPopupMessage(g, "## UNLOADER ##\nERROR", Properties.Resources.alert); } void Draw_Menu(Graphics g) { //var buttonOk = new CMenuButton("OK", "1"); //var buttonNo = new CMenuButton("CANCLE", "0"); //var newmenu = new CMenu("body str", "title", eMsgIcon.Error, buttonOk, buttonNo) //{ // BorderColor = Color.Gray //}; //this.menus.Push(newmenu); if (arMenus == null || arMenus.Length < 1) { this.HasPopupMenu = false; return; } else HasPopupMenu = true; ShowMaskLayer(g, Color.FromArgb(250, Color.Black)); var item = this.arMenus.Last();//.Peek(); //이 메뉴를 표시 합니다. PopupMenuRequireInput = item.RequireInput; var buttonSpace = 10; var hSpace = 5; var vSpace = 10; var iconSize = 80; var menuheight = 64; var padding = 10; var msgW = 900;// (int)(this.rect_main.Width * 0.65f);// 640;// (int)(rect_main.Width * 0.7f); var msgH = 400; var rect = new RectangleF( rect_main.Left + (rect_main.Width - msgW) / 2.0f, rect_main.Top + (rect_main.Height - msgH) / 2.0f, msgW, msgH); Rectangle rectT = Rectangle.Empty; //title Rectangle rectI = Rectangle.Empty; //icon Rectangle rectC = Rectangle.Empty; //content Rectangle rectB = Rectangle.Empty; //button rectT = new Rectangle((int)rect.Left + padding, (int)rect.Top + padding, (int)rect.Width - (padding * 2), (int)(rect.Height * 0.1)); rectI = new Rectangle((int)rect.Left + padding + 10, (int)rectT.Bottom + vSpace, iconSize, iconSize); //icon size rectB = new Rectangle((int)(rect.Left + padding * 2), (int)(rect.Bottom - menuheight - padding), (int)rect.Width - (padding * 4), menuheight); rectC = new Rectangle((int)rectI.Right + 20 + hSpace * 2, (int)rectT.Bottom + 10 + vSpace, (int)(rect.Width - hSpace - (padding * 2) - rectI.Width), (int)(rect.Height - rectT.Height - rectB.Height - (padding * 2) - vSpace * 2)); g.FillRectangle(new SolidBrush(Color.FromArgb(220, item.BackColor)), rect); //제목줄 표시 using (LinearGradientBrush sb = new LinearGradientBrush(rectT, Color.FromArgb(160, 160, 160), Color.FromArgb(180, 180, 180), LinearGradientMode.Vertical)) { g.FillRectangle(sb, rectT); } g.DrawString(item.Title, item.Font, new SolidBrush(item.ForeColor), rectT, sfCenter); //버튼표시 if (item.buttons != null && item.buttons.Length > 0) { //현재 버튼 영역의 갯수가 다르면 다시 생성한다. if (menuButtons.Count != item.buttons.Length) { menuButtons = new List(); foreach (var bt in item.buttons) menuButtons.Add(bt); g.DrawString("!!", this.Font, Brushes.Red, rectB.Left + 10, rectB.Top + 10); } else { for (int i = 0; i < menuButtons.Count; i++) menuButtons[i] = item.buttons[i]; } g.DrawString(item.buttons.Length.ToString() + "/" + menuButtons.Count.ToString(), this.Font, Brushes.Red, rectB); var butidx = 0; var butwid = (rectB.Width - (item.buttons.Length - 1) * buttonSpace) / item.buttons.Length; foreach (var but in item.buttons) { but.menutag = item.Tag; but.Rect = new Rectangle(rectB.Left + butwid * butidx + buttonSpace * butidx, rectB.Top, butwid, rectB.Height); g.FillRectangle(new SolidBrush(but.BackColor), but.Rect); g.DrawRectangle(new Pen(but.BorderColor, but.BorderSize), but.Rect); g.DrawString(but.Text, item.Font, new SolidBrush(but.ForeColor), but.Rect, sfCenter); butidx++; } } else menuButtons.Clear(); //아이콘 영역에 그림표시 if (rectI.IsEmpty == false) { g.DrawImage(Properties.Resources.info, rectI); } //본문데이터표시 if (string.IsNullOrEmpty(item.Text) == false) //contec { g.DrawString(item.Text, item.Font, new SolidBrush(item.ForeColor), rectC); } //외각 테두리 //g.DrawRectangle(new Pen(Color.FromArgb(20,20,20), 10) { Alignment = PenAlignment.Center }, rect.Left + 1, rect.Top + 1, rect.Width, rect.Height); g.DrawRectangle(new Pen(Color.FromArgb(180, 180, 180), 10) { Alignment = PenAlignment.Center }, rect.Left, rect.Top, rect.Width, rect.Height); //g.DrawRectangle(Pens.Black, rect.Left, rect.Top, rect.Width, rect.Height); //g.DrawRectangle(Pens.Red, rectT); //제목표시줄 //g.DrawRectangle(Pens.Blue, rectI); //아이콘 //g.DrawRectangle(Pens.Green, rectB); //버튼영역 //g.DrawRectangle(Pens.Black, rectC); //본문영역 } void ShowMaskLayer(Graphics g, Color maskColor) { g.FillRectangle(new SolidBrush(maskColor), this.DisplayRectangle.Left, DisplayRectangle.Top, DisplayRectangle.Width, DisplayRectangle.Height); } void ShowPopupMessage(Graphics g, string title, string msg, Image icon, Boolean isError) { //팝업표시할때마다 배경 마스킹을 한다 //var maskColor = Color.FromArgb(100, Color.White); //ShowMaskLayer(g, maskColor); if (isError == false) { //팝업표시할때마다 배경 마스킹을 한다 var maskColor = Color.FromArgb(50, Color.Gray); ShowMaskLayer(g, maskColor); var msgW = (int)(this.rect_main.Width * 0.65f);// 640;// (int)(rect_main.Width * 0.7f); var msgH = 105; var rect = new RectangleF( rect_main.Left + (rect_main.Width - msgW) / 2.0f, rect_main.Top + (rect_main.Height - msgH) / 2.0f, msgW, msgH); var TitleHeight = 25; var rectT = new Rectangle((int)rect.Left, (int)rect.Bottom - TitleHeight, (int)rect.Width, TitleHeight); var rectI = new Rectangle((int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height - rectT.Height); //g.FillRectangle(new SolidBrush(Color.FromArgb(220, Color.Black)), rect); g.FillRectangle(new SolidBrush(Color.FromArgb(120, Color.White)), rect); var rectTL = new RectangleF(rectT.Left, rectT.Top, rectT.Width / 2.0f, rectT.Height); var rectTR = new RectangleF(rectTL.Right, rectT.Top, rectTL.Width, rectTL.Height); using (var sb = new LinearGradientBrush(rectT, Color.Transparent, Color.White, LinearGradientMode.Horizontal)) g.FillRectangle(sb, rectTL); using (var sb = new LinearGradientBrush(rectT, Color.White, Color.Transparent, LinearGradientMode.Horizontal)) g.FillRectangle(sb, rectTR); //g.DrawImage(icon, // (int)(rect.Left + 20), // (int)(rect.Top + (rect.Height - icon.Height) / 2.0f)); g.DrawString(title, new Font("맑은 고딕", 10f, FontStyle.Bold), Color.Black, rectT, ContentAlignment.MiddleCenter); g.DrawString(msg, new Font("맑은 고딕", 30f, FontStyle.Bold), Color.White, rectI, ContentAlignment.MiddleCenter, Color.FromArgb(24, 24, 24)); if (errstep % 5 == 0) errstepR = !errstepR; if (errstepR) g.DrawRectangle(new Pen(Color.Gold, 2), rect.Left, rect.Top, rect.Width, rect.Height); else g.DrawRectangle(new Pen(Color.White, 2), rect.Left, rect.Top, rect.Width, rect.Height); if (errstep < 255) errstep += 1; else errstep = 0; } else { //팝업표시할때마다 배경 마스킹을 한다 var maskColor = Color.FromArgb(253, 15, 15, 15); ShowMaskLayer(g, maskColor); var msgW = (int)(this.rect_main.Width * 0.65f);// 640;// (int)(rect_main.Width * 0.7f); var msgH = 400; var rect = new RectangleF( rect_main.Left + (rect_main.Width - msgW) / 2.0f, rect_main.Top + (rect_main.Height - msgH) / 2.0f, msgW, msgH); var rectT = new Rectangle((int)rect.Left, (int)rect.Bottom - 200, (int)rect.Width, 200); var rectI = new Rectangle((int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height - rectT.Height); //g.FillRectangle(new SolidBrush(Color.FromArgb(220, Color.Black)), rect); g.FillRectangle(new SolidBrush(Color.FromArgb(253, Color.Black)), rect); g.DrawImage(icon, (int)(rectI.Left + rectI.Width / 2.0f) - 40, (int)(rectI.Top + rectI.Height / 2.0f) + 10); g.DrawString(msg, new Font("맑은 고딕", 30f, FontStyle.Bold), Brushes.Gold, rectT, sfCenter); if (errstep % 5 == 0) errstepR = !errstepR; if (errstepR) g.DrawRectangle(new Pen(Color.Red, 10), rect.Left, rect.Top, rect.Width, rect.Height); else g.DrawRectangle(new Pen(Color.Gold, 10), rect.Left, rect.Top, rect.Width, rect.Height); if (errstep < 255) errstep += 1; else errstep = 0; } } void Draw_Conveyor(Graphics g, RectangleF rect) { //컨베어표시 g.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Black)), rect); if (arDI_Safty_CvIn || arDI_Cv_Detect[6]) { //입구쪽 감지센서 var rectdetIn = new RectangleF(rect.Right - 10, rect.Top + 9, 5, rect.Height - 10); g.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Blue)), rectdetIn); } if (arDI_Safty_CvOut || arDI_Cv_Detect[7]) { //출구쪽 감지센서 var rectdetOut = new RectangleF(rect.Left, rect.Top + 9, 5, rect.Height - 10); g.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Blue)), rectdetOut); } //컨베어의 릴감지센서 위치를 표시한다 var gridsize = rect.Width / (6 + 1f); var senseW = rect.Width * 0.02f; var senseH = rect.Height * 0.05f; var slist = new double[] { 50, 350, 470, 890, 1110, 1440 }; for (int i = 0; i < slist.Length; i++) { //선으로 영역을 표시해준다. var PosMM = rect.Width * (slist[i] / arMcLengthW); var x = (float)(rect.Left + PosMM); var rx = x - senseW / 2.0f; //센서모양을 그려준다 var rectT = new RectangleF(rx, rect.Top + 3, senseW, senseH); var rectB = new RectangleF(rx, rect.Bottom - senseH - 3, senseW, senseH); if (arDI_Cv_Detect[i] == true) { g.DrawLine(Pens.SkyBlue, x, rect.Top, x, rect.Bottom); arLastDetectIndex = i; } if (i == arLastDetectIndex) //마지막으로 지나간 것은 색상을 변경 해준다. { g.FillRectangle(Brushes.Gold, rectT); g.FillRectangle(Brushes.Gold, rectB); } else { g.FillRectangle(Brushes.White, rectT); g.FillRectangle(Brushes.White, rectB); } // g.DrawString(i.ToString(), this.Font, Brushes.White, x, rect.Top - 20); } Color borderColor = CVHasItem ? Color.Gold : (arConvRun ? Color.Red : Color.Gray); using (var p = new Pen(borderColor, 6)) { g.DrawLine(p, rect.Left, rect.Top, rect.Right, rect.Top); g.DrawLine(p, rect.Left, rect.Bottom, rect.Right, rect.Bottom); //g.DrawLine(new Pen(Color.Red), rect.Left, rect.Top , rect.Right, rect.Top ); //g.DrawLine(new Pen(Color.Red), rect.Left, rect.Bottom, rect.Right, rect.Bottom); } //동작시 모터의 진행방ㅎㅇ을 표시한다 if (arConvRun) UIControl.Common.Draw_Arrow(g, rect, eDirection.RightToLeft, ConveyorRunPoint, AnimationStepConv, Color.FromArgb(50, 50, 50), this.Font); } void Draw_Port(Graphics g, double motposition, double maxLength, RectangleF area, int portindex) { CPort portL = arVar_Port[portindex + 0]; CPort portR = arVar_Port[portindex + 1]; maxLength = arMcLengthW - 200; var PosX = area.Left + (area.Width * (motposition / maxLength)); // g.DrawLine(Pens.DarkViolet, (int)PosX, (int)(area.Top - 10), (int)PosX, (int)(area.Bottom + 10)); var portwidth = CvtMMtoPX_W(350, 0); // area.Width * 0.25; var port_space = CvtMMtoPX_W(60, 0); //각 포트사이가 60mm var port_height = CvtMMtoPX_H(250, 0); var position_front_px = area.Left + ((area.Width * (motposition / maxLength))); var borderSize = 7; var offsetY = CvtMMtoPX_H(10, 0); //포트는 축으로 부터 10mm 이격되어있음 var portY = area.Top + (portindex < 2 ? (offsetY + borderSize - area.Height / 2.0f) : (-offsetY - port_height + area.Height / 2.0f)); //left port var NewX0 = PosX; // 기준부터 좌측 셔틀이 시작한다 (PosX - portwidth - port_space); this.arVar_Port[portindex + 0].Rect = new RectangleF( (float)NewX0, (float)portY, (float)portwidth, (float)port_height); //right port var NewX1 = (float)(PosX + portwidth + port_space); this.arVar_Port[portindex + 1].Rect = new RectangleF( NewX1, (float)portY, (float)portwidth, (float)port_height); var Rect_L = arVar_Port[portindex + 0].Rect; var Rect_R = arVar_Port[portindex + 1].Rect; using (Font fCnt = new Font("consolas", 30, FontStyle.Bold)) { using (Font fMSg = new Font("맑은 고딕", 12, FontStyle.Bold)) { portL.Display(g, fCnt, fMSg, this.arFGInputMode, (portindex == 0 ? this.arFGInputFL : this.arFGInputRL)); portR.Display(g, fCnt, fMSg, this.arFGInputMode, (portindex == 0 ? this.arFGInputFR : this.arFGInputRR)); } } //g.DrawRect(area, Color.DarkViolet, 1); } private void Tm_Tick(object sender, EventArgs e) { if (ConveyorRunPoint < (AnimationStepConv - 3)) ConveyorRunPoint += 1; else ConveyorRunPoint = 1; for (int i = 0; i < 4; i++) { if (this.arVar_Port[i].arrowIndex < (arVar_Port[i].AnimationStepPort - 3)) this.arVar_Port[i].arrowIndex += 1; else this.arVar_Port[i].arrowIndex = 1; } this.Invalidate(); // var ts = DateTime.Now - updatetime; //if (ts.TotalMilliseconds >= tm.Interval) this.Invalidate(); } } }