using HalconDotNet; using Rs.Framework; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Serialization; namespace Rs.Controls { public enum ESortDir { Horizontal, Vertical } public enum ESlotStatus { Have, NotHave, Ok, Ng, Disable } public partial class RsTray : UserControl { public string RecipeName { get; set; } = "default"; private int CurrentSlot { get; set; } = 1; private TrayInfo trayInfo; public string ItemName { get; set; } public ESortDir SortDir { get; set; } = ESortDir.Horizontal; public event Action SlotClickEvent; private bool mShowStatus = true; public bool ShowStatus { get { return mShowStatus; } set { mShowStatus = value; lblStatus.Visible = mShowStatus; } } private string mStatus; public string Status { get { return mStatus; } set { mStatus = value; lblStatus.Text = mStatus; Invalidate(); } } public RsTray() { InitializeComponent(); DoubleBuffered = true; InitSlot(InitSlotStatus); this.SizeChanged += (s, e) => { UpdateSlotPos(); }; } public void NextSlot() { CurrentSlot++; } public void ResetTray() { CurrentSlot = 1; } public bool IsLastSlot() { if(CurrentSlot == RowNum*ColumnNum) { return true; } return false; } private ESlotStatus _InitSlotStatus = ESlotStatus.Have; public ESlotStatus InitSlotStatus { get { return _InitSlotStatus; } set { _InitSlotStatus = value; InitSlot(InitSlotStatus); Invalidate(); } } public TraySlot GetSlot(ESlotStatus status) { foreach(KeyValuePair kv in traySlotsDic) { if (kv.Value.SlotStatus == status) return kv.Value; } return null; } public List GetSlots(ESlotStatus status) { List slots = new List(); foreach (KeyValuePair kv in traySlotsDic) { if (kv.Value.SlotStatus == status) slots.Add(kv.Value); } return slots; } public bool CanDraw { get; set; } = true; private List traySlots = new List(); private Dictionary traySlotsDic = new Dictionary(); private string _HeadText; public string HeadText { get { return _HeadText; } set { _HeadText = value; this.label1.Text = value; } } private int _RowNum = 26; /// /// 行数 /// public int RowNum { get { return _RowNum; } set { _RowNum = value; InitSlot(InitSlotStatus); Invalidate(); } } private int _ColumnNum = 10; /// /// 列数量 /// public int ColumnNum { get { return _ColumnNum; } set { _ColumnNum = value; InitSlot(InitSlotStatus); Invalidate(); } } private int _TopSpaceHeight = 20; /// /// 料盘上部留白高度 /// public int TopSpaceHeight { get { return _TopSpaceHeight; } set { _TopSpaceHeight = value; } } private int _LeftSpaceWidth = 20; /// /// 料盘左边留白宽度 /// public int LeftSpaceWidth { get { return _LeftSpaceWidth; } set { _LeftSpaceWidth = value; } } private int _RowSpace = 3; public int RowSpace { get { return _RowSpace; } set { _RowSpace = value; } } private int _ColSpace = 5; public int ColSpace { get { return _ColSpace; } set { _ColSpace = value; } } private bool _ShowText; public bool ShowText { get { return _ShowText; } set { _ShowText = value; } } private float _OffsetX; /// /// X方向偏移 /// public float OffsetX { get { return _OffsetX; } set { _OffsetX = value; } } private float _OffsetY; /// /// Y方向偏移 /// public float OffsetY { get { return _OffsetY; } set { _OffsetY = value; } } private float _OffsetYEven; /// /// Y方向偏移(偶数行) /// public float OffsetYEven { get { return _OffsetYEven; } set { _OffsetYEven = value; } } private bool _SinglePoint=false; /// /// 单点定位 /// public bool SinglePoint { get { return _SinglePoint; } set { _SinglePoint = value; } } private Bitmap drawImage; private void InitSlot(ESlotStatus status) { int index = 0; traySlots.Clear(); traySlotsDic.Clear(); if (SortDir == ESortDir.Vertical) { for (int c = 0; c < ColumnNum; c++) { for (int r = 0; r < RowNum; r++) { index++; TraySlot slot = new TraySlot(); slot.Index = index; slot.Row = r; slot.Column = c; slot.SlotStatus = status; //slot.Bound = new RectangleF((LeftSpaceWidth + widthPer * c), (TopSpaceHeight + heightPer * r), (int)widthPer - 5, (int)heightPer - 5); //slot.Draw(g2); traySlots.Add(slot); traySlotsDic.Add(index, slot); } } } else { for (int r = 0; r < RowNum; r++) { for (int c = 0; c < ColumnNum; c++) { index++; TraySlot slot = new TraySlot(); slot.Index = index; slot.Row = r; slot.Column = c; slot.SlotStatus = status; //slot.Bound = new RectangleF((LeftSpaceWidth + widthPer * c), (TopSpaceHeight + heightPer * r), (int)widthPer - 5, (int)heightPer - 5); //slot.Draw(g2); traySlots.Add(slot); traySlotsDic.Add(index, slot); } } } UpdateSlotPos(); } public void Init() { trayInfo = new TrayInfo(SortDir, RowNum, ColumnNum, ItemName); trayInfo = trayInfo.Init(RecipeName); } public bool Save() { return trayInfo.Save(this); } public void SetLeftTop(PointF point) { trayInfo.LeftTop = point; } public void SetLeftBottom(PointF point) { trayInfo.LeftBottom = point; } public void SetRightBottom(PointF point) { trayInfo.RightBottom = point; } public PointF GetLeftTop() { return trayInfo.LeftTop; } public PointF GetLeftBottom() { return trayInfo.LeftBottom; } public PointF GetRightBottom() { return trayInfo.RightBottom; } public List GetAllSlot() { return trayInfo.SlotPoints; } public TraySlot GetSlot(int index) { return trayInfo.GetSlot(index); } public TraySlot GetCurrentSlot() { return trayInfo.GetSlot(CurrentSlot); } public void Fill() { foreach (TraySlot item in traySlots) { ChangeStatus(item.Index, ESlotStatus.Have); } } public void Clear() { foreach (TraySlot item in traySlots) { ChangeStatus(item.Index, ESlotStatus.NotHave); } } public void ChangeStatus(int index, ESlotStatus status) { if (traySlotsDic.ContainsKey(index)) { traySlotsDic[index].SlotStatus = status; traySlotsDic[index].Refresh(this.panel2.CreateGraphics(), ShowText); } //panel2_Paint(null, null); } private void UpdateSlotPos() { float slotWidth = (this.panel2.Width - LeftSpaceWidth) / ColumnNum; float slotHeight = (this.panel2.Height - TopSpaceHeight) / RowNum; int index = 0; if (SortDir == ESortDir.Vertical) { for (int c = 0; c < ColumnNum; c++) { for (int r = 0; r < RowNum; r++) { index++; if (traySlotsDic.ContainsKey(index)) { traySlotsDic[index].Bound = new RectangleF((LeftSpaceWidth + slotWidth * c), (TopSpaceHeight + slotHeight * r), (int)slotWidth - ColSpace, (int)slotHeight - RowSpace); } } } } else { for (int r = 0; r < RowNum; r++) { for (int c = 0; c < ColumnNum; c++) { index++; if (traySlotsDic.ContainsKey(index)) { traySlotsDic[index].Bound = new RectangleF((LeftSpaceWidth + slotWidth * c), (TopSpaceHeight + slotHeight * r), (int)slotWidth - ColSpace, (int)slotHeight - RowSpace); } } } } panel2.Refresh(); } private void panel2_Paint(object sender, PaintEventArgs e) { this.DoubleBuffered = true; Graphics g = this.panel2.CreateGraphics(); drawImage = new Bitmap(this.panel2.Width, this.panel2.Height); Graphics g2 = Graphics.FromImage(drawImage); g2.Clear(BackColor); //先计算出每一个料仓中穴位占用的宽度和高度 float widthPer = (this.panel2.Width - LeftSpaceWidth) / ColumnNum; float heightPer = (this.panel2.Height - TopSpaceHeight) / RowNum; //先画列,再画行 int index = 0; for (int c = 0; c < ColumnNum; c++) { for (int r = 0; r < RowNum; r++) { index++; if (r == 0) { //画料盘的列号 g2.DrawString((c + 1).ToString(), new Font("宋体", 7.0F), new SolidBrush(Color.White), new PointF(LeftSpaceWidth + (widthPer * c) + 5, 5)); } if (c == 0) { //画料盘的行号 g2.DrawString((r + 1).ToString(), new Font("宋体", 7.0F), new SolidBrush(Color.White), new PointF(5, TopSpaceHeight + (heightPer * r))); } //Rectangle rect = new Rectangle((int)(LeftSpaceWidth + widthPer * c), (int)(TopSpaceHeight + heightPer * r), (int)widthPer - 5, (int)heightPer - 5); //g2.DrawRectangle(Pens.Red, (LeftSpaceWidth + widthPer * c), (TopSpaceHeight + heightPer * r), (int)widthPer - 5, (int)heightPer - 5); //TraySlot slot = new TraySlot(); //slot.Row = r; //slot.Column = c; //slot.Bound = new RectangleF((LeftSpaceWidth + widthPer * c), (TopSpaceHeight + heightPer * r), (int)widthPer - 5, (int)heightPer - 5); //slot.Draw(g2); if (traySlotsDic.ContainsKey(index)) { traySlotsDic[index].Draw(g2, ShowText); } } } g2.Flush(); g.DrawImage(drawImage, 0, 0, drawImage.Width, drawImage.Height); if (drawRegion) { //drawRect.Width = 20; //drawRect.Height = 20; //g.DrawRectangle(Pens.Green, drawRect); g.FillRectangle(new SolidBrush(Color.FromArgb(200, Color.Pink)), drawRect); } g.Flush(); g.Dispose(); g2.Dispose(); } bool drawRegion = false; RectangleF drawRect = new RectangleF(); private void panel2_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left && drawRegion == false) { if (CanDraw) { drawRegion = true; drawRect.X = e.X; drawRect.Y = e.Y; } } } private void panel2_MouseMove(object sender, MouseEventArgs e) { if (drawRegion) { drawRect.Width = e.X - drawRect.X; drawRect.Height = e.Y - drawRect.Y; panel2_Paint(null, null); } } private void panel2_MouseUp(object sender, MouseEventArgs e) { drawRegion = false; } public TraySlot SelectSlot { get; set; } private void panel2_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { if (!drawRect.IsEmpty && drawRect.Contains(e.Location)) { contextMenuStrip1.Show(panel2, e.Location); } else { SelectSlot = null; bool find = false; foreach (TraySlot slot in this.traySlots) { if (slot.Bound.Contains(e.Location)) { find = true; SelectSlot = slot; break; } } if (find) { if (SlotClickEvent != null) SlotClickEvent(SelectSlot, e); } } } } private void 禁用ToolStripMenuItem_Click(object sender, EventArgs e) { ChangeSlotStatus(ESlotStatus.Disable); } private void ChangeSlotStatus(ESlotStatus status) { foreach (TraySlot slot in this.traySlots) { if (drawRect.IntersectsWith(slot.Bound)) { slot.SlotStatus = status; } } UpdateSlotPos(); } private void 设置有料ToolStripMenuItem_Click(object sender, EventArgs e) { ChangeSlotStatus(ESlotStatus.Have); } private void 设置无料ToolStripMenuItem_Click(object sender, EventArgs e) { ChangeSlotStatus(ESlotStatus.NotHave); } } /// /// 料盘槽位 /// public class TraySlot { public ESlotStatus SlotStatus { get; set; } = ESlotStatus.Have; private PointF _Position; public PointF Position { get { return _Position; } set { _Position = value; } } private int _Index; public int Index { get { return _Index; } set { _Index = value; } } private int _Row; public int Row { get { return _Row; } set { _Row = value; } } private int _Column; public int Column { get { return _Column; } set { _Column = value; } } private RectangleF _Bound; [XmlIgnore] public RectangleF Bound { get { return _Bound; } set { _Bound = value; } } public void Refresh(Graphics g, bool isShowText) { Draw(g, isShowText); } public void Draw(Graphics g, bool isShowText) { if (_Bound != null) { StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Center; sf.LineAlignment = StringAlignment.Center; switch (SlotStatus) { case ESlotStatus.Have: g.FillRectangle(new SolidBrush(Color.Blue), Bound.X, Bound.Y, Bound.Width - 1, Bound.Height - 1); break; case ESlotStatus.NotHave: g.FillRectangle(new SolidBrush(Color.FromArgb(11, 16, 36)), Bound.X, Bound.Y, Bound.Width - 1, Bound.Height - 1); break; case ESlotStatus.Ok: g.FillRectangle(new SolidBrush(Color.Green), Bound.X, Bound.Y, Bound.Width - 1, Bound.Height - 1); break; case ESlotStatus.Ng: g.FillRectangle(new SolidBrush(Color.Red), Bound.X, Bound.Y, Bound.Width - 1, Bound.Height - 1); break; case ESlotStatus.Disable: g.FillRectangle(new SolidBrush(Color.Gray), Bound.X, Bound.Y, Bound.Width - 1, Bound.Height - 1); break; default: break; } //if(Status==1) //{ // g.FillRectangle(new SolidBrush(Color.Red), Bound.X, Bound.Y, Bound.Width - 1, Bound.Height - 1); //} //else if(Status==0) //{ // g.FillRectangle(new SolidBrush(Color.FromArgb(11, 16, 36)), Bound.X, Bound.Y, Bound.Width-1, Bound.Height-1); // // g.FillRectangle(new SolidBrush(Color.Red), Bound.X, Bound.Y, Bound.Width , Bound.Height ); //} g.DrawRectangle(Pens.White, Bound.X, Bound.Y, Bound.Width, Bound.Height); if (isShowText) { g.DrawString((Row + 1) + "-" + (Column + 1), new Font("宋体", 8), new SolidBrush(Color.Yellow), _Bound, sf); } } } } public class TrayInfo { public TrayInfo() { } public TrayInfo(ESortDir sortDir,int rowNum,int colNum,string itemName) { RowNum=rowNum; ColumnNum=colNum; ItemName=itemName; SortDir=sortDir; } public ESortDir SortDir { get; set; } = ESortDir.Horizontal; public string ItemName { get; set; } private int _RowNum = 26; /// /// 行数 /// public int RowNum { get { return _RowNum; } set { _RowNum = value; } } private int _ColumnNum = 10; /// /// 列数量 /// public int ColumnNum { get { return _ColumnNum; } set { _ColumnNum = value; } } public PointF LeftTop { get; set; } = new PointF(0, 0); public PointF LeftBottom { get; set; } = new PointF(0, 0); public PointF RightBottom { get; set; } = new PointF(0, 0); public List SlotPoints { get; set; } = new List(); public bool Save(RsTray rsTray) { try { float offsetX = -12.8f; float offsetY = 11.8f; int index = 0; int rowNum = 0; SlotPoints.Clear(); HTuple rows = new HTuple(); HTuple columns = new HTuple(); if (SortDir == ESortDir.Horizontal) { for (int i = 0; i < RowNum; i++) { for (int j = 0; j < ColumnNum; j++) { index++; TraySlot ts = new TraySlot(); ts.Index = index; ts.Row = i + 1; ts.Column = j + 1; ts.Position = new PointF(LeftTop.X + (j * rsTray.OffsetX), LeftTop.Y + (i * rsTray.OffsetY)); //1 2 3 4 //ts.Position = new PointF(LeftTop.X + (j * rsTray.OffsetX), LeftTop.Y + ((i-(i/2)) * rsTray.OffsetY) +(i/2)*rsTray.OffsetYEven); rows.Append(ts.Position.Y); columns.Append(ts.Position.X); SlotPoints.Add(ts); } } if(!rsTray.SinglePoint) { //求斜率 HOperatorSet.AngleLx(LeftTop.Y, LeftTop.X, LeftBottom.Y, LeftBottom.X, out HTuple angle); double deg = AngleTool.Rad2Deg(angle) + 90; HOperatorSet.HomMat2dIdentity(out HTuple homMat2dIdentity); HOperatorSet.HomMat2dRotate(homMat2dIdentity, AngleTool.Deg2Rad(deg), LeftTop.Y, LeftTop.X, out HTuple homMat2dRotate); HOperatorSet.AffineTransPoint2d(homMat2dRotate, rows, columns, out HTuple qx, out HTuple qy); for (int i = 0; i < qx.Length; i++) { GetSlot(i + 1).Position = new PointF((float)qy.DArr[i], (float)qx.DArr[i]); } } } else { for (int i = 0; i < ColumnNum; i++) { for (int j = 0; j < RowNum; j++) { index++; TraySlot ts = new TraySlot(); ts.Index = index; ts.Row = i + 1; ts.Column = j + 1; ts.Position = new PointF(LeftTop.X + (i * offsetX), LeftTop.Y + (j * offsetY)); SlotPoints.Add(ts); } } } string dirPath = Path.Combine("recipe",rsTray.RecipeName, ItemName); if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } XmlSerializerHelper.Instance.Serialize($"{dirPath}/tray.xml", this); } catch (Exception) { return false; } return true; } public TrayInfo Init(string recipeName) { string dirPath = Path.Combine("recipe",recipeName, ItemName); if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } XmlSerializerHelper.Instance.Deserialize($"{dirPath}/tray.xml", out TrayInfo tray); if (tray == null) return new TrayInfo(SortDir,RowNum,ColumnNum,ItemName); tray.RowNum = RowNum; tray.ColumnNum = ColumnNum; return tray; } public TraySlot GetSlot(int index) { if (SlotPoints != null && SlotPoints.Count > 0) { TraySlot ts = SlotPoints.Where(s => s.Index == index).First(); if (ts != null) return ts; } return null; } } }