■ 외곽선 경로 구하기
------------------------------------------------------------------------------------------------------------------------
▶ 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 } }
|
------------------------------------------------------------------------------------------------------------------------
'C# > WPF' 카테고리의 다른 글
[C#/WPF] 정육면체(Cube) 사용하기 (0) | 2018.12.31 |
---|---|
[C#/WPF] 사면체(Tetrahedron) 사용하기 (0) | 2018.12.31 |
[C#/WPF] 설치 폰트 샘플 표시하기 (0) | 2018.12.30 |
[C#/WPF] 색상 리스트 표시하기 (0) | 2018.12.30 |
[C#/WPF] FrameworkElement 클래스 : 이미지 저장하기 (0) | 2018.12.30 |
[C#/WPF] 외곽선 경로 구하기 (0) | 2018.12.30 |
[C#/WPF] 대칭 복합 선 그리기 (0) | 2018.12.30 |
[C#/WPF] WriteableBitmap 클래스 : 비트맵 픽셀 설정하기 (0) | 2018.12.29 |
[C#/WPF] RenderTargetBitmap 클래스 : 텍스트 그리기 (0) | 2018.12.27 |
[C#/WPF] 회전 텍스트 그리기 (0) | 2018.12.27 |
[C#/WPF] 이미지 텍스트 그리기 (0) | 2018.12.26 |
댓글을 달아 주세요