プログラミング実習I : 課題 R5
目次
目標
- 教科書にはない番外編として,自作関数(自分で作ったメソッド)に関する理解を得る
- メソッドとは?
- 与えられた値(引数)をもとに,定められた独自の処理を実行し,その結果を返す命令
- 例: fillRect や fillOval など
- fillRect メソッドの引数
- 描画する四角形の左上の座標や幅,高さ
- fillRect メソッドの独自の処理
- 引数で指定されたウィンドウ内の位置に,指定された大きさの四角形を描画
- fillRect メソッドで返されるもの(戻り値)
- なし
- fillRect メソッドの引数
- メソッド(命令)は,自分で定義して使う(呼び出す)ことができる
- メリット
- 複数の命令を一つの命令にまとめることができ,(1) プログラムが分かりやすくなるだけでなく,(2) 同じような処理を何度も繰り返して書く必要がなくなる
- メリット
- メソッドは,引数の有無や戻り値の型などで分類される
- 様々なメソッドを定義したり,使用したりできるようになるのが R5 の目標
- メソッドとは?
メソッド(引数なし,戻り値なし)
定義と呼び出し方
- Test クラス内に,引数と戻り値が共にないメソッドを定義する際には,以下の 2 行目のように書く
「実行する命令(※)」の部分で,定義したメソッドを呼び出した際に実行される命令を書く
1: public class Test { 2: public void メソッド名() { 3: 実行する命令(※) 4: } 5: 6: public void run() { 7: ... 8: メソッド名(); 9: ... 10: } 11: }
- 別のメソッド(例えば,run メソッド)から,定義したメソッドを呼び出すには,↑の例の 8 行目のように書けばよい
具体例
以下のサンプルプログラムでは,以下を行っている
- 引数と戻り値がない drawNumbers メソッドを Sample クラス内に定義している
- 定義した drawNumbers メソッドを run メソッドから呼び出している
public class Sample extends MyFrame2 { /** 0 から 9 までをウィンドウに表示するメソッドの定義(引数なし,戻り値なし) */ public void drawNumbers() { int n = 10; // 表示する数字の最大値 + 1 int x = 50; // 文字描画の左下 x 座標 int y = 100; // 文字描画の左下 y 座標 int s = 20; // 文字のサイズ for (int i = 0; i < n; i++) { drawString("" + i, x, y, s); // ウィンドウに i が表示される x += 25; } } public void run() { drawNumbers(); // 定義したメソッドを呼び出す } public static void main(String[] args) { new Sample(); } }
図1: ↑のサンプルプログラムで表示されるウィンドウ
メソッド(引数あり,戻り値なし)
定義と呼び出し方
- Test クラス内に,2 つの引数を持つメソッド(戻り値なし)を定義する際には,以下の 2 行目のように書く
「実行する命令(※)」の部分で,定義したメソッドを呼び出した際に実行される命令を書く
1: public class Test { 2: public void メソッド名(引数1の型 引数1, 引数2の型 引数2) { 3: 実行する命令(※) 4: } 5: 6: public void run() { 7: ... 8: メソッド名(値1, 値2); 9: ... 10: } 11: }
※ 3 つの引数を持つメソッドを定義する際には,2 行目を以下のように書き換えればよい
public void メソッド名(引数1の型 引数1, 引数2の型 引数2, 引数3の型 引数3) {
- 別のメソッド(例えば,run メソッド)から,定義したメソッドを呼び出すには,↑の例の 8 行目のように書けばよい
- 定義したメソッドを呼び出した際に,「値1」と「値2」がそれぞれ「引数1」と「引数2」に代入される
- 注意:定義された引数の数だけ,値を指定して呼出さないとエラーとなる
- ↑の例では,2つの引数のメソッドを定義しているので,値を 2 つ指定している
具体例
- 以下のサンプルプログラムでは以下のメソッドを定義している
- drawNumbers : n (int 型)を引数として持ち,0 から n-1 までの数字をウィンドウに表示する
- drawNumbersWithSize : n (int型) と s (int型) の 2 つを引数として持ち,大きさ s で 0 から n-1 までの数字をウィンドウに表示する
- また,定義した drawNumbers メソッドを run メソッドを呼び出している
- 呼び出しの際に 8 が drawNumbers に与えられている
- 0 から 7 までの数字がウィンドウに表示される(図 2)
- 注意:以下のサンプルプログラムでは同じ名前の変数が定義されている
- 例えば,以下の変数
- drawNumbers メソッドの変数 x
- drawNumberslWithSize メソッドの変数 x
このことに関しては,変数のスコープについて の項目を参考にすること
public class Sample extends MyFrame2 { /** 0 から n-1 までの数字をウィンドウに表示するメソッドの定義(引数あり,戻り値なし) */ public void drawNumbers(int n) { int x = 50; // 文字描画の左下 x 座標 (★1) int y = 100; // 文字描画の左下 y 座標 int s = 20; // 文字のサイズ for (int i = 0; i < n; i++) { // △△ drawString("" + i, x, y, s); // ウィンドウに数字 i が表示される x += 25; } // ★1 で定義されている変数 x のスコープはここまで (★2) } /** 大きさ s で 0 から n-1 までの数字をウィンドウに表示するメソッドの定義(引数あり,戻り値なし) */ public void drawNumbersWithSize(int n, int s) { int x = 50; // 文字描画の左下 x 座標 (★★1) int y = 100; // 文字描画の左下 y 座標 for (int i = 0; i < n; i++) { drawString("" + i, x, y, s); // ウィンドウに数字 i が表示される x += 25; } // ★★1 で定義されている変数 x のスコープはここまで (★★2) } public void run() { drawNumbers(8); // 定義したメソッドを呼び出し,0 から 7 までの数字を表示 } public static void main(String[] args) { new Sample(); } }
図2: ↑のサンプルプログラムで表示されるウィンドウ
- 例えば,以下の変数
- 呼び出しの際に 8 が drawNumbers に与えられている
参考:メソッド内で定義された変数の使用可能範囲(スコープ) について
- それぞれの変数は,プログラムの中で使用できる範囲が決まっています
- この範囲のことを「スコープ」と言います
- Java では,ある変数のスコープの中に同じ名前の変数を定義することはできません
- 逆にスコープが違っていれば,同じ名前の変数を定義して使用することができます
- ここでは,いくつかのよくある変数のスコープについて簡単に説明します
- メソッド内で定義された変数のスコープ
- ↑のサンプルプログラムでは,以下の変数がメソッド内で定義された変数になります
- drawNumbers メソッドの変数 n, x, y, s
- drawNumbersWithSize メソッドの変数 n, s, x, y
- スコープの始まり → 変数を定義した場所
- スコープの終わり → メソッドの終わり
- スコープの例
- drawNumbers メソッドの変数 x のスコープは,★1〜★2
- drawNumbersWithSize メソッドの変数 x のスコープは,★★1〜★★2
- 別のメソッドで定義された変数はスコープが異なるため,変数名が同じでも問題ない
- drawNumbers と drawNumbersWithSize のそれぞれのメソッドで変数 x が定義されていても問題ない
- ↑のサンプルプログラムでは,以下の変数がメソッド内で定義された変数になります
- for 文のカウンタ変数のスコープ
- 例:↑のサンプルプログラムにおける for 文のカウンタ変数 i
- drawNumbers の △△ にある for 文の i など
- スコープの始まり → for 文の始まり
- スコープの終わり → for 文の終わり
- △△ にある for 文のカウンタ変数 i を,この for 文の外で使用することはできない
- 例:↑のサンプルプログラムにおける for 文のカウンタ変数 i
メソッド(引数あり,戻り値あり)
定義と呼び出し方
- Test クラス内に,2 つの引数を持つメソッド(戻り値あり)を定義する際には,以下の 2 行目のように書く
「実行する命令(※)」の部分で,定義したメソッドを呼び出した際に実行される命令を書く
- 最後に実行される命令として「return 戻り値;」を書く
- 定義したメソッドの処理は,return 命令で終わる
- 定義したメソッドの実行結果として,ここで書いた値が返される
1: public class Test { 2: public 戻り値の型 メソッド名(引数1の型 引数1, 引数2の型 引数2) { 3: 実行する命令(※) 4: 5: return 戻り値; 6: } 7: 8: public void run() { 9: ... 10: 変数 = メソッド名(値1, 値2); 11: ... 12: } 13: }
- 最後に実行される命令として「return 戻り値;」を書く
- 別のメソッド(例えば,run メソッド)から,定義したメソッドを呼び出すには,↑の例の 10 行目のように書けばよい
- 定義したメソッドを呼び出した際に,「値1」と「値2」がそれぞれ「引数1」と「引数2」に代入される
- 定義したメソッドの実行後に,その戻り値が 10 行目の左辺の変数に代入される
具体例
- 以下のサンプルプログラムでは,以下の仕様の min メソッドを定義している
- min メソッドの仕様
- 引数: 整数 a と 整数 b
- 戻り値: a と b の小さい方の値
- min メソッドの仕様
public class Sample extends MyFrame2 { /** a と b のうち小さい方を返すメソッドの定義(引数あり,戻り値あり) */ public int min(int a, int b) { if (a < b) { return a; // a の値を返して終了 } else { return b; // b の値を返して終了 } } public void run() { int val = min(10, 15); // min メソッドの実行後に,val には 10 が代入される drawString("" + val, 100, 100, 20); // ウィンドウには 10 が表示される } public static void main(String[] args) { new Sample(); } }
図3: ↑のサンプルプログラムで表示されるウィンドウ
R5_1
準備
- 以下の Line.java を作成せよ
Line.java
public class Line extends MyFrame2 { /** a と b のうち小さい方を返すメソッド */ public int min(int a, int b) { if (a < b) { return a; } else { return b; } } /** a の絶対値を返すメソッド */ public int abs(int a) { if (a < 0) { return -a; } else { return a; } } public void drawHorizontalLine(int x0, int x1, int y) { // TODO: 座標 (x0, y) から座標 (x1, y) に水平線を描く } public void drawVerticalLine(int y0, int y1, int x) { // TODO: 座標 (x, y0) から座標 (x, y1) に垂直線を描く } public void drawRect(int x, int y, int w, int h) { // TODO: 左上の座標が (x, y) で,幅 w および 高さ h の四角形(塗りつぶし無し)を描画する(↑の 2 つのメソッドを使うこと) } public void run() { // TODO: drawRect メソッドを呼び出す } public static void main(String[] args) { new Line(); } }
課題
- 上記の Line.java にある空のメソッド(drawHorizontalLine, drawVerticalLine および drawRect) を R5_1 で作成するメソッドの仕様 を満たすように修正せよ
- drawHorizontalLine : 水平線を描画するメソッド
- drawVerticalLine : : 垂直線を描画するメソッド
- drawRect : 塗りつぶし無し の四角形を描画するメソッド
- また,Line.java にある run メソッドを以下の条件を満たすように修正し,図 4 に示すような \(n\) 個の四角形(塗りつぶし無し)を描画するプログラム(Line.java) を作成せよ
- ※ 説明のために,四角形(塗りつぶし無し) には左上から順番に,0 番, 1 番, … \(n-1\) 番の番号が付けられているとする
- 満たすべき条件
- 描画する四角形の個数 \(n\) を変更できるようにすること
- for 文を用い,その中でのみ drawRect を呼び出すこと
- \(i\) 番目の四角形の左上の座標が \((10*i +20, 10*i + 80)\) となること
- ※ \(i = 0, 1, ..., n-1\) とする
- 全ての四角形の幅 \(w\) および高さ \(h\) は 50 とすること
- レポートには,\(n\) を以下で与えた実行結果のスクリーンショットを貼り付けること
- \(n\) = 「学籍番号の下 1 ケタ」 + 3
- 例えば,学籍番号が 12345678 である時,\(n = 8 + 3 = 11\) となる
- \(n\) = 「学籍番号の下 1 ケタ」 + 3
図4: R5_1 で表示されるウィンドウの例 (\(n = 12\) の場合)
R5_1 で作成するメソッドの仕様
public void drawHorizontalLine(int x0, int x1, int y)
- 引数
- x0 : 始点の \(x\) 座標(int)
- x1 : 終点の \(x\) 座標(int)
- y : 始点と終点の \(y\) 座標(int)
- 動作
- 座標 (x0, y) から座標 (x1, y) までの水平線を描画する
- fillRect を用いて,幅 |x0 - x1| + 1 で高さが 1 の四角形を表示すればよい
- ※ fillRect には,四角形の左上の座標を指定する必要があることに注意せよ
- 左上の座標はどのような座標か?
- ※ filRect(x, y, w, 1) を呼出した時,座標 (x+w, y) は塗りつぶされないことに注意せよ
- (x+w, y) まで塗りつぶすためには,fillRect の第 3 引数 に w+1 を指定しないといけない
- ※ fillRect には,四角形の左上の座標を指定する必要があることに注意せよ
- fillRect を用いて,幅 |x0 - x1| + 1 で高さが 1 の四角形を表示すればよい
- 座標 (x0, y) から座標 (x1, y) までの水平線を描画する
- 戻り値
- なし
図5: drawHorizontalLine メソッドで描画される水平線の例
public void drawVerticalLine(int y0, int y1, int x)
- 引数
- y0 : 始点の \(y\) 座標(int)
- y1 : 終点の \(y\) 座標(int)
- x : 始点と終点の \(x\) 座標(int)
- 動作
- 座標 (x, y0) から座標 (x, y1) までの水平線を描画する
- fillRect を用いて,幅 1 および高さ |y0 - y1| + 1 の四角形を表示すればよい
- 座標 (x, y0) から座標 (x, y1) までの水平線を描画する
- 戻り値
- なし
図6: drawVerticalLine メソッドで描画される垂直線の例
public void drawRect(int x, int y, int w, int h)
- 引数
- x : 四角形の左上の \(x\) 座標(int)
- y : 四角形の左上の \(y\) 座標(int)
- w : 四角形の幅(int)
- h : 四角形の高さ(int)
- 動作
- drawHorizontalLine メソッドと drawVerticalLine メソッドを呼び出して,四角形の水平線および垂直線を描画する
- ただし,drawRect で描画する四角形の右下の座標は,fillRect と同様に (x+w-1, y+h-1) とすること
- ※ 図 7 に示すような四隅の座標間に水平線や垂直線を引けばよい
- drawHorizontalLine メソッドと drawVerticalLine メソッドを呼び出して,四角形の水平線および垂直線を描画する
- 戻り値
- なし
図7: drawRect を描画する際に描画する水平線や垂直線の四隅の座標
R5_2
準備
- 以下の Circle.java を作成する
Circle.java
public class Circle extends MyFrame2 { public void fillOvalWithBorder(int x, int y, int r, int w) { // TODO: 枠線がある円(塗りつぶし有り)を描画 } public void run() { // TODO: fillOvalWithBorder メソッドを呼び出す } public static void main(String[] args) { new Circle(); } }
課題
- 上記の Circle.java にある空の fillOvalWithBorder メソッドを R5_2 で作成するメソッドの仕様 を満たすように修正せよ
- fillOvalWithBorder: 枠線がある円(塗りつぶしあり)を描画するメソッド
- また,Circle.java にある run メソッドを以下の条件を満たすように修正し,図 8 に示すような \(n\) 個の円(塗りつぶしあり)を描画するプログラム(Circle.java) を作成せよ
- ※ 説明のために,円(塗りつぶしあり) には左上から順番に,0 番, 1 番, … \(n-1\) 番の番号が付けられているとする
- 満たすべき条件
- 描画する円(塗りつぶしあり)の個数 \(n\) を変更できるようにすること
- for 文を用い,その中でのみ fillOvalWithBorder を呼び出すこと
- \(i\) 番目の円の左端と上端が \((45*i + 20, 80)\) となること
- 枠線の太さ \(w\) は \(i+1\) とすること
- ※ \(i = 0, 1, ..., n-1\) とする
- 全ての円の半径 r は 20 とすること
- レポートには,\(n\) を以下で与えた実行結果のスクリーンショットを貼り付けること
- \(n\) = 「学籍番号を 5 で割った余り」 + 3
- 例えば,学籍番号が 12345678 である時,\(n = 3 + 3 = 6\) となる
- \(n\) = 「学籍番号を 5 で割った余り」 + 3
図8: R5_2 で表示されるウィンドウの例 \((n = 8)\)
R5_2 で作成するメソッドの仕様
public void fillOvalWithBorder(int x, int y, int r, int w)
- 引数
- x : 円の左端の \(x\) 座標(int)
- y : 円の上端の \(y\) 座標(int)
- r : 円の半径(int)
- ※ 枠線を含んだ半径とすること
- w : 枠線の太さ(int)
- 動作
- 枠線の太さが w で半径 r の円(塗りつぶしあり)を描画する
- ※ 以下の色で描画すること
- 枠線の色 → 黒
- 円の中を塗りつぶす色 → 白
- fillOval を 2 回呼びだして,半径 r と半径 r-w の同心円を 2 つ描画すればよい
- 半径 \(r-w\) の円を描画する時に,fillOval に指定する左上の座標をいくつにしたらよいか,ノートによく整理してからプログラムを作成すること
- ※ 以下の色で描画すること
- 枠線の太さが w で半径 r の円(塗りつぶしあり)を描画する
R5_3
準備
- 以下の Digit.java を作成する
Digit.java
public class Digit extends MyFrame2 { public int getDigit(int n, int k) { // TODO: 正の整数 n の k 桁目を数字返す(※桁 k は 1 オリジン) } public void run() { // TODO: getDigit メソッドを呼び出す } public static void main(String[] args) { new Digit(); } }
課題
- 上記の Digit.java にある空の getDigit メソッドを R5_3 で作成するメソッドの仕様 を満たすように修正せよ
- getDigit: 与えられた正の整数 \(n\) を 10 進数で表記した際の下から \(k\) 桁目の数字(0〜9)を返すメソッド
- ※ 例えば,\(n = 12345678\) で \(k = 2\) の時,getDigit(n, k) は 7 を返す
- ※ 桁 \(k\) は 1 オリジンである(1 桁,2 桁,3 桁,… と数える)
- getDigit: 与えられた正の整数 \(n\) を 10 進数で表記した際の下から \(k\) 桁目の数字(0〜9)を返すメソッド
- また,Digit.java にある run メソッドを以下の条件を満たすように修正し,図 9 のように,整数 n を 10 進数で表記した際の各桁が逆順で表示されるプログラム(Digit.java) を作成せよ
- 満たすべき条件
- \(n\) を変更できるようにすること
- for 文を用い,その中でのみ getDigit を呼び出すこと
- for 文は k = 1, 2, …, 10 と変化させること
- getDigit(n, k) の返り値 \(d\) を,drawString を用いて描画すること
- ただし,drawString に与える左下の座標を \((30*k + 20, 80)\) とする
- ※ drawString の第 1 引数を 「"" + d」 とすれば,返り値 \(d\) を描画できる
- ※ drawString に与える文字サイズは 20 とすること
- レポートには,\(n\) を以下で与えた実行結果のスクリーンショットを貼り付けよ
- n = 自身の学籍番号
- 満たすべき条件
図9: R5_3 で表示されるウィンドウの例 (n = 17045623 の場合)
R5_3 で作成するメソッドの仕様
public int getDigit(int n, int k)
- 引数
- n : 正の整数(int)
- k : 桁(int)
- 動作
- 1. n を 10 で k-1 回割った値 \(m\) を求める
- 割り算での小数点以下は切り捨てる
- 2. \(m\) が 0 かどうかを調べる
- \(m = 0\) ならば,\(k\) は \(n\) の桁数よりも大きいので \(-1\) (エラー)を return 命令で返す
- \(m > 0\) ならば,\(m\) を 10 で割った余り \(r\) を計算し,\(r\) を return 命令で返す
- 1. n を 10 で k-1 回割った値 \(m\) を求める
R5_4 (オプション)
準備
- 以下の Circle.java を作成する
Circle.java
public class Circle extends MyFrame2 { public void drawCircle(int cx, int cy, int r) { // TODO: メソッドの中身を書く } public void run() { // TODO: drawCircle を呼出して,半径が異なる n 個の同心円を表示 } public static void main(String[] args) { new Circle(); } }
課題
- Circle.java の中にある空の drawCircle メソッドを R5_4 で作成するメソッドの仕様 を満たすように修正せよ
- drawCircle メソッド: 円(塗りつぶし無し) を描画する
- また,Circle.java にある run メソッドを以下の条件を満たすように修正し,図 10 のように,半径が異なる \(n\) 個の同心円を描画するプログラム(Circle.java) を作成せよ
- ※ 説明のために,円(塗りつぶし無し) には中心から外側に向けて,0 番, 1 番, … \(n-1\) 番の番号が付けられているとする
- 満たすべき条件
- \(n\) を変更できるようにすること
- for 文を用い,その中でのみ drawCircle を呼び出すこと
- すべての円の中心の座標が \((150, 150)\) となること
- \(i\) 番目の円の半径 \(r\) が \((i+1)*10\) となること
- ※ \(i = 0, 1, ..., n-1\) とする
- レポートには,\(n\) を以下で与えた実行結果のスクリーンショットを貼り付けよ
- \(n\) = 「学籍番号の下 1 ケタ」 + 3
図10: R5_4 で作成するプログラムで表示されるウィンドウの例
R5_4 で作成するメソッドの仕様
public void drawCircle(int cx, int cy, int r)
- 引数
- cx : 円の中心 x 座標(int)
- cy : 円の中心 y 座標(int)
- r : 円の半径(int)
- 動作
- 座標 (cx, cy) を中心とした半径 r の円(塗りつぶし無し)を描画する
- そのための簡易的な方法として,deg = 0°,1°,2°,3°, …, 359°の角度にある円周上の座標に点(1×1の正方形)を一つずつ描画していくものがある
- ※ 別の方法で描画していってもいいが,この方法を用いたほうが R5_6 で作成するプログラムに変更しやすい
- \(\theta\) [rad] の角度にある円周上の座標 \((x, y)\) に,1×1の正方形を描画するためには,どうしたらよいか?
以下の式で座標 \((x, y)\) (実数)を計算し,fillRect((int)x, (int)y, 1, 1) を呼び出せばよい
\begin{align} x &= r \cos \theta + cx \\ y &= r \sin \theta + cy \end{align}- ただし,\((cx, cy)\) および \(r\) はそれぞれ円の中心座標および半径である
図11: 円の円周上の座標 \((x, y)\) の計算式
- そのための簡易的な方法として,deg = 0°,1°,2°,3°, …, 359°の角度にある円周上の座標に点(1×1の正方形)を一つずつ描画していくものがある
- 注意事項
- \(\cos(x)\) および \(\sin(x)\) を計算する際ためには,Java ではそれぞれ Math.cos(x) および Math.sin(x) と書けばよい
- この時,\(x\) の単位はラジアンであることに注意
- deg [°] (0°〜 360°) から \(\theta\) [rad] (0 〜 \(2\pi\)) に Java で変換するには, Math.toRadians(deg) を用いればよい
- この時,\(x\) の単位はラジアンであることに注意
普段よく見る \(xy\) 座標とウィンドウの \(xy\) 座標では,\(y\) 軸が反転しているため,以下の図のような違いがあることに注意すること
- ウィンドウの \(xy\) 座標では,上が 270°,角度の増加方向は時計回りである
図12: 普段よく見る \(xy\) 座標とウィンドウの \(xy\) 座標
- \(\cos(x)\) および \(\sin(x)\) を計算する際ためには,Java ではそれぞれ Math.cos(x) および Math.sin(x) と書けばよい
- 座標 (cx, cy) を中心とした半径 r の円(塗りつぶし無し)を描画する
- 戻り値
- なし
R5_5 (オプション)
課題
- R5_4 で作成した Circle.java に,R5_5 で作成するメソッドの仕様 を満たす drawSpiral メソッドを追加せよ
- drawSpiral メソッド: 渦巻を描画する
- また,Circle.java にある run メソッドを以下の条件を満たすように修正し,図 13 のような渦巻を描画するプログラム(Circle.java) を作成せよ
- 満たすべき条件
- 合計 6 つの渦巻を 2 段に分けて描画すること
- 上段: 左から順に,回転数 num = 1, 2, 3 の渦巻を描画すること
- 初期角度 deg はどれも 0°
- 下段: 左から順に,初期角度 deg = 90°,180°, 270°の渦巻を描画すること
- 回転数 num はどれも 4
- ただし,下段の一番左の渦巻には,参考のために,初期角度(=最終角度) deg = 90°を赤で示している
- 上段: 左から順に,回転数 num = 1, 2, 3 の渦巻を描画すること
- 合計 6 つの渦巻を 2 段に分けて描画すること
- 満たすべき条件
図13: R5_5 で作成するプログラムで表示されるウィンドウの例
R5_5 で作成するメソッドの仕様
public void drawSpiral(int cx, int cy, int dist, int num, int deg)
- 引数
- cx : 渦巻の中心 x 座標(int)
- cy : 渦巻の中心 y 座標(int)
- dist : 渦巻の一番外側の座標と中心座標の距離(int)
- num : 渦巻の回転数(int)
- deg : 渦巻の初期角度(int)
- ※ 単位は 「°(度)」とする
- 動作
- 中心座標 (cx, cy) から渦巻を描画していく
- ヒント
- drawCircle メソッドの仕様で説明した動作では,円周上の座標に点を描画していく際に半径 rad を固定していた
- 角度の変化とともに,半径 rad を徐々に大きくしていったらどうなるか?
- drawCircle メソッドの仕様で説明した動作では,円周上の座標に点を描画していく際に半径 rad を固定していた
- 渦巻の中心からの距離が dist となったら,描画を終わること
- 描画を始めてから終わるまでの渦巻の回転数が num となること
- そのため,初期角度で指定した deg が,描画の終了角度と一致する
- ヒント
- 中心座標 (cx, cy) から渦巻を描画していく
- 戻り値
- なし
R5_6 (オプション)
準備
- R5_1 で作成した Line.java をコピーする
課題
- コピーした Line.java に,R5_6 で作成するメソッドの仕様 を満たす drawLine メソッドおよび drawDiamond メソッドを追加せよ
- drawLine : 線分を描画するメソッド
- drawDiamond : 菱形(塗りつぶしなし)を描画するメソッド
- また,Line.java にある run メソッドを以下の条件を満たすように修正し,図 14 のように \(n\) 個の菱形(塗りつぶしなし)を描画するプログラム(Line.java) を作成せよ
- ※ 説明のために,菱形(塗りつぶしなし) には中心から外側に向けて,0 番, 1 番, … \(n-1\) 番の番号が付けられているとする
- 満たすべき条件
- 描画する菱形の個数 \(n\) を変更できるようにすること
- for 文を用い,その中でのみ drawDiamond を呼び出すこと
- すべての菱形の中心の座標が \((200, 200)\) となること
- \(i\) 番目の菱形の幅 \(w\) および高さ \(h\) がそれぞれ以下となること
- ※ \(i = 0, 1, ..., n-1\) とする
- 幅 \(w = 20 \times i + 50\)
- 高さ \(h = 10 \times i + 100\)
- レポートには,\(n\) を以下で与えた実行結果のスクリーンショットを貼り付けよ
- \(n\) = 「学籍番号の下 1 ケタ」 + 3
図14: R5_6 で表示されるウィンドウの例 \((n = 12)\)
R5_6 で作成するメソッドの仕様
public void drawLine(int x0, int y0, int x1, int y1)
- 引数
- x0 : 線分の端点 1 の \(x\) 座標(int)
- y0 : 線分の端点 1 の \(y\) 座標(int)
- x1 : 線分の端点 2 の \(x\) 座標(int)
- y1 : 線分の端点 2 の \(y\) 座標(int)
- 動作
- 座標 (x0, y0) から座標 (x1, y1) までの線を描画する
- 1×1の四角形を fillRect(x, y, 1, 1) を用いて少しづつ描画していけばいい
- どのように描画していったらよいか自分で考え,レポートの方法にまとめよ
- 2 つの座標間にだいたい線が引けていれば,線の綺麗さはそこまで求めない
- もし綺麗に描画できない部分があったら,考察でどのような原因が考えられるかまとめてみよ
- 1×1の四角形を fillRect(x, y, 1, 1) を用いて少しづつ描画していけばいい
- 座標 (x0, y0) から座標 (x1, y1) までの線を描画する
- 戻り値
- なし
public void drawDiamond(int cx, int cy, int w, int h)
- 引数
- cx : 菱形の中心 \(x\) 座標(int)
- cy : 菱形の中心 \(y\) 座標(int)
- w : 菱形の幅(int)
- h : 菱形の高さ(int)
- 動作
- drawLine メソッドを 4 回呼出し,図 15 に示すような菱形を描画する
- ※ MyFrame2 クラスに定義されている drawLine メソッドを呼び出すのは NG
- drawLine メソッドを 4 回呼出し,図 15 に示すような菱形を描画する
- 戻り値
- なし
図15: drawDiamond メソッドで描画される菱形
R5_7 (オプション)
準備
- R5_4 (or R5_5) で作成した Circle.java と R5_6 で作成した Line.java を統合した,CircleAndLine.java を作成せよ
- CircleAndLine.java 内で main メソッドや run メソッドが複数存在しないように気をつけること
課題
- CircleAndLine.java に,R5_7 で作成するメソッドの仕様 を満たす drawClock メソッドを作成せよ
- drawClock メソッド: 指定した時刻のアナログ時計を描画する
- 作成した drawClock メソッドを run メソッドから呼び出し,指定した時刻(\(h\) 時 \(m\) 分)の状態の時計を描画するプログラム(CircleAndLine.java) を作成せよ
- レポートには,\(h\) と \(m\) を以下で与えた実行結果のスクリーンショットを貼り付けよ
- \(h\) : 学籍番号を 12 で割った余り
- \(m\) : 学籍番号を 60 で割った余り
- レポートには,\(h\) と \(m\) を以下で与えた実行結果のスクリーンショットを貼り付けよ
R5_7 で作成するメソッドの仕様
public void drawClock(int cx, int cy, int r, int h, int m)
- 引数
- cx : 時計の中心 x 座標(int)
- cy : 時計の中心 y 座標(int)
- r : 時計の大きさ(int)
- h : 時間(0 〜 11 の整数) (int)
- ※ 12時台の時刻は 0 時台の時刻とする
- m : 分(0 〜 59 の整数) (int)
- 動作
- 以下の図のような時計を描画する
- 時計の中心座標は (cx, cy) とすること
- 時計を表す円の半径は r とすること
- 与えられた時刻(h 時 m 分) に対応した位置に時針(短針と長針)を描画すること
- R5_6 で作成した drawLine ではなく,MyFrame2 にある drawLine メソッドを使用してもよい
- MyFrame2 の drawLine の仕様は, R5_6 で作成するメソッドの仕様 のものと同じ
- R5_6 で作成した drawLine ではなく,MyFrame2 にある drawLine メソッドを使用してもよい
- 時針から時刻が分かるように,時計の回りに数字の描画 or 時計に目盛の描画,を行うこと
- 以下の図では,その両方の描画を行っている
- 以下の図のような時計を描画する
- 補足
- プログラムの可読性を高めるために,以下のようなことを心掛けること
- まず,時計の一部を描画するメソッド(例えば以下のようなメソッド)を作る
- 円周上に 1 〜 12 の数字を描画するメソッド
- 円周の内部に,主目盛と補助目盛の全てを描画するメソッド
- \(h\) と \(m\) を入力として,長針と短針を描画するメソッド
- つぎに,それらのメソッドを組み合わせて時計全体を描画する drawClock メソッドを作る
- まず,時計の一部を描画するメソッド(例えば以下のようなメソッド)を作る
- プログラムの可読性を高めるために,以下のようなことを心掛けること
図16: drawClock メソッドで描画される時計の例 (4 時 38 分の状態)