Presentation is loading. Please wait.

Presentation is loading. Please wait.

計算機プログラミングI 第10回 データ構造とクラスの設計 例題: 話題: 複素数 図形要素 Morphing 複雑な値を一つにまとめる

Similar presentations


Presentation on theme: "計算機プログラミングI 第10回 データ構造とクラスの設計 例題: 話題: 複素数 図形要素 Morphing 複雑な値を一つにまとめる"— Presentation transcript:

1 計算機プログラミングI 第10回 データ構造とクラスの設計 例題: 話題: 複素数 図形要素 Morphing 複雑な値を一つにまとめる
似たような値を統一的に扱う 中身を気にしないで扱いたい 計算機プログラミングI (増原) 2003年度

2 複雑な値を一つにまとめる プログラム中で扱うモノ 整数・タートル・複素数・図形要素・・・ 複数の値の組み合わせで表わされるモノも多い
プログラム中で扱うモノ 整数・タートル・複素数・図形要素・・・ 複数の値の組み合わせで表わされるモノも多い タートル = X,Y座標,方向,色,ペン状態,… 複素数 = 実・虚成分 直線 = 両端点のX,Y座標 各値をバラバラに扱うのは大変 → 1つの値として扱いたい (変数に代入・引数・・・) → オブジェクトとして表現 計算機プログラミングI (増原) 2003年度

3 例題: マンデルブロ集合を表示したい 直感的なアルゴリズム: 複素関数 f(c,z) = z2+c が与えられた場合
z0=0としてi=0,1,2,…,29まで繰り返す |zi|>2となったら 繰り返しを止める zi+1=zi2+cとする 繰り返しの回数に 応じた色をc上に塗る オブジェクトを用いない プログラム for(c_real=…) for(c_imag=…) z_real=0, z_imag=0; for (k=0;k<30;k++) { mag = sqrt(z_real*z_real +z_imag*z_imag); if (mag<2) break; z_sq_real=z_real*z_real -z_imag*z_imag; z_sq_imag=2*z_real*z_imag; z_real = z_sq_real+c_real; z_imag = z_sq_imag+c_imag; } 計算機プログラミングI (増原) 2003年度

4 複素数をクラスとして表わす 「複素数」という1つの数を 「1つのオブジェクト」として表わそう!  クラスを定義する
「複素数」という1つの数を 「1つのオブジェクト」として表わそう!  クラスを定義する 複素数という1つの数を簡単に作れるようにしよう  コンストラクタを定義する 複素数に関する計算は複素数クラスに定義しよう  インスタンスメソッドを定義する 複素数の表現形式を使い分けよう  継承を利用する 計算機プログラミングI (増原) 2003年度

