Files
ATV_STDLabelAttach/Handler/Sub/UIControl/HMI.cs
ChiKyun Kim b037dd53e6 ..
2025-09-23 15:41:16 +09:00

1657 lines
71 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
using AR;
namespace UIControl
{
public partial class HMI : System.Windows.Forms.Control
{
arDev.DIO.IDIO dio = null;
arDev.MOT.IMotion mot = null;
#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));
Font arFont_MotPosName { get; set; }
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_printl = RectangleF.Empty;
RectangleF rect_printr = RectangleF.Empty;
//영역(피커)
RectangleF rect_picker_left = 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[7];
List<CMenuButton> Buttons = new List<CMenuButton>();
List<CMenuButton> menuButtons = new List<CMenuButton>();
#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;//
public bool CVLeftBusy = false;
public bool CVLeftReady = false;
public bool CVRightBusy = false;
public bool CVRightReady = false;
#endregion
#region "Property"
public int arCountV0 { get; set; }
public int arCountV1 { get; set; }
public int arCountV2 { get; set; }
public int arCountPrint0 { get; set; }
public int arCountPrint1 { get; set; }
public Boolean arPortLItemOn { get; set; }
public Boolean arPortRItemOn { get; set; }
public Boolean arPLItemON { get; set; }
public Boolean arPRItemON { get; set; }
public Boolean arMagnet0 { get; set; }
public Boolean arMagnet1 { get; set; }
public Boolean arMagnet2 { get; set; }
public Boolean arPickerSafeZone { get; set; }
private Padding _padding = new Padding(0);
public new Padding Padding { get { return _padding; } set { _padding = value; bRemakeRect = true; this.Invalidate(); } }
/// <summary>
/// 현재 메뉴가 표시되어있는가?
/// </summary>
public Boolean HasPopupMenu { get; private set; }
/// <summary>
/// 현재표시된 메뉴는 사용자의 입력을 반드시 받아야 하는가?
/// </summary>
public Boolean PopupMenuRequireInput { get; private set; }
public Font arFont_PortMessage { 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 arFGVision0RDY { get; set; }
public Boolean arFGVision1RDY { get; set; }
public Boolean arFGVision2RDY { get; set; }
public Boolean arFGVision0END { get; set; }
public Boolean arFGVision1END { get; set; }
public Boolean arFGVision2END { get; set; }
public Boolean arFGPrinter0RDY { get; set; }
public Boolean arFGPrinter1RDY { get; set; }
public Boolean arFGPrinter2RDY { get; set; }
public Boolean arFGPrinter0END { get; set; }
public Boolean arFGPrinter1END { get; set; }
public Boolean arFGPrinter2END { get; set; }
public Boolean arDI_SaftyOk { get; set; }
public string arMotPosNamePX { get; set; }
public string arMotPosNamePZ { get; set; }
public string arMotPosNameLM { get; set; }
public string arMotPosNameLZ { get; set; }
public string arMotPosNameRM { get; set; }
public string arMotPosNameRZ { get; set; }
public Boolean arMotILockPKX { get; set; }
public Boolean arMotILockPKZ { get; set; }
public Boolean arMotILockPLM { get; set; }
public Boolean arMotILockPLZ { get; set; }
public Boolean arMotILockPRM { get; set; }
public Boolean arMotILockPRZ { get; set; }
public Boolean arMotILockPRL { get; set; }
public Boolean arMotILockPRR { get; set; }
public Boolean arMotILockVS0 { get; set; }
public Boolean arMotILockVS1 { get; set; }
public Boolean arMotILockVS2 { get; set; }
public Boolean arMotILockCVL { get; set; }
public Boolean arMotILockCVR { get; set; }
public Boolean PrintLPICK { get; set; }
public Boolean PrintRPICK { get; set; }
public Boolean L_PICK_FW { get; set; }
public Boolean L_PICK_BW { get; set; }
public Boolean R_PICK_FW { get; set; }
public Boolean R_PICK_BW { get; set; }
public Boolean[] arMOT_LimUp = new bool[] { false, false, false, false, false, false, false };
public Boolean[] arMOT_LimDn = new bool[] { false, false, false, false, false, false, false };
public Boolean[] arMOT_Origin = new bool[] { false, false, false, false, false, false, false };
public Boolean[] arMOT_Alm = new bool[] { false, false, false, false, false, false, false };
public Boolean[] arMOT_HSet = new bool[] { false, false, false, false, false, false, false };
public Boolean[] arMOT_SVOn = new bool[] { false, false, false, false, false, false, false };
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_Emergency { get; set; }
public Boolean arDIAir { get; set; }
public Boolean arConn_MOT { get; set; }
public Boolean arConn_DIO { get; set; }
public Boolean arAIRDetect { 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; }
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 arMotorLengthZL { get; set; }
public double arMotorLengthZR { get; set; }
private double[] _armotpos = new double[] { 0, 0, 0, 0, 0, 0, 0 };
public double[] arMotorPosition { get { return _armotpos; } set { _armotpos = value; } }
private double[] _arhomepgoress = new double[] { 0, 0, 0, 0, 0, 0, 0 };
public double[] arHomeProgress { get { return _arhomepgoress; } set { _arhomepgoress = value; } }
private CMenu[] _menus = null;
public CMenu[] arMenus { get { return _menus; } set { _menus = value; this.Invalidate(); } }
#endregion
public Boolean PickerSafezone = false;
public HMI()
{
// 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);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.Resize += Loader_Resize;
sfCenter = new StringFormat();
sfCenter.Alignment = StringAlignment.Center;
sfCenter.LineAlignment = StringAlignment.Center;
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);
arFont_MotPosName = new Font("Consolas", 10, FontStyle.Bold);
arUnloaderSeq = 0;
arMotorLengthY = 400;
arMotorLengthZL = 580;
arMotorLengthZR = 590;
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[3];
arVar_Picker = new CPicker[1];
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;
//미리 10개를 생성한다. 슬롯에 10개이상 생기기 않는다.
zitem = new List<CItem>(10);
for (int i = 0; i < zitem.Count; i++)
zitem[i] = new CItem();
}
public void ClearMessage()
{
}
private List<string> lkitemsF = new List<string>();
private List<string> lkitemsR = new List<string>();
#region "Common Data & Device"
DateTime UpdateTime = DateTime.Now.AddSeconds(-1);
//public void SetFLAG(arUtil.IInterLock dio_)
//{
// this.flag = dio_;
// this.flag.ValueChanged += Flag_ValueChanged;
//}
public void SetDIO(arDev.DIO.IDIO dio_)
{
this.dio = dio_;
this.dio.IOValueChanged += Dio_IOValueChanged;
}
public void SetMOT(arDev.MOT.IMotion dio_)
{
this.mot = dio_;
this.mot.HomeStatusChanged += Mot_HomeStatusChanged;
this.mot.PositionChanged += Mot_PositionChanged;
this.mot.StatusChanged += Mot_StatusChanged;
}
private void Dio_IOValueChanged(object sender, arDev.DIO.IOValueEventArgs e)
{
var ts = DateTime.Now - UpdateTime;
if (ts.TotalMilliseconds < 500) return;
else UpdateTime = DateTime.Now;
this.Invalidate();
}
private void Mot_StatusChanged(object sender, arDev.MOT.StatusChangeEventArags e)
{
var ts = DateTime.Now - UpdateTime;
if (ts.TotalMilliseconds < 500) return;
else UpdateTime = DateTime.Now;
this.Invalidate();
}
private void Mot_PositionChanged(object sender, arDev.MOT.PositionChangeEventArgs e)
{
var ts = DateTime.Now - UpdateTime;
if (ts.TotalMilliseconds < 500) return;
else UpdateTime = DateTime.Now;
this.Invalidate();
}
private void Mot_HomeStatusChanged(object sender, arDev.MOT.HomeStatusChangeEventArgs e)
{
var ts = DateTime.Now - UpdateTime;
if (ts.TotalMilliseconds < 500) return;
else UpdateTime = DateTime.Now;
this.Invalidate();
}
//private void Flag_ValueChanged(object sender, arUtil.InterfaceValueEventArgs e)
//{
// var ts = DateTime.Now - UpdateTime;
// if (ts.TotalMilliseconds < 500) return;
// else UpdateTime = DateTime.Now;
// this.Invalidate();
//}
public Boolean MotionHome { get; set; }
bool GetBOOL(eVarBool idx)
{
return VAR.BOOL?[(int)idx] ?? false;
}
string GetSTR(eVarString idx)
{
return VAR.STR?[(int)idx] ?? string.Empty;
}
bool GetDOValue(eDOName pin)
{
return dio?.GetDOValue((int)pin) ?? false;
}
bool GetDIValue(eDIName pin)
{
return dio?.GetDIValue((int)pin) ?? false;
}
#endregion
public void ClearLockItem(int idx)
{
if (idx == 0)
{
lock (lkitemsF)
lkitemsF.Clear();
}
else
{
lock (lkitemsR)
lkitemsR.Clear();
}
}
public void AddLockItem(int idx, params string[] values)
{
if (idx == 0)
{
lock (lkitemsF)
{
foreach (var value in values)
{
if (lkitemsF.Contains(value) == false)
lkitemsF.Add(value);
}
}
}
else
{
lock (lkitemsR)
{
foreach (var value in values)
{
if (lkitemsR.Contains(value) == false)
lkitemsR.Add(value);
}
}
}
}
public void RemoveLockItem(int idx, params string[] values)
{
if (idx == 0)
{
lock (lkitemsF)
{
foreach (var value in values)
{
if (lkitemsF.Contains(value) == true)
lkitemsF.Remove(value);
}
}
}
else
{
lock (lkitemsR)
{
foreach (var value in values)
{
if (lkitemsR.Contains(value) == true)
lkitemsR.Remove(value);
}
}
}
}
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));
//}
var zitem = this.zitem.Where(t => t.Rect.Contains(e.Location)).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;
}
/// <summary>
/// 각 영역을 현재 크기대비하여 재계산 한다
/// </summary>
void makeRect_Normal()
{
rect_main = new RectangleF(
DisplayRectangle.Left + Padding.Left,
DisplayRectangle.Top + Padding.Top,
DisplayRectangle.Width - Padding.Left - Padding.Right,
DisplayRectangle.Height - Padding.Top - Padding.Bottom);
//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;
//프론트셔틀의 영역(가동 영역) - 아래서 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(100, rect_main.Top)),
// (float)xAxisLengthPX,
// (float)(CvtMMtoPX_H(20, 0)));
//세로축 총길이 1400mm Y축 모터는 양끝에 100mm 의 여유가 있으며, Y축
var pickWidth = rect_main.Width * 0.6f;
var pickerX = rect_main.Width / 2.0f;// CvtMMtoPX_W(750, rect_conveyor.Left);
var YAxisLenWMM = arMcLengthW - 100 * 2;
var YAxisLenHMM = 100;//
var yAxisLenWPx = CvtMMtoPX_W(YAxisLenWMM, 0); //너비
var yAxisLenHPx = CvtMMtoPX_H(YAxisLenHMM, 0); //길이
var yAxisX = CvtMMtoPX_W(100, rect_main.Left);
var yAxisY = CvtMMtoPX_H(200, rect_main.Top);
rect_picker = new RectangleF(
(float)(yAxisX),
(float)(yAxisY),
(float)(yAxisLenWPx),
(float)(yAxisLenHPx)
);
rect_printl = new RectangleF(rect_main.Left + 30, rect_picker.Bottom + 30, 30, rect_main.Height * 0.25f);
rect_printr = new RectangleF(rect_main.Right - rect_printl.Width - rect_printl.Left, rect_printl.Top, rect_printl.Width, rect_printl.Height);
//Y축 피커 관련 세부 영역 설정 (VAC 와 원)
//전체영역의 80% 영역에 Y-로봇의 축을 그린다.
//var motorMax = 400; //전체 가동 길이 400mm
RectangleF rect = rect_picker;
var MotPosPx = rect.Left + rect.Width * (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(200, 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 PickerSpaceW = CvtMMtoPX_H(100, 0);
rect_picker_left = new RectangleF(
(float)(MotPosPx - PickerSpaceW),
(float)(rect.Top + 50),
(float)PickerSizeW,
(float)PickerSizeH);
var pointoffset = 5;
//진공표시영역
rect_picker_front_vac1 = new RectangleF(
(float)rect_picker_left.Left + pointoffset,
(float)rect_picker_left.Top + pointoffset,
(float)rect_picker_left.Width * 0.2f,
(float)rect_picker_left.Height * 0.2f);
rect_picker_front_vac2 = new RectangleF(
(float)rect_picker_left.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_left.Left + pointoffset,
(float)rect_picker_left.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_left.Right - rect_picker_front_vac1.Width - pointoffset,
(float)rect_picker_left.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);
}
//입출력포트의 영역을 다시 계산한다
var portW = (int)(rect_main.Width * 0.175f);
var portH = (int)(rect_main.Height * 0.25f);
var portPad = (int)(rect_main.Width / 7f);
var MarginX = (int)((rect_main.Width - portW * 3 - portPad * 2) / 2.0);
var MarginY = (int)(rect_main.Height - portH - (portPad / 2f));
for (int i = 0; i < arVar_Port.Length; i++)
{
arVar_Port[i].Rect = new Rectangle(
(int)rect_main.Left + MarginX + (i * portW) + (i * portPad),
(int)rect_main.Top + MarginY,
portW, portH);
zitem.Add(new CItem
{
Rect = arVar_Port[i].Rect.toRect(),
index = i,
Tag = $"PORT{i}",
});
}
}
void makeRect_xmove()
{
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);
var width = (int)((cx - rect_main.Left) - padding * 2);
var height = (int)((cy - rect_main.Top) - padding * 2);
arVar_Port[0].Rect = new Rectangle(
(int)rect_main.Left + padding,
(int)cy + padding,
width, height);
arVar_Port[1].Rect = new Rectangle(
(int)cx + padding,
(int)cy + padding,
width, height);
arVar_Port[2].Rect = new Rectangle(
(int)(rect_main.Left + (rect_main.Width - width) / 2f),
(int)rect_main.Top + padding,
width, height);
}
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 startPos)
{
//컨베어 기준으로 값을 반환한ㄷ.
return startPos + rect_main.Width * (PosMM / arMcLengthW);
}
double CvtMMtoPX_H(double PosMM, double startPos)
{
//컨베어 기준으로 값을 반환한ㄷ.
return startPos + 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
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)
{
this.zitem.Clear();
if (Scean == eScean.Nomal) makeRect_Normal();
else if (Scean == eScean.MotHome) makeRect_MotHome();
else if (Scean == eScean.xmove) makeRect_xmove();
bRemakeRect = false;
}
if (this.Scean == eScean.Nomal) Scean_Normal(e.Graphics);
else if (this.Scean == eScean.MotHome) Scean_MotHome(e.Graphics);
else if (this.Scean == eScean.xmove) Scean_XMove(e.Graphics);
}
/// <summary>
/// Z축이 아이템을 내려놓은 시간(연속으로 놓는 증상이 발생하여, 일단 이것으로 2초이상 빠르게 놓는일이 없도록 한다)
/// </summary>
public DateTime LastDropTime = DateTime.Now;
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));
}
/// <summary>
/// 아이템을 DROP해도 되는가? 존 3번 부터 아이템이 존재하면 drop 불가능으로 한다
/// </summary>
void Scean_XMove(Graphics g)
{
//g.DrawRect(arVar_Port[0].Rect, Color.White, 3);
Pen p = new Pen(Color.White, 5);
var pts = new List<PointF>();
pts.Add(new PointF(arVar_Port[0].Rect.Right, arVar_Port[0].Rect.Top));
pts.Add(new PointF(arVar_Port[0].Rect.Left, arVar_Port[0].Rect.Bottom - arVar_Port[0].Rect.Height / 2f));
pts.Add(new PointF(arVar_Port[0].Rect.Right, arVar_Port[0].Rect.Bottom));
g.FillPolygon(Brushes.Blue, pts.ToArray());
g.DrawPolygon(p, pts.ToArray());
g.DrawString("[START]\nLEFT", this.Font, Brushes.Gold, arVar_Port[0].Rect, new StringFormat { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Center });
pts.Clear();
pts.Add(new PointF(arVar_Port[1].Rect.Left, arVar_Port[1].Rect.Top));
pts.Add(new PointF(arVar_Port[1].Rect.Right, arVar_Port[1].Rect.Bottom - arVar_Port[1].Rect.Height / 2f));
pts.Add(new PointF(arVar_Port[1].Rect.Left, arVar_Port[1].Rect.Bottom));
g.FillPolygon(Brushes.Brown, pts.ToArray());
g.DrawPolygon(p, pts.ToArray());
g.DrawString("[STOP]\nRIGHT", this.Font, Brushes.Gold, arVar_Port[1].Rect, new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center });
if (arPickerSafeZone)
g.FillEllipse(Brushes.Lime, arVar_Port[2].Rect);
else
g.FillEllipse(Brushes.Tomato, arVar_Port[2].Rect);
g.DrawEllipse(new Pen(Color.White, 3), arVar_Port[2].Rect);
g.DrawString("PICKER\nSAFTY\n" + (arPickerSafeZone ? "ON" : "OFF"), this.Font, Brushes.Black, arVar_Port[2].Rect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
//중앙에 메세지를 표시한다.
var cpad = rect_main.Width * 0.1f;
var cheigh = rect_main.Height * 0.20f;
var crect = new RectangleF(rect_main.Left + cpad, rect_main.Top + (rect_main.Height - cheigh) / 2f, rect_main.Width - cpad * 2f, cheigh);
g.FillRectangle(new SolidBrush(Color.FromArgb(20, 20, 20)), crect);
if (arPickerSafeZone)
g.DrawString("홈 검색이 가능합니다", new Font("맑은 고딕", 20, FontStyle.Bold), Brushes.Lime, crect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
else
{
if (MessageOn)
g.DrawString("피커를 움직여 안전위치로 이동하세요", new Font("맑은 고딕", 12, FontStyle.Bold), Brushes.Red, crect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
else
g.DrawString("피커를 움직여 안전위치로 이동하세요", new Font("맑은 고딕", 12, FontStyle.Bold), Brushes.White, crect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
}
g.DrawRect(crect, Color.White, 5);
p.Dispose();
var ts = DateTime.Now - ScreenUpdateTime;
if (ts.TotalMilliseconds >= 200)
{
MessageOn = !MessageOn;
ScreenUpdateTime = DateTime.Now;
}
}
DateTime ScreenUpdateTime = DateTime.Now;
Boolean MessageOn = false;
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, 20f, FontStyle.Bold);
var titleSize = g.MeasureString("HOME", f);
var rectTitle = new RectangleF(
rect_main.Left,
rect_main.Top + 10,
rect_main.Width,
titleSize.Height * 1.2f);
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 + 10,
rectTitle.Bottom + 10,
rect_main.Width - 20,
rect_main.Height - rectTitle.Height - 10 - 20);
//g.DrawRectangle(Pens.White, rectBody.Left, rectBody.Top, rectBody.Width, rectBody.Height);
var rectT = new Rectangle(
(int)(rectBody.Left + 20),
(int)(rectBody.Top + 30),
(int)(rectBody.Width * 0.3f),
(int)(rectBody.Height * 0.07));
var rectXF = new Rectangle(
(int)(rectT.Right + 20),
(int)(rectBody.Top + 30),
(int)(rectBody.Width - rectT.Width - rectT.Left - 10),
(int)(rectBody.Height * 0.07));
//g.DrawRect(rectT, Color.White, 1);
//g.DrawRect(rectXF, Color.Red, 1);
var titles = new string[] { "[0] PICKER-Y", "[1] PICKER-Z", "[2] PRINTL-Y", "[3] PRINTL-Z", "[4] PRINTR-Y", "[5] PRINTR-Z", "[6] ANGLE" };
for (int i = 0; i < titles.Length; i++)
{
var perc = arHomeProgress[i];
var title = titles[i];
var offsetY = (rectBody.Height * 0.12f);
//0번은 처리하지 않음
if (i > 0)
{
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, 10f, 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)
{
//Draw_Icon(g);
//전체 영역 테두리
g.DrawRectangle(new Pen(Color.White, 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, true, this.arMOT_Origin[(int)eAxis.X_F], arMOT_LimDn[(int)eAxis.X_F], arMOT_LimUp[(int)eAxis.X_F]);
//포트표시(셔틀위에 표시됨)
Draw_Port(g); //front
Draw_Vision(g);
//프린터영역그리기 201228
var printareahei = 50;
var printareaw = 100;
var printbordersize = 5;
var rectpl = new RectangleF(arVar_Port[0].Rect.Right + printbordersize, arVar_Port[0].Rect.Top - 85, printareaw, printareahei);
var fColorPrn = arFGPrinter0END ? Color.Lime : (arFGPrinter0RDY ? Color.Gold : Color.Gray);
g.DrawRect(rectpl, fColorPrn, printbordersize);
var prnstrbase = "";// "인쇄수량:" + arCountPrint0.ToString("000") + "\n";
var prnstr = prnstrbase + (arFGPrinter0END ? "인쇄완료" : (arFGPrinter0RDY ? "인쇄중" : "인쇄대기"));
prnstr += "\n" + arCountPrint0.ToString("0000");
g.DrawString(prnstr, new Font("맑은 고딕", 10, FontStyle.Bold), new SolidBrush(fColorPrn), rectpl,
new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
//g.DrawString(string.Format("AIR:{0}\nVI:{1}\nVO:{2}", PrintLAIRO, PrintLVACI, PrintLVACO), new Font("Consolas", 11, FontStyle.Bold),
// Brushes.Tomato, rectpl.Left, rectpl.Top);
rectpl = new RectangleF(arVar_Port[2].Rect.Left - 90 - printbordersize, arVar_Port[2].Rect.Top - 85, printareaw, printareahei);
fColorPrn = arFGPrinter1END ? Color.Lime : (arFGPrinter1RDY ? Color.Gold : Color.Gray);
g.DrawRect(rectpl, fColorPrn, printbordersize);
prnstrbase = "";// "인쇄수량:" + arCountPrint1.ToString("000") + "\n";
prnstr = prnstrbase + (arFGPrinter1END ? "인쇄완료" : (arFGPrinter1RDY ? "인쇄중" : "인쇄대기"));
prnstr += "\n" + arCountPrint1.ToString("0000");
g.DrawString(prnstr, new Font("맑은 고딕", 10, FontStyle.Bold), new SolidBrush(fColorPrn), rectpl,
new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
//g.DrawString(string.Format("AIR:{0}\nVI:{1}\nVO:{2}", PrintRAIRO, PrintRVACI, PrintRVACO), new Font("Consolas", 11, FontStyle.Bold),
// Brushes.Tomato, rectpl.Left, rectpl.Top);
//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/Z축
Draw_PickerY(g, rect_picker);
//왼쪽 프린터
Draw_PickerPrinter(g, rect_printl, 2, 3, false, arMotILockPLM, arMotILockPLZ, arPLItemON, PrintLPICK, L_PICK_FW, L_PICK_BW);
//오른쪽 프린터
Draw_PickerPrinter(g, rect_printr, 4, 5, true, arMotILockPRM, arMotILockPRZ, arPRItemON, PrintRPICK, R_PICK_FW, R_PICK_BW);
//정보 표시 (나중에 제거해야함) 별도 인포박스형태를 취해야 함
Draw_Info(g, rect_conveyor);
Draw_Error(g);
//메뉴는 최상위에 표시한다
Draw_Menu(g);
//arDebugMode = true;
if (arDebugMode)
{
var sb = new System.Text.StringBuilder();
sb.AppendLine("Debug Message");
sb.AppendLine(string.Format("Display {0}", rect_main));
sb.AppendLine(string.Format("Mot Name : {0}/{1}/{2}/{3}/{4}/{5}", arMotPosNamePX, arMotPosNamePZ, arMotPosNameLM, arMotPosNameLZ, arMotPosNameRM, arMotPosNameRZ));
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));
sb.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,
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));
}
var pad = 10;
using (Font f = new Font("맑은 고딕", 9))
{
var smgsize = g.MeasureString(sb.ToString(), f);
var dbgrect = new RectangleF(rect_main.Left + pad, rect_main.Top + pad, smgsize.Width + pad * 2f, smgsize.Height + pad * 2f);
//g.FillRectangle(new SolidBrush(Color.FromArgb(252, 0, 0, 0)), dbgrect);
//g.DrawString(sb.ToString(), f, Brushes.SkyBlue, dbgrect, new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center });
}
}
}
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 (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, "언로더 작업 대기 중", "NO SETTING(#4)", Properties.Resources.info, false);
// else if (arUnloaderSeq == 5) ShowPopupMessage(g, "언로더 작업 대기 중", "SIZE SETTING(#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);
//}
RectangleF rect_zlaxis = RectangleF.Empty;// new RectangleF((float)motZLPosX, (float)motZPosY, motZwPx, (float)motZhPx);
//RectangleF rect_zraxis = RectangleF.Empty;//new RectangleF((float)motZRPosX, (float)motZPosY, motZwPx, (float)motZhPx);
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_SVOn[0] == false) ShowPopupMessage(g, "SERVO ALARM", "Y-PICKER\nSERVO-OFF", Properties.Resources.alert, true);
else if (arConn_MOT && this.arMOT_SVOn[1] == false) ShowPopupMessage(g, "SERVO ALARM", "Z-PICKER\nSERVO-OFF", Properties.Resources.alert, true);
else if (arConn_MOT && this.arMOT_SVOn[2] == false) ShowPopupMessage(g, "SERVO ALARM", "L-PRINT-Y\nSERVO-OFF", Properties.Resources.alert, true);
else if (arConn_MOT && this.arMOT_SVOn[3] == false) ShowPopupMessage(g, "SERVO ALARM", "L-PRINT-Z\nSERVO-OFF", Properties.Resources.alert, true);
else if (arConn_MOT && this.arMOT_SVOn[4] == false) ShowPopupMessage(g, "SERVO ALARM", "R-PRINT-Y\nSERVO-OFF", Properties.Resources.alert, true);
else if (arConn_DIO && this.arAIRDetect == false) ShowPopupMessage(g, "AIR DETECT", "*전면의 AIR버튼(청색)을 눌러 AIR를 공급하세요\n* AIR 라인을 확인하세요", Properties.Resources.error, true);
else if (arConn_MOT && (this.arMOT_HSet[0] == false || this.arMOT_HSet[1] == false || this.arMOT_HSet[2] == false))
{
//안전오류도 표시해줘야한다
var SaftyMessage = string.Empty;
if (arVar_Port[0].SaftyErr == true) SaftyMessage += "DOOR:LEFT";
if (arVar_Port[1].SaftyErr == true) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "," : string.Empty) + "DOOR:CENTER";
if (arVar_Port[2].SaftyErr == true) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "," : string.Empty) + "DOOR:RIGHT";
if (arPickerSafeZone == false) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "\n" : string.Empty) + "피커안전위치 : OFF";
else SaftyMessage += "피커안전위치 : ON"; ;
ShowPopupMessage(g, "SYSTEM NOT READY", "초기화가 필요 합니다\n" + SaftyMessage, 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 (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 (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);
}
public Font MessageBody { get; set; } = new Font("맑은 고딕", 20, FontStyle.Bold);
public Font MessageTitle { get; set; } = new Font("맑은 고딕", 10, FontStyle.Bold);
void ShowPopupMessage(Graphics g, string title, string msg, Image icon, Boolean isError)
{
//팝업표시할때마다 배경 마스킹을 한다
//var maskColor = Color.FromArgb(100, Color.White);
//ShowMaskLayer(g, maskColor);
//var msgf = new Font("맑은 고딕", 20, FontStyle.Bold);
//var msgt = new Font("맑은 고딕", 10, FontStyle.Bold);
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, MessageTitle, Color.Black, rectT, ContentAlignment.MiddleCenter);
g.DrawString(msg, MessageBody, 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.8f);// 640;// (int)(rect_main.Width * 0.7f);
var msgH = (int)(this.rect_main.Height * 0.8f);//
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, MessageBody, 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;
}
//msgf.Dispose();
//msgt.Dispose();
}
void Draw_Port(Graphics g)
{
var fSizeCnt = 20;
var convmode = VAR.BOOL?[eVarBool.Use_Conveyor] ?? false;
using (Font fCnt = new Font("consolas", fSizeCnt, FontStyle.Bold))
{
using (Font fMSg = new Font("맑은 고딕", 15, FontStyle.Bold))
{
if (convmode)
this.arVar_Port[0].DisplayConv(g, fCnt, fMSg, arMagnet0, arFGVision0RDY, arFGVision0END, arPortLItemOn, arMotILockVS0, arCountV0, CVLeftBusy, CVLeftReady);
else
this.arVar_Port[0].Display(g, fCnt, fMSg, arMagnet0, arFGVision0RDY, arFGVision0END, arPortLItemOn, arMotILockVS0, arCountV0);
this.arVar_Port[1].Display(g, fCnt, fMSg, arMagnet1, arFGVision1RDY, arFGVision1END, false, arMotILockVS1, arCountV1);
if (convmode)
this.arVar_Port[2].DisplayConv(g, fCnt, fMSg, arMagnet2, arFGVision2RDY, arFGVision2END, arPortRItemOn, arMotILockVS2, arCountV2, CVRightBusy, CVRightReady);
else
this.arVar_Port[2].Display(g, fCnt, fMSg, arMagnet2, arFGVision2RDY, arFGVision2END, arPortRItemOn, arMotILockVS2, arCountV2);
}
}
}
void Draw_Vision(Graphics g)
{
//var NewX0 = arVar_Port[0].Rect.Right;
//var NewXDist = arVar_Port[1].Rect.Left - arVar_Port[0].Rect.Right;
//var NewYDist = arVar_Port[0].Rect.Height;
//var NewY = arVar_Port[0].Rect.Top;
//var portw_Px = arVar_Port[0].Rect.Width;
////둘사이의 공간으로 처리한다
//var VisionRectSizePx = (int)Math.Min(NewXDist - 10, NewYDist - 10);
//rect_vision = new RectangleF(
// (float)(NewX0 + (NewXDist - VisionRectSizePx) / 2.0f),
// (float)(NewY + (NewYDist - VisionRectSizePx) / 2.0f),
// (float)VisionRectSizePx,
// (float)VisionRectSizePx);
//g.DrawEllipse(Pens.Gray, rect_vision);
////가운에 영역(10% 작은)에. 감지된 릴 모양을 그려준다
//var padval = rect_vision.Width * 0.05f;
//var rellrect = new RectangleF(
// rect_vision.Left + padval,
// rect_vision.Top + padval,
// rect_vision.Width - padval * 2,
// rect_vision.Height - padval * 2);
//if (arVisionProcessC)
//{
// using (LinearGradientBrush br = new LinearGradientBrush(rellrect, Color.Lime, Color.Green, LinearGradientMode.BackwardDiagonal))
// g.FillEllipse(br, rellrect);
// g.DrawEllipse(Pens.Lime, rellrect);
//}
//else
//{
// using (LinearGradientBrush br = new LinearGradientBrush(rellrect, Color.Yellow, Color.Gold, LinearGradientMode.BackwardDiagonal))
// g.FillEllipse(br, rellrect);
// g.DrawEllipse(Pens.Lime, rellrect);
//}
////감지상태를 글자료 표시해준다.
////비젼데이터가 있다면 그것을 사용해준다
//var msg = string.IsNullOrEmpty(arVision_RID) ? "REEL ON" : arVision_RID;
//using (var sb = new SolidBrush(Color.FromArgb(120, Color.Black)))
// g.DrawString(msg, this.Font, sb, rellrect,
// new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
}
RectangleF rect_vision = RectangleF.Empty;
public string arVision_RID { get; set; }
public string arVision_SID { get; set; }
public Boolean arVisionProcessL { get; set; }
public Boolean arVisionProcessC { get; set; }
public Boolean arVisionProcessR { get; set; }
private void Tm_Tick(object sender, EventArgs e)
{
if (ConveyorRunPoint < (AnimationStepConv - 3)) ConveyorRunPoint += 1;
else ConveyorRunPoint = 1;
for (int i = 0; i < 3; 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();
}
}
}