生命情報アート論
| 目次 | 
概要
- 成績評価
- 出席:学生証scan+Minutes paper
- 課題:セルオートマトン課題、再帰呼び出し図形課題、複素平面フラクタル課題
- 小テスト:ハイスコア
 
- 授業概要及び到達目標
- インタラクティブアートは芸術を基盤として科学や工学を統合する新しい領域である。生物科学に関連した分野として、人工生命、ライフゲーム、フラクタル、オートマトン、遺伝的アルゴリズム、ニューラルネットワークなど応用範囲の広いものが数多く存在する。
そういった生物に見られる特徴をアートに応用したジェネラティブアートの作品をC++のプログラミングを使用して、実際に作成してみる。
本講義の目標は以下の通り。
- 生物の特徴と生物的なシステムについて理解する。
- 複雑系システムについて理解し、応用例を作成できる。
- openFrameworksを使って作品のプログラミングができる。
アナウンス
開発環境としてopenFrameworks for Visual studioを使用します。
テキストや開発環境については、以下を参照してください。
一年生の時にメディアプログラミング演習I程度のプログラミングスキルがあるものとして、授業を進めます。 もし、プログラミングに不安があるなら、上記テキストを使って、自分で予習や自習をしてください。
予定
- 2014年度
- 9/30(火) ガイダンス, 生物と情報とアート,openFrameworksプログラミング演習
- 10/7(火) openFrameworks C++プログラミング
- 10/14(火) 幾何学図形の描画
- 10/21(火) ランダムウォーク
- 10/28(火) セルオートマトン
- 11/4(火) セルオートマトン
- 11/11(火) セルオートマトン
- 11/18(火) セルオートマトン
- 11/25(火) セルオートマトン
- 12/2(火) フラクタルと再帰呼び出し
- 12/9(火) 課題制作日
- 12/16(火) フラクタルと再帰呼び出し
- 1/6(火) 予備演習日(出席はとりません)
- 1/20(火) 遺伝的アルゴリズム
- 1/28(火) 小テスト
生物と情報とアート
-  生物とは? 生物の特徴とは?
- 例:小石と貝殻
- * 簡単BBSに「生物と無生物の違いは何か?」説明してみよう。
 
- ゲノムのDNAマップ NCBI Map Viewer
- ヒト一人を再生するのに必要な情報量は?
メモ
Visual Studioのショートカット
- Ctrl-K Ctrl-C コメントアウト
- Ctrl-K Ctrl-U コメントアウト解除
- Ctrl-K Ctrl-F インデントをそろえる
複雑系
セルオートマトン
ライフゲーム
ライフゲームの例 / ライフゲーム入門 / セルオートマトン・ギャラリー /
- セルオートマトン音楽
WolframTones/ CAMUS/ Glitch DS/ Life Game Orchestra /
- ギャラリー
Modern Cellular Automata/ CArt gallery/ Cellular Automata Art/ ASCII Art Cell Automaton/
- 参考
ワイヤワールド /
人工生命
ラングトンのアリ / ラングトンのループ / 自己増殖ループ / Reynolds Boid /
http://www.local-guru.net/blog/2010/8/19/openframeworks-boid-demo
https://gist.github.com/tado/6603347
Birds Algorhythm Craig Reynolds
http://processing.org/examples/flocking.html
openFrameworks Visual C++プログラミング
1つのボールがふらふら動く
配列とマウスインタラクション
クラスの使用
ランダムウォーク
ラングトンのアリ
物理エンジン Box2D
自己相似形
Tips
- パーティクルの位置に画像を置く
ofApp.h
ofImage particleImage;
ofApp.cpp
setup(){
   particleImage.loadImage("particle.png");
}
draw(){
  particleImage.draw(pos.x, pos.y, w, h);
}
- パーティクルの位置を辿る直線を描く
ofApp.cpp
ofBeginShape();
    for(int i = 0; i < particle.size(); i++){
        ofVertex(pos[i].x, pos[i].y);
    }
ofEndShape();
- パーティクルの位置を辿る曲線を描く
ofApp.cpp
ofBeginShape();
    for(int i = 0; i < particle.size(); i++){
        ofCurveVertex(pos[i].x, pos[i].y);
    }
ofEndShape();
C#プログラミング
Visual Studio C#を使用した描画プログラムの作成
プロパティの変更
- ラベルの変更
label1.Text = "おはよう"; label1.BackColor = Color.FromArgb(100,0,255,0);
乱数の使用
- サイコロ
Random saikoro = new Random(); label2.Text = saikoro.Next(1, 7).ToString();
Timerの使用
- ルーレット
- Timerのスタートとストップのトグルボタン
if (timer1.Enabled == true)
{
  timer1.Stop();
}
else
{
  timer1.Start();
}
- timer1_Tick()メソッドの処理。Interval時間間隔ごとにテキストボックスから得た数字を最大値として乱数を発生させる。
Random roulette = new Random(); int kazu_max = int.Parse(textBox1.Text); label2.Text = roulette.Next(1, kazu_max).ToString();
幾何学模様描画例
- 描画例のソース
exeプログラム例 直線,矩形,円弧,多角形,曲線など
線の描画
- pictureboxを作成
- Graphic gの作成
- Penの作成
- g.Draw系のメソッドで線を描画
- g.DrawLine (pen, x1, y1, x2, y2)
- (x1,y1)と(x2,y2)を結ぶ直線を描画する。
- g.DrawRectangle (pen, x, y, w, h)
- (x,y)を左上頂点とする幅w、高さhで指定された四角形を描画する。
- g.DrawEllipse (pen, x, y, w, h)
- (x,y)を左上頂点とする幅w、高さhで指定された四角形に内接する楕円を描画する。
以下のライブラリーをインポートしておく。
using System.Drawing.Drawing2D;
直線、矩形などの描画の基礎
        private void button1_Click(object sender, EventArgs e)
        {
            Graphics g = pictureBox1.CreateGraphics();
            Pen pen = new Pen(Color.Black);  //黒のペンを定義
            Pen boldPen = new Pen(Color.Black, 5); // 太いペン
            Pen dotPen = new Pen(Color.Black, 5); // 点線
            dotPen.DashStyle = DashStyle.Dot; 
            g.DrawLine(pen, 0, 10, 300, 10);
            g.DrawLine(boldPen, 0, 30, 300, 30);// 太い線
            g.DrawLine(dotPen, 0, 60, 300, 60);// 点線
            //点線パターンの変更
            dotPen.DashStyle = DashStyle.DashDot;
            g.DrawLine(dotPen, 0, 90, 300, 90);
            dotPen.DashStyle = DashStyle.DashDotDot;
            g.DrawLine(dotPen, 0, 120, pictureBox1.Width, 120);
            pen.Color = Color.Red; //ペンの色変更
            g.DrawLine(pen, 0, 150, pictureBox1.Width, 150);
        }
        private void button2_Click(object sender, EventArgs e)
        {
            Graphics g = pictureBox1.CreateGraphics();
            Pen pen = new Pen(Color.Black);  //黒のペンを定義
            SolidBrush brush = new SolidBrush(Color.Black);//黒のブラシを定義
            // 枠の四角形を描画する
            g.DrawRectangle(pen, 0, 0, 100, 100);
            // 塗り潰しの四角形を描画する
            g.FillRectangle(brush, 50, 50, 100, 100);
            brush.Color = Color.Red;
            g.FillRectangle(brush, 150, 150, 200, 100);
        }
        private void button3_Click(object sender, EventArgs e)
        {
            Graphics g = pictureBox1.CreateGraphics();
            Pen pen = new Pen(Color.Black);
            SolidBrush brush = new SolidBrush(Color.Black);
            // 円を描画する
            g.DrawEllipse(pen, 0, 0, 100, 100);
            // 楕円を描画する
            g.DrawEllipse(pen, 0, 0, 200, 100);
            // 円弧を描画する
            g.DrawArc(pen, 200, 300, 150, 100, 10, 30);
            // 扇形を描画する
            g.DrawPie(pen, 300, 300, 200, 100, 10, 30);
            // 塗り潰した円を描画する
            g.FillEllipse(brush, 50, 50, 100, 100);
            // 作成したBrushオブジェクトを指定する
            TextureBrush br = new TextureBrush(Properties.Resources.book);
            g.FillEllipse(br, 100, 100, 100, 100);
        }
        private void button4_Click(object sender, EventArgs e)
        {
            Graphics g = pictureBox1.CreateGraphics();
            Pen pen = new Pen(Color.Black);
            // 折れ線を描画する
            Point[] points = new Point[4];
            points[0] = new Point(50, 0);
            points[1] = new Point(100, 50);
            points[2] = new Point(50, 100);
            points[3] = new Point(0, 50);
            g.DrawLines(pen, points);
            // 閉じた多角形を描画する
            points[0] = new Point(100, 0);
            points[1] = new Point(150, 50);
            points[2] = new Point(100, 100);
            points[3] = new Point(50, 50);
            pen.Color = Color.Red; //ペンの色変更
            g.DrawPolygon(pen, points);
        }
        private void button7_Click(object sender, EventArgs e)
        {
            Graphics g = pictureBox1.CreateGraphics();
            Pen pen = new Pen(Color.Black);
            Point[] points = new Point[4];
            // 曲線を描画する
            points[0] = new Point(20, 20);
            points[1] = new Point(100, 200);
            points[2] = new Point(200, 0);
            points[3] = new Point(300, 200);
            g.DrawLines(pen, points);
            //ヴェジェ
            g.DrawBeziers(pen, points);
            //スプライン
            g.DrawCurve(pen, points);
            g.DrawCurve(pen, points, 0F);
            g.DrawCurve(pen, points, 0.5F);
            g.DrawCurve(pen, points, 1F);
            g.DrawCurve(pen, points, 1.5F);
            g.DrawCurve(pen, points, 2F);
        }
