http://ja.wikipedia.org/wiki/L-system
G = {V, S, ω, P},
参考ページ
http://local.wasp.uwa.edu.au/~pbourke/fractals/lsys/
V A 変数
S 無し 定数
ω A 最初の文字列の状態
P ( A ->AB )( B ->BA ) 「A」の文字にあたる部分を「AB」, 「B」の文字にあたる部分を「A」に書き換える
V F 変数
S [ ] - + 定数
ω F 最初の文字列の状態
P ( F -> F[+FF][-F]F ) 「F」の文字にあたる部分を「F[+FF][-F]F」に書き換える基本的に「文字(コード)を書き換える命令(コード)が文字(コード)の中に含まれているシステム」、と考えても良いかもしれない。
Lsystem コア部分
![]()
文字列 を書き換えるプログラムを組めばよいです。
blab_lsystem.zip このフレームからはじめてみてください。
文字列をL-Systemの考え方に従って書き換えていく機能を考える。
P ( A ->AB )( B ->BA ) 「A」の文字にあたる部分を「AB」, 「B」の文字にあたる部分を「A」に書き換えるこの場合の P には2種類の動作があります。
「A」の文字にあたる部分を「AB」
と
「B」の文字にあたる部分を「BA」
std::string testApp::rule(std::string &acode, char rep, std::string rew);
という関数として実装してみましょう。
変更後の文字列を返す testApp::rule(変更前の文字列, 置き換える文字, 置き換えられる文字);
関連:
size_t 文字列 .find(探す文字、探し始める位置);
文字列の中から指定する文字の位置を返します。
size_t :
ほぼ int と同じ型を示すものですが、もっと大きな整数を扱えます。
Lsystem 生成されるコードの利用
![]()
SndObjと組み合わせる。
lsystemで生成・変化している文字列ひとつづつ読み、文字に応じてfrequencyを変化させる。
testApp.h 内
define MACOSX
#include <SndObj/AudioDefs.h>
//このあたりはSndObjのサンプルと一緒int codeCount; //文字列をどこまで読んだか記録しておくための整数変数
testApp.cpp 内
void testApp::setup() {} 内
codeCount = 0 ; // 0からスタート
//このあたりはSndObjのサンプルと一緒
table1=new HarmTable(1024,1,SINE); //SIN
oscil=new Oscili(table1, 440.f, 10000.f);
output=new SndRTIO(2, SND_OUTPUT);
output->SetOutput(1, oscil);
sndthread.AddObj(oscil);
sndthread.AddObj(output, SNDIO_OUT);
sndthread.ProcOn();
//このあたりはSndObjのサンプルと一緒void testApp::update() {} 内
if(lsys_code.size())>codeCount)
{codeCount++;
}else
{codeCount=0;
}// 文字列のカウントを繰り返す
//文字列の中のカウントに当たる文字によって音を変化
switch(lsys_code[codeCount])
{case 'A' :
osil-LSetFreq(440.0);
break;case 'B' :
osil-LSetFreq(1800.0);
break;}
void testApp::draw() {} 内
glClearColor(0.1,0,0,0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
font.drawString( lsys_code ,0 ,98); // 文字列表示void testApp::exit(){
delete table1;
delete oscil;
delete output;}
Lsystem 生成されるコードの利用
![]()
描画する。
描画クラス LSysDraw : 以下の座標変換を駆使して作ってあります。 LSysDraw.zip
glTranslatef( , , );
glRotatef( , , , );
glPushMatrix();
glPopMatrix();パターンの翻訳
共通パラメータ
llen 移動距離
langle 方向変更の角度
lenfactor
F
llenの長さ分上方に線を残して進む f
llenの長さ分上方に線を残さないで進む #
線の太さを太くする !
線の太さを細くする >
線の長さをlenfactorの値の倍率で長くする <
線の長さをlenfactorの値の倍率で短くする @
曲がる方向を逆転する (
曲がる角度を5度増やす )
曲がる角度を5度減らす +
z軸を中心にlangleの値分左回りに、方向を変える -
z軸を中心にlangleの値分右回りに、方向を変える [
座標をスタック ]
座標をポップ =座標をスタックしたところまで戻る 拡張
} x軸を中心にlangleの値分左回りに、方向を変える { x軸を中心にlangleの値分右回りに、方向を変える | y軸を中心にlangleの値分左回りに、方向を変える _
y軸を中心にlangleの値分右回りに、方向を変える 使い方:
testApp.h 内
#include "LSysDraw.h"
LSysDraw lsysdraw; // インスタンス
testApp.cpp 内
void testApp::setup() {} 内
lsysdraw.len = 2 ; // 描画要素の長さを変えられます。
lsysdraw.R =1; // 基本描画色RGB (0 - 1.0 )
lsysdraw.G =1;
lsysdraw.B =1;void testApp::draw() {} 内
lsysdraw.draw(lsys-code); // 引数として、Lsystemで生成される文字列を渡す。
Boid
![]()
pthread をラップしたものです。
プロジェクトフォルダ内の "src" にSimplePthread.h, SimplePthread.cpp を配置
SimplePthreadクラスを継承して、スレッド実装したクラスを作るのが良いと思います。
#include "SimplePthread.h"
class myTask: public SimplePthread{
ThreadProc(){
//この TreadProcが仮想関数になっていますので
//ここにスレッドで行いたい処理を書く}
};
testApp.h 内
myTask mtask; //インスタンス
testApp.cpp 内
mtask.Begin(); // スレッドスタート
mtask.End()// スレッド終了
いずれもこちらのシリアルドライバのインストールが必要です。
OSX (intel i386)
http://www.ftdichip.com/Drivers/VCP/MacOSX/UniBin/FTDIUSBSerialDriver_v2_2_9.dmg
OSX (ppc)
http://www.ftdichip.com/Drivers/VCP/MacOSX/FTDIUSBSerialDriver_v2_1_9.dmgFramework版とスタティックライブラリ版を作りました。両方いっぺんに使う必要はありません。
Framework版
PriPro.framework.zip PriPro.Framework 他のframeworkと一緒にシステムにインストールしてください。
HD->System->Library->Frameworks
#include "PriPro/PriPro.h"
として使ってください。
blab_pripro_fw.zip 以下のように配置してください。
pre release v0.05 x-code FAT
├─ apps
│ ├ blabExample
│ ├ blab_pripro_fw
├─ blablib
├─ libs
└─ otherスタティックライブラリ版
PriProlib.zip PriProlib 以下のように配置してください。
pre release v0.05 x-code FAT
├─ apps
├─ blablib
│ ├ PriProlib
│ ├
├─ libs
└─ otherblab_pripro.zip スタティックライブラリ板を使った サンプルプロジェクトファイル、以下のように配置してください。
pre release v0.05 x-code FAT
├─ apps
│ ├ blabExample
│ ├ blab_pripro
├─ blablib
├─ libs
└─ other使い方はクワクボ先生の公開しているprocessing用のドライバと一緒です。
サンプルプロジェクトファイル blab_serialization.zip
'S' キーと、'R'キーを押してみてください。
dataフォルダに、array1.insect というファイルができているのを確認してください。
ちょっと難しいですが、太字の部分が重要な部分ですので、自分で使用する場合はほぼ、その箇所を変更するだけでよいと思います。
シリアライズしてアーカイブにしたいクラス内のメンバーシリアライズするメンバーとして追加しておく。
今回はInsect の配列、その中のそれぞれのメンバーをシリアライズするため、Insect.h と testApp.h に記述する。
// Insect.h 内
#include <boost/serialization/vector.hpp> // これをインクルード
//boost serialization
template <typename Archive>
void serialize(Archive &ar, const unsigned int version){ar & posX;
ar & posY;
ar & dirX;
ar & dirY;
ar & speed;
ar & name;
//ar & *img; // これらをシリアライズするには、
//ar & *font;//ofImageなどのクラスに、
//ar & *sndp;//これと同様のシリアライズの関数を
//ar & *sndp2;//書き込む必要がある}
次にシリアライズしたアーカイブを保存する関数を実装する。
// testApp.h内
void save(const std::string& path);
// testApp.cpp内
#include <fstream>
#include <ostream>
#include <string>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp> // これらをインクルードしておく。void
testApp::save(const std::string& path)
{std::ofstream outPutStream(ofToDataPath(path.c_str()).c_str(), std::ios::out | std::ios::binary );
if(outPutStream.is_open())
{try{
std::ostringstream archive_stream;
boost::archive::binary_oarchive archive(outPutStream);
archive << (const std::vector<Insect>&) this->insectArray;//この部分がそ れぞれのアプリの設計によって変更されます。}
catch (std::exception& /*e*/)
{outPutStream.close();
//return false;
std::cout << "could not save: " << std::endl;}
outPutStream.close();
std::cout << "saved to: " << path << std::endl;}
}
次にシリアライズしたアーカイブからデータを読み込む関数を実装する。
// testApp.h内
void load(const std::string& path);
// testApp.cpp内
void
testApp::load(const std::string& path)
{std::ifstream inPutStream(ofToDataPath(path.c_str()).c_str(), std::ios::in | std::ios::binary );
if(inPutStream.is_open())
{try{
std::ostringstream archive_stream;
boost::archive::binary_iarchive archive(inPutStream);
archive >> this->insectArray;//この部分がそれぞれのアプリの設計によって 変更されます。
std::cout << "loaded from: " << path << std::endl;}
catch (std::exception& /*e*/)
{inPutStream.close();
//return false;
std::cout << "could not save: " << std::endl;}
inPutStream.close();
}
}
vector配列内のクラスや構造体のソート
![]()
> < の オペレータをオーバーライドしておく。
//testApp.cpp の上方に以下を記述しておく
bool operator<(const Insect& left, const Insect& right) // クラス Insect のメンバーによってソートする。
{if(left.posY == right.posY) // posY の大小によってソートする想定
{return left.ID < right.ID;
}else
{return left.posY < right.posY ;
}
}
bool operator>(const Insect& left, const Insect& right)
{if(left.posY == right.posY)
{return left.ID > right.ID;
}else
{return left.posY > right.posY ;
}
}
// testApp.h 内 でinsectArrayを定義してあるケース
std::vector<Insect> insectArray; //
// testApp.cpp 内 たとえば
void test::keyreleased(int key) {
if(insectArray.size()>0){
std::sort(insectArray.begin(),insectArray.end()); // イテレータでソート範囲を指定する。
// こうするとposYの大きい順に配列内の順序が入れ替わる。‘}
}