第05章-图层系统详解

第05章:图层系统详解

5.1 图层概述

5.1.1 图层类型体系

SharpMap 提供了丰富的图层类型,满足不同的地图展示需求:

ILayer (接口)
    │
    └── Layer (抽象基类)
            │
            ├── VectorLayer        矢量图层(点、线、面)
            │
            ├── LabelLayer         标注图层
            │
            ├── TileLayer          瓦片图层
            │
            ├── TileAsyncLayer     异步瓦片图层
            │
            ├── WmsLayer           WMS 服务图层
            │
            ├── GdalRasterLayer    GDAL 栅格图层
            │
            └── LayerGroup         图层组

5.1.2 图层集合类型

地图包含三种图层集合,渲染顺序为:背景图层 → 普通图层 → 动态图层

// 背景图层集合 - 最先渲染
map.BackgroundLayer.Add(tileLayer);

// 普通图层集合 - 按添加顺序渲染
map.Layers.Add(vectorLayer);

// 动态图层集合 - 每次刷新都重新获取数据
map.VariableLayers.Add(realtimeLayer);

5.1.3 图层通用属性

// ILayer 接口定义的属性
public interface ILayer
{
    string LayerName { get; set; }           // 图层名称
    bool Enabled { get; set; }               // 是否启用
    int SRID { get; set; }                   // 空间参考 ID
    Envelope Envelope { get; }               // 数据范围
    double MinVisible { get; set; }          // 最小可见比例尺
    double MaxVisible { get; set; }          // 最大可见比例尺
    ICoordinateTransformation CoordinateTransformation { get; set; }  // 坐标转换
}

5.2 VectorLayer 矢量图层

5.2.1 基本使用

using SharpMap.Layers;
using SharpMap.Data.Providers;
using SharpMap.Styles;

// 创建矢量图层
var layer = new VectorLayer("Countries");

// 设置数据源
layer.DataSource = new ShapeFile("countries.shp", true);

// 设置样式
layer.Style = new VectorStyle
{
    Fill = new SolidBrush(Color.LightGreen),
    Outline = new Pen(Color.DarkGreen, 1),
    EnableOutline = true
};

// 启用图层
layer.Enabled = true;

// 添加到地图
map.Layers.Add(layer);

5.2.2 样式设置

// 多边形填充样式
var polygonStyle = new VectorStyle
{
    // 填充
    Fill = new SolidBrush(Color.FromArgb(150, 200, 200, 100)),
    
    // 边框
    Outline = new Pen(Color.DarkOliveGreen, 2)
    {
        DashStyle = DashStyle.Solid,
        LineJoin = LineJoin.Round
    },
    EnableOutline = true
};

// 线样式
var lineStyle = new VectorStyle
{
    Line = new Pen(Color.Blue, 3)
    {
        DashStyle = DashStyle.Dash,
        StartCap = LineCap.Round,
        EndCap = LineCap.ArrowAnchor
    }
};

// 点样式
var pointStyle = new VectorStyle
{
    PointColor = Brushes.Red,
    PointSize = 10
};

// 使用图片符号
var imageSymbol = new VectorStyle
{
    Symbol = new ImageSymbol(Image.FromFile("marker.png"))
};

// 空心样式(仅边框)
var hollowStyle = new VectorStyle
{
    Fill = null,
    Outline = new Pen(Color.Black, 2),
    EnableOutline = true
};

5.2.3 渲染质量设置

// 设置平滑模式
layer.SmoothingMode = SmoothingMode.AntiAlias;      // 抗锯齿
layer.SmoothingMode = SmoothingMode.HighQuality;    // 高质量
layer.SmoothingMode = SmoothingMode.HighSpeed;      // 高速度

// 启用剪裁(提高性能)
layer.ClippingEnabled = true;

5.2.4 可见性控制

// 设置可见比例尺范围
layer.MinVisible = 1000;        // 最小可见比例尺(最大放大)
layer.MaxVisible = 1000000;     // 最大可见比例尺(最小缩小)

// 检查图层是否可见
public static bool IsLayerVisible(VectorLayer layer, double currentZoom)
{
    return layer.Enabled && 
           currentZoom >= layer.MinVisible && 
           currentZoom <= layer.MaxVisible;
}

// 动态显示/隐藏图层
layer.Enabled = true;   // 显示
layer.Enabled = false;  // 隐藏

