/// <summary> /// Expands the current fill area with all neighbors of the specified <see cref="Graph"/> /// node for which the matching predicate succeeds.</summary> /// <param name="node"> /// The <see cref="Graph"/> node whose neighbors to examine.</param> /// <remarks><para> /// <b>ExpandArea</b> recursively visits all contiguous nodes for which the matching /// predicate succeeds, and adds them to the <see cref="Nodes"/> collection. /// </para><para> /// <b>ExpandArea</b> never revisits nodes that were already added or rejected. The source /// node specified in the <see cref="FindMatching"/> call is never added to the <b>Nodes</b> /// collection.</para></remarks> private void ExpandArea(T node) { // get valid neighbors of current node IList <T> neighbors = Graph.GetNeighbors(node); // recurse into all valid neighbors for (int i = 0; i < neighbors.Count; i++) { T neighbor = neighbors[i]; // skip visited nodes if (_visited.Contains(neighbor)) { continue; } _visited.Add(neighbor); // add match and visit neighbors if (_match(neighbor)) { _nodes.Add(neighbor); ExpandArea(neighbor); } } }
/// <summary> /// Expands the current coverage area with all neighbors of the specified <see /// cref="Graph"/> node that can be reached by the current <see cref="Agent"/>.</summary> /// <param name="node"> /// The <see cref="Graph"/> node whose neighbors to examine.</param> /// <param name="cost"> /// The total path cost to reach <paramref name="node"/>, measured as the sum of all <see /// cref="IGraphAgent{T}.GetStepCost"/> results for each movement step between neighboring /// nodes.</param> /// <remarks><para> /// <b>ExpandArea</b> recursively computes all possible movement paths for the current <see /// cref="Agent"/>, adding all valid nodes in any affordable path to the <see cref="Nodes"/> /// collection. /// </para><para> /// <b>ExpandArea</b> never revisits nodes that were already reached by a better path. The /// source node specified in the <see cref="FindReachable"/> call is never added to the /// <b>Nodes</b> collection.</para></remarks> private void ExpandArea(T node, double cost) { // get valid neighbors of current node IList <T> neighbors = Graph.GetNeighbors(node); // recurse into all valid neighbors for (int i = 0; i < neighbors.Count; i++) { T neighbor = neighbors[i]; double minCost; // skip nodes with better path _pathCosts.TryGetValue(neighbor, out minCost); if (minCost != 0 && minCost <= cost) { continue; } // skip unreachable nodes if (!_agent.CanMakeStep(node, neighbor)) { continue; } // get cost for next movement step double stepCost = _agent.GetStepCost(node, neighbor); Debug.Assert(stepCost > 0); // skip unaffordable nodes if (!_agent.RelaxedRange && cost + stepCost > _maxCost) { continue; } // skip nodes with better path if (minCost != 0 && minCost <= cost + stepCost) { continue; } // add newly reached neighbor if possible if (minCost == 0 && _agent.CanOccupy(neighbor)) { _nodes.Add(neighbor); } // store new minimum path cost _pathCosts[neighbor] = cost + stepCost; // visit neighbors if still affordable if (cost + stepCost < _maxCost) { ExpandArea(neighbor, cost + stepCost); } } }
/// <summary> /// Adds all valid neighbors as children to the specified parent node.</summary> /// <param name="parent"> /// The <see cref="PathNode{T}"/> whose neighbors to examine.</param> private void CreateChildren(PathNode <T> parent) { T source = parent.Node; // compute direct neighbors of parent node IList <T> neighbors = Graph.GetNeighbors(source); // link all children that can be reached for (int i = 0; i < neighbors.Count; i++) { T neighbor = neighbors[i]; if (_agent.CanMakeStep(source, neighbor)) { LinkChild(parent, neighbor); } } }
/// <summary> /// Expands the current collection of obscuring <see cref="Graph"/> nodes with all neighbors /// of the specified node, within maximum world distance from the source node.</summary> /// <param name="node"> /// The <see cref="Graph"/> node whose neighbors to examine.</param> /// <remarks><para> /// <b>FindObscuringNodes</b> recursively visits all directly connected nodes, and adds them /// to an internal collection of obscuring nodes if they are opaque. Nodes which are fully /// obscured by other obscuring nodes are removed from the collection. /// </para><para> /// <b>FindObscuringNodes</b> never revisits nodes that were already examined. All visited /// nodes are added to <see cref="NodeArcs"/> for later processing by <see /// cref="FindVisibleNodes"/>.</para></remarks> private void FindObscuringNodes(T node) { // get valid neighbors of current node IList <T> neighbors = Graph.GetNeighbors(node); // recurse into all valid neighbors for (int i = 0; i < neighbors.Count; i++) { T neighbor = neighbors[i]; // skip source and previously visited nodes if (ComparerCache <T> .EqualityComparer.Equals(_source, neighbor) || _nodeArcs.ContainsKey(neighbor)) { continue; } // compute tangential arc and source distance NodeArc arc = CreateNodeArc(neighbor); // skip nodes beyond maximum distance if (_distance > 0 && arc.Distance > _distance) { continue; } // record visited node with tangential arc _nodeArcs.Add(neighbor, arc); // nothing else to do for transparent nodes if (!_isOpaque(neighbor)) { goto nextNeighbor; } /* * Try adding current opaque node to list of all obscuring nodes recorded so far. * * If any single recorded node completely obscures the current node, we skip it. * If the current node completely obscures any recorded nodes, we delete those. * * We also clear the VisiblityFraction for all completely obscured nodes (current * or recorded) so we won't waste time testing them again in FindVisibleNodes. */ foreach (var pair in _obscuringNodes) { int result = arc.IsObscured(pair.Value); if (result < 0) { arc._visibleFraction = 0; goto nextNeighbor; } if (result > 0) { pair.Value._visibleFraction = 0; _removeNodes.Add(pair.Key); } } // remove obscuring nodes that were themselves obscured for (int j = 0; j < _removeNodes.Count; j++) { _obscuringNodes.Remove(_removeNodes[j]); } _removeNodes.Clear(); // add neighbor to obscuring nodes _obscuringNodes.Add(neighbor, arc); nextNeighbor: FindObscuringNodes(neighbor); } }