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

728x90
반응형
728x170

TestProject.zip
다운로드

▶ SegmentInformation.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 세그먼트 정보
    /// </summary>
    public class SegmentInformation
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 시작 포인트
        /// </summary>
        public PointF StartPoint;

        /// <summary>
        /// 종료 포인트
        /// </summary>
        public PointF EndPoint;

        #endregion

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

        #region 생성자 - SegmentInformation(startPoint, endPoint)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="startPoint">시작 포인트</param>
        /// <param name="endPoint">종료 포인트</param>
        public SegmentInformation(PointF startPoint, PointF endPoint)
        {
            StartPoint = startPoint;
            EndPoint   = endPoint;
        }

        #endregion
    }
}

 

728x90

 

▶ ArcInformation.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 호 정보
    /// </summary>
    public class ArcInformation
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 사각형
        /// </summary>
        public RectangleF Rectangle;

        /// <summary>
        /// 시작 각도
        /// </summary>
        public float StartAngle;
        
        /// <summary>
        /// 스윕 각도
        /// </summary>
        public float SweepAngle;

        #endregion

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

        #region 생성자 - ArcInformation(rectangle, startAngle, sweepAngle)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="rectangle">사각형</param>
        /// <param name="startAngle">시작 각도</param>
        /// <param name="sweepAngle">스윕 각도</param>
        public ArcInformation(RectangleF rectangle, float startAngle, float sweepAngle)
        {
            Rectangle  = rectangle;
            StartAngle = startAngle;
            SweepAngle = sweepAngle;
        }

        #endregion
    }
}

 

300x250

 

▶ ArcHelper.cs

