Introduction Custom Gis
Introduction Custom Gis
MapWindow GIS Introduction to Custom GIS Application Development for Windows Copyright 2008 Brian Marchionni All Rights Reserved. Department of Geosciences Idaho State University 1776 Science Center Dr. Idaho Falls, ID 83402 USA
Printed in the United States of America The names of companies and products herein are trademarks or registered trademarks of their respective trademark owners. Revision 0.1
C. From the New Project window select Windows Forms Application, enter MyFirstMapApp for the name and then click OK
You will be returned to the main Visual Basic window. Notice that a new tab has formed titled Form1.vb [Design] beside the original Start Page tab. The body of this design tab contains a windows form titled Form1. This is a representation of what the program would look like if you ran it now. To the right of the main tab window you will notice the Solution Explorer panel, and below it, the Properties Panel. D. Click File -> Save All E. Click Save from the Save Project dialog box From now on you will be able to save your work by simply clicking File -> Save All, or by clicking the Save All button on the main tool bar F. Click the Toolbox button on the left hand side of your screen
This causes the Toolbox to pop out. The toolbox contains components that you can drag onto your applications form to add new functionalities. G. Click the sign next to All Windows Forms collapsible menu
This will cause the All Windows Form collapsible menu to expand, revealing components that can be dropped onto a window. The MapWinGIS ActiveX component is absent, however, from this list. If your system has other GIS software installed on it, you may find other mapping components in this list.
10
H. Right click on the All Windows Forms collapsible menu and select Choose Items from the drop down menu.
Depending on how fast your computer is and what software you have installed, it may take several moments for the next window to open and to change tabs. Please be patient: your machine has not locked up. I. Click on the COM Components tab J. Locate the Map Control in the list of COM Components, make sure that it has a check mark to the left of it, and then click OK
If you have other GIS software installed, ensure that you have selected the Map Control with MapWinGIS Components in the column labeled Library.
11
B. Highlight the Map Component by left clicking on it This changes the properties panel to show the properties of the Map Component. Notice that the Map Component has been named AxMap1. The properties panel allows various aspects of the control to be changed. For example, scrolling down to (Name) under the Design heading allows the user to change the name of the Map Component. C. Left click on the resize boxes of the Map Component and drag it to fill the form. Resize boxes are located on the edges and corners of a component.
12
This opens a new tab called Form1.vb beside the existing tabs: Form1.vb [Design] and start page. The new tab contains the following code: Public Class Form1 Private Sub Form1_Load(...) Handles MyBase.Load End Sub End Class Any code written between the lines Private Sub Form1_Load... and End Sub is considered to be part of the subroutine Form1_Load. This particular subroutine will be executed when Form1 loads for the first time.
13
B. Dimension a shapefile object by adding the following code to the Form1_Load subroutine Dim myWorldShape As new MapWinGIS.Shapefile Once you have added the line, your project should look like this: Public Class Form1 Private Sub Form1_Load(...) Handles MyBase.Load Dim myWorldShape As New MapWinGIS.Shapefile End Sub End Class This is the first step in adding data to the map. The line of code just added dimensions a new object called myWorldShape of type MapWinGIS.Shapefile, which can be used to open a shapefile and load it into memory. C. Use the myWorldShape object to open a shapefile stored on the local disk by adding the following code below the previous line you added myWorldShape.Open("C:\Program Files\MapWindow\_ Sample projects\world\Shapefiles\world_adm0.shp") This command instructs the myWorldShape object to open the shape file that is specified in the path between quotes. The full path, including the file extension, has to be present for the file to be found and opened. D. Next add the myWorldShape object to the map by adding this line of code below the previous line you added AxMap1.AddLayer(myWorldShape, True) Once you have added the line, your project should look like this: Public Class Form1 Private Sub Form1_Load(...) Handles MyBase.Load Dim myWorldShape As New MapWinGIS.Shapefile myWorldShape.Open(...) AxMap1.AddLayer(myWorldShape, True) End Sub End Class
14
E. Click on the Form1.vb [Design] tab, and then click the Start Debugging button (the icon with the green play button) to run your program
Your program should now be running. The Map Component should be filed with a simple map of the world. The default cursor function is zoom in. Try manipulating the map with the cursor by clicking and dragging a bounding box.
You will soon discover that more tools are needed, such as the ability to zoom out and to pan the map; these features will be added in the next section. F. When you are done, close your program to return to the development environment
15
16
E. Left click on the ToolStripButton1 Component and examine its properties in the properties panel. F. Rename your button by locating the (Name) attribute and changing its value from ToolStripButton1 to btnZoomIn. This is the name that we will use to later access the component programmatically.
G. Locate the DisplayStyle attribute and change its value from Image to Text H. Change the buttons Label by locating the Text attribute and changing it from ToolStripButton1 to Zoom In
I. Now that you have learned how to add buttons to your form, add three additional buttons beside the one that you just created. Name the new buttons btnZoomOut, btnPan and btnFullExtent, and label them Zoom Out, Pan and Full Extent respectively.
17
J. Double click the Zoom In button on Form1 in the designer to create an event handler This action opens the Form1.vb tab and creates the event handler for the Zoom In button called btnZoomIn_Click. Any code written between the line Private Sub btnZoomIn_Click... and the End Sub below it will be executed when the button is pressed. K. Add the line AxMap1.CursorMode = MapWinGIS.tkCursorMode.cmZoomIn to the btnZoomIn_Click sub by inserting it below the line Private Sub btnZoomIn_Click(... The btnZoomIn_Click sub should now look like this. Private Sub btnZoomIn_Click(...) Handles btnZoomIn.Click AxMap1.CursorMode = MapWinGIS.tkCursorMode.cmZoomIn End Sub This line of code changes the CusorMode attribute of the AxMap1 MapComponent to MapWinGIS.thCursorMode.cmZoomIn. You can change the public attributes of any component programmatically by typing the components name and then pressing . This will then generate a drop down box of all the attributes and methods associated with that component. In this case we are accessing the MapComponents CursorMode attribute. Notice that once you type the equal sign, another drop down box forms showing all the possible values that can be assigned to that attribute. L. Now create an event handler for the Zoom Out button by repeating step J M. In the event handler for btnPan_Click set the AxMap1.CursorMode attribute to MapWinGIS.tkCursorMode.cmZoomOut N. Repeat steps L and M for the Pan button setting the CursorMode attribute to MapWinGIS.tkCursorMode.cmPan O. Now create an event handler for the Full Extent button The MapComponent contains a built-in method to zoom the map to the full extent of all layers loaded. We will call this method to quickly and easily zoom to the maps full extent.
18
P. In the btnFullExtent_Click event handler type AxMap1. Once you type the . a drop down box will form with all the public methods and properties MapComponent that you can access. Q. Look for the ZoomToMaxVisibleExtents method in the list that forms, select it from the drop down list and press enter.
R. Now that you have added functionality to all of the buttons, try to run your application. Try each of the buttons to manipulate the map. S. Close your program to return to the development environment, and save your work now by clicking File -> Save All
19
20
21
Notice how the Map Component now occupies the entire lower portion of Form1 and that the resize boxes on all sides have disappeared. F. Run the program again and resize the main form Since the Map Component is docked to the main form, its size is linked to the size of Form1.
22
23
F. Now modify the line AxMap1.AddLayer(myWorldShape, True) to read hndWorldShape = AxMap1.AddLayer(myWorldShape, True) The hndWorldShape variable now contains the handle number of the layer. This handle can be used to access the layer from the AxMap1 map component so that later the layers properties can be modified. G. Add the following lines to the bottom of Private Sub loadWorldShape() Dim FillColor As UInt32 Dim LineColor As UInt32 Dim LineWidth As Single FillColor = Convert.ToUInt32(RGB(100, 255, 0)) LineColor = Convert.ToUInt32(RGB(0, 0, 255)) LineWidth = 2.0 The variables FillColor and LineColor each contain a Red / Green / Blue color value stored as a 32 bit unsigned integer. The function Convert.ToUInt32(RGB(0,0,255)) takes three parameters with values from 0 255. Each parameter represents one of the primary color components which, when combined, create a shade. This is then converted into the unsigned interger format that the MapComponent understands. The LineWidth variable contains a single precision decimal number which represents how thick to draw lines.
24
H. Now assign the symbology that you defined in the previous step to the myWorldShape layer by adding the following lines below the ones you just added AxMap1.set_ShapeLayerFillColor(hndWorldShape, FillColor) AxMap1.set_ShapeLayerLineColor(hndWorldShape, LineColor) AxMap1.set_ShapeLayerLineWidth(hndWorldSahpe, LineWidth) Your final code should read as follows: Private Sub loadWorldShape() Dim myWorldShape As New MapWinGIS.Shapefile myWorldShape.Open("C:\Program Files\...\world_adm0.shp") Dim hndWorldShape As Integer hndWorldShape = AxMap1.AddLayer(myWorldShape, True) Dim fillColor As UInt32 Dim lineColor As UInt32 Dim lineWidth As Single fillColor = Convert.ToUInt32(RGB(100, 255, 0)) lineColor = Convert.ToUInt32(RGB(0, 0, 255)) lineWidth = 2.0 AxMap1.set_ShapeLayerFillColor(hndWorldShape, fillColor) AxMap1.set_ShapeLayerLineColor(hndWorldShape, lineColor) AxMap1.set_ShapeLayerLineWidth(hndWorldShape, lineWidth) End Sub I. Run your program and examine the modified symbology
25
26
H. Assign the pointColor symbology definition to the layer myCitiesShape using its handle and the Map Components set_ShapeLayerPointColor method I. Assign the pointSize symbology definition to the layer myCitiesShape using its handle and the Map Components set_ShapeLayerPointSize method In order to define the size and color of the point that will appear on the map, we first created variables to hold the color and size definitions, and then we assigned them to the layer we wanted to apply the symbology to by using methods on the Map Component. In order to change the shape of the point that will be drawn, we can use internal definitions that predefine some basic shapes. The class MapWinGIS.tkPointType contains many different point style definitions that we can use. J. Add the following line to the loadCitiesShape sub to assign a circle symbology to the points of the myCitiesShape layer axMap1.set_ShapeLayerPointType(hndCitiesShape,_ MapWinGIS.tkPointType.ptCircle) Now that you have defined the symbology for the myCitiesShape layer, your code should look like this: Private Sub loadCitiesShape() Dim myCitiesShape As New MapWinGIS.Shapefile myCitiesShape.Open("C:\Program Files\MapWindow\_ Sample projects\World\Shapefiles\cities_capital_pt.shp") Dim hndCitiesShape As Integer hndCitiesShape = AxMap1.AddLayer(myCitiesShape, True) Dim pointColor As UInt32 pointColor = Convert.ToUInt32(RGB(255, 255, 0)) Dim pointSize As UInt32 pointSize = 8.0 AxMap1.set_ShapeLayerPointColor(hndCitiesShape,pointColor) AxMap1.set_ShapeLayerPointSize(hndCitiesShape,pointSize) AxMap1.set_ShapeLayerPointType(hndCitiesShape,_ MapWinGIS.tkPointType.ptCircle) End Sub K. Run your program and examine the new symbology This demonstrates using a predefined point symbol contained within the MapWinGIS library. It is also possible to use an external symbol or image to represent a point. To do this we first need to load an image and then assign it to the point layer as a user defined point symbol.
27
L. In the last line replace MapWinGIS.tkPointType.ptCircle with MapWinGIS.tkPointType.ptUserDefine so that it reads: AxMap1.set_ShapeLayerPointType(hndCitiesShape,_ MapWinGIS.tkPointType.ptUserDefined) Now that the point type is set to user defined, a user defined bitmap needs to be loaded and assigned as the point symbol. M. Dimension a new variable called imgCities of type MapWinGIS.Image N. Use the Open method on the imgCities object to open the file C:\Program Files\MapWindow\OfflineDocs\content\skins\_ common\images\Arr_d.png O. We now assign the custom point image symbol to the myCitiesShape layer with the line AxMap1.set_UDPointType(hndCitiesShape, imgCities) The loadCitiesShape sub should now read: Private Sub loadCitiesShape() Dim myCitiesShape As New MapWinGIS.Shapefile myCitiesShape.Open("C:\...\cities_capital_pt.shp") Dim hndCitiesShape As Integer hndCitiesShape = AxMap1.AddLayer(myCitiesShape, True) Dim pointColor As UInt32 pointColor = Convert.ToUInt32(RGB(255, 255, 0)) Dim pointSize As UInt32 pointSize = 1 AxMap1.set_ShapeLayerPointColor(hndCitiesShape,_ pointColor) AxMap1.set_ShapeLayerPointSize(hndCitiesShape, pointSize) AxMap1.set_ShapeLayerPointType(hndCitiesShape,_ mapWinGIS.tkPointType.ptUserDefined) Dim imgCities As New MapWinGIS.Image imgCities.Open("C:\Program Files\...\Arr_d.png") AxMap1.set_UDPointType(hndCitiesShape, imgCities) End Sub P. Run your program and examine the new symbology Q. Close your program to return to the development environment, and save your work now by clicking File -> Save All
28
29
30
31
32
G. Now add the following code For i As Integer = 0 To myWorldShape.NumShapes If myWorldShape.CellValue(0, i) = "South Africa" Then MsgBox(i,MsgBoxStyle.OkOnly,_ "Which shape is South Africa?") End If Next This code loops from i = 0 to i = the number of shapes in the myWorldShape shapefile variable. Each iteration of the loop checks to see if the current shape contains the text South Africa in its column with index 0. If the shape does contain the text, a dialog box is created displaying the shapes index. H. Run your program and press the Find South Africa button
I. Close your program to return to the development environment and save your work now by clicking File -> Save All
33
34
L. Resize Form1 so that there is room to see all the buttons M. Double click the btnShowDataGrid button to create an event handler for the button and open the Form1 code tab N. In the Private Sub btnShowDataGrid_Click() sub add the lines Dim myWorldShape As New MapWinGIS.Shapefile myWorldShape = AxMap1.get_GetObject(hndWorldShape) O. Declare a new instance of the FormTable form and display it with the lines Dim myTableForm As New FormTable(myWorldShape) myTableForm.Showdialog() Whenever the user presses the Show Data Grid button, a new instance of the FormTable will be created and then displayed. P. Open the FormTable [Design] Tab, double click the FormTables title bar to open the FormTable code tab, and create the event handler sub FormTable_Load(...) Q. Add the following lines to the FormTable_Load sub Dim myDataTable As New DataTable Dim myDataRow As DataRow These lines of code create a temporary datatable, datacolumn, and datarow for us to populate with data from the shapefiles attribute table. R. Insert the following lines of code next For i As Integer = 0 To pMyShapeFile.NumFields - 1 myDataTable.Columns.Add(pMyShapeFile.Field(i).Name) Next This snippet of code will loop through the column names found in the pMyShapeFile shapefile variable and add them to the myDataTable.
35
S. Add the following lines of code next For j As Integer = 0 To pMyShapeFile.NumShapes - 1 myDataRow = myDataTable.NewRow For k As Integer = 0 To pMyShapeFile.NumFields - 1 myDataRow(k) = pMyShapeFile.CellValue(k, j) Next myDataTable.Rows.Add(myDataRow) Next This will loop through each shape in pMyShapeFile, create a new temporary row for its values, and then loop through each column of the current shape and add them to the temporary row variable. Finally the temporary row is added to the myDataTable variable. T. Now set the DataGridView1.DataSource attribute to be equal to myDataTable with the line DataGridView1.DataSource = myDataTable U. Run your program and press the Show Data Grid button
V. Close your program to return to the development environment and save your work now by clicking File -> Save All
36
37
38
G. Select all the code in this window and copy it by pressing crtl+c
H. Returns to Visual Basic 2008 Express Edition and paste the code into the Class1.vb tab by pressing ctrl+v You will get several errors at the bottom of your screen because some of the references made by the code have not been met. We will add those references now and the errors will clear.
I. Right click MyFirstPlugin in the Solution Explorer and select Add Reference from the drop down menu J. From the Add Reference window select the Browse tab
39
K. Browse to the folder C:\Program Files\Map Window\ L. Select MapWinInterfaces.dll and MapWinGIS.ocx and click OK M. Right click MyFirstPlugin in the Solution Explorer and select Add Reference from the drop down menu once more N. From the Add Reference window select the .NET tab O. Scroll down to System.Window.Forms, highlight it then click OK P. Right click MyFirstPlugin in the Solution Explorer and select Add Reference from the drop down menu Q. From the .NET tab Scroll down to System.Drawing, highlight it then click OK All of the error messages should now be gone. If some error messages remain, check to make sure you did not accidentally skip adding a reference. R. Right click Class1.vb in the solution explorer and rename it MyFirstPlugin.vb S. In the MyFirstPlugin.vb tab modify the line Public Class MyPlugin To read Public Class MyFirstPlugin While it is permissible to have classes with a different name than the file that contains them, it is a good idea to keep them the same to simplify file management on large projects. T. Modify the line Return My New Plug-in To read Return My First Plug-in This is the name that is returned to MapWindow GIS when it loads the plug-in. This value must be unique among all the plug-ins as it is used to identify them.
40
U. Click Tools -> Options in the options window expand the Project and Solutions tree, and highlight General. Place a check mark beside Show advanced build configurations and click OK
V. Right click MyFirstPlugin from the Solution Explorer and select Properties from the drop down menu W. Click the Compile tab on the left hand side of the properties page and change the Build output path to C:\Program Files\MapWindow\Plugins X. Click the Debug tab and select Start external program and enter C:\Program Files\MapWindow\MapWindow.exe
41
Please note that if you are using Visual Studio 2008 Express, the Start External Program option is missing due to changes that Microsoft made to the development environment. A work around has been found but MapWindow must be installed into its default location C:\Program Files\MapWindow\ Download the file http://idahofalls.mapwindow.org/myfirstplugin.zip and extract its contents to your hard drive. Close your current project and open the MyFirstPlugin.sln file with Visual Studio 2008 Express. If you are presented with a security warning, select Load Project Normally and click OK
42
Y. Run your plug-in by clicking the green Debug button MapWindow GIS should launch and your plug-in should appear in the Plug-ins menu.
Z. Close MapWindow GIS and save your project by clicking File -> Save All
43
44
D. Scroll down to the Terminate() Sub and add this code While g_MenuStack.Count > 0 g_MapWin.Menus.Remove(g_MenuStack.Pop()) End While This will loop through all the items that are in the stack in the reverse order that they were added, and remove them from the MapWindow GIS menu. E. Next find the Sub ItemClicked() and add the code If ItemName = "mfpItem1" Then MsgBox("My First Plug-in Clicked", MsgBoxStyle.OkOnly,_ "My First Plug-in") Handled = True End If The ItemClicked() sub catches an event which is fired whenever a menu item is clicked. The variable ItemName contains the name of the menu item that was clicked. This code checks if ItemName equals the name of the item added in Step C. If it is equal the code displays a msgbox indicating that it is. Finally the Handled variable is set to true; this prevents the event from fireing in other plug-ins and improves performance. F. Run your plug-in by clicking the green Debug button G. Expand the Plug-ins menu and make sure My First Plug-in is checked
45
I. Close MapWindow and save your project by clicking File -> Save All
46
47
J. Run your plug-in by clicking the green Debug button and click My First Plug-in -> Add Data A random color scheme has been assigned to the layer, but the layer has been named My World.
48
49
B. Run your plug-in by clicking the green Debug button and click My First Plug-in -> Add Data The program will stop at the break point and the line will turn yellow. Notice that the lock icon on the code tab has disappeared. This indicates that the code can now be edited. Runtime code editing can be done only when the program has stopped at break point.
C. Below the lines g_MapWin.Layers.Add(myWorldShape, "My World") Handled = True add the line g_MapWin.Layers(0).Color = Drawing.Color.Aqua Notice that working with colors from Plug-ins is much simpler because the MapWindow GIS application handles translating Microsoft .NET color variables for you. D. Continue debugging by pressing the Debug button again E. Close MapWindow and save your project by clicking File -> Save All F. Remove the break point by clicking the Red dot
50
51
52
J. Add the following code to the btnQuery_Click Sub Dim worldSF As New MapWinGIS.Shapefile worldSF = g_MapWin.Layers(0).GetObject() For i As Integer = 0 To worldSF.NumShapes If worldSF.CellValue(0, i) = txtBoxQuery.Text Then g_MapWin.Layers(0).Shapes(i).Color = _ Drawing.Color.LightBlue Exit Sub End If Next This will search through all the shapes in the file looking for the one with a corresponding attribute matching the text the user entered. K. Return to the MyFristPlugin.vb tab L. Below the line ElseIf ItemName = mfpAddData then add the lines Dim myQueryForm As New Query(g_MapWin) myQueryForm.Show() These two lines of code pass the MapWindow GIS application interface to the form and then display it. M. Run your plug-in by clicking the green Debug button N. Add the world data layer by clicking My First Plug-in -> Add Data O. Click My First Plug-in -> Find Country
53
P. Enter South Africa in the text box and click Search Q. Close the Query Window Notice the color of South Africa has changed. R. Close MapWindow and save your project by clicking File -> Save All
54
55
E. Add the following code below that Dim neighbor As MapWinGIS.Shape For i As Integer = 0 To worldSF.NumShapes() - 1 neighbor = worldSF.Shape(i) For j As Integer = 0 To neighbor.numPoints - 1 Dim point As MapWinGIS.Point = neighbor.Point(j) If worldSF.PointInShape(countryIndex, point.x,_ point.y) And i <> countryIndex Then g_MapWin.View.SelectedShapes.AddByIndex(i,_ Drawing.Color.Yellow) End If Next Next The first loop in the preceding code increments i from 0 to the number of shapes in the worldSF shapefile. The variable neighbor is then assigned the shape that i corresponds to. The second loop increments j from 0 to the number of points in the neighbor shape. The variable point is then assigned the point that j corresponds to. Each point is then tested to see if it borders the country being searched for; if it does the country is then selected and highlighted lavender. F. Now run your plug-in G. Add the My World layer to the map by clicking My First Plug-in -> Add Data H. Locate a country and select its neighbors by clicking My First Plug-in -> Find Country I. Enter South Africa in the text box and click Search The world map should change slightly: South Africa should change from cyan to light blue and its neighbors should have been selected and highlighted yellow.
56
57
Next myProjWorld is created to store to load the re-projected data from the disk. Dim myProjWorld As New MapWinGIS.Shapefile myProjWorld.Open(tmpShapePath) The next line enables editing the shapefiles attribute table. myWorldShape.StartEditingTable() This delcares a new field for the attribute and defines its name, the type of data stored in it, how wide to make it, and finally inserts the column into column possition 0. Dim myNewField As New MapWinGIS.Field myNewField.Name = "Area" myNewField.Type = FieldType.DOUBLE_FIELD myNewField.Width = 15 myWorldShape.EditInsertField(myNewField, 0) Once the area of the plygon is calculated, a variable is defined to temporarily hold the area. Dim myArea As Double This loop cycles through all the shapes in the projected shapefile and calculates their area. Since the shapefile is in meters, the resulting area is in square meters. This is not practical, so the MapWinGeoProc.UnitConverter.ConvertArea(...) is used to convert the value to hectares. Finally the value is stored in the corresponding cell of the original shapefile. For I As Integer = 0 To myProjWorld.NumShapes myArea = MapWinGeoProc.Utils.Area(myProjWorld.Shape(I)) myArea = MapWinGeoProc.UnitConverter.ConvertArea(_ UnitOfMeasure.Meters, UnitOfMeasure.Hectares, myArea) myWorldShape.EditCellValue(0, I, myArea) Next D. Now run your plug-in E. Add the My World layer to the map by clicking My First Plug-in -> Add Data F. Calculate the area of each country by clicking My First Plug-in -> Calculate Area
58
G. Now examine the attribute table of the My World layer by right clicking on it in the legend and selecting View Attribute Table Editor from the drop down menu
H. Close MapWindow and save your project by clicking File -> Save All
59
60
61
62
How helpful were the tutorials? ___________________________________________________________________________ ___________________________________________________________________________ ___________________________________________________________________________ Was there any material that you would have liked to see but did not? ___________________________________________________________________________ ___________________________________________________________________________ ___________________________________________________________________________
Do you have any suggestions for improving future labs and workshops? ___________________________________________________________________________ ___________________________________________________________________________ ___________________________________________________________________________
63