1

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?

Technaton
  • 944
  • 4
  • 15
  • Why use the distance function from OGR? OGR calls GEOS to compute the distance between geometries. The GEOS documents state that they use a simple brute force O(nm) algorithm, where n and m are the number of points in the geometries. There is no implicit coordinate system conversion that I know of. Seems you would be better off letting boost::geometry calculate distances. – THK Jan 08 '15 at 03:26
  • Only that the results differ, sometimes by just a fraction. While PostGIS and the GEOS/OGR ensemble naturally produce the same result (PostGIS uses GEOS, too), Boost.Geometry arrives at a different one. – Technaton Jan 08 '15 at 08:47
  • Actually, I am glad I looked this up because I was under the impression that GEOS (and PostGIS by association) computed the true minimum distance between geometries. It does not. It only computes the minimum distance between any pair of vertices spanning the two geometries. That means a point near a very long line segment will register a large distance. Not what I had assumed in the past. Does Boost Geometry compute true geometric distances? Not sure. That could explain the difference observed. – THK Jan 08 '15 at 15:56
  • @THK Boost.Geometry does calculate the minimum distance. E.g. the result of distance(POINT(50 1), LINESTRING(0 0, 100 0)) is 1. – Adam Wulkiewicz Jan 08 '15 at 16:32
  • So, the difference in the algorithms would explain the deivations I encounter with respect to bg::distance() vs. GEOS' distance algorithm? E.g., bg::distance has another result for 'LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)' and 'POINT(15.0 15.0)' than GEOS' distance() method. – Technaton Jan 09 '15 at 14:00
  • @Technaton Feel free to prove me wrong but AFAIU GEOS calculates the cartesian distance, no matter what SRID is passed. In Boost.Geometry it's possible to calculate the distance e.g. on the surface of a sphere or ellipsoid. The distance calculated this way will be different, it'll also depend on the radius of a sphere. The result should be the same if the geometries were defined in cartesian CS in Boost.Geometry. – Adam Wulkiewicz Jan 24 '15 at 03:15
  • @AdamWulkiewicz: You are right, GEOS calculates the cartesian distance only. With an actually working iterator facade, bg::distance and GEOS' distance yielded the same results, when bg::distance() used cs::cartesian. So only my code was to blame; both Boost.Geometry and GEOS work correctly for cartesian, plus Boost offers distances calculated on a sphere/ellipsoid. Thanks! – Technaton Jan 26 '15 at 14:39

1 Answers1

2

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.

Community
  • 1
  • 1
Technaton
  • 944
  • 4
  • 15