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

■ 외곽선 경로 구하기

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


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="외곽선 경로 그리기">

    <Grid Name="mainGrid">

        <Path Name="sourcePath"

            HorizontalAlignment="Center"

            VerticalAlignment="Center"

            Stroke="LightGreen"

            StrokeThickness="10">

            <Path.Data>

                <PathGeometry x:Name="sourcePathGeometry"

                    Figures="M 20 20 C 200 0, 0 200, 40 60

                             L 150 30 C 60 200, 200 150, 200 60

                             M 70 140 L 150 240, 180 170, 30 200

                             M 270 70 L 270 230, 200 200 Z" />

            </Path.Data>

        </Path>

        <Button Name="runButton"

            HorizontalAlignment="Left"

            VerticalAlignment="Bottom"

            Margin="5"

            Width="100"

            Height="30"

            IsDefault="True"

            Content="실행"

            Click="runButton_Click"/>

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System;

using System.Collections.Generic;

using System.Windows;

using System.Windows.Controls;

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 실행 버튼 클릭시 처리하기 - runButton_Click(sender, e)

 

        /// <summary>

        /// 실행 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void runButton_Click(object sender, RoutedEventArgs e)

        {

            PathGeometry pathGeometry = this.sourcePathGeometry.GetFlattenedPathGeometry();

 

            double thickness = this.sourcePath.StrokeThickness;

 

            List<Polygon> polygonList = GetOutlinePolygonList(pathGeometry, thickness);

 

            Grid grid = new Grid();

 

            grid.VerticalAlignment   = VerticalAlignment.Center;

            grid.HorizontalAlignment = HorizontalAlignment.Center;

 

            foreach(Polygon polygon in polygonList)

            {

                polygon.Stroke          = Brushes.Red;

                polygon.StrokeThickness = 1;

 

                grid.Children.Add(polygon);

            }

 

            this.mainGrid.Children.Add(grid);

 

            this.runButton.IsEnabled = false;

            this.runButton.Opacity   = 0.5;

        }

 

        #endregion

 

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

 

        #region 평탄화 포인트 리스트 구하기 - GetFlattenedPointList(pathFigure)

 

        /// <summary>

        /// 평탄화 포인트 리스트 구하기

        /// </summary>

        /// <param name="pathFigure">패스 피겨</param>

        /// <returns>평탄화 포인트 리스트</returns>

        private List<Point> GetFlattenedPointList(PathFigure pathFigure)

        {

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

 

            pointList.Add(pathFigure.StartPoint);

 

            foreach(PathSegment pathSegment in pathFigure.Segments)

            {

                if(pathSegment is LineSegment)

                {

                    LineSegment lineSegment = pathSegment as LineSegment;

 

                    pointList.Add(lineSegment.Point);

                }

                else if(pathSegment is PolyLineSegment)

                {

                    PolyLineSegment polyLineSegment = pathSegment as PolyLineSegment;

 

                    foreach(Point point in polyLineSegment.Points)

                    {

                        pointList.Add(point);

                    }

                }

                else

                {

                    throw new Exception("알 수 없는 평탄화 경로 세그먼트 타입 : " + pathSegment.GetType().Name);

                }

            }

 

            return pointList;

        }

 

        #endregion

        #region 엣지 포인트 설정하기 - SetEdgePoint(point1, point2, thickness, left1Point, left2Point, right1Point, right2Point)

 

        /// <summary>

        /// 엣지 포인트 설정하기

        /// </summary>

        /// <param name="point1">포인트 1</param>

        /// <param name="point2">포인트 2</param>

        /// <param name="thickness">두께</param>

        /// <param name="left1Point">왼쪽 1 포인트</param>

        /// <param name="left2Point">왼쪽 2 포인트</param>

        /// <param name="right1Point">오른쪽 1 포인트</param>

        /// <param name="right2Point">오른쪽 2 포인트</param>

        private void SetEdgePoint(Point point1, Point point2, double thickness,

            out Point left1Point, out Point left2Point, out Point right1Point, out Point right2Point)

        {

            double dx = point2.X - point1.X;

            double dy = point2.Y - point1.Y;

 

            double length = Math.Sqrt(dx * dx + dy * dy);

 

            double nx = dx / length;

            double ny = dy / length;

 

            left1Point = new Point

            (

                point1.X - ny * thickness / 2.0,

                point1.Y + nx * thickness / 2.0

            );

 

            left2Point = new Point

            (

                point2.X - ny * thickness / 2.0,

                point2.Y + nx * thickness / 2.0

            );

 

            right1Point = new Point

            (

                point1.X + ny * thickness / 2.0,

                point1.Y - nx * thickness / 2.0

            );

 

            right2Point = new Point

            (

                point2.X + ny * thickness / 2.0,

                point2.Y - nx * thickness / 2.0

            );

        }

 

        #endregion

        #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">포인트 4</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 교차 포인트 찾기 - FindIntersectionPoint(point1, point2, point3, thickness, leftPoint, rightPoint)

 

        /// <summary>

        /// 교차 포인트 찾기

        /// </summary>

        /// <param name="point1">포인트 1</param>

        /// <param name="point2">포인트 2</param>

        /// <param name="point3">포인트 3</param>

        /// <param name="thickness">두께</param>

        /// <param name="leftPoint">왼쪽 포인트</param>

        /// <param name="rightPoint">오른쪽 포인트</param>

        private void FindIntersectionPoint(Point point1, Point point2, Point point3, double thickness,

            out Point leftPoint, out Point rightPoint)

        {

            Point close1Point;

            Point close2Point;

 

            bool lineIntersect;

            bool segmentIntersect;

 

            Point left11Point;

            Point left12Point;

            Point left21Point;

            Point left22Point;

            Point right11Point;

            Point right12Point;

            Point right21Point;

            Point right22Point;

 

            SetEdgePoint(point1, point2, thickness, out left11Point, out left12Point, out right11Point, out right12Point);

            SetEdgePoint(point2, point3, thickness, out left21Point, out left22Point, out right21Point, out right22Point);

 

            FindIntersectionPoint

            (

                left11Point,

                left12Point,

                left21Point,

                left22Point,

                out lineIntersect,

                out segmentIntersect,

                out leftPoint,

                out close1Point,

                out close2Point

            );

 

            FindIntersectionPoint

            (

                right11Point,

                right12Point,

                right21Point,

                right22Point,

                out lineIntersect,

                out segmentIntersect,

                out rightPoint,

                out close1Point,

                out close2Point

            );

        }

 

        #endregion

        #region 외곽선 포인트 리스트 리스트 구하기 - GetOutlinePointListList(pathFigure, thickness)

 

        /// <summary>

        /// 외곽선 포인트 리스트 리스트 구하기

        /// </summary>

        /// <param name="pathFigure">패스 피겨</param>

        /// <param name="thickness">두께</param>

        /// <returns>포인트 리스트 리스트</returns>

        private List<List<Point>> GetOutlinePointListList(PathFigure pathFigure, double thickness)

        {

            List<Point> pointList = GetFlattenedPointList(pathFigure);

 

            List<Point> leftPointList  = new List<Point>();

            List<Point> rightPointList = new List<Point>();

 

            Point leftPoint;

            Point rightPoint;

            Point ignore1Point;

            Point ignore2Point;

 

            if(pathFigure.IsClosed)

            {

                pointList.Add(pointList[1]);

            }

            else

            {

                SetEdgePoint

                (

                    pointList[0],

                    pointList[1],

                    thickness,

                    out leftPoint,

                    out ignore1Point,

                    out rightPoint,

                    out ignore2Point

                );

 

                leftPointList.Add(leftPoint);

 

                rightPointList.Add(rightPoint);

            }

 

            for(int i = 1; i <= pointList.Count - 2; i++)

            {

                FindIntersectionPoint(pointList[i - 1], pointList[i], pointList[i + 1], thickness, out leftPoint, out rightPoint);

 

                leftPointList.Add(leftPoint);

 

                rightPointList.Add(rightPoint);

            }

 

            SetEdgePoint

            (

                pointList[pointList.Count - 2],

                pointList[pointList.Count - 1],

                thickness,

                out ignore1Point,

                out leftPoint,

                out ignore2Point,

                out rightPoint

            );

 

            List<List<Point>> pointListList = new List<List<Point>>();

 

            if(pathFigure.IsClosed)

            {

                pointListList.Add(leftPointList);

 

                pointListList.Add(rightPointList);

            }

            else

            {

                leftPointList.Add(leftPoint);

 

                rightPointList.Add(rightPoint);

 

                rightPointList.Reverse();

 

                leftPointList.AddRange(rightPointList);

 

                pointListList.Add(leftPointList);

            }

 

            return pointListList;

        }

 

        #endregion

        #region 외곽선 다각형 리스트 구하기 - GetOutlinePolygonList(pathGeometry, thickness)

 

        /// <summary>

        /// 외곽선 다각형 리스트 구하기

        /// </summary>

        /// <param name="pathGeometry">경로 기하</param>

        /// <param name="thickness">두께</param>

        /// <returns>다각형 리스트</returns>

        private List<Polygon> GetOutlinePolygonList(PathGeometry pathGeometry, double thickness)

        {

            List<Polygon> polygonList = new List<Polygon>();

 

            foreach(PathFigure pathFigure in pathGeometry.Figures)

            {

                List<List<Point>> pointListList = GetOutlinePointListList(pathFigure, thickness);

 

                foreach(List<Point> pointList in pointListList)

                {

                    Polygon polygon = new Polygon();

 

                    polygon.Points = new PointCollection(pointList);

 

                    polygonList.Add(polygon);

                }

            }

 

            return polygonList;

        }

 

        #endregion

    }

}

 

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

Posted by 사용자 icodebroker

댓글을 달아 주세요