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

TestProject.zip
다운로드

▶ MainForm.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

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

        #region Field

        /// <summary>
        /// A
        /// </summary>
        private float a;
        
        /// <summary>
        /// B
        /// </summary>
        private float b;
        
        /// <summary>
        /// H
        /// </summary>
        private float h;
        
        /// <summary>
        /// DT
        /// </summary>
        private float dt;

        /// <summary>
        /// 포인트 배열
        /// </summary>
        private PointF[] pointArray = null;

        /// <summary>
        /// 세타 배열
        /// </summary>
        private float[] thetaArray = null;

        /// <summary>
        /// 최대 그리기 인덱스
        /// </summary>
        private int maximumDrawIndex = 0;

        #endregion

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

        #region 생성자 - MainForm()

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

            ResizeRedraw = true;

            #region 이벤트를 설정한다.

            this.drawButton.Click       += drawButton_Click;
            this.canvasPictureBox.Paint += canvasPictureBox_Paint;
            this.timer.Tick             += timer_Tick;

            #endregion
        }

        #endregion

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

        #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.timer.Enabled)
            {
                Cursor = Cursors.Default;

                this.timer.Enabled = false;
            }
            else
            {
                Cursor = Cursors.WaitCursor;

                this.a  = float.Parse(this.aTextBox.Text );
                this.b  = float.Parse(this.bTextBox.Text );
                this.h  = float.Parse(this.hTextBox.Text );
                this.dt = float.Parse(this.dtTextBox.Text);

                DrawEpitrochoidPoint(a, b, h, dt);

                this.maximumDrawIndex = 0;

                this.timer.Enabled = true;
            }
        }

        #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);

            if(this.pointArray == null)
            {
                return;
            }

            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            float scale = Math.Min
            (
                this.canvasPictureBox.ClientSize.Width  * 0.45f,
                this.canvasPictureBox.ClientSize.Height * 0.45f
            );

            e.Graphics.ScaleTransform(scale / (a + b + h), scale / (a + b + h));

            e.Graphics.TranslateTransform
            (
                this.canvasPictureBox.ClientSize.Width  / 2,
                this.canvasPictureBox.ClientSize.Height / 2,
                MatrixOrder.Append
            );

            using(Pen blackPen = new Pen(Color.Black, 0))
            {
                e.Graphics.DrawEllipse(blackPen, -a, -a, 2 * a, 2 * a);

                float theta = this.thetaArray[this.maximumDrawIndex];
                float cx    = (float)((a + b) * Math.Cos(theta));
                float cy    = (float)((a + b) * Math.Sin(theta));

                e.Graphics.DrawEllipse(blackPen, cx - b, cy - b, 2 * b, 2 * b);

                e.Graphics.DrawLine
                (
                    blackPen,
                    cx,
                    cy,
                    this.pointArray[this.maximumDrawIndex].X,
                    this.pointArray[this.maximumDrawIndex].Y
                );
            }

            using(Pen whitePen = new Pen(Color.White, 0))
            {
                for(int i = 0; i < this.maximumDrawIndex; i++)
                {
                    e.Graphics.DrawLine(whitePen, this.pointArray[i], this.pointArray[i + 1]);
                }
            }
        }

        #endregion
        #region 타이머 틱 처리하기 - timer_Tick(sender, e)

        /// <summary>
        /// 타이머 틱 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void timer_Tick(object sender, EventArgs e)
        {
            this.maximumDrawIndex++;

            if(this.maximumDrawIndex >= this.pointArray.Length - 1)
            {
                this.timer.Enabled = false;

                Cursor = Cursors.Default;
            }

            this.canvasPictureBox.Refresh();
        }

        #endregion

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

        #region X 좌표 구하기 - GetX(a, b, h, t)

        /// <summary>
        /// X 좌표 구하기
        /// </summary>
        /// <param name="a">A</param>
        /// <param name="b">B</param>
        /// <param name="h">H</param>
        /// <param name="t">T</param>
        /// <returns>X 좌표</returns>
        private float GetX(float a, float b, float h, float t)
        {
            return (float)((a + b) * Math.Cos(t) - h * Math.Cos(t * (a + b) / b));
        }

        #endregion
        #region Y 좌표 구하기 - GetY(a, b, h, t)

        /// <summary>
        /// Y 좌표 구하기
        /// </summary>
        /// <param name="a">A</param>
        /// <param name="b">B</param>
        /// <param name="h">H</param>
        /// <param name="t">T</param>
        /// <returns>X 좌표</returns>
        private float GetY(float a, float b, float h, float t)
        {
            return (float)((a + b) * Math.Sin(t) - h * Math.Sin(t * (a + b) / b));
        }

        #endregion
        #region 에피트로코이드 포인트 그리기 - DrawEpitrochoidPoint(a, b, h, dt)

        /// <summary>
        /// 에피트로코이드 포인트 그리기
        /// </summary>
        /// <param name="a">A</param>
        /// <param name="b">B</param>
        /// <param name="h">H</param>
        /// <param name="dt">DT</param>
        private void DrawEpitrochoidPoint(float a, float b, float h, float dt)
        {
            float stopT = (float)(b * 2 * Math.PI);

            List<PointF> pointList = new List<PointF>();
            List<float>  thetaList = new List<float>();

            pointList.Add(new PointF(GetX(a, b, h, 0), GetY(a, b, h, 0)));

            thetaList.Add(0);

            for(float t = dt; t <= stopT; t += dt)
            {
                pointList.Add(new PointF(GetX(a, b, h, t), GetY(a, b, h, t)));

                thetaList.Add(t);
            }

            pointList.Add(new PointF(GetX(a, b, h, 0), GetY(a, b, h, 0)));

            thetaList.Add(0);

            this.pointArray = pointList.ToArray();
            this.thetaArray = thetaList.ToArray();
        }

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

댓글을 달아 주세요