使用增强几何适应几何对象模型的进一步问题 注意

问题描述

我想将 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 } } );
   auto innerPolygonSP = std::make_shared< NGeometry::Polygon2D >(
      NGeometry::TyPoints2D { { -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;
}

Problems in adapting a geometry object model using boost geometry 类中描述的第一步相比,类已被修改并移至 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>)’ 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>)
In file included from /usr/include/boost/geometry/core/coordinate_dimension.hpp:23,from /usr/include/boost/geometry/geometry.hpp:26,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,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 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 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>’
/usr/include/boost/geometry/geometries/concepts/check.hpp:69:8:   required from ‘struct boost::geometry::dispatch::check<const NGeometry::PolygonalDomain2D,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>::THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED69::assert_arg()’ from ‘mpl_::failed************ (boost::geometry::nyi::not_implemented_error<void,void>::THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED::************)(mpl_::assert_::types<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,mpl_::na>)
In file included from /usr/include/boost/geometry/core/coordinate_dimension.hpp:21,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,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 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 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*,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();
      |                    ~~^~~

解决方法

首先,让我们修复 Undefined Behaviour,因为您在 range_beginrange_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。这不起作用,因为它不是多边形概念所必需的:RingPolygon

解决这个问题

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}});

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";

印刷品

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

扩展到PolygonalDomain2D

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

但是,您不是直接而是通过 shared_ptr 聚合环,从而使情况稍微复杂化。我认为您可能也会遇到将 shared_ptr 调整为合适的环的麻烦。我将在下面向您展示我做了什么。

如何注册多边形

没有针对它的“REGISTER_XXX”工具。您必须通过记录在案的 Concept Requirements

文档并非 100% 与现实同步,我不久前就发现了这一点:(How to) Create own polygon type in boost geometry and use multi_polygon type with it?

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

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();
    }
};

现在它变得很辣,因为我们已经到达了你的内部环,它不是作为一个简单的 Ring 模型容器存储的,而是一个包含指向它们的共享指针的容器。

我将站在巨人的肩膀上并使用 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}});
    auto inner =
        std::make_shared<NGeometry::Polygon2D>(NGeometry::TyPoints2D{
            {-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))
Area:      36
Perimeter: 24
 == Inner ========================
Warning: Geometry has wrong orientation
WKT:       POLYGON((-2 -2,-2 -2))
DSV:       ((-2,-2))
Area:      -16
Perimeter: 16
 == Domain ========================
WKT:       POLYGON((-3 -3,-3 -3),(-2 -2,-2 -2))
DSV:       (((-3,-3)),((-2,2
),-2)))
Area:      20
Perimeter: 40
Outer Perimeter: 24
 == Within Check ========================
Point (0,0) within domain? false

注意

由于内部环具有相反点序的概念要求,Warning: Geometry has wrong orientation 正是您想要的。因此,支票确认了我们想要看到的内容。

完整演示Live On Coliru

#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,domain) << "\n";
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...