Как пересечь два полигона?

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

вход: 2 полигона (A и B) в 2D, заданные как список ребер [(x0, y0, x1, y2), ...] каждый. Точки представлены парами doubles. Я не знаю, даны ли они по часовой стрелке, против часовой стрелки или в любом направлении вообще. Я!--6-->do знаю, что они не обязательно выпуклый.

выход: 3 многоугольника, представляющие A, B и пересекающийся многоугольник AB. Любой из которых может быть пустым (?) многоугольник, например,null.

подсказки для оптимизации: эти полигоны представляют границы комнаты и пола. Таким образом, граница комнаты обычно полностью пересекается с границей пола, если она не принадлежит другому полу в той же плоскости (argh!).

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

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

выход: первый многоугольник минус все пересекающиеся биты, многоугольники пересечения (множественное число в порядке). Меня не очень интересует второй многоугольник, только его пересечение с первым.

EDIT2: в настоящее время я использую GPC (General Polygon Clipper) библиотека, которая делает это действительно легко!

9 ответов


что я думаю, что вы должны сделать

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

Я сильно рассматривал следующую кодовую базу в силу их демонстрационного кода и того факта, что они упомянули об их обработке большинства/всех странных случаев. Вам нужно будет пожертвовать сумму (по вашему выбору / вашей компании), если вы ее используете коммерчески, но это стоит того, чтобы получить надежную версию такого рода кода.

http://www.cs.man.ac.uk / ~toby/gpc/

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

есть и другие варианты; ищите "polygon clipper" или "polygon clipping", так как те же основные алгоритмы, которые обрабатывают пересечение многоугольников также может использоваться для общих случаев отсечения.

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

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

когда я рассматривал возможность прокатки собственного, я обнаружил, что алгоритм Вейлера-Атертона имеет больше всего потенциал для общей полигональной резки. Я использовал следующее в качестве ссылки:

http://cs1.bradley.edu/public/jcm/weileratherton.html

http://en.wikipedia.org/wiki/Weiler-Atherton

детали, как говорится, слишком плотные, чтобы включать их здесь, но я не сомневаюсь, что вы сможете найти ссылки на Weiler-Atherton на долгие годы. По сути, вы разделяете все точки на те, которые входят в финал многоугольник или выход из конечного многоугольника, затем вы формируете график из всех точек, а затем идете по графику в соответствующих направлениях, чтобы извлечь все части многоугольника, которые вы хотите. Изменяя способ определения и обработки "входящих" и "выходящих" полигонов, вы можете достичь нескольких возможных пересечений полигонов (и, или, XOR и т. д.).

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


Араш Partow это FastGEO библиотека содержит реализации многих интересных алгоритмов вычислительной геометрии. Пересечение полигонов-одно из них. Он написан на Паскале, но он только реализует математику, поэтому он довольно удобочитаем. Обратите внимание, что вам обязательно нужно будет немного обработать ваши края, чтобы получить их по часовой стрелке или против часовой стрелки.

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


Если вы программируете в .NET Framework, вы можете взглянуть на класс SqlGeometry, доступный в сборках .NET, поставляемых как типы среды CLR системы Microsoft SQL Server

класс SqlGeometry предоставляет STIntersection метод

SqlGeometry g1 = SqlGeometry.Parse("POLYGON ((...))");
SqlGeometry g2 = SqlGeometry.Parse("POLYGON ((...))");
SqlGeometry intersection = g1.STIntersection(g2);

вы также можете посмотреть на NetTopologySuite или даже попробуйте импортировать его в Sql server 2008 и это пространственные инструменты.


полигон полностью описывается упорядоченным списком точек (P1, P2, ..., Pn). Ребра (P1 - P2), (P2 - P3), ..., (Pn - P1). Если у вас есть два многоугольника A и B, которые перекрываются, будет точка An (из списка точек, описывающих многоугольник A), которая лежит в области, окруженной многоугольником B или наоборот (точка B лежит в A). Если такой точки не найдено, то полигоны не перекрываются. Если такая точка найдена (т. е. Ai), проверьте соседние точки многоугольника A (i-1) и A (i+1). Повторяйте до тех пор, пока не найдете точку вне области или все точки не будут проверены (тогда первый многоугольник полностью лежит внутри второго многоугольника). Если вы нашли точку снаружи, то вы можете рассчитать точку пересечения. Найдите соответствующее ребро многоугольника B и следуйте за ним с resersed ролями = теперь проверьте, лежат ли точки многоугольника B в пределах многоугольника A. Таким образом, вы можете построить список точек, которые описывают перекрывающийся многоугольник. При необходимости вы должны проверить, идентичны ли полигоны, (P1, P2, P3) === (P2, P3, P1).

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

narozed


попробуйте использовать для этого инструменты ГИС, такие как ArcObjects, TopologySuite, GEOS, OGR и т. д. Я не уверен, что все эти дистрибутивы доступны для .net, но все они делают то же самое.


Клипер-это С открытым исходным кодом freeware библиотека обрезки полигонов (написанная на Delphi и C++), которая делает именно то, что вы просите -http://sourceforge.net/projects/polyclipping/

в моем тестировании Clipper значительно быстрее и гораздо менее подвержен ошибкам, чем GPC (см. Более подробные сравнения здесь -http://www.angusj.com/delphi/clipper.php#features). Кроме того, хотя есть исходный код для Delphi и c++, Клипер библиотека также включает в себя скомпилированную DLL, чтобы сделать его очень простым в использовании функций отсечения в других языках (Windows) тоже.


этой научные статьи объясняет как это делать.


Если вы осмелитесь взглянуть на код GPL c++ других людей, вы можете увидеть, как они это делают в Inkscape:

http://bazaar.launchpad.net/~inkscape.dev/inkscape/trunk/view/head:/src/2geom/shape.cpp (строка 126)