「Androidは電気羊の夢を見るか」を読みたい管理者のブログ

仕事などでの色々な発見を記事にしてます。不定期更新。

割と簡単にマンデルブロ集合が描けてしまった

フラクタル幾何学(上) (ちくま学芸文庫)

フラクタル幾何学(上) (ちくま学芸文庫)

フラクタル幾何学(下) (ちくま学芸文庫)

フラクタル幾何学(下) (ちくま学芸文庫)

「読まなくてもいい本」の読書案内:知の最前線を5日間で探検する (単行本)

「読まなくてもいい本」の読書案内:知の最前線を5日間で探検する (単行本)

f:id:bignight:20160427203133p:plain

理系の人間には割と常識なのかもしれないけど
この複雑な図がたったの2行の数式で描けるんだよ
C#だけどユーザコントロールとかフォームとか使わないver

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;

namespace opentktest
{
    static class Program
    {
        //表示領域の縦幅
        static readonly double _Height = 4.0;
        //注視点
        static readonly Vector2 _CentralPoint = Vector2.Zero;
        //まんでるぶろ集合描画時の色リスト
        static readonly List<Color> _ColorList = new List<Color>();

        static void InitializeColorList()
        {
            _ColorList.Add(Color.Black);
            for (int i = 1; i <= 16; ++i)
            {
                int x = 31 + 14 * i;
                _ColorList.Add(Color.FromArgb(x, x, x));
            }
        }

        static void SetProjection(int width,int height)
        {
            // ビューポートの設定
            GL.Viewport(0, 0, width, height);

            // 変換行列の初期化
            GL.LoadIdentity();

            // 描画領域の設定
            double sideY = _Height * 0.5;
            double sideX = sideY;
            GL.Ortho(_CentralPoint.X - sideX, _CentralPoint.X + sideX, _CentralPoint.Y - sideY, _CentralPoint.Y + sideY, -1.0, 1.0);
        }
        static void DrawMandelbrot(double xMin, double xMax, double yMin, double yMax, int screenWidth, int screenHeight)
        {
            double xDiff = xMax - xMin, yDiff = yMax - yMin;
            ++screenWidth; ++screenHeight;
            GL.Begin(BeginMode.Points);
            for (int i = 0; i < screenWidth; ++i)
            {
                double x = xMin + xDiff * (double)i / (double)screenWidth;
                for (int j = 0; j < screenHeight; ++j)
                {
                    double y = yMin + yDiff * (double)j / (double)screenHeight;
                    GL.Color3(_ColorList[Mandelbrot(x, y, 16)]);
                    GL.Vertex2(x, y);
                }
            }
            GL.End();
        }
        static int Mandelbrot(double re, double im)
        {
            return Mandelbrot(re, im, 16);
        }
        static int Mandelbrot(double re, double im, int nMax)
        {
            double x = 0.0, y = 0.0, x1, y1;
            for (int n = 0; n < nMax; ++n)
            {
                x1 = x * x - y * y + re;
                y1 = 2.0 * x * y + im;
                if (x1 * x1 + y1 * y1 > 4.0) { return n + 1; }
                x = x1; y = y1;
            }
            return 0;
        }

        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main()
        {


            InitializeColorList();
            

            using(var game = new GameWindow())
            {

                game.Load+=(sender,e)=>
                    {
                        
                        game.VSync = VSyncMode.On;
                        GL.ClearColor(Color4.Red);
                        SetProjection(game.Width, game.Height);
                    };
                game.Resize += (sender, e)=>
                    {
                        SetProjection(game.Width, game.Height);
                        //GL.Viewport(0,0,game.Width,game.Height);
                    };
                game.UpdateFrame+=(sender,e)=>
                    {
                        if(game.Keyboard[Key.Escape])
                        {
                            game.Exit();
                        }
                    };
                game.RenderFrame += (sender, e) =>
                    {
                        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

                        GL.PointSize(1.0f);
                        double sideY = _Height * 0.5;
                        double sideX = sideY;
                        DrawMandelbrot(_CentralPoint.X - sideX, _CentralPoint.X + sideX, _CentralPoint.Y - sideY, _CentralPoint.Y + sideY, game.Width, game.Height);

                        game.SwapBuffers();
                    };

                game.Run(60.0);
            }

        }
    }
}

via:
[C#][OpenTK] マンデルブロ集合の描画 - クソネミ( ˘ω˘ )
Chapter 0: Learn OpenTK in 15' | OpenTK