/// <summary> /// Creates a Person with a start and end PseudoNode and a name. /// </summary> /// <param name="name"></param> /// <param name="start_node"></param> /// <param name="end_node"></param> public Person(string name, PseudoNode start_node, PseudoNode end_node) { this.name = name; route = new Route(start_node, end_node); List <Node> node_route = route.GetNodeRoute(); position = start_node; destination_reached = false; }
/// <summary> /// This method returns a double representing the length of time (in seconds) that it would /// take to get to from a PseudoNode to a Node along the same Path. If the given Node is /// not on the same Path, this returns Double.MAX_VALUE as this method contains no support /// for routing. /// </summary> /// <param name="node"></param> /// <param name="pseudoNode"></param> /// <returns></returns> public double GetTimeToNodeFrom(Node node, PseudoNode pseudoNode) { if (pseudoNode.GetPath() == this) { return(GetTimeToNodeFrom(node, pseudoNode.GetDistanceAlongPath())); } else { Debug.WriteLine("The PseudoNode does not lie on this Path."); return(Double.MaxValue); } }
/// <summary> /// This method returns a double that represents the length of time (in seconds) that it /// would take to get from one PseudoNode on the Path to another on the Path. If one of /// the nodes is not on this Path, this method will return Double.MaxValue. /// </summary> /// <param name="destination_node"></param> /// <param name="source_node"></param> /// <returns></returns> public double GetTimeToPseudoNodeFrom(PseudoNode destination_node, PseudoNode source_node) { // Check both PseudoNodes are on the Path if (destination_node.GetPath() != this || source_node.GetPath() != this) { return(Double.MaxValue); } // Calculate length of time double destination_distance = destination_node.GetDistanceAlongPath(); double source_distance = source_node.GetDistanceAlongPath(); double time = (destination_distance - source_distance) / speed_limit; time = (time > 0) ? time : -time; return(time); }
/// <summary> /// Sets up a PseudoNode at the same point as the given PseudoNode. /// </summary> /// <param name="node"></param> public PseudoNode(PseudoNode node) { path = node.GetPath(); distance_along_path = node.GetDistanceAlongPath(); }
/// <summary> /// Initialises a Route by giving a start and end PseudoNode, and calculates the quickest Route between them. /// </summary> /// <param name="_source_node"></param> /// <param name="_end_node"></param> public Route(PseudoNode _source_node, PseudoNode _end_node) { // Storing the source and destination nodes source_node = new PseudoNode(_source_node); end_node = new PseudoNode(_end_node); Node [] source_nodes = source_node.GetPath().GetNodes(); Node [] end_nodes = end_node.GetPath().GetNodes(); bool [] end_nodes_mapped = { false, false }; List <NodeAndTime> nodes_and_times = new List <NodeAndTime>(); List <Node> nodes = Map.GetNodes(); // Setting the initial times to get to each node from the source node foreach (Node node in nodes) { if (node == source_nodes[0] || node == source_nodes[1]) { nodes_and_times.Add(new NodeAndTime(node, source_node.GetPath().GetTimeToNodeFrom(node, source_node))); } else { nodes_and_times.Add(new NodeAndTime(node, false)); } } // Implementing Dijkstra's algorithm: bool complete = false; while (!complete) { // Sort to ensure that the nearest (by time) nodes to the source node are at the top of the List Sort(nodes_and_times); // Finding the next node that has not been mapped NodeAndTime analysis_node = null; foreach (NodeAndTime node_and_time in nodes_and_times) { if (!node_and_time.AdjacentNodesMapped()) { analysis_node = node_and_time; break; } } // If all nodes have been mapped, then the analysis_node was not set in the previous code snippet. // Hence we need not run the rest of the loop and we can finish the while loop. This is a fail safe // to ensure that the code does not crash. In ordinary circumstances, this scenario should be // handled below, at the bottom of the while loop. if (analysis_node == null) { complete = true; continue; } // Get adjacent nodes List <Node> adj_nodes_temp = Map.GetNodesAdjacentToNode(analysis_node.GetNode()); foreach (Node node in adj_nodes_temp) { // Calculate time coming from this node double new_time = Map.GetPathWithNodes(analysis_node.GetNode(), node).GetTime() + analysis_node.GetTime(); // If the time lower than it would be taking the previous route here, change that NodeAndTime object to come through this way instead NodeAndTime previous_node_and_time = GetNodeAndTime(node, nodes_and_times); if (new_time < previous_node_and_time.GetTime()) { List <NodeAndTime> new_shortest_route = new List <NodeAndTime>(analysis_node.GetShortestRouteToNodeForCalc()); new_shortest_route.Add(analysis_node); previous_node_and_time.SetShortestRouteToNode(new_shortest_route); previous_node_and_time.SetTime(new_time); } } analysis_node.SetAdjacentNodesMapped(true); // Check if both Nodes either side of the PseudoNode have been analysed. if (analysis_node.GetNode() == end_nodes[0]) { end_nodes_mapped[0] = true; } else if (analysis_node.GetNode() == end_nodes[1]) { end_nodes_mapped[1] = true; } // Completing the loop if both of the end Nodes have been mapped if (end_nodes_mapped[0] && end_nodes_mapped[1]) { complete = true; } } // Getting the time that it will take to get to the PseudoNode via both Nodes either side of the containing Route NodeAndTime [] end_node_and_times = { GetNodeAndTime(end_nodes[0], nodes_and_times), GetNodeAndTime(end_nodes[1], nodes_and_times) }; double time_from_end_node_1 = end_node_and_times[0].GetTime() + end_node.GetPath().GetTimeToNodeFrom(end_node_and_times[0].GetNode(), end_node); double time_from_end_node_2 = end_node_and_times[1].GetTime() + end_node.GetPath().GetTimeToNodeFrom(end_node_and_times[1].GetNode(), end_node); // Selecting to go through the Node that will give the shortest time, and converting these to a list of Nodes. if (time_from_end_node_1 <= time_from_end_node_2) { node_route = end_node_and_times[0].ConvertToListOfNodes(); path_route = end_node_and_times[0].ConvertToListOfPaths(); } else { node_route = end_node_and_times[1].ConvertToListOfNodes(); path_route = end_node_and_times[1].ConvertToListOfPaths(); } // Adding start and end Paths on as they may not currently be there if (path_route.Count == 0) { path_route.Add(source_node.GetPath()); } if (path_route[0] != source_node.GetPath()) { path_route.Insert(0, source_node.GetPath()); } if (path_route[path_route.Count - 1] != end_node.GetPath()) { path_route.Add(end_node.GetPath()); } // Determine which directions the Paths should be travelled in DetermineDirections(); }
/// <summary> /// Initialises a Route by giving a start PseudoNode and end Node, and calculates the quickest Route between /// them. /// </summary> /// <param name="source_node"></param> /// <param name="end_node"></param> public Route(PseudoNode source_node, Node end_node) : this(source_node, new PseudoNode(end_node)) { }
/// <summary> /// Initialises a Route by giving a start Node and end PseudoNode, and calculates the quickest Route between /// them. /// </summary> /// <param name="source_node"></param> /// <param name="end_node"></param> public Route(Node source_node, PseudoNode end_node) : this(new PseudoNode(source_node), end_node) { }
/// <summary> /// This method returns a Direction that specifies whether the Path that the PseudoNode is on should be travelled /// forwards or backwards (i.e. from Path.GetNodes()[0] to Path.GetNodes()[1] or vice versa). If the PseudoNode /// does not sit on a Path in this Route, this method will return Direction.FORWARDS. /// </summary> /// <param name="pseudo_node"></param> /// <returns></returns> public Direction GetDirection(PseudoNode pseudo_node) { return(GetDirection(pseudo_node.GetPath())); }
/// <summary> /// This method finds the next Path on the Route by the current position of the PseudoNode. If the PseudoNode is /// not on the Route, or if it lies on the last Path in the Route, this method will return null. /// </summary> /// <param name="current_position"></param> /// <returns></returns> public Path GetNextPath(PseudoNode current_position) { return(GetNextPath(current_position.GetPath())); }
/// <summary> /// This method will update the position of the Person. The number of seconds since the /// last update is required in order to calculate the Person's new position. If the /// Person reaches the next part of their Path, their current_path and last_node_passed /// values will be updated. If the Person reaches the end of their route, the Person will /// be deleted from the List in Persons. /// </summary> /// <param name="seconds_since_last_update"></param> public void update(double seconds_since_last_update) { // If the Pwerson is at the destination already, there's no need to change position if (destination_reached) { return; } double time_to_destination = Double.MaxValue; // Check if we're on the final path of the route if (route.GetNextPath(position.GetPath()) == null) { time_to_destination = position.GetPath().GetTimeToPseudoNodeFrom(route.GetDestinationNode(), position); } // If the Person is nearly at the destination, set the Person at the destination node if (time_to_destination <= seconds_since_last_update) { position = new PseudoNode(route.GetDestinationNode()); destination_reached = true; return; // Stop processing } // ------------------------------------------------ // Otherwise, the Person is not at the destination: Direction current_direction = route.GetDirection(position); double time_to_next_path = 0; // Work out the time it will take to reach the next Path if (current_direction == Direction.FORWARDS) { time_to_next_path = position.GetPath().GetTimeToNodeFrom(position.GetPath().GetNodes()[1], position); } else { time_to_next_path = position.GetPath().GetTimeToNodeFrom(position.GetPath().GetNodes()[0], position); } // If this loop is entered, the Person will switch paths. Update the position and the // path. while (time_to_next_path <= seconds_since_last_update) { // If this loop is entered, the Person will switch paths. Update the position // and the path. // Take off the amount of time that it would take to get to the next Path seconds_since_last_update -= time_to_next_path; // Update the position PseudoNode Path next_path = route.GetNextPath(position.GetPath()); current_direction = route.GetDirection(next_path); if (current_direction == Direction.FORWARDS) { position.SetPath(next_path, 0); time_to_next_path = position.GetPath().GetTimeToNodeFrom(position.GetPath().GetNodes()[1], position); } else { position.SetPath(next_path, next_path.GetDistance()); time_to_next_path = position.GetPath().GetTimeToNodeFrom(position.GetPath().GetNodes()[0], position); } } // Do the final updates on the current path only double new_distance = 0; if (current_direction == Direction.FORWARDS) { new_distance = position.GetDistanceAlongPath() + GetCurrentPath().GetSpeedLimit() * seconds_since_last_update; } else { new_distance = position.GetDistanceAlongPath() - GetCurrentPath().GetSpeedLimit() * seconds_since_last_update; } position.SetDistanceAlongPath(new_distance); }