У мене є 2 багатокутники. Я знаю координати вершин обох багатокутників. Який найкращий спосіб перевірити, чи знаходиться один повністю всередині іншого? Наприклад, алгоритм повинен розпізнавати лише нижню частину чорної трапеції нижче:
У мене є 2 багатокутники. Я знаю координати вершин обох багатокутників. Який найкращий спосіб перевірити, чи знаходиться один повністю всередині іншого? Наприклад, алгоритм повинен розпізнавати лише нижню частину чорної трапеції нижче:
Відповіді:
Існують тонни фрагментів джерела для методу, який виконує тест на " точку всередині багатокутника ". Принцип випливає з теореми кривої Джордана для полігонів ( 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-форми, але перетинати його , таким чином маючи принаймні деякі ділянки зовні).
після того, як перевіряється, чи хоча б одна з вершин внутрішнього багатокутника знаходиться всередині зовнішньої, і якщо немає пересічних ребер, це означає, що шукана умова виконується.
Спробуйте зробити перетин лінії з кожною червоною лінією. У псевдокоді:
// 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
}
Однак, як бачите, це рішення буде повільніше, коли ви додасте більше полігонів для перевірки. Іншим рішенням може бути:
Це рішення дуже швидко, але це залежить від вашої реалізації (і що ви хочете зробити з результатом перевірки), яке рішення найкраще підходить для вас.