WPF繪製深圳地鐵路線圖

来源:https://www.cnblogs.com/hsiang/archive/2023/06/01/17447750.html
-Advertisement-
Play Games

經常坐地鐵,卻不知道地鐵多少條線路?哪個站下車?今天就帶領大家熟悉並繪製深圳地鐵路線圖。 WPF在繪製矢量圖方面有非常強大的優勢,利用WPF可以繪製出各種矢量圖形,如線,圓,多邊形,矩形,及組合圖形。今天以繪製深圳地鐵路線圖為例,簡述WPF在圖形繪製方面的一些知識,僅供學習分享使用,如有不足之處,還 ...


經常坐地鐵,卻不知道地鐵多少條線路?哪個站下車?今天就帶領大家熟悉並繪製深圳地鐵路線圖。

WPF在繪製矢量圖方面有非常強大的優勢,利用WPF可以繪製出各種矢量圖形,如線,圓,多邊形,矩形,及組合圖形。今天以繪製深圳地鐵路線圖為例,簡述WPF在圖形繪製方面的一些知識,僅供學習分享使用,如有不足之處,還請指正。

 

WPF圖形概述


與傳統的.NET開發使用GDI+進行繪圖不同,WPF擁有自己的一套圖形API,繪圖為矢量圖。繪圖可以在任何一種佈局控制項中完成,wpf會根據容器計算相應坐標。最常用的是Canvas和Grid。基本圖形包括以下幾個,都是Shaper類的派生類。

  1. Line,直線段,可以設置Stroke
  2. Rectangle,有Stroke也有Fill
  3. Ellipse,橢圓,同上
  4. Polygon,多邊形。由多條直線線段圍成的閉合區域,同上。
  5. Polyline,折線,不閉合,由多條首尾相接的直線段組成
  6. 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         [JsonProperty("s")]
  9         public string? Name { get; set; }
 10 
 11         [JsonProperty("i")]
 12         public string? Index { get; set; }
 13 
 14         [JsonProperty("l")]
 15         public SubwayLine[]? SubwayLines { get; set; }
 16 
 17         [JsonProperty("o")]
 18         public string? Obj { get;set; }
 19     }
 20 
 21     public class SubwayLine
 22     {
 23         [JsonProperty("st")]
 24         public St[]? Sites { get; set; }
 25 
 26         [JsonProperty("ln")]
 27         public string? LineNumber { get; set; }
 28 
 29         [JsonProperty("su")]
 30         public string? Su { get; set; }
 31 
 32         [JsonProperty("kn")]
 33         public string? KName { get; set; }
 34 
 35         [JsonProperty("c")]
 36         public string[]? Circles { get;set; }
 37 
 38         [JsonProperty("lo")]
 39         public string? Lo { get; set; }
 40 
 41         [JsonProperty("lp")]
 42         public string[]? LinePosition { get; set; }
 43 
 44         [JsonProperty("ls")]
 45         public string? Ls { get; set; }
 46 
 47         [JsonProperty("cl")]
 48         public string? Color { get; set; }
 49 
 50         [JsonProperty("la")]
 51         public string? La { get; set; }
 52 
 53         [JsonProperty("x")]
 54         public string? X { get; set; }
 55 
 56         [JsonProperty("li")]
 57         public string? Li { get; set; }
 58     }
 59 
 60     public class St
 61     {
 62         [JsonProperty("rs")]
 63         public string? Rs { get; set; }
 64 
 65         [JsonProperty("udpx")]
 66         public string? Udpx { get; set; }
 67 
 68         [JsonProperty("su")]
 69         public string? Su { get; set; }
 70 
 71         [JsonProperty("udsu")]
 72         public string? Udsu { get; set;}
 73 
 74         [JsonProperty("n")]
 75         public string? Name { get; set;}
 76 
 77         [JsonProperty("en")]
 78         public string? En { get; set; }
 79 
 80         [JsonProperty("sid")]
 81         public string? Sid { get; set; }
 82 
 83         [JsonProperty("p")]
 84         public string? Position { get; set; }
 85 
 86         [JsonProperty("r")]
 87         public string? R { get; set; }
 88 
 89         [JsonProperty("udsi")]
 90         public string? Udsi { get; set; }
 91 
 92         [JsonProperty("t")]
 93         public string? T { get; set;}
 94 
 95         [JsonProperty("si")]
 96         public string? Si { get; set; }
 97 
 98         [JsonProperty("sl")]
 99         public string? Sl { get; set;}
100 
101         [JsonProperty("udli")]
102         public string? Udli { get; set; }
103 
104         [JsonProperty("poiid")]
105         public string? Poiid { get; set; }
106 
107         [JsonProperty("lg")]
108         public string? Lg { get; set; }
109 
110         [JsonProperty("sp")]
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[i];
 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?[0].Split(" ");//線路起始位置
 21             lineFigure.StartPoint = new System.Windows.Point(int.Parse(start[0]), int.Parse(start[1]));
 22 
 23             for (int j= 0;j< circles?.Length;j++)
 24             {
 25                 var circle= circles[j].Split(" ");
 26                 LineSegment lineSegment = new LineSegment(new System.Windows.Point(int.Parse(circle[0]), int.Parse(circle[1])),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[j];
 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[0]), int.Parse(sitePosition[1]));
 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[0]);
 65                     var y = int.Parse(sitePosition[1]);
 66                     if (j + 1 < subwayLine.Sites?.Length)
 67                     {
 68                         //站點位置適當偏移
 69                         var next = subwayLine.Sites[j + 1]?.Position?.Split(" ");
 70                         var nextx = int.Parse(next[0]);
 71                         var nexty = int.Parse(next[1]);
 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?[0].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[0]);
