Search code examples
c++boostboost-geometryogr

How to register a Boost.Geometry distance strategy for OGRPoint and OGRLineString?


I am creating a wrapper that allows using OGR's classes with Boost.Geometry. So far, I've created that necessary iterator facade and registered OGR's geometry classes (OGRPoint, OGRLineString, OGRLinearRing and OGRPolygon) with Boost.Geometry.

Now, I'd like to use the OGR classes predicates such as OGRGeometry::Distance() with boost instead of those employed by Boost.Geometry (because, for example, stock Boost.Geometry 1.57.0 does not have any notion of map projections). It worked for boost::geometry::distance(OGRPoint, OGRPoint), but it does not for bg::distance(OGRPoint, OGRLineString) or any other collection of points. My guess that is because Boost.Geometry treats linestrings, rings and polygons as an ordered collection of points to iterate on, since the compiler tries to instanciate the following template:

struct boost::geometry::strategy::distance::services::default_strategy<
        boost::geometry::point_tag,
        boost::geometry::segment_tag,
        OGRPoint,                           // NOTE: Twice OGRPoint!
        OGRPoint,
        MyCode::OGRCoordinateSystemTag,
        MyCode::OGRCoordinateSystemTag, void>

The full error message is as follows:

In file included from /usr/include/boost/geometry/strategies/strategies.hpp:30:0,
                 from /usr/include/boost/geometry/geometry.hpp:43,
                 from /usr/include/boost/geometry.hpp:17,
                 from ../../../winzent/test/simulation/OGRLineStringAdapterTest.cpp:7:
/usr/include/boost/geometry/strategies/distance.hpp: In instantiation of 'struct boost::geometry::strategy::distance::services::default_strategy<boost::geometry::point_tag, boost::geometry::segment_tag, OGRPoint, OGRPoint, Winzent::Simulation::boost::OGRCoordinateSystemTag, Winzent::Simulation::boost::OGRCoordinateSystemTag, void>':
/usr/include/boost/geometry/algorithms/detail/distance/default_strategies.hpp:57:8:   required from 'struct boost::geometry::detail::distance::default_strategy<OGRPoint, OGRLineString, boost::geometry::pointlike_tag, boost::geometry::linestring_tag, false>'
/usr/include/boost/geometry/algorithms/detail/distance/default_strategies.hpp:73:8:   required from 'struct boost::geometry::detail::distance::default_strategy<OGRLineString, OGRPoint, boost::geometry::linestring_tag, boost::geometry::pointlike_tag, true>'
/usr/include/boost/geometry/strategies/distance_result.hpp:60:8:   required from 'struct boost::geometry::resolve_strategy::distance_result<OGRLineString, OGRPoint, boost::geometry::default_strategy>'
/usr/include/boost/geometry/strategies/distance_result.hpp:79:8:   required from 'struct boost::geometry::resolve_variant::distance_result<OGRLineString, OGRPoint, boost::geometry::default_strategy>'
/usr/include/boost/geometry/strategies/distance_result.hpp:199:8:   required from 'struct boost::geometry::distance_result<OGRLineString, OGRPoint, boost::geometry::default_strategy>'
/usr/include/boost/geometry/strategies/distance_result.hpp:205:8:   required from 'struct boost::geometry::distance_result<OGRLineString, OGRPoint, void>'
/usr/include/boost/geometry/strategies/default_distance_result.hpp:35:8:   required from 'struct boost::geometry::default_distance_result<OGRLineString, OGRPoint>'
/usr/include/boost/geometry/algorithms/detail/distance/interface.hpp:392:1:   required by substitution of 'template<class Geometry1, class Geometry2> typename boost::geometry::default_distance_result<Geometry1, Geometry2>::type boost::geometry::distance(const Geometry1&, const Geometry2&) [with Geometry1 = OGRLineString; Geometry2 = OGRPoint]'
../../../winzent/test/simulation/OGRLineStringAdapterTest.cpp:71:62:   required from here
/usr/include/boost/geometry/strategies/distance.hpp:97:456: error: no matching function for call to 'assertion_failed(mpl_::failed************ (boost::geometry::strategy::distance::services::default_strategy<boost::geometry::point_tag, boost::geometry::segment_tag, OGRPoint, OGRPoint, Winzent::Simulation::boost::OGRCoordinateSystemTag, Winzent::Simulation::boost::OGRCoordinateSystemTag, void>::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE_COMBINATION::************)(mpl_::assert_::types<OGRPoint, OGRPoint, Winzent::Simulation::boost::OGRCoordinateSystemTag, Winzent::Simulation::boost::OGRCoordinateSystemTag>))'
     BOOST_MPL_ASSERT_MSG

So I tried to provide a template specialization specifically for struct boost::geometry::detail::distance::default_strategy<OGRPoint, OGRLineString, boost::geometry::pointlike_tag, boost::geometry::linestring_tag, false>, but with no luck --- the same error message prevails.

This is my code:

namespace boost {
    namespace geometry {
        namespace detail {
            namespace distance {


                template <>
                struct default_strategy<
                        OGRPoint,
                        OGRLineString,
                        pointlike_tag,
                        linestring_tag,
                        false>
                {
                    typedef OGRPointToLineStringDistanceStrategy type;
                };
            } // namespace distance
        } // namespace detail
    } // namespace geometry
} // namespace boost

How can I "intercept" the template instanciation that leads to the usage of the iterator/range concept and use OGRGeometry::Distance() directly?


Solution

  • It turned out that the problem wasn't related to OGR and Boost using two different algorithms. Instead, it was my adapter code that was to blame. More specifically, the iterator facade I wrote in order to adapt OGRLineString, OGRLinearRing and ultimately OGRPolygon to the Boost.Geometry code. I posted a question as soon as I recognized the issue: Create a well-behaved iterator for a write-to-pointer API.

    My currently working (and final) version is available as a GitHub project. Perhaps somebody finds it useful.