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 变量
|
|
/// <summary>
|
/// 有效范围
|
/// </summary>
|
private Rectangle? _rect;//矩形
|
|
/// <summary>
|
/// 是否正在获取等效线
|
/// </summary>
|
private bool _isCaptureEuqualCurve = false;
|
|
/// <summary>
|
/// 是否打点等效线
|
/// </summary>
|
private bool _isCaputueEtaPtInEqupCurve = false;
|
|
/// <summary>
|
/// 是否打点等效线,产生流量扬程(原水,五号沟泵站金海支线 是这个情况)
|
/// </summary>
|
public bool IsCaputueEtaPtInEqupCurve
|
{
|
set
|
{
|
_isCaputueEtaPtInEqupCurve = value;
|
}
|
}
|
|
/// <summary>
|
/// 捕捉曲线类型
|
/// </summary>
|
private Yw.Ahart.eCurveType _currentCaptureCruve = Yw.Ahart.eCurveType.QH;
|
|
/// <summary>
|
/// 当前捕捉曲线类型
|
/// </summary>
|
public Yw.Ahart.eCurveType CurrentCaptureCruve
|
{
|
get => _currentCaptureCruve;
|
set => _currentCaptureCruve = value;
|
}
|
|
|
|
/// <summary>
|
/// 流量单位 (默认m3/h)
|
/// </summary>
|
private Unit.eUnitQ _unitQ = Unit.eUnitQ.M3H;
|
|
/// <summary>
|
/// 流量单位 (默认m3/h)
|
/// </summary>
|
public Unit.eUnitQ UnitQ
|
{
|
get => _unitQ;
|
set => _unitQ = value;
|
}
|
|
|
private bool _isSelBoundary;
|
|
/// <summary>
|
/// 允许设置有效范围
|
/// </summary>
|
public bool IsSelBoundary
|
{
|
get
|
{
|
return _isSelBoundary;
|
}
|
set
|
{
|
_isSelBoundary = value;
|
|
}
|
}
|
|
private bool _isPickPoint;
|
|
/// <summary>
|
/// 允许获取点
|
/// </summary>
|
public bool IsPickPoint
|
{
|
get
|
{
|
return _isPickPoint;
|
}
|
set
|
{
|
_isPickPoint = value;
|
}
|
}
|
|
|
#endregion
|
|
#region 事件
|
|
/// <summary>
|
/// 刷新曲线点事件
|
/// </summary>
|
public event Action<List<Yw.Geometry.Point2d>> ReloadPickPointsEvent;
|
|
/// <summary>
|
/// 刷新框选范围事件
|
/// </summary>
|
public event Action<Rectangle?> ReloadBoundaryEvent;
|
|
#endregion
|
|
// 曲线图表坐标
|
public double ChartMinX = 0, ChartMaxX = 0;
|
public double ChartMinY = 0, ChartMaxY = 0;
|
|
/// <summary>
|
/// 绑定数据列表
|
/// </summary>
|
private List<CurrentViewModel> _allClickPoints;
|
|
// <summary>
|
/// 绑定数据
|
/// </summary>
|
public void SetBindingData(string path)
|
{
|
if (!System.IO.File.Exists(path))
|
return;
|
this.pictureBox1.Image = Image.FromFile(path);
|
|
_rect = null;
|
_allClickPoints = new List<CurrentViewModel>();
|
this.bindingSource1.DataSource = _allClickPoints;
|
}
|
|
/// <summary>
|
/// 设置图片显示方式
|
/// </summary>
|
public void SetPictureSizeMode(PictureBoxSizeMode sizeMode)
|
{
|
this.pictureBox1.SizeMode = sizeMode;
|
}
|
|
|
#region 选取点并绘制曲线
|
|
/// <summary>
|
/// 开始获取点
|
/// </summary>
|
public void StartPickPoint()
|
{
|
_isPickPoint = true;
|
}
|
|
/// <summary>
|
/// 结束选取点
|
/// </summary>
|
public void EndPickPoint()
|
{
|
_isPickPoint = false;
|
}
|
|
/// <summary>
|
/// 清除选取点
|
/// </summary>
|
public void ClearPickPoint()
|
{
|
if (XtraMessageBox.Show("是否清空点?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
|
return;
|
_allClickPoints.Clear();
|
ReloadPickPoints();
|
DrawPictureShape();
|
}
|
|
/// <summary>
|
/// 刷新界面
|
/// </summary>
|
public void RefreshPictureShape(List<Yw.Geometry.Point2d> 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
|
|
/// <summary>
|
/// 绘图
|
/// </summary>
|
public void DrawPictureShape()
|
{
|
try
|
{
|
var list = _allClickPoints;
|
this.pictureBox1.Refresh();
|
var picPoints = new List<Yw.Geometry.Point2d>();
|
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;
|
}
|
}
|
|
/// <summary>
|
/// 画点和线(拟合)
|
/// </summary>
|
/// <param name="picPoints">图片点</param>
|
/// <param name="tension"></param>
|
private void DrawFitPoint(List<Yw.Geometry.Point2d> 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<Point>();
|
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);
|
}
|
|
/// <summary>
|
/// 绘制通过点
|
/// </summary>
|
/// <param name="picPoints">图片点</param>
|
/// <param name="tension"></param>
|
private void DrawThrountPoint(List<Yw.Geometry.Point2d> picPoints, float tension)
|
{
|
if (picPoints == null || picPoints.Count < 4)
|
return;
|
var resultPts = new List<PointF>();
|
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;//开始点
|
|
/// <summary>
|
/// 开始选取范围
|
/// </summary>
|
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();
|
}
|
}
|
|
/// <summary>
|
/// 鼠标按下
|
/// </summary>
|
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();
|
}
|
}
|
}
|
|
/// <summary>
|
/// 鼠标移动
|
/// </summary>
|
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);
|
}
|
|
/// <summary>
|
/// 鼠标松开
|
/// </summary>
|
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);
|
}
|
}
|
|
|
|
|
/// <summary>
|
/// 绘制
|
/// </summary>
|
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
|
|
/// <summary>
|
/// 得到图片曲线上的点
|
/// </summary>
|
/// <param name="clickPoints">返回获取点</param>
|
/// <returns></returns>
|
public bool GetPicPoints(out List<Yw.Geometry.Point2d> clickPoints)
|
{
|
clickPoints = null;
|
if (_allClickPoints == null)
|
return false;
|
|
clickPoints = _allClickPoints.Select(x => new Yw.Geometry.Point2d(x.X, x.Y)).ToList();
|
|
List<Yw.Geometry.Point2d> 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);
|
}
|
|
}
|
}
|