Як визначити, чи повністю містить один многокутник інший?


9

У мене є 2 багатокутники. Я знаю координати вершин обох багатокутників. Який найкращий спосіб перевірити, чи знаходиться один повністю всередині іншого? Наприклад, алгоритм повинен розпізнавати лише нижню частину чорної трапеції нижче:

приклад багатокутників


Зараз я не можу дати детальної відповіді (можу це зробити пізніше), але вам слід поглянути на реалізацію теореми, що розділяє вісь для виявлення зіткнення. Алгоритм можна трохи змінити, щоб легко перевірити, що ви хочете. наприклад, codezealot.org/archives/55
TravisG

1
Вам не зовсім зрозуміло, що ви розумієте під багатокутником всередині багатокутника. Що робити, якщо всі точки меншого многокутника знаходяться у більшому, але кожна з них має сторону на одній прямій, чи знаходяться вони один в одному? i47.tinypic.com/4i0sgg.jpg
speedyGonzales

@speedyGonzales, це все називається всередині.
user960567

Відповіді:


5

Існують тонни фрагментів джерела для методу, який виконує тест на " точку всередині багатокутника ". Принцип випливає з теореми кривої Джордана для полігонів ( http://www-cgrl.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Octavian/compgeom.html ).

Наївним шляхом було б: маючи цей метод, назвіть його PointInsidePolygon(Point p, Polygon poly):

  bool isInside = true;
  for each (Point p in innerPoly)
  {
    if (!PointInsidePolygon(p, outerPoly))
    {
      isInside = false; // at least one point of the innerPoly is outside the outerPoly
      break;
    }
  }
  if (!isInside) return false;
  // COMPULSORY EDGE INTERSECTION CHECK
  for each (innerEdge in innerPoly)
    for each (outerEdge in outerPoly)
    {
      if (EdgesIntersect(innerEdge, outerEdge))
      {
        isInside = false;
        break;
      }
    }

  return isInside;

Теоретично він не повинен пропускати жодного сценарію для ваших полігонів, але це не оптимальне рішення.

Зауваження справи "Край"

  • PointInsidePolygon(..) повинен повернути істину, якщо точка знаходиться на межі багатокутника (або лежить на краю, або є вершиною)

  • EdgesIntersect(..)повинен повернути помилкове значення, якщо значення innerEdgeє підмножиною (геометрично) outerEdge. У цьому випадку краї очевидно перетинаються, але для цілей алгоритму нам потрібно вказати, що перетин не порушує семантику за isInsideзмінною

Загальні ремарки :

  • без перевірки перетину краю та краю, як зазначено в коментарях, підхід може повернути помилкові позитиви для деяких увігнутих багатокутників (наприклад, V-образний квадратик та прямокутник - прямокутник може мати всі свої вершини всередині V-форми, але перетинати його , таким чином маючи принаймні деякі ділянки зовні).

  • після того, як перевіряється, чи хоча б одна з вершин внутрішнього багатокутника знаходиться всередині зовнішньої, і якщо немає пересічних ребер, це означає, що шукана умова виконується.


1
Це поверне помилкові позитиви, коли зовнішній багатокутник увігнутий.
sam hocevar

2
Досить смішно, хоча теодрон і лицар666 помиляються окремо, коли їх поєднувати, вони повинні дати правильну відповідь. Якщо всі точки багатокутника знаходяться всередині іншого, і якщо їхні лінії не перетинаються, то перший полі знаходиться повністю всередині іншого.
Хакворт

Щоправда, вона повертає помилкові позитиви, вона також повинна враховувати крайові перехрестя.
теодрон

Це здається правильною відповіддю. Я думаю, не потрібно перевіряти стан другого циклу.
user960567

Це не працює для перетину кінцевих точок або якщо краї перетинаються.
Брендон Кон

2

Спробуйте зробити перетин лінії з кожною червоною лінією. У псевдокоді:

// loop over polygons
for (int i = 0; i < m_PolygonCount; i++)
{
    bool contained = false;

    for (int j = 0; j < m_Polygon[i].GetLineCount(); j++)
    {
        for (int k = 0; k < m_PolygonContainer.GetLineCount(); k++)
        {
            // if a line of the container polygon intersects with a line of the polygon
            // we know it's not fully contained
            if (m_PolygonContainer.GetLine(k).Intersects(m_Polygon[i].GetLine(j)))
            {
                contained = false;
                break;
            }
        }

        // it only takes one intersection to invalidate the polygon
        if (!contained) { break; }
    }

    // here contained is true if the polygon is fully inside the container
    // and false if it's not
}

Однак, як бачите, це рішення буде повільніше, коли ви додасте більше полігонів для перевірки. Іншим рішенням може бути:

  • Візьміть багатокутник контейнера на піксельний буфер з білим кольором.
  • Виведіть дочірній багатокутник на інший піксельний буфер з білим кольором.
  • Маскуйте буфер контейнера над буфером багатокутника за допомогою маски XOR.
  • Порахуйте кількість білих пікселів; якщо він більший за 0, дочірній багатокутник повністю не міститься в контейнері.

Це рішення дуже швидко, але це залежить від вашої реалізації (і що ви хочете зробити з результатом перевірки), яке рішення найкраще підходить для вас.


1
Перетину ліній не буде достатньо, щоб помітити повноцінні багатокутники.
Кілотан

1
Питання: якщо багатокутники повністю роз'єднані, жоден край не перетинатиметься. Чи спрацює в цьому випадку? Другий, на основі графіки підхід повинен справді працювати!
теодрон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.