Drawing Circles in ruby for pie graphs

Sarlecc

Veteran
Veteran
Joined
Sep 16, 2012
Messages
453
Reaction score
211
First Language
English
Primarily Uses
RMMV
So recently I've kinda wanted to program a pie graph to show stats inside of an rpg game. I am thinking that the slices will be the easy part. Where it would be the number of slices with their sizes added together, then divide that number from each individual slice to get the percentage. Finally having each slice be that percentage of the 360 degrees. However for that I need to know how to first program in a circle this is where I am getting stuck. I have looked at multiple sites and have yet to find out how to do this.

Thoughts on how to accomplish this?

(Also if you see a problem in my logic for the pie slices please don't hesitate to point it out).

Thanks in advance for any help.
 

Wavelength

MSD Strong
Global Mod
Joined
Jul 22, 2014
Messages
5,624
Reaction score
5,104
First Language
English
Primarily Uses
RMVXA
I haven't yet worked with creating circles from scratch in RGSS.  So hopefully someone who has can come along and show you how to do it.

But in the absence of that, don't underestimate the usefulness of using scripting to launch "Show Picture" commands.  For example, I have a "timer" in my game that has 20 separate wedges of a circle picture that will show in one color or the other based on how much time is left.

Math can be done behind the scenes for your pie graph to dynamically determine which wedges should show up in which color - then you just create the appropriate string for each wedge's name based on which color (or whatever) needs to be shown for that wedge.
 

Evgenij

Veteran
Veteran
Joined
Aug 28, 2013
Messages
349
Reaction score
100
First Language
German
Primarily Uses
N/A
You could look up one algorithm and translate it to ruby. This for example would be the code to draw a simple circle with the Midpoint circle algorithm:

Code:
class Bitmap  def draw_circle(radius, x0, y0, c)    x = radius    y = 0    radiusError = 1 - x    while x >= y      set_pixel( x + x0,  y + y0, c)      set_pixel( y + x0,  x + y0, c)      set_pixel(-x + x0,  y + y0, c)      set_pixel(-y + x0,  x + y0, c)      set_pixel(-x + x0, -y + y0, c)      set_pixel(-y + x0, -x + y0, c)      set_pixel( x + x0, -y + y0, c)      set_pixel( y + x0, -x + y0, c)      y += 1      if radiusError < 0        radiusError += 2 * y + 1      else        x -= 1        radiusError += 2 *(y-x) + 1      end    end  endend
 

Sarlecc

Veteran
Veteran
Joined
Sep 16, 2012
Messages
453
Reaction score
211
First Language
English
Primarily Uses
RMMV
That is really cool! Trying to figure out how to fill the circle with color using some of the other algorithms I found from your above post. Might have to sleep on it for awhile.

Anyways thank you very much. :D

@Wavelength I had thought about using the show picture command; however the more I thought on it I realized it would be much more hassle than it's worth.
 

Evgenij

Veteran
Veteran
Joined
Aug 28, 2013
Messages
349
Reaction score
100
First Language
German
Primarily Uses
N/A
You can do it, but I thought that it would be easier if you use something already done for you.

I have made some experiments with the script and got some nice results haha.

Will use that myself to make better looking gauges.
 

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
564
Reaction score
275
First Language
German
Primarily Uses
<deleted :)>

@Evgenij: A very interesting library you found there. Thanks for posting :)
 
Last edited by a moderator:

Sarlecc

Veteran
Veteran
Joined
Sep 16, 2012
Messages
453
Reaction score
211
First Language
English
Primarily Uses
RMMV
So I have found out that in order to fill the circle I have to use the Bresenham's line algorithm which takes two points then draws a line between them. I can get a filled circle now; however I am running into a few empty lines and pixels inside the circle. Here is how I have it set up:

class Bitmap#def draw_line is a bit modified from the ruby sample on http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithmdef draw_line(p1 = [x, y], p2 = [x, y], colour) #p1 is the first point p2 is the second. x1, y1 = p1[0], p1[1] x2, y2 = p2[0], p2[1] steep = (y2 - y1).abs > (x2 - x1).abs if steep x1, y1 = y1, x1 x2, y2 = y2, x2 end if x1 > x2 x1, x2 = x2, x1 y1, y2 = y2, y1 end deltax = x2 - x1 deltay = (y2 - y1).abs error = deltax / 2 ystep = y1 < y2 ? 1 : -1 y = y1 x1.upto(x2) do |x| pixel = steep ? [y,x] : [x,y] set_pixel(x, y, colour) error -= deltay if error < 0 y += ystep error += deltax end end end def draw_circle(radius, x0, y0, c) x = radius y = 0 radiusError = 1 - x while x >= y draw_line( [x0 - x, y0 + y], [x0 + x, y0 + y], c) draw_line( [x0 - x, y0 + y], [y + x0, x + y0], c) draw_line( [x0 - x, y0 + y], [-x + x0, y + y0], c) draw_line( [x0 - x, y0 + y], [-y + x0, x + y0], c) draw_line( [x0 - x, y0 + y], [-x + x0, -y + y0], c) draw_line( [x0 - x, y0 + y], [-y + x0, -x + y0], c) draw_line( [x0 - x, y0 + y], [x + x0, -y + y0], c) draw_line( [x0 - x, y0 + y], [y + x0, -x + y0], c) y += 1 if radiusError < 0 radiusError += 2 * y + 1 else x -= 1 radiusError += 2 *(y-x) + 1 end end endend
I would like to learn why it has those empty lines/pixels. Also I have tried it with the first point (p1) in the draw circle::draw_line area being the mid point. This draws two 1/4th circles on either side so it is shaped like: >< (which still has some missing pixels and I am not certain how to draw the top or bottom 1/4th parts when using the mid point).

