■ 피타고라스 나무 프랙탈(Pythagorean Tree Fractal) 그리기

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


TestProject.zip


VectorF.cs

 

 

using System;

using System.Drawing;

 

namespace TestProject

{

    /// <summary>

    /// 벡터

    /// </summary>

    public class VectorF

    {

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

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

 

        #region Field

 

        /// <summary>

        /// X

        /// </summary>

        public float X;

        

        /// <summary>

        /// Y

        /// </summary>

        public float Y;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

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

 

        #region 길이 - Length

 

        /// <summary>

        /// 길이

        /// </summary>

        public float Length

        {

            get

            {

                return (float)Math.Sqrt(X * X + Y * Y);

            }

            set

            {

                float scale = value / Length;

 

                X *= scale;

                Y *= scale;

            }

        }

 

        #endregion

 

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

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

 

        #region 생성자 - VectorF(vector)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="vector">벡터</param>

        public VectorF(VectorF vector)

        {

            X = vector.X;

            Y = vector.Y;

        }

 

        #endregion

        #region 생성자 - VectorF(x, y)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="x">X 좌표</param>

        /// <param name="y">Y 좌표</param>

        public VectorF(float x, float y)

        {

            X = x;

            Y = y;

        }

 

        #endregion

        #region 생성자 - VectorF(point1, point2)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="point1">포인트 1</param>

        /// <param name="point2">포인트 2</param>

        public VectorF(PointF point1, PointF point2)

        {

            X = point2.X - point1.X;

            Y = point2.Y - point1.Y;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

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

 

        #region + 연산자 재정의하기 - +(v1, v2)

 

        /// <summary>

        /// + 연산자 재정의하기

        /// </summary>

        /// <param name="v1">벡터 1</param>

        /// <param name="v2">벡터 2</param>

        /// <returns>벡터</returns>

        public static VectorF operator +(VectorF v1, VectorF v2)

        {

            return new VectorF(v1.X + v2.X, v1.Y + v2.Y);

        }

 

        #endregion

        #region + 연산자 재정의하기 - +(point, vector)

 

        /// <summary>

        /// + 연산자 재정의하기

        /// </summary>

        /// <param name="point">포인트</param>

        /// <param name="vector">벡터</param>

        /// <returns>포인트</returns>

        public static PointF operator +(PointF point, VectorF vector)

        {

            return new PointF(point.X + vector.X, point.Y + vector.Y);

        }

 

        #endregion

        #region - 연산자 재정의하기 - -(vector)

 

        /// <summary>

        /// - 연산자 재정의하기

        /// </summary>

        /// <param name="vector">벡터</param>

        /// <returns>벡터</returns>

        public static VectorF operator -(VectorF vector)

        {

            return -1 * vector;

        }

 

        #endregion

        #region - 연산자 재정의하기 - -(v1, v2)

 

        /// <summary>

        /// - 연산자 재정의하기

        /// </summary>

        /// <param name="v1">벡터 1</param>

        /// <param name="v2">벡터 2</param>

        /// <returns>벡터</returns>

        public static VectorF operator -(VectorF v1, VectorF v2)

        {

            return new VectorF(v1.X - v2.X, v1.Y - v2.Y);

        }

 

        #endregion

        #region - 연산자 재정의하기 - (point, vector)

 

        /// <summary>

        /// - 연산자 재정의하기

        /// </summary>

        /// <param name="point">포인트</param>

        /// <param name="vector">벡터</param>

        /// <returns>포인트</returns>

        public static PointF operator -(PointF point, VectorF vector)

        {

            return new PointF(point.X - vector.X, point.Y - vector.Y);

        }

 

        #endregion

        #region * 연산자 재정의하기 - *(vector, scale)

 

        /// <summary>

        /// * 연산자 재정의하기

        /// </summary>

        /// <param name="vector">벡터</param>

        /// <param name="scale">스케일</param>

        /// <returns>벡터</returns>

        public static VectorF operator *(VectorF vector, float scale)

        {

            return new VectorF(vector.X * scale, vector.Y * scale);

        }

 

        #endregion

        #region * 연산자 재정의하기 - *(scale, vector)

 

        /// <summary>

        /// * 연산자 재정의하기

        /// </summary>

        /// <param name="scale">스케일</param>

        /// <param name="vector">벡터</param>

        /// <returns>벡터</returns>

        public static VectorF operator *(float scale, VectorF vector)

        {

            return vector * scale;

        }

 

        #endregion

        #region / 연산자 재정의하기 -  /(vector, scale)

 

        /// <summary>

        /// / 연산자 재정의하기

        /// </summary>

        /// <param name="vector">벡터</param>

        /// <param name="scale">스케일</param>

        /// <returns>벡터</returns>

        public static VectorF operator /(VectorF vector, float scale)

        {

            return new VectorF(vector.X / scale, vector.Y / scale);

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Instance

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

 

        #region 스케일 처리하기 - Scale(scale)

 

        /// <summary>

        /// 스케일 처리하기

        /// </summary>

        /// <param name="scale">스케일</param>

        /// <returns>벡터</returns>

        public VectorF Scale(float scale)

        {

            return this * scale / Length;

        }

 

        #endregion

        #region 정규화 하기 - Normalize()

 

        /// <summary>

        /// 정규화 하기

        /// </summary>

        public void Normalize()

        {

            Length = 1;

        }

 

        #endregion

        #region 반시계 방향 수직 벡터 구하기 - GetPerpendicularVectorCCW()

 

        /// <summary>

        /// 반시계 방향 수직 벡터 구하기

        /// </summary>

        /// <returns>반시계 방향 수직 벡터</returns>

        public VectorF GetPerpendicularVectorCCW()

        {

            return new VectorF(Y, -X);

        }

 

        #endregion

        #region 시계 방향 수직 벡터 구하기 - GetPerpendicularVectorCW()

 

        /// <summary>

        /// 시계 방향 수직 벡터 구하기

        /// </summary>

        /// <returns>시계 방향 수직 벡터</returns>

        public VectorF GetPerpendicularVectorCW()

        {

            return new VectorF(-Y, X);

        }

 

        #endregion

    }

}

 

 

MainForm.cs

 

 

using System;

using System.Drawing;

using System.Drawing.Drawing2D;

using System.Windows.Forms;

 

namespace TestProject

{

