自己相似形

提供:kuhalaboWiki
(版間での差分)
移動: 案内, 検索
(ドラゴン図形の描画)
(シダ葉の描画)
163行: 163行:
 
[[ファイル:Sida2.JPG]]
 
[[ファイル:Sida2.JPG]]
  
;Taneクラスのメソッド
+
;sida()メソッドの追加
 
+
 
<pre>
 
<pre>
        public void Fern(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
 
        {
 
            double x3, y3, x4, y4, x5, y5;
 
 
            if (n > 0)
 
            {
 
                x3 = ( x1 + x2 ) / 2.0;
 
                y3 = ( y1 + y2 ) / 2.0;
 
                x4 = ( x1 + x3 - y1 + y3) / 2.0;
 
                y4 = ( x1 - x3 + y1 + y3) / 2.0;
 
                x5 = ( x2 + x3 - y2 + y3) / 2.0;
 
                y5 = ( x2 - x3 + y2 + y3) / 2.0;
 
                // 枝を描画する
 
                pen.Color = Color.Green;
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x2, (float)y2);
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x3, (float)y3);
 
                g.DrawLine(pen, (float)x3, (float)y3, (float)x5, (float)y5);
 
                Fern(n - 1, x1, y1, x4, y4, g, pen);
 
                Fern(n - 1, x1, y1, x3, y3, g, pen);
 
                Fern(n - 1, x3, y3, x2, y2, g, pen);
 
                Fern(n - 1, x3, y3, x5, y5, g, pen);
 
            }
 
        }
 
 
</pre>
 
</pre>
  
;シダ葉描画ボタンクリックの中身
+
=== Cカーブの描画 ===
 
+
<pre>
+
            Graphics g = pictureBox1.CreateGraphics();
+
            Pen pen = new Pen(Color.Green, 2);
+
            Tane tane = new Tane();
+
 
+
            int n = 7;  //子の世代数
+
            double x0 = pictureBox1.Width * 0.1; //開始位置 x座標
+
            double y0 = pictureBox1.Height * 0.5; //開始位置 y座標
+
            double x1 = pictureBox1.Width * 0.9; //終了位置 x座標
+
            double y1 = pictureBox1.Height * 0.5; //終了位置 y座標
+
            tane.Fern(n, x0, y0, x1, y1, g, pen);
+
</pre>
+
 
+
==== Cカーブの描画 ====
+
  
 
[[ファイル:Ccurve.jpg]]
 
[[ファイル:Ccurve.jpg]]
 
[[ファイル:Ccurve2.jpg]]
 
[[ファイル:Ccurve2.jpg]]
  
;Taneクラスのメソッド
+
;ccurve()メソッドの追加
 
+
 
<pre>
 
<pre>
        public void Ccurve(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
 
        {
 
            double x3, y3;
 
 
            if (n > 0)
 
            {
 
                x3 = 0.5 * (x1 + x2 - y1 + y2);
 
                y3 = 0.5 * (x1 - x2 + y1 + y2);
 
                // 枝を描画する
 
                pen.Color = Color.Black;
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x2, (float)y2);
 
                pen.Color = Color.Green;
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x3, (float)y3);
 
                g.DrawLine(pen, (float)x3, (float)y3, (float)x2, (float)y2);
 
                Ccurve(n - 1, x1, y1, x3, y3, g, pen);
 
                Ccurve(n - 1, x3, y3, x2, y2, g, pen);
 
            }
 
        }
 
 
</pre>
 
</pre>
  
;Cカーブ画ボタンクリックの中身
+
=== 樹木の描画 ===
 
+
<pre>
+
            Graphics g = pictureBox1.CreateGraphics();
+
            Pen pen = new Pen(Color.Green, 2);
+
            Tane tane = new Tane();
+
 
+
            int n = 12;  //子の世代数
+
            double x0 = pictureBox1.Width * 0.25; //開始位置 x座標
