用DotSpatial写了个Shapefile viewer

读大学那会儿老师大概给我们讲过shapefile格式,老师也鼓励我们自己动手写个 Shapefile 解析器,但当时我也不知道干啥了,并没有去了解它,只知道它是个矢量数据格式,而且在gis圈很流行。最近发现 DotSpatial 对 Shapefile 的支持也很完善,而且代码风格简洁,所以想写一篇分享,介绍下 Shapefile 的基本概念和使用方法。

Shapefile 格式快速入门

Shapefile 是 ESRI 在上世纪提出的一种矢量数据格式,虽然资历很老,但在政企与生产环境里依然非常常见(没办法谁让人家进入行业早呢)。它的核心特点是由多文件共同描述同一个图层,最常用的文件包括:

  • .shp
    • 存储几何形状本体,支持点、折线、多边形等,支持多部件几何,单个文件最大2G
  • .shx
    • 几何索引文件,加速按记录定位,缺失会影响性能
  • .dbf
    • 属性表,dBASE 格式,每条几何对应一行属性
  • .prj
    • 坐标参考信息,WKT 文本,可选但非常重要
  • 其他常见伴随文件
    • .cpg 指定字符编码
    • .sbn .sbx 空间索引等

几个上手就会用到的小知识点:

  • 几何类型是固定的
    • 一个 Shapefile 图层只能是点图层、线图层或面图层之一
  • 坐标系可能缺失
    • 没有 .prj 依然能显示,但坐标参考不明确,量测和叠加需要谨慎。说到坐标系,我当年上大学乃至毕业后一两年内都没搞明白是啥玩意(也幸好我没搞明白,不让当时我就可能去了另外一个部门了😂)。
  • 属性有长度限制
    • .dbf 的字段名和类型有历史限制,适合结构化但不超长的字段
  • 优缺点
    • 优点是通用、简单、读取速度快
    • 缺点是文件分散、字段和编码有限制、不支持拓扑和更丰富的约束

利用 DotSpatial 在 WinForms 中加载并显示shp文件

DotSpatial 是一个用于 .NET 平台的地理信息系统库,支持在 Windows Forms 中显示地图(提供了地图控件),可打开矢量、栅格等空间数据,提供投影转换、符号渲染、属性操作和空间分析等功能。该库采用MIT协议,非常宽松,不过用纯C#做地图渲染,我觉得应该不会有多少公司会这么选择。

下面用 DotSpatial 做一个能打开 Shapefile、浏览地图、选中要素并查看属性的小工具。核心依赖是 DotSpatial.Controls、DotSpatial.Data、DotSpatial.Symbology,必要时可加 DotSpatial.Projections。

先看一眼最终展示效果的截图:

主界面截图:

    属性查看截图:

    关键代码片段

    说实话,WinForms真的太简单了,写个demo非常快(但即便如此,我用Codebuddy还是没能完成这个viewer,最后还得我自己一步一步排查各种问题,AI虽好但也只能打打下手)。 下面用极简代码说明如何把 Map 控件加入 WinForms,并打开一个 .shp 文件显示在地图上。代码仅为示例结构。

    using System;
    using System.Windows.Forms;
    using DotSpatial.Controls;
    using DotSpatial.Data;
    using DotSpatial.Symbology;

    public partial class MainForm : Form
    {
        private Map m_map;

        public MainForm()
        {
            InitializeComponent();

            // Init map control
            m_map = new Map();
            m_map.Dock = DockStyle.Fill;

            Controls.Add(m_map);
        }

        // Open and render a shapefile
        private void OpenShapefile(string path)
        {
            if (string.IsNullOrWhiteSpace(path))
            {
                return;
            }

            IFeatureSet fs = FeatureSet.Open(path);
            fs.FillAttributes();

            // Add to map and zoom to extent
            IMapLayer layer = m_map.Layers.Add(fs);
            m_map.ZoomToMaxExtent();
        }
    }

    几点说明:FeatureSet.Open 会读取 .shp 和 .shx,FillAttributes 会加载 .dbf 属性,m_map.Layers.Add 会根据类型应用默认样式,必要时可再用 Symbology 自定义。

    如果需要要素选择和右侧属性表展示,可以将 Map 的功能模式切换到 Select,并在选择事件里读取当前选择的要素,然后把属性绑定到一个 PropertyGrid 或 DataGridView。示例伪代码如下:

    m_map.FunctionMode = FunctionMode.Select;

    private void RefreshSelectedAttributes()
    {
        var featureLayer = m_map.Layers[0] as IMapFeatureLayer;
        if (featureLayer == null)
        {
            return;
        }

        var selection = featureLayer.Selection;
    }

    配合简单的菜单或快捷键,就能完成打开文件、缩放漫游、选中高亮、查看属性等常见工作流。性能方面,大数据量时务必确保 .shx 存在;如果涉及坐标转换,再加上 DotSpatial.Projections 并设置正确的坐标参考,目前没对坐标系处理,只是个简单的demo,所以并没做什么复杂的操作。


    地址

    DotSpatial: https://github.com/DotSpatial/DotSpatial

    ShapefileViewer: https://github.com/AfricChang/ShapefileViewer

    完整示例工程包含菜单、工具栏、选择高亮、属性查看、状态栏等功能,适合做成一个轻量的 Shapefile 浏览器(为充分测试,使用需谨慎!)。

    发表回复

    您的邮箱地址不会被公开。 必填项已用 * 标注