使用 boost 几何体调整几何对象模型的其他问题

2023-12-08

我想将 boost::geometry 算法应用于以下不可变的 2D 模型,分别由点、多边形(开放或封闭)和多边形域类(具有任意数量的孔)类组成,如下所示:

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/linestring.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/range.hpp>
#include <memory>
#include <vector>

namespace NGeometry {
   class Point2D {
   public:
      Point2D( double x, double y ) : m_x( x ), m_y( y ) {}
      double getX() const { return m_x; }
      double getY() const { return m_y; }
   private:
      double m_x, m_y;
   };
   using TyPoints2D = std::vector< Point2D >;

   // Either open (first point != last point) or closed (first point == last point) polygon
   class Polygon2D {
   public:
      Polygon2D( TyPoints2D points ) : m_points( std::move( points ) ) {}
      const TyPoints2D& getPoints() const { return m_points; }
   private:
      TyPoints2D m_points;
   };
   using TyPolygon2D = std::shared_ptr< Polygon2D >;
   using TyPolygons2D = std::vector< TyPolygon2D >;

   // Polygonal domain with outer cw oriented closed polygon and >= 0 ccw oriented inner polygons
   class PolygonalDomain2D {
   public:
      PolygonalDomain2D( TyPolygon2D outer, TyPolygons2D inners )
         : m_outer( std::move( outer ) ), m_inners( std::move( inners ) ) {}
      const TyPolygon2D& getOuter() const { return m_outer; }
      const TyPolygons2D& getInners() const { return m_inners; }
   private:
      TyPolygon2D m_outer;
      TyPolygons2D m_inners;
   };
} // namespace NGeometry


// Provide read only Boost.Range for Polygon2D
namespace boost {
   template<>
   struct range_const_iterator< NGeometry::Polygon2D >
   {
      typedef std::vector< NGeometry::Point2D >::const_iterator type;
   };
   template<>
   struct range_value< NGeometry::Polygon2D >
   {
      typedef NGeometry::Point2D type;
   };
} // namespace boost
inline std::vector< NGeometry::Point2D >::const_iterator range_begin( const NGeometry::Polygon2D polygon ) {
   return polygon.getPoints().cbegin();
}
inline std::vector< NGeometry::Point2D >::const_iterator range_end( const NGeometry::Polygon2D polygon ) {
   return polygon.getPoints().cend();
}

BOOST_GEOMETRY_REGISTER_POINT_2D_CONST( NGeometry::Point2D, double, cs::cartesian, getX(), getY() );
BOOST_GEOMETRY_REGISTER_LINESTRING( NGeometry::Polygon2D );
// How to register PolygonalDomain2D?

int main( int argc, char* argv[] )
{
   NGeometry::Point2D point( 0.0, 0.0 );
   auto outerPolygonSP = std::make_shared< NGeometry::Polygon2D >(
      NGeometry::TyPoints2D { { -2.0, -2.0 }, { -2.0, 2.0 }, { 2.0, 2.0 }, { 2.0, -2.0 }, { -2.0, -2.0 } } );
   auto innerPolygonSP = std::make_shared< NGeometry::Polygon2D >(
      NGeometry::TyPoints2D { { -1.0, -1.0 }, { 1.0, -1.0 }, { 1.0, 1.0 }, { -1.0, 1.0 }, { -1.0, -1.0 } } );
   NGeometry::PolygonalDomain2D domain( outerPolygonSP, { innerPolygonSP } );

   double length = boost::geometry::length( *outerPolygonSP );
   double area = boost::geometry::area( domain );
   bool isInside = boost::geometry::within( point, domain );

   return 0;
}

与中描述的第一步相比使用 boost 几何体调整几何对象模型时出现的问题类已被修改并移至 NGeometry 命名空间,这会导致编译器出现有关 NGeometry::Polygon2D 缺少开始和结束的错误。此外,我不知道如何适应域。我将非常感谢任何帮助。

g++ 编译器输出:

In file included from /usr/include/boost/geometry/core/closure.hpp:22,
                 from /usr/include/boost/geometry/geometry.hpp:25,
                 from /usr/include/boost/geometry.hpp:17,
                 from main.cpp:1:
