/// <summary> /// Gets a list of related frame element /// </summary> /// <param name="relation">Type of relation to fetch</param> /// <param name="relationDirection">Relation direction</param> /// <param name="recursive">Whether or not to recursively get related frame elements</param> /// <returns>List of FEs</returns> public FrameElementSet GetRelatedFrameElements(Frame.FrameRelation relation, Frame.FrameRelationDirection relationDirection, bool recursive) { FrameElementSet relatedFEs = new FrameElementSet(); GetRelatedFrameElements(relation, relationDirection, recursive, relatedFEs); return(relatedFEs); }
/// <summary> /// Gets list of related frame elements /// </summary> /// <param name="relation">Type of relation to fetch</param> /// <param name="relationDirection">Relation direction</param> /// <param name="recursive">Whether or not to recursively get related frame elements</param> /// <param name="currentFEs">Current list of related FEs</param> private void GetRelatedFrameElements(Frame.FrameRelation relation, Frame.FrameRelationDirection relationDirection, bool recursive, FrameElementSet currentFEs) { // add sub-FEs if (relationDirection == Frame.FrameRelationDirection.Sub || relationDirection == Frame.FrameRelationDirection.Both) { foreach (FrameElement subFE in _relationSubFrameElements[relation]) { if (!currentFEs.Contains(subFE)) { currentFEs.Add(subFE); // recursively add sub-FEs if (recursive) { subFE.GetRelatedFrameElements(relation, relationDirection, recursive, currentFEs); } } } } // add super-FEs if (relationDirection == Frame.FrameRelationDirection.Super || relationDirection == Frame.FrameRelationDirection.Both) { foreach (FrameElement superFE in _relationSuperFrameElements[relation]) { if (!currentFEs.Contains(superFE)) { currentFEs.Add(superFE); // recursively add super-FEs if (recursive) { superFE.GetRelatedFrameElements(relation, relationDirection, recursive, currentFEs); } } } } }
/// <summary> /// Gets the shortest network path from the current frame element to another frame element /// </summary> /// <param name="destinationFrameElement">Destination frame element</param> /// <param name="searchRelations">Relations to search</param> /// <param name="searchDirection">Relation direction to search</param> /// <param name="maxDepth">Maximum depth to search within the network (i.e., maximum distance destination frame element can be from the current one)</param> /// <param name="frameElementPath">Path from this frame element to the destination frame element, or null for no path</param> /// <param name="relationPath">Relation path between this frame element and the destination frame element, or null for no path</param> /// <returns>True if path exists, false otherwise</returns> public bool GetShortestPathTo(FrameElement destinationFrameElement, Set <Frame.FrameRelation> searchRelations, Frame.FrameRelationDirection searchDirection, int maxDepth, out List <FrameElement> frameElementPath, out List <Frame.FrameRelation> relationPath) { frameElementPath = null; relationPath = null; // breadth-first search originating at the current frame element Queue <FrameElement> searchQueue = new Queue <FrameElement>(); _frameElementSearchBackPointer = null; // make sure to null out the source frame element back pointer searchQueue.Enqueue(this); Set <FrameElement> frameElementsEncountered = new Set <FrameElement>(); // keep track of frame elements we see so we don't enter any cycles frameElementsEncountered.Add(this); int currentDepth = 0; // tracks current search depth int nodesAtCurrentDepth = 1; // tracks nodes at current search depth int nodesAtCurrentDepthPlusOne = 0; // tracks nodes at one beyond the current search depth while (searchQueue.Count > 0 && currentDepth <= maxDepth) { FrameElement currentFrameElement = searchQueue.Dequeue(); // check for destination frame element if (currentFrameElement == destinationFrameElement) { // create path by following backpointers frameElementPath = new List <FrameElement>(); relationPath = new List <Frame.FrameRelation>(); while (destinationFrameElement != null) { frameElementPath.Add(destinationFrameElement); // back up to previous frame element FrameElement previousFrameElement = destinationFrameElement.FrameElementSearchBackPointer; // if the previous frame element isn't null, record the relationship if (previousFrameElement != null) { relationPath.Add(destinationFrameElement.FrameRelationSearchBackPointer); } destinationFrameElement = previousFrameElement; } // reverse paths to be from the current to the destination frame elements frameElementPath.Reverse(); relationPath.Reverse(); if (frameElementPath[0] != this) { throw new Exception("Path should start at current frame element"); } if (frameElementPath.Count != relationPath.Count + 1) { throw new Exception("Path length mismatch between frame elements and relations"); } if (frameElementPath.Count - 1 > maxDepth) { throw new Exception("Exceeded maximum allowed search depth"); } return(true); } // queue up frame elements related to the current one by any of the given relations int nodesAdded = 0; foreach (Frame.FrameRelation searchRelation in searchRelations) { // add sub-FEs if (searchDirection == Frame.FrameRelationDirection.Sub || searchDirection == Frame.FrameRelationDirection.Both) { foreach (FrameElement subFE in currentFrameElement._relationSubFrameElements[searchRelation]) { if (!frameElementsEncountered.Contains(subFE)) { subFE._frameElementSearchBackPointer = currentFrameElement; subFE._frameRelationSearchBackPointer = searchRelation; searchQueue.Enqueue(subFE); frameElementsEncountered.Add(subFE); ++nodesAdded; } } } // add super-FEs if (searchDirection == Frame.FrameRelationDirection.Super || searchDirection == Frame.FrameRelationDirection.Both) { foreach (FrameElement superFE in currentFrameElement._relationSuperFrameElements[searchRelation]) { if (!frameElementsEncountered.Contains(superFE)) { superFE._frameElementSearchBackPointer = currentFrameElement; superFE._frameRelationSearchBackPointer = searchRelation; searchQueue.Enqueue(superFE); frameElementsEncountered.Add(superFE); ++nodesAdded; } } } } // all generated search nodes belong in the next depth level nodesAtCurrentDepthPlusOne += nodesAdded; // if there aren't any nodes left at the current depth level, move to next level out if (--nodesAtCurrentDepth == 0) { nodesAtCurrentDepth = nodesAtCurrentDepthPlusOne; nodesAtCurrentDepthPlusOne = 0; currentDepth++; } } return(false); }