- Added QRValidation vision control system - Includes CapCleaningControl UI components - WebSocket-based barcode validation system - Support for Crevis PLC integration - Test projects for PLC emulator, motion, IO panel, and Modbus 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2324 lines
101 KiB
C#
2324 lines
101 KiB
C#
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<CMenuButton> Buttons = new List<CMenuButton>();
|
|
List<CMenuButton> menuButtons = new List<CMenuButton>();
|
|
|
|
/// <summary>
|
|
/// 외부에서 입력된 릴의 갯수
|
|
/// </summary>
|
|
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"
|
|
|
|
/// <summary>
|
|
/// 현재 메뉴가 표시되어있는가?
|
|
/// </summary>
|
|
public Boolean HasPopupMenu { get; private set; }
|
|
/// <summary>
|
|
/// 현재표시된 메뉴는 사용자의 입력을 반드시 받아야 하는가?
|
|
/// </summary>
|
|
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<CItem> zitem = new List<CItem>();
|
|
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<CItem>(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<MenuItemClickEventargs> ButtonClick;
|
|
public event EventHandler<IconClickEventargs> IConClick;
|
|
public event EventHandler<ZoneItemClickEventargs> 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<CMenu> newlist = new List<CMenu>();
|
|
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<CMenu> newlist = new List<CMenu>();
|
|
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
|
|
|
|
/// <summary>
|
|
/// 각 영역을 현재 크기대비하여 재계산 한다
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 지정된 시간을 초과한 자료를 삭제한다
|
|
/// </summary>
|
|
/// <param name="timeSec"></param>
|
|
public List<string> ZoneItem_GetOldItemList(int timeSec)
|
|
{
|
|
|
|
var retval = new List<string>();
|
|
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;
|
|
}
|
|
|
|
}
|
|
/// <summary>
|
|
/// 해당 존에 아이템이 들어왔다
|
|
/// </summary>
|
|
/// <param name="InputZoneIdx"></param>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Z축이 아이템을 내려놓은 시간(연속으로 놓는 증상이 발생하여, 일단 이것으로 2초이상 빠르게 놓는일이 없도록 한다)
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// 컨베이어에 아이템이 있는가?
|
|
/// </summary>
|
|
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;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 바코드 존의 데이터를 변경해준다.
|
|
/// </summary>
|
|
/// <param name="_reelid"></param>
|
|
/// <param name="_sid"></param>
|
|
/// <param name="_rawdata"></param>
|
|
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;
|
|
// });
|
|
//}
|
|
|
|
/// <summary>
|
|
/// 아이템을 DROP해도 되는가? 존 3번 부터 아이템이 존재하면 drop 불가능으로 한다
|
|
/// </summary>
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 컨베이어의 아이템을 화면에 표시한ㄷ
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
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<CMenuButton>();
|
|
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();
|
|
}
|
|
|
|
}
|
|
}
|