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

■ Polygon 클래스 : 다각형 그리기/편집하기

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


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="Polygon 클래스 : 다각형 그리기/편집하기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <Window.CommandBindings>

        <CommandBinding Command="New"

            CanExecute="NewCommand_CanExecute"

            Executed="NewCommand_Executed" />

        <CommandBinding Command="Open"

            CanExecute="OpenCommand_CanExecute"

            Executed="OpenCommand_Executed" />

        <CommandBinding Command="SaveAs"

            CanExecute="SaveAsCommand_CanExecute"

            Executed="SaveAsCommand_Executed" />

    </Window.CommandBindings>

    <Window.InputBindings>

        <KeyBinding Gesture="Ctrl+S" Command="SaveAs" />

    </Window.InputBindings>

    <DockPanel>

        <Menu DockPanel.Dock="Top"

            Padding="5"

            FontFamily="나눔고딕코딩"

            FontSize="16">

            <MenuItem Header="파일(_F)">

                <MenuItem Command="New" />

                <MenuItem Command="Open" />

                <MenuItem Command="SaveAs"

                    InputGestureText="Ctrl+S" />

                <Separator />

                <MenuItem Name="exitMenuItem"

                    Header="종료(_E)" />

            </MenuItem>

        </Menu>

        <StackPanel DockPanel.Dock="Top"

            Margin="10"

            Orientation="Horizontal">

            <RadioButton Name="drawRadioButton"

                Margin="5"

                IsChecked="True"

                Content="그리기" />

            <RadioButton Name="editRadioButton"

                Margin="5"

                Content="편집" />

        </StackPanel>

        <Border Name="border"

            Margin="10"

            BorderBrush="Gray"

            BorderThickness="1">

            <Canvas Name="canvas"

                Background="Transparent"

                ClipToBounds="True" />

        </Border>

    </DockPanel>

</Window>

 

 

MainWindow.xaml.cs

 

 

using Microsoft.Win32;

using System.IO;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Input;

using System.Windows.Markup;

using System.Windows.Media;