5.2.5 空间查询

// 范围查询
var queryEnvelope = new Envelope(116.0, 117.0, 39.0, 40.0);
var featureDataSet = new FeatureDataSet();
layer.DataSource.ExecuteIntersectionQuery(queryEnvelope, featureDataSet);

// 获取查询结果
if (featureDataSet.Tables.Count > 0)
{
    var table = featureDataSet.Tables[0];
    foreach (FeatureDataRow row in table.Rows)
    {
        var geometry = row.Geometry;
        Console.WriteLine($"几何类型:{geometry.GeometryType}");
        
        // 访问属性
        foreach (DataColumn column in table.Columns)
        {
            Console.WriteLine($"{column.ColumnName}: {row[column]}");
        }
    }
}

// 几何查询
var queryGeometry = new GeometryFactory().CreatePoint(new Coordinate(116.4, 39.9));
var buffer = queryGeometry.Buffer(0.1);
layer.DataSource.ExecuteIntersectionQuery(buffer, featureDataSet);

5.3 LabelLayer 标注图层

5.3.1 基本使用

// 创建标注图层
var labelLayer = new LabelLayer("City Labels");

// 设置数据源(通常与矢量图层共享)
labelLayer.DataSource = vectorLayer.DataSource;

// 设置标注字段
labelLayer.LabelColumn = "CITY_NAME";

// 设置样式
labelLayer.Style = new LabelStyle
{
    Font = new Font("Microsoft YaHei", 10, FontStyle.Bold),
    ForeColor = Color.Black
};

// 启用
labelLayer.Enabled = true;

// 添加到地图(标注图层通常在矢量图层之后添加)
map.Layers.Add(labelLayer);

5.3.2 标注样式详解

var labelStyle = new LabelStyle
{
    // 字体
    Font = new Font("Arial", 12, FontStyle.Bold),
    
    // 前景色
    ForeColor = Color.DarkBlue,
    
    // 背景色(标注框)
    BackColor = new SolidBrush(Color.FromArgb(200, 255, 255, 200)),
    
    // 光晕效果(提高可读性)
    Halo = new Pen(Color.White, 3),
    
    // 对齐方式
    HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center,
    VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Middle,
    
    // 偏移(像素)
    Offset = new PointF(0, -15),
    
    // 旋转角度
    Rotation = 0,
    
    // 碰撞检测
    CollisionDetection = true,
    CollisionBuffer = new SizeF(10, 10),
    
    // 忽略线串长度
    IgnoreLength = false
};

labelLayer.Style = labelStyle;

5.3.3 动态标注文本

// 使用委托动态生成标注文本
labelLayer.LabelStringDelegate = (row) =>
{
    string name = row["NAME"]?.ToString() ?? "";
    
    // 可以根据属性值格式化标注
    if (row["POPULATION"] != DBNull.Value)
    {
        long population = Convert.ToInt64(row["POPULATION"]);
        return $"{name}\n{population:N0}人";
    }
    
    return name;
};

// 使用多个字段组合
labelLayer.LabelStringDelegate = (row) =>
{
    return $"{row["NAME"]} ({row["CODE"]})";
};

5.3.4 标注优先级

// 设置优先级字段(数值越大优先级越高)
labelLayer.PriorityColumn = "PRIORITY";

// 或者使用人口作为优先级
labelLayer.PriorityColumn = "POPULATION";

// 自定义优先级委托
labelLayer.GetPriorityDelegate = (row) =>
{
    if (row["TYPE"]?.ToString() == "Capital")
        return 100;
    if (row["TYPE"]?.ToString() == "City")
        return 50;
    return 10;
};

5.3.5 标注旋转

// 使用字段控制旋转
labelLayer.RotationColumn = "ANGLE";

// 自定义旋转委托
labelLayer.GetRotationDelegate = (row) =>
{
    // 根据线的方向计算旋转角度
    if (row.Geometry is LineString line)
    {
        var start = line.StartPoint.Coordinate;
        var end = line.EndPoint.Coordinate;
        double angle = Math.Atan2(end.Y - start.Y, end.X - start.X);
        return angle * 180 / Math.PI;
    }
    return 0;
};

5.3.6 多部分几何的标注行为

