Определить, можно ли объединить два прямоугольника в один прямоугольник - PullRequest
4 голосов
/ 12 июля 2011

Я ищу алгоритм, который принимает два прямоугольника, определенных (xa1, ya1, xa2, ya2) и (xb1, yb1, xb2, yb2), проверяет, могут ли они быть объединены в один прямоугольник и могут ли они , возвращает новый прямоугольник. Пример:

xa1=0,ya1=0,xa2=320,ya2=119
xb1=0,yb1=120,xb2=320,yb2=239

Эти два прямоугольника можно объединить в следующий прямоугольник:

xc1=0,yc1=0,xc2=320,yc2=240

Как бы вы реализовали такой алгоритм? Спасибо!

Ответы [ 4 ]

8 голосов
/ 12 июля 2011

Я бы нарисовал следующие картинки и записал бы их в виде алгоритма:

...xxxxxxx       xxxxxxx....
.  x  .  x       x   . x   .
.  x  .  x       x   . x   .
...xxxxxxx       xxxxxxx....

xxxxxxx          .......
x     x          .     .
x.....x          xxxxxxx
xxxxxxx          x.....x
.     .          x     x
.......          xxxxxxx

..........
.        .
. xxxx   .
. x  x   .
. x  x   .
. xxxx   .
..........

xxxxxxxxxxxxxx
x            x
x   .......  x
x   .     .  x
x   .     .  x
x   .......  x
x            x
xxxxxxxxxxxxxx

Проверьте угловые случаи!

0 голосов
/ 12 июля 2011

После долгих потрясений я вроде сработал, что вы хотите.Обратите внимание, что по-прежнему существует определенное противоречие с тем, что вы подразумеваете под «строгой рамкой»: образец в вашем первоначальном вопросе не удовлетворяет приведенному вами описанию:

Но прямоугольникиследует комбинировать только в том случае, если ограничивающий прямоугольник точно соответствует размеру двух прямоугольников, то есть площадь ограничивающего прямоугольника должна быть точно такой же, как и размер областей двух исходных прямоугольников.Если площадь прямоугольника 1 равна a1, а площадь прямоугольника 2 равна a2, а площадь ограничивающего прямоугольника равна a3, то a1 + a2 = a3.

Эта реализация должна дать вам множествоидеи, и я уверен, что вы знаете, как написать

r.area() == a.area() + b.area()

, если вы действительно этого хотели.


Код кодовой панели :

// Final proposal: combine adjacent rectangles, 
// if they are 'flush': almost touching

#include <iostream>

struct R
{
    int x1,y1,x2,y2;
    int height() const { return y2-y1; }
    int width() const  { return y2-y1; }

    void normalize() 
    { 
        if (x1>x2) std::swap(x1,x2);
        if (y1>y2) std::swap(y1,y2);
    }

    /*
     * adjacent: return whether two rectangles
     * are adjacent; the tolerance in pixels
     * allow you to specify the gap:
     *    tolerance = 0: require at least one pixel overlap
     *    tolerance = 1: accepts 'flush' adjacent neighbours
     * Negative tolerance require more overlap;
     * tolerance > 1 allows gaps between rects;
     */
    bool adjacent(R const& other, int tolerance=1) const
    {
        return !( (other.x1 - x2) > tolerance
               || (x1 - other.x2) > tolerance
               || (other.y1 - y2) > tolerance
               || (y1 - other.y2) > tolerance);
    }
};

/* 
 * tolerance: see R::adjacent()
 * 
 * strict: only allow strict ('pure') combinations of rects
 */
R combined(R const& a, R const& b, int tolerance=1, bool strict=false)
{
    if (!a.adjacent(b, tolerance))
        throw "combined(a,b): a and b don't satisfy adjacency requirements (are the coords normalized?)";

    R r = { min(a.x1, b.x1), 1,1,1};
    r.x1 = min(a.x1, b.x1);
    r.y1 = min(a.y1, b.y1);
    r.x2 = max(a.x2, b.x2);
    r.y2 = max(a.y2, b.y2);

    if (!strict)
        return r;

    if ( (r.height() <= max(a.height(), b.height()))
     &&  (r.width () <= max(a.width (), b.width ())) )
        return r;
    else
        throw "combined(a,b): strict combination not available";
}

std::ostream& operator<<(std::ostream &os, R const& r)
{
    return os << '(' << r.x1 << "," << r.y1 << ")-(" << r.x2 << ',' << r.y2 << ')';
}

int main()
{
    const int tolerance = 1;
    {
        std::cout << "sample from original question" << std::endl;
        R a = { 0, 0,   320, 119 }; /* a.normalize(); */
        R b = { 0, 120, 320, 239 }; /* b.normalize(); */

        std::cout << "a: " << a << "\t b: " << b << std::endl;
        std::cout << "r: " << combined(a,b, tolerance) << std::endl;
    }
    {
        std::cout << "sample from the comment" << std::endl;
        R a = { 0, 0, 1, 320 }; /* a.normalize(); */
        R b = { 0, 0, 2, 320 }; /* b.normalize(); */

        std::cout << "a: " << a << "\t b: " << b << std::endl;

        // NOTE: strict mode
        std::cout << "r: " << combined(a,b, tolerance, true) << std::endl;
    }
}

Выход:

sample from original question
a: (0,0)-(320,119)   b: (0,120)-(320,239)
r: (0,0)-(320,239)
sample from the comment
a: (0,0)-(1,320)     b: (0,0)-(2,320)
r: (0,0)-(2,320)
0 голосов
/ 12 июля 2011

Два прямоугольника должны пересекаться.Все углы ограничивающего прямоугольника должны соприкасаться с существующими углами.

Эти два условия необходимы и достаточны.Очевидно, что прямоугольники должны пересекаться, и, поскольку вы не можете создать неугловую пустую область, используя только 2 пересекающихся прямоугольника, ограничивающие углы должны приземляться на существующие углы.

return r1.Intersects(r2) and r1.BoundingRectangleWith(r2).Corners.IsSubsetOf(r1.Corners.Union(r2.Corners))

Реализация Intersects,BoundingRectangleWith, Corners и IsSubsetOf просты.Затем вы можете встроить их для лучшей производительности, но это будет беспорядок нечитаемых сравнений.

Редактировать

Один из ваших комментариев предполагает, что вы не хотите, чтобы прямоугольникиперекрывать, только трогать.В этом случае вам нужно только проверить, что на одной оси (то есть X или Y) диапазоны прямоугольника равны, а на другой оси диапазоны касаются.Два диапазона касаются, если медиана их границ имеет 2 вхождения.Обратите внимание, что если вы хотите, чтобы вправо = 1 касалось левой = 2, вам нужно добавить 1 к границам потолка.

0 голосов
/ 12 июля 2011

Они могут быть объединены, если и только если одна пара противоположных сторон одного прямоугольника перекрывает одну пару противоположных сторон другого прямоугольника. Под перекрытием я подразумеваю, если они параллельны и содержат хотя бы одну общую точку.

Вы должны быть в состоянии выяснить код;)

РЕДАКТИРОВАТЬ: О, я забыл упомянуть случай, когда два прямоугольника полностью перекрываются. Это не должно быть слишком сложно проверить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...