最終效果圖如下:
還是圖、鄰接表,可以模擬出幾個對象=》節點、邊、路徑。三個類分別如下:
Node 節點:
using System; using System.Collections.Generic; namespace Road.Plan { public class Node { private string id; private IList<Edge> edgeList; public double Lat { get; set; } public double Lng { get; set; } public Node(string nid) { id = nid; edgeList = new List<Edge>(); } public string Id { get { return id; } } public IList<Edge> EdgeList { get { return edgeList; } } } }
Edge 邊:
using System; using System.Web.Script.Serialization; namespace Road.Plan { public class Edge { [ScriptIgnore] public Node StartNode { get; set; } [ScriptIgnore] public Node EndNode { get; set; } public int Weight { get; set; } } }
Graph 圖:
using System; using System.Collections.Generic; namespace Road.Plan { /// <summary> /// 由於邊存在節點里了,鄰接表的方式的圖就這么簡單 /// </summary> public class Graph { public List<Node> NodeList = new List<Node>(); } }
路徑Path:
using System; using System.Collections.Generic; namespace Road.Plan { public class Path { //起始點 到 這個點 public string CurrentNodeId; //該點是否已經計算 public bool IsProcessed = false; //路徑 權重合計 public int Weight = 99999999; //路徑表示 public List<Node> PathNodeList = new List<Node>(); } }
路徑規划輔助類:
using System; using System.Collections.Generic; using System.Linq; namespace Road.Plan { /// <summary> /// 計算最短路徑幫助類 /// </summary> public class CaculateHelper { private Dictionary<string, Path> dicPath = new Dictionary<string, Path>(); public Dictionary<string, Path> DicPath { get { return dicPath; } } public void IniFirstNode(Graph graph, string StartNodeId) { Node OriginNode = null; foreach (Node node in graph.NodeList) { if (node.Id == StartNodeId) { OriginNode = node; } else { Path path = new Path(); path.CurrentNodeId = node.Id; dicPath.Add(path.CurrentNodeId, path); //初始化A->到所有邊都是默認的Path 99999999 } } //如果有A直接進入的邊,則設置為相應權重值,和記錄下路徑 foreach (Edge edge in OriginNode.EdgeList) { Path path = new Path(); path.CurrentNodeId = edge.EndNode.Id; path.Weight = edge.Weight; path.PathNodeList.Add(edge.StartNode); dicPath[path.CurrentNodeId] = path; } } public Node GetFromNodeMinWeightNode(Graph graph) { Node CNode = null; KeyValuePair<string, Path> KVPPath = dicPath.Where(m => !m.Value.IsProcessed).OrderBy(m => m.Value.Weight).FirstOrDefault(); if (KVPPath.Key != null) { CNode = graph.NodeList.FirstOrDefault(m => m.Id == KVPPath.Value.CurrentNodeId); } return CNode; } /// <summary> /// 計算最短權值路徑 /// </summary> public void CatelateMinWeightRoad(Graph graph, string StartNodeId) { //取從第一個點出發,最小權值且未被訪問果的節點的點 Node CNode = GetFromNodeMinWeightNode(graph); //這段代碼是核心 循環每個頂點,看看經過該頂點是否會讓權值變小,如果會則存起此路徑。直到再未訪問過的點 while (CNode != null) { Path CurrentPath = dicPath[CNode.Id]; foreach (Edge edge in CNode.EdgeList) { if (edge.EndNode.Id == StartNodeId) { continue; } Path TargetPath = dicPath[edge.EndNode.Id]; int tempWeight = CurrentPath.Weight + edge.Weight; if (tempWeight < TargetPath.Weight) { TargetPath.Weight = tempWeight; TargetPath.PathNodeList.Clear(); for (int i = 0; i < CurrentPath.PathNodeList.Count; i++) { TargetPath.PathNodeList.Add(CurrentPath.PathNodeList[i]); } TargetPath.PathNodeList.Add(CNode); } } //標志為已處理 dicPath[CNode.Id].IsProcessed = true; //再次獲取權值最小的點 CNode = GetFromNodeMinWeightNode(graph); } } } }
此處需要1個Controller、3個Action、1個頁面。
第一步,打開地圖、並初始化好“運算-圖”。
第二步,獲取所有節點,並將節點在地圖上顯示出來。
第三步,獲取運算結果,並在地圖上根據計算結果將線划出來。
Controller代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Road.Plan; namespace Road.Controllers { public class HomeController : Controller { static Graph graph = new Graph(); public ActionResult GetAllNodes() { return Json(graph.NodeList, JsonRequestBehavior.AllowGet); } public ActionResult Index() { graph.NodeList.Clear(); #region 初始化航路-圖 Node Node1 = new Node("1"); Node1.Lat = 23.1589850342836; Node1.Lng = 112.7859878540039; graph.NodeList.Add(Node1); Node Node2 = new Node("2"); Node2.Lat = 23.136255816129122; Node2.Lng = 112.79937744140625; graph.NodeList.Add(Node2); Node Node3 = new Node("3"); Node3.Lat = 23.11447003284563; Node3.Lng = 112.79869079589844; graph.NodeList.Add(Node3); Node Node4 = new Node("4"); Node4.Lat = 23.142885569598484; Node4.Lng = 112.80890464782715; graph.NodeList.Add(Node4); Node Node5 = new Node("5"); Node5.Lat = 23.144621879424374; Node5.Lng = 112.81577110290527; graph.NodeList.Add(Node5); Node Node6 = new Node("6"); Node6.Lat = 23.151566893799817; Node6.Lng = 112.82074928283691; graph.NodeList.Add(Node6); Node Node7 = new Node("7"); Node7.Lat = 23.15551276434145; Node7.Lng = 112.82984733581543; graph.NodeList.Add(Node7); Node Node8 = new Node("8"); Node8.Lat = 23.1545657660099; Node8.Lng = 112.84452438354492; graph.NodeList.Add(Node8); Node Node9 = new Node("9"); Node9.Lat = 23.167507497056675; Node9.Lng = 112.81705856323242; graph.NodeList.Add(Node9); //***************** 1 Node ******************* //1 -> 2 Edge aEdge1 = new Edge(); aEdge1.StartNode = Node1; aEdge1.EndNode = Node2; aEdge1.Weight = 1; Node1.EdgeList.Add(aEdge1); //***************** 2 Node ******************* //2 -> 3 Edge bEdge3 = new Edge(); bEdge3.StartNode = Node2; bEdge3.EndNode = Node3; bEdge3.Weight = 1; Node2.EdgeList.Add(bEdge3); //2 -> 1 Edge bEdge1 = new Edge(); bEdge1.StartNode = Node2; bEdge1.EndNode = Node1; bEdge1.Weight = 1; Node2.EdgeList.Add(bEdge1); //2 -> 4 Edge bEdge4 = new Edge(); bEdge4.StartNode = Node2; bEdge4.EndNode = Node4; bEdge4.Weight = 1; Node2.EdgeList.Add(bEdge4); //***************** 3 Node ******************* //3 -> 2 Edge cEdge2 = new Edge(); cEdge2.StartNode = Node3; cEdge2.EndNode = Node2; cEdge2.Weight = 1; Node3.EdgeList.Add(cEdge2); //***************** 4 Node ******************* //4 -> 2 Edge dEdge2 = new Edge(); dEdge2.StartNode = Node4; dEdge2.EndNode = Node2; dEdge2.Weight = 1; Node4.EdgeList.Add(dEdge2); //4 -> 5 Edge dEdge5 = new Edge(); dEdge5.StartNode = Node4; dEdge5.EndNode = Node5; dEdge5.Weight = 1; Node4.EdgeList.Add(dEdge5); //***************** 5 Node ******************* //5 -> 6 Edge eEdge6 = new Edge(); eEdge6.StartNode = Node5; eEdge6.EndNode = Node6; eEdge6.Weight = 1; Node5.EdgeList.Add(eEdge6); //5 -> 4 Edge eEdge4 = new Edge(); eEdge4.StartNode = Node5; eEdge4.EndNode = Node4; eEdge4.Weight = 1; Node5.EdgeList.Add(eEdge4); //***************** 6 Node ******************* //6 -> 5 Edge fEdge5 = new Edge(); fEdge5.StartNode = Node6; fEdge5.EndNode = Node5; fEdge5.Weight = 1; Node6.EdgeList.Add(fEdge5); //6 -> 7 Edge fEdge7 = new Edge(); fEdge7.StartNode = Node6; fEdge7.EndNode = Node7; fEdge7.Weight = 1; Node6.EdgeList.Add(fEdge7); //***************** 7 Node ******************* //7 -> 6 Edge gEdge6 = new Edge(); gEdge6.StartNode = Node7; gEdge6.EndNode = Node6; gEdge6.Weight = 1; Node7.EdgeList.Add(gEdge6); //7 -> 8 Edge gEdge8 = new Edge(); gEdge8.StartNode = Node7; gEdge8.EndNode = Node8; gEdge8.Weight = 1; Node7.EdgeList.Add(gEdge8); //7 -> 9 Edge gEdge9 = new Edge(); gEdge9.StartNode = Node7; gEdge9.EndNode = Node9; gEdge9.Weight = 1; Node7.EdgeList.Add(gEdge9); //***************** 8 Node ******************* //8 -> 7 Edge hEdge7 = new Edge(); hEdge7.StartNode = Node8; hEdge7.EndNode = Node7; hEdge7.Weight = 1; Node8.EdgeList.Add(hEdge7); //***************** 9 Node ******************* //9 -> 7 Edge iEdge7 = new Edge(); iEdge7.StartNode = Node9; iEdge7.EndNode = Node7; iEdge7.Weight = 1; Node9.EdgeList.Add(iEdge7); #endregion return View(); } /// <summary> /// 計算起始點,結束點的最短路徑 /// </summary> /// <param name="StartNodeId"></param> /// <param name="EndNodeId"></param> /// <returns></returns> public ActionResult GetWaterWay(string StartNodeId, string EndNodeId) { CaculateHelper CH = new CaculateHelper(); //第一步,初始化初始化源點 A 到 其他各點的 權重以及 路徑(完成 A->B A->C A->E A->D 邊權重,與A無直接邊的則默認99999999) CH.IniFirstNode(graph, StartNodeId); //第二步,從權重最小的點開始,一直到權值最大的點 CH.CatelateMinWeightRoad(graph, StartNodeId); //組合返回值 Path ShowPath = CH.DicPath[EndNodeId]; ShowPath.PathNodeList.Add(graph.NodeList.First(m => m.Id == EndNodeId)); //補上結束點 return Json(ShowPath.PathNodeList); } } }
頁面HTML代碼如下:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="initial-scale=1.0, user-scalable=no"> <meta charset="utf-8"> <title>Complex icons</title> <style> html, body, #map-canvas { height: 100%; margin: 0px; padding: 0px; } </style> <script src="/jquery-1.10.2.min.js"></script> <script src="http://ditu.google.cn/maps/api/js?sensor=false" type="text/javascript"></script> <script> var map; var lat = 23.144621879424374; var lng = 112.81577110290527; var myLatlng = new google.maps.LatLng(lat, lng); //添加一個標記 function addMarker(lat, lng, title) { var LatLng = new google.maps.LatLng(lat, lng); var marker = new google.maps.Marker({ map: map, position: LatLng, title: title }); return marker; } function LatLng(lat, lng) { return { lat: lat, lng: lng }; } //線條選項 function lineOption() { var lineOption = { strokeColor: "#FF0000", strokeOpacity: 1.0, strokeWeight: 2, coordinates: [] }; return lineOption; } //畫線 function addLine(lineOption) { var linecoordinates = []; for (var i = 0; i < lineOption.coordinates.length; i++) { linecoordinates.push(new google.maps.LatLng(lineOption.coordinates[i].lat, lineOption.coordinates[i].lng)); } //顯示線 var line = new google.maps.Polyline({ path: linecoordinates, strokeColor: lineOption.strokeColor, strokeOpacity: lineOption.strokeOpacity, strokeWeight: lineOption.strokeWeight, map: map }); return line; } var MarkerId = 1; //初始化谷歌地圖 function initialize() { //設置地圖中心 var mapOptions = { zoom: 12, center: myLatlng } map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions); //google.maps.event.addListener(map, 'click', function (e) { // var str = $("#position").html(); // var MID = MarkerId++; // addMarker(e.latLng.lat(), e.latLng.lng(), MID); // $("#position").html(str + " " + MID + " " + e.latLng.lat() + " " + e.latLng.lng() + "<br/>"); //}); $.ajax({ url: "/Home/GetAllNodes", dataType: "json", type: "post", success: function (data) { for (var i = 0; i < data.length; i++) { addMarker(data[i].Lat, data[i].Lng, data[i].Id); } } }) $.ajax({ url: "/Home/GetWaterWay", dataType: "json", type: "post", data:{ StartNodeId: "1", EndNodeId: "9" }, success: function (data) { var lo = lineOption(); lo.strokeWeight = 4; lo.strokeColor = "Green"; lo.strokeOpacity = 0.8; //用返回的路線畫線 for (var i = 0; i < data.length; i++) { lo.coordinates.push(LatLng(data[i].Lat, data[i].Lng)); } addLine(lo); } }) } //監聽頁面事件,當頁面加載完畢,加載谷歌地圖 google.maps.event.addDomListener(window, 'load', initialize); </script> </head> <body> <div id="map-canvas" style="height:600px;"></div> <div id="position"></div> </body> </html>