You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

785 lines
24 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<TraySlot, MouseEventArgs> SlotClickEvent;
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<int,TraySlot> kv in traySlotsDic)
{
if (kv.Value.SlotStatus == status)
return kv.Value;
}
return null;
}
public List<TraySlot> GetSlots(ESlotStatus status)
{
List<TraySlot> slots = new List<TraySlot>();
foreach (KeyValuePair<int, TraySlot> kv in traySlotsDic)
{
if (kv.Value.SlotStatus == status)
slots.Add(kv.Value);
}
return slots;
}
public bool CanDraw { get; set; } = true;
private List<TraySlot> traySlots = new List<TraySlot>();
private Dictionary<int, TraySlot> traySlotsDic = new Dictionary<int, TraySlot>();
private string _HeadText;
public string HeadText
{
get { return _HeadText; }
set { _HeadText = value; this.label1.Text = value; }
}
private int _RowNum = 26;
/// <summary>
/// 行数
/// </summary>
public int RowNum
{
get { return _RowNum; }
set { _RowNum = value; InitSlot(InitSlotStatus); Invalidate(); }
}
private int _ColumnNum = 10;
/// <summary>
/// 列数量
/// </summary>
public int ColumnNum
{
get { return _ColumnNum; }
set { _ColumnNum = value; InitSlot(InitSlotStatus); Invalidate(); }
}
private int _TopSpaceHeight = 20;
/// <summary>
/// 料盘上部留白高度
/// </summary>
public int TopSpaceHeight
{
get { return _TopSpaceHeight; }
set { _TopSpaceHeight = value; }
}
private int _LeftSpaceWidth = 20;
/// <summary>
/// 料盘左边留白宽度
/// </summary>
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;
/// <summary>
/// X方向偏移
/// </summary>
public float OffsetX
{
get { return _OffsetX; }
set { _OffsetX = value; }
}
private float _OffsetY;
/// <summary>
/// Y方向偏移
/// </summary>
public float OffsetY
{
get { return _OffsetY; }
set { _OffsetY = value; }
}
private float _OffsetYEven;
/// <summary>
/// Y方向偏移偶数行
/// </summary>
public float OffsetYEven
{
get { return _OffsetYEven; }
set { _OffsetYEven = value; }
}
private bool _SinglePoint=false;
/// <summary>
/// 单点定位
/// </summary>
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<TraySlot> 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);
}
}
/// <summary>
/// 料盘槽位
/// </summary>
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;
/// <summary>
/// 行数
/// </summary>
public int RowNum
{
get { return _RowNum; }
set { _RowNum = value; }
}
private int _ColumnNum = 10;
/// <summary>
/// 列数量
/// </summary>
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<TraySlot> SlotPoints { get; set; } = new List<TraySlot>();
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;
}
}
}