Как я могу определить, полностью ли один прямоугольник содержится в другом?

у меня есть теоретическая сетка перекрывающихся прямоугольников, которые могут выглядеть примерно так:

grid layout

но все, с чем я должен работать, это коллекция объектов Rectangle:

var shapes = new List<Rectangle>();
shapes.Add(new Rectangle(10, 10, 580, 380));
shapes.Add(new Rectangle(15, 20, 555, 100));
shapes.Add(new Rectangle(35, 50, 40, 75));
// ...

то, что я хотел бы сделать, это построить DOM-подобную структуру, где каждый прямоугольник имеет свойство ChildRectangles, которое содержит прямоугольники, содержащиеся в нем на сетке.

конечный результат должен позволить мне преобразовать такую структуру в XML, что-то вроде:

<grid>
  <shape rectangle="10, 10, 580, 380">
    <shape rectangle="5, 10, 555, 100">
      <shape rectangle="20, 30, 40, 75"/>
    </shape>
  </shape>
  <shape rectangle="etc..."/>
</grid>

но в основном это DOM-подобная структура в памяти, которую я хочу, выходной XML-это просто пример того, как я могу использовать такую структуру.

бит, на котором я застрял, - это как эффективно определить, какие прямоугольники принадлежат к которым.

Примечание никакие прямоугольники частично не содержатся внутри другого, они всегда полностью внутри другого.

редактировать обычно сотни прямоугольников, должен ли я просто перебирать каждый прямоугольник, чтобы увидеть, содержится ли он в другом?

редактировать кто-то предложил содержит (не мой лучший момент, пропуская это!), но я не уверен, как лучше выстроить дом. Например, возьмите внука первого прямоугольника, родитель действительно содержит внука, но он не должен быть прямым ребенком, он должен быть ребенком первого ребенка родителя.

5 ответов


Как указывает @BeemerGuy,Rect.Contains скажет вам, содержит ли один прямоугольник другой. Построение иерархии немного сложнее...

есть решение O(N^2), в котором для каждого прямоугольника вы просматриваете список других прямоугольников, чтобы увидеть, подходит ли он внутрь. "Владелец" каждого прямоугольника-это самый маленький прямоугольник, который его содержит. Псевдокод:

foreach (rect in rectangles)
{
    owner = null
    foreach (possible_owner in rectangles)
    {
        if (possible_owner != rect)
        {
            if (possible_owner.contains(rect))
            {
                if (owner === null || owner.Contains(possible_owner))
                {
                    owner = possible_owner;
                }
            }
        }
    }
    // at this point you can record that `owner` contains `rect`
}

это не очень эффективно, но это может быть "достаточно быстро" для ваших целей. Я уверен Я видел решение O(n log n) (в конце концов, это просто операция сортировки), но оно было несколько сложнее.


использовать Contains() на Rectangle.

Rectangle rect1, rect2;
// initialize them
if(rect1.Continas(rect2))
{
    // do...
}

обновление:
Для дальнейшего использования...
Интересно добавить, что Rectangle также IntersectsWith(Rectangle rect) если вы хотите проверить, частично ли прямоугольник сталкивается с другим прямоугольником.


решение среднего случая O (N log n):

подумайте о своем наборе прямоугольников как о дереве, где родительские узлы "содержат" дочерние узлы-то же самое, что и структура DOM. Вы будете строить дерево по прямоугольнику за раз.

сделайте фиктивный узел, который будет служить корнем вашего дерева. Затем для каждого из ваших прямоугольников ("current_rect") начните с дочерних элементов корня и работайте вниз, пока не найдете, куда он идет:

parent_node = root_node
sibling_nodes = [children of parent_node]

for this_node in sibling_nodes:
    if current_rect contains this_node:
        move this_node: make it a child of current_rect instead of parent_node
    elseif this_node contains current_rect:
        parent_node = this_node
        sibling_nodes = [children of parent_node]
        restart the "for" loop using new set of sibling_nodes

make current_rect a child of parent_node

в "содержит" relation спрашивает, содержит ли один прямоугольник другой. "Родитель", "ребенок" и "брат" относятся к древовидной структуре.

редактировать: Исправлена ошибка, которая пропустит перемещение некоторых узлов в current_rect.


убедитесь, что каждая точка в прямоугольнике находится в пределах других прямоугольников. В .NET класс Rectangle имеет a .Содержит(точечный) метод. Или вы можете проверить координаты угловой точки againt целевой прямой кишки .Влево. ,Право. ,Верх и. Свойства дна.


псевдо код:

for i = 0 to rectangles.length - 2
 for j = i + 1 to rectangles.length - 1
     if rectangles[i].Contains(rectangles[j])
        //code here
}}}