/// <summary> /// 查找一次中转的路线。 /// </summary> /// <param name="startNode">开始节点。</param> /// <param name="endNode">结束节点。</param> /// <returns>乘车路线。</returns> private MetroPath FindOneTransferPath(MetroNode startNode, MetroNode endNode) { List <MetroPath> pathList = new List <MetroPath>(); foreach (var startLine in startNode.Links.Select(c => c.Line).Distinct()) { foreach (var endLine in endNode.Links.Select(c => c.Line).Where(c => c != startLine).Distinct()) { //两条线路的中转站 foreach (var transferNode in this.Graph.GetTransferNodes(startLine, endLine)) { //起点到中转站的直达路线 var startDirectPathList = FindShortestPaths(startNode, transferNode, startLine); //中转站到终点的直达路线 var endDirectPathList = FindShortestPaths(transferNode, endNode, endLine); //合并两条直达路线 foreach (var startDirectPath in startDirectPathList) { foreach (var endDirectPath in endDirectPathList) { var directPath = startDirectPath.Merge(endDirectPath); pathList.Add(directPath); } } } } } //挑选最短路线 return(GetShortestPath(pathList)); }
/// <summary> /// 查找直达路线。 /// </summary> /// <param name="startNode">开始节点。</param> /// <param name="endNode">结束节点。</param> /// <returns>乘车路线。</returns> private MetroPath FindDirectPath(MetroNode startNode, MetroNode endNode) { MetroPath path = new MetroPath(); var startLines = startNode.Links.Select(c => c.Line).Distinct().ToList(); var endLines = endNode.Links.Select(c => c.Line).Distinct().ToList(); var lines = startLines.Where(c => endLines.Contains(c)).ToList(); if (lines.Count == 0) { return(path); } //查找直达路线 List <MetroPath> pathList = new List <MetroPath>(); foreach (var line in lines) { pathList.AddRange(FindShortestPaths(startNode, endNode, line)); } //挑选最短路线 return(GetShortestPath(pathList)); }
/// <summary> /// 判断是否包含指定的站点。 /// </summary> /// <param name="node">目标站点。</param> /// <returns></returns> /// <exception cref="ArgumentNullException">如果node为空引用,则跑出该异常。</exception> public bool ContainsNode(MetroNode node) { if (node == null) { throw new ArgumentNullException("node"); } return(Links.FirstOrDefault(c => c.From == node || c.To == node) != null); }
/// <summary> /// 查找指定两个节点之间的最短路径。 /// </summary> /// <param name="startNode">开始节点。</param> /// <param name="endNode">结束节点。</param> /// <param name="line">目标线路(为null表示不限制线路)。</param> /// <returns>乘车路线列表。</returns> private List <MetroPath> FindShortestPaths(MetroNode startNode, MetroNode endNode, MetroLine line) { List <MetroPath> pathtList = new List <MetroPath>(); if (startNode == endNode) { return(pathtList); } //路径队列,用于遍历路径 Queue <MetroPath> pathQueue = new Queue <MetroPath>(); pathQueue.Enqueue(new MetroPath()); while (pathQueue.Count > 0) { var path = pathQueue.Dequeue(); //如果已经超过最短路径,则直接返回 if (pathtList.Count > 0 && path.Links.Count > pathtList[0].Links.Count) { continue; } //路径的最后一个节点 MetroNode prevNode = path.Links.Count > 0 ? path.Links[path.Links.Count - 1].From : null; MetroNode lastNode = path.Links.Count > 0 ? path.Links[path.Links.Count - 1].To : startNode; //继续寻找后续节点 foreach (var link in lastNode.Links.Where(c => c.To != prevNode && (line == null || c.Line == line))) { if (link.To == endNode) { MetroPath newPath = path.Append(link); if (pathtList.Count == 0 || newPath.Links.Count == pathtList[0].Links.Count) {//找到一条路径 pathtList.Add(newPath); } else if (newPath.Links.Count < pathtList[0].Links.Count) {//找到一条更短的路径 pathtList.Clear(); pathtList.Add(newPath); } else { break; //更长的路径没有意义 } } else if (!path.ContainsNode(link.To)) { pathQueue.Enqueue(path.Append(link)); } } } return(pathtList); }
/// <summary> /// 绘制地铁站点。 /// </summary> /// <param name="g">绘图图面。</param> /// <param name="node">地铁站点。</param> private void PaintNode(Graphics g, MetroNode node) { //绘制站点圆圈 Color color = node.Links.Count > 2 ? Color.Black : node.Links[0].Line.Color; var rect = GetNodeRect(node); g.FillEllipse(Brushes.White, rect); using (Pen pen = new Pen(color)) { g.DrawEllipse(pen, rect); } //绘制站点名称 var sz = g.MeasureString(node.Name, this.Font).ToSize(); Point pt = new Point(node.X - sz.Width / 2, node.Y + (rect.Height >> 1) + 4); g.DrawString(node.Name, Font, Brushes.Black, pt); }
/// <summary> /// 查找乘车路线。 /// </summary> /// <param name="startNode">起点。</param> /// <param name="endNode">终点。</param> /// <returns>乘车路线。</returns> public MetroPath FindPath(MetroNode startNode, MetroNode endNode) { MetroPath path = new MetroPath(); if (startNode == null || endNode == null) { return(path); } if (startNode == endNode) { return(path); } //如果起点和终点拥有共同线路,则查找直达路线 path = FindDirectPath(startNode, endNode); if (path.Links.Count > 0) { return(path); } //如果起点和终点拥有一个共同的换乘站点,则查找一次换乘路线 path = FindOneTransferPath(startNode, endNode); if (path.Links.Count > 0) { return(path); } //查找路径最短的乘车路线 var pathList = FindShortestPaths(startNode, endNode, null); //查找换乘次数最少的一条路线 int minTransfers = int.MaxValue; foreach (var item in pathList) { var curTransfers = item.Transfers; if (curTransfers < minTransfers) { minTransfers = curTransfers; path = item; } } return(path); }
/// <summary> /// 构造函数。 /// </summary> /// <param name="line">所属线路。</param> /// <param name="from">来源站点。</param> /// <param name="to">目标站点。</param> /// <exception cref="ArgumentNullException">如果from或to为空引用,则抛出该异常。</exception> public MetroLink(MetroLine line, MetroNode from, MetroNode to) { if (line == null) { throw new ArgumentNullException("line"); } if (from == null) { throw new ArgumentNullException("from"); } if (to == null) { throw new ArgumentNullException("to"); } m_line = line; m_from = from; m_to = to; }
/// <summary> /// 获取地铁站点的矩形区域。 /// </summary> /// <param name="node">地铁站点。</param> /// <returns></returns> private Rectangle GetNodeRect(MetroNode node) { int r = node.Links.Count > 2 ? 7 : 5; return(new Rectangle(node.X - r, node.Y - r, (r << 1) + 1, (r << 1) + 1)); }
private void button1_Click(object sender, EventArgs e) { if (!metroGraphView1.Graph.Nodes.Contains(textBox5.Text)) { MessageBox.Show("没有此前站点", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } if (!metroGraphView1.Graph.Nodes.Contains(textBox6.Text)) { MessageBox.Show("没有此后站点", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } if (metroGraphView1.Graph.Nodes.Contains(textBox1.Text) && metroGraphView1.Graph.Lines.Contains(numericUpDown1.Text + "号线")) { MessageBox.Show("已存在该线路中的该站点", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } MetroLine nLine; if (!metroGraphView1.Graph.Lines.Contains(numericUpDown1.Text + "号线")) { nLine = new MetroLine(); nLine.Name = numericUpDown1.Text + "号线"; nLine.Color = Color.FromArgb(new Random().Next()); metroGraphView1.Graph.Lines.Add(nLine); } else { nLine = metroGraphView1.Graph.Lines[numericUpDown1.Text + "号线"]; } MetroNode temp = new MetroNode(); temp.Name = textBox1.Text; temp.X = (metroGraphView1.Graph.Nodes[textBox5.Text].X + metroGraphView1.Graph.Nodes[textBox6.Text].X) / 2; temp.Y = (metroGraphView1.Graph.Nodes[textBox5.Text].Y + metroGraphView1.Graph.Nodes[textBox6.Text].Y) / 2; temp.Links.Add(new MetroLink(nLine, metroGraphView1.Graph.Nodes[textBox5.Text], metroGraphView1.Graph.Nodes[textBox6.Text])); metroGraphView1.Graph.Nodes[textBox5.Text].Links.Add(new MetroLink(nLine, metroGraphView1.Graph.Nodes[textBox6.Text], temp)); metroGraphView1.Graph.Nodes.Add(temp); String fileName = Application.StartupPath + "\\MetroGraph_new.xml"; if (string.IsNullOrEmpty(fileName)) { return; } XmlDocument doc = new XmlDocument(); doc.LoadXml("<?xml version=\"1.0\" encoding=\"gb2312\"?><MetroGraph/>"); var graphNode = doc.DocumentElement; metroGraphView1.AddAtrribute(graphNode, "ScrollX", metroGraphView1.ScrollX.ToString()); metroGraphView1.AddAtrribute(graphNode, "ScrollY", metroGraphView1.ScrollY.ToString()); metroGraphView1.AddAtrribute(graphNode, "ZoomScale", metroGraphView1.ZoomScale.ToString()); //线路 var linesNode = metroGraphView1.AddChildNode(graphNode, "Lines"); foreach (var line in metroGraphView1.Graph.Lines) { var lineNode = metroGraphView1.AddChildNode(linesNode, "Line"); metroGraphView1.AddAtrribute(lineNode, "Name", line.Name); metroGraphView1.AddAtrribute(lineNode, "Color", line.Color.ToArgb().ToString()); } //站点 var sitesNode = metroGraphView1.AddChildNode(graphNode, "Nodes"); foreach (var site in metroGraphView1.Graph.Nodes) { var siteNode = metroGraphView1.AddChildNode(sitesNode, "Node"); metroGraphView1.AddAtrribute(siteNode, "Name", site.Name); metroGraphView1.AddAtrribute(siteNode, "X", site.X.ToString()); metroGraphView1.AddAtrribute(siteNode, "Y", site.Y.ToString()); //路径 foreach (var link in site.Links) { var linkNode = metroGraphView1.AddChildNode(siteNode, "Link"); metroGraphView1.AddAtrribute(linkNode, "To", link.To.Name); metroGraphView1.AddAtrribute(linkNode, "Line", link.Line.Name); metroGraphView1.AddAtrribute(linkNode, "Flag", link.Flag.ToString()); metroGraphView1.AddAtrribute(linkNode, "Weight", link.Weight.ToString()); } } doc.Save(fileName); metroGraphView1.OpenFromFile(fileName); }