今週はまず次のプログラムをJ2SE 5.0で動作させてみてください。
サンプルのソース:TinyCircleSample.java
このサンプルは3種類の方法で直径が1から20までの円を描画しています。描画の部分を次に示します。
public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D)g; g2d.drawString("Graphics#drawOval", 10, 15); g2d.drawString("Graphics2D#draw(Ellipse.FLoat)", 10, 60); g2d.drawString("Graphics2D#draw(Ellipse.Double)", 10, 105); int x = 10; for (int i = 1; i < 20; i++) { x += (i * 1.5); // AWT で描画 g.drawOval(x, 20, i, i); // Java2D で描画(単精度) Ellipse2D ellipse = new Ellipse2D.Float(x, 65, i, i); g2d.draw(ellipse); // Java2D で描画(倍精度) ellipse = new Ellipse2D.Double(x, 110, i, i); g2d.draw(ellipse); } }
はじめにAWTで描画し,次にJava2Dで単精度,最後にJava2Dで倍精度で描画しています。
図1にLinux(Fedora Core 5)での実行結果を示します。
![]() |
図1 サンプルの実行結果(J2SE 5.0) |
---|
なんとなく変な感じがしますね。わかりやすいように図2に拡大図を示しました。
![]() |
図2 実行結果の拡大図(J2SE 5.0) |
---|
一番上のAWTで描画しているものはちゃんと円になっていますが,Java2Dを使用したものはとうてい円とはいえないようなものまで含まれています。
Java2Dではなぜこんないびつな円になってしまうのでしょう。
Java2Dでは描画に実数を使用できます。円を表すEllipse2Dクラスでも,Ellipse2D.DoubleクラスとEllipse2D.Floatという精度の異なる二つの内部クラスが定義されています。
実数が使用できるのはいいのですが,問題は最終的に整数にしなくてはならないということです。floatやdoubleからintに単純に変換すると,小数点以下は切り捨てられてしまいます。これが,円がいびつになる原因です。
さて,このサンプルをJava SE 6で実行してみましょう(図3)。
![]() |
図3 実行結果の拡大図(Java SE 6) |
---|
ちゃんと円になりました。今までこれができなかったことのほうが不思議です。
小さい形状が正確に描画されるだけでなく,Java2Dの内部表現としてもPath2D.Doubleクラスを導入し,倍精度で扱うことができるようになりました。
ところで,サンプルの実行にLinuxを使用したのには理由があります。Windowsではまだ円がいびつなままなのです。
Windowsでは,Java2Dの描画にDirectXの一部であるDirect3Dをデフォルトで使用します。これがどうやらいまいちのようなのです。
次に示すように,Direct3Dを使用せずにOpenGLを使用すると,ちゃんと丸が丸として描画されます(図4,図5)。
これからは,Javaで描画するときはWindowsでもLinuxでもOpenGLを使用するのが常道になるのかもしれません。
>java -Dsun.java2d.opengl=true TinyCircleSample
![]() |
![]() |
図4 Direct3Dでの実行結果 | 図5 OpenGLでの実行結果 |
---|
著者紹介 櫻庭祐一 横河電機 ネットワーク開発センタ所属。Java in the Box 主筆 今月の櫻庭 サン・マイクロシステムズとリクルートがタイアップして行っているMash up Award 2ndが開催されています。 昨年行われたMash up AwardではリクルートのWeb APIだけが対象でした。ところが,今回はサンとリクルート以外に,Skypeやシックスアパート,テクノラティなど協賛企業が17社もあります。使用できるWeb APIもバラエティに富んでいます。ということは,Mash upする材料がいろいろあるということ。アイデアしだいで,クールなアプリケーションが思いのままです。 締め切りは3月12日。何かおもしろいことをやってみたい方,ぜひトライしてみてくださいね。 |