using DevExpress.Utils; 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 _query_flow_line; 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 _paralle_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(); _query_flow_line = (ConstantLine)_diagram.AxisX.ConstantLines.GetElementByName("WorkPointLine"); _query_flow_line.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; _query_flow_line.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.CustomPaint += ChartControl1_CustomPaint; } /// /// 图表重绘 /// private void ChartControl1_CustomPaint(object sender, CustomPaintEventArgs e) { if (e is not DXCustomPaintEventArgs dxArgs) return; if (_vm_list == null || !_vm_list.Any()) return; if (_equip_line != null && _equip_sect_pt != null && _equip_visible) { var dis_min_h = _coordinate.DispMinH(); using Pen pen = new(Color.Black, 2); pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDotDot; var c_pt_qh = _diagram.DiagramToPoint(_equip_sect_pt.X, _equip_sect_pt.Y, _axis_x_flow, _axis_y_head); dxArgs.Cache.DrawLine(pen, new Point((int)c_pt_qh.Point.X, (int)c_pt_qh.Point.Y - 10), new Point((int)c_pt_qh.Point.X, (int)c_pt_qh.Point.Y + 10)); if (_qe_visible) { var y_qe = _paralle_vm.CurrentCurveQE.GetPointY(_equip_sect_pt.X); var c_pt_qe = _diagram.DiagramToPoint(_equip_sect_pt.X, y_qe, _axis_x_flow, _axis_y_eff); dxArgs.Cache.DrawLine(pen, new Point((int)c_pt_qe.Point.X, (int)c_pt_qe.Point.Y - 10), new Point((int)c_pt_qe.Point.X, (int)c_pt_qe.Point.Y + 10)); } if (_qp_visible) { var y_qp = _paralle_vm.CurrentCurveQP.GetPointY(_equip_sect_pt.X); var c_pt_qp = _diagram.DiagramToPoint(_equip_sect_pt.X, y_qp, _axis_x_flow, _axis_y_power); dxArgs.Cache.DrawLine(pen, new Point((int)c_pt_qp.Point.X, (int)c_pt_qp.Point.Y - 10), new Point((int)c_pt_qp.Point.X, (int)c_pt_qp.Point.Y + 10)); } var pts = _equip_line.GetPointList().Select(x => new PointF((float)x.X, (float)x.Y)).ToArray(); var g_pts = new List(); foreach (var pt in pts) { var x = pt.X; var y = pt.Y; var c_pt = _diagram.DiagramToPoint(x, y, _axis_x_flow, _axis_y_head); g_pts.Add(new PointF(c_pt.Point.X, c_pt.Point.Y)); } using var path = new System.Drawing.Drawing2D.GraphicsPath(); path.AddCurve(g_pts.ToArray()); dxArgs.Cache.DrawPath(pen, path); } foreach (var vm in _vm_list) { if (!vm.CurrentExtendFlow.HasValue) continue; var max_flow = vm.CurrentExtendFlow.Value; using Pen pen = new(Color.White, 2); pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; { var pt_list = vm.CurrentCurveQH.GetPointList(12).ToList(); pt_list = pt_list.Where(x => x.X >= max_flow).ToList(); if (pt_list.Count > 0) { if (pt_list.Count == 1) { var max_flow_head = vm.CurrentCurveQH.GetPointY(max_flow); pt_list.Add(new Yw.Geometry.Point2d(max_flow, max_flow_head)); } var pt_c_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_c_list.Add(new PointF(c_pt.Point.X, c_pt.Point.Y)); } using var path = new System.Drawing.Drawing2D.GraphicsPath(); path.AddCurve(pt_c_list.ToArray()); dxArgs.Cache.DrawPath(pen, path); } } if (_qe_visible) { var pt_list = vm.CurrentCurveQE.GetPointList(12).ToList(); pt_list = pt_list.Where(x => x.X > max_flow).ToList(); if (pt_list.Count > 0) { if (pt_list.Count == 1) { var max_flow_eff = vm.CurrentCurveQE.GetPointY(max_flow); pt_list.Add(new Yw.Geometry.Point2d(max_flow, max_flow_eff)); } var pt_c_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_eff); pt_c_list.Add(new PointF(c_pt.Point.X, c_pt.Point.Y)); } using var path = new System.Drawing.Drawing2D.GraphicsPath(); path.AddCurve(pt_c_list.ToArray()); dxArgs.Cache.DrawPath(pen, path); } } if (_qp_visible) { var pt_list = vm.CurrentCurveQP.GetPointList(12).ToList(); pt_list = pt_list.Where(x => x.X > max_flow).ToList(); if (pt_list.Count > 0) { if (pt_list.Count == 1) { var max_flow_power = vm.CurrentCurveQP.GetPointY(max_flow); pt_list.Add(new Yw.Geometry.Point2d(max_flow, max_flow_power)); } var pt_c_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_power); pt_c_list.Add(new PointF(c_pt.Point.X, c_pt.Point.Y)); } using var path = new System.Drawing.Drawing2D.GraphicsPath(); path.AddCurve(pt_c_list.ToArray()); dxArgs.Cache.DrawPath(pen, path); } } } } /// /// 初始化图表数据 /// 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 x, double y, double? start_head = null) { _equip_pt = new Geometry.Point2d(x, y); _equip_line = null; _equip_sect_pt = null; if (_paralle_vm == null || (_vm_list == null || !_vm_list.Any())) { this.DesignPointChangedEvent?.Invoke(null); return; } start_head ??= _coordinate.DispMinH(); var equip_line = Yw.Geometry.EquipCurveHelper.CalcEquipCurve(_paralle_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.GetPointY(flow); if (vm.CurrentCurveQP != null) { power = vm.CurrentCurveQP.GetPointY(flow); eff = PumpCalcHelper.CalculateE(flow, head, power.Value); } else if (vm.CurrentCurveQE != null) { eff = vm.CurrentCurveQE.GetPointY(flow); power = PumpCalcHelper.CalculateP(flow, head, eff.Value); } var design_pt = new PumpDesignPointViewModel(); design_pt.Id = vm.Id; design_pt.Q = flow; design_pt.H = head; design_pt.E = eff; design_pt.P = power; design_pt.Hz = vm.CurrentHz; design_pt.N = vm.CurrentN; design_pt_list.Add(design_pt); } 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) { if (calc_coordinate || _coordinate == null) { //不强迫计算,就用上次更新的坐标系 CalcCoordinate(); } CalcSeries(); 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.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) { if (vm.CurrentCurveQE == null) continue; var qe_pt_list = vm.CurrentCurveQE.GetPointList(); var yyy = qe_pt_list.Select(x => x.Y); _max_eff = Math.Max(_max_eff, yyy.Max()); } foreach (PumpParallelViewModel vm in _vm_list) { if (vm.CurrentCurveQP == null) continue; var yyy = vm.CurrentCurveQP.GetPointList().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; _query_flow_line.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) { //计算刻度 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 annotationCount = this.chartControl1.AnnotationRepository.Count; for (int i = annotationCount - 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); } this.chartControl1.EndInit(); } /// /// 计算并联线 /// private void CalcParallelSeries(List list) { _paralle_vm = null; if (list == null || !list.Any()) 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) { 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); _paralle_vm = new Yw.WinFrmUI.Phart.PumpParallelViewModel(); _paralle_vm.Id = "parallel"; _paralle_vm.Name = "并联线"; _paralle_vm.CurrentColor = Color.Black; _paralle_vm.CurveQH = qh; _paralle_vm.CurveQE = qe; _paralle_vm.CurveQP = qp; _paralle_vm.CurrentCurveQH = qh; _paralle_vm.CurrentCurveQE = qe; _paralle_vm.CurrentCurveQP = qp; _paralle_vm.CurveQH = qh; _paralle_vm.CurveQE = qe; _paralle_vm.CurveQP = qp; CreateLineSeries(_paralle_vm); } /// /// 计算注释定位 /// private void CalcTextAnchorPoint() { var x = this.chartControl1.Location.X + this.chartControl1.Width - (100); var y = this.chartControl1.Location.Y + 100; (_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) { _query_flow_line.Visible = false; _query_flow_line.Title.Visible = false; _anno_txt_query_info.Visible = false; return; } else { _query_flow_line.Visible = true; _query_flow_line.Title.Visible = true; _anno_txt_query_info.Visible = true; } if (_paralle_vm==null) return; if (_vm_list == null || !_vm_list.Any()) return; var min_flow = _paralle_vm.CurveQH.MinX; var max_flow = _paralle_vm.CurveQH.MaxX; x_flow ??= _equip_pt?.X ?? max_flow / 3 * 2; 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 = _paralle_vm.CurrentCurveQH.GetPointY(paralle_flow); if (_paralle_vm.CurrentCurveQP != null) { paralle_power = _paralle_vm.CurrentCurveQP.GetPointY(paralle_flow); paralle_eff = PumpCalcHelper.CalculateE(paralle_flow, paralle_head, paralle_power.Value); } else if (_paralle_vm.CurrentCurveQE != null) { paralle_eff = _paralle_vm.CurrentCurveQE.GetPointY(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 = _paralle_vm.CurrentCurveQP.GetPointY(flow); eff = PumpCalcHelper.CalculateE(flow, head, power.Value); } else if (vm.CurrentCurveQE != null) { eff = _paralle_vm.CurrentCurveQE.GetPointY(flow); power = PumpCalcHelper.CalculateP(flow, head, eff.Value); } var pump_query_pt = new PumpQueryPointViewModel(); pump_query_pt.Id = vm.Id; pump_query_pt.Q = flow; pump_query_pt.H = head; pump_query_pt.E = eff; pump_query_pt.P = power; pump_query_pt.Hz = vm.CurrentHz; pump_query_pt.N = vm.CurrentN; query_pt_list.Add(pump_query_pt); } 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}"); _query_flow_line.AxisValue = x_flow; _query_flow_line.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.ShowInLegend = true; 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(12); 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 = Perform2dChartDisplay.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(12); 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(12); 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 == _query_flow_line) { _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_Resize(object sender, EventArgs e) { CalcTextAnchorPoint(); } #endregion #region Right Click Menu #region Event private void barBtnSetAxisQValue_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { 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(); } 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) { _bottom_pane.Visibility = _bottom_pane.Visibility == ChartElementVisibility.Visible ? ChartElementVisibility.Hidden : ChartElementVisibility.Visible; _qp_visible = _bottom_pane.Visibility == ChartElementVisibility.Visible ? true : false; } 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; } /// /// 设置曲线名 /// 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(); } #endregion } }