自己相似形

提供:kuhalaboWiki
(版間での差分)
移動: 案内, 検索
(openFrameworksによる実装)
 
(1人の利用者による、間の29版が非表示)
1行: 1行:
 +
== openFrameworksのサンプル ==
 +
 
=== 再帰的呼出しによる樹木の描画 ===
 
=== 再帰的呼出しによる樹木の描画 ===
 
*'''再帰的( recursive )呼び出し'''とは,サブルーチンや関数が,自分自身を呼び出すことをいう。樹木は,枝の1つを取り出して拡大しても,元の枝と同じ形(相似形)をしている。これは,同じサブルーチンで枝を描画しているからである。
 
*'''再帰的( recursive )呼び出し'''とは,サブルーチンや関数が,自分自身を呼び出すことをいう。樹木は,枝の1つを取り出して拡大しても,元の枝と同じ形(相似形)をしている。これは,同じサブルーチンで枝を描画しているからである。
5行: 7行:
 
*例:実行ファイル,ソース,Taneクラス  
 
*例:実行ファイル,ソース,Taneクラス  
  
=== openFrameworksによる実装 ===
+
=== コッホ図形の描画 ===
==== コッホ図形の描画 ====
+
  
 
[[ファイル:Koch.jpg]]
 
[[ファイル:Koch.jpg]]
 
[[ファイル:Koch2.jpg]]
 
[[ファイル:Koch2.jpg]]
  
;Kochクラスの作成
+
;Recursクラスの作成
 
+
* Recurs.h
* Koch.h
+
 
<pre>
 
<pre>
 
#pragma once
 
#pragma once
 
#include "ofMain.h"
 
#include "ofMain.h"
#include <math.h>
+
#include <math.h> //算術関数の読み込み
  
class Koch {
+
class Recurs {
 
public:
 
public:
ofColor bcolor;
+
ofColor bcolor; //描画色
 
int generation;  // 世代
 
int generation;  // 世代
  
void recurse(int n, ofPoint p1, ofPoint p2);
+
void koch(int n, ofPoint p1, ofPoint p2); //再帰的呼び出しメソッド
 
};
 
};
 
</pre>
 
</pre>
  
* Koch.cpp
+
* Recurs.cpp
 
<pre>
 
<pre>
#include "Koch.h"
+
#include "Recurs.h"
  
void Koch::recurse(int n, ofPoint p1, ofPoint p2){
+
//三角関数の値をstaticグローバル定数として定義
 +
static const double S60 = sin( PI / 3.0); // sin(60)
 +
static const double C60 = cos( PI / 3.0); // cos(60)
 +
 
 +
void Recurs::koch(int n, ofPoint p1, ofPoint p2){
 
ofPoint p3,p4,p5;
 
ofPoint p3,p4,p5;
double s = sin( PI / 3.0);
 
double c = cos( PI / 3.0);
 
  
 
if( n > 0 ){
 
if( n > 0 ){
p3 = ( 2 * p1 + p2 ) / 3.0;
+
p3 = ( 2 * p1 + p2 ) / 3.0; //内分点
 
p4 = ( p1 + 2 * p2 ) / 3.0;
 
p4 = ( p1 + 2 * p2 ) / 3.0;
p5.x = p3.x + ( p4.x - p3.x ) * c + (p4.y - p3.y) * s;
+
p5.x = p3.x + ( p4.x - p3.x ) * C60 + (p4.y - p3.y) * S60; //回転移動
p5.y = p3.y - ( p4.x - p3.x ) * s + (p4.y - p3.y) * c;
+
p5.y = p3.y - ( p4.x - p3.x ) * S60 + (p4.y - p3.y) * C60;
 
ofSetColor(0,0,0);
 
ofSetColor(0,0,0);
ofLine(p3,p4);
+
ofLine(p3,p4); //余分な線を消す
 
ofSetColor(bcolor);
 
ofSetColor(bcolor);
ofLine(p1,p3);
+
ofLine(p1,p3); //線分の描画
 
ofLine(p3,p5);
 
ofLine(p3,p5);
 
ofLine(p5,p4);
 
ofLine(p5,p4);
 
ofLine(p4,p2);
 
ofLine(p4,p2);
  
recurse( n-1, p1, p3);
+
koch( n-1, p1, p3); //再帰呼び出し n>0
recurse( n-1, p3, p5);
+
koch( n-1, p3, p5);
recurse( n-1, p5, p4);
+
koch( n-1, p5, p4);
recurse( n-1, p4, p2);
+
koch( n-1, p4, p2);
 
}
 
}
 
}
 
}
 
</pre>
 
</pre>
  
 
+
* ofApp.h
;コッホ図形描画ボタンクリックの中身
+
 
+
<pre>
+
            Graphics g = pictureBox1.CreateGraphics();
