Without going into the details of X11 drawing primitives, I coded a method in my python & tkinter code to capture the canvas coordinate of every pixel of a tkinter canvas line created with a known width. It's lacking formal proof but visual inspections seems to indicates it works. I share my research and code below. Hope it helps tkinter users. Suggestions on improvement or feedback on it's use are appreciated.
Assumptions:
- Line width has odd number of pixels.
- Three types of pixel representation are used to draw the line width
pixels: (a) vertical type (|), (b) horizontal type (_) & (c)
diagonal types (/) & (). I observed these line width
representations when tk.canvas.create_line is active.
- The criteria to determine the type of line width pixel
representation are based on the gradient of the relative position
between the two points of a line.
Line Width Pixel Representation Criteria:
Examples:
Code:
def linewidthpixels(self, width, Acol, Arow, Bcol, Brow):
"""
This method attempts to replicate how tk.canvas.createline creates a
line with a given width on tk.canvas. The line width's orientation is a
function of the gradient of the line. Verification was done by visual
comparison; formal proof lacking.
Input Mandatory Argument:
-------------------------
width - width of line including its center pixel (in pixel units).
Acol - line 1st point column coordinate (x-axis).
Arow - line 1st point row coordinate (y-axis).
Bcol - line 2nd point column coordinate (x-axis).
Brow - line 2nd point row coordinate (y-axis).
Internal Variables:
-------------------------
swidth - half the width of line excluding its center pixel (in pixel units).
Return Variable:
----------------
linepixels - a numpy 1D array consisting the (col,row) position [] of every pixel
used to represent a line with a given width.
Created: 20th Jan 2016
Amended: 21st Jan 2016
Acknowledgement: Kindly acknowledge author when using this code (with or without modifications).
"""
print('def linewidthpixels(self, width, Acol, Arow, Bcol, Brow):')
print ('width, Acol, Arow, Bcol, Brow =', width, Acol, Arow, Bcol, Brow)
# 1. Initialise return variable
linepixels = np.array([], dtype=np.uint16)
# 2. Calculate the number of side pixels given to the line
swidth = int(abs((width-1)/2))
print('swidth =', swidth)
# 3. Calculate gradient (m) of the line (B: endpoint, A: startpoint)
if (Bcol - Acol) != 0: # When m is finite
m = (Brow - Arow) / (Bcol - Acol)
else: # when m is infinite
m = float('Infinity')
print ('m =', m)
# 4. Store A: starpoint, it is the centre pixel of the line width
linepixels = np.array([Acol, Arow])
# 5. Determine and store the coordinates of the pixels of the line width
if width != 1: # line width > 1 pixel wide
if m > -0.5 and m < 0.5: # Linewidth type = |
print('Linetype = |')
for k in range(1,swidth+1,1):
linepixels = np.append(linepixels, [[Acol, Arow+k], [Acol, Arow-k]])
elif m >= 0.5 and m < 2.0: # Linewidth type = /
print('Linetype = /')
for k in range(1,swidth+1,1):
linepixels = np.append(linepixels, [[Acol+k, Arow-k], [Acol-k, Arow+k]])
elif m > -2.0 and m <= -0.5: # Linewidth type = \
print('Linetype = \\')
for k in range(1,swidth+1,1):
linepixels = np.append(linepixels, [[Acol-k, Arow-k], [Acol+k, Arow+k]])
else: # Linewidth type = --
print('Linetype = --')
for k in range(1,swidth+1,1):
linepixels = np.append(linepixels, [[Acol+k, Arow], [Acol-k, Arow]])
print ('linepixels =', linepixels)
print ('Size of linepixels =', linepixels.size)
return linepixels