描画領域のクリア
g.Clear(Color.White); //描画領域をクリア(白で塗りつぶす)
グラデーション
Graphics g = pictureBox1.CreateGraphics(); // グラデーションのペンを作成 Brush br = new LinearGradientBrush(new Point(0, 0), new Point(0, pictureBox1.Height), Color.Green, Color.White); // グラデーションで塗り潰し g.FillRectangle(br, 0, 0, pictureBox1.Width, pictureBox1.Height);
マウスムーブを使った描画
プロパティウィンドウにイベント(稲妻のアイコン)のリストを表示させ、MouseMoveイベントをダブルクリックすると、MouseMoveのメソッドが自動生成されます。
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
  Graphics g = pictureBox1.CreateGraphics();
  Pen pen = new Pen(Color.Black);
  Random rndcolor = new Random();
  //描画色の決定
  int aa = rndcolor.Next(0, 256);
  int rr = rndcolor.Next(0, 256);
  int gg = 255 - e.X * 255 / pictureBox1.Width;
  int bb = e.Y * 255 / pictureBox1.Height;
  pen.Color = Color.FromArgb(aa, rr, gg, bb);
  // マウス位置へ直線を描画する
  g.DrawLine(pen, 0, 0, e.X, e.Y);
  g.DrawLine(pen, 0, pictureBox1.Height, e.X, e.Y);
  g.DrawLine(pen, pictureBox1.Width, 0, e.X, e.Y);
  g.DrawLine(pen, pictureBox1.Width, pictureBox1.Height, e.X, e.Y);
  label3.Text = e.X.ToString();
  label4.Text = e.Y.ToString();
}
forループを使った描画
  Graphics g = pictureBox1.CreateGraphics();
// 直線をループで描画する
  Pen pen = new Pen(Color.Black);
  Random rnd = new Random();
  for (int i = 0; i < pictureBox1.Width; i++)
  {
    int aa = rnd.Next(0, 256);
    int rr = rnd.Next(0, 256);
    int gg = rnd.Next(0, 256);
    int bb = rnd.Next(0, 256);
    pen.Color = Color.FromArgb(aa, rr, gg, bb);
    g.DrawLine(pen, pictureBox1.Width / 2, 0, i, pictureBox1.Height);
  }
// 点をループで描画する
  SolidBrush brush = new SolidBrush(Color.Black);
  Random rnd = new Random();
  int imax = 10000;
  for (int i = 0; i < imax; i++)
  {
    int aa = rnd.Next(0, 256);
    int rr = rnd.Next(0, 256);
    int gg = rnd.Next(0, 256);
    int bb = rnd.Next(0, 256);
    int xx = rnd.Next(0, pictureBox1.Width);
    int yy = rnd.Next(0, pictureBox1.Height);
    pen.Color = Color.FromArgb(aa, rr, gg, bb);
    brush.Color = Color.FromArgb(aa, rr, gg, bb);
    g.DrawRectangle(pen, xx, yy, 5, 5);
    g.FillRectangle(brush, xx, yy, 5, 5);
  }
// 円をループで描画する
    double pi = 3.14159;
   int x3 = pictureBox1.Width / 2;
   int y3 = pictureBox1.Height / 2;
   int r1 = 100, r2 = 50;
   int kkizami = 100;
   int shukai = 1;
   int n = 5;
   for (int i = 0; i < kkizami * shukai; i++)
   {
     double k = 2 * pi / kkizami * i;
     double x = x3 + r1 * Math.Cos(k);
     double y = y3 - r1 * Math.Sin(k);
     g.DrawEllipse(pen, (int)x - r2, (int)y - r2, 2 * r2, 2 * r2);
   }
アルキメデスの渦巻き
Graphics g = pictureBox1.CreateGraphics();
Pen pen = new Pen(Color.Black);
double pi = 3.14159;
int x3 = pictureBox1.Width / 2;
int y3 = pictureBox1.Height / 2;
double r1;
int kkizami = 1000;
int shukai = 100;
double n = 2;
double k,x=0,y=0,nx=0,ny=0;
nx = x3; ny = y3;
for (int i = 0; i < kkizami * shukai; i++)
{
  k = 2 * pi / kkizami * i;
  r1 = n * k;
  x = nx;
  y = ny;
  nx = x3 + r1 * Math.Cos(k);
  ny = y3 - r1 * Math.Sin(k);
  g.DrawLine(pen, (int)x, (int)y, (int)nx, (int)ny);
}
フェルマーの渦巻き
Graphics g = pictureBox1.CreateGraphics();
Pen pen = new Pen(Color.Black);
double pi = 3.14159;
int x3 = pictureBox1.Width / 2;
int y3 = pictureBox1.Height / 2;
double r1;
int kkizami = 100;
int shukai = 100;
double n = 10;
double k, x = 0, y = 0, nx = 0, ny = 0;
nx = x3; ny = y3;
for (int i = 0; i < kkizami * shukai; i++)
{
  k = 2 * pi / kkizami * i;
  r1 = n * Math.Sqrt(k);
  x = nx;
  y = ny;
  nx = x3 + r1 * Math.Cos(k);
  ny = y3 - r1 * Math.Sin(k);
  g.DrawLine(pen, (int)x, (int)y, (int)nx, (int)ny);
}
正葉曲線:単
Graphics g = pictureBox1.CreateGraphics();
Pen pen = new Pen(Color.Black);
double pi = 3.14159;
int x3 = pictureBox1.Width / 2;
int y3 = pictureBox1.Height / 2;
double r1;
int kkizami = 1000;
int shukai = 1;
double n = 5,m=100;
double k, x = 0, y = 0, nx = 0, ny = 0;
nx = x3; ny = y3;
for (int i = 0; i < kkizami * shukai; i++)
{
  k = 2 * pi / kkizami * i;
  r1 = m * Math.Abs(Math.Sin(n * k));
  x = nx;
  y = ny;
  nx = x3 + r1 * Math.Cos(k);
  ny = y3 - r1 * Math.Sin(k);
  g.DrawLine(pen, (int)x, (int)y, (int)nx, (int)ny);
}
正葉曲線:複
Graphics g = pictureBox1.CreateGraphics();
Pen pen = new Pen(Color.Black);
double pi = 3.14159;
int x3 = pictureBox1.Width / 2;
int y3 = pictureBox1.Height / 2;
double r1;
int kkizami = 1000;
int shukai = 1;
double n = 5, m = 20;
double k, x = 0, y = 0, nx = 0, ny = 0;
nx = x3; ny = y3;
for (int i = 0; i < kkizami * shukai; i++)
{
  k = 2 * pi / kkizami * i;
  r1 = m * Math.Abs( 7* Math.Sin(n * k) + 1 * Math.Sin(3 * n * k) + 1 * Math.Sin(5 * n * k ));
  x = nx;
  y = ny;
  nx = x3 + r1 * Math.Cos(k);
  ny = y3 - r1 * Math.Sin(k);
  g.DrawLine(pen, (int)x, (int)y, (int)nx, (int)ny);
}
外サイクロイド
Graphics g = pictureBox1.CreateGraphics();
Pen pen = new Pen(Color.Black);
double pi = 3.14159;
int x3 = pictureBox1.Width / 2;
int y3 = pictureBox1.Height / 2;
double r1;
int kkizami = 100;
int shukai = 50;
double a = 100, b = 65;
double k, x = 0, y = 0, nx = 0, ny = 0;
nx = x3 + a; ny = y3;
for (int i = 0; i < kkizami * shukai; i++)
{
  k = 2 * pi / kkizami * i;
  x = nx; y = ny;
  nx = x3 + ((a + b) * Math.Cos(k) - b * Math.Cos((a + b) / b * k));
  ny = y3 - ((a + b) * Math.Sin(k) - b * Math.Sin((a + b) / b * k));
  g.DrawLine(pen, (int)x, (int)y, (int)nx, (int)ny);
}
内サイクロイド
Graphics g = pictureBox1.CreateGraphics();
Pen pen = new Pen(Color.Black);
double pi = 3.14159;
int x3 = pictureBox1.Width / 2;
int y3 = pictureBox1.Height / 2;
double r1;
int kkizami = 100;
int shukai = 50;
double a = 100, b = 23;
double k, x = 0, y = 0, nx = 0, ny = 0;
for (int i = 0; i < kkizami * shukai; i++)
{
  k = 2 * pi / kkizami * i;
  if (i == 0)
  {
     x = x3 + ((a - b) * Math.Cos(k) + b * Math.Cos((a - b) / b * k));
     y = y3 - ((a - b) * Math.Sin(k) - b * Math.Sin((a - b) / b * k));
  }
  else
  {
     x = nx;
     y = ny;
  }
     nx = x3 + ((a - b) * Math.Cos(k) + b * Math.Cos((a - b) * k / b));
     ny = y3 - ((a - b) * Math.Sin(k) - b * Math.Sin((a - b) * k / b));
     g.DrawLine(pen, (int)x, (int)y, (int)nx, (int)ny);
  }
}
セルオートマトン例
ランダムウォーク
- 新しいクラスの定義
ランダムウォークする固体をクラスとして定義する。
- 「プロジェクト」メニューから「クラスの追加」でクラス名を入力する。
- クラス名は、自由につけてよい。
- クラスの定義の中にメンバー変数とメソッドを記述する。
- 変数やクラス名の名前の付け方のヒント(文法ではない。様々な流儀がある)
- クラス名 Pascal型 KougeiTaro
- 変数名 Camel型 kougeiTaro
 
    class RandWalker
    {
        public int dx { get; set; } // X軸の歩幅
        public int dy { get; set; } // Y軸の歩幅
        public int X { get; set; } // ウォーカーの現在位置のX座標
        public int Y { get; set; } // ウォーカーの現在位置のX座標
        public int r { get; set; } // ウォーカーの大きさ(直径)
        public int MaxHeight { get; set; } // ウォーカーの移動範囲のX座標の最大値(右の壁)
        public int MaxWidth { get; set; } // ウォーカーの移動範囲のY座標の最大値(下の壁)
        private Random rnd = new Random(); //乱数の定義
        public void walk() {
          int d = rnd.Next(1, 5); //1から4までの乱数を発生
            switch(d)
            {
                case 1:  // 1のときX軸の右(正)へ進む
                    X = X + dx;
                    break;
                case 2:  // 2のときX軸の左(負)へ進む
                    X = X - dx;
                    break;
                case 3: // 3のときY軸の下(正)へ進む
                    Y = Y + dy;
                    break;
                case 4: // 4のときY軸の上(負)へ進む
                    Y = Y - dy;
                    break;
            }
            if (X <= 0) // 壁にぶつかると進めない
                X = 1;
            if (X >= MaxWidth)
                X = MaxWidth;
            if (Y <= 0)
                Y = 1;
            if (Y >= MaxHeight)
                Y = MaxHeight;
        }
    }
