第2章.格子模様の描画(規則的な図形の描画①)

CG プログラミング論 平成 28 年 4 月 27 日
第2章.格子模様の描画(規則的な図形の描画①)
【学習のねらい】
① CG は基本的にある規則に従って描かれるものです。その意味で、
CG を作成するとは、
その規則性を見い出しアルゴリズムとして表現することに他なりません。そこで、CG
学習のスタートにあたって、今週から 2 週にわたって、簡単な規則性の図形を描くト
レーニングを行う事にします。今週は格子模様を描くアルゴリズムを学習します。
2-1
はじめに
今回描く CG は下の様な格子模様です。図より、赤色に塗りつぶされた四角形が一つお
きに現れる、という規則性があることが分かります。
この時点ですぐにプログラムが思い浮かぶ人もいると思いますが、ここでは、幾つかの段
階を踏んでプログラムを完成させる方法を体験しましょう。具体的には、
1.5 行 5 列のマス目を描く。(2-2 節)
2.ある規則に従って特定のマス目の中を塗りつぶす。
(2-3 節)
という 2 段階に分けてプログラムを作成する事にします。
<作成にあたって>
ここでは、先週の【基礎課題 1-6】が終了した事を前提にしています。まだ終了してい
ない人はまずそちらを先に行って下さい。
まず、
【基礎課題 1-6】で行った要領で【基礎課題 1-6】のプログラム「Kadai1_6」をコ
ピーして、名称を[Kiso2_1]として下さい。
【基礎課題 1-6】で説明した通り、変更する(い
じる)必要のあるのは、NewJFrame.java 内の DrawGraphics(g)メソッドの内容のみで
す。それを開いた状態にして下さい。この要領は今後も同様です。
13
CG プログラミング論 平成 28 年 4 月 27 日
2-2
四角のマス目の描画
描画の規則性については後に考えることにして、とりあえず、下のようにマス目を描画
するプログラムを考えましょう(このプログラムが基本になる事は明らかでしょう)
。
このプログラムを具体的に記述すると、例えば次のようになります。
void DrawGraphics(Graphics g) {
int x,y,w,h;
x=10; //(最初に描画する)マスの左上隅のx座標(右方向の位置)
y=10; //(最初に描画する)マスの左上隅のy座標(下方向の位置)
w=40; //マスの横幅
h=40; //マスの高さ
③
g.setColor(Color.red); //描画色を赤色に指定
for (int i=1; i<=5; i++) { //行(縦)方向の繰り返し ②
for (int j=1; j<=5; j++) { //列(横)方向の繰り返し
g.drawRect(x,y,w,h); //マスの描画
x=x+w; //描画位置を右に w だけずらす
※ ①~③の番号は次の【基
}
x=10; ①
礎課題 2-1】に関係してい
y=y+h; //描画位置を下に h だけずらす
ます。
}
}
プログラムの意味はコメントからおおよそのことが分かると思います。まずはこのプロ
グラムを作成し実行して下さい。そしてプログラムの意味を考えてみて下さい。流れが大
まかにつかめたら、次の【基礎課題 2-1】に進んで下さい。課題に答えることで理解が深ま
って行く様に考慮しています。
14
CG プログラミング論 平成 28 年 4 月 27 日
※
プログラムを読んでその流れを把握できるようにすることはプログラミング力を向
上させるためには不可欠です。そのため、基本情報技術者の試験でも、プログラム(ソ
ースコード)を示してその処理内容を問う問題がよく出題されています。本講義でも
課題を通じてその様なトレーニングを積んで行きます。
【基礎課題 2-1】
① 上のプログラムの①の部分の意味を確かめるために「x=30;」と変更してみました。
このとき、実行結果はどのように変わるでしょうか?下の中から該当するものを選びその
記号を記入して下さい。
A
②
B
C
プログラムの②の繰り返しの部分を次のように書き換えてみました。このとき、実行
結果はどのように変わるでしょうか?下の中から該当するものを選びその記号を記入し
for (int i=1; i<=3; i++)
て下さい。
B
A
C
③ プログラムの③で定義しているhを「h=20;」と書き換えてみました。このとき、実
行結果はどのように変わるでしょうか?下の中から該当するものを選びその記号を記入
して下さい。
A
B
C
※ 課題の提出要領は、プリント p.2(4/13 配布)<課題提出の仕方>の通りです。
15
CG プログラミング論 平成 28 年 4 月 27 日
2-3
格子模様への改良
ここで、上で作成したプログラムを改良して下の格子模様を描くことにしましょう。
1 列 2列
3列 4列
5列
1 行目
2行目
3行目
4行目
5行目
改めて 1 行ずつ上図を見てみると、赤色に塗りつぶされたマスを描くのは、
1 行目の場合は、1 列目、3 列目、5 列目
2 行目の場合は 2 列目、4 列目
・・・
という条件が成り立つ場合となっています。
このことより、上の格子模様は
「奇数行の場合は奇数列、偶数行の場合は偶数列」という条件が成り立つ場合に(のみ)
赤色のマスを描き、それ以外の場合は何もしない
というアルゴリズムで記述できる事が分かります。
これをプログラムで記述すると、次のように、今まで(無条件に)マス目を描いていた部
分(下の点線枠内)を次ページの様なプログラムで置き換えれば良い事になります。
void DrawGraphics(Graphics g) {
int x,y,w,h;
・・・
for (int i=1; i<=5; i++) {
for (int j=1; j<=5; j++) {
g.drawRect(x,y,w,h);
x=x+w;
}
・・・
}
}
16
この部分を置き換える。
CG プログラミング論 平成 28 年 4 月 27 日
<置き換えるプログラム>
if(偶数行の場合) {
if(偶数列の場合) {
g.fillRect(x,y,w,h);
//マス内を塗りつぶす
}
}
if(奇数行の場合) {
if(奇数列の場合) {
g.fillRect(x,y,w,h);
//マス内を塗りつぶす
}
}
すると、あとは行あるいは列が偶数か奇数かを判定できれば良いことになります。ここ
で、Java 言語には、整数 A を整数 B で割ったときの余りを
A % B
という形で求める剰余演算子があった事を思い出して下さい。これを用いればある整数 A
が偶数か奇数かは、
「A % 2」が0 → 偶数
「A % 2」が1 → 奇数
と判定できます。これを考えると、上のプログラムは次のように記述できます(iが行、
jが列に対応している事に注意して下さい)
。
if((i%2)==0) {
if((j%2)==0 ) {
g.fillRect(x,y,w,h);
}
}
if((i%2)==1) {
if((j%2)==1 ) {
g.fillRect(x,y,w,h);
}
}
//行、列共に偶数の時のみマスを描画する
//行、列共に奇数の時のみマスを描画する
プログラムを修正したら実行し、格子模様が描かれることを確認して下さい。その上で【基
礎課題 2-2】に進んで下さい。
17
CG プログラミング論 平成 28 年 4 月 27 日
【基礎課題 2-2】
上で表した、
(塗りつぶされた)マスを描く条件をまとめて書くと、
(行、列共に偶数である) または
(行、列共に奇数である)
場合
ということになります。したがって、上の2つの if 文は
if( (行・列共に偶数)または(行・列共に奇数) ) {
g.fillRect(x,y,w,h); //行、列共に偶数または奇数の時のみ描画する
}
という様に一つの if 文にまとめられるはずです。
一方、
「プログラミング」で学習した通り、Java 言語では、複数の条件を「または」あるい
は「かつ」で結んで次の様に表現できます。
A=0 かつ B=0 → A==0 && B==0
A=0 または B=0 → A==0 || B==0
これを用いると、上の if 文は次のように表現できます。
if( ((i%2)==0 && (j%2)==0) ||
) {
①
g.fillRect(x,y,w,h); //行、列共に偶数または奇数の時のみ描画する
}
空欄に条件式を記入してプログラムを完成させて下さい。
「(行が奇数)かつ(列が奇数)
」
という条件式を入れれば良いのです。
2-4
格子模様の応用
【応用課題 2-A】
【基礎課題 2-2】で作成したプログラムにおいて、if 文内の条件式を変更するだけで、下の
様な模様を描くことができます。どのように条件式を変更したら良いでしょうか?
if(
①
) {
g.fillRect(x,y,w,h);
}
空欄を埋めてプログラムを完成させて下さい。
18
CG プログラミング論 平成 28 年 4 月 27 日
【応用課題 2-B】
【基礎課題 2-2】のプログラムを改良して、下のように、プログラムを起動して行数およ
び列数を入力した後[描画]ボタンをクリックすると、それに応じて(パネル画面にちょ
うど収まるように)格子模様を描くようにしましょう。
3 行 3 列の場合
4 行 7 列の場合。
行や列の数に応じて、パ
ネルの中 に格子模様 が
ピッタリ と収まるよ う
にマスの 幅や高さを 変
化させている事に注意。
このプログラムは、次のようになります。枠線部が新たに加わった部分で、下線部が(
【基
礎課題 2-2】からの)変更部分です。
19
CG プログラミング論 平成 28 年 4 月 27 日
void DrawGraphics(Graphics g) {
int Gyou=Integer.parseInt(jTextFieldGyou.getText());
int Retsu=Integer.parseInt(jTextFieldRetsu.getText());
int width=myPanel1.getWidth(); //パネル幅の取得
int height=myPanel1.getHeight(); //パネルの高さの取得
int x,y,w,h;
x=0; //(最初に描画する)マスの左上隅のx座標(右方向の位置)
y=0; //(最初に描画する)マスの左上隅のy座標(下方向の位置)
w=
①
//マスの横幅
h=
//マスの高さ
②
g.setColor(Color.red); //描画色を赤色に指定
for (int i=1; i<=Gyou; i++) { //行方向の繰り返し
for (int j=1; j<=Retsu; j++) { //列方向の繰り返し
if(((i%2)==0 && (j%2)==0) || ((i%2)==1 && (j%2)==1) ) {
g.fillRect(x,y,w,h); //マス内を塗りつぶす
}
x=x+w; //描画位置を右に w だけずらす
}
x=0;
y=y+h; //描画位置を下に h だけずらす
}
}
入力した行数および列数に応じて、格子模様がパネル内にきちんと収まるようにするため
には、マスの幅wと高さhをそれに応じて変更しなければなりません。そうなるように、
空欄①および②を埋めてプログラムを完成させて下さい。
<ヒント>
パネルの幅と高さはそれぞれ、width および height という変数で取得しています。これ
と、行数および列数から一つのマスの幅「w」と高さ「h」が求まるはずです。
もっと具体的に言えば・・・
width=(列の数)×w
height=(行の数)×h
が成立しなければなりません。
※
上のプログラムでは、列の数は「Retsu」
、行の数は「Gyou」という変数で表していま
す。
20