2024-06-17 11:02:28 +08:00
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing.Drawing2D;
|
|
|
|
|
using System.Drawing.Text;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using XKRS.UI.Helper;
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
|
using System.Xml.Serialization;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using Sunny.UI;
|
|
|
|
|
using Sunny.UI.Win32;
|
|
|
|
|
using OpenCvSharp;
|
|
|
|
|
using OpenCvSharp.Extensions;
|
|
|
|
|
using Point = System.Drawing.Point;
|
|
|
|
|
|
|
|
|
|
namespace XKRS.UI
|
|
|
|
|
{
|
|
|
|
|
public partial class Canvas : UserControl, INotifyPropertyChanged
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#region 变量通知
|
|
|
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
|
private void NotifyPropertyChanged(string name)
|
|
|
|
|
{
|
|
|
|
|
if (PropertyChanged != null)
|
|
|
|
|
{
|
|
|
|
|
PropertyChanged(this, new PropertyChangedEventArgs(name));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[DisplayName("方向键移动间距")]
|
|
|
|
|
[Description("按下方向键时,选中的缺陷可以向对应的方向平移,该值设置按下一次方向键缺陷图片的移动距离,单位:像素")]
|
|
|
|
|
public float MoveStep { get; set; } = 5f;
|
|
|
|
|
|
|
|
|
|
[DisplayName("允许选中缺陷")]
|
|
|
|
|
[Description("鼠标单击时,是否允许选中图上绘制的缺陷,允许选中时才可以对缺陷进行操作")]
|
|
|
|
|
public bool AllowSelectDefect { get; set; } = true;
|
|
|
|
|
|
|
|
|
|
private Keys _keyLastPressed = Keys.None;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 顺序查找已选中的缺陷
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Defect? _selectedDefect;
|
|
|
|
|
|
|
|
|
|
public Defect SelectedDefect
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
_selectedDefect = DefectList.FirstOrDefault(d => d.Selected);
|
|
|
|
|
return _selectedDefect;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 整体缩放比例
|
|
|
|
|
/// </summary>
|
|
|
|
|
private float _wholeScale;
|
|
|
|
|
|
|
|
|
|
public float WholeScale
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _wholeScale;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_wholeScale = value;
|
|
|
|
|
WholeScaleChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 横向缩放比列
|
|
|
|
|
/// </summary>
|
|
|
|
|
private float _xScale;
|
|
|
|
|
|
|
|
|
|
public float XScale
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _xScale;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_xScale = value;
|
|
|
|
|
XScaleChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 竖向缩放比例
|
|
|
|
|
/// </summary>
|
|
|
|
|
private float _yScale;
|
|
|
|
|
|
|
|
|
|
public float YScale
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _yScale;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_yScale = value;
|
|
|
|
|
YScaleChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 缩放比例,该参数必须大于0
|
|
|
|
|
/// </summary>
|
|
|
|
|
private double _scale = 1.0;
|
|
|
|
|
|
|
|
|
|
public double Scale
|
|
|
|
|
{
|
|
|
|
|
get { return _scale; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (value <= 0.000001)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_scale = value;
|
|
|
|
|
NotifyPropertyChanged("DScale");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 旋转角度
|
|
|
|
|
/// </summary>
|
|
|
|
|
private double _route = 0.0;
|
|
|
|
|
public double Route
|
|
|
|
|
{
|
|
|
|
|
get { return _route; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_route = value;
|
|
|
|
|
DRouteChange();
|
|
|
|
|
NotifyPropertyChanged("DRoute");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 横向移动距离
|
|
|
|
|
/// </summary>
|
|
|
|
|
private float _xMove;
|
|
|
|
|
public float XMove
|
|
|
|
|
{
|
|
|
|
|
get { return _xMove; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_xMove = value;
|
|
|
|
|
XMoveChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 竖向移动距离
|
|
|
|
|
/// </summary>
|
|
|
|
|
private float _yMove;
|
|
|
|
|
public float YMove
|
|
|
|
|
{
|
|
|
|
|
get { return _yMove; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_yMove = value;
|
|
|
|
|
YMoveChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 边框颜色
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Brush _brushColor;
|
|
|
|
|
public Brush BrushColor
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _brushColor;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_brushColor = value;
|
|
|
|
|
ColorChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 变换矩阵
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Matrix _matrix = new Matrix();
|
|
|
|
|
public Matrix Matrix => _matrix.Clone();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 矩形框
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Rectangle _rcImg = new Rectangle(0, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
public int _width { get; private set; }
|
|
|
|
|
public int _height { get; private set; }
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 位图
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Bitmap? _bitmap = null;
|
|
|
|
|
|
|
|
|
|
public Bitmap CanvasBitmap
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _bitmap;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 预览缺陷图片的GraphicsPath
|
|
|
|
|
/// </summary>
|
|
|
|
|
private GraphicsPath? _path = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Bitmap ImgData
|
|
|
|
|
{
|
|
|
|
|
get { return _bitmap; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
Init();
|
|
|
|
|
_bitmap = value;
|
|
|
|
|
if (null == _bitmap)
|
|
|
|
|
{
|
|
|
|
|
_rcImg.Width = 0;
|
|
|
|
|
_rcImg.Height = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_rcImg.Width = _bitmap.Width;
|
|
|
|
|
_rcImg.Height = _bitmap.Height;
|
|
|
|
|
FitImage();
|
|
|
|
|
}
|
|
|
|
|
//强制控件使其工作区无效并且重新绘制自己以及任何子控件
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string strImgPath = string.Empty;
|
|
|
|
|
|
|
|
|
|
public string ImagePath
|
|
|
|
|
{
|
|
|
|
|
get { return strImgPath; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (null != _bitmap)
|
|
|
|
|
{
|
|
|
|
|
_bitmap.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using (Stream s = File.Open(value, FileMode.Open))
|
|
|
|
|
{
|
|
|
|
|
ImgData = (Bitmap)Image.FromStream(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
_bitmap = null;
|
|
|
|
|
strImgPath = string.Empty;
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private Mat strImgMat = new Mat();
|
|
|
|
|
public Mat ImaMAt
|
|
|
|
|
{
|
|
|
|
|
get { return strImgMat; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (null != _bitmap)
|
|
|
|
|
{
|
|
|
|
|
_bitmap.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ImgData = value.ToBitmap();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
_bitmap = null;
|
|
|
|
|
strImgPath = string.Empty;
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private PointF _panBasePoint = PointF.Empty;
|
|
|
|
|
private ClickArea _clickArea = ClickArea.AREA_UNKNOW;
|
|
|
|
|
public List<Defect> DefectList = new List<Defect>();
|
|
|
|
|
public List<GraphicsPath> GPathList = new List<GraphicsPath>();
|
|
|
|
|
Action<object, MouseEventArgs> actionMove;
|
|
|
|
|
Action<object, MouseEventArgs> actionUp;
|
|
|
|
|
Action<object, MouseEventArgs> actionDown;
|
|
|
|
|
//action1+=
|
|
|
|
|
object osender;
|
|
|
|
|
private Dictionary<MouseButtons, Action<object, MouseEventArgs>> _mouseEventDic = new Dictionary<MouseButtons, Action<object, MouseEventArgs>>()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public Canvas()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
DoubleBuffered = true;
|
|
|
|
|
SetStyle(ControlStyles.AllPaintingInWmPaint//控件忽略窗口消息 WM_ERASEBKGND 以减少闪烁
|
|
|
|
|
| ControlStyles.UserPaint//由控件而不是由操作系统来绘制控件自身,即自定义绘制
|
|
|
|
|
| ControlStyles.OptimizedDoubleBuffer//控件将首先绘制到缓冲区而不是直接绘制到屏幕,这可以减少闪烁
|
|
|
|
|
| ControlStyles.ResizeRedraw, true);//控件会在调整大小时进行重绘
|
|
|
|
|
|
|
|
|
|
//添加鼠标滑轮事件
|
|
|
|
|
//MouseWheel += OnCanvasMouseWheel;
|
|
|
|
|
//actionMove += ImageMoveFunc;
|
|
|
|
|
// actionUp += ImageUPFunc;
|
|
|
|
|
// actionDown += ImageDownFunc;
|
|
|
|
|
_mouseEventDic.Add(MouseButtons.Left, actionMove);
|
|
|
|
|
// _mouseEventDic.Add(MouseButtons.Left, actionMove);
|
|
|
|
|
// _mouseEventDic.Add(MouseButtons.Left, actionMove);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Init()
|
|
|
|
|
{
|
|
|
|
|
_clickArea = ClickArea.AREA_UNKNOW;//枚举
|
|
|
|
|
_rcImg = new Rectangle(0, 0, 0, 0);
|
|
|
|
|
Scale = 1.0;
|
|
|
|
|
Route = 0.0;
|
|
|
|
|
_matrix.Reset();//重置为单位矩阵
|
|
|
|
|
strImgPath = string.Empty;
|
|
|
|
|
_bitmap = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//base.OnPaint(e);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//获取表示控件的工作区的矩形
|
|
|
|
|
Rectangle rect = ClientRectangle;
|
|
|
|
|
|
|
|
|
|
Graphics oriGraphics = e.Graphics;
|
|
|
|
|
|
|
|
|
|
//设置平滑程度为高质量,减少抗锯齿的出现
|
|
|
|
|
oriGraphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
|
|
|
|
|
// 双缓冲绘图
|
|
|
|
|
//获取当前应用程序域的 BufferedGraphicsContext,此实例管理该应用程序的所有默认双缓冲
|
|
|
|
|
BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
|
|
|
|
|
//BufferedGraphics 对象管理与呈现图面(例如窗体或控件)关联的内存缓冲
|
|
|
|
|
BufferedGraphics myBuffer = currentContext.Allocate(oriGraphics, rect);
|
|
|
|
|
//实例化一个直接表示内存缓冲的 Graphics 对象,可将图形呈现到内存缓冲,绘制到此对象中
|
|
|
|
|
Graphics bufferGraphics = myBuffer.Graphics;
|
|
|
|
|
bufferGraphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
//高质量低速度呈现
|
|
|
|
|
bufferGraphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
|
|
|
//使用的插值算法
|
|
|
|
|
bufferGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
|
|
|
|
|
//清除整个绘图面并以指定背景色填充,Console.BackColor指获取当前控件的背景色
|
|
|
|
|
bufferGraphics.Clear(BackColor);
|
|
|
|
|
|
|
|
|
|
bufferGraphics.MultiplyTransform(_matrix);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 画背景图
|
|
|
|
|
|
|
|
|
|
if (_bitmap != null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
bufferGraphics.DrawImage(_bitmap, 0, 0, _bitmap.Width, _bitmap.Height);
|
|
|
|
|
if (_path != null)
|
|
|
|
|
{
|
|
|
|
|
bufferGraphics.DrawPath(new Pen(Brushes.Yellow, 1f), _path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_bitmap = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
2024-07-05 11:22:41 +08:00
|
|
|
|
|
2024-06-17 11:02:28 +08:00
|
|
|
|
#region 画矩形
|
|
|
|
|
GPathList.ForEach(path =>
|
|
|
|
|
{
|
|
|
|
|
if (path != null)
|
|
|
|
|
{
|
|
|
|
|
bufferGraphics.DrawPath(new Pen(Brushes.Green, 2f), path);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 画缺陷
|
|
|
|
|
|
|
|
|
|
DefectList.ForEach(item =>
|
|
|
|
|
{
|
|
|
|
|
// 缺陷图片
|
|
|
|
|
Bitmap bitmapDefect = item.OriBitMap;
|
|
|
|
|
|
|
|
|
|
// 基准矩阵为背景图的矩阵
|
|
|
|
|
Matrix baseMatrix = _matrix.Clone();
|
|
|
|
|
baseMatrix.Multiply(item.PrivateMatrix); // 右乘每个缺陷自己的矩阵
|
|
|
|
|
bufferGraphics.Transform = baseMatrix;
|
|
|
|
|
|
|
|
|
|
PointF upperLeftPoint = item.UpperLeftPoint;
|
|
|
|
|
bufferGraphics.DrawImage(bitmapDefect, upperLeftPoint.X, upperLeftPoint.Y, bitmapDefect.Width, bitmapDefect.Height);
|
|
|
|
|
if (item.Selected)
|
|
|
|
|
{
|
|
|
|
|
// bufferGraphics.DrawPath(new Pen(Brushes.Yellow, 1f), item.Path);
|
|
|
|
|
item.DrawPath(bufferGraphics);
|
|
|
|
|
}
|
|
|
|
|
baseMatrix.Dispose();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
myBuffer.Render(oriGraphics);
|
|
|
|
|
//释放资源
|
|
|
|
|
bufferGraphics.Dispose();
|
|
|
|
|
myBuffer.Dispose();
|
|
|
|
|
currentContext.Dispose();
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 鼠标滚轮事件
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Canvas_MouseWheel(object? sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//绑定滚轮键
|
|
|
|
|
if (_clickArea == ClickArea.AREA_UNKNOW || _clickArea == ClickArea.AREA_IMG)
|
|
|
|
|
{
|
|
|
|
|
var delta = e.Delta;
|
|
|
|
|
var p = e.Location.ToImageCoordinate(_matrix);
|
|
|
|
|
var mat = new Matrix();
|
|
|
|
|
mat.Translate(p.X, p.Y);
|
|
|
|
|
if (delta > 0)
|
|
|
|
|
{
|
|
|
|
|
mat.Scale(1.1f, 1.1f);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mat.Scale(0.9f, 0.9f);
|
|
|
|
|
}
|
|
|
|
|
mat.Translate(-p.X, -p.Y);
|
|
|
|
|
_matrix.Multiply(mat);
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
else if (_clickArea == ClickArea.AREA_DEFECT)
|
|
|
|
|
{
|
|
|
|
|
var delta = e.Delta;
|
|
|
|
|
var tmpMatrix = _matrix.Clone();
|
|
|
|
|
tmpMatrix.Multiply(SelectedDefect.PrivateMatrix);
|
|
|
|
|
var point = e.Location.ToImageCoordinate(tmpMatrix);
|
|
|
|
|
SelectedDefect.Move(point.X, point.Y);
|
|
|
|
|
if (delta > 0)
|
|
|
|
|
{
|
|
|
|
|
SelectedDefect.Scale(1.1f, 1.1f);
|
|
|
|
|
SelectedDefect.WholeDScale *= 1.1f;
|
|
|
|
|
SelectedDefect.XDScale *= 1.1f;
|
|
|
|
|
SelectedDefect.YDScale *= 1.1f;
|
|
|
|
|
for (int i = 0; i < SelectedDefect.LastSetScale.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
SelectedDefect.LastSetScale[i] *= 1.1f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SelectedDefect.Scale(0.9f, 0.9f);
|
|
|
|
|
SelectedDefect.WholeDScale *= 0.9f;
|
|
|
|
|
SelectedDefect.XDScale *= 0.9f;
|
|
|
|
|
SelectedDefect.YDScale *= 0.9f;
|
|
|
|
|
for (int i = 0; i < SelectedDefect.LastSetScale.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
SelectedDefect.LastSetScale[i] *= 0.9f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SelectedDefect.Move(-point.X, -point.Y);
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 整体缩放比列改变时触发
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void WholeScaleChange()
|
|
|
|
|
{
|
|
|
|
|
if (SelectedDefect == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float scaleWhole = WholeScale / SelectedDefect.LastSetScale[0];
|
|
|
|
|
SelectedDefect.LastSetScale[0] = WholeScale;
|
|
|
|
|
SelectedDefect.WholeDScale = WholeScale;
|
|
|
|
|
SelectedDefect.XDScale *= scaleWhole;
|
|
|
|
|
SelectedDefect.YDScale *= scaleWhole;
|
|
|
|
|
SelectedDefect.LastSetScale[1] *= scaleWhole;
|
|
|
|
|
SelectedDefect.LastSetScale[2] *= scaleWhole;
|
|
|
|
|
|
|
|
|
|
var point = SelectedDefect._defectCenterPoint;
|
|
|
|
|
SelectedDefect.Move(point.X, point.Y);
|
|
|
|
|
SelectedDefect.Scale(scaleWhole, scaleWhole);
|
|
|
|
|
SelectedDefect.Move(-point.X, -point.Y);
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 横向缩放比例改变时触发
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void XScaleChange()
|
|
|
|
|
{
|
|
|
|
|
if (SelectedDefect == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float scaleX = XScale / SelectedDefect.LastSetScale[1];
|
|
|
|
|
SelectedDefect.LastSetScale[1] = XScale;
|
|
|
|
|
SelectedDefect.XDScale = XScale;
|
|
|
|
|
|
|
|
|
|
var point = SelectedDefect._defectCenterPoint;
|
|
|
|
|
SelectedDefect.Move(point.X, point.Y);
|
|
|
|
|
SelectedDefect.Scale(scaleX, 1f);
|
|
|
|
|
SelectedDefect.Move(-point.X, -point.Y);
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 竖向缩放比例改变时触发
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void YScaleChange()
|
|
|
|
|
{
|
|
|
|
|
if (SelectedDefect == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float scaleY = YScale / SelectedDefect.LastSetScale[2];
|
|
|
|
|
SelectedDefect.LastSetScale[2] = YScale;
|
|
|
|
|
SelectedDefect.YDScale = YScale;
|
|
|
|
|
|
|
|
|
|
var point = SelectedDefect._defectCenterPoint;
|
|
|
|
|
SelectedDefect.Move(point.X, point.Y);
|
|
|
|
|
SelectedDefect.Scale(1f, scaleY);
|
|
|
|
|
SelectedDefect.Move(-point.X, -point.Y);
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 自适应图片,缩放到符合控件尺寸
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void FitImage()
|
|
|
|
|
{
|
|
|
|
|
if (null == _bitmap)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_matrix = new Matrix();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 先将图片缩放到适配控件尺寸
|
|
|
|
|
// 宽高比例中的较大值
|
|
|
|
|
float wRatio = 1f * _bitmap.Width / Width;
|
|
|
|
|
float hRatio = 1f * _bitmap.Height / Height;
|
|
|
|
|
float ratio = 1 / Math.Max(wRatio, hRatio);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_matrix.Scale(ratio, ratio);
|
|
|
|
|
_width = (int)(_bitmap.Width * ratio);
|
|
|
|
|
_height = (int)(_bitmap.Height * ratio);
|
|
|
|
|
|
|
|
|
|
// 再将图片平移到控件中心
|
|
|
|
|
// 将plMain的中心转换为图片坐标
|
|
|
|
|
PointF pControlCenter = new(Width / 2.0f, Height / 2.0f);
|
|
|
|
|
PointF pImgCoordinate = pControlCenter.ToImageCoordinate(_matrix);
|
|
|
|
|
|
|
|
|
|
//目标坐标减去当前坐标
|
|
|
|
|
_matrix.Translate(pImgCoordinate.X - _bitmap.Width / 2.0f,
|
|
|
|
|
pImgCoordinate.Y - _bitmap.Height / 2.0f);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//强制控件使其工作区无效并立即重绘自己和任何子控件
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Canvas_SizeChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//{
|
|
|
|
|
// { MouseButtons.Left, ImageMoveFunc()},
|
|
|
|
|
|
|
|
|
|
// { MouseButtons.Right, ImageMoveFunc},
|
|
|
|
|
|
|
|
|
|
//};
|
|
|
|
|
|
|
|
|
|
// _mouseEventDic
|
|
|
|
|
|
|
|
|
|
public enum ActionEnum
|
|
|
|
|
{
|
|
|
|
|
MOVE_ACTION,
|
|
|
|
|
Move_Down,
|
|
|
|
|
Move_Up,
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Set(MouseButtons btn, ActionEnum action)
|
|
|
|
|
{
|
|
|
|
|
switch (action)
|
|
|
|
|
{
|
|
|
|
|
case ActionEnum.MOVE_ACTION:
|
|
|
|
|
_mouseEventDic[btn] = ImageMoveFunc;
|
|
|
|
|
break;
|
|
|
|
|
case ActionEnum.Move_Up:
|
|
|
|
|
_mouseEventDic[btn] = ImageUPFunc;
|
|
|
|
|
break;
|
|
|
|
|
case ActionEnum.Move_Down:
|
|
|
|
|
_mouseEventDic[btn] = ImageDownFunc;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void ImageMoveFunc(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//鼠标左键移动触发移动事件
|
|
|
|
|
if (MouseButtons.Left == e.Button)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (PointF.Empty == _panBasePoint)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (_clickArea)
|
|
|
|
|
{
|
|
|
|
|
//case ClickArea.AREA_DEFECT: // 点击了缺陷区域
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
|
|
// // 选中的缺陷
|
|
|
|
|
// if (null == SelectedDefect)
|
|
|
|
|
// {
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// var tmpMatrix = _matrix.Clone();
|
|
|
|
|
// tmpMatrix.Multiply(SelectedDefect.PrivateMatrix);
|
|
|
|
|
|
|
|
|
|
// //MouseEventArgs.Location包含相对于控件左上角的point坐标
|
|
|
|
|
// //得到点击的坐标在缺陷坐标系中的坐标值
|
|
|
|
|
// PointF p = e.Location.ToImageCoordinate(tmpMatrix);
|
|
|
|
|
|
|
|
|
|
// float x = p.X - _panBasePoint.X;
|
|
|
|
|
// float y = p.Y - _panBasePoint.Y;
|
|
|
|
|
// Rectangle rectangle = new Rectangle((int)_panBasePoint.X, (int)_panBasePoint.Y,(int)x,(int)y);
|
|
|
|
|
|
|
|
|
|
// // 位移矩阵左乘缺陷矩阵
|
|
|
|
|
// SelectedDefect.Move(x, y);
|
|
|
|
|
|
|
|
|
|
// // 更新缺陷在控件坐标系中的位移
|
|
|
|
|
// PointF nowPoint = SelectedDefect._defectCenterPoint.ToControlCoordinate(tmpMatrix);
|
|
|
|
|
// PointF initialPoint = SelectedDefect.InitialPosition.ToControlCoordinate(_matrix);
|
|
|
|
|
// SelectedDefect.XDMove = nowPoint.X - initialPoint.X;
|
|
|
|
|
// SelectedDefect.YDMove = nowPoint.Y - initialPoint.Y;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case ClickArea.AREA_IMG: // 点击了图像区域
|
|
|
|
|
{
|
|
|
|
|
PointF p = e.Location.ToImageCoordinate(_matrix);
|
|
|
|
|
|
|
|
|
|
float x = p.X - _panBasePoint.X;
|
|
|
|
|
float y = p.Y - _panBasePoint.Y;
|
|
|
|
|
_matrix.Translate(x, y);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void ImageUPFunc(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (MouseButtons.Left == e.Button || MouseButtons.Right == e.Button)
|
|
|
|
|
{
|
|
|
|
|
_panBasePoint = Point.Empty;
|
|
|
|
|
_clickArea = ClickArea.AREA_UNKNOW;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void ImageDownFunc(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Func<Defect, bool> funcContain = defect =>
|
|
|
|
|
{
|
|
|
|
|
// 每个图片的最终矩阵,即背景图的矩阵 右乘 缺陷自身的矩阵
|
|
|
|
|
var tmpMatrix = _matrix.Clone();
|
|
|
|
|
tmpMatrix.Multiply(defect.PrivateMatrix);
|
|
|
|
|
// 得到点击的坐标在每个缺陷的坐标系中的坐标值
|
|
|
|
|
PointF tmpP = e.Location.ToImageCoordinate(tmpMatrix);
|
|
|
|
|
|
|
|
|
|
if (defect.ContainPoint(tmpP.ToPoint())) // 点击了缺陷区域
|
|
|
|
|
{
|
|
|
|
|
_clickArea = ClickArea.AREA_DEFECT;
|
|
|
|
|
_panBasePoint = tmpP;
|
|
|
|
|
a = e.Location;
|
|
|
|
|
// 此时基准点的坐标系为缺陷图片的坐标系
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (AllowSelectDefect)
|
|
|
|
|
{
|
|
|
|
|
if (MouseButtons.Left == e.Button)
|
|
|
|
|
{
|
|
|
|
|
// 如果允许选中缺陷功能
|
|
|
|
|
// 检查是否在缺陷范围内,倒序查找
|
|
|
|
|
var ret = DefectList.LastOrDefault(d => funcContain(d));
|
|
|
|
|
if (null != ret) // 点击了缺陷
|
|
|
|
|
{
|
|
|
|
|
if (ret.Selected) // 点击的是已经选择过的缺陷
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else // 点击的是未选择的缺陷
|
|
|
|
|
{
|
|
|
|
|
// 取消选择所有的,并选中当前点击的
|
|
|
|
|
DefectList.ForEach(d => d.UnSelect());
|
|
|
|
|
ret.Select();
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DefectList.ForEach(d => d.UnSelect());
|
|
|
|
|
|
|
|
|
|
PointF clickPoint = e.Location.ToImageCoordinate(_matrix);
|
|
|
|
|
if (_rcImg.Contains(clickPoint.ToPoint()))
|
|
|
|
|
{
|
|
|
|
|
_clickArea = ClickArea.AREA_IMG;
|
|
|
|
|
_panBasePoint = clickPoint;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e.Button == MouseButtons.Right)
|
|
|
|
|
{
|
|
|
|
|
PointF clickPoint = e.Location.ToImageCoordinate(_matrix);
|
|
|
|
|
if (_rcImg.Contains(clickPoint.ToPoint()))
|
|
|
|
|
{
|
|
|
|
|
if (null == SelectedDefect)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_clickArea = ClickArea.AREA_IMG;
|
|
|
|
|
_panBasePoint = clickPoint.ToImageCoordinate(SelectedDefect.PrivateMatrix);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 图像移动与旋转
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Canvas_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//鼠标左键移动触发移动事件
|
|
|
|
|
if (MouseButtons.Left == e.Button)
|
|
|
|
|
{
|
|
|
|
|
//_mouseEventDic[MouseButtons.Left].Invoke(sender, e);
|
|
|
|
|
|
|
|
|
|
if (PointF.Empty == _panBasePoint)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (_clickArea)
|
|
|
|
|
{
|
|
|
|
|
//case ClickArea.AREA_DEFECT: // 点击了缺陷区域
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
|
|
// // 选中的缺陷
|
|
|
|
|
// if (null == SelectedDefect)
|
|
|
|
|
// {
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// var tmpMatrix = _matrix.Clone();
|
|
|
|
|
// tmpMatrix.Multiply(SelectedDefect.PrivateMatrix);
|
|
|
|
|
|
|
|
|
|
// //MouseEventArgs.Location包含相对于控件左上角的point坐标
|
|
|
|
|
// //得到点击的坐标在缺陷坐标系中的坐标值
|
|
|
|
|
// PointF p = e.Location.ToImageCoordinate(tmpMatrix);
|
|
|
|
|
|
|
|
|
|
// float x = p.X - _panBasePoint.X;
|
|
|
|
|
// float y = p.Y - _panBasePoint.Y;
|
|
|
|
|
|
|
|
|
|
// // 位移矩阵左乘缺陷矩阵
|
|
|
|
|
// SelectedDefect.Move(x, y);
|
|
|
|
|
|
|
|
|
|
// // 更新缺陷在控件坐标系中的位移
|
|
|
|
|
// PointF nowPoint = SelectedDefect._defectCenterPoint.ToControlCoordinate(tmpMatrix);
|
|
|
|
|
// PointF initialPoint = SelectedDefect.InitialPosition.ToControlCoordinate(_matrix);
|
|
|
|
|
// SelectedDefect.XDMove = nowPoint.X - initialPoint.X;
|
|
|
|
|
// SelectedDefect.YDMove = nowPoint.Y - initialPoint.Y;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case ClickArea.AREA_IMG: // 点击了图像区域
|
|
|
|
|
{
|
|
|
|
|
PointF p = e.Location.ToImageCoordinate(_matrix);
|
|
|
|
|
string log = "x:" + p.X.ToString() + "Y:" + p.Y.ToString();
|
|
|
|
|
WriteLog(log);
|
|
|
|
|
float x = p.X - _panBasePoint.X;
|
|
|
|
|
float y = p.Y - _panBasePoint.Y;
|
|
|
|
|
string log2 = "mmmx:" + x.ToString() + "mmmY:" + y.ToString();
|
|
|
|
|
WriteLog(log2);
|
|
|
|
|
//Rectangle rectangle = new Rectangle((int)_panBasePoint.X, (int)_panBasePoint.Y, (int)x, (int)y);
|
|
|
|
|
// _path = new GraphicsPath();
|
|
|
|
|
//_path.AddRectangle(rectangle);
|
|
|
|
|
//_path.CloseAllFigures();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Defect defect = new Defect(rectangle, _matrixcs);
|
|
|
|
|
// DefectList.Add(defect);
|
|
|
|
|
//PointF[] ps = new PointF[] { defect._defectCenterPoint };
|
|
|
|
|
// defect.PrivateMatrix.TransformPoints(ps);
|
|
|
|
|
// defect.InitialPosition = ps[0];
|
|
|
|
|
// defect.Select();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//鼠标右键移动触发旋转事件
|
|
|
|
|
if (e.Button == MouseButtons.Right)
|
|
|
|
|
{
|
|
|
|
|
if (_panBasePoint == PointF.Empty || _clickArea == ClickArea.AREA_UNKNOW)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (_clickArea)
|
|
|
|
|
{
|
|
|
|
|
case ClickArea.AREA_UNKNOW:
|
|
|
|
|
case ClickArea.AREA_DEFECT:
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ClickArea.AREA_IMG:
|
|
|
|
|
{
|
|
|
|
|
if (SelectedDefect == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Matrix tmpMatrix = _matrix.Clone();
|
|
|
|
|
tmpMatrix.Multiply(SelectedDefect.PrivateMatrix);
|
|
|
|
|
|
|
|
|
|
PointF p = e.Location.ToImageCoordinate(tmpMatrix);
|
|
|
|
|
|
|
|
|
|
float xBefore = _panBasePoint.X - SelectedDefect._defectCenterPoint.X;
|
|
|
|
|
float yBefore = _panBasePoint.Y - SelectedDefect._defectCenterPoint.Y;
|
|
|
|
|
float xAfter = p.X - SelectedDefect._defectCenterPoint.X;
|
|
|
|
|
float yAfter = p.Y - SelectedDefect._defectCenterPoint.Y;
|
|
|
|
|
|
|
|
|
|
double coorBefore = Math.Atan2(yBefore, xBefore);
|
|
|
|
|
double coorAfter = Math.Atan2(yAfter, xAfter);
|
|
|
|
|
|
|
|
|
|
SelectedDefect.DRoute = ((coorAfter - coorBefore) * 180 / Math.PI);
|
|
|
|
|
Route = SelectedDefect.DRoute;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 角度变化触发
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void DRouteChange()
|
|
|
|
|
{
|
|
|
|
|
if (SelectedDefect == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
SelectedDefect.RotateAt((float)Route, SelectedDefect._defectCenterPoint);
|
|
|
|
|
SelectedDefect.TotalDRoute += Route;
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private PointF a;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 横向位移触发
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void XMoveChange()
|
|
|
|
|
{
|
|
|
|
|
if (null == SelectedDefect)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Matrix tmpMatrix = _matrix.Clone();
|
|
|
|
|
tmpMatrix.Multiply(SelectedDefect.PrivateMatrix);
|
|
|
|
|
SelectedDefect.LastSetPosition = SelectedDefect._defectCenterPoint.ToControlCoordinate(tmpMatrix);
|
|
|
|
|
PointF nowPoint = new PointF(SelectedDefect.LastSetPosition.X + XMove, SelectedDefect.LastSetPosition.Y);
|
|
|
|
|
nowPoint = nowPoint.ToImageCoordinate(tmpMatrix);
|
|
|
|
|
float x = nowPoint.X - SelectedDefect._defectCenterPoint.X;
|
|
|
|
|
float y = nowPoint.Y - SelectedDefect._defectCenterPoint.Y;
|
|
|
|
|
SelectedDefect.Move(x, y);
|
|
|
|
|
SelectedDefect.XDMove += XMove;
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 竖向位移触发
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void YMoveChange()
|
|
|
|
|
{
|
|
|
|
|
if (null == SelectedDefect)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Matrix tmpMatrix = _matrix.Clone();
|
|
|
|
|
tmpMatrix.Multiply(SelectedDefect.PrivateMatrix);
|
|
|
|
|
SelectedDefect.LastSetPosition = SelectedDefect._defectCenterPoint.ToControlCoordinate(tmpMatrix);
|
|
|
|
|
PointF nowPoint = new PointF(SelectedDefect.LastSetPosition.X, SelectedDefect.LastSetPosition.Y + YMove);
|
|
|
|
|
nowPoint = nowPoint.ToImageCoordinate(tmpMatrix);
|
|
|
|
|
int x = (int)(nowPoint.X - SelectedDefect._defectCenterPoint.X);
|
|
|
|
|
int y = (int)(nowPoint.Y - SelectedDefect._defectCenterPoint.Y);
|
|
|
|
|
SelectedDefect.Move(x, y);
|
|
|
|
|
SelectedDefect.YDMove += YMove;
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void ColorChange()
|
|
|
|
|
{
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 鼠标按下事件
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Canvas_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Func<Defect, bool> funcContain = defect =>
|
|
|
|
|
{
|
|
|
|
|
// 每个图片的最终矩阵,即背景图的矩阵 右乘 缺陷自身的矩阵
|
|
|
|
|
var tmpMatrix = _matrix.Clone();
|
|
|
|
|
tmpMatrix.Multiply(defect.PrivateMatrix);
|
|
|
|
|
// 得到点击的坐标在每个缺陷的坐标系中的坐标值
|
|
|
|
|
PointF tmpP = e.Location.ToImageCoordinate(tmpMatrix);
|
|
|
|
|
|
|
|
|
|
if (defect.ContainPoint(tmpP.ToPoint())) // 点击了缺陷区域
|
|
|
|
|
{
|
|
|
|
|
_clickArea = ClickArea.AREA_DEFECT;
|
|
|
|
|
_panBasePoint = tmpP;
|
|
|
|
|
a = e.Location;
|
|
|
|
|
// 此时基准点的坐标系为缺陷图片的坐标系
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (AllowSelectDefect)
|
|
|
|
|
{
|
|
|
|
|
if (MouseButtons.Left == e.Button)
|
|
|
|
|
{
|
|
|
|
|
// 如果允许选中缺陷功能
|
|
|
|
|
// 检查是否在缺陷范围内,倒序查找
|
|
|
|
|
var ret = DefectList.LastOrDefault(d => funcContain(d));
|
|
|
|
|
if (null != ret) // 点击了缺陷
|
|
|
|
|
{
|
|
|
|
|
if (ret.Selected) // 点击的是已经选择过的缺陷
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else // 点击的是未选择的缺陷
|
|
|
|
|
{
|
|
|
|
|
// 取消选择所有的,并选中当前点击的
|
|
|
|
|
DefectList.ForEach(d => d.UnSelect());
|
|
|
|
|
ret.Select();
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//Defect rectitem=new Defect();
|
|
|
|
|
// DefectList.Add()
|
|
|
|
|
DefectList.ForEach(d => d.UnSelect());
|
|
|
|
|
|
|
|
|
|
PointF clickPoint = e.Location.ToImageCoordinate(_matrix);
|
|
|
|
|
if (_rcImg.Contains(clickPoint.ToPoint()))
|
|
|
|
|
{
|
|
|
|
|
_clickArea = ClickArea.AREA_IMG;
|
|
|
|
|
_panBasePoint = clickPoint;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e.Button == MouseButtons.Right)
|
|
|
|
|
{
|
|
|
|
|
PointF clickPoint = e.Location.ToImageCoordinate(_matrix);
|
|
|
|
|
if (_rcImg.Contains(clickPoint.ToPoint()))
|
|
|
|
|
{
|
|
|
|
|
if (null == SelectedDefect)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_clickArea = ClickArea.AREA_IMG;
|
|
|
|
|
_panBasePoint = clickPoint.ToImageCoordinate(SelectedDefect.PrivateMatrix);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 鼠标松开的事件
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Canvas_MouseUp(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (MouseButtons.Left == e.Button || MouseButtons.Right == e.Button)
|
|
|
|
|
{
|
|
|
|
|
PointF p = e.Location.ToImageCoordinate(_matrix);
|
|
|
|
|
string log = "x:" + p.X.ToString() + "Y:" + p.Y.ToString();
|
|
|
|
|
WriteLog(log);
|
|
|
|
|
float x = p.X - _panBasePoint.X;
|
|
|
|
|
float y = p.Y - _panBasePoint.Y;
|
|
|
|
|
string log2 = "mmmx:" + x.ToString() + "mmmY:" + y.ToString();
|
|
|
|
|
WriteLog(log2);
|
|
|
|
|
//Rectangle rectangle = new Rectangle((int)_panBasePoint.X, (int)_panBasePoint.Y, (int)x, (int)y);
|
|
|
|
|
//GraphicsPath path = new GraphicsPath();
|
|
|
|
|
//path.AddRectangle(rectangle);
|
|
|
|
|
//path.CloseAllFigures();
|
|
|
|
|
//GPathList.Add(path);
|
|
|
|
|
//Matrix _matrixcs = new Matrix();
|
|
|
|
|
//Defect defect = new Defect(rectangle, _matrixcs);
|
|
|
|
|
//DefectList.Add(defect);
|
|
|
|
|
//PointF[] ps = new PointF[] { defect._defectCenterPoint };
|
|
|
|
|
//defect.PrivateMatrix.TransformPoints(ps);
|
|
|
|
|
//defect.InitialPosition = ps[0];
|
|
|
|
|
//defect.Select();
|
|
|
|
|
_panBasePoint = Point.Empty;
|
|
|
|
|
_clickArea = ClickArea.AREA_UNKNOW;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 载入缺陷预览图
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void LoadDefect(string file, Polygon p)
|
|
|
|
|
{
|
|
|
|
|
_path = null;
|
|
|
|
|
PointF[] points = p.GetPoints().ToArray();
|
|
|
|
|
_path = new GraphicsPath();
|
|
|
|
|
_path.AddPolygon(points);
|
|
|
|
|
_path.CloseAllFigures();
|
|
|
|
|
ImagePath = file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadDefect(string file)
|
|
|
|
|
{
|
|
|
|
|
_path = null;
|
|
|
|
|
ImagePath = file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadPolygon(string file)
|
|
|
|
|
{
|
|
|
|
|
Matrix _matrix = new Matrix();
|
|
|
|
|
_path = null;
|
|
|
|
|
Defect defect = new Defect(file, _matrix);
|
|
|
|
|
DefectList.Add(defect);
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadPolygon(string file, Polygon p)
|
|
|
|
|
{
|
|
|
|
|
Matrix _matrix = new Matrix();
|
|
|
|
|
PointF[] points = p.GetPoints().ToArray();
|
|
|
|
|
Defect defect = new Defect(file, points, _matrix);
|
|
|
|
|
DefectList.Add(defect);
|
|
|
|
|
PointF[] ps = new PointF[] { defect._defectCenterPoint };
|
|
|
|
|
defect.PrivateMatrix.TransformPoints(ps);
|
|
|
|
|
defect.InitialPosition = ps[0];
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void WriteLog(string log)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {log}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 删除新增缺陷
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void deleteDefect()
|
|
|
|
|
{
|
|
|
|
|
var defect = DefectList.FirstOrDefault(d => d.Selected);
|
|
|
|
|
|
|
|
|
|
if (defect == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DefectList.Remove(defect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 按键按下
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Canvas_KeyDown(object sender, KeyEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (SelectedDefect == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (e.KeyCode)
|
|
|
|
|
{
|
|
|
|
|
case Keys.Left:
|
|
|
|
|
{
|
|
|
|
|
SelectedDefect.Move(-MoveStep, 0, MatrixOrder.Append);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Keys.Up:
|
|
|
|
|
{
|
|
|
|
|
SelectedDefect.Move(0, -MoveStep, MatrixOrder.Append);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Keys.Right:
|
|
|
|
|
{
|
|
|
|
|
SelectedDefect.Move(MoveStep, 0, MatrixOrder.Append);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Keys.Down:
|
|
|
|
|
{
|
|
|
|
|
SelectedDefect.Move(0, MoveStep, MatrixOrder.Append);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Keys.Delete:
|
|
|
|
|
{
|
|
|
|
|
DefectList.Remove(SelectedDefect);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 按键抬起
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Canvas_KeyUp(object sender, KeyEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_keyLastPressed = Keys.None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 重写 ProcessDialogKey 使控件可以监听方向键与删除键
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override bool ProcessDialogKey(Keys keyData)
|
|
|
|
|
{
|
|
|
|
|
if (keyData == Keys.Up || keyData == Keys.Down ||
|
|
|
|
|
keyData == Keys.Left || keyData == Keys.Right || keyData == Keys.Delete)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return base.ProcessDialogKey(keyData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|