メインプログラムでウォーカーをランダムに歩かせる。
- pictureBox1に描画
- timer1で、歩かせる。
- buttonでタイマーのstart, pause, clearを指定
- クラスRandwalkerのメンバーやメソッドは、以下のように呼び出す。
- walker.X
- walker.walk()
 
    public partial class Form1 : Form
    {
        //グラフィック、ペン、ブラシ、ウォーカーをグローバルとして宣言
        Graphics g;
        Pen pen;
        SolidBrush brush;
        private RandWalker walker;
        public Form1()
        {
            InitializeComponent();
            g = pictureBox1.CreateGraphics();
            pen = new Pen(Color.Black);
            brush = new SolidBrush(Color.Black);
            walker = new RandWalker() // ウォーカーの初期値を指定
            {
                dx = 5,
                dy =5,
                r = 5,
                X = (int)pictureBox1.Width / 2,
                Y = (int)pictureBox1.Height / 2,
                MaxWidth = (int)pictureBox1.Width,
                MaxHeight = (int)pictureBox1.Height,
            };
        }
        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            timer1.Stop();
        }
        private void button3_Click(object sender, EventArgs e)
        {
            g.Clear(Color.White);
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            //ウォーカーの足跡をライトグレイで上書きする
            pen.Color = Color.LightGray;
            brush.Color = Color.LightGray;
            g.DrawRectangle(pen, walker.X, walker.Y, walker.r, walker.r);
            g.FillRectangle(brush, walker.X, walker.Y, walker.r, walker.r);
 
            //ウォーカーを歩かせ、現在位置を赤で描く
            walker.walk();
            pen.Color = Color.Red;
            g.DrawRectangle(pen, walker.X, walker.Y, walker.r, walker.r);
            brush.Color = Color.Red;
            g.FillRectangle(brush, walker.X, walker.Y, walker.r, walker.r);
        }
    }
物理法則
等速移動
クラスのwalkメソッド
- 位置の変化(速度)であるdx dyが常に一定値
        public void walk()
        {
            // 等速移動
            X = X + dx;
            Y = Y + dy;
            //壁で跳ね返る
            if (X < 0)
            {
                X = -X;
                dx = dx * (-1);
            }
            if (X > MaxWidth)
            {
                X = MaxWidth - (X - MaxWidth);
                dx = dx * (-1);
            }
            if (Y < 0)
            {
                Y = -Y;
                dy = dy * (-1);
            }
            if (Y > MaxHeight)
            {
                Y = MaxHeight - (Y - MaxHeight);
                dy = dy * (-1);
            }
        }
等加速度移動
クラスのwalkメソッド
- x軸の位置の変化であるdxは、常に一定値
- y軸の位置の変化であるdyは、一定の割合で変化
            // 等加速度移動
            dy++;
            X = X + dx;
            Y = Y + dy;
万有引力
- 恒星を固定する
クラスのwalkメソッド
- 惑星位置の変化であるdx,dyは、恒星との距離の2乗に反比例し、恒星の質量に比例する。
    class planet
    {
        public double dx { get; set; }
        public double dy { get; set; }
        public int X { get; set; }
        public int Y { get; set; }
        public int r { get; set; }
        public int X0 { get; set; } //恒星の座標
        public int Y0 { get; set; }
        public double m { get; set; } //自分の質量
        public int MaxHeight { get; set; }
        public int MaxWidth { get; set; }
        public void walk()
        {
            double dd = (X - X0) * (X - X0) + (Y - Y0) * (Y - Y0); //恒星との距離の2乗
            dx = dx - ( X - X0 ) * m /dd;
            dy = dy - ( Y - Y0 ) * m / dd;
            X = (int)(X + dx);
            Y = (int)(Y + dy);
            //壁で跳ね返る
            if (X < 0)
            {
                X = -X;
            }
            if (X > MaxWidth)
            {
                X = MaxWidth - (X - MaxWidth);
            }
            if (Y < 0)
            {
                Y = -Y;
            }
            if (Y > MaxHeight)
            {
                Y = MaxHeight - (Y - MaxHeight);
            }
        }
    }
        // Planet classのインスタンスmarsをグローバルに宣言
        private Planet mars;
        public Form1()
        {
            InitializeComponent();
            // Planet classのインスタンスmarsをグローバルの定義
            mars = new Planet()
            {
                dx = -0.1,
                dy = 4.0,
                r = 5,
                m = 350,
                X = (int)pictureBox1.Width / 7 * 6,
                Y = (int)pictureBox1.Height / 4,
                X0 = (int)pictureBox1.Width / 2,
                Y0 = (int)pictureBox1.Height / 2,
                MaxWidth = (int)pictureBox1.Width,
                MaxHeight = (int)pictureBox1.Height,
            };
        }
- 2体問題
- クラスの定義は同様
-  恒星の座標に相手の座標を代入する。すなわち惑星2つの相互作用とみなす。
- より正確な位置計算が必要なため、2体の座標データ(X,Y)と(X0,Y0)は、整数(int)ではなく、倍制度(double)で定義する。
- 重力定数gを導入
 
    class Planet
    {
        public double dx { get; set; }
        public double dy { get; set; }
        public double X { get; set; }
        public double Y { get; set; }
        public int r { get; set; }
        public double m { get; set; } //質量
        public double X0 { get; set; } //相手の座標
        public double Y0 { get; set; }
        public double m0 { get; set; } //相手の質量
        public int MaxHeight { get; set; }
        public int MaxWidth { get; set; }
        public void walk()
        {
            double g = 0.115;  //重力定数
            double dd = (X - X0) * (X - X0) + (Y - Y0) * (Y - Y0); //相手との距離の2乗
            dx = dx - (X - X0) * m0 / dd * g;
            dy = dy - (Y - Y0) * m0 / dd * g;
            X = X + dx;
            Y = Y + dy;
            //壁で跳ね返る
            
            if (X < 0)
            {
                X = -X;
                dx = -dx * 0.01;
            }
            if (X > MaxWidth)
            {
                X = MaxWidth - (X - MaxWidth);
                dx = -dx;
            }
            if (Y < 0)
            {
                Y = -Y;
                dy = -dy * 0.01;
            }
            if (Y > MaxHeight)
            {
                Y = MaxHeight - (Y - MaxHeight);
                dy = -dy;
            }
        }
    }
