Results 1 to 6 of 6

Thread: DrawLine function with pixel count output

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    DrawLine function with pixel count output

    This is a function I wrote intended to replace the built-in VB6 Line method. With the internal Line method, in addition to all the intermediate pixels of a line, the first pixel is also drawn. But there's a problem, the last pixel is never drawn. So if you want a complete line between 2 points, you will need to use both the line and pset commands. Another problem is that it doesn't draw anything if the line has no length (the first pixel is the same as the last pixel). The problem with the internal Line method, it sees a line with the first and last points being the same as having a length of 0, and a line with a length of 1 being a line who's last pixel is just adjacent to the first pixel.

    My function fixes these problems. A line with the first pixel being the same as the last pixel, using my function, is seen by my function as a line with a length of 1 (though it has a length, this line has no direction, because the first and last pixels are the same), so it draws a single pixel. If the last pixel is adjacent the first pixel, then the line has a length of 2. The length is simply equal to the number of pixels drawn, by my definition. Therefore, a single pixel has a length of 1 (seems counterintuitive, because in real life, a length must also have a direction, but real life is analog, while pixels are quantized, so that's why it's different here). The return value of the function is the length of the line, which is the number of pixels drawn by the function. This is another advantage of my function over the internal built-in Line method, which has no way to return the number of pixels drawn.


    Here's the code for my DrawLine function.

    Code:
    Private Function DrawLine(ByVal x1 As Long, ByVal y1 As Long, ByVal x2 As Long, ByVal y2 As Long) As Long
    Dim x As Long
    Dim y As Long
    Dim m As Single
    Dim PixelCount As Long
    
    
    If (x2 = x1) And (y2 = y1) Then
        PSet (x1, y1)
        PixelCount = 1
    Else
        If Abs(x2 - x1) > Abs(y2 - y1) Then
            m = (y2 - y1) / (x2 - x1)
            If x2 < x1 Then
                For x = x1 To x2 Step -1
                    y = (x - x1) * m + y1
                    PSet (x, y)
                    PixelCount = PixelCount + 1
                Next x
            Else
                For x = x1 To x2
                    y = (x - x1) * m + y1
                    PSet (x, y)
                    PixelCount = PixelCount + 1
                Next x
            End If
        Else
            m = (x2 - x1) / (y2 - y1)
            If y2 < y1 Then
                For y = y1 To y2 Step -1
                    x = (y - y1) * m + x1
                    PSet (x, y)
                    PixelCount = PixelCount + 1
                Next y
            Else
                For y = y1 To y2
                    x = (y - y1) * m + x1
                    PSet (x, y)
                    PixelCount = PixelCount + 1
                Next y
            End If
        End If
    End If
    DrawLine = PixelCount
    End Function

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: DrawLine function with pixel count output

    There is a reason that a line doesn't draw the last pixel, although it usually doesn't matter in most current uses.
    In the day of stroke writers, and today when using alpha based (translucent) pixels, if you drew a number of connected line segments, for instance drawing a rectangle, the last pixel of one line segment would be the first pixel of the next line segment, which would mean that the corner pixels of the rectangle would be drawn twice, as the last pixel of one line and the first pixel of the second line.
    In a stroke writing CRT that pixel would thus be brighter than the other pixels of the lines (in theory twice as bright).
    When drawing a curve you would see these bright dots along the curve where each line overlapped the other.

    The same is true for environments that allow using a pen with a less than full opacity alpha.
    Where the two lines overlapped on that one pixel joint, the color of the pixel would be different from the rest of the line, so would be considered an undesired drawing artifact when drawing a series of connected lines.

    So, to prevent that from happening, the line command doesn't draw the last pixel in a segment, because it will be drawn by the beginning of some other line segment in any closed polygon figure.

    Another advantage of your line drawing is that it can be hundreds or thousands of times slower than than regular line drawing command, so makes it easier to watch how the drawing progresses.
    Last edited by passel; May 29th, 2015 at 01:32 PM.

  3. #3

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: DrawLine function with pixel count output

    Quote Originally Posted by passel View Post
    There is a reason that a line doesn't draw the last pixel, although it usually doesn't matter in most current uses.
    In the day of stroke writers, and today when using alpha based (translucent) pixels, if you drew a number of connected line segments, for instance drawing a rectangle, the last pixel of one line segment would be the first pixel of the next line segment, which would mean that the corner pixels of the rectangle would be drawn twice, as the last pixel of one line and the first pixel of the second line.
    In a stroke writing CRT that pixel would thus be brighter than the other pixels of the lines (in theory twice as bright).
    When drawing a curve you would see these bright dots along the curve where each line overlapped the other.

    The same is true for environments that allow using a pen with a less than full opacity alpha.
    Where the two lines overlapped on that one pixel joint, the color of the pixel would be different from the rest of the line, so would be considered an undesired drawing artifact when drawing a series of connected lines.

    So, to prevent that from happening, the line command doesn't draw the last pixel in a segment, because it will be drawn by the beginning of some other line segment in any closed polygon figure.

    Another advantage of your line drawing is that it can be hundreds or thousands of times slower than than regular line drawing command, so makes it easier to watch how the drawing progresses.


    On screens where the background is black, lines would be white, and a double-drawn pixel would be extra-bright. But in Windows, the default background is white, and foreground is black, and there's no such thing as doubly dark, because a scanning electron beam adds brightness, not darkness. And also, once a line has been drawn on the screen, it stays there, so both copies of the pixel that was "double drawn" actually is only one pixel. So once it has been drawn the first time, it doesn't get drawn again, so it ends up being part of the final shape, and thus is only "double drawn" when it is being first drawn, not on any of the future screen refreshes.

    Even if it is technically "hundreds of thousands of times slower", the original Line command was already so fast, that even my DrawLine function appears to draw a line instantly. You don't see any drawing progression. Maybe if you were drawing something complex that involved hundreds of line segments (called a spline, which is the way a computer approximates a smooth curve, using a whole bunch of tiny line segments), then it might matter, but if it's being used just to draw a single line from point A to point B, then it is visually instantaneous.

    My DrawLine function is far superior to the internal Line method, because it outputs the number of pixels drawn, a very useful feature if you are using it in an industrial or scientific measuring software, where you are actually analyzing the spatial dimensions of objects in an image.

  4. #4
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: DrawLine function with pixel count output

    Quote Originally Posted by Ben321 View Post
    My DrawLine function is far superior to the internal Line method, because it outputs the number of pixels drawn, a very useful feature if you are using it in an industrial or scientific measuring software, where you are actually analyzing the spatial dimensions of objects in an image.
    Not sure that is a true advantage. To measure how many pixels in a line, one can simply measure the line distance between two points, correct?
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  5. #5

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: DrawLine function with pixel count output

    Quote Originally Posted by LaVolpe View Post
    Not sure that is a true advantage. To measure how many pixels in a line, one can simply measure the line distance between two points, correct?

    That only measures physical distance between 2 points, and can result in a number with a fraction (like 10.125 pixels). But what if you want to know how many pixels were actually drawn. In the case with a quantized amount of something (like pixels) the number output must be an integer. So to find the total number of pixels, it uses PSet, and then simply counts the number of times that the PSet command is used. This guarenties that in integer number is generated. Also if you look at my code, you will see that it is impossible for the same pixel to be drawn more than one time for a given line, so the output number won't be counting any pixel more than once.

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: DrawLine function with pixel count output

    If it works for you, fine. I'm not sure your statement about measuring line distance is valid. Any measurement can be used to round up/down as needed (which would occur on diagonal line measurements only) and still produce a valid value.

    But in the case of your code, it is even simpler. Since you are not anti-aliasing the line, the length of any line (for your purposes) would be this:
    MaxOf(Abs(X1-X2), Abs(Y1-Y2)) + 1

    Knowing this, why couldn't VB's Line method be used instead and produce exactly the same distance as your code? To include the final point in the line as part of the line, simply add/subtract 1 to/from the X2,Y2 values as needed; depending on direction/angle of line

    EXample: using these coordinates for x1,y1,x2,y2 respectively: 66 36 226 311
    Your code returned a distance of 276
    MaxOf(Abs(X1-X2), Abs(Y1-Y2)) + 1 returns: 276
    If using VB's Line method, just 1 call, not 276 loop iterations & calculations. Though a couple calcs would be needed to determine where to draw the last pixel in the line to meet your requirement in your original post above. The last pixel can be drawn with PSet or added to the X2,Y2 coordinates as appropriate. Quick sample only; may need a tweak or two
    Code:
        If x1 = x2 Then
            If y2 > y1 Then y2 = y2 + 1 Else y2 = y2 - 1
        ElseIf y1 = y2 Then
            If x2 > x1 Then x2 = x2 + 1 Else x2 = x2 - 1
        Else
            If y2 > y1 Then y2 = y2 + 1 Else y2 = y2 - 1
            If x2 > x1 Then x2 = x2 + 1 Else x2 = x2 - 1
        End If
        
        Me.Line (x1, y1)-(x2, y2)
        
        x1 = Abs(x2 - x1): y1 = Abs(y2 - y1)
        If x1 > y1 Then DrawLine = x1 Else DrawLine = y1
    If you want to continue to use the pixel-by-pixel approach, as Passel mentioned, your routine would likely be very slow compared to native VB methods. Here are a couple tips to speed it up somewhat:

    1. In your loops, you are adding PixelCount in each loop iteration. Waste of CPU cycles. Simply calculate it before or after the loop, i.e., PixelCount = (loop end - loop start + 1). Adjust by reversing start/stop in the calculation for the loop you step by -1

    2. Use VB's Line method for non-diagonal lines. Example: for a 200 pixel line, you must admit that one Line method call is better than 200 loop iterations to set individual pixels. And the line length calculation is as simple as it can be, no chance of being off by a pixel
    Last edited by LaVolpe; May 31st, 2015 at 11:54 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width