using System;
using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 호 헬퍼
    /// </summary>
    public static class ArcHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 세그먼트에서 호 찾기 - FindArcFromSegment(point1, point2, point3, point4,
            rectangle, startAngle, sweepAngle, farPoint1, closePoint1, farPoint2, closePoint2)

        /// <summary>
        /// 세그먼트에서 호 찾기
        /// </summary>
        /// <param name="point1">포인트 1</param>
        /// <param name="point2">포인트 2</param>
        /// <param name="point3">포인트 3</param>
        /// <param name="point4">포인트 4</param>
        /// <param name="rectangle">사각형</param>
        /// <param name="startAngle">시작 각도</param>
        /// <param name="sweepAngle">스윕 각도</param>
        /// <param name="farPoint1">원거리 포인트 1</param>
        /// <param name="closePoint1">근거리 포인트 1</param>
        /// <param name="farPoint2">원거리 포인트 2</param>
        /// <param name="closePoint2">근거리 포인트 2</param>
        /// <returns>처리 결과</returns>
        public static bool FindArcFromSegment
        (
            PointF         point1,
            PointF         point2,
            PointF         point3,
            PointF         point4,
            out RectangleF rectangle,
            out float      startAngle,
            out float      sweepAngle,
            out PointF     farPoint1,
            out PointF     closePoint1,
            out PointF     farPoint2,
            out PointF     closePoint2
        )
        {
            rectangle   = new RectangleF(0, 0, 0, 0);
            startAngle  = float.NaN;
            sweepAngle  = float.NaN;
            farPoint1   = new PointF();
            closePoint1 = new PointF();
            farPoint2   = new PointF();
            closePoint2 = new PointF();

            PointF intersectionPoint;
            bool   isLineIntersected;
            bool   isSegmentIntersected;
            PointF temporaryClosePoint1;
            PointF temporaryClosePoint2;

            if
            (
                !FindIntersection
                (
                    point1,
                    point2,
                    point3,
                    point4,
                    out isLineIntersected,
                    out isSegmentIntersected,
                    out intersectionPoint,
                    out temporaryClosePoint1,
                    out temporaryClosePoint2
                )
            )
            {
                return false;
            }

            if(!isLineIntersected)
            {
                throw new NotImplementedException("The segments are parallel.");
            }

            float closeDistance1;
            float closeDistance2;
            float farDistance1;
            float farDistance2;

            if(point1.GetDistance(intersectionPoint) < point2.GetDistance(intersectionPoint))
            {
                closePoint1    = point1;
                farPoint1      = point2;
                closeDistance1 = point1.GetDistance(intersectionPoint);
                farDistance1   = point2.GetDistance(intersectionPoint);
            }
            else
            {
                closePoint1    = point2;
                farPoint1      = point1;
                closeDistance1 = point2.GetDistance(intersectionPoint);
                farDistance1   = point1.GetDistance(intersectionPoint);
            }

            if(point3.GetDistance(intersectionPoint) < point4.GetDistance(intersectionPoint))
            {
                closePoint2    = point3;
                farPoint2      = point4;
                closeDistance2 = point3.GetDistance(intersectionPoint);
                farDistance2   = point2.GetDistance(intersectionPoint);
            }
            else
            {
                closePoint2    = point4;
                farPoint2      = point3;
                closeDistance2 = point4.GetDistance(intersectionPoint);
                farDistance2   = point1.GetDistance(intersectionPoint);
            }

            if(closeDistance1 < closeDistance2)
            {
                closePoint2    = GetPointAtDistance(intersectionPoint, farPoint2, closeDistance1);
                closeDistance2 = closeDistance1;
            }
            else
            {
                closePoint1    = GetPointAtDistance(intersectionPoint, farPoint1, closeDistance2);
                closeDistance1 = closeDistance2;
            }

            FindArcFromTangent
            (
                closePoint1,
                farPoint1,
                closePoint2,
                farPoint2,
                out rectangle,
                out startAngle,
                out sweepAngle
            );

            return true;
        }

        #endregion
        #region 반경을 갖고 호 찾기 - FindArcWithRadius(point1, point2, point3, point4,
            radius, rectangle, startAngle, sweepAngle, farPoint1, closePoint1, farPoint2, closePoint2)

        /// <summary>
        /// 반경을 갖고 호 찾기
        /// </summary>
        /// <param name="point1">포인트 1</param>
        /// <param name="point2">포인트 2</param>
        /// <param name="point3">포인트 3</param>
        /// <param name="point4">포인트 4</param>
        /// <param name="radius">반경</param>
        /// <param name="rectangle">사각형</param>
        /// <param name="startAngle">시작 각도</param>
        /// <param name="sweepAngle">스윕 각도</param>
        /// <param name="farPoint1">원거리 포인트 1</param>
        /// <param name="closePoint1">근거리 포인트 1</param>
        /// <param name="farPoint2">원거리 포인트 2</param>
        /// <param name="closePoint2">근거리 포인트 2</param>
        /// <returns>처리 결과</returns>
        public static bool FindArcWithRadius
        (
            PointF         point1,
            PointF         point2,
            PointF         point3,
            PointF         point4,
            float          radius,
            out RectangleF rectangle,
            out float      startAngle,
            out float      sweepAngle,
            out PointF     farPoint1,
            out PointF     closePoint1,
            out PointF     farPoint2,
            out PointF     closePoint2
        )
        {
            rectangle   = new RectangleF(0, 0, 0, 0);
            startAngle  = float.NaN;
            sweepAngle  = float.NaN;
            farPoint1   = new PointF();
            closePoint1 = new PointF();
            farPoint2   = new PointF();
            closePoint2 = new PointF();

            PointF intersectionPoint;
            bool   isLineIntersected;
            bool   isSegmentIntersected;
            PointF temporaryClosePoint1;
            PointF temporaryClosePoint2;

            if
            (
                !FindIntersection
                (
                    point1,
                    point2,
                    point3,
                    point4,
                    out isLineIntersected,
                    out isSegmentIntersected,
                    out intersectionPoint,
                    out temporaryClosePoint1,
                    out temporaryClosePoint2
                )
            )
            {
                return false;
            }

            float distance1 = point1.GetDistance(intersectionPoint) - radius;

            point2 = GetPointAtDistance(point1, intersectionPoint, distance1);

            float distance2 = point3.GetDistance(intersectionPoint) - radius;

            point4 = GetPointAtDistance(point3, intersectionPoint, distance2);

            return FindArcFromSegment
            (
                point1,
                point2,
                point3,
                point4,
                out rectangle,
                out startAngle,
                out sweepAngle,
                out farPoint1,
                out closePoint1,
                out farPoint2,
                out closePoint2
            );
        }

        #endregion

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

        #region 거리 내 포인트 구하기 - GetPointAtDistance(point1, point2, distance)

        /// <summary>
        /// 거리 내 포인트 구하기
        /// </summary>
        /// <param name="point1">포인트 1</param>
        /// <param name="point2">포인트 2</param>
        /// <param name="distance">거리</param>
        /// <returns>거리 내 포인트</returns>
        private static PointF GetPointAtDistance(PointF point1, PointF point2, float distance)
        {
            float deltaX = point2.X - point1.X;
            float deltaY = point2.Y - point1.Y;

            float temporaryDistance = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);

            return new PointF
            (
                point1.X + deltaX / temporaryDistance * distance,
                point1.Y + deltaY / temporaryDistance * distance
            );
        }

        #endregion
        #region 교차 찾기 - FindIntersection(point1, point2, point3, point4,
            isLineIntersected, isSegmentIntersected, intersectionPoint, closePoint1, closePoint2)

        /// <summary>
        /// 교차 찾기
        /// </summary>
        /// <param name="point1">포인트 1</param>
        /// <param name="point2">포인트 2</param>
        /// <param name="point3">포인트 3</param>
        /// <param name="point4">포인트 4</param>
        /// <param name="isLineIntersected">라인 교차 여부</param>
        /// <param name="isSegmentIntersected">세그먼트 교차 여부</param>
        /// <param name="intersectionPoint">교차 포인트</param>
        /// <param name="closePoint1">근거리 포인트 1</param>
        /// <param name="closePoint2">근거리 포인트 2</param>
        /// <returns>처리 결과</returns>
        private static bool FindIntersection
        (
            PointF     point1,
            PointF     point2,
            PointF     point3,
            PointF     point4,
            out bool   isLineIntersected,
            out bool   isSegmentIntersected,
            out PointF intersectionPoint,
            out PointF closePoint1,
            out PointF closePoint2
        )
        {
            float deltaX1 = point2.X - point1.X;
            float deltaY1 = point2.Y - point1.Y;
            float deltaX2 = point4.X - point3.X;
            float deltaY2 = point4.Y - point3.Y;

            float denominator = (deltaY1 * deltaX2 - deltaX1 * deltaY2);

            float temporary1 = ((point1.X - point3.X) * deltaY2 + (point3.Y - point1.Y) * deltaX2) / denominator;

            if(float.IsInfinity(temporary1))
            {
                isLineIntersected    = false;
                isSegmentIntersected = false;
                intersectionPoint    = new PointF(float.NaN, float.NaN);
                closePoint1          = new PointF(float.NaN, float.NaN);
                closePoint2          = new PointF(float.NaN, float.NaN);

                return false;
            }

            isLineIntersected = true;

            float temporary2 = ((point3.X - point1.X) * deltaY1 + (point1.Y - point3.Y) * deltaX1) / -denominator;

            intersectionPoint = new PointF(point1.X + deltaX1 * temporary1, point1.Y + deltaY1 * temporary1);

            isSegmentIntersected = ((temporary1 >= 0) && (temporary1 <= 1) && (temporary2 >= 0) && (temporary2 <= 1));

            if(temporary1 < 0)
            {
                temporary1 = 0;
            }
            else if(temporary1 > 1)
            {
                temporary1 = 1;
            }

            if(temporary2 < 0)
            {
                temporary2 = 0;
            }
            else if(temporary2 > 1)
            {
                temporary2 = 1;
            }

            closePoint1 = new PointF(point1.X + deltaX1 * temporary1, point1.Y + deltaY1 * temporary1);
            closePoint2 = new PointF(point3.X + deltaX2 * temporary2, point3.Y + deltaY2 * temporary2);

            return true;
        }

        #endregion
        #region 탄젠트에서 호 찾기 - FindArcFromTangent(closePoint1, farPoint1, closePoint2, farPoint2,
            rectangle, startAngle, sweepAngle)

        /// <summary>
        /// 탄젠트에서 호 찾기
        /// </summary>
        /// <param name="closePoint1">근거리 포인트 1</param>
        /// <param name="farPoint1">원거리 포인트 1</param>
        /// <param name="closePoint2">근거리 포인트 2</param>
        /// <param name="farPoint2">원거리 포인트 2</param>
        /// <param name="rectangle">사각형</param>
        /// <param name="startAngle">시작 각도</param>
        /// <param name="sweepAngle">스윕 각도</param>
        private static void FindArcFromTangent
        (
            PointF         closePoint1,
            PointF         farPoint1,
            PointF         closePoint2,
            PointF         farPoint2,
            out RectangleF rectangle,
            out float      startAngle,
            out float      sweepAngle
        )
        {
            PointF perpendicularPoint1;
            PointF perpendicularPoint2;

            float deltaX1 = closePoint1.X - farPoint1.X;
            float deltaY1 = closePoint1.Y - farPoint1.Y;

            perpendicularPoint1 = new PointF
            (
                closePoint1.X - deltaY1,
                closePoint1.Y + deltaX1
            );

            float deltaX2 = closePoint2.X - farPoint2.X;
            float deltaY2 = closePoint2.Y - farPoint2.Y;

            perpendicularPoint2 = new PointF
            (
                closePoint2.X + deltaY2,
                closePoint2.Y - deltaX2
            );

            bool   isLineIntersected;
            bool   isSegmentIntersected;
            PointF intersectionPoint;
            PointF temporaryClosePoint1;
            PointF temporaryClosePoint2;

            FindIntersection
            (
                closePoint1,
                perpendicularPoint1,
                closePoint2,
                perpendicularPoint2,
                out isLineIntersected,
                out isSegmentIntersected,
                out intersectionPoint,
                out temporaryClosePoint1,
                out temporaryClosePoint2
            );

            float deltaX = closePoint1.X - intersectionPoint.X;
            float deltaY = closePoint1.Y - intersectionPoint.Y;
            float radius = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);

            rectangle = new RectangleF
            (
                intersectionPoint.X - radius,
                intersectionPoint.Y - radius,
                2 * radius,
                2 * radius
            );

            startAngle = (float)(Math.Atan2(deltaY, deltaX) * 180 / Math.PI);

            deltaX = closePoint2.X - intersectionPoint.X;
            deltaY = closePoint2.Y - intersectionPoint.Y;

            float endAngle = (float)(Math.Atan2(deltaY, deltaX) * 180 / Math.PI);

            sweepAngle = endAngle - startAngle;

            if(sweepAngle > 180)
            {
                sweepAngle = sweepAngle - 360;
            }

            if(sweepAngle < -180)
            {
                sweepAngle = 360 + sweepAngle;
            }
        }

        #endregion
    }
}

 

