Геометрия карты пересечения двух трехмерных линий с использованием Boost - PullRequest
1 голос
/ 18 июня 2020

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

Насколько я понимаю [1], Boost должен рассчитывать пересечение с использованием Геометрия карты - то есть координата Z не учитывается. Это то, что мне нужно.

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

Но если вторая линия пересекает плоскость, содержащую первую линию - случай 2 - тогда пересечение обнаруживается - даже если две линии не пересекаются в трехмерном пространстве.

Я неправильно понимаю? Или есть способ заставить случай 1 работать?

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

Спасибо

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

namespace bg = boost::geometry;

int main()
{
    typedef bg::model::point<double, 3, bg::cs::cartesian> point_t;
    typedef bg::model::linestring<point_t> linestring_t;

    linestring_t ls1{{0, 0, 1}, {1, 1, 1}};
    linestring_t ls2{{0, 1, 0}, {1, 0, 0}};
    linestring_t ls3{{0, 1, 0}, {1, 0, 1}};

    std::vector<point_t> intersections;

    bg::intersection(ls1, ls2, intersections);


    std::cout << "Case 1: Intersection between l1 and l2? " << (intersections.size() > 0 ? "Yes" : "No") << std::endl;

    bg::intersection(ls1, ls3, intersections);
    std::cout << "Case 2: Intersection between l1 and l3? " << (intersections.size() > 0 ? "Yes" : "No") << std::endl;


    return 0;
}

вывод:

Case 1: Intersection between l1 and l2? No
Case 2: Intersection between l1 and l3? Yes

Ссылки:

[1] «Как пересечь трехмерные полигоны с помощью библиотеки Boost C ++?» , { ссылка }

1 Ответ

1 голос
/ 18 июня 2020

В связанном ответе просто говорится, что

  • Boost Geometry area действительно поддерживает размеры реализации> 2¹
  • Стандарт OGM позволяет соответствующим реализациям работать с геометрией карты, хотя они могут реализовать полную трехмерную геометрию, если она соответствует другому стандарту.

Сегодня я не могу найти ничего другого в отношении intersection. Для меня довольно удивительно, что в документации нет четких предупреждений о неуказанном поведении.

Однако, похоже, единственный способ получить поведение map-geo - вручную сопоставить:

Live On Coliru

#include <iostream>
#include <vector>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/geometries/multi_point.hpp>
#include <boost/geometry/algorithms/for_each.hpp>

namespace bg = boost::geometry;
static inline constexpr auto io = [](auto& g) { return bg::dsv(g); }; // switch to bg::wkt easily
using point_t      = bg::model::point<double, 3, bg::cs::cartesian>;
using points_t     = bg::model::multi_point<point_t>;
using linestring_t = bg::model::linestring<point_t>;

struct ZeroZ {
    inline void operator()(point_t& p)          const  { p.set<2>(0);                  } 
    template <typename G> void operator()(G& g) const  { bg::for_each_point(g, *this); } 
} static inline constexpr zeroz{};

int main() {
    std::cout << std::fixed << std::setprecision(2);

    linestring_t const lss[] = {
        {{0, 0, 1}, {1, 1, 1}},
        {{0, 1, 0}, {1, 0, 0}},
        {{0, 1, 0}, {1, 0, 1}},
    };

    for (auto a : lss) for (auto b : lss) {
        points_t c, d;
        bg::intersection(a, b, c);

        std::cout << "Normal:  " << io(a) << " with " << io(b) << " ->" << io(c) << "\n";
        zeroz(a);
        zeroz(b);

        bg::intersection(a, b, d);
        if (!bg::equals(c, d))
            std::cout << " -- but: " << io(a) << " with " << io(b) << " ->" << io(d) << "\n";
    }
}

Печать

Normal:  ((0.00, 0.00, 1.00), (1.00, 1.00, 1.00)) with ((0.00, 0.00, 1.00), (1.00, 1.00, 1.00)) ->((0.00, 0.00, 1.00), (1.00, 1.00, 1.00))
 -- but: ((0.00, 0.00, 0.00), (1.00, 1.00, 0.00)) with ((0.00, 0.00, 0.00), (1.00, 1.00, 0.00)) ->((0.00, 0.00, 0.00), (1.00, 1.00, 0.00))
Normal:  ((0.00, 0.00, 0.00), (1.00, 1.00, 0.00)) with ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) ->((0.50, 0.50, 0.00))
Normal:  ((0.00, 0.00, 0.00), (1.00, 1.00, 0.00)) with ((0.00, 1.00, 0.00), (1.00, 0.00, 1.00)) ->((0.50, 0.50, 0.00))
Normal:  ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) with ((0.00, 0.00, 1.00), (1.00, 1.00, 1.00)) ->()
 -- but: ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) with ((0.00, 0.00, 0.00), (1.00, 1.00, 0.00)) ->((0.50, 0.50, 0.00))
Normal:  ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) with ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) ->((0.00, 1.00, 0.00), (1.00, 0.00, 0.00))
Normal:  ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) with ((0.00, 1.00, 0.00), (1.00, 0.00, 1.00)) ->((0.00, 1.00, 0.00), (1.00, 0.00, 0.00))
Normal:  ((0.00, 1.00, 0.00), (1.00, 0.00, 1.00)) with ((0.00, 0.00, 1.00), (1.00, 1.00, 1.00)) ->((0.50, 0.50, 0.00))
Normal:  ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) with ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) ->((0.00, 1.00, 0.00), (1.00, 0.00, 0.00))
Normal:  ((0.00, 1.00, 0.00), (1.00, 0.00, 0.00)) with ((0.00, 1.00, 0.00), (1.00, 0.00, 1.00)) ->((0.00, 1.00, 0.00), (1.00, 0.00, 0.00))

¹ в то время, даже не проверено, изменилось ли это

...