+
            double y0 = pictureBox1.Height * 0.75; //開始位置 y座標
+
            double x1 = pictureBox1.Width * 0.75; //終了位置 x座標
+
            double y1 = pictureBox1.Height * 0.75; //終了位置 y座標
+
            tane.Ccurve(n, x0, y0, x1, y1, g, pen);
+
</pre>
+
 
+
==== 樹木の描画 ====
+
  
 
[[ファイル:Bintree.jpg]]
 
[[ファイル:Bintree.jpg]]
256行: 183行:
 
;Taneクラスのメソッド
 
;Taneクラスのメソッド
 
線分(x1,y1)-(x2,y2)が与えられたら、(x2,y2)の先端に(x3,y3), (x4,y4)を取り、線分(x2,y2)-(x3,y3)と線分(x2,y2)-(x4,y4)を描画する。
 
線分(x1,y1)-(x2,y2)が与えられたら、(x2,y2)の先端に(x3,y3), (x4,y4)を取り、線分(x2,y2)-(x3,y3)と線分(x2,y2)-(x4,y4)を描画する。
<pre>
 
    class Tane
 
    {
 
        public void Eda(int n, double x1, double y1, double x2, double y2, double angle, Graphics g, Pen pen)
 
        {
 
            double x3, y3, x4, y4;
 
            double s = Math.Sin(angle * Math.PI / 180.0);
 
            double c = Math.Cos(angle * Math.PI / 180.0);
 
            double dx = 0.7 * (x2 - x1);
 
            double dy = 0.7 * (y2 - y1);
 
  
            if (n > 0)
 
            {
 
                x3 = x2 + dx * c - dy * s;
 
                y3 = y2 + dx * s + dy * c;
 
                x4 = x2 + dx * c + dy * s;
 
                y4 = y2 - dx * s + dy * c;
 
                // 枝を描画する
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x2, (float)y2);
 
                g.DrawLine(pen, (float)x2, (float)y2, (float)x3, (float)y3);
 
                g.DrawLine(pen, (float)x2, (float)y2, (float)x4, (float)y4);
 
                //子の再起呼び出し
 
                Eda(n - 1, x2, y2, x3, y3, angle, g, pen);
 
                Eda(n - 1, x2, y2, x4, y4, angle, g, pen);
 
            }
 
        }
 
    }
 
</pre>
 
  
;樹木描画ボタンクリックの中身
+
;jumoku()メソッドの追加
 
<pre>
 
<pre>
            Graphics g = pictureBox1.CreateGraphics();
 
            Pen pen = new Pen(Color.Green, 2);
 
            Tane tane = new Tane();
 
 
            int n = 10;  //枝の世代数
 
            double x0 = pictureBox1.Width / 2; //開始位置 x座標
 
            double y0 = pictureBox1.Height; //開始位置 y座標
 
            double x1 = pictureBox1.Width / 2; //開始位置 x座標
 
            double y1 = pictureBox1.Height * 0.8; //開始位置 y座標
 
            double angle = 30.0; //子供の枝の角度の差分
 
            tane.Eda(n, x0, y0, x1, y1, angle, g, pen);
 
</pre>
 
 
==== 内分点と回転によるカスタムジェネレータの描画 ====
 
 
[[ファイル:gene01.JPG]]
 
[[ファイル:gene012.JPG]]
 
 
;Taneクラスのメソッド
 
 
<pre>
 
        public void Gene01(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
 
        {
 
            double x3, y3, x4, y4;
 
            double p = 2.0;
 
            double q = 3.0;
 
            double th = -30.0;
 
            double s = Math.Sin(th * Math.PI / 180.0);
 
            double c = Math.Cos(th * Math.PI / 180.0);
 
 
            if (n > 0)
 
            {
 
                x3 = (q * x1 + p * x2) / (p + q);
 
                y3 = (q * y1 + p * y2) / (p + q);
 
                x4 = x1 + (x3 - x1) * c - (y3 - y1) * s;
 
                y4 = y1 + (x3 - x1) * s + (y3 - y1) * c;
 
                pen.Color = Color.Yellow;
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x2, (float)y2);
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x4, (float)y4);
 
                Gene01(n - 1, x1, y1, x3, y3, g, pen);
 
                Gene01(n - 1, x1, y1, x4, y4, g, pen);
 
                Gene01(n - 1, x3, y3, x2, y2, g, pen);
 
            }
 
        }
 
