첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ 브다브로 프랙탈(Buddhabrot Fractal) 그리기

------------------------------------------------------------------------------------------------------------------------


TestProject.zip


MainForm.cs

 

 

using System;

using System.Drawing;

using System.Drawing.Imaging;

using System.Windows.Forms;

 

namespace TestProject

{

    /// <summary>

    /// 메인 폼

    /// </summary>

    public partial class MainForm : Form

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// WX_MINIMUM

        /// </summary>

        private const double WX_MINIMUM = -1.5;

 

        /// <summary>

        /// WX_MAXIMUM

        /// </summary>

        private const double WX_MAXIMUM = 1.5;

 

        /// <summary>

        /// WY_MINIMUM

        /// </summary>

        private const double WY_MINIMUM = -1.5;

 

        /// <summary>

        /// WY_MAXIMUM

        /// </summary>

        private const double WY_MAXIMUM = 1.5;

 

        /// <summary>

        /// 비트맵

        /// </summary>

        private Bitmap bitmap = null;

 

        /// <summary>

        /// 그리기 여부

        /// </summary>

        private bool isDrawing = false;

 

        /// <summary>

        /// 난수 발생기

        /// </summary>

        private Random random = new Random();

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainForm()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainForm()

        {

            InitializeComponent();

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 저장하기 메뉴 항목 클릭시 처리하기 - saveMenuItem_Click(sender, e)

 

        /// <summary>

        /// 저장하기 메뉴 항목 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void saveMenuItem_Click(object sender, EventArgs e)

        {

            if(this.saveFileDialog.ShowDialog() == DialogResult.OK)

            {

                string filePath = saveFileDialog.FileName;

 

                if(!filePath.Contains("."))

                {

                    filePath += ".bmp";

                }

 

                string fileExtension = filePath.Substring(filePath.LastIndexOf(".")).ToLower();

 

                switch(fileExtension)

                {

                    case ".bmp"   : bitmap.Save(filePath, ImageFormat.Bmp); break;

                    case ".bmgif" : bitmap.Save(filePath, ImageFormat.Gif); break;

                    case ".jpg"   :

                    case ".jpeg"  : bitmap.Save(filePath, ImageFormat.Jpeg); break;

                    case ".png"   : bitmap.Save(filePath, ImageFormat.Png ); break;

                    case ".tif"   :

                    case ".tiff"  : bitmap.Save(filePath, ImageFormat.Tiff); break;

                    default       :

                    

                        MessageBox.Show(this, "알 수 없는 파일 타입 입니다 : " + fileExtension, "확인",

                            MessageBoxButtons.OK, MessageBoxIcon.Information);

 

                        break;

                }

            }

        }

 

        #endregion

        #region 그리기 버튼 클릭시 처리하기 - drawButton_Click(sender, e)

 

        /// <summary>

        /// 그리기 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void drawButton_Click(object sender, EventArgs e)

        {

            if(this.drawButton.Text == "그리기")

            {

                this.drawButton.Text = "중단";

 

                DrawBuddhabrotFractalCurve();

            }

 

            this.isDrawing = false;

 

            this.drawButton.Text = "그리기";

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 포인트 그리기 - DrawPoint(countX, countY, imageWidth, imageHeight, deltaX, deltaY,

            maximumHitCount, hitArray, cutoff, hitCount)

 

        /// <summary>

        /// 포인트 그리기

        /// </summary>

        /// <param name="countX">카운트 X</param>

        /// <param name="countY">카운트 Y</param>

        /// <param name="imageWidth">이미지 너비</param>

        /// <param name="imageHeight">이미지 높이</param>

        /// <param name="deltaX">델타 X</param>

        /// <param name="deltaY">델타 Y</param>

        /// <param name="maximumHitCount">최대 히트 카운트</param>

        /// <param name="hitArray">히트 배열</param>

        /// <param name="cutoff">컷오프</param>

        /// <param name="hitCount">히트 카운트</param>

        private void DrawPoint(double countX, double countY, int imageWidth, int imageHeight, double deltaX,

            double deltaY, ref int maximumHitCount, int[,] hitArray, int cutoff, ref int hitCount)

        {

            const double ESCAPING = 4;

 

            double x;

            double xx;

            double y;

            double yy;

 

            x  = countX;

            y  = countY;

            xx = x * x;

            yy = y * y;

 

            for(int i = 1; i <= cutoff; i++)

            {

                y = 2 * x * y + countY;

                x = xx - yy + countX;

                

                xx = x * x;

                yy = y * y;

 

                if(xx + yy >= ESCAPING)

                {

                    break;

                }

            }

 

            if(xx + yy >= ESCAPING)

            {

                x = countX;

                y = countY;

 

                xx = x * x;

                yy = y * y;

 

                for(int i = 1; i <= cutoff; i++)

                {

                    int ix = (int)Math.Round((x - WX_MINIMUM) / deltaX);

                    int iy = (int)Math.Round((y - WY_MINIMUM) / deltaY);

 

                    if((ix >= 0) && (ix < imageHeight) && (iy >= 0) && (iy < imageWidth))

                    {

                        hitArray[iy, ix] += 1;

 

                        if(maximumHitCount < hitArray[iy, ix])

                        {

                            maximumHitCount = hitArray[iy, ix];

                        }

                    }

                    else

                    {

                        break;

                    }

 

                    y = 2 * x * y + countY;

                    x = xx - yy + countX;

 

                    xx = x * x;

                    yy = y * y;

 

                    if(xx + yy >= ESCAPING)

                    {

                        break;

                    }

                }

 

                hitCount += 1;

            }

        }

 

        #endregion

        #region 브다브로 프랙탈 표시하기 - DrawBuddhabrotFractal(imageWidth, imageHeight, maximumRed,

            maximumGreen, maximumBlue, redHitArray, greenHitArray, blueHitArray)

 

        /// <summary>

        /// 브다브로 프랙탈 커브 표시하기

        /// </summary>

        /// <param name="imageWidth">이미지 너비</param>

        /// <param name="imageHeight">이미지 높이</param>

        /// <param name="maximumRed">최대 적색</param>

        /// <param name="maximumGreen">최대 녹색</param>

        /// <param name="maximumBlue">최대 청색</param>

        /// <param name="redHitArray">적색 히트 배열</param>

        /// <param name="greenHitArray">녹색 히트 배열</param>

        /// <param name="blueHitArray">청색 히트 배역</param>

        private void DrawBuddhabrotFractal(int imageWidth, int imageHeight, int maximumRed, int maximumGreen,

            int maximumBlue, int[,] redHitArray, int[,] greenHitArray, int[,] blueHitArray)

        {

            using(Graphics graphics = Graphics.FromImage(this.bitmap))

            {

                graphics.Clear(Color.Black);

            }

 

            double scaleRed   = 255 * 2.5 / maximumRed;

            double scaleGreen = 255 * 2.5 / maximumGreen;

            double scaleBlue  = 255 * 2.5 / maximumBlue;

 

            for(int y = 0; y < imageHeight; y++)

            {

                for(int x = 0; x < imageWidth; x++)

                {

                    int red = (int)Math.Round(redHitArray[x, y] * scaleRed);

 

                    if(red > 255)

                    {

                        red = 255;

                    }

 

                    int green = (int)Math.Round(greenHitArray[x, y] * scaleGreen);

 

                    if(green > 255)

                    {

                        green = 255;

                    }

 

                    int blue = (int)Math.Round(blueHitArray[x, y] * scaleBlue);

 

                    if(blue > 255)

                    {

                        blue = 255;

                    }

 

                    this.bitmap.SetPixel(x, y, Color.FromArgb(255, red, green, blue));

                }

            }

 

            this.canvasPictureBox.Refresh();

        }

 

        #endregion

        #region 브다브로 프랙탈 그리기 - DrawBuddhabrotFractal()

 

        /// <summary>

        /// 브다브로 프랙탈 그리기

        /// </summary>

        private void DrawBuddhabrotFractal()

        {

            int imageWidth  = int.Parse(this.imageWidthTextBox.Text );

            int imageHeight = int.Parse(this.imageHeightTextBox.Text);

            int redCutoff   = int.Parse(this.redCutoffTextBox.Text  );

            int greenCutoff = int.Parse(this.greenCutoffTextBox.Text);

            int blueCutoff  = int.Parse(this.txtBlueCutoff.Text     );

            int stopAfter   = int.Parse(this.stopPointTextBox.Text  );

            int drawEvery   = int.Parse(this.drawPointTextBox.Text  );

 

            if((imageWidth <= 0) || (imageHeight <= 0))

            {

                MessageBox.Show(this, "매개 변수가 적절하지 않습니다.", "확인",

                    MessageBoxButtons.OK, MessageBoxIcon.Information);

 

                return;

            }

 

            int[,] redHitArray   = new int[imageWidth, imageHeight];

            int[,] greenHitArray = new int[imageWidth, imageHeight];

            int[,] blueHitArray  = new int[imageWidth, imageHeight];

 

            this.bitmap = new Bitmap(imageWidth, imageHeight);

 

            this.canvasPictureBox.Image = this.bitmap;

 

            ClientSize = new Size

            (

                this.canvasPictureBox.Left + this.canvasPictureBox.Width + 20,

                Math.Max

                (

                    this.drawButton.Top + this.drawButton.Height,

                    this.canvasPictureBox.Top + this.canvasPictureBox.Height

                ) + 20

            );

 

            this.saveMenuItem.Enabled = true;

 

            DateTime startTime = DateTime.Now;

            DateTime stopTime;

            TimeSpan elapsed;

 

            this.isDrawing = true;

 

            double deltaX = (WX_MAXIMUM - WX_MINIMUM) / imageHeight;

            double deltaY = (WY_MAXIMUM - WY_MINIMUM) / imageWidth;

 

            int maximumRed    = 0;

            int maximumGreen  = 0;

            int maximumBlue   = 0;

            int hitCount      = 0;

            int totalHitCount = 0;

 

            while(totalHitCount < stopAfter)

            {

                double countX = WX_MINIMUM + this.random.NextDouble() * (WX_MAXIMUM - WX_MINIMUM);

                double countY = WY_MINIMUM + this.random.NextDouble() * (WY_MAXIMUM - WY_MINIMUM);

 

                double dd = countX * countX + countY * countY;

 

                if(dd < 1)

                {

                    DrawPoint

                    (

                        countX,

                        countY,

                        imageWidth,

                        imageHeight,

                        deltaX,

                        deltaY,

                        ref maximumRed,

                        redHitArray,

                        redCutoff,

                        ref hitCount

                    );

                }

                else if(dd < 2)

                {

                    DrawPoint

                    (

                        countX,

                        countY,

                        imageWidth,

                        imageHeight,

                        deltaX,

                        deltaY,

                        ref maximumGreen,

                        greenHitArray,

                        greenCutoff,

                        ref hitCount

                    );

                }

                else

                {

                    DrawPoint

                    (

                        countX,

                        countY,

                        imageWidth,

                        imageHeight,

                        deltaX,

                        deltaY,

                        ref maximumBlue,

                        blueHitArray,

                        blueCutoff,

                        ref hitCount

                    );

                }

 

                if(hitCount >= drawEvery)

                {

                    totalHitCount += hitCount;

 

                    hitCount = 0;

 

                    DrawBuddhabrotFractal

                    (

                        imageWidth,

                        imageHeight,

                        maximumRed,

                        maximumGreen,

                        maximumBlue,

                        redHitArray,

                        greenHitArray,

                        blueHitArray

                    );

 

                    stopTime = DateTime.Now;

 

                    elapsed = stopTime.Subtract(startTime);

 

                    Text = "브다브로 프랙탈(Buddhabrot Fractal) 그리기 : " +

                        elapsed.TotalSeconds.ToString("0.00") + " 초, " + totalHitCount.ToString() + " 히트";

 

                    Application.DoEvents();

 

                    if(!this.isDrawing)

                    {

                        break;

                    }

                }

            }

        }

 

        #endregion

    }

}

 

------------------------------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker

댓글을 달아 주세요