using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace SIASUN.Autopilot.View
{
public partial class PicExControl : UserControl
{
///
/// 支持缩放和画框以及对框进行微调的图片显示控件
///
public PicExControl()
{
//InitializeComponent();
_fineTuningRect = new FineTuningRect { FatherControl = this };
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
}
#region 字段和事件
public delegate void MouseWheelDraw(object sender, MouseEventArgs e); //显示树
public event MouseWheelDraw MouseWheelDrawEvent;
public delegate void AfterDraw(bool isMove, bool isRight);
public event AfterDraw AfterDrawEvent;
///
/// 鼠标移动显示坐标
///
///
public delegate void MouseMoveTooltip(MouseEventArgs e); //鼠标移动显示坐标
///
/// 鼠标移动显示坐标
///
public event MouseMoveTooltip MouseMoveTooltipEvent;
///
/// 画路径
///
///
public delegate void DrawPath(Graphics g); //画路径
///
/// 画原始路径
///
public event DrawPath DrawOriginalPathEvent; //画原始路径
///
/// 画行驶路径
///
public event DrawPath DrawDrivingPathEvent; //画行驶路径
///
/// 原图
///
private Image _image; //原图
private FineTuningRect _fineTuningRect;
///
/// 鼠标所在矩形位置
///
private PosSizableRect _nodeSelected = PosSizableRect.None;
///
/// 变换形式,如:放大、重绘
///
private TreatmentType _treatmentType = TreatmentType.Zoom;
private TreatmentType _lasttreatmentType = TreatmentType.None;
///
/// 基于原图的框
///
private Rectangle _imageRect;
///
/// 左上点
///
private PointF _luPonit = new PointF(0, 0);
///
/// 右下点
///
private PointF _rbPonit = new PointF(0, 0);
///
/// 起始点
///
private PointF _startPoint = new PointF(0, 0);
///
/// 鼠标点击点
///
private PointF _mouseDownPoint = new PointF(0, 0);
///
/// 允许画框
///
private bool _allawDraw;
///
/// 鼠标按下
///
private bool _mIsClick;
///
/// 鼠标移动
///
private bool _isMouseMove;
private int _i;
///
/// 竖向缩放比
///
public float Hrate = 1; //竖向缩放比
///
/// 横向缩放比
///
public float Wrate = 1; //横向缩放比
private Color _rectColor = Color.Red;
///
/// 是否微调
///
private bool _isFirstZoom = false;
///
/// 适应屏幕的横向缩放比
///
private float _FitWrate;
///
/// 适应屏幕的纵向缩放比
///
private float _FitHrate;
#endregion
#region 属性
///
/// 是否是微调状态
///
public bool IsFineTuring // 是否是微调状态
=> _nodeSelected != PosSizableRect.None;
///
/// 基于原图的框
///
public Rectangle ImageRect //基于原图的框
{
get
{
int x = (int)Math.Round((_luPonit.X - _startPoint.X) / Wrate);
int y = (int)Math.Round((_luPonit.Y - _startPoint.Y) / Hrate);
int width = (int)Math.Round((_rbPonit.X - _luPonit.X) / Wrate);
int height = (int)Math.Round((_rbPonit.Y - _luPonit.Y) / Wrate);
Rectangle rect = new Rectangle(x, y, width, height);
Rectangle imageRect = new Rectangle(0, 0, _image == null ? 0 : _image.Width, _image == null ? 0 : _image.Height);
_imageRect = Rectangle.Intersect(rect, imageRect);
if (_imageRect != rect)
{
_luPonit.X = (int)(_imageRect.X * Wrate + _startPoint.X);
_luPonit.Y = (int)(_imageRect.Y * Hrate + _startPoint.Y);
_rbPonit.X = (int)(_imageRect.Width * Wrate + _luPonit.X);
_rbPonit.Y = (int)(_imageRect.Height * Hrate + _luPonit.Y);
}
return _imageRect;
}
set
{
if (_imageRect != value)
{
_luPonit.X = (int)(value.X * Wrate + _startPoint.X);
_luPonit.Y = (int)(value.Y * Hrate + _startPoint.Y);
_rbPonit.X = (int)(value.Width * Wrate + _luPonit.X);
_rbPonit.Y = (int)(value.Height * Hrate + _luPonit.Y);
}
Invalidate();
}
}
///
/// 是否保持图片比例不变
///
public bool BIsStretch
{
get;
set;
}
///
/// 是否是微调状态
///
public bool IsFirstZoom // 是否是微调状态
{
get { return _isFirstZoom; }
set { _isFirstZoom = value; }
}
///
/// 允许画框
///
public bool AllawDraw
{
get
{
return _allawDraw;
}
set
{
_allawDraw = value;
_treatmentType = _allawDraw ? TreatmentType.Draw : TreatmentType.Zoom;
}
}
public Color RectColor
{
get
{
return _rectColor;
}
set
{
_rectColor = value;
}
}
///
/// 横向缩放比
///
public float ZoomHrate
{
get
{
return Hrate;
}
}
///
/// /纵向缩放比
///
public float ZoomWrate
{
get
{
return Wrate;
}
}
///
/// 图片起始点
///
public PointF StartPoint
{
get
{
return _startPoint;
}
set
{
_startPoint = value;
}
}
///
/// 鼠标点击点
///
public PointF MouseDownPoint
{
get
{
return _mouseDownPoint;
}
}
#endregion
#region 重写
protected override void OnPaint(PaintEventArgs e)
{
try
{
if (_image != null)
{
using (Bitmap imageToDraw = (Bitmap)_image.Clone())
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
int width = (int)Math.Round(_image.Width * Wrate);
int height = (int)Math.Round(_image.Height * Hrate);
g.DrawImage(imageToDraw, new Rectangle((int)Math.Round(_startPoint.X), (int)Math.Round(_startPoint.Y), width, height));
g.DrawRectangle(new Pen(_rectColor, 1), _fineTuningRect.GetRectByF(new RectangleF(_luPonit.X, _luPonit.Y, (_rbPonit.X - _luPonit.X), (_rbPonit.Y - _luPonit.Y))));
//g.DrawLine(new Pen(_rectColor,1),point1,point2);
if (DrawOriginalPathEvent != null)
{
DrawOriginalPathEvent(g);
}
if (DrawDrivingPathEvent != null)
{
DrawDrivingPathEvent(g);
}
}
}
}
finally
{
base.OnPaint(e);
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.ControlKey && _i == 0)
{
_lasttreatmentType = _treatmentType;
SetZoom();
_i++;
}
if (e.Control && e.KeyCode == Keys.R)
{
FitToScreen();
}
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyCode == Keys.ControlKey)
{
_i = 0;
if (_lasttreatmentType != TreatmentType.None)
_treatmentType = _lasttreatmentType;
}
base.OnKeyUp(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
return;
}
_isMouseMove = false;
_mouseDownPoint = new Point(e.X, e.Y);
if (_image == null) return;//图片不为空
if (e.X < _startPoint.X || // left
e.X > _startPoint.X + Math.Round(_image.Width * Wrate) || // right
e.Y < _startPoint.Y || // top
e.Y > _startPoint.Y + Math.Round(_image.Height * Hrate)) // buttom
return; //且鼠标在图片内
_nodeSelected = _fineTuningRect.GetNodeSelectable(new Point(e.X, e.Y), _luPonit, _rbPonit);
if (e.Button == MouseButtons.Left)
_mIsClick = true;
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
return;
}
if (_treatmentType != TreatmentType.Zoom)
if (AfterDrawEvent != null)
AfterDrawEvent(_isMouseMove, e.Button == MouseButtons.Right);
_mIsClick = false;
}
protected override void OnMouseMove(MouseEventArgs e)
{
_isMouseMove = true;
PosSizableRect r = _fineTuningRect.GetNodeSelectable(new Point(e.X, e.Y), _luPonit, _rbPonit);
if (_image == null) return;
//if (!_mIsClick && _treatmentType != TreatmentType.Zoom)
//{
// Cursor = _fineTuningRect.GetCursor(r);
// if (r != PosSizableRect.None)
// SetFineTuring();
// else
// SetDraw();
// return;
//}
if (_mIsClick)
{
switch (_treatmentType)
{
case TreatmentType.Zoom:
ZoomMouseMove(e);
break;
case TreatmentType.Draw:
//DrawMouseMove(e); //鼠标移动画方框
break;
case TreatmentType.FineTuring:
//FineTuringMouseMove(e); //对鼠标画的方框进行微调
break;
}
}
else
{
if (MouseMoveTooltipEvent != null)
{
//超出图片不显示气泡
if (e.X >= _startPoint.X && e.X <= (_startPoint.X + _image.Width * Wrate) && e.Y >= _startPoint.Y && e.Y <= _startPoint.Y + _image.Height * Hrate)
{
MouseMoveTooltipEvent(e);
}
}
}
}
///
/// 鼠标滚轮事件
///
///
protected override void OnMouseWheel(MouseEventArgs e)
{
if (_image == null) return;
switch (_treatmentType)
{
case TreatmentType.Zoom:
ZoomMouseWheel(e);
break;
case TreatmentType.Draw:
//DrawMouseWheel(e); //画框模式下,鼠标滚轮变化执行的动作
break;
}
}
protected override void OnMouseEnter(EventArgs e)
{
Focus();
}
#endregion
#region 内部方法
///
///图片适应屏幕
///
private void FitToScreen()
{
if (_image != null)
{
if (BIsStretch)
{
Hrate = ((float)(Height)) / (_image.Height);
Wrate = ((float)(Width)) / (_image.Width);
}
else
{
Hrate = Wrate = Math.Min(((float)(Width)) / (_image.Width), ((float)(Height)) / (_image.Height));
}
_FitHrate = Hrate;
_FitWrate = Wrate;
float x = (Width - (_image.Width * Wrate)) / 2;
float y = (Height - (_image.Height * Hrate)) / 2;
_startPoint = new PointF(x, y);
}
Invalidate();
}
///
/// 鼠标移动画框
///
///
private void DrawMouseMove(MouseEventArgs e)
{
_luPonit.X = Math.Min(_mouseDownPoint.X, e.X);
_luPonit.Y = Math.Min(_mouseDownPoint.Y, e.Y);
_rbPonit.X = Math.Max(_mouseDownPoint.X, e.X);
_rbPonit.Y = Math.Max(_mouseDownPoint.Y, e.Y);
Invalidate();
}
private void DrawMouseWheel(MouseEventArgs e)
{
MouseWheelDrawEvent?.Invoke(this, e);
}
///
/// 鼠标移动图片
///
///
private void ZoomMouseMove(MouseEventArgs e)
{
_startPoint.X += e.X - _mouseDownPoint.X;
_startPoint.Y += e.Y - _mouseDownPoint.Y;
_luPonit.X += e.X - _mouseDownPoint.X;
_luPonit.Y += e.Y - _mouseDownPoint.Y;
_rbPonit.X += e.X - _mouseDownPoint.X;
_rbPonit.Y += e.Y - _mouseDownPoint.Y;
_mouseDownPoint = new PointF(e.X, e.Y);
Invalidate();
}
///
/// 鼠标滚轮缩放图片
///
///
private void ZoomMouseWheel(MouseEventArgs e)
{
if (e.X >= _startPoint.X && e.X <= (_startPoint.X + _image.Width * Wrate) && e.Y >= _startPoint.Y && e.Y <= _startPoint.Y + _image.Height * Hrate)
{
float imageX = (e.X - _startPoint.X) / Wrate;
float imageY = (e.Y - _startPoint.Y) / Hrate;
PointF firstLu = new PointF((e.X - _luPonit.X) / Wrate, (e.Y - _luPonit.Y) / Hrate);
PointF firstRb = new PointF((e.X - _rbPonit.X) / Wrate, (e.Y - _rbPonit.Y) / Hrate);
float rate = 1;
if (e.Delta > 0)
{
if (Math.Max(Wrate, Hrate) <= 10)
{
rate = 1.15F;
}
}
else
{
if (Math.Min(Wrate, Hrate) > Math.Max(_FitWrate, _FitHrate))
{
rate = 0.85F;
}
}
if (rate == 1) return;
Hrate *= rate;
Wrate *= rate;
_luPonit.X = e.X - firstLu.X * Wrate;
_luPonit.Y = e.Y - firstLu.Y * Hrate;
_rbPonit.X = e.X - firstRb.X * Wrate;
_rbPonit.Y = e.Y - firstRb.Y * Hrate;
_startPoint = new PointF(e.X - imageX * Wrate, e.Y - imageY * Hrate);
Invalidate();
}
}
private void FineTuringMouseMove(MouseEventArgs e)
{
PointF firstLu = new PointF(_luPonit.X, _luPonit.Y);
PointF firstRb = new PointF(_rbPonit.X, _rbPonit.Y);
switch (_nodeSelected)
{
case PosSizableRect.LeftUp:
_luPonit.X += e.X - _mouseDownPoint.X;
_luPonit.Y += e.Y - _mouseDownPoint.Y;
break;
case PosSizableRect.LeftMiddle:
_luPonit.X += e.X - _mouseDownPoint.X;
break;
case PosSizableRect.LeftBottom:
_luPonit.X += e.X - _mouseDownPoint.X;
_rbPonit.Y += e.Y - _mouseDownPoint.Y;
break;
case PosSizableRect.BottomMiddle:
_rbPonit.Y += e.Y - _mouseDownPoint.Y;
break;
case PosSizableRect.RightBottom:
_rbPonit.X += e.X - _mouseDownPoint.X;
_rbPonit.Y += e.Y - _mouseDownPoint.Y;
break;
case PosSizableRect.RightMiddle:
_rbPonit.X += e.X - _mouseDownPoint.X;
break;
case PosSizableRect.RightUp:
_rbPonit.X += e.X - _mouseDownPoint.X;
_luPonit.Y += e.Y - _mouseDownPoint.Y;
break;
case PosSizableRect.UpMiddle:
_luPonit.Y += e.Y - _mouseDownPoint.Y;
break;
case PosSizableRect.TopIn:
_luPonit.X += e.X - _mouseDownPoint.X;
_luPonit.Y += e.Y - _mouseDownPoint.Y;
_rbPonit.X += e.X - _mouseDownPoint.X;
_rbPonit.Y += e.Y - _mouseDownPoint.Y;
break;
case PosSizableRect.ButtonIn:
_luPonit.X += e.X - _mouseDownPoint.X;
_luPonit.Y += e.Y - _mouseDownPoint.Y;
_rbPonit.X += e.X - _mouseDownPoint.X;
_rbPonit.Y += e.Y - _mouseDownPoint.Y;
break;
}
_mouseDownPoint.X = e.X;
_mouseDownPoint.Y = e.Y;
if ((_rbPonit.X - _luPonit.X) < 5 || (_rbPonit.Y - _luPonit.Y) < 5)
{
_luPonit = new PointF(firstLu.X, firstLu.Y);
_rbPonit = new PointF(firstRb.X, firstRb.Y);
}
Invalidate();
}
///
/// 控件尺寸改变
///
///
///
private void PicExControl_SizeChanged(object sender, EventArgs e)
{
if (_image != null)
{
if (BIsStretch)
{
Hrate = ((float)(Height)) / (_image.Height);
Wrate = ((float)(Width)) / (_image.Width);
}
else
{
Hrate = Wrate = Math.Min(((float)(Width)) / (_image.Width), ((float)(Height)) / (_image.Height));
}
}
Invalidate();
}
///
/// 设置画框模式
///
private void SetDraw()
{
Cursor = Cursors.Default;
_treatmentType = _allawDraw ? TreatmentType.Draw : TreatmentType.Zoom;
Invalidate();
}
///
///设置微调模式
///
private void SetFineTuring()
{
_treatmentType = _allawDraw ? TreatmentType.FineTuring : TreatmentType.Zoom;
Invalidate();
}
#endregion
#region 公用方法
///
/// 获取图片
///
///
public Image GetImage()
{
return _image;
}
///
/// 设置图片
///
/// 图片
/// 适应屏幕
/// 原图的框
/// 缩放比例
public void SetImage(Image bitmap, bool isFirst, bool isDeleteRect = false, int zoom = 1)
{
if (_image != null)
{
_image.Dispose();
_image = null;
}
if (bitmap == null)
{
return;
}
_image = (Image)bitmap.Clone();
if (isFirst)
{
if (_isFirstZoom)
FitToScreen();
else
{
Hrate = zoom; //竖向缩放比
Wrate = zoom; //横向缩放比
_startPoint = new PointF((Width - _image.Width * Wrate) / 2, (Height - _image.Height * Hrate) / 2);
}
SetDraw();
}
if (isDeleteRect)
ImageRect = new Rectangle(0, 0, 0, 0);
Refresh();
bitmap.Dispose();
Invalidate();
}
///
/// 获取鼠标点击的点
///
///
public Point GetClickPoint()
{
return new Point((int)((_mouseDownPoint.X - _startPoint.X) / Wrate), (int)((_mouseDownPoint.Y - _startPoint.Y) / Hrate));
}
///
///进入缩放模式
///
public void SetZoom()
{
_treatmentType = TreatmentType.Zoom;
Invalidate();
}
#endregion
}
///
/// 微调类
///
public class FineTuningRect
{
public PicExControl FatherControl;
private const int SizeNodeRect = 10;
public Rectangle GetRectByF(RectangleF rectf)
{
return new Rectangle((int)rectf.X, (int)rectf.Y, (int)rectf.Width, (int)rectf.Height);
}
private RectangleF GetRect(PosSizableRect p, PointF luPointF, PointF rbPointF)
{
switch (p)
{
//// 点
case PosSizableRect.LeftUp:
return new RectangleF(luPointF.X - SizeNodeRect / 2, luPointF.Y - SizeNodeRect / 2, SizeNodeRect, SizeNodeRect);
case PosSizableRect.LeftBottom:
return new RectangleF(luPointF.X - SizeNodeRect / 2, rbPointF.Y - SizeNodeRect / 2, SizeNodeRect, SizeNodeRect);
case PosSizableRect.RightUp:
return new RectangleF(rbPointF.X - SizeNodeRect / 2, luPointF.Y - SizeNodeRect / 2, SizeNodeRect, SizeNodeRect);
case PosSizableRect.RightBottom:
return new RectangleF(rbPointF.X - SizeNodeRect / 2, rbPointF.Y - SizeNodeRect / 2, SizeNodeRect, SizeNodeRect);
case PosSizableRect.TopIn:
return new RectangleF(luPointF.X + (rbPointF.X - luPointF.X) / 6 - SizeNodeRect / 2, luPointF.Y - SizeNodeRect / 2, (rbPointF.X - luPointF.X) / 3, SizeNodeRect);
case PosSizableRect.ButtonIn:
return new RectangleF(luPointF.X + (rbPointF.X - luPointF.X) / 6 - SizeNodeRect / 2, rbPointF.Y - SizeNodeRect / 2, (rbPointF.X - luPointF.X) / 3, SizeNodeRect);
//// 线
case PosSizableRect.LeftMiddle:
return new RectangleF(luPointF.X, luPointF.Y, SizeNodeRect, rbPointF.Y - luPointF.Y);
case PosSizableRect.UpMiddle:
return new RectangleF(luPointF.X, luPointF.Y, rbPointF.X - luPointF.X, SizeNodeRect);
case PosSizableRect.RightMiddle:
return new RectangleF(rbPointF.X, luPointF.Y, SizeNodeRect, rbPointF.Y - luPointF.Y);
case PosSizableRect.BottomMiddle:
return new RectangleF(luPointF.X, rbPointF.Y, rbPointF.X - luPointF.X, SizeNodeRect);
default:
return new RectangleF();
}
}
public PosSizableRect GetNodeSelectable(Point p, PointF luPointF, PointF rbPointF)
{
foreach (PosSizableRect r in Enum.GetValues(typeof(PosSizableRect)))
{
if (r == PosSizableRect.LeftMiddle || r == PosSizableRect.UpMiddle || r == PosSizableRect.RightMiddle ||
r == PosSizableRect.BottomMiddle)
continue;
if (GetRect(r, luPointF, rbPointF).Contains(p))
{
return r;
}
}
foreach (PosSizableRect r in Enum.GetValues(typeof(PosSizableRect)))
{
if (GetRect(r, luPointF, rbPointF).Contains(p))
{
return r;
}
}
return PosSizableRect.None;
}
public Cursor GetCursor(PosSizableRect r)
{
switch (r)
{
case PosSizableRect.LeftUp:
return Cursors.SizeNWSE;
case PosSizableRect.LeftMiddle:
return Cursors.SizeWE;
case PosSizableRect.LeftBottom:
return Cursors.SizeNESW;
case PosSizableRect.BottomMiddle:
return Cursors.SizeNS;
case PosSizableRect.RightUp:
return Cursors.SizeNESW;
case PosSizableRect.RightBottom:
return Cursors.SizeNWSE;
case PosSizableRect.RightMiddle:
return Cursors.SizeWE;
case PosSizableRect.UpMiddle:
return Cursors.SizeNS;
case PosSizableRect.TopIn:
return Cursors.SizeAll;
case PosSizableRect.ButtonIn:
return Cursors.SizeAll;
default:
return Cursors.Default;
}
}
}
public enum TreatmentType
{
Zoom,
Draw,
FineTuring,
None
}
public enum PosSizableRect
{
UpMiddle,
LeftMiddle,
LeftBottom,
LeftUp,
RightUp,
RightMiddle,
RightBottom,
BottomMiddle,
None,
TopIn,
ButtonIn
};
}