2023.01.24
数学グラフ
xy-座標を描画するクラスの作成
Graphicsオブジェクトにxy-座標とグリッドを描画するためのクラスを作成しました。
このクラスを使うと、数学座標(xy-座標)からグラフィック座標への座標変換を意識することなく数学グラフが描画できます。下図は、xy-座標の描画例です。
用意したメソッドは以下のとおりです。
Axis2D.initメソッド
public boolean init( int fw, int fh, int ox, int oy, int gx, int gy, double sx, double sy )
・描画するxy-座標の情報を設定します。 パラメータ fw : フレームの横のピクセル数 fh : フレームの縦のピクセル数 ox : グラフィック座標の原点xの位置(pixel) oy : グラフィック座標の原点yの位置(pixel) gx : グラフィック座標のグリッドの幅(pixel) gy : グラフィック座標のグリッドの高さ(pixel) sx : 数学座標のグリッドの幅(gxあたりの幅) 例)sx=1.0を指定した場合、数学座標でのグリッド幅は1.0になり、右方向が+(プラス)となります。 例)sx=-0.5を指定した場合、数学座標でのグリッド高は-0.5になり、右方向が-(マイナス)となります。 sy : 数学座標のグリッドの高さ(gyあたりの高さ) 例)sy=-1.0を指定した場合、数学座標でのグリッド幅は-1.0になり、上方向が+(プラス)となります。 例)sy=1.0を指定した場合、数学座標でのグリッド高は1.0になり、上方向が-(マイナス)となります。 グラフィック座標のY軸のプラス方向は下で、数学座標のY軸のプラス方向は上です。 このメソッドでは、syにマイナスを代入することで数学座標の上方向をプラスにしています。 戻り値 true : 設定に成功 false : 設定に失敗
Axis2D.draw_gridメソッド
public void draw_grid( Graphics g, Color axiscolor, Color gridcolor )
・座標軸とグリッドを描画します。 パラメータ g : 描画するGraphicsオブジェクト axiscolor : 座標軸の色 gridcolor : グリッド(格子)の色 戻り値 なし 詳細 initメソッドで設定後に、このメソッドを呼ぶとGraphicsオブジェクトに座標とグリッドを描画します。座標軸とグリッドの線幅は1です。
Axis2D.draw_fillcircleメソッド
public void draw_fillcircle( Graphics g, double x, double y, int radius, Color color )
・塗りつぶし円を描画します。 パラメータ g : 描画するGraphicsオブジェクト x : 数学座標の円の中心座標x y : 数学座標の円の中心座標y radius : グラフィック座標の円の半径 color : 色 戻り値 なし 詳細 initメソッドで設定後に、このメソッドを呼んでください。
Axis2D.draw_lineメソッド
public void draw_line( Graphics g, double x1, double y1, double x2, double y2, Color color )
・線分を描画します。 パラメータ g : 描画するGraphicsオブジェクト x1 : 数学座標の座標x1 y1 : 数学座標の座標y1 x2 : 数学座標の座標x2 y2 : 数学座標の座標y2 color : 色 戻り値 なし 詳細 initメソッドで設定後に、このメソッドを呼んでください。描画する線分の線幅は1です。
Javaのソースコード
このソースコードは、座標変換を行うための「Transformation2d.java」を使用しています。
Graphicsオブジェクトにxy-座標を描画するソース
Axis2D.java
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
import java.awt.*; public class Axis2D { private Transformation2d trans = new Transformation2d(); // 座標変換クラス private int frame_w, frame_h; // フレームサイズ private int grid_x, grid_y; // グラフィック座標のグリッドサイズ private int origin_x, origin_y; // グラフィック座標の原点の位置 private double scale_x, scale_y; // 数学座標のグリッドのサイズ // 初期化 // fw : フレームの幅(pixel) // fh : フレームの高さ(pixel) // ox : グラフィック座標の原点xの位置(pixel) // oy : グラフィック座標の原点yの位置(pixel) // gx : グラフィック座標のグリッドの幅(pixel) // gy : グラフィック座標のグリッドの高さ(pixel) // sx : 数学座標のグリッドの幅 // sy : 数学座標のグリッドの高さ public boolean init( int fw, int fh, int ox, int oy, int gx, int gy, double sx, double sy ) { // グラフィック座標のグリッドの大きさをチェック if ( 1 > gx ) return false; if ( 1 > gy ) return false; // 数学座標→グラフィック座標へ変換するオブジェクトtransを作成 // ( 0.0, 0.0 ) → ( ox, oy )、( sx, sy ) → ( ox + gx, oy + gy )となるようにパラメーターを指定 if ( !trans.set( 0.0, 0.0, sx, sy, (double)ox, (double)oy, (double)( ox + gx ), (double)( oy + gy ) ) ) return false; // フレームサイズをメンバ変数に代入 frame_w = fw; frame_h = fh; // グラフィックの原点座標をメンバ変数に代入 origin_x = ox; origin_y = oy; // グラフィック座標のグリッドサイズをメンバ変数に代入 grid_x = gx; grid_y = gy; // 数学座標のグリッドサイズをメンバ変数に代入 scale_x = sx; scale_y = sy; return true; } // グリッドとxy座標軸を描画 // g : Graphics オブジェクト // axiscolor : 描画するxy座標軸の色 // gridcolor : 描画するグリッドの色 public void draw_grid( Graphics g, Color axiscolor, Color gridcolor ) { // 方眼線の色を設定 g.setColor( gridcolor ); // y軸より上のグリッド線(水平線)を描画 for ( int y = origin_y - grid_y; y >= 0; y -= grid_y ) g.drawLine( 0, y, frame_w - 1, y ); // y軸より下のグリッド線(水平線)を描画 for ( int y = origin_y + grid_y; y < frame_h; y += grid_y ) g.drawLine( 0, y, frame_w - 1, y ); // x軸より左のグリッド線(垂直線)を描画 for ( int x = origin_x - grid_x; x >= 0; x -= grid_x ) g.drawLine( x, 0, x, frame_h - 1 ); // x軸より右のグリッド線(垂直線)を描画 for ( int x = origin_x + grid_x; x < frame_w; x += grid_x ) g.drawLine( x, 0, x, frame_h - 1 ); // 座標軸の描画 // 座標軸の色を設定 g.setColor( axiscolor ); // x軸の描画 g.drawLine( 0, origin_y, frame_w - 1, origin_y ); // y軸の描画 g.drawLine( origin_x, 0, origin_x, frame_h - 1 ); } // 塗りつぶし円の描画 // g : Graphics オブジェクト // x : 数学座標の円の中心座標x // y : 数学座標の円の中心座標y // radius : グラフィック座標の円の半径 // color : 色 public void draw_fillcircle( Graphics g, double x, double y, int radius, Color col ) { // グラフィック座標格納変数 int vx, vy; // 色の設定 g.setColor( col ); // 数学座標からグラフィック座標へ変換 vx = (int)( trans.getX( x ) - (double)radius ); vy = (int)( trans.getY( y ) - (double)radius ); // 塗りつぶし円の描画 g.fillOval( vx, vy, radius * 2 + 1, radius * 2 + 1 ); } // 線分の描画 線幅は1 // g : Graphics オブジェクト // x1 : 数学座標の座標x1 // y1 : 数学座標の座標y1 // x2 : 数学座標の座標x2 // y2 : 数学座標の座標y2 // color : 色 public void draw_line( Graphics g, double x1, double y1, double x2, double y2, Color col ) { // グラフィック座標格納変数 int vx1, vy1; int vx2, vy2; // 色の設定 g.setColor( col ); // 数学座標からグラフィック座標へ変換 vx1 = (int)trans.getX( x1 ); vy1 = (int)trans.getY( y1 ); vx2 = (int)trans.getX( x2 ); vy2 = (int)trans.getY( y2 ); // 線分の描画 g.drawLine( vx1, vy1, vx2, vy2 ); } }
座標変換を行うソース
Transformation2d.java
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045
public class Transformation2d { // 変換パラメータ a,b,c,d private double a = 0.0; private double b = 0.0; private double c = 0.0; private double d = 0.0; // パラメータを計算 boolean set( double x1, double y1, double x2, double y2, double px1, double py1, double px2, double py2 ) { // ゼロとみなす値 double e = 0.0000000001; // 初期値を代入 a = b = c = d = 0.0; // x1とx2が同じ値であればエラー if ( e > Math.abs( x1 - x2 ) ) return false; // y1とy2が同じ値であればエラー if ( e > Math.abs( y1 - y2 ) ) return false; // パラメータの計算 a = ( px1 - px2 ) / ( x1 - x2 ); b = ( px1 * x2 - px2 * x1 ) / ( x2 - x1 ); c = ( py1 - py2 ) / ( y1 - y2 ); d = ( py1 * y2 - py2 * y1 ) / ( y2 - y1 ); return true; } // 変換後のx座標を取得 public double getX( double x ) { return a * x + b; } // 変換後のy座標を取得 public double getY( double y ) { return c * y + d; } }
Javaソースコードの解説
001
import java.awt.*;
003
public class Axis2D {
004
private Transformation2d trans = new Transformation2d(); // 座標変換クラス
数学座標からグラフィック座標に変換するTransformation2dクラスをインスタンス化しています。
005
private int frame_w, frame_h; // フレームサイズ
006
private int grid_x, grid_y; // グラフィック座標のグリッドサイズ
007
private int origin_x, origin_y; // グラフィック座標の原点の位置
008
private double scale_x, scale_y; // 数学座標のグリッドのサイズ
010 011 012 013 014 015 016 017 018 019 020
// 初期化 // fw : フレームの幅(pixel) // fh : フレームの高さ(pixel) // ox : グラフィック座標の原点xの位置(pixel) // oy : グラフィック座標の原点yの位置(pixel) // gx : グラフィック座標のグリッドの幅(pixel) // gy : グラフィック座標のグリッドの高さ(pixel) // sx : 数学座標のグリッドの幅 // sy : 数学座標のグリッドの高さ public boolean init( int fw, int fh, int ox, int oy, int gx, int gy, double sx, double sy ) {
初期化するメソッドです。
021 022 023
// グラフィック座標のグリッドの大きさをチェック
if ( 1 > gx ) return false;
if ( 1 > gy ) return false;
025 026 027
// 数学座標→グラフィック座標へ変換するオブジェクトtransを作成 // ( 0.0, 0.0 ) → ( ox, oy )、( sx, sy ) → ( ox + gx, oy + gy )となるようにパラメーターを指定 if ( !trans.set( 0.0, 0.0, sx, sy, (double)ox, (double)oy, (double)( ox + gx ), (double)( oy + gy ) ) ) return false;
座標変換するオブジェクトtransに、数学座標( 0.0, 0.0 )をグラフィック座標( ox, oy )に、数学座標( sx, sy )をグラフィック座標( ox + gx, oy + gy )に変換する引数を与えています。2次元座標系の場合は、変換前と変換後の座標の組み合わせが2つあれば、座標系全体の座標変換が行えます。
ここでは、グラフィック座標の原点座標( ox, oy )と数学座標の原点座標( 0.0, 0.0 )と、グラフィック座標の1グリッド先の座標( ox + gx, oy + gy )と数学座標のの1グリッド先の座標( 0.0 + sx, 0.0 + sy )の2つの組み合わせを使用しています。
029 030 031
// フレームサイズをメンバ変数に代入
frame_w = fw;
frame_h = fh;
033 034 035
// グラフィックの原点座標をメンバ変数に代入
origin_x = ox;
origin_y = oy;
037 038 039
// グラフィック座標のグリッドサイズをメンバ変数に代入
grid_x = gx;
grid_y = gy;
041 042 043
// 数学座標のグリッドサイズをメンバ変数に代入
scale_x = sx;
scale_y = sy;
049 050 051 052 053 054
// グリッドとxy座標軸を描画 // g : Graphics オブジェクト // axiscolor : 描画するxy座標軸の色 // gridcolor : 描画するグリッドの色 public void draw_grid( Graphics g, Color axiscolor, Color gridcolor ) {
055 056
// 方眼線の色を設定
g.setColor( gridcolor );
Graphics.setColorメソッド
public abstract void setColor( Color c )
・このグラフィックスコンテキストの現在の色を、指定された色に設定します。 パラメータ c : 色 戻り値 なし
058 059 060
// y軸より上のグリッド線(水平線)を描画 for ( int y = origin_y - grid_y; y >= 0; y -= grid_y ) g.drawLine( 0, y, frame_w - 1, y );
y軸より上のグリッド線を描画しています。
グラフィック座標の原点座標origin_yからグリッドの高さgrid_yを引いた値origin_y - grid_yから間隔grid_yで上方向に水平のラインを描画していき、フレームの外に出れば描画を終了します。これをfor文の繰り返し処理で行っています。
Graphics.drawLineメソッド
public abstract void drawLine( int x1, int y1, int x2, int y2 )
・このグラフィックスコンテキストの座標系の点 (x1, y1) と点 (x2, y2) との間に現在の色を使って線を描きます。 パラメータ x1 : グラフィックスコンテキストのx座標1 y1 : グラフィックスコンテキストのy座標1 x2 : グラフィックスコンテキストのx座標2 y2 : グラフィックスコンテキストのy座標2 戻り値 なし
062 063 064
// y軸より下のグリッド線(水平線)を描画 for ( int y = origin_y + grid_y; y < frame_h; y += grid_y ) g.drawLine( 0, y, frame_w - 1, y );
y軸より下のグリッド線を描画しています。
066 067 068
// x軸より左のグリッド線(垂直線)を描画 for ( int x = origin_x - grid_x; x >= 0; x -= grid_x ) g.drawLine( x, 0, x, frame_h - 1 );
x軸より左のグリッド線を描画しています。
070 071 072
// x軸より右のグリッド線(垂直線)を描画 for ( int x = origin_x + grid_x; x < frame_w; x += grid_x ) g.drawLine( x, 0, x, frame_h - 1 );
x軸より右グリッド線を描画しています。
074 075 076
// 座標軸の描画 // 座標軸の色を設定 g.setColor( axiscolor );
078 079
// x軸の描画
g.drawLine( 0, origin_y, frame_w - 1, origin_y );
081 082
// y軸の描画
g.drawLine( origin_x, 0, origin_x, frame_h - 1 );
086 087 088 089 090 091 092 093
// 塗りつぶし円の描画 // g : Graphics オブジェクト // x : 数学座標の円の中心座標x // y : 数学座標の円の中心座標y // radius : グラフィック座標の円の半径 // color : 色 public void draw_fillcircle( Graphics g, double x, double y, int radius, Color col ) {
094 095
// グラフィック座標格納変数 int vx, vy;
097 098
// 色の設定
g.setColor( col );
100 101 102
// 数学座標からグラフィック座標へ変換 vx = (int)( trans.getX( x ) - (double)radius ); vy = (int)( trans.getY( y ) - (double)radius );
メソッドの引数で渡された数学座標の円の中心座標(x,y)をtrans.getXメソッド、trans.getYメソッドで変換した値をから円の半径radiusを引いた値をvx、vyに代入しています。
変換した座標から半径radiusを引く理由は、塗りつぶし円を描画するdrawOvalメソッドに渡す座標が、描画する円の左上隅の座標であるためです。
円の中心座標を変換した座標をvxとvyに代入して半径radiusを引いた値をdrawOvalメソッドに渡してもほぼ同じ結果が得られます。
Graphics.drawOvalメソッド
public abstract void drawOval( int x, int y, int width, int height )
・楕円の輪郭線を描きます。 パラメータ x : 描画する楕円の左上隅のx座標 y : 描画する楕円の左上隅のy座標 width : 描画する楕円の幅 height : 描画する楕円の高さ 戻り値 なし
104 105
// 塗りつぶし円の描画
g.fillOval( vx, vy, radius * 2 + 1, radius * 2 + 1 );
drawOvalメソッドに左隅の座標( vx, vy )、幅と高さに( radius * 2 + 1 )を渡して塗りつぶし円を描画しています。
この幅と高さの計算では厳密に半径radiusの円にはなりませんが、ここでは円の中心が真ん中になるように幅と高さを奇数にしています。
109 110 111 112 113 114 115 116 117
// 線分の描画 線幅は1 // g : Graphics オブジェクト // x1 : 数学座標の座標x1 // y1 : 数学座標の座標y1 // x2 : 数学座標の座標x2 // y2 : 数学座標の座標y2 // color : 色 public void draw_line( Graphics g, double x1, double y1, double x2, double y2, Color col ) {
118 119 120
// グラフィック座標格納変数 int vx1, vy1; int vx2, vy2;
122 123
// 色の設定
g.setColor( col );
125 126 127 128 129
// 数学座標からグラフィック座標へ変換 vx1 = (int)trans.getX( x1 ); vy1 = (int)trans.getY( y1 ); vx2 = (int)trans.getX( x2 ); vy2 = (int)trans.getY( y2 );
メソッドの引数で渡された数学座標の線分の2つ座標( x1, y1 )、( x2, y2 )をtrans.getXメソッド、trans.getYメソッドで変換した値を( vx1, vy1 )、( vx2, vy2 )に格納しています。
131 132
// 線分の描画
g.drawLine( vx1, vy1, vx2, vy2 );
drawLineメソッドに2つの座標( vx1, vy1 )、( vx2, vy2 )を渡して線分を描画しています。
以上です。