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

728x90
반응형

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
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

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

            #region 이벤트를 설정한다.

            Load   += Form_Load;
            Resize += Form_Resize;

            #endregion
        }

        #endregion

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

        #region 폼 로드시 처리하기 - Form_Load(sender, e)

        /// <summary>
        /// 폼 로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_Load(object sender, EventArgs e)
        {
            this.canvasPictureBox.Image = GetHeartBitmap
            (
                this.canvasPictureBox.ClientSize.Width,
                this.canvasPictureBox.ClientSize.Height
            );
        }

        #endregion
        #region 폼 크기 조정시 처리하기 - Form_Resize(sender, e)

        /// <summary>
        /// 폼 크기 조정시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_Resize(object sender, EventArgs e)
        {
            this.canvasPictureBox.Image = GetHeartBitmap
            (
                this.canvasPictureBox.ClientSize.Width,
                this.canvasPictureBox.ClientSize.Height
            );
        }

        #endregion

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

        #region X 좌표 구하기 - GetX(t)

        /// <summary>
        /// X 좌표 구하기
        /// </summary>
        /// <param name="t">T</param>
        /// <returns>X 좌표</returns>
        private float GetX(float t)
        {
            double sinT = Math.Sin(t);

            return (float)(16 * sinT * sinT * sinT);
        }

        #endregion
        #region Y 좌표 구하기 - GetY(t)

        /// <summary>
        /// Y 좌표 구하기
        /// </summary>
        /// <param name="t">T</param>
        /// <returns>Y 좌표</returns>
        private float GetY(float t)
        {
            return (float)(13 * Math.Cos(t) - 5 * Math.Cos(2 * t) - 2 * Math.Cos(3 * t) - Math.Cos(4 * t));
        }

        #endregion
        #region 변환 설정하기 - SetTransformation(graphics, worldRectangle, deviceRectangle, invertX, invertY)

        /// <summary>
        /// 변환 설정하기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="worldRectangle">세계 사각형</param>
        /// <param name="deviceRectangle">장치 사각형</param>
        /// <param name="invertX">X축 반전 여부</param>
        /// <param name="invertY">Y축 반전 여부</param>
        private void SetTransformation(Graphics graphics, RectangleF worldRectangle, RectangleF deviceRectangle, bool invertX, bool invertY)
        {
            PointF[] devicePointArray =
            {
                new PointF(deviceRectangle.Left , deviceRectangle.Top   ),
                new PointF(deviceRectangle.Right, deviceRectangle.Top   ),
                new PointF(deviceRectangle.Left , deviceRectangle.Bottom),
            };

            if(invertX)
            {
                devicePointArray[0].X = deviceRectangle.Right;
                devicePointArray[1].X = deviceRectangle.Left;
                devicePointArray[2].X = deviceRectangle.Right;
            }

            if(invertY)
            {
                devicePointArray[0].Y = deviceRectangle.Bottom;
                devicePointArray[1].Y = deviceRectangle.Bottom;
                devicePointArray[2].Y = deviceRectangle.Top;
            }

            graphics.Transform = new Matrix(worldRectangle, devicePointArray);
        }

        #endregion
        #region 왜곡 없이 변환 설정하기 - SetTransformationWithoutDisortion(graphics, worldRectangle, deviceRectangle, invertX, invertY)

        /// <summary>
        /// 왜곡 없이 변환 설정하기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="worldRectangle">세계 사각형</param>
        /// <param name="deviceRectangle">장치 사각형</param>
        /// <param name="invertX">X축 반전 여부</param>
        /// <param name="invertY">Y축 반전 여부</param>
        private void SetTransformationWithoutDisortion(Graphics graphics, RectangleF worldRectangle, RectangleF deviceRectangle, bool invertX, bool invertY)
        {
            float worldAspect  = worldRectangle.Width  / worldRectangle.Height;
            float deviceAspect = deviceRectangle.Width / deviceRectangle.Height;

            float worldCenterX = worldRectangle.X + worldRectangle.Width  / 2f;
            float worldCenterY = worldRectangle.Y + worldRectangle.Height / 2f;

            if(worldAspect > deviceAspect)
            {
                float worldHeight = worldRectangle.Width / deviceAspect;

                worldRectangle = new RectangleF
                (
                    worldRectangle.Left,
                    worldCenterY - worldHeight / 2f,
                    worldRectangle.Width,
                    worldHeight
                );
            }
            else
            {
                float worldWidth = deviceAspect * worldRectangle.Height;

                worldRectangle = new RectangleF
                (
                    worldCenterX - worldWidth / 2f,
                    worldRectangle.Top,
                    worldWidth,
                    worldRectangle.Height
                );
            }

            SetTransformation(graphics, worldRectangle, deviceRectangle, invertX, invertY);
        }

        #endregion
        #region 하트 비트맵 구하기 - GetHeartBitmap(width, height)

        /// <summary>
        /// 하트 비트맵 구하기
        /// </summary>
        /// <param name="width">너비</param>
        /// <param name="height">높이</param>
        /// <returns>하트 비트맵</returns>
        private Bitmap GetHeartBitmap(int width, int height)
        {
            Bitmap bitmap = new Bitmap(width, height);

            using(Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.SmoothingMode = SmoothingMode.AntiAlias;

                const int POINT_COUNT = 100;

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

                float dt = (float)(2 * Math.PI / POINT_COUNT);

                float x;
                float y;

                for(float t = 0; t <= 2 * Math.PI; t += dt)
                {
                    x = GetX(t);
                    y = GetY(t);

                    pointList.Add(new PointF(x, y));
                }

                float worldMinimumX = pointList[0].X;
                float worldMaximumX = worldMinimumX;
                float worldMinimumY = pointList[0].Y;
                float worldMaximumY = worldMinimumY;

                foreach(PointF point in pointList)
                {
                    if(worldMinimumX > point.X)
                    {
                        worldMinimumX = point.X;
                    }

                    if(worldMaximumX < point.X)
                    {
                        worldMaximumX = point.X;
                    }

                    if(worldMinimumY > point.Y)
                    {
                        worldMinimumY = point.Y;
                    }

                    if(worldMaximumY < point.Y)
                    {
                        worldMaximumY = point.Y;
                    }
                }

                RectangleF worldRectangle = new RectangleF
                (
                    worldMinimumX,
                    worldMinimumY,
                    worldMaximumX - worldMinimumX,
                    worldMaximumY - worldMinimumY
                );

                const int MARGIN = 5;

                Rectangle deviceRectangle = new Rectangle
                (
                    MARGIN,
                    MARGIN,
                    this.canvasPictureBox.ClientSize.Width  - 2 * MARGIN,
                    this.canvasPictureBox.ClientSize.Height - 2 * MARGIN
                );

                SetTransformationWithoutDisortion(graphics, worldRectangle, deviceRectangle, false, true);

                graphics.FillPolygon(Brushes.Pink, pointList.ToArray());

                using(Pen pen = new Pen(Color.Red, 0))
                {
                    graphics.DrawPolygon(pen, pointList.ToArray());
                }
            }

            return bitmap;
        }

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

댓글을 달아 주세요