// 设置多部分几何的标注方式
labelLayer.MultipartGeometryBehaviour = 
    LabelLayer.MultipartGeometryBehaviourEnum.All;        // 标注所有部分
    LabelLayer.MultipartGeometryBehaviourEnum.First;      // 只标注第一个
    LabelLayer.MultipartGeometryBehaviourEnum.Largest;    // 标注最大的
    LabelLayer.MultipartGeometryBehaviourEnum.CommonCenter; // 标注共同中心

5.4 TileLayer 瓦片图层

5.4.1 使用 BruTile

// 安装 NuGet 包
// Install-Package SharpMap.Layers.BruTile

using BruTile;
using BruTile.Web;
using SharpMap.Layers;

// 创建 OpenStreetMap 瓦片源
var osmTileSource = new HttpTileSource(
    new GlobalSphericalMercator(),
    "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
    new[] { "a", "b", "c" },
    "OSM");

// 创建瓦片图层
var tileLayer = new TileLayer(osmTileSource, "OpenStreetMap");

// 添加到背景图层
map.BackgroundLayer.Add(tileLayer);

5.4.2 常用瓦片源

// OpenStreetMap
var osmSource = new HttpTileSource(
    new GlobalSphericalMercator(),
    "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
    new[] { "a", "b", "c" },
    "OSM");

// 天地图(需要申请 key)
var tiandituSource = new HttpTileSource(
    new GlobalSphericalMercator(),
    "https://t{s}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=YOUR_KEY",
    new[] { "0", "1", "2", "3", "4", "5", "6", "7" },
    "Tianditu");

// ArcGIS Online
var arcgisSource = new HttpTileSource(
    new GlobalSphericalMercator(),
    "https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
    null,
    "ArcGIS");

// 创建图层
var osmLayer = new TileLayer(osmSource, "OpenStreetMap");
var tiandituLayer = new TileLayer(tiandituSource, "天地图");
var arcgisLayer = new TileLayer(arcgisSource, "ArcGIS Online");

5.4.3 异步瓦片加载

// 使用 TileAsyncLayer 异步加载瓦片
var asyncTileLayer = new TileAsyncLayer(osmTileSource, "Async OSM");

// 设置缓存
asyncTileLayer.TileFetcher.AsyncMode = AsyncMode.Async;

// 添加到地图
map.BackgroundLayer.Add(asyncTileLayer);

5.4.4 瓦片缓存

using BruTile.Cache;

// 创建文件缓存
var fileCache = new FileCache(@"C:\TileCache", "png");

// 创建内存缓存
var memoryCache = new MemoryCache<byte[]>(100, 200);  // 最小100,最大200个瓦片

// 使用缓存的瓦片源
var cachedTileSource = new CachedTileSource(osmTileSource, fileCache);

// 创建图层
var cachedTileLayer = new TileLayer(cachedTileSource, "Cached OSM");

5.5 WmsLayer WMS 服务图层

5.5.1 基本使用

using SharpMap.Layers;

// 创建 WMS 图层
var wmsLayer = new WmsLayer("WMS Layer", "http://wms-service-url/wms");

// 设置 WMS 参数
wmsLayer.AddLayer("layer_name");
wmsLayer.SetImageFormat("image/png");
wmsLayer.SRID = 4326;
wmsLayer.Transparent = true;

// 添加到地图
map.Layers.Add(wmsLayer);

5.5.2 WMS 客户端配置

using SharpMap.Web.Wms;

// 获取 WMS 能力文档
var wmsClient = new Client("http://wms-service-url/wms");

// 获取可用图层
foreach (var layer in wmsClient.Layers)
{
    Console.WriteLine($"图层名称:{layer.Name}");
    Console.WriteLine($"图层标题:{layer.Title}");
    Console.WriteLine($"可查询:{layer.Queryable}");
}

// 获取支持的格式
foreach (var format in wmsClient.GetMapFormats)
{
    Console.WriteLine($"支持格式:{format}");
}

// 获取支持的坐标系
foreach (var crs in wmsClient.CRS)
{
    Console.WriteLine($"坐标系:{crs}");
}

5.5.3 WMS 高级配置

// 创建 WMS 图层
var wmsLayer = new WmsLayer("GeoServer WMS", "http://localhost:8080/geoserver/wms");

// 添加多个图层
wmsLayer.AddLayer("topp:states");
wmsLayer.AddLayer("topp:roads");

