如何填充直线上和曲线下的所有内容?

Dea*_*irl 5 c# charts winforms

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

我创建了一个straight line使用

chart1.Series["Grenzwert"].Points.Add(new DataPoint(0, y));
chart1.Series["Grenzwert"].Points.Add(new DataPoint(maxwidth, y));
Run Code Online (Sandbox Code Playgroud)

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

如何显示所有内容的填充straight linecurve填充不足?

Column 填满整个区域,而不仅仅是在 上方straight line

例子:

在此处输入图片说明

TaW*_*TaW 6

这很晚而且不是很短,但我认为这是在图表中为区域着色的最佳方式。

Lines,也是Splinecharttypes可以通过编码的非常精确的彩色Paint用正确的数据事件。可以通过axis函数获得必要的像素值ValueToPixelPosition。请参见此处的另一个示例!

下面的代码是一个长一点,因为我们需要在开始添加某些点结束两个图表每个颜色的区域。除此之外,它是非常简单的:创建GraphicsPaths通过增加像素坐标AddLines,并填写GraphicsPathsPaint事件。

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

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

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(); }
}
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

它使用两个辅助函数:

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);
}
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)


use*_*781 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 });

}
Run Code Online (Sandbox Code Playgroud)

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

下图判断直线与(x0,y0)和(x1,y1)之间的直线是否相交