最終更新日



マンデルブロート・カオス(アプレット2)

[ブラウザソフトのJava対応]
 アプレットを見るには、Java対応、すなわち、JavaのVMをそなえたブラウザソフトでないといけない。マイクロソフトのIEは、Java1.1という古いシステムをサポートしていたが、XPのSP1以降、サポートをうちきりました。その後は、各メーカが独自に対応しているが、統一はされていない。もし、このページのアプレット画面が見られない場合は、ブラウザソフトのJava対応 を参照ください。

なお、Java1.1という古いシステムをサポートしていた頃の遺物、J2SE1.2.2でコンパイルし直したものを5章に残しておきます。


1 マンデルブロート 2 プログラムの一般化 3 拡大率をあげた場合のマンデルブロート図 4 カオス
 5 J2SE1.2.2でコンバイルしたマンデルブロート

1 マンデルブロート

初期値のちょっとした違いが計算の繰り返しで大きく異なることを色づけしたマンデルブロート図形やシダの葉などである。フラクタル図形はなんとか解析できるが、このマンデルブロートやカオスの計算式と図形との関連はよくわからない。不思議な図形を描くので、パラメータを変えてトライしてみる。

横軸a,縦軸bで指定した位置に、その値を初期値とするzの計算をして、4より大きいなら、その値に応じた色で打点していくというもの。したがって、苦労して作ったTurtleパッケージも特に必要としない作りにした。

なお、フラクタル図形のページにも書いたことだが、下記のトライ例が動かない場合の対策。マイクロソフトのOSにも、アプレット対応のVMは入っていると思うが、最新のサンマイクロシステムズのJavaシステム(J2SE)に対応していないのかもしれない。JavaのVM(Vertual Machine、Run Time System)を導入いただきたい。 Java Web Start

実際のトライ例
倍率と横軸の範囲による違い。クリックすると、Javaが働いて実際に図形を描いていく様子が見える。

100倍 -5.12から-5.12 400倍 -2.03から2.03" 1000倍 -2.012から-1.012

1 マンデルブロート100

import java.applet.Applet;
import java.awt.*;

public class Mandel100 extends Applet {
	public int curr_x,curr_y;
	
    public void paint(Graphics g) { 
      // setBackground(Color.black);
        Dimension d = getSize();
        curr_x=d.width/2;
        curr_y=d.height/2;
        //背景を黒く
        g.fillRect(0,0,2*curr_x,2*curr_y);
        //マンデルブローの呼び出し
        mandel100(g,-5.12,-3.84,100);
   }     

  void mandel100(Graphics g,double a,double b,int zoom) {
	double a0=a;
	double b0=b;
 	while (a<-a0) {
          while (b<0.0) {
  	        double z=keisan(0.0,0.0,0,a,b);
 	           if (z>4.0) {
			if (z>12.0)
			  setc(g,(int)(z*30.0)%12);
		        else
		      	  setc(g,(int)(z));
			 dot(g,curr_x+(int)(zoom*a),curr_y-(int)(zoom*b));
 			 dot(g,curr_x+(int)(zoom*a),curr_y+(int)(zoom*b));
		   }
		b=b + 0.005;
	  }
	        a= a + 0.005;
	        b=b0;
	} 
    }

  double keisan(double x,double y,int k,double a,double b) {
 	double x1 =x*x-y*y+a;
 	double y1 =2*x*y+b;
 	double z=x1*x1+y1*y1;
 	if (k>30) return z;
 	if (z>4.0) return z;
	return keisan(x1,y1,k+1,a,b);
   }

  void setc(Graphics g, int c) {
	//黒、オレンジ、青、ピンク、グリーン、赤、黄、白、マゼンダ、シアン
	Color colors[] = {Color.black,Color.orange,Color.blue,Color.pink,
	      Color.green,Color.red,Color.yellow,Color.white,Color.magenta,
	      Color.cyan,Color.lightGray,Color.darkGray,Color.gray};
  	//if (c>12) c=4;
        g.setColor(colors[c]);
  }
  
   void dot(Graphics g,int x, int y) {
   	g.fillRect(x,y,1,1);
   }
}

