This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
TheOddByte's profile picture

Something is wrong with the line algoritm.

Started by TheOddByte, 23 February 2015 - 01:03 AM
TheOddByte #1
Posted 23 February 2015 - 02:03 AM
So I was developing a graphic API today and stumbled upon a problem with my line function, it doesn't really work that well when drawing a vertical line. Here's a screenshot of what I mean.

See the difference? I don't really know what's wrong, I've looked into paintutils function but that didn't get me anywhere.
Some help would be much appreciated.

Here's the code for the Graphics API
Graphics API

--[[
	[Library] Graphics
	@version 1.0, 2015-02-23
	@author TheOddByte
--]]



local Graphics = {}




Graphics.setColor = function( col )
	assert( type( col ) == "number" or type( col ) == "string", "string/number expected, got " .. type( col ), 2 )
	term.setTextColor( type( col ) == "number" and col or colors[col] )
end



Graphics.setBackgroundColor = function( col )
	assert( type( col ) == "number" or type( col ) == "string", "string/number expected, got " .. type( col ), 2 )
	term.setBackgroundColor( type( col ) == "number" and col or colors[col] )
end



Graphics.writeAt = function( x, y, text )
	term.setCursorPos( x, y )
	term.write( text )
end



Graphics.line = function( x1, y1, x2, y2, col )
	local dx, dy = x2-x1, y2-y1

	if col then
		Graphics.setBackgroundColor( col )
	end

	Graphics.writeAt( x1, y1, " " )
	if (dx ~= 0) then
		local m = dy / dx;
		local b = y1 - m*x1;
		dx = x2 > x1 and 1 or -1
		while x1 ~= x2 do
			x1 = x1 + dx
			y1 = math.floor( m*x1 + b + 0.5);
			Graphics.writeAt( x1, y1, " " )
		end
	end
end



Graphics.rectangle = function( mode, x, y, width, height, col )
	assert( mode == "fill" or mode == "line", "invalid mode", 2 )
	Graphics.setBackgroundColor( col )
	local line = string.rep( " ", width )
	if mode == "fill" then
		for i = 1, height do
			Graphics.writeAt( x, (y-1)+i, line )
		end
	else
		for i = 1, height do
			if i == 1 or i == height then
				Graphics.writeAt( x, (y-1)+i, line )
			else
				Graphics.writeAt( x, (y-1)+i, " " )
				Graphics.writeAt( x + width - 1, (y-1)+i, " " )
			end
		end
	end
end



return Graphics
Main code

local Graphics = dofile( "Graphics" )

local line = {
	x1 = 1,
	y1 = 3,
	x2 = 51;
	y2 = 19;
}


local mode = "graphics"
while true do
	Graphics.setBackgroundColor( "black" )
	term.clear()
	Graphics.writeAt( 1, 1, mode == "graphics" and "Graphics API" or "Paintutils" )
	if mode == "graphics" then
		Graphics.line( line.x1, line.y1, line.x2, line.y2, "white" )
	else
		paintutils.drawLine( line.x1, line.y1, line.x2, line.y2, colors.red )
	end
	local e = { os.pullEvent() }
	if e[1] == "mouse_click" or e[1] == "mouse_drag" then
		if e[2] == 1 then
			line.x1, line.y1 = e[3], e[4]

		elseif e[2] == 2 then
			line.x2, line.y2 = e[3], e[4]
		end

	elseif e[1] == "key" then
		if e[2] == 28 then
			mode = mode == "graphics" and "paintutils" or "graphics"
		end

	elseif e[1] == "char" then
		if e[2] == "r" then
			local w, h = term.getSize()
			line.x1, line.y1 = math.random( 1, w ), math.random( 1, h )
			line.x2, line.y2 = math.random( 1, w ), math.random( 1, h )
		end
	end
end
Bomb Bloke #2
Posted 23 February 2015 - 02:34 AM
You're drawing one character for each column the line covers, even though there's more rows than columns. Thus you get gaps.
TheOddByte #3
Posted 23 February 2015 - 02:43 AM
Call me stupid, but I'm not quite sure how to fix it ( I blame the lack of sleep ). Is there any error you can spot in the Graphics.line function that causes this?
Is there something wrong with the algoritm? ( FYI, I'm really bad with algoritms )
Bomb Bloke #4
Posted 23 February 2015 - 03:08 AM
What I'm saying is that if your line will cover more columns then rows (that is to say, dx > dy), looping from x1 to x2 works fine - you're drawing one character in all columns, and you're drawing one or more characters in each row.

But if your line covers more rows than columns (dx < dy), looping from x1 to x2 will perform less iterations than there are rows - meaning some rows won't have a character drawn in them.
TheOddByte #5
Posted 23 February 2015 - 03:24 AM
Ahh, thanks. I'll try to fix it tomorrow. It's getting kinda late :P/>
dan200 #6
Posted 23 February 2015 - 10:07 AM
You know the bresenham line drawing algorithm is already implemented in ComptuerCraft, right? paintutils.drawLine()
ElvishJerricco #7
Posted 23 February 2015 - 10:19 AM
You know the bresenham line drawing algorithm is already implemented in ComptuerCraft, right? paintutils.drawLine()

Yes, in his post he compared his algorithm to the one used by paintutils =P I think he just wants his own.
TheOddByte #8
Posted 23 February 2015 - 02:43 PM
Yes I know that, just wanted to create my own as ElvishJerricco said.

Edit: 1337th post! :D/>
Edited on 23 February 2015 - 01:44 PM