第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 的图层系统:
- 图层类型:了解了 VectorLayer、LabelLayer、TileLayer、WmsLayer、GdalRasterLayer 等图层类型
- VectorLayer:掌握了矢量图层的样式设置和空间查询
- LabelLayer:学习了标注图层的配置和动态标注
- TileLayer:了解了瓦片图层和常用瓦片源
- WmsLayer:掌握了 WMS 服务图层的使用
- GdalRasterLayer:学习了栅格图层的基本操作
- 图层管理:了解了图层集合操作和图层管理器实现
5.10 参考资源
下一章预告:第06章将详细介绍 SharpMap 的数据提供者,包括各种数据源的访问方法和自定义数据提供者的实现。

浙公网安备 33010602011771号