incorrect line rendering
Michal Bozon
Michal.Bozon at vscht.cz
Sat Oct 13 13:11:27 PDT 2007
Hi,
I have noticed that arcs and lines in certain angles are rendered ugly in X11. They are not the same as would be the result of the Bresenham's rasterization algorithm.
For example, look at the image at http://tinyurl.com/2u2ru6
The first window has drawn the line close to 45deg angle rendered with in Xorg/linux (xorg<-tk<-tkinter<-python). In the second one, there is the same line rendered in MS operating system. The latter looks much nicer, and it is the the correct result of Bresenham's algorithm. I was looking into xorg sources, and there seem to be the same algorithm used (at least when looking to the comments)..
I wonder why the result is as is.. is it a bug or intention ?
Is there a chance the drawing algorithm will be fixed, or eventually, if someone provides the patch, is there a chance it will be accepted ?
Thanks,
-m.
PS: I have created a little utility, which helps interactively comparing
the lines rendered by X Windows, and the lines rendered with correct
Bresenham's rasterization algorihm. It's written in Python.
--cut--
#! /usr/bin/env python
# bresenhamlines.py
# 2007 Michal Bozon <michal . bozon (a) gmail . com>
#
# Demonstration of incorrect Xorg line rasterization algorithm
#
from Tkinter import Tk, Canvas, Label
from UserList import UserList
def pixel(canvas, x, y):
"""simulate a pixel by the line
(tk canvas cannot do single pixel ?)"""
return canvas.create_line(x-1, y, x, y)
class Line:
"""Normal line wrapper"""
def __init__(self, canvas, x0, y0, x1, y1):
self.canvas = canvas
self.line = canvas.create_line(x0, y0, x1, y1)
def delete(self):
self.canvas.delete(self.line)
class BresenhamLine:
"""Bresenham line algorithm"""
# taken from
# http://tide4javascript.com/?s=Bresenham
def __init__(self, canvas, x0, y0, x1, y1):
self.canvas = canvas
# simulate pixels by lines
self.pixels = []
steep = abs(y1 - y0) > abs(x1 - x0)
if steep:
# swap
x0, y0 = y0, x0
x1, y1 = y1, x1
if x0 > x1:
x0, x1 = x1, x0
y0, y1 = y1, y0
dx = x1 - x0
dy = abs(y1 - y0)
err = 0
if y0 < y1:
ystep = 1
else:
ystep = -1
y = y0
for x in range(x0, x1):
if steep:
X = y
Y = x
else:
X = x
Y = y
self.pixels.append(pixel(canvas, X, Y))
err += dy
if (2 * err >= dx):
y += ystep
err -= dx
def delete(self):
while self.pixels:
self.canvas.delete(self.pixels.pop())
class App:
line_types = {'xorg': Line,
'Bresenham': BresenhamLine,
}
def line_init(self, event):
self.currline.x0 = event.x
self.currline.y0 = event.y
def line_update(self, event):
for canv in self.canvases:
try:
canv.line.delete()
except:
pass
line_class = self.line_types[canv._name.lstrip('canv_')]
l = line_class(canv,
self.currline.x0,
self.currline.y0,
event.x,
event.y
)
canv.line = l
# canv.update()
def line_drop(self, event):
for canv in self.canvases:
canv.line = None
def __init__(self, root):
self.root = root
self.canvases = []
self.currline = UserList()
for i in enumerate(self.line_types):
canv = Canvas(root,
name='canv_' + i[1],
width=150,
height=150,
bg="#aaaaaa")
canv.grid(row=0, column=i[0])
self.canvases.append(canv)
lbl = Label(root, text=i[1])
lbl.grid(row=1, column=i[0])
for canv in self.canvases:
canv.bind('<1>', self.line_init)
canv.bind('<B1-Motion>', self.line_update)
canv.bind('<ButtonRelease-1>', self.line_drop)
def run(self):
self.root.mainloop()
w = Tk()
app = App(w)
app.run()
--cut--
More information about the xorg
mailing list