Проверьте, является ли полигон самопересекающимся
У меня есть объект System.Windows.Shapes.Polygon, макет которого полностью определяется серией точек. Мне нужно определить, является ли этот многоугольник самопересекающимся; т. е. если любая из сторон многоугольника пересекается с любой другой стороной в точке, которая не является вершиной. Есть ли простой / быстрый способ вычислить это?
3 ответа
Легкий, медленный, малый объем памяти: сравните каждый сегмент со всеми остальными и проверьте наличие пересечений. Сложность O (n2).
Немного быстрее, средний объем памяти (измененная версия выше): сохраняйте ребра в пространственных "сегментах", затем выполняйте описанный выше алгоритм для каждого сегмента. Сложность O (n2 / m) для m ведер (при условии равномерного распределения).
Быстрый и большой объем памяти: используйте пространственную хеш-функцию, чтобы разбить края на сегменты. Проверьте на столкновения. Сложность O (n).
Быстрый и низкий объем памяти: используйте алгоритм строчной развертки, такой как описанный здесь (или здесь). Сложность O(n log n)
Последний мой любимый, так как у него хорошая скорость - баланс памяти, особенно алгоритм Бентли-Оттмана. Реализация тоже не слишком сложна.
Я здесь новая пчела, и этот вопрос достаточно старый. Однако вот мой код Java для определения пересечения любой пары сторон многоугольника упорядоченным набором точек. Вы можете удалить операторы печати, используемые для отладки. Я также не включил код для возврата первой найденной точки пересечения.
/**
* Checks if any two sides of a polygon cross-over.
* If so, returns that Point.
*
* The polygon is determined by the ordered sequence
* of Points P
*
* If not returns null
*
* @param V vertices of the Polygon
*
* @return
*/
public static Point verify(Point[] V)
{
if (V == null)
{
return null;
}
int len = V.length;
/*
* No cross-over if len < 4
*/
if (len < 4)
{
return null;
}
System.out.printf("\nChecking %d Sided Polygon\n\n", len);
for (int i = 0; i < len-1; i++)
{
for (int j = i+2; j < len; j++)
{
/*
* Eliminate combinations already checked
* or not valid
*/
if ((i == 0) && ( j == (len-1)))
{
continue;
}
System.out.printf("\nChecking if Side %3d cuts Side %3d: ", i, j);
boolean cut = Line2D.linesIntersect(
V[i].X,
V[i].Y,
V[i+1].X,
V[i+1].Y,
V[j].X,
V[j].Y,
V[(j+1) % len].X,
V[(j+1) % len].Y);
if (cut)
{
System.out.printf("\nSide %3d CUTS Side %3d. Returning\n", i, j);
return ( ... some point or the point of intersection....)
}
else
{
System.out.printf("NO\n");
}
}
}
return null;
}
Проверьте, пересекается ли какая-либо пара несмежных отрезков.
Ради полноты я добавлю еще один алгоритм к этому обсуждению.
Предполагая, что читатель знает об ограничивающих прямоугольниках, выровненных по оси (если нет, то Google). Очень эффективно быстро найти пары ребер, у которых есть конфликты AABB, с использованием "алгоритма очистки и сокращения". (погугли это). Затем на этих парах вызываются процедуры пересечения.
Преимущество здесь в том, что вы можете даже пересекать непрямой край (круги и сплайны), и этот подход является более общим, хотя и почти таким же эффективным.