サンプルコード

javaで書いたサンプルコードです。 実行ディレクトリに「CircleRenderTest.png」という画像ファイルを出力します。 フレームは使っていません。

// CircleRenderTest.java
import java.io.File;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;

public class CircleRenderTest
{
    public static final int IMAGE_SIZE = 420;
    public static final String FILE_NAME = "CircleRenderTest.png";
    
    public static final int ALPHA_MAX  = 255;
    public static final int RADIUS_MAX = 200;
    
    private int [][] _D;
    
    private BufferedImage _img;
    
    public void initD()
    {
        _D = new int[RADIUS_MAX + 1][];
        
        _D[0] = new int[1];
        _D[0][0] = 0;
        for(int r = 1; r <= RADIUS_MAX; r++)
        {
            int y_max = (int)(Math.ceil( (double)r / Math.sqrt(2.0) ) );
            _D[r] = new int[y_max + 1];
            
            for(int y = 0; y <= y_max; y++)
            {
                double x = Math.sqrt(r * r - y * y);
                _D[r][y] = (int)(ALPHA_MAX * (Math.ceil(x) - x) );
            }
        }
    }
    
    public void drawCircle(int cx, int cy, int r, int color)
    {
        int[] Dr = _D[r];
        
        int x = r;
        int y = 0;
        int d = 0;
        int d_old = 0;
        
        // 軸上の点は4wayでいいんだけど、手抜き
        setPixel8way(cx, cy, x, y, color, ALPHA_MAX);
        
        while(y < x - 1) // 内側のピクセルと45度の線を比べる
        {
            y++;
            d = Dr[y];
            
            if(d < d_old)
            {
                x--;
            }
            
            setPixel8way(cx, cy, x    , y, color, ALPHA_MAX - d); // 外側のピクセル
            setPixel8way(cx, cy, x - 1, y, color, d);             // 内側のピクセル
            d_old = d;
        }
    }
    
    public void setPixel8way(int cx, int cy, int x, int y, int color, int alpha)
    {
        int rgba = alpha << 24 | color;
        _img.setRGB(cx + x, cy + y, rgba);
        _img.setRGB(cx + x, cy - y, rgba);
        _img.setRGB(cx - x, cy + y, rgba);
        _img.setRGB(cx - x, cy - y, rgba);
        _img.setRGB(cx + y, cy + x, rgba);
        _img.setRGB(cx + y, cy - x, rgba);
        _img.setRGB(cx - y, cy + x, rgba);
        _img.setRGB(cx - y, cy - x, rgba);
    }
    
    public void run()
    {
        _img = new BufferedImage(IMAGE_SIZE, IMAGE_SIZE, BufferedImage.TYPE_INT_ARGB);
        Graphics g = _img.createGraphics();
        
        initD();
        int color = 0;
        for(int r = 0; r <= RADIUS_MAX; r += 10)
        {
            drawCircle(
                IMAGE_SIZE / 2,
                IMAGE_SIZE / 2,
                r,
                calcColor(color++) );
        }
        
        try
        {
            ImageIO.write(_img, "png", new File(FILE_NAME) );
        }
        catch(Exception exc)
        {
            exc.printStackTrace();
        }
    }
    
    public int calcColor(int r)
    {
        int rgb = (r % 6) + 1;
        return
            ( (rgb & 0x4) > 0 ? 0xff0000 : 0) |
            ( (rgb & 0x2) > 0 ? 0x00ff00 : 0) |
            ( (rgb & 0x1) > 0 ? 0x0000ff : 0);
    }
    
    public static void main(String[] args)
    {
        CircleRenderTest thisApp = new CircleRenderTest();
        thisApp.run();
    }
}

実行結果はこんな感じ。

実行結果の画像を保存してペイントソフトなどで拡大すると、アンチエイリアスがかかっているのが確認できます。 ただし、WindowsXPのMSペイントはアルファ値に対応していないらしく、アンチエイリアスが確認できません。 (以降のMSペイントはどうなんでしょう?) 適当なペイントソフトを用意して見てください。

サンプルコードはコピー&ペースト可です。 しかし、いくつか注意点があります。

コピー&ペーストしてコーディングする場合は、↑の項目を各自で改良して使ってください。 それと、次の項目に書いた課題も参照。