范明 发表于 2023-6-1 22:46:57

WPF绘制深圳地铁路线图

经常坐地铁,却不知道地铁多少条线路?哪个站下车?今天就带领大家熟悉并绘制深圳地铁路线图。
WPF在绘制矢量图方面有非常强大的优势,利用WPF可以绘制出各种矢量图形,如线,圆,多边形,矩形,及组合图形。今天以绘制深圳地铁路线图为例,简述WPF在图形绘制方面的一些知识,仅供学习分享使用,如有不足之处,还请指正。
 
WPF图形概述


与传统的.NET开发使用GDI+进行绘图不同,WPF拥有自己的一套图形API,绘图为矢量图。绘图可以在任何一种布局控件中完成,wpf会根据容器计算相应坐标。最常用的是Canvas和Grid。基本图形包括以下几个,都是Shaper类的派生类。

[*]Line,直线段,可以设置Stroke
[*]Rectangle,有Stroke也有Fill
[*]Ellipse,椭圆,同上
[*]Polygon,多边形。由多条直线线段围成的闭合区域,同上。
[*]Polyline,折线,不闭合,由多条首尾相接的直线段组成
[*]Path,路径,闭合。可以由若干直线、圆弧、贝塞尔曲线(由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋)组成。很强大。
 
地铁官网效果

 
首先打开深圳地铁官网【https://www.szmc.net/map/】,可查看深圳地铁的路线图,如下所示:

 
获取地铁路线数据

 
通过对地铁官网的网络接口接收数据分析,可以获取地铁数据的原始JSON文件,将原始JSON文件保存到本地,在程序中进行引用,如下所示:

 
构建地铁数据模型

 
在得到shentie.json文件后,通过分析,构建模型类,如下所示:
1 namespace DemoSubway.Models
2 {
3   /// <summary>
4   /// 深圳地铁模型
5   /// </summary>
6   public class ShenTie
7   {
8         
9         public string? Name { get; set; }
10
11         
12         public string? Index { get; set; }
13
14         
15         public SubwayLine[]? SubwayLines { get; set; }
16
17         
18         public string? Obj { get;set; }
19   }
20
21   public class SubwayLine
22   {
23         
24         public St[]? Sites { get; set; }
25
26         
27         public string? LineNumber { get; set; }
28
29         
30         public string? Su { get; set; }
31
32         
33         public string? KName { get; set; }
34
35         
36         public string[]? Circles { get;set; }
37
38         
39         public string? Lo { get; set; }
40
41         
42         public string[]? LinePosition { get; set; }
43
44         
45         public string? Ls { get; set; }
46
47         
48         public string? Color { get; set; }
49
50         
51         public string? La { get; set; }
52
53         
54         public string? X { get; set; }
55
56         
57         public string? Li { get; set; }
58   }
59
60   public class St
61   {
62         
63         public string? Rs { get; set; }
64
65         
66         public string? Udpx { get; set; }
67
68         
69         public string? Su { get; set; }
70
71         
72         public string? Udsu { get; set;}
73
74         
75         public string? Name { get; set;}
76
77         
78         public string? En { get; set; }
79
80         
81         public string? Sid { get; set; }
82
83         
84         public string? Position { get; set; }
85
86         
87         public string? R { get; set; }
88
89         
90         public string? Udsi { get; set; }
91
92         
93         public string? T { get; set;}
94
95         
96         public string? Si { get; set; }
97
98         
99         public string? Sl { get; set;}
100
101         
102         public string? Udli { get; set; }
103
104         
105         public string? Poiid { get; set; }
106
107         
108         public string? Lg { get; set; }
109
110         
111         public string? Sp { get; set; }
112   }
113 } 
解析数据源

 
通过反序列化,将shentie.json文件内容,加载到内存并实例化为ShenTie对象,在此需要用到第三方库【Newtonsoft.Json】,如下所示:

 
绘制地铁路线图

 
地铁路线图在WPF主页面显示,用Grid作为容器【subwayBox】,如下所示:
1 <Window x:Class="DemoSubway.MainWindow"
2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6         xmlns:local="clr-namespace:DemoSubway"
7         mc:Ignorable="d"
8         Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
9
10   <Grid>
11         <Grid.RowDefinitions>
12             <RowDefinition Height="Auto"></RowDefinition>
13             <RowDefinition Height="*"></RowDefinition>
14         </Grid.RowDefinitions>
15         <StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center">
16             <TextBlock x:Name="tbTitle" FontSize="30" HorizontalAlignment="Center"></TextBlock>
17         </StackPanel>
18         <Viewbox Stretch="Fill" Grid.Row="1">
19             <Grid x:Name="subwayBox">
20
21             </Grid>
22         </Viewbox>
23   </Grid>
24 </Window>ShenTie对象创建成功后,就可以获取路线数据,然后创建地铁路线元素,如下所示:
1 private void Window_Loaded(object sender, RoutedEventArgs e)
2 {
3   string jsonFile = "shentie.json";
4   JsonHelper jsonHelper = new JsonHelper();
5   var shentie = jsonHelper.Deserialize<ShenTie>(jsonFile);
6   this.tbTitle.Text = shentie.Name;
7   List<string> lstSites = new List<string>();
8   for(int i = 0; i < shentie.SubwayLines?.Length; i++)
9   {
10         var subwayLine= shentie.SubwayLines;
11         if(subwayLine != null)
12         {
13             //地铁线路
14             var color = ColorTranslator.FromHtml($"#{subwayLine.Color}");//线路颜色
15             var circles = subwayLine.Circles;//线路节点
16             Path line = new Path();
17             PathFigureCollection lineFigures = new PathFigureCollection();
18             PathFigure lineFigure = new PathFigure();
19             lineFigure.IsClosed= false;
20             var start = circles?.Split(" ");//线路起始位置
21             lineFigure.StartPoint = new System.Windows.Point(int.Parse(start), int.Parse(start));
22
23             for (int j= 0;j< circles?.Length;j++)
24             {
25               var circle= circles.Split(" ");
26               LineSegment lineSegment = new LineSegment(new System.Windows.Point(int.Parse(circle), int.Parse(circle)),true);
27               lineFigure.Segments.Add(lineSegment);
28             }
29             lineFigures.Add(lineFigure);
30             line.Data = new PathGeometry(lineFigures, FillRule.Nonzero, null);
31             line.Stroke = new SolidColorBrush(System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B));
32             line.StrokeThickness = 4;
33             this.subwayBox.Children.Add(line);
34             //地铁站点
35             for (int j = 0; j < subwayLine.Sites?.Length; j++)
36             {
37               var site = subwayLine.Sites;
38               if (site != null)
39               {
40                     
41                     //站点标识,圆圈
42                     Path siteCirclePath = new Path();
43                     var sitePosition = site?.Position?.Split(" ");
44                     EllipseGeometry ellipse = new EllipseGeometry();
45                     ellipse.Center = new System.Windows.Point(int.Parse(sitePosition), int.Parse(sitePosition));
46                     ellipse.RadiusX = 4;
47                     ellipse.RadiusY=4;
48                     siteCirclePath.Data=ellipse;
49                     siteCirclePath.Fill = Brushes.White;
50                     siteCirclePath.Stroke = new SolidColorBrush(System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B));
51                     siteCirclePath.Cursor= Cursors.Hand;
52                     siteCirclePath.Focusable = true;
53                     siteCirclePath.Tag = site?.Name;
54                     siteCirclePath.MouseDown += SiteCirclePath_MouseDown;
55                     this.subwayBox.Children.Add(siteCirclePath);
56                     //站点名字
57                     if (lstSites.Contains(site?.Name))
58                     {
59                         continue;//对于交汇站点,只绘制一次
60                     }
61                     //站点名称
62                     Path siteTextPath = new Path();
63                     FormattedText siteContent = new FormattedText(site?.Name,CultureInfo.CurrentCulture,FlowDirection.LeftToRight,new Typeface("Arial"),14,Brushes.Black, 1.25);
64                     var x = int.Parse(sitePosition);
65                     var y = int.Parse(sitePosition);
66                     if (j + 1 < subwayLine.Sites?.Length)
67                     {
68                         //站点位置适当偏移
69                         var next = subwayLine.Sites?.Position?.Split(" ");
70                         var nextx = int.Parse(next);
71                         var nexty = int.Parse(next);
72                         if (x == nextx)
73                         {
74                           x = x + 6;
75                         }
76                         else if (y == nexty)
77                         {
78                           y = y + 6;
79                         }
80                         else
81                         {
82                           x = x + 1;
83                           y = y + 1;
84                         }
85                     }
86                     Geometry geometry = siteContent.BuildGeometry(new System.Windows.Point(x, y));
87                     siteTextPath.Data = geometry;
88                     siteTextPath.Stroke = Brushes.Black;
89                     siteTextPath.Focusable = true;
90                     siteTextPath.Cursor = Cursors.Hand;
91                     siteTextPath.MouseDown += SiteTextPath_MouseDown;
92                     siteTextPath.Tag = site?.Name;
93                     this.subwayBox.Children.Add(siteTextPath);
94                     lstSites.Add(site?.Name);
95               }
96             }
97
98             var kName = subwayLine.KName;//线路名称
99             var linePosition= subwayLine.LinePosition?.Split(" ");
100             if(kName != null)
101             {
102               Path lineNamePath = new Path();
103               FormattedText lineNameText = new FormattedText(kName, CultureInfo.CurrentCulture,FlowDirection.LeftToRight,new Typeface("Arial"),16,Brushes.Black,1.25);
104               var lineX = int.Parse(linePosition);
105               var lineY = int.Parse(linePosition);
106               if (subwayLine.LineNumber == "1")
107               {
108                     lineX = lineX - 10;
109                     lineY = lineY + 20;
110               }
111               Geometry geometry = lineNameText.BuildGeometry(new System.Windows.Point(lineX, lineY));
112               lineNamePath.Data=geometry;
113               lineNamePath.Stroke = new SolidColorBrush(System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B));
114               this.subwayBox.Children.Add(lineNamePath);
115             }
116         }
117   }
118 } 
效果展示

 
本示例效果图如下所示:

 在获取的JSON文件中,有些属性名都是简写,所以在编写示例代码过程中,对有些属性的理解并不准确,需要不断测试优化,绘制出的地铁路线图可能与实际存在稍微的差异,如站点名称,路线名称等内容的位置。
 以上就是本篇文章的全部内容,旨在学习分享,传播知识。

来源:https://www.cnblogs.com/hsiang/archive/2023/06/01/17447750.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: WPF绘制深圳地铁路线图