C# GDI+;线描算法

C# GDI+;线描算法,c#,graphics,gdi+,C#,Graphics,Gdi+,我无法理解GDI+在曲面上画线的方式,可能是它有一些算法 例如,我们取一个10x10 px的表面 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.Wi

我无法理解GDI+在曲面上画线的方式,可能是它有一些算法

例如,我们取一个10x10 px的表面

  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);
     }
我们将获得:

绘图不是从像素5开始的,而是从像素4开始的。 很明显,起点是单独计算的。但是怎么做呢

我试着得到一个规律,得到了:

  y = offset + width/2 - 1
其中y为实际起点y,偏移为选定的起点y

但在某些情况下,这是行不通的。例如,假设宽度=6,选定的顶部偏移=0,我们将得到y=2,它将按如下方式绘制:

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

因此,必须有更通用的算法来选择起点,但我真的不知道它可以是什么。
感谢您的帮助。

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


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

线条图中没有偏移。在
绘制线方法中指定的坐标定义了线的中心。顶部像素为
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

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

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

在绘制直线时,GDI+概念上沿这些坐标定义的直线移动指定宽度的笔。请注意,您可以通过指定
pen.StartCap
pen.EndCap
在行首和行尾定义此笔的确切形状

由于您指定了宽度
5f
并绘制了一条水平线,因此该线将
2.5
像素向上和向下延伸,从而覆盖从#3到(包括#7)的完整像素行。注意,根据上述定义,像素行3的上边缘具有y坐标
2.5
,行7的下边缘具有
7.5
,分别为
5f-2.5f
5f+2.5f

对于第二个示例(我尝试了),我没有得到与您相同的结果。相反,我得到了一条覆盖前三个像素行的线。理论上,它甚至应该覆盖前3.5个船头(因为坐标指定了第一排的中心,所以上面的部分被简单地剪裁)。但如果禁用抗锯齿,底部的“半行”将被截断

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