Advertisement

circle drawing method comparison

Started by April 20, 2018 07:18 AM
4 comments, last by Fulcrum.013 6 years, 6 months ago

Hello,

I am trying to make a GeometryUtil class that has methods to draw point,line ,polygon etc. I am trying to make a method to draw circle.  

There are many ways to draw a circle.  I have found two ways, 

The one way:


public static void drawBresenhamCircle(PolygonSpriteBatch batch, int centerX, int centerY, int radius, ColorRGBA color)
{
   
   int x = 0, y = radius;
   int d = 3 - 2 * radius;
   while (y >= x)
   {
      drawCirclePoints(batch, centerX, centerY, x, y, color);
      if (d <= 0)
      {
         d = d + 4 * x + 6;
      }
      else
      {
         y--;
         d = d + 4 * (x - y) + 10;
      }
      x++;
      //drawCirclePoints(batch,centerX,centerY,x,y,color);
   }
 
}

private static void drawCirclePoints(PolygonSpriteBatch batch, int centerX, int centerY, int x, int y, ColorRGBA color)
{

   drawPoint(batch, centerX + x, centerY + y, color);
   drawPoint(batch, centerX - x, centerY + y, color);
   drawPoint(batch, centerX + x, centerY - y, color);
   drawPoint(batch, centerX - x, centerY - y, color);

   drawPoint(batch, centerX + y, centerY + x, color);
   drawPoint(batch, centerX - y, centerY + x, color);
   drawPoint(batch, centerX + y, centerY - x, color);
   drawPoint(batch, centerX - y, centerY - x, color);

}

The other way:


public static void drawCircle(PolygonSpriteBatch target, Vector2 center, float radius, int lineWidth, int segments,
                              int tintColorR, int tintColorG, int tintColorB, int tintColorA)
{
   Vector2[] vertices = new Vector2[segments];

   double increment = Math.PI * 2.0 / segments;
   double theta = 0.0;

   for (int i = 0; i < segments; i++)
   {
      vertices[i] = new Vector2((float) Math.cos(theta) * radius + center.x, (float) Math.sin(theta) * radius
            + center.y);
      theta += increment;
   }

   drawPolygon(target, vertices, lineWidth, segments, tintColorR, tintColorG, tintColorB, tintColorA);
}

In the render loop:


polygonSpriteBatch.begin();

Bitmap.drawBresenhamCircle(polygonSpriteBatch,500,300,200,ColorRGBA.Blue);
Bitmap.drawCircle(polygonSpriteBatch,new Vector2(500,300),200,5,50,255,0,0,255);

polygonSpriteBatch.end();

I am trying to choose one of them. So I thought that I should go with the one that does not involve heavy calculations and is efficient and faster.  It is said that the use of floating point numbers , trigonometric operations etc. slows down things a bit.  What do you think would be the best method to use?  When I compared the code by observing the time taken by the flow from start of the method to the end, it shows that the second one is faster. (I think I am doing something wrong here :( ).

Please help!  
Thank you. :) 

Until you draw a million circles / second, I wouldn't worry much about performance, whatever you pick it's always fast enough for a few circles.

As to why it's faster, CPUs have changed, and compilers have improved. It's extremely hard to understand why code is faster or slower. For example, I would not be surprised if the loop of the second solution is unrolled a few times, and several points are computed in parallel in SSE. Secondly, sending a bunch of vectors to the GPU versus sending loads of pixels to the GPU does make a huge difference.

 

Advertisement

Although Albert is right that these things change over time, trigonometric functions are typically very expensive. So are hard-to-predict branches, which perhaps is what's slowing down the first piece of code.

It could also be that the drawing primitives are expensive, and you are making many more calls in your first piece of code than in your second piece of code.

You could also start with a vector (1,0) and progressively rotate it. It would be like your second code but without most of the trigonometric function calls, or hard-to-predict branches.

One more thing: Why is the function that draws 8 symmetric points in the circle called `drawBresenhamCircle'? That's very confusing.

Thank you very much for the responses. I appreciate it. :)

Both the methods, drawPoint() and drawPolygon() eventually draw a pixel image. drawpoint() keeps the scale to (1,1) while drawPolygon() passes the data to drawLine() that scales the image to the distance between two points. So overall it should be the number of calls in first method that is making it a little slow than the use of trigonometric calculations in second. right?

Ah...so rendering 50 lines(segments) + expensive calculations takes less time than rendering 50+ points with simple calculations.

 

5 hours ago, alvaro said:

One more thing: Why is the function that draws 8 symmetric points in the circle called `drawBresenhamCircle'? That's very confusing.

I had previously named it drawCirclePoints() then I changed it to drawBresenhamCircle() just to show that it is the part of the above function. But yeah you are right it is confusing. I will change it. Thanks.
 

Spoiler

 

 

On 4/21/2018 at 4:32 AM, akshayMore said:

Ah...so rendering 50 lines(segments) + expensive calculations takes less time than rendering 50+ points with simple calculations

Also draving a pixel have execution time too.  And in case you make actual drawing thru the windows DCб it uses lot of calculations to find best match color per each drawn pixel, while line drawing using precalculated value, that calculated on pen creation/selection. 

#define if(a) if((a) && rand()%100)

This topic is closed to new replies.

Advertisement