+
            Pen pen = new Pen(Color.Green, 2);
+
            Tane tane = new Tane();
+
 
+
            // マウス位置へ直線を描画する
+
            int n = 4;  //子の世代数
+
            double x0 = 0; //開始位置 x座標
+
            double y0 = pictureBox1.Height * 0.6 ; //開始位置 y座標
+
            double x1 = pictureBox1.Width; //終了位置 x座標
+
            double y1 = pictureBox1.Height * 0.6; //終了位置 y座標
+
            tane.Koch(n, x0, y0, x1, y1, g, pen);
+
</pre>
+
* Koch.h
+
 
<pre>
 
<pre>
 
#pragma once
 
#pragma once
 +
 
#include "ofMain.h"
 
#include "ofMain.h"
#include <math.h>
+
#include "Recurs.h"
  
class Koch {
+
class ofApp : public ofBaseApp{
public:
+
 
ofColor bcolor;
+
public:
int generation; // 世代
+
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);
  
void recurse(int n, ofPoint p1, ofPoint p2);
+
Recurs myKoch;
 +
ofPoint pos1;
 +
ofPoint pos2;
 +
 
};
 
};
 
</pre>
 
</pre>
  
;コッホ図形描画ボタンクリックの中身
+
* ofApp.cpp
 
+
 
<pre>
 
<pre>
            Graphics g = pictureBox1.CreateGraphics();
+
#include "ofApp.h"
            Pen pen = new Pen(Color.Green, 2);
+
            Tane tane = new Tane();
+
  
            // マウス位置へ直線を描画する
+
//--------------------------------------------------------------
            int n = 4;  //子の世代数
+
void ofApp::setup(){
            double x0 = 0; //開始位置 x座標
+
            double y0 = pictureBox1.Height * 0.6 ; //開始位置 y座標
+
            double x1 = pictureBox1.Width; //終了位置 x座標
+
            double y1 = pictureBox1.Height * 0.6; //終了位置 y座標
+
            tane.Koch(n, x0, y0, x1, y1, g, pen);
+
</pre>
+
  
==== ドラゴン図形の描画 ====
+
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); //描画色の設定
 +
}
  
[[ファイル:Dragon.jpg]]
+
//--------------------------------------------------------------
[[ファイル:Dragon2.jpg]]
+
void ofApp::update(){
 +
}
  
;Taneクラスのメソッド
+
//--------------------------------------------------------------
 +
void ofApp::draw(){
 +
myKoch.koch(myKoch.generation, pos1, pos2);
 +
}
 +
</pre>
  
 +
=== 動かしてみる ===
 +
* Recurs.h
 +
** 現在位置と速度のプロパティを追加
 +
** 現在位置と速度を更新するupdate()メソッドの追加
 
<pre>
 
