첨부 소스 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

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 = "중단";

                DrawBuddhabrotFractal();
            }

            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
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요