Tuesday, May 22, 2018

mathematics - How can I render a circular progress bar procedurally?


I'm working in Flash AS3, but pseudo-code or any other language is fine.


How can I make a circular progress bar? Akin to the ship bars in Pax Britanica, you can see them in the screenshot here.


Apart from making them frame by frame, is there some obvious solution I'm missing here?


I'm seeking the equivalent of stretching a rectangle for a regular progress bar, or using a simple mask (if such a solution exists).



(Also I can't tag this with circle or progress bar due to lack of rep if anyone could that would be great)



Answer



First I'll explain the principle, then the drawing part:


In my example I'm assuming that you have a progress value of 0 to 100 (%), even though anything else will do.


On a straight line, the current position of progress-bar would simply be that progress value.


On a circle you get that position with trigonometry. Any point on a circle is given as:


point.x = r * cos(angle);
point.y = r * sin(angle);

where r is the radius of the circle. As you see, the angle is the only variable in those equations. That means that you somehow have to integrate your progress into the angle.



The solution is simple: One "run" around the circle equals 2*Pi (or 360 degrees). You have to split that distance into 100 smaller parts, so that when the progress value is 100, the value inside cos() and sin() is 2*pi (or 360 degrees).


You achieve that by simply dividing 2*pi (or 360 degrees) by 100 and multiplying it with the progress:


float step = 2*pi/100;

point.x = r * cos(progress * step);
point.y = r * sin(progress * step);

Now to the drawing part.


I don't know anything about Actionscript3 (or Flash, for that matter), so I can't tell you the exact procedures, but in general there would be two ways to do this:


First, and (in my opinion easier of the two): Draw the partial circle manually as simply a connection of colored lines with a certain thickness (if you don't need a texture on it and a simple color suffices), or draw the circle as a connection of textured quads (if you need texturing).



Second: You draw a picture which represents your fully-loaded circle and load it as a texture, put it on a quad and render it. Then, you again manually draw a partial circle over that quad and only render the part of the textured quad where the circle is rendered in front of it. In OpenGL, for example, you could easily do this using the stencil buffer.


If you want to know how to calculate the different points on your circle to use them to assemble the required polygons/lines, you can take a look at the above equations again:


point.x = r * cos(angle);
point.y = r * sin(angle);

You can run those inside a for-loop that runs from 0 to your current progress, for example, if it was a circle that consisted of a series of connected dots (in c++ syntax):


float granularity = 2*PI/required_granularity; //determines how smooth your circle will look
float step = 2*PI/100.0f;

list points; //list of all the calculated points

for(float angle=0; angle < progress*step; angle += granularity)
{
Vector2 point(radius*cos(angle), radius*sin(angle));
points.push_back(point); //adds the point to the list
}

Now these points will all be centered on the origin of your coordinate system, so you need to move them to whatever position where you want your circle to be. But I think you can figure that one out yourself :P


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...