/// <summary> /// Is there a connection on the same track between two nodes? /// </summary> /// <param name="fromNode">The node to connect from</param> /// <param name="toNode">The node to connect to</param> /// <param name="tvnIndex">Possibly a requirement on the index of the trackvectornode</param> private bool ExistsConnectionSameTrack(ConnectableNode fromNode, ConnectableNode toNode, int?tvnIndex) { if (connectableNodeOptions.Count == 0) { return(false); } // we can only connect on the same track if the both start and reconnectnodes are on the same track // This means that both need to be vector nodes. // It also means, this is only possible for the first node TrainpathVectorNode fromAsVector = fromNode.OriginalNodeAsVector; TrainpathVectorNode toAsVector = toNode.OriginalNodeAsVector; if (fromAsVector == null) { return(false); } if (toAsVector == null) { return(false); } if (fromAsVector.TvnIndex != toAsVector.TvnIndex) { return(false); } if (tvnIndex.HasValue && (tvnIndex.Value != fromAsVector.TvnIndex)) { return(false); } //for a reverse point the orientation is defined as being after the reversal. bool reconnectIsForward = (toAsVector.NodeType == TrainpathNodeType.Reverse) ? !toAsVector.ForwardOriented : toAsVector.ForwardOriented; if (fromAsVector.ForwardOriented != reconnectIsForward) { return(false); } if (isForwardConnecting) { if (fromAsVector.ForwardOriented != fromAsVector.IsEarlierOnTrackThan(toAsVector)) { return(false); } } else { if (fromAsVector.ForwardOriented == fromAsVector.IsEarlierOnTrackThan(toAsVector)) { return(false); } } return(true); }
/// <summary> /// Determine if a connection can be made (and store the found solution), from a 'dynamic node' meaning that /// it can change. /// </summary> /// <param name="fromNode">The node that is from which to connect</param> public bool CanConnect(TrainpathVectorNode fromNode) { autoConnectFromNode = new ConnectableNode(fromNode, true, isForward); FromNodeNeedsReverse = false; // reset to correct value bool canIndeedConnect = FindConnectionFromTo(null, true); //debugWindows[isForward].DrawString = String.Format("{0}:{1} ({2}) {3}", canIndeedConnect, // (autoConnectToNodeOptions.ActualReconnectNode == null ? "none" : autoConnectToNodeOptions.ActualReconnectNode.OriginalNode.ToStringShort()), // LinkingTvnsAsString(), debugString); return(canIndeedConnect); }
/// <summary> /// Try to find a connection between two given nodes. Depth-first search via main track at junctions. /// Also reversing the start or reconnectNode is tried, in case one of these nodes has a non-defined orientation /// because both before and after the node the path is broken. /// </summary> /// <param name="fromNode">Node at which the reconnection should start</param> /// <param name="toNode">Node at which the reconnection should end</param> /// <param name="firstTvnIndex">In case defined, the index of the first TVN the path has to follow</param> /// <returns>True if a connection has been found</returns> public bool FindConnection(TrainpathNode fromNode, TrainpathNode toNode, int?firstTvnIndex) { // We try to find a connection between two non-broken nodes. // We store the connection as a stack of linking tvns (track-node-vector-indexes) // The connection will only contain junctions (apart from maybe start and end=reconnect nodes) autoConnectFromNode = new ConnectableNode(fromNode, true, true); autoConnectToNodeOptions = new ReconnectNodeOptions(true); autoConnectToNodeOptions.AddNode(toNode, false); // only one option here return(FindConnectionFromTo(firstTvnIndex, false)); }
/// <summary> /// Find whether it is possible to connect directly two points on the same track. /// Store the reconnectpoint for later use during actual reconnecting /// </summary> /// <param name="fromNode">The point to connect from</param> /// <param name="firstTvnIndex">In case defined, the index of the first TVN the path has to follow</param> /// <returns>true if such a direct path has been found</returns> public bool FoundConnectionSameTrack(ConnectableNode fromNode, int?firstTvnIndex) { if (connectableNodeOptions.Count == 0) { return(false); } ConnectableNode candidate = connectableNodeOptions[0]; if (ExistsConnectionSameTrack(fromNode, candidate, firstTvnIndex)) { ActualReconnectNode = candidate; return(true); } return(false); }
/// <summary> /// Actually create the path by linking nodes following the stored linking tvns. /// </summary> /// <param name="modificationTools">The tool set that is used to actually modify the path</param> /// <param name="isMainPath">Do we add the node to the main path or not</param> /// <param name="isFromNodeDirectionOK">Set this to true when the FromNode has already been set to correct orientation elsewhere</param> public void CreateFoundConnection(ModificationTools modificationTools, bool isMainPath, bool isFromNodeDirectionOK) { ConnectableNode autoConnectToNode = autoConnectToNodeOptions.ActualReconnectNode; if (FromNodeNeedsReverse && !isFromNodeDirectionOK) { autoConnectFromNode.ReverseOrientation(); } if (ToNodeNeedsReverse) { autoConnectToNode.ReverseOrientation(); } if (!autoConnectToNode.IsConnectingForward) { linkingTvns.Reverse(); ConnectableNode swap = autoConnectToNode; autoConnectToNode = autoConnectFromNode; autoConnectFromNode = swap; } TrainpathNode currentNode = autoConnectFromNode.OriginalNode; if ((currentNode is TrainpathVectorNode) && !sameTrackConnect) { // in case the first node is a vector node (and not a direct connect), go to its junction first currentNode = modificationTools.AddAdditionalNode(currentNode, isMainPath); } //create the new path using the stored Tvns foreach (int tvn in linkingTvns) { currentNode = modificationTools.AddAdditionalNode(currentNode, tvn, isMainPath); while (currentNode is TrainpathVectorNode) { // apparently a disambiguity node has been added. currentNode = modificationTools.AddAdditionalNode(currentNode, tvn, isMainPath); } } //make the final connections TrainpathNode toNode = autoConnectToNode.OriginalNode; modificationTools.StitchTwoPaths(currentNode, toNode, isMainPath); }
/// <summary> /// Try to find a connection between a previously defined startNode and previously defined possible endNodes. /// Depth-first search via main track at junctions. /// Also reversing the start or single endNode is tried, in case one of these nodes has a non-defined orientation /// because both before and after the node the path is broken. /// </summary> /// <param name="firstTvnIndex">If non-null define the first TVN index that needs to be followed</param> /// <param name="allowOnlyStartReverse">If true, only start node is allowed to be reversed</param> /// <returns>Whether a path has been found</returns> protected bool FindConnectionFromTo(int?firstTvnIndex, bool allowOnlyStartReverse) { if (FindConnectionSameTrack(firstTvnIndex)) { return(true); } //first try to see if we succeed without re-orienting the startNode or reconnectNode if (FindConnectionThisOrientation(firstTvnIndex)) { return(true); } //perhaps there is a path with a reversed start node. if (allowOnlyStartReverse || CanReverse(autoConnectFromNode.OriginalNode)) { autoConnectFromNode.ReverseOrientation(); FromNodeNeedsReverse = FindConnectionThisOrientation(firstTvnIndex); autoConnectFromNode.ReverseOrientation(); // we only do the actual reverse in CreateFoundConnection if (FromNodeNeedsReverse) { return(true); } } //perhaps there is a path with a reversed reconnect node. ConnectableNode reconnectNode = autoConnectToNodeOptions.SingleNode(); if ((reconnectNode != null) && !allowOnlyStartReverse && CanReverse(reconnectNode.OriginalNode)) { reconnectNode.ReverseOrientation(); ToNodeNeedsReverse = FindConnectionThisOrientation(firstTvnIndex); reconnectNode.ReverseOrientation(); // we only do the actual reverse in CreateFoundConnection if (ToNodeNeedsReverse) { return(true); } } return(false); }
/// <summary> /// Does the junction with given index correspond to the connecting junction of any of the options. /// If so, determine whether the connection is good (based on the direction of the junctions). /// If the connection is good, store the actual Connectable node for later use. /// </summary> /// <param name="junctionIndex">The index of the junction that we want to check for a connection</param> /// <param name="isFacing">Whether the junction is a facing junction</param> /// <returns>true if a connection can be made, even if it is not a good connection</returns> public bool FoundConnection(int junctionIndex, bool isFacing) { ActualReconnectNode = null; // give a good default if (connectableNodeOptions.Count == 0) { return(false); } foreach (ConnectableNode candidate in connectableNodeOptions) { if (candidate.ConnectingJunctionIndex == junctionIndex) { // we found a connection. We will not search for other connections. // Now we just need to check if it is in the right direction // If it is not in the right direction, we did not succeed. bool goodConnection = (candidate.IsConnectingJunctionFacing == isFacing); if (goodConnection) { ActualReconnectNode = candidate; } return(true); } } return(false); }
/// <summary> /// Constructor. /// </summary> /// <param name="isConnectingForward">Are the options needed for connecting forwards (along the path) or not</param> public ReconnectNodeOptions(bool isConnectingForward) { connectableNodeOptions = new List <ConnectableNode>(); ActualReconnectNode = null; this.isForwardConnecting = isConnectingForward; }