5 複素数: クラスの定義 /** 複素数 */ class Complex { インスタンス変数・ インスタンスメソッド・
複素数オブジェクトの性質の定義 = クラスの定義 名前 : Complex /** 複素数 */ class Complex { インスタンス変数・ インスタンスメソッド・ コンストラクタの定義 } 計算機プログラミングI (増原) 2003年度

6 複素数: インスタンス変数の定義 複素数のベクトル表現: x+yi → 2つの実数 → 2つの実数型インスタンス変数
class Complex { public double real; // 実部 public double imag; // 虚部 インスタンスメソッド・ コンストラクタの定義 } Complex c = new Complex(); c.real = 1; c.imag = 2; 計算機プログラミングI (増原) 2003年度

7 複素数:コンストラクタの定義 Complex c = new Complex(1,2); のようにしたい
class Complex { public double real; // 実部 public double imag; // 虚部 /** 実部, 虚部から複素数を作る */ public Complex(double r, double i) { real = r; imag = i; } 計算機プログラミングI (増原) 2003年度

8 複素数の演算とメソッド 複素数どうしの演算 (乗算、加算、etc.) を どのように定義するか? (例: z*c)
方針1: 新しく複素数の値を作って返す 例: zとcの積は新しいオブジェクト。zやcはそのまま 数学的。z*c+(z*z+c)のような計算が素直に書ける 方針2: メソッド呼び出しを受けたオブジェクトの 状態を変化 例: zの新しい状態がz*cになる オブジェクトが何かの実体に対応している場合に便利 (例: タートル・図形要素・etc.) 計算機プログラミングI (増原) 2003年度

9 複素数:インスタンスメソッドの定義 public Complex add(Complex y) {
class Complex { インスタンス変数・ コンストラクタの定義 public Complex add(Complex y) { double r = real + y.real; //実部の計算 double i = imag + y.imag; //虚部の計算 return new Complex(r,i); //新しい複素数を作って返す } Complex c1 = new Complex(1,2); Complex c2 = new Complex(3,4); Complex c3 = c1.add(c2); 計算機プログラミングI (増原) 2003年度

10 例題: マンデルブロ集合 オブジェクトを用いた プログラム オブジェクトを用いない プログラム for(c_real=…)
for(c_imag=…) c = new Complex(c_real,c_imag); z = new Complex(0,0); for (k=0;k<30;k++) { if (z.mag()<2) break; z = z.mul(z).add(c); } オブジェクトを用いない プログラム for(c_real=…) for(c_imag=…) z_real=0, z_imag=0; for (k=0;k<30;k++) { mag = sqrt(z_real*z_real +z_imag*z_imag); if (mag<2) break; z_sq_real=z_real*z_real -z_imag*z_imag; z_sq_imag=2*z_real*z_imag; z_real = z_sq_real+c_real; z_imag = z_sq_imag+c_imag; } 計算機プログラミングI (増原) 2003年度

11 似たような値を統一的に扱う 異なるけど統一的に扱いたい値 → 継承を活用する
例: 図形要素の線と円は違うモノだけど 「表示する」「距離を求める」等は同様に行いたい → 継承を活用する 共通する性質・操作は親クラスに定義 個別の操作内容は子クラスのメソッドで再定義 個別の性質・操作は子クラスに(追加定義) → 「同様に行いたい」部分は親クラスのオブジェクトとして扱うことができる 計算機プログラミングI (増原) 2003年度

12 図形要素 図形エディタの中の個々の要素 (線や円など)を どのようにして扱うか? ―― 行う操作を考える
例: マウスによる消去 1. 画面上の1点を選ぶ 2. その点に最も近い図形要素を見つける 3. 画面を消す 4. 全ての図形要素(ただし2で見つけたもの以外)を再描画する 図形要素を単位として操作→オブジェクト 統一して行いたい(だけど図形ごとに違う)操作: 距離を求める 画面に表示する 計算機プログラミングI (増原) 2003年度

13 共通図形要素のクラス定義 とりあえず共通するクラスを作り、 共通して存在すべき操作をメソッドとして定義
public class FigureElement { public void draw(Turtle m) {} public double distance(int x, int y) { return 0; } 計算機プログラミングI (増原) 2003年度

14 個々の図形要素のクラス定義 public class FigureElement {
public void draw(Turtle m) {} public double distance(int x, int y) { return 0; } public class Point extends FigureElement { int x, y; public void draw(Turtle m) { … } public double distance(int x, int y) { …; } public class Line extends FigureElement { インスタンス変数 public void draw(Turtle m) { … } public double distance(int x, int y) { …; } 計算機プログラミングI (増原) 2003年度

15 図形要素を使う側のプログラム 使う側はどのような 図形要素かを気にせずに距離を求め、再描画できる。 図形要素が増えても、この部分は変更不用!
FigureElement[] figs = …; int numFigs = …; /* x,y に最も近い図形を見つける*/ double minDist = MAX; for (int i=0; i<numFigus; i++) { if (figs[i].distance(x,y) < minDist) { …} } //見つけた図形要素を取り除く(略) //再描画 for (int i= …) figs[i].draw(m); public class FigureElement { public void draw(Turtle m) {} public double distance(int x, int y) { return 0; } 使う側はどのような 図形要素かを気にせずに距離を求め、再描画できる。 図形要素が増えても、この部分は変更不用! 計算機プログラミングI (増原) 2003年度

16 何が共通? 何が個有? 色: 全てに共通 回転・拡大: 設計による 時にはクラスの設計を1からやり直す必要も
FigureElementのインスタンス変数 個々のdrawメソッド 回転・拡大: 設計による 回転角や拡大率を共通の性質として持たせる 拡大すると個々の状態(例えば線分の座標)を変化 時にはクラスの設計を1からやり直す必要も public class FigureElement { public void draw(Turtle m) {} public double distance(int x, int y) { return 0; } public class Point extends FigureElement { int x, y; public void draw(Turtle m) { … } public double distance(int x, int y) { …; } public class Line extends FigureElement { インスタンス変数 public void draw(Turtle m) { … } public double distance(int x, int y) { …; } 計算機プログラミングI (増原) 2003年度

17 中身を気にしたくない 複雑な値の詳細を気にせずに扱いたい
例: タートルの座標が整数か実数か 例: 複素数は直交座標か極形式か 例: 直線は「両端点」か「1点と幅・高さ」か「1点と方向・長さ」か → インスタンスメソッドを通してのみ オブジェクト状態を得るようにプログラムを書くと クラス定義の中身を変えても大丈夫 計算機プログラミングI (増原) 2003年度

18 一つの値、二つの表現 複素数の表わし方には二つある: y r q x 直交座標系: 実部と虚部の成分の組 x+iy 極形式: reiq

19 2つの複素数クラス 直交座標系 class Complex { double real, imag;
double getReal() {return real;} double getImag() {return real;} double getMag() { … } double getAng() { … } Complex add(Complex c) { … } Complex mul(Complex c) { … } } 極形式 class Complex { double mag, theta; double getReal() { … } double getImag() { … } double getMag() { return mag; } double getAng() { return theta; } Complex add(Complex c) { … } Complex mul(Complex c) { … } } 使う側は同じプログラムでOK for(c_real=…) for(c_imag=…) c = new Complex(c_real,c_imag); z = new Complex(0,0); for (k=0;k<30;k++) { if (z.mag()<2) break; z = z.mul(z).add(c); } 計算機プログラミングI (増原) 2003年度

20 一つの値、二つの表現 複素数の表わし方には二つある: それぞれ向き、不向きがある 二つの表現のイイトコドリをしたい! → 2つの複素数クラス
直交座標系: 実部と虚部の成分の組 x+iy 極形式: reiq それぞれ向き、不向きがある 直交座標系: 和・差 (成分ごと) 極形式: 積・商・絶対値 (絶対値の積・商,偏角の和・差) 二つの表現のイイトコドリをしたい! → 2つの複素数クラス y r q x 計算機プログラミングI (増原) 2003年度

21 一つの値、二つの表現 複素数の表わし方には二つある: それぞれ向き、不向きがある 二つの表現のイイトコドリをしたい! → 2つの複素数クラス
直交座標系: 実部と虚部の成分の組 x+iy 極形式: reiq それぞれ向き、不向きがある 直交座標系: 和・差 (成分ごと) 極形式: 積・商・絶対値 (絶対値の積・商,偏角の和・差) 二つの表現のイイトコドリをしたい! → 2つの複素数クラス y r q x 計算機プログラミングI (増原) 2003年度

22 2つの複素数クラス 共通の性質・操作 実部・虚部などを 求める 四則演算 直交座標系 極形式
class Comlpex { double getReal() {…} double getImag() {…} double getMag() {…} double getAng() {…} Complex add(Complex c) { … } } 直交座標系 極形式 class CartesianComplex extends Complex { double real, imag; double getReal() { … } } class PolarComplex extends Complex { double mag, theta; dobule getReal() { … } } 計算機プログラミングI (増原) 2003年度

23 2つの複素数クラス 共通の性質 実部・虚部などを 求める――個別 四則演算―― 共通 直交座標系 極形式
class Comlpex { …略… Complex add(Complex c) { return new CartesianComlpex( this.getReal()+c.getReal(), this.getImag()+c.getImag());} Complex mul(Complex c) { return new PolarComplex( this.getMag()*c.getMag(), this.getAng()+c.getAng());} } 直交座標系 極形式 class PolarComplex extends Complex { double mag, theta; dobule getReal() { return mag*cos(theta);} } class CartesianComplex extends Complex { double real, imag; double getReal() { return real;} } 計算機プログラミングI (増原) 2003年度

24 2つの複素数を使う人は? 使う人はどっちの表現かを気にしなくてもよい!
class Comlpex { double getReal() {…} double getImag() {…} double getMag() {…} double getAng() {…} Complex add(Complex c) { … } } Complex c1 = new CatesianComplex(1,2); Complex c2 = new PolarComplex(0,PI/2); Complex c3 = c1.add(c2).mul(c2); if (c3.getMag() < 2) … 使う人はどっちの表現かを気にしなくてもよい! 計算機プログラミングI (増原) 2003年度

25 おまけ 継承でひろがる可能性 計算機プログラミングI (増原) 2003年度

26 Morphing再び Morphingのためのコード 中間の位置を計算し、 その位置へタートルを移動させる
中間の位置を計算し、 その位置へタートルを移動させる for(i = 0; i < steps; i++){ mc (円)を移動 ms (星形)を移動 mm.moveTo((mc.getX()+ms.getX())/2, (mc.getY()+ms.getY())/2, 0); } 計算機プログラミングI (増原) 2003年度

27 オブジェクト指向によるMorphing 中間の図形を描くタートルは 追いかけるタートルを知っている 星
追いかけろ、と指示を受けると 自ら中間地点へ移動 for(i = 0; i < steps; i++){ mc (円)を移動 ms (星形)を移動 mm.step(); } Morph 計算機プログラミングI (増原) 2003年度

28 Morphクラスの設計 Turtleクラスを拡張 追いかける対象 →インスタンス変数
public class Morph extends Turtle { // 追いかける対象 Turtle m1, m2; コンストラクタ・インスタンスメソッドの定義 } 計算機プログラミングI (増原) 2003年度

29 Morph: コンストラクタ Morph m = new Morph(mCircle, mStar); のようにしたい
public class Morph extends Turtle { public Turtle m1, m2; public Morph(Turtle m1, Turtle m2) { this.m1 = m1; this.m2 = m2; } インスタンスメソッドの定義 計算機プログラミングI (増原) 2003年度

30 Morph:インスタンスメソッド m.step() とすると、m1 と m2 の中間へ移動 public void step() {
public class Morph extends Turtle { public Turtle m1, m2; コンストラクタ(略) public void step() { 自身をm1とm2の中間に移動 } 計算機プログラミングI (増原) 2003年度

31 Morphクラスの使用 使う側は「どうやって中間の位置を 追いかけているか」を気にしなくてよい
Turtle mc = new Turtle(); Turtle ms = new Turtle(); Morph mm = new Morph(mc,ms); for(i = 0; i < steps; i++){ mc (円)を移動 ms (星形)を移動 mm.step(); } 使う側は「どうやって中間の位置を 追いかけているか」を気にしなくてよい 計算機プログラミングI (増原) 2003年度

32 Morphクラスの使用 星 円 Morph m0 = new Morph(mc,ms); m0
Turtle mc = new Turtle(); Turtle ms = new Turtle(); Morph m0 = new Morph(mc,ms); Morph m1 = new Morph(mc,m0); Morph m2 = new Morph(m0,ms); for(i = 0; i < steps; i++){ mc (円)を移動 ms (星形)を移動 m0.step(); m1.step(); m2.step(); } m0 m2 m1 「Morphオブジェクトを追いかけるMorphオブジェクト」 も可能 ← MorphはTurtleの子クラス 計算機プログラミングI (増原) 2003年度

33 Morphingの発展 各タートルはstepメソッドを呼び出されると、 各自、自分のやり方で適当な図を描くとする(T61.java)
組み合わせれば stepによって星を描くタートルがあれば円と星のMorphing 手書きの図を覚えるタートルを作り、stepメソッドで再生するようにしておけば、手書き図のMorphing フラクタル図形をstepごとに描くタートルがあればフラクタル図形のMorphing 必要なもの? ―― 共通の親クラス 計算機プログラミングI (増原) 2003年度


Download ppt "計算機プログラミングI 第10回 データ構造とクラスの設計 例題: 話題: 複素数 図形要素 Morphing 複雑な値を一つにまとめる"

Similar presentations


Ads by Google