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 }; }