Bitmap/Bresenham's line algorithm: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎Python: Add Python example)
m (Fixed lang tags.)
Line 4: Line 4:


=={{header|Ada}}==
=={{header|Ada}}==
<lang ada>procedure Line (Picture : in out Image; Start, Stop : Point; Color : Pixel) is
<lang ada>
procedure Line (Picture : in out Image; Start, Stop : Point; Color : Pixel) is
DX : constant Float := abs Float (Stop.X - Start.X);
DX : constant Float := abs Float (Stop.X - Start.X);
DY : constant Float := abs Float (Stop.Y - Start.Y);
DY : constant Float := abs Float (Stop.Y - Start.Y);
Line 44: Line 43:
end if;
end if;
Picture (X, Y) := Color; -- Ensure dots to be drawn
Picture (X, Y) := Color; -- Ensure dots to be drawn
end Line;
end Line;</lang>
</lang>
The test program's
The test program's
<lang ada>
<lang ada> X : Image (1..16, 1..16);
X : Image (1..16, 1..16);
begin
begin
Fill (X, White);
Fill (X, White);
Line 55: Line 52:
Line (X, (16, 8), ( 8, 1), Black);
Line (X, (16, 8), ( 8, 1), Black);
Line (X, ( 8, 1), ( 1, 8), Black);
Line (X, ( 8, 1), ( 1, 8), Black);
Print (X);
Print (X);</lang>
</lang>
sample output
sample output
<pre>
<pre>
Line 82: Line 78:
{{works with|ALGOL 68G|Any - tested with release mk15-0.8b.fc9.i386}}
{{works with|ALGOL 68G|Any - tested with release mk15-0.8b.fc9.i386}}
<!-- {{does not work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386 - '''pragmat''' '''read''' is not part of algol68rs}} -->
<!-- {{does not work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386 - '''pragmat''' '''read''' is not part of algol68rs}} -->
<lang algol>PRAGMAT READ "Basic_bitmap_storage.a68" PRAGMAT;
<lang algol68>PRAGMAT READ "Basic_bitmap_storage.a68" PRAGMAT;


line OF class image := (REF IMAGE picture, POINT start, stop, PIXEL color)VOID:
line OF class image := (REF IMAGE picture, POINT start, stop, PIXEL color)VOID:
Line 215: Line 211:
=={{header|Common Lisp}}==
=={{header|Common Lisp}}==


<lang lisp>
<lang lisp>(defun draw-line (buffer x1 y1 x2 y2 pixel)
(defun draw-line (buffer x1 y1 x2 y2 pixel)
(declare (type rgb-pixel-buffer buffer))
(declare (type rgb-pixel-buffer buffer))
(declare (type integer x1 y1 x2 y2))
(declare (type integer x1 y1 x2 y2))
Line 243: Line 238:
(incf y y-step)
(incf y y-step)
(incf error delta-x)))))
(incf error delta-x)))))
buffer))
buffer))</lang>
</lang>


=={{header|D}}==
=={{header|D}}==
Line 252: Line 246:
This version uses direct pointers to the data to speed things up.
This version uses direct pointers to the data to speed things up.


<lang D>
<lang D>// swap function template
// swap function template
void swap(T)(ref T a, ref T b) { T t = a; a = b; b = t; }
void swap(T)(ref T a, ref T b) { T t = a; a = b; b = t; }
// absolute value, this could be taken from std.math or
// absolute value, this could be taken from std.math or
Line 299: Line 292:


}
}
}</lang>
}
</lang>


Sample usage:
Sample usage:
<lang D>
<lang D>Rgb black;
Rgb black;
Rgb yellow = {[255, 255, 0]};
Rgb yellow = {[255, 255, 0]};
auto foobar = RgbBitmap(200, 100);
auto foobar = RgbBitmap(200, 100);
drawLine(foobar, 20, 20, 180, 80, yellow);
drawLine(foobar, 20, 20, 180, 80, yellow);
drawLine(foobar, 180, 20, 20, 80, yellow);
drawLine(foobar, 180, 20, 20, 80, yellow);</lang>
</lang>


=={{header|E}}==
=={{header|E}}==
Line 351: Line 341:


=={{header|Forth}}==
=={{header|Forth}}==
defer steep \ noop or swap
<lang forth>defer steep \ noop or swap
defer ystep \ 1+ or 1-
defer ystep \ 1+ or 1-

