17
$\begingroup$

Bresenham's line algorithm is producing discretized line for given two points for purpose of plotting for example.

Like that:

enter image description here

I have to stress that I'm interested in positions, not a plot.

Wikipedia link I've provided includes an algorithm of course. I've just rewritten it thoughtlessly, I don't have time now or special need to work on neat implementation.

But if someone want to improve it (compile e.g.), got it already or know something more, I think this thread may be usefull for future visitors.

Very nice implementation can be found on rossetacode :P, according to that this algorithm should be built in so maybe someone knows how to get it.

Anyway, here's that code:

bresenham[{x1_, y1_}, {x2_, y2_}] := 
 Module[{dx, xi, dy, yi, ai, bi, x, y, d},
     If[x1 < x2, {xi, dx} = {1, x2 - x1};, {xi, dx} = {-1, x1 - x2};];
     If[y1 < y2, {yi, dy} = {1, y2 - y1};, {yi, dy} = {-1, y1 - y2};];
     x = x1; y = y1;
     Sow[{x, y}];
     If[dx > dy,
      (ai = 2 (dy - dx); bi = 2 dy; d = bi - dx;
       While[
        If[d >= 0,
         {x, y, d} += {xi, yi, ai},
         {x, d} += {xi, bi}];
        Sow[{x, y}];
        x != x2])
      ,
      (ai = 2 (dx - dy); bi = 2 dx; d = bi - dy;
       While[
        If[d >= 0,
         {x, y, d} += {xi, yi, ai},
         {y, d} += {yi, bi}];
        Sow[{x, y}];
        y != y2])
      ]] // Reap // Last // First
$\endgroup$
5
  • 1
    $\begingroup$ If your aim is to just draw a line, you can do it in a simpler way with floating point operations. The reason why Bresenham's algorithm is/was important is that it only uses integer operations. Early computers couldn't do floating point operations directly at all. (An Intel 80386 couldn't do floating point operations directly, it required a floating point coprocessor.) Later integer operations were still faster than floating point operations, so it made sense to use this algorithm for good performance. $\endgroup$
    – Szabolcs
    Apr 10, 2014 at 22:48
  • $\begingroup$ Of course it's more fun to use the original Bresenham algorithm ;-) $\endgroup$
    – Szabolcs
    Apr 10, 2014 at 22:52
  • $\begingroup$ @Szabolcs I hope it's just an intro the the answer you are going to post :) I've used it because I needed it here. I wanted it fast so I just took that :) $\endgroup$
    – Kuba
    Apr 10, 2014 at 22:53
  • $\begingroup$ Well, I'm asking about neat/fast implementations or other solutions, it is written, but if it's unclear I can specify. I think it has not sense to cast a close vote without asking... $\endgroup$
    – Kuba
    Apr 11, 2014 at 8:43
  • $\begingroup$ @Kuba Can you put that in the form of a question, in the question? You hint at it, but the Q does come right out and ask. (I did not vote to close, btw.) $\endgroup$
    – Michael E2
    Apr 12, 2014 at 15:33

2 Answers 2

18
$\begingroup$

Original Bresenham

I guess I can come of with a somewhat shorter implementation without using Reap and Sow. If someone is interested, it follows almost exactly the pseudo-code here

