Raster Vector Data Analysis ~ Hiking Path Finder

Purpose of this tutorial: Finding an elevation distance profile for any hiking path on any DEM.

This tutorial has 5 important steps.

Step 1: Download the DotSpatial class library

Step 2: Add the DotSpatial reference and change the compile option.

Step 3: Add the DotSpatial Controls into the Visual Studio Toolbox.

Step 4: Copy the Data Extensions folder to the debugs folder of the current project

Step 5: Design the GUI. (GUI – Graphical User Interface)

Step 6: Write the code for implementing the map operations.

Step 1: Download the DotSpatial class library

This step is similar to the Tutorial #1 step 1.

Step 2: Add the DotSpatial reference and change the compile option.

1.1) Adding the references.

DotSpatial.Data.Forms.dll, DotSpatial.Symbology.dll, DotSpatial.Controls.dll, DotSpatial.Projections.dll, DotSpatial.Data.dll, DotSpatial.Topology.dll

Fig. 1 Required references.

2.2) Change the compile option.

Change the compile option from .Net Framework 4 Client Profile to .Net Framework4. This step is as same as the Tutorial # 1 step 2.2.

READ ALSO
Visual Basic Creating a simple Calculator to get familiar with the interface and code

Step 2: Add the DotSpatial controls on the Visual Studio Toolbox window.

Create a new tab on the toolbox and add the DotSpatial controls on it, the same as tutorial (1) step 1.

Step 3: Add the DotSpatial Controls into the Visual Studio Toolbox.

This step is as same as the Tutorial # 1 step 3.

Step 4: Copy the Data Extension folder from your downloaded folder to your current project debug folder. The .dlls from this folder is necessary for GDAL data provider access.

Fig. 2 Data Extensions folder from DotSpatial downloaded unzip folder

Step 5: Design the GUI : GUI has 2 different parts such as Main interface form and Graph interface form.

5.1 ) Design the main interface form.

Fig. 2 Final GUI. (frmMain form)

Interface design considerations.

1. Add three panel controls. Panel control’s properties should be as follows:

Properties Panel1 Panel2 Panel3
Name pnlOperations pnlLegend pnlMap
Dock Top Left Fill
READ ALSO
Comments C Language

Optional step : Panel 1 background color : ActiveCaption

2. Add three buttons. Button properties should be as follows:

Properties Button1 Button2 Button3
Name btnLoadDEM btnDrawPath btnViewElevation
Text &Load DEM &Draw Hiking Path &View Elevation

3. Add a label control and set its property as follows:

Name : lbltile Text: Hiking Path Finder.

4. Drag a “Legend” control from the DotSpatial tab under toolbox and drop it on pnlLegend. Legend properties should be as follows:

Name: Legend1 Dock: Fill

5. Drag a “Map” control from the DotSpatial tab under toolbox and drop it on pnlMap. Map properties should be as follows:

Name: Map1, Dock: Fill, Legend: Legend1 , Back color: Silver , ProjectionModeDefine: Never ProjectionModeReproject: Never

6. Drag an “AppManager” control from DotSpatial tab under toolbox and drop it on the form.

Note: This control is necessary for loading different formats of raster data.

Fig. 3 AppManager.

7. Set the properties of AppManager1 as follows:

Map: Map1 Legend: Legend1

READ ALSO
Ansible Interview Questions 1

9. Rename the form1 as frmTutorial6.

5.2 ) Design the graph interface form.

1. Download the ZedGraph.dll from the class form website or from the following URL: http://sourceforge.net/projects/zedgraph/files/

2. from the tool box, right click on the DotSpatial tab OR all windows forms tab and select the choose items from the context menu.

Fig. 6 Choose Item context menu.

Select the ZedGraph.dll from the downloaded folder.

3. Design the interface as follows:

4. Add a second form and name it as frmGraph.

Fig. 7 frmGraph form.

5. Add a panel control and set its properties as follows:

name : pnlGraph Dock= fill

6. Drag the ZedGraph control from the toolbox and drop into the pnlGraph control. Set its properties as follows:

Dock : fill

Step 6: Code implementation

6.1) Following code is related to frmMain form.

Import the following namespaces

VB

#Region “NameSpaces”

Imports DotSpatial.Controls

Imports DotSpatial.Data

Imports DotSpatial.Symbology

Imports DotSpatial.Topology

Imports System.Collections.Generic

#End Region

READ ALSO
How to set DISPLAY variable in Linux

C#

#region “NameSpaces”

using DotSpatial.Controls;

using DotSpatial.Data;

using DotSpatial.Symbology;

using DotSpatial.Topology;

