/// <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> /// <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="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="g">绘图图面。</param> /// <param name="node">地铁站点。</param> private void PaintNode(Graphics g, MetroNode node) { if (node.Name != "1" && node.Name != "2" && node.Name != "3") { //绘制站点圆圈 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); } if (node.Links.Count > 2) { Point p = new Point(node.X - 4, node.Y - 4); //g.DrawString("C", Font, Brushes.Red, p); var startNodeImage = Properties.Resources.Trans; g.DrawImage(startNodeImage, node.X - 10, node.Y - 10); } //绘制站点名称 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, new Font("微软雅黑", 9, FontStyle.Bold), Brushes.Black, pt); } if (node.Name == "2") { 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); g.FillEllipse(new SolidBrush(color), node.X - 2, node.Y - 2, 8, 8); } } }
private void BtnAddNodeC_Click(object sender, EventArgs e) { try { bool IsDouLine1 = false; bool IsDouLine2 = false; MetroNode NewNode = new MetroNode(); MetroNode PreNode = new MetroNode(); MetroNode NexNode = new MetroNode(); String Prename = (CobPreNode.Text.ToString() == "海伦路" && CobNexNode.Text.ToString() == "宝山路") || (CobPreNode.Text.ToString() == "宝山路" && CobNexNode.Text.ToString() == "海伦路") ? "3" : CobPreNode.Text.ToString(); String Nexname = (CobPreNode.Text.ToString() == "海伦路" && CobNexNode.Text.ToString() == "宝山路") || (CobPreNode.Text.ToString() == "宝山路" && CobNexNode.Text.ToString() == "海伦路") ? "2" : CobNexNode.Text.ToString(); foreach (var node in metroGraphView1.Graph.Nodes) { if (node.Name == Prename) { PreNode = node; } if (node.Name == Nexname) { NexNode = node; } } NewNode.Name = this.TxtNodeName.Text.ToString(); NewNode.X = (CobPreNode.Text.ToString() == "海伦路" && CobNexNode.Text.ToString() == "宝山路") || (CobPreNode.Text.ToString() == "宝山路" && CobNexNode.Text.ToString() == "海伦路") ? 2033 : int.Parse(this.TxtNodeX.Text.ToString()); NewNode.Y = (CobPreNode.Text.ToString() == "海伦路" && CobNexNode.Text.ToString() == "宝山路") || (CobPreNode.Text.ToString() == "宝山路" && CobNexNode.Text.ToString() == "海伦路") ? 750 : int.Parse(this.TxtNodeY.Text.ToString()); if ((Math.Abs(NewNode.X - PreNode.X) > 200 || Math.Abs(NewNode.Y - PreNode.Y) > 200 || Math.Abs(NewNode.X - NexNode.X) > 200 || Math.Abs(NewNode.Y - NexNode.Y) > 200) && (PreNode.Name != "" && NexNode.Name != "")) { MessageBox.Show("距离太远了哦,请重新设定坐标(´▽`ʃ♡ƪ)"); this.TxtNodeX.Text = ""; this.TxtNodeY.Text = ""; return; } for (int i = 0; i < PreNode.Links.Count; i++) { if (PreNode.Links[i].Flag == 1 && PreNode.Links.Count > 3) { IsDouLine1 = true; } } for (int i = 0; i < NexNode.Links.Count; i++) { if (NexNode.Links[i].Flag == 1 && NexNode.Links.Count > 3) { IsDouLine2 = true; } } if (!IsDouLine2 || !IsDouLine1) { MetroLine NewLine = new MetroLine(); foreach (var line in metroGraphView1.Graph.Lines) { if (line.Name == CobNodeLine.Text.ToString()) { NewLine = line; } } if (!((CobPreNode.Text == "" || CobPreNode.Text == null) && NexNode.Links.Count <= 1)) { MetroLink NewLink = new MetroLink(NewLine, NewNode, PreNode); NewLink.Weight = 3; NewNode.Links.Add(NewLink); NewLink.Flag = 0; } if (!((CobNexNode.Text == "" || CobNexNode.Text == null) && PreNode.Links.Count <= 1)) { MetroLink NewLink = new MetroLink(NewLine, NewNode, NexNode); NewLink.Flag = 0; NewLink.Weight = 3; NewNode.Links.Add(NewLink); } if (!((CobPreNode.Text == "" || CobPreNode.Text == null) && NexNode.Links.Count <= 1)) { for (int i = 0; i < PreNode.Links.Count; i++) { if (PreNode.Links[i].To.Name == NexNode.Name) { PreNode.Links.RemoveAt(i); } } } PreNode.Links.Add(new MetroLink(NewLine, PreNode, NewNode)); if (!((CobNexNode.Text == "" || CobNexNode.Text == null) && PreNode.Links.Count <= 1)) { for (int i = 0; i < NexNode.Links.Count; i++) { if (NexNode.Links[i].To.Name == PreNode.Name) { NexNode.Links.RemoveAt(i); } } } NexNode.Links.Add(new MetroLink(NewLine, NexNode, NewNode)); metroGraphView1.Graph.Nodes.Add(NewNode); } else { for (int i = 0; i < PreNode.Links.Count; i++) { if (PreNode.Links[i].To.Name == NexNode.Name) { MetroLine NewLine = new MetroLine(); NewLine = PreNode.Links[i].Line; MetroLink NewLink = new MetroLink(NewLine, PreNode, NewNode); NewLink.Flag = PreNode.Links[i].Flag; MetroLink SNewLink = new MetroLink(NewLine, NewNode, NexNode); SNewLink.Flag = PreNode.Links[i].Flag; SNewLink.Weight = 3; NewNode.Links.Add(SNewLink); PreNode.Links.RemoveAt(i); PreNode.Links.Add(NewLink); } } for (int i = 0; i < NexNode.Links.Count; i++) { if (NexNode.Links[i].To.Name == PreNode.Name) { MetroLine NewLine = new MetroLine(); NewLine = NexNode.Links[i].Line; MetroLink NewLink = new MetroLink(NewLine, NexNode, NewNode); NewLink.Flag = NexNode.Links[i].Flag; MetroLink SNewLink = new MetroLink(NewLine, NewNode, PreNode); SNewLink.Flag = NexNode.Links[i].Flag; SNewLink.Weight = 3; NewNode.Links.Add(SNewLink); NexNode.Links.RemoveAt(i); NexNode.Links.Add(NewLink); } } metroGraphView1.Graph.Nodes.Add(NewNode); } //metroGraphView1.SaveToFile(Application.StartupPath + "\\MetroGraph.xml"); metroGraphView1.Invalidate(); this.CobPreNode.Text = ""; this.CobNexNode.Text = ""; this.TxtNodeName.Text = ""; this.TxtNodeX.Text = ""; this.TxtNodeY.Text = ""; this.TxtLineName.Text = ""; this.CobNodeLine.Text = ""; this.colorDialog1.Reset(); this.LabNexXY.Text = ""; this.LabPreXY.Text = ""; } catch { MessageBox.Show("请检查是否有误哦(✿◕‿◕✿)"); return; } this.PnlAddNode.Visible = false; this.BtnMetroHelp.Visible = true; this.BtnAdd.Visible = true; this.BtnSave.Visible = true; }
/// <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)); }
/// <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; //继续寻找后续节点 //int Gx_min = int.MaxValue; //int Gx; foreach (var link in lastNode.Links.Where(c => c.To != prevNode && (line == null || c.Line == line))) { /*Gx = Math.Abs(link.To.X - endNode.X) + Math.Abs(link.To.Y - endNode.Y) + 500 * path.Links.Count; * * if (Gx < Gx_min) * Gx_min = Gx; * else * continue;*/ if (link.Weight == 2) { continue; } 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)); } link.Weight = 2; } } return(pathtList); }
/// <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); } foreach (var item in this.Graph.Nodes) { foreach (var link in item.Links) { link.Weight = 3; } } //如果起点和终点拥有共同线路,则查找直达路线 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; } } if (CurPath.Links.Count > 0) { this.BackColor = Color.White; } else { this.BackColor = Color.WhiteSmoke; } return(path); }