【问题标题】:Boost Geometry and exact point typesBoost Geometry 和精确的点类型
【发布时间】:2014-08-27 16:48:22
【问题描述】:

我目前正在从事一个处理几何问题的项目。由于这个项目将用于商业用途,我不能使用像 CGAL 这样的库。

我目前正在使用具有不精确类型的 boost::geometry,但遇到了数字问题。 我试图简单地使用 boost::multiprecision 中的精确点类型,但是当我调用 boost::geometry 函数时它不会编译。

我找到了this page,它展示了如何使用 numeric_adaptor 来使用具有精确数字类型的 boost::geometry。但是,它似乎已经过时了,我无法让它工作。

boost::geometry 可以与精确数字类型一起使用吗?怎么样?

#include <vector>

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

#include <boost/multiprecision/gmp.hpp>

namespace bg = boost::geometry;
namespace bm = boost::multiprecision;

typedef bg::model::d2::point_xy<bm::mpq_rational> point;
typedef boost::geometry::model::segment<point> segment;

int main(void)
{
    point a(0,0);
    point b(1,0);
    point c(1,1);
    point d(0,1);

    segment s1(a,c);
    segment s2(b,d);

    std::vector<point> ip;
    bg::intersection(s1, s2, ip); // Doesn't compile

    return 0;
}

clang++3.4.2 输出:

In file included from boost_geom_intersect.cpp:3:
In file included from /usr/include/boost/geometry.hpp:17:
In file included from /usr/include/boost/geometry/geometry.hpp:36:
In file included from /usr/include/boost/geometry/core/radian_access.hpp:21:
In file included from /usr/include/boost/numeric/conversion/cast.hpp:33:
In file included from /usr/include/boost/numeric/conversion/converter.hpp:14:
/usr/include/boost/numeric/conversion/converter_policies.hpp:187:69: error: cannot convert 'const
      boost::multiprecision::detail::expression<boost::multiprecision::detail::divides,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      void, void>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, void, void>' to 'result_type' (aka 'double') without a conversion
      operator
  static result_type low_level_convert ( argument_type s ) { return static_cast<result_type>(s) ; }
                                                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/numeric/conversion/detail/converter.hpp:524:32: note: in instantiation of member function
      'boost::numeric::raw_converter<boost::numeric::conversion_traits<double, boost::multiprecision::detail::expression<boost::multiprecision::detail::divides,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      void, void>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, void, void> > >::low_level_convert' requested here
      return RawConverterBase::low_level_convert(s);
                               ^
/usr/include/boost/numeric/conversion/cast.hpp:53:27: note: in instantiation of member function
      'boost::numeric::convdetail::non_rounding_converter<boost::numeric::conversion_traits<double,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::divides,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      void, void>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, void, void> >,
      boost::numeric::convdetail::dummy_range_checker<boost::numeric::conversion_traits<double,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::divides,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      void, void>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, void, void> > >,
      boost::numeric::raw_converter<boost::numeric::conversion_traits<double, boost::multiprecision::detail::expression<boost::multiprecision::detail::divides,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      void, void>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, void, void> > > >::convert' requested here
        return converter::convert(arg);
                          ^
/usr/include/boost/geometry/policies/robustness/segment_ratio.hpp:146:22: note: in instantiation of function template specialization 'boost::numeric_cast<double,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::divides,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      void, void>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, void, void> >' requested here
            : boost::numeric_cast<double>
                     ^
/usr/include/boost/geometry/policies/robustness/segment_ratio.hpp:129:9: note: in instantiation of member function
      'boost::geometry::segment_ratio<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1> >::initialize' requested here
        initialize();
        ^
/usr/include/boost/geometry/strategies/cartesian/cart_intersect.hpp:207:33: note: in instantiation of member function
      'boost::geometry::segment_ratio<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1> >::assign' requested here
                sinfo.robust_ra.assign(robust_da, robust_da0);
                                ^
