65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 MapWinGIS 将 ESRI Shape 文件转换为 Google Earth KML

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (3投票s)

2012年9月4日

CPOL

3分钟阅读

viewsIcon

28234

downloadIcon

1106

一组简单的函数,用于将 Shape 文件多边形转换为 KML 多边形

引言

Google Earth 可能是目前可用的最佳 GIS 数据可视化工具。 唯一的问题是,您必须将 GIS 数据转换为 Google Earth 的 Keyhole Markup Language (KML),才能让 Google Earth 显示它。

ESRI Shape 文件通常用于表示 GIS 数据,并且有很多工具可用于可视化它们,其中最受欢迎的开源工具之一是 Mapwindow。 但是,Mapwindow 目前没有内置的 Google Earth Keyhole Markup Language (KML) 导出选项,尽管有付费插件可用。

幸运的是,Google 已经使创建 KML 变得非常简单,因此编写一组简单的函数(使用 MapWinGIS 类)将多边形 Shapefile 转换为 KML 相对容易。

为了说明在 MapWindow 和 Google Earth 中查看 Shapefile 数据之间的区别,请比较以下两个屏幕截图。 左侧显示在 MapWindow 中查看的 Shapefile,而右侧显示在 Google Earth 中叠加的相同数据。 在此示例中,数据显示了伦敦市中心的建筑物。

使用代码 

ESRI 标准中有 13 种 Shape 类型(不包括 NullShape),但此示例中的代码仅处理多边形。 但是,由于这些是最常用的 Shape 类型,因此这并不是一个很大的限制。 可以通过在下面的 Case 语句中添加相关函数来轻松扩展代码,以支持其他 Shape 类型。 目前,任何非多边形 Shape 都会被干净地跳过,并且会在 Visual Studio 调试控制台中显示一条通知给用户。

'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

在 KML 中创建多边形

KML 具有 Polygon 函数,因此要将 Shape 转换为 KML,您只需要从 Shape 中读取点,并应用适当的 KML 语法即可。

在 KML 中定义的 Polygon 如下所示:  

 <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>

坐标定义为包含经度(度)、纬度(度)和高度(米)的元组。 高度可以相对于地面、海洋、海底等。 这由高度模式定义,因此请确保为您的高度数据使用适当的高度模式!

<altitudeMode>relativeToGround</altitudeMode>

将所有这些放在一起,下面显示了一个将 Shape 多边形转换为 KML 多边形的简单函数。 此函数忽略了多边形可能具有多个部分的事实,因此多部分多边形可能无法正确显示。 注意:我可能会在以后添加此功能。 

 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

使用源代码 

源代码包含一组独立的函数,它将接受 Shapefile 并将其转换为 KML 文件。 主函数头如下所示

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

关注点

编写 KML 的最佳技巧是记住,在列出坐标时,不要在经度、纬度和高度之间的逗号周围留有任何空格,否则 GE 会假定它们是单独的坐标,您将花费大量时间弄清楚为什么 KML 不起作用
<coordinates>-1.1,-2.2,100</coordinates>      'works fine
<coordinates>-1.1, -2.2, 100</coordinates>    'will not work as expected!

历史 

版本 1.0,2012 年 9 月 4 日

© . All rights reserved.