Exemplo n.º 1
0
        /// <summary>
        /// Built an index for a specified objects.
        /// <para>
        /// This method creates a more optimal partitioning of the space
        /// than the one which is obtained by sequentially adding objects
        /// to the index. The resulting tree is unbalanced.
        /// </para>
        /// </summary>
        /// <remarks>
        /// <para>
        /// The algorithm is optimized for fast discarding the empty space.
        /// The criterion for the optimal partition is the minimum of
        /// (number_of_objects_in_1st_area * square_of_1st_area + number_of_objects_in_2nd_area * square_of_2nd_area).
        /// The number of possible partitions defined into <see cref="KDTree.DividingGridRowCount"/>.
        /// </para>
        /// </remarks>
        /// <param name="objects">Enumerator of objects for indexing</param>
        public void Build <T>(IEnumerable <T> objects)
            where T : IIndexable
        {
            Clear();

            List <T> list = new List <T>();

            foreach (T obj in objects)
            {
                if (IndexedSpace.ContainsRectangle(obj.BoundingRectangle))
                {
                    list.Add(obj);
                }
                else
                {
                    throw new ArgumentException("At least one object goes beyond the indexed space", "objects");
                }
            }

            _root.BuildUnbalanced(list, 1);
        }
Exemplo n.º 2
0
            /// <summary>
            /// Builds an index for the specified objects.
            /// </summary>
            internal void BuildUnbalanced <T>(List <T> objects, int currentDepth)
                where T : IIndexable
            {
                if (currentDepth > _parent.Depth)
                {
                    _parent._depth = currentDepth;
                }

                // Возможно мы достигли:
                // 1. максимально допустимой глубины индекса
                // 2. порогового значения площади ячейки узла
                // или кол-во объектов переданных для индексирования
                // не превысило минимального.
                // При этом создавать дочерние узлы уже нельзя
                if (_parent.Depth >= _parent.MaxDepth ||
                    _parent._boxSquareThreshold > _boundingBox.Width * _boundingBox.Height ||
                    _parent.MinObjectCount >= objects.Count)
                {
                    foreach (T obj in objects)
                    {
                        _objects.Add(obj);
                    }

                    objects.Clear();
                    return;
                }

                List <IIndexable> objects0 = new List <IIndexable>();
                List <IIndexable> objects1 = new List <IIndexable>();

                double minCost = double.MaxValue;

                BoundingRectangle box0, box1;
                BoundingRectangle minCostBox0 = _parent._indexedSpace,
                                  minCostBox1 = _parent._indexedSpace;

                #region Вычисление разбиения с минимальной стоимостью: стоимость = кол-во объекты * площадь

                for (int i = 1; i < KDTree.DividingGridRowCount; i++)
                {
                    double x = _boundingBox.MinX + _boundingBox.Width / KDTree.DividingGridRowCount * i;
                    splitX(_boundingBox, x, out box0, out box1);

                    double cost = getSplitCostVertical(objects, box0, box1);

                    if (cost < minCost)
                    {
                        minCost     = cost;
                        minCostBox0 = box0;
                        minCostBox1 = box1;
                    }

                    double y = _boundingBox.MinY + _boundingBox.Height / KDTree.DividingGridRowCount * i;

                    splitY(_boundingBox, y, out box0, out box1);

                    cost = getSplitCostHorizontal(objects, ref box0, ref box1);

                    if (cost < minCost)
                    {
                        minCost     = cost;
                        minCostBox0 = box0;
                        minCostBox1 = box1;
                    }
                }

                #endregion

                // разбиваем исходный список на 3 множества:
                // objects0 - объекты индексируемые в дочернем узле _child0
                // objects1 - объекты индексируемые в дочернем узле _child1
                // _objects - объекты этого узла
                foreach (T obj in objects)
                {
                    if (minCostBox0.ContainsRectangle(obj.BoundingRectangle))
                    {
                        objects0.Add(obj);
                    }
                    else
                    {
                        if (minCostBox1.ContainsRectangle(obj.BoundingRectangle))
                        {
                            objects1.Add(obj);
                        }
                        else
                        {
                            _objects.Add(obj);
                        }
                    }
                }

                objects.Clear();

                if (objects0.Count > 0 || objects1.Count > 0)
                {
                    _child0 = new KDTreeNode(minCostBox0, _parent);
                    _child1 = new KDTreeNode(minCostBox1, _parent);
                    _child0.BuildUnbalanced(objects0, currentDepth + 1);
                    _child1.BuildUnbalanced(objects1, currentDepth + 1);
                }
            }