実際のトライ例は、マンデルブロート100 にある。なお、最初は、Logoの例にならって再帰でトライしたが、途中でとまってしまったので、上記のように、二重のwhileで書き直した(詳しくは1-7)。

setBackground(Color.black)は、背景色を設定するものだが、これを使うと、最初に灰色を背景とした描画を行ってから、背景色を黒としてまたやり直す。 前に書いたことだが、homeメソットを使うまでもないと、g.fillRect(0,0,2*curr_x,2*curr_y)とする全画面塗りつぶしで行った。

2 マンデルブロート400

座標の値は、a,bでとっており、小数点以上は1桁で渡している。dot(g.fillRectを使った1辺が1の正方形の塗りつぶし)で、a,bで指定された座標値に打点していくには、少なくともとも100倍する必要がある。それが1-1であった。もっと拡大表示するため、400倍とした。

描画画面は1024×768であるが、100倍のときは、-5.12から5.12までとっている。400倍とすると、描画範囲はその1/4になる。どうとるかが問題となるが、-2.0あたりから大小の亀の模様がみられるので、そのようにしぼった。

        //マンデルブローの呼び出し
           mandel400(g,-2.0,-0.96,400);

   void mandel400(Graphics g,double a,double b,int zoom) {
	double a0=a;
	double a1=a0+(2.0*curr_x)/zoom;
	double b0=b;
 	while (a4.0) {
	 	   if (z>12.0)
		     setc(g,(int)(z*77.0)%12);
		    else
		     setc(g,(int)(z));
		    dot(g,(int)(zoom*(a-a0)),curr_y-(int)(zoom*b));
 		    dot(g,(int)(zoom*(a-a0)),curr_y+(int)(zoom*b));
		}
		b=b + 0.001;
	  }
	        a= a + 0.001;
	        b=b0;
	} 
    }

mandel400のプログラムは、本質的には1-1と同じだが、描画の始点をずらしたときに、終点などを自動的に求めるよう変更した。描画の始点を-2.0とした図をだしているが、mandel400では、その値をa0で受けて、aの終点をa1で求めることに変更した。始まりが-2.0*400=-800と-512よりマイナス側にずらしてスタートさせているが、それも、dotの中の(zoom*(a-a0))で吸収できている(Javaの横軸は0から始まる)。実際のトライ例は、マンデルブロート400 にある。

2 プログラムの一般化

1 主な変更箇所

1000倍から100万倍と拡大してみる。当然、興味ある図形部分のみを拡大するので、a,bの始点を変える必要がある。1-1や1-2のように、逐一、プログラムで修正して、それをアップするはばかばかしい。拡大率なども含め、html文から4つのパラメータを 読み込み、それにしたがってマンデルブロート図が描けるよう、プログラムを一般化した。1-1、1-2にも使えるが、一気に抽象化すると、ただでさえ難しいものがいっそう難解になるので、一歩一歩とした。

ただ、すでに、1-2 の400倍で、横方向 aの始点が与えられた場合、終点を自動的に求める方法はとりいれている。縦方向 bは、1-1や1-2のように上下対照になるように始点を選ぶ場合は、終点は0である。打点するdotの行を2本として計算量は省略できるようにしていた。bは-b0から計算をはじめ、少し増やしてその都度計算し、bが0になったら、横軸aを少し増やして、bは-b0に戻ってくりかえしていた。上下対象だから、打点のdotの行が2つあった。

拡大率をあげていく場合、きわめて狭い範囲が対象になり、上下対照でない場合 もありうる。bの終点なども自動的に求めるようにした方が楽である。dotの行は1行になり、その分、計算量は増える(もちろん、上下対照の場合にも使える)。主要な変更点のひとつである。

a,bの刻みも拡大率zoomに応じて、小さくしていく必要がある。また、keisanの中でa,bの値を初期値として計算して、zが4.0以上のとき、色つけ をするようにしているが、この値を変えて、どう変わるのかをみるのも面白いとパラメータに加えた。下記プログラムのコメントにある、色付けの限界値というのがそれである。

