첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
------------------------------------------------------------------------------------------------------------------------------------------------------
728x90
728x170

■ 소수 프랙탈(Prime Number Fractal)을 그리는 방법을 보여준다.

TestProject.zip
다운로드

▶ MainForm.cs

using System;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 너비
        /// </summary>
        private const int WIDTH = 800;

        /// <summary>
        /// 높이
        /// </summary>
        private const int HEIGHT = 800;

        /// <summary>
        /// 오프셋 X
        /// </summary>
        private const int X_OFFSET = 150;

        /// <summary>
        /// 오프셋 Y
        /// </summary>
        private const int Y_OFFSET = 200;

        /// <summary>
        /// 히트 배열
        /// </summary>
        private int[,] hitArray = new int[WIDTH, HEIGHT];

        /// <summary>
        /// 현재 포인트
        /// </summary>
        private Point currentPoint = new Point(0, 0);

        /// <summary>
        /// 현재 소수
        /// </summary>
        private long currentPrimeNumber = 1;

        /// <summary>
        /// 실행 여부
        /// </summary>
        private bool isRunning = false;

        /// <summary>
        /// 포인트 카운트
        /// </summary>
        private int pointCount = 0;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            #region 이벤트를 설정한다.

            FormClosing               += Form_FormClosing;
            this.startMenuItem.Click  += startMenuItem_Click;
            this.saveAsMenuItem.Click += saveAsMenuItem_Click;

            #endregion
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 폼을 닫을 경우 처리하기 - Form_FormClosing(sender, e)

        /// <summary>
        /// 폼을 닫을 경우 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.isRunning = false;
        }

        #endregion
        #region 시작하기 메뉴 항목 클릭시 처리하기 - startMenuItem_Click(sender, e)

        /// <summary>
        /// 시작하기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void startMenuItem_Click(object sender, EventArgs e)
        {
            if(this.startMenuItem.Text == "시작하기(&S)")
            {
                this.isRunning = true;

                this.startMenuItem.Text = "중단하기(&S)";

                this.drawPictureBox.Visible = true;

                DrawPrimeNumberFractal();

                this.startMenuItem.Enabled = true;
                this.startMenuItem.Text    = "시작하기(&S)";
            }
            else
            {
                this.isRunning = false;

                this.startMenuItem.Enabled = false;
            }
        }

        #endregion
        #region 다른 이름으로 저장하기 메뉴 항목 클릭시 처리하기 - saveAsMenuItem_Click(sender, e)

        /// <summary>
        /// 다른 이름으로 저장하기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void saveAsMenuItem_Click(object sender, EventArgs e)
        {
            if(this.saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                Bitmap bitmap = this.drawPictureBox.Image as Bitmap;

                SaveImage(bitmap, this.saveFileDialog.FileName);
            }
        }

        #endregion

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

        #region 소수 여부 구하기 - IsPrimeNumber(value)

        /// <summary>
        /// 소수 여부 구하기
        /// </summary>
        /// <param name="value">값</param>
        /// <returns>소수 여부</returns>
        private bool IsPrimeNumber(long value)
        {
            long stopAt = (long)Math.Sqrt(value);

            for(long factor = 3; factor <= stopAt; factor += 2)
            {
                if(value % factor == 0)
                {
                    return false;
                }
            }

            return true;
        }

        #endregion
        #region 다음 소수 찾기 - FindNextPrimeName(value)

        /// <summary>
        /// 다음 소수 찾기
        /// </summary>
        /// <param name="value">값</param>
        /// <returns>다음 소수</returns>
        private long FindNextPrimeName(long value)
        {
            for(long i = value + 2; ; i += 2)
            {
                if(IsPrimeNumber(i))
                {
                    return i;
                }
            }
        }

        #endregion
        #region 무지개 색상 구하기 - GetRainbowColor(value, redValue, blueValue)

        /// <summary>
        /// 무지개 색상 구하기
        /// </summary>
        /// <param name="value">값</param>
        /// <param name="redValue">빨강색 값</param>
        /// <param name="blueValue">파랑색 값</param>
        /// <returns>무지개 색상</returns>
        private Color GetRainbowColor(float value, float redValue, float blueValue)
        {
            int mappingValue = (int)(1023 * (value - redValue) / (blueValue - redValue));

            if(mappingValue < 256)
            {
                return Color.FromArgb(255, mappingValue, 0);
            }
            else if(mappingValue < 512)
            {
                mappingValue -= 256;

                return Color.FromArgb(255 - mappingValue, 255, 0);
            }
            else if(mappingValue < 768)
            {
                mappingValue -= 512;

                return Color.FromArgb(0, 255, mappingValue);
            }
            else
            {
                mappingValue -= 768;

                return Color.FromArgb(0, 255 - mappingValue, 255);
            }
        }

        #endregion
        #region 이미지 생성하기 - CreateImage()

        /// <summary>
        /// 이미지 생성하기
        /// </summary>
        private void CreateImage()
        {
            Bitmap bitmap = new Bitmap(WIDTH, HEIGHT);

            using(Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.Clear(Color.Black);

                var query = from int count in this.hitArray
                            select count;

                float maximumValue = (float)query.Max();

                for(int x = 0; x < WIDTH; x++)
                {
                    for(int y = 0; y < HEIGHT; y++)
                    {
                        if(this.hitArray[x, y] > 0)
                        {
                            bitmap.SetPixel(x, y, GetRainbowColor(this.hitArray[x, y], 1, maximumValue));
                        }
                    }
                }

                graphics.DrawLine(Pens.Blue, X_OFFSET, 0, X_OFFSET, HEIGHT);

                graphics.DrawLine(Pens.Blue, 0, Y_OFFSET, WIDTH, Y_OFFSET);
            }

            this.drawPictureBox.Image = bitmap;
        }

        #endregion
        #region 소수 프랙탈 그리기 - DrawPrimeNumberFractal()

        /// <summary>
        /// 소수 프랙탈 그리기
        /// </summary>
        private void DrawPrimeNumberFractal()
        {
            const int pointCountPerLoop = 10000;

            while(this.isRunning)
            {
                for(int i = 0; i < pointCountPerLoop; i++)
                {
                    this.currentPrimeNumber = FindNextPrimeName(this.currentPrimeNumber);

                    switch(this.currentPrimeNumber % 5)
                    {
                        case 1 : this.currentPoint.Y--; break;
                        case 2 : this.currentPoint.X++; break;
                        case 3 : this.currentPoint.Y++; break;
                        case 4 : this.currentPoint.X--; break;
                    }

                    int xIndex = this.currentPoint.X + X_OFFSET;
                    int yIndex = this.currentPoint.Y + Y_OFFSET;

                    if(xIndex >= 0 && yIndex >= 0 && xIndex < WIDTH && yIndex < HEIGHT)
                    {
                        this.hitArray[xIndex, yIndex]++;
                    }
                }

                CreateImage();

                this.pointCount += pointCountPerLoop;

                this.pointCountValueLabel.Text  = this.pointCount.ToString();
                this.primeNumberValueLabel.Text = this.currentPrimeNumber.ToString();

                Application.DoEvents();
            }
        }

        #endregion
        #region 이미지 저장하기 - SaveImage(image, filePath)

        /// <summary>
        /// 이미지 저장하기
        /// </summary>
        /// <param name="image">이미지</param>
        /// <param name="filePath">파일 경로</param>
        private void SaveImage(Image image, string filePath)
        {
            string fileExtension = Path.GetExtension(filePath);

            switch(fileExtension.ToLower())
            {
                case ".bmp"  : image.Save(filePath, ImageFormat.Bmp ); break;
                case ".exif" : image.Save(filePath, ImageFormat.Exif); break;
                case ".gif"  : image.Save(filePath, ImageFormat.Gif ); break;
                case ".jpg"  :
                case ".jpeg" : image.Save(filePath, ImageFormat.Jpeg); break;
                case ".png"  : image.Save(filePath, ImageFormat.Png ); break;
                case ".tif"  :
                case ".tiff" : image.Save(filePath, ImageFormat.Tiff); break;
                default      :

                    throw new NotSupportedException("알 수 없는 파일 확장자 입니다 : " + fileExtension);
            }
        }

        #endregion
    }
}
728x90
그리드형(광고전용)
Posted by icodebroker
,