Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Plotting A Line

by mdog (Pilgrim)
on Oct 27, 2003 at 21:43 UTC ( [id://302529]=perlquestion: print w/replies, xml ) Need Help??

mdog has asked for the wisdom of the Perl Monks concerning the following question:

Brethern --

What is the best/easiest way to determine the points of a line if you have the start and end points of a line?

You know the beginning x,y coords and the ending x,y coords but how do you determine all the coords in between your start and end spots? I was thinking that I could roll my own but realized reinventing the wheel is dumb.

Looked on cpan but didn't find anything too promising but I may have just overlooked something great, too.

Thanks in advance,
Matt

Replies are listed 'Best First'.
Re: Plotting A Line
by BrowserUk (Patriarch) on Oct 27, 2003 at 22:33 UTC

    Ignoring anti-aliasing possibilities...

    #! perl -slw use strict; sub lpoints { my( $x1, $y1, $x2, $y2 ) = @_; # Switch ends in need be ( $x1, $x2 ) = ( $x2, $x1 ) if $x2 < $x1; ( $y1, $y2 ) = ( $y2, $y1 ) if $y2 < $y1; # Calculate deltas my( $dx, $dy ) = ( $x2 - $x1, $y2 - $y1 ); #return the point if the first is equal to the second return [$x1, $y1] unless $dx or $dy; # calculate the gradient. Account for vertical and horizontal line +s my $m = $dx != 0 ? $dy / $dx : $dx / $dy; # if dx != 0 then do it X-wise if( $dx ) { map { my $y = int $y1; $y1 += $m; [ $_, $y ] } $x1 .. $x2; } else { map { my $x = int $x1; $x1 += $m; [ $x, $_ ] } $y1 .. $y2; } } # Test 9 possibilities. for my $Y ( -10, 0, +10 ) { for my $X ( -10, 0, +10 ) { printf "\n[0,0] -> [% 3d,% 3d] :: ", $X, $Y; printf "[$_->[0],$_->[1]], " for lpoints 0, 0, $X, $Y; } } __END__ P:\test>test3 [0,0] -> [-10,-10] :: [-10,-10], [-9,-9], [-8,-8], [-7,-7], [-6,-6], [-5,-5], [-4,-4], [-3,-3], [-2,-2], [-1,-1], [0, +0], [0,0] -> [ 0,-10] :: [0,-10], [0,-9], [0,-8], [0,-7], [0,-6], [0,-5], + [0,-4], [0,-3], [0,-2], [0,-1], [0,0], [0,0] -> [ 10,-10] :: [0,-10], [1,-9], [2,-8], [3,-7], [4,-6], [5,-5], + [6,-4], [7,-3], [8,-2], [9,-1], [10,0], [0,0] -> [-10, 0] :: [-10,0], [-9,0], [-8,0], [-7,0], [-6,0], [-5,0], + [-4,0], [-3,0], [-2,0], [-1,0], [0,0], [0,0] -> [ 0, 0] :: [0,0], [0,0] -> [ 10, 0] :: [0,0], [1,0], [2,0], [3,0], [4,0], [5,0], [6,0], + [7,0], [8,0], [9,0], [10,0], [0,0] -> [-10, 10] :: [-10,0], [-9,1], [-8,2], [-7,3], [-6,4], [-5,5], + [-4,6], [-3,7], [-2,8], [-1,9], [0,10], [0,0] -> [ 0, 10] :: [0,0], [0,1], [0,2], [0,3], [0,4], [0,5], [0,6], [0,7], [0,8], [0,9], [0,10], [0,0] -> [ 10, 10] :: [0,0], [1,1], [2,2], [3,3], [4,4], [5,5], [6,6], [7,7], [8,8], [9,9], [10,10],

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!

Re: Plotting A Line
by Corion (Patriarch) on Oct 27, 2003 at 21:54 UTC

    What you are looking for is Bresenhams algorithm for drawing a line. I don't know of an implementation of it for Perl, as most drawing in Perl is done on a higher level by using OpenGL or SVG though. The concept of Bresenhams algorithm is relatively easy - you step down the longer distance and keep a counter for when you have to move one column in the other direction. The fun thing is to understand how and why the algorithm works without requiring floating point math.

    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
      Bresenham is an algorithm for devices that only have 1 bit pixels, on and off. You also get very nasty artifacts. A line from (0, 0) to (8, 2) would look like:
      +-+-+-+-+-+-+-+-+-+ | | | | | | |*|*|*| +-+-+-+-+-+-+-+-+-+ | | | |*|*|*| | | | +-+-+-+-+-+-+-+-+-+ |*|*|*| | | | | | | +-+-+-+-+-+-+-+-+-+

      Now, if all your pixels are either black or white, this isn't too bad. But the human eye is very good in seeing the non-smoothness, the "staircase" sticks out like a sore thumb.

      But if you have a grayscale (or full colour) device available, there are much better techniques. One technique revolves around the observation a line needs thickness to be seen. So, if you want to draw a line from say (0, 0) to (8, 2), assume you have a rectangle of width 1 and length 2 * sqrt (17), running from (0, 0) to (8, 2). This will cover some of the pixels partially. If a pixel is covered for say, 61%, the pixel should get a gray value that's 61% of pure black.

      Now, this still isn't perfect, but it's a step better. There are lots of line drawing algorithms, each of them finding a different balance between simplicity, speed, good results and avoidance of artifacts.

      Abigail

        Adding to what Abigail's written:
        Michael Abrash covered the topic of eye-pleasing lines in detail in Zen of Graphics Programming. This book's quite fascinating, and pretty well written. And although most of the examples were (quite naturally) not in perl, all that's really needed to absorb most of the book's functionality are some basic math skills, typically algebra. You can also purchase a subscription to Byte magazine and get access to a seemingly similar book, where chapter 35 would be of particular interest.

Re: Plotting A Line
by flounder99 (Friar) on Oct 27, 2003 at 22:58 UTC
    From algebra I:

    Equation of a line:

    y = mx + b

    what you know:

    x1,y1
    x2,y2

    Therefore:

    y1 = mx1 + b

    y2 = mx2 + b

    Subtracting:

    y1 - y2 = m(x1 - x2)

    if x1 == x2 then it is a vertical line on y

    therefore (assuming x1 != x2)

    m = (y1 - y2)/(x1 - x2)

    substituting in first equation:

    y1 = (y1 - y2)/(x1 - x2)x1 + b

    b = y1 - (y1 - y2)/(x1 - x2)x1

    therefore the equation of a line (assuming x1 != x2) is:

    y = (y1 - y2)/(x1 - x2)x + (y1 + y1 - y2)/(x1 - x2)x1

    --

    flounder

Re: Plotting A Line
by TomDLux (Vicar) on Oct 27, 2003 at 22:04 UTC

    Drawing a line is only a concern if you are implementing a graphics package. If you are generating a single 'page' of output, use the line command of your output API to generate the line

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://302529]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-04-23 16:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found