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

■ 파이 슬라이스 그리기

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


TestProject.zip


DrawingExtension.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 static class DrawingExtension

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region 호 추가하기 - AddArc(canvas, fillBrush, strokeBrush, strokeThickness, startPoint, endPoint, size, rotationAngle,

            isLargeArc, sweepDirection, isStroked)

 

        /// <summary>

        /// 호 추가하기

        /// </summary>

        /// <param name="canvas">캔버스</param>

        /// <param name="fillBrush">칠하기 브러시</param>

        /// <param name="strokeBrush">스트로크 브러시</param>

        /// <param name="strokeThickness">스트로크 두께</param>

        /// <param name="startPoint">시작 포인트</param>

        /// <param name="endPoint">종료 포인트</param>

        /// <param name="size">크기</param>

        /// <param name="rotationAngle">회전 각도</param>

        /// <param name="isLargeArc">큰 아크 여부</param>

        /// <param name="sweepDirection">스윕 방향</param>

        /// <param name="isStroked">스트로크 여부</param>

        /// <returns></returns>

        public static Path AddArc

        (

            this Canvas    canvas,

            Brush          fillBrush,

            Brush          strokeBrush,

            double         strokeThickness,

            Point          startPoint,

            Point          endPoint,

            Size           size,

            double         rotationAngle,

            bool           isLargeArc,

            SweepDirection sweepDirection,

            bool           isStroked

        )

        {

            #region 패스 지오메트리를 설정한다.

 

            PathGeometry pathGeometry = new PathGeometry();

 

            #endregion

            #region 패스 세그먼트 컬렉션을 설정한다.

 

            PathSegmentCollection pathSegmentCollection = new PathSegmentCollection();

 

            #endregion

            #region 호 세그먼트를 설정한다.

 

            ArcSegment arcSegment = new ArcSegment

            (

                endPoint,

                size,

                rotationAngle,

                isLargeArc,

                sweepDirection,

                isStroked

            );

 

            pathSegmentCollection.Add(arcSegment);

 

            #endregion

            #region 패스 모양을 설정한다.

 

            PathFigure pathFigure = new PathFigure();

 

            pathFigure.StartPoint = startPoint;

            pathFigure.Segments   = pathSegmentCollection;

 

            pathGeometry.Figures.Add(pathFigure);

 

            #endregion

            #region 패스를 설정한다.

 

            Path path = new Path();

 

            path.Stroke          = strokeBrush;

            path.StrokeThickness = strokeThickness;

            path.Fill            = fillBrush;

            path.Data            = pathGeometry;

 

            canvas.Children.Add(path);

 

            #endregion

 

            return path;

        }

 

        #endregion

        #region 호 추가하기 - AddArc(canvas, fillBrush, strokeBrush, strokeThickness, rect, angle1, angle2,

            isLargeArc, sweepDirection, point1, point2)

 

        /// <summary>

        /// 호 추가하기

        /// </summary>

        /// <param name="canvas">캔버스</param>

        /// <param name="fillBrush">칠하기 브러시</param>

        /// <param name="strokeBrush">스트로크 브러시</param>

        /// <param name="strokeThickness">스트로크 두께</param>

        /// <param name="rect">사각형</param>

        /// <param name="angle1">각도 1</param>

        /// <param name="angle2">각도 2</param>

        /// <param name="isLargeArc">큰 아크 여부</param>

        /// <param name="sweepDirection">스윕 방향</param>

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

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

        /// <returns></returns>

        public static Path AddArc

        (

            this Canvas    canvas,

            Brush          fillBrush,

            Brush          strokeBrush,

            double         strokeThickness,

            Rect           rect,

            double         angle1,

            double         angle2,

            bool           isLargeArc,

            SweepDirection sweepDirection,

            out Point      point1,

            out Point      point2

        )

        {

            Point[] pointArray = FindEllipsePointArray(rect, angle1, angle2);

 

            point1 = pointArray[0];

            point2 = pointArray[1];

 

            Size size = new Size(rect.Width / 2, rect.Height / 2);

 

            return canvas.AddArc

            (

                fillBrush,

                strokeBrush,

                strokeThickness,

                pointArray[0],

                pointArray[1],

                size,

                0,

                isLargeArc,

                sweepDirection,

                true

            );

        }

 

        #endregion

 

        #region 파이 슬라이스 추가하기 - AddPieSlice(canvas, fillBrush, strokeBrush, strokeThickness, rect, angle1, angle2,

            isLargeArc, sweepFirection, point1, point2)

 

        /// <summary>

        /// 파이 슬라이스 추가하기

        /// </summary>

        /// <param name="canvas">캔버스</param>

        /// <param name="fillBrush">칠하기 브러시</param>

        /// <param name="strokeBrush">스트로크 브러시</param>

        /// <param name="strokeThickness">스트로크 두께</param>

        /// <param name="rect">사각형</param>

        /// <param name="angle1">각도 1</param>

        /// <param name="angle2">각도 2</param>

        /// <param name="isLargeArc">큰 아크 여부</param>

        /// <param name="sweepFirection">스윕 방향</param>

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

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

        /// <returns>파이 슬라이스 패스</returns>

        public static Path AddPieSlice

        (

            this Canvas    canvas,

            Brush          fillBrush,

            Brush          strokeBrush,

            double         strokeThickness,

            Rect           rect,

            double         angle1,

            double         angle2,

            bool           isLargeArc,

            SweepDirection sweepFirection,

            out Point      point1,

            out Point      point2

        )

        {

            Path path = canvas.AddArc

            (

                fillBrush,

                strokeBrush,

                strokeThickness,

                rect,

                angle1,

                angle2,

                isLargeArc,

                sweepFirection,

                out point1,

                out point2

            );

 

            PathGeometry pathGeometry = (PathGeometry)path.Data;

 

            PathFigureCollection pathFigureCollection = pathGeometry.Figures;

 

            PathFigure pathFigure = pathFigureCollection[0];

 

            PathSegmentCollection pathSegmentCollection = pathFigure.Segments;

 

            Point centerPoint = new Point

            (

                (rect.Left + rect.Right ) / 2,

                (rect.Top  + rect.Bottom) / 2

            );

 

            LineSegment lineSegment1 = new LineSegment(centerPoint, true);

 

            pathSegmentCollection.Add(lineSegment1);

            

            LineSegment lineSegment2 = new LineSegment(point1, true);

 

            pathSegmentCollection.Add(lineSegment2);

 

            return path;

        }

 

        #endregion

 

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

 

        #region 타원 세그먼트 교차점 배열 찾기 - FindEllipseSegmentIntersectionPointArray(rect, point1, point2, segmentOnly)

 

        /// <summary>

        /// 타원 세그먼트 교차점 배열 찾기

        /// </summary>

        /// <param name="rect">사각형</param>

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

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

        /// <param name="segmentOnly">세그먼트 전용 여부</param>

        /// <returns>타원 세그먼트 교차점 배열</returns>

        private static Point[] FindEllipseSegmentIntersectionPointArray(Rect rect, Point point1, Point point2, bool segmentOnly)

        {

            if((rect.Width == 0) || (rect.Height == 0) || ((point1.X == point2.X) && (point1.Y == point2.Y)))

            {

                return new Point[] { };

            }

 

            if(rect.Width < 0)

            {

                rect.X     =  rect.Right;

                rect.Width = -rect.Width;

            }

 

            if(rect.Height < 0)

            {

                rect.Y      =  rect.Bottom;

                rect.Height = -rect.Height;

            }

 

            double centerX = rect.Left + rect.Width  / 2f;

            double centerY = rect.Top  + rect.Height / 2f;

 

            rect.X -= centerX;

            rect.Y -= centerY;

 

            point1.X -= centerX;

            point1.Y -= centerY;

            point2.X -= centerX;

            point2.Y -= centerY;

 

            double a = rect.Width  / 2;

            double b = rect.Height / 2;

 

            double A = (point2.X - point1.X) * (point2.X - point1.X) / a / a + (point2.Y - point1.Y) * (point2.Y - point1.Y) / b / b;

            double B = 2 * point1.X * (point2.X - point1.X) / a / a + 2 * point1.Y * (point2.Y - point1.Y) / b / b;

            double C = point1.X * point1.X / a / a + point1.Y * point1.Y / b / b - 1;

 

            List<double> valueList = new List<double>();

 

            double discriminant = B * B - 4 * A * C;

 

            if(discriminant == 0)

            {

                valueList.Add(-B / 2 / A);

            }

            else if(discriminant > 0)

            {

                valueList.Add((double)((-B + Math.Sqrt(discriminant)) / 2 / A));

                valueList.Add((double)((-B - Math.Sqrt(discriminant)) / 2 / A));

            }

 

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

 

            foreach(double value in valueList)

            {

                if(!segmentOnly || ((value >= 0f) && (value <= 1f)))

                {

                    double x = point1.X + (point2.X - point1.X) * value + centerX;

                    double y = point1.Y + (point2.Y - point1.Y) * value + centerY;

 

                    pointList.Add(new Point(x, y));

                }

            }

 

            return pointList.ToArray();

        }

 

        #endregion

        #region 타원 포인트 배열 찾기 - FindEllipsePointArray(rect, angle1, angle2)

 

        /// <summary>

        /// 타원 포인트 배열 찾기

        /// </summary>

        /// <param name="rect">사각형</param>

        /// <param name="angle1">각도 1</param>

        /// <param name="angle2">각도 2</param>

        /// <returns>타원 포인트 배열</returns>

        private static Point[] FindEllipsePointArray(Rect rect, double angle1, double angle2)

        {

            Point centerPoint = new Point

            (

                rect.X + rect.Width  / 2.0,

                rect.Y + rect.Height / 2.0

            );

 

            double distance = rect.Width + rect.Height;

 

            Point point1 = new Point

            (

                centerPoint.X + distance * Math.Cos(angle1),

                centerPoint.Y + distance * Math.Sin(angle1)

            );

 

            Point point2 = new Point

            (

                centerPoint.X + distance * Math.Cos(angle2),

                centerPoint.Y + distance * Math.Sin(angle2)

            );

 

            Point[] intersectionPointArray1 = FindEllipseSegmentIntersectionPointArray(rect, centerPoint, point1, true);

            Point[] intersectionPointArray2 = FindEllipseSegmentIntersectionPointArray(rect, centerPoint, point2, true);

 

            return new Point[]

            {

                intersectionPointArray1[0],

                intersectionPointArray2[0]

            };

        }

 

        #endregion

    }

}

 

 

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="800"

    Height="600"

    Title="파이 슬라이스 그리기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <Grid>

        <Canvas Name="canvas"/>

    </Grid>