2対の座標データ(X,Y)と(X0,Y0)を描画する際に、doubleをintに型変換するために、グローバル変数x1,y1,x2.y2を使用する。
    public partial class Form1 : Form
    {
        //グラフィック、ペン、ブラシ、ウォーカーをグローバルとして宣言
        Graphics g;
        Pen pen;
        SolidBrush brush;
        private Planet mars;
        private Planet virnus;
        int x1, y1, x2, y2;
        public Form1()
        {
            InitializeComponent();
            g = pictureBox1.CreateGraphics();
            pen = new Pen(Color.Black);
            brush = new SolidBrush(Color.Black);
            mars = new Planet() // ウォーカーの初期値を指定
            {
                dx = -0.1,
                dy = 4.0,
                r = 5,
                m = 350,
                X = (int)pictureBox1.Width / 7 * 6,
                Y = (int)pictureBox1.Height / 4,
                MaxWidth = (int)pictureBox1.Width,
                MaxHeight = (int)pictureBox1.Height,
            };
            virnus = new Planet() // ウォーカーの初期値を指定
            {
                dx = 0.1,
                dy = -4.0,
                r = 5,
                m = 300,
                X = (int)pictureBox1.Width / 7 * 5,
                Y = (int)pictureBox1.Height / 4,
                MaxWidth = (int)pictureBox1.Width,
                MaxHeight = (int)pictureBox1.Height,
            };
        }
        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            timer1.Stop();
        }
        private void button3_Click(object sender, EventArgs e)
        {
            g.Clear(Color.White);
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            //お互いの座標と質量を代入する
            mars.X0 = virnus.X;
            mars.Y0 = virnus.Y;
            mars.m0 = virnus.m;
            virnus.X0 = mars.X;
            virnus.Y0 = mars.Y;
            virnus.m0 = mars.m;
            //足跡をライトグレイで上書きする
            x1 = (int)Math.Round(mars.X);
            y1 = (int)Math.Round(mars.Y);
            x2 = (int)Math.Round(virnus.X);
            y2 = (int)Math.Round(virnus.Y);
            pen.Color = Color.LightGray;
            brush.Color = Color.LightGray;
            g.DrawRectangle(pen, x1, y1, mars.r, mars.r);
            g.FillRectangle(brush, x1, y1, mars.r, mars.r);
            g.DrawRectangle(pen, x2, y2, virnus.r, virnus.r);
            g.FillRectangle(brush, x2, y2, virnus.r, virnus.r);
            //歩かせる
            mars.walk();
            virnus.walk();
            //現在位置を赤と緑で描く
            x1 = (int)Math.Round(mars.X);
            y1 = (int)Math.Round(mars.Y);
            x2 = (int)Math.Round(virnus.X);
            y2 = (int)Math.Round(virnus.Y);
            pen.Color = Color.Red;
            brush.Color = Color.Red;
            g.DrawRectangle(pen, x1, y1, mars.r, mars.r);
            g.FillRectangle(brush, x1, y1, mars.r, mars.r);
            pen.Color = Color.Green;
            brush.Color = Color.Green;
            g.DrawRectangle(pen, x2, y2, virnus.r, virnus.r);
            g.FillRectangle(brush, x2, y2, virnus.r, virnus.r);
        }
    }
色をグラデーションで変化させる例
        //グローバルに色のARGBの値の変数を宣言
        int aa, rr, gg, bb, da, dr, dg, db, x1, y1, x2, y2;
        public Form1()
        {
           //Form1の中で変数の初期値を定義
            aa = 255;  rr = 11; gg = 31; bb = 29;
            da = 1; dr = 1; db = 1; dg = 1;
        }
      private void timer1_Tick(object sender, EventArgs e)
        {
            Random rnd = new Random();
            //Timerの中で変数を徐々に変化させる。
            aa = aa + da;
            rr = rr + dr;
            gg = gg + dg;
            bb = bb + db;
            //変化量をランダムに変更する。
            if (aa > 255){ aa = 255; da = rnd.Next(-3,0); }
            if (aa < 1) { aa = 0; da = rnd.Next(1, 4); }
            if (rr > 255) { rr = 255; dr = rnd.Next(-3, 0); }
            if (rr < 1) { rr = 0; dr = rnd.Next(1, 4); }
            if (gg > 255) { gg = 255; dg = rnd.Next(-3, 0); }
            if (gg < 1) { gg = 0; dg = rnd.Next(1, 4); }
            if (bb > 255) { bb = 255; db = rnd.Next(-3, 0); }
            if (bb < 1) { bb = 0; db = rnd.Next(1, 4); }
            pen.Color = Color.FromArgb(aa, rr, gg, bb);
            brush.Color = Color.FromArgb(aa, rr, gg, bb);
            g.DrawRectangle(pen, x1, y1, mars.r, mars.r);
            g.FillRectangle(brush, x1, y1, mars.r, mars.r);
        }
- 3体問題の例
クラスの定義
   class Planet
    {
        public double dx { get; set; }
        public double dy { get; set; }
        public double X { get; set; }
        public double Y { get; set; }
        public int r { get; set; }
        public double m { get; set; } //質量
        public double X0 { get; set; } //相手の座標
        public double Y0 { get; set; }
        public double m0 { get; set; } //相手の質量
        public double X1 { get; set; } //相手の座標
        public double Y1 { get; set; }
        public double m1 { get; set; } //相手の質量
        public int MaxHeight { get; set; }
        public int MaxWidth { get; set; }
        public void walk()
        {
            double g = 0.115;
            double dd = (X - X0) * (X - X0) + (Y - Y0) * (Y - Y0); //相手との距離の2乗
            dx = dx - (X - X0) * m0 / dd * g;
            dy = dy - (Y - Y0) * m0 / dd * g;
            X = X + dx;
            Y = Y + dy;
            dd = (X - X1) * (X - X1) + (Y - Y1) * (Y - Y1); //相手との距離の2乗
            dx = dx - (X - X1) * m1 / dd * g;
            dy = dy - (Y - Y1) * m1 / dd * g;
            X = X + dx;
            Y = Y + dy;
            //壁で止まる
            if (X < 0)
            {
                X = -X;
            }
            if (X > MaxWidth)
            {
                X = MaxWidth - (X - MaxWidth);
            }
            if (Y < 0)
            {
                Y = -Y;
            }
            if (Y > MaxHeight)
            {
                Y = MaxHeight - (Y - MaxHeight);
            }
        }
    }
メイン部
    public partial class Form1 : Form
    {
        //グラフィック、ペン、ブラシ、ウォーカーをグローバルとして宣言
        Graphics g;
        Pen pen;
        SolidBrush brush;
        private Planet mars;
        private Planet virnus;
        private Planet jupiter;
        int aa, rr, gg, bb, da, dr, dg, db;
        int x1, y1, x2, y2, x3, y3;
        public Form1()
        {
            InitializeComponent();
            g = pictureBox1.CreateGraphics();
            aa = 255;  rr = 11; gg = 31; bb = 29;
            da = 1; dr = 1; db = 1; dg = 1;
            pen = new Pen(Color.Black);
            brush = new SolidBrush(Color.Black);
            mars = new Planet() // ウォーカーの初期値を指定
            {
                dx = -0.01,
                dy = 0.4,
                r = 5,
                m = 100,
                X = (int)pictureBox1.Width / 7 * 6,
                Y = (int)pictureBox1.Height / 4,
                MaxWidth = (int)pictureBox1.Width,
                MaxHeight = (int)pictureBox1.Height,
            };
            virnus = new Planet() // ウォーカーの初期値を指定
            {
                dx = 0.01,
                dy = -0.4,
                r = 10,
                m = 300,
                X = (int)pictureBox1.Width / 7 * 5,
                Y = (int)pictureBox1.Height / 4,
                MaxWidth = (int)pictureBox1.Width,
                MaxHeight = (int)pictureBox1.Height,
            };
            jupiter = new Planet() // ウォーカーの初期値を指定
            {
                dx = 0.4,
                dy = 0.01,
                r = 7,
                m = 200,
                X = (int)pictureBox1.Width / 7 * 5.5,
                Y = (int)pictureBox1.Height / 4 * 2,
                MaxWidth = (int)pictureBox1.Width,
                MaxHeight = (int)pictureBox1.Height,
            };
        }
        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            timer1.Stop();
        }
        private void button3_Click(object sender, EventArgs e)
        {
            g.Clear(Color.White);
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            Random rnd = new Random();
            aa = aa + da;
            rr = rr + dr;
            gg = gg + dg;
            bb = bb + db;
            if (aa > 255){ aa = 255; da = rnd.Next(-3,0); }
            if (aa < 1) { aa = 0; da = rnd.Next(1, 4); }
            if (rr > 255) { rr = 255; dr = rnd.Next(-3, 0); }
            if (rr < 1) { rr = 0; dr = rnd.Next(1, 4); }
            if (gg > 255) { gg = 255; dg = rnd.Next(-3, 0); }
            if (gg < 1) { gg = 0; dg = rnd.Next(1, 4); }
            if (bb > 255) { bb = 255; db = rnd.Next(-3, 0); }
            if (bb < 1) { bb = 0; db = rnd.Next(1, 4); }
            mars.X0 = virnus.X;
            mars.Y0 = virnus.Y;
            mars.m0 = virnus.m;
            mars.X1 = jupiter.X;
            mars.Y1 = jupiter.Y;
            mars.m1 = jupiter.m;
            virnus.X0 = jupiter.X;
            virnus.Y0 = jupiter.Y;
            virnus.m0 = jupiter.m;
            virnus.X1 = mars.X;
            virnus.Y1 = mars.Y;
            virnus.m1 = mars.m;
            jupiter.X0 = mars.X;
            jupiter.Y0 = mars.Y;
            jupiter.m0 = mars.m;
            jupiter.X1 = virnus.X;
            jupiter.Y1 = virnus.Y;
            jupiter.m1 = virnus.m;
            //足跡は描かない
            
            //歩かせる
            mars.walk();
            virnus.walk();
            jupiter.walk();
            //現在位置を描く
            x1 = (int)Math.Round(mars.X);
            y1 = (int)Math.Round(mars.Y);
            x2 = (int)Math.Round(virnus.X);
            y2 = (int)Math.Round(virnus.Y);
            x3 = (int)Math.Round(jupiter.X);
            y3 = (int)Math.Round(jupiter.Y);
            pen.Color = Color.Red;
            brush.Color = Color.Red;
            pen.Color = Color.FromArgb(aa, rr, gg, bb);
            brush.Color = Color.FromArgb(aa, rr, gg, bb);
            g.DrawEllipse(pen, x1, y1, mars.r, mars.r);
            g.FillEllipse(brush, x1, y1, mars.r, mars.r);
            pen.Color = Color.Green;
            brush.Color = Color.Green;
            pen.Color = Color.FromArgb(bb, aa, rr, gg);
            brush.Color = Color.FromArgb(bb, aa, rr, gg);
            g.DrawEllipse(pen, x2, y2, virnus.r, virnus.r);
            g.FillEllipse(brush, x2, y2, virnus.r, virnus.r);
            pen.Color = Color.FromArgb(gg, bb, aa, rr);
            brush.Color = Color.FromArgb(gg, bb, aa, rr);
            g.DrawEllipse(pen, x3, y3, jupiter.r, jupiter.r);
            g.FillEllipse(brush, x3, y3, jupiter.r, jupiter.r);
        }
    }