htmlのバラメータで、文字列、as,bs,colorとして読み込んだものは、doubleに変換したい。
double a=Double.valueOf(as).doubleValue() と、ごつい感じになる。

1-1の100倍、1-2の400倍は、Colorクラスの定数13色 でやったが、もっと色数をふやしたく、Colorクラスのコンストラクタ、Color(int red,int green,int blue)を使って24色にふやした。ほんとうは、Color(int rgb)を使いたかったが、16進数の表記法がよくわからないので、いまのところ保留(Color lightblue=new Color(Integer.toHexString("add8e6").intValue())などではだめ。)

メソッド setc には、こうして作ったlime,navyなどのインスタンス定数も、Color colors[] に加えた。このときの順序によってもマンデルブロート図の色合いは大きく異なる。特に、色づけの境界値が4.0の場合は、colors[4]の色が決定的で、1-1,1-2では緑、ここでは赤としたので、感じががらっと変わる。

2 プログラム例

//cd c:\HPTak\Program\Java\Mandel\Mandel
//javac Mandel.java

import java.applet.Applet;
import java.awt.*;

public class Mandel extends Applet {
  public int curr_x,curr_y;
  String as=null;   //aの始点
  String bs=null;   //bの始点 
  String zs=null;   //拡大率
  String cs=null;   //色づけの境界値

  public void paint(Graphics g) { 
        Dimension d = getSize();
        curr_x=d.width/2;
        curr_y=d.height/2;
       //背景を黒く
        g.fillRect(0,0,2*curr_x,2*curr_y);
       //のhtml文のパラメータを読み込み、a,bの始点、拡大率などを決める
        as=getParameter("start-x");
        if (as==null) as="0.3125";
        double a=Double.valueOf(as).doubleValue();
        bs=getParameter("start-y");
        if (bs==null) bs="-0.00384";
        double b=Double.valueOf(bs).doubleValue();
        zs=getParameter("zoom");
        if (zs==null) zs="100000";
        int zoom=Integer.parseInt(zs);
	cs=getParameter("color");
        if (cs==null) cs="4.0";
        double c=Double.valueOf(cs).doubleValue();
       //マンデルブローの呼び出し
        mandel(g,a,b,zoom,c);
  }

   void mandel(Graphics g,double a,double b,int zoom,double c) {
	double a0=a;
	double a1=a0+(2.0*curr_x)/zoom;
	double b0=b;
 	double b1=b0+2.0*curr_y/zoom;
 	while (ac) {
	 	   if (z>22.0)
		     setc(g,(int)(z*77.0)%22);
		 //    setc(g,(int)(z*30.0)%12);
		    else
		     setc(g,(int)(z));
		    dot(g,(int)(zoom*(a-a0)),2*curr_y-(int)(zoom*(b-b0)));
		}
		b = b + (double)(0.5/zoom);
	  }
	        a = a + (double)(0.5/zoom);
	        b=b0;
	} 
    }

   double keisan(double x,double y,int k,double a,double b,double c) {
 	double x1 =x*x-y*y+a;
 	double y1 =2*x*y+b;
 	double z=x1*x1+y1*y1;
 	if (k>30) return z;
 	if (z>c) return z;
	return keisan(x1,y1,k+1,a,b,c);
   }

  void setc(Graphics g, int c) {
	Color lime=new Color(0,255,0);
	Color navy=new Color(0,0,80);
	Color hotpink=new Color(255,69,180);
	Color orangered=new Color(255,45,00);
	Color orange=new Color(255,165,00);
	Color aqua=new Color(0,255,255);
	Color greenyellow=new Color(100,205,32);
	Color violet=new Color(238,82,238);
	Color purple=new Color(80,0,80);
	Color chocolate=new Color(226,69,175);
	Color colors[] = {Color.black,Color.gray,Color.orange,aqua,
	  Color.red,Color.green,Color.blue,Color.yellow,
	  Color.white,Color.magenta,lime,orangered,navy,orange,greenyellow,
	  chocolate,purple,violet,Color.lightGray,Color.darkGray,
	  Color.cyan,hotpink,Color.pink};
	g.setColor(colors[c]);
  }

  void dot(Graphics g,int x, int y) {
   	g.fillRect(x,y,1,1);
   }
}

