첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.

728x90
반응형
728x170

TestProject.zip
다운로드

▶ PolygonEventArgs.cs

using System.Collections.Generic;
using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 다각형 이벤트 인자
    /// </summary>
    public class PolygonEventArgs
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 포인트 리스트
        /// </summary>
        public List<Point> PointList;

        #endregion

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

        #region 생성자 - PolygonEventArgs(pointList)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="pointList">포인트 리스트</param>
        public PolygonEventArgs(List<Point> pointList)
        {
            PointList = pointList;
        }

        #endregion
    }
}

 

728x90

 

▶ PolygonSelector.cs

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

namespace TestProject
{
    /// <summary>
    /// 다각형 선택자
    /// </summary>
    public class PolygonSelector
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Delegate
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 다각형 선택 이벤트 핸들러 - PolygonSelectedEventHandler(sender, e)

        /// <summary>
        /// 다각형 선택 이벤트 핸들러
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        public delegate void PolygonSelectedEventHandler(object sender, PolygonEventArgs e);

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 다각형 선택시 이벤트 - PolygonSelected

        /// <summary>
        /// 다각형 선택시 이벤트
        /// </summary>
        public event PolygonSelectedEventHandler PolygonSelected;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 컨트롤
        /// </summary>
        private Control control;

        /// <summary>
        /// 펜
        /// </summary>
        private Pen pen;

        /// <summary>
        /// 포인트 리스트
        /// </summary>
        private List<Point> pointList;

        /// <summary>
        /// 이용 가능 여부
        /// </summary>
        private bool enabled = true;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 이용 가능 여부 - Enabled

        /// <summary>
        /// 이용 가능 여부
        /// </summary>
        public bool Enabled
        {
            get
            {
                return this.enabled;
            }
            set
            {
                if(value == this.enabled)
                {
                    return;
                }

                this.enabled = value;

                if(this.enabled)
                {
                    this.control.MouseDown += control_MouseDown;
                }
                else
                {
                    this.control.MouseDown  -= control_MouseDown;
                    this.control.MouseMove  -= control_MouseMove;
                    this.control.MouseClick -= control_MouseClick;
                    this.control.Paint      -= control_Paint;
                }
            }
        }

        #endregion

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

        #region 생성자 - PolygonSelector(control, pen)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="control">컨트롤</param>
        /// <param name="pen">펜</param>
        public PolygonSelector(Control control, Pen pen)
        {
            this.control = control;
            this.pen     = pen;

            this.control.MouseDown += control_MouseDown;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 다각형 선택시 이벤트 발생시키기 - FirePolygonSelectedEvent()

        /// <summary>
        /// 다각형 선택시 이벤트 발생시키기
        /// </summary>
        protected virtual void FirePolygonSelectedEvent()
        {
            if((PolygonSelected == null) || (this.pointList.Count < 3))
            {
                this.control.Refresh();
            }
            else
            {
                PolygonEventArgs e = new PolygonEventArgs(this.pointList);

                PolygonSelected(this, e);
            }
        }

        #endregion

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

        #region 컨트롤 마우스 DOWN 처리하기 - control_MouseDown(sender, e)

        /// <summary>
        /// 컨트롤 마우스 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void control_MouseDown(object sender, MouseEventArgs e)
        {
            if(e.Button != MouseButtons.Left)
            {
                return;
            }

            this.control.MouseDown -= control_MouseDown;

            this.pointList = new List<Point>();

            this.pointList.Add(e.Location);
            this.pointList.Add(e.Location);

            this.control.MouseMove  += control_MouseMove;
            this.control.MouseClick += control_MouseClick;
            this.control.Paint      += control_Paint;
        }

        #endregion
        #region 컨트롤 마우스 이동시 처리하기 - control_MouseMove(sender, e)

        /// <summary>
        /// 컨트롤 마우스 이동시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void control_MouseMove(object sender, MouseEventArgs e)
        {
            this.pointList[this.pointList.Count - 1] = e.Location;

            this.control.Refresh();
        }

        #endregion
        #region 컨트롤 마우스 클릭시 처리하기 - control_MouseClick(sender, e)

        /// <summary>
        /// 컨트롤 마우스 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void control_MouseClick(object sender, MouseEventArgs e)
        {
            int pointCount = pointList.Count;

            if(e.Button == MouseButtons.Right)
            {
                this.pointList.RemoveAt(pointCount - 1);

                this.control.MouseMove  -= control_MouseMove;
                this.control.MouseClick -= control_MouseClick;
                this.control.Paint      -= control_Paint;

                FirePolygonSelectedEvent();

                this.control.MouseDown += control_MouseDown;
            }
            else
            {
                if(this.pointList[pointCount - 1] != this.pointList[pointCount - 2])
                {
                    this.pointList.Add(e.Location);

                    this.control.Refresh();
                }
            }
        }

        #endregion
        #region 컨트롤 페인트시 처리하기 - control_Paint(sender, e)

        /// <summary>
        /// 컨트롤 페인트시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void control_Paint(object sender, PaintEventArgs e)
        {
            if(this.pointList.Count > 1)
            {
                e.Graphics.DrawLines(pen, this.pointList.ToArray());
            }
        }

        #endregion
    }
}

 

