当前位置: 首页 > news >正文

第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 的综合应用:

  1. 地图浏览器:基本的地图浏览和查询功能
  2. 专题地图:分级色彩地图制作
  3. 实时定位:车辆/人员实时追踪系统
  4. Web 服务:WMS/TMS 地图服务
  5. 空间分析:缓冲区、叠加、最近邻分析

这些案例涵盖了桌面应用和 Web 服务的主要场景,可以作为实际项目开发的参考。

17.7 参考资源

  • SharpMap GitHub 示例
  • SharpMap Wiki
  • GIS Stack Exchange

教程总结:本教程系统地介绍了 SharpMap 的各个方面,从基础概念到高级应用,希望能够帮助读者快速掌握 SharpMap 的使用方法,在实际项目中灵活运用。


← 上一章目录
http://www.jsqmd.com/news/327331/

相关文章:

  • 文明6 MOD制作入门:解密官方阿兹特克配置文件
  • 《文明6》XML建筑文件全标签解析:从代码到游戏的完整指南
  • 第03章 - 核心架构与组件设计
  • 药店药品管理系统的设计与实现开题报告
  • 文明6 Mod制作核心组件关系解密:从XML到游戏的奇幻漂流
  • 《Foundation 开关:深度解析其原理与应用》
  • 药膳食堂点餐系统的设计与实现 开题报告
  • 开题报告+基于Python的家庭安防监控系统设计与实现
  • 选择(Selectable)
  • Java语言提供了八种基本类型。六种数字类型【函数不可123】
  • 开题报告_基于SSM的校园报修管理系统的设计与实现
  • 开题报告_基于Vue框架的影院购票APP的设计与实现
  • 产品经理案例分析(二):电商产品立项:从 0 到 1 启动前,这 5 件事必须想透
  • 开题报告+ 基于Android的运动会管理APP设计与实现)
  • 【易经系列】六五:黄裳,元吉。
  • 【易经系列】上六:龙战于野,其血玄黄。
  • [LCD Monitor] 液晶显示器超频设置方法
  • [特殊字符]_可扩展性架构设计:从单体到微服务的性能演进[20260131140509]
  • foobar2000 v2.25.6 汉化版
  • 算法:二叉树最大路径和
  • 社会网络仿真软件:NodeXL_(14).社会网络理论在NodeXL中的实现
  • 百亿美元赌注变数,AI军备竞赛迎来转折点?
  • 显示器(LCD) 屏幕故障排除方式 - 黑屏(电源有亮灯/不亮灯)
  • 从0到1,快速训练并使用YOLO模型
  • C++-集群聊天室(2):muduo网络库
  • malloc底层实现
  • abc443
  • 社会网络仿真软件:NodeXL_(14).案例研究:NodeXL在社会科学研究中的应用
  • 信号处理仿真:语音信号处理_(10).回声消除技术
  • 基于Android的在线音乐个性化推荐APP的设计与实现_53084988