Shuxia Ning
2024-12-04 bbcdd8088ee3efb8b24e4aa422a918a4d21b5750
WinFrmUI/Yw.WinFrmUI.Phart.Core/01-pump/01-single/04-variable-speed-view/PumpVariableSpeedViewChart.cs
@@ -18,61 +18,25 @@
        #region Private Variable 
        private List<PumpVariableSpeedViewModel> _vm_list = new List<PumpVariableSpeedViewModel>();
        private readonly string _tag_qh = "QH", _tag_qe = "QE", _tag_qp = "QP";
        private XYDiagram _diagram;
        private XYDiagramDefaultPane _default_pane;
        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 bool _run_visible = true;
        private bool _initial_data = false;
        #endregion
        #region Public Variable
        /// <summary>
        /// 工作线是否可见
        /// </summary>
        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;
        /// <summary>
        /// 曲线名是否可见
        /// </summary>
        public bool LineNameVisible
        {
            get => _line_name_visible;
            set
            {
                _line_name_visible = value;
                this.barCekCurveNameVisible.Checked = _line_name_visible;
            }
        }
        private bool _line_name_visible = true;
        private PumpVariableSpeedViewViewModel _vm = null;
        #endregion
@@ -82,27 +46,6 @@
        /// 坐标变换事件
        /// </summary>
        public event Action<PumpCoordinate> CoordinateChangedEvent = null;
        /// <summary>
        /// 并联状态变换事件
        /// </summary>
        public event Action<bool, string> ParallelStatusChangedEvent = null;
        /// <summary>
        /// 查询点变换事件
        /// </summary>
        public event Action<List<PumpQueryPointViewModel>> QueryPointChangedEvent = null;
        /// <summary>
        /// 设计点变换事件
        /// </summary>
        public event Action<List<PumpDesignPointViewModel>> DesignPointChangedEvent = null;
        public event Action AddBySpeedEvent = null;
        public event Action AddByHzEvent = null;
        public event Action AddByPointEvent = null;
        #endregion
@@ -117,11 +60,11 @@
            this.chartControl1.Legend.Direction = DevExpress.XtraCharts.LegendDirection.TopToBottom;
            _diagram = (XYDiagram)this.chartControl1.Diagram;
            _default_pane = _diagram.DefaultPane;
            _default_pane = _diagram.DefaultPane;
            _bottom_pane = (XYDiagramPane)_diagram.FindPaneByName("BottomPanel");
            _axis_x_flow = _diagram.AxisX;
            _axis_x_flow.SetAxisXQDisplay();
            _axis_x_flow.SetAxisXQDisplay();
            _axis_y_head = _diagram.AxisY;
            _axis_y_head.SetAxisYQHDisplay();
            _axis_y_eff = _diagram.SecondaryAxesY.GetAxisByName("AxisYQE");
@@ -130,11 +73,7 @@
            _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();
            this.chartControl1.SetChartMonoColorDisplay();
            _axis_x_flow.Visibility = DefaultBoolean.False;
            _axis_x_flow.GridLines.Visible = false;
@@ -146,14 +85,6 @@
            _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;
        }
@@ -161,75 +92,37 @@
        {
            if (e is not DXCustomPaintEventArgs dxArgs)
                return;
            if (_vm_list == null || !_vm_list.Any())
            if (_vm == null)
                return;
            if (_equip_line != null && _equip_visible)
            if (_vm.Items!=null&&_vm.Items.Any()&& _run_visible)
            {
                using Pen pen = new(Color.Black, 2);
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDotDot;
                foreach (var vm in _vm_list)
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDotDot;
                foreach (var vm in _vm.Items)
                {
                    var sect_pt = vm.EquipPoint;
                    if (sect_pt == null)
                        continue;
                    DrawEquipPoint(dxArgs.Cache, pen, sect_pt, vm.CurrentCurveQE, vm.CurrentCurveQP);
                    var color = vm.Color;
                    var flow = vm.Q;
                    var head = vm.H;
                    var eff = vm.E;
                    var power = vm.P;
                    DrawWorkPoint(dxArgs.Cache, color, _axis_y_head, flow, head);
                    if (eff.HasValue && _qe_visible)
                        DrawWorkPoint(dxArgs.Cache, color, _axis_y_eff, flow, eff.Value);
                    if (power.HasValue && _qp_visible)
                        DrawWorkPoint(dxArgs.Cache, color, _axis_y_power, flow, power.Value);
                }
                DrawEquipLine(dxArgs.Cache, pen, _equip_line);
            }
        }
        private void DrawEquipLine(GraphicsCache cache, Pen pen, Yw.Geometry.CubicSpline2d qh)
        private void DrawWorkPoint(GraphicsCache cache, Color color, AxisYBase axis_y, double x, double y)
        {
            if (qh == null)
                return;
            var pt_list = qh.GetPointList().ToArray();
            var pt_f_list = new List<PointF>();
            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);
            var dg_pt = _diagram.DiagramToPoint(x, y, _axis_x_flow, axis_y);
            cache.FillEllipse((int)(dg_pt.Point.X - 5), (int)(dg_pt.Point.Y - 5), 10, 10, color);
        }
        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 = qe.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));
            }
        }
        /// <summary>
        /// 初始化图表数据
        /// </summary>
