如何通过直线和曲线填充所有内容?

时间:2014-01-08 16:28:32

标签: c# winforms charts

我在Windows窗体中使用Charts组件。

我使用

创建straight line
chart1.Series["Grenzwert"].Points.Add(new DataPoint(0, y));
chart1.Series["Grenzwert"].Points.Add(new DataPoint(maxwidth, y));

我还绘制了一系列由一条线连接的点,我们称之为curve

如何在straight linecurve填充下显示所有内容?

列填充整个区域,而不仅仅是straight line上方。

示例:

enter image description here

3 个答案:

答案 0 :(得分:4)

这是迟到的,并不是很短暂,但是它是在图表中为区域着色的最佳方式。

通过使用正确的数据对Lines事件进行编码,Spline以及Paint图表类型可以非常精确地着色。轴函数ValueToPixelPosition可以获得必要的像素值。有关其他示例,请参阅here

以下代码有点长,因为我们需要在的开头结尾处添加某些点图表每个颜色区域。除此之外,它非常直接:通过使用GraphicsPaths添加像素坐标来创建AddLines并填充GraphicsPaths事件中的Paint

为了测试和娱乐我添加了一个可移动的HorizontalLineAnnotation,所以当我上下拖动它时,我可以看到区域的变化..:

enter image description here enter image description here enter image description here

Paint事件相当简单;它指的是HorizontalLineAnnotation 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(); }
}

获取路径的代码显然太长了以至于不舒服..:

List<GraphicsPath> getPaths(ChartArea ca, Series ser, double limit)
{
    List<GraphicsPath> paths = new List<GraphicsPath>();
    List<PointF> points = new List<PointF>();
    int first = 0;
    float limitPix = (float)ca.AxisY.ValueToPixelPosition(limit);

    for (int i = 0; i < ser.Points.Count; i++)
    {
        if ((ser.Points[i].YValues[0] > limit) && (i < ser.Points.Count - 1))
        {
            if (points.Count == 0) first = i;  // remember group start
            // insert very first point:
            if (i == 0) points.Insert(0, new PointF( 
                 (float)ca.AxisX.ValueToPixelPosition(ser.Points[0].XValue), limitPix));

            points.Add( pointfFromDataPoint(ser.Points[i], ca)); // the regular points
        }
        else
        {
            if (points.Count > 0)
            {
                if (first > 0)  points.Insert(0, median(  
                                  pointfFromDataPoint(ser.Points[first - 1], ca),
                                  pointfFromDataPoint(ser.Points[first], ca), limitPix));
                if (i == ser.Points.Count - 1)
                {
                    if ((ser.Points[i].YValues[0] > limit)) 
                         points.Add(pointfFromDataPoint(ser.Points[i], ca));
                    points.Add(new PointF( 
                  (float)ca.AxisX.ValueToPixelPosition(ser.Points[i].XValue), limitPix));
                }
                else
                    points.Add(median(pointfFromDataPoint(ser.Points[i - 1], ca),
                                 pointfFromDataPoint(ser.Points[i], ca), limitPix));

                GraphicsPath gp = new GraphicsPath();
                gp.FillMode = FillMode.Winding;
                gp.AddLines(points.ToArray());
                gp.CloseFigure();
                paths.Add(gp);
                points.Clear();
            }
        }
    }
    return paths;
}

它使用两个辅助函数:

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);
}

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);

答案 1 :(得分:2)

我知道如下使用SeriesChartType.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 });

}

如下图所示,判断直线与(x0,y0)和(x1,y1)之间的直线是否相交,情况1为(y0 < y && y1 > y),情况2为(y0 > y && y1 < y)。在情况1和情况2中,它们彼此相交。在案例3和案例4中,它们彼此不相交。

the below drawing to judge whether the straight line and a line between (x0,y0) and (x1,y1) intersect

答案 2 :(得分:0)

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

  1. 像以前一样设置列填充。一切都会变红。
  2. 在同一图表上创建新的列图。
  3. 将其值设置为与锯齿线相同的值,但加上您已经拥有的直线的y值。
  4. 将列的填充颜色设置为白色。这将阻止红线填充任何不在线之间的区域。