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

■ PolyBezierSegment 클래스 : 폐곡선 그리기

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


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

    Height="600"

    Title="PolyBezierSegment 클래스 : 폐곡선 그리기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <Grid>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="*"    />

            <ColumnDefinition Width="Auto" />

        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto" />

            <RowDefinition Height="*"    />

        </Grid.RowDefinitions>

        <ScrollBar Name="tensionScrollBar" Grid.Row="0" Grid.Column="0"

            Margin="10"

            Orientation="Horizontal"

            Minimum="0"

            Maximum="50"

            SmallChange="1"

            LargeChange="10"

            Value="10" />

        <Label Name="tensionLabel" Grid.Row="0" Grid.Column="1"

            Margin="10"

            Content="1.0" />

        <Canvas Name="canvas" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"

            Margin="10"

            Background="White" />

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System.Collections.Generic;

using System.Linq;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Controls.Primitives;

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;

            this.tensionScrollBar.Scroll += tensionScrollBar_Scroll;

        }

 

        #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)

        {

            DrawClosedCurve(1.0);

        }

 

        #endregion

        #region 텐션 스크롤바 스크롤시 처리하기 - tensionScrollBar_Scroll(sender, e)

 

        /// <summary>

        /// 텐션 스크롤바 스크롤시 처리하기

        /// </summary>

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

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

        private void tensionScrollBar_Scroll(object sender, ScrollEventArgs e)

        {

            double tension = this.tensionScrollBar.Value / 10;

 

            this.tensionLabel.Content = tension.ToString("0.0");

 

            DrawClosedCurve(tension);

        }

 

        #endregion

 

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

 

        #region 폐곡선 포인트 배열 구하기 - GetClosedCurvePointArray(sourcePointArray, tension)

 

        /// <summary>

        /// 폐곡선 포인트 배열 구하기

        /// </summary>

        /// <param name="sourcePointArray">소스 포인트 배열</param>

        /// <param name="tension">텐션</param>

        /// <returns>폐곡선 포인트 배열</returns>

        private Point[] GetClosedCurvePointArray(Point[] sourcePointArray, double tension)

        {

            if(sourcePointArray.Length < 2)

            {

                return null;

            }

 

            double controlScale = tension / 0.5 * 0.175;

 

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

 

            targetPointList.Add(sourcePointArray[0]);

 

            int pointCount = sourcePointArray.Length;

 

            for(int i = 0; i < pointCount; i++)

            {

                Point previousPoint = sourcePointArray[(i - 1 + pointCount) % pointCount];

                Point point         = sourcePointArray[i];

                Point nextPoint     = sourcePointArray[(i + 1) % pointCount];

                Point nextNextPoint = sourcePointArray[(i + 2) % pointCount];

 

                double deltaX1 = nextPoint.X - previousPoint.X;

                double deltaY1 = nextPoint.Y - previousPoint.Y;

 

                Point point1 = sourcePointArray[i];

                Point point4 = nextPoint;

 

                double deltaX2 = nextPoint.X - previousPoint.X;

                double deltaY2 = nextPoint.Y - previousPoint.Y;

 

                Point point2 = new Point

                (

                    point.X + controlScale * deltaX2,

                    point.Y + controlScale * deltaY2

                );

 

                deltaX2 = nextNextPoint.X - point.X;

                deltaY2 = nextNextPoint.Y - point.Y;

 

                Point point3 = new Point

                (

                    nextPoint.X - controlScale * deltaX2,

                    nextPoint.Y - controlScale * deltaY2

                );

 

                targetPointList.Add(point2);

                targetPointList.Add(point3);

                targetPointList.Add(point4);

            }

 

            return targetPointList.ToArray();

        }

 

        #endregion

        #region 폐곡선 베지어 경로 구하기 - GetClosedBezierPath(sourcePointArray)

 

        /// <summary>

        /// 폐곡선 베지어 경로 구하기

        /// </summary>

        /// <param name="sourcePointArray">소스 포인트 배열</param>

        /// <returns>폐곡선 베지어 경로</returns>

        private Path GetClosedBezierPath(Point[] sourcePointArray)

        {

            Path path = new Path();

 

            PathGeometry pathGeometry = new PathGeometry();

 

            path.Data = pathGeometry;

 

            PathFigure pathFigure = new PathFigure();

 

            pathGeometry.Figures.Add(pathFigure);

 

            pathFigure.StartPoint = sourcePointArray[0];

 

            PathSegmentCollection pathSegmentCollection = new PathSegmentCollection();

 

            pathFigure.Segments = pathSegmentCollection;

 

            PointCollection pointCollection = new PointCollection(sourcePointArray.Length - 1);

 

            for(int i = 1; i < sourcePointArray.Length; i++)

            {

                pointCollection.Add(sourcePointArray[i]);

            }

 

            PolyBezierSegment polyBezierSegment = new PolyBezierSegment();

 

            polyBezierSegment.Points = pointCollection;

 

            pathSegmentCollection.Add(polyBezierSegment);

 

            return path;

        }

 

        #endregion

        #region 폐곡선 경로 구하기 - GetClosedCurvePath(sourcePointArray, tension)

 

        /// <summary>

        /// 폐곡선 경로 구하기

        /// </summary>

        /// <param name="sourcePointArray">소스 포인트 배열</param>

        /// <param name="tension">텐션</param>

        /// <returns>폐곡선 경로</returns>

        private Path GetClosedCurvePath(Point[] sourcePointArray, double tension)

        {

            if(sourcePointArray.Length < 2)

            {

                return null;

            }

 

            Point[] targetPointArray = GetClosedCurvePointArray(sourcePointArray, tension);

 

            return GetClosedBezierPath(targetPointArray.ToArray());

        }

 

        #endregion

        #region 폐곡선 그리기 - DrawClosedCurve(tension)

 

        /// <summary>

        /// 폐곡선 그리기

        /// </summary>

        /// <param name="tension">텐션</param>

        private void DrawClosedCurve(double tension)

        {

            this.canvas.Children.Clear();

 

            Point[] pointArray =

            {

                new Point(160, 100),

                new Point(400, 300),

                new Point(200, 320),

                new Point(400, 120)

            };

 

            Path path = GetClosedCurvePath(pointArray, tension);

 

            path.Stroke          = Brushes.LightBlue;

            path.StrokeThickness = 5;

            

            this.canvas.Children.Add(path);

 

            foreach(Point point in pointArray)

            {

                Rectangle rectangle = new Rectangle();

 

                rectangle.Width           = 6;

                rectangle.Height          = 6;

                rectangle.Stroke          = Brushes.Black;

                rectangle.StrokeThickness = 1;

                rectangle.Fill            = Brushes.White;

 

                Canvas.SetLeft(rectangle, point.X - 3);

                Canvas.SetTop(rectangle , point.Y - 3);

 

                this.canvas.Children.Add(rectangle);

            }

        }

 

        #endregion

    }

}

 

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

Posted by 사용자 icodebroker

댓글을 달아 주세요