@@ -248,91 +141,27 @@
        /// <summary>
        /// 绑定数据
        /// </summary> 
        public void SetBindingData(List<PumpVariableSpeedViewModel> list)
        public void SetBindingData(PumpVariableSpeedViewViewModel vm)
        {
            _vm_list = list;
            _initial_data = list != null && list.Any();
            _vm = vm;
            _initial_data = vm != null;
            UpdateChart(true);
        }
        /// <summary>
        /// 设置设计点
        /// </summary>
        public void SetDesignPoint(double x, double y, double? start_head = null)
        {
            _equip_pt = new Geometry.Point2d(x, y);
            _equip_line = null;
            if (_vm_list == null || !_vm_list.Any())
            {
                this.DesignPointChangedEvent?.Invoke(null);
                return;
            }
            start_head ??= _coordinate.DispMinH();
            var max_hz_vm = _vm_list.OrderBy(x => x.CurrentHz).FirstOrDefault();
            var equip_line = Yw.Geometry.EquipCurveHelper.CalcEquipCurve(max_hz_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;
            var design_pt_list = new List<PumpDesignPointViewModel>();
            foreach (var vm in _vm_list)
            {
                double flow = 0, head = 0;
                double? eff = null, power = null;
                var pump_equip_line = Yw.Geometry.EquipCurveHelper.CalcEquipCurve(vm.CurrentCurveQH, _equip_pt, start_head.Value, out Yw.Geometry.Point2d pump_sect_pt);
                if (pump_equip_line == null || pump_sect_pt == null)
                    return;
                vm.EquipPoint = pump_sect_pt;
                flow = pump_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);
        }
        /// <summary>
        /// 清空曲线
        /// </summary> 
        public void Clear()
        {
            _vm_list = new List<PumpVariableSpeedViewModel>();
            _vm = null;
            _initial_data = false;
            UpdateChart(true);
        }
        /// <summary>
        /// 更新图表
        /// </summary>s
        /// </summary>
        public void UpdateChart(bool calc_coordinate = false)
        {
            if (calc_coordinate || _coordinate == null)
@@ -344,10 +173,6 @@
            CalcSeries();
            CalcChartAxis();
            CalcWorkPointByQ();
            //CalcTextAnchorPoint();
        }
        #endregion
@@ -364,7 +189,7 @@
        /// </summary>
        private void CalcCoordinate()
        {
            if (_vm_list == null || !_vm_list.Any())
            if (_vm == null)
            {
                //设置成白板坐标
                _coordinate = new PumpCoordinate();
@@ -392,9 +217,8 @@
            double _scaleMinH = 1, _scaleMaxH = 1;
            foreach (var vm in _vm_list)
            {
                var qh_pt_list = vm.CurrentCurveQH.GetPointList();
                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);
@@ -405,23 +229,52 @@
                _max_head = Math.Max(_max_head, yyy.Max());
            }
            foreach (PumpVariableSpeedViewModel vm in _vm_list)
            if (_vm.CurveQE != null)
            {
                if (vm.CurrentCurveQE == null)
                    continue;
                var qe_pt_list = vm.CurrentCurveQE.GetPointList();
                var qe_pt_list = _vm.CurveQE.GetPointList();
                var yyy = qe_pt_list.Select(x => x.Y);
                _min_eff = Math.Min(_min_eff, yyy.Min());
                _max_eff = Math.Max(_max_eff, yyy.Max());
            }
            foreach (PumpVariableSpeedViewModel vm in _vm_list)
            if (_vm.CurveQP != null)
            {
                if (vm.CurrentCurveQP == null)
                    continue;
                var yyy = vm.CurrentCurveQP.GetPointList().Select(x => x.Y);
                var yyy = _vm.CurveQP.GetPointList().Select(x => x.Y);
                _min_power = Math.Min(_min_power, yyy.Min());
                _max_power = Math.Max(_max_power, yyy.Max());
            }
            if (_vm.Items != null && _vm.Items.Any())
            {
                foreach (var vm in _vm.Items)
                {
                    {
                        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.Min(_min_eff, yyy.Min());
                        _max_eff = Math.Max(_max_eff, yyy.Max());
                    }
                    if (vm.CurveQP != null)
                    {
                        var yyy = vm.CurveQP.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,
@@ -440,6 +293,7 @@
            {
                _coordinate.GridNumberX++;
            }
        }
        /// <summary>
@@ -456,11 +310,8 @@
            _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
@@ -511,7 +362,7 @@
            }
            //功率
            if (_max_power > _min_power)
            if (_max_power > _min_power && _qp_visible)
            {
                //计算刻度
                var labels = new List<CustomAxisLabel>();
@@ -551,7 +402,7 @@
            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);
            _axis_y_power.SetAxisRange(min_axis_power, max_axis_power);
        }
        /// <summary>
@@ -561,121 +412,46 @@
        {
            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.AnnotationRepository.Clear();
            this.chartControl1.Legend.CustomItems.Clear();
            if (_vm_list.Count > 0)
            if (_vm != null)
            {
                foreach (var vm in _vm_list)
                _vm.Color = RandomColorHelper.Get(0);
                CreateLineSeries(_vm.Id, _vm.Color, _vm.Name, _vm.CurveQH, _vm.CurveQE, _vm.CurveQP);
                if (_vm.Items != null && _vm.Items.Any())
                {
                    CreateLineSeries(vm);
                    for (int i = 0; i < _vm.Items.Count; i++)
                    {
                        var vm = _vm.Items[i];
                        vm.Color = RandomColorHelper.Get(i + 1);
                        CreateLineSeries(vm.Id, vm.Color, vm.CurveName, vm.CurveQH, vm.CurveQE, vm.CurveQP);
                    }
                }
            }
            this.chartControl1.EndInit();
        }
        /// <summary>
        /// 计算注释定位
        /// </summary>
        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;
        }
        /// <summary>
        /// 计算工作点
        /// </summary>
        public void CalcWorkPointByQ(double? x_flow = null)
        {
            if (!_line_visible)
            {
                _query_flow_line.Visible = false;
                _query_flow_line.Title.Visible = false;
                return;
            }
            else
            {
                _query_flow_line.Visible = true;
                _query_flow_line.Title.Visible = true;
            }
            if (_vm_list == null || !_vm_list.Any())
                return;
            x_flow ??= _equip_pt?.X ?? _max_flow * 0.8;
            if (x_flow < _min_flow || x_flow > _max_flow)
                return;
            var query_pt_list = new List<PumpQueryPointViewModel>();
            foreach (var vm in _vm_list)
            {
                double flow = 0, head = 0;
                double? eff = null, power = null;
                flow = x_flow.Value;
                head = vm.CurrentCurveQH.GetPointY(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);
                }
                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
                });
            }
            _query_flow_line.AxisValue = x_flow;
            _query_flow_line.Title.Text = $"{x_flow:N1}";
            this.QueryPointChangedEvent?.Invoke(query_pt_list);
            this.chartControl1.EndInit();
        }
        /// <summary>
        /// 创建线系列
        /// </summary> 
        private void CreateLineSeries(PumpVariableSpeedViewModel vm)
        private void CreateLineSeries(string id, Color color, string curve_name, Yw.Geometry.CubicSpline2d qh, Yw.Geometry.CubicSpline2d qe, Yw.Geometry.CubicSpline2d qp)
        {
            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.Name = _tag_qh + id;
            series_qh.ShowInLegend = false;
            series_qh.CrosshairEnabled = DefaultBoolean.False;
            series_qh.Tag = vm.Id.ToString();
            series_qh.LegendTextPattern = vm.Name;
            series_qh.LegendTextPattern = curve_name;
            var series_qh_view = new DevExpress.XtraCharts.SplineSeriesView();
            series_qh_view.LineStyle.Thickness = 2;
            series_qh_view.Color = vm.CurrentColor;
            series_qh_view.Color = color;
            series_qh_view.EnableAntialiasing = DefaultBoolean.True;
            series_qh_view.LineTensionPercent = 50;
@@ -684,7 +460,7 @@
            series_qh.View = series_qh_view;
            series_qh.Visible = true;
            var pt_qh_list = vm.CurrentCurveQH.GetPointList(12);
            var pt_qh_list = qh.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 }));
