強火で進め

このブログではプログラム関連の記事を中心に書いてます。

プログラムでシダを描画する


プログラマーであれば誰もが描画したくなるシダ。

自分もご多分にもれず描画したく成ってしまったので計算式を求めてググってみた所、こちらの動画を発見。

こちらの動画には十進BASIC向けの以下のコードが記載されていました。

【十進BASIC用のコード】

SET TEXT BACKGROUND "OPAQUE"
LET t$="シダ"
LET N=20
LET xm=0
LET ym=0.5
LET h=0.6
!----------------------------
SET WINDOW xm-h, xm+h, ym-h, ym+h
DRAW axes
PLOT TEXT,AT xm+h*0.1,ym+h*0.85:t$
PLOT TEXT,AT xm+h*0.5,ym+h*0.85, USING "N =%%":N
PLOT TEXT,AT xm-h*0.75, ym+h*0.85:"しばらくおまちください"
SET POINT STYLE 1
SET POINT COLOR 10 !51
CALL f(N, 0,0)
beep
PLOT TEXT,AT xm-h*0.75, ym+h*0.85:"描画終了"
!------------------------------------------------------------
DEF W1x(x,y)=0.836*x+0.044*y
DEF W1y(x,y)=-0.044*x+0.836*y+0.169 ! p1=0.4
DEF W2x(x,y)=-0.141*x+0.302*y
DEF W2y(x,y)=0.302*x+0.141*y+0.127 ! p2=0.2
DEF W3x(x,y)=0.141*x-0.302*y
DEF W3y(x,y)=0.302*x+0.141*y+0.169 ! p3=0.2
DEF W4x(x,y)=0
DEF W4y(x,y)=0.175337*y !p4=0.2
!------------------------------------------------------------
SUB f(k, x,y)
   IF 0<k THEN
      CALL f(k-1,W1x(x,y),W1y(x,y))
      IF RND<0.3 THEN CALL f(k-1,W2x(x,y),W2y(x,y))
      IF RND<0.3 THEN CALL f(k-1,W3x(x,y),W3y(x,y))
      IF RND<0.3 THEN CALL f(k-1,W4x(x,y),W4y(x,y))
   ELSE
      PLOT POINTS:x,y
   END IF
END SUB
END

行番号の付いてない様な高度なBASICはさっぱり読めないのですが勘で Processing に移植してみました(十進BASICでは ! はコメントに使うっぽいというのに気がつくまでちょっとだけ苦戦させられましたw)。

【 Processing 用のコード】

int N=20;
float xm=0;
float ym=0.5;
float h=0.6;

float W1x(float x, float y) {
  return 0.836*x+0.044*y;
}
float W1y(float x, float y) {
  return -0.044*x+0.836*y+0.169;
}
float W2x(float x, float y) {
  return -0.141*x+0.302*y;
}
float W2y(float x, float y) {
  return 0.302*x+0.141*y+0.127;
}
float W3x(float x, float y) {
  return 0.141*x-0.302*y;
}
float W3y(float x, float y) {
  return 0.302*x+0.141*y+0.169;
}
float W4x(float x, float y) {
  return 0;
}
float W4y(float x, float y) {
  return 0.175337*y;
}

void f(int k, float x, float y) {
  if (0<k) {
    f(k-1, W1x(x,y), W1y(x,y));
    if (random(1.0) < 0.3) f(k-1, W2x(x,y), W2y(x,y));
    if (random(1.0) < 0.3) f(k-1, W3x(x,y), W3y(x,y));
    if (random(1.0) < 0.3) f(k-1, W4x(x,y), W4y(x,y));
  } else {
    float s = 490;
    point(x*s+width*.5, height-y*s);
  }
}

void setup() {
  background(255);
  size(500, 500);
  stroke(0, 128, 0);
  f(N, 0, 0);
}

こんな感じに無事、十進BASIC版と同様の描画が出来ました。満足!!