WPF - XDL Tutorial

XDL MilmapView 활용 두번째

(piXoneer XDL Tutorial)

 

 

 

 

 

 NXMilmapView를 이용하여 군 지도 도시 환경에서

 다양한 측정방법을 구현해 보고, 사용자 정의 설정한 정점에 대한

  거리 및 각도 측정도 구현해 봅니다.

 

 

2019. 04.

 

 

목차

XDL MilmapView 활용 두번째... 1

1    사용하기... 1

1.1    XDL 엔진... 1

2    NXMilmapView 이용 예제 프로그램 만들기... 1

2.1    기본 프로그램 작성... 1

2.2    프로그램 디자인... 1

2.3    기능 이벤트 추가... 1

 

 

 

 

1     사용하기

 

1.1    XDL 엔진

설치 프로그램으로 배포되는 XDL 엔진은 Visual Studio 2010 x86 Release 버전으로, Visual Studio 2010 이상의 버전에서 사용 가능하다.

아래의 설명은 Visual Studio 2015을 기준으로 하겠다.

2     NXMilmapView를 이용한 예제 프로그램 만들기

l  본 예제 프로그램은 NXMilmapView의 기본 측정 모드를 설정하여 길이, 면적 등을 측정해 보고, 세 점을 이용한 거리 및 각도를 사용자 코드를 이용하여 도시하고 측정해 보도록 한다.

2.1    기본 프로그램 작성

2.1.1     Visual Studio 2015을 이용하여 예제 “XDL_MilmapView1”“Config 파일 설정하기기본 프로그램 작성방법을 참고로 기본 프로젝트를 생성한다.

프로젝트 이름은 “XDL_MilmapView2”로 한다.

2.2    프로그램 디자인

 

 

2.2.1     (1) 에 메뉴를 생성한다. MainWindow.xaml 창에서 기본으로 생성된 Grid 레이아웃에 Grid.RowDefinition을 이용하여 두 개의 Row을 생성한다. 첫 번째 Row에는 메뉴를 생성하는 작업을 할 것이다. 두 번째 Row에는 NXMilmapView 컨트롤을 배치할 것이다.

메뉴를 생성하기 위해서 이에 대한 Name도 설정한다. 예제의 메뉴 구성은 아래와 같다.

 

 

Control Type

Header

Name

MenuItem

Measurement

 

MenuItem

거리(단선) 측정

MeasureLineMenuItem

MenuItem

거리(폴리라인) 측정

MeasurePolyLineMenuItem

MenuItem

면적 측정

MeasureAreaMenuItem

MenuItem

각도 측정(진북방향)

MeasureAngleMenuItem

MenuItem

원형 측정

MeasureCircleMenuItem

 

 

Control Type

Header

Name

MenuItem

사용자 정의

 

MenuItem

거리 및 각도 측정

UserDefinedMeasureMenuItem

 

2.2.2     (2)에는 NXMilmapView 컨트롤를 추가하고 이름은 nxMilmapView1으로 한다.

2.2.3     이어서 NXMilmapView위에 NXMilmapLayer를 추가하고 이름은 nxMilmapLayer1 이라고 명명한다.

NXMilmapLayerMilmapView에 추가되어 XDL 엔진에서 발생하는 이벤트를 외부 어플리케이션에서 처리할 수 있다. 자세한 코드는 아래와 같다.

 

<Grid Grid.Row="1">
       <WindowsFormsHost>
             <nxMilmap:NXMilmapView x:Name="nxMilmapView1">
                   <nxMilmap:NXMilmapView.Controls>
                     <nxMilmap:NXMilmapLayer x:Name="nxMilmapLayer1">
                   </nxMilmap:NXMilmapView.Controls>
             </nxMilmap:NXMilmapView>
        </WindowsFormsHost>
</Grid>

 

2.3    기능 및 이벤트 추가

2.3.1     MainWindow를 선택하고 [속성] - [이벤트 ] 메뉴를 선택한 뒤 “Loaded” 이벤트를 더블 클릭한다.

Window_Loaded 함수와 함께 아래와 같이 코드를 추가한다.

 

using Pixoneer.NXDL;            // 기본 기능
using Pixoneer.NXDL.NGR;        // 그래픽 관련 기능
using Pixoneer.NXDL.NXMilmap;   // 군사 지도 도시 관련 기능
using Pixoneer.NXDL.NCC;        // 좌표 관련 기능