: line ( x0 y0 x1 y1 color bmp -- )
: line ( x0 y0 x1 y1 color bmp -- )
{ color bmp }
{ color bmp }
rot swap
rot swap
( x0 x1 y0 y1 )
( x0 x1 y0 y1 )
2dup - abs >r
2dup - abs >r
2over - abs r> <
2over - abs r> <
if ['] swap \ swap use of x and y
if ['] swap \ swap use of x and y
else 2swap ['] noop
else 2swap ['] noop
then is steep
then is steep
( y0 y1 x0 x1 )
( y0 y1 x0 x1 )
2dup >
2dup >
if swap 2swap swap \ ensure x1 > x0
if swap 2swap swap \ ensure x1 > x0
else 2swap
else 2swap
then
then
( x0 x1 y0 y1 )
( x0 x1 y0 y1 )
2dup >
2dup >
if ['] 1-
if ['] 1-
else ['] 1+
else ['] 1+
then is ystep
then is ystep
over - abs { y deltay }
over - abs { y deltay }
swap 2dup - dup { deltax }
swap 2dup - dup { deltax }
2/ rot 1+ rot
2/ rot 1+ rot
( error x1+1 x0 )
( error x1+1 x0 )
do color i y steep bmp b!
do color i y steep bmp b!
deltay -
deltay -
dup 0<
dup 0<
if y ystep to y
if y ystep to y
deltax +
deltax +
then
then
loop
loop
drop ;
drop ;


5 5 bitmap value test
5 5 bitmap value test
0 test bfill
0 test bfill
1 0 4 1 red test line
1 0 4 1 red test line
4 1 3 4 red test line
4 1 3 4 red test line
3 4 0 3 red test line
3 4 0 3 red test line
0 3 1 0 red test line
0 3 1 0 red test line
test bshow cr
test bshow cr
**
**
* **
* **
* *
* *
** *
** *
**
**
ok</lang>
ok


=={{header|Fortran}}==
=={{header|Fortran}}==
Line 543: Line 533:


Using definitions from [[Basic bitmap storage#J|Basic bitmap storage]].
Using definitions from [[Basic bitmap storage#J|Basic bitmap storage]].
<lang j>thru=: <./ + -~ i.@+ _1 ^ > NB. integers from x through y
<lang j>
thru=: <./ + -~ i.@+ _1 ^ > NB. integers from x through y


NB.*getBresenhamLine v Returns points for a line given start and end points
NB.*getBresenhamLine v Returns points for a line given start and end points
Line 559: Line 548:
NB.*drawLines v Draws lines (x) on image (y)
NB.*drawLines v Draws lines (x) on image (y)
NB. x is: 2-item list (start and end points) ; (color)
NB. x is: 2-item list (start and end points) ; (color)
drawLines=: (1&{:: ;~ [: ; [: <@getBresenhamLine"2 (0&{::))@[ setPixels ]
drawLines=: (1&{:: ;~ [: ; [: <@getBresenhamLine"2 (0&{::))@[ setPixels ]</lang>
</lang>


'''Example Usage:'''
'''Example Usage:'''
<lang j> myimg=: 0 255 0 makeRGB 20 32 NB. 32 by 20 green image
<lang j>
myimg=: 0 255 0 makeRGB 20 32 NB. 32 by 20 green image
myimg=: ((1 1 ,: 5 11) ; 255 0 0 ) drawLines myimg NB. draw red line from xy point 1 1 to 11 5
myimg=: ((1 1 ,: 5 11) ; 255 0 0 ) drawLines myimg NB. draw red line from xy point 1 1 to 11 5


Line 572: Line 559:
viewRGB myimg=: (Diamond;255 0 0) drawLines myimg NB. draw 4 red lines to form a diamond
viewRGB myimg=: (Diamond;255 0 0) drawLines myimg NB. draw 4 red lines to form a diamond
viewRGB myimg=: (Square;0 0 255) drawLines myimg NB. draw 4 blue lines to form a square
viewRGB myimg=: (Square;0 0 255) drawLines myimg NB. draw 4 blue lines to form a square
viewRGB (Diamond;255 0 0) drawLines (Square;0 0 255) drawLines myimg
viewRGB (Diamond;255 0 0) drawLines (Square;0 0 255) drawLines myimg</lang>
</lang>


=={{header|Maple}}==
=={{header|Maple}}==


<lang maple>
<lang maple>SegmentBresenham := proc (img, x0, y0, x1, y1)
SegmentBresenham := proc (img, x0, y0, x1, y1)
local deltax, deltay, x, y, ystep, bool, e, img2, swap, x02, y02, x12, y12;
local deltax, deltay, x, y, ystep, bool, e, img2, swap, x02, y02, x12, y12;
x02 := y0; x12 := y1; y12 := x1; y02 := x0;
x02 := y0; x12 := y1; y12 := x1; y02 := x0;
Line 615: Line 600:
=={{header|MAXScript}}==
=={{header|MAXScript}}==


<pre>fn plot img coord steep col =
<lang maxscript>fn plot img coord steep col =
(
(
if steep then
if steep then
Line 666: Line 651:
myBitmap = bitmap 512 512 color:(color 0 0 0)
myBitmap = bitmap 512 512 color:(color 0 0 0)
myBitmap = drawLine myBitmap [0, 511] [511, 0] #((color 255 255 255))
myBitmap = drawLine myBitmap [0, 511] [511, 0] #((color 255 255 255))
display myBitmap</pre>
display myBitmap</lang>


=={{header|OCaml}}==
=={{header|OCaml}}==
Line 849: Line 834:
Use this routine together with the code from [[Basic_bitmap_storage#RapidQ|Basic bitmap storage]] to create a full application.
Use this routine together with the code from [[Basic_bitmap_storage#RapidQ|Basic bitmap storage]] to create a full application.


<lang rapidq>
<lang rapidq>SUB draw_line(x1, y1, x2, y2, colour)
SUB draw_line(x1, y1, x2, y2, colour)
x_dist = abs(x2-x1)
x_dist = abs(x2-x1)
y_dist = abs(y2-y1)
y_dist = abs(y2-y1)
Line 884: Line 868:
END IF
END IF
END SUB
END SUB</lang>
</lang>


Example usage:
Example usage:


<lang rapidq>
<lang rapidq>SUB PaintCanvas
SUB PaintCanvas
draw_line 200, 10, 100, 200, &H00ff00
draw_line 200, 10, 100, 200, &H00ff00
draw_line 100, 200, 200, 400, &H00ff00
draw_line 100, 200, 200, 400, &H00ff00
draw_line 200, 400, 300, 200, &H00ff00
draw_line 200, 400, 300, 200, &H00ff00
draw_line 300, 200, 200, 10, &H00ff00
draw_line 300, 200, 200, 10, &H00ff00
END SUB
END SUB</lang>
</lang>


=={{header|Ruby}}==
=={{header|Ruby}}==
Line 994: Line 975:
{{trans|E}}
{{trans|E}}


<pre style="font-family:'TI Uni'">(lx0, ly0, lx1, ly1)
<lang ti89b>(lx0, ly0, lx1, ly1)
Prgm
Prgm
Local steep, x, y, dx, dy, ystep, error, tmp
Local steep, x, y, dx, dy, ystep, error, tmp
Line 1,027: Line 1,008:
EndIf
EndIf
EndFor
EndFor
EndPrgm</pre>
EndPrgm</lang>


=={{header|Vedit macro language}}==
=={{header|Vedit macro language}}==


<lang vedit>// Daw a line using Bresenham's line algorithm.
<pre>
// Daw a line using Bresenham's line algorithm.
// #1=x1, #2=y1; #3=x2, #4=y2
// #1=x1, #2=y1; #3=x2, #4=y2


Line 1,070: Line 1,050:
}
}
Num_Pop(31,35)
Num_Pop(31,35)
return
return</lang>
</pre>

Revision as of 15:30, 19 November 2009

Task
Bitmap/Bresenham's line algorithm
You are encouraged to solve this task according to the task description, using any language you may know.

Using the data storage type defined on this page for raster graphics images, draw a line given 2 points with the Bresenham's algorithm.

Ada

<lang ada>procedure Line (Picture : in out Image; Start, Stop : Point; Color : Pixel) is

  DX  : constant Float := abs Float (Stop.X - Start.X);
  DY  : constant Float := abs Float (Stop.Y - Start.Y);
  Err : Float;
  X   : Positive := Start.X;
  Y   : Positive := Start.Y;
  Step_X : Integer := 1;
  Step_Y : Integer := 1;

begin

  if Start.X > Stop.X then
     Step_X := -1;
  end if;
  if Start.Y > Stop.Y then
     Step_Y := -1;
  end if;
  if DX > DY then
     Err := DX / 2.0;
     while X /= Stop.X loop
        Picture (X, Y) := Color;
        Err := Err - DY;
        if Err < 0.0 then
           Y := Y + Step_Y;
           Err := Err + DX;
        end if;
        X := X + Step_X;
     end loop;
  else
     Err := DY / 2.0;
     while Y /= Stop.Y loop
        Picture (X, Y) := Color;
        Err := Err - DX;
        if Err < 0.0 then
           X := X + Step_X;
           Err := Err + DY;
        end if;
        Y := Y + Step_Y;
     end loop;
  end if;
  Picture (X, Y) := Color; -- Ensure dots to be drawn

end Line;</lang> The test program's <lang ada> X : Image (1..16, 1..16); begin

  Fill (X, White);
  Line (X, ( 1, 8), ( 8,16), Black);
  Line (X, ( 8,16), (16, 8), Black);
  Line (X, (16, 8), ( 8, 1), Black);
  Line (X, ( 8, 1), ( 1, 8), Black);
  Print (X);</lang>

sample output

       H
      H H
     H   H
    H     HH
   H        H
  H          H
 H            H
H              H
 H            H
  H          H
   H        H
    H      H
    H     H
     H   H
      H H
       H

ALGOL 68

Translation of: Ada
Works with: ALGOL 68 version Standard - pragmat read is an extension
Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386

<lang algol68>PRAGMAT READ "Basic_bitmap_storage.a68" PRAGMAT;

line OF class image := (REF IMAGE picture, POINT start, stop, PIXEL color)VOID: BEGIN

  REAL dx = ABS (x OF stop - x OF start),
       dy = ABS (y OF stop - y OF start);
  REAL err;
  POINT here := start,
        step := (1, 1);
  IF x OF start > x OF stop THEN
     x OF step := -1
  FI;
  IF y OF start > y OF stop THEN
     y OF step := -1
  FI;
  IF dx > dy THEN
     err := dx / 2;
     WHILE x OF here /= x OF stop DO
        picture[x OF here, y OF here] := color;
        err -:= dy;
        IF err < 0 THEN
           y OF here +:= y OF step;
           err +:= dx
        FI;
        x OF here +:= x OF step
     OD
  ELSE
     err := dy / 2;
     WHILE y OF here /= y OF stop DO
        picture[x OF here, y OF here] := color;
        err -:= dx;
        IF err < 0 THEN
           x OF here +:= x OF step;
           err +:= dy
        FI;
        y OF here +:= y OF step
     OD
  FI;
  picture[x OF here, y OF here] := color # ensure dots to be drawn #

END # line #;

The test program:

IF test THEN

  REF IMAGE x = INIT LOC[1:16, 1:16]PIXEL;
  (fill OF class image)(x, white OF class image);
  (line OF class image)(x, ( 1, 8), ( 8,16), black OF class image);
  (line OF class image)(x, ( 8,16), (16, 8), black OF class image);
  (line OF class image)(x, (16, 8), ( 8, 1), black OF class image);
  (line OF class image)(x, ( 8, 1), ( 1, 8), black OF class image);
  (print OF class image)(x)

FI</lang> Output:

ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff

C

To be added to imglib.h.

<lang c>void draw_line(

       image img,
       unsigned int x0, unsigned int y0,
       unsigned int x1, unsigned int y1,
       color_component r,
       color_component g,
       color_component b );</lang>

The implementation code:

<lang c>#include "imglib.h"

  1. define plot(x, y) put_pixel_clip(img, x, y, r, g, b)
  2. define swap_uint(a, b) do{ unsigned int tmp; tmp = a; a = b; b = tmp; }while(0)

void draw_line(

       image img,
       unsigned int x0, unsigned int y0,
       unsigned int x1, unsigned int y1,
       color_component r,
       color_component g,
       color_component b )

{

   unsigned short steep;
   steep = abs(y1 - y0) > abs(x1 - x0);
   if (steep) {
       swap_uint(x0, y0);
       swap_uint(x1, y1);
   }
   if (x0 > x1) {
       swap_uint(x0, x1);
       swap_uint(y0, y1);
   }
   {
       int deltax = x1 - x0;
       int deltay = abs(y1 - y0);
       int error = deltax / 2;
       int ystep;
       int y = y0;
       int x;
       if (y0 < y1) ystep = 1; else ystep = -1;
       for (x = x0; x <= x1; ++x) {
           if (steep) plot(y,x); else plot(x,y);
           error = error - deltay;
           if (error < 0) {
               y = y + ystep;
               error = error + deltax;
           }
       }
   }

}

  1. undef swap_uint
  2. undef plot</lang>

Common Lisp

<lang lisp>(defun draw-line (buffer x1 y1 x2 y2 pixel)

 (declare (type rgb-pixel-buffer buffer))
 (declare (type integer x1 y1 x2 y2))
 (declare (type rgb-pixel pixel))
 (let* ((dist-x (abs (- x1 x2)))

(dist-y (abs (- y1 y2))) (steep (> dist-y dist-x)))

   (when steep
     (psetf x1 y1 y1 x1

x2 y2 y2 x2))

   (when (> x1 x2)
     (psetf x1 x2 x2 x1

y1 y2 y2 y1))

   (let* ((delta-x (- x2 x1))

(delta-y (abs (- y1 y2))) (error (floor delta-x 2)) (y-step (if (< y1 y2) 1 -1)) (y y1))

     (loop 

:for x :upfrom x1 :to x2 :do (progn (if steep (setf (rgb-pixel buffer x y) pixel) (setf (rgb-pixel buffer y x) pixel)) (setf error (- error delta-y)) (when (< error 0) (incf y y-step) (incf error delta-x)))))

   buffer))</lang>

D

This example uses Bitmap structure template defined in Basic bitmap storage task.

This version uses direct pointers to the data to speed things up.

<lang D>// swap function template void swap(T)(ref T a, ref T b) { T t = a; a = b; b = t; } // absolute value, this could be taken from std.math or // tango.math.Math, but is placed here for convenience T labs(T)(T a) { return a < 0 ? -a : a; }

void drawLine(T)(Bitmap!(T) dest, int x0, int y0, int x1, int y1, T color) {

   auto deltaY = labs(y1 - y0);
   auto deltaX = labs(x1 - x0);
   auto skew = deltaX > deltaY ? 1 : 0;
   if (! skew ) {
       swap (deltaX, deltaY);
       swap (x0, y0);
       swap (x1, y1);
   }
   auto d = (deltaY << 1) - deltaX;
   deltaX = (deltaY - deltaX) << 1;
   deltaY <<= 1;
   if (x1 < x0) {
       swap (x0, x1);
       swap (y0, y1);
   }
   int step = (x0 < x1 && y0 < y1) ? 1 : -1;
   if (skew) {
       T *ptr = &dest.data[y0*dest.width + x0];
       for (; x0 < x1; x0++, ptr++) {
           *ptr = color;
           d += (d < 0) ? deltaY : deltaX;
           if (d >= 0)
               ptr += step*dest.width;
       } 
   } else {
       T *ptr = &dest.data[x0*dest.width + y0];
       for (; x0 < x1; x0++, ptr+=dest.width) {
           *ptr = color;
           d += (d < 0) ? deltaY : deltaX;
           if (d >= 0)
               ptr += step;
       } 
   }

}</lang>

Sample usage: <lang D>Rgb black; Rgb yellow = {[255, 255, 0]}; auto foobar = RgbBitmap(200, 100); drawLine(foobar, 20, 20, 180, 80, yellow); drawLine(foobar, 180, 20, 20, 80, yellow);</lang>

E

Translation of: C

<lang e>def swap(&left, &right) { # From Generic swap

 def t := left
 left := right
 right := t

}

def drawLine(image, var x0, var y0, var x1, var y1, color) {

   def steep := (y1 - y0).abs() > (x1 - x0).abs()
   if (steep) {
       swap(&x0, &y0)
       swap(&x1, &y1)
   }
   if (x0 > x1) {
       swap(&x0, &x1)
       swap(&y0, &y1)
   }
   def deltax := x1 - x0
   def deltay := (y1 - y0).abs()
   def ystep := if (y0 < y1) { 1 } else { -1 }
   var error := deltax // 2
   var y := y0
   for x in x0..x1 {
       if (steep) { image[y, x] := color } else { image[x, y] := color }
       error -= deltay
       if (error < 0) {
           y += ystep
           error += deltax
       }
   }

}</lang>

<lang e>def i := makeImage(5, 20) drawLine(i, 1, 1, 3, 18, makeColor.fromFloat(0,1,1)) i.writePPM(<import:java.io.makeFileOutputStream>(<file:~/Desktop/Bresenham.ppm>))</lang>

Forth

<lang forth>defer steep \ noop or swap defer ystep \ 1+ or 1-

line ( x0 y0 x1 y1 color bmp -- )
 { color bmp }
 rot swap
 ( x0 x1 y0 y1 )
 2dup  - abs >r
 2over - abs r> <
 if         ['] swap	\ swap use of x and y
 else 2swap ['] noop
 then       is steep
 ( y0 y1 x0 x1 )
 2dup >
 if swap 2swap swap	\ ensure x1 > x0
 else    2swap
 then
 ( x0 x1 y0 y1 )
 2dup >
 if   ['] 1-
 else ['] 1+
 then is ystep
 over - abs    { y deltay }
 swap 2dup - dup { deltax }
 2/ rot 1+ rot
 ( error x1+1 x0 )
 do  color i y steep bmp b!
     deltay -
     dup 0<
     if   y ystep to y
          deltax +
     then
 loop
 drop ;

5 5 bitmap value test 0 test bfill 1 0 4 1 red test line 4 1 3 4 red test line 3 4 0 3 red test line 0 3 1 0 red test line test bshow cr

**  
* **
  • *
    • *
 ** 

ok</lang>

Fortran

Works with: Fortran version 90 and later
Translation of: C

<lang fortran>module RCImagePrimitive

 use RCImageBasic
 implicit none
 type point
    integer :: x, y
 end type point
 private :: swapcoord

contains

 subroutine swapcoord(p1, p2)
   integer, intent(inout) :: p1, p2
   integer :: t
   t = p2
   p2 = p1
   p1 = t
 end subroutine swapcoord
 subroutine draw_line(img, from, to, color)
   type(rgbimage), intent(inout) :: img
   type(point), intent(in) :: from, to
   type(rgb), intent(in) :: color
   type(point) :: rfrom, rto
   integer :: dx, dy, error, ystep, x, y
   logical :: steep
   rfrom = from
   rto = to
   steep = (abs(rto%y - rfrom%y) > abs(rto%x - rfrom%x))
   if ( steep ) then
      call swapcoord(rfrom%x, rfrom%y)
      call swapcoord(rto%x, rto%y)
   end if
   if ( rfrom%x > rto%x ) then
      call swapcoord(rfrom%x, rto%x)
      call swapcoord(rfrom%y, rto%y)
   end if
   dx = rto%x - rfrom%x
   dy = abs(rto%y - rfrom%y)
   error = dx / 2
   y = rfrom%y
   if ( rfrom%y < rto%y ) then
      ystep = 1
   else
      ystep = -1
   end if
   do x = rfrom%x, rto%x
      if ( steep ) then
         call put_pixel(img, y, x, color)
      else 
         call put_pixel(img, x, y, color)
      end if
      error = error - dy
      if ( error < 0 ) then
         y = y + ystep
         error = error + dx
      end if
   end do
 end subroutine draw_line

end module RCImagePrimitive</lang>

Usage example:

<lang fortran>program BasicImageTests

 use RCImageBasic
 use RCImageIO
 use RCImagePrimitive
 implicit none
 type(rgbimage) :: animage
 integer :: x, y
 call alloc_img(animage, 200, 200)
 call fill_img(animage, rgb(255,255,255))
 call draw_line(animage, point(0,0), point(199,199), rgb(0,0,0))
 do y=0,219,20
    call draw_line(animage, point(0,0), point(199, y), &
                   rgb(0,0,0))
 end do
 open(unit=10, file='outputimage.ppm', status='new')
 call output_ppm(10, animage)
 close(10)
 call free_img(animage)

end program BasicImageTests</lang>

Haskell

<lang haskell>module Bitmap.Line(line) where

import Bitmap import Control.Monad import Control.Monad.ST import qualified Data.STRef

var = Data.STRef.newSTRef get = Data.STRef.readSTRef mutate = Data.STRef.modifySTRef

line :: Color c => Image s c -> Pixel -> Pixel -> c -> ST s () line i (Pixel (xa, ya)) (Pixel (xb, yb)) c = do

   yV <- var y1
   errorV <- var $ deltax `div` 2
   forM_ [x1 .. x2] (\x -> do
       y <- get yV
       setPix i (Pixel $ if steep then (y, x) else (x, y)) c
       mutate errorV $ subtract deltay
       error <- get errorV
       when (error < 0) (do
           mutate yV (+ ystep)
           mutate errorV (+ deltax)))
 where steep = abs (yb - ya) > abs (xb - xa)
       (xa', ya', xb', yb') = if steep
         then (ya, xa, yb, xb)
         else (xa, ya, xb, yb)
       (x1, y1, x2, y2) = if xa' > xb'
         then (xb', yb', xa', ya')
         else (xa', ya', xb', yb')
       deltax = x2 - x1
       deltay = abs $ y2 - y1
       ystep = if y1 < y2 then 1 else -1</lang>

J

Solution:

Using definitions from Basic bitmap storage. <lang j>thru=: <./ + -~ i.@+ _1 ^ > NB. integers from x through y

NB.*getBresenhamLine v Returns points for a line given start and end points NB. y is: y0 x0 ,: y1 x1 getBresenhamLine=: monad define

 steep=. ([: </ |@-~/) y
 points=. |."1^:steep y
 slope=. %~/ -~/ points
 ypts=. thru/ {."1 points
 xpts=. ({: + 0.5 <.@:+ slope * ypts - {.) {.points
 |."1^:steep ypts,.xpts

)

NB.*drawLines v Draws lines (x) on image (y) NB. x is: 2-item list (start and end points) ; (color) drawLines=: (1&{:: ;~ [: ; [: <@getBresenhamLine"2 (0&{::))@[ setPixels ]</lang>

Example Usage: <lang j> myimg=: 0 255 0 makeRGB 20 32 NB. 32 by 20 green image

  myimg=: ((1 1 ,: 5 11) ; 255 0 0 ) drawLines myimg  NB. draw red line from xy point 1 1 to 11 5

NB. Works for lists of 2 by 2 arrays each defining a line's start and end point.

  Diamond=: _2]\ _2]\ 9 5 5 15 , 5 15 9 25 , 9 25 13 15 , 13 15 9 5
  Square =: _2]\ _2]\ 5 5 5 25 , 5 25 13 25 , 13 25 13 5 , 13 5 5 5
  viewRGB myimg=: (Diamond;255 0 0) drawLines myimg   NB. draw 4 red lines to form a diamond   
  viewRGB myimg=: (Square;0 0 255) drawLines myimg    NB. draw 4 blue lines to form a square
  viewRGB (Diamond;255 0 0) drawLines (Square;0 0 255) drawLines myimg</lang>

Maple

<lang maple>SegmentBresenham := proc (img, x0, y0, x1, y1) local deltax, deltay, x, y, ystep, bool, e, img2, swap, x02, y02, x12, y12; x02 := y0; x12 := y1; y12 := x1; y02 := x0; bool := abs(x12-x02) < abs(y12-y02); img2 := copy(img); if bool then

   swap := x02; x02 := y02; y02 := swap; 
   swap := x12; x12 := y12; y12 := swap; 

end if; if x12 < x02 then

   swap := x02; x02 := x12; x12 := swap; 
   swap := y02; y02 := y12; y12 := swap; 

end if; deltax := x12-x02; deltay := abs(y12-y02); e := (1/2)*deltax; y := y02; if y02 < y12 then

   ystep := 1 else ystep := -1; end if; 

for x from x02 to x12 do

   if bool then 
       img2[y, x] := 0 
   else 
       img2[x, y] := 0;
   end if; 
   e := e-deltay; 
   if e < 0 then 
       y := y+ystep; 
       e := e+deltax;
   end if; 

end do; img2; end proc:</lang>


MAXScript

<lang maxscript>fn plot img coord steep col = (

   if steep then
   (
       swap coord[1] coord[2]
   )
   setPixels img coord col

)

fn drawLine img start end col = (

   local steep = (abs (end.y - start.y)) > (abs (end.x - start.x))
   if steep then
   (
       swap start.x start.y
       swap end.x end.y
   )
   if start.x > end.x then
   (
       swap start.x end.x
       swap start.y end.y
   )
   local deltaX = end.x - start.x
   local deltaY = abs (end.y - start.y)
   local error = deltaX / 2.0
   local yStep = -1
   local y = start.y
   if start.y < end.y then
   (
       yStep = 1
   )
   for x in start.x to end.x do
   (
       plot img [x, y] steep col
       error -= deltaY
       if error < 0 then
       (
           y += yStep
           error += deltaX
       )
   )
   img

)

myBitmap = bitmap 512 512 color:(color 0 0 0) myBitmap = drawLine myBitmap [0, 511] [511, 0] #((color 255 255 255)) display myBitmap</lang>

OCaml

<lang ocaml>let draw_line ~img ~color ~p0:(x0,y0) ~p1:(x1,y1) =

 let steep = abs(y1 - y0) > abs(x1 - x0) in
 let plot =
   if steep
   then (fun x y -> put_pixel img color y x)
   else (fun x y -> put_pixel img color x y)
 in
 let x0, y0, x1, y1 =
   if steep
   then y0, x0, y1, x1
   else x0, y0, x1, y1
 in
 let x0, x1, y0, y1 =
   if x0 > x1
   then x1, x0, y1, y0
   else x0, x1, y0, y1
 in
 let delta_x = x1 - x0
 and delta_y = abs(y1 - y0) in
 let error = -delta_x / 2
 and y_step =
   if y0 < y1 then 1 else -1
 in
 let rec loop x y error =
   plot x y;
   if x <= x1 then
     let error = error + delta_y in
     let y, error =
       if error > 0
       then (y + y_step), (error - delta_x)
       else y, error
     in
     loop (succ x) y error
 in
 loop x0 y0 error
</lang>

Perl

Library: Imlib2

<lang perl>#! /usr/bin/perl use strict; use Image::Imlib2;

sub my_draw_line {

   my ( $img, $x0, $y0, $x1, $y1) = @_;
   
   my $steep = (abs($y1 - $y0) > abs($x1 - $x0));
   if ( $steep ) {

( $y0, $x0 ) = ( $x0, $y0); ( $y1, $x1 ) = ( $x1, $y1 );

   }
   if ( $x0 > $x1 ) {

( $x1, $x0 ) = ( $x0, $x1 ); ( $y1, $y0 ) = ( $y0, $y1 );

   }
   my $deltax = $x1 - $x0;
   my $deltay = abs($y1 - $y0);
   my $error = $deltax / 2;
   my $ystep;
   my $y = $y0;
   my $x;
   $ystep = ( $y0 < $y1 ) ? 1 : -1;
   for( $x = $x0; $x <= $x1; $x += 1 ) {

if ( $steep ) { $img->draw_point($y, $x); } else { $img->draw_point($x, $y); } $error -= $deltay; if ( $error < 0 ) { $y += $ystep; $error += $deltax; }

   }

}

  1. test

my $img = Image::Imlib2->new(160, 160); $img->set_color(255, 255, 255, 255); # white $img->fill_rectangle(0,0,160,160);

$img->set_color(0,0,0,255); # black my_draw_line($img, 10, 80, 80, 160); my_draw_line($img, 80, 160, 160, 80); my_draw_line($img, 160, 80, 80, 10); my_draw_line($img, 80, 10, 10, 80);

$img->save("test0.png");

  1. let's try the same using its internal algo

$img->set_color(255, 255, 255, 255); # white $img->fill_rectangle(0,0,160,160); $img->set_color(0,0,0,255); # black $img->draw_line(10, 80, 80, 160); $img->draw_line(80, 160, 160, 80); $img->draw_line(160, 80, 80, 10); $img->draw_line(80, 10, 10, 80);

$img->save("test1.png");

exit 0;</lang>

Images test0.png and test1.png look different since Imlib2 draw lines with antialiasing.

Python

Works with: Python version 3.1

Extending the example given here and using the algorithm from the ADA solution:

<lang python>def line(self, x0, y0, x1, y1):

   "Bresenham's line algorithm"
   dx = abs(x1 - x0)
   dy = abs(y1 - y0)
   x, y = x0, y0
   sx = -1 if x0 > x1 else 1
   sy = -1 if y0 > y1 else 1
   if dx > dy:
       err = dx / 2.0
       while x != x1:
           self.set(x, y)
           err -= dy
           if err < 0:
               y += sy
               err += dx
           x += sx
   else:
       err = dy / 2.0
       while y != y1:
           self.set(x, y)
           err -= dx
           if err < 0:
               x += sx
               err += dy
           y += sy        
   self.set(x, y)

Bitmap.line = line

bitmap = Bitmap(17,17) for points in ((1,8,8,16),(8,16,16,8),(16,8,8,1),(8,1,1,8)):

   bitmap.line(*points)

bitmap.chardisplay()

The origin, 0,0; is the lower left, with x increasing to the right, and Y increasing upwards.

The chardisplay above produces the following output : +-----------------+ | @ | | @ @ | | @ @ | | @ @ | | @ @ | | @ @ | | @ @ | | @ @ | | @ @| | @ @ | | @ @ | | @ @@ | | @ @ | | @ @ | | @ @ | | @ | | | +-----------------+ </lang>

RapidQ

Use this routine together with the code from Basic bitmap storage to create a full application.

<lang rapidq>SUB draw_line(x1, y1, x2, y2, colour)

   x_dist = abs(x2-x1)
   y_dist = abs(y2-y1)
   IF y2-y1 < -x_dist OR x2-x1 <= -y_dist THEN
       SWAP x1, x2				' Swap start and end points

SWAP y1, y2

   END IF
   IF x1 < x2 THEN x_step = 1 ELSE x_step = -1
   IF y1 < y2 THEN y_step = 1 ELSE y_step = -1
   
   IF y_dist > x_dist THEN			' steep angle, step by y

error = y_dist/2 x = x1 FOR y = y1 TO y2 canvas.Pset(x, y, colour) error = error - x_dist IF error < 0 THEN x = x + x_step error = error + y_dist END IF NEXT y

   ELSE					' not steep, step by x
       error = x_dist/2

y = y1 FOR x = x1 TO x2 canvas.Pset(x, y, colour) error = error - y_dist IF error < 0 THEN y = y + y_step error = error + x_dist END IF NEXT y

   END IF
   

END SUB</lang>

Example usage:

<lang rapidq>SUB PaintCanvas

   draw_line 200,  10, 100, 200, &H00ff00
   draw_line 100, 200, 200, 400, &H00ff00
   draw_line 200, 400, 300, 200, &H00ff00
   draw_line 300, 200, 200,  10, &H00ff00

END SUB</lang>

Ruby

<lang ruby>Pixel = Struct.new(:x, :y)

class Pixmap

 def draw_line(p1, p2, colour)
   validate_pixel(p1.x, p2.y)
   validate_pixel(p2.x, p2.y)
   x1, y1 = p1.x, p1.y
   x2, y2 = p2.x, p2.y

   steep = (y2 - y1).abs > (x2 - x1).abs
   if steep
     x1, y1 = y1, x1
     x2, y2 = y2, x2
   end
   if x1 > x2
     x1, x2 = x2, x1
     y1, y2 = y2, y1
   end
   deltax = x2 - x1
   deltay = (y2 - y1).abs
   error = deltax / 2
   ystep = y1 < y2 ? 1 : -1

   y = y1
   x1.upto(x2) do |x|
     pixel = steep ? [y,x] : [x,y]
     self[*pixel] = colour
     error -= deltay
     if error < 0
       y += ystep
       error += deltax
     end
   end
 end

end

bitmap = Pixmap.new(500, 500) bitmap.fill(RGBColour::BLUE) 10.step(430, 60) do |a|

 bitmap.draw_line(Pixel[10, 10], Pixel[490,a], RGBColour::YELLOW)
 bitmap.draw_line(Pixel[10, 10], Pixel[a,490], RGBColour::YELLOW)

end bitmap.draw_line(Pixel[10, 10], Pixel[490,490], RGBColour::YELLOW)</lang>

Tcl

Library: Tk

ref Basic bitmap storage#Tcl <lang tcl>package require Tcl 8.5 package require Tk

proc drawLine {image colour point0 point1} {

   lassign $point0 x0 y0
   lassign $point1 x1 y1
   
   set steep [expr {abs($y1 - $y0) > abs($x1 - $x0)}]
   if {$steep} {
       lassign [list $x0 $y0] y0 x0
       lassign [list $x1 $y1] y1 x1
   }
   if {$x0 > $x1} {
       lassign [list $x0 $x1] x1 x0
       lassign [list $y0 $y1] y1 y0
   }
   set deltax [expr {$x1 - $x0}]
   set deltay [expr {abs($y1 - $y0)}]
   set error [expr {$deltax / 2}]
   set ystep [expr {$y0 < $y1 ? 1 : -1}]
   
   for {set x $x0; set y $y0} {$x <= $x1} {incr x} {
       setPixel $image $colour [expr {$steep ? [list $y $x] : [list $x $y]}]
       incr error -$deltay
       if {$error < 0} {
           incr y $ystep
           incr error $deltax
       }
   }

}

  1. create the image and display it

set img [newImage 200 100] label .l -image $img pack .l

fill $img black drawLine $img yellow {20 20} {180 80} drawLine $img yellow {180 20} {20 80}</lang>

TI-89 BASIC

Note: This example does not use a user-defined image type, since that would be particularly impractical, but rather draws on the calculator's graph screen, which has essentially the same operations as an implementation of Basic bitmap storage would, except for being black-and-white.
Translation of: E

<lang ti89b>(lx0, ly0, lx1, ly1) Prgm

 Local steep, x, y, dx, dy, ystep, error, tmp
 abs(ly1 - ly0) > abs(lx1 - lx0) → steep
 If steep Then
   lx0 → tmp
   ly0 → lx0
   tmp → ly0
   lx1 → tmp
   ly1 → lx1
   tmp → ly1
 EndIf
 If lx0 > lx1 Then
   lx0 → tmp
   lx1 → lx0
   tmp → lx1
   ly0 → tmp
   ly1 → ly0
   tmp → ly1
 EndIf
 lx1 - lx0 → dx
 abs(ly1 - ly0) → dy
 when(ly0 < ly1, 1, –1) → ystep
 intDiv(dx, 2) → error
 ly0 → y
 For x,lx0,lx1
   If steep Then: PxlChg x, y :Else: PxlChg y, x :EndIf
   error - dy → error
   If error < 0 Then
     y + ystep → y
     error + dx → error
   EndIf
 EndFor

EndPrgm</lang>

Vedit macro language

<lang vedit>// Daw a line using Bresenham's line algorithm. // #1=x1, #2=y1; #3=x2, #4=y2

DRAW_LINE:

Num_Push(31,35)

  1. 31 = abs(#3-#1) // x distance
  2. 32 = abs(#4-#2) // y distance

if (#4-#2 < -#31 || #3-#1 <= -#32) {

   #99=#1; #1=#3; #3=#99	// swap start and end points
   #99=#2; #2=#4; #4=#99

} if (#1 < #3) { #34=1 } else { #34=-1 } // x step if (#2 < #4) { #35=1 } else { #35=-1 } // y step

if (#32 > #31) { // steep angle, step by Y

   #33 = #32 / 2		// error distance
   while (#2 <= #4) {

Call("DRAW_PIXEL") #33 -= #31 if (#33 < 0) { #1 += #34 // move right #33 += #32 } #2++ // move up

   }

} else { // not steep, step by X

   #33 = #31 / 2
   while (#1 <= #3) {

Call("DRAW_PIXEL") #33 -= #32 if (#33 < 0) { #2 += #35 // move up #33 += #31 } #1++ // move right

   }

} Num_Pop(31,35) return</lang>