4

Original Bresenham's line drawing algorithm it limited to drawing lines between two integer pixel positions and does not allow subpixel rendering. However with my reformulation of this algorithm as a system of equations it seems straighforward to extend it for subpixel rendering as follows (code for version 10):

Clear[bresenhamSolve];
bresenhamSolve[p1_, p2_] /; 
   GreaterEqual @@ Abs[p2 - p1] && MatchQ[Sign[p2 - p1], {1, 1} | {1, 0}] := 
  Block[{ab = First@Solve[{p1, p2}.{a, 1} == b], x, y}, {x, y} /. 
    Solve[{a x + y + err == b /. ab, -1/2 < err <= 1/2, {x, y} \[Element] Integers, 
      Round[p1] <= {x, y} <= Round[p2]}, {x, y, err}]];
bresenhamSolve[p1_, p2_] /; 
   Less @@ Abs[p2 - p1] && MatchQ[Sign[p2 - p1], {1, 1} | {0, 1}] := 
  Reverse /@ bresenhamSolve[Reverse[p1], Reverse[p2]];
bresenhamSolve[p1_, p2_] := 
  With[{s = 2 UnitStep[p2 - p1] - 1}, 
   Replace[bresenhamSolve[p1 s, p2 s], {x_, y_} :> s {x, y}, {1}]];

As one can see, the only change as compared to my previous formulation is wrapping the boundary coordinates for {x, y} by Round.

This implementation has nice radial distribution of sampled pixels:

r = 20; center = {-11, 0};
pointsOnCircle = Rationalize[N@CirclePoints[center, 20, 200], 0];
ArrayPlot[SparseArray[
  Rule @@@ Tally[# - center & /@ 
     Flatten[bresenhamSolve[center, #] & /@ pointsOnCircle + r + 1, 1]], {2 r + 1, 
   2 r + 1}], Mesh -> True, PlotRange -> {All, All, {0, 10}}, ClippingStyle -> Red, 
 PixelConstrained -> True]

plot

Unfortunately this implementation is quite slow. I tried to create more efficient version using nikie's approach but was not able to reproduce the behavior of bresenhamSolve. For example with simplest implementation

Clear[pointsOnLine]
pointsOnLine[{p1_, p2_}] := 
 Array[Round[p1 + # (p2 - p1)] &, Round@Max[Abs[p2 - p1]] + 1, {0, 1}]

the distribution of sampled pixels is not so pleasing:

r = 20; center = {0, 0};
pointsOnCircle = Rationalize[N@CirclePoints[center, 20, 200], 0];
ArrayPlot[SparseArray[
  Rule @@@ Tally[# - center & /@ 
     Flatten[pointsOnLine[{center, #}] & /@ pointsOnCircle + r + 1, 1]], {2 r + 1, 
   2 r + 1}], Mesh -> True, PlotRange -> {All, All, {0, 10}}, ClippingStyle -> Red, 
 PixelConstrained -> True]

plot

What is an efficient way to implement subpixel version of Bresenham's algorithm?

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368

0 Answers0