第17章-实战案例与综合应用
第17章:实战案例与综合应用
17.1 案例一:地图浏览器
17.1.1 功能需求
- 加载多种数据格式(Shapefile、GeoJSON)
- 支持图层管理(显示/隐藏、排序)
- 基本地图操作(缩放、平移、查询)
- 要素信息查询
- 地图导出
17.1.2 核心代码
public class MapBrowser
{
private readonly Map _map;
private readonly MapBox _mapBox;
private readonly HighlightLayer _highlightLayer;
public MapBrowser(MapBox mapBox)
{
_mapBox = mapBox;
_map = new Map(mapBox.Size);
_map.BackColor = Color.White;
_highlightLayer = new HighlightLayer(_map);
_mapBox.Map = _map;
_mapBox.MouseClick += OnMapClick;
}
public void LoadShapefile(string filePath)
{
var layerName = Path.GetFileNameWithoutExtension(filePath);
var layer = new VectorLayer(layerName);
layer.DataSource = new ShapeFile(filePath, true, true);
layer.Style = CreateRandomStyle();
_map.Layers.Add(layer);
_map.ZoomToExtents();
_mapBox.Refresh();
}
public void LoadGeoJson(string filePath)
{
var layerName = Path.GetFileNameWithoutExtension(filePath);
var layer = new VectorLayer(layerName);
layer.DataSource = new Ogr(filePath);
layer.Style = CreateRandomStyle();
_map.Layers.Add(layer);
_map.ZoomToExtents();
_mapBox.Refresh();
}
public void QueryFeature(PointF screenPoint)
{
var worldPoint = _map.ImageToWorld(screenPoint);
var tolerance = _map.PixelWidth * 5;
var envelope = new Envelope(
worldPoint.X - tolerance, worldPoint.X + tolerance,
worldPoint.Y - tolerance, worldPoint.Y + tolerance);
foreach (var layer in _map.Layers.OfType<VectorLayer>())
{
var ds = new FeatureDataSet();
layer.DataSource.ExecuteIntersectionQuery(envelope, ds);
if (ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
{
var feature = ds.Tables[0].Rows[0] as FeatureDataRow;
_highlightLayer.Highlight(feature.Geometry);
ShowFeatureInfo(feature);
_mapBox.Refresh();
return;
}
}
}
public void ExportMap(string filePath, ImageFormat format)
{
using (var image = _map.GetMap())
{
image.Save(filePath, format);
}
}
private VectorStyle CreateRandomStyle()
{
var random = new Random();
return new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(
150,
random.Next(256),
random.Next(256),
random.Next(256))),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
};
}
}
17.2 案例二:专题地图制作
17.2.1 功能需求
- 加载行政区划数据
- 根据人口数据创建分级色彩地图
- 添加标注
- 添加图例和比例尺
17.2.2 核心代码
public class ThematicMap
{
private readonly Map _map;
public ThematicMap(int width, int height)
{
_map = new Map(new Size(width, height));
_map.BackColor = Color.White;
}
public void CreatePopulationMap(string dataPath, string populationField)
{
// 1. 加载数据
var layer = new VectorLayer("Population");
var provider = new ShapeFile(dataPath, true);
layer.DataSource = provider;
// 2. 创建分级主题
var theme = CreateGraduatedTheme(provider, populationField);
layer.Theme = theme;
_map.Layers.Add(layer);
// 3. 添加标注
var labelLayer = new LabelLayer("Labels");
labelLayer.DataSource = provider;
labelLayer.LabelColumn = "NAME";
labelLayer.Style = new LabelStyle
{
Font = new Font("Arial", 8),
ForeColor = Color.Black,
Halo = new Pen(Color.White, 2),
CollisionDetection = true
};
_map.Layers.Add(labelLayer);
_map.ZoomToExtents();
}
private ITheme CreateGraduatedTheme(IProvider provider, string field)
{
// 计算统计信息
var stats = CalculateStatistics(provider, field);
// 使用等间距分类
var breaks = CalculateEqualInterval(stats.Min, stats.Max, 5);
// 创建分级主题
var theme = new ClassBreaksTheme(field);
var colors = new[]
{
Color.FromArgb(255, 255, 178),
Color.FromArgb(254, 204, 92),
Color.FromArgb(253, 141, 60),
Color.FromArgb(240, 59, 32),
Color.FromArgb(189, 0, 38)
};
for (int i = 0; i < breaks.Length - 1; i++)
{
theme.AddBreak(breaks[i], breaks[i + 1], new VectorStyle
{
Fill = new SolidBrush(colors[i]),
Outline = new Pen(Color.Gray, 0.5f),
EnableOutline = true
});
}
return theme;
}
public Image RenderWithLegend()
{
var mapImage = _map.GetMap();
// 创建带图例的图片
var finalImage = new Bitmap(_map.Size.Width + 200, _map.Size.Height);
using (var g = Graphics.FromImage(finalImage))
{
g.Clear(Color.White);
// 绘制地图
g.DrawImage(mapImage, 0, 0);
// 绘制图例
DrawLegend(g, _map.Size.Width + 10, 10);
// 绘制比例尺
DrawScaleBar(g, 10, _map.Size.Height - 40);
}
return finalImage;
}
private void DrawLegend(Graphics g, int x, int y)
{
g.DrawString("人口密度 (人/km²)", new Font("Arial", 10, FontStyle.Bold),
Brushes.Black, x, y);
var colors = new[]
{
(Color.FromArgb(255, 255, 178), "< 100"),
(Color.FromArgb(254, 204, 92), "100 - 500"),
(Color.FromArgb(253, 141, 60), "500 - 1000"),
(Color.FromArgb(240, 59, 32), "1000 - 2000"),
(Color.FromArgb(189, 0, 38), "> 2000")
};
int itemY = y + 25;
foreach (var (color, label) in colors)
{
g.FillRectangle(new SolidBrush(color), x, itemY, 20, 15);
g.DrawRectangle(Pens.Black, x, itemY, 20, 15);
g.DrawString(label, new Font("Arial", 9), Brushes.Black, x + 25, itemY);
itemY += 20;
}
}
}
17.3 案例三:实时定位系统
17.3.1 功能需求
- 显示底图
- 实时显示车辆/人员位置
- 历史轨迹回放
- 电子围栏告警
17.3.2 核心代码
public class RealtimeTrackingSystem
{
private readonly Map _map;
private readonly MapBox _mapBox;
private readonly RealtimeGpsProvider _gpsProvider;
private readonly TrackLayer _trackLayer;
private readonly GeofenceManager _geofenceManager;
private readonly Timer _updateTimer;
public event Action<string, GpsPoint> GeofenceAlert;
public RealtimeTrackingSystem(MapBox mapBox)
{
_mapBox = mapBox;
_map = new Map(mapBox.Size);
InitializeBaseLayers();
InitializeTrackingLayers();
_geofenceManager = new GeofenceManager();
_updateTimer = new Timer(1000); // 1秒更新
_updateTimer.Elapsed += OnUpdateTimer;
_mapBox.Map = _map;
}
private void InitializeBaseLayers()
{
// 添加瓦片底图
var osmSource = KnownTileSources.Create(KnownTileSource.OpenStreetMap);
var tileLayer = new TileLayer(osmSource, "OpenStreetMap");
_map.BackgroundLayer.Add(tileLayer);
}
private void InitializeTrackingLayers()
{
// GPS 点图层(动态)
_gpsProvider = new RealtimeGpsProvider(() => GetCurrentPositions());
var gpsLayer = new VectorLayer("GPS Points", _gpsProvider);
gpsLayer.Style = new VectorStyle
{
Symbol = Image.FromFile("car_icon.png"),
SymbolScale = 0.5f
};
_map.VariableLayers.Add(gpsLayer);
// 轨迹图层
_trackLayer = new TrackLayer("Tracks");
_map.Layers.Add(_trackLayer);
// 电子围栏图层
var geofenceLayer = new VectorLayer("Geofences");
geofenceLayer.Style = new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(50, 255, 0, 0)),
Outline = new Pen(Color.Red, 2),
EnableOutline = true
};
_map.Layers.Add(geofenceLayer);
}
public void AddGeofence(string name, Polygon boundary)
{
_geofenceManager.AddGeofence(name, boundary);
}
private void OnUpdateTimer(object sender, ElapsedEventArgs e)
{
// 更新位置
var positions = GetCurrentPositions();
foreach (var pos in positions)
{
// 添加到轨迹
_trackLayer.AddPoint(new TrackPoint
{
VehicleId = pos.VehicleId,
Longitude = pos.Longitude,
Latitude = pos.Latitude,
Timestamp = pos.Timestamp
});
// 检查电子围栏
var point = new GeometryFactory().CreatePoint(
new Coordinate(pos.Longitude, pos.Latitude));
var violations = _geofenceManager.CheckViolations(point);
foreach (var violation in violations)
{
GeofenceAlert?.Invoke(violation, pos);
}
}
// 刷新地图
_mapBox.BeginInvoke((Action)(() => _mapBox.Refresh()));
}
public void StartTracking()
{
_updateTimer.Start();
}
public void StopTracking()
{
_updateTimer.Stop();
}
public void PlaybackTrack(string vehicleId, DateTime start, DateTime end)
{
var track = GetHistoricalTrack(vehicleId, start, end);
_trackLayer.SetTrack(track);
_mapBox.Refresh();
}
}
17.4 案例四:Web 地图服务
17.4.1 功能需求
- 提供 WMS/TMS 服务
- 支持多图层
- 要素查询 API
- 缓存机制
17.4.2 完整实现
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton<IMapService, MapService>();
services.AddMemoryCache();
services.AddResponseCaching();
}
// MapService.cs
public interface IMapService
{
Map CreateMap(int width, int height, string[] layers = null);
IEnumerable<LayerInfo> GetLayerInfos();
FeatureCollection QueryFeatures(string layer, Envelope envelope);
}
public class MapService : IMapService
{
private readonly string _dataPath;
private readonly Dictionary<string, VectorStyle> _layerStyles;
public MapService(IConfiguration config)
{
_dataPath = config["MapData:Path"];
_layerStyles = new Dictionary<string, VectorStyle>();
LoadLayerConfigurations();
}
public Map CreateMap(int width, int height, string[] layers = null)
{
var map = new Map(new Size(width, height));
map.BackColor = Color.White;
var shapeFiles = Directory.GetFiles(_dataPath, "*.shp");
foreach (var shapeFile in shapeFiles)
{
var layerName = Path.GetFileNameWithoutExtension(shapeFile);
if (layers != null && !layers.Contains(layerName))
continue;
var layer = new VectorLayer(layerName);
layer.DataSource = new ShapeFile(shapeFile, true, true);
layer.Style = _layerStyles.GetValueOrDefault(layerName) ?? GetDefaultStyle();
map.Layers.Add(layer);
}
return map;
}
public FeatureCollection QueryFeatures(string layerName, Envelope envelope)
{
var shapeFile = Path.Combine(_dataPath, $"{layerName}.shp");
if (!File.Exists(shapeFile))
return new FeatureCollection();
var provider = new ShapeFile(shapeFile, true);
var ds = new FeatureDataSet();
provider.ExecuteIntersectionQuery(envelope, ds);
return ConvertToGeoJson(ds);
}
}
// TmsController.cs
[ApiController]
[Route("tms/1.0.0/{layer}")]
public class TmsController : ControllerBase
{
private readonly IMapService _mapService;
private readonly IMemoryCache _cache;
[HttpGet("{z:int}/{x:int}/{y:int}.png")]
[ResponseCache(Duration = 3600)]
public async Task<IActionResult> GetTile(string layer, int z, int x, int y)
{
var cacheKey = $"tile_{layer}_{z}_{x}_{y}";
if (!_cache.TryGetValue(cacheKey, out byte[] tileBytes))
{
var envelope = TileToEnvelope(x, y, z);
var map = _mapService.CreateMap(256, 256, new[] { layer });
map.ZoomToBox(envelope);
using (var image = map.GetMap())
using (var stream = new MemoryStream())
{
image.Save(stream, ImageFormat.Png);
tileBytes = stream.ToArray();
}
_cache.Set(cacheKey, tileBytes, TimeSpan.FromHours(1));
}
return File(tileBytes, "image/png");
}
}
17.5 案例五:空间分析工具
17.5.1 功能需求
- 缓冲区分析
- 叠加分析
- 最近邻分析
- 结果可视化
17.5.2 核心代码
public class SpatialAnalysisTool
{
private readonly Map _map;
private readonly VectorLayer _resultLayer;
public SpatialAnalysisTool(Map map)
{
_map = map;
_resultLayer = new VectorLayer("Analysis Result");
_resultLayer.Style = new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(100, 255, 0, 0)),
Outline = new Pen(Color.Red, 2),
EnableOutline = true
};
_map.Layers.Add(_resultLayer);
}
public Geometry BufferAnalysis(string layerName, double distance)
{
var layer = _map.Layers.FirstOrDefault(l => l.LayerName == layerName) as VectorLayer;
if (layer == null)
return null;
var geometries = layer.DataSource.GetGeometriesInView(layer.Envelope);
var buffers = geometries.Select(g => g.Buffer(distance)).ToList();
var union = CascadedPolygonUnion.Union(buffers);
_resultLayer.DataSource = new GeometryProvider(new[] { union });
return union;
}
public Geometry IntersectionAnalysis(string layer1Name, string layer2Name)
{
var layer1 = GetLayer(layer1Name);
var layer2 = GetLayer(layer2Name);
var geom1 = UnionAllGeometries(layer1);
var geom2 = UnionAllGeometries(layer2);
var intersection = geom1.Intersection(geom2);
_resultLayer.DataSource = new GeometryProvider(new[] { intersection });
return intersection;
}
public IEnumerable<(FeatureDataRow source, FeatureDataRow nearest, double distance)>
NearestNeighborAnalysis(string sourceLayer, string targetLayer)
{
var sourceFeatures = GetFeatures(sourceLayer);
var targetFeatures = GetFeatures(targetLayer);
var index = new STRtree<FeatureDataRow>();
foreach (var target in targetFeatures)
{
index.Insert(target.Geometry.EnvelopeInternal, target);
}
index.Build();
var results = new List<(FeatureDataRow, FeatureDataRow, double)>();
foreach (var source in sourceFeatures)
{
FeatureDataRow nearest = null;
double minDistance = double.MaxValue;
var envelope = source.Geometry.EnvelopeInternal.Copy();
envelope.ExpandBy(1); // 初始搜索范围
var candidates = index.Query(envelope);
foreach (var candidate in candidates)
{
var dist = source.Geometry.Distance(candidate.Geometry);
if (dist < minDistance)
{
minDistance = dist;
nearest = candidate;
}
}
results.Add((source, nearest, minDistance));
}
return results;
}
}
17.6 本章小结
本章通过五个实战案例展示了 SharpMap 的综合应用:
- 地图浏览器:基本的地图浏览和查询功能
- 专题地图:分级色彩地图制作
- 实时定位:车辆/人员实时追踪系统
- Web 服务:WMS/TMS 地图服务
- 空间分析:缓冲区、叠加、最近邻分析
这些案例涵盖了桌面应用和 Web 服务的主要场景,可以作为实际项目开发的参考。
17.7 参考资源
教程总结:本教程系统地介绍了 SharpMap 的各个方面,从基础概念到高级应用,希望能够帮助读者快速掌握 SharpMap 的使用方法,在实际项目中灵活运用。

浙公网安备 33010602011771号