▶ Extension.cs

using System;
using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 확장
    /// </summary>
    public static class Extension
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 거리 구하기 - GetDistance(point1, point2)

        /// <summary>
        /// 거리 구하기
        /// </summary>
        /// <param name="point1">포인트 1</param>
        /// <param name="point2">포인트 2</param>
        /// <returns>거리</returns>
        public static float GetDistance(this PointF point1, PointF point2)
        {
            float deltaX = point1.X - point2.X;
            float deltaY = point1.Y - point2.Y;

            return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
        }

        #endregion
        #region 사각형 채우기 - FillRectangle(graphics, brush, rectangle)

        /// <summary>
        /// 사각형 채우기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="brush">브러시</param>
        /// <param name="rectangle">사각형</param>
        public static void FillRectangle(this Graphics graphics, Brush brush, RectangleF rectangle)
        {
            graphics.FillRectangle(brush, rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
        }

        #endregion
        #region 사각형 그리기 - DrawRectangle(graphics, pen, rectangle)

        /// <summary>
        /// 사각형 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="pen">펜</param>
        /// <param name="rectangle">사각형</param>
        public static void DrawRectangle(this Graphics graphics, Pen pen, RectangleF rectangle)
        {
            graphics.DrawRectangle(pen, rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
        }

        #endregion
        #region 포인트 채우기 - FillPoint(graphics, brush, point, radius)

        /// <summary>
        /// 포인트 채우기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="brush">브러시</param>
        /// <param name="point">포인트</param>
        /// <param name="radius">반경</param>
        public static void FillPoint(this Graphics graphics, Brush brush, PointF point, float radius)
        {
            graphics.FillEllipse(brush, point.X - radius, point.Y - radius, 2 * radius, 2 * radius);
        }

        #endregion
        #region 포인트 그리기 - DrawPoint(graphics, pen, point, radius)

        /// <summary>
        /// 포인트 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="pen">펜</param>
        /// <param name="point">포인트</param>
        /// <param name="radius">반경</param>
        public static void DrawPoint(this Graphics graphics, Pen pen, PointF point, float radius)
        {
            graphics.DrawEllipse(pen, point.X - radius, point.Y - radius, 2 * radius, 2 * radius);
        }

        #endregion
    }
}

 

