Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Using MapWinGIS to Convert ESRI Shape Files to Google Earth KML

4.67/5 (3 votes)
12 Sep 2012CPOL2 min read 28K   1.1K  
A simple set of functions to convert Shape File Polygons into KML Polygons

This article appears in the Third Party Products and Tools section. Articles in this section are for the members only and must not be used to promote or advertise products in any way, shape or form. Please report any spam or advertising.

Introduction

Google Earth is possibly the best visualisation tool available for GIS data. The only problem is that you have to get the GIS data into Google Earth's Keyhole Markup Language (KML) in order for Google Earth to be able to display it for you.

ESRI Shape files are commonly used to represent GIS data and there are many tools available for visualising them, one of the most popular Open Source tools being Mapwindow. However, Mapwindow currently doesn't have a built-in Google Earth Keyhole Markup Language (KML) export option, although there are Paid for Plugins available.

Luckily, Google has made creating KML very straightforward and so it is relatively easy to write a simple set of functions (using the MapWinGIS class) to convert Polygon Shapefiles to KML.

Just to illustrate the difference between looking at Shapefile data in MapWindow and GoogleEarth, compare the two screen extracts below. The left hand one shows the Shapefile viewed in MapWindow, whilst the right hand one shows the same data overlaid in Google Earth. In this example the data shows buildings in central London.

Image 1

Using the Code 

There are 13 Shape types in the ESRI standard (excluding the NullShape) but the code in this example only handles Polygons. However, as these are the most common Shape type used, this is not such a big limitation. The code can be easily extended, to support other Shape types, by adding the relevant functions to the Case Statement below. Currently any non Polygon shapes will be skipped cleanly and a note will appear in the Visual Studio debug console to tell the user.

VB.NET
'Loop through the shape file, shape by shape
Dim ShapeIndex As Integer, ConvertedShapeCount As Integer
For ShapeIndex = 0 To SF.NumShapes - 1
 
    'Process each shape depending on ShapeType
    Select Case SF.Shape(ShapeIndex).ShapeType
 
        Case ShpfileType.SHP_POLYGON
            Call AddPolygonKML(SF.Shape(ShapeIndex), KMLFile, CStr(ShapeIndex))
            ConvertedShapeCount = ConvertedShapeCount + 1
 
        Case Else
            Debug.Print("Shape # " & ShapeIndex & " of type " & SF.Shape(ShapeIndex).ShapeType & " not supported yet.")
 
    End Select
 
Next ShapeIndex

Creating a Polygon in KML

KML has a Polygon function, so to convert a Shape into KML, you just need to read out the points from the Shape and apply the appropriate KML syntax to them.

A Polygon defined in KML looks like this:  

XML
<Polygon>
    <extrude>1</extrude>
    <altitudeMode>relativeToGround</altitudeMode>
    <outerBoundaryIs>
       <LinearRing>
          <coordinates>
             -0.10615258,51.51241061,26.0
             -0.10617222,51.51241083,26.0
             -0.10617112,51.51248367,26.0
             -0.10599687,51.51248266,26.0
             -0.10599709,51.51247534,26.0
             -0.10599741,51.51246417,26.0
             -0.10606998,51.51246500,26.0
             -0.10615098,51.51246545,26.0
             -0.10615258,51.51241061,26.0
          </coordinates>
       </LinearRing>
    </outerBoundaryIs>
 </Polygon>

The coordinates are defined as tuples with Longitude (degrees), Latitude (degrees) and Height (metres). The height can be relative to Ground, Sea, Seabed etc. This is defined by the Altitude Mode, so make sure you use the appropriate altitude mode for your height data!

XML
<altitudeMode>relativeToGround</altitudeMode>

Putting this all together, a simple function to convert from a Shape Polygon to a KML Polygon is shown below. This function ignores the fact that Polygons may have more than one part and so multi-part polygons may not display correctly. NB I'll probably add this functionality at a later date. 

VB.NET
Private Sub AddPolygonKML(ByRef Shape As MapWinGIS.Shape, _
                          ByRef oWrite As System.IO.StreamWriter, _
                          ByVal ShapeID As String)

       'The key parameters for defining the KML Polygon's points are:
       Dim LatDeg As Double
       Dim LonDeg As Double
       Dim Height As Double    'Note: depending on whether this is AGL or ASL, change the KML setting below accordingly

       'Create a Placemark with no label to wrap the Polygon in
       oWrite.WriteLine("   <Placemark>")

       'Use the Shapes ID as a Name (optional)
       oWrite.WriteLine("      <name>Shape " & ShapeID & "</name>")

       'Pick up the Style we wish to use (otional, but allows for nice colours etc)
       oWrite.WriteLine("      <styleUrl>Shape Style</styleUrl>")

       'Start the Polygon KML object
       oWrite.WriteLine("      <Polygon>")

       'The <extrude> tag extends the line down to the ground
       oWrite.WriteLine("         <extrude>1</extrude>")

       'Note there are two common options for Altitude:
       ' "relativeToGround"  for Above Ground Level
       ' "absolute" for Above Sea Level
       ' See https://developers.google.com/kml/documentation/altitudemode
       oWrite.WriteLine("         <altitudeMode>relativeToGround</altitudeMode>")

       'A Polygon is defined by a ring of coordinates
       oWrite.WriteLine("         <outerBoundaryIs>")
       oWrite.WriteLine("            <LinearRing>")
       oWrite.WriteLine("               <coordinates>")

       'Loop through the points one by one
       Dim PointIndex As Integer
       For PointIndex = 0 To Shape.numPoints - 1

           'Extract the 3D coordinates for the Point
           LonDeg = Shape.Point(PointIndex).x
           LatDeg = Shape.Point(PointIndex).y
           Height = Shape.Point(PointIndex).Z


           'create KML coordinate string is <lon,lat,height> {space} <lon,lat,height>
           'Note: Any space next to a ',' will create a new coordinate!
           oWrite.Write("                  ")
           oWrite.Write(FormatNumber(LonDeg, 8) & ",")
           oWrite.Write(FormatNumber(LatDeg, 8) & ",")
           oWrite.Write(FormatNumber(Height, 1) & " ")
           oWrite.WriteLine()

       Next PointIndex

       'Close the relevant folders in reverse order
       oWrite.WriteLine("               </coordinates>")
       oWrite.WriteLine("            </LinearRing>")
       oWrite.WriteLine("         </outerBoundaryIs>")
       oWrite.WriteLine("      </Polygon>")
       oWrite.WriteLine("   </Placemark>")

End Sub

Using the Source Code  

The Source Code contains a standalone set of functions which will take a Shapefile and convert it to a KML file. The main function header is shown below:

VB
Public Sub ConvertShapeFileToKML(ByVal ShapeFileName As String, _
                                 ByVal KMLFileName As String)

Points of Interest

The best tip I can give for writing KML is to remember that when listing coordinates, do not have any spaces around the commas between Longitude, Latitude and Height, otherwise GE assumes they are separate coordinates and you will spend ages trying to figure out why the KML isn't working so:
XML
<coordinates>-1.1,-2.2,100</coordinates>      'works fine
<coordinates>-1.1, -2.2, 100</coordinates>    'will not work as expected!

History 

Version 1.0, 4th September 2012

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)