いろいろなCircleアルゴリズムで描画してみた。
元ネタ:http://openfmi.net/snippet/detail.php?type=snippet&id=8
(Google Chromeブラウザでのみ動作チェックしています)
/*--------------------------------------------------------------------
DrawingCircles.c - javascript porting version
Comparing Circles Drawed By
canvas, The Simplest Drawing Circle Algorithm,
Bresenham Circle Algorithm, Michener Algorithm
By S.F.
元ネタ:http://openfmi.net/snippet/detail.php?type=snippet&id=8
--------------------------------------------------------------------*/
var ctx;
var bmp;
var w,h;
var dt;
function pset(x,y,r,g,b,a)
{
var st = (x + w * y) * 4;
dt[st++] = r;
dt[st++] = g;
dt[st++] = b;
dt[st++] = a;
}
// the simplest way to draw a circle:
function reallySimpleCircle (radius, centerx,centery,r,g,b,a)
{
var cx = 0, cy;
var xLimit = Math.sqrt ((radius * radius) / 2);
while (cx++ <= xLimit)
{
cy = Math.floor (Math.sqrt (radius * radius - cx * cx));
pset ( cx + centerx, cy + centery, r,g,b,a); // 45-90 degrees
pset ( cx + centerx, -cy + centery, r,g,b,a); // 270-315 degrees
pset ( -cx + centerx, cy + centery, r,g,b,a); // 90-135 degrees
pset ( -cx + centerx, -cy + centery, r,g,b,a); // 225-270 degrees
pset ( cy + centerx, cx + centery, r,g,b,a); // 0-45 degrees
pset ( cy + centerx, -cx + centery, r,g,b,a); // 315-360 degrees
pset ( -cy + centerx, cx + centery, r,g,b,a); // 135-180 degrees
pset ( -cy + centerx, -cx + centery, r,g,b,a); // 180-225 degrees
}
}
////////////////////////////////////////////////////////
// Bresenham Circle Algorithm:
//
// -Yi Xi
// ---------------o---------------o---------------
// Hi <= | > Di <= | > Vi
// | |
// x++ | x++,y-- | y--
////////////////////////////////////////////////////////
function bresenhamCircle (radius, centerx,centery, r,g,b,a)
{
var cx, cy, d;
cx = 0;
cy = radius;
d = 2 - 2 * radius;
// let's start drawing the circle:
pset ( cx + centerx, cy + centery, r,g,b,a); // point (0, R);
pset ( cx + centerx, -cy + centery, r,g,b,a); // point (0, -R);
pset ( cy + centerx, cx + centery, r,g,b,a); // point (R, 0);
pset ( -cy + centerx, cx + centery, r,g,b,a); // point (-R, 0);
while (1)
{
if (d > -cy)
{
--cy;
d += 1 - 2 * cy;
}
if (d <= cx)
{
++cx;
d += 1 + 2 * cx;
}
if (!cy) return; // cy is 0, but these points are already drawn;
// the actual drawing:
pset ( cx + centerx, cy + centery, r,g,b,a); // 0-90 degrees
pset ( -cx + centerx, cy + centery, r,g,b,a); // 90-180 degrees
pset ( -cx + centerx, -cy + centery, r,g,b,a); // 180-270 degrees
pset ( cx + centerx, -cy + centery, r,g,b,a); // 270-360 degrees
}
}
// Miechener circle algorithm:
function miechenerCircle (radius, centerx,centery, r,g,b,a)
{
var cx, cy, d;
d = 3 - 2 * radius;
cy = radius;
// let's start drawing the circle:
pset ( centerx, radius + centery, r,g,b,a); // point (0, R);
pset ( centerx, -radius + centery, r,g,b,a); // point (0, -R);
pset ( radius + centerx, centery, r,g,b,a); // point (R, 0);
pset ( -radius + centerx, centery, r,g,b,a); // point (-R, 0);
for (cx = 0; cx <= cy; cx++)
{
if (d >= 0)
// in this case we choose Hi:
d += 10 + 4 * cx - 4 * cy--;
else
// in this case we choose Di:
d += 6 + 4 * cx;
// the actual drawing:
pset ( cy + centerx, cx + centery, r,g,b,a); // 0-45 degrees
pset ( cx + centerx, cy + centery, r,g,b,a); // 45-90 degrees
pset ( -cx + centerx, cy + centery, r,g,b,a); // 90-135 degrees
pset ( -cy + centerx, cx + centery, r,g,b,a); // 135-180 degrees
pset ( -cy + centerx, -cx + centery, r,g,b,a); // 180-225 degrees
pset ( -cx + centerx, -cy + centery, r,g,b,a); // 225-270 degrees
pset ( cx + centerx, -cy + centery, r,g,b,a); // 270-315 degrees
pset ( cy + centerx, -cx + centery, r,g,b,a); // 315-360 degrees
}
}
///////////////////////////////////////////////////////////
// double substraction method for drawing a circle:
//
// d0 -> H -> d1 = d0H+d0 -> D -> d2 = d1D+d1
// d0H -> d1H = d0H+2 -> d2H = d1H+2
// d0D -> d1D = d0D+2 -> d2D = d1D+4
// step 0 step 1 step 2
//
///////////////////////////////////////////////////////////
function dsCircle (radius, centerx,centery, r,g,b,a)
{
var cx, cy, d, dH, dD;
d = 1 - radius;
dH = 3;
dD = 5 - 2 * radius;
cy = radius;
// drawing the circle:
for (cx = 0; cx <= cy; cx++)
{
if (d < 0)
{
d += dH;
dH += 2;
dD += 2;
}
else
{
d += dD;
dH += 2;
dD += 4;
--cy;
}
// the actual drawing:
pset ( cy + centerx, cx + centery, r,g,b,a); // 0-45 degrees
pset ( cx + centerx, cy + centery, r,g,b,a); // 45-90 degrees
pset ( -cx + centerx, cy + centery, r,g,b,a); // 90-135 degrees
pset ( -cy + centerx, cx + centery, r,g,b,a); // 135-180 degrees
pset ( -cy + centerx, -cx + centery, r,g,b,a); // 180-225 degrees
pset ( -cx + centerx, -cy + centery, r,g,b,a); // 225-270 degrees
pset ( cx + centerx, -cy + centery, r,g,b,a); // 270-315 degrees
pset ( cy + centerx, -cx + centery, r,g,b,a); // 315-360 degrees
}
}
function draw()
{
reallySimpleCircle(60,w/4,100,80,80,80,255);
bresenhamCircle(60,w/4 * 3,100,80,80,80,255);
miechenerCircle(60,w/4,240,80,80,80,255);
dsCircle(60,w/4*3,240,80,80,80,255);
ctx.putImageData(bmp,0,0);
ctx.beginPath();
ctx.arc(w/4,380, 60, 0, 2 * Math.PI, true);
ctx.stroke();
ctx.textAlign = "center";
ctx.fillText("Simple",w/4,100);
ctx.fillText("Bresenham",w/4*3,100);
ctx.fillText("Miechener",w/4,240);
ctx.fillText("Double Substraction",w/4*3,240);
ctx.fillText("Canvas",w/4,380);
}
window.onload = function()
{
ctx = document.getElementById("ctx").getContext("2d");
w = document.getElementById("ctx").width;
h = document.getElementById("ctx").height;
bmp = ctx.createImageData(w,h);
dt = bmp.data;
draw();
}