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

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

我使用创建一条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上方。

例:

在此处输入图像描述

我有一个想法,使用SeriesChartType.Range如下。

 private void UpdateChart(float straight_line, List 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中,它们彼此不相交。

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

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

通过使用正确的数据编写Paint事件,可以非常精确地着色LinesSpline Lines图表类型。 必要的像素值可以通过轴函数ValueToPixelPosition 。 在这里看另一个例子!

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

为了测试和乐趣,我添加了一个可移动的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 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 getPaths(ChartArea ca, Series ser, double limit) { List paths = new List(); List points = new List(); 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. 在同一图表上创建新的柱形图。
  3. 将其值设置为与锯齿线相同,但是限制在您已经拥有的直线的y值。
  4. 将列的填充颜色设置为白色。 这将阻止红线填充任何不在线之间的区域。