第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 的扩展开发:

  1. GDAL 扩展:栅格数据和 OGR 数据支持
  2. BruTile 扩展:自定义瓦片源和缓存
  3. NTS 集成:高级几何操作
  4. ProjNet 扩展:坐标系统服务
  5. 自定义提供者:实时数据和数据库数据
  6. 自定义图层:热力图和轨迹图层
  7. 插件架构:可扩展的插件系统

下一章预告:第16章将介绍性能优化与最佳实践。

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