300x250

 

▶ MainForm.cs

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

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

        #region Field

        /// <summary>
        /// 다각형 셀렉터
        /// </summary>
        private PolygonSelector polygonSelector;

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

        #endregion

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

        #region 생성자 - MainForm()

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

            Load                  += Form_Load;
            this.pictureBox.Paint += pictureBox_Paint;
        }

        #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.polygonSelector = new PolygonSelector(this.pictureBox, new Pen(Color.Red, 3));

            this.polygonSelector.PolygonSelected += polygonSelector_PolygonSelected;
        }

        #endregion
        #region 다각형 셀렉터 다각형 선택시 처리하기 - polygonSelector_PolygonSelected(sender, e)

        /// <summary>
        /// 다각형 셀렉터 다각형 선택시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void polygonSelector_PolygonSelected(object sender, PolygonEventArgs e)
        {
            this.pointArray = GetPointArray(e.PointList);

            this.pictureBox.Refresh();
        }

        #endregion
        #region 픽처 박스 페인트시 처리하기 - pictureBox_Paint(sender, e)

        /// <summary>
        /// 픽처 박스 페인트시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void pictureBox_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            e.Graphics.Clear(pictureBox.BackColor);

            if(this.pointArray != null)
            {
                DrawImageInPolygon(e.Graphics, this.pointArray, Properties.Resources.sample);

                using(Pen pen = new Pen(Color.Green, 3))
                {
                    e.Graphics.DrawPolygon(pen, this.pointArray.ToArray());
                }
            }
        }

        #endregion

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

        #region 포인트 배열 구하기 - GetPointArray(pointEnumerable)

        /// <summary>
        /// 포인트 배열 구하기
        /// </summary>
        /// <param name="pointEnumerable">포인트 열거 가능형</param>
        /// <returns>포인트 배열</returns>
        private PointF[] GetPointArray(IEnumerable<Point> pointEnumerable)
        {
            var resultEnumerable = from Point point in pointEnumerable select (PointF)point;

            return resultEnumerable.ToArray();
        }

        #endregion
        #region 다각형 테두리 설정하기 - SetPolygonBound(pointArray, minimumX, maximumX, minimumY, maximumY)

        /// <summary>
        /// 다각형 테두리 설정하기
        /// </summary>
        /// <param name="pointArray">포인트 배열</param>
        /// <param name="minimumX">최소 X</param>
        /// <param name="maximumX">최대 X</param>
        /// <param name="minimumY">최소 Y</param>
        /// <param name="maximumY">최대 Y</param>
        public void SetPolygonBound
        (
            PointF[]  pointArray,
            out float minimumX,
            out float maximumX,
            out float minimumY,
            out float maximumY
        )
        {
            minimumX = pointArray[0].X;
            maximumX = minimumX;
            minimumY = pointArray[0].Y;
            maximumY = minimumY;

            foreach(PointF point in pointArray)
            {
                if(minimumX > point.X) minimumX = point.X;
                if(maximumX < point.X) maximumX = point.X;
                if(minimumY > point.Y) minimumY = point.Y;
                if(maximumY < point.Y) maximumY = point.Y;
            }
        }

        #endregion
        #region 다각형 내에서 이미지 그리기 - DrawImageInPolygon(graphics, pointArray, image)

        /// <summary>
        /// 다각형 내에서 이미지 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="pointArray">포인트 배열</param>
        /// <param name="image">이미지</param>
        public void DrawImageInPolygon(Graphics graphics, PointF[] pointArray, Image image)
        {
            float minimumX;
            float maximumX;
            float minimumY;
            float maximumY;

            SetPolygonBound(pointArray, out minimumX, out maximumX, out minimumY, out maximumY);

            float width   = maximumX - minimumX;
            float height  = maximumY - minimumY;
            float centerX = (minimumX + maximumX) / 2f;
            float centerY = (minimumY + maximumY) / 2f;

            float scaleX = width / image.Width;
            float scaleY = height / image.Height;
            float scale  = Math.Max(scaleX, scaleY);

            float imageWidth   = image.Width  * scale;
            float imageHeight  = image.Height * scale;
            float imageCenterX = imageWidth  / 2f;
            float imageCenterY = imageHeight / 2f;

            RectangleF sourceRectangle = new RectangleF(0, 0, image.Width, image.Height);

            PointF[] targetPointArray =
            {
                new PointF(centerX - imageCenterX,  centerY - imageCenterY),
                new PointF(centerX + imageCenterX,  centerY - imageCenterY),
                new PointF(centerX - imageCenterX,  centerY + imageCenterY)
            };

            GraphicsPath path = new GraphicsPath();

            path.AddPolygon(pointArray);

            GraphicsState state = graphics.Save();

            graphics.SetClip(path);

            graphics.DrawImage(image, targetPointArray, sourceRectangle, GraphicsUnit.Pixel);

            graphics.Restore(state);
        }

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

댓글을 달아 주세요