#endregion

Declare the following class level variables.

VB

#Region “Class level varibales”

‘the line layer

Dim lineLayer As MapLineLayer

‘the line feature set

Dim lineF As New FeatureSet(FeatureType.Line)

Dim lineID As Integer = 0

‘boolean variable for first time mouse click

Dim firstClick As Boolean = False

‘boolean variable for ski path drawing finished

Dim hikingpathPathFinished As Boolean = False

#End Region

C#

#region “Class level varibales”

//the line layer

MapLineLayer lineLayer = default(MapLineLayer);

//the line feature set

FeatureSet lineF = new FeatureSet(FeatureType.Line);

int lineID = 0;

//boolean variable for first time mouse click

bool firstClick = false;

//boolean variable for ski path drawing finished

bool hikingpathPathFinished = false;

#endregion

Create a PathPoint class as follows below the frmTutorial6 class.

VB

Public Class PathPoint

Public X As Double

Public Y As Double

Public Distance As Double

Public Elevation As Double

End Class

C#

public class PathPoint

{

public double X;

READ ALSO
alexa-skills-kit

public double Y;

public double Distance;

public double Elevation;

}

Crate an ExtractElevation function as follows: This function is used to get the elevation from the DEM along with the line segment.

VB

”’ <summary>

”’ This function is used to get the elevation.

”’ Based on the given line segment’s start and endpoint, 100 points will be divided and based on the points elevation will be claculated.

”’ </summary>

”’ <param name=”startX”>Line segement’s start X point</param>

”’ <param name=”startY”>Line segement’s start Y point</param>

”’ <param name=”endX”>Line segement’s end X point</param>

”’ <param name=”endY”>Line segement’s end Y point</param>

”’ <param name=”raster”>Raster DEM</param>

”’ <returns>List of elevation</returns>

”’ <remarks></remarks>

Public Function ExtractElevation(ByVal startX As Double, ByVal startY As Double, ByVal endX As Double, ByVal endY As Double, ByVal raster As IMapRasterLayer) As List(Of PathPoint)

Dim curX As Double = startX

Dim curY As Double = startY

Dim curElevation As Double = 0

Dim pathPointList As New List(Of PathPoint)

READ ALSO
AWS Interview Questions 8

Dim numberofpoints As Integer = 100

Dim constXdif = ((endX – startX) / numberofpoints)

Dim constYdif = ((endY – startY) / numberofpoints)

For i As Integer = 0 To numberofpoints

Dim newPathPoint As New PathPoint

If (i = 0) Then

curX = startX

curY = startY

Else

curX = curX + constXdif

curY = curY + constYdif

End If

Dim coordinate As New Coordinate(curX, curY)

Dim rowColumn As RcIndex = raster.DataSet.Bounds.ProjToCell(coordinate)

curElevation = raster.DataSet.Value(rowColumn.Row, rowColumn.Column)

‘set the properties of new PathPoint

newPathPoint.X = curX

newPathPoint.Y = curY

newPathPoint.Elevation = curElevation

pathPointList.Add(newPathPoint)

Next

Return pathPointList

End Function

C#

/// <summary>

/// This function is used to get the elevation.

/// Based on the given line segment’s start and endpoint, 100 points will be divided and based on the points elevation will be claculated.

/// </summary>

/// <param name=”startX”>Line segement’s start X point</param>

/// <param name=”startY”>Line segement’s start Y point</param>

/// <param name=”endX”>Line segement’s end X point</param>

/// <param name=”endY”>Line segement’s end Y point</param>

/// <param name=”raster”>Raster DEM</param>

/// <returns>List of elevation</returns>

/// <remarks></remarks>

READ ALSO
Getting started with C++

public List<PathPoint> ExtractElevation(double startX, double startY, double endX, double endY, IMapRasterLayer raster)

{

double curX = startX;

double curY = startY;

double curElevation = 0;

List<PathPoint> pathPointList = new List<PathPoint>();

int numberofpoints = 100;

double constXdif = ((endX – startX) / numberofpoints);

double constYdif = ((endY – startY) / numberofpoints);

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

{

PathPoint newPathPoint = new PathPoint();

if ((i == 0))

{

curX = startX;

curY = startY;

}

else

{

curX = curX + constXdif;

curY = curY + constYdif;

}

Coordinate coordinate = new Coordinate(curX, curY);

RcIndex rowColumn = raster.DataSet.Bounds.ProjToCell(coordinate);

curElevation = raster.DataSet.Value[rowColumn.Row, rowColumn.Column];

//set the properties of new PathPoint

newPathPoint.X = curX;

newPathPoint.Y = curY;

newPathPoint.Elevation = curElevation;

pathPointList.Add(newPathPoint);

}

return pathPointList;

}