/usr/include/boost/geometry/core/point_type.hpp: In instantiation of ‘struct boost::geometry::traits::point_type<NGeometry::PolygonalDomain2D>’:
/usr/include/boost/geometry/core/point_type.hpp:66:17:   required from ‘struct boost::geometry::core_dispatch::point_type<void, NGeometry::PolygonalDomain2D>’
/usr/include/boost/geometry/core/coordinate_system.hpp:58:59:   required from ‘struct boost::geometry::core_dispatch::coordinate_system<void, NGeometry::PolygonalDomain2D>’
/usr/include/boost/geometry/core/coordinate_system.hpp:93:17:   required from ‘struct boost::geometry::coordinate_system<NGeometry::PolygonalDomain2D>’
/usr/include/boost/geometry/core/cs.hpp:244:17:   required from ‘struct boost::geometry::cs_tag<NGeometry::PolygonalDomain2D>’
/usr/include/boost/geometry/strategies/area_result.hpp:59:8:   required from ‘struct boost::geometry::area_result<NGeometry::PolygonalDomain2D, boost::geometry::default_strategy>’
/usr/include/boost/geometry/algorithms/area.hpp:320:1:   required by substitution of ‘template<class Geometry> typename boost::geometry::area_result<Geometry, boost::geometry::default_strategy>::type boost::geometry::area(const Geometry&) [with Geometry = NGeometry::PolygonalDomain2D]’
main.cpp:78:48:   required from here
/usr/include/boost/geometry/core/point_type.hpp:45:5: error: could not convert ‘boost::geometry::traits::point_type<NGeometry::PolygonalDomain2D>::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE45::assert_arg()’ from ‘mpl_::failed************ (boost::geometry::traits::point_type<NGeometry::PolygonalDomain2D>::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE::************)(mpl_::assert_::types<NGeometry::PolygonalDomain2D, mpl_::na, mpl_::na, mpl_::na>)’ to ‘mpl_::assert<false>::type’ {aka ‘mpl_::assert<false>’}
   45 |     BOOST_MPL_ASSERT_MSG
      |     ^
      |     |
      |     mpl_::failed************ (boost::geometry::traits::point_type<NGeometry::PolygonalDomain2D>::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE::************)(mpl_::assert_::types<NGeometry::PolygonalDomain2D, mpl_::na, mpl_::na, mpl_::na>)
In file included from /usr/include/boost/geometry/core/coordinate_dimension.hpp:23,
                 from /usr/include/boost/geometry/geometry.hpp:26,
                 from /usr/include/boost/geometry.hpp:17,
                 from main.cpp:1:
/usr/include/boost/geometry/core/point_type.hpp: In instantiation of ‘struct boost::geometry::core_dispatch::point_type<void, NGeometry::PolygonalDomain2D>’:
/usr/include/boost/geometry/core/coordinate_system.hpp:58:59:   required from ‘struct boost::geometry::core_dispatch::coordinate_system<void, NGeometry::PolygonalDomain2D>’
/usr/include/boost/geometry/core/coordinate_system.hpp:93:17:   required from ‘struct boost::geometry::coordinate_system<NGeometry::PolygonalDomain2D>’
/usr/include/boost/geometry/core/cs.hpp:244:17:   required from ‘struct boost::geometry::cs_tag<NGeometry::PolygonalDomain2D>’
/usr/include/boost/geometry/strategies/area_result.hpp:59:8:   required from ‘struct boost::geometry::area_result<NGeometry::PolygonalDomain2D, boost::geometry::default_strategy>’
/usr/include/boost/geometry/algorithms/area.hpp:320:1:   required by substitution of ‘template<class Geometry> typename boost::geometry::area_result<Geometry, boost::geometry::default_strategy>::type boost::geometry::area(const Geometry&) [with Geometry = NGeometry::PolygonalDomain2D]’
main.cpp:78:48:   required from here
/usr/include/boost/geometry/core/point_type.hpp:66:17: error: no type named ‘type’ in ‘struct boost::geometry::traits::point_type<NGeometry::PolygonalDomain2D>’
   66 |         >::type type;
      |                 ^~~~
main.cpp: In function ‘int main(int, char**)’:
main.cpp:78:48: error: no matching function for call to ‘area(NGeometry::PolygonalDomain2D&)’
   78 |    double area = boost::geometry::area( domain );
      |                                                ^
In file included from /usr/include/boost/geometry/geometry.hpp:52,
                 from /usr/include/boost/geometry.hpp:17,
                 from main.cpp:1:
/usr/include/boost/geometry/algorithms/area.hpp:320:1: note: candidate: ‘template<class Geometry> typename boost::geometry::area_result<Geometry, boost::geometry::default_strategy>::type boost::geometry::area(const Geometry&)’
  320 | area(Geometry const& geometry)
      | ^~~~
