Exemplo n.º 1
0
        /// <summary>
        /// Finds all contiguous <see cref="Graph"/> nodes within the specified maximum world
        /// distance that are visible from the specified node.</summary>
        /// <param name="isOpaque">
        /// The <see cref="Predicate{T}"/> delegate that determines whether a <see cref="Graph"/>
        /// node blocks the line of sight.</param>
        /// <param name="source">
        /// The source node within <see cref="Graph"/> where the search starts.</param>
        /// <param name="distance"><para>
        /// The maximum world distance from the specified <paramref name="source"/> to search.
        /// </para><para>-or-</para><para>
        /// Zero to search the entire <see cref="Graph"/>. The default is zero.</para></param>
        /// <returns>
        /// <c>true</c> if one or more nodes are visible from <paramref name="source"/> within the
        /// specified <paramref name="distance"/>; otherwise, <c>false</c>.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="isOpaque"/> or <paramref name="source"/> is a null reference.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="distance"/> is less than zero.</exception>
        /// <remarks><para>
        /// <b>FindVisible</b> returns <c>false</c> if the specified <paramref name="source"/> node
        /// is invalid, or if there are no visible nodes. Otherwise, <b>FindVisible</b> returns
        /// <c>true</c> and sets the <see cref="Nodes"/> and <see cref="NodeArcs"/> properties to
        /// the result of the visibility search.
        /// </para><para>
        /// All nodes within the specified maximum <paramref name="distance"/> are considered
        /// visible, except for those that are obscured by a node for which <paramref
        /// name="isOpaque"/> succeeds, as described for the <see cref="Visibility{T}"/> class.
        /// </para><para>
        /// If <paramref name="distance"/> is positive, any visible node must be reachable by a path
        /// that only includes other nodes within <paramref name="distance"/>; otherwise, it will
        /// not be found. This condition holds for any <see cref="PolygonGrid"/>, and for any <see
        /// cref="Subdivision"/> that was created from a Delaunay triangulation.</para></remarks>

        public bool FindVisible(Predicate <T> isOpaque, T source, double distance = 0)
        {
            if (isOpaque == null)
            {
                ThrowHelper.ThrowArgumentNullException("isOpaque");
            }
            if (source == null)
            {
                ThrowHelper.ThrowArgumentNullException("source");
            }
            if (distance < 0)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException(
                    "distance", distance, Strings.ArgumentNegative);
            }

            // clear previous results
            _nodes.Clear();
            _nodeArcs.Clear();

            // fail if source node is invalid
            if (!Graph.Contains(source))
            {
                return(false);
            }

            _isOpaque = isOpaque;
            _source   = source;
            _distance = distance;

            // compute world coordinates of source node
            _sourceWorld = Graph.GetWorldLocation(source);

            // expand visibility area from source
            FindObscuringNodes(source);
            FindVisibleNodes();

            // clear intermediate data
            _isOpaque = null;
            _source   = default(T);
            _obscuringNodes.Clear();

            // succeed if any nodes reached
            return(_nodes.Count > 0);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Finds the best path to move the specified agent from one specified <see cref="Graph"/>
        /// node to another.</summary>
        /// <param name="agent">
        /// The <see cref="IGraphAgent{T}"/> that performs the movement.</param>
        /// <param name="source">
        /// The source node within <see cref="Graph"/>.</param>
        /// <param name="target">
        /// The target node within <see cref="Graph"/>.</param>
        /// <returns>
        /// <c>true</c> if a best path between <paramref name="source"/> and <paramref
        /// name="target"/> could be found; otherwise, <c>false</c>.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="agent"/>, <paramref name="source"/>, or <paramref name="target"/> is a
        /// null reference.</exception>
        /// <remarks><para>
        /// <b>FindBestPath</b> returns <c>false</c> if either of the specified <paramref
        /// name="source"/> and <paramref name="target"/> nodes is invalid, or if no connecting path
        /// could be found.
        /// </para><para>
        /// Otherwise, <b>FindBestPath</b> returns <c>true</c> and sets the <see cref="BestNode"/>,
        /// <see cref="Nodes"/>, and <see cref="TotalCost"/> properties to the results of the path
        /// search.
        /// </para><para>
        /// <b>FindBestPath</b> calls <see cref="IGraphAgent{T}.CanOccupy"/> and <see
        /// cref="IGraphAgent{T}.IsNearTarget"/> on the specified <paramref name="agent"/> to
        /// determine whether a given <see cref="BestNode"/> candidate is acceptable. Depending on
        /// the implementation of <b>IsNearTarget</b>, the <see cref="PathNode{T}.Node"/> of the
        /// final <see cref="BestNode"/> may differ from the specified <paramref name="target"/>,
        /// and possibly equal the specified <paramref name="source"/>. <b>CanOccupy</b> is never
        /// called on path nodes that match the <paramref name="source"/> node.
        /// </para><para>
        /// <b>FindBestPath</b> operates with a <em>restricted search radius</em> if <see
        /// cref="RelativeLimit"/> is greater than zero. In this case, <see cref="AbsoluteLimit"/>
        /// is set to the product (rounded up) of <b>RelativeLimit</b> and the distance between
        /// <paramref name="source"/> and <paramref name="target"/>. Whenever a node is considered
        /// for inclusion in the search path, its distances from <paramref name="source"/> and
        /// <paramref name="target"/> are calculated, and the node is ignored if the sum exceeds
        /// <b>AbsoluteLimit</b>.</para></remarks>

        public bool FindBestPath(IGraphAgent <T> agent, T source, T target)
        {
            if (agent == null)
            {
                ThrowHelper.ThrowArgumentNullException("agent");
            }
            if (source == null)
            {
                ThrowHelper.ThrowArgumentNullException("source");
            }
            if (target == null)
            {
                ThrowHelper.ThrowArgumentNullException("target");
            }

            _agent  = agent;
            _source = source;
            _target = target;

            // clear previous results
            _absoluteLimit = 0;
            _bestNode      = null;
            _nodes.Clear();
            _targetWorld = PointD.Empty;

            // fail if either node is invalid
            if (!Graph.Contains(source) || !Graph.Contains(target))
            {
                return(false);
            }

            // compute absolute distance limit if desired
            double distance = Graph.GetDistance(source, target);

            if (_relativeLimit > 0)
            {
                _absoluteLimit = distance * _relativeLimit;
            }

            // compute world distance to target if desired
            if (UseWorldDistance)
            {
                _targetWorld = Graph.GetWorldLocation(target);
            }

            // initialize search list
            _openList    = new PathNode <T>(source, Graph.Connectivity);
            _openList._h = distance;

            bool success = false;

            while (SetBestNode())
            {
                T node = _bestNode.Node;

                // succeed if occupation target is in range
                if (_agent.IsNearTarget(node, target, _bestNode._h) &&
                    (ComparerCache <T> .EqualityComparer.Equals(source, node) ||
                     _agent.CanOccupy(node)))
                {
                    success = true;
                    break;
                }

                // add children to search space
                CreateChildren(_bestNode);
            }

            // clear intermediate data
            _source = _target = default(T);
            Debug.Assert(_parents.Count == 0);
            _openList = null;
            _openTable.Clear();
            _closedTable.Clear();

            return(success);
        }