첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ 하트 모양 파라메트릭(Parametric) 곡선 그리기

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


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

    }

}

 

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

Posted by 사용자 icodebroker

댓글을 달아 주세요