using DevExpress.XtraEditors;
using System.Data;
namespace Yw.WinFrmUI.Phart
{
public partial class PumpPictureBoxCtrl : DevExpress.XtraEditors.XtraUserControl
{
public PumpPictureBoxCtrl()
{
InitializeComponent();
this.gridView1.SetDefaultEditView();
this.colDelete.OptionsColumn.AllowEdit = false;
this.colDelete.OptionsColumn.ReadOnly = false;
this.gridView1.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
}
#region 页面类
protected class CurrentViewModel
{
public CurrentViewModel() { }
public CurrentViewModel(Yw.Geometry.Point2d rhs)
{
this.X = rhs.X;
this.Y = rhs.Y;
}
public CurrentViewModel(double x, double y, int xp, int yp)
{
this.X = x;
this.Y = y;
this.Xpic = xp;
this.Ypic = yp;
}
public double X { get; set; }
public double Y { get; set; }
public int Xpic { get; set; }
public int Ypic { get; set; }
}
#endregion
#region 变量
///
/// 有效范围
///
private Rectangle? _rect;//矩形
///
/// 是否正在获取等效线
///
private bool _isCaptureEuqualCurve = false;
///
/// 是否打点等效线
///
private bool _isCaputueEtaPtInEqupCurve = false;
///
/// 是否打点等效线,产生流量扬程(原水,五号沟泵站金海支线 是这个情况)
///
public bool IsCaputueEtaPtInEqupCurve
{
set
{
_isCaputueEtaPtInEqupCurve = value;
}
}
///
/// 捕捉曲线类型
///
private Yw.Ahart.eCurveType _currentCaptureCruve = Yw.Ahart.eCurveType.QH;
///
/// 当前捕捉曲线类型
///
public Yw.Ahart.eCurveType CurrentCaptureCruve
{
get => _currentCaptureCruve;
set => _currentCaptureCruve = value;
}
///
/// 流量单位 (默认m3/h)
///
private Unit.eUnitQ _unitQ = Unit.eUnitQ.M3H;
///
/// 流量单位 (默认m3/h)
///
public Unit.eUnitQ UnitQ
{
get => _unitQ;
set => _unitQ = value;
}
private bool _isSelBoundary;
///
/// 允许设置有效范围
///
public bool IsSelBoundary
{
get
{
return _isSelBoundary;
}
set
{
_isSelBoundary = value;
}
}
private bool _isPickPoint;
///
/// 允许获取点
///
public bool IsPickPoint
{
get
{
return _isPickPoint;
}
set
{
_isPickPoint = value;
}
}
#endregion
#region 事件
///
/// 刷新曲线点事件
///
public event Action> ReloadPickPointsEvent;
///
/// 刷新框选范围事件
///
public event Action ReloadBoundaryEvent;
#endregion
// 曲线图表坐标
public double ChartMinX = 0, ChartMaxX = 0;
public double ChartMinY = 0, ChartMaxY = 0;
///
/// 绑定数据列表
///
private List _allClickPoints;
//
/// 绑定数据
///
public void SetBindingData(string path)
{
if (!System.IO.File.Exists(path))
return;
this.pictureBox1.Image = Image.FromFile(path);
_rect = null;
_allClickPoints = new List();
this.bindingSource1.DataSource = _allClickPoints;
}
///
/// 设置图片显示方式
///
public void SetPictureSizeMode(PictureBoxSizeMode sizeMode)
{
this.pictureBox1.SizeMode = sizeMode;
}
#region 选取点并绘制曲线
///
/// 开始获取点
///
public void StartPickPoint()
{
_isPickPoint = true;
}
///
/// 结束选取点
///
public void EndPickPoint()
{
_isPickPoint = false;
}
///
/// 清除选取点
///
public void ClearPickPoint()
{
if (XtraMessageBox.Show("是否清空点?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
return;
_allClickPoints.Clear();
ReloadPickPoints();
DrawPictureShape();
}
///
/// 刷新界面
///
public void RefreshPictureShape(List points = null, Rectangle? picRect = null)
{
_rect = picRect;
if (_rect == null)
{
this.pictureBox1.Invalidate();
return;
}
var rect = _rect.Value;
_allClickPoints.Clear();
if (points != null && points.Any())
foreach (var item in points)
_allClickPoints.Add(new CurrentViewModel(item));
ReloadPickPoints();
foreach (var row in _allClickPoints)
{
double ptX = row.X;
double ptY = row.Y;
int rX = 0, rY = 0;
if (Math.Abs(ptX - ChartMinX) < 0.01)
{
rX = rect.Left;//防止分母为0
}
else
{
rX = (int)(rect.Left + (rect.Right - rect.Left) / (ChartMaxX - ChartMinX) * (ptX - ChartMinX));
}
if (Math.Abs(ptY - ChartMaxY) < 0.01)
{
rY = rect.Top; //防止分母为0
}
else
{
rY = (int)(rect.Top - (rect.Bottom - rect.Top) / (ChartMaxY - ChartMinY) * (ptY - ChartMaxY));
}
row.Xpic = rX;
row.Ypic = rY;
};
DrawPictureShape();
}
#endregion
#region Draw Picture
///
/// 绘图
///
public void DrawPictureShape()
{
try
{
var list = _allClickPoints;
this.pictureBox1.Refresh();
var picPoints = new List();
using (Graphics g = this.pictureBox1.CreateGraphics())
{
//绘制边框
if (_rect != null)
{
using (Pen pen = new Pen(Color.Red, 3))
{
g.DrawRectangle(pen, _rect.Value);
}
}
//绘制点
if (list != null && list.Any())
{
var num = 5;
foreach (var row in list)
{
g.DrawLine(new Pen(Color.Black, 3), row.Xpic - num, row.Ypic + num, row.Xpic + num, row.Ypic - num);
g.DrawLine(new Pen(Color.Black, 3), row.Xpic - num, row.Ypic - num, row.Xpic + num, row.Ypic + num);
picPoints.Add(new Yw.Geometry.Point2d(row.Xpic, row.Ypic));
}
//绘制线
if (list.Count >= 4 && !_isCaptureEuqualCurve)
{
//if (_currentCaptureCruveFitType == AStation.Curve.eFitType.ThroughPoint)
// DrawThrountPoint(picPoints, 0.5f);
//else
DrawFitPoint(picPoints, 0.5f);
}
}
}
}
catch (Exception)
{
throw;
}
}
///
/// 画点和线(拟合)
///
/// 图片点
///
private void DrawFitPoint(List picPoints, float tension)
{
if (picPoints == null || picPoints.Count < 4)
return;
var fitPoints = picPoints.GetFitPointList();
if (fitPoints == null || fitPoints.Count < 4)
return;
var resultPts = new List();
fitPoints.ForEach(x => resultPts.Add(new Point((int)x.X, (int)x.Y)));
using (Graphics g = this.pictureBox1.CreateGraphics())
using (Pen pen = new Pen(Color.Red, 3))
g.DrawCurve(pen, resultPts.ToArray(), tension);
}
///
/// 绘制通过点
///
/// 图片点
///
private void DrawThrountPoint(List picPoints, float tension)
{
if (picPoints == null || picPoints.Count < 4)
return;
var resultPts = new List();
picPoints.ForEach(x => resultPts.Add(new PointF((float)x.X, (float)x.Y)));
using (Graphics g = this.pictureBox1.CreateGraphics())
using (Pen pen = new Pen(Color.Red, 3))
g.DrawCurve(pen, resultPts.ToArray(), tension);
}
#endregion
#region 图片区域的鼠标操作
private Point? _startPoint;//开始点
///
/// 开始选取范围
///
public void StartSelectionRange()
{
this.pictureBox1.Invalidate();
_rect = null;
_startPoint = null;
_isSelBoundary = true;
this.Cursor = System.Windows.Forms.Cursors.Cross;
this.DoubleBuffered = true;
if (_allClickPoints != null)
{
_allClickPoints.Clear();
this.ReloadBoundaryEvent?.Invoke(_rect);
ReloadPickPoints();
}
}
///
/// 鼠标按下
///
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (_isSelBoundary)
{
_startPoint = e.Location;
}
else if (_isPickPoint)
{
int rX = e.X;
int rY = e.Y;
//精度
int xJd = 1, yJd = 1;
if (Math.Abs(ChartMaxX - ChartMinX) < 12)
xJd = 2;
if (Math.Abs(ChartMaxX - ChartMinX) < 1)
xJd = 3;
double ptX = 0;
if (rX == _rect.Value.Left)
{
ptX = ChartMinX;
}
else
{
ptX = UtilsHelper.Regulate(ChartMinX + (ChartMaxX - ChartMinX) / (_rect.Value.Right - _rect.Value.Left) * (rX - _rect.Value.Left), xJd);
}
if (ptX < 0)
ptX = 0;
Yw.Geometry.Point2d picPoint = null;
if (!_isCaputueEtaPtInEqupCurve)
{
if (Math.Abs(ChartMaxY - ChartMinY) < 12)
yJd = 2;
if (Math.Abs(ChartMaxY - ChartMinY) < 2)
yJd = 3;
double ptY = 0;
if (rY <= _rect.Value.Top)
{
ptY = ChartMaxY;
}
else
{
ptY = UtilsHelper.Regulate(ChartMaxY + (ChartMinY - ChartMaxY) / (_rect.Value.Bottom - _rect.Value.Top) * (rY - _rect.Value.Top), yJd);
}
if (ptY < 0)
ptY = 0;
_allClickPoints.Add(new CurrentViewModel(ptX, ptY, rX, rY));
picPoint = new Yw.Geometry.Point2d(ptX, ptY);
}
else
{
var dlg = new PickEqupPointDlg();
dlg.ReloadDataEvent += (ptY) =>
{
_allClickPoints.Add(new CurrentViewModel(ptX, ptY, rX, rY));
picPoint = new Yw.Geometry.Point2d(ptX, ptY);
return true;
};
dlg.ShowDialog();
}
ReloadPickPoints();
DrawPictureShape();
}
}
}
///
/// 鼠标移动
///
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (_isSelBoundary && _startPoint != null)
{
_rect = GetRectangle(_startPoint.Value, e.Location);
this.pictureBox1.Invalidate();
}
}
//获取矩形
private Rectangle GetRectangle(Point p1, Point p2)
{
int x = p1.X < p2.X ? p1.X : p2.X;
int y = p1.Y < p2.Y ? p1.Y : p2.Y;
int width = Math.Abs(p1.X - p2.X);
int height = Math.Abs(p1.Y - p2.Y);
return new Rectangle(x, y, width, height);
}
///
/// 鼠标松开
///
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (_isSelBoundary)
{
_startPoint = null;
_isSelBoundary = false;
this.Cursor = System.Windows.Forms.Cursors.Arrow;
this.DoubleBuffered = false;
this.ReloadBoundaryEvent?.Invoke(_rect);
}
}
///
/// 绘制
///
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_rect != null && _isSelBoundary)
{
using (Pen pen = new Pen(Color.Red, 3))
{
e.Graphics.DrawRectangle(pen, _rect.Value);
}
}
}
#endregion
#region gridView
//删除点
private void gridView1_RowCellClick(object sender, DevExpress.XtraGrid.Views.Grid.RowCellClickEventArgs e)
{
if (e.Column == this.colDelete)
{
if (this.gridView1.GetRow(e.RowHandle) is CurrentViewModel row)
{
_allClickPoints.Remove(row);
ReloadPickPoints();
DrawPictureShape();
}
}
}
#endregion
///
/// 得到图片曲线上的点
///
/// 返回获取点
///
public bool GetPicPoints(out List clickPoints)
{
clickPoints = null;
if (_allClickPoints == null)
return false;
clickPoints = _allClickPoints.Select(x => new Yw.Geometry.Point2d(x.X, x.Y)).ToList();
List curvePoints = null;
if (!_isCaptureEuqualCurve)
{
curvePoints = clickPoints.GetFitPointList(12);
curvePoints?.OrderBy(x => x.X);
}
else
{
/*
* 暂时只用完全通过点的方法,因为有时垂直很厉害时DrawFitPoint现状不好看
* 有增减性 就可以用拟合的方法
* 只用通过点的方法
*/
curvePoints = clickPoints;
}
_allClickPoints.Clear();
ReloadPickPoints();
DrawPictureShape();
return true;
}
//刷新抓起点列表
private void ReloadPickPoints()
{
this.bindingSource1.ResetBindings(false);
var pickPoints = _allClickPoints?.Select(x => new Yw.Geometry.Point2d(x.X, x.Y)).ToList();
this.ReloadPickPointsEvent?.Invoke(pickPoints);
}
}
}