    /// <summary>

    /// 메인 폼

    /// </summary>

    public partial class MainForm : Form

    {

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

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

 

        #region 생성자 - MainForm()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainForm()

        {

            InitializeComponent();

 

            #region 이벤트를 설정한다.

 

            this.depthNumericUpDown.ValueChanged  += parameterControl_ValueChanged;

            this.lengthNumericUpDown.ValueChanged += parameterControl_ValueChanged;

            this.alphaNumericUpDown.ValueChanged  += parameterControl_ValueChanged;

            this.fillCheckBox.CheckedChanged      += parameterControl_ValueChanged;

            this.canvasPictureBox.Resize          += canvasPictureBox_Resize;

            this.canvasPictureBox.Paint           += canvasPictureBox_Paint;

 

            #endregion

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

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

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

 

        #region 매개 변수 컨트롤 값 변경시 처리하기 - parameterControl_ValueChanged(sender, e)

 

        /// <summary>

        /// 매개 변수 컨트롤 값 변경시 처리하기

        /// </summary>

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

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

        private void parameterControl_ValueChanged(object sender, EventArgs e)

        {

            this.canvasPictureBox.Refresh();

        }

 

        #endregion

        #region 캔버스 픽처 박스 크기 조정시 처리하기 - canvasPictureBox_Resize(sender, e)

 

        /// <summary>

        /// 캔버스 픽처 박스 크기 조정시 처리하기

        /// </summary>

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

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

        private void canvasPictureBox_Resize(object sender, EventArgs e)

        {

            this.canvasPictureBox.Refresh();

        }

 

        #endregion

        #region 캔버스 픽처 박스 페인트시 처리하기 - canvasPictureBox_Paint(sender, e)

 

        /// <summary>

        /// 캔버스 픽처 박스 페인트시 처리하기

        /// </summary>

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

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

        private void canvasPictureBox_Paint(object sender, PaintEventArgs e)

        {

            e.Graphics.Clear(this.canvasPictureBox.BackColor);

 

            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

 

            try

            {

                int   depth  = (int)this.depthNumericUpDown.Value;

                int   length = (int)this.lengthNumericUpDown.Value;

                float alpha  = (float)((double)this.alphaNumericUpDown.Value * Math.PI / 180.0);

                float rootX  = this.canvasPictureBox.ClientSize.Width / 2;

                float rootY  = this.canvasPictureBox.ClientSize.Height * 0.9f;

 

                VectorF baseVector = new VectorF(length, 0);

 

                PointF lowerLeftCorner = new PointF(rootX, rootY) - baseVector / 2;

 

                Brush brush = null;

 

                if(fillCheckBox.Checked)

                {

                    brush = Brushes.Green;

                }

                

                DrawBranch(e.Graphics, Pens.Black, brush, depth, lowerLeftCorner, baseVector, alpha);

            }

            catch

            {

            }

        }

 

        #endregion

 

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

 

        #region 가지 그리기 - DrawBranch(graphics, pen, brush, depth, lowerLeftCornerPoint, baseVector, alpha)

 

        /// <summary>

        /// 가지 그리기

        /// </summary>

        /// <param name="graphics">그래픽스</param>

        /// <param name="pen"></param>

        /// <param name="brush">브러시</param>

        /// <param name="depth">깊이</param>

        /// <param name="lowerLeftCornerPoint">좌하단 코너 포인트</param>

        /// <param name="baseVector">기준 벡터</param>

        /// <param name="alpha">알파</param>

        private void DrawBranch(Graphics graphics, Pen pen, Brush brush, int depth, PointF lowerLeftCornerPoint, VectorF baseVector,

            float alpha)

        {

            VectorF heightVector = baseVector.GetPerpendicularVectorCCW();

 

            PointF[] pointArray =

            {

                lowerLeftCornerPoint,

                lowerLeftCornerPoint + baseVector,

                lowerLeftCornerPoint + baseVector + heightVector,

                lowerLeftCornerPoint + heightVector,

            };

 

            if(brush != null)

            {

                graphics.FillPolygon(brush, pointArray);

            }

 

            graphics.DrawPolygon(pen, pointArray);

 

            if(depth > 0)

            {

                // 왼쪽 가지

                double w1 = baseVector.Length * Math.Cos(alpha);

 

                float wb1 = (float)(w1 * Math.Cos(alpha));

                float wh1 = (float)(w1 * Math.Sin(alpha));

 

                VectorF baseVector1 = baseVector.Scale(wb1) + heightVector.Scale(wh1);

 

                PointF lowerLeftCornerPoint1 = lowerLeftCornerPoint + heightVector;

 

                DrawBranch(graphics, pen, brush, depth - 1, lowerLeftCornerPoint1, baseVector1, alpha);

 

                // 오른쪽 가지

                double beta = Math.PI / 2.0 - alpha;

                double w2   = baseVector.Length * Math.Sin(alpha);

 

                float wb2 = (float)(w2 * Math.Cos(beta));

                float wh2 = (float)(w2 * Math.Sin(beta));

 

                VectorF baseVector2 = baseVector.Scale(wb2) - heightVector.Scale(wh2);

 

                PointF lowerLeftCornerPoint2 = lowerLeftCornerPoint1 + baseVector1;

 

                DrawBranch(graphics, pen, brush, depth - 1, lowerLeftCornerPoint2, baseVector2, alpha);

            }

        }

 

        #endregion

    }

}

 

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

Posted by 사용자 icodebroker

댓글을 달아 주세요