</pre>
 
 
;カスタムジェネレータ描画ボタンクリックの中身
 
 
<pre>
 
            Graphics g = pictureBox1.CreateGraphics();
 
            Pen pen = new Pen(Color.Green, 2);
 
            Tane tane = new Tane();
 
 
            int n = 7;  //子の世代数
 
            double x0 = pictureBox1.Width * 0.1; //開始位置 x座標
 
            double y0 = pictureBox1.Height * 0.5; //開始位置 y座標
 
            double x1 = pictureBox1.Width * 0.9; //終了位置 x座標
 
            double y1 = pictureBox1.Height * 0.5; //終了位置 y座標
 
            tane.Gene01(n, x0, y0, x1, y1, g, pen);
 
</pre>
 
 
;マウスドラッグで始点と終点を決めて描く
 
*プロパティウィンドウにイベント(稲妻のアイコン)のリストを表示させ、MouseDownイベントをダブルクリックすると、MouseDownのメソッドが自動生成されます。
 
*label1,label2に始点の座標を、label3, label4に終点の座標を入れる
 
 
<pre>
 
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
 
        {
 
            label1.Text = e.X.ToString();
 
            label2.Text = e.Y.ToString();
 
 
        }
 
 
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
 
        {
 
            Graphics g = pictureBox1.CreateGraphics();
 
            Pen pen = new Pen(Color.Green, 2);
 
            Tane tane = new Tane();
 
 
            int n = 7;
 
            double x0 = double.Parse(label1.Text);
 
            double y0 = double.Parse(label2.Text);
 
            double x1 = double.Parse(label3.Text);
 
            double y1 = double.Parse(label4.Text);
 
 
            tane.Gene01(n, x0, y0, x1, y1, g, pen);
 
        }
 
 
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
 
        {
 
            label3.Text = e.X.ToString();
 
            label4.Text = e.Y.ToString();
 
 
        }
 
</pre>
 
 
p,q,thをクラスのメンバー変数にして、外部からランダムに与える。
 
 
<pre>
 
    class Tane
 
    {
 
        public double p { get; set; }
 
        public double q { get; set; }
 
        public double th { get; set; }
 
 
        public void Gene01(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
 
        {
 
            double x3, y3, x4, y4;
 
            double s = Math.Sin(th * Math.PI / 180.0);
 
            double c = Math.Cos(th * Math.PI / 180.0);
 
 
            if (n > 0)
 
            {
 
                x3 = (q * x1 + p * x2) / (p + q);
 
                y3 = (q * y1 + p * y2) / (p + q);
 
                x4 = x1 + (x3 - x1) * c - (y3 - y1) * s;
 
                y4 = y1 + (x3 - x1) * s + (y3 - y1) * c;
 
                pen.Color = Color.Yellow;
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x2, (float)y2);
 
                g.DrawLine(pen, (float)x1, (float)y1, (float)x4, (float)y4);
 
                Gene01(n - 1, x1, y1, x3, y3, g, pen);
 
                Gene01(n - 1, x1, y1, x4, y4, g, pen);
 
                Gene01(n - 1, x3, y3, x2, y2, g, pen);
 
            }
 
        }
 
 
    }
 
 