ラングトンのアリ
- 新しいクラスの定義
ラングトンのアリのローカルルールに従って動く固体をクラスとして定義する。
- Antクラスは、色の情報を持っているので、Ant.csの冒頭に以下のライブラリーを追加する。
using System.Drawing;
Antクラスの例
    class Ant
    {
        public int d { get; set; }
        public int X { get; set; }
        public int Y { get; set; }
        public int r { get; set; }
        public int MaxHeight { get; set; }
        public int MaxWidth { get; set; }
        private int direction;
        public Color myColor;
        public Color walk( Color nowColor )
        {
            Color retColor;
            if (nowColor == Color.White)
            {
                retColor = myColor;
                direction = (direction + 3) % 4;
            }
            else {
                retColor = Color.White;
                direction = (direction + 1) % 4;
            }
            switch( direction )
            {
                case 0: // north
                    Y = Y - d;
                    break;
                case 1: //east
                    X = X + d;
                    break;
                case 2: // south
                    Y = Y + d;
                    break;
                case 3: // west
                    X = X - d;
                    break;
            }
            // トーラス(ドーナツ型)の世界
            if (X < 0) // 左に抜けると右から出てくる。
                X = MaxWidth + X;
            if (X >= MaxWidth) // 右に抜けると左から出てくる。
                X = X - MaxWidth;
            if (Y < 0) // 上に抜けると下から出てくる。
                Y = MaxHeight + Y;
            if (Y >= MaxHeight)// 下に抜けると上から出てくる。
                Y = Y - MaxHeight;
            return retColor;
        }
    }
メインプログラムでアリをローカルルールに従って歩かせる。
    public partial class Form1 : Form
    {
        Graphics g;
        Pen pen;
        SolidBrush brush;
        private Ant _ant;
        Color antColor1;
        Color antColor2;
        private Color[] map1;
        int X1, Y1;
        public Form1()
        {
            InitializeComponent();
            // 上の行は最初から書かれているので、コピペしない
       
            g = pictureBox1.CreateGraphics();
            map1 = new Color[pictureBox1.Width * pictureBox1.Height];
            for (int i = 0; i < map1.Length; i++)
            {
                map1[i] = Color.White;
            }
            pen = new Pen(Color.Black);
            brush = new SolidBrush(Color.Black);
            _ant = new Ant()
            {
                d = 2,
                X = (int)pictureBox1.Width / 3,
                Y = (int)pictureBox1.Height / 3,
                r = 2,
                MaxWidth = (int)pictureBox1.Width,
                MaxHeight = (int)pictureBox1.Height,
                myColor = Color.SkyBlue,
            };
        }
        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            pen.Color = antColor2;
            g.DrawRectangle(pen, X1, Y1, _ant.r, _ant.r);
            brush.Color = antColor2;
            g.FillRectangle(brush, X1, Y1, _ant.r, _ant.r);
            X1 = _ant.X;
            Y1 = _ant.Y;
            antColor1 = map1[ X1 + Y1 * pictureBox1.Width];
            antColor2 = _ant.walk(antColor1);
            map1[X1 + Y1 * pictureBox1.Width] = antColor2;
            pen.Color = Color.Red;
            g.DrawRectangle(pen, X1, Y1, _ant.r, _ant.r);
            brush.Color = Color.Red;
            g.FillRectangle(brush, X1, Y1, _ant.r, _ant.r);
        }
    }
1次元セルオートマトン
// グラフィック,描画ブラシ,乱数の準備
Graphics g = pictureBox1.CreateGraphics();
SolidBrush brush = new SolidBrush(Color.Black);
Random rnd = new Random();
// セルの状態格納用の2次元整数型配列を用意
int ookisa = 100;// 配列の大きさ
int[ , ] cell = new int[ookisa, ookisa];
//セルの初期状態
for (int j = 0; j < ookisa; j++)
{
  cell[0, j] = rnd.Next(0, 0);
}
cell[0, ookisa / 2] = 128;
//セルの状態遷移則
for (int i = 1; i < ookisa; i++)
{
  for (int j = 1; j < ookisa - 1; j++)
  {
     cell[i, j] = (cell[i - 1, j - 1] + cell[i - 1, j + 1]) % 256;
  }
}
//セルの描画
int pixsz = 5;
for (int i=0; i < ookisa; i++){
  for (int j=0; j < ookisa; j++)
  {
    brush.Color = Color.FromArgb(255, cell[i, j], 0, 0);
    g.FillRectangle(brush, j * pixsz, i * pixsz, pixsz, pixsz);
  }
}
変化形
//セルの初期状態
for (int j = 0; j < ookisa; j++)
{
   cell[0, j] = rnd.Next(0, 0) ;
}
cell[0, ookisa / 2] = 7;
cell[0, ookisa / 3] = 6;
cell[0, ookisa / 4] = 3;
cell[0, ookisa / 3 * 2] = 70;
//セルの状態遷移則
for (int i = 1; i < ookisa; i++)
{
  for (int j = 1; j < ookisa - 1; j++)
  {
     cell[i, j] = (cell[i - 1, j - 1] + cell[i - 1, j + 1] + cell[i - 1, j] ) % 256;
  }
}
//セルの描画
int pixsz = 5;
for (int i=0; i < ookisa; i++)
{
  for (int j=0; j < ookisa; j++)
  {
     brush.Color = Color.FromArgb(255, cell[i, j], cell[j, i], 0);
     g.FillRectangle(brush, j * pixsz, i * pixsz, pixsz, pixsz);
  }
}
フラクタル
古代ギリシャからあるユークリッド幾何学と20世紀のフラクタル幾何学の比較
- 考察
- 古代エジプト人は3:4:5の辺を持つ三角形で直角が得られることを知っていた.ピラミッドなどの巨大建造物.
- 三平方の定理を発見したピタゴラスはどこがすごいか?
- フラクタル図形
自己相似系
再帰的呼出しによる樹木の描画
- 再帰的( recursive )呼び出しとは,サブルーチンや関数が,自分自身を呼び出すことをいう。樹木は,枝の1つを取り出して拡大しても,元の枝と同じ形(相似形)をしている。これは,同じサブルーチンで枝を描画しているからである。
C#による実装
新しいクラスの定義
- 「プロジェクト」メニューから「クラスの追加」で新しいクラス名を入力する。クラスの定義の中にメソッドを記述する。
- 注意
using System.Drawing;
をTane.csの冒頭に追加
樹木の描画
- Taneクラスのメソッド
線分(x1,y1)-(x2,y2)が与えられたら、(x2,y2)の先端に(x3,y3), (x4,y4)を取り、線分(x2,y2)-(x3,y3)と線分(x2,y2)-(x4,y4)を描画する。
    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);
            }
        }
    }
- 樹木描画ボタンクリックの中身
            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);
コッホ図形の描画
- Taneクラスのメソッド
        public void Koch(int n, double x1, double y1, double x2, double y2, Graphics g, Pen pen)
        {
            double x3, y3, x4, y4, x5, y5;
            double s = Math.Sin(Math.PI / 3.0);
            double c = Math.Cos(Math.PI / 3.0);
            if (n > 0)
            {
                x3 = (2 * x1 + x2) / 3.0;
                y3 = (2 * y1 + y2) / 3.0;
                x4 = (x1 + 2 * x2) / 3.0;
                y4 = (y1 + 2 * y2) / 3.0;
                x5 = x3 + (x4 - x3) * c + (y4 - y3) * s;
                y5 = y3 - (x4 - x3) * s + (y4 - y3) * c;
                // ジェネレータを描画する
                pen.Color = Color.Black;
                g.DrawLine(pen, (float)x3, (float)y3, (float)x4, (float)y4);
                pen.Color = Color.Green;
                g.DrawLine(pen, (float)x1, (float)y1, (float)x3, (float)y3);
                g.DrawLine(pen, (float)x3, (float)y3, (float)x5, (float)y5);
                g.DrawLine(pen, (float)x5, (float)y5, (float)x4, (float)y4);
                g.DrawLine(pen, (float)x4, (float)y4, (float)x2, (float)y2);
                // 子の再起呼び出し
                Koch(n - 1, x1, y1, x3, y3, g, pen);
                Koch(n - 1, x3, y3, x5, y5, g, pen);
                Koch(n - 1, x5, y5, x4, y4, g, pen);
                Koch(n - 1, x4, y4, x2, y2, g, pen);
            }
        }
