Example #1
0
        /**
         * Returns the nearest node to a position using the specified NNConstraint.
         * Searches through all graphs for their nearest nodes to the specified position and picks the closest one.
         * The NNConstraint can be used to specify constraints on which nodes can be chosen such as only picking walkable nodes.
         * \see Pathfinding.NNConstraint
         */
        public static NNInfo GetNearest(Vector3 position, NNConstraint constraint, GraphNode hint)
        {
            // Cache property lookup
            var localGraphs = GetConfig().graphs;

            float          minDist      = float.PositiveInfinity;
            NNInfoInternal nearestNode  = new NNInfoInternal();
            int            nearestGraph = -1;

            if (localGraphs != null)
            {
                for (int i = 0; i < localGraphs.Length; i++)
                {
                    NavGraph graph = localGraphs[i];

                    // Check if this graph should be searched
                    if (graph == null || !constraint.SuitableGraph(i, graph))
                    {
                        continue;
                    }

                    NNInfoInternal nnInfo;
                    if (GetConfig().fullGetNearestSearch)
                    {
                        // Slower nearest node search
                        // this will try to find a node which is suitable according to the constraint
                        nnInfo = graph.GetNearestForce(position, constraint);
                    }
                    else
                    {
                        // Fast nearest node search
                        // just find a node close to the position without using the constraint that much
                        // (unless that comes essentially 'for free')
                        nnInfo = graph.GetNearest(position, constraint);
                    }

                    GraphNode node = nnInfo.node;

                    // No node found in this graph
                    if (node == null)
                    {
                        continue;
                    }

                    // Distance to the closest point on the node from the requested position
                    float dist = ((Vector3)nnInfo.clampedPosition - position).magnitude;

                    if (GetConfig().prioritizeGraphs&& dist < GetConfig().prioritizeGraphsLimit)
                    {
                        // The node is close enough, choose this graph and discard all others
                        minDist      = dist;
                        nearestNode  = nnInfo;
                        nearestGraph = i;
                        break;
                    }
                    else
                    {
                        // Choose the best node found so far
                        if (dist < minDist)
                        {
                            minDist      = dist;
                            nearestNode  = nnInfo;
                            nearestGraph = i;
                        }
                    }
                }
            }

            // No matches found
            if (nearestGraph == -1)
            {
                return(new NNInfo());
            }

            // Check if a constrained node has already been set
            if (nearestNode.constrainedNode != null)
            {
                nearestNode.node            = nearestNode.constrainedNode;
                nearestNode.clampedPosition = nearestNode.constClampedPosition;
            }

            if (!GetConfig().fullGetNearestSearch&& nearestNode.node != null && !constraint.Suitable(nearestNode.node))
            {
                // Otherwise, perform a check to force the graphs to check for a suitable node
                NNInfoInternal nnInfo = localGraphs[nearestGraph].GetNearestForce(position, constraint);

                if (nnInfo.node != null)
                {
                    nearestNode = nnInfo;
                }
            }

            if (!constraint.Suitable(nearestNode.node) || (constraint.constrainDistance &&
                                                           (nearestNode.clampedPosition - position).sqrMagnitude > GetConfig().maxNearestNodeDistanceSqr))
            {
                return(new NNInfo());
            }

            // Convert to NNInfo which doesn't have all the internal fields
            return(new NNInfo(nearestNode));
        }
Example #2
0
        /** Queries the tree for the closest node to \a p constrained by the NNConstraint trying to improve an existing solution.
         * Note that this function will only fill in the constrained node.
         * If you want a node not constrained by any NNConstraint, do an additional search with constraint = NNConstraint.None
         *
         * \param p Point to search around
         * \param constraint Optionally set to constrain which nodes to return
         * \param distance The best distance for the \a previous solution. Will be updated with the best distance
         * after this search. Will be positive infinity if no node could be found.
         * Set to positive infinity if there was no previous solution.
         * \param previous This search will start from the \a previous NNInfo and improve it if possible.
         * Even if the search fails on this call, the solution will never be worse than \a previous.
         */
        public NNInfoInternal QueryClosest(Vector3 p, NNConstraint constraint, ref float distance, NNInfoInternal previous)
        {
            var sqrDistance     = distance * distance;
            var origSqrDistance = sqrDistance;

            if (count > 0 && SquaredRectPointDistance(tree[0].rect, p) < sqrDistance)
            {
                SearchBoxClosest(0, p, ref sqrDistance, constraint, ref previous);
                // Only update the distance if the squared distance changed as otherwise #distance
                // might change due to rounding errors even if no better solution was found
                if (sqrDistance < origSqrDistance)
                {
                    distance = Mathf.Sqrt(sqrDistance);
                }
            }
            return(previous);
        }
