Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Build a Desktop GIS Application Using MapWinGIS and C# - Part 3

0.00/5 (No votes)
22 Nov 2009 2  
Raster data display and manipulation using MapWinGIS.

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_array.gif

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.

raster1.gif

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
//(1) Create an integer variable to store the raster grid layer handler
public int intHandler;
//(2) Create an instance for the grid raster 
public MapWinGIS.Grid myGrid = new MapWinGIS.Grid();
//(3) Create a new grid header object
public MapWinGIS.GridHeader myHeader = new MapWinGIS.GridHeader();
//(4) Create an image instance to store and display the raster
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
//(1) Open the grid
myGrid.Open(@"D:\SampleData\dem.tif",
        MapWinGIS.GridDataType.DoubleDataType,
        false,MapWinGIS.GridFileType.GeoTiff,
        null);
//(2) Get the header of the raster
myHeader = myGrid.Header;

//Symobolize the raster grid
//(3) Create a raster grid color scheme
MapWinGIS.GridColorScheme myScheme = 
        new MapWinGIS.GridColorScheme();            
//(4)Assign the no data color to lack
myScheme.NoDataColor =
        System.Convert.ToUInt32( 
        System.Drawing.ColorTranslator.ToOle( //
        System.Drawing.Color.FromArgb(0, 0, 0)));
//(5) Set the attributes of the color scheme
myScheme.UsePredefined(
        (double)myGrid.Minimum,
        (double)myGrid.Maximum,
        MapWinGIS.PredefinedColorScheme.DeadSea );

//Convert the grid to an image
//(6) Create a Utili instance
MapWinGIS.Utils myUtil = new MapWinGIS.Utils();
//(7) and use it to convert the grid to the image
myImage = myUtil.GridToImage(myGrid, myScheme, null);

//(8) Finally add the layer to the map
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:

01.jpg

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:

//(1) Get the width and height of the 
//grid in pixels
int width = myHeader.NumberCols;
int hight = myHeader.NumberRows;
string sizeInPixels = 
  String.Format("Grid sizs - in pixels - is ({0},{1})\n", width, hight);      

//(2) Get the width and height of the pixel
double deltaX = myHeader.dX;
double deltaY = myHeader.dY;
string pixelDimensions = 
  String.Format("Pixel dimensions are ({0},{1})\n", deltaX, deltaY);

//(3) Get the lower left corner coordiantes
double xLlLocation = myHeader.XllCenter;
double yLlLocation = myHeader.YllCenter;
string lowerLeftCorner = String.Format("Lower Left corner coordinates ({0},{1})\n", 
                                       xLlLocation ,yLlLocation );
    
//(4) Show the message
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:.

02.jpg

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:

//(1) Get the location of the cursor
// form the MapControl and transform it to
//the projection location
double X =0;
double Y =0;
axMap1.PixelToProj(e.x, e.y, ref X, ref Y);
//(2) Get the value of pixel at specified point
double pixelVal = (double) myGrid.get_Value(e.x, e.y);
//(3) Print the result to the status toolbar.
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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here