Использование усиленной геометрии для проверки пересечения двух линий

Можно ли использовать boost :: geometry, чтобы проверить, пересекаются ли два линейных сегмента (каждый из которых задан двумя точками в 2D)? Если это возможно, позволяет ли boost :: geometry проверять также особые случаи, например, что только одна точка (численно) находится на другой строке или что обе линии равны?


person Thomas W.    schedule 08.11.2013    source источник
comment
Чтобы уточнить свой вопрос: я имею в виду два отрезка линии   -  person Thomas W.    schedule 08.11.2013


Ответы (4)


Если вы говорите конкретно о Boost.Geometry API, то это, конечно, возможно.

Ваш код должен выглядеть примерно так

#include <boost/geometry/geometries/segment.hpp> 
#include <boost/geometry/algorithms/intersection.hpp>

typedef boost::geometry::model::segment<Point> Segment;
Segment AB( Point(x1,y1), Point(x2,y2) );
Segment CD; //similar code

bool result = boost::geometry::intersects(AB, CD);

Если вам нужны точки пересечения:

std::vector<Point> output; 
boost::geometry::intersection(AB, CD, output);

Теперь на выходе будет 0, 1 или 2 балла, в зависимости от местоположения.

Конечно, ваш тип Point должен "соответствовать" концепциям Boost.Geometry. Следующий код сделает QPointF совместимым:

#include <boost/geometry/geometries/register/point.hpp>
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(QPointF, qreal, cs::cartesian, x, y, setX, setY);
person Michael Simbirsky    schedule 08.11.2013
comment
Как новичок в Boost, не могли бы вы уточнить последнюю часть о соответствии? Я не очень понимаю, что там имеется в виду. - person michaelgulak; 29.06.2015
comment
Классы и функции из Boost.Geometry используют определенные приемы метапрограммирования для доступа к координатам точки (точек). Если вы попытаетесь использовать их со своим пользовательским классом Point, вы, вероятно, получите много ошибок компиляции. Макросы, подобные BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET, объясняют Boost.Geometry, как получить доступ к вашему пользовательскому классу Point или изменить его. - person Michael Simbirsky; 01.07.2015

Вы спрашиваете, пересекаются ли две линии. Две линии всегда будут пересекаться, если они не параллельны.

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

x1 y1 1
x2 y2 1
x3 y3 1

Где (x1; y1) и (x2; y2) - это точка, представляющая вашу линию, а (x3; y3) - вашу 3-ю точку (одну из крайностей вашего сегмента). Если определитель положительный, то (x3; y3) находится справа от вектора, ориентированного от (x1; y1) к (x2; y2), если он отрицательный, то вправо. И если определитель равен 0, то точка находится на прямой.

Что вам нужно сделать, так это применить этот алгоритм дважды, один раз для одного конца сегмента и один раз для другого, если произведение детерминант отрицательное, оно пересекается, если нет, это не так.

Вы можете пойти дальше и вычислить, пересекаются ли два сегмента. Все, что вам нужно сделать, это применить ту же идею дважды, только во второй раз ваши (x1; y1) и (x2; y2) будут значениями, которые вы использовали для (x3; y3), а ваш новый (x3; y3) ваш старые (x1; y1) и (x2; y2).

Я изучил этот алгоритм под «алгоритмом Сарруса», так что, возможно, поиск в Google может дать лучшее объяснение.

person Alexandru Barbarosie    schedule 08.11.2013
comment
Я подумал об этом, и это работает не для всех угловых случаев. Просто подумайте о первом отрезке [0,0] - ›[1,1] и втором отрезке [2,2] -› [3,3]. Грубо говоря, отрезки линии не пересекаются, но оба определителя равны нулю, поскольку оба отрезка линии являются частью одной (бесконечной) линии. - person Thomas W.; 09.11.2013
comment
Что ж, вы можете легко проверить этот конкретный случай - вы можете вычислить линейную функцию из двух точек и сравнить наклоны и коэффициенты, а затем проверить, не перекрываются ли они. - person Alexandru Barbarosie; 09.11.2013

пример для новичков без использования BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET

namespace bg = boost::geometry;

typedef bg::model::point<double, 2, bg::cs::cartesian> point_t;
typedef bg::model::segment<point_t> segment_t;

segment_t seg1(point_t(0.0, 0.0), point_t(5.0, 5.0));
segment_t seg2(point_t(10.0, 5.0), point_t(5.0, 0.0));

bool result = boost::geometry::intersects(seg1, seg2);
person user1277317    schedule 06.01.2017

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

person anjruu    schedule 08.11.2013
comment
Интересно, а эффективно ли это? Меня просто интересует, пересекаются ли обе линии или нет, мне не нужна результирующая геометрия пересечения. И что еще важнее, как насчет числовой устойчивости этих функций? Как он себя ведет, если одна точка содержится в эпсилон-окружении другой строки? - person Thomas W.; 08.11.2013
comment
Подожди, ты в 2D. Ответ положительный, если только линии не параллельны. - person anjruu; 08.11.2013
comment
@anjruu Я думаю, он имеет в виду два отрезка - person ; 08.11.2013
comment
О, тогда неважно. Я не знаю о числовой устойчивости boost :: geometry :: crossction. - person anjruu; 08.11.2013