@@ -706,10 +482,10 @@
            txt_qh.AutoHeight = true;
            txt_qh.AutoWidth = true;
            txt_qh.BackColor = System.Drawing.Color.Transparent;
            txt_qh.Border.Color = vm.CurrentColor;
            txt_qh.Border.Color = color;
            txt_qh.ConnectorStyle = DevExpress.XtraCharts.AnnotationConnectorStyle.Line;
            txt_qh.DXFont = PumpChartDisplay.AnnoFontQH;
            txt_qh.Name = _tag_qh + vm.Id.ToString();
            txt_qh.Name = _tag_qh + id;
            txt_qh.Padding.Bottom = 1;
            txt_qh.Padding.Left = 1;
            txt_qh.Padding.Right = 1;
@@ -718,26 +494,26 @@
            txt_qh.RuntimeMoving = true;
            txt_qh.RuntimeResizing = false;
            txt_qh.RuntimeRotation = false;
            txt_qh.Text = vm.Name;
            txt_qh.TextColor = vm.CurrentColor;
            txt_qh.Text = curve_name;
            txt_qh.TextColor = color;
            txt_qh.ShapePosition = position_qh;
            txt_qh.Visible = _line_name_visible;
            txt_qh.Visible = true;
            this.chartControl1.AnnotationRepository.Add(txt_qh);
            this.chartControl1.Series.Add(series_qh);
            if (vm.CurrentCurveQE != null)
            if (qe != 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.Name = _tag_qe + id;
                series_qe.ShowInLegend = false;
                series_qe.CrosshairEnabled = DefaultBoolean.False;
                series_qe.Tag = vm.Id.ToString();
                series_qe.Tag = id;
                var series_qe_view = new DevExpress.XtraCharts.SplineSeriesView();
                series_qe_view.LineStyle.Thickness = 2;
                series_qe_view.Color = vm.CurrentColor;
                series_qe_view.Color = color;
                series_qe_view.AxisY = _axis_y_eff;
                series_qe_view.Pane = _default_pane;
                series_qe_view.EnableAntialiasing = DefaultBoolean.True;
@@ -748,7 +524,7 @@
                series_qe.View = series_qe_view;
                series_qe.Visible = _qe_visible;
                var pt_qe_list = vm.CurrentCurveQE.GetPointList(12);
                var pt_qe_list = qe.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 }));