Example #3
0
        void SearchBoxClosest(int boxi, Vector3 p, ref float closestSqrDist, NNConstraint constraint, ref NNInfoInternal nnInfo)
        {
            BBTreeBox box = tree[boxi];

            if (box.IsLeaf)
            {
                var nodes = nodeLookup;
                for (int i = 0; i < MaximumLeafSize && nodes[box.nodeOffset + i] != null; i++)
                {
                    var     node    = nodes[box.nodeOffset + i];
                    Vector3 closest = node.ClosestPointOnNode(p);
                    float   dist    = (closest - p).sqrMagnitude;
                    if (dist < closestSqrDist)
                    {
#if !SERVER
                        DrawDebugNode(node, 0.2f, UnityEngine.Color.red);
#endif

                        if (constraint == null || constraint.Suitable(node))
                        {
                            // Update the NNInfo
                            nnInfo.constrainedNode      = node;
                            nnInfo.constClampedPosition = closest;
                            closestSqrDist = dist;
                        }
                    }
                    else
                    {
#if !SERVER
                        DrawDebugNode(node, 0.0f, UnityEngine.Color.blue);
#endif
                    }
                }
            }
            else
            {
#if !SERVER
                DrawDebugRect(box.rect);
#endif
                int   first = box.left, second = box.right;
                float firstDist, secondDist;
                GetOrderedChildren(ref first, ref second, out firstDist, out secondDist, p);

                // Search children (closest box first to improve performance)
                if (firstDist < closestSqrDist)
                {
                    SearchBoxClosest(first, p, ref closestSqrDist, constraint, ref nnInfo);
                }

                if (secondDist < closestSqrDist)
                {
                    SearchBoxClosest(second, p, ref closestSqrDist, constraint, ref nnInfo);
                }
            }
        }
Example #4
0
        void SearchBoxClosestXZ(int boxi, Vector3 p, ref float closestSqrDist, NNConstraint constraint, ref NNInfoInternal nnInfo)
        {
            BBTreeBox box = tree[boxi];

            if (box.IsLeaf)
            {
                var nodes = nodeLookup;
                for (int i = 0; i < MaximumLeafSize && nodes[box.nodeOffset + i] != null; i++)
                {
                    var node = nodes[box.nodeOffset + i];
                    // Update the NNInfo
#if !SERVER
                    DrawDebugNode(node, 0.2f, UnityEngine.Color.red);
#endif

                    if (constraint == null || constraint.Suitable(node))
                    {
                        Vector3 closest = node.ClosestPointOnNodeXZ(p);
                        // XZ squared distance
                        float dist = (closest.x - p.x) * (closest.x - p.x) + (closest.z - p.z) * (closest.z - p.z);

                        // There's a theoretical case when the closest point is on the edge of a node which may cause the
                        // closest point's xz coordinates to not line up perfectly with p's xz coordinates even though they should
                        // (because floating point errors are annoying). So use a tiny margin to cover most of those cases.
                        const float fuzziness = 0.000001f;
                        if (nnInfo.constrainedNode == null || dist < closestSqrDist - fuzziness || (dist <= closestSqrDist + fuzziness && Mathf.Abs(closest.y - p.y) < Mathf.Abs(nnInfo.constClampedPosition.y - p.y)))
                        {
                            nnInfo.constrainedNode      = node;
                            nnInfo.constClampedPosition = closest;
                            closestSqrDist = dist;
                        }
                    }
                }
            }
            else
            {
#if !SERVER
                DrawDebugRect(box.rect);
#endif

                int   first = box.left, second = box.right;
                float firstDist, secondDist;
                GetOrderedChildren(ref first, ref second, out firstDist, out secondDist, p);

                // Search children (closest box first to improve performance)
                if (firstDist <= closestSqrDist)
                {
                    SearchBoxClosestXZ(first, p, ref closestSqrDist, constraint, ref nnInfo);
                }

                if (secondDist <= closestSqrDist)
                {
                    SearchBoxClosestXZ(second, p, ref closestSqrDist, constraint, ref nnInfo);
                }
            }
        }