namespace XDL_MilmapView2
{
     public partial class MainWindow : Window  
     {
        public MainWindow()
        {
            InitializeComponent();
        }

         private void Window_Loaded(object sender, RoutedEventArgs e)
         {
            // XMilmapConfig.xml을 이용하여 군사지도를 위한 
// NXMilmapView 및 NXMilmapEngine을 초기화한다.
            if (!NXMilmapView.m_MapEngine.InitFromXML("c:\\Pixoneer\\Xdl1.2\\Config\\XMilmapConfig.xml"))
            {
                return;
            }

            nxMilmapView1.AddRenderLayer(ref nxMilmapLayer1);

            // 마우스 휠을 끌고 당기는 것을 확대/축소 요인으로 계산하여 화면을
// 확대/축소한다.
            // 이 때, 계산된 공간 해상도와 가까운 축척(scale)이 있는 경우 
// 자동적으로 해당 축척으로 바뀌면서 도시된다.
            // 마우스 휠을 끌고 당기는 것으로 화면의 축척을 변경하려면,
// NXMilmapView.eWheelZoomAction.ByScaleIndex으로 설정
            nxMilmapView1.WheelZoomAction = 
NXMilmapView.eWheelZoomAction.ByZoomFactor;
            nxMilmapView1.SetGeoToCenter(0, new XVertex2d(127.0, 36.0));

            // MilmapView의 측정 단위 설정
            // 거리 측정 단위
            nxMilmapView1.ToolboxDistUnit = 
NXMilmapView.eToolboxDistUnit.KiloMeter;
            // 면적 측정 단위
            nxMilmapView1.ToolboxAreaUnit = 
NXMilmapView.eToolboxAreaUnit.SquareKiloMeter;
         }
     }
}

측정 결과를 표시하는 데에 측정 단위를 설정하려면, 면적에 대해서는 NXMilmapView ToolboxAreaUnit 속성을 NXMilmapView.eToolboxAreaUnit 값으로 설정하면 되고, 거리에 대해서는 NXMilmapView ToolboxDistUnit 속성을 NXMilmapView.eToolboxDistUnit 값으로 설정한다.

Window_Loaded 함수에서는 면적 측정 단위는 ㎢로, 길이 측정 단위는 ㎞로 한다.

 

2.3.2     [Measurement/사용자 정의]-[거리 및 각도 측정] 메뉴를 선택한 후 더블 클릭한다.

메뉴에서 마우스로 더블 클릭하면 “Click”에 대한 이벤트 함수가 자동 추가된다.

private void UserDefinedMeasureMenuItem_Click(object sender, RoutedEventArgs e)
{
        userMeasure = !userMeasure;
        countPos = 0;
}

2.3.3     각 메뉴에 따른 MilmapViewToolboxMode를 설정한다.

NXMilmapView의 측정모드로는 2점을 이용한 거리 측정(NXMilmapView.eToolboxMode. DistanceMeasurer), 다중 점을 이용한 거리 측정(eToolboxMode.PathMeasurer), 다중 점을 이용한 면적 측정(eToolboxMode.AreaMeasurer), 점의 거리를 반지름으로 원형 측정(eToolboxMode.CircleMeasurer), 점으로 이루어진 벡터와 진북방향과의 각도 측정(eToolboxMode.AngleMeasurer) 있다.

코드는 아래와 같다.

 

private void MeasureLineMenuItem_Click(object sender, RoutedEventArgs e)
{
   nxMilmapView1.ToolboxMode = NXMilmapView.eToolboxMode.DistanceMeasurer;
}

private void MeasurePolyLineMenuItem_Click(object sender, RoutedEventArgs e)
{
   nxMilmapView1.ToolboxMode = NXMilmapView.eToolboxMode.PathMeasurer;
}

private void MeasureAreaMenuItem_Click(object sender, RoutedEventArgs e)
{
   nxMilmapView1.ToolboxMode = NXMilmapView.eToolboxMode.AreaMeasurer;
}

private void MeasureAngleMenuItem_Click(object sender, RoutedEventArgs e)
{
   nxMilmapView1.ToolboxMode = NXMilmapView.eToolboxMode.AngleMeasurer;
}
    
