我目前正在使用GDI +绘制折线图,并使用Graphics.DrawCurve
来平滑线条。问题是曲线并不总是与我提供的点匹配,这使曲线在某些点上长出图形框架,如下所示(红色为Graphics.DrawLines
,绿色为{{ 1}})。
我将如何解决这个问题?
答案 0 :(得分:6)
最简单的解决方案是设置张力:
使用默认张力绘制绿色曲线,蓝色曲线设置张力Task<T>
:
0.1f
您需要测试什么是最佳折衷方案,private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawLines(Pens.Red, points.ToArray());
e.Graphics.DrawCurve(Pens.Green, points.ToArray());
e.Graphics.DrawCurve(Pens.Blue, points.ToArray(), 0.1f);
}
仍然可以,0.2f
已经透支了很多..
要获得真正好的解决方案,您需要使用DrawBeziers
。这将允许您绘制可以通过点的曲线,而无需任何透支,并完全控制曲线的半径;但要这样你就需要找到&#39;,即计算好 0.3f
,这不过是微不足道的......:
这个结果绝不是完美的,但已经足够复杂了......我已经以相同的颜色显示了control points
及其各自的curve points
。对于每个点,都有传入和传出控制点。对于平滑曲线,它们需要在曲线点上具有相同的切线/渐变。
我使用一些辅助函数来计算关于段的一些内容:
main函数计算control points
的数组,即bezier points
,每对之间上一个和下一个 { {1}}。
在curve points
事件中,它的使用方式如下:
control points
以下是我使用的功能:
Paint
最后是主要功能;在这里我做了一个区别:极值点(极小值和最大值)的控制点应该与点本身在同一高度。这样可以防止垂直溢出。它们很容易找到:它们的渐变迹象总是会有所不同。
其他点需要对传入和传出控制点具有相同的渐变。我使用段之间的平均值&#39;梯度。 (也许一个称重的平均值会更好......)然后我根据段长度来衡量它们的距离..
List<PointF> bezz = getBezz(points);
using (Pen pen = new Pen(Color.Black, 2f))
e.Graphics.DrawBeziers(pen, bezz.ToArray());
请注意,对于具有相同x坐标的点的情况,我没有编码。所以这对于功能图表来说是可以的。但不是说,比如数字,例如分..
答案 1 :(得分:0)
也许你只是想看看“超越边界”问题,因为这不是超调问题,而是有界限。在这种情况下,您可以使用System.Drawing.Drawing2D.GraphicsPath对象确定曲线的实际边界:
GraphicsPath gp = new GraphicsPath();
gp.AddCurve(listOfPoints);
RectangleF bounds = gp.GetBounds();
您可以直接绘制GraphicsPath:
graphics.DrawPath(Pens.Black, gp);
就解决边界问题而言,线必然会超过某些轴上的顶点。当线条与边界对齐时,更容易看到这一事实。
鉴于以下几点:
为了使它们弯曲,它们必须以某种方式超出界限:
如果您永远不想超过它们的垂直边界,您可以简单地确保贝塞尔曲线手柄具有与顶点相同的Y值,但它们会在X上超调:
反之亦然:
你可以故意下冲到足以避免曲线过冲的方式。这可以通过交换贝塞尔手柄来完成,贝塞尔手柄可能位于线中心,顶点为: