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

Circles 2 - A Simple API that draws circles

Started by EtzGamer, 03 July 2016 - 09:47 PM
EtzGamer #1
Posted 03 July 2016 - 11:47 PM
Circles 2


A simple API that draws circles


After some research, I have created an API that efficiently draws circles using basic algorithms. For now, it only draws circles. However, I plan to add other features soon. :)/>

You may also wish to install the new v2 demo program! [ Installer: pastebin run 8NwC8KxF ]

How to install:
SpoilerStable Release: pastebin get dnegTmJY circles
Beta Release: pastebin get xeZeZutq circles

Note:
Ensure that you save the api in the correct location when installing it as a dependency.
Also ensure that you understand that this project is still under heavy development and big, breaking changes may occur.

Outdated Demo Program Screenshots:
SpoilerSeriously, these are outdated. The circles no longer look the same.
I won't update this as often as this API is under heavy development.

http://imgur.com/Yuc2Apj

http://imgur.com/MEo3bRS

http://imgur.com/eMP6gA9

How to use:
Spoiler
circles.drawCircle(radius, centerX, centerY, color)
Radius: The radius of the circle.
centerX: The X-position of the center of the circle.
centerY: The Y-position of the center of the circle.
color: The color to draw the circle (Using paint / decimal color codes)

circles.drawFilledCircle(radius, centerX, centerY, color, outlineColor)
Radius: The radius of the circle.
centerX: The X-position of the center of the circle.
centerY: The Y-position of the center of the circle.
color: The color to draw the circle (Using decimal color codes)
outlineColor: [Optional] The color of the outline of the circle.

Upcoming Features:
Spoiler-Add drawEllipse()
-Add drawFilledEllipse()

Obsolete Commands:
Spoilercircles.draw()
Spoiler
circles.draw(radius, centerX, centerY, colour)
Draws a simple circle.
No longer usable from v2.0.0be / v2.0.0r!

Known Issues:
Spoiler-API will crash when given invalid decimal color code

Changelog:
Spoilerv2.0.3r [Beta Version: v2.0.3b]
-Accounted ComputerCraft's 6:9 color block ratio for a more accurate circle :D/>
-Used Pythagorean Theorem to replace existing drawCircle() algorithm (it's more efficient and accurate)
-Removed drawFilledCircle() function for now.

v2.0.0r [Beta Version: v2.0.0b]
-New version scheme :P/>
-Optimized circles.drawCircle()
-Fixed and optimized circles.drawFilledCircle()

Beta Changelog:
Spoilerv2.0.2b / v2.0.3b
-Accounted ComputerCraft's 6:9 color block ratio for a more accurate circle

v2.0.1b
-Used Pythagorean Theorem to replace existing drawCircle() algorithm (it's more efficient and accurate)

v2.0.0b
-New version scheme :P/>
-Optimized circles.drawCircle()
-Fixed and optimized circles.drawFilledCircle()
Edited on 08 July 2016 - 01:31 PM
eniallator #2
Posted 04 July 2016 - 04:54 AM
do you know about the for loop in Lua? you have used a lot of while loops when they can be for loops. This would be more efficient and less code :P/>
EtzGamer #3
Posted 04 July 2016 - 04:58 AM
do you know about the for loop in Lua? you have used a lot of while loops when they can be for loops. This would be more efficient and less code :P/>

Never really got around using for loops. :P/>

But I'll add it in the next version

I do appreciate your feedback :)/>
EtzGamer #4
Posted 04 July 2016 - 03:14 PM
I'm currently working on a much more optimized version of Circles: Circles 2.

It is a complete rewrite of the code and would include drawFilledCircle() and fix number rounding errors (as seen on the 2nd demo program screenshot).

Circles 2 is expected to be up some time tomorrow.

UPDATE:
Circles 2 is now LIVE!

What's new in Circles 2:
-New version scheme :P/>
-Optimized circles.drawCircle()
-Fixed and optimized circles.drawFilledCircle()
Edited on 04 July 2016 - 09:37 PM
LDDestroier #5
Posted 04 July 2016 - 08:46 PM
Can you add a circle function that accounts for the rectangular shape of ComputerCraft pixels?
ReBraLaCC #6
Posted 04 July 2016 - 09:00 PM
maybe idea to make filled circles

function filledCircle(rad,centerx,centery,color)
 for i = 1,rad do
  draw(rad-i+1,centerx,centery,color)
 end
end

maybe it works but its a prototype ;)/>
nice api!
EtzGamer #7
Posted 04 July 2016 - 11:42 PM
maybe idea to make filled circles