▶ 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
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 포인트 리스트
        /// </summary>
        private List<PointF> pointList = new List<PointF>();

        /// <summary>
        /// 그리기 여부
        /// </summary>
        private bool isDrawing = false;

        /// <summary>
        /// 반경
        /// </summary>
        private int radius = 5;

        #endregion

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

        #region 생성자 - MainForm()

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

            Load                           += Form_Load;
            this.radiusTextBox.TextChanged += radiusTextBox_TextChanged;
            this.pictureBox.MouseClick     += pictureBox_MouseClick;
            this.pictureBox.MouseMove      += pictureBox_MouseMove;
            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.radius = int.Parse(this.radiusTextBox.Text);
        }

        #endregion
        #region 반경 텍스트 박스 텍스트 변경시 처리하기 - radiusTextBox_TextChanged(sender, e)

        /// <summary>
        /// 반경 텍스트 박스 텍스트 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void radiusTextBox_TextChanged(object sender, EventArgs e)
        {
            try
            {
                int newRadius = int.Parse(this.radiusTextBox.Text);

                if(newRadius > 0)
                {
                    this.radius = newRadius;

                    this.pictureBox.Refresh();
                }
            }
            catch
            {
            }
        }

        #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(e.Button == MouseButtons.Left)
            {
                if(!this.isDrawing)
                {
                    this.pointList = new List<PointF>();

                    this.pointList.Add(e.Location);

                    this.isDrawing = true;
                }

                this.pointList.Add(e.Location);
            }
            else
            {
                if(!this.isDrawing)
                {
                    return;
                }

                this.pointList.RemoveAt(this.pointList.Count - 1);

                this.isDrawing = false;
            }

            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.isDrawing)
            {
                return;
            }

            this.pointList[this.pointList.Count - 1] = e.Location;

            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.Clear(pictureBox.BackColor);

            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            if(this.isDrawing && (this.pointList.Count >= 2))
            {
                GraphicsPath path = GetRoundedPolylineGraphicsPath(this.pointList, this.radius, false);

                if(path != null)
                {
                    using(Pen pen = new Pen(Color.Red, 3))
                    {
                        e.Graphics.DrawPath(pen, path);
                    }
                }
            }
            else if(!this.isDrawing && (this.pointList.Count >= 3))
            {
                GraphicsPath path = GetRoundedPolylineGraphicsPath(this.pointList, this.radius, true);

                if(path != null)
                {
                    e.Graphics.FillPath(Brushes.LightGreen, path);

                    using(Pen pen = new Pen(Color.Green, 3))
                    {
                        e.Graphics.DrawPath(pen, path);
                    }
                }
            }
        }

        #endregion

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

        #region 중복 제거하기 - RemoveDuplicate<TItem>(sourceList)

        /// <summary>
        /// 중복 제거하기
        /// </summary>
        /// <typeparam name="TItem">항목 타입</typeparam>
        /// <param name="sourceList">소스 리스트</param>
        /// <returns>중복 제거 리스트</returns>
        private List<TItem> RemoveDuplicate<TItem>(List<TItem> sourceList)
        {
            List<TItem> targetList = new List<TItem>();

            int itemCount = sourceList.Count;

            TItem lastItem = sourceList[itemCount - 1];

            foreach(TItem item in sourceList)
            {
                if(!item.Equals(lastItem))
                {
                    targetList.Add(item);

                    lastItem = item;
                }
            }

            return targetList;
        }

        #endregion
        #region 라운드 대각선 그래픽스 패스 구하기 - GetRoundedPolylineGraphicsPath(pointList, radius, isClosed)

        /// <summary>
        /// 라운드 대각선 그래픽스 패스 구하기
        /// </summary>
        /// <param name="pointList">포인트 리스트</param>
        /// <param name="radius">반경</param>
        /// <param name="isClosed">폐쇄 여부</param>
        /// <returns>라운드 대각선 그래픽스 패스</returns>
        private GraphicsPath GetRoundedPolylineGraphicsPath(List<PointF> pointList, int radius, bool isClosed)
        {
            pointList = RemoveDuplicate(pointList);

            int pointCount = pointList.Count;

            if(pointCount < 2)
            {
                return null;
            }

            PointF[] pointArray = pointList.ToArray();

            SegmentInformation[] segmentInformationArray = new SegmentInformation[pointCount];

            for(int i = 0; i < pointCount; i++)
            {
                int j = (i + 1) % pointCount;

                segmentInformationArray[i] = new SegmentInformation(pointArray[i], pointArray[j]);
            }

            ArcInformation[] arcInformationArray = new ArcInformation[pointCount];

            for(int i = 0; i < pointCount; i++)
            {
                int j = i - 1;

                if(j < 0)
                {
                    j += pointCount;
                }

                PointF point1 = pointArray[j];
                PointF point2 = pointArray[i];
                PointF point3 = pointArray[(i + 1) % pointCount];
                PointF point4 = pointArray[i];

                RectangleF rectangle;
                float      startAngle;
                float      sweepAngle;
                PointF     farPoint1;
                PointF     closePoint1;
                PointF     farPoint2;
                PointF     closePoint2;

                if
                (
                    ArcHelper.FindArcWithRadius
                    (
                        point1,
                        point2,
                        point3,
                        point4,
                        radius,
                        out rectangle,
                        out startAngle,
                        out sweepAngle,
                        out farPoint1,
                        out closePoint1,
                        out farPoint2,
                        out closePoint2
                    )
                )
                {
                    arcInformationArray[i] = new ArcInformation(rectangle, startAngle, sweepAngle);

                    j = i - 1;

                    if(j < 0)
                    {
                        j += pointCount;
                    }

                    segmentInformationArray[j].EndPoint   = closePoint1;
                    segmentInformationArray[i].StartPoint = closePoint2;
                }
            }

            if(!isClosed)
            {
                segmentInformationArray[0].StartPoint = pointArray[0];

                segmentInformationArray[pointCount - 2].EndPoint = pointArray[pointCount - 1];
            }

            GraphicsPath path = new GraphicsPath();

            for(int i = 0; i < pointCount - 1; i++)
            {
                if(isClosed || i > 0)
                {
                    path.AddArc
                    (
                        arcInformationArray[i].Rectangle,
                        arcInformationArray[i].StartAngle,
                        arcInformationArray[i].SweepAngle
                    );
                }

                path.AddLine(segmentInformationArray[i].StartPoint, segmentInformationArray[i].EndPoint);
            }

            if(isClosed)
            {
                path.AddArc
                (
                    arcInformationArray[pointCount - 1].Rectangle,
                    arcInformationArray[pointCount - 1].StartAngle,
                    arcInformationArray[pointCount - 1].SweepAngle
                );

                path.AddLine
                (
                    segmentInformationArray[pointCount - 1].StartPoint,
                    segmentInformationArray[pointCount - 1].EndPoint
                );

                path.CloseFigure();
            }

            return path;
        }

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

댓글을 달아 주세요