LINUX.ORG.RU

Пересечение прямоугольника и отрезка

 


0

1

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

Разыскивается самый тупой и быстрый алгоритм для определения факта пересечения.

Более того, если что-то такое есть в Qt, то насрать на скорость — скорость реализации на первом месте.

А ну поделитесь-ка кодом. А то я начинаю вспоминать аналитическую геометрию и, чувствую, начинаю делать всё слишком сложно. А мне лень делать сложно:(

★★☆

Последнее исправление: Stahl (всего исправлений: 1)

Пиши формулу плоскости, формулу отрезка, составляй систему, находи точку пересечения, затем проверяй, входит ли эта точка внутрь прямоугольника.

Qt

Выбрось эту гадость.

Eddy_Em ☆☆☆☆☆
()

4 раза посчитать точку пересечения двух прямых и проверить, что полученная точка внутри отрезка (т.е. x1<x<x2 && y1<y<y2)

Формула есть тут: http://e-maxx.ru/algo/lines_intersection

Плюс частные случаи, когда делишь на нуль. Если есть.

Kakadu
()
Ответ на: комментарий от Eddy_Em

Пиши... составляй... находи... проверяй

Не хочу. Хочу готовое... Задача-то типичная. Уверен, что у кого-то из ЛОРовцев тупо есть нужный мне кусок кода.

гадость

Видал я такую гадость, по сравнению с которой Qt — квинтэссенция рационализма.

Stahl ★★☆
() автор топика
Ответ на: комментарий от exception13

Затем, что проще найти координаты точки в СК прямоугольника и проверить принадлежность, нежели мучиться с кучей прямых (а если у тебя прямоугольник расположен в пространстве произвольно, то с плоскостью элементарно получится, а с прямыми сложно)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от blexey

В любом банальном решении есть частные случаи и прочая билиберда, тестирующая моё внимание.
Да, задачка для старшеклассника, но вы не представляете НАСКОЛЬКО МНЕ ЛЕНЬ её решать:)
Тем более, что этот код написан сотни тысяч раз. Не хочу писать его в 100501 раз.

Stahl ★★☆
() автор топика
Ответ на: комментарий от Stahl

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

blexey ★★★★★
()

Как-то так должно работать:

отрезок - px1, py1 - px2, py2 прямоугольник: x1, y1 - x2, y2

min( px1, px2 ) <= max( x1, x2 ) && max( px1, px2 ) >= min( x1, x2 ) && min( py1, py2 ) <= max( y1, y2 ) && max( py1, py2 ) >= min( y1, y2 )

И не надо ничего умножать-делить.

grondek
()
Ответ на: комментарий от Stahl

Да, считается.

Тогда для пересечения достаточно, чтобы внутри бокса находился любой из концов отрезка:

function p_inside_b(bx1,by1, bx2,by2, px,py) {
  return (bx1<=px) && (px<=bx2) && (by1<=py) && (py<=by2)
}

function crossed(bx1,by1, bx2,by2, px1,py1, px2,py2) {
  return p_inside_b(bx1,by1, bx2,by2, px1,py1) || p_inside_b(bx1,by1, bx2,by2, px2,py2)
}

На «ассемблерах для быстроты» переписывайте сами ;)

blexey ★★★★★
()

Да ну, это же очень просто. Если одна точка отрезка в прямоугольнике, а другая нет то пересекает.

abs ★★★
()
Ответ на: комментарий от blexey

Нет, не достаточно.
Представь себе ситуацию, когда оба конца вне прямоугольника и отрезок отсекает «уголок».

Stahl ★★☆
() автор топика
Ответ на: комментарий от blexey

Точнее дня пересечения этого достаточно, но это не исчерпывающее условие. Возможно пересечение когда оба конца отрезка как вне, так и внутри прямоугольника.

Stahl ★★☆
() автор топика
Ответ на: комментарий от blexey

Тогда для пересечения достаточно, чтобы внутри бокса находился любой из концов отрезка:

А если

    ***********************
    *                     *
    *                     *
    *                     *
A-----------------------------B
    *                     *
    *                     *
    *                     *
    ***********************
PolarFox ★★★★★
()
Ответ на: комментарий от Stahl

Действительно, забыл. Ну, тогда уравнения в зубы и барабан на шею :)

blexey ★★★★★
()
Ответ на: комментарий от Stahl

Представь себе ситуацию, когда оба конца вне прямоугольника и отрезок отсекает «уголок».