function filledCircle(rad,centerx,centery,color)
for i = 1,rad do
  draw(rad-i+1,centerx,centery,color)
end
end

maybe it works but its a prototype ;)/>
nice api!

Thanks :)/>

If I am not mistaken, the code you got there draws diagonal lines; from the center point of the circle to the edges.

I tried that, but it did not work due to math.floor() rounding issues, thus leaving the circle with some holes :P/>

I have found a solution to this and is now live, I would like to hear feedback regarding this rewritten API, Circles 2.

Can you add a circle function that accounts for the rectangular shape of ComputerCraft pixels?

Can you elaborate? :)/>
Edited on 04 July 2016 - 09:41 PM
Lemmmy #8
Posted 04 July 2016 - 11:52 PM
For filled circles, you can use the Pythagoras Theorem. However, this algorithm draws a few extra pixels, but it shows one of the ways you can draw them.


for y = -radius, radius do
    for x = -radius, radius do
        if x * x + y * y <= radius * radius then
            --# draw pixel at x + originX, y + originY
        end
    end
end

Another method, and this is the method I would recommend you use for both non-filled and filled, is Bresenham's Midpoint Circle Algorithm. This is the most accurate way to draw a circle, and it is fairly fast. I'd suggest reading up on how it works. Wikipedia shows you an implementation for outlined circles in C and JavaScript, which should be easy to port to Lua.

In order to draw filled circles, you can change the algorithm slightly, so instead of:

plot(x0 + x, y0 + y)
plot(x0 - x, y0 + y)
and similar lines, you instead do:

paintutils.drawLine(x0 - x, y0 + y, x0 + x, y0 + y)

Generally, I would also suggest allowing the user to pass in their own term objects to draw the circles with, instead of having to redirect to the term object just to use paintutils. This means you need to implement line drawing. Luckily, Bresenham also came up with a line drawing algorithm. Allowing users to pass in their own term object would let them use your API in a buffer such as a framebuffer, or BLittle's drawing buffer.
Edited on 04 July 2016 - 09:52 PM
LDDestroier #9
Posted 05 July 2016 - 12:24 AM
Can you add a circle function that accounts for the rectangular shape of ComputerCraft pixels?

Can you elaborate? :)/>

The characters for ComputerCraft are not square, they are 5x7. So, like, this new circle render function would make the circle 7/5 of the radius wider.
Lemmmy #10
Posted 05 July 2016 - 01:15 AM
The characters for ComputerCraft are not square, they are 5x7. So, like, this new circle render function would make the circle 7/5 of the radius wider.

what are you on, characters are 1:1.5 w:h ratio, so they are 6x9 not 5x7

standard text characters are 5:7 though but regular drawing chars don't include that whitespace of course
Edited on 04 July 2016 - 11:16 PM
Bomb Bloke #11
Posted 05 July 2016 - 02:36 AM
Also somewhat worth noting that if you're using the teletext characters to draw things, then the "pixels" are effectively square - so in cases where eg BLittle's buffer is being used, you wouldn't want to apply any scaling.
EtzGamer #12
Posted 05 July 2016 - 10:16 AM
For filled circles, you can use the Pythagoras Theorem. However, this algorithm draws a few extra pixels, but it shows one of the ways you can draw them.


for y = -radius, radius do
	for x = -radius, radius do
		if x * x + y * y <= radius * radius then
			--# draw pixel at x + originX, y + originY
		end
	end
end

Another method, and this is the method I would recommend you use for both non-filled and filled, is Bresenham's Midpoint Circle Algorithm. This is the most accurate way to draw a circle, and it is fairly fast. I'd suggest reading up on how it works. Wikipedia shows you an implementation for outlined circles in C and JavaScript, which should be easy to port to Lua.

In order to draw filled circles, you can change the algorithm slightly, so instead of:

plot(x0 + x, y0 + y)
plot(x0 - x, y0 + y)
and similar lines, you instead do:

paintutils.drawLine(x0 - x, y0 + y, x0 + x, y0 + y)