<pre>
        public void Dragon(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
+
class Recurs {
        {
+
public:
            double x3, y3, x4, y4, x5, y5;
+
ofColor bcolor;  //描画色
 +
int generation;  // 世代
 +
//ここから追加
 +
ofPoint pos1; //初期位置
 +
ofPoint pos2;
 +
ofPoint vel1; //初期速度
 +
ofPoint vel2;
 +
//ここまで追加
  
            if (n > 0)
+
Recurs();
            {
+
void update(); // 追加分
                x3 = 0.5 * ( x1 + x2);
+
void koch(int n, ofPoint p1, ofPoint p2); //再帰的呼び出しメソッド
                y3 = 0.5 * ( y1 + y2);
+
};
                x4 = 0.5 * (x1 + x3 - y1 + y3);
+
                y4 = 0.5 * (x1 - x3 + y1 + y3);
+
                x5 = 0.5 * (x2 + x3 - y2 + y3);
+
                y5 = 0.5 * (x2 - x3 + y2 + y3);
+
 
+
                // 枝を描画する
+
                pen.Color = Color.Black;
+
                g.DrawLine(pen, (float)x1, (float)y1, (float)x3, (float)y3);
+
                g.DrawLine(pen, (float)x3, (float)y3, (float)x2, (float)y2);
+
                pen.Color = Color.Green;
+
                g.DrawLine(pen, (float)x1, (float)y1, (float)x4, (float)y4);
+
                g.DrawLine(pen, (float)x4, (float)y4, (float)x3, (float)y3);
+
                g.DrawLine(pen, (float)x3, (float)y3, (float)x5, (float)y5);
+
                g.DrawLine(pen, (float)x5, (float)y5, (float)x2, (float)y2);
+
                Dragon(n - 1, x1, y1, x4, y4, g, pen);
+
                Dragon(n - 1, x4, y4, x3, y3, g, pen);
+
                Dragon(n - 1, x3, y3, x5, y5, g, pen);
+
                Dragon(n - 1, x5, y5, x2, y2, g, pen);
+
            }
+
        }
+
 
</pre>
 
</pre>
  
;ドラゴン図形描画ボタンクリックの中身
+
* Recurs.cpp
 
+
** Recurs()で初期の位置と速度を設定
 +
** update()で位置と速度を更新
 
<pre>
 
<pre>
            Graphics g = pictureBox1.CreateGraphics();
+
#include "Recurs.h"
            Pen pen = new Pen(Color.Green, 2);
+
            Tane tane = new Tane();
+
  
            int n = 7;  //子の世代数
+
//三角関数の値をstaticグローバル定数として定義
            double x0 = pictureBox1.Width * 0.1; //開始位置 x座標
+
static const double S60 = sin( PI / 3.0); // sin(60)
            double y0 = pictureBox1.Height * 0.5; //開始位置 y座標
+
static const double C60 = cos( PI / 3.0); // cos(60)
            double x1 = pictureBox1.Width * 0.9; //終了位置 x座標
+
            double y1 = pictureBox1.Height * 0.5; //終了位置 y座標
+
            tane.Dragon(n, x0, y0, x1, y1, g, pen);
+
  
</pre>
+
Recurs::Recurs(){
 +
pos1 = ofPoint(ofGetWidth()*1/4, ofGetHeight()*2/4);
 +
vel1 = ofPoint(ofRandom(-5,5),ofRandom(-3,3));
 +
pos2 = ofPoint(ofGetWidth()*3/4, ofGetHeight()*2/4);
 +
vel2 = ofPoint(ofRandom(-5,5),ofRandom(-3,3));
 +
generation = 7; //世代の設定
 +
bcolor = ofColor(0,255,0); //描画色の設定
 +
}
  
==== シダ葉の描画 ====
+
void Recurs::update(){
;ドラゴン図形の変化形
+
pos1 += vel1;
* ドラゴン図形で使用した(x1,y1), (x2,y2), (x3,y3), (x4,y4), (x5,y5)を使う
+
pos2 += vel2;
* 直線(x1,y1)-(x2,y2), 直線(x1,y1)-(x4,y4),  直線(x3,y3)-(x5,y5)を基本図形とする。
+
if(pos1.x > ofGetWidth() || pos1.x < 0){
 +
vel1.x *= -1;
 +
}
 +
if(pos1.y > ofGetHeight() || pos1.y < 0){
 +
vel1.y *= -1;
 +
}
 +
if(pos2.x > ofGetWidth() || pos2.x < 0){
 +
vel2.x *= -1;
 +
}
 +
if(pos2.y > ofGetHeight() || pos2.y < 0){
 +
vel2.y *= -1;
 +
}
 +
}
  
[[ファイル:Sida2.JPG]]
+
void Recurs::koch(int n, ofPoint p1, ofPoint p2){
 +
ofPoint p3,p4,p5;
  
;Taneクラスのメソッド
+
if( n > 0 ){
 +
p3 = ( 2 * p1 + p2 ) / 3.0; //内分点
 +
p4 = ( p1 + 2 * p2 ) / 3.0;
 +
p5.x = p3.x + ( p4.x - p3.x ) * C60 + (p4.y - p3.y) * S60; //回転移動
 +
p5.y = p3.y - ( p4.x - p3.x ) * S60 + (p4.y - p3.y) * C60;
 +
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);
 +
}
 +
}
 +
</pre>
  
 +
* ofApp.cpp
 +
** update()でmyKoch.update()を呼び出し、位置、速度を更新
 
<pre>
 
