Я использую центроид многоугольников, чтобы прикрепить маркер в приложении карты. Это определенно хорошо работает для выпуклых многоугольников и неплохо для многих вогнутых многоугольников.
Однако некоторые многоугольники (банан, пончик) явно не дают желаемого результата: центроид в этих случаях за пределами является площадью многоугольника.
Кто-нибудь знает, как лучше найти подходящую точку в в любой области полигонов (которая может содержать дыры!) Для прикрепления маркера?
Я думаю, это можно сделать с помощью триангуляции. Например, на первом этапе триангулируйте многоугольник, а затем попытайтесь найти треугольник, который кажется центральным треугольником в желаемых критериях, и верните его центроид.
Я бы разделил вогнутый многоугольник на выпуклые части (возможно, он уже так представлен), взял бы «самый толстый» из них (с большим абсолютным диаметром и отношением максимального диаметра к минимальному диаметру, близким к 1), и поместил точку в центр этой части. Однако это может потребовать значительного объема вычислений, поэтому я бы подумал о кешировании результатов или их сохранении вместе с многоугольниками.
Кажется, вы ищете точку, наиболее удаленную от любой границы. Спросите об этом на математическом форуме.
@ChristopheRoussy: Совершенно верно!
У Географические информационные системы могут быть похожие вопросы, поэтому ищите и там.
Я создал аналогичный вопрос о корпусе. Если вы знаете какой-либо подход, вы можете любезно ответить на него. Благодарить.





Я понятия не имею, как решить эту проблему для любой возможной формы (и не выполнять тяжелые вычисления), но, возможно, для более простых форм, подобных тем, которые вы показали:
https://en.wikipedia.org/wiki/Force-directed_graph_drawing
Эвристический: через некоторое время это может сойтись к разумному приближению
Другой способ - использовать несколько алгоритмов в зависимости от характера формы (например, другой для пончиков ...). Также, возможно, полагаться в первую очередь на измерение «самых толстых» участков?
ИМХО спросит об этом на математическом форуме.
Аналогично: Вычислить центроид ВНУТРИ / ВНУТРИ пространственного многоугольника
Аналогично: Как найти две самые далекие точки?
for (int i = 0; i < n; /*++i*/) {
p = RandomPointInsideConvexHull();
if (IsInsidePolygon(p)) {
++i;
d = DistanceToClosestEdge(p);
if (d > bestD) {
bestP = p;
}
}
}
После запуска этого цикла вы получите приблизительное решение по bestP. n - параметр для выбора. Если вам нужен более точный результат, вы можете перезапустить поиск, но теперь вместо того, чтобы выбирать точку внутри выпуклой оболочки многоугольника, вы можете выбрать точку в районе bestP, скажем, не дальше, чем bestD / 5 (на этот раз вам не нужно проверять, есть ли случайная точка находится внутри многоугольника).
Этот алгоритм не будет работать для многоугольников с множеством вершин, но небольшой площадью, например, с контуром тонкой дорожки / дороги, петляющей через горы. Проблема в том, что случайно выбранная точка внутри выпуклой оболочки, скорее всего, окажется за пределами многоугольника. В некоторых случаях точки все могут находиться за пределами многоугольника.
@ AdamGawne-Cain, пожалуйста, проверьте условие, при котором увеличивается i. Хотя это не самый эффективный алгоритм для упомянутых вами типов полигонов.
Ваш метод хорош тем, что он найдет интересную точку во многих полигонах. Но OP хотел метод для "любого многоугольника". Ваш код будет работать вечно, если входной многоугольник является вырожденным (например, L-образная форма с площадью = 0, например {0 0, 1 0, 1 1, 1 0, 0 0}).
@ AdamGawne-Cain Хм ... верно, но многоугольник с нулевой площадью не имеет точек, которые строго являются в многоугольника;)
Один из подходов - создать и уточнить скелет многоугольника, а затем использовать среднюю точку скелета для размещения маркера (и, если это текст, для правильной ориентации текста). Это хорошо подходит для большинства форм, в том числе с отверстиями и полумесяцами в форме банана или головастика.
В библиотеке CGAL есть модуль 2D прямой каркас и смещение многоугольника, или вы могли бы, например, использовать PostGIS.
Итак, если каждому контуру в процессе непрерывной усадки придается увеличивающаяся высота, возьмите наивысшую точку.
@Will - это один из подходов (и он даст вам точку, наиболее удаленную от любого края). Для многоугольника в форме гантели вы можете захотеть, чтобы алгоритм выбирал точку на «полосе» - в этом случае вы должны предпочесть (возможно, взвешенное) среднее положение вдоль позвоночника скелета.
Перефразируя комментарий Кристофа Русси, мы можем искать самый большой круг внутри многоугольника.
Самый большой круг - это тот, который больше не может расти, потому что он касается трех вершин или ребер (если он касается только двух, он может стать больше или просто перемещаться, пока не коснется третьего).
Итак, если у вас мало вершин, вы можете просто перечислить все возможные тройки вершин / ребер, найти для каждой из них круг, а затем выбрать самую большую.
Но для этого потребуется создать четыре функции:
Все они возможны, но могут потребовать некоторых усилий.
Найдите крайние ординаты и проведите горизонтальную линию посередине. Гарантированно пересечение полигона.
Найдите пересечение со сторонами и отсортируйте их по возрастанию абсцисс. Выберите точку посередине двух пересечений.
Это процесс O (N + K Log K), где K - количество пересечений (обычно очень маленькое четное число). Писать довольно просто.
Чтобы увеличить шансы на удачное размещение, вы можете попробовать три горизонтали вместо одной и выбрать самый длинный сегмент пересечения.
Этот метод может не сработать, если внутренняя часть многоугольника не соединена и пересечение горизонтальной линии и многоугольника лежит на самопересечении многоугольника. Например, многоугольник может быть цифрой 8, а горизонтальная линия может пересекать талию восьмерки.
@ AdamGawne-Cain: нет, это работает. Вы получите две перекрывающиеся точки пересечения, определяющие вырожденный сегмент.
Я согласен, что вы получите точку, но это не будет строго в многоугольник, как запрашивал OP. На самом деле, я думаю, что ваш метод подходит для получения точки для маркера, поскольку маркер, вероятно, больше точки и может быть больше, чем все пространство внутри многоугольника.
Чтобы получить точку для маркера, я бы использовал метод Ива Дауста.
Чтобы получить точку, которая надежно находится «внутри любого многоугольника с отверстиями», я бы разделил многоугольник на треугольники с помощью надежной библиотеки (например, OpenGL GLUtessellator), а затем получил бы центроид треугольника с наибольшей площадью.
Если бы у меня было время на разработку и тестирование, и я хотел бы получить хорошую производительность, я бы использовал гибридный метод: сначала используйте метод Ива Дауста, чтобы получить некоторые кандидатские очки, а затем протестируйте кандидатов, чтобы увидеть, находятся ли они в пределах многоугольника. Если все кандидаты терпят неудачу, используйте более медленный и надежный метод (например, GLUtesselator).
некоторые приложения создают точку в многоугольнике после нахождения центроида. Если он находится снаружи, либо новый x, либо y вычисляется на основе средней точки луча, пересекающего многоугольник.