第15章-扩展开发与插件集成
第15章:扩展开发与插件集成
15.1 SharpMap 扩展概述
SharpMap 提供了多种扩展机制:
- 数据提供者扩展:支持新的数据格式
- 图层扩展:自定义图层渲染
- 样式扩展:自定义符号和渲染
- 第三方库集成:GDAL、BruTile、ProjNet 等
15.2 GDAL 扩展
15.2.1 安装配置
Install-Package SharpMap.Extensions
Install-Package Gdal.Native
15.2.2 栅格图层
using SharpMap.Layers;
// 配置 GDAL
GdalConfiguration.ConfigureGdal();
// 创建 GDAL 栅格图层
var rasterLayer = new GdalRasterLayer("Satellite", "satellite.tif");
rasterLayer.Transparency = 0.8f;
map.Layers.Add(rasterLayer);
15.2.3 OGR 数据提供者
using SharpMap.Data.Providers;
// 支持 GeoJSON
var geoJsonProvider = new Ogr("data.geojson");
// 支持 KML
var kmlProvider = new Ogr("data.kml");
// 支持 FileGDB
var fgdbProvider = new Ogr("database.gdb", "layer_name");
var layer = new VectorLayer("GeoJSON Data", geoJsonProvider);
15.3 BruTile 扩展
15.3.1 自定义瓦片源
using BruTile;
using BruTile.Web;
public class CustomTileSource : HttpTileSource
{
public CustomTileSource() : base(
new GlobalSphericalMercator(0, 18),
GetUrlFormatter(),
GetServerNodes(),
"CustomSource")
{
}
private static Func<Uri, byte[]> GetUrlFormatter()
{
return (uri) =>
{
using (var client = new WebClient())
{
client.Headers.Add("User-Agent", "SharpMap/1.0");
return client.DownloadData(uri);
}
};
}
private static IEnumerable<string> GetServerNodes()
{
return new[] { "a", "b", "c" };
}
}
15.3.2 瓦片缓存策略
public class TwoLevelCache : ITileCache<byte[]>
{
private readonly MemoryCache<byte[]> _memoryCache;
private readonly FileCache _fileCache;
public TwoLevelCache(string cachePath, int memoryCacheSize = 100)
{
_memoryCache = new MemoryCache<byte[]>(memoryCacheSize, memoryCacheSize * 2);
_fileCache = new FileCache(cachePath, "png");
}
public void Add(TileIndex index, byte[] tile)
{
_memoryCache.Add(index, tile);
_fileCache.Add(index, tile);
}
public byte[] Find(TileIndex index)
{
// 先查内存
var tile = _memoryCache.Find(index);
if (tile != null)
return tile;
// 再查文件
tile = _fileCache.Find(index);
if (tile != null)
{
_memoryCache.Add(index, tile); // 加载到内存
}
return tile;
}
public void Remove(TileIndex index)
{
_memoryCache.Remove(index);
_fileCache.Remove(index);
}
}
15.4 NetTopologySuite 集成
15.4.1 几何操作
using NetTopologySuite.Geometries;
using NetTopologySuite.Operation.Buffer;
using NetTopologySuite.Operation.Union;
// 高级缓冲区
var bufferParams = new BufferParameters
{
EndCapStyle = EndCapStyle.Round,
JoinStyle = JoinStyle.Round,
QuadrantSegments = 16
};
var buffer = BufferOp.Buffer(geometry, distance, bufferParams);
// 高性能合并
var geometries = new List<Geometry> { poly1, poly2, poly3 };
var union = CascadedPolygonUnion.Union(geometries);
// 简化
using NetTopologySuite.Simplify;
var simplified = TopologyPreservingSimplifier.Simplify(geometry, tolerance);
15.4.2 空间索引
using NetTopologySuite.Index.Strtree;
using NetTopologySuite.Index.KdTree;
// STRtree(适合静态数据)
var strTree = new STRtree<string>();
strTree.Insert(geometry.EnvelopeInternal, "feature1");
strTree.Build();
// KdTree(适合点数据)
var kdTree = new KdTree<string>();
foreach (var point in points)
{
kdTree.Insert(point.Coordinate, "point");
}
15.5 ProjNet 扩展
15.5.1 坐标系统工厂
using ProjNet.CoordinateSystems;
using ProjNet.CoordinateSystems.Transformations;
public class CoordinateSystemService
{
private readonly Dictionary<int, ICoordinateSystem> _systems;
private readonly CoordinateSystemFactory _factory;
private readonly CoordinateTransformationFactory _transformFactory;
public CoordinateSystemService()
{
_systems = new Dictionary<int, ICoordinateSystem>();
_factory = new CoordinateSystemFactory();
_transformFactory = new CoordinateTransformationFactory();
LoadCommonSystems();
}
private void LoadCommonSystems()
{
// 从 EPSG 数据库或配置文件加载
_systems[4326] = GeographicCoordinateSystem.WGS84;
_systems[3857] = CreateWebMercator();
// ...
}
public ICoordinateTransformation GetTransformation(int sourceSrid, int targetSrid)
{
var source = _systems[sourceSrid];
var target = _systems[targetSrid];
return _transformFactory.CreateFromCoordinateSystems(source, target);
}
}
15.6 自定义数据提供者
15.6.1 实时数据提供者
public class RealtimeGpsProvider : IProvider
{
private readonly Func<IEnumerable<GpsPoint>> _dataSource;
private readonly GeometryFactory _factory;
public RealtimeGpsProvider(Func<IEnumerable<GpsPoint>> dataSource)
{
_dataSource = dataSource;
_factory = new GeometryFactory();
}
public Collection<Geometry> GetGeometriesInView(Envelope envelope)
{
var points = _dataSource()
.Where(p => envelope.Contains(p.Longitude, p.Latitude))
.Select(p => _factory.CreatePoint(new Coordinate(p.Longitude, p.Latitude)))
.Cast<Geometry>()
.ToList();
return new Collection<Geometry>(points);
}
// 其他接口方法实现...
}
// 使用
var gpsProvider = new RealtimeGpsProvider(() => GetGpsPositions());
var gpsLayer = new VectorLayer("GPS", gpsProvider);
map.VariableLayers.Add(gpsLayer); // 动态图层
15.6.2 数据库提供者
public class CustomDbProvider : IProvider
{
private readonly string _connectionString;
private readonly string _tableName;
private readonly string _geometryColumn;
public void ExecuteIntersectionQuery(Envelope envelope, FeatureDataSet ds)
{
using (var conn = new SqlConnection(_connectionString))
{
conn.Open();
var sql = $@"
SELECT * FROM {_tableName}
WHERE {_geometryColumn}.STIntersects(
geometry::STGeomFromText('POLYGON(({envelope.MinX} {envelope.MinY},
{envelope.MaxX} {envelope.MinY}, {envelope.MaxX} {envelope.MaxY},
{envelope.MinX} {envelope.MaxY}, {envelope.MinX} {envelope.MinY}))',
{SRID})) = 1";
using (var cmd = new SqlCommand(sql, conn))
using (var reader = cmd.ExecuteReader())
{
var table = CreateFeatureDataTable();
while (reader.Read())
{
var row = table.NewRow() as FeatureDataRow;
// 填充数据...
table.AddRow(row);
}
ds.Tables.Add(table);
}
}
}
}
15.7 自定义图层
15.7.1 热力图图层
public class HeatmapLayer : Layer
{
private readonly IProvider _dataSource;
private readonly int _radius;
private readonly Color[] _gradient;
public HeatmapLayer(string name, IProvider dataSource, int radius = 20)
: base(name)
{
_dataSource = dataSource;
_radius = radius;
_gradient = CreateGradient();
}
public override Envelope Envelope => _dataSource.GetExtents();
public override void Render(Graphics g, Map map)
{
var points = _dataSource.GetGeometriesInView(map.Envelope)
.OfType<Point>()
.Select(p => map.WorldToImage(p.Coordinate))
.ToList();
// 创建热力图
using (var heatmap = new Bitmap(map.Size.Width, map.Size.Height))
{
foreach (var point in points)
{
DrawHeatPoint(heatmap, point, _radius);
}
ApplyGradient(heatmap);
g.DrawImage(heatmap, 0, 0);
}
}
private void DrawHeatPoint(Bitmap bitmap, PointF center, int radius)
{
// 绘制热力点(高斯衰减)
for (int x = -radius; x <= radius; x++)
{
for (int y = -radius; y <= radius; y++)
{
int px = (int)center.X + x;
int py = (int)center.Y + y;
if (px >= 0 && px < bitmap.Width && py >= 0 && py < bitmap.Height)
{
double distance = Math.Sqrt(x * x + y * y);
if (distance <= radius)
{
double intensity = 1 - (distance / radius);
var currentColor = bitmap.GetPixel(px, py);
int newAlpha = Math.Min(255, currentColor.A + (int)(intensity * 50));
bitmap.SetPixel(px, py, Color.FromArgb(newAlpha, 255, 0, 0));
}
}
}
}
}
}
15.7.2 轨迹图层
public class TrackLayer : Layer
{
private readonly List<TrackPoint> _trackPoints;
public TrackLayer(string name) : base(name)
{
_trackPoints = new List<TrackPoint>();
}
public void AddPoint(TrackPoint point)
{
_trackPoints.Add(point);
}
public override void Render(Graphics g, Map map)
{
if (_trackPoints.Count < 2)
return;
var screenPoints = _trackPoints
.Select(p => map.WorldToImage(new Coordinate(p.Longitude, p.Latitude)))
.ToArray();
// 渐变轨迹
for (int i = 1; i < screenPoints.Length; i++)
{
float progress = (float)i / screenPoints.Length;
var color = InterpolateColor(Color.Blue, Color.Red, progress);
using (var pen = new Pen(color, 3))
{
g.DrawLine(pen, screenPoints[i - 1], screenPoints[i]);
}
}
// 绘制终点
var lastPoint = screenPoints.Last();
using (var brush = new SolidBrush(Color.Red))
{
g.FillEllipse(brush, lastPoint.X - 6, lastPoint.Y - 6, 12, 12);
}
}
}
15.8 插件架构
15.8.1 插件接口
public interface IMapPlugin
{
string Name { get; }
string Description { get; }
void Initialize(Map map, MapBox mapBox);
void Dispose();
}
public interface IToolPlugin : IMapPlugin
{
Cursor Cursor { get; }
void OnMouseDown(MouseEventArgs e);
void OnMouseMove(MouseEventArgs e);
void OnMouseUp(MouseEventArgs e);
}
15.8.2 插件管理器
public class PluginManager
{
private readonly List<IMapPlugin> _plugins;
private readonly Map _map;
private readonly MapBox _mapBox;
public PluginManager(Map map, MapBox mapBox)
{
_plugins = new List<IMapPlugin>();
_map = map;
_mapBox = mapBox;
}
public void LoadPlugins(string pluginPath)
{
var dlls = Directory.GetFiles(pluginPath, "*.dll");
foreach (var dll in dlls)
{
try
{
var assembly = Assembly.LoadFrom(dll);
var pluginTypes = assembly.GetTypes()
.Where(t => typeof(IMapPlugin).IsAssignableFrom(t) && !t.IsInterface);
foreach (var type in pluginTypes)
{
var plugin = Activator.CreateInstance(type) as IMapPlugin;
if (plugin != null)
{
plugin.Initialize(_map, _mapBox);
_plugins.Add(plugin);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"加载插件失败: {dll} - {ex.Message}");
}
}
}
public IEnumerable<IMapPlugin> GetPlugins() => _plugins;
public T GetPlugin<T>() where T : IMapPlugin
{
return _plugins.OfType<T>().FirstOrDefault();
}
}
15.9 本章小结
本章介绍了 SharpMap 的扩展开发:
- GDAL 扩展:栅格数据和 OGR 数据支持
- BruTile 扩展:自定义瓦片源和缓存
- NTS 集成:高级几何操作
- ProjNet 扩展:坐标系统服务
- 自定义提供者:实时数据和数据库数据
- 自定义图层:热力图和轨迹图层
- 插件架构:可扩展的插件系统
下一章预告:第16章将介绍性能优化与最佳实践。

浙公网安备 33010602011771号