Add the following code in the Load DEM button click event.

VB

Private Sub btnLoadDEM_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadDEM.Click

Map1.AddRasterLayer()

Map1.ZoomToMaxExtent()

End Sub

C#

private void btnLoadDEM_Click(object sender, EventArgs e)

{

map1.AddRasterLayer();

map1.ZoomToMaxExtent();

}

Add the following code in the Drawing hiking path button click event.

VB

Private Sub btnDrawPath_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDrawPath.Click

READ ALSO
How to check query plan change in oracle

‘remove any existing path

Dim existingPathList = Map1.GetLineLayers()

For Each existingPath As IMapLineLayer In existingPathList

Map1.Layers.Remove(existingPath)

Next

lineF = New FeatureSet(FeatureType.Line)

‘ski path is not finished

hikingpathPathFinished = False

‘initialize polyline feature set

Map1.Cursor = Cursors.Cross

‘set projection

lineF.Projection = Map1.Projection

‘initialize the featureSet attribute table

Dim column As New DataColumn(“ID”)

lineF.DataTable.Columns.Add(column)

‘add the featureSet as map layer

lineLayer = Map1.Layers.Add(lineF)

Dim symbol As New LineSymbolizer(Color.Blue, 2)

lineLayer.Symbolizer = symbol

lineLayer.LegendText = “Hiking path”

firstClick = True

End Sub

C#

private void btnDrawPath_Click(System.Object sender, System.EventArgs e)

{

//remove any existing path

foreach (IMapLineLayer existingPath in map1.GetLineLayers())

{

map1.Layers.Remove(existingPath);

}

lineF = new FeatureSet(FeatureType.Line);

//ski path is not finished

hikingpathPathFinished = false;

//initialize polyline feature set

map1.Cursor = Cursors.Cross;

//set projection

lineF.Projection = map1.Projection;

//initialize the featureSet attribute table

DataColumn column = new DataColumn(“ID”);

lineF.DataTable.Columns.Add(column);

//add the featureSet as map layer

lineLayer = (MapLineLayer)map1.Layers.Add(lineF);

LineSymbolizer symbol = new LineSymbolizer(Color.Blue, 2);

lineLayer.Symbolizer = symbol;

lineLayer.LegendText = “Hiking path”;

firstClick = true;

}

Add the following code in the Map1_MouseDown event.

READ ALSO
Ansible Interview Questions and Answers 1

VB

Private Sub Map1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Map1.MouseDown

‘if ski path is fininshed, don’t draw any line

If hikingpathPathFinished = True Then Exit Sub

If e.Button = MouseButtons.Left Then

‘left click – fill array of coordinates

‘coordinate of clicked point

Dim coord As Coordinate = Map1.PixelToProj(e.Location)

‘first time left click – create empty line feature

If firstClick Then

‘Create a new List called lineArray.

‘In List we need not define the size and also

‘Here this list will store the Coordinates

‘We are going to store the mouse click coordinates into this array.

Dim lineArray As New List(Of Coordinate)

‘Create an instance for LineString class.

‘We need to pass collection of list coordinates

Dim lineGeometry As New LineString(lineArray)

‘Add the linegeometry to line feature

Dim lineFeature As IFeature = lineF.AddFeature(lineGeometry)

‘add first coordinate to the line feature

lineFeature.Coordinates.Add(coord)

‘set the line feature attribute

lineID = lineID + 1

lineFeature.DataRow(“ID”) = lineID

firstClick = False

READ ALSO
Counting Words in File(s) using Elastic MapReduce (AWS)

Else

‘second or more clicks – add points to the existing feature

Dim existingFeature As IFeature = lineF.Features(lineF.Features.Count – 1)

existingFeature.Coordinates.Add(coord)

‘refresh the map if line has 2 or more points

If existingFeature.Coordinates.Count >= 2 Then

lineF.InitializeVertices()

Map1.ResetBuffer()

End If

End If

Else

‘right click – reset first mouse click

firstClick = True

Map1.ResetBuffer()

lineF.SaveAs(“c:\2009 Falls\linepath.shp”, True)

MsgBox(“The line shapefile has been saved.”)

Map1.Cursor = Cursors.Arrow

‘the ski path is finished

hikingpathPathFinished = True

End If

End Sub

C#

private void map1_MouseDown(object sender, MouseEventArgs e)

