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

728x90
반응형
728x170

TestProject.zip
다운로드

▶ MainWindow.xaml

<Window x:Class="TestProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="600"
    Height="450"
    Title="대칭 복합 선 그리기"
    Loaded="Window_Loaded">
    <Grid Name="mainGrid">
    </Grid>
</Window>

 

728x90

 

▶ MainWindow.xaml.cs

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우
    /// </summary>
    public partial class MainWindow : Window
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindow()

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

        #endregion

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

        #region 윈도우 로드시 처리하기 - Window_Loaded(sender, e)

        /// <summary>
        /// 윈도우 로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            double width = Math.Min
            (
                this.mainGrid.ActualWidth  - 60,
                this.mainGrid.ActualHeight - 40
            );

            Rect rectangle = new Rect(30, 40, width, width);

            Point[] pointArray = GetStarPointArray(-Math.PI / 2, 5, 2, rectangle);

            double[] thicknessesArray = { 15, 10, 6 };

            Brush[] brusheArray = { Brushes.Blue, Brushes.White, Brushes.Blue };

            for(int i = 0; i < thicknessesArray.Length; i++)
            {
                Polygon polygon = new Polygon();

                polygon.Points          = new PointCollection(pointArray);
                polygon.StrokeThickness = thicknessesArray[i];
                polygon.Stroke          = brusheArray[i];

                this.mainGrid.Children.Add(polygon);
            }
        }

        #endregion

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

        #region 교차 포인트 찾기 - FindIntersectionPoint(point1, point2, point3, point4,
            lineIntersect, segmentIntersect, intersectionPoint, closePoint1, closePoint2)

        /// <summary>
        /// 교차 포인트 찾기
        /// </summary>
        /// <param name="point1">포인트 1</param>
        /// <param name="point2">포인트 2</param>
        /// <param name="point3">포인트 3</param>
        /// <param name="point4">포인트 41</param>
        /// <param name="lineIntersect">직선 교차 여부</param>
        /// <param name="segmentIntersect">세그먼트 교차 여부</param>
        /// <param name="intersectionPoint">교차 포인트</param>
        /// <param name="closePoint1">근접 포인트 1</param>
        /// <param name="closePoint2">근접 포인트 2</param>
        private void FindIntersectionPoint(Point point1, Point point2, Point point3, Point point4,
            out bool lineIntersect, out bool segmentIntersect, out Point intersectionPoint, out Point closePoint1, out Point closePoint2)
        {
            double dx12 = point2.X - point1.X;
            double dy12 = point2.Y - point1.Y;
            double dx34 = point4.X - point3.X;
            double dy34 = point4.Y - point3.Y;

            double denominator = (dy12 * dx34 - dx12 * dy34);

            double t1 = ((point1.X - point3.X) * dy34 + (point3.Y - point1.Y) * dx34) / denominator;

            if(double.IsInfinity(t1))
            {
                lineIntersect    = false;
                segmentIntersect = false;

                intersectionPoint = new Point(double.NaN, double.NaN);

                closePoint1 = new Point(double.NaN, double.NaN);
                closePoint2 = new Point(double.NaN, double.NaN);

                return;
            }

            lineIntersect = true;

            double t2 = ((point3.X - point1.X) * dy12 + (point1.Y - point3.Y) * dx12) / -denominator;

            intersectionPoint = new Point(point1.X + dx12 * t1, point1.Y + dy12 * t1);

            segmentIntersect = ((t1 >= 0) && (t1 <= 1) && (t2 >= 0) && (t2 <= 1));

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

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

            closePoint1 = new Point(point1.X + dx12 * t1, point1.Y + dy12 * t1);
            closePoint2 = new Point(point3.X + dx34 * t2, point3.Y + dy34 * t2);
        }

        #endregion
        #region 오목 반지름 구하기 - GetConcaveRadius(pointCount, skip)

        /// <summary>
        /// 오목 반지름 구하기
        /// </summary>
        /// <param name="pointCount">포인트 카운트</param>
        /// <param name="skip">건너띄기</param>
        /// <returns>오목 반지름</returns>
        private double GetConcaveRadius(int pointCount, int skip)
        {
            if(pointCount < 5)
            {
                return 0.33f;
            }

            double deltaTheta = 2 * Math.PI / pointCount;
            double theta00    = -Math.PI / 2;
            double theta01    = theta00 + deltaTheta * skip;
            double theta10    = theta00 + deltaTheta;
            double theta11    = theta10 - deltaTheta * skip;

            Point pt00 = new Point
            (
                (double)Math.Cos(theta00),
                (double)Math.Sin(theta00)
            );

            Point pt01 = new Point
            (
                (double)Math.Cos(theta01),
                (double)Math.Sin(theta01)
            );

            Point pt10 = new Point
            (
                (double)Math.Cos(theta10),
                (double)Math.Sin(theta10)
            );

            Point pt11 = new Point
            (
                (double)Math.Cos(theta11),
                (double)Math.Sin(theta11)
            );

            bool lineIntersect;
            bool segmentIntersect;

            Point intersectionPoint;
            Point closePoint1;
            Point closePoint2;

            FindIntersectionPoint
            (
                pt00,
                pt01,
                pt10,
                pt11,
                out lineIntersect,
                out segmentIntersect,
                out intersectionPoint,
                out closePoint1,
                out closePoint2
            );

            return Math.Sqrt(intersectionPoint.X * intersectionPoint.X + intersectionPoint.Y * intersectionPoint.Y);
        }

        #endregion
        #region 별 포인트 배열 구하기 - GetStarPointArray(startTheta, pointCount, skip, rectangle)

        /// <summary>
        /// 별 포인트 배열 구하기
        /// </summary>
        /// <param name="startTheta">시작 세타</param>
        /// <param name="pointCount">포인트 카운트</param>
        /// <param name="skip">건너띄기</param>
        /// <param name="rectangle">사각형</param>
        /// <returns>별 포인트 배열</returns>
        private Point[] GetStarPointArray(double startTheta, int pointCount, int skip, Rect rectangle)
        {
            double  theta;
            double  deltaTheta;
            Point[] pointArray;

            double  halfWidth  = rectangle.Width  / 2f;
            double  halfHeight = rectangle.Height / 2f;
            double  centerX    = rectangle.X + halfWidth;
            double  centerY    = rectangle.Y + halfHeight;

            if(skip == 1)
            {
                pointArray = new Point[pointCount];

                theta = startTheta;

                deltaTheta = 2 * Math.PI / pointCount;

                for(int i = 0; i < pointCount; i++)
                {
                    pointArray[i] = new Point
                    (
                        (double)(centerX + halfWidth * Math.Cos(theta)),
                        (double)(centerY + halfHeight * Math.Sin(theta))
                    );

                    theta += deltaTheta;
                }

                return pointArray;
            }

            double concaveRadius = GetConcaveRadius(pointCount, skip);

            pointArray = new Point[2 * pointCount];
            theta      = startTheta;
            deltaTheta = Math.PI / pointCount;

            for(int i = 0; i < pointCount; i++)
            {
                pointArray[2 * i] = new Point
                (
                    (double)(centerX + halfWidth  * Math.Cos(theta)),
                    (double)(centerY + halfHeight * Math.Sin(theta))
                );

                theta += deltaTheta;

                pointArray[2 * i + 1] = new Point
                (
                    (double)(centerX + halfWidth  * Math.Cos(theta) * concaveRadius),
                    (double)(centerY + halfHeight * Math.Sin(theta) * concaveRadius)
                );

                theta += deltaTheta;
            }

            return pointArray;
        }

        #endregion
    }
}
728x90
반응형
그리드형
Posted by 사용자 icodebroker
TAG , , ,

댓글을 달아 주세요