Generally, I would also suggest allowing the user to pass in their own term objects to draw the circles with, instead of having to redirect to the term object just to use paintutils. This means you need to implement line drawing. Luckily, Bresenham also came up with a line drawing algorithm. Allowing users to pass in their own term object would let them use your API in a buffer such as a framebuffer, or BLittle's drawing buffer.

Thanks for the suggestion!

I'll definitely consider including these Bresenham's Midpoint Circle Algorithm into the API in the near future. :)/>

[strike]However, I may not include Pythagoras Theorem as it is 'not efficient' from the drawing of extra pixels.[/strike]
EDIT : I have implemented Pythagorean Theorem into Circles 2 Beta v2.0.1b as it was found to be faster. :D/>

But I'll definitely compare these algorithms and time them, seeing which one is faster.

Also, could you emphasize on 'allowing the user to pass in their own term objects to draw the circles with'?
Edited on 06 July 2016 - 01:22 AM
Bomb Bloke #13
Posted 05 July 2016 - 12:39 PM
Also, could you emphasize on 'allowing the user to pass in their own term objects to draw the circles with'?

Allow this sort of thing:

local mon = peripheral.wrap("right")

local oldTerm = term.redirect(mon)

circles.drawCircle(5, 10, 10, colours.yellow)

term.redirect(oldTerm)

… to instead be performed via this sort of thing:

local mon = peripheral.wrap("right")

circles.drawCircle(5, 10, 10, colours.yellow, mon)
Lemmmy #14
Posted 05 July 2016 - 01:18 PM
Also, could you emphasize on 'allowing the user to pass in their own term objects to draw the circles with'?

Allow this sort of thing:

local mon = peripheral.wrap("right")

local oldTerm = term.redirect(mon)

circles.drawCircle(5, 10, 10, colours.yellow)

term.redirect(oldTerm)

… to instead be performed via this sort of thing:

local mon = peripheral.wrap("right")

circles.drawCircle(5, 10, 10, colours.yellow, mon)

More common usages include redirecting to a framebuffer from Lyqyd's framebuffer API, a surface from CrazedProgrammer's Surface API, windows from ComputerCraft's window API, windows from Bomb Bloke's BLittle API and more.
EtzGamer #15
Posted 06 July 2016 - 03:30 AM
Circles Beta v2.0.1b is out now!


v2.0.1b Changelog:
-Used Pythagorean Theorem to replace existing drawCircle() algorithm (it's more accurate)
-Accounted ComputerCraft's 6:9 color block ratio for a more accurate circle Removed for now.

EDIT:
There is a severe issue that was discovered in the code. In the mean time, please use the stable build instead.


EDIT 2:
A hotfix has been issued and the issue has been resolved! The version number will not change. Thanks for your patience :)/>/>
Edited on 09 July 2016 - 03:55 AM
EtzGamer #16
Posted 08 July 2016 - 11:23 AM
Can you add a circle function that accounts for the rectangular shape of ComputerCraft pixels?

Circles Beta v2.0.2b / v2.0.3b is out now!


v2.0.2b / v2.0.3b Changelog:
-Accounted ComputerCraft's 6:9 color block ratio for a more accurate circle :D/>
Edited on 08 July 2016 - 01:28 PM
EtzGamer #17
Posted 08 July 2016 - 03:28 PM
Circles Beta v2.0.3r is out now!


v2.0.3r Changelog:
-Accounted ComputerCraft's 6:9 color block ratio for a more accurate circle :D/>/>
-Used Pythagorean Theorem to replace existing drawCircle() algorithm (it's more accurate)
-Removed drawFilledCircle() function for now.
Edited on 09 July 2016 - 03:57 AM
Lemmmy #18
Posted 08 July 2016 - 04:27 PM
-Used Pythagorean Theorem to replace existing drawCircle() algorithm (it's more efficient and accurate)

I said it wasn't, and it isn't - implement Bresenham's Midpoint Circle Algorithm instead.
EtzGamer #19
Posted 09 July 2016 - 08:00 AM
-Used Pythagorean Theorem to replace existing drawCircle() algorithm (it's more efficient and accurate)

I said it wasn't, and it isn't - implement Bresenham's Midpoint Circle Algorithm instead.

I got my facts wrong about it being efficient; my bad. But the midpoint circle algorithm will be implemented alongside.