<pre>
        public void Fern(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
+
#include "ofApp.h"
        {
+
            double x3, y3, x4, y4, x5, y5;
+
  
            if (n > 0)
+
//--------------------------------------------------------------
            {
+
void ofApp::setup(){
                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>
+
  
;シダ葉描画ボタンクリックの中身
+
ofBackground(0, 0, 0); //背景色の設定
 +
ofSetFrameRate(30); //フレームレイト設定
 +
}
  
<pre>
+
//--------------------------------------------------------------
            Graphics g = pictureBox1.CreateGraphics();
+
void ofApp::update(){
            Pen pen = new Pen(Color.Green, 2);
+
myKoch.update();
            Tane tane = new Tane();
+
}
 +
 
 +
//--------------------------------------------------------------
 +
void ofApp::draw(){
 +
myKoch.koch(myKoch.generation, myKoch.pos1, myKoch.pos2);
 +
}
  
            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>
 
</pre>
  
==== Cカーブの描画 ====
+
=== 複数個の図形を配置 ===
 +
* ofApp.h
 +
** myKochとmyKoch2を作る
 +
<pre>
 +
#include "ofMain.h"
 +
#include "Recurs.h"
  
[[ファイル:Ccurve.jpg]]
+
class ofApp : public ofBaseApp{
[[ファイル:Ccurve2.jpg]]
+
  
;Taneクラスのメソッド
+
public:
 +
void setup();
 +
void update();
 +
void draw();
  
<pre>
+
void keyPressed(int key);
        public void Ccurve(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
+
void keyReleased(int key);
        {
+
void mouseMoved(int x, int y );
            double x3, y3;
+
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);
  
            if (n > 0)
+
Recurs myKoch;
            {
+
Recurs myKoch2;
                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カーブ画ボタンクリックの中身
+
* ofApp.cpp
 
+
** update()で位置と速度を更新
 +
** myKoch2はmyKochとミラー配置
 
<pre>
 
<pre>
            Graphics g = pictureBox1.CreateGraphics();
+
//--------------------------------------------------------------
            Pen pen = new Pen(Color.Green, 2);
+
void ofApp::update(){
            Tane tane = new Tane();
+
myKoch.update();
 +
myKoch2.pos1 = myKoch.pos2;
 +
myKoch2.pos2 = myKoch.pos1;
 +
}
  
            int n = 12;  //子の世代数
+
//--------------------------------------------------------------
            double x0 = pictureBox1.Width * 0.25; //開始位置 x座標
+
void ofApp::draw(){
            double y0 = pictureBox1.Height * 0.75; //開始位置 y座標
+
myKoch.koch(myKoch.generation, myKoch.pos1, myKoch.pos2);
            double x1 = pictureBox1.Width * 0.75; //終了位置 x座標
+
myKoch2.koch(myKoch2.generation, myKoch2.pos1, myKoch2.pos2);
            double y1 = pictureBox1.Height * 0.75; //終了位置 y座標
+
}
            tane.Ccurve(n, x0, y0, x1, y1, g, pen);
+
 
</pre>
 
</pre>
  
==== 樹木の描画 ====
+
=== ドラゴン図形の描画 ===
  
[[ファイル:Bintree.jpg]]
+
[[ファイル:Dragon.jpg]]
[[ファイル:Bintree2.JPG]]
+
[[ファイル:Dragon2.jpg]]
 +
 
 +
;dragon()メソッドの追加
 +
Recurs.cppに以下のメソッドを追加する。
  
;Taneクラスのメソッド
 
線分(x1,y1)-(x2,y2)が与えられたら、(x2,y2)の先端に(x3,y3), (x4,y4)を取り、線分(x2,y2)-(x3,y3)と線分(x2,y2)-(x4,y4)を描画する。
 
 
<pre>
 
<pre>
    class Tane
+
void Recurs::dragon(int n, ofPoint p1, ofPoint p2){
    {
+
ofPoint p3,p4,p5;
        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)
+
if( n > 0 ){
            {
+
p3 = ( p1 + p2 ) / 2.0; //内分点
                x3 = x2 + dx * c - dy * s;
+
p4.x = ( p1.x + p3.x - p1.y + p3.y ) / 2.0;
                y3 = y2 + dx * s + dy * c;
+
p4.y = ( p1.x - p3.x + p1.y + p3.y ) / 2.0;
                x4 = x2 + dx * c + dy * s;
+
p5.x = ( p2.x + p3.x - p2.y + p3.y ) / 2.0;
                y4 = y2 - dx * s + dy * c;
+
p5.y = ( p2.x - p3.x + p2.y + p3.y ) / 2.0;
                // 枝を描画する
+
ofSetColor(0,0,0);
                g.DrawLine(pen, (float)x1, (float)y1, (float)x2, (float)y2);
+
ofLine(p1,p3); //余分な線を消す
                g.DrawLine(pen, (float)x2, (float)y2, (float)x3, (float)y3);
+
ofLine(p3,p2); //余分な線を消す
                g.DrawLine(pen, (float)x2, (float)y2, (float)x4, (float)y4);
+
ofSetColor(bcolor);
                //子の再起呼び出し
+
ofLine(p1,p4); //線分の描画
                Eda(n - 1, x2, y2, x3, y3, angle, g, pen);
+
ofLine(p4,p3);
                Eda(n - 1, x2, y2, x4, y4, angle, g, pen);
+
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
 +
}
 +
}
 
</pre>
 
</pre>
  
;樹木描画ボタンクリックの中身
+
=== シダ葉の描画 ===
 +
;ドラゴン図形の変化形
 +
* ドラゴン図形で使用した(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()メソッドの追加
 
<pre>
 
<pre>
            Graphics g = pictureBox1.CreateGraphics();
+
void Recurs::shida(int n, ofPoint p1, ofPoint p2){
            Pen pen = new Pen(Color.Green, 2);
+
ofPoint p3,p4,p5;
            Tane tane = new Tane();
+
  
            int n = 10; //枝の世代数
+
if( n > 0 ){
            double x0 = pictureBox1.Width / 2; //開始位置 x座標
+
p3 = ( p1 + p2 ) / 2.0; //内分点
            double y0 = pictureBox1.Height; //開始位置 y座標
+
p4.x = ( p1.x + p3.x - p1.y + p3.y ) / 2.0;
            double x1 = pictureBox1.Width / 2; //開始位置 x座標
+
p4.y = ( p1.x - p3.x + p1.y + p3.y ) / 2.0;
            double y1 = pictureBox1.Height * 0.8; //開始位置 y座標
+
p5.x = ( p2.x + p3.x - p2.y + p3.y ) / 2.0;
            double angle = 30.0; //子供の枝の角度の差分
+
p5.y = ( p2.x - p3.x + p2.y + p3.y ) / 2.0;
            tane.Eda(n, x0, y0, x1, y1, angle, g, pen);
+
ofSetColor(0,0,0);
 +
ofLine(p4,p5); //余分な線を消す
 +
ofSetColor(bcolor);
 +
ofLine(p1,p2); //線分の描画
 +
ofLine(p1,p4);
 +
ofLine(p3,p5);
 +
 
 +
shida( n-1, p1, p3); //再帰呼び出し n>0
 +
shida( n-1, p3, p2); //再帰呼び出し n>0
 +
shida( n-1, p1, p4); //再帰呼び出し n>0
 +
shida( n-1, p3, p5); //再帰呼び出し n>0
 +
}
 +
}
 
</pre>
 
</pre>
  
==== 内分点と回転によるカスタムジェネレータの描画 ====
+
=== Cカーブの描画 ===
  
[[ファイル:gene01.JPG]]
+
[[ファイル:Ccurve.jpg]]
[[ファイル:gene012.JPG]]
+
[[ファイル:Ccurve2.jpg]]
 
+
;Taneクラスのメソッド
+
  
 +
;ccurve()メソッドの追加
 
<pre>
 
<pre>
        public void Gene01(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
+
void Recurs::ccurve(int n, ofPoint p1, ofPoint p2){
        {
+
ofPoint p3;
            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)
+
if( n > 0 ){
            {
+
p3.x = ( p1.x + p2.x - p1.y + p2.y ) / 2.0;
                x3 = (q * x1 + p * x2) / (p + q);
+
p3.y = ( p1.x - p2.x + p1.y + p2.y ) / 2.0;
                y3 = (q * y1 + p * y2) / (p + q);
+
ofSetColor(0,0,0);
                x4 = x1 + (x3 - x1) * c - (y3 - y1) * s;
+
ofLine(p1,p2); //余分な線を消す
                y4 = y1 + (x3 - x1) * s + (y3 - y1) * c;
+
ofSetColor(bcolor);
                pen.Color = Color.Yellow;
+
ofLine(p1,p3); //線分の描画
                g.DrawLine(pen, (float)x1, (float)y1, (float)x2, (float)y2);
+
ofLine(p3,p2);
                g.DrawLine(pen, (float)x1, (float)y1, (float)x4, (float)y4);
+
 
                Gene01(n - 1, x1, y1, x3, y3, g, pen);
+
ccurve( n-1, p1, p3); //再帰呼び出し n>0
                Gene01(n - 1, x1, y1, x4, y4, g, pen);
+
ccurve( n-1, p3, p2); //再帰呼び出し n>0
                Gene01(n - 1, x3, y3, x2, y2, g, pen);
+
}
            }
+
}
        }
+
 
</pre>
 
</pre>
  
;カスタムジェネレータ描画ボタンクリックの中身
+
=== 樹木の描画 ===
  
<pre>
+
[[ファイル:Bintree.jpg]]
            Graphics g = pictureBox1.CreateGraphics();
+
[[ファイル:Bintree2.JPG]]
            Pen pen = new Pen(Color.Green, 2);
+
            Tane tane = new Tane();
+
  
            int n = 7;  //子の世代数
+
線分(x1,y1)-(x2,y2)が与えられたら、(x2,y2)の先端に(x3,y3), (x4,y4)を取り、線分(x2,y2)-(x3,y3)と線分(x2,y2)-(x4,y4)を描画する。
            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に終点の座標を入れる
 
  
 +
* Recurs.cppにjumoku()メソッドを追加
 
<pre>
 
<pre>
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
+
void Recurs::jumoku(int n, ofPoint p1, ofPoint p2){
        {
+
double s = sin( theta * PI / 180.0); // sin(theta)
            label1.Text = e.X.ToString();
+
double c = cos( theta * PI / 180.0); // cos(theta)
            label2.Text = e.Y.ToString();
+
  
        }
+
ofPoint p3,p4,dp;
  
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
+
dp = 0.7 * (p2 - p1); // 枝の収縮率を0.7とする
        {
+
            Graphics g = pictureBox1.CreateGraphics();
+
            Pen pen = new Pen(Color.Green, 2);
+
            Tane tane = new Tane();
+
  
            int n = 7;
+
if( n > 0 ){
            double x0 = double.Parse(label1.Text);
+
p3.x = p2.x + c * dp.x - s * dp.y;
            double y0 = double.Parse(label2.Text);
+
p3.y = p2.y + s * dp.x + c * dp.y;
            double x1 = double.Parse(label3.Text);
+
p4.x = p2.x + c * dp.x + s * dp.y;
            double y1 = double.Parse(label4.Text);
+
p4.y = p2.y - s * dp.x + c * dp.y;
  
            tane.Gene01(n, x0, y0, x1, y1, g, pen);
+
ofSetColor(bcolor);
        }
+
ofLine(p1,p2); //線分の描画
 
+
ofLine(p2,p3);
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
+
ofLine(p2,p4);
        {
+
            label3.Text = e.X.ToString();
+
            label4.Text = e.Y.ToString();
+
  
        }
+
jumoku( n-1, p2, p3); //再帰呼び出し n>0
 +
jumoku( n-1, p2, p4); //再帰呼び出し n>0
 +
}
 +
}
 
</pre>
 
</pre>
  
p,q,thをクラスのメンバー変数にして、外部からランダムに与える。
+
=== 内分点と回転によるカスタムジェネレータの描画 ===
  
<pre>
+
[[ファイル:gene01.JPG]]
    class Tane
+
[[ファイル:gene012.JPG]]
    {
+
        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)
+
* Recurs.hにtheta, p, q, gene()を追加する。
        {
+
<pre>
            double x3, y3, x4, y4;
+
class Recurs {
            double s = Math.Sin(th * Math.PI / 180.0);
+
public:
            double c = Math.Cos(th * Math.PI / 180.0);
+
ofColor bcolor;  //描画色
 
+
int generation; // 世代
            if (n > 0)
+
ofPoint pos1;
            {
+
ofPoint pos2;
                x3 = (q * x1 + p * x2) / (p + q);
+
ofPoint vel1;
                y3 = (q * y1 + p * y2) / (p + q);
+
ofPoint vel2;
                x4 = x1 + (x3 - x1) * c - (y3 - y1) * s;
+
double theta; //樹木の枝の広がりの角度
                y4 = y1 + (x3 - x1) * s + (y3 - y1) * c;
+
double p; //内分点の比
                pen.Color = Color.Yellow;
+
double q; //内分点の比
                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);
+
            }
+
        }
+
 
+
    }
+
  
 +
void gene(int n, ofPoint p1, ofPoint p2); //再帰的呼び出しメソッド カスタム
 
</pre>
 
</pre>
  
 +
* Recurs.cppにgene()を追加する。
 
<pre>
 
<pre>
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
+
Recurs::Recurs(){
        {
+
            Graphics g = pictureBox1.CreateGraphics();
+
            Pen pen = new Pen(Color.Green, 2);
+
            Tane tane = new Tane();
+
            Random rnd = new Random();
+
  
            int n = 7;
+
theta = 30;
            double x0 = double.Parse(label1.Text);
+
p = 2.0;
            double y0 = double.Parse(label2.Text);
+
q = 3.0;
            double x1 = double.Parse(label3.Text);
+
}
            double y1 = double.Parse(label4.Text);
+
  
            tane.p = rnd.Next(2, 6);
+
void Recurs::gene(int n, ofPoint p1, ofPoint p2){
            tane.q = rnd.Next(3, 7);
+
ofPoint p3,p4,dp;
            tane.th = rnd.Next(10, 90);
+
  
            tane.Gene01(n, x0, y0, x1, y1, g, pen);
+
double s = sin( theta * PI / 180.0); // sin(theta)
        }
+
double c = cos( theta * PI / 180.0); // cos(theta)
  
</pre>
+
if( n > 0 ){
 +
p3 = ( q * p1 + p * p2 ) / ( p + q ); //内分点
 +
dp = p3 - p1;
 +
p4.x = p1.x + c * dp.x - s * dp.y;
 +
p4.y = p1.y + s * dp.x + c * dp.y;
  
 +
ofSetColor(bcolor);
 +
ofLine(p1,p2); //線分の描画
  
 +
gene( n-1, p1, p3); //再帰呼び出し n>0
 +
gene( n-1, p1, p4); //再帰呼び出し n>0
 +
gene( n-1, p3, p2); //再帰呼び出し n>0
 +
}
 +
}
 +
</pre>
  
==== タイマーを使用した樹木のアニメーション ====
+
=== カスタムジェネレータの位置とtheta, p, qを動かしてみる ===
  
 +
* Recurs.cppのupdate()にp,q,thetaの変化を追加する。
 
<pre>
 
<pre>
        private void button3_Click(object sender, EventArgs e)
+
void Recurs::update(){
        {
+
pos1 += vel1;
            timer1.Enabled = true;
+
pos2 += vel2;
            timer1.Start();
+
if(pos1.x > ofGetWidth() || pos1.x < 0){
        }
+
vel1.x *= -1;
 +
}
 +
if(pos1.y > ofGetHeight() || pos1.y < 0){
 +
vel1.y *= -1;
 +
}
 +
if(pos2.x > ofGetWidth() || pos2.x < 0){
 +
vel2.x *= -1;
 +
}
 +
if(pos2.y > ofGetHeight() || pos2.y < 0){
 +
vel2.y *= -1;
 +
}
 +
p += 0.1;
 +
q += 0.01;
 +
theta += 0.7;
 +
}
 +
</pre>
  
        private void button4_Click(object sender, EventArgs e)
+
*ofApp()のupdate()でmyGeneを更新する。
        {
+
<pre>
            timer1.Stop();
+
void ofApp::update(){
            timer1.Enabled = false;
+
myGene.update();
        }
+
}
  
 +
</pre>
  
        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);
+
[[Category:授業]]
 
+
            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>
+

2020年10月31日 (土) 00:25時点における最新版

目次

[編集] openFrameworksのサンプル

[編集] 再帰的呼出しによる樹木の描画

  • 再帰的( 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"

//三角関数の値をstaticグローバル定数として定義
static const double S60 = sin( PI / 3.0); // sin(60)
static const double C60 = cos( PI / 3.0); // cos(60)

void Recurs::koch(int n, ofPoint p1, ofPoint p2){
	ofPoint p3,p4,p5;

	if( n > 0 ){
		p3 = ( 2 * p1 + p2 ) / 3.0; //内分点
		p4 = ( p1 + 2 * p2 ) / 3.0;
		p5.x = p3.x + ( p4.x - p3.x ) * C60 + (p4.y - p3.y) * S60; //回転移動
		p5.y = p3.y - ( p4.x - p3.x ) * S60 + (p4.y - p3.y) * C60;
		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);
}

[編集] 動かしてみる

  • Recurs.h
    • 現在位置と速度のプロパティを追加
    • 現在位置と速度を更新するupdate()メソッドの追加
class Recurs {
public:
	ofColor bcolor;  //描画色
	int generation;  // 世代
//ここから追加
	ofPoint pos1; //初期位置
	ofPoint pos2;
	ofPoint vel1; //初期速度
	ofPoint vel2;
//ここまで追加

	Recurs();
	void update(); // 追加分
	void koch(int n, ofPoint p1, ofPoint p2); //再帰的呼び出しメソッド
};
  • Recurs.cpp
    • Recurs()で初期の位置と速度を設定
    • update()で位置と速度を更新
#include "Recurs.h"

//三角関数の値をstaticグローバル定数として定義
static const double S60 = sin( PI / 3.0); // sin(60)
static const double C60 = cos( PI / 3.0); // cos(60)

Recurs::Recurs(){
	pos1 = ofPoint(ofGetWidth()*1/4, ofGetHeight()*2/4);
	vel1 = ofPoint(ofRandom(-5,5),ofRandom(-3,3));
	pos2 = ofPoint(ofGetWidth()*3/4, ofGetHeight()*2/4);
	vel2 = ofPoint(ofRandom(-5,5),ofRandom(-3,3));
	generation = 7; //世代の設定
	bcolor = ofColor(0,255,0); //描画色の設定
}

void Recurs::update(){
	pos1 += vel1;
	pos2 += vel2;
	if(pos1.x > ofGetWidth() || pos1.x < 0){
		vel1.x *= -1;
	}
	if(pos1.y > ofGetHeight() || pos1.y < 0){
		vel1.y *= -1;
	}
	if(pos2.x > ofGetWidth() || pos2.x < 0){
		vel2.x *= -1;
	}
	if(pos2.y > ofGetHeight() || pos2.y < 0){
		vel2.y *= -1;
	}
}

void Recurs::koch(int n, ofPoint p1, ofPoint p2){
	ofPoint p3,p4,p5;

	if( n > 0 ){
		p3 = ( 2 * p1 + p2 ) / 3.0; //内分点
		p4 = ( p1 + 2 * p2 ) / 3.0;
		p5.x = p3.x + ( p4.x - p3.x ) * C60 + (p4.y - p3.y) * S60; //回転移動
		p5.y = p3.y - ( p4.x - p3.x ) * S60 + (p4.y - p3.y) * C60;
		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.cpp
    • update()でmyKoch.update()を呼び出し、位置、速度を更新
#include "ofApp.h"

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

	ofBackground(0, 0, 0); //背景色の設定
	ofSetFrameRate(30); //フレームレイト設定
}

//--------------------------------------------------------------
void ofApp::update(){
	myKoch.update();
}

//--------------------------------------------------------------
void ofApp::draw(){
	myKoch.koch(myKoch.generation, myKoch.pos1, myKoch.pos2);
}

[編集] 複数個の図形を配置

  • ofApp.h
    • myKochとmyKoch2を作る
#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;
		Recurs myKoch2;
};
  • ofApp.cpp
    • update()で位置と速度を更新
    • myKoch2はmyKochとミラー配置
//--------------------------------------------------------------
void ofApp::update(){
	myKoch.update();
	myKoch2.pos1 = myKoch.pos2;
	myKoch2.pos2 = myKoch.pos1;
}

//--------------------------------------------------------------
void ofApp::draw(){
	myKoch.koch(myKoch.generation, myKoch.pos1, myKoch.pos2);
	myKoch2.koch(myKoch2.generation, myKoch2.pos1, myKoch2.pos2);
}

[編集] ドラゴン図形の描画

Dragon.jpg Dragon2.jpg

dragon()メソッドの追加

Recurs.cppに以下のメソッドを追加する。

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()メソッドの追加
void Recurs::shida(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(p4,p5); //余分な線を消す
		ofSetColor(bcolor);
		ofLine(p1,p2); //線分の描画
		ofLine(p1,p4);
		ofLine(p3,p5);

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

[編集] Cカーブの描画

Ccurve.jpg Ccurve2.jpg

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

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

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

[編集] 樹木の描画

Bintree.jpg Bintree2.JPG

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


  • Recurs.cppにjumoku()メソッドを追加
void Recurs::jumoku(int n, ofPoint p1, ofPoint p2){
	double s = sin( theta * PI / 180.0); // sin(theta)
	double c = cos( theta * PI / 180.0); // cos(theta)

	ofPoint p3,p4,dp;

	dp = 0.7 * (p2 - p1); // 枝の収縮率を0.7とする

	if( n > 0 ){
		p3.x = p2.x + c * dp.x - s * dp.y;
		p3.y = p2.y + s * dp.x + c * dp.y;
		p4.x = p2.x + c * dp.x + s * dp.y;
		p4.y = p2.y - s * dp.x + c * dp.y;

		ofSetColor(bcolor);
		ofLine(p1,p2); //線分の描画
		ofLine(p2,p3);
		ofLine(p2,p4);

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

[編集] 内分点と回転によるカスタムジェネレータの描画

Gene01.JPG Gene012.JPG

  • Recurs.hにtheta, p, q, gene()を追加する。
class Recurs {
public:
	ofColor bcolor;  //描画色
	int generation;  // 世代
	ofPoint pos1;
	ofPoint pos2;
	ofPoint vel1;
	ofPoint vel2;
	double theta; //樹木の枝の広がりの角度
	double p; //内分点の比
	double q; //内分点の比

	void gene(int n, ofPoint p1, ofPoint p2); //再帰的呼び出しメソッド カスタム
  • Recurs.cppにgene()を追加する。
Recurs::Recurs(){

	theta = 30;
	p = 2.0;
	q = 3.0;
}

void Recurs::gene(int n, ofPoint p1, ofPoint p2){
	ofPoint p3,p4,dp;

	double s = sin( theta * PI / 180.0); // sin(theta)
	double c = cos( theta * PI / 180.0); // cos(theta)

	if( n > 0 ){
		p3 = ( q * p1 + p * p2 ) / ( p + q ); //内分点
		dp = p3 - p1;
		p4.x = p1.x + c * dp.x - s * dp.y;
		p4.y = p1.y + s * dp.x + c * dp.y;

		ofSetColor(bcolor);
		ofLine(p1,p2); //線分の描画

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

[編集] カスタムジェネレータの位置とtheta, p, qを動かしてみる

  • Recurs.cppのupdate()にp,q,thetaの変化を追加する。
void Recurs::update(){
	pos1 += vel1;
	pos2 += vel2;
	if(pos1.x > ofGetWidth() || pos1.x < 0){
		vel1.x *= -1;
	}
	if(pos1.y > ofGetHeight() || pos1.y < 0){
		vel1.y *= -1;
	}
	if(pos2.x > ofGetWidth() || pos2.x < 0){
		vel2.x *= -1;
	}
	if(pos2.y > ofGetHeight() || pos2.y < 0){
		vel2.y *= -1;
	}
	p += 0.1;
	q += 0.01;
	theta += 0.7;
}
  • ofApp()のupdate()でmyGeneを更新する。
void ofApp::update(){
	myGene.update();
}

[編集] 参考

ジェネラティブアート論

個人用ツール
名前空間

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