using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlClient; using System.Drawing; using System.IO; using System.Text; using System.Threading; using System.Windows.Forms; using skmDataStructures.Graph; namespace TrafficMan { public partial class frmTrafficMan : Form { Graph virginia = new Graph(); private Hashtable Dist = new Hashtable(); private Hashtable Route = new Hashtable(); int mincount = 0; int mintime = 0; string start; string end; private intersect[] intersectionList = new intersect[4]; public frmTrafficMan() { InitializeComponent(); } private struct intersect { public string intersectId; public string intersectName; } private void frmTrafficMan_Load(object sender, EventArgs e) { intersectionList[0].intersectId = "32012"; intersectionList[0].intersectName = "Rolling Green"; intersectionList[1].intersectId = "5402"; intersectionList[1].intersectName = "Woodland Park"; intersectionList[2].intersectId = "10230"; intersectionList[2].intersectName = "Fairview Park Dr."; intersectionList[3].intersectId = "45206"; intersectionList[3].intersectName = "Ridge Heights"; intersectionList[4].intersectId = "45206"; intersectionList[4].intersectName = "Ridge Heights"; btnRun.Enabled = false; btnCancel.Enabled = true; bwLoadPoints.RunWorkerAsync(); reloadListBox(false); } private void worker_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = (BackgroundWorker)sender; //loads data from sql into graph nodes virginia.Clear(); Dist.Clear(); Route.Clear(); // get data from ms sql SqlConnection myConnection = new SqlConnection("user id=tiger;" + "password=tiger;server=computername\\SQLEXPRESS;" + "Trusted_Connection=yes;" + "database=tiger; " + "connection timeout=5"); try { myConnection.Open(); } catch (Exception ex) { MessageBox.Show("There was an exception: " + ex.Message); } try { int total = 0; SqlDataReader myReader = null; SqlCommand myCommand2 = new SqlCommand("SELECT COUNT(*) AS cnt FROM links", myConnection); myReader = myCommand2.ExecuteReader(); while (myReader.Read()) { total = (int)myReader["cnt"]; } myReader.Close(); if (rbSpeedLimit.Checked) { SqlCommand myCommand = new SqlCommand("SELECT intersectionId1, intersectionId2, time FROM links", myConnection); } myReader = myCommand.ExecuteReader(); int count = 0; while (myReader.Read()) { // get values from sql String intersectionId1 = myReader["intersectionId1"].ToString(); String intersectionId2 = myReader["intersectionId2"].ToString(); int time = (int)myReader["time"]; // add values to nodes if (!virginia.Contains(intersectionId1)) virginia.AddNode(new Node(intersectionId1, null)); if ( !virginia.Contains(intersectionId2)) virginia.AddNode(new Node(intersectionId2, null)); virginia.AddUndirectedEdge(intersectionId1, intersectionId2, time); // if (count % 10000 == 0) { if (worker.CancellationPending) { e.Cancel = true; break; } else { worker.ReportProgress((int)count * 100 / total); } } count++; } e.Result = total; myReader.Close(); } catch (Exception ex) { MessageBox.Show("There was an exception(2)" + ex.Message); } myConnection.Close(); } private void reloadListBox(bool sql) { if (sql == false) { for (int a = 0; a < intersectionList.GetLength(0); a++) { lbStart.Items.Add(intersectionList[a].intersectName); lbEnd.Items.Add(intersectionList[a].intersectName); } } else { reloadListBox(); } } private void reloadListBox() { // reload the combo boxes lbStart.Items.Clear(); lbEnd.Items.Clear(); foreach (Node n in virginia.Nodes) { lbStart.Items.Add(n.Key); lbEnd.Items.Add(n.Key); } if (lbStart.Items.Count > 0) lbStart.SelectedIndex = 0; if (lbEnd.Items.Count > 1) lbEnd.SelectedIndex = 1; else if (lbEnd.Items.Count > 0) lbEnd.SelectedIndex = 0; } private string getIntersectionID(String name) { for (int a = 0; a < intersectionList.GetLength(0); a++) { if (intersectionList[a].intersectName == name) return intersectionList[a].intersectId; } return null; } private void writeRoute(Hashtable route, String start, String end, String filename) { Stack traceBackSteps = new Stack(); Node current = new Node(end, null); Node prev = null; if (File.Exists(filename)) File.Delete(filename); do { prev = current; current = (Node)route[current.Key]; String[] coord = getLatLong(current.Key); String temp = coord[0] + "," + coord[1]; traceBackSteps.Push(temp); } while (current.Key != start); StreamWriter sw = new StreamWriter(filename); while (traceBackSteps.Count > 0) sw.WriteLine((string)traceBackSteps.Pop()); sw.Close(); } private void InitDistRouteTables(String start, ref Hashtable dist, ref Hashtable route) { // set the initial distance and route for each city in the graph int total = virginia.Nodes.Count; foreach (Node n in virginia.Nodes) { //if (dist.Contains(n.Key)) // dist[n.Key] = Int32.MaxValue; //else dist.Add(n.Key, Int32.MaxValue); //if (route.Contains(n.Key)) // route[n.Key] = null; //else route.Add(n.Key, null); } // set the initial distance of start to 0 dist[start] = 0; } /// /// Relaxes the edge from the Node uCity to vCity. /// /// The distance between uCity and vCity. private void Relax(Node minNode, Node minNodeNeighbors, int cost, ref Hashtable dist, ref Hashtable route) //private void Relax(Node minNode, Node minNodeNeighbors, int cost, ref Hashtable dist, ref Hashtable route) { int distTouCity = (int)dist[minNode.Key]; int distTovCity = (int)dist[minNodeNeighbors.Key]; if (distTovCity > distTouCity + cost) { // update distance and route dist[minNodeNeighbors.Key] = distTouCity + cost; route[minNodeNeighbors.Key] = minNode; } } /// /// Retrieves the Node from the passed-in NodeList that has the smallest value in the distance table. /// /// This method of grabbing the smallest Node gives Dijkstra's Algorithm a running time of /// O(n2), where n is the number of nodes in the graph. A better approach is to /// use a priority queue data structure to store the nodes, rather than an array. Using a priority queue /// will improve Dijkstra's running time to O(E lg n), where E is the number of edges. This approach is /// preferred for sparse graphs. For more information on this, consult the README included in the download. private Node GetMin(NodeList nodes, Hashtable dist, String end) { // find the node in nodes with the smallest distance value int minDist = Int32.MaxValue; Node minNode = null; foreach (Node n in nodes) { if (((int)dist[n.Key]) <= minDist) { minDist = (int)dist[n.Key]; minNode = n; } } return minNode; } private void btnRun_Click(object sender, EventArgs e) { lblStatus.Text = "In progress..."; DateTime currentSystemTime = DateTime.Now; shortestPath(); TimeSpan diff = DateTime.Now.Subtract(currentSystemTime); lblStatus.Text = "Complete"; double avgtime = diff.TotalMilliseconds / mincount; avgtime = Math.Round(avgtime, 3); MessageBox.Show("Total time or distance: " + Dist[end] + ". Execution time: " + diff.ToString() + " seconds. " + mincount + " iterations. Average time: " + avgtime + " milliseconds."); } private String[] getLatLong(String intersectionID) { String[] ret = new String[2]; SqlConnection myConnection = new SqlConnection("user id=tiger;" + "password=tiger;server=computername\\SQLEXPRESS;" + "Trusted_Connection=yes;" + "database=tiger; " + "connection timeout=5"); try { myConnection.Open(); } catch (Exception e) { MessageBox.Show("Error getting lat/long: " + e.Message); } SqlDataReader myReader = null; SqlCommand myCommand = new SqlCommand("SELECT TOP 1 lat/1000000.0 AS lat, long/1000000.0 AS lon FROM intersections WHERE intersectionId = " + intersectionID, myConnection); myReader = myCommand.ExecuteReader(); while (myReader.Read()) { ret[0] = myReader["lat"].ToString(); ret[1] = myReader["lon"].ToString(); myReader.Close(); myConnection.Close(); return ret; } myReader.Close(); myConnection.Close(); return null; } private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { pbStatus.Value = e.ProgressPercentage; } private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) MessageBox.Show( this, "Background processing completed with errors: " + e.Error.Message, "ERROR!"); else if (e.Cancelled) { lblPoints.Text = null; pbStatus.Value = 0; } else { lblPoints.Text = e.Result.ToString(); pbStatus.Value = 0; } btnRun.Enabled = true; btnCancel.Enabled = false; } private void btnCancel_Click(object sender, EventArgs e) { // Cancel asynchronous processing if (bwLoadPoints.IsBusy) bwLoadPoints.CancelAsync(); if (bwShortestPath.IsBusy) bwShortestPath.CancelAsync(); } private void bwShortestPath_DoWork(object sender, DoWorkEventArgs e) { } private void shortestPath() { start = getIntersectionID(lbStart.Text); end = getIntersectionID(lbEnd.Text); InitDistRouteTables(start, ref Dist, ref Route); // initialize the route & distance tables NodeList startNodes = virginia.Nodes; // nodes == Q int total = new int(); total = startNodes.Count; bool done = false; /**** START DIJKSTRA ****/ while (done == false) { DateTime currenttime = DateTime.Now; Node u = GetMin(startNodes, Dist, end); // get the minimum node TimeSpan diff = DateTime.Now.Subtract(currenttime); mintime =+ diff.Milliseconds; mincount++; Dist.Remove(u.Key); startNodes.Remove(u); // remove it from the set Q // iterate through all of u's neighbors foreach(EdgeToNeighbor edge in u.Neighbors) { Relax(u, edge.Neighbor, edge.Cost); // relax each edge if (startEdge.Neighbor.Key == end) // if this is the last node, end process done = true; } if (startNodes.Count == 0) // end after runs out of nodes done = true; } // repeat until Q is empty /**** END DIJKSTRA ****/ // write file writeRoute(Route, start, end, "c:\\route.csv"); } } }