初探oxyplot

发布时间 2023-12-22 15:13:49作者: echo-efun
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using DLVisionH;
using OxyPlot;
using OxyPlot.Annotations;
using OxyPlot.Axes;
using OxyPlot.Series;
using OxyPlot.WindowsForms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrayNotify;
using Annotation = OxyPlot.Annotations.Annotation;
using ArrowAnnotation = OxyPlot.Annotations.ArrowAnnotation;
using DataPoint = OxyPlot.DataPoint;
using EllipseAnnotation = OxyPlot.Annotations.EllipseAnnotation;
using HitTestResult = OxyPlot.HitTestResult;
using LineAnnotation = OxyPlot.Annotations.LineAnnotation;
using RectangleAnnotation = OxyPlot.Annotations.RectangleAnnotation;
using TextAnnotation = OxyPlot.Annotations.TextAnnotation;
using TickStyle = OxyPlot.Axes.TickStyle;

namespace WindowsFormsApp2
{
  public partial class Formoxyplot : Form
  {

    enum CrossSectionBaseUnitType
    {
       MaxPoint,
       MinPoint,
       MeanPoint,
       FitLine,
       FitCircle,
       None
    }


    static List<PointAnnotation> GrapPoints { get; set; } = new List<PointAnnotation>();
    static List<PointAnnotation> SelectPoints { get; set; } = new List<PointAnnotation>();




    #region  CommonFuncation

    //读取txt文件获取点数据
    public static double[] ReadTxtFile()
    {
      List<double> data = new List<double>();

      OpenFileDialog openFileDialog = new OpenFileDialog();
      if (openFileDialog.ShowDialog() == DialogResult.OK)
      {
        string[] lines = File.ReadAllLines(openFileDialog.FileName);
        data.Clear();
        foreach (string s in lines)
        {
          data.Add(Convert.ToDouble(s.Trim()));
        }

      }

      return data == null ? new double[0] : data.ToArray();
    }



    // n 生成随机数个数
    public static double[] GenerateUniqueRandom(int minValue, int maxValue, int n)
    {
      // Random.Nex(1, 10) 只能产生到 9 的随机数,若要产生到 10 的随机数, maxValue 要加 1
      maxValue++;

      // Random.Nex(1, 10) 只能产生 9 个随机数,因此 n 不能大于 10 - 1
      //if (n > maxValue - minValue)
      //  n = maxValue - minValue;

      double[] arr = new double[n];
      Random ran = new Random();

      bool flag = true;
      for (int i = 0; i < n; i++)
      {
        do
        {
          double val = ran.NextDouble() * (maxValue - minValue) + minValue;
          if (!IsDuplicates(ref arr, val))
          {
            arr[i] = val;
            flag = false;
          }
        } while (flag);
        if (!flag)
          flag = true;
      }
      return arr;
    }

    // 查检当前生成的随机数是否重复
    public static bool IsDuplicates(ref double[] arr, double currRandNum)
    {
      bool flag = false;
      for (int i = 0; i < arr.Length; i++)
      {
        if (arr[i] == currRandNum)
        {
          flag = true;
          break;
        }
      }
      return flag;
    }

    //  //调用方法:

    //  int[] arr = GenerateUniqueRandom(1, 10, 10);// 生成 10 个 1 到 10 的随机数
    //for (int i = 0; i<arr.Length; i++)
    //Response.Write(arr[i] + ", ");// 结果 10, 7, 9, 4, 3, 5, 1, 2, 6, 8

    //GenerateUniqueRandom(1, 10, 5);// 生成 5 个 1 到 10 的随机数,结果 9, 1, 7, 2, 10


    #endregion

    #region CommonVariable
    static CrossSectionBaseUnitType BaseUnitType = CrossSectionBaseUnitType.None;
    #endregion

    public Formoxyplot()
    {
      InitializeComponent();
      InitPlot();
      this.Load += Formoxyplot_Load;
    }


    private PlotView plot1;
    private void InitPlot()
      {
        this.plot1 = new OxyPlot.WindowsForms.PlotView();
        this.SuspendLayout();
        this.plot1.Dock = System.Windows.Forms.DockStyle.Fill;
        this.plot1.Location = new System.Drawing.Point(0, 0);
        this.plot1.Name = "profile";
        this.plot1.TabIndex = 0;
        this.plot1.Margin = new System.Windows.Forms.Padding(0);
        this.panel1.Controls.Add(this.plot1);



      this.ResumeLayout();
      }
    //private PlotModel _myPlotModel;
    //private DateTimeAxis _dateAxis;
    //private LinearAxis _valueAxis;

    //private Random rand = new Random();

    int samples = 5;
    int distance = 179;
    int rectPad = 34;
    PlotModel model = null;
    static float PixelRate = 0.01975f;

