开发者

GDI+ Line Drawing Algorithm

I cannot understand the way GDI+ is drawing line on a surface, may be it has some algorithm to do it.

For ex. lets take a surface 10x10 px.

  Bitmap img = new Bitmap(10, 10);

Now lets draw a line on this surface, with width 5px and top offset 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);
     }

We will get:

GDI+ Line Drawing Algorithm

The drawing didn't begin at pixel #5, it began from pixel #4. It is obvious, that the start point is calculated separately. But how?

I've tried to get a regularity, and got this:

  y = offset + width/2 - 1

where y is real start point y, offset is selected start point y.

But in some cases this doesn't work. For example, lets take width=6, selected top o开发者_JAVA百科ffset = 0, we will get y=2, and it will be drawn this way:

GDI+ Line Drawing Algorithm

It must show 6 pixels but it didn't.

So there must be more general algorythm for selecting the start point, but I really have no idea aboit what it can be. Any help appreciated.


There is no offset in the line drawing. The co-ordinates you specify in the DrawLine method define the centre of the line. The top pixel is y - width / 2 and the bottom is y - width / 2 + width - 1. That second formula takes into account the fact that width / 2 is rounded down. Also, the top line is y = 0 and the bottom line is y = 9. So, for you first line:

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

and the second line:

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

The top edge is clipped to the edge of the bitmap so the line width is reduced.


In the first example, it looks like a line with a width of 5 pixels, centered on row 5 (counting starts at 0, not 1). This seems like a reasonable outcome.

In the second example, it looks like a line of width 6, centered between rows 1 and 2, where the top row is cut off, because it extends beyond the borders of the image.


Coordinates in GDI+ don't designate the pixels itself but the (infinitly small) points at their center. Thus (0f,5f) means the center of the pixel in the first column and 6th row (since counting starts at zero). Therefore, I will differentiate between coordinates and pixel rows from now on.

When drawing a line, GDI+ conceptually moves a pen of the specified width along the line defined by these coordinates. Note that you can define the exact shape of this pen at the beginning and the end of the line by specifying Pen.StartCap and Pen.EndCap.

Since you specified width 5f and you're drawing a horizontal line, the line extends 2.5 pixels to the top and to the bottom thus covering complete pixel rows from #3 to (and including) #7. Note that the upper edge of pixel row #3 has a y-coordinate 2.5 and the lower edge of row #7 has 7.5 according to the above definition, which is 5f-2.5f and 5f+2.5f respectively

I do not get the same result as you for your second example (I tried in Try GDI+ application). Instead I get a line which covers the first three pixel rows. Theoretically, it should even cover the first 3.5 prows (since the coordinate designates the center of the first row, the upper part is simply clipped). But if antialiasing is turned off, the 'half row' at the bottom gets truncated.

This can be shown by setting g.SmoothingMode to SmoothingMode.AntiAlias in which case the fourth row is drawn transparently. When using antialiasing you'll also notice, that the first and last column are not completely painted since the start coordinate is, again, at the center of the column.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