</pre>
 
 
<pre>
 
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
 
        {
 
            Graphics g = pictureBox1.CreateGraphics();
 
            Pen pen = new Pen(Color.Green, 2);
 
            Tane tane = new Tane();
 
            Random rnd = new Random();
 
 
            int n = 7;
 
            double x0 = double.Parse(label1.Text);
 
            double y0 = double.Parse(label2.Text);
 
            double x1 = double.Parse(label3.Text);
 
            double y1 = double.Parse(label4.Text);
 
 
            tane.p = rnd.Next(2, 6);
 
            tane.q = rnd.Next(3, 7);
 
            tane.th = rnd.Next(10, 90);
 
 
            tane.Gene01(n, x0, y0, x1, y1, g, pen);
 
        }
 
 
</pre>
 
 
 
 
==== タイマーを使用した樹木のアニメーション ====
 
 
<pre>
 
        private void button3_Click(object sender, EventArgs e)
 
        {
 
            timer1.Enabled = true;
 
            timer1.Start();
 
        }
 
 
        private void button4_Click(object sender, EventArgs e)
 
        {
 
            timer1.Stop();
 
            timer1.Enabled = false;
 
        }
 
 
 
        public int cnt; //タイマー用カウンタ
 
        private void timer1_Tick(object sender, EventArgs e)
 
        {
 
            Graphics g = pictureBox1.CreateGraphics();
 
            Pen pen = new Pen(Color.Green, 1);
 
            Tane tane = new Tane();
 
 
            g.Clear(Color.Black);
 
 
            cnt++;  //タイマー用カウンタのカウントアップ
 
            int n = 10;  //枝の世代数
 
            double x0 = pictureBox1.Width / 2; //開始位置 x座標
 
            double y0 = pictureBox1.Height; //開始位置 y座標
 
            double x1 = pictureBox1.Width / 2; //開始位置 x座標
 
            double y1 = pictureBox1.Height * 0.9 - cnt * 2; //開始位置 y座標
 
            double angle = 30.0; //子供の枝の角度の変化の差分
 
            double a_rate = angle + cnt * 2;
 
            tane.Eda(n, x0, y0, x1, y1, a_rate, g, pen);
 
        }
 
 
</pre>
 
</pre>

2014年12月2日 (火) 06:54時点における版

目次

再帰的呼出しによる樹木の描画

  • 再帰的( recursive )呼び出しとは,サブルーチンや関数が,自分自身を呼び出すことをいう。樹木は,枝の1つを取り出して拡大しても,元の枝と同じ形(相似形)をしている。これは,同じサブルーチンで枝を描画しているからである。
  • 再帰的呼出し的なCollaborate Flash Animation:zoomquilt (swf)
  • 例:実行ファイル,ソース,Taneクラス

コッホ図形の描画

Koch.jpg Koch2.jpg

Recursクラスの作成
  • Recurs.h
#pragma once
#include "ofMain.h"
#include <math.h> //算術関数の読み込み

class Recurs {
public:
	ofColor bcolor;  //描画色
	int generation;  // 世代

	void koch(int n, ofPoint p1, ofPoint p2); //再帰的呼び出しメソッド
};
  • Recurs.cpp
#include "Recurs.h"

void Recurs::koch(int n, ofPoint p1, ofPoint p2){
	ofPoint p3,p4,p5;
	double s = sin( PI / 3.0); // sin(60)
	double c = cos( PI / 3.0); // cos(60)

	if( n > 0 ){
		p3 = ( 2 * p1 + p2 ) / 3.0; //内分点
		p4 = ( p1 + 2 * p2 ) / 3.0;
		p5.x = p3.x + ( p4.x - p3.x ) * c + (p4.y - p3.y) * s; //回転移動
		p5.y = p3.y - ( p4.x - p3.x ) * s + (p4.y - p3.y) * c;
		ofSetColor(0,0,0);
		ofLine(p3,p4); //余分な線を消す
		ofSetColor(bcolor);
		ofLine(p1,p3); //線分の描画
		ofLine(p3,p5);
		ofLine(p5,p4);
		ofLine(p4,p2);

		koch( n-1, p1, p3); //再帰呼び出し n>0
		koch( n-1, p3, p5);
		koch( n-1, p5, p4);
		koch( n-1, p4, p2);
	}
}
  • ofApp.h