// 设置样式
wmsLayer.AddStyle("population");

// 设置透明度
wmsLayer.Transparent = true;
wmsLayer.BgColor = Color.Transparent;

// 设置输出格式
wmsLayer.SetImageFormat("image/png");

// 设置版本
wmsLayer.WmsVersion = "1.3.0";

// 设置超时
wmsLayer.TimeOut = 10000;  // 毫秒

// 设置代理
wmsLayer.Proxy = new WebProxy("http://proxy:8080");

// 设置认证
wmsLayer.Credentials = new NetworkCredential("user", "password");

5.6 GdalRasterLayer 栅格图层

5.6.1 基本使用

// 需要安装 SharpMap.Extensions
using SharpMap.Layers;

// 创建栅格图层
var rasterLayer = new GdalRasterLayer("Satellite", "satellite.tif");

// 添加到地图
map.Layers.Add(rasterLayer);

5.6.2 栅格样式设置

// 设置透明度
rasterLayer.Transparency = 0.5f;  // 50% 透明

// 设置透明色
rasterLayer.TransparentColor = Color.White;

// 设置 NoData 值的显示颜色
rasterLayer.NoDataInitColor = Color.Transparent;

// 设置颜色映射
rasterLayer.ColorCorrect = true;

5.6.3 栅格投影转换

using ProjNet.CoordinateSystems;
using ProjNet.CoordinateSystems.Transformations;

// 创建坐标转换
var ctFactory = new CoordinateTransformationFactory();
var csFactory = new CoordinateSystemFactory();

// 定义源和目标坐标系
var sourceCS = GeographicCoordinateSystem.WGS84;
var targetCS = csFactory.CreateFromWkt(webMercatorWkt);

// 创建转换
var transform = ctFactory.CreateFromCoordinateSystems(sourceCS, targetCS);

// 应用到栅格图层
rasterLayer.CoordinateTransformation = transform;

5.7 LayerGroup 图层组

5.7.1 创建图层组

// 创建图层组
var layerGroup = new LayerGroup("Base Layers");

// 添加图层到组
layerGroup.Layers.Add(polygonLayer);
layerGroup.Layers.Add(lineLayer);
layerGroup.Layers.Add(pointLayer);

// 添加图层组到地图
map.Layers.Add(layerGroup);

5.7.2 图层组控制

// 统一控制图层组的显示/隐藏
layerGroup.Enabled = true;

// 设置图层组的可见比例尺
layerGroup.MinVisible = 1000;
layerGroup.MaxVisible = 1000000;

// 遍历图层组
foreach (var layer in layerGroup.Layers)
{
    Console.WriteLine($"子图层:{layer.LayerName}");
}

5.8 图层管理

5.8.1 图层集合操作

// 添加图层
map.Layers.Add(layer);

// 插入图层到指定位置
map.Layers.Insert(0, layer);  // 插入到底部

// 移除图层
map.Layers.Remove(layer);
map.Layers.RemoveAt(0);

// 清空图层
map.Layers.Clear();

// 获取图层数量
int count = map.Layers.Count;

// 按索引访问
var firstLayer = map.Layers[0];

// 按名称查找
var layer = map.Layers.FirstOrDefault(l => l.LayerName == "States");

// 检查图层是否存在
bool exists = map.Layers.Any(l => l.LayerName == "States");

5.8.2 图层顺序调整

public static class LayerExtensions
{
    /// <summary>
    /// 上移图层
    /// </summary>
    public static void MoveUp(this LayerCollection layers, ILayer layer)
    {
        int index = layers.IndexOf(layer);
        if (index > 0)
        {
            layers.Remove(layer);
            layers.Insert(index - 1, layer);
        }
    }
    
    /// <summary>
    /// 下移图层
    /// </summary>
    public static void MoveDown(this LayerCollection layers, ILayer layer)
    {
        int index = layers.IndexOf(layer);
        if (index < layers.Count - 1)
        {
            layers.Remove(layer);
            layers.Insert(index + 1, layer);
        }
    }
    
    /// <summary>
    /// 移到顶部
    /// </summary>
    public static void MoveToTop(this LayerCollection layers, ILayer layer)
    {
        layers.Remove(layer);
        layers.Add(layer);
    }
    
    /// <summary>
    /// 移到底部
    /// </summary>
    public static void MoveToBottom(this LayerCollection layers, ILayer layer)
    {
        layers.Remove(layer);
        layers.Insert(0, layer);
    }
}