- コッホ図形描画ボタンクリックの中身
            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);
ドラゴン図形の描画
- Taneクラスのメソッド
        public void Dragon(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 = 0.5 * ( x1 + x2);
                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);
            }
        }
- ドラゴン図形描画ボタンクリックの中身
            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.Dragon(n, x0, y0, x1, y1, g, pen);
シダ葉の描画
- ドラゴン図形の変化形
- ドラゴン図形で使用した(x1,y1), (x2,y2), (x3,y3), (x4,y4), (x5,y5)を使う
- 直線(x1,y1)-(x2,y2), 直線(x1,y1)-(x4,y4), 直線(x3,y3)-(x5,y5)を基本図形とする。
- Taneクラスのメソッド
        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);
            }
        }
- シダ葉描画ボタンクリックの中身
            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);
Cカーブの描画
- Taneクラスのメソッド
        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);
            }
        }
- Cカーブ画ボタンクリックの中身
            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);
内分点と回転によるカスタムジェネレータの描画
- Taneクラスのメソッド
        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);
            }
        }
- カスタムジェネレータ描画ボタンクリックの中身
            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);
- マウスドラッグで始点と終点を決めて描く
- プロパティウィンドウにイベント(稲妻のアイコン)のリストを表示させ、MouseDownイベントをダブルクリックすると、MouseDownのメソッドが自動生成されます。
- label1,label2に始点の座標を、label3, label4に終点の座標を入れる
        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();
        }
p,q,thをクラスのメンバー変数にして、外部からランダムに与える。
    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);
            }
        }
    }
        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);
        }
タイマーを使用した樹木のアニメーション
        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);
        }
複素平面フラクタル
- 配布資料PDF
- 複複素平面フラクタル図形描画ソフトウェア for Windows
- 注)comdlg32.ocxがない場合は,ここからRuntimeファイル群をダウンロードしてください。
 
C#の座標変換
- 座標原点
原点を移動するには、TranslateTransformメソッドを使う。
          g.TranslateTransform(x1,y1); //座標原点を(x1,y1)に移動
- 座標の回転
座標軸をth度(degree)だけ回転するには、RotateTransformメソッドを使う。
g.RotateTransform(th);
- 座標軸のスケール、方向
座標スケールを変換するには、ScaleTransformメソッドを使う。
            g.ScaleTransform(scx,scy);  //X軸をscx倍、Y軸をscy倍する
X軸は右、Y軸は下が正方向なので、座標軸方向を反転するには、次のとおり。
g.ScaleTransform(1,-1); //Y軸方向の反転 g.ScaleTransform(-1,1); //X軸方向の反転
複素平面フラクタルの描画
- 自己平方の描画プログラム
            Graphics g = pictureBox1.CreateGraphics();
            g.TranslateTransform(pictureBox1.Width / 2, pictureBox1.Height / 2); //原点を中央に移動
            g.ScaleTransform(1, -1); //Y軸の向きを反転
            Pen pen = new Pen(Color.White);
            int Xmax = pictureBox1.Width / 2;
            int Xmin = -pictureBox1.Width / 2;
            int Ymax = pictureBox1.Height / 2;
            int Ymin = -pictureBox1.Height / 2;
            double Rmax = 0.5;
            double Rmin = -0.5;
            double Imax = 0.5;
            double Imin = -0.5;
            double Zr, newZr;
            double Zi, newZi;
            double Ar = -0.2;
            double Ai = 0.675;
            int Nmax = 100;
            int Rstep = 1; // 何ピクセルごとに計算するか
            int Istep = 1;
            for (int x = Xmin; x < Xmax; x = x + Rstep)
            {
                for (int y = Ymin; y < Ymax; y = y + Istep)
                {
                    Zr = ( x - Xmin ) * (Rmax - Rmin) / (Xmax - Xmin) + Rmin; // pictureBoxの座標を複素平面Zの座標に変換
                    Zi = ( y - Ymin ) * (Imax - Imin) / (Ymax - Ymin) + Imin;
                    int n = 0;
                    while ( Zr * Zr + Zi * Zi < 4 & n < Nmax )
                    {
                        newZr = Zr * Zr - Zi * Zi + Ar; // f(z) = X^2 * Aの実数部
                        newZi = 2 * Zr * Zi + Ai; // f(z) = X^2 * Aの虚数部
                        Zr = newZr;
                        Zi = newZi;
                        n++;
                    }
                    if (n < Nmax)
                    {
                        pen.Color = Color.FromArgb(255, n * 255 / Nmax, 0, 0);//nの数に応じて色分ける
                        g.DrawRectangle(pen, x, y, 1, 1);
                    }
                }
            }
- マンデルブロー集合の描画プログラム
            Graphics g = pictureBox1.CreateGraphics();
            g.TranslateTransform(pictureBox1.Width / 2, pictureBox1.Height / 2); //原点を中央に移動
            g.ScaleTransform(1, -1); //Y軸の向きを反転
            Pen pen = new Pen(Color.White);
            int Xmax = pictureBox1.Width / 2;
            int Xmin = -pictureBox1.Width / 2;
            int Ymax = pictureBox1.Height / 2;
            int Ymin = -pictureBox1.Height / 2;
            double Rmax = 1.5;
            double Rmin = -1.5;
            double Imax = 1.5;
            double Imin = -1.5;
            double Zr, newZr;
            double Zi, newZi;
            double Cr;
            double Ci;
            int Nmax = 50;
            int Rstep = 1; // 何ピクセルごとに計算するか
            int Istep = 1;
            for (int x = Xmin; x < Xmax; x = x + Rstep)
            {
                for (int y = Ymin; y < Ymax; y = y + Istep)
                {
                    Cr = ( x - Xmin ) * (Rmax - Rmin) / (Xmax - Xmin) + Rmin; // pictureBoxの座標を複素平面Cの座標に変換
                    Ci = ( y - Ymin ) * (Imax - Imin) / (Ymax - Ymin) + Imin;
                    int n = 0;
                    Zr = 0.0;
                    Zi = 0.0;
                    while (Zr * Zr + Zi * Zi < 4 & n < Nmax)
                    {
                        newZr = Zr * Zr - Zi * Zi + Cr; // f(z) = X^2 * Cの実数部
                        newZi = 2 * Zr * Zi + Ci; // f(z) = X^2 * Cの虚数部
                        Zr = newZr;
                        Zi = newZi;
                        n++;
                    }
                    if (n < Nmax)
                    {
                        pen.Color = Color.FromArgb(255, 0, n * 255 / Nmax, 0);//nの数に応じて色分ける
                        g.DrawRectangle(pen, x, y, 1, 1);
                    }
                }
            }
- Julia集合
            Graphics g = pictureBox1.CreateGraphics();
            g.TranslateTransform(pictureBox1.Width / 2, pictureBox1.Height / 2); //原点を中央に移動
            g.ScaleTransform(1, -1); //Y軸の向きを反転
            Pen pen = new Pen(Color.White);
            int Xmax = pictureBox1.Width / 2;
            int Xmin = -pictureBox1.Width / 2;
            int Ymax = pictureBox1.Height / 2;
            int Ymin = -pictureBox1.Height / 2;
            double Rmax = 1.5;
            double Rmin = -1.5;
            double Imax = 1.5;
            double Imin = -1.5;
            double Xr, Xr2, XrXi23, newXr;
            double Xi, Xi2, newXi;
            double Dr;
            double Di;
            int Nmax = 50;
            int Rstep = 1; // 何ピクセルごとに計算するか
            int Istep = 1;
            for (int x = Xmin; x < Xmax; x = x + Rstep)
            {
                for (int y = Ymin; y < Ymax; y = y + Istep)
                {
                    Xr = ( x - Xmin ) * (Rmax - Rmin) / (Xmax - Xmin) + Rmin; // pictureBoxの座標を複素平面Cの座標に変換
                    Xi = ( y - Ymin ) * (Imax - Imin) / (Ymax - Ymin) + Imin;
                    int n = 0;
                    Dr = 1.0;
                    Di = 1.0;
                    while (Dr + Di > 0.001 & n < Nmax)
                    {
                        Xr2 = Xr * Xr;
                        Xi2 = Xi * Xi;
                        XrXi23 = (Xr2 + Xi2) * (Xr2 + Xi2) / 3;
                        newXr = Xr * 2 / 3 + (Xr2 - Xi2) / XrXi23; // f(z) = X^2 * Cの実数部
                        newXi = Xi * 2 / 3 - 2 * Xr * Xi / XrXi23; // f(z) = X^2 * Cの虚数部
                        Dr = Math.Abs(newXr - Xr);
                        Di = Math.Abs(newXi - Xi);
                        Xr = newXr;
                        Xi = newXi;
                        n++;
                    }
                    if (n < Nmax)
                    {
                        int rr = n * 255 / Nmax;
                        int gg = 0;
                        int bb = 0;
                        pen.Color = Color.FromArgb(255, rr, gg, bb);//nの数に応じて色分ける
                        g.DrawRectangle(pen, x, y, 1, 1);
                    }
                }
            }
配色の工夫
個々の色の差をハッキリさせる。
    int rr = (n % 13 + 1) * 255 / 14;
    int gg = (n % 11 + 1) * 255 / 12;
    int bb = (n % 7 + 1) * 255 / 8;
    pen.Color = Color.FromArgb(255, rr, gg, bb);
    g.DrawRectangle(pen, x, y, Rstep, Istep);