private void MeasureCircleMenuItem_Click(object sender, RoutedEventArgs e)
{
   nxMilmapView1.ToolboxMode = NXMilmapView.eToolboxMode.CircleMeasurer;
}

 

2.3.4     사용자 정의 측정을 위한 변수를 추가하고 UserDefinedMeasureToolStripMenuItem 이벤트 함수에서 초기화한다.

사용자 정의 측정 여부를 설정하는 “bool userMeasure”와 각도 측정을 위한 세 변수 “XVertex2d posMeasure0, posMeasure1, posMeasure2”를 생성하고 초기화한다.

 

public partial class MainWindow : Window
{
    bool userMeasure = false;
    int countPos = 0;
    XVertex2d posAngle0, posAngle1, posAngle2;    // index 0 : start, index 1 : center, index 2 : end

public MainWindow()
    {
        InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)    
{
        // XMilmapConfig.xml을 이용하여 군사지도를 위한 
// NXMilmapView 및 NXMilmapEngine을 초기화한다.
        if (!NXMilmapView.m_MapEngine.InitFromXML("c:\\Pixoneer\\Xdl1.2\\Config\\XMilmapConfig.xml"))
        {
            return;
        }

        nxMilmapView1.AddRenderLayer(ref nxMilmapLayer1);

        // 마우스 휠을 끌고 당기는 것을 확대/축소 요인으로 계산하여 
// 화면을 확대/축소한다.
        // 이 때, 계산된 공간 해상도와 가까운 축척(scale)이 있는 경우 
// 자동적으로 해당 축척으로 바뀌면서 도시된다.
        // 마우스 휠을 끌고 당기는 것으로 화면의 축척을 변경하려면, 
// NXMilmapView.eWheelZoomAction.ByScaleIndex으로 설정
        nxMilmapView1.WheelZoomAction = NXMilmapView.eWheelZoomAction.ByZoomFactor;
        nxMilmapView1.SetGeoToCenter(0, new XVertex2d(127.0, 36.0));

        // MilmapView의 측정 단위 설정
        // 거리 측정 단위
        nxMilmapView1.ToolboxDistUnit = NXMilmapView.eToolboxDistUnit.KiloMeter;
        // 면적 측정 단위
        nxMilmapView1.ToolboxAreaUnit = NXMilmapView.eToolboxAreaUnit.SquareKiloMeter;

        // 사용자 정의 측정을 위한 변수 초기화
        userMeasure = false;
        countPos = 0;
}

private void UserDefinedMeasureMenuItem_Click(object sender, RoutedEventArgs e)
{
        userMeasure = !userMeasure;
        countPos = 0;
}

}

2.3.5     각도 및 거리를 측정하는 함수를 이용하기 위해서 “NXDLcc.dll”을 참조에 추가한다.

WGS84체를 반영한 거리를 측정하는 함수는 Xcc.CalcGeodeticDistance이며, 각도를 측정하는 함수는 Xcc.CalcGeodeticAngle이다. 이를 위해 NXDLcc.dll을 참조에 추가하고, “using Pixoneer.NXDL.NCC;” 구문 또한 추가한다.

2.3.6     nxMilmapLayer1을 선택하여 “OnWndProc” 이벤트와 “OnRender” 이벤트 함수를 추가하여 코드를 작성한다.

OnWndProc 이벤트는 NXMilmapLayer가 추가되어 있는 View의 윈도우 이벤트를 외부에서 받아서 사용할 수 있도록 한다. OnRenderNXMilmapLayer가 추가되어 있는 ViewRendering이 완료된 후 어플리케이션에서 추가적인 작업을 구현해야 할 필요가 있을 때 사용하면 된다.

왼쪽 버튼이 클릭할 때마다 각도 측정을 위한 점을 차례대로 설정하고 3점이 모두 설정되면 계산결과를 Visual Studio 2015 출력창에 출력하도록 한다. 또한 2점 이상인 경우 화면에 붉은 선으로 도시한다. 코드는 아래와 같다.