105                 var lineY = int.Parse(linePosition[1]);
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文件中,有些屬性名都是簡寫,所以在編寫示例代碼過程中,對有些屬性的理解並不准確,需要不斷測試優化,繪製出的地鐵路線圖可能與實際存在稍微的差異,如站點名稱,路線名稱等內容的位置。

 以上就是本篇文章的全部內容,旨在學習分享,傳播知識。


作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文版權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段聲明,且在文章頁面明顯位置給出原文連接,謝謝。
關註個人公眾號,定時同步更新技術及職場文章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 有時候我們使用python自動化框架的時候,打開一個網頁的時候,它會出現出線這一種登錄框,我們f12檢查不了,用開發者工具強制檢查裡面沒有任何屬性. 那這時候我們就可以用到python第三方庫:pyautogui PyAutoGUI:是一個Python庫,可用於自動化GUI(圖形用戶界面)程式的任務 ...
  • 本文介紹基於**Python**中**ArcPy**模塊,對大量柵格遙感影像文件**批量**進行**無效值**(**NoData**值)填充的方法。 在處理柵格圖像文件時,我們經常會遇到圖像中存在有無效值(即**NoData**值)的情況。如下圖所示,這裡有一個**矢量面要素圖層**和該矢量圖層範圍 ...
  • 我們在初學 Java 編程的時候,總是感覺很枯燥乏味,想著做點可以交互的小系統,可以讓用戶自由輸入,系統可以接收做出反映。這就要介紹一下 Java 中的 Scanner 類了。 ...
  • 通過python來開發web應用,可以產簡化了web開發的流程,功能和函數庫也是非常豐富,我們也是開箱即用,目前比較流程的WEB框架就是Flask和django。 > 根據2020年JetBrains Python開發人員調查,Django和Flask是迄今為止最受歡迎的兩個Python Web框架 ...
  • 在今年2月14日的時候,Keycloak 團隊宣佈他們正在棄用大多數 Keycloak 適配器。其中包括Spring Security和Spring Boot的適配器,這意味著今後Keycloak團隊將不再提供針對Spring Security和Spring Boot的集成方案。但是,如此強大的Ke ...
  • # 1.初識列表(list) **列表由一系列按特定順序排列的數據元素組成**。可以將任何類型數據元素加入列表中,其中的數據元素之間沒有任何關係。鑒於列表通常包含多個數據元素,給列表指定一個表示覆數的名稱是個不錯的選擇。 在python中,用方括弧[]來表示列表,並用逗號來分隔其中的數據元素。編寫程 ...
  • # 出錯信息 ``` 我使用flask時,運行後出現下麵的錯誤:Traceback (most recent call last): File "D:/github/lind-python/test-web.py", line 1, in from flask import Flask File " ...
  • ## 引言 之前說的做自動記錄 Todo 執行過程中消耗的時間的[Todo 項目]( https://github.com/circler3/TodoTrack ),由於想持續保持程式執行,就放棄了 `Spectre.Console.Cli`,後來隨著命令越來越多,自己處理覺得很是麻煩,想了想要不試 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...