/usr/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp:114:47: note: in instantiation of function template specialization
      'boost::geometry::strategy::intersection::relate_cartesian_segments<boost::geometry::policies::relate::segments_intersection_points<boost::geometry::segment_intersection_points<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational,
      1>, boost::geometry::cs::cartesian>, boost::geometry::segment_ratio<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1> > > >,
      void>::apply<boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >, boost::geometry::detail::no_rescale_policy,
      boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, boost::geometry::cs::cartesian> >' requested
      here
        intersection_return_type is = policy::apply(segment1, segment2,
                                              ^
/usr/include/boost/geometry/algorithms/intersection.hpp:51:12: note: in instantiation of function template specialization
      'boost::geometry::detail::intersection::intersection_segment_segment_point<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational,
      1>, boost::geometry::cs::cartesian>
      >::apply<boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >, boost::geometry::detail::no_rescale_policy,
      std::back_insert_iterator<std::vector<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian>, std::allocator<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational,
      1>, boost::geometry::cs::cartesian> > > >, boost::geometry::strategy_intersection<boost::geometry::cartesian_tag,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >, boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian>, boost::geometry::detail::no_rescale_policy, void> >' requested here
        >::apply(geometry1, geometry2, robust_policy, std::back_inserter(geometry_out), strategy);
           ^
/usr/include/boost/geometry/algorithms/intersection.hpp:148:12: note: in instantiation of function template specialization
      'boost::geometry::dispatch::intersection<boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational,
      1>, boost::geometry::cs::cartesian> >,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >, boost::geometry::segment_tag, boost::geometry::segment_tag, false>::apply<boost::geometry::detail::no_rescale_policy,
      std::vector<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>, boost::geometry::cs::cartesian>,
      std::allocator<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> > >, boost::geometry::strategy_intersection<boost::geometry::cartesian_tag,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >, boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian>, boost::geometry::detail::no_rescale_policy, void> >' requested here
        >::apply(geometry1, geometry2, robust_policy, geometry_out, strategy());
           ^
/usr/include/boost/geometry/algorithms/intersection.hpp:308:21: note: in instantiation of function template specialization
      'boost::geometry::resolve_variant::intersection<boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational,
      1>, boost::geometry::cs::cartesian> >,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >
      >::apply<std::vector<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian>, std::allocator<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational,
      1>, boost::geometry::cs::cartesian> > > >' requested here
        >::template apply
                    ^
boost_geom_intersect.cpp:27:9: note: in instantiation of function template specialization
      'boost::geometry::intersection<boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational,
      1>, boost::geometry::cs::cartesian> >,
      boost::geometry::model::segment<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> >, std::vector<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational,
      1>, boost::geometry::cs::cartesian>,
      std::allocator<boost::geometry::model::d2::point_xy<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational, 1>,
      boost::geometry::cs::cartesian> > > >' requested here
    bg::intersection(s1, s2, ip); // Doesn't compile
        ^
1 error generated.

【问题讨论】:

  • 旁注:你完全可以在商业项目中使用 CGAL,你应该与 GeometryFactory 讨论,商业许可证是负担得起的。虽然如果 Boost.Geometry 适合你,那确实更便宜。

标签: c++ boost computational-geometry arbitrary-precision boost-geometry


【解决方案1】:

Boost Geometry 被 表达式模板 返回的代理类型弄糊涂了,它期待具体的数字结果:documentation

多精度库分为两个不同的部分:

  • 一个启用表达式模板的前端编号,可处理所有运算符重载、表达式求值优化和代码缩减。
  • 执行实际算术运算的后端选择,只需要符合前端​​的简化接口要求。

元编程在那里停止。

幸运的是,您可以简单地使用修改后的mpq_rational 来禁用表达式模板:

typedef bm::number<bm::gmp_rational, bm::et_off> my_rational;

这将毫无问题地编译。


Coliru 窒息,但这里是:http://coliru.stacked-crooked.com/a/232d98bfbb430468

#include <vector>

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

#include <boost/multiprecision/gmp.hpp>
#include <boost/multiprecision/number.hpp>

namespace bg = boost::geometry;
namespace bm = boost::multiprecision;

typedef bm::number<bm::gmp_rational, bm::et_off> my_rational;
typedef bg::model::d2::point_xy<my_rational > point;
typedef boost::geometry::model::segment<point> segment;

int main(void)
{
    point a(0,0);
    point b(1,0);
    point c(1,1);
    point d(0,1);

    segment s1(a,c);
    segment s2(b,d);

    std::vector<point> ip;
    bg::intersection(s1, s2, ip); // Doesn't compile

    return 0;
}

【讨论】:

  • 它有效,谢谢 =)。我的运行时间现在是 73 分钟(不准确:10 秒)。为了加快速度,我会尝试使用惰性精确类型(避免不必要的精确计算),但我没有在 boost.js 中找到任何东西。 CGAL 处理这些类型。但是,看起来 CGAL 有理类型使用了无法停用的表达式模板(在使用 CGAL 精确数字类型时,我遇到了与上述相同的错误)。另一方面,使用 boost::multiprecision 类型的 CGAL::Lazy_exact_nt 似乎并不简单(我没有在 CGAL 中找到自定义数字类型的示例)。您对如何做到这一点有任何想法吗?
  • 原来的mpq_rational就是这样:一个懒惰的精确类型。问题是,几何不支持未评估的表达式,所以这就是路的尽头。问题不在于没有延迟评估的类型,而是 Boost Geo 不支持这种类型。您可以包装自己的隐藏它的类型,但这需要相当多的 type-erasure-fu
  • @deadlock CGAL 数字类型不使用表达式模板(GMP 中的 mpq_class 使用,但在 CGAL 中默认不使用),因此您得到的错误可能不同。
猜你喜欢
  • 1970-01-01
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
  • 2014-06-03
  • 1970-01-01
  • 2018-05-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多