3 HTML文のパラメータ

<html>
<head>
<title>マンデルプロート1000-2012-0384-4</title>
</head>
<body>
  <applet code="Mandel.class" width=1024 height=768>
  <param name=start-x value="-2.012">
  <param name=start-y value="-0.384">
  <param name=zoom value="1000">
  <param name=color value="4.0">
  </applet>
</body>
</html>

3 拡大率をあげた場合のマンデルブロート図

1 1000倍のマンデルブロート

1000倍、aを-2.012から始めている。bは、-0.384から0まで(上下対照)。aの終わりは、-1近辺となり、400倍で見た大きな亀模様の前にある亀模様も一部しかとらえていない。しかし、その前に、小さな亀があることがわかる。400倍のときも、ひとつ見えていたが、さらに小さいのがある。拡大していくと、次々と相似形が見えてくる。形の不思議さもさることながら、それもマンデルブロートの不思議なところ。

上記のトライ例は、1章冒頭の完成図つきでだしたMandel1000 と同じであるが、2-1で述べたように、setcの色数をふやしたこととclors[4]を赤としたことで、色合いはがらっと異なる。ただ、zの値が4.0以下で色を変えない部分、背景色の黒のままの亀模様の形は変わらない。

2 1万倍のマンデルブロート

10000倍、a=-1.49から、b=-0.0384から 10000倍、a=-1.40から、b=0.003から

1000倍の図から、-1.5近辺の小さな亀模様のあたりを試行錯誤で調べ、結局、a=-1.49 b=-0.0384から始めた。亀模様は右側の大きそうなものであり、1000倍ではほとんど見えないが、その左側にもいろいろと模様のあることがわかる。

右の図は、右側の亀模様の上にさらに出ているあたりを始点にしてどうなるかを見た。上下対照でない例である。a=-1.40 b=0.03から始めたもので、亀、かぶと虫、盆栽模様と多彩である。

3 10万倍のマンデルブロート

さらに拡大して、10万倍。

100000倍、a=-1.493から、b=-0.00384から 100000倍、a=0.3123から、b=0.0285から

左の図は、1万倍の上の上下対照の図の中央部分を10倍拡大したものである。右は、400倍の図の右の大きな亀の上を見たもの。いままで見た形ともまた違う。さしずめ、恐竜?

4 100万倍のマンデルブロート

100000倍、a=-1.499から、b=-0.000384から 100000倍、a=0.318から、b=0.02953から

図にのって100万倍。左の図は、10万倍左の図で、中央やや右の部分う拡大。右の図は、10万倍右の中央部下に見える小さい竜の落とし子のようなものを拡大してみた。これをz>3.0とした。colors[3]が基調となるが、水色という設定である。他の図もz>3.0とすると、同様の色調になる。拡大率が大きい場合、配色によっては、z>2.0も幻想的で面白くなることを確かめている。

7 再帰によるプログラムとLogoの例

最初は、下記のように再帰でトライしたが、途中でとまってしまって苦心した。再帰回数が多く、スタックオーバするためではないかと判断して、前述のように、二重のwhileで書き直した。ロゴの場合は、再帰に工夫がこらされているときいたことがある。

     mandel100(g,-5.12,-3.86,100);

	void mandel100(Graphics g,double a,double b,int zoom) {
 	if (a<3.5) return;
        if (b<0.0) mandel100(g,a+0.01,-2.5);
        double z=keisan(0.0,0.0,0,a,b);
        if (z>4.0) {
	   if (z>12.0)
		setc(g,(int)(z*77.0)%12);
	   else
	       setc(g,(int)(z));
	   dot(g,curr_x+(int)(zoom*(a)),curr_y-(int)(zoom*b));
 	   dot(g,curr_x+(int)(zoom*(a)),curr_y+(int)(zoom*b));
	}
      mandel100(g,a,b+0.01);
    }
