Часто при разработке различных интерфейсов возникает задача проверки пересекаются ли два заданных прямоугольника. Решение в данном случае очень простое, однако мной нигде не найденное и поэтому в очередной раз пришлось писать свой велосипед. При этом грабли на которые наступают разработчики одни и те же, а решение выдаваемые гуру на форумах работают лишь в частных случаях и не покрывают все варианты расстановки двух прямоугольников на плоскости.
Функция работает только для прямоугольников, чьи стороны параллельны осям координат. В общем-то задача сведена к проецированию сторон на оси координат и попарной проверке пересечений двух отрезков. Если две пары отрезков пересекаются между собой то значит один из прямоугольников лежит на другом. Однако здесь есть подвох: нужно проверять также случай, когда одна сторона прямоугольника №1 лежит внутри той же стороны прямоугольника №2, а другая, сторона у №2 сама лежит внутри такой же в №1. Этот случай представлен на рисунке выше, под номером 1.
Пусть есть два прямоугольника A и B.
(a.x,a.y)--------------| | | | | | | |---------------(a.x1,a.y1) (b.x,b.y)---------------------| | | | | | | |---------------------(b.x1,b.y1)
тогда проверку на пересечение двух этих прямоугольников произведет следующая функция
var intersect = function(a,b){ return( ( ( ( a.x>=b.x && a.x<=b.x1 )||( a.x1>=b.x && a.x1<=b.x1 ) ) && ( ( a.y>=b.y && a.y<=b.y1 )||( a.y1>=b.y && a.y1<=b.y1 ) ) )||( ( ( b.x>=a.x && b.x<=a.x1 )||( b.x1>=a.x && b.x1<=a.x1 ) ) && ( ( b.y>=a.y && b.y<=a.y1 )||( b.y1>=a.y && b.y1<=a.y1 ) ) ) )||( ( ( ( a.x>=b.x && a.x<=b.x1 )||( a.x1>=b.x && a.x1<=b.x1 ) ) && ( ( b.y>=a.y && b.y<=a.y1 )||( b.y1>=a.y && b.y1<=a.y1 ) ) )||( ( ( b.x>=a.x && b.x<=a.x1 )||( b.x1>=a.x && b.x1<=a.x1 ) ) && ( ( a.y>=b.y && a.y<=b.y1 )||( a.y1>=b.y && a.y1<=b.y1 ) ) ) ); }
а Вы думали все просто. Я тоже так думал, пока не поймал ряд вариантов, которые не подходят под решения названные на форумах. Первая половина этой «многоэтажки» проверяет все случаи, кроме первого, вторая создана специально для случая №1.
UPD
Благодаря пользователю с ником Ruslan и его комментарию узнаем, что есть еще один достаточно просто способ проверить. Нужно действовать от обратного, проверять не 1,3,4 а только 2
var intersects = function ( a, b ) { return ( a.y < b.y1 || a.y1 > b.y || a.x1 < b.x || a.x > b.x1 ); }
Просто, как дважды два. Проверяем если верхняя грань первого прямоугольника находится ниже второго, или нижняя выше верхней грани первого. Тоже самое и для оси X.
Комментарии
( b.x>=a.x && b.x=a.x && b.x1=a.y && b.y=a.y && b.y1
boolean intersects(Box box1, Box box2) {
//Y not intersects
if (box1.getY() < box2.getY1() || box1.getY1() > box2.getY()) {
return false;
}
//X not intersects
if (box1.getX1() < box2.getX() || box1.getX() > box2.getX1()) {
return false;
}
return true;
}
П.С. упрощенный вариант у меня почему-то не заработал:(
http://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other
http://silentmatt.com/rectangle-intersection/
var intersects = function ( a, b ) {
return !( a.y > b.y1 || a.y1 b.x1 );
}
Вот как хотел написать:
var intersects = function ( a, b ) {
return !( a.y > b.y1 || a.y1 < b.y || a.x1 < b.x || a.x > b.x1 );
}
С одинаковыми прямоугольниками довольно просто, там можно проверять пересечение граней или их совпадение, а вот с прямоугольниками произвольных размеров ума не приложу что делать
Т.е. в коде надо будет прогнать циклом все стороны одного прямоугольника со сторонами другого.
Я решил задачу немного по другому. Сначала описываю вокруг заданных многоугольников прямоугольники, параллельные осям, потом проверяю попадания вершин многоугольника 1 в описаный вокруг многоугольника 2 прямоугольник простым способом, описанным здесь. Далее, для полученных точек методом трассировки луча узнаю принадлежит ли вершина многоугольника 1 многоугольнику 2. Можно и без описаных прямоугольников обойтись, но тогда все вершины по более сложному алгоритму нужно считать.
Реализацию на javascript описал здесь http://geekpage.ru/posts/29 (сюда код не вставляю так как довольно много получилось).
Метод конечно требует доработок и добавления всевозможных проверок входных данных, но он работает.
вот простейшее решение, никаких операторов "или" не нужно
всеволиш нунжно проверить пересечение по x и по y
function rectIntersect(a, b){
// interval intersection
function ii(a1, a2, b1, b2){ return a1
function ii(a1, a2, b1, b2){ return a1
// interval intersection
function ii(a1, a2, b1, b2){ return a1 <= b2 && b1 <= a2; }
return ii(a.x, a.x + a.w, b.x, b.x + b.w) && ii(a.y - a.h, a.y, b.y - b.h, b.y);
}
function rectIntersect(a, b){
// interval intersection
function ii(a1, a2, b1, b2){ return a1
return ii(a.x, a.x + a.w, b.x, b.x + b.w) && ii(a.y, a.y + a.h, b.y, b.y + b.h);
}