ピクセルの目を粗くした時に、矩形の中身を塗りつぶす。
    pen.Color = Color.FromArgb(255, rr, gg, bb);
    brush.Color = Color.FromArgb(255, rr, gg, bb);
    g.DrawRectangle(pen, x, y, Rstep, Istep);
    g.FillRectangle(brush, x, y, Rstep, Istep);
Ar, Ai, Rstep, Istepなどをテキストボックスから入力する。
            Ar = double.Parse(textBox1.Text);
            Ai = double.Parse(textBox2.Text);
            Rstep = int.Parse(textBox3.Text);
            Istep = Rstep;
いろいろカスタマイズ
- 複素平面の座標のスケールをラベルに表示する。
- マウスドラッグで、新しく描画する範囲を選択する。
- 選択領域を正方形にするかどうかを、チェックボックスで指定する。
        // グローバルに宣言
        Point MD = new Point();//マウスダウンの位置
        Point MU = new Point(); //マウスアップの位置
        bool view = false;//選択領域を描画するかどうかの判定
        bool view2 = false;
        Graphics g;
        int Xmax;
        int Xmin;
        int Ymax;
        int Ymin;
        double Rmax;
        double Rmin;
        double Imax;
        double Imin;
        double Rmax2;//マウスドラッグで指定した新しい範囲
        double Rmin2;
        double Imax2;
        double Imin2;
        public Form1()
        {
            InitializeComponent();
            g = pictureBox1.CreateGraphics();
            g.TranslateTransform(pictureBox1.Width / 2, pictureBox1.Height / 2); //原点を中央に移動
            g.ScaleTransform(1, -1); //Y軸の向きを反転
            view2 = true;
            Xmax = pictureBox1.Width / 2;
            Xmin = -pictureBox1.Width / 2;
            Ymax = pictureBox1.Height / 2;
            Ymin = -pictureBox1.Height / 2;
            Rmax2 = 0.5;
            Rmin2 = -0.5;
            Imax2 = 0.5;
            Imin2 = -0.5;
            Rmax = Rmax2;
            Rmin = Rmin2;
            Imax = Imax2;
            Imin = Imin2;
            label1.Text = null;
            label2.Text = null;
            label3.Text = null;
            label4.Text = null;
            label5.Text = Rmax2.ToString();
            label6.Text = Rmin2.ToString();
            label7.Text = Imax2.ToString();
            label8.Text = Imin2.ToString();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            Pen pen = new Pen(Color.White);
            SolidBrush brush = new SolidBrush(Color.FromArgb(90, 200, 200, 200));
            g.Clear(Color.Black); //描画領域をクリア(黒で塗りつぶす)
            Rmax = Rmax2;
            Rmin = Rmin2;
            Imax = Imax2;
            Imin = Imin2;
            label5.Text = Rmax2.ToString();
            label6.Text = Rmin2.ToString();
            label7.Text = Imax2.ToString();
            label8.Text = Imin2.ToString();
            label5.Refresh();
            label6.Refresh();
            label7.Refresh();
            label8.Refresh();
            view2 = true;
            double Zr, newZr;
            double Zi, newZi;
            double Ar = -0.2;
            double Ai = 0.675;
//            double Ar = -0.3;
//            double Ai = 0.63;
            Ar = double.Parse(textBox1.Text);//テキストボックスから値を取得
            Ai = double.Parse(textBox2.Text);
            int Nmax = 500;
            int Rstep = 3; // 何ピクセルごとに計算するか
            int Istep = 3;
            Rstep = int.Parse(textBox3.Text);
            Istep = Rstep;
            for (int x = Xmin; x < Xmax; x = x + Rstep)
            {
                for (int y = Ymin; y < Ymax; y = y + Istep)
                {
                    Zr = ( x - Xmin ) * (Rmax - Rmin) / (Xmax - Xmin) + Rmin; // pictureBoxの座標を複素平面Zの座標に変換
                    Zi = ( y - Ymin ) * (Imax - Imin) / (Ymax - Ymin) + Imin;
                    int n = 0;
                    while ( Zr * Zr + Zi * Zi < 4 & n < Nmax )
                    {
                        newZr = Zr * Zr - Zi * Zi + Ar; // f(z) = X^2 * Aの実数部
                        newZi = 2 * Zr * Zi + Ai; // f(z) = X^2 * Aの虚数部
                        Zr = newZr;
                        Zi = newZi;
                        n++;
                    }
                    if (n < Nmax)
                    {
                        int dr = 17;
                        int rr = (n % dr + 1) * 255 / (dr + 1);
                        int gg = (n % 11 + 1) * 255 / 12;
                        int bb = (n % 7 + 1) * 255 / 8;
                        pen.Color = Color.FromArgb(255, rr, gg, 255 - bb);//nの数に応じて色分ける
                        brush.Color = Color.FromArgb(255, rr, gg, 255 - bb);//nの数に応じて色分ける
                        g.DrawRectangle(pen, x, y, Rstep, Istep);
                        g.FillRectangle(brush, x, y, Rstep, Istep);
                    }
                }
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            Graphics g = pictureBox1.CreateGraphics();
            g.Clear(Color.Black); //描画領域をクリア(黒で塗りつぶす)
            label1.Text = null;
            label2.Text = null;
            label3.Text = null;
            label4.Text = null;
            label5.Text = Rmax2.ToString();
            label6.Text = Rmin2.ToString();
            label7.Text = Imax2.ToString();
            label8.Text = Imin2.ToString();
            view2 = true;
        }
        // 以下、マウスイベントによって選択範囲を取得する処理
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (view2 == false) return;
            // 描画フラグON
            view = true;
            // Mouseを押した座標を記録
            MD.X = e.X - Xmax;
            MD.Y = Ymax - e.Y;
        }
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (view2 == false) return;
            Point start = new Point();
            Point end = new Point();
            // Mouseを離した座標を記録
            MU.X = e.X - Xmax;
            MU.Y = Ymax - e.Y;
            // 座標から(X,Y)座標を計算
            GetRegion(MD, MU, ref start, ref end);
            // 領域を描画
            DrawRegion(start, end);
            // 描画フラグOFF
            view = false;
            view2 = false;
        }
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (view2 == false) return;
            Point p = new Point();
            p.X = e.X - Xmax;
            p.Y = Ymax - e.Y;
            // 描画フラグcheck
            if (view == false)
            {
                label1.Text = ( ( p.X - Xmin ) * (Rmax - Rmin) / (Xmax - Xmin) + Rmin ).ToString();
                label2.Text = ( ( p.Y - Ymin ) * (Imax - Imin) / (Ymax - Ymin) + Imin ).ToString();
                label3.Text = null;
                label4.Text = null;
                return;
            }
            // カーソルが示している場所の座標を取得
            label3.Text = ( (p.X - Xmin) * (Rmax - Rmin) / (Xmax - Xmin) + Rmin ).ToString();
            label4.Text = ( (p.Y - Ymin) * (Imax - Imin) / (Ymax - Ymin) + Imin ).ToString();
        }
        private void GetRegion(Point p1, Point p2, ref Point start, ref Point end)
        {
            start.X = Math.Min(p1.X, p2.X);
            start.Y = Math.Min(p1.Y, p2.Y);
            end.X = Math.Max(p1.X, p2.X);
            end.Y = Math.Max(p1.Y, p2.Y);
            if (checkBox1.Checked == true) //選択領域を正方形にする
            {
                int min_x_y = Math.Min(Math.Abs(end.X - start.X), Math.Abs(end.Y - start.Y));
                end.X = start.X + min_x_y;
                end.Y = start.Y + min_x_y;
            }
            Rmax2 = ( end.X - Xmin ) * (Rmax - Rmin) / (Xmax - Xmin) + Rmin; // pictureBoxの座標を複素平面Zの座標に変換
            Imax2 = ( end.Y - Ymin ) * (Imax - Imin) / (Ymax - Ymin) + Imin;
            Rmin2 = ( start.X - Xmin ) * (Rmax - Rmin) / (Xmax - Xmin) + Rmin;
            Imin2 = ( start.Y - Ymin ) * (Imax - Imin) / (Ymax - Ymin) + Imin;
        }
        private int GetLength(int start, int end)
        {
            return Math.Abs(start - end);
        }
        private void DrawRegion(Point start, Point end)
        {
            Pen blackPen = new Pen(Color.White);
            SolidBrush tbrush = new SolidBrush(Color.FromArgb(100,220,220,220));
            // 描画する線を点線に設定
//            blackPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
            // 画面を消去
//            g.Clear(SystemColors.Control);
            // 領域を描画
            g.DrawRectangle(blackPen, start.X, start.Y, GetLength(start.X, end.X), GetLength(start.Y, end.Y));
            g.FillRectangle(tbrush, start.X, start.Y, GetLength(start.X, end.X), GetLength(start.Y, end.Y));
        }
        private void button5_Click(object sender, EventArgs e)
        {
            // 座標を初期値に戻す
            Rmax2 = 0.5;
            Rmin2 = -0.5;
            Imax2 = 0.5;
            Imin2 = -0.5;
            label1.Text = null;
            label2.Text = null;
            label3.Text = null;
            label4.Text = null;
            label5.Text = Rmax2.ToString();
            label6.Text = Rmin2.ToString();
            label7.Text = Imax2.ToString();
            label8.Text = Imin2.ToString();
        }
