C# 如何在直线上和曲线下填充所有内容?

C# 如何在直线上和曲线下填充所有内容?,c#,winforms,charts,C#,Winforms,Charts,我正在Windows窗体中使用图表组件 我使用 chart1.Series["Grenzwert"].Points.Add(new DataPoint(0, y)); chart1.Series["Grenzwert"].Points.Add(new DataPoint(maxwidth, y)); 此外,我还绘制了一系列由直线连接的点,我们称之为曲线 如何在直线上和曲线下显示所有内容 列填充整个区域,而不仅仅是直线上方 例如: 您可以按如下方式执行此操作 像以前一样设置列填充。一切都是红色的

我正在Windows窗体中使用图表组件

我使用

chart1.Series["Grenzwert"].Points.Add(new DataPoint(0, y));
chart1.Series["Grenzwert"].Points.Add(new DataPoint(maxwidth, y));
此外,我还绘制了一系列由直线连接的点,我们称之为曲线

如何在直线上和曲线下显示所有内容

列填充整个区域,而不仅仅是直线上方

例如:


您可以按如下方式执行此操作

  • 像以前一样设置列填充。一切都是红色的
  • 在同一图表上创建新的柱状图
  • 将其值设置为与锯齿线相同,但上限为现有直线的y值
  • 将列的填充颜色设置为白色。这将阻止线之间以外任何区域的红色填充
    我有一个想法,使用
    序列chartType.Range
    如下

    private void UpdateChart(float straight_line, List<DataPoint> curve)
    {
        float y = straight_line;    // YValue of the straight line
        var list = curve.ToList();  // Clone the curve
    
        int count = list.Count - 2;
    
        for (int i = 0; i < count; i++)  // Calculate intersection point between the straight line and a line between (x0,y0) and (x1,y1) 
        {
            double x0 = list[i + 0].XValue;
            double y0 = list[i + 0].YValues[0];
            double x1 = list[i + 1].XValue;
            double y1 = list[i + 1].YValues[0];
    
            if ((y0 > y && y1 < y) || (y0 < y && y1 > y))
            {
                double x = (y - y0) * (x1 - x0) / (y1 - y0) + x0;
    
                list.Add(new DataPoint(x, y));
            }
        }
    
        list.Sort((a, b) => Math.Sign(a.XValue - b.XValue));
    
        chart1.Series[0].Points.Clear();
        chart1.Series[0].ChartType = SeriesChartType.Range;
        chart1.Series[0].Color = Color.Red;
        chart1.Series[0].BorderColor = Color.Cyan;
        chart1.ChartAreas[0].AxisX.Minimum = 0;
        chart1.ChartAreas[0].AxisX.Interval = 1;
    
        for (int i = 0; i < list.Count; i++)
        {
            double xx = list[i].XValue;
            double yy = list[i].YValues[0];
            if (yy > y)
            {
                chart1.Series[0].Points.AddXY(xx, y, yy);
            }
            else
            {
                chart1.Series[0].Points.AddXY(xx, yy, yy);
            }
        }
    
        chart1.ChartAreas[0].AxisY.StripLines.Add(new StripLine { IntervalOffset = y, Interval = 0, BorderColor = Color.Orange, BorderWidth = 2 });
    
    }
    
    private void UpdateChart(浮动直线,列表曲线)
    {
    浮动y=直线;//直线的y值
    var list=curve.ToList();//克隆曲线
    int count=list.count-2;
    对于(int i=0;iy&&y1y))
    {
    双x=(y-y0)*(x1-x0)/(y1-y0)+x0;
    添加(新数据点(x,y));
    }
    }
    list.Sort((a,b)=>数学符号(a.XValue-b.XValue));
    chart1.Series[0]。Points.Clear();
    chart1.Series[0]。ChartType=SerieChartType.Range;
    图表1.系列[0]。颜色=颜色。红色;
    chart1.系列[0]。BorderColor=Color.Cyan;
    chart1.ChartAreas[0]。AxisX.Minimum=0;
    chart1.ChartAreas[0]。AxisX.Interval=1;
    for(int i=0;iy)
    {
    图1.系列[0].点.AddXY(xx,y,yy);
    }
    其他的
    {
    图1.系列[0].点.AddXY(xx,yy,yy);
    }
    }
    chart1.ChartAreas[0].AxisY.StripLines.Add(新的带状线{IntervalOffset=y,Interval=0,BorderColor=Color.Orange,BorderWidth=2});
    }
    
    如下图所示,判断直线与(x0,y0)和(x1,y1)之间的直线是否相交,情况1为
    (y0y)
    ,情况2为
    (y0>y&&y1
    。在案例1和案例2中,它们彼此相交。在案例3和案例4中,它们彼此不相交


    这已经很晚了,也不是很短,但在我看来,这是给图表中的区域着色的最好方法

    通过使用正确的数据对
    Paint
    事件进行编码,可以非常精确地为
    样条曲线
    图表类型着色。通过轴函数
    ValueToPixelPosition
    可以获得必要的像素值。再看一个例子

    下面的代码稍微长一些,因为我们需要在的开始结束处添加某些点,这两个点都是图表每个彩色区域。除此之外,它非常简单:通过使用
    AddLines
    添加像素坐标来创建
    GraphicsPaths
    ,并在
    Paint
    事件中填充
    GraphicsPaths

    为了测试和娱乐,我添加了一个可移动的
    水平线批注
    ,这样我可以在上下拖动它时看到区域的变化

    Paint
    事件相当简单;它指的是一个
    水平线批注hl

    private void chart1_Paint(object sender, PaintEventArgs e)
    {
        double limit = hl.Y;    // get the limit value
        hl.X = 0;               // reset the x value of the annotation
    
        List<GraphicsPath> paths = getPaths(chart1.ChartAreas[0], chart1.Series[0], limit);
    
        using (SolidBrush brush = new SolidBrush(Color.FromArgb(127, Color.Red)))
            foreach (GraphicsPath gp in paths)
                { e.Graphics.FillPath(brush, gp); gp.Dispose(); }
    }
    
    HorizontalLineAnnotation
    的设置如下:

    hl = new HorizontalLineAnnotation();
    hl.AllowMoving = true;
    hl.LineColor = Color.OrangeRed;
    hl.LineWidth = 1;
    hl.AnchorDataPoint = S1.Points[1];
    hl.X = 0;
    hl.Y = 0;         // or some other starting value..
    hl.Width = 100;   // percent of chart..
    hl.ClipToChartArea = chart1.ChartAreas[0].Name;  // ..but clipped
    chart1.Annotations.Add(hl);
    

    工作,但它阻止网格以及后面的所有其他曲线。我只需要画有趣的区域,而不是用视觉技巧…嗯。我不确定有没有没有没有视觉技巧的方法。让我们希望另一张海报有更好的解决方案。它有效,但我不明白你在做什么。你能详细说明并创建一个类似于
    private void UpdateChart(浮动直线,列表曲线)
    这样的函数吗。你能详细说明它是如何工作的吗?特别是
    if((y0>y&&y1y))
    部分。你能帮我一下吗?这么棒的功能!非常感谢。
    PointF pointfFromDataPoint(DataPoint dp, ChartArea ca)
    {
        return new PointF( (float)ca.AxisX.ValueToPixelPosition(dp.XValue),
                           (float)ca.AxisY.ValueToPixelPosition(dp.YValues[0]));
    }
    
    PointF median(PointF p1, PointF p2, float y0)
    {
        float x0 = p2.X - (p2.X - p1.X) * (p2.Y - y0) / (p2.Y - p1.Y);
        return new PointF(x0, y0);
    }
    
    hl = new HorizontalLineAnnotation();
    hl.AllowMoving = true;
    hl.LineColor = Color.OrangeRed;
    hl.LineWidth = 1;
    hl.AnchorDataPoint = S1.Points[1];
    hl.X = 0;
    hl.Y = 0;         // or some other starting value..
    hl.Width = 100;   // percent of chart..
    hl.ClipToChartArea = chart1.ChartAreas[0].Name;  // ..but clipped
    chart1.Annotations.Add(hl);