using DevExpress.Utils;
using DevExpress.Utils.Drawing;
using DevExpress.XtraCharts;
using SqlSugar;
using System.Text;
namespace Yw.WinFrmUI.Phart
{
///
/// 泵并联图表
///
public partial class PumpParallelChart : DevExpress.XtraEditors.XtraUserControl
{
public PumpParallelChart()
{
InitializeComponent();
InitialChart();
this.chartControl1.RuntimeHitTesting = true;
}
#region Private Variable
private List _vm_list = new List();
private readonly string _tag_qh = "QH", _tag_qe = "QE", _tag_qp = "QP";
private XYDiagram _diagram;
private XYDiagramDefaultPane _default_pane;
private XYDiagramPane _bottom_pane;
private AxisX _axis_x_flow;
private AxisY _axis_y_head;
private SecondaryAxisY _axis_y_eff, _axis_y_power;
private ConstantLine _const_line_x;
private TextAnnotation _anno_txt_query_info;
private PumpCoordinate _coordinate;
private bool _qe_visible = true;
private bool _qp_visible = true;
private bool _equip_visible = true;
private Yw.Geometry.CubicSpline2d _equip_line = null;
private Yw.Geometry.Point2d _equip_pt = null;
private Yw.Geometry.Point2d _equip_sect_pt=null;
private bool _initial_data = false;
private PumpParallelViewModel _vm = null;
#endregion
#region Public Variable
///
/// 工作线是否可见
///
public bool LineVisible
{
get => _line_visible;
set
{
_line_visible = value;
this.barCekLineVisible.Checked = _line_visible;
this.barBtnSetAxisQValue.Enabled = _line_visible;
}
}
private bool _line_visible = false;
///
/// 曲线名是否可见
///
public bool LineNameVisible
{
get => _line_name_visible;
set
{
_line_name_visible = value;
this.barCekCurveNameVisible.Checked = _line_name_visible;
}
}
private bool _line_name_visible = true;
#endregion
#region Public Evnet
///
/// 坐标变换事件
///
public event Action CoordinateChangedEvent = null;
///
/// 并联状态变换事件
///
public event Action ParallelStatusChangedEvent = null;
///
/// 查询点变换事件
///
public event Action> QueryPointChangedEvent = null;
///
/// 设计点变换事件
///
public event Action> DesignPointChangedEvent = null;
#endregion
#region Initial
///
/// 初始化图表
///
private void InitialChart()
{
this.chartControl1.SetChartDisplay();
this.chartControl1.Legend.Direction = DevExpress.XtraCharts.LegendDirection.TopToBottom;
_diagram = (XYDiagram)this.chartControl1.Diagram;
_default_pane = _diagram.DefaultPane;
_bottom_pane = (XYDiagramPane)_diagram.FindPaneByName("BottomPanel");
_axis_x_flow = _diagram.AxisX;
_axis_x_flow.SetAxisXQDisplay();
_axis_y_head = _diagram.AxisY;
_axis_y_head.SetAxisYQHDisplay();
_axis_y_eff = _diagram.SecondaryAxesY.GetAxisByName("AxisYQE");
_axis_y_eff.SetSecondaryAxisYQEDisplay();
_axis_y_eff.Alignment = AxisAlignment.Far;
_axis_y_power = _diagram.SecondaryAxesY.GetAxisByName("AxisYQP");
_axis_y_power.SetSecondaryAxisYQPDisplay();
_const_line_x = (ConstantLine)_diagram.AxisX.ConstantLines.GetElementByName("WorkPointLine");
_const_line_x.SetWorkPointLineDisplay();
_anno_txt_query_info = this.chartControl1.AnnotationRepository[0] as TextAnnotation;
_anno_txt_query_info.SetTextAnnoWorkPointDisplay();
_axis_x_flow.Visibility = DefaultBoolean.False;
_axis_x_flow.GridLines.Visible = false;
_axis_y_head.Visibility = DefaultBoolean.False;
_axis_y_head.GridLines.Visible = false;
_axis_y_eff.Visibility = DefaultBoolean.False;
_axis_y_eff.GridLines.Visible = false;
_axis_y_power.Visibility = DefaultBoolean.False;
_axis_y_power.GridLines.Visible = false;
_const_line_x.Visible = false;
_anno_txt_query_info.Visible = false;
this.chartControl1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chartControl1_MouseMove);
this.chartControl1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.chartControl1_MouseUp);
this.chartControl1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chartControl1_MouseDown);
this.chartControl1.Resize += new System.EventHandler(this.chartControl1_Resize);
this.chartControl1.MouseDoubleClick += ChartControl1_MouseDoubleClick;
this.chartControl1.CustomPaint += ChartControl1_CustomPaint;
}
///
/// 图表重绘
///
private void ChartControl1_CustomPaint(object sender, CustomPaintEventArgs e)
{
if (e is not DXCustomPaintEventArgs dx_args)
return;
if (_vm_list == null || !_vm_list.Any())
return;
if (_equip_line != null && _equip_sect_pt != null && _equip_visible)
{
using Pen pen = new(Color.Black, 2);
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDotDot;
DrawEquipPoint(dx_args.Cache, pen, _equip_sect_pt, _vm.CurrentCurveQE, _vm.CurrentCurveQP);
DrawEquipLine(dx_args.Cache, pen, _equip_line);
}
foreach (var vm in _vm_list)
{
if (!vm.CurrentExtendFlow.HasValue)
continue;
using Pen pen = new(Color.White, 2);
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
var max_flow = vm.CurrentExtendFlow.Value;
DrawExpandLine(dx_args.Cache, pen, _axis_y_head, vm.CurrentCurveQH, max_flow);
if (_qe_visible)
{
DrawExpandLine(dx_args.Cache, pen, _axis_y_eff, vm.CurrentCurveQE, max_flow);
}
if (_qp_visible)
{
DrawExpandLine(dx_args.Cache, pen, _axis_y_power, vm.CurrentCurveQP, max_flow);
}
}
}
private void DrawExpandLine(GraphicsCache cache, Pen pen, AxisYBase axis_y, Yw.Geometry.CubicSpline2d line, double x_max)
{
var pt_list = line.GetPointList(100).ToList();
pt_list = pt_list?.Where(x => x.X > x_max).ToList();
if (pt_list == null || !pt_list.Any())
return;
if (pt_list.Count == 1)
{
var y = line.GetPointYUnlimited(x_max);
pt_list.Add(new Yw.Geometry.Point2d(x_max, y));
}
var pt_f_list = new List();
foreach (var pt in pt_list)
{
var x = pt.X;
var y = pt.Y;
var dg_pt = _diagram.DiagramToPoint(x, y, _axis_x_flow, axis_y);
pt_f_list.Add(new PointF(dg_pt.Point.X, dg_pt.Point.Y));
}
using var path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddCurve(pt_f_list.ToArray());
cache.DrawPath(pen, path);
}
private void DrawEquipLine(GraphicsCache cache, Pen pen, Yw.Geometry.CubicSpline2d qh)
{
if (qh == null)
return;
var pt_list = qh.GetPointList().ToArray();
var pt_f_list = new List();
foreach (var pt in pt_list)
{
var x = pt.X;
var y = pt.Y;
var c_pt = _diagram.DiagramToPoint(x, y, _axis_x_flow, _axis_y_head);
pt_f_list.Add(new PointF(c_pt.Point.X, c_pt.Point.Y));
}
using var path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddCurve(pt_f_list.ToArray());
cache.DrawPath(pen, path);
}
private void DrawEquipPoint(GraphicsCache cache, Pen pen, Yw.Geometry.Point2d qh_sect_pt, Yw.Geometry.CubicSpline2d qe, Yw.Geometry.CubicSpline2d qp)
{
if (qh_sect_pt == null)
return;
var offset_size = 10;
var qh_x = qh_sect_pt.X;
var qh_pt = _diagram.DiagramToPoint(qh_sect_pt.X, qh_sect_pt.Y, _axis_x_flow, _axis_y_head);
var qh_pt_x = qh_pt.Point.X;
var qh_pt_y = qh_pt.Point.Y;
cache.DrawLine(pen, new Point(qh_pt_x, qh_pt_y - offset_size), new Point(qh_pt_x, qh_pt_y + offset_size));
if (qe != null && _qe_visible)
{
var qe_y = qe.GetPointY(qh_x);
var qe_pt = _diagram.DiagramToPoint(qh_x, qe_y, _axis_x_flow, _axis_y_eff);
var qe_pt_x = qe_pt.Point.X;
var qe_pt_y = qe_pt.Point.Y;
cache.DrawLine(pen, new Point(qe_pt_x, qe_pt_y - offset_size), new Point(qe_pt_x, qe_pt_y + offset_size));
}
if (qp != null && _qp_visible)
{
var qp_y = qp.GetPointY(qh_x);
var qp_pt = _diagram.DiagramToPoint(qh_x, qp_y, _axis_x_flow, _axis_y_power);
var qp_pt_x = qp_pt.Point.X;
var qp_pt_y = qp_pt.Point.Y;
cache.DrawLine(pen, new Point(qp_pt_x, qp_pt_y - offset_size), new Point(qp_pt_x, qp_pt_y + offset_size));
}
}
///
/// 初始化图表数据
///
public void InitialChartData()
{
_initial_data = false;
_coordinate = null;
UpdateChart(false);
}
#endregion
#region Set
///
/// 绑定数据
///
public void SetBindingData(List list)
{
_vm_list = list;
_initial_data = list != null && list.Any();
UpdateChart(true);
}
///
/// 设置设计点
///
public void SetDesignPoint(double pipe_flow, double pipe_head, double? start_head = null)
{
_equip_pt = new Geometry.Point2d(pipe_flow, pipe_head);
_equip_line = null;
_equip_sect_pt = null;
if (_vm == null || (_vm_list == null || !_vm_list.Any()))
{
this.DesignPointChangedEvent?.Invoke(null);
return;
}
start_head ??= _coordinate.DispMinH();
var equip_line = Yw.Geometry.EquipCurveHelper.CalcEquipCurve(_vm.CurrentCurveQH, _equip_pt, start_head.Value, out Yw.Geometry.Point2d sect_pt);
if (equip_line == null || sect_pt == null)
return;
_equip_line = equip_line;
_equip_sect_pt = sect_pt;
var design_pt_list = new List();
foreach (var vm in _vm_list)
{
double flow = 0, head = 0;
double? eff = null, power = null;
flow = sect_pt.X;
head = vm.CurrentCurveQH.GetPointYUnlimited(flow);
if (vm.CurrentCurveQP != null)
{
power = vm.CurrentCurveQP.GetPointYUnlimited(flow);
eff = PumpCalcHelper.CalculateE(flow, head, power.Value);
}
else if (vm.CurrentCurveQE != null)
{
eff = vm.CurrentCurveQE.GetPointYUnlimited(flow);
power = PumpCalcHelper.CalculateP(flow, head, eff.Value);
}
design_pt_list.Add(new PumpDesignPointViewModel
{
Id = vm.Id,
Name = vm.Name,
Q = flow,
H = head,
E = eff,
P = power,
Hz = vm.CurrentHz,
N = vm.CurrentN
});
}
this.DesignPointChangedEvent?.Invoke(design_pt_list);
UpdateChart(true);
}
///
/// 清空曲线
///
public void Clear()
{
_vm_list = new List();
_initial_data = false;
UpdateChart(true);
}
///
/// 更新图表
/// s
public void UpdateChart(bool calc_coordinate = false)
{
CalcSeries();
if (calc_coordinate || _coordinate == null)
{
//不强迫计算,就用上次更新的坐标系
CalcCoordinate();
}
CalcChartAxis();
CalcWorkPointByQ();
CalcTextAnchorPoint();
}
#endregion
#region Calc
private double _min_flow, _max_flow;
private double _max_head = 0, _min_head = 10000;
private double _max_eff = 0, _min_eff = 0;
private double _max_power = 0, _min_power = 1000;
///
/// 计算坐标
///
private void CalcCoordinate()
{
if (_vm_list == null || !_vm_list.Any())
{
//设置成白板坐标
_coordinate = new PumpCoordinate();
_coordinate.GridNumberX = 30;
_coordinate.GridNumberY = 16;
//显示的坐标线号
_coordinate.StartLineNoH = 10;
_coordinate.EndLineNoH = 15;
_coordinate.StartLineNoE = 0;
_coordinate.EndLineNoE = 10;
_coordinate.StartLineNoP = 2;
_coordinate.EndLineNoP = 9;
//坐标最小值和间隔
_coordinate.CoordMinQ = 0; _coordinate.CoordSpaceQ = 1000;
_coordinate.CoordMinH = 10; _coordinate.CoordSpaceH = 100;
_coordinate.CoordMinE = 0; _coordinate.CoordSpaceE = 100;
_coordinate.CoordMinP = 10; _coordinate.CoordSpaceP = 100;
return;
}
_max_flow = 0; _min_flow = 10000;
_max_head = 0; _min_head = 10000;
_max_eff = 0; _min_eff = 0;
_max_power = 0; _min_power = 1000;
double _scaleMinH = 1, _scaleMaxH = 1;
foreach (var vm in _vm_list)
{
var qh_pt_list = vm.CurveQH.GetPointList();
if (vm.CurrentCurveQH != null)
qh_pt_list.AddRange(vm.CurrentCurveQH.GetPointList());
var xxx = qh_pt_list.Select(x => x.X);
var yyy = qh_pt_list.Select(x => x.Y);
_min_flow = Math.Min(_min_flow, xxx.Min());
_max_flow = Math.Max(_max_flow, xxx.Max());
_min_head = Math.Min(_min_head, yyy.Min());
_max_head = Math.Max(_max_head, yyy.Max());
}
foreach (PumpParallelViewModel vm in _vm_list)
{
var qe_pt_list = vm.CurveQE.GetPointList();
if (vm.CurrentCurveQE != null)
qe_pt_list.AddRange(vm.CurrentCurveQE.GetPointList());
var yyy = qe_pt_list.Select(x => x.Y);
_min_eff = Math.Max(_min_eff, yyy.Min());
_max_eff = Math.Max(_max_eff, yyy.Max());
}
foreach (PumpParallelViewModel vm in _vm_list)
{
var qe_pt_list = vm.CurveQP.GetPointList();
if (vm.CurrentCurveQP != null)
qe_pt_list.AddRange(vm.CurrentCurveQP.GetPointList());
var yyy = qe_pt_list.Select(x => x.Y);
_min_power = Math.Min(_min_power, yyy.Min());
_max_power = Math.Max(_max_power, yyy.Max());
}
if (_vm != null)
{
{
var qh_pt_list = _vm.CurveQH.GetPointList();
var xxx = qh_pt_list.Select(x => x.X);
var yyy = qh_pt_list.Select(x => x.Y);
_min_flow = Math.Min(_min_flow, xxx.Min());
_max_flow = Math.Max(_max_flow, xxx.Max());
_min_head = Math.Min(_min_head, yyy.Min());
_max_head = Math.Max(_max_head, yyy.Max());
}
if (_vm.CurveQE != null)
{
var qe_pt_list = _vm.CurveQE.GetPointList();
var yyy = qe_pt_list.Select(x => x.Y);
_min_eff = Math.Max(_min_eff, yyy.Min());
_max_eff = Math.Max(_max_eff, yyy.Max());
}
if (_vm.CurveQP != null)
{
var qp_pt_list = _vm.CurveQP.GetPointList();
var yyy = qp_pt_list.Select(x => x.Y);
_min_power = Math.Min(_min_power, yyy.Min());
_max_power = Math.Max(_max_power, yyy.Max());
}
}
_coordinate = PumpCoordinate.CalcCoordinate(_min_flow,
_max_flow,
_min_head * _scaleMinH,
_max_head * _scaleMaxH,
_min_eff,
_max_eff,
_min_power,
_max_power);
if (_coordinate == null)
return;
if (_coordinate.CoordMinQ + _coordinate.CoordSpaceQ * this._coordinate.GridNumberX < _max_flow * 1.05)
{
_coordinate.GridNumberX++;
}
}
///
/// 计算图表轴
///
private void CalcChartAxis()
{
_axis_x_flow.Visibility = DefaultBoolean.False;
_axis_x_flow.GridLines.Visible = false;
_axis_y_head.Visibility = DefaultBoolean.False;
_axis_y_head.GridLines.Visible = false;
_axis_y_eff.Visibility = DefaultBoolean.False;
_axis_y_eff.GridLines.Visible = false;
_axis_y_power.Visibility = DefaultBoolean.False;
_axis_y_power.GridLines.Visible = false;
_const_line_x.Visible = false;
_bottom_pane.Visibility = ChartElementVisibility.Hidden;
_bottom_pane.Visibility = _qp_visible ? ChartElementVisibility.Visible : ChartElementVisibility.Hidden;
//计算刻度 Q
var axisQLabels = new List();
var disQ = _coordinate.CoordMinQ;
for (int i = 0; i < _coordinate.GridNumberX + 1; i++)
{
axisQLabels.Add(new CustomAxisLabel(disQ.ToString("N0"), disQ));
disQ = disQ + _coordinate.CoordSpaceQ;
}
_axis_x_flow.CustomLabels.Clear();
_axis_x_flow.CustomLabels.AddRange(axisQLabels.ToArray());
_axis_x_flow.Visibility = DefaultBoolean.True;
_axis_x_flow.GridLines.Visible = true;
//计算刻度
var axis_head_labels = new List();
var display_head = _coordinate.CoordMinH + _coordinate.CoordSpaceH * _coordinate.StartLineNoH;
for (int i = _coordinate.StartLineNoH; i < _coordinate.EndLineNoH + 1; i++)
{
axis_head_labels.Add(new CustomAxisLabel(display_head.ToString(), display_head));
display_head = display_head + _coordinate.CoordSpaceH;
}
_axis_y_head.CustomLabels.Clear();
_axis_y_head.CustomLabels.AddRange(axis_head_labels.ToArray());
_axis_y_head.Visibility = DefaultBoolean.True;
_axis_y_head.GridLines.Visible = true;
//效率
if (_max_eff > _min_eff && _qe_visible)
{
//计算刻度
var labels = new List();
var display_eff = _coordinate.CoordMinE + _coordinate.CoordSpaceE * _coordinate.StartLineNoE;
for (int i = _coordinate.StartLineNoE; i < _coordinate.EndLineNoE + 1; i++)
{
labels.Add(new CustomAxisLabel(display_eff.ToString(), display_eff));
display_eff = display_eff + _coordinate.CoordSpaceE;
}
_axis_y_eff.CustomLabels.Clear();
_axis_y_eff.CustomLabels.AddRange(labels.ToArray());
_axis_y_eff.Visibility = DefaultBoolean.True;
_axis_y_eff.GridLines.Visible = true;
}
//功率
if (_max_power > _min_power && _qp_visible)
{
//计算刻度
var labels = new List();
double display_power = _coordinate.CoordMinP + _coordinate.CoordSpaceP * _coordinate.StartLineNoP;
for (int i = _coordinate.StartLineNoP; i < _coordinate.EndLineNoP + 1; i++)
{
labels.Add(new CustomAxisLabel(display_power.ToString(), display_power));
display_power = display_power + _coordinate.CoordSpaceP;
}
_axis_y_power.CustomLabels.Clear();
_axis_y_power.CustomLabels.AddRange(labels.ToArray());
_axis_y_power.Visibility = DefaultBoolean.True;
_axis_y_power.GridLines.Visible = true;
}
var min_flow = _coordinate.CoordMinQ;
var max_flow = _coordinate.DispMaxQ();
_axis_x_flow.SetAxisRange(min_flow, max_flow);
var grid_count_head = _coordinate.EndLineNoH - _coordinate.StartLineNoH;
var grid_count_eff = _coordinate.EndLineNoE - _coordinate.StartLineNoE;
int grid_count_up = Math.Max(grid_count_head, grid_count_eff);
if (_qe_visible)
{
grid_count_up += 2;//多两条
}
var max_axis_head = _coordinate.CoordMinH + _coordinate.EndLineNoH * _coordinate.CoordSpaceH;
var min_axis_head = max_axis_head - grid_count_up * _coordinate.CoordSpaceH;
_axis_y_head.SetAxisRange(min_axis_head, max_axis_head);
var min_axis_eff = _coordinate.CoordMinE + _coordinate.StartLineNoE * _coordinate.CoordSpaceE;
var max_axis_eff = min_axis_eff + grid_count_up * _coordinate.CoordSpaceE;
_axis_y_eff.SetAxisRange(min_axis_eff, max_axis_eff);
var grid_count_power = _coordinate.EndLineNoP - _coordinate.StartLineNoP;
var min_axis_power = _coordinate.CoordMinP + _coordinate.StartLineNoP * _coordinate.CoordSpaceP;
var max_axis_power = min_axis_power + grid_count_power * _coordinate.CoordSpaceP;
_axis_y_power.SetAxisRange(min_axis_power, max_axis_power);
}
///
/// 计算系列
///
private void CalcSeries()
{
this.chartControl1.BeginInit();
this.chartControl1.Series.Clear();
var annotation_count = this.chartControl1.AnnotationRepository.Count;
for (int i = annotation_count - 1; i > 0; i--)
{
if (i == 0)
break;
this.chartControl1.AnnotationRepository.RemoveAt(i);
}
this.chartControl1.Legend.CustomItems.Clear();
if (_vm_list.Count > 0)
{
foreach (var vm in _vm_list)
{
CreateLineSeries(vm);
}
CalcParallelSeries(_vm_list.Count >= 2 ? _vm_list : null);
}
this.chartControl1.EndInit();
}
///
/// 计算并联线
///
private void CalcParallelSeries(List list)
{
_vm = null;
this.barCekLineVisible.Enabled = false;
if (list == null || !list.Any())
{
LineVisible = false;
this.ParallelStatusChangedEvent?.Invoke(false, "并联失败!");
return;
}
var helper = new Yw.WinFrmUI.Phart.PumpParallelConnectionHelper();
foreach (var item in list)
{
if (item.CurrentCurveQH == null)
continue;
if (item.CurrentCurveQP == null)
continue;
helper.Add(item.CurrentCurveQH, item.CurrentCurveQP);
}
List calc_pt_qh_list;
List calc_pt_qe_list;
List calc_pt_qp_list;
var calc_staus = helper.CalculateParallel(out calc_pt_qh_list, out calc_pt_qe_list, out calc_pt_qp_list);
if (!calc_staus || calc_pt_qh_list.Count < 4)
{
LineVisible = false;
this.ParallelStatusChangedEvent?.Invoke(false, "并联失败!");
return;
}
var qh = new Yw.Geometry.CubicSpline2d(calc_pt_qh_list);
var qe = new Yw.Geometry.CubicSpline2d(calc_pt_qe_list);
var qp = new Yw.Geometry.CubicSpline2d(calc_pt_qp_list);
_vm = new Yw.WinFrmUI.Phart.PumpParallelViewModel();
_vm.Id = "parallel";
_vm.Name = "并联线";
_vm.CurrentColor = Color.Black;
_vm.CurveQH = qh;
_vm.CurveQE = qe;
_vm.CurveQP = qp;
_vm.CurrentCurveQH = qh;
_vm.CurrentCurveQE = qe;
_vm.CurrentCurveQP = qp;
_vm.CurveQH = qh;
_vm.CurveQE = qe;
_vm.CurveQP = qp;
CreateLineSeries(_vm);
this.barCekLineVisible.Enabled = true;
this.ParallelStatusChangedEvent?.Invoke(true, "并联成功!");
}
///
/// 计算注释定位
///
private void CalcTextAnchorPoint()
{
var x = this.chartControl1.Location.X + this.chartControl1.Width;
var y = this.chartControl1.Location.Y;
(_anno_txt_query_info.AnchorPoint as ChartAnchorPoint).X = x;
(_anno_txt_query_info.AnchorPoint as ChartAnchorPoint).Y = y;
}
///
/// 计算工作点
///
public void CalcWorkPointByQ(double? x_flow = null)
{
if (!_line_visible)
{
_const_line_x.Visible = false;
_const_line_x.Title.Visible = false;
_anno_txt_query_info.Visible = false;
return;
}
else
{
_const_line_x.Visible = true;
_const_line_x.Title.Visible = true;
_anno_txt_query_info.Visible = true;
}
if (_vm==null)
return;
if (_vm_list == null || !_vm_list.Any())
return;
var min_flow = _vm.CurveQH.MinX;
var max_flow = _vm.CurveQH.MaxX;
x_flow ??= _equip_pt?.X ?? max_flow *0.8;
if (x_flow < min_flow || x_flow > max_flow)
return;
double paralle_flow = 0, paralle_head = 0;
double? paralle_eff = null, paralle_power = null;
paralle_flow = x_flow.Value;
paralle_head = _vm.CurrentCurveQH.GetPointYUnlimited(paralle_flow);
if (_vm.CurrentCurveQP != null)
{
paralle_power = _vm.CurrentCurveQP.GetPointYUnlimited(paralle_flow);
paralle_eff = PumpCalcHelper.CalculateE(paralle_flow, paralle_head, paralle_power.Value);
}
else if (_vm.CurrentCurveQE != null)
{
paralle_eff = _vm.CurrentCurveQE.GetPointYUnlimited(paralle_flow);
paralle_power = PumpCalcHelper.CalculateP(paralle_flow, paralle_head, paralle_eff.Value);
}
var query_pt_list = new List();
foreach (var vm in _vm_list)
{
double flow = 0, head = 0;
double? eff = null, power = null;
head = paralle_head;
flow = vm.CurrentCurveQH.GetPointsX(head).LastOrDefault();
if (vm.CurrentCurveQP != null)
{
power = vm.CurrentCurveQP.GetPointYUnlimited(flow);
eff = PumpCalcHelper.CalculateE(flow, head, power.Value);
}
else if (vm.CurrentCurveQE != null)
{
eff = vm.CurrentCurveQE.GetPointYUnlimited(flow);
power = PumpCalcHelper.CalculateP(flow, head, eff.Value);
}
query_pt_list.Add(new()
{
Id = vm.Id,
Name=vm.Name,
Q = flow,
H = head,
E = eff,
P = power,
Hz = vm.CurrentHz,
N = vm.CurrentN
});
}
var work_info_str_builder = new StringBuilder();
work_info_str_builder.AppendLine($"流量:{paralle_flow:N2} ");
work_info_str_builder.AppendLine($"扬程:{paralle_head:N2} ");
if (paralle_eff.HasValue)
work_info_str_builder.AppendLine($"效率:{paralle_eff:N2} ");
if (paralle_power.HasValue)
work_info_str_builder.Append($"功率:{paralle_power:N2}");
_const_line_x.AxisValue = x_flow;
_const_line_x.Title.Text = $"{x_flow:N1}";
_anno_txt_query_info.Text = work_info_str_builder.ToString();
_anno_txt_query_info.AutoSize = true;
_anno_txt_query_info.Visible = true;
this.QueryPointChangedEvent?.Invoke(query_pt_list);
}
///
/// 创建线系列
///
private void CreateLineSeries(PumpParallelViewModel vm)
{
var series_qh = new DevExpress.XtraCharts.Series();
series_qh.ArgumentScaleType = DevExpress.XtraCharts.ScaleType.Numerical;
series_qh.LabelsVisibility = DevExpress.Utils.DefaultBoolean.False;
series_qh.Name = _tag_qh + vm.Id.ToString();
series_qh.ShowInLegend = false;
series_qh.CrosshairEnabled = DefaultBoolean.False;
series_qh.Tag = vm.Id.ToString();
series_qh.LegendTextPattern = vm.Name;
var series_qh_view = new DevExpress.XtraCharts.SplineSeriesView();
series_qh_view.LineStyle.Thickness = 2;
series_qh_view.Color = vm.CurrentColor;
series_qh_view.EnableAntialiasing = DefaultBoolean.True;
series_qh_view.LineTensionPercent = 50;
series_qh.SeriesPointsSorting = SortingMode.None;
series_qh.SeriesPointsSortingKey = SeriesPointKey.Value_1;
series_qh.View = series_qh_view;
series_qh.Visible = true;
var pt_qh_list = vm.CurrentCurveQH.GetPointList(100);
for (int i = 0; i < pt_qh_list.Count; i++)
{
series_qh.Points.Add(new SeriesPoint(pt_qh_list[i].X, new double[] { pt_qh_list[i].Y }));
}
var point_qh = pt_qh_list[pt_qh_list.Count() - 1];
var anchor_qh_pt = new DevExpress.XtraCharts.PaneAnchorPoint();
anchor_qh_pt.Pane = _default_pane;
anchor_qh_pt.AxisXCoordinate.AxisValue = point_qh.X.ToString();
anchor_qh_pt.AxisYCoordinate.AxisValue = point_qh.Y.ToString();
var position_qh = new DevExpress.XtraCharts.RelativePosition();
position_qh.Angle = -50;
position_qh.ConnectorLength = 10;
var txt_qh = new TextAnnotation();
txt_qh.Border.Visibility = DefaultBoolean.False;
txt_qh.AnchorPoint = anchor_qh_pt;
txt_qh.AutoHeight = true;
txt_qh.AutoWidth = true;
txt_qh.BackColor = System.Drawing.Color.Transparent;
txt_qh.Border.Color = vm.CurrentColor;
txt_qh.ConnectorStyle = DevExpress.XtraCharts.AnnotationConnectorStyle.Line;
txt_qh.DXFont = PumpChartDisplay.AnnoFontQH;
txt_qh.Name = _tag_qh + vm.Id.ToString();
txt_qh.Padding.Bottom = 1;
txt_qh.Padding.Left = 1;
txt_qh.Padding.Right = 1;
txt_qh.Padding.Top = 1;
txt_qh.RuntimeAnchoring = false;
txt_qh.RuntimeMoving = true;
txt_qh.RuntimeResizing = false;
txt_qh.RuntimeRotation = false;
txt_qh.Text = vm.Name;
txt_qh.TextColor = vm.CurrentColor;
txt_qh.ShapePosition = position_qh;
txt_qh.Visible = _line_name_visible;
this.chartControl1.AnnotationRepository.Add(txt_qh);
this.chartControl1.Series.Add(series_qh);
if (vm.CurrentCurveQE != null)
{
var series_qe = new DevExpress.XtraCharts.Series();
series_qe.ArgumentScaleType = DevExpress.XtraCharts.ScaleType.Numerical;
series_qe.LabelsVisibility = DevExpress.Utils.DefaultBoolean.False;
series_qe.Name = _tag_qe + vm.Id.ToString();
series_qe.ShowInLegend = false;
series_qe.CrosshairEnabled = DefaultBoolean.False;
series_qe.Tag = vm.Id.ToString();
var series_qe_view = new DevExpress.XtraCharts.SplineSeriesView();
series_qe_view.LineStyle.Thickness = 2;
series_qe_view.Color = vm.CurrentColor;
series_qe_view.AxisY = _axis_y_eff;
series_qe_view.Pane = _default_pane;
series_qe_view.EnableAntialiasing = DefaultBoolean.True;
series_qe_view.LineTensionPercent = 50;
series_qe.SeriesPointsSorting = SortingMode.None;
series_qe.SeriesPointsSortingKey = SeriesPointKey.Value_1;
series_qe.View = series_qe_view;
series_qe.Visible = _qe_visible;
var pt_qe_list = vm.CurrentCurveQE.GetPointList(100);
for (int i = 0; i < pt_qe_list.Count; i++)
{
series_qe.Points.Add(new SeriesPoint(pt_qe_list[i].X, new double[] { pt_qe_list[i].Y }));
}
this.chartControl1.Series.Add(series_qe);
}
if (vm.CurrentCurveQP != null)
{
var series_qp = new DevExpress.XtraCharts.Series();
series_qp.ArgumentScaleType = DevExpress.XtraCharts.ScaleType.Numerical;
series_qp.LabelsVisibility = DevExpress.Utils.DefaultBoolean.False;
series_qp.Name = _tag_qp + vm.Id.ToString();
series_qp.ShowInLegend = false;
series_qp.CrosshairEnabled = DefaultBoolean.False;
series_qp.Tag = vm.Id.ToString();
var series_qp_view = new DevExpress.XtraCharts.SplineSeriesView();
series_qp_view.LineStyle.Thickness = 2;
series_qp_view.Color = vm.CurrentColor;
series_qp_view.AxisY = _axis_y_power;
series_qp_view.Pane = _bottom_pane;
series_qp_view.EnableAntialiasing = DefaultBoolean.True;
series_qp_view.LineTensionPercent = 50;
series_qp.SeriesPointsSorting = SortingMode.None;
series_qp.SeriesPointsSortingKey = SeriesPointKey.Value_1;
series_qp.View = series_qp_view;
series_qp.Visible = _qp_visible;
var pt_qp_list = vm.CurrentCurveQP.GetPointList(100);
for (int i = 0; i < pt_qp_list.Count; i++)
{
series_qp.Points.Add(new SeriesPoint(pt_qp_list[i].X, new double[] { pt_qp_list[i].Y }));
}
this.chartControl1.Series.Add(series_qp);
}
}
#endregion
#region ChartEvent
// 右键对象
private object _rightClickObj = null;
private bool _onMoveWorkPointLine = false;
private void chartControl1_MouseDown(object sender, MouseEventArgs e)
{
if (!_initial_data)
return;
var hitInfo = chartControl1.CalcHitInfo(e.Location);
if (e.Button == MouseButtons.Left)
{
if (hitInfo.InSeries)
{
_rightClickObj = hitInfo.Series;
}
else if (hitInfo.InAxis)
{
_rightClickObj = hitInfo.Axis;
}
else if (hitInfo.InConstantLine)
{
if (hitInfo.ConstantLine == _const_line_x)
{
_onMoveWorkPointLine = true;
}
}
else if (hitInfo.InAnnotation)
{
_rightClickObj = hitInfo.Annotation;
}
else
{
_rightClickObj = null;
}
}
}
private void chartControl1_MouseMove(object sender, MouseEventArgs e)
{
if (!_initial_data)
return;
if (_onMoveWorkPointLine)
{
var diagramCoordinates = _diagram.PointToDiagram(e.Location);
var axisValue = diagramCoordinates.GetAxisValue(_axis_x_flow);
if (axisValue == null)
return;
double chartQ = axisValue.NumericalValue;
CalcWorkPointByQ(chartQ);
}
else
{
var hitInfo = chartControl1.CalcHitInfo(e.Location);
if (hitInfo.InConstantLine)
{
this.chartControl1.Cursor = Cursors.Hand;
}
else if (hitInfo.InAnnotation)
{
this.chartControl1.Cursor = Cursors.SizeAll;
}
else
{
this.chartControl1.Cursor = Cursors.Default;
}
}
}
private void chartControl1_MouseUp(object sender, MouseEventArgs e)
{
if (!_initial_data)
return;
_onMoveWorkPointLine = false;
}
private void ChartControl1_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (!_initial_data)
return;
if (!_line_visible)
return;
if (e.Button != MouseButtons.Left)
return;
var hitInfo = chartControl1.CalcHitInfo(e.Location);
if (!hitInfo.InConstantLine)
return;
if (hitInfo.ConstantLine == _const_line_x)
{
SetAxisQValue();
}
}
private void chartControl1_Resize(object sender, EventArgs e)
{
CalcTextAnchorPoint();
}
#endregion
#region Right Click Menu
#region Event
private void barBtnSetAxisQValue_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
SetAxisQValue();
}
private void barCekLineVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
SetLineVisible(this.barCekLineVisible.Checked);
}
private void barCekCurveNameVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
SetCurveNameVisible(this.barCekCurveNameVisible.Checked);
}
private void barCekLegendVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
SetLegendVisible(this.barCekLegendVisible.Checked);
}
private void barCekSetAxisNameVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
SetAxisNameVisible(this.barCekSetAxisNameVisible.Checked);
}
private void barBtnSetChartAxis_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
SetChartAxis();
}
private void barCekCurveQHVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
_default_pane.Visibility = _default_pane.Visibility == ChartElementVisibility.Visible ? ChartElementVisibility.Hidden : ChartElementVisibility.Visible;
}
private void barCekCurveQEVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
_qe_visible = this.barCekCurveQEVisible.Checked;
UpdateChart();
}
private void barCekCurveQPVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
_qp_visible = this.barCekCurveQPVisible.Checked;
_bottom_pane.Visibility = _qp_visible ? ChartElementVisibility.Visible : ChartElementVisibility.Hidden;
UpdateChart();
}
private void barCekCurveEQVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
_equip_visible = this.barCekCurveEQVisible.Checked;
}
#endregion
///
/// 设置工作点显示
///
public void SetLineVisible(bool visible)
{
if (!_initial_data)
return;
LineVisible = visible;
CalcWorkPointByQ();
}
///
/// 设置装置曲线显示
///
public void SetEquipVisible(bool visible)
{
if (!_initial_data)
return;
_equip_visible = visible;
UpdateChart(true);
}
///
/// 设置效率曲线显示
///
public void SetQeVisible(bool visible)
{
this.barCekCurveQEVisible.Checked = visible;
UpdateChart(true);
}
///
/// 设置曲线名
///
public void SetCurveNameVisible(bool visible)
{
if (!_initial_data)
return;
_line_name_visible = visible;
for (int i = 1; i < this.chartControl1.AnnotationRepository.Count; i++)
{
var anno = this.chartControl1.AnnotationRepository[i];
anno.Visible = _line_name_visible;
}
}
///
/// 设置图例显示
///
public void SetLegendVisible(bool visible)
{
this.chartControl1.Legend.Visibility = visible ? DefaultBoolean.True : DefaultBoolean.False;
}
///
/// 设置轴名称显示
///
public void SetAxisNameVisible(bool visible)
{
_axis_x_flow.Title.Visibility = visible ? DefaultBoolean.True : DefaultBoolean.False;
_axis_y_head.Title.Visibility = visible ? DefaultBoolean.True : DefaultBoolean.False;
_axis_y_eff.Title.Visibility = visible ? DefaultBoolean.True : DefaultBoolean.False;
_axis_y_power.Title.Visibility = visible ? DefaultBoolean.True : DefaultBoolean.False;
}
///
/// 设置坐标轴
///
public void SetChartAxis()
{
var dlg = new PumpChartCoordinateDlg();
dlg.SetBindingData(_coordinate);
dlg.OnChangedCoord += (rhs) =>
{
_coordinate = rhs;
CalcChartAxis();
this.CoordinateChangedEvent?.Invoke(_coordinate);
};
dlg.ShowDialog();
}
///
/// 设置查询流量
///
public void SetAxisQValue()
{
if (_vm_list == null || !_vm_list.Any())
return;
var dlg = new PumpAxisValueDlg();
dlg.SetBindingData();
dlg.VerifyValueChanged += (value) =>
{
if (value < _min_flow || value > _max_flow)
return false;
CalcWorkPointByQ(value);
return true;
};
dlg.ShowDialog();
}
#endregion
}
}