{

//if ski path is fininshed, don’t draw any line

if (hikingpathPathFinished == true)

return;

if (e.Button == MouseButtons.Left)

{

//left click – fill array of coordinates

//coordinate of clicked point

Coordinate coord = map1.PixelToProj(e.Location);

//first time left click – create empty line feature

if (firstClick)

{

//Create a new List called lineArray.

//In List we need not define the size and also

//Here this list will store the Coordinates

//We are going to store the mouse click coordinates into this array.

READ ALSO
How to check execution plan of a query

List<Coordinate> lineArray = new List<Coordinate>();

//Create an instance for LineString class.

//We need to pass collection of list coordinates

LineString lineGeometry = new LineString(lineArray);

//Add the linegeometry to line feature

IFeature lineFeature = lineF.AddFeature(lineGeometry);

//add first coordinate to the line feature

lineFeature.Coordinates.Add(coord);

//set the line feature attribute

lineID = lineID + 1;

lineFeature.DataRow[“ID”] = lineID;

firstClick = false;

}

else

{

//second or more clicks – add points to the existing feature

IFeature existingFeature = lineF.Features[lineF.Features.Count – 1];

existingFeature.Coordinates.Add(coord);

//refresh the map if line has 2 or more points

if (existingFeature.Coordinates.Count >= 2)

{

lineF.InitializeVertices();

map1.ResetBuffer();

}

}

}

else

{

//right click – reset first mouse click

firstClick = true;

map1.ResetBuffer();

lineF.SaveAs(“c:\\2009 Falls\\linepath.shp”, true);

MessageBox.Show(“The line shapefile has been saved.”);

map1.Cursor = Cursors.Arrow;

//the ski path is finished

hikingpathPathFinished = true;

}

}

Add the following code in the frmGraph.vb form.

VB

Public Class frmGraph

Public Sub New(ByVal pathList As List(Of PathPoint))

InitializeComponent()

‘populate the graph

‘create the distance and elevation arrays..

READ ALSO
AWS Interview Questions 7

Dim distanceArray(pathList.Count – 1) As Double

Dim elevationArray(pathList.Count – 1) As Double

For i As Integer = 0 To pathList.Count – 1

distanceArray(i) = pathList(i).Distance

elevationArray(i) = pathList(i).Elevation

Next

 

ZedGraphControl1.GraphPane.CurveList.Clear()

Dim myCurve As ZedGraph.LineItem = ZedGraphControl1.GraphPane.AddCurve(“Elevation Profile”, distanceArray, elevationArray, Color.Blue)

myCurve.Line.Width = 2.0F

myCurve.Symbol.Type = ZedGraph.SymbolType.None

myCurve.Line.Fill.Color = Color.LightBlue

myCurve.Line.Fill.Color = Color.FromArgb(100, 0, 0, 255)

myCurve.Line.Fill.IsVisible = True

ZedGraphControl1.GraphPane.XAxis.Title.Text = “Distance (meters)”

ZedGraphControl1.GraphPane.YAxis.Title.Text = “Elevation (meters)”

‘refresh the graph

ZedGraphControl1.AxisChange()

‘set the graph title

ZedGraphControl1.GraphPane.Title.Text = “Hiking Path Graph”

End Sub

End Class

C#

public frmGraph(List<PathPoint> pathList)

{

InitializeComponent();

//populate the graph

//create the distance and elevation arrays..

double[] distanceArray = new double[pathList.Count];

double[] elevationArray = new double[pathList.Count];

for (int i = 0; i <= pathList.Count – 1; i++)

{

distanceArray[i] = pathList[i].Distance;

elevationArray[i] = pathList[i].Elevation;

}

zedGraphControl1.GraphPane.CurveList.Clear();

ZedGraph.LineItem myCurve = zedGraphControl1.GraphPane.AddCurve(“Elevation Profile”, distanceArray, elevationArray, Color.Blue);

myCurve.Line.Width = 2f;

myCurve.Symbol.Type = ZedGraph.SymbolType.None;

myCurve.Line.Fill.Color = Color.LightBlue;

myCurve.Line.Fill.Color = Color.FromArgb(100, 0, 0, 255);

myCurve.Line.Fill.IsVisible = true;

zedGraphControl1.GraphPane.XAxis.Title.Text = “Distance (meters)”;

zedGraphControl1.GraphPane.YAxis.Title.Text = “Elevation (meters)”;

//refresh the graph

zedGraphControl1.AxisChange();

//set the graph title

zedGraphControl1.GraphPane.Title.Text = “Hiking Path Graph”;

}

Add the following code in the frmMain.vb form’s btnViewElevation_Click event

READ ALSO
What Is Amazon Ec2 Service?

VB

