Boost logo

Geometry :

Subject: Re: [geometry] Integrating OGR library with Boost.Geometry
From: Adam Wulkiewicz (adam.wulkiewicz_at_[hidden])
Date: 2015-01-08 13:08:56


Hi Eric,

Eric Msp Veith wrote:
> [ Disclaimer: This is a cross-post; a similar question has been posted on
> stackoverflow.com: <http://stackoverflow.com/questions/27767656/how-to-register-a-boost-geometry-distance-strategy-for-ogrpoint-and-ogrlinestrin> ]
>
> Hello list!
>
> I am a first-time user of Boost.Geometry. My goal is to use Boost.Geometry's
> rtree implementation with OGRGeometry instances [0]. To that end, I've adapted
> the necessary OGR classes (OGRPoint, OGRLineString, OGRLinearRing and
> OGRPolygon) to Boost.Geometry's model. Iterating, etc. works good.
>
> However, the current version of Boost.Geometry has no support for different
> map projections, which is why I'm forced to stick with OGRGeometry in general.
> Also, the existing codebase makes heavy use of the OGR* interfaces.
>
> What I am looking for is to use Boost.Geometry's tag/dispatch feature to call
> OGRGeometry::Distance() whenever I (or rtree) uses bg::distance(),
> OGRGeometry::Crosses() when bg::crosses() is used, and so an. Basically, the
> Boost.Geometry predicates are then nothing more than wrappers around the
> corresponding OGR* counterparts.
>
> I've begun with bg::distance for OGRPoint to OGRPoint, and it worked. However,
> I'm stuck with bg::distance(OGRPoint &, OGRLineString &), with a compile
> error. My guess is that it stems from Boost.Geometry's concept of a
> linestring, which is nothing more than an ordered collection of points.

If you have problems with this function this probably mean that you're
using geographic CS. Is that right?

Boost.Geometry supports Point/Point, Point/Linestring, and Point/Box
distance in cartesian and spherical_equatorial. Couldn't you just switch
to e.g. spherical equatorial?

Btw, during any operation Boost.Geometry is not doing any projections,
and probably will never do, at least in 2D. In particular the distance
in a specific coordinate system (defined by the Point-type of a
geometry) is calculated (or approximated) using a
method/algorithm/formula designed for this coordinate system. If the
user wanted to perform some projection and then some operation for a
projected geometry, that's ok. But the library will probably always try
to calculate the "correct" result. This is why for example to calculate
the distance between the Points the library is using or could use:
- in cartesian - well-known cartesian distance
- in spherical - haversine formula or a formula derived from spherical
law of cosines*
- in geographic - formulas of Vincenty**, Andoyer-Lambert**,
Andoyer-Lambert-Thomas* etc.

* - currently not implemented
** - planned for release in 1.58

> Is there any kind of template specialisation I can use so that a call to
> bg::distance(OGRGeometry const&, OGRGeometry const&) is dispatched to
> OGRGeometry::Distance(...)?

Why not overload the bg::distance() directly?

namespace boost { namespace geometry {

template <>
struct default_distance_result<OGRPoint, OGRLineString>
{
     typedef /*some_type*/ type;
};

/*some_type*/ distance(OGRPoint const& g1, OGRLineString const& g2)
{
     // some implementation
}

}}

And probably the same for bg::comparable_distance() and
bg::default_distance_result<> since it's the function and trait used by
the rtree.

The rest if you have much time to spare :)
TL; DR;
>
> What follows is the template instanciation that makes me believe that my
> dispatching does not work due to a Boost.Geometry linestring being a
> collection of points, the full error message, and my current code:
>
>
> ---%<---
> 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>
> --->%---
Everything is ok here, see. e.g.
https://github.com/boostorg/geometry/blob/develop/include/boost/geometry/strategies/distance.hpp
line 85.
Those are Point types from which the algorithm can for instance extract
coordinate types.

>
> The full error message is:
>
<snip>

In Boost.Geometry operations are divided into 2 parts - an algorithm and
a strategy. The strategy defines some critical parts of the calculation
and the algorithms knows how to use the strategies to get the result.

So in order to support some combination of geometries there must be an
algorithm and a strategy adapted to a concept which this algorithm can use.

E.g. distance(Point, Point) requires a strategy calculating the distance
between 2 points, obviously. But in the case of distance(Point,
Linestring) it requires a strategy calculating the distance between a
Point and a Segment, not Point and Linestring. It's because the strategy
defines only the most critical part of the calculation and the algorithm
does the rest.

So the default distance(Point, Linestring) algorithm knows how to use a
strategy calculating the distance between a Point and a Segment.
In order to support your strategy calculating the distance between a
Point and a Linestring you'd be forced to implement an algorithm that
knows how to use it.

> And this is my current attempt on a distance strategy:
>
>
> ---%<---
> 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
> --->%---

So you could try to implement Point/Segment strategy instead for your
coordinate system (geographic?), and e.g. arbitrary geometries, not only
OGRPoint and OGRLineString.

A distance strategy also requires a lot of various traits. See this file
defining the default Point/Segment strategy for spherical_equatorial CS:
https://github.com/boostorg/geometry/blob/develop/include/boost/geometry/strategies/spherical/distance_cross_track.hpp
At the beginning of the file the strategies (comparable::cross_track and
cross_track) are defined, and then at line 545 there are various traits
which must be specialized for a distance strategy. They're for errors
detaction, conversion between comparable and direct distance, etc. Then
at the very end the default_strategy is specialized in line 716.

Or here the same for Point/Point strategy in spherical_equatorial CS:
https://github.com/boostorg/geometry/blob/develop/include/boost/geometry/strategies/spherical/distance_haversine.hpp
in line 179.

Those files are from develop branch, Boost-1.57.0 version may be
slightly different.

Regards,
Adam


Geometry list run by mateusz at loskot.net