Introduction
In the previous lessons, we had learned how to display and manage vector data using MapWInGIS.ocx and embed these functions in a Windows application developed using C#. In this lesson, I am going to teach you how to manage raster data in the same manner. The objectives of the reader are to understand how to add the raster layer to the map control, how to manipulate the raster symbology, how to get the raster information, and how to join the cursor to the location on raster. As usual, my tools pack includes MapWinGIS.ocx, which is an ActiveX control that can be used in any language that supports ActiveX (e.g., C#, VB, Microsoft Access, Microsoft PowerPoint, … ). MapWinGIS.ocx is Open Source, and you can download it free of charge under the MPL license. All code examples and screenshots in this article are based on the Microsoft Visual C# 2008 Professional Edition, but the reader can use Microsoft Visual C# Express Edition to get the same results.
Raster Data in GIS
Raster data is a very common and useful data model in GIS. Any raster may be introduced as an array of columns and rows. A row intersects a column to create a rectangular area called raster cell. In the most common raster forms, the width of the column equals the height of the row, so the raster cell shape is square. The raster cell often represents a squared area on the study area. Each cell has two identifiers (X, Y) that demonstrate the coordinates of the cell location. The first identifier/coordinate, X, denotes the column that passes across the cell. The second identifier/coordinate, Y, denotes the row that passes across the cell. In general purpose raster formats like Joint Photographic Experts Group (JPEG) and Graphical Interchange File Format (GIFF), X, Y express directly the number of columns and rows that pass across the cell, but in GIS raster data format, these coordinates are connected to the world coordinate system to describe the geographic location of the cell in real life.
Raster cells are usually illustrated using a digital value which may be discrete (integer-like data types) or continuous (real-like data types). These digital values are used to represent geographic features. For example, digital values may be 1 to describe the existence of a feature, and 0 to describe the absence of a feature. The following figure shows how to illustrate a geographical feature using these previous two values (1 and 0), where the blue squares express the cells marked with one, and white squares express the cells marked with zero.
The discrete digital values in GIS raster data are used to model discrete phenomenon like land use and administrative units, where continuous digital values are often used to represent continuous phenomenon like terrain elevation and soil acidity. GIS professionals know many ways to get raster data. They can produce it directly using different tools like automatic scanning and vector data rasterization. They can get raster data as aerial photographs and remotely sensed data.
Sample Application
The sample application in this lesson demonstrates many features of GIS raster data manipulation using MapWinGIS.ocx. In the following sections, I will discuss these features in detail, and I will ignore the features that were discussed in the early lessons.
Ready, Steady, Gooooooo
In the beginning, you have to start a new Windows application. Give your project a name. I named mine "GISSampleApplication3". In the Solution Explorer window, select the project node, right click on it, and select Add Reference from the context menu. Use the COM tab in the Add Reference window that will appear, find MapWinGIS.ocx in the list, and add it. Now, you have all the functionalities of MapWinGIS.ocx in your project, but you still need to add the visualization functionality provided by the MapWinGIS.ocx Map control. To add this control to your toolbox, select the General tab in the toolbox, right click on it, select Choose Items from the context menu, select the COM component tab from the Choose Toolbox Items window, find the Map control, check it, and press OK. Now, the Map control tool will be shown in your toolbox. The above steps are described in detail with illustration in lesson 1.
Give me Something to See
The sample application of the current lesson is a simple, single-form application. This form has a ToolStrip
named toolStrip1
which has five buttons: toolCursor
, toolZoomExtent
, toolZoomIn
, toolZoomOut
, and toolPan
. The code for these buttons is discussed in lesson 1. The form also has a status bar named StatusStrip1docked
at the bottom. The status bar contains a ToolStripStatusLabel
called ToolStripStatusLabel1
. The form has a SplitContainer
named splitContainer1
which is split vertically into two panels: splitContainer1.panel1
to the left and splitContainer1.panel2
to the right. The left panel includes a single button named tbnInfo
. The right panel includes the MapWinGIS.ocx Map Control component named axMap1
which is docked to fill the right panel completely.
Let's Write Some Code
Now it's time for some real work. We will now discuss the required code to achieve our lesson's objectives and its meaning. After the beginning brace of the declaration of the Form1
class, add the following code:
#region PublicDeclaration
public int intHandler;
public MapWinGIS.Grid myGrid = new MapWinGIS.Grid();
public MapWinGIS.GridHeader myHeader = new MapWinGIS.GridHeader();
public MapWinGIS.Image myImage = new MapWinGIS.Image();
#endregion
This set of type declaration shows the four main types required to manipulate the raster grid data in MapWinGIS. The first type is the layer handler which is stored in an integer variable (intHandler
). The layer handler is a unique value used to manipulate the layers. The second type is MapWinGIS.Grid
. This is a specific MapWinGIS type used to store the raster grids. The third type is MapWinGIS.GridHeader
, which is another type provided by MapWinGIS to manipulate the raster header. The fourth type is MapWinGIS.Image
. It is a type provided by MapWinGIS, and is used to store an image copy of the raster, which can be used to visualize the raster grid data in the Map control. All pervious MapWinGIS types are reference types, and require the new
keyword to be initiated.
Now we have all the required instances to manipulate our raster. The raster used in this lesson is a sample digital elevation model DEM for a study area in the north western desert of Egypt created by achieving an interpolation for a set of elevation points collected from the field and from topographic maps. This raster is stored in GeoTIFF format. The GeoTIFF format is a regular TIFF format with additional information about the spatial domain of the data. Add the following code in the Form1_Load
event:
#region LoadTheData
myGrid.Open(@"D:\SampleData\dem.tif",
MapWinGIS.GridDataType.DoubleDataType,
false,MapWinGIS.GridFileType.GeoTiff,
null);
myHeader = myGrid.Header;
MapWinGIS.GridColorScheme myScheme =
new MapWinGIS.GridColorScheme();
myScheme.NoDataColor =
System.Convert.ToUInt32(
System.Drawing.ColorTranslator.ToOle( System.Drawing.Color.FromArgb(0, 0, 0)));
myScheme.UsePredefined(
(double)myGrid.Minimum,
(double)myGrid.Maximum,
MapWinGIS.PredefinedColorScheme.DeadSea );
MapWinGIS.Utils myUtil = new MapWinGIS.Utils();
myImage = myUtil.GridToImage(myGrid, myScheme, null);
intHandler = axMap1.AddLayer(myImage, true);
#endregion
The first step to display the data is to load the raster data from the file to the grid instance (myGrid
). The Open
method is used to load the data into the grid instance. The Open
method needs five arguments:
- The first argument is the full path to the file that contains the raster data.
- The second argument is the type of grid data which is presented in MapWinGIS as an enum type
MapWinGIS.GridDataType
, which represents six elements. These elements include four defined elements (ShortDataType
for short integer data type pixels, LongDataType
for long integer data type pixels, FloatDataType
for single precision data type pixels, and DoubleDataType
for a double precision data type pixels) and two undefined elements (UnknownDataType
for use with unknown data types, and InvalidDataType
for invalid data types).
- The third argument is a
bool
value that shows if the raster should read from RAM (true
) or from file (false
).
- The fourth argument is a
GridFileType
. MapWinGIS provides an enumeration to describe the grid file type supported by MapWinGIS itself. The supported grid file types are: ASCII grid file format (MapWinGIS.GridFileType.Ascii
), Band Interleaved by Line format (MapWinGIS.GridFileType.Bil
), Binary grid file format (MapWinGIS.GridFileType.Binary
), Digital Terrain Elevation Data file format (MapWinGIS.GridFileType.DTed
), ERMapper Compressed Wavelet file format (MapWinGIS.GridFileType.Ecw
), ESRI Grid file format (MapWinGIS.GridFileType.Esri
), ArcView Binary Raster file format (MapWinGIS.GridFileType.Flt
), GeoTIFF raster file format (MapWinGIS.GridFileType.GeoTiff
), MrSID raster file format (MapWinGIS.GridFileType.MrSid
), PCI PAux raster file format (MapWinGIS.GridFileType.PAux
), PCI Geomatics database file format for raster data (MapWinGIS.GridFileType.PCIDsk
), and United States Geological Survey USGS Spatial Data Transfer Standard raster data format (MapWinGIS.GridFileType.Sdts
).
Beside these types, the user can assign two different enums: MapWinGIS.GridFileType.InvalidGridFileType
, which may be used to handle data with gaps or errors, and MapWinGIS.GridFileType.UseExtension
, which lets the user open different common raster formats.
- The last argument required for the
Open
method is the callback. null
is assigned for this argument in most common cases.
The second step is to assign the grid header to the header instance (myHeader
). The grid header includes basic information about the raster grid like its width, height, pixel resolution etc. After the second step, the grid and its header are loaded to the computer memory, and for that reason, the procedure requires a time. The objective of steps 3, 4, and 5 is to prepare the symbology required to display the grid. The third step is a creation of the raster grid color scheme. The raster grid color scheme is presented by the MapWinGIS.GridColorScheme
class in MapWinGIS. In step 3, an instance (myScheme
) of this class is created and initiated.
In the fourth step, we will set a color to illustrate the no-data pixels using the NoDataColor
property of the MapWinGIS.GridColorScheme
instance (myScheme
). The assigned color is black. The fifth step is to use the UsePredefined
method for the instance myScheme
to assign a predefined grid color scheme setting for myScheme
settings. This method requires three components: the minimum pixel value, the maximum pixel value, and the predefined grid color scheme. The minimum and maximum pixel values can easily be got using the grid instance properties Minimum
and Maximum
. The predefined grid color scheme introduced in MapWinGIS as an enumeration type includes eight elements:
MapWinGIS.PredefinedColorScheme.DeadSea
MapWinGIS.PredefinedColorScheme.Desert
MapWinGIS.PredefinedColorScheme.FallLeaves
MapWinGIS.PredefinedColorScheme.Glaciers
MapWinGIS.PredefinedColorScheme.Highway1
MapWinGIS.PredefinedColorScheme.Meadow
MapWinGIS.PredefinedColorScheme.SummerMountains
MapWinGIS.PredefinedColorScheme.ValleyFires
And now, it’s show time. Let's add the code required to display our grid. To display the grid, you have to convert it to an image. Conversion of a grid to an image requires an instance of the MapWinGIS.Utils
class. In step 7, this instance (myUtil
) is created and initiated. In step 8, the method GridToImage
- which is provided by MapWinGIS.Utils
(myUtil
) – is used to convert the gird – the first argument (myGrid
) – to an image using a defined grid color scheme – the second argument (myScheme
). The third argument required for the GridToImage
method is the callback. Now, add the image (myImage
) to the Map control (axMap1
) using the AddLayer
method. Don't forget to assign the required code to the navigation buttons. The code for these buttons is available in lesson 1. Now, strike the F5 function key in your keyboard to start debugging the application, and if you did everything right, you will get the following screen:
Something About my Grid
Each raster grid has a set of basic information – called metadata in some technical literature – which is required to understand many facts about the grid and the geographic features presented by the grid. The most common and important information icludes the pixel dimensions in measurement unit (e.g., Meter), the width and the height of the grid in pixels, and the lower left corner coordinates. This information helps the programmer to know and calculate many useful information like the width and the height of the grid in the measurement unit (width (or height) in measurement unit = width (or height) in pixels * pixel edge length), the area of the grid (width in pixels * height in pixels * pixel edge length * pixel edge length). All these basic data are available in the GridHeader
instance (myHeader
). Add the following code to the btnInfo_Click
event:
int width = myHeader.NumberCols;
int hight = myHeader.NumberRows;
string sizeInPixels =
String.Format("Grid sizs - in pixels - is ({0},{1})\n", width, hight);
double deltaX = myHeader.dX;
double deltaY = myHeader.dY;
string pixelDimensions =
String.Format("Pixel dimensions are ({0},{1})\n", deltaX, deltaY);
double xLlLocation = myHeader.XllCenter;
double yLlLocation = myHeader.YllCenter;
string lowerLeftCorner = String.Format("Lower Left corner coordinates ({0},{1})\n",
xLlLocation ,yLlLocation );
string infoMessage = sizeInPixels + pixelDimensions + lowerLeftCorner;
MessageBox.Show(infoMessage, "Raster Information",
MessageBoxButtons.OK, MessageBoxIcon.Information);
In the first set of statements, the properties NumberCols
and NumberRows
of the GridHeader
instance (myHeader
) were used, and the restored values stored in the width
and height
integer data variables. These properties restore the number of columns and the number of rows, respectively. In the second set, the properties dX
and dY
of the GridHeader
instance (myHeader
) were used, and the restored values stored in the deltaX
and deltaY
integer data variables. In the third set, the properties xllCenter
and yllCenter
of the GridHeader
instance (myHeader
) were used, and the restored values stored in the xLlLocation
and xLlLocation
integer data variables. These two variables represent the coordinates of the center of the lower left corner pixel. The fourth and the last set of the code is where we will build a string to represent the previous information and launch it visually to let the user read it. Strike the F5 function key in your keyboard. You will get something like this as the output:.
Tell Me, Where Am I???
Some of the most important functions GIS provides are where it is and what it is. For raster data, this information can be introduced using the PixelToProj
method for the Map control instance and the get_Value
method for the Grid instance, respectively. Go to Form1
in Design view and select the axMap1
control. Press F4 to get axMap1
's Properties window. Find the SendMouseMove
property in axMap1
's Properties window and set it to true
. This action will activate axMap1_MouseMoveEvent
. Now, bring this event axMap1_MouseMoveEvent
for the axMap1
event list, and double click it to open it in Code view. Add the following code for this event:
double X =0;
double Y =0;
axMap1.PixelToProj(e.x, e.y, ref X, ref Y);
double pixelVal = (double) myGrid.get_Value(e.x, e.y);
string pointLocation = String.Format("Cursor location ({0},{1}) " +
"and the pixel value is {2}",X,Y, pixelVal );
toolStripStatusLabel1.Text = pointLocation;
The first set of code aims to identify the location of the cursor on the axMap1
control. In this code, we will declare two double
type variables X
, Y
, and assign an initial value (0) for both. The PixelToProj
method for the axMap1
instance is used, and it needs four arguments: the first two arguments are the position of the cursor on axMap1
, which is represented by e.x
and e.y
, and the variables where the converted value will be stored. These variables, X
, Y
, should be passed using the keyword ref
. After using this method, the values of X
and Y
will store the location of the cursor on axMap1
in the projection measurement unit. The second set of code aims to identify the value of the pixel where the cursor is. In this code, we will declare a double
type variable pixelVal
and assign a value returned by the method get_Value
for the Grid instance (myGrid
). The method get_Value
requires two arguments representing the location of the cursor. These arguments are represented using e.x
and e.y
. Now, strike F5, and try to move the cursor above the map and show how the status bar will change directly to show you the location of the cursor and the value of the pixel located in this location.
Conclusion
MapWinGIS presents an easy-to-use approach to display and manipulate raster data in a two level manipulation. The first level treats the grid so the programmer can return information like the width and the height of the grid or the lower left corner coordinates. The second level treats the grid data on the pixel level, where the programmer can set or return the value of the pixel using its location. Using the same toolbox, programmers may display and manipulate images which add great functionality for GIS programmers and support their applications that include procedures to handle complex raster formats like multispectral images and aerial photographs.
History
- First edition: Sunday, Nov. 22, 2009.