첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestProject.zip
다운로드

▶ MainForm.cs

using System;
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>
        /// 시작 각도
        /// </summary>
        private float startAngle = 0;

        /// <summary>
        /// 델타 시작 각도
        /// </summary>
        private float deltaStartAngle = (float)(Math.PI / 180);

        #endregion

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

        #region 생성자 - MainForm()

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

            DoubleBuffered = true;

            #region 이벤트를 설정한다.

            this.startButton.Click      += startButton_Click;
            this.canvasPictureBox.Paint += canvasPictureBox_Paint;
            this.timer.Tick             += timer_Tick;

            #endregion
        }

        #endregion

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

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

        /// <summary>
        /// 시작 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void startButton_Click(object sender, EventArgs e)
        {
            this.timer.Enabled = !this.timer.Enabled;

            if(this.timer.Enabled)
            {
                this.startButton.Text = "중단하기";
            }
            else
            {
                this.startButton.Text = "시작하기";
            }
        }

        #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.SmoothingMode = SmoothingMode.AntiAlias;

            const float RADIUS       = 50;
            const float TOOTH_LENGTH = 10;

            float x = this.canvasPictureBox.ClientSize.Width / 2 - RADIUS - TOOTH_LENGTH - 1;
            float y = this.canvasPictureBox.ClientSize.Height / 3;

            DrawGear
            (
                this.startAngle,
                e.Graphics,
                Brushes.Black,
                Brushes.LightBlue,
                Pens.Blue,
                new PointF(x, y),
                RADIUS,
                TOOTH_LENGTH,
                10,
                5,
                true
            );

            x += 2 * RADIUS + TOOTH_LENGTH + 2;

            DrawGear
            (
                -this.startAngle,
                e.Graphics,
                Brushes.Black,
                Brushes.LightGreen,
                Pens.Green,
                new PointF(x, y),
                RADIUS,
                TOOTH_LENGTH,
                10,
                5,
                false
            );

            y += 2f * RADIUS + TOOTH_LENGTH + 2;

            DrawGear
            (
                this.startAngle,
                e.Graphics,
                Brushes.Black,
                Brushes.Pink,
                Pens.Red,
                new PointF(x, y),
                RADIUS,
                TOOTH_LENGTH,
                10,
                5,
                true
            );
        }

        #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.startAngle += this.deltaStartAngle;

            this.canvasPictureBox.Refresh();
        }

        #endregion

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

        #region 기어 그리기 - DrawGear(startAngle, graphics, axleBrush, gearBrush, gearPen, centerPoint, radius, toothLength,
            teethCount, axleRadius, startWithTooth)

        /// <summary>
        /// 기어 그리기
        /// </summary>
        /// <param name="startAngle">시작 각도</param>
        /// <param name="graphics">그래픽스</param>
        /// <param name="axleBrush">차축 브러시</param>
        /// <param name="gearBrush">기어 브러시</param>
        /// <param name="gearPen">기어 펜</param>
        /// <param name="centerPoint">중심 포인트</param>
        /// <param name="radius">반지름</param>
        /// <param name="toothLength">톱니 길이</param>
        /// <param name="teethCount">톱니 카운트</param>
        /// <param name="axleRadius">차축 반지름</param>
        /// <param name="startWithTooth">톱니 시작 여부</param>
        private void DrawGear(float startAngle, Graphics graphics, Brush axleBrush, Brush gearBrush, Pen gearPen, PointF centerPoint,
            float radius, float toothLength, int teethCount, float axleRadius, bool startWithTooth)
        {
            float deltaTheta       = (float)(Math.PI / teethCount);
            float deltaThetaDegree = (float)(deltaTheta * 180 / Math.PI);

            const float CHAMFER = 2;

            float toothWidth  = radius * deltaTheta - CHAMFER;
            float alpha       = toothWidth / (radius + toothLength);
            float alphaDegree = (float)(alpha * 180 / Math.PI);
            float phi         = (deltaTheta - alpha) / 2;

            float theta = startAngle;

            if(startWithTooth)
            {
                theta += deltaTheta / 2;
            }
            else
            {
                theta -= deltaTheta / 2;
            }

            RectangleF innerRectangle = new RectangleF
            (
                centerPoint.X - radius,
                centerPoint.Y - radius,
                2 * radius,
                2 * radius
            );

            RectangleF outerRectangle = new RectangleF
            (
                centerPoint.X - radius - toothLength,
                centerPoint.Y - radius - toothLength,
                2 * (radius + toothLength),
                2 * (radius + toothLength)
            );

            GraphicsPath graphicsPath = new GraphicsPath();

            for(int i = 0; i < teethCount; i++)
            {
                float degree = (float)(theta * 180 / Math.PI);

                graphicsPath.AddArc(innerRectangle, degree, deltaThetaDegree);

                theta += deltaTheta;

                degree = (float)((theta + phi) * 180 / Math.PI);

                graphicsPath.AddArc(outerRectangle, degree, alphaDegree);

                theta += deltaTheta;
            }

            graphicsPath.CloseFigure();

            graphics.FillPath(gearBrush, graphicsPath);

            graphics.DrawPath(gearPen, graphicsPath);

            graphics.FillEllipse
            (
                axleBrush,
                centerPoint.X - axleRadius,
                centerPoint.Y - axleRadius,
                2 * axleRadius,
                2 * axleRadius
            );
        }

        #endregion
    }
}
728x90
반응형
그리드형
Posted by 사용자 icodebroker

댓글을 달아 주세요