/usr/include/boost/geometry/algorithms/area.hpp:320:1: note:   substitution of deduced template arguments resulted in errors seen above
/usr/include/boost/geometry/algorithms/area.hpp:356:1: note: candidate: ‘template<class Geometry, class Strategy> typename boost::geometry::area_result<Geometry, Strategy>::type boost::geometry::area(const Geometry&, const Strategy&)’
  356 | area(Geometry const& geometry, Strategy const& strategy)
      | ^~~~
/usr/include/boost/geometry/algorithms/area.hpp:356:1: note:   template argument deduction/substitution failed:
main.cpp:78:48: note:   candidate expects 2 arguments, 1 provided
   78 |    double area = boost::geometry::area( domain );
      |                                                ^
In file included from /usr/include/boost/geometry/core/closure.hpp:22,
                 from /usr/include/boost/geometry/geometry.hpp:25,
                 from /usr/include/boost/geometry.hpp:17,
                 from main.cpp:1:
/usr/include/boost/geometry/algorithms/not_implemented.hpp: In instantiation of ‘struct boost::geometry::nyi::not_implemented_error<void, void, void>’:
/usr/include/boost/geometry/algorithms/not_implemented.hpp:108:8:   required from ‘struct boost::geometry::not_implemented<void, void, void>’
/usr/include/boost/geometry/geometries/concepts/check.hpp:69:8:   required from ‘struct boost::geometry::dispatch::check<const NGeometry::PolygonalDomain2D, void, true>’
/usr/include/boost/geometry/geometries/concepts/check.hpp:196:8:   required from ‘struct boost::geometry::concepts::detail::checker<const NGeometry::PolygonalDomain2D>’
/usr/include/boost/geometry/geometries/concepts/check.hpp:219:31:   required from ‘void boost::geometry::concepts::check() [with Geometry = const NGeometry::PolygonalDomain2D]’
/usr/include/boost/geometry/algorithms/detail/within/interface.hpp:108:41:   required from ‘static bool boost::geometry::resolve_variant::within<Geometry1, Geometry2>::apply(const Geometry1&, const Geometry2&, const Strategy&) [with Strategy = boost::geometry::default_strategy; Geometry1 = NGeometry::Point2D; Geometry2 = NGeometry::PolygonalDomain2D]’
/usr/include/boost/geometry/algorithms/detail/within/interface.hpp:255:17:   required from ‘bool boost::geometry::within(const Geometry1&, const Geometry2&) [with Geometry1 = NGeometry::Point2D; Geometry2 = NGeometry::PolygonalDomain2D]’
main.cpp:79:59:   required from here
/usr/include/boost/geometry/algorithms/not_implemented.hpp:69:5: error: could not convert ‘boost::geometry::nyi::not_implemented_error<void, void, void>::THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED69::assert_arg()’ from ‘mpl_::failed************ (boost::geometry::nyi::not_implemented_error<void, void, void>::THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED::************)(mpl_::assert_::types<void, void, void, mpl_::na>)’ to ‘mpl_::assert<false>::type’ {aka ‘mpl_::assert<false>’}
   69 |     BOOST_MPL_ASSERT_MSG
      |     ^
      |     |
      |     mpl_::failed************ (boost::geometry::nyi::not_implemented_error<void, void, void>::THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED::************)(mpl_::assert_::types<void, void, void, mpl_::na>)
In file included from /usr/include/boost/geometry/core/coordinate_dimension.hpp:21,
                 from /usr/include/boost/geometry/geometry.hpp:26,
                 from /usr/include/boost/geometry.hpp:17,
                 from main.cpp:1:
/usr/include/boost/geometry/core/coordinate_dimension.hpp: In instantiation of ‘void boost::geometry::assert_dimension_equal() [with G1 = NGeometry::Point2D; G2 = NGeometry::PolygonalDomain2D]’:
/usr/include/boost/geometry/algorithms/detail/within/interface.hpp:109:53:   required from ‘static bool boost::geometry::resolve_variant::within<Geometry1, Geometry2>::apply(const Geometry1&, const Geometry2&, const Strategy&) [with Strategy = boost::geometry::default_strategy; Geometry1 = NGeometry::Point2D; Geometry2 = NGeometry::PolygonalDomain2D]’
/usr/include/boost/geometry/algorithms/detail/within/interface.hpp:255:17:   required from ‘bool boost::geometry::within(const Geometry1&, const Geometry2&) [with Geometry1 = NGeometry::Point2D; Geometry2 = NGeometry::PolygonalDomain2D]’
main.cpp:79:59:   required from here
/usr/include/boost/geometry/core/coordinate_dimension.hpp:122:5: error: no type named ‘type’ in ‘struct boost::geometry::dimension<NGeometry::PolygonalDomain2D>’
  122 |     BOOST_STATIC_ASSERT(( static_cast<size_t>(dimension<G1>::type::value) == static_cast<size_t>(dimension<G2>::type::value) ));
      |     ^~~~~~~~~~~~~~~~~~~
