Circle drawing alternatives

JavaScript performance comparison

Test case created by Timo

Preparation code


      
      <script>
Benchmark.prototype.setup = function() {
  var PI2=Math.PI*2;
  
  function drawpixel(x,y)
  {
    return;
  }

};
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
sqrt
var r=50, dia, refX, refY, refOrigoDist;
for(var dia=0;dia<4;dia=dia+0.03)
{

  refX = (dia < 2 ? 1-dia : dia-3); 
  refY = (dia < 3 ? ((dia > 1) ? 2-dia : dia) : dia-4);
  refOrigoDist = Math.sqrt(refX*refX + refY*refY);
  drawpixel( 50 + r * refX / refOrigoDist, 
           50 + r * refY / refOrigoDist);
}
pending…
cos sin
var r=50, point;
for(var i=0;i<PI2;i=i+0.05)
{
  drawpixel(50 + Math.cos(i) * r, 50 + Math.sin(i) * r);
}
pending…
Incremental
var xm=50, ym=50, r=50;
   var x = -r, y = 0, err = 2-2*r; /* II. Quadrant */ 
   do {
      drawpixel(xm-x, ym+y); /*   I. Quadrant */
      drawpixel(xm-y, ym-x); /*  II. Quadrant */
      drawpixel(xm+x, ym-y); /* III. Quadrant */
      drawpixel(xm+y, ym+x); /*  IV. Quadrant */
      
      r = err;
     if (r <= y) {
       ++y;
       err += y*2+1;           /* e_xy+e_y < 0 */
     }
     if (r > x || err > y) 
     {
       ++x;
       err += x*2+1; /* e_xy+e_x > 0 or no 2nd y-step */
     }
   } while (x < 0);
pending…
Precalculate trigs
var cx=50, cy=50, px=0, py=50, theta=PI2, N=125, point;

    var dx = px - cx;
    var dy = py - cy;
    var r2 = dx * dx + dy * dy;
    var r = Math.sqrt(r2);
    var ctheta = Math.cos(theta/(N-1));
    var stheta = Math.sin(theta/(N-1));
    drawpixel(cx + dx, cy + dy);
    for(var i = 1; i != N; ++i)
    {
        var dxtemp = ctheta * dx - stheta * dy;
        dy = stheta * dx + ctheta * dy;
        dx = dxtemp;
        drawpixel(cx + dx, cy + dy);
    }
pending…
CircleBresenham
//http://willperone.net/Code/codecircle.php
var xc=50, yc=50, r=50;

    var x = 0, 
    y = r, 
    p = 3 - 2 * r;
    while (y >= x) // only formulate 1/8 of circle
    {
        drawpixel(xc-x, yc-y);//upper left left
        drawpixel(xc-y, yc-x);//upper upper left
        drawpixel(xc+y, yc-x);//upper upper right
        drawpixel(xc+x, yc-y);//upper right right
        drawpixel(xc-x, yc+y);//lower left left
        drawpixel(xc-y, yc+x);//lower lower left
        drawpixel(xc+y, yc+x);//lower lower right
        drawpixel(xc+x, yc+y);//lower right right
        if (p < 0) p += 4*x++ + 6; 
              else p += 4*(x++ - y--) + 10; 
     }
pending…
CircleMidpoint
//http://willperone.net/Code/codecircle.php
var xc=50, yc=50, r=50;

    var   x= 0, y= r, d= 1-r, dE= 3, dSE= 5 - 2*r;
    drawpixel(xc-r, yc);
    drawpixel(xc+r, yc);
    drawpixel(xc, yc-r);
    drawpixel(xc, yc+r);
      
    while (y > x)    //only formulate 1/8 of circle
    {
        if (d < 0) 
        {
            d+= dE;
            dE+=2, dSE+=2;
        } else {
            d+=dSE;
            dE+=2, dSE+=4;
            y--;
        }
        x++;
 
        drawpixel(xc-x, yc-y);//upper left left
        drawpixel(xc-y, yc-x);//upper upper left
        drawpixel(xc+y, yc-x);//upper upper right
        drawpixel(xc+x, yc-y);//upper right right
        drawpixel(xc-x, yc+y);//lower left left
        drawpixel(xc-y, yc+x);//lower lower left
        drawpixel(xc+y, yc+x);//lower lower right
        drawpixel(xc+x, yc+y);//lower right right
     }
pending…
CircleOptimized
//http://willperone.net/Code/codecircle.php
var xc=50, yc=50, r=50;

    var x= r, y= 0, cd2= 0;
    drawpixel(xc-r, yc);
    drawpixel(xc+r, yc);
    drawpixel(xc, yc-r);
    drawpixel(xc, yc+r);
 
    while (x > y)    //only formulate 1/8 of circle
    {
        cd2-= (--x) - (++y);
        if (cd2 < 0) cd2+=x++;

        drawpixel(xc-x, yc-y);//upper left left
        drawpixel(xc-y, yc-x);//upper upper left
        drawpixel(xc+y, yc-x);//upper upper right
        drawpixel(xc+x, yc-y);//upper right right
        drawpixel(xc-x, yc+y);//lower left left
        drawpixel(xc-y, yc+x);//lower lower left
        drawpixel(xc+y, yc+x);//lower lower right
        drawpixel(xc+x, yc+y);//lower right right
     } 
pending…
DrawCircle
// http://slabode.exofire.net/circle_draw.shtml
var cx=50, cy=50, r=50, num_segments=125;
 
	var theta = 2 * 3.1415926 / num_segments, 
	tangetial_factor = Math.tan(theta), //calculate the tangential factor 

	radial_factor = Math.cos(theta), //calculate the radial factor 
	
	x = r, //we start at angle = 0 
	y = 0, tx, ty, ii; 
    
	for(ii = 0; ii < num_segments; ii++) 
	{ 
		drawpixel(x + cx, y + cy); //output vertex 
        
		//calculate the tangential vector 
		//remember, the radial vector is (x, y) 
		//to get the tangential vector we flip those coordinates and negate one of them 

		tx = -y; 
		ty = x; 
        
		//add the tangential vector 

		x += tx * tangetial_factor; 
		y += ty * tangetial_factor; 
        
		//correct using the radial factor 

		x *= radial_factor; 
		y *= radial_factor; 
	} 
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL.

1 Comment

Will Perone commented :

Hah just found this; glad to see that my optimized circle algorithm is indeed optimized :)