첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
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
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 그리기 모드 - DrawMode

        /// <summary>
        /// 그리기 모드
        /// </summary>
        private enum DrawMode
        {
            /// <summary>
            /// 해당 무
            /// </summary>
            None,

            /// <summary>
            /// 기준선 그리기
            /// </summary>
            DrawBaseline,

            /// <summary>
            /// 다각형 그리기
            /// </summary>
            DrawPolygon
        }

        #endregion

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

        #region Field

        /// <summary>
        /// 기준선 시작 포인트
        /// </summary>
        private Point baselineStartPoint = new Point(0, 00);

        /// <summary>
        /// 기준선 종료 포인트
        /// </summary>
        private Point baselineEndPoint = new Point(200, 100);

        /// <summary>
        /// 다각형 리스트
        /// </summary>
        private List<List<PointF>> polygonList = new List<List<PointF>>();

        /// <summary>
        /// 신규 포인트 리스트
        /// </summary>
        private List<PointF> newPointList = null;

        /// <summary>
        /// 마지막 포인트
        /// </summary>
        private PointF lastPoint;

        /// <summary>
        /// 그리기 모드
        /// </summary>
        private DrawMode drawMode = DrawMode.None;

        /// <summary>
        /// 기준선 그리기 여부
        /// </summary>
        private bool isDrawingBaseline = false;

        #endregion

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

        #region 생성자 - MainForm()

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

            this.openMenuItem.Click         += openMenuItem_Click;
            this.newMenuItem.Click          += newMenuItem_Click;
            this.exitMenuItem.Click         += exitMenuitem_Click;
            this.setBaselineMenuItem.Click  += setBaselineMenuItem_Click;
            this.drawPolygonMenuItem.Click  += drawPolygonMenuItem_Click;
            this.clearPolygonMenuItem.Click += clearPolygonMenuItem_Click;
            this.pictureBox.MouseDown       += pictureBox_MouseDown;
            this.pictureBox.MouseMove       += pictureBox_MouseMove;
            this.pictureBox.MouseUp         += pictureBox_MouseUp;
            this.pictureBox.MouseClick      += pictureBox_MouseClick;
        }

        #endregion

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

        #region 열기 메뉴 항목 클릭시 처리하기 - openMenuItem_Click(sender, e)

        /// <summary>
        /// 열기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void openMenuItem_Click(object sender, EventArgs e)
        {
            if(this.openFileDialog.ShowDialog() == DialogResult.OK)
            {
                this.pictureBox.Image = LoadBitmapUnlocked(this.openFileDialog.FileName);
            }
        }

        #endregion
        #region 새로 그리기 메뉴 항목 클릭시 처리하기 - newMenuItem_Click(sender, e)

        /// <summary>
        /// 새로 그리기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void newMenuItem_Click(object sender, EventArgs e)
        {
            this.pictureBox.Image = null;

            this.polygonList.Clear();

            this.pictureBox.Refresh();
        }

        #endregion
        #region 종료 메뉴 항목 클릭시 처리하기 - exitMenuitem_Click(sender, e)

        /// <summary>
        /// 종료 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void exitMenuitem_Click(object sender, EventArgs e)
        {
            Close();
        }

        #endregion
        #region 기준선 설정하기 메뉴 항목 클릭시 처리하기 - setBaselineMenuItem_Click(sender, e)

        /// <summary>
        /// 기준선 설정하기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void setBaselineMenuItem_Click(object sender, EventArgs e)
        {
            this.drawMode = DrawMode.DrawBaseline;

            this.pictureBox.Cursor = Cursors.Cross;
        }

        #endregion
        #region 다각형 그리기 메뉴 항목 클릭시 처리하기 - drawPolygonMenuItem_Click(sender, e)

        /// <summary>
        /// 다각형 그리기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void drawPolygonMenuItem_Click(object sender, EventArgs e)
        {
            this.drawMode = DrawMode.DrawPolygon;

            this.newPointList = new List<PointF>();

            this.pictureBox.Cursor = Cursors.Cross;
        }

        #endregion
        #region 다각형 지우기 메뉴 항목 클릭시 처리하기 - clearPolygonMenuItem_Click(sender, e)

        /// <summary>
        /// 다각형 지우기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void clearPolygonMenuItem_Click(object sender, EventArgs e)
        {
            this.polygonList.Clear();

            this.pictureBox.Refresh();
        }

        #endregion
        #region 픽처 박스 마우스 DOWN 처리하기 - pictureBox_MouseDown(sender, e)

        /// <summary>
        /// 픽처 박스 마우스 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void pictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            if(this.drawMode == DrawMode.DrawBaseline)
            {
                this.isDrawingBaseline = true;

                this.baselineStartPoint = e.Location;
                this.baselineEndPoint   = e.Location;

                this.pictureBox.Refresh();
            }
        }

        #endregion
        #region 픽처 박스 마우스 이동시 처리하기 - pictureBox_MouseMove(sender, e)

        /// <summary>
        /// 픽처 박스 마우스 이동시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void pictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            if(this.drawMode == DrawMode.DrawBaseline)
            {
                if(this.isDrawingBaseline)
                {
                    this.baselineEndPoint = e.Location;

                    this.pictureBox.Refresh();
                }
            }
            else if(this.drawMode == DrawMode.DrawPolygon)
            {
                if(this.newPointList.Count == 0)
                {
                    return;
                }

                this.lastPoint = AdjustPoint(e.Location);

                this.pictureBox.Refresh();
            }
        }

        #endregion
        #region 픽처 박스 마우스 UP 처리하기 - pictureBox_MouseUp(sender, e)

        /// <summary>
        /// 픽처 박스 마우스 UP 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void pictureBox_MouseUp(object sender, MouseEventArgs e)
        {
            if(this.drawMode == DrawMode.DrawBaseline) 
            {
                this.isDrawingBaseline = false;

                this.pictureBox.Cursor = Cursors.Default;

                this.drawMode = DrawMode.None;
            }
        }

        #endregion
        #region 픽처 박스 마우스 클릭시 처리하기 - pictureBox_MouseClick(sender, e)

        /// <summary>
        /// 픽처 박스 마우스 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void pictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            if(this.drawMode == DrawMode.DrawPolygon)
            {
                if(e.Button == MouseButtons.Right)
                {
                    this.pictureBox.Cursor = Cursors.Default;

                    if(this.newPointList.Count > 3)
                    {
                        SaveNewPolygon();
                    }

                    this.newPointList = null;

                    this.drawMode = DrawMode.None;
                }
                else
                {
                    PointF adjustedPoint = AdjustPoint(e.Location);

                    this.newPointList.Add(adjustedPoint);

                    this.lastPoint = adjustedPoint;
                }

                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;

            using(Pen pen = new Pen(Color.Red, 2))
            {
                e.Graphics.DrawLine(pen, this.baselineStartPoint, this.baselineEndPoint);

                pen.Color       = Color.Yellow;
                pen.DashPattern = new float[] { 3, 3 };

                e.Graphics.DrawLine(pen, this.baselineStartPoint, this.baselineEndPoint);

                pen.Color     = Color.Blue;
                pen.DashStyle = DashStyle.Solid;

                using(Brush brush = new SolidBrush(Color.FromArgb(128, Color.LightBlue)))
                {
                    foreach(List<PointF> pointList in this.polygonList)
                    {
                        e.Graphics.FillPolygon(brush, pointList.ToArray());

                        e.Graphics.DrawPolygon(pen, pointList.ToArray());
                    }
                }

                if(this.newPointList != null)
                {
                    pen.Color     = Color.Green;
                    pen.DashStyle = DashStyle.Solid;

                    if(this.newPointList.Count > 1)
                    {
                        e.Graphics.DrawLines(pen, this.newPointList.ToArray());
                    }

                    e.Graphics.DrawLine(pen, this.newPointList[this.newPointList.Count - 1], this.lastPoint);

                    foreach(PointF point in this.newPointList)
                    {
                        e.Graphics.FillEllipse(Brushes.Red, point.X - 3, point.Y - 3, 6, 6);
                    }
                }
            }
        }

        #endregion

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

        #region 잠금없이 비트맵 로드하기 - LoadBitmapUnlocked(filePath)

        /// <summary>
        /// 잠금없이 비트맵 로드하기
        /// </summary>
        /// <param name="filePath">파일 경로</param>
        /// <returns>비트맵</returns>
        private Bitmap LoadBitmapUnlocked(string filePath)
        {
            using(Bitmap bitmap = new Bitmap(filePath))
            {
                return new Bitmap(bitmap);
            }
        }

        #endregion
        #region 변환 매트릭스 구하기 - GetTransformMatrix()

        /// <summary>
        /// 변환 매트릭스 구하기
        /// </summary>
        /// <returns>변환 매트릭스</returns>
        private Matrix GetTransformMatrix()
        {
            float deltaX = this.baselineStartPoint.X - this.baselineEndPoint.X;
            float deltaY = this.baselineStartPoint.Y - this.baselineEndPoint.Y;

            double angle = -Math.Atan2(deltaY, deltaX) * 180 / Math.PI;

            Matrix matrix = new Matrix();

            matrix.Rotate((float)angle);

            return matrix;
        }

        #endregion
        #region 포인트 조정하기 - AdjustPoint(pointToAdjust, referencePoint)

        /// <summary>
        /// 포인트 조정하기
        /// </summary>
        /// <param name="pointToAdjust">조정할 포인트</param>
        /// <param name="referencePoint">참조 포인트</param>
        /// <returns>조정 포인트</returns>
        private PointF AdjustPoint(PointF pointToAdjust, PointF referencePoint)
        {
            if(this.newPointList == null)
            {
                return pointToAdjust;
            }

            if(this.newPointList.Count == 0)
            {
                return pointToAdjust;
            }

            Matrix matrix = GetTransformMatrix();

            PointF[] pointArray =
            {
                referencePoint,
                pointToAdjust,
            };

            matrix.TransformPoints(pointArray);

            float deltaX = Math.Abs(pointArray[1].X - pointArray[0].X);
            float deltaY = Math.Abs(pointArray[1].Y - pointArray[0].Y);

            if(deltaX <= deltaY)
            {
                pointArray[1].X = pointArray[0].X;
            }
            else
            {
                pointArray[1].Y = pointArray[0].Y;
            }

            matrix.Invert();

            matrix.TransformPoints(pointArray);

            return pointArray[1];
        }

        #endregion
        #region 포인트 조정하기 - AdjustPoint(point)

        /// <summary>
        /// 포인트 조정하기
        /// </summary>
        /// <param name="point">포인트</param>
        /// <returns>조정 포인트</returns>
        private PointF AdjustPoint(PointF point)
        {
            if(this.newPointList == null)
            {
                return point;
            }

            if(this.newPointList.Count == 0)
            {
                return point;
            }

            return AdjustPoint(point, newPointList[newPointList.Count - 1]);
        }

        #endregion
        #region 신규 다각형 저장하기 - SaveNewPolygon()

        /// <summary>
        /// 신규 다각형 저장하기
        /// </summary>
        private void SaveNewPolygon()
        {
            this.newPointList[this.newPointList.Count - 1] = AdjustPoint
            (
                this.newPointList[this.newPointList.Count - 1],
                this.newPointList[0]
            );

            this.polygonList.Add(this.newPointList);
        }

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

댓글을 달아 주세요