5.8.3 图层管理器实现

public class LayerManager
{
    private readonly Map _map;
    
    public LayerManager(Map map)
    {
        _map = map;
    }
    
    /// <summary>
    /// 添加矢量图层
    /// </summary>
    public VectorLayer AddVectorLayer(string name, string shapefile, VectorStyle style = null)
    {
        var layer = new VectorLayer(name);
        layer.DataSource = new ShapeFile(shapefile, true);
        layer.Style = style ?? new VectorStyle
        {
            Fill = new SolidBrush(Color.LightGreen),
            Outline = new Pen(Color.DarkGreen, 1),
            EnableOutline = true
        };
        
        _map.Layers.Add(layer);
        return layer;
    }
    
    /// <summary>
    /// 添加标注图层
    /// </summary>
    public LabelLayer AddLabelLayer(string name, VectorLayer baseLayer, string labelColumn)
    {
        var labelLayer = new LabelLayer(name);
        labelLayer.DataSource = baseLayer.DataSource;
        labelLayer.LabelColumn = labelColumn;
        labelLayer.Style = new LabelStyle
        {
            Font = new Font("Arial", 10),
            ForeColor = Color.Black,
            CollisionDetection = true
        };
        
        _map.Layers.Add(labelLayer);
        return labelLayer;
    }
    
    /// <summary>
    /// 添加瓦片底图
    /// </summary>
    public TileLayer AddTileLayer(string name, ITileSource tileSource)
    {
        var layer = new TileLayer(tileSource, name);
        _map.BackgroundLayer.Add(layer);
        return layer;
    }
    
    /// <summary>
    /// 获取图层
    /// </summary>
    public ILayer GetLayer(string name)
    {
        return _map.Layers.FirstOrDefault(l => l.LayerName == name) ??
               _map.BackgroundLayer.FirstOrDefault(l => l.LayerName == name);
    }
    
    /// <summary>
    /// 切换图层可见性
    /// </summary>
    public void ToggleLayerVisibility(string name)
    {
        var layer = GetLayer(name);
        if (layer != null)
        {
            layer.Enabled = !layer.Enabled;
        }
    }
    
    /// <summary>
    /// 缩放到图层
    /// </summary>
    public void ZoomToLayer(string name)
    {
        var layer = GetLayer(name);
        if (layer != null)
        {
            _map.ZoomToBox(layer.Envelope);
        }
    }
    
    /// <summary>
    /// 获取所有图层信息
    /// </summary>
    public IEnumerable<LayerInfo> GetLayerInfos()
    {
        var infos = new List<LayerInfo>();
        
        // 背景图层
        foreach (var layer in _map.BackgroundLayer)
        {
            infos.Add(new LayerInfo
            {
                Name = layer.LayerName,
                Type = layer.GetType().Name,
                Enabled = layer.Enabled,
                IsBackground = true
            });
        }
        
        // 普通图层
        foreach (var layer in _map.Layers)
        {
            infos.Add(new LayerInfo
            {
                Name = layer.LayerName,
                Type = layer.GetType().Name,
                Enabled = layer.Enabled,
                IsBackground = false
            });
        }
        
        return infos;
    }
}

public class LayerInfo
{
    public string Name { get; set; }
    public string Type { get; set; }
    public bool Enabled { get; set; }
    public bool IsBackground { get; set; }
}

5.9 本章小结

本章详细介绍了 SharpMap 的图层系统:

  1. 图层类型:了解了 VectorLayer、LabelLayer、TileLayer、WmsLayer、GdalRasterLayer 等图层类型
  2. VectorLayer:掌握了矢量图层的样式设置和空间查询
  3. LabelLayer:学习了标注图层的配置和动态标注
  4. TileLayer:了解了瓦片图层和常用瓦片源
  5. WmsLayer:掌握了 WMS 服务图层的使用
  6. GdalRasterLayer:学习了栅格图层的基本操作
  7. 图层管理:了解了图层集合操作和图层管理器实现

5.10 参考资源


下一章预告:第06章将详细介绍 SharpMap 的数据提供者,包括各种数据源的访问方法和自定义数据提供者的实现。

posted @ 2026-01-08 14:09  我才是银古  阅读(22)  评论(0)    收藏  举报