ArcGIS網路分析之Silverlight客戶端最近設施點分析(二)
最近設施點分析實際上和路徑分析有些相識,實現的過程基本一致,不同的是引數的設定,選用的分析圖層為最近設施點網路分析圖層,一般形式為:
http://<伺服器名或ip地址>/ArcGIS/rest/services/<地圖服務名稱>/NAServer/<最近設施點分析圖層名稱>
在ArcGIS Api for Silverlight中,最近設施點分析的引數名稱為:RouteClosestFacilityParameters,同樣它也繼承自BaseRouteParameters。其主要的引數(屬性)有:
屬性名稱 | |
Incidents | 表示事件點 |
Facilities |
表示設施點 |
Barriers | 表示障礙點,還有線障礙:PolylineBarriers,面障礙:PolygonBarriers |
DefaultCutoff | 表示預設終斷值,即不會搜尋超出該值的設施點(從事件點到設施點,反之同理) |
ReturnDirections | 表示是否返回方向指南 |
DirectionsLanguage | 表示返回方向指南使用的描述語言(預設與網路分析圖層一致,NAServer中只有英語,其他語言需要自己安裝) |
DirectionsLengthUnits | 表示計算方向時使用的長度單位。預設與路徑網路圖層的設定一致。可用的值包括esriFeet,esriKilometers, esriMeters,esriMile,esriNauticalMiles和esriYards |
ReturnRoutes | 表示是否返回設施點與事件點的路徑 |
ReturnFacilities | 表示是否返回設施點 |
ReturnIncidents | 表示是否返回事件點 |
TravelDirection | 表示路徑的方向(從設施點到事件點還是事件點到設施點) |
UseHierarchy | 表示是否啟用等級屬性 |
FacilityReturnType | 表示設施返回型別,預設為FacilityReturnType.ServerFacilityReturnAll |
DefaultTargetFacilityCount | 表示預設搜尋的設施點個數 |
以上是最近設施點引數中一般用到的屬性說明。
下面我們來看一下實現的具體過程。
1.首先我們需要一個最近設施點的網路分析圖層,並例項化一個RouteTask。
例如本文釋出的最近設施點的網路分析圖層地址為:
例項化RouteTask
RouteTask closestFacilityTask = new RouteTask("http://qzj-pc/ArcGIS/rest/services/NetworkAnaysisMap/NAServer/ClosestFacility");//最近設施點Task
這裡在之前的博文中已經說了網路分析圖層的建立和釋出。在此不再討論。
2.註冊RouteTask的完成和失敗事件
註冊事件:
closestFacilityTask.SolveClosestFacilityCompleted += new EventHandler<RouteEventArgs>(closestFacilityTask_SolveClosestFacilityCompleted); closestFacilityTask.Failed += new EventHandler<TaskFailedEventArgs>(Task_Failed);
事件完成響應函式:
private void closestFacilityTask_SolveClosestFacilityCompleted(object sender, RouteEventArgs e) { //獲取結果的程式碼 } private void Task_Failed(object sender, TaskFailedEventArgs e) { MessageBox.Show("求解失敗" + e.Error.ToString()); }
3.設定最近設施點分析的引數,即RouteClosestFacilityParameters,例如:
RouteClosestFacilityParameters closestFacilityParameter = new RouteClosestFacilityParameters() { //設定事件點 Incidents = stopsGraphicsLayer.Graphics, //設定設定點 Facilities = gplayer.Graphics, //設定障礙點 Barriers = barriesGraphicsLayer.Graphics, ReturnDirections = true, DirectionsLanguage = new System.Globalization.CultureInfo("en-US"), ReturnRoutes = true, ReturnFacilities = true, ReturnBarriers = false, ReturnIncidents = true, ReturnPolygonBarriers = false, ReturnPolylineBarriers = false, DefaultCutoff = 100000, FacilityReturnType = FacilityReturnType.ServerFacilityReturnAll, DefaultTargetFacilityCount = Convert.ToInt32(ClosestFaciclityNumTextBox.Text), TravelDirection = FacilityTravelDirection.TravelDirectionToFacility, OutSpatialReference = MyMap.SpatialReference, };
以上過程省略了關於新增障礙點和事件點的過程,其過程和最短路徑分析的過程完全一致,所以在此不再多做解釋,具體過程可以參考前一篇的博文。
4.進行最近設施點分析
if (closestFacilityTask.IsBusy) closestFacilityTask.CancelAsync(); closestFacilityTask.SolveClosestFacilityAsync(closestFacilityParameter);
5.獲取分析結果,以及處理分析失敗的情況
最近設施點查詢返回的結果和最短路徑是一樣的,引數都是RouteEventArgs。所以這裡我們取得RouteEventArgs中的RouteResults集合即可。
但是對結果的處理方式和最短路徑又有一點點小差別。因為最短路徑返回的結果只有一條路徑,而最近設施點的分析結果則根據查詢的設施點不同而不同,例如我們想查詢最近的3個設施點,如果查詢成功,並且找到最近的三個設施點,那麼返回的路徑就有3條。
所以這裡我們需要對設施點查詢返回的結果進行迴圈。然後剩下的工作就和最短路徑一樣了。
這裡我們選擇用TreeView控制元件來顯示不同的路徑,最後生成的介面如下:
例如查詢附近4個最近的警察局,獲得四條路線,並可以展看檢視每一天的詳情:
同時當選中一條路徑時(位置1-第二警局),高亮顯示。
示例程式碼如下:
private void closestFacilityTask_SolveClosestFacilityCompleted(object sender, RouteEventArgs e) { //清空顯示方向的面板 DirectionStackPanel.Children.Clear(); //情況路線圖層(即上一次查詢的結果) RoutegraphicsLayer.Graphics.Clear(); //定義一個TreeView控制元件,將用於顯示路徑 TreeView RouteTree = new TreeView(); //註冊TreeView事件,當選擇不同的節點時,高亮顯示相應的路徑 RouteTree.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(RouteTree_SelectedItemChanged); //遍歷返回的結果(路線) foreach (RouteResult SolvedRoute in e.RouteResults) { RouteResult routeResult = SolvedRoute; //定義路線樣式 routeResult.Route.Symbol = LayoutRoot.Resources["MyRouteLineSymbol"] as SimpleLineSymbol; //將路線新增到圖層中 RoutegraphicsLayer.Graphics.Add(routeResult.Route); //新增一個Item,即表示當前的路線。將路線以樹檢視的形式展示出來 TreeViewItem RouteItem = new TreeViewItem(); //樹檢視一級標題格式:<路線ID>.<路線名稱> RouteItem.Header = string.Format("{0}: {1}", SolvedRoute.Directions.RouteID, SolvedRoute.Directions.RouteName); //將TreeViewItem的Tag設定為相應路線的ID,以便之後高亮顯示其對應路線。 RouteItem.Tag = SolvedRoute.Directions.RouteID; int i = 1; foreach (Graphic g in routeResult.Directions) { StringBuilder direction = new StringBuilder(); direction.AppendFormat("{0}. {1}", i, g.Attributes["text"]); if (i > 1 && i < routeResult.Directions.Features.Count) { decimal Distance = (decimal)g.Attributes["length"]; direction.AppendFormat(" {0}米", Distance.ToString("#0.000")); decimal NeedTime = (decimal)g.Attributes["time"]; direction.AppendFormat(", {0}分鐘", NeedTime.ToString("#0.00")); } RouteItem.Items.Add(new TextBlock() { Text = direction.ToString(), Margin = new Thickness(4) }); i++; } //新增總時間和路程的屬性 RouteItem.Items.Add(new TextBlock() { Text = string.Format(" 總路程為:{0}千米\n\n 總時間為:{1}分鐘", (SolvedRoute.Directions.TotalLength).ToString("#0.000"), SolvedRoute.Directions.TotalDriveTime.ToString("#0.00")) }); //遍歷一條路線結束,將該路線的資訊新增到TreeView中,TreeView獲得一個節點。 RouteTree.Items.Add(RouteItem); } //遍歷路線結束,將路線結果新增到顯示方向的面板中。 DirectionStackPanel.Children.Add(RouteTree); }
高亮顯示當前選中的路線,並取消高亮上一次選擇的路線,示例程式碼如下:
//記錄上一次點選的是哪一個節點 int OldIndex = 0; private void RouteTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { //必須點選節點才有效,節點下的TextBlock雖然也能觸發Changed事件,但是無效 if (e.NewValue.ToString() == typeof(TextBlock).ToString()) { return; } //如果舊值不為空,即不是第一次點選,那麼上一次點選就有可能是節點還有可能是節點下的TextBlock。 //因為當點選不同的節點時,我們需要將上一次高亮顯示的路線不高亮,而高亮顯示本次選中的路線 //所以在此需要處理 if (e.OldValue != null) { //如果上一次點選的是TreeViewItem則直接將其還原成不高亮顯示 if (e.OldValue.ToString() == typeof(TreeViewItem).ToString()) { TreeViewItem treeViewItem = (TreeViewItem)e.OldValue; OldIndex = Convert.ToInt32(treeViewItem.Tag); //在Tag中1表示的是第一條路線,其對應Graphics的索引值為0,一次類推減1. RoutegraphicsLayer.Graphics[OldIndex - 1].Symbol = LayoutRoot.Resources["MyRouteLineSymbol"] as SimpleLineSymbol; }//如果上一次點選的不是TreeView,則需要通過記錄上一次點選的索引:Oldindex來確定上一次點選的是那一個TreeView,並將其還原成不高亮 else { RoutegraphicsLayer.Graphics[OldIndex].Symbol = LayoutRoot.Resources["MyRouteLineSymbol"] as SimpleLineSymbol; } } //獲得當前點選節點的索引 int currentIndex = Convert.ToInt32(((TreeViewItem)((TreeView)sender).SelectedItem).Tag); //高亮顯示當前選擇的路線 RoutegraphicsLayer.Graphics[currentIndex - 1].Symbol = LayoutRoot.Resources["RouteRenderer"] as SimpleLineSymbol; //將本次點選的所以賦給OldIndex. OldIndex = currentIndex - 1; }
這樣所有的工作基本就已經完成了。下面是整體效果圖:
注:以上內容參考了ERSI官網例子,以及ESRI中國編寫的ArcGIS Api For Silverlight指導教程。
下一篇將講解服務區分析的實現過程,歡迎關注!
(版權所有,轉載請標明出處) 轉載於http://www.cnblogs.com/potential/archive/2012/11/17/2775141.html