private bool nxMilmapLayer1_OnWndProc(object sender, NXMilmapDrawArgs e, ref System.Windows.Forms.Message m)
{
     if (m.Msg == Pixoneer.NXDL.XWndMsg.XWM_LBUTTONDOWN)
     {
       if (userMeasure)
       {
         double x = Pixoneer.NXDL.XWndMsg.GetLowValue(m.LParam);
         double y = Pixoneer.NXDL.XWndMsg.GetHighValue(m.LParam);

         NXMilmapDrawArgs drawArgs = nxMilmapView1.GetDrawArgs();
         XVertex2d gpPos = drawArgs.ScreenToGeographic(new XVertex2d(x, y));
         if (countPos == 0)
         {
             posAngle0 = gpPos;
         }
         else if (countPos == 1)
         {
             posAngle1 = gpPos;
         }
         else if (countPos == 2)
         {
            posAngle2 = gpPos;

            // 두 선분의 길이와 3 점으로 이루어지는 각도 계산
            double distance = 0.0;
            distance += 
Xcc.CalcGeodeticDistance(XAngle.FromDegree(posAngle0.x),XAngle.FromDegree(posAngle0.y),XAngle.FromDegree(posAngle1.x),XAngle.FromDegree(posAngle1.y));
            distance += Xcc.CalcGeodeticDistance(XAngle.FromDegree(posAngle1.x),XAngle.FromDegree(posAngle1.y),XAngle.FromDegree(posAngle2.x),XAngle.FromDegree(posAngle2.y));
             double angle = 0.0;
             angle = Xcc.CalcGeodeticAngle(XAngle.FromDegree(posAngle1.x), XAngle.FromDegree(posAngle1.y),XAngle.FromDegree(posAngle0.x), XAngle.FromDegree(posAngle0.y),XAngle.FromDegree(posAngle2.x), XAngle.FromDegree(posAngle2.y));

             System.Diagnostics.Debug.WriteLine("Distance : " + distance.ToString());
             System.Diagnostics.Debug.WriteLine("Angle    : " + angle.ToString());
        }

           countPos++;

          nxMilmapView1.RefreshScreen();
       }
     }

       return default(bool);
}


private bool nxMilmapLayer1_OnRender(object sender, NXMilmapDrawArgs e)
{
     if (!userMeasure) return false;

       if (countPos > 1)
       {
            e.Graphics.glDisable(XGraphics.GL_DEPTH_TEST);
            e.Graphics.glEnable(XGraphics.GL_BLEND);
            e.Graphics.glBlendFunc(XGraphics.GL_SRC_ALPHA, XGraphics.GL_ONE_MINUS_SRC_ALPHA);

            e.Graphics.glPushMatrix();

            e.Graphics.glColor3f(1.0f, 0.0f, 0.0f);
            e.Graphics.glLineWidth(3);
            e.Graphics.glBegin(XGraphics.GL_LINE_STRIP);

            NXMilmapDrawArgs drawArgs = nxMilmapView1.GetDrawArgs();
            XVertex3d posWorld = drawArgs.GeographicToWorld(posAngle0);
            e.Graphics.glVertex3d(posWorld);

            posWorld = drawArgs.GeographicToWorld(posAngle1);
            e.Graphics.glVertex3d(posWorld);

         if (countPos >= 3)
         {
            posWorld = drawArgs.GeographicToWorld(posAngle2);
            e.Graphics.glVertex3d(posWorld);
         }

            e.Graphics.glEnd();
            e.Graphics.glColor3f(1.0f, 1.0f, 1.0f);
            e.Graphics.glPopMatrix();
            e.Graphics.glEnable(XGraphics.GL_DEPTH_TEST);
       }

          return default(bool);
}

 

2.3.7     솔루션을 빌드하고 실행한다.

Measurement거리(폴리라인) 측정메뉴를 선택한 뒤 nxMilmapView1 위에서 마우스 왼쪽 버튼을 클릭하면서 측정하고자 하는 정점을 설정한다. 아래 그림과 같이 측정 결과가 각 선분 요소에 도시된다.

 

 

사용자 정의 메뉴의 거리 및 각도 측정을 선택한 뒤 nxMilmapView1 위에서 마우스 왼쪽 버튼을 클릭하면 2점 이상부터 화면에 붉은 실선이 도시되고, 3점이 선택되면 Visual Studio 2015의 출력창에 측정결과가 나타난다.

 

 

 

Xcc.CalcGeodeticAngle 측정결과의 단위는 거리의 경우 meter, 각도의 경우 ˚(degree)이다.