Exemple #1
0
        public void Query(TSVector p, FP speed, FP timeHorizon, FP TRadius, T T)
        {
            QuadtreeQuery tmp = new QuadtreeQuery();

            tmp.p           = p;
            tmp.speed       = speed;
            tmp.timeHorizon = timeHorizon;
            tmp.maxRadius   = FP.One * 1000000;//avoid overflow
            tmp.TRadius     = TRadius;
            tmp.T           = T;
            tmp.nodes       = nodes;
            tmp.QueryRec(0, bounds);
        }
        public void QueryKNearest(QuadtreeQuery query)
        {
            if (!agents.IsCreated)
            {
                return;
            }
            float maxRadius = float.PositiveInfinity;

            for (int i = 0; i < query.maxCount; i++)
            {
                query.result[query.outputStartIndex + i] = -1;
            }
            for (int i = 0; i < query.maxCount; i++)
            {
                query.resultDistances[i] = float.PositiveInfinity;
            }

            QueryRec(ref query, 0, boundingBoxBuffer[0], boundingBoxBuffer[1], ref maxRadius);
        }
        void QueryRec(ref QuadtreeQuery query, int treeNodeIndex, float3 nodeMin, float3 nodeMax, ref float maxRadius)
        {
            // Note: the second agentRadius usage should actually be the radius of the other agents, not this agent
            // Determine the radius that we need to search to take all agents into account
            // but for performance reasons and for simplicity we assume that agents have approximately the same radius.
            // Thus an agent with a very small radius may in some cases detect an agent with a very large radius too late
            // however this effect should be minor.
            var    radius = math.min(math.max((maxSpeeds[treeNodeIndex] + query.speed) * query.timeHorizon, query.agentRadius) + query.agentRadius, maxRadius);
            float3 p      = query.position;

            if ((childPointers[treeNodeIndex] & LeafNodeBit) != 0)
            {
                // Leaf node
                int maxCount   = query.maxCount;
                int startIndex = childPointers[treeNodeIndex] & BitPackingMask;
                int endIndex   = (childPointers[treeNodeIndex] >> BitPackingShift) & BitPackingMask;

                var result          = query.result;
                var resultDistances = query.resultDistances;
                for (int j = startIndex; j < endIndex; j++)
                {
                    var   agent       = agents[j];
                    float sqrDistance = math.lengthsq(p - agentPositions[agent]);
                    if (sqrDistance < radius * radius)
                    {
                        // Close enough

                        // Insert the agent into the results list using insertion sort
                        for (int k = 0; k < maxCount; k++)
                        {
                            if (sqrDistance < resultDistances[k])
                            {
                                // Move the remaining items one step in the array
                                for (int q = maxCount - 1; q > k; q--)
                                {
                                    result[query.outputStartIndex + q] = result[query.outputStartIndex + q - 1];
                                    resultDistances[q] = resultDistances[q - 1];
                                }
                                result[query.outputStartIndex + k] = agent;
                                resultDistances[k] = sqrDistance;

                                if (k == maxCount - 1)
                                {
                                    // We reached the end of the array. This means that we just updated the largest distance.
                                    // We can use this to restrict the future search. We know that no other agent distance we find can be larger than this value.
                                    maxRadius = math.min(maxRadius, math.sqrt(sqrDistance));
                                    radius    = math.min(radius, maxRadius);
                                }
                                break;
                            }
                        }
                    }
                }
            }
            else
            {
                // Not a leaf node
                int childIndex = childPointers[treeNodeIndex];

                float3 nodeMid = (nodeMin + nodeMax) * 0.5f;
                if (movementPlane == MovementPlane.Arbitrary)
                {
                    if (p.x - radius < nodeMid.x)
                    {
                        if (p.y - radius < nodeMid.y)
                        {
                            if (p.z - radius < nodeMid.z)
                            {
                                QueryRec(ref query, childIndex + 0, new float3(nodeMin.x, nodeMin.y, nodeMin.z), new float3(nodeMid.x, nodeMid.y, nodeMid.z), ref maxRadius);
                                radius = math.min(radius, maxRadius);
                            }
                            if (p.z + radius > nodeMid.z)
                            {
                                QueryRec(ref query, childIndex + 1, new float3(nodeMin.x, nodeMin.y, nodeMid.z), new float3(nodeMid.x, nodeMid.y, nodeMax.z), ref maxRadius);
                                radius = math.min(radius, maxRadius);
                            }
                        }
                        if (p.y + radius > nodeMid.y)
                        {
                            if (p.z - radius < nodeMid.z)
                            {
                                QueryRec(ref query, childIndex + 2, new float3(nodeMin.x, nodeMid.y, nodeMin.z), new float3(nodeMid.x, nodeMax.y, nodeMid.z), ref maxRadius);
                                radius = math.min(radius, maxRadius);
                            }
                            if (p.z + radius > nodeMid.z)
                            {
                                QueryRec(ref query, childIndex + 3, new float3(nodeMin.x, nodeMid.y, nodeMid.z), new float3(nodeMid.x, nodeMax.y, nodeMax.z), ref maxRadius);
                                radius = math.min(radius, maxRadius);
                            }
                        }
                    }
                    if (p.x + radius > nodeMid.x)
                    {
                        if (p.y - radius < nodeMid.y)
                        {
                            if (p.z - radius < nodeMid.z)
                            {
                                QueryRec(ref query, childIndex + 4, new float3(nodeMid.x, nodeMin.y, nodeMin.z), new float3(nodeMax.x, nodeMid.y, nodeMid.z), ref maxRadius);
                                radius = math.min(radius, maxRadius);
                            }
                            if (p.z + radius > nodeMid.z)
                            {
                                QueryRec(ref query, childIndex + 5, new float3(nodeMid.x, nodeMin.y, nodeMid.z), new float3(nodeMax.x, nodeMid.y, nodeMax.z), ref maxRadius);
                                radius = math.min(radius, maxRadius);
                            }
                        }
                        if (p.y + radius > nodeMid.y)
                        {
                            if (p.z - radius < nodeMid.z)
                            {
                                QueryRec(ref query, childIndex + 6, new float3(nodeMid.x, nodeMid.y, nodeMin.z), new float3(nodeMax.x, nodeMax.y, nodeMid.z), ref maxRadius);
                                radius = math.min(radius, maxRadius);
                            }
                            if (p.z + radius > nodeMid.z)
                            {
                                QueryRec(ref query, childIndex + 7, new float3(nodeMid.x, nodeMid.y, nodeMid.z), new float3(nodeMax.x, nodeMax.y, nodeMax.z), ref maxRadius);
                                radius = math.min(radius, maxRadius);
                            }
                        }
                    }
                }
                else if (movementPlane == MovementPlane.XY)
                {
                    if (p.x - radius < nodeMid.x)
                    {
                        if (p.y - radius < nodeMid.y)
                        {
                            QueryRec(ref query, childIndex + 0, new float3(nodeMin.x, nodeMin.y, nodeMin.z), new float3(nodeMid.x, nodeMid.y, nodeMax.z), ref maxRadius);
                            radius = math.min(radius, maxRadius);
                        }
                        if (p.y + radius > nodeMid.y)
                        {
                            QueryRec(ref query, childIndex + 1, new float3(nodeMin.x, nodeMid.y, nodeMin.z), new float3(nodeMid.x, nodeMax.y, nodeMax.z), ref maxRadius);
                            radius = math.min(radius, maxRadius);
                        }
                    }
                    if (p.x + radius > nodeMid.x)
                    {
                        if (p.y - radius < nodeMid.y)
                        {
                            QueryRec(ref query, childIndex + 2, new float3(nodeMid.x, nodeMin.y, nodeMin.z), new float3(nodeMax.x, nodeMid.y, nodeMax.z), ref maxRadius);
                            radius = math.min(radius, maxRadius);
                        }
                        if (p.y + radius > nodeMid.y)
                        {
                            QueryRec(ref query, childIndex + 3, new float3(nodeMid.x, nodeMid.y, nodeMin.z), new float3(nodeMax.x, nodeMax.y, nodeMax.z), ref maxRadius);
                            radius = math.min(radius, maxRadius);
                        }
                    }
                }
                else
                {
                    if (p.x - radius < nodeMid.x)
                    {
                        if (p.z - radius < nodeMid.z)
                        {
                            QueryRec(ref query, childIndex + 0, new float3(nodeMin.x, nodeMin.y, nodeMin.z), new float3(nodeMid.x, nodeMax.y, nodeMid.z), ref maxRadius);
                            radius = math.min(radius, maxRadius);
                        }
                        if (p.z + radius > nodeMid.z)
                        {
                            QueryRec(ref query, childIndex + 1, new float3(nodeMin.x, nodeMin.y, nodeMid.z), new float3(nodeMid.x, nodeMax.y, nodeMax.z), ref maxRadius);
                            radius = math.min(radius, maxRadius);
                        }
                    }
                    if (p.x + radius > nodeMid.x)
                    {
                        if (p.z - radius < nodeMid.z)
                        {
                            QueryRec(ref query, childIndex + 2, new float3(nodeMid.x, nodeMin.y, nodeMin.z), new float3(nodeMax.x, nodeMax.y, nodeMid.z), ref maxRadius);
                            radius = math.min(radius, maxRadius);
                        }
                        if (p.z + radius > nodeMid.z)
                        {
                            QueryRec(ref query, childIndex + 3, new float3(nodeMid.x, nodeMin.y, nodeMid.z), new float3(nodeMax.x, nodeMax.y, nodeMax.z), ref maxRadius);
                            radius = math.min(radius, maxRadius);
                        }
                    }
                }
            }
        }