GDI +线条绘制算法

时间:2011-10-12 15:58:09

标签: c# graphics gdi+

我无法理解GDI +在曲面上画线的方式,可能有一些算法可以做到。

对于前。让我们采取10x10像素的表面。

  Bitmap img = new Bitmap(10, 10);

现在让我们在这个表面上绘制一条线,宽度为5px,顶部偏移为5px。

  using (var g = Graphics.FromImage(img))
     {
        g.Clear(Color.White);
        var pen = new Pen(Color.Brown);
        pen.Width = 5;
        g.DrawLine(pen, 0F, 5F, 10F,  5F);
     }

我们会得到:

enter image description here

绘图没有从像素#5开始,它从像素#4开始。 很明显,起点是单独计算的。但是如何?

我试图获得规律性,并得到了这个:

  y = offset + width/2 - 1

其中y是实际起点y,偏移是选择起点y。

但在某些情况下,这不起作用。例如,让我们取宽度= 6,选择顶部偏移= 0,我们将得到y = 2,它将以这种方式绘制:

enter image description here

它必须显示6个像素,但它没有。

因此选择起点必须有更一般的算法,但我真的不知道它是什么。 任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:3)

线条图中没有offset。您在DrawLine方法中指定的坐标定义了线的中心。顶部像素为y - width / 2,底部为y - width / 2 + width - 1。第二个公式考虑了width / 2向下舍入的事实。此外,顶行为y = 0,底线为y = 9。那么,对你来说第一行:

top = 5 - (5 / 2) = 3
bottom = 5 - (5 / 2) + 5 - 1 = 7

和第二行:

top = 2 - (6 / 2) = -1
bottom = 2 - (6 / 2) + 6 - 1 = 4

顶边被剪裁到位图的边缘,因此线宽减小了。

答案 1 :(得分:1)

在第一个示例中,它看起来像一条宽度为5像素的行,以第5行为中心(计数从0开始,而不是1)。 这似乎是一个合理的结果。

在第二个示例中,它看起来像一条宽度为6的线,位于第1行和第2行之间,顶行被切掉,因为它超出了图像的边界。

答案 2 :(得分:0)

GDI +中的坐标不指定像素本身,而是指定其中心的(无限小)点。因此(0f,5f)表示第一列和第六行中像素的中心(因为计数从零开始)。因此,从现在开始,我将区分坐标像素行

绘制直线时,GDI +概念性地沿着这些坐标定义的直线移动指定宽度的笔。请注意,您可以通过指定Pen.StartCapPen.EndCap在行的开头和结尾定义此笔的确切形状。

由于您指定了宽度5f并且您正在绘制一条水平线,因此该行将2.5像素扩展到顶部和底部,从而覆盖从#3到(包括)的完整像素行#7。请注意,根据上面的定义,像素行#3的上边缘具有y坐标2.5,行#7的下边缘具有7.5,即{分别为{1}}和5f-2.5f

我没有得到与你的第二个例子相同的结果(我试过Try GDI+ application)。相反,我得到一条覆盖前三个像素行的线。从理论上讲,它甚至应该覆盖前3.5个prows(因为坐标指定第一行的 center ,上部只是被剪裁)。但是如果关闭抗锯齿,底部的“半行”会被截断。

这可以通过将5f+2.5f设置为g.SmoothingMode来显示,在这种情况下,第四行是透明绘制的。使用抗锯齿时,您还会注意到,第一个和最后一个未完全绘制,因为起始坐标同样位于列的中心。