#pragma once

#include "ofMain.h"
#include "Recurs.h"

class ofApp : public ofBaseApp{

	public:
		void setup();
		void update();
		void draw();

		void keyPressed(int key);
		void keyReleased(int key);
		void mouseMoved(int x, int y );
		void mouseDragged(int x, int y, int button);
		void mousePressed(int x, int y, int button);
		void mouseReleased(int x, int y, int button);
		void windowResized(int w, int h);
		void dragEvent(ofDragInfo dragInfo);
		void gotMessage(ofMessage msg);

		Recurs myKoch;
		ofPoint pos1;
		ofPoint pos2;
		
};
  • ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){

	ofBackground(0, 0, 0); //背景色の設定
	ofSetFrameRate(30); //フレームレイト設定
	pos1 = ofPoint(ofGetWidth()*1/4, ofGetHeight()*2/4);//初期点の設定
	pos2 = ofPoint(ofGetWidth()*3/4, ofGetHeight()*2/4);
	myKoch.generation = 5; //世代の設定
	myKoch.bcolor = ofColor(0,255,0); //描画色の設定
}

//--------------------------------------------------------------
void ofApp::update(){
}

//--------------------------------------------------------------
void ofApp::draw(){
	myKoch.koch(myKoch.generation, pos1, pos2);
}
  • update()で動かしてみる
//--------------------------------------------------------------
void ofApp::update(){
//	pos1 = pos1 + (1,1);
//	pos2 = pos2 + (-1,-1);
}


ドラゴン図形の描画

Dragon.jpg Dragon2.jpg

dragon()メソッドの追加
void Recurs::dragon(int n, ofPoint p1, ofPoint p2){
	ofPoint p3,p4,p5;

	if( n > 0 ){
		p3 = ( p1 + p2 ) / 2.0; //内分点
		p4.x = ( p1.x + p3.x - p1.y + p3.y ) / 2.0;
		p4.y = ( p1.x - p3.x + p1.y + p3.y ) / 2.0;
		p5.x = ( p2.x + p3.x - p2.y + p3.y ) / 2.0;
		p5.y = ( p2.x - p3.x + p2.y + p3.y ) / 2.0;
		ofSetColor(0,0,0);
		ofLine(p1,p3); //余分な線を消す
		ofLine(p3,p2); //余分な線を消す
		ofSetColor(bcolor);
		ofLine(p1,p4); //線分の描画
		ofLine(p4,p3);
		ofLine(p3,p5);
		ofLine(p5,p2);

		dragon( n-1, p1, p4); //再帰呼び出し n>0
		dragon( n-1, p4, p3); //再帰呼び出し n>0
		dragon( n-1, p3, p5); //再帰呼び出し n>0
		dragon( n-1, p5, p2); //再帰呼び出し n>0
	}
}

シダ葉の描画

ドラゴン図形の変化形
  • ドラゴン図形で使用した(x1,y1), (x2,y2), (x3,y3), (x4,y4), (x5,y5)を使う
  • 直線(x1,y1)-(x2,y2), 直線(x1,y1)-(x4,y4), 直線(x3,y3)-(x5,y5)を基本図形とする。

Sida2.JPG

sida()メソッドの追加

Cカーブの描画

Ccurve.jpg Ccurve2.jpg

ccurve()メソッドの追加

樹木の描画

Bintree.jpg Bintree2.JPG

Taneクラスのメソッド

線分(x1,y1)-(x2,y2)が与えられたら、(x2,y2)の先端に(x3,y3), (x4,y4)を取り、線分(x2,y2)-(x3,y3)と線分(x2,y2)-(x4,y4)を描画する。


jumoku()メソッドの追加



個人用ツール
名前空間

変種
操作
案内
ツールボックス