Хм... что-то я затупил.(

abs ★★★
()

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

  static boolean intersect(Rect a, Rect b) {
    final float bxMin = b.getXMin();
    final float bxMax = b.getXMax();
    final float axMin = a.getXMin();
    final float axMax = a.getXMax();
    
    final float ayMin = a.getYMin();
    final float ayMax = a.getYMax();
    final float byMin = b.getYMin();
    final float byMax = b.getYMax();
    
    return (
            bxMin >= axMin && bxMin <= axMax ||
            bxMax >= axMin && bxMax <= axMax ||
            bxMin <= axMin && bxMax >= axMax
           ) && (
            byMin >= ayMin && byMin <= ayMax ||
            byMax >= ayMin && byMax <= ayMax ||
            byMin <= ayMin && byMax >= ayMax
           );
  }

результат ковыряния R*-tree Split

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от MyTrooName

Ну ситуация когда оба конца отрезка внутри прямоугольника тривиальна. Так что не важно на самом деле-то.

Stahl ★★☆
() автор топика

для определения факта пересечения.

Ласло М. Вычислительная геометрия и компьютерная графика на C++: ©
5.6. алгоритм Цируса-Бека.
5.7. алгоритм Сазерленда-Хожмана.

quickquest ★★★★★
()

Если все сделано на сцене с QGraphicsItem'ами, и простота реализации на первом месте, то самый очевидный вариант — использовать contains, где point это точки отрезка.

comp00 ★★★★
()
Ответ на: комментарий от Stahl

если тебе нужен самый простой в реализации способ, то важно.

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

быстрее реализовать это парой функций, чем пытаться сократить

MyTrooName ★★★★★
()

для float:

struct rect { float x1,y1,x2,y2; }
struct line  { float kx,ky,b;}//kx*x+ky*y+b=0
float p1 = kx*x1+ky*y1+b;
float p2 = kx*x1+ky*y2+b;
float p3 = kx*x2+ky*y1+b;
float p4 = kx*x2+ky*y2+b;
int32 i1  = 0x80000000 & reinterpret_cast<int32>(p1);
... то же для остальных p2 p3 p4;
int32 sum = 0xF & ((i1>>31)+(i2>>30)+(i3>>29)+(i4>>28));
if (sum != 0 && sum != 0xF) пересекаются;

можно сделать и на SSE2. для последней операции есть команда maskmov - она сразу и 0x80000000& и сдвиги сделает.

ckotinko ☆☆☆
()

Алгоритм Коэна — Сазерленда

Kosyak ★★★★
()

Взять уравнение прямой вида Ax+By+C=0. подставить все четыре точки в уравнение. Если результат для всех четырех будет одного знака, то пересечения нет.

dikiy ★★☆☆☆
()
Ответ на: комментарий от dikiy

Ах да, проверку данного условия легко сделать так:

пусть

a[i]=A*x[i]+B*y[i]+C

для каждго из углов прямоугольника.

if(a[0]*a[1]*a[2]*a[3]==0 || abs(a[0]/abs(a[0])+a[1]/abs(a[1])+a[2]/abs(a[2])+a[3]/abs(a[3]))!=4)
return пересекаются.
dikiy ★★☆☆☆
()
Последнее исправление: dikiy (всего исправлений: 3)

Уравнения прямых какие-то советуют... Четыре (или меньше) раза проверяем на пересечение отрезка с стороной прямоугольника плюс проверка на то, что отрезок целиком внутри (что тривиально).

Проверка на пересечение двух отрезков — два левых поворота плюс, возможно, частные случаи. Энивей, уж пересечение двух отрезков-то легко нагуглить можно, наверняка на каком-нибудь e-maxx.ru/algo есть реализация.

devsdc ★★
()
3 февраля 2015 г.
protected bool CrossSegments(System.Drawing.PointF A1, System.Drawing.PointF A2, System.Drawing.PointF B1, System.Drawing.PointF B2) 
    {
      float v1 = (B2.X - B1.X) * (A1.Y - B1.Y) - (B2.Y - B1.Y) * (A1.X - B1.X);
      float v2 = (B2.X - B1.X) * (A2.Y - B1.Y) - (B2.Y - B1.Y) * (A2.X - B1.X);
      float v3 = (A2.X - A1.X) * (B1.Y - A1.Y) - (A2.Y - A1.Y) * (B1.X - A1.X);
      float v4 = (A2.X - A1.X) * (B2.Y - A1.Y) - (A2.Y - A1.Y) * (B2.X - A1.X);
      return (v1 * v2 <= 0) && (v3 * v4 <= 0);
    }

    protected bool CrossPointAndRect(System.Drawing.PointF A, System.Drawing.RectangleF Rect)
    {
      float x1 = Math.Min(Rect.Left, Rect.Right);
      float x2 = Math.Max(Rect.Left, Rect.Right);
      float y1 = Math.Min(Rect.Top, Rect.Bottom);
      float y2 = Math.Max(Rect.Top, Rect.Bottom);
      return A.X >= x1 && A.Y >= y1 && A.X <= x2 && A.Y <= y2;
    }

    protected bool CrossSegmentAndRect(System.Drawing.PointF A1, System.Drawing.PointF A2, System.Drawing.RectangleF Rect)
    {
      if (CrossPointAndRect(A1, Rect))
        return true;
      if (CrossPointAndRect(A2, Rect))
        return true;
      if (CrossSegments(A1, A2, new System.Drawing.PointF(Rect.Left, Rect.Top), new System.Drawing.PointF(Rect.Right, Rect.Top)))
        return true;
      if (CrossSegments(A1, A2, new System.Drawing.PointF(Rect.Left, Rect.Bottom), new System.Drawing.PointF(Rect.Right, Rect.Bottom)))
        return true;
      if (CrossSegments(A1, A2, new System.Drawing.PointF(Rect.Left, Rect.Bottom), new System.Drawing.PointF(Rect.Left, Rect.Top)))
        return true;
      if (CrossSegments(A1, A2, new System.Drawing.PointF(Rect.Right, Rect.Bottom), new System.Drawing.PointF(Rect.Right, Rect.Top)))
        return true;
      return false;
    }
anonymous
()
Ответ на: комментарий от Kakadu

Плюсую, задачка простая. Спроси у меня кто еще в школе, и то, кажется, решил бы.

iVS ★★★★★
()
Ответ на: комментарий от redgremlin

но вы не представляете НАСКОЛЬКО МНЕ ЛЕНЬ

Это ты не представляешь, насколько нам ЛЕ…

В голос!

Stil ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.