In file included from /usr/include/boost/range/functions.hpp:18,
                 from /usr/include/boost/range/iterator_range_core.hpp:38,
                 from /usr/include/boost/lexical_cast.hpp:30,
                 from /usr/include/boost/math/tools/convert_from_string.hpp:15,
                 from /usr/include/boost/math/constants/constants.hpp:13,
                 from /usr/include/boost/geometry/util/math.hpp:29,
                 from /usr/include/boost/geometry/core/radian_access.hpp:33,
                 from /usr/include/boost/geometry/geometry.hpp:42,
                 from /usr/include/boost/geometry.hpp:17,
                 from main.cpp:1:
/usr/include/boost/range/begin.hpp: In instantiation of ‘constexpr typename boost::range_iterator<T>::type boost::range_detail::range_begin(C&) [with C = const NGeometry::Polygon2D; typename boost::range_iterator<T>::type = __gnu_cxx::__normal_iterator<const NGeometry::Point2D*, std::vector<NGeometry::Point2D> >]’:
/usr/include/boost/range/begin.hpp:119:23:   required from ‘void boost::SinglePassRangeConcept<T>::const_constraints(const Rng&) [with T = const NGeometry::Polygon2D; boost::SinglePassRangeConcept<T>::Rng = const NGeometry::Polygon2D]’
/usr/include/boost/range/concepts.hpp:295:13:   required from ‘boost::SinglePassRangeConcept<T>::~SinglePassRangeConcept() [with T = const NGeometry::Polygon2D]’
/usr/include/boost/range/concepts.hpp:318:12:   required from ‘static void boost::concepts::requirement<boost::concepts::failed************ Model::************>::failed() [with Model = boost::ForwardRangeConcept<const NGeometry::Polygon2D>]’
/usr/include/boost/geometry/geometries/concepts/linestring_concept.hpp:111:5:   required from ‘class boost::geometry::concepts::ConstLinestring<const NGeometry::Polygon2D>’
/usr/include/boost/concept/detail/has_constraints.hpp:32:62:   required by substitution of ‘template<class Model> boost::concepts::detail::yes boost::concepts::detail::has_constraints_(Model*, boost::concepts::detail::wrap_constraints<Model, (& Model::constraints)>*) [with Model = boost::geometry::concepts::ConstLinestring<const NGeometry::Polygon2D>]’
/usr/include/boost/concept/detail/has_constraints.hpp:42:5:   [ skipping 3 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/concept_check.hpp:50:7:   required from ‘class boost::geometry::detail::concept_check::check<boost::geometry::concepts::ConstLinestring<const NGeometry::Polygon2D> >’
/usr/include/boost/geometry/geometries/concepts/check.hpp:86:8:   required from ‘struct boost::geometry::dispatch::check<const NGeometry::Polygon2D, boost::geometry::linestring_tag, true>’
/usr/include/boost/geometry/geometries/concepts/check.hpp:196:8:   required from ‘struct boost::geometry::concepts::detail::checker<const NGeometry::Polygon2D>’
/usr/include/boost/geometry/geometries/concepts/check.hpp:219:31:   required from ‘void boost::geometry::concepts::check() [with Geometry = const NGeometry::Polygon2D]’
/usr/include/boost/geometry/algorithms/length.hpp:282:36:   required from ‘typename boost::geometry::default_length_result<Geometry>::type boost::geometry::length(const Geometry&) [with Geometry = NGeometry::Polygon2D; typename boost::geometry::default_length_result<Geometry>::type = long double]’
main.cpp:77:61:   required from here
/usr/include/boost/range/concepts.hpp:301:46:   in ‘constexpr’ expansion of ‘boost::range_adl_barrier::begin<NGeometry::Polygon2D>((* & const_range))’
/usr/include/boost/range/begin.hpp:49:18: error: ‘const class NGeometry::Polygon2D’ has no member named ‘begin’
   49 |         return c.begin();
      |                ~~^~~~~
In file included from /usr/include/boost/range/functions.hpp:19,
                 from /usr/include/boost/range/iterator_range_core.hpp:38,
                 from /usr/include/boost/lexical_cast.hpp:30,
                 from /usr/include/boost/math/tools/convert_from_string.hpp:15,
                 from /usr/include/boost/math/constants/constants.hpp:13,
                 from /usr/include/boost/geometry/util/math.hpp:29,
                 from /usr/include/boost/geometry/core/radian_access.hpp:33,
                 from /usr/include/boost/geometry/geometry.hpp:42,
                 from /usr/include/boost/geometry.hpp:17,
                 from main.cpp:1:
/usr/include/boost/range/end.hpp: In instantiation of ‘constexpr typename boost::range_iterator<T>::type boost::range_detail::range_end(C&) [with C = const NGeometry::Polygon2D; typename boost::range_iterator<T>::type = __gnu_cxx::__normal_iterator<const NGeometry::Point2D*, std::vector<NGeometry::Point2D> >]’:
/usr/include/boost/range/end.hpp:113:21:   required from ‘void boost::SinglePassRangeConcept<T>::const_constraints(const Rng&) [with T = const NGeometry::Polygon2D; boost::SinglePassRangeConcept<T>::Rng = const NGeometry::Polygon2D]’
/usr/include/boost/range/concepts.hpp:295:13:   required from ‘boost::SinglePassRangeConcept<T>::~SinglePassRangeConcept() [with T = const NGeometry::Polygon2D]’
/usr/include/boost/range/concepts.hpp:318:12:   required from ‘static void boost::concepts::requirement<boost::concepts::failed************ Model::************>::failed() [with Model = boost::ForwardRangeConcept<const NGeometry::Polygon2D>]’
/usr/include/boost/geometry/geometries/concepts/linestring_concept.hpp:111:5:   required from ‘class boost::geometry::concepts::ConstLinestring<const NGeometry::Polygon2D>’
/usr/include/boost/concept/detail/has_constraints.hpp:32:62:   required by substitution of ‘template<class Model> boost::concepts::detail::yes boost::concepts::detail::has_constraints_(Model*, boost::concepts::detail::wrap_constraints<Model, (& Model::constraints)>*) [with Model = boost::geometry::concepts::ConstLinestring<const NGeometry::Polygon2D>]’
/usr/include/boost/concept/detail/has_constraints.hpp:42:5:   [ skipping 3 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/concept_check.hpp:50:7:   required from ‘class boost::geometry::detail::concept_check::check<boost::geometry::concepts::ConstLinestring<const NGeometry::Polygon2D> >’
/usr/include/boost/geometry/geometries/concepts/check.hpp:86:8:   required from ‘struct boost::geometry::dispatch::check<const NGeometry::Polygon2D, boost::geometry::linestring_tag, true>’
/usr/include/boost/geometry/geometries/concepts/check.hpp:196:8:   required from ‘struct boost::geometry::concepts::detail::checker<const NGeometry::Polygon2D>’
/usr/include/boost/geometry/geometries/concepts/check.hpp:219:31:   required from ‘void boost::geometry::concepts::check() [with Geometry = const NGeometry::Polygon2D]’
/usr/include/boost/geometry/algorithms/length.hpp:282:36:   required from ‘typename boost::geometry::default_length_result<Geometry>::type boost::geometry::length(const Geometry&) [with Geometry = NGeometry::Polygon2D; typename boost::geometry::default_length_result<Geometry>::type = long double]’
main.cpp:77:61:   required from here
/usr/include/boost/range/concepts.hpp:302:44:   in ‘constexpr’ expansion of ‘boost::range_adl_barrier::end<NGeometry::Polygon2D>((* & const_range))’
/usr/include/boost/range/end.hpp:50:22: error: ‘const class NGeometry::Polygon2D’ has no member named ‘end’
   50 |             return c.end();
      |                    ~~^~~

首先,让我们修复未定义的行为因为你按值获取参数range_begin and range_end。这意味着,根据定义,您将迭代器返回到在您使用它们之前就已经消失的临时对象中。

此外,通过将这些重载放入其范围类型的声明命名空间中,根据 Boost Range 设计启用 ADL:

namespace NGeometry {
    inline std::vector<NGeometry::Point2D>::const_iterator
    range_begin(NGeometry::Polygon2D const& polygon) {
        return polygon.getPoints().cbegin();
    }
    inline std::vector<NGeometry::Point2D>::const_iterator
    range_end(NGeometry::Polygon2D const& polygon) {
        return polygon.getPoints().cend();
    }
}

好吧,哇。现在,只要我们运行任何东西,它就不会崩溃(或者更糟糕的是,不会崩溃并导致巨额法律费用)。

戒指概念

接下来,您将多边形类型注册为... LINESTRING。这是行不通的,因为它不是多边形概念所需要的:Ring and Polygon.

解决这个问题

BOOST_GEOMETRY_REGISTER_RING(NGeometry::Polygon2D)

让您走得更远:

namespace bg = boost::geometry;
auto outer =
    std::make_shared<NGeometry::Polygon2D>(NGeometry::TyPoints2D{
        {-2.0, -2.0}, {-2.0, 2.0}, {2.0, 2.0}, {2.0, -2.0}, {-2.0, -2.0}});

std::cout << bg::wkt(*outer) << "\n";
std::cout << bg::dsv(*outer) << "\n";
std::cout << "Length: " << bg::length(*outer) << "\n";
std::cout << "Area: " << bg::area(*outer) << "\n";

Prints

POLYGON((-2 -2,-2 2,2 2,2 -2,-2 -2))
((-2, -2), (-2, 2), (2, 2), (2, -2), (-2, -2))
Length: 0
Area: 16

扩展到PolygonalDomain2D

您的“域”就是 OGC 所称的多边形。它具有一个外环和可选的多个内环。幸运的是,OGC 标准还要求反转内环的点顺序。

然而,你通过聚合环而不是聚合环使事情变得有点复杂化。directly但是通过shared_ptr。我觉得你might还要经历将shared_ptr调整为适当的环的麻烦。下面我将向您展示我所做的事情。

如何注册多边形

没有“REGISTER_XXX”功能。你必须按照记录进行概念要求.

该文档与现实并不 100% 同步,我不久前就发现了这一点:(如何)在 boost 几何体中创建自己的多边形类型并使用 multi_polygon 类型?

如果你去写出相关的特征:

template <> struct tag<NGeometry::PolygonalDomain2D> {
    using type = polygon_tag;
};
template <> struct ring_mutable_type<NGeometry::PolygonalDomain2D> {
    using type = NGeometry::Polygon2D;
};
template <> struct ring_const_type<NGeometry::PolygonalDomain2D> {
    using type = NGeometry::Polygon2D const;
};
template <> struct exterior_ring<NGeometry::PolygonalDomain2D> {
    static decltype(auto) get(NGeometry::PolygonalDomain2D &v) {
        return *v.getOuter();
    }
    static decltype(auto) get(NGeometry::PolygonalDomain2D const &v) {
        return *v.getOuter();
    }
};

现在它变得很有趣,因为我们已经到达了您的内部环,它不是存储为环模型的简单容器,而是存储为指向它们的共享指针的容器。

我要站在巨人的肩膀上并利用boost::adaptors::indirected合成隐藏该间接层的范围。

template <> struct interior_rings<NGeometry::PolygonalDomain2D> {
    static decltype(auto) get(NGeometry::PolygonalDomain2D &v) {
        return v.getInners() | boost::adaptors::indirected;
    }
    static decltype(auto) get(NGeometry::PolygonalDomain2D const &v) {
        return v.getInners() | boost::adaptors::indirected;
    }
};

接下来,我重新排序了该实现之后的类型特征,以便我可以使用类型推导而不是拼写出实现类型名称:

template <> struct interior_mutable_type<NGeometry::PolygonalDomain2D> {
    using type = decltype(interior_rings<NGeometry::PolygonalDomain2D>::get(
        std::declval<NGeometry::PolygonalDomain2D>()));
};
template <> struct interior_const_type<NGeometry::PolygonalDomain2D> {
    using type = decltype(interior_rings<NGeometry::PolygonalDomain2D>::get(
        std::declval<NGeometry::PolygonalDomain2D>())) const;
};

有了这个技巧,我们就可以测试:

int main() {
    auto report = [](auto heading, auto &g) {
        std::cout << " == " << heading << " ========================\n";
        check_poly(g);
        std::cout << "WKT:       " << bg::wkt(g)       << "\n";
        std::cout << "DSV:       " << bg::dsv(g)       << "\n";
        std::cout << "Area:      " << bg::area(g)      << "\n";
        std::cout << "Perimeter: " << bg::perimeter(g) << "\n";

        if constexpr (std::is_same_v<bg::polygon_tag,
                                     typename bg::traits::tag<
                                         std::decay_t<decltype(g)>>::type>)
        {
            std::cout << "Outer Perimeter: "
                      << bg::perimeter(bg::exterior_ring(g)) << "\n";
        }
    };

    auto outer =
        std::make_shared<NGeometry::Polygon2D>(NGeometry::TyPoints2D{
            {-3.0, -3.0}, {-3.0, 3.0}, {3.0, 3.0}, {3.0, -3.0}, {-3.0, -3.0}});
    auto inner =
        std::make_shared<NGeometry::Polygon2D>(NGeometry::TyPoints2D{
            {-2.0, -2.0}, {2.0, -2.0}, {2.0, 2.0}, {-2.0, 2.0}, {-2.0, -2.0}});

    NGeometry::PolygonalDomain2D domain(outer, {inner});

    report("Outer", *outer);
    report("Inner", *inner);
    report("Domain", domain);

    std::cout << " == Within Check ========================\n";
    std::cout << "Point (0,0) within domain? " << std::boolalpha
              << bg::within(NGeometry::Point2D(0.0, 0.0), domain) << "\n";
}

哪个打印

 == Outer ========================
WKT:       POLYGON((-3 -3,-3 3,3 3,3 -3,-3 -3))
DSV:       ((-3, -3), (-3, 3), (3, 3), (3, -3), (-3, -3))
Area:      36
Perimeter: 24
 == Inner ========================
Warning: Geometry has wrong orientation
WKT:       POLYGON((-2 -2,2 -2,2 2,-2 2,-2 -2))
DSV:       ((-2, -2), (2, -2), (2, 2), (-2, 2), (-2, -2))
Area:      -16
Perimeter: 16
 == Domain ========================
WKT:       POLYGON((-3 -3,-3 3,3 3,3 -3,-3 -3),(-2 -2,2 -2,2 2,-2 2,-2 -2))
DSV:       (((-3, -3), (-3, 3), (3, 3), (3, -3), (-3, -3)), ((-2, -2), (2, -2), (2, 2), (-2, 2
), (-2, -2)))
Area:      20
Perimeter: 40
Outer Perimeter: 24
 == Within Check ========================
Point (0,0) within domain? false

Note

The Warning: Geometry has wrong orientation由于内环具有相反点顺序的概念要求,这正是您想要的。因此,检查证实了我们想要看到的内容。

完整演示住在科里鲁

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/ring.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <memory>
#include <vector>
#include <iostream>

namespace NGeometry {
class Point2D {
  public:
    Point2D(double x, double y) : m_x(x) , m_y(y) { }
    [[nodiscard]] double getX() const { return m_x; }
    [[nodiscard]] double getY() const { return m_y; }

  private:
    double m_x, m_y;
};
using TyPoints2D = std::vector<Point2D>;

// Either open (first point != last point) or closed (first point == last
// point) polygon
class Polygon2D {
  public:
    Polygon2D(TyPoints2D points) : m_points(std::move(points)) {}
    [[nodiscard]] const TyPoints2D &getPoints() const { return m_points; }

  private:
    TyPoints2D m_points;
};

using SharedPolygon2D = std::shared_ptr<Polygon2D>;
using TyPolygons2D = std::vector<SharedPolygon2D>;

// Polygonal domain with outer cw oriented closed
// polygon and >= 0 ccw oriented inner polygons
class PolygonalDomain2D {
  public:
    PolygonalDomain2D(SharedPolygon2D outer, TyPolygons2D inners)
        : m_outer(std::move(outer)), m_inners(std::move(inners)) {}
    [[nodiscard]] const SharedPolygon2D &getOuter() const { return m_outer; }
    [[nodiscard]] const TyPolygons2D &getInners() const { return m_inners; }

  private:
    SharedPolygon2D m_outer;
    TyPolygons2D m_inners;
};
} // namespace NGeometry

// Provide read only Boost.Range for Polygon2D
namespace NGeometry {
    inline std::vector<NGeometry::Point2D>::const_iterator
    range_begin(NGeometry::Polygon2D const& polygon) {
        return polygon.getPoints().cbegin();
    }
    inline std::vector<NGeometry::Point2D>::const_iterator
    range_end(NGeometry::Polygon2D const& polygon) {
        return polygon.getPoints().cend();
    }

    inline std::vector<NGeometry::Point2D>::const_iterator
    range_begin(NGeometry::Polygon2D& polygon) {
        return polygon.getPoints().cbegin();
    }
    inline std::vector<NGeometry::Point2D>::const_iterator
    range_end(NGeometry::Polygon2D& polygon) {
        return polygon.getPoints().cend();
    }
}

namespace boost {
    template <> struct range_iterator<NGeometry::Polygon2D> {
        using type = std::vector<NGeometry::Point2D>::const_iterator;
    };
    template <> struct range_const_iterator<NGeometry::Polygon2D> {
        using type = std::vector<NGeometry::Point2D>::const_iterator;
    };
    template <> struct range_value<NGeometry::Polygon2D> {
        using type = NGeometry::Point2D;
    };
} // namespace boost

BOOST_GEOMETRY_REGISTER_POINT_2D_CONST(NGeometry::Point2D, double,
                                       cs::cartesian, getX(), getY())
BOOST_GEOMETRY_REGISTER_RING(NGeometry::Polygon2D)

// How to register PolygonalDomain2D?
namespace boost::geometry::traits {
    template <> struct tag<NGeometry::PolygonalDomain2D> {
        using type = polygon_tag;
    };
    template <> struct ring_mutable_type<NGeometry::PolygonalDomain2D> {
        using type = NGeometry::Polygon2D;
    };
    template <> struct ring_const_type<NGeometry::PolygonalDomain2D> {
        using type = NGeometry::Polygon2D const;
    };
    template <> struct exterior_ring<NGeometry::PolygonalDomain2D> {
        static decltype(auto) get(NGeometry::PolygonalDomain2D &v) {
            return *v.getOuter();
        }
        static decltype(auto) get(NGeometry::PolygonalDomain2D const &v) {
            return *v.getOuter();
        }
    };
    template <> struct interior_rings<NGeometry::PolygonalDomain2D> {
        static decltype(auto) get(NGeometry::PolygonalDomain2D &v) {
            return v.getInners() | boost::adaptors::indirected;
        }
        static decltype(auto) get(NGeometry::PolygonalDomain2D const &v) {
            return v.getInners() | boost::adaptors::indirected;
        }
    };
    template <> struct interior_mutable_type<NGeometry::PolygonalDomain2D> {
        using type = decltype(interior_rings<NGeometry::PolygonalDomain2D>::get(
            std::declval<NGeometry::PolygonalDomain2D>()));
    };
    template <> struct interior_const_type<NGeometry::PolygonalDomain2D> {
        using type = decltype(interior_rings<NGeometry::PolygonalDomain2D>::get(
            std::declval<NGeometry::PolygonalDomain2D>())) const;
    };
}

namespace bg = boost::geometry;

template <typename G>
void check_poly(G& g) {
    if constexpr (1) {
        bg::model::polygon<bg::model::d2::point_xy<double>> copy;
        bg::convert(g, copy);
        std::string reason;
        while (!bg::is_valid(copy, reason)) {
            std::cout << "Warning: " << reason << "\n";
            bg::correct(copy);
        }
    }
}

int main() {
    auto report = [](auto heading, auto &g) {
        std::cout << " == " << heading << " ========================\n";
        check_poly(g);
        std::cout << "WKT:       " << bg::wkt(g)       << "\n";
        std::cout << "DSV:       " << bg::dsv(g)       << "\n";
        std::cout << "Area:      " << bg::area(g)      << "\n";
        std::cout << "Perimeter: " << bg::perimeter(g) << "\n";

        if constexpr (std::is_same_v<bg::polygon_tag,
                                     typename bg::traits::tag<
                                         std::decay_t<decltype(g)>>::type>)
        {
            std::cout << "Outer Perimeter: "
                      << bg::perimeter(bg::exterior_ring(g)) << "\n";
        }
    };

    auto outer =
        std::make_shared<NGeometry::Polygon2D>(NGeometry::TyPoints2D{
            {-3.0, -3.0}, {-3.0, 3.0}, {3.0, 3.0}, {3.0, -3.0}, {-3.0, -3.0}});
    auto inner =
        std::make_shared<NGeometry::Polygon2D>(NGeometry::TyPoints2D{
            {-2.0, -2.0}, {2.0, -2.0}, {2.0, 2.0}, {-2.0, 2.0}, {-2.0, -2.0}});

    NGeometry::PolygonalDomain2D domain(outer, {inner});

    report("Outer", *outer);
    report("Inner", *inner);
    report("Domain", domain);

    std::cout << " == Within Check ========================\n";
    std::cout << "Point (0,0) within domain? " << std::boolalpha
              << bg::within(NGeometry::Point2D(0.0, 0.0), domain) << "\n";
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 boost 几何体调整几何对象模型的其他问题 的相关文章

随机推荐