I am currently using Bresenham\'s algorithm to draw lines but they are (of course) one pixel in thickness. My question is what is the most efficient way to draw lines of arb
http://members.chello.at/~easyfilter/bresenham.html
The example at the bottom of this link is javascript, but should be easy enough to adapt to C. It's a fairly straightforward antialiasing algorithm to draw lines of variable thickness.
Take another Bresenham loop and use it to modify the start and end position of original line in rectangular direction. Problem is to efficently find the right starting point and not to draw any pixel twice (or skip a pixel) while drawing next line.
Working and tested C code is available from Github C code .
Here a test page including a few sample lines created by this code. The black pixels are the starting points for the algorithm.
I assume that you would draw horizontal spans from one bounding line to another, and compute the x-value of each of the lines by Bresenham's method as you go (in a single loop).
Haven't tried it.
The end points may need some attention, lest they look oddly cut-off.
For those who want a Python version here goes the code (based on the answer of @Fabel):
def drawline(x1,y1,x2,y2,**kwargs):
if kwargs.get('thickness')==None:
thickness=1
else:
thickness=kwargs['thickness']
if kwargs.get('roundcap')==None:
roundcap=False
else:
roundcap=True
angle = np.arctan2(y2-y1,x2-x1)
xx = np.zeros(4)
yy = np.zeros(4)
xx[0] = np.round(x1 + thickness*np.cos(angle+np.pi/2))
yy[0] = np.round(y1 + thickness*np.sin(angle+np.pi/2))
xx[1] = np.round(x1 + thickness*np.cos(angle-np.pi/2))
yy[1] = np.round(y1 + thickness*np.sin(angle-np.pi/2))
xx[2] = np.round(x2 + thickness*np.cos(angle-np.pi/2))
yy[2] = np.round(y2 + thickness*np.sin(angle-np.pi/2))
xx[3] = np.round(x2 + thickness*np.cos(angle+np.pi/2))
yy[3] = np.round(y2 + thickness*np.sin(angle+np.pi/2))
u,v=polygon(xx,yy)
if roundcap:
temp1x, temp1y = circle(x1,y1,thickness)
temp2x, temp2y = circle(x1,y1,thickness)
u = np.append(u,temp1x,temp2x)
v = np.append(v,temp1y,temp2y)
return u,v
When calling the function you can optionally specify thickness and roundcap. For example:
drawline(10,10,50,50,thickness=3,roundcap=False)
Here is a paper and Delphi implementation of a modified version of Bresenham's algorithm for drawing thickened lines.
You may also want to take a look at Anti-Grain Geometry, a library for high-quality and high-performance software rendering of 2D graphics. Take a look at the demo page to get an idea of what it can do.
I do this quite often to generate images of fibers and spheres for porous media simulations. I have a nice simple way do this using a very standard image analysis technique know as the 'distance transform'. This requires having access to some image analysis package. I use Python with Scipy, so this is no problem. Here is a demo to convert randomly distributed points into spheres:
import scipy as sp
import scipy.ndimage as spim
im1 = sp.rand(100, 100) < 0.995 # Create random points in space
dt = spim.distance_transform_edt(im1)
im2 = dt < 5 # To create sphere with a radius of 5
And that is it! The distance transform can be slow for very large images, but there are efficient version out there. For instance, ImageJ has a parallelized one. Obviously, to create thick fibers you just create your image of thin ones, then apply the steps 2 and 3 above.