/// <summary>Gets a leaf node from a given point.</summary>
        /// <param name="pt">the point to retrieve the parent node from</param>
        /// <returns>the node which contains the given point; null if the point is invalid</returns>
        internal ZoneSpacePartitionNode GetLeafFromPoint(ref Vector3 pt)
        {
            if (IsLeaf)
            {
                if (m_bounds.Contains(ref pt))
                {
                    return(this);
                }
                return(null);
            }

            for (int index1 = 0; index1 < 2; ++index1)
            {
                for (int index2 = 0; index2 < 2; ++index2)
                {
                    ZoneSpacePartitionNode child = m_children[index1, index2];
                    if (child.Bounds.Contains(ref pt))
                    {
                        return(child.GetLeafFromPoint(ref pt));
                    }
                }
            }

            return(null);
        }
        /// <summary>Iterates over all objects in this Node.</summary>
        /// <param name="predicate">Returns whether to continue iteration.</param>
        /// <returns>Whether Iteration was not cancelled (usually indicating that we did not find what we were looking for).</returns>
        internal bool Iterate(ref BoundingSphere sphere, Func <WorldObject, bool> predicate, uint phase)
        {
            if (IsLeaf)
            {
                if (HasObjects)
                {
                    foreach (WorldObject worldObject in m_objects.Values)
                    {
                        Vector3 position = worldObject.Position;
                        if (sphere.Contains(ref position) && worldObject.IsInPhase(phase) && !predicate(worldObject))
                        {
                            return(false);
                        }
                    }
                }
            }
            else
            {
                for (int index1 = 0; index1 < 2; ++index1)
                {
                    for (int index2 = 0; index2 < 2; ++index2)
                    {
                        ZoneSpacePartitionNode child = m_children[index1, index2];
                        if (child.Bounds.Intersects(ref sphere).HasAnyFlag(IntersectionType.Touches) &&
                            !child.Iterate(ref sphere, predicate, phase))
                        {
                            return(false);
                        }
                    }
                }
            }

            return(true);
        }
        /// <summary>Adds an object to the node.</summary>
        /// <param name="obj">the object to add</param>
        /// <returns>whether or not the object was added successfully</returns>
        internal bool AddObject(WorldObject obj)
        {
            if (IsLeaf)
            {
                if (m_objects.ContainsKey(obj.EntityId))
                {
                    throw new ArgumentException(string.Format(
                                                    "Tried to add Object \"{0}\" with duplicate EntityId {1} to Map.", obj,
                                                    obj.EntityId));
                }
                m_objects.Add(obj.EntityId, obj);
                obj.Node = this;
                return(true);
            }

            Vector3 position = obj.Position;

            for (int index1 = 0; index1 < 2; ++index1)
            {
                for (int index2 = 0; index2 < 2; ++index2)
                {
                    ZoneSpacePartitionNode child = m_children[index1, index2];
                    if (child.Bounds.Contains(ref position))
                    {
                        return(child.AddObject(obj));
                    }
                }
            }

            return(false);
        }
        /// <summary>
        /// Partitions the node, dividing it into subnodes until the desired depth is reached.
        /// </summary>
        /// <param name="maxLevels">the maximum depth to partition</param>
        /// <param name="startingDepth">the depth to start partitioning from</param>
        internal void PartitionSpace(ZoneSpacePartitionNode parent, int maxLevels, int startingDepth)
        {
            float num1 = Length / 2f;
            float num2 = Width / 2f;

            if (startingDepth < maxLevels && num1 > (double)MinNodeLength &&
                num2 > (double)MinNodeLength)
            {
                m_children       = new ZoneSpacePartitionNode[2, 2];
                m_children[1, 0] = new ZoneSpacePartitionNode(new BoundingBox(
                                                                  new Vector3(m_bounds.Min.X, m_bounds.Min.Y, m_bounds.Min.Z),
                                                                  new Vector3(m_bounds.Min.X + num1, m_bounds.Min.Y + num2, m_bounds.Max.Z)));
                m_children[0, 0] = new ZoneSpacePartitionNode(new BoundingBox(
                                                                  new Vector3(m_bounds.Min.X, m_bounds.Min.Y + num2, m_bounds.Min.Z),
                                                                  new Vector3(m_bounds.Min.X + num1, m_bounds.Max.Y, m_bounds.Max.Z)));
                m_children[1, 1] = new ZoneSpacePartitionNode(new BoundingBox(
                                                                  new Vector3(m_bounds.Min.X + num1, m_bounds.Min.Y, m_bounds.Min.Z),
                                                                  new Vector3(m_bounds.Max.X, m_bounds.Min.Y + num2, m_bounds.Max.Z)));
                m_children[0, 1] = new ZoneSpacePartitionNode(new BoundingBox(
                                                                  new Vector3(m_bounds.Min.X + num1, m_bounds.Min.Y + num2, m_bounds.Min.Z),
                                                                  new Vector3(m_bounds.Max.X, m_bounds.Max.Y, m_bounds.Max.Z)));
                ++startingDepth;
                for (int index1 = 0; index1 < 2; ++index1)
                {
                    for (int index2 = 0; index2 < 2; ++index2)
                    {
                        m_children[index1, index2].PartitionSpace(this, maxLevels, startingDepth);
                    }
                }
            }
            else
            {
                m_objects = new Dictionary <EntityId, WorldObject>(0);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Partitions the node, dividing it into subnodes until the desired depth is reached.
        /// </summary>
        /// <param name="maxLevels">the maximum depth to partition</param>
        /// <param name="startingDepth">the depth to start partitioning from</param>
        internal void PartitionSpace(ZoneSpacePartitionNode parent, int maxLevels, int startingDepth)
        {
            var width  = Length / Two;
            var height = Width / Two;

            if (startingDepth < maxLevels && width > MinNodeLength && height > MinNodeLength)
            {
                m_children = new ZoneSpacePartitionNode[Two, Two];

                // Bottom left
                m_children[SOUTH, WEST] =
                    new ZoneSpacePartitionNode(
                        new BoundingBox(new Vector3(m_bounds.Min.X, m_bounds.Min.Y, m_bounds.Min.Z),
                                        new Vector3(m_bounds.Min.X + width, m_bounds.Min.Y + height, m_bounds.Max.Z)));

                // Top left
                m_children[NORTH, WEST] =
                    new ZoneSpacePartitionNode(
                        new BoundingBox(new Vector3(m_bounds.Min.X, m_bounds.Min.Y + height, m_bounds.Min.Z),
                                        new Vector3(m_bounds.Min.X + width, m_bounds.Max.Y, m_bounds.Max.Z)));

                // Bottom right
                m_children[SOUTH, EAST] =
                    new ZoneSpacePartitionNode(
                        new BoundingBox(new Vector3(m_bounds.Min.X + width, m_bounds.Min.Y, m_bounds.Min.Z),
                                        new Vector3(m_bounds.Max.X, m_bounds.Min.Y + height, m_bounds.Max.Z)));

                // Top right
                m_children[NORTH, EAST] =
                    new ZoneSpacePartitionNode(
                        new BoundingBox(new Vector3(m_bounds.Min.X + width, m_bounds.Min.Y + height, m_bounds.Min.Z),
                                        new Vector3(m_bounds.Max.X, m_bounds.Max.Y, m_bounds.Max.Z)));

                // Set the next level's depth
                startingDepth++;

                // Partition any further depths
                for (var i0 = 0; i0 < Two; i0++)
                {
                    for (var i1 = 0; i1 < Two; i1++)
                    {
                        var node = m_children[i0, i1];
                        node.PartitionSpace(this, maxLevels, startingDepth);
                    }
                }
            }
            else
            {
                m_objects = new Dictionary <EntityId, WorldObject>(0);
            }
        }
Beispiel #6
0
        //private static Dictionary<int, ZoneSpacePartitionNode[,]> m_raster = new Dictionary<int, ZoneSpacePartitionNode[,]>();

        // private static Dictionary<int, ZoneSpacePartitionNode[,]> m_raster = new Dictionary<int, ZoneSpacePartitionNode[,]>();

        ///// <summary>
        ///// Partitions the node, dividing it into subnodes until the desired depth is reached.
        ///// </summary>
        ///// <param name="maxLevels">the maximum depth to partition</param>
        ///// <param name="startingDepth">the depth to start partitioning from</param>
        //internal void PartitionSpace(int maxLevels, int startingDepth, int nodeY, int nodeX, int nodesCountAtCurrentDepth)
        //{
        //    float incX = Length / 2;
        //    float incY = Width / 2;

        //    if (!m_raster.ContainsKey(startingDepth))
        //    {
        //        m_raster.Add(startingDepth, new ZoneSpacePartitionNode[nodesCountAtCurrentDepth, nodesCountAtCurrentDepth]);
        //    }

        //    if (m_raster[startingDepth][nodeY, nodeX] != null)
        //    {
        //        throw new Exception();
        //    }

        //    m_raster[startingDepth][nodeY, nodeX] = this;

        //    if (startingDepth < maxLevels)
        //    {
        //        m_children = new ZoneSpacePartitionNode[2, 2];

        //        // Bottom left
        //        m_children[SOUTH, WEST] =
        //            new ZoneSpacePartitionNode(
        //                new BoundingBox(new Vector3(m_bounds.Min.X, m_bounds.Min.Y, m_bounds.Min.Z),
        //                                new Vector3(m_bounds.Min.X + incX, m_bounds.Min.Y + incY, m_bounds.Max.Z)));

        //        // Top left
        //        m_children[NORTH, WEST] =
        //            new ZoneSpacePartitionNode(
        //                new BoundingBox(new Vector3(m_bounds.Min.X, m_bounds.Min.Y + incY, m_bounds.Min.Z),
        //                                new Vector3(m_bounds.Min.X + incX, m_bounds.Max.Y, m_bounds.Max.Z)));

        //        // Bottom right
        //        m_children[SOUTH, EAST] =
        //            new ZoneSpacePartitionNode(
        //                new BoundingBox(new Vector3(m_bounds.Min.X + incX, m_bounds.Min.Y, m_bounds.Min.Z),
        //                                new Vector3(m_bounds.Max.X, m_bounds.Min.Y + incY, m_bounds.Max.Z)));

        //        // Top right
        //        m_children[NORTH, EAST] =
        //            new ZoneSpacePartitionNode(
        //                new BoundingBox(new Vector3(m_bounds.Min.X + incX, m_bounds.Min.Y + incY, m_bounds.Min.Z),
        //                                new Vector3(m_bounds.Max.X, m_bounds.Max.Y, m_bounds.Max.Z)));



        //        // Set the next level's depth
        //        startingDepth++;

        //        int newNodesCount = nodesCountAtCurrentDepth * 2;

        //        m_children[SOUTH, WEST].PartitionSpace(maxLevels, startingDepth, nodeY * 2 + SOUTH, nodeX * 2 + WEST, newNodesCount);
        //        m_children[NORTH, WEST].PartitionSpace(maxLevels, startingDepth, nodeY * 2 + NORTH, nodeX * 2 + WEST, newNodesCount);
        //        m_children[SOUTH, EAST].PartitionSpace(maxLevels, startingDepth, nodeY * 2 + SOUTH, nodeX * 2 + EAST, newNodesCount);
        //        m_children[NORTH, EAST].PartitionSpace(maxLevels, startingDepth, nodeY * 2 + NORTH, nodeX * 2 + EAST, newNodesCount);

        //        //// Partition any further depths
        //        //foreach (var node in m_children)
        //        //{
        //        //    node.PartitionSpace(maxLevels, startingDepth, nodesCountAtCurrentDepth * 2);
        //        //}

        //        //FindNeighbors(parent, 0, 0);
        //    }
        //    else
        //    {
        //        m_objects = new Dictionary<EntityId, WorldObject>();
        //    }
        //}



        ///// <summary>
        ///// Partitions the space of the zone.
        ///// </summary>
        //public void PartitionSpace()
        //{
        //    // Start partitioning the map space
        //    m_root.PartitionSpace(ZoneSpacePartitionNode.DefaultPartitionThreshold, 0, 0, 0, 1);
        //}

        /// <summary>
        /// TODO: Find all intermediate neighbors
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="vertical"></param>
        /// <param name="horizontal"></param>
        internal void FindNeighbors(ZoneSpacePartitionNode parent, int vertical, int horizontal)
        {
            //m_neighbors = new ZoneSpacePartitionNode[3, 3];
            //if (parent != null)
            //{
            //    if (vertical == NORTH)
            //    {
            //        if (horizontal == EAST)
            //        {
            //            m_neighbors[VER_CENTER, HOR_WEST] = parent.m_children[NORTH, WEST];
            //            m_neighbors[VER_CENTER, HOR_WEST] = parent.m_children[NORTH, WEST];
            //        }
            //    }
            //}
        }
 /// <summary>Gets all objects within a specified radius.</summary>
 /// <typeparam name="T">the minimum type of the objects to retrieve</typeparam>
 /// <param name="sphere">the area to search</param>
 /// <param name="entities">the list to append retrieved objects to</param>
 internal void GetEntitiesInArea <T>(ref BoundingSphere sphere, List <T> entities, Func <T, bool> filter,
                                     uint phase, ref int limitCounter) where T : WorldObject
 {
     if (IsLeaf)
     {
         if (!HasObjects)
         {
             return;
         }
         foreach (WorldObject worldObject in m_objects.Values)
         {
             Vector3 position = worldObject.Position;
             if (sphere.Contains(ref position) && worldObject.IsInPhase(phase) && worldObject is T)
             {
                 T obj = worldObject as T;
                 if (filter(obj))
                 {
                     entities.Add(obj);
                     if (--limitCounter == 0)
                     {
                         break;
                     }
                 }
             }
         }
     }
     else
     {
         for (int index1 = 0; index1 < 2; ++index1)
         {
             for (int index2 = 0; index2 < 2; ++index2)
             {
                 ZoneSpacePartitionNode child = m_children[index1, index2];
                 if (child.Bounds.Intersects(ref sphere).HasAnyFlag(IntersectionType.Touches))
                 {
                     child.GetEntitiesInArea(ref sphere, entities, filter, phase, ref limitCounter);
                 }
             }
         }
     }
 }
        /// <summary>Removes an object from the node.</summary>
        /// <param name="obj">the object to remove</param>
        /// <returns>whether or not the object was removed successfully</returns>
        internal bool RemoveObject(WorldObject obj)
        {
            if (IsLeaf)
            {
                return(m_objects.Remove(obj.EntityId));
            }
            Vector3 position = obj.Position;

            for (int index1 = 0; index1 < 2; ++index1)
            {
                for (int index2 = 0; index2 < 2; ++index2)
                {
                    ZoneSpacePartitionNode child = m_children[index1, index2];
                    if (child.Bounds.Contains(ref position))
                    {
                        return(child.RemoveObject(obj));
                    }
                }
            }

            return(false);
        }
 /// <summary>Gets all objects within a specified radius.</summary>
 /// <param name="box">the area to search</param>
 /// <param name="entities">the list to append retrieved objects to</param>
 /// <param name="filter">the type (in respect to the WoW client) that the object must be</param>
 internal void GetEntitiesInArea(ref BoundingBox box, List <WorldObject> entities, ObjectTypes filter, uint phase,
                                 ref int limitCounter)
 {
     if (IsLeaf)
     {
         if (!HasObjects)
         {
             return;
         }
         foreach (WorldObject worldObject in m_objects.Values)
         {
             Vector3 position = worldObject.Position;
             if (box.Contains(ref position) && worldObject.IsInPhase(phase) &&
                 worldObject.Type.HasAnyFlag(filter))
             {
                 entities.Add(worldObject);
                 if (--limitCounter == 0)
                 {
                     break;
                 }
             }
         }
     }
     else
     {
         for (int index1 = 0; index1 < 2; ++index1)
         {
             for (int index2 = 0; index2 < 2; ++index2)
             {
                 ZoneSpacePartitionNode child = m_children[index1, index2];
                 if (child.Bounds.Intersects(ref box).HasAnyFlag(IntersectionType.Touches))
                 {
                     child.GetEntitiesInArea(ref box, entities, filter, phase, ref limitCounter);
                 }
             }
         }
     }
 }
 /// <summary>Gets all objects within a specified radius.</summary>
 /// <typeparam name="T">the specific type of the objects to retrieve</typeparam>
 /// <param name="entities">the list to append retrieved objects to</param>
 internal void GetObjectsOfSpecificType <T>(ref BoundingBox box, List <T> entities, uint phase,
                                            ref int limitCounter) where T : WorldObject
 {
     if (IsLeaf)
     {
         if (!HasObjects)
         {
             return;
         }
         foreach (WorldObject worldObject in m_objects.Values)
         {
             Vector3 position = worldObject.Position;
             if (box.Contains(ref position) && worldObject.IsInPhase(phase) &&
                 worldObject.GetType() == typeof(T))
             {
                 entities.Add(worldObject as T);
                 if (--limitCounter == 0)
                 {
                     break;
                 }
             }
         }
     }
     else
     {
         for (int index1 = 0; index1 < 2; ++index1)
         {
             for (int index2 = 0; index2 < 2; ++index2)
             {
                 ZoneSpacePartitionNode child = m_children[index1, index2];
                 if (child.Bounds.Intersects(ref box).HasAnyFlag(IntersectionType.Touches))
                 {
                     child.GetObjectsOfSpecificType(ref box, entities, phase, ref limitCounter);
                 }
             }
         }
     }
 }
 /// <summary>TODO: Find all intermediate neighbors</summary>
 /// <param name="parent"></param>
 /// <param name="vertical"></param>
 /// <param name="horizontal"></param>
 internal void FindNeighbors(ZoneSpacePartitionNode parent, int vertical, int horizontal)
 {
 }