[Logoの例]
TO マンデル :A :B 
 IF :A > 1.5 [STOP]
 IF :B > 0 [マンデル :A + 0.01  -1.75]
 MAKE "Z 計算 0 0 0  
 IF :Z > 4 
   [SETC (14 * :Z / 30 ) + 1    
   DOT 100 * :A  100 * :B
   DOT 100 * :A  -100 * :B]
 マンデル :A :B + 0.01
END

TO  計算 :X :Y :K
  IF :K > 30 [OP :Z] 
  MAKE "X1 :X * :X - :Y * :Y + :A
  MAKE "Y1 2 * :X * :Y + :B
  MAKE "Z :X1 * :X1 + :Y1 * :Y1
  IF :Z > 4 [OP :Z]
  OP 計算 :X1 :Y1 :K + 1
END

TO  DOT :X :Y
 PU 
 SETPOS LIST :X :Y
 PD 
 FD 0
END

実行は,マンデル -1.5 -1.75  

4 カオス

これもマンデルブロートの理屈に近いと思うが、繰り返し計算結果を直接、打点していくのだが、シダの葉など実によくできている。「カオスの数学」(芹沢浩著 東京図書1993.7)を参考にした。c言語で書かれているものを変更しただけ、パラメータの選び方はどうするのだろう?というところである。

実際のトライ例は、シダの葉 にある。

//cd c:\HPTak\Program\Java\Kaos\Shida
//javac Shida.java

import java.applet.Applet;
import java.awt.*;

public class Shida extends Applet {
    public int curr_x,curr_y;
   	
    public void paint(Graphics g) { 
       .................
      //タイトル文字を大きく赤く
        g.setColor(Color.red);
        g.setFont(new Font("Serif", Font.BOLD, 36));
        g.drawString("しだの葉(1.0,0.0,1)", 5, 60);
       //しだの呼び出し
        shida(g,1.0, 0.0, 1);
   }     

  void shida(Graphics g,double x,double y,int n) {
	if (n >10) return; 
	double x1=(0.74 * x -0.03 * y  + 0.33);
	double y1=(0.03 * x + 0.67 * y);
	dot(g,curr_x+(int)(600*x1)-300,curr_y-(int)(600*y1));
	shida(g,x1,y1, n+1);
	double x2=(0.1 * x + 0.33 * y  + 0.2);
	double y2=(0.33 * x -0.1 * y);
	dot(g,curr_x+(int)(600*x2)-300,curr_y-(int)(600*y2));
	shida(g,x2,y2, n+1);
	double x3=(0.1 * x + 0.33 * y  + 0.2);
	double y3=(-0.33 * x + 0.1 * y);
	dot(g,curr_x+(int)(600*x3)-300, curr_y-(int)(600*y3));
	shida(g,x3,y3, n+1);
	double x4=(0.12 * x + 0.43 * y  + 0.12);
	double y4=0.0;
	dot(g,curr_x+(int)(600*x4)-300, curr_y);
	shida(g,x4,y4, n+1);
   }
}

5 J2SE1.2.2でコンバイルしたマンデルブロート

かっては、IEもNetscapeもJava1.1という古いシステムをサポートしていたので、わざわざ、2003/10時点で入手し得る古いJ2SE1.2.2でコンパイルし直したものを別途、アップしていたが、ブラウザのJavaに対する対応は大きく変わってきた(詳しくはブラウザソフトのJava対応 参照)。別途アップのページは廃止し、ここに移すことにした(2005/1)。

1 マンデルブロート

100倍 -5.12から-5.12 400倍 -2.03から2.03" 1000倍 -2.01から-1.01

2 1000倍のマンデルブロート

上記、一番右も1000倍のものだが、配色を変えたものである。黒い亀模様は同じ。





3 1万倍のマンデルブロート

さらに拡大して、1万倍。

10000倍、a=-1.49から、b=-0.03から 10000倍、a=-1.40から、b=0.003から

4 10万倍のマンデルブロート

100000倍、a=-1.493から、b=-0.003から 100000倍、a=0.3123から、b=0.0285から

5 100万倍のマンデルブロート

100000倍、a=-1.499から、b=-0.0003から 100000倍、a=0.318から、b=0.02953から

6 カオス

シダの葉

ページ独自カウント