    public static PlotModel MouseEvents()
    {
      var model = new PlotModel { Title = "Mouse events", Subtitle = "Left click and drag" };
      var yaxis = new LinearAxis { Position = AxisPosition.Left, Minimum = -1, Maximum = 1 };
      var xaxis = new LinearAxis { Position = AxisPosition.Bottom, Minimum = -1, Maximum = 1 };
      model.Axes.Add(yaxis);
      model.Axes.Add(xaxis);

      LineSeries s1 = null;

      // Subscribe to the mouse down event on the line series
      model.MouseDown += (s, e) =>
      {
        // only handle the left mouse button (right button can still be used to pan)
        if (e.ChangedButton == OxyMouseButton.Left)
        {
          // Add a line series
          s1 = new LineSeries
          {
            Title = "LineSeries" + (model.Series.Count + 1),
            MarkerType = MarkerType.None,
            StrokeThickness = 2
          };
          s1.Points.Add(xaxis.InverseTransform(e.Position.X, e.Position.Y, yaxis));
          model.Series.Add(s1);
          model.InvalidatePlot(false);
          e.Handled = true;
        }
      };

      model.MouseMove += (s, e) =>
      {
        if (s1 != null)
        {
          s1.Points.Add(xaxis.InverseTransform(e.Position.X, e.Position.Y, yaxis));
          model.InvalidatePlot(false);
          e.Handled = true;
        }
      };

      model.MouseUp += (s, e) =>
      {
        if (s1 != null)
        {
          s1 = null;
          e.Handled = true;
        }
      };
      return model;
    }

    static List<OxyPlot.DataPoint> GetPoints(double[] zValues)
    {
      List<OxyPlot.DataPoint> points = new List<OxyPlot.DataPoint>();
      for (int i = 0; i < zValues.Length; i++)
      {
         points.Add(new OxyPlot.DataPoint( (i+1), zValues[i]));
      }
      return points;
    }

    private static PlotModel CreateGridlinesModel(PlotModel model, LineStyle horizontal, LineStyle vertical)
    {
      model.Axes.Add(new LinearAxis
      {
        Position = AxisPosition.Bottom,
        MajorGridlineStyle = vertical,
        MinorGridlineStyle = vertical == LineStyle.Solid ? LineStyle.Dot : LineStyle.None,
        MaximumPadding = 0,
        MinimumPadding = 0
      });
      model.Axes.Add(new LinearAxis
      {
        Position = AxisPosition.Left,
        MajorGridlineStyle = horizontal,
        MinorGridlineStyle = horizontal == LineStyle.Solid ? LineStyle.Dot : LineStyle.None,
        MaximumPadding = 0,
        MinimumPadding = 0
      });
      return model;
    }