- 座標のスケールの拡大、縮小ボタンを付ける
        private void button6_Click(object sender, EventArgs e)
        {
            // 座標のスケールを5倍にする
            double ratio = 5.0;
            double R_ave = ( Rmax2 + Rmin2 ) / 2;
            double R_dif2 = ( Rmax2 - Rmin2 ) / 2;
            double I_ave = ( Imax2 + Imin2 ) / 2;
            double I_dif2 = ( Imax2 - Imin2 ) / 2;
            Rmax2 = R_ave + R_dif2 * ratio;
            Rmin2 = R_ave - R_dif2 * ratio;
            Imax2 = I_ave + I_dif2 * ratio;
            Imin2 = I_ave - I_dif2 * ratio;
            label5.Text = Rmax2.ToString();
            label6.Text = Rmin2.ToString();
            label7.Text = Imax2.ToString();
            label8.Text = Imin2.ToString();
        }
        private void button7_Click(object sender, EventArgs e)
        {
            // 座標のスケールを5分の1倍にする
            double ratio = 5.0;
            double R_ave = (Rmax2 + Rmin2) / 2;
            double R_dif2 = (Rmax2 - Rmin2) / 2;
            double I_ave = (Imax2 + Imin2) / 2;
            double I_dif2 = (Imax2 - Imin2) / 2;
            Rmax2 = R_ave + R_dif2 / ratio;
            Rmin2 = R_ave - R_dif2 / ratio;
            Imax2 = I_ave + I_dif2 / ratio;
            Imin2 = I_ave - I_dif2 / ratio;
            
            label5.Text = Rmax2.ToString();
            label6.Text = Rmin2.ToString();
            label7.Text = Imax2.ToString();
            label8.Text = Imin2.ToString();
        }
- 座標の上下左右へシフトさせるボタンを付ける
        private void button8_Click(object sender, EventArgs e)
        {
            // 座標のスケールを左に0.5スケールシフトする
            double R_ave = (Rmax2 + Rmin2) * 0.5;
            double R_dif2 = (Rmax2 - Rmin2) * 0.5;
            Rmax2 = Rmax2 - R_dif2;
            Rmin2 = Rmin2 - R_dif2;
            label5.Text = Rmax2.ToString();
            label6.Text = Rmin2.ToString();
        }
        private void button9_Click(object sender, EventArgs e)
        {
            // 座標のスケールを右に0.5スケールシフトする
            double R_ave = (Rmax2 + Rmin2) * 0.5;
            double R_dif2 = (Rmax2 - Rmin2) * 0.5;
            Rmax2 = Rmax2 + R_dif2;
            Rmin2 = Rmin2 + R_dif2;
            label5.Text = Rmax2.ToString();
            label6.Text = Rmin2.ToString();
        }
        private void button10_Click(object sender, EventArgs e)
        {
            // 座標のスケールを下に0.5スケールシフトする
            double I_ave = (Imax2 + Imin2) * 0.5 ;
            double I_dif2 = (Imax2 - Imin2) * 0.5;
            Imax2 = Imax2 - I_dif2;
            Imin2 = Imin2 - I_dif2;
            label7.Text = Imax2.ToString();
            label8.Text = Imin2.ToString();
        }
        private void button11_Click(object sender, EventArgs e)
        {
            // 座標のスケールを上に0.5スケールシフトする
            double I_ave = (Imax2 + Imin2) * 0.5;
            double I_dif2 = (Imax2 - Imin2) * 0.5;
            Imax2 = Imax2 + I_dif2;
            Imin2 = Imin2 + I_dif2;
            label7.Text = Imax2.ToString();
            label8.Text = Imin2.ToString();
        }
人間の感覚
アロマアート
嗅覚を利用したアート
かんたん掲示板に「香りの特徴」を書いてみよう。
- 香りの印刷
- アロマプリンタ
- 映画RAMPO
- ブンマー・モンティエン,呼吸の家
- 彫刻の中に入ってハーブの香りを体感するもの (東京都現代美術館) http://www.tokyoartbeat.com/tablog/images/ShowMeThai3.jpg
 
- アムラックスシアター
- シーンに合わせた座席の振動・香りつきのシアター(トヨタ・アムラックス)
 
共感覚
- 色彩と調性の関係性についての実験サイト(久原ゼミの実験企画)
- 色聴は共感覚(関西学院理工学部情報科学科の長田典子先生の研究室)
ヒーリングアート
- リラックスとリフレッシュ
- リラックス時には副交感神経が優勢に,興奮状態にある場合は、交感神経が優勢になる。
- リラックス時にはアルファ波が出る?
- 1/f揺らぎ
- ホワイトノイズ、サイン波、ピンクノイズ(1/f揺らぎ)
- 自然界の音を使用した楽曲 URL
-  スペクトル
- EQ(イコライザ)によって,音のスペクトルを加工する。
-  スペクトルとは周波数構成のこと。ピッチ感のある音は,ピークとなる基本周波数を中心として複数の倍音成分から構成される。
- SoundEngineやAudacityでsin波などを生成し,周波数構成を観察。sin波は基本周波数1つのみ。ノコギリ波はsin波の倍数の無限級数。ホワイトノイズはランダムな周波数構成。
- 人のボーカル,楽器の音,車のエンジン音のスペクトルを比較してみる。
 
 
- 子守唄
- 生物的なシステム,生物の癒し効果
flash effects / Levitated the Exploration of Computation / sodaplay/ Vector Park / リヴリー・アイランド / エレクトロプランクトン / たまごっちプラス / メンタルコミットロボアザラシ型「パロ」 / 猫型コミュニケーションロボット「ネコロ」 / nintendogs / What is TRUTH? /
- Vector Parkのegg.swf
- CLAMBON FARM
- flOw
- 電子ペット Comたま URL / PDF
脳
- 脳波,脳電図(electroencephalogram EEG)
- 大脳皮質のニューロンの膨大な数のシナプス結合における電位(シナプス後電位)の集合と考えられている。
- 通常は,空間的および時間的分散性のために一定の形状の波形にはならない。しかし,大脳皮質の活性度が低下した時にはある程度の同期性がみられ,その代表的な状態が睡眠時の脳波である。
- 開眼時,脳の神経細胞があちこちで活発に作動していると,シナプス電位は同期が取れずに,脳波はランダムなになり,特定の周波数は測定されない。
- デルタ波(δ波):1~3Hz ぐっすり睡眠.昏睡.
- シータ波(θ波):4~7Hz うたたうね.ぼんやり.
- アルファ波(α波):8~13Hz 覚醒,安静,閉眼時。リラックス。
- ベータ波(β波):14~30Hz 開眼時,五感が働いている状態。活発な思考。
- ガンマ波(γ波):30~64Hz 高次精神活動に関連(?)
- オメガ波(ω波):64~128Hz(?)
- ロー波(ρ波):128-512Hz (?)
- シグマ波(σ波):512-1024Hz (?)
- アーティファクト:ノイズ(雑音)。まばたき,眼球運動,電極の接着不良など脳と無関係のものが要因。
バイノーラルビート
周波数追従反応
脳磁図,生物フォトン,心電図,筋電図,眼電図。
- イリュージュン・フォーラム
- 簡単BBSに聞こえ方を書いてみよう。
 
Neural Networks
- 神経回路モデル(PPT)
- 神経細胞の写真,構成図[ 1 | 2 | 3 ]
- ニューラルネットワーク入門
- Perceptron,
- Back Propagation
- Hopfield Network
- 自己組織化ネットワーク
- 脳の潜在能力
- 天文学者カール・セーガン「人間の脳はおよそ2,000万冊,すなわち世界最大の図書館に収められているのと同じ数の本を満たすほどの情報を収納することができる」
- 神経科学者「人は平均寿命の間に脳の潜在能力の0.01%(0.0001)しか使っていない」
 
Genetic Algorithm
- カール・セーガン「コスモス」エピソードII第3話「平家物語と蟹のなぞ」
- 瀬戸内海の蟹の甲羅は武士の顔に似ているのはなぜか?
 
- geno typeとpheno type
- GAの概念と応用例
小テスト
- 場所 いつものPC演習室
- 出題 配布資料などから出題されます。ノート,配布資料などを復習しておいてください。問題の形式は,選択式です。
-  注意事項
- 座席は自由ですが,隣の座席を1つ空けて座ってください。
- 持ち込みは不可です。机の上には一切,何も置かないで下さい。
- PC上のソフトはブラウザだけ起動してください。他のアプリケーションはすべて終了させてください。
 
Github
共同開発するときに便利。
学内のプロキシー環境で作業する場合、コンソールで
git config --global http.proxy proxy-n.t-kougei.ac.jp:8080 git config --global https.proxy proxy-n.t-kougei.ac.jp:8080
とする。
通常のプロキシーのない環境で作業する場合、コンソールで
git config --global --unset http.proxy proxy-n.t-kougei.ac.jp:8080 git config --global --unset https.proxy proxy-n.t-kougei.ac.jp:8080
とする。
現在の設定を確認するには、コンソールで、
git config --list
とする。
リンク
素数のグラフィック http://www.datapointed.net/visualizations/math/factorization/animated-diagrams/?infinity







