講義プリント

CG プログラミング論 平成 26 年 5 月 12 日
第4章.グラフの描画
【学習のねらい】
① 先週までに、規則的な図形を描く方法を学習しました。ある規則性に従って所定の操
作を繰り返せば、様々な CG を描くことができる事を理解できたと思います。今週は
それに引き続いて、y=f(x)のグラフを描く方法を学習します。これも、関数という規則
に従って図形を描くことに他なりません。その際、ポイントになるのは、コンピュー
タ上の座標の取り方です。その理解に重点を置いて学習して下さい。
4-1
コンピュータの座標の取り方
「プログラミング」テキストの 8-1 節に示した通り、CG を描く際には、コンピュータ画
面の左上隅を原点とします。そして、右に進む毎にx座標が増加し、下に進む毎にy座標
が増加します。したがって、下のように、CG の世界での y 座標は、通常の数学で用いる座
標と向きが逆である事に、改めて注意しておいて下さい。
CG の世界では、左上を原点
(0,0)とし、y 座標が下向き
に伸びていることに注意し
て下さい。
4-2
折れ線グラフの描画
【基礎課題4-1】
右の様な折れ線グラフを描画す
るプログラムを考えましょう。
このグラフの詳細を(数学で用
いる)座標上で表すと次ページ上
方の図の様になります。まずこれ
を確認して下さい。
31
CG プログラミング論 平成 26 年 5 月 12 日
y軸
<一般的な(数学で用いる)座標>
150
100
50
(0,0)
100
150
175
x軸
このグラフを、左上隅が原点となっているコンピュータ画面上の座標で表すと次の様にな
ります。
<コンピュータ上の座標>
(0,0)
x軸
50
y軸
線分3
y0
50
線分2
50
x0
グ
線分1
(x0,y0)
100
50
25
注意
英字のエル
この図にしたがって、
(折れ線グラフを描く)プログラムを記述すると次の様になります。
void DrawGraphics(Graphics g) {
上方向に 50 移動するので
int x0,y0,lx,ly;
lx=200; //x 軸の長さ
負号(マイナス)になるこ
ly=180; //y 軸の長さ
とに注意。
x0=10; //グラフの原点のx座標
y0=200; //グラフの原点のy座標
g.setColor(Color.black); //軸の描画色を黒色に指定
g.drawLine(x0,y0,x0+lx,y0); //x 軸の描画
g.drawLine(x0,y0,x0,y0-ly); //y 軸の描画
g.setColor(Color.blue); //グラフの描画色を青色に指定
g.drawLine(x0,y0,x0+100, y0-50 ) ; //線分1の描画
①
g.drawLine(x0+100,y0-50,x0+150, y0-100
); //線分2の描画
g.drawLine(x0+150,y0-100,x0+175, y0-150
②
); //線分3の描画
}
32
CG プログラミング論 平成 26 年 5 月 12 日
前ページの中央の図とプログラムを見比べながら、空欄①~②に入る適切な式を記述し
て下さい。
【基礎課題4-2】
この折れ線グラフを描く際には、原点から始まって3つの点を順次直線で結んで行って
います。この点に注目して、
【基礎課題4-1】のプログラムを次のように書き換えました。
ここに、下線部と枠線部が変更部分です。
void DrawGraphics(Graphics g) {
int x0,y0,lx,ly,x1,y1,x2,y2;
lx=200; //x 軸の長さ
・・・
g.setColor(Color.blue); //グラフの描画色を青色に指定
//線分1の描画
x1=0; //始点のx座標の設定
y1=0; //始点の y 座標の設定
x2=x1+100; //終点のx座標の設定
y2=y1+50; //終点のy座標の設定
g.drawLine(x0+x1,y0-y1,x0+x2,y0-y2);
//線分2の描画
x1=x2; //始点のx座標の設定
y1=y2; //始点のx座標の設定
x2=x1+50; //終点のx座標の設定
y2=y1+50; //終点のy座標の設定
g.drawLine(x0+x1,y0-y1,x0+x2,y0-y2);
//線分3の描画
x1=x2; //始点のx座標の設定
y1=y2; //始点のx座標の設定
x2=x1+25; //終点のx座標の設定
y2=y1+50; //終点のy座標の設定
g.drawLine(x0+x1,y0-y1,x0+x2,y0-y2);
}
(x2,y2)
このプログラムは、線分1から線分3までの各線分を描く部
分を、始点(x1,y1)および終点(x2,y2)の座標変数で表しただけ
で、それ以外は【基礎課題 4-1】のプログラムと何も変わって
(x1,y1)
いません。
ただ、このように記述することで、
”一つ前の点と次の点を順に結んで行く”と言う処理
(上の波線部)がいずれも全く同じ処理として記述できる事がはっきりしました。ですから、
これら3つの処理は繰り返し処理として実現できそうです。その考えに基づいて上のプログ
ラムをさらに書き換えたのが次のプログラムです。下線部と枠線部が変更部分です。
33
CG プログラミング論 平成 26 年 5 月 12 日
void DrawGraphics(Graphics g) {
int x0,y0,lx,ly,x1,y1,x2,y2;
lx=200; //x 軸の長さ
・・・
g.setColor(Color.blue); //グラフの描画色を青色に指定
//グラフの描画
int wx=100; //x 軸方向の移動幅の設定
x1=0; //最初の始点のx座標の設定
y1=0; //最初の始点のy座標の設定
for(int i=1;i<=3;i++) {
x2=x1+wx; //終点のx座標の設定
y2= y1+50
; //終点のy座標の設定
①
g.drawLine(x0+x1,y0-y1,x0+x2,y0-y2);
x1=x2; //次の始点のx座標の設定
y1=y2; //次の始点のy座標の設定
wx=wx/2; //次の x 軸方向の移動幅の設定
}
}
ここに、線分1から線分3に進むにつれて、x軸方向の移動幅 wx が(一つ前の)半分にな
っている事に注目して波線部のように表しています。空欄①に適切な式を記入して下さい。
4-3
放物線グラフの描画
【基礎課題 4-3】
【基礎課題4-2】のプログラムを修正して、今度は、放物線のグラフ y=x2 (0≦x≦10)
を描いてみましょう。プログラムは次の通りです(下線部が変更部分)。
void DrawGraphics(Graphics g) {
int x0,y0,lx,ly,x1,y1,x2,y2;
lx=200; //x 軸の長さ
y軸の長さを延長
ly=200; //y 軸の長さ
x0=10; //グラフの原点のx座標
y0=210; //グラフの原点のy座標
・・・
g.setColor(Color.blue); //グラフの描画色を青色に指定
//グラフの描画
int wx=2; //x 軸方向の刻み幅の設定
x1=0; //最初の始点のx座標の設定
y1=0; //最初の始点のy座標の設定
for(int i=1;i<=5;i++) {
x2=i*wx; //終点のx座標の設定
y2=x2*x2; //終点のy座標の設定
g.drawLine(x0+x1,y0-y1,x0+x2,y0-y2);
x1=x2; //次の始点のx座標の設定
これは削除
y1=y2; //次の始点のy座標の設定
wx=wx/2; //次のx軸方向移動幅の設定
}
34
CG プログラミング論 平成 26 年 5 月 12 日
プログラムより、x軸方向の刻み幅 wx を2としているので、xが(0,2,4,6,8,10)の6点
における関数(今の場合 x2)の値を順に結んでグラフを描いていることが分かるはずです。
このプログラムを作成したら実行してみて下さい。次の様な出力になるはずです。
少し見にくいグラフになってしまいました。これは、
(プログラムとしては間違っていな
いのですが)今の場合、x 軸、y軸の長さを 200 としているのに対し、(x,y)の値が(0,0)
から(10,100)の範囲に収まっているので、小さすぎて良く関数の形が見えないためです。
そこで、グラフの座標値をx軸方向に 20 倍、y 軸方向に 2 倍拡大してみましょう。プロ
グラムの変更は次の下線部分です。
・・・
for(int i=1;i<=5;i++) {
x2=i*wx;
y2=x2*x2;
g.drawLine(x0+20*x1,y0-2*y1,x0+20*x2,y0-2*y2);
x1=x2;
y1=y2;
}
・・・
例えば、x 軸方向に 20 倍するとは、基準値である原点x0 らの距離を 20 倍にする事ですか
ら、上のようにすれば、グラフが拡大表示されることは理解できるでしょう。
このプログラムを実行すると次ページの様になります。図のように拡大表示される事を
確認して下さい。
35
CG プログラミング論 平成 26 年 5 月 12 日
これで関数の形がよく確認できるようになりましたが、今の場合x軸方向の刻み幅を2
としているので、少しギザギザしています。そこで、x軸方向の刻み幅を(今の)半分の
1にして、同じく(0≦x≦10)の範囲でグラフを描くようにしたものが下のグラフです(下線
部が変更部分)
。空欄①を埋めてプログラムを完成させて下さい。
・・・
//グラフの描画
int wx=1;
x1=0;
y1=0;
for(int i=1; i<=10
;i++) {
①
x2=i*wx;
y2=x2*x2;
g.drawLine(x0+20*x1,y0-2*y1,x0+20*x2,y0-2*y2);
x1=x2;
y1=y2;
}
・・・
このプログラムを実行すると次ページの様に出力され、グラフは滑らかになります。こ
のように、一般に CG で y=f(x)のグラフを描く際には、
1.グラフが滑らかになるように x 軸方向の刻み幅を調節する。
2.画面内に見やすく収まる様に、x軸方向、y軸方向の縮尺を調節する。
という操作が必要になります。
36
CG プログラミング論 平成 26 年 5 月 12 日
【基礎課題 4-4】
上の要領に従えば、基本的にどのような関数でもグラフとして描画することができます。
しかし、実はもう 1 点だけ改良を要する点があります。それを考えるために、y=x2 のグラ
フを、今度は 0≦x≦1 の範囲において 0.1 刻みで描く場合を考えてみましょう。この場合、
xもyも実数になります。一方、コンピュータ上の座標には整数しかありません。そこで、
実数として求めた関数の座標値を整数に変換する必要が生じます。
このプログラムは、次のようになります。下線部が【基礎課題 4-3】からの変更部分です。
void DrawGraphics(Graphics g) {
int x0,y0,lx,ly;
double x1,y1,x2,y2; //一般的には座標値は実数型で表す
lx=200; //x 軸の長さ
・・・
//グラフの描画
double wx=0.1; //x軸方向の刻み幅も一般には実数型変数で表す。
x1=0;
(x1,y1),(x2,y2)共に実数である事
y1=0;
for(int i=1; i<=10
;i++)
{
①
に注意!
x2=i*wx;
y2=x2*x2;
g.drawLine( x0+(int)(100*x1),y0-(int)(100*y1),
x0+(int)(100*x2),y0-(int)(100*y2) );
x1=x2;
y1=y2;
}
}
37
CG プログラミング論 平成 26 年 5 月 12 日
このプログラムを実行すると次のように表示されます。上の空欄①を埋めてプログラムを
完成させて下さい。
なお、上のプログラムでは、x軸方向およびy軸方向の縮尺をそれぞれ 100 倍としてい
ます。
補足
上のプログラムの枠線部がこのプログラムのポイントです。ここで、Java 言語では実数
から整数に変換する際には型キャストという方法を用いたことを思い出して下さい(「プロ
グラミング」テキスト p.84 参照)
。例えば
double b=1.2;
int a;
a=(int) (2*b);
ここで、実数値を整数に変換して
整数型変数aに代入している。
を実行すると、整数型変数 a の値は、2.4 の小数点以下が切り捨てられて、整数「2」とな
ります。この型キャストを用いれば、元々実数値であった座標の値を整数に変換して、CG
として描画する事ができます。
最後に、x軸方向およびy軸方向の縮尺をそれぞれ、Cx および Cy という変数で表すよ
うに一般化しましょう。そうした方が、プログラムとして拡張しやすいからです。
プログラムは次ページの様になります。下線部が変更部分です。これで、関数のグラフ
を描く一般的なプログラムが完成しました。
38
CG プログラミング論 平成 26 年 5 月 12 日
void DrawGraphics(Graphics g) {
int x0,y0,lx,ly;
double x1,y1,x2,y2;
・・・
//グラフの描画
double wx=0.1;
int Cx=100,Cy=100; //x 軸およびy軸方向の縮尺
x1=0;
y1=0;
for(int i=1; i<=10
;i++) {
x2=i*wx;
y2=x2*x2;
g.drawLine( x0+(int)(Cx*x1),y0-(int)(Cy*y1),
x0+(int)(Cx*x2),y0-(int)(Cy*y2) );
x1=x2;
y1=y2;
}
}
4-4
一般の関数のグラフの描画
【応用課題 4-A】
前節までの方法を用いれば、一般の関数のグラフを描画する事ができます。その例とし
て次のように、y=x3 (-3≦x≦3)のグラフをx軸について 0.1 刻みで描くプログラムを考え
ましょう。
このグラフの場合、x軸とy軸共に正負両方の値を表示できるよう、グラフの原点の位
置を移動させる必要があります。そこで、原点およびグラフのx軸及びy軸を次ページの
ようにとりました。
39
CG プログラミング論 平成 26 年 5 月 12 日
<座標軸のとりかた>
(0,0)
(
コ
ン
ピ
ュ
ー
タ
上
の
)
y
軸
(コンピュータ上の)x軸
(10,10)
x軸
(x0,y0)
ly
y軸
lx
この様に原点(x0,y0)をとると、求めるプログラムは次のようになります。下線部が【基
礎課題 4-4】からの変更部分です。空欄①~③を埋めてプログラムを完成させて下さい。
void DrawGraphics(Graphics g) {
int x0,y0,lx,ly;
double x1,y1,x2,y2;
lx=200; //x 軸の長さ
ly=200; //y 軸の長さ
x0=10+lx/2; //グラフの原点のx座標
y0=10+ly/2; //グラフの原点のy座標
g.setColor(Color.black); //軸の描画色を黒色に指定
g.drawLine(10,y0, 10+lx
①
,y0); //x 軸の描画
g.drawLine(x0,10,x0, 10+ly
); //y 軸の描画
②
g.setColor(Color.blue); //グラフの描画色を青色に指定
//グラフの描画
double wx=0.1;
int Cx=20,Cy=3;
x1= -3
③ ;
y1=x1*x1*x1;
for(int i=1;i<=60;i++) {
x2=i*wx-3;
y2=x2*x2*x2;
g.drawLine( x0+(int)(Cx*x1),y0-(int)(Cy*y1),
x0+(int)(Cx*x2),y0-(int)(Cy*y2) );
x1=x2;
y1=y2;
}
}
40
CG プログラミング論 平成 26 年 5 月 12 日
【応用課題 4-B】
【応用課題 4-A】を利用して今度は三角関数
y=sin(x) ( -3.14≦x≦3.14 )
のグラフを描いてみましょう。プログラムの実行結果は次の通りです。
このプログラムを次のように作成しました。下線部が【応用課題 4-A】からの変更部分で
す。空欄①~②を埋めてプログラムを完成させて下さい。
※ 三角関数の扱い方については「プログラミング」テキスト p.166(2012)でふれていま
す。
void DrawGraphics(Graphics g) {
int x0,y0,lx,ly;
double x1,y1,x2,y2;
lx=200; //x 軸の長さ
・・・
関数を求める点の数を Num
//グラフの描画
としています。
int Cx=30,Cy=60;
int Num=100;
double wx=3.14*2/Num;
x軸方向の描画領域の幅を Num 等分
x1=-3.14;
すれば、刻み幅 wx が求まります。
y1= Math.sin(x1)
;
①
for(int i=1;i<=Num;i++) {
x2=i*wx-3.14;
y2= Math.sin(x2)
;
②
g.drawLine(x0+(int)(Cx*x1),y0-(int)(Cy*y1),
x0+(int)(Cx*x2),y0-(int)(Cy*y2));
x1=x2;
y1=y2;
}
}
41