Graphics2Dで描画する
では、さっそくGraphics2Dを使った簡単なサンプルを作成しましょう。Graphics2Dでは「Shape」と呼ばれる図形の形状インスタンスを用意し、これを使って描画を行います。まずは、四角形と円形のShapeを使って描画を行うサンプルを挙げます。
public void paint(Graphics2D g){ // 四角形を使った描画 Rectangle2D.Double rect = new Rectangle2D.Double(0d,0d,16d,16d); for(int i = 0;i < 16;i++){ for(int j = 0;j < 16;j++){ Color c = new Color(i * 16,0,255 - j * 16); g.setColor(c); g.fill(rect); rect.x += 16; } rect.y += 16; rect.x = 0; } // 円形を使った描画 Ellipse2D.Double elps = new Ellipse2D.Double(0d,0d,255d,255d); g.setStroke(new BasicStroke(3f)); for(int i = 0;i < 16;i++){ Color c2 = new Color(i * 16,255 - i * 16,0); g.setColor(c2); g.draw(elps); elps.width -= 16; elps.height -= 16; elps.x += 8; elps.y += 8; } }

java.awt.Shapeは、図形の形状を表すインターフェイスです。これを実装したさまざまな形状クラスがjava.awt.geomパッケージに用意されています。ここでは、Rectangle2D.DoubleとEllipse2D.Doubleの2つのクラスを利用しています。形状クラスは、通常、抽象クラスとして用意され、その実装としてfloat精度およびdouble精度で図形を表す2つの入れ子クラスが用意されているのが一般的です。
例えば、四角形の図形を表す抽象クラスはRectangle2Dであり、その実装としてRectangle2D.FloatとRectangle2D.Doubleが用意されています。実際の描画には、これらのクラスのインスタンスを作成して利用します。ここでは、以下の2行でインスタンスを作成しています。
Rectangle2D.Double rect = new Rectangle2D.Double(0d,0d,16d,16d); Ellipse2D.Double elps = new Ellipse2D.Double(0d,0d,255d,255d);
いずれも図形のx、y位置と大きさ(横幅と高さ)の値を引数に指定しています。ここではDoubleクラスを使っていますが、Floatクラスでも基本的な扱いは同じです。このRectangle2D/Ellipse2Dの他にも、定型図形を現すShapeとして次のようなものが用意されています。いずれも抽象クラスで、実際の利用はそれぞれのDouble/Floatクラスを使います。
| クラス名 | 説明 |
| Arc2D | 円弧を表すクラスです。位置と大きさの他、描く円弧の角度、閉じ方の種類などの設定を行うことができます。 |
| Line2D | 直線を表すクラスです。開始点と終了点の2点の位置を設定できます。 |
| Point2D | 点を表すクラスです。描画する位置を設定できます。 |
| RoundRectangle2D | 角に丸みのある四角形を描画するクラスです。位置と大きさの他、角の丸みの大きさに関する設定を行うことができます。 |
| QuadCurve2D | 開始点と終了点および1つのコントロールポイントからなる2次元パラメトリック曲線のセグメントを表すクラスです。曲線を構成する3つの点を設定できます。 |
| CubicCurve2D | 開始点と終了点および2つのコントロールポイントからなる3次元パラメトリック曲線のセグメントを表すクラスです。曲線を構成する4つの点を設定できます。 |
クラスによっては、入れ子クラスであるDouble/Floatインスタンスの作成に必要な引数が異なってきますので、利用する際には確認をしておくとよいでしょう。とりあえずここではサンプルとしてEllipse2DとRectangle2Dを使って描画を行います。
Shapeを描画する
こうして図形のShapeを用意したら、後はsetColorで色を設定し、描画をします。描画は、輪郭線のみを描く「draw」と、塗りつぶした図形を描く「fill」の2つがあります。
g.fill(rect); g.draw(elps);
このように、引数に描画するShapeを指定すれば、そのShapeの形状を描画します。Shapeの導入により、Graphicsの描画用メソッドは非常にシンプルになりました。
まぁ、これだけなら「描画用メソッドがShapeというクラスを使う形になっただけ」としか感じないでしょう。Shapeを使う利点は、「一度作ったShapeは、使い回しができる」という点です。
Shapeには、その位置や大きさを示す「x」「y」「width」「height」といったpublicフィールドが用意されています。これらの値を書き換えることで、Shapeの位置や大きさを自由に変更することができます。これを利用し、1つのShapeで複雑な図形を描くことも可能になります。
ここでは、Rectangle2D.Doubleの位置を少しずつ移動することで四角形をきれいに並べて描画しています。またEllipse2D.Doubleの位置と大きさを変更することで次第に縮小するように円を描画しています。
この他、次のような見慣れない処理も書かれています。
g.setStroke(new BasicStroke(3f));
このsetStrokeは、「Stroke」と呼ばれる輪郭線の描画に関する情報を持つクラスをGraphics2Dに設定するものです。これについては後に改めて説明します。
座標空間と変換
これでShapeを利用したGraphics2Dによる描画の基本は分かりました。Shapeを利用すれば、あらかじめ用意しておいた図形を再利用した描画が楽に行なえます。が、正直、1つ1つのShapeの位置と大きさを設定しながら描画をするのであれば、やり方こそ違えどあまり旧来の方式と変わらない感じもします。
こうした不満を解消するには、「それまでのGraphicsでは面倒だったことがGraphics2Dでは簡単にできる」というような機能を紹介しないといけませんね。その代表的なものをあげておきましょう。それは「座標変換」です。
Graphics2Dでは、図形の描画はあらかじめ設定されている座標軸を使って位置や大きさを設定し行います。Graphics2Dでは、この座標軸に「2次元アフィン変換」と呼ばれる座標変換を適用し、座標軸そのものを変更し描画を行うことができます。
アフィン変換とは、物体の幾何学的な性質を保持したまま、平行移動・回転・拡大縮小を行うためのものです。座標の変換に関する行列を用意し、これを使って座標軸を変換することで各種の物体の位置や大きさなどを変えてみせることができます。要するに、「あらかじめ変換のためのデータを用意してやれば、描画する図形そのものを一切変更しなくてもさまざまな位置や大きさで描画を行なえるようにできる」ということです。
これも実際にサンプルを見てみれば働きがよく分かるでしょう。先ほどのサーブレットのpaintメソッドを修正して、アフィン変換による描画を行ってみましょう。
public void paint(Graphics2D g){ g.setColor(new Color(0,0,100)); g.fillRect(0, 0, 255, 255); Ellipse2D.Double elps = new Ellipse2D.Double(0d,0d,100d,100d); g.setStroke(new BasicStroke(3f)); AffineTransform defaultAT = g.getTransform(); g.setTransform(AffineTransform.getTranslateInstance(127, 127)); for(int i = 0;i < 16;i++){ Color c = new Color(i * 16,255 - i * 16,0); g.setColor(c); g.draw(elps); g.rotate(Math.PI / 8); } g.setTransform(defaultAT); }

これを実行すると、円がぐるりと回転して描画されます。これをGraphicsでやらせようとすると、X軸とY軸の位置情報を三角関数で計算して……ということになります。が、アフィン変換を使えば、そんな面倒な処理など不要です。