using System.Windows.Shapes;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

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

 

        #region Field

 

        /// <summary>

        /// 신규 다각형

        /// </summary>

        private Polyline newPolyline = null;

 

        /// <summary>

        /// 편집 여부

        /// </summary>

        private bool isEditing = false;

 

        /// <summary>

        /// 편집시 다각형 히트 타입

        /// </summary>

        private PolygonHitType editPolygonHitType = PolygonHitType.None;

 

        /// <summary>

        /// 편집 다각형

        /// </summary>

        private Polygon editPolygon = null;

 

        /// <summary>

        /// 편집 다각형 파트 인덱스

        /// </summary>

        private int editPolygonPartIndex = -1;

 

        /// <summary>

        /// 편집 마지막 포인트

        /// </summary>

        private Point editLastPoint = new Point(double.NegativeInfinity, double.NegativeInfinity);

 

        /// <summary>

        /// 파일 열기 대화 상자

        /// </summary>

        private OpenFileDialog openFileDialog = new OpenFileDialog();

 

        /// <summary>

        /// 파일 저장 대화 상자

        /// </summary>

        private SaveFileDialog saveFileDialog = new SaveFileDialog();

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

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

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

 

            this.openFileDialog.Filter     = "DRW Files (*.drw)|*.drw|All files (*.*)|*.*";

            this.openFileDialog.DefaultExt = "drw";

 

            this.saveFileDialog.Filter     = "DRW Files (*.drw)|*.drw|All files (*.*)|*.*";

            this.saveFileDialog.DefaultExt = "drw";

 

            this.exitMenuItem.Click    += exitMenuItem_Click;

            this.editRadioButton.Click += editRadioButton_Click;

            this.canvas.MouseDown      += canvas_MouseDown;

            this.canvas.MouseMove      += canvas_MouseMove;

            this.canvas.MouseUp        += canvas_MouseUp;

        }

 

        #endregion

 

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

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

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 새로 만들기 명령 실행 가능 여부 구하기 - NewCommand_CanExecute(sender, e)

 

        /// <summary>

        /// 새로 만들기 명령 실행 가능 여부 구하기

        /// </summary>

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

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

        private void NewCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)

        {

            e.CanExecute = CanExecute(true);

        }

 

        #endregion

        #region 새로 만들기 명령 실행시 처리하기 - NewCommand_Executed(sender, e)

 

        /// <summary>

        /// 새로 만들기 명령 실행시 처리하기

        /// </summary>

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

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

        private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)

        {

            this.canvas.Children.Clear();

        }

 

        #endregion

        #region 열기 명령 실행 가능 여부 구하기 - OpenCommand_CanExecute(sender, e)

 

        /// <summary>

        /// 열기 명령 실행 가능 여부 구하기

        /// </summary>

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

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

        private void OpenCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)

        {

            e.CanExecute = CanExecute(false);

        }

 

        #endregion

        #region 열기 명령 실행시 처리하기 - OpenCommand_Executed(sender, e)

 

        /// <summary>

        /// 열기 명령 실행시 처리하기

        /// </summary>

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

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

        private void OpenCommand_Executed(object sender, ExecutedRoutedEventArgs e)

        {

            if(this.openFileDialog.ShowDialog().Value)

            {

                string xaml = File.ReadAllText(this.openFileDialog.FileName);

 

                this.canvas = (Canvas)XamlReader.Parse(xaml);

 

                this.border.Child = this.canvas;

 

                this.canvas.MouseMove += canvas_MouseMove;

                this.canvas.MouseDown += canvas_MouseDown;

                this.canvas.MouseUp   += canvas_MouseUp;

            }

        }

 

        #endregion

        #region 다른 이름으로 저장 명령 실행 가능 여부 구하기 - SaveAsCommand_CanExecute(sender, e)

 

        /// <summary>

        /// 다른 이름으로 저장 명령 실행 가능 여부 구하기

        /// </summary>

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

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

        private void SaveAsCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)

        {

            e.CanExecute = CanExecute(true);

        }

 

        #endregion        

        #region 다른 이름으로 저장 명령 실행시 처리하기 - SaveAsCommand_Executed(sender, e)

 

        /// <summary>

        /// 다른 이름으로 저장 명령 실행시 처리하기

        /// </summary>

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

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

        private void SaveAsCommand_Executed(object sender, ExecutedRoutedEventArgs e)

        {

            if(this.saveFileDialog.ShowDialog().Value)

            {

                string xaml = XamlWriter.Save(this.canvas);

 

                File.WriteAllText(this.saveFileDialog.FileName, xaml);

            }

        }

 

        #endregion

 

        #region 종료 메뉴 항목 클릭시 처리하기 - exitMenuItem_Click(sender, e)

 

        /// <summary>

        /// 종료 메뉴 항목 클릭시 처리하기

        /// </summary>

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

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

        private void exitMenuItem_Click(object sender, RoutedEventArgs e)

        {

            Close();

        }

 

        #endregion

        #region 편집 라디오 버튼 클릭시 처리하기 - editRadioButton_Click(sender, e)

 

        /// <summary>

        /// 편집 라디오 버튼 클릭시 처리하기

        /// </summary>

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

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

        private void editRadioButton_Click(object sender, RoutedEventArgs e)

        {

            FinishPolygon();

        }

 

        #endregion

        #region 캔버스 마우스 DOWN 처리하기 - canvas_MouseDown(sender, e)

 

        /// <summary>

        /// 캔버스 마우스 DOWN 처리하기

        /// </summary>

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

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

        private void canvas_MouseDown(object sender, MouseButtonEventArgs e)

        {

            if(this.drawRadioButton.IsChecked.Value)

            {

                #region 그리기시

 

                if(e.RightButton == MouseButtonState.Pressed)

                {

                    FinishPolygon();

 

                    return;

                }

 

                Point mousePoint = e.GetPosition(this.canvas);

 

                if(this.newPolyline == null)

                {

                    this.newPolyline = new Polyline();

 

                    this.newPolyline.Stroke          = Brushes.Red;

                    this.newPolyline.StrokeThickness = 1;

                    this.newPolyline.StrokeDashArray = new DoubleCollection();

 

                    this.newPolyline.StrokeDashArray.Add(5);

                    this.newPolyline.StrokeDashArray.Add(5);

 

                    this.newPolyline.Points.Add(mousePoint);

 

                    this.canvas.Children.Add(this.newPolyline);

                }

 

                this.newPolyline.Points.Add(mousePoint);

 

                #endregion

            }

            else

            {

                #region 편집시

 

                if(this.editPolygon == null)

                {

                    return;

                }

 

                this.editLastPoint = e.GetPosition(canvas);

 

                this.isEditing = true;

 

                this.canvas.CaptureMouse();

 

                #endregion

            }

        }

 

        #endregion

        #region 캔버스 마우스 이동시 처리하기 - canvas_MouseMove(sender, e)

 

        /// <summary>

        /// 캔버스 마우스 이동시 처리하기

        /// </summary>

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

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

        private void canvas_MouseMove(object sender, MouseEventArgs e)

        {

            Point mousePoint = e.GetPosition(this.canvas);

 

            if(this.drawRadioButton.IsChecked.Value)

            {

                if(this.newPolyline == null)

                {

                    return;

                }

 

                this.newPolyline.Points[this.newPolyline.Points.Count - 1] = mousePoint;

            }

            else

            {

                if(this.isEditing)

                {

                    if(this.editPolygonHitType == PolygonHitType.Vertex)

                    {

                        MoveVertex(e);

                    }

                    else if(this.editPolygonHitType == PolygonHitType.Edge)

                    {

                        MovePolygon(e);

                    }

                }

                else

                {

                    Cursor newCursor = null;

 

                    SetEditPolygon(mousePoint);

 

                    if(this.editPolygonHitType == PolygonHitType.Vertex)

                    {

                        newCursor = Cursors.Cross;

                    }

                    else if(this.editPolygonHitType == PolygonHitType.Edge)

                    {

                        newCursor = Cursors.SizeAll;

                    }

 

                    if(this.canvas.Cursor != newCursor)

                    {

                        this.canvas.Cursor = newCursor;

                    }

                }

            }

        }

 

        #endregion

        #region 캔버스 마우스 UP 처리하기 - canvas_MouseUp(sender, e)

 

        /// <summary>

        /// 캔버스 마우스 UP 처리하기

        /// </summary>

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

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

        private void canvas_MouseUp(object sender, MouseButtonEventArgs e)

        {

            this.isEditing = false;

 

            this.canvas.ReleaseMouseCapture();

        }

 

        #endregion

 

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

 

        #region 실행 가능 여부 구하기 - CanExecute(requirePolygon)

 

        /// <summary>

        /// 실행 가능 여부 구하기

        /// </summary>

        /// <param name="requirePolygon">다각형 필요 여부</param>

        /// <returns>실행 가능 여부 구하기</returns>

        private bool CanExecute(bool requirePolygon)

        {

            if(this.newPolyline != null)

            {

                return false;

            }

 

            if(this.editPolygon != null)

            {

                return false;

            }

 

            if(requirePolygon)

            {

                return this.canvas.Children.Count > 0;

            }

 

            return true;

        }

 

        #endregion

        #region 다각형 끝내기 - FinishPolygon()

 

        /// <summary>

        /// 다각형 끝내기

        /// </summary>

        private void FinishPolygon()

        {

            if(this.newPolyline == null)

            {

                return;

            }

 

            if(this.newPolyline.Points.Count > 3)

            {

                this.newPolyline.Points.RemoveAt(this.newPolyline.Points.Count - 1);

 

                Polygon newPolygon = new Polygon();

 

                newPolygon.Stroke          = Brushes.Blue;

                newPolygon.StrokeThickness = 2;

                newPolygon.Points          = this.newPolyline.Points;

 

                this.canvas.Children.Add(newPolygon);

            }

 

            this.canvas.Children.Remove(this.newPolyline);

 

            this.newPolyline = null;

        }

 

        #endregion

        #region 꼭지점 이동하기 - MoveVertex(e)

 

        /// <summary>

        /// 꼭지점 이동하기

        /// </summary>

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

        private void MoveVertex(MouseEventArgs e)

        {

            Point mousePoint = e.GetPosition(this.canvas);

 

            double deltaX = mousePoint.X - this.editLastPoint.X;

            double deltaY = mousePoint.Y - this.editLastPoint.Y;

 

            Point newPoint = new Point

            (

                this.editPolygon.Points[this.editPolygonPartIndex].X + deltaX,

                this.editPolygon.Points[this.editPolygonPartIndex].Y + deltaY

            );

 

            this.editPolygon.Points[this.editPolygonPartIndex] = newPoint;

 

            this.editLastPoint = mousePoint;

        }

 

        #endregion

        #region 다각형 이동하기 - MovePolygon(e)

 

        /// <summary>

        /// 다각형 이동하기

        /// </summary>

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

        private void MovePolygon(MouseEventArgs e)

        {

            Point mousePoint = e.GetPosition(this.canvas);

 

            double deltaX = mousePoint.X - this.editLastPoint.X;

            double deltaY = mousePoint.Y - this.editLastPoint.Y;

 

            int pointCount = this.editPolygon.Points.Count;

 

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

            {

                Point newPoint = new Point

                (

                    this.editPolygon.Points[i].X + deltaX,

                    this.editPolygon.Points[i].Y + deltaY

                );

 

                this.editPolygon.Points[i] = newPoint;

            }

 

            this.editLastPoint = mousePoint;

        }

 

        #endregion

        #region 편집 다각형 설정하기 - SetEditPolygon(point)

 

        /// <summary>

        /// 편집 다각형 설정하기

        /// </summary>

        /// <param name="point">포인트</param>

        private void SetEditPolygon(Point point)

        {

            this.editPolygon          = null;

            this.editPolygonHitType   = PolygonHitType.None;

            this.editPolygonPartIndex = -1;

 

            foreach(UIElement element in this.canvas.Children)

            {

                Polygon polygon = element as Polygon;

 

                if(polygon == null)

                {

                    continue;

                }

 

                if(polygon.IsAt(point, out this.editPolygonHitType, out this.editPolygonPartIndex))

                {

                    this.editPolygon = polygon;

 

                    return;

                }

            }

        }

 

        #endregion

    }

}

 

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

Posted by 사용자 icodebroker

댓글을 달아 주세요