bresenham[p0_, p1_] := Module[{dx, dy, sx, sy, err, newp},
  {dx, dy} = Abs[p1 - p0];
  {sx, sy} = Sign[p1 - p0];
  err = dx - dy;
  newp[{x_, y_}] := 
   With[{e2 = 2 err}, {If[e2 > -dy, err -= dy; x + sx, x], 
     If[e2 < dx, err += dx; y + sy, y]}];
  NestWhileList[newp, p0, # =!= p1 &, 1]
]

To test this I use the setup given by the comment of Kuba under this answer:

p1 = {17, 1}; p2 = {7, 25}; 
Graphics[{EdgeForm[{Thick, RGBColor[203/255, 5/17, 22/255]}], 
  FaceForm[RGBColor[131/255, 148/255, 10/17]], 
  Rectangle /@ (bresenham[p1, p2] - .5), {RGBColor[0, 43/255, 18/85], 
   Thick, Line[{p1, p2}]}}, 
 GridLines -> {Range[150], Range[150]} - .5]

Mathematica graphics

Exercise implementation

What follows was only a fun project I did with my wife. Actually, this is not the original Bresenham algorithm. The task for this weekend-fun was to re-invent the algorithm (the iterative steps and the required correction steps) on the blackboard.

For simplicity this algorithm only makes correction steps in one direction (meaning the points stay always on one half-plane of the line) and therefore, the final points are not as close to the original line as with the real Bresenham algorithm.

Anyway, this is my Mathematica implementation of what my wife had to do in Python:

bresenham[p1 : {x1_, y1_}, p2 : {x2_, y2_}] := 
 Module[{dx, dy, dir, corr, test, side},
  {dx, dy} = p2 - p1;
  dir = If[Abs[dx] > Abs[dy], {Sign[dx], 0}, {0, Sign[dy]}];
  test[{x_, y_}] := dy*x - dx*y + dx*y1 - dy*x1;
  side = Sign[test[p1 + dir]];
  corr = side*{-1, 1}*Reverse[dir];
  NestWhileList[
   Block[{new = # + dir}, If[Sign[test[new]] == side, new += corr];
     new] &, p1, #1 =!= p2 &, 1, 500]]

Here a small dynamic test whether the calculated points do indeed look like a line:

DynamicModule[{p = {{0, 0}, {50, 40}}},
 LocatorPane[Dynamic[p],
  Dynamic@
   Graphics[{Line[bresenham @@ Round[p]], Red, PointSize[Large], 
     Dynamic[Point[p]]}, PlotRange -> {{-200, 200}, {-200, 200}}, 
    ImageSize -> 400, Frame -> True, FrameTicks -> False, 
    GridLines -> True],
  Appearance -> None
  ]
 ]

Mathematica graphics

$\endgroup$
4
  • $\begingroup$ @Kuba You are doing nothing wrong. For the Bresenham you need to ensure that you stay on the line and you have to do certain correction steps. It really was only a fun project where we recalculated everything by hand and for simplicity we took correction steps only in one direction. I will point out that this is not the original algorithm. $\endgroup$
    – halirutan
    Apr 10, 2014 at 22:21
  • $\begingroup$ Ok, thanks. :-) $\endgroup$
    – Kuba
    Apr 10, 2014 at 22:30
  • $\begingroup$ @Kuba OK, for the sake of brevity, I included an implementation of the original algorithm in my answer which satisfies your test-code:-) $\endgroup$
    – halirutan
    Apr 10, 2014 at 23:19
  • $\begingroup$ @Kuba For me they are always equal when you switch p1 and p2 in either your or my implementation. Additionally, although the lines are not identical, but they are surely equivalent. $\endgroup$
    – halirutan
    Apr 11, 2014 at 0:24
3
$\begingroup$

Willing to draw lines on the frame-buffer (/dev/fb0) of a Raspberry Pi, I ended up reformulating the Bresenham's line algorithm in a functional way. Let's say the frame-buffer is 16 columns by 9 rows fb0=Array[{#1, #2} &, {9, 16}]. Given two input points {p1,p2} belonging to the grid fb0, the bresenhamn function finds the points of fb0 that are the nearest to the intersections between the Line[{p1,p2}] and all the the grid-lines.

fb0 = Array[{#1,#2}&,{9,16}];

gridLines = Line@{First@#,Last@#}&/@Join[#,Transpose@#]&@fb0;

bresenham = Function[{p1,p2},(RegionIntersection[#,Line@{p1,p2}]&/@gridLines)~DeleteCases~EmptyRegion[_]~Level~{3}//DeleteDuplicates//First/@Nearest[Join@@fb0]@#&]

In this example p1={2,3}; p2={8,15};

SparseArray@Append[#->1&/@bresenham[{2,3},{8,15}],Last@Last@fb0->0]//MatrixPlot[#,Mesh->All]&

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.