    public static PlotModel ToolTips()
    {
      var model = new PlotModel { Title = "Tool tips" };
      model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom });
      model.Axes.Add(new LinearAxis { Position = AxisPosition.Left });
      model.Annotations.Add(new LineAnnotation { Slope = 0.1, Intercept = 1, Text = "LineAnnotation", ToolTip = "This is a tool tip for the LineAnnotation" });
      model.Annotations.Add(new RectangleAnnotation { MinimumX = 20, MaximumX = 70, MinimumY = 10, MaximumY = 40, TextRotation = 10, Text = "RectangleAnnotation", ToolTip = "This is a tooltip for the RectangleAnnotation", Fill = OxyColor.FromAColor(99, OxyColors.Blue), Stroke = OxyColors.Black, StrokeThickness = 2 });
      model.Annotations.Add(new EllipseAnnotation { X = 20, Y = 60, Width = 20, Height = 15, Text = "EllipseAnnotation", ToolTip = "This is a tool tip for the EllipseAnnotation", TextRotation = 10, Fill = OxyColor.FromAColor(99, OxyColors.Green), Stroke = OxyColors.Black, StrokeThickness = 2 });
      model.Annotations.Add(new PointAnnotation { X = 50, Y = 50, Text = "P1", ToolTip = "This is a tool tip for the PointAnnotation" });
      model.Annotations.Add(new ArrowAnnotation { StartPoint = new DataPoint(8, 4), EndPoint = new DataPoint(0, 0), Color = OxyColors.Green, Text = "ArrowAnnotation", ToolTip = "This is a tool tip for the ArrowAnnotation" });
      model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(60, 60), Text = "TextAnnotation", ToolTip = "This is a tool tip for the TextAnnotation" });
      return model;
    }

    public static PlotModel InvisibleVerticalAxis()
    {
      var model = new PlotModel { Title = "Invisible vertical axis" };
      model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom });
      model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, IsAxisVisible = false });
      model.Series.Add(new FunctionSeries(x => Math.Sin(x) / x, -5, 5, 0.1));
      return model;
    }


    private static void SmoothContour(List<DataPoint> points, int level = 1, int severity = 1)
    {
      for (int ii = 0; ii < level; ii++)
      {
        for (int i = 1; i < points.Count; i++)
        {
          var start = (i - severity > 0 ? i - severity + 1 : 0);
          var end = (i + severity < points.Count ? i + severity + 1 : points.Count);

          double sumX = 0, sumY = 0;

          for (int j = start; j < end; j++)
          {
            sumX += points[j].X;
            sumY += points[j].Y;
          }

          DataPoint sum = new DataPoint(sumX, sumY);

          DataPoint avg = new DataPoint(sum.X / (end - start), sum.Y / (end - start));

          points[i] = avg;

        }
      }
    }


    //("Select range")]
    public static PlotModel SelectRange()
    {
      //初始化X轴/Y轴
      var model = new PlotModel { Title = "", Subtitle = "轮廓线" };
      model.PlotType = PlotType.Cartesian;  //make sure x/y axis have the same ratio
      LineSeries ls = new LineSeries();
      ls.Color = OxyColors.Cyan;
      ///ls.LineStyle = LineStyle.Dot;
      ls.StrokeThickness = 1;
      ls.MarkerType = MarkerType.Circle;
      ls.MarkerSize = 1;
      ls.MarkerStroke = OxyColors.Cyan;
      //ls.MarkerFill = OxyColors.SkyBlue;
      ls.MarkerStrokeThickness = 1;

      double[] data = ReadTxtFile();
      List<OxyPlot.DataPoint> points = GetPoints(data);
      SmoothContour(points,1);
      double abs = data.Max() - data.Min();
      double max = data.Max()+abs;
      double min = data.Min()-abs;

      foreach (OxyPlot.DataPoint p in points)
      {
        ls.Points.Add(p);
      }
      model.Series.Add(ls);

      var yaxis = new LinearAxis
      {
        Position = AxisPosition.Left,   //坐标轴位置,左
        PositionTier = 0,     //坐标轴离图表位置
        IsAxisVisible= true,  //坐标轴是否显示
        Layer = AxisLayer.BelowSeries,    //坐标轴层级
        //视图缩放平移最大值
        FilterMinValue = min,
        FilterMaxValue = max,

        //坐标轴绝对最大最小值
        AbsoluteMinimum = min,
        AbsoluteMaximum = max,
        //坐标轴固定范围最大最小值
        Minimum = min,
        Maximum = max,

        MinorStep = 0.05,   //辅刻线间隔
        MajorStep = 0.5,    //主刻线间隔
        MinimumMinorStep = 0.0001,  //辅刻线最小间隔
        MinimumMajorStep = 0.001,   //主刻线最小间隔
        MinimumPadding = 0.01,                     //最小值额外空间(0.01表示1%)(设置了Minimum则此处无效)
        MaximumPadding = 0.01,                    //最大值额外空间
        MinimumRange = 0,                          //最小范围(ActualMaximum-ActualMinimum > MinimumRange)
        MaximumRange = double.PositiveInfinity,    //最大范围(ActualMaximum-ActualMinimum < MinimumRange)
        MinimumDataMargin = 0,                     //最小值的屏幕空间数据边距
        MaximumDataMargin = 0,                     //最大值的屏幕空间数据边距
        MinimumMargin = 0,                         //最小值的屏幕空间边距
        MaximumMargin = 0,                         //最大值的屏幕空间边距
        TickStyle = TickStyle.Outside,             //刻度样式
        TicklineColor = OxyColors.White,           //刻度线颜色
        MinorTicklineColor = OxyColors.White,  //辅刻度线颜色
        AxislineStyle = LineStyle.None,            //坐标轴线样式
        AxislineColor = OxyColors.White,           //坐标轴线颜色
        AxislineThickness = 1.0,                   //坐标轴线粗细
        MajorGridlineStyle = LineStyle.None,                               //主网格线样式
        MajorGridlineColor = OxyColor.FromArgb(0x40, 0, 0, 0),             //主网格线颜色
        MajorGridlineThickness = 1,                                        //主网格线粗细
        MinorGridlineStyle = LineStyle.None,                               //辅网格线样式
        MinorGridlineColor = OxyColor.FromArgb(0x20, 0, 0, 0x00),          //辅网格线颜色
        MinorGridlineThickness = 1,                                        //辅网格线粗细
        ExtraGridlineStyle = LineStyle.Solid,                              //额外网格线样式
        ExtraGridlineColor = OxyColors.White,                              //额外网格线颜色
        ExtraGridlineThickness = 1,                                        //额外网格线粗细
        //MinorTickSize = 4,                         //辅刻度大小
        //MajorTickSize = 7,                         //主刻度大小
        StartPosition = 0,                         //坐标轴在图表区的起点(0-1)
        EndPosition = 1,                           //坐标轴在图表区的终点(0-1)
        TitlePosition = 0.5,                       //标题位置(0-1)
        TitleFormatString = "{0} [{1}]",           //标题格式化字符串(0代表Title,1代表Unit)
        TitleClippingLength = 0.9,                 //标题长度(0-1)
        TitleColor = OxyColors.White,          //标题颜色
        TitleFontSize = double.NaN,                //标题字体大小
        TitleFontWeight = FontWeights.Normal,      //标题字重
        ClipTitle = true,                          //是否截断标题
        Angle = 0,                                 //坐标轴标签角度
        IsZoomEnabled = true,                      //是否允许缩放
        IsPanEnabled = false,                       //是否允许平移
        //FilterMinValue = double.MinValue,          //可显示的最小值(小等于该值将不会显示)
        //FilterMaxValue = double.MaxValue,          //可显示的最大值(大等于该值将不会显示)
        FilterFunction = null,                     //过滤方法
        IntervalLength = 60,                       //主刻度划分份数
        AxisDistance = 0,                          //坐标轴和图表的距离
        AxisTitleDistance = 4,                     //坐标轴标题和标签的距离
        AxisTickToLabelDistance = 4,               //坐标轴刻度和标签的距离
        //DataMaximum = double.NaN,                  //数据最大值
        //DataMinimum = double.NaN,                  //数据最小值
    };
      var xaxis = new LinearAxis
      {
        Position = AxisPosition.Bottom,   //坐标轴位置,底部
        PositionTier = 0,     //坐标轴离图表位置
        IsAxisVisible = true,  //坐标轴是否显示
        Layer = AxisLayer.BelowSeries,    //坐标轴层级
        //视图缩放平移最大值
        FilterMaxValue = points.Count,
        FilterMinValue = 0,
        //坐标轴绝对最大最小值
        AbsoluteMinimum = 0,
        AbsoluteMaximum = points.Count,
        //坐标轴固定范围最大最小值
        Minimum = 0,
        Maximum = points.Count,

        MinorStep = 5,   //辅刻线间隔
        MajorStep = 50,    //主刻线间隔
        MinimumMinorStep = 1 ,  //辅刻线最小间隔
        MinimumMajorStep = 10,   //主刻线最小间隔
        MinimumPadding = 0.01 ,                     //最小值额外空间(0.01表示1%)(设置了Minimum则此处无效)
        MaximumPadding = 0.01 ,                    //最大值额外空间
        MinimumRange = 0,                          //最小范围(ActualMaximum-ActualMinimum > MinimumRange)
        MaximumRange = double.PositiveInfinity,    //最大范围(ActualMaximum-ActualMinimum < MinimumRange)
        MinimumDataMargin = 0,                     //最小值的屏幕空间数据边距
        MaximumDataMargin = 0,                     //最大值的屏幕空间数据边距
        MinimumMargin = 0,                         //最小值的屏幕空间边距
        MaximumMargin = 0,                         //最大值的屏幕空间边距
        TickStyle = TickStyle.None,             //刻度样式
        TicklineColor = OxyColors.Cyan,           //刻度线颜色
        MinorTicklineColor = OxyColors.Automatic,  //辅刻度线颜色
        AxislineStyle = LineStyle.None,            //坐标轴线样式
        AxislineColor = OxyColors.White,           //坐标轴线颜色
        AxislineThickness = 1.0,                   //坐标轴线粗细
        MajorGridlineStyle = LineStyle.None,                               //主网格线样式
        MajorGridlineColor = OxyColor.FromArgb(0x40, 0, 0, 0),             //主网格线颜色
        MajorGridlineThickness = 1,                                        //主网格线粗细
        MinorGridlineStyle = LineStyle.None,                               //辅网格线样式
        MinorGridlineColor = OxyColor.FromArgb(0x20, 0, 0, 0x00),          //辅网格线颜色
        MinorGridlineThickness = 1,                                        //辅网格线粗细
        ExtraGridlineStyle = LineStyle.Solid,                              //额外网格线样式
        ExtraGridlineColor = OxyColors.White,                              //额外网格线颜色
        ExtraGridlineThickness = 1,                                        //额外网格线粗细
        //MinorTickSize = 4,                         //辅刻度大小
        //MajorTickSize = 7,                         //主刻度大小
        StartPosition = 0,                         //坐标轴在图表区的起点(0-1)
        EndPosition = 1,                           //坐标轴在图表区的终点(0-1)
        TitlePosition = 0.5,                       //标题位置(0-1)
        TitleFormatString = "{0} [{1}]",           //标题格式化字符串(0代表Title,1代表Unit)
        TitleClippingLength = 0.9,                 //标题长度(0-1)
        TitleColor = OxyColors.White,          //标题颜色
        TitleFontSize = double.NaN,                //标题字体大小
        TitleFontWeight = FontWeights.Normal,      //标题字重
        ClipTitle = true,                          //是否截断标题
        Angle = 0,                                 //坐标轴标签角度
        IsZoomEnabled = true,                      //是否允许缩放
        IsPanEnabled = true,                       //是否允许平移
        //FilterMinValue = double.MinValue,          //可显示的最小值(小等于该值将不会显示)
        //FilterMaxValue = double.MaxValue,          //可显示的最大值(大等于该值将不会显示)
        FilterFunction = null,                     //过滤方法
        IntervalLength = 60,                       //主刻度划分份数
        AxisDistance = 0,                          //坐标轴和图表的距离
        AxisTitleDistance = 4,                     //坐标轴标题和标签的距离
        AxisTickToLabelDistance = 4,               //坐标轴刻度和标签的距离
                                                   //DataMaximum = double.NaN,                  //数据最大值
                                                   //DataMinimum = double.NaN,                  //数据最小值
      };

      model.Axes.Add(yaxis);
      model.Axes.Add(xaxis);
      model.Background = OxyColors.Black;
      model.PlotAreaBorderColor  = OxyColors.White;
      model.TextColor = OxyColors.White;
      //model.PlotAreaBackground= OxyColors.Black;

      var range = new RectangleAnnotation { Fill = OxyColor.FromAColor(120, OxyColors.Green), MinimumX = 0, MaximumX = 0 };
      range.FontSize = 18;
      model.Annotations.Add(range);

      double startx = double.NaN;

      model.MouseDown += (s, e) =>
      {
        if (e.ChangedButton == OxyMouseButton.Left)
        {
          startx = range.InverseTransform(e.Position).X;
          range.MinimumX = startx;
          range.MaximumX = startx;
          model.InvalidatePlot(true);
          e.Handled = true;
        }
        else if (e.ChangedButton == OxyMouseButton.Right)   //
        {
          if (BaseUnitType == CrossSectionBaseUnitType.None)
            return;
          else
          {
             switch (BaseUnitType)
            {
              case CrossSectionBaseUnitType.MaxPoint:
                DataPoint p = GetMaxPoint(data,points.ToArray(),(int)range.MinimumX, (int)range.MaximumX);
                //draw a point
                GrapPoints.Add(new PointAnnotation { X = p.X, Y = p.Y, Text = "P"+(GrapPoints.Count+1).ToString()});
                //model.Annotations.Add(new PointAnnotation { X = p.X, Y = p.Y, Text = "P1", ToolTip = "This is a tool tip for the PointAnnotation" });

                //reset
                BaseUnitType = CrossSectionBaseUnitType.None;
                break;
              case CrossSectionBaseUnitType.MinPoint:
                GetMinPoint(data,points.ToArray(),(int)range.MinimumX, (int)range.MaximumX);


                BaseUnitType = CrossSectionBaseUnitType.None;
                break;
              case CrossSectionBaseUnitType.MeanPoint:
                GetMeanPoint(data,points.ToArray(),(int)range.MinimumX, (int)range.MaximumX);


                BaseUnitType = CrossSectionBaseUnitType.None;
                break;
              case CrossSectionBaseUnitType.FitLine:
                FitLine(points.ToArray(),(int)range.MinimumX, (int)range.MaximumX);

                BaseUnitType = CrossSectionBaseUnitType.None;
                break;
              case CrossSectionBaseUnitType.FitCircle:
                FitCircle(points.ToArray(),(int)range.MinimumX, (int)range.MaximumX);

                BaseUnitType = CrossSectionBaseUnitType.None;
                break;
              default:
                break;
            }
          }
        }
      };
      model.MouseMove += (s, e) =>
      {
        if (!double.IsNaN(startx))
        {
          var x = range.InverseTransform(e.Position).X;
          //var y = range.InverseTransform(e.Position).Y;
          range.MinimumX = Math.Min(x, startx);
          range.MaximumX = Math.Max(x, startx);
          if((int)x<points.Count && (int)x >=0)
            range.Text = string.Format("(X:{0:0.000},Z:{1:0.000})", x, points[(int)x].Y);
          model.Subtitle = string.Format("X: {0:0.000} >> {1:0.000}", range.MinimumX, range.MaximumX);

          //////////////////////////////////////
          //test draw a line
          LineSeries  l = new LineSeries();
          l.Color = OxyColors.White;
          l.Points.Add(new DataPoint(range.MinimumX, points[(int)range.MinimumX].Y));
          l.Points.Add(new DataPoint(range.MaximumX, points[(int)range.MaximumX].Y));
          l.MarkerType = MarkerType.Circle;
          for(int i=1;i< model.Series.Count;i++)
          {
            model.Series.Remove(model.Series[i]);
          }
          model.Series.Add(l);
          //////////////////////////////////////////////////////////////////////
          ////test draw a circle
          ////model.Annotations.Clear();
          ////model.Annotations.Add(new EllipseAnnotation { X = range.MinimumX, Y = points[(int)range.MinimumX].Y, Width = 0.3*(xaxis.MinorStep/yaxis.MinorStep), Height = 0.3, Fill = OxyColors.Transparent, Stroke = OxyColors.Cyan, StrokeThickness = 1 });
          //////////////////////////////////////////////////////////////////////
          ///
          ///////////////////////////////////////////////////////////////////
          ////draw a point
          //model.Annotations.Add(new PointAnnotation { X = 50, Y = 50, Text = "P1", ToolTip = "This is a tool tip for the PointAnnotation" });
          ////////////////////////////////////////////////////////////////////////////////////////
          

          model.InvalidatePlot(true);
          e.Handled = true;
        }
      };

      model.MouseUp += (s, e) =>
      {
        startx = double.NaN;
      };

      return model;
    }

    public static PlotModel EllipseAnnotation()
    {
      var model = new PlotModel { Title = "EllipseAnnotation" };
      model.PlotType = PlotType.Cartesian;
      model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom });
      model.Axes.Add(new LinearAxis { Position = AxisPosition.Left });
      model.Annotations.Add(new EllipseAnnotation { X = 20, Y = 60, Width = 20, Height = 15, Text = "EllipseAnnotation", TextRotation = 10, Fill = OxyColor.FromAColor(99, OxyColors.Green), Stroke = OxyColors.Black, StrokeThickness = 2 });

      model.Annotations.Add(new EllipseAnnotation { X = 20, Y = 20, Width = 20, Height = 20, Fill = OxyColor.FromAColor(99, OxyColors.Green), Stroke = OxyColors.Black, StrokeThickness = 2 });
      model.Annotations.Add(new EllipseAnnotation { X = 30, Y = 20, Width = 20, Height = 20, Fill = OxyColor.FromAColor(99, OxyColors.Red), Stroke = OxyColors.Black, StrokeThickness = 2 });
      model.Annotations.Add(new EllipseAnnotation { X = 25, Y = 30, Width = 20, Height = 20, Fill = OxyColor.FromAColor(99, OxyColors.Blue), Stroke = OxyColors.Black, StrokeThickness = 2 });
      return model;
    }


    private void Formoxyplot_Load(object sender, EventArgs e)
    {
      plot1.Model = SelectRange();
      //plot1.Model = CreateGridlinesModel(plot1.Model, LineStyle.Solid, LineStyle.None);

      //plot1.Model = EllipseAnnotation();
    }

    private void Model_KeyDown(object sender, OxyKeyEventArgs e)
    {
      if(e.Key == OxyKey.Right)
      {
        plot1.InvalidatePlot(true);
      }
    }

    enum MouseState
    {

    }
    private void Model_MouseUp(object sender, OxyMouseEventArgs e)
    {
      OxyPlot.DataPoint p = OxyPlot.Axes.Axis.InverseTransform(e.Position, plot1.Model.DefaultXAxis, plot1.Model.DefaultYAxis);
      if (TwoPointFs.Count == 2)
      {
        var rect1 = new RectangleAnnotation()
        {
          MinimumX = TwoPointFs[0].X,
          MaximumX = TwoPointFs[1].X,
          MinimumY = TwoPointFs[0].Y,
          MaximumY = TwoPointFs[1].Y,
          Fill = OxyColor.FromRgb(155, 188, 243),//sky blue
          Stroke = OxyColors.Transparent
        };
        rect1.Selectable = true;
        model.Annotations.Add(rect1);

        TwoPointFs.Clear();
      }
      else
      {
        TwoPointFs.Add(new PointF((float)p.X, (float)p.Y));
      }
    }

    private void Model_MouseMove(object sender, OxyMouseEventArgs e)
    {
      throw new NotImplementedException();
    }

    List<PointF> TwoPointFs = new List<PointF>(); 
    private void Model_MouseDown(object sender, OxyMouseDownEventArgs e)
      {

        double x = e.Position.X;
        double y = e.Position.Y;
        OxyPlot.DataPoint p = OxyPlot.Axes.Axis.InverseTransform(e.Position, plot1.Model.DefaultXAxis, plot1.Model.DefaultYAxis);

        this.Text = ($"X is {x} and Y is {y} and Inverse is {p.ToString()}");

      if (TwoPointFs.Count == 2)
      {
        var rect1 = new RectangleAnnotation()
        {
          MinimumX = TwoPointFs[0].X,
          MaximumX = TwoPointFs[1].X,
          MinimumY = TwoPointFs[0].Y,
          MaximumY = TwoPointFs[1].Y,
          Fill = OxyColor.FromRgb(155, 188, 243),//sky blue
          Stroke = OxyColors.Transparent
        };
        model.Annotations.Add(rect1);

        TwoPointFs.Clear();
      }
      else
      {
        TwoPointFs.Add(new PointF((float)p.X,(float)p.Y));
      }
    }


    private void 最高点ToolStripMenuItem_Click(object sender, EventArgs e)
    {
      BaseUnitType = CrossSectionBaseUnitType.MaxPoint;
    }

    private void 最低点ToolStripMenuItem_Click(object sender, EventArgs e)
    {
      BaseUnitType = CrossSectionBaseUnitType.MinPoint;
    }

    private void 平均点ToolStripMenuItem_Click(object sender, EventArgs e)
    {
      BaseUnitType = CrossSectionBaseUnitType.MeanPoint;
    }



    private static void FitCircle(DataPoint[] ps,int startX, int endX)
    {
      DataPoint[] data = GetPointsByRange(ps,startX,endX);
    }

    private static void FitLine(DataPoint[] ps,int startX, int endX)
    {
      DataPoint[] data = GetPointsByRange(ps, startX, endX);
    }

    private static DataPoint GetMeanPoint(double[] data, DataPoint[] dataPoints,int startX, int endX)
    {
      double[] getData = GetDataByRange(data, startX, endX);
      List<double> tmpList = getData.ToList();
      tmpList.Sort();
      double value = tmpList[(int)(tmpList.Count/2.0)];
      int index = data.ToList().IndexOf(value);

      return dataPoints[index];
    }

    private static DataPoint GetMinPoint(double[] data, DataPoint[] dataPoints, int startX,int endX)
    {
      double[] getData = GetDataByRange(data, startX, endX);
      List<double> tmpList = getData.ToList();
      tmpList.Sort();
      double value = double.MaxValue;
      if (tmpList[0] < 0)
        value = tmpList[tmpList.Count - 1];
      else
        value = tmpList[0];
      int index = data.ToList().IndexOf(value);

      return dataPoints[index];
    }

    private static DataPoint GetMaxPoint(double[] data, DataPoint[] dataPoints,int startX,int endX)
    {
      double[] getData = GetDataByRange(data,startX,endX);
      List<double> tmpList = getData.ToList();
      tmpList.Sort();
      double value = double.MaxValue;
      if (tmpList[0] > 0)
        value=tmpList[tmpList.Count-1];
      else
        value = tmpList[0];
      int index = data.ToList().IndexOf(value);

      return dataPoints[index];
    }


    private static DataPoint[] GetPointsByRange(DataPoint[] points,int startX,int endX)
    {
      try
      {
        if (endX - startX <= 0)
          return new DataPoint[0];
      }
      catch
      {
        return new DataPoint[0];
      }
      DataPoint[] getPoints = new DataPoint[endX-startX];

      if (points != null)
      {
         getPoints = (points.ToList().GetRange(startX, endX-startX)).ToArray();
      }
      else
        return new DataPoint[0];

      return getPoints;
        
    }

    private static double[] GetDataByRange(double[] data, int startX, int endX)
    {
      try
      {
        if (endX - startX <= 0)
          return new double[0];
      }
      catch
      {
        return new double[0];
      }
      double[] getData = new double[endX - startX];

      if (data != null)
      {
        getData = (data.ToList().GetRange(startX, endX - startX)).ToArray();
      }
      else
        return new double[0];

      return getData;

    }

    void Refresh()
    {
      //点显示
      if (GrapPoints.Count > 0 && plot1.Model != null)
      {
        plot1.Model.Annotations.Clear();
        foreach (var point in GrapPoints)
        {
          plot1.Model.Annotations.Add(point);
        }

        plot1.Model.MouseMove += (s, ee) =>
        {
          foreach (var ann in plot1.Model.Annotations)
          {
            HitTestResult hitTestResult = ann.HitTest(new HitTestArguments(ee.Position, 10));
            if (hitTestResult != null)
            {

              switch (ann.GetType().Name)
              {
                case "PointAnnotation":
                  int i = Convert.ToInt32(((PointAnnotation)(hitTestResult.Element)).Text.Replace("P", "")) - 1;
                  PointAnnotation p = (PointAnnotation)(plot1.Model.Annotations[i]);
                  p.TextColor = OxyColors.Green;
                  //plot1.Model.Annotations.Add(p);                  
                  //plot1.Model.Annotations.RemoveAt(i);
                  //ann.TextColor = OxyColors.Red;

                  break;


              }



              return;
            }
          }

        };

        //plot1.Model.MouseDown += (s, ee) =>
        //{
        //  var args = new HitTestArguments(ee.Position, 10);
        //  foreach (var result in plot1.Model.Annotations[0].HitTest(args))
        //  {
        //    ee.HitTestResult = result;
        //    result.Element.OnMouseDown(e);
        //    if (ee.Handled)
        //    {
        //      this.currentMouseEventElement = result.Element;
        //      return;
        //    }
        //  }

        //if (!ee.Handled)
        //{
        //  point.OnMouseDown(sender, ee);
        //}
        //};

      }

    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    //[Obsolete]
    private void timer1_Tick(object sender, EventArgs e)
    {
      //点显示
      if (GrapPoints.Count > 0 && plot1.Model != null)
      {
        plot1.Model.Annotations.Clear();
         foreach(var point in GrapPoints)
        {
          plot1.Model.Annotations.Add(point);
        }

        plot1.Model.MouseMove += (s, ee) =>
        {
          foreach (var ann in plot1.Model.Annotations)
          {
            HitTestResult hitTestResult = ann.HitTest(new HitTestArguments(ee.Position, 10));
            if (hitTestResult != null)
            {

              switch(ann.GetType().Name)
              {
                case "PointAnnotation":
                  int i = Convert.ToInt32(((PointAnnotation)(hitTestResult.Element)).Text.Replace("P",""))-1;
                  PointAnnotation p = (PointAnnotation)(plot1.Model.Annotations[i]);
                  p.TextColor = OxyColors.Green;
                  p.FontSize = 30;
                  //plot1.Model.Annotations.Add(p);                  
                  //plot1.Model.Annotations.RemoveAt(i);
                  //ann.TextColor = OxyColors.Red;
                  SelectPoints.Add(p);  
                  break;

                
              }



              return;
            }
          }

        };

        //plot1.Model.MouseDown += (s, ee) =>
        //{
        //  var args = new HitTestArguments(ee.Position, 10);
        //  foreach (var result in plot1.Model.Annotations[0].HitTest(args))
        //  {
        //    ee.HitTestResult = result;
        //    result.Element.OnMouseDown(e);
        //    if (ee.Handled)
        //    {
        //      this.currentMouseEventElement = result.Element;
        //      return;
        //    }
        //  }

          //if (!ee.Handled)
          //{
          //  point.OnMouseDown(sender, ee);
          //}
        //};

      }
    }

    private void toolStripSplitButtonPPHeight_ButtonClick(object sender, EventArgs e)
    {
      if (SelectPoints.Count >= 2)
      {
        //test draw a line
        LineSeries l1 = new LineSeries();
        l1.Color = OxyColors.White;
        l1.Points.Add(new DataPoint(SelectPoints[0].X, SelectPoints[0].Y));
        l1.Points.Add(new DataPoint(SelectPoints[0].X, SelectPoints[SelectPoints.Count-1].Y));
        l1.MarkerType = MarkerType.Circle;

        LineSeries l2 = new LineSeries();
        l2.Color = OxyColors.White;
        l2.Points.Add(new DataPoint(SelectPoints[0].X, SelectPoints[SelectPoints.Count - 1].Y));
        l2.Points.Add(new DataPoint(SelectPoints[SelectPoints.Count - 1].X, SelectPoints[SelectPoints.Count - 1].Y));
        l2.MarkerType = MarkerType.Circle;
        for (int i = 1; i < plot1.Model.Series.Count; i++)
        {
          plot1.Model.Series.Remove(plot1.Model.Series[i]);
        }
        plot1.Model.Series.Add(l1);
        plot1.Model.Series.Add(l2);

        plot1.Model.Annotations.Add(new DelegateAnnotation(rc =>
        {
          const double FontSize = 20d;
          const double D = FontSize * 1.6;
          const double X = 20;
          double y = 20 - D;
          rc.DrawText(new ScreenPoint(X, y += D), "Default font", OxyColors.Black, null, FontSize);
          //rc.DrawText(new ScreenPoint(X, y += D), "Helvetica", OxyColors.Black, "Helvetica", FontSize);
          //rc.DrawText(new ScreenPoint(X, y += D), "Arial", OxyColors.Black, "Arial", FontSize);
          //rc.DrawText(new ScreenPoint(X, y += D), "Courier", OxyColors.Black, "Courier", FontSize);
          //rc.DrawText(new ScreenPoint(X, y += D), "Courier New", OxyColors.Black, "Courier New", FontSize);
          //rc.DrawText(new ScreenPoint(X, y += D), "Times", OxyColors.Black, "Times", FontSize);
          //rc.DrawText(new ScreenPoint(X, y + D), "Times New Roman", OxyColors.Black, "Times New Roman", FontSize);
        }));


      }
    }
  }

  /// <summary>
  /// Represents an annotation that renders by a delegate.
  /// </summary>
  public class DelegateAnnotation : Annotation
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="DelegateAnnotation"/> class.
    /// </summary>
    /// <param name="rendering">The rendering delegate.</param>
    public DelegateAnnotation(Action<IRenderContext> rendering)
    {
      this.Rendering = rendering;
    }

    /// <summary>
    /// Gets the rendering delegate.
    /// </summary>
    /// <value>
    /// The rendering.
    /// </value>
    public Action<IRenderContext> Rendering { get; private set; }

    /// <summary>
    /// Renders the annotation on the specified context.
    /// </summary>
    /// <param name="rc">The render context.</param>
    public override void Render(IRenderContext rc)
    {
      base.Render(rc);
      this.Rendering(rc);
    }

    /// <inheritdoc/>
    public override OxyRect GetClippingRect()
    {
      return OxyRect.Everything;
    }
  }

}