</Window>

 

 

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();

 

            Loaded += Window_Loaded;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

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

 

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

 

        /// <summary>

        /// 윈도우 로드시 처리하기

        /// </summary>

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

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

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            Rect rect = new Rect(150, 50, 480, 480);

 

            Point point1;

            Point point2;

 

            Path pieSlice1 = this.canvas.AddPieSlice

            (

                Brushes.Yellow,

                Brushes.Orange,

                5,

                rect,

                0,

                0.15 * Math.PI,

                false,

                SweepDirection.Clockwise,

                out point1,

                out point2

            );

 

            pieSlice1.StrokeLineJoin = PenLineJoin.Round;

 

            Path pieSlice2 = this.canvas.AddPieSlice

            (

                Brushes.Pink,

                Brushes.Red,

                5,

                rect,

                0.15 * Math.PI,

                0.6 * Math.PI,

                false,

                SweepDirection.Clockwise,

                out point1,

                out point2

            );

 

            pieSlice2.StrokeLineJoin = PenLineJoin.Round;

 

            Path pieSlice3 = this.canvas.AddPieSlice

            (

                Brushes.LightBlue,

                Brushes.Blue,

                5,

                rect,

                0.6 * Math.PI,

                1.25 * Math.PI,

                false,

                SweepDirection.Clockwise,

                out point1,

                out point2

            );

 

            pieSlice3.StrokeLineJoin = PenLineJoin.Round;

 

            Path pieSlice4 = this.canvas.AddPieSlice

            (

                Brushes.LightGreen,

                Brushes.Green,

                5,

                rect,

                1.25 * Math.PI,

                1.6 * Math.PI,

                false,

                SweepDirection.Clockwise,

                out point1,

                out point2

            );

 

            pieSlice4.StrokeLineJoin = PenLineJoin.Round;

 

            Path pieSlice5 = this.canvas.AddPieSlice

            (

                Brushes.Fuchsia,

                Brushes.Purple,

                5, rect,

                1.6 * Math.PI,

                2 * Math.PI,

                false,

                SweepDirection.Clockwise,

                out point1,

                out point2

            );

 

            pieSlice5.StrokeLineJoin = PenLineJoin.Round;

        }

 

        #endregion

    }

}

 

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

Posted by 사용자 icodebroker

댓글을 달아 주세요