My logic on how it should work based on what I have been reading is this:

The draw circle algorithm takes a mid point defined by (x0, y0) and a radius.

The normal algorithm will then set a pixel color on pixels that are on the radius with each set_pixel drawing 1/8th of the circle.

The draw_line algorithm takes two points defined by p1 = [x, y] and p2 = [x, y].

It will then set_pixel color of all the pixels between those two points drawing a line.

To get a filled circle I was thinking of using the mid point for the draw_line p1.

Then from that point draw a line extending to the radius for each 1/8th of the circle.

This is done until the circle is filled.

I am thinking my logic is fairly sound but got something wrong in either my math or in the programming. Any thoughts?

(Hopefully I make sense).
 
Last edited by a moderator:

Sixth

Veteran
Veteran
Joined
Jul 4, 2014
Messages
2,162
Reaction score
822
First Language
Hungarian
Primarily Uses
RMVXA
You got empty pixels because the line you draw each time inside the circle is too narrow (only 1 pixel width).


You work with radius*1 lines, so each line's width is 1 pixel only. While that might work with smaller circles, the bigger the circle itself, the more empty pixels will you see. That is because 1 pixel width lines can not cover the whole circle, not even if 360 lines are drawn in the circle. And looking the code you use, you use integers only, so 360 lines is the max you can write in one circle.


Imagine a very big circle, mark it's mid point, and start to draw lines from the mid point to the edge of the circle in each angle. You will end up with 360 lines, and while the part closer to the middle will be fully filled (the lines are closer to each other), the part closer to the edge will certainly not be filled.


To fix the empty lines, either increase the width of the lines themselves, or lower the radius of the circle itself, until no empty pixels are shown. The latter will most probably result in a very small circle not really suited for representing values or statistics of anything.


I encountered this same problem when I worked on efeberk's Circle Gauges script. I had to increase the width of the points drawn for the mask, or else some pixels would not be "emptied" on the gauge.


You can check that script (with my modifications) here:


http://forums.rpgmakerweb.com/index.php?/topic/37720-battle-hud-request-preferred-compatible-with-yanfly-battle-engine/


Can be good for reference.


Ideally, instead of lines, you should use long and narrow triangles. The triangle should be very narrow closer to the middle of the circle, and it should increase in width the father it gets from the midpoint. That is how a real circle should be drawn, mathematically speaking. I never actually tried to script this. But there are many bitmap extension scripts which can draw polygons easily, so it is just a matter of getting the right math for it.


Or you could just simply use that awesome bitmap extension dll Evgenij posted. Saves you the head-ache of math. :p
 

Sarlecc

Veteran
Veteran
Joined
Sep 16, 2012
Messages
453
Reaction score
211
First Language
English
Primarily Uses
RMMV
Okay that makes sense. When I was doing my research all the articles I was seeing focused on using a line algorithm. Thanks for posting the reference looks like I am going to be doing even more research on the matter. ;)

I'll also have to see what articles I can find with drawing circles with triangles.

Or you could just simply use that awesome bitmap extension dll Evgenij posted. Saves you the head-ache of math.
Yea I know (but learning the math for my self is a whole lot more fun plus it will help me learn more programming which is always a bonus). :)

Edit: In case anyone else wants to read up on this I've found several articles linked in this stackoverflow discussion. It's for c++ however still good information.
 
Last edited by a moderator:

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Couple hours of work. Might use in my game as a secret find or something. Not sure. Fancy though no? :D
Holy stink, where have I been? Well, I started my temporary job this week. So less time to spend on game design... :(
Cartoonier cloud cover that better fits the art style, as well as (slightly) improved blending/fading... fading clouds when there are larger patterns is still somewhat abrupt for some reason.
Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??

Forum statistics

Threads
105,865
Messages
1,017,059
Members
137,574
Latest member
nikisknight
Top