/// <summary> /// Adds objects, which bounding rectangles intersect /// specified rectangle, to the list. /// </summary> /// <param name="box">A bounding rectangle defining queryable area</param> /// <param name="objects">A list for adding objects</param> internal void QueryObjectsInRectangle <T>(BoundingRectangle box, IList <T> objects) where T : IIndexable { // возможно ячейка узла лежит внутри запрашиваемой области, // в этом случае мы должны добавить все объекты дочерних узлов // без выполнения проверок на пересечения if (box.ContainsRectangle(BoundingBox)) { addAllObjectsRecursively(objects); return; } // предпринимаем действия по добавлению объектов в список только // в том случае, если ограничивающие прямоугольники пересеклись if (box.Intersects(BoundingBox)) { foreach (T obj in _objects) { if (box.Intersects(obj.BoundingRectangle)) { objects.Add(obj); } } if (_child0 != null && _child1 != null) { _child0.QueryObjectsInRectangle(box, objects); _child1.QueryObjectsInRectangle(box, objects); } } }
public void AddPolygonObstaclesLayer(FeatureLayer layer) { foreach (var polygonFeature in layer.Polygons) { var bounds = polygonFeature.BoundingRectangle; if (BoundingRectangle.ContainsRectangle(bounds)) { _obstacles.Add(polygonFeature.Polygon); RegisterObstacle(polygonFeature.Polygon); } } }
internal void Insert(IIndexable obj, int branchDepth) { if (!_fullRectangle.ContainsRectangle(obj.BoundingRectangle)) { throw new ArgumentException("Bounding rectangle of the indexed object exceeds the node bounding rectangle", "obj"); } // возможно глубина текущей ветки // уже больше глубины индекса if (branchDepth > _owner.Depth) { _owner._depth++; } if (HasChildren) { if (!canAddingToChildCell(obj.BoundingRectangle)) { forceInsert(obj); } else { insertIntoChild(obj, branchDepth); } } else { if (_owner._minObjectCount < _objects.Count) { forceInsert(obj); } else { forceInsert(obj); // ячейку можно разбивать, если ее площадь превосходит // порог площади ячейки и текущая глубина ветви меньше предельной if (_owner.BoxSquareThreshold < _fullRectangle.Width * _fullRectangle.Height && _owner.MaxDepth > branchDepth) { splitAndRebuild(branchDepth); } } } }
/// <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); } }
internal void QueryObjectsInRectangle <T>(BoundingRectangle box, IList <T> objects) where T : IIndexable { // если прямоугольник ячейки не пересекается // с запрашиваемым прямоугольником - считать нечего if (!box.Intersects(_fullRectangle)) { return; } // если прямоугольник ячейки целиком содержится в // запрашиваемом прямоугольнике - добавляем все объекты рекурсивно if (box.ContainsRectangle(this._fullRectangle)) { addAllObjectsRecursively(objects); return; } // если прямоугольник объектов ячейки целиком содержится в // запрашиваемом прямоугольнике - добавляем все объекты этой ячейки if (_geometriesRectangle != null && box.ContainsRectangle(_geometriesRectangle)) { foreach (IIndexable obj in _objects) { objects.Add((T)obj); } } else { // иначе выполняем проверки на пересечение // прямоугольников для каждого объекта foreach (IIndexable obj in _objects) { if (box.Intersects(obj.BoundingRectangle)) { objects.Add((T)obj); } } } // если дочерние узлы отсутствуют, // дальше считать нечего if (!HasChildren) { return; } // разбираемся с детьми if (_leftUpChild != null) { _leftUpChild.QueryObjectsInRectangle(box, objects); } if (_rightUpChild != null) { _rightUpChild.QueryObjectsInRectangle(box, objects); } if (_rightDownChild != null) { _rightDownChild.QueryObjectsInRectangle(box, objects); } if (_leftDownChild != null) { _leftDownChild.QueryObjectsInRectangle(box, objects); } }