@@ -757,19 +533,19 @@
                this.chartControl1.Series.Add(series_qe);
            }
            if (vm.CurrentCurveQP != null)
            if (qp != 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.Name = _tag_qp + id;
                series_qp.ShowInLegend = false;
                series_qp.CrosshairEnabled = DefaultBoolean.False;
                series_qp.Tag = vm.Id.ToString();
                series_qp.Tag = id;
                var series_qp_view = new DevExpress.XtraCharts.SplineSeriesView();
                series_qp_view.LineStyle.Thickness = 2;
                series_qp_view.Color = vm.CurrentColor;
                series_qp_view.Color = color;
                series_qp_view.AxisY = _axis_y_power;
                series_qp_view.Pane = _bottom_pane;
                series_qp_view.EnableAntialiasing = DefaultBoolean.True;
@@ -780,7 +556,7 @@
                series_qp.View = series_qp_view;
                series_qp.Visible = _qp_visible;
                var pt_qp_list = vm.CurrentCurveQP.GetPointList(12);
                var pt_qp_list = qp.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 }));
@@ -791,147 +567,23 @@
        }
        #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;
            _qe_visible = this.barCekCurveQEVisible.Checked;
            UpdateChart();
        }
@@ -939,79 +591,16 @@
        {
            _bottom_pane.Visibility = _bottom_pane.Visibility == ChartElementVisibility.Visible ? ChartElementVisibility.Hidden : ChartElementVisibility.Visible;
            _qp_visible = _bottom_pane.Visibility == ChartElementVisibility.Visible ? true : false;
            UpdateChart();
        }
        private void barCekCurveEQVisible_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            _equip_visible = this.barCekCurveEQVisible.Checked;
            _run_visible = this.barCekCurveEQVisible.Checked;
        }
        #endregion
        /// <summary>
        /// 设置工作点显示
        /// </summary>
        public void SetLineVisible(bool visible)
        {
            if (!_initial_data)
                return;
            LineVisible = visible;
            CalcWorkPointByQ();
        }
        /// <summary>
        /// 设置装置曲线显示
        /// </summary>
        public void SetEquipVisible(bool visible)
        {
            if (!_initial_data)
                return;
            _equip_visible = visible;
            UpdateChart(true);
        }
        /// <summary>
        /// 设置效率曲线显示
        /// </summary>
        public void SetQeVisible(bool visible)
        {
            this.barCekCurveQEVisible.Checked = visible;
        }
        /// <summary>
        /// 设置曲线名
        /// </summary>
        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;
            }
        }
        /// <summary>
        /// 设置图例显示
        /// </summary>
        public void SetLegendVisible(bool visible)
        {
            this.chartControl1.Legend.Visibility = visible ? DefaultBoolean.True : DefaultBoolean.False;
        }
        /// <summary>
        /// 设置轴名称显示
        /// </summary>
        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;
        }
        /// <summary>
        /// 设置坐标轴
@@ -1031,26 +620,8 @@
        #endregion
        #region Add Event
        private void barBtnAddBySpeed_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            this.AddBySpeedEvent?.Invoke();
        }
        private void barBtnAddByHz_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            this.AddByHzEvent?.Invoke();
        }
        private void barBtnAddByPoint_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            this.AddByPointEvent?.Invoke();
        }
        #endregion
    }