Private Sub btnViewElevation_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnViewElevation.Click

Try

‘extract the complete elevation

‘get the raster layer

Dim rasterLayer As IMapRasterLayer

If Map1.GetRasterLayers().Count = 0 Then

MsgBox(“Please add a raster layer”)

Exit Sub

End If

‘use the first raster layer in the map

rasterLayer = Map1.GetRasterLayers(0)

‘get the ski path line layer

Dim pathLayer As IMapLineLayer

If Map1.GetLineLayers().Count = 0 Then

MsgBox(“Please add the ski path”)

Exit Sub

End If

pathLayer = Map1.GetLineLayers(0)

Dim featureSet As IFeatureSet = pathLayer.DataSet

‘get the coordinates of the ski path. this is the first feature of

‘the feature set.

Dim coordinateList = featureSet.Features(0).Coordinates

‘get elevation of all segments of the path

Dim fullPathList As New List(Of PathPoint)

For i As Integer = 1 To coordinateList.Count – 1

‘for each line segment

Dim startCoord = coordinateList(i – 1)

Dim endCoord = coordinateList(i)

Dim segmentPointList = ExtractElevation(startCoord.X, startCoord.Y, endCoord.X, endCoord.Y, rasterLayer)

‘add list of points from this line segment to the complete list

READ ALSO
How to analyze wait events in Oracle

fullPathList.AddRange(segmentPointList)

Next

‘calculate the distance

Dim distanceFromStart As Double = 0

For i As Integer = 1 To fullPathList.Count – 1

‘distance between two neighbouring points

Dim x1 = fullPathList(i – 1).X

Dim y1 = fullPathList(i – 1).Y

Dim x2 = fullPathList(i).X

Dim y2 = fullPathList(i).Y

Dim distance12 = Math.Sqrt(((x2 – x1) * (x2 – x1)) + ((y2 – y1) * (y2 – y1)))

distanceFromStart += distance12

fullPathList(i).Distance = distanceFromStart

Next

Dim graphForm As New frmGraph(fullPathList)

graphForm.Show()

Catch ex As Exception

MessageBox.Show(“Error calculating elevation. the whole path should be inside the DEM area”)

End Try

End Sub

C#

private void btnViewElevation_Click(System.Object sender, System.EventArgs e)

{

try

{

//extract the complete elevation

//get the raster layer

IMapRasterLayer rasterLayer = default(IMapRasterLayer);

if (map1.GetRasterLayers().Count() == 0)

{

MessageBox.Show(“Please add a raster layer”);

return;

}

//use the first raster layer in the map

rasterLayer = map1.GetRasterLayers()[0];

//get the ski path line layer

IMapLineLayer pathLayer = default(IMapLineLayer);

if (map1.GetLineLayers().Count() == 0)

{

MessageBox.Show(“Please add the ski path”);

return;

}

pathLayer = map1.GetLineLayers()[0];

IFeatureSet featureSet = pathLayer.DataSet;

READ ALSO
SSH Keys for Amazon EC2 instances

//get the coordinates of the ski path. this is the first feature of

//the feature set.

IList<Coordinate> coordinateList = featureSet.Features[0].Coordinates;

//get elevation of all segments of the path

List<PathPoint> fullPathList = new List<PathPoint>();

for (int i = 0; i < coordinateList.Count – 1; i++)

{

//for each line segment

Coordinate startCoord = coordinateList[i];

Coordinate endCoord = coordinateList[i + 1];

List<PathPoint> segmentPointList = ExtractElevation(startCoord.X, startCoord.Y, endCoord.X, endCoord.Y, rasterLayer);

//add list of points from this line segment to the complete list

fullPathList.AddRange(segmentPointList);

}

//calculate the distance

double distanceFromStart = 0;

for (int i = 1; i <= fullPathList.Count – 1; i++)

{

//distance between two neighbouring points

double x1 = fullPathList[i – 1].X;

double y1 = fullPathList[i – 1].Y;

double x2 = fullPathList[i].X;

double y2 = fullPathList[i].Y;

double distance12 = Math.Sqrt(((x2 – x1) * (x2 – x1)) + ((y2 – y1) * (y2 – y1)));

distanceFromStart += distance12;

fullPathList[i].Distance = distanceFromStart;

}

frmGraph graphForm = new frmGraph(fullPathList);

graphForm.Show();

}

catch (Exception ex)

{

MessageBox.Show(“Error calculating elevation. the whole path should be inside the DEM area”);

}

}

Output screen shots

Fig. 8 HikingMain form output screen.

Fig. 9 Elevation distance profile for the drawn path.

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.