Integrating OGR library with Boost.Geometry

classic Classic list List threaded Threaded
29 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Integrating OGR library with Boost.Geometry

Eric MSP Veith
[ 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.

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(...)?

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>
--->%---


The full error message is:


--->%---
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
---%<---


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
--->%---


Thanks a lot in advance for any hints!

Kind Regards,
Eric


[0] http://www.gdal.org/classOGRGeometry.html
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Adam Wulkiewicz
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 mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hi Adam,

thank you for your extensive reply! It already helped me a lot.

I guess that there are actually two topics that are covered by my problem and
your answer. First, the simple question of how to overwrite bg::distance()
with OGRGeometry::Distance, and second, the underlying question of why the
results of bg::distance() and OGRGeometry::Distance actually differ.

Since my data source is a PostGIS database, and PostGIS relies on GEOS just as
OGR does, I'll go for the low-hangig fruit first before diving deeper into the
actual problem, if that's OK with you.

I've tried overloading bg::distance(), and tried to overload it for all
instances of OGRGeometry's derived classes. OGRPoint is derived from
OGRGeometry, OGRLineString, too, and all the over ones (OGRPolygon,
OGRLinearRing, ...) the same.

C++11 templates are not (yet) my league, so I've run into problems using
enable_if<> and is_base_of<>. What I tried is the following:

---%<---

namespace boost {
    namespace geometry {

        template <>
        struct default_distance_result<OGRGeometry, OGRGeometry>
        {
            typedef qreal type;
        };


        template <
                typename Geometry1,
                typename Geometry2,
                typename std::enable_if<
                    std::is_base_of<OGRGeometry, Geometry1>::value
                        and std::is_base_of<
                            OGRGeometry,
                            Geometry2>::value, int>::type = 0>
        inline typename default_distance_result<Geometry1, Geometry2>::value
        distance(Geometry1 const &geometry1, Geometry2 const &geometry2)
        {
            return geometry1.Distance(&geometry2);
        }
    }
}

--->%---

Replacing the specialization's parameters with, e.g. <OGRPoint, OGRLineString>
does what I want, but it also means I need to create a specialized struct for
every possible combination of OGRGeometry-derived classes, i.e.,
<OGRLineString, OGRPoint>, <OGRLineString, OGRPolygon>, <OGRPolygon,
OGRLineString>, and so on.

Do you know a more general way of doing it for all of OGR's geometry classes?

Now to the deeper-lying root cause:

On Thursday 08 January 2015, 19:08:56, Adam Wulkiewicz wrote:
> If you have problems with this function this probably mean that you're
> using geographic CS. Is that right?

Yes, that is 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?

I've tried using different coordinate systems, because adapting the
OGRGeometry classes to Boost's range concept was not that hard. To make things
easier to explain, I've set up a github.com repository that contains the
adapter code at <https://github.com/eveith/ogr-boost-adapter>. Perhaps there's
just an error hidden somewhere in my adapter code.  ;-)

However, I'm presented with different results for OGRGeometry::Distance() and
bg::distance().

For example, consider the following geometries:

ST_GeomFromText('LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)',
4326),
ST_GeomFromText('LINESTRING(15.0 15.0, 16.0 16.0)', 4326)
ST_GEomFromText('POINT(15.0 15.0)', 4326)

For this, the database gives:

---%<---

db=# SELECT ST_Distance(
    ST_GeomFromText('LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)',
4326),
    ST_GeomFromText('POINT(15.0 15.0)', 4326));

   st_distance
-----------------
 15.556349186104

db=# SELECT ST_Distance(
    ST_GeomFromText('LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)',
4326),
    ST_GeomFromText('LINESTRING(15.0 15.0, 16.0 16.0)', 4326));
   st_distance
-----------------
 15.556349186104

--->%---

The 15.556... is of course the same result OGR gives me, since both PostGIS
and OGR use GEOS.

Using cs::cartesian yields 16.9706 on bg::distance for the very same
geometries. When using cs::geographic, 0.294082 is returned. I'm at loss for
an explanation why. That was the point where I decided to just use
OGRGeometry::Distance.  Since I'm not under time pressure (and relatively new
to anything GIS), I'd like to learn about the backgrounds and hope to come up
with an actually useable wrapper for OGRGeometry/GEOS classes, using
Boost.Geometry's facilities the right way --- just resorting to template
specialization seems like a bad hack to me.   :-)

> 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

Perhaps I'm mistaken, but the obvious conclusion seems to be that as long as I
use the same projection for all geometries I apply predicates to, e.g. force
WGS84 for all geometries, and choose the right algorithm, I'm on the safe
side? At least that's how I always understood it.

From what I could find out, GEOS uses the Discrete Hausdorff Distance
algorithm? But that doesn't make much sense, given that the Hausdorff Distance
is the longest distance one has to travel to a Geometry G1 if a point P is
chosen on another Geometry G0. But again, I lack the knowledge to be sure and
am most probably mistaken.

> The rest if you have much time to spare :)

Yes, I have.  :-)

> Everything is ok here, see. e.g.
> https://github.com/boostorg/geometry/blob/develop/include/boost/geometry/str
> ategies/distance.hpp line 85.
> Those are Point types from which the algorithm can for instance extract
> coordinate types.

Like boost::model::point?

> 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.

I'm sorry, I cannot wrap my head around it. The Andoyer-Lambert formula, for
example, would be part of ... the strategy? I.e., the algorithm is
bg::distance() and the strategy is chosen according to the actual geometries
and the coordinate system, arriving at, for example, the Pythagoras strategy
for cs::cartesian or the haversine strategy for cs::geographic?

> 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.

So, in order to use OGRLineString::Distance(OGRPoint const&), I'd have to
implement my own bg::distance()? If so, that sounds like "back to square one,
specialize that template"?

> 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.

Yes, geographic. But from that paragraph I fear I got the idea of
strategy/algorithm wrong. :-(

Thank you very much for the help and the background info. I currently try to
understand why there are different distance algorithms and when they are
employed. If you can suggest sources to read up on this, I'll happily consume
them.

Thanks!

      --- Eric

_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Adam Wulkiewicz
Hi Eric,

Eric Msp Veith wrote:

> Hi Adam,
>
> thank you for your extensive reply! It already helped me a lot.
>
> I guess that there are actually two topics that are covered by my problem and
> your answer. First, the simple question of how to overwrite bg::distance()
> with OGRGeometry::Distance, and second, the underlying question of why the
> results of bg::distance() and OGRGeometry::Distance actually differ.
>
> Since my data source is a PostGIS database, and PostGIS relies on GEOS just as
> OGR does, I'll go for the low-hangig fruit first before diving deeper into the
> actual problem, if that's OK with you.
>
> I've tried overloading bg::distance(), and tried to overload it for all
> instances of OGRGeometry's derived classes. OGRPoint is derived from
> OGRGeometry, OGRLineString, too, and all the over ones (OGRPolygon,
> OGRLinearRing, ...) the same.
>
> C++11 templates are not (yet) my league, so I've run into problems using
> enable_if<> and is_base_of<>. What I tried is the following:
>
> ---%<---
>
> namespace boost {
>      namespace geometry {
>
>          template <>
>          struct default_distance_result<OGRGeometry, OGRGeometry>
>          {
>              typedef qreal type;
>          };
>
>
>          template <
>                  typename Geometry1,
>                  typename Geometry2,
>                  typename std::enable_if<
>                      std::is_base_of<OGRGeometry, Geometry1>::value
>                          and std::is_base_of<
>                              OGRGeometry,
>                              Geometry2>::value, int>::type = 0>
>          inline typename default_distance_result<Geometry1, Geometry2>::value
>          distance(Geometry1 const &geometry1, Geometry2 const &geometry2)
>          {
>              return geometry1.Distance(&geometry2);
>          }
>      }
> }
>
> --->%---

It looks good. Well, your default_distance_result<> specialization
wouldn't be instantiated since it's specialized for base type. But it
probably isn't needed really, the default one should probably work. It
creates the type the distance taking into account coordinate types of
both geometries. The function overload looks ok, if you can use C++11
function default template parameters. In C++98 you could use Boost.Core
(enable_if), Boost.MPL (and_), Boost.TypeTraits (is_base_of) and
implement a return type as enable_if<...>::type. Anyway, the problem is
that it's ambiguous since there are 2 overloads of bg::distance(), both
taking 2 arbitrary types, the original and yours. So this can't be done
this way or at least I don't have any idea.

> Replacing the specialization's parameters with, e.g. <OGRPoint, OGRLineString>
> does what I want, but it also means I need to create a specialized struct for
> every possible combination of OGRGeometry-derived classes, i.e.,
> <OGRLineString, OGRPoint>, <OGRLineString, OGRPolygon>, <OGRPolygon,
> OGRLineString>, and so on.
>
> Do you know a more general way of doing it for all of OGR's geometry classes?

I could think about some hacks but you'd be forced to mess with the
internals of the library so I'd discourage that.

You could implement some convenient macro and then use it like this:

DEFINE_DISTANCE(OGRPoint,OGRPoint)
DEFINE_DISTANCE(OGRPoint,OGRLinestring)
DEFINE_DISTANCE(OGRPoint,OGRBox)
/*...*/

> Now to the deeper-lying root cause:
>
> On Thursday 08 January 2015, 19:08:56, Adam Wulkiewicz wrote:
>> If you have problems with this function this probably mean that you're
>> using geographic CS. Is that right?
> Yes, that is 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?
> I've tried using different coordinate systems, because adapting the
> OGRGeometry classes to Boost's range concept was not that hard. To make things
> easier to explain, I've set up a github.com repository that contains the
> adapter code at <https://github.com/eveith/ogr-boost-adapter>. Perhaps there's
> just an error hidden somewhere in my adapter code.  ;-)

Well, I see now that you've defined your own coordinate system tag. In
this case you should support it by implementation of a set of strategies
and maybe more. In general, it's playing with the internals of the
library which is something that a user shouldn't do. But if you're
interested below is more information about the strategies and how
algorithms use them.

> However, I'm presented with different results for OGRGeometry::Distance() and
> bg::distance().
>
> For example, consider the following geometries:
>
> ST_GeomFromText('LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)',
> 4326),
> ST_GeomFromText('LINESTRING(15.0 15.0, 16.0 16.0)', 4326)
> ST_GEomFromText('POINT(15.0 15.0)', 4326)
>
> For this, the database gives:
>
> ---%<---
>
> db=# SELECT ST_Distance(
>      ST_GeomFromText('LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)',
> 4326),
>      ST_GeomFromText('POINT(15.0 15.0)', 4326));
>
>     st_distance
> -----------------
>   15.556349186104

(Below BG means Boost.Geometry)

In BG, using cartesian CS, the result is 15.556349186104 so the same.

AFAIR if you're using PostGIS like in your example all calculations are
done using cartesian CS.
Instead of ST_GeomFromText you could try to use ST_GeogFromText
(http://postgis.net/docs/ST_GeogFromText.html). But in this case you
should notice that the functionality is limited.

Furthermore, I'm not sure if it's possible to calculate distances (or
perform other operations) in other coordinate systems than cartesian in
GEOS. I'd guess that they probably support SRIDs somehow (store?), but
besides that all calculations are done in cartesian.
Note that GEOS =/= PostGIS, AFAIR in PostGIS there are additional things
implemented.

Some time ago I checked PostGIS code and I found some functions for the
Point/Point distance calculation in geographic CS, maybe there are other
like Point/Segment but I didn't see them. It's possible that they
calculate the closest distance between the Points of geometries, not the
"true"/"correct" one. You could easily check it defining some very long
segment and a Point very close to it somewhere near the middle.

In BG, in spherical_equatorial<degree> the result is 0.26942677292131906
[radians] for a unit sphere, or 1716517.97 [meters] for spherical Earth
with radius 6371000 [meters]. To get the distance in meters you may
multiply the resulting radians by the radius or pass the strategy
explicitly into the distance() function specifying the radius.

FYI, in 1.57, distance(Point, Linestring) or even distance(Point, Point)
doesn't compile for geographic CS. However in develop branch (probably
1.58) the distance(POINT(4, 4), POINT(15, 15)) does compile and the
result is 1712939.35 meters for WGS84 ellipsoid. Currently by default
Andoyer-Lambert formula is used. If Vincenty strategy is passed
explicitly, the result is 1712955.94 meters. You can verify the results
e.g. using this form:
http://www.ga.gov.au/geodesy/datums/vincenty_direct.jsp

> db=# SELECT ST_Distance(
>      ST_GeomFromText('LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)',
> 4326),
>      ST_GeomFromText('LINESTRING(15.0 15.0, 16.0 16.0)', 4326));
>     st_distance
> -----------------
>   15.556349186104
>
> --->%---
>
> The 15.556... is of course the same result OGR gives me, since both PostGIS
> and OGR use GEOS.

And Boost.Geometry returns the same distances as the ones mentioned above.
However distance(Linestring, Linestring) doesn't compile for
spherical_equatorial in 1.57 but it compiles in develop so probably
expect the same in 1.58.

>
> Using cs::cartesian yields 16.9706 on bg::distance for the very same
> geometries. When using cs::geographic, 0.294082 is returned. I'm at loss for
> an explanation why. That was the point where I decided to just use
> OGRGeometry::Distance.  Since I'm not under time pressure (and relatively new
> to anything GIS), I'd like to learn about the backgrounds and hope to come up
> with an actually useable wrapper for OGRGeometry/GEOS classes, using
> Boost.Geometry's facilities the right way --- just resorting to template
> specialization seems like a bad hack to me.   :-)

So I guess the answer is already above. First you should probably check
if you really need this workadound.
The right way would be to properly implement missing elements in
Boost.Geometry :)

What bothers me is why your results are slightly different than mine. Do
you get the same for the following program?

#include <iostream>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>

namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;

int main()
{
     typedef bg::model::point<double, 2, bg::cs::cartesian> point;
     typedef bg::model::linestring<point> linestring;

     point pt;
     linestring ls, ls2;

     bg::read_wkt("LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0
4.0)", ls);
     bg::read_wkt("POINT(15.0 15.0)", pt);
     bg::read_wkt("LINESTRING(15.0 15.0, 16.0 16.0)", ls2);

     std::cout << std::setprecision(24) << bg::distance(pt, ls) <<
std::endl;
     std::cout << std::setprecision(24) << bg::distance(ls, ls2) <<
std::endl;
}

>> 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
> Perhaps I'm mistaken, but the obvious conclusion seems to be that as long as I
> use the same projection for all geometries I apply predicates to, e.g. force
> WGS84 for all geometries, and choose the right algorithm, I'm on the safe
> side? At least that's how I always understood it.

Yes, as long as one coordinate system is used and the distances
calculated for various geometries are compatible you should be safe. You
probably shouldn't mix 2 libraries calculating similar things in a
different way, e.g. Boost.Geometry using one formula for Point/Point and
GEOS/GDAL/XXX for Point/Linestring calculating the distance differently,
e.g. using different formula or using cartesian CS, etc. I'm not sure
how this library does it.

I'm guessing that if you used GEOS/GDAL/XXX for all distance
calculations the rtree should work properly, probably... I can't really
guarantee anything.
Furthermore assuming that this library uses cartesian CS (I'm not sure)
it really doesn't have sense to replace Boost.Geometry. So this probably
needs some testing. If you plan to perform them could you please share
the results?

> >From what I could find out, GEOS uses the Discrete Hausdorff Distance
> algorithm? But that doesn't make much sense, given that the Hausdorff Distance
> is the longest distance one has to travel to a Geometry G1 if a point P is
> chosen on another Geometry G0. But again, I lack the knowledge to be sure and
> am most probably mistaken.

It's a different algorithm, it measures how two geometries are similar
to each other.

>> The rest if you have much time to spare :)
> Yes, I have.  :-)
Ok :)
>
>> Everything is ok here, see. e.g.
>> https://github.com/boostorg/geometry/blob/develop/include/boost/geometry/str
>> ategies/distance.hpp line 85.
>> Those are Point types from which the algorithm can for instance extract
>> coordinate types.
> Like boost::model::point?
This, or OGRPoint, every type adapted to the Point concept. In
Boost.Geometry a Point bound with some geometry like Linestring or
Polygon defines the coordinate type, dimension and coordinate system.
This Point can be retrieved from a Geometry by
bg::point_type<Geometry>::type internally using bg::traits::point_type<>
specialized by you when you were adapting your legacy geometries to
Boost.Geometry Concepts.

>
>> 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.
> I'm sorry, I cannot wrap my head around it. The Andoyer-Lambert formula, for
> example, would be part of ... the strategy? I.e., the algorithm is
> bg::distance() and the strategy is chosen according to the actual geometries
> and the coordinate system, arriving at, for example, the Pythagoras strategy
> for cs::cartesian or the haversine strategy for cs::geographic?

Yes, the Andoyer-Lambert formula is a part of a Strategy. This
particular Strategy defines how a distance between 2 points is
calculated in geographic CS.

The algorithm is the distance(), but internally there are many versions
of it, dispatched for various pairs of input Geometries, by using the
tags of those Geometries. Each dispatched version requires some specific
kind of strategy.

For instance, algorithm dispatched for Point/Point or
MultiPoint/MultiPoint requires Point-Point Strategy. It knows how to use
only this kind of Strategy. For example, Point/Point version calls the
strategy once for a pair of Points. MultiPoint/MultiPoint version could
for instance check all possible pairs of Points and return the smallest
distance found (this is just an example, actually different algorithm is
used since this'd have complexity O(N^2)).

Version for Point/Linestring or Point/Polygon requires Point/Segment
strategy. The former checks all segments in a Linestring, the latter
checks the exterior ring and all interior rings, etc.

For the algorithm it doesn't matter what is the coordinate system, the
required operation is defined in the Strategy.

>
>> 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.
> So, in order to use OGRLineString::Distance(OGRPoint const&), I'd have to
> implement my own bg::distance()? If so, that sounds like "back to square one,
> specialize that template"?
The short answer is yes, this would be the most simple way of achieving
what you planned to do.
Of course this'd be needed assuming that using cartesian or
spherical_equatorial CS wouldn't be enough.

>> 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.
> Yes, geographic. But from that paragraph I fear I got the idea of
> strategy/algorithm wrong. :-(
>
> Thank you very much for the help and the background info. I currently try to
> understand why there are different distance algorithms and when they are
> employed. If you can suggest sources to read up on this, I'll happily consume
> them.
>

Sorry, I should be more clear before. I already described above what a
strategy and algorithm is. So what an already implemented algorithm
(e.g. distance(Point, Point) or distance(Point, Linestring)) needs is a
Strategy defined for some coordinate system. E.g. to support
distance(PointLike, PointLike) the Point/Point strategy is required
(this is already done in develop for geographic CS as mentioned above).
To support distance(PointLike, LinearOrAreal) we'd need a strategy
calculating the distance between a Point and a Segment on ellipsoid.
This would be required to support all combinations like
Point/Linestring, Point/Polygon, MultiPoint/MultiPolygon etc. to
calculate the "true" distance. Well, actually we'd need more things but
that's another story.

Regards,
Adam
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hi Adam,

On Sunday 11 January 2015 03:47:01, Adam Wulkiewicz
<[hidden email]> wrote:
> [...]
>
> You could implement some convenient macro and then use it like this:
>
> DEFINE_DISTANCE(OGRPoint,OGRPoint)
> DEFINE_DISTANCE(OGRPoint,OGRLinestring)
> DEFINE_DISTANCE(OGRPoint,OGRBox)

all right; good to know that there's a last-resort hackedy-hack possible.

> Well, I see now that you've defined your own coordinate system tag. [...]

Yes, that was because I wanted to ensure that none of the BG strategies was
used, because I though the deviation comes from different formulae being used.
That's, of course, neither a problem of BG nor OGR, because I assume that both
libraries implement their corresponding formulae correctly --- I just needed  
consistency between the two.

However, I fear that neither Boost nor OGR are to blame, but simply my very
own code, because with your test code, I get the correct result.

> What bothers me is why your results are slightly different than mine. Do
> you get the same for the following program?
>
> #include <iostream>
>
> #include <boost/geometry.hpp>
> #include <boost/geometry/geometries/geometries.hpp>
> #include <boost/geometry/io/wkt/wkt.hpp>
>
> namespace bg = boost::geometry;
> namespace bgi = boost::geometry::index;
>
> int main()
> {
>      typedef bg::model::point<double, 2, bg::cs::cartesian> point;
>      typedef bg::model::linestring<point> linestring;
>
>      point pt;
>      linestring ls, ls2;
>
>      bg::read_wkt("LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0
> 4.0)", ls);
>      bg::read_wkt("POINT(15.0 15.0)", pt);
>      bg::read_wkt("LINESTRING(15.0 15.0, 16.0 16.0)", ls2);
>
>      std::cout << std::setprecision(24) << bg::distance(pt, ls) <<
> std::endl;
>      std::cout << std::setprecision(24) << bg::distance(ls, ls2) <<
> std::endl;
> }
This outputs:

[eveith@basileia:~/tmp/boosttest]% ./bgtest
15.5563491861040450459086
15.5563491861040450459086

Exactly what I was looking for. So I cut all the custom CS/strategy stuff I
implemented over the last few days and went back to cs::cartesian. This is my
current testcase:

--->%---

OGRGeometry *ls3 = nullptr, *p2 = nullptr;
char wktLS[] = "LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)";
char wktP[] = "POINT(15.0 15.0)";
char *wktLSp = static_cast<char *>(wktLS);
char *wktPp = static_cast<char *>(wktP);
OGRGeometryFactory::createFromWkt(&wktLSp, sref, &ls3);
OGRGeometryFactory::createFromWkt(&wktPp, sref, &p2);

QCOMPARE(
        bg::distance(
                *(dynamic_cast<OGRPoint *>(p2)),
                *(dynamic_cast<OGRLineString *>(ls3))),
        ls3->Distance(p2));

--->%---

The result, however, is:

---%<---

FAIL!  : OGRLineStringAdapterTest::testGeometry() Compared doubles are not the
same (fuzzy compare)
   Actual   (bg::distance( *(dynamic_cast<OGRPoint *>(p2)),
*(dynamic_cast<OGRLineString *>(ls3)))): 16,9706
   Expected (ls3->Distance(p2)): 15,5563

--->%---

Meh. Oh, and the distance between the two linestrings is 0.0, according to my
code.

> So I guess the answer is already above. First you should probably check
> if you really need this workadound.
> The right way would be to properly implement missing elements in
> Boost.Geometry :)
 
So, yes, it seems I've made a mistake somewhere in my adapter code, and all
workarounds are unnecessary. The iterator itself seems to work, though,
because I can iterate over all points on a given OGRLineString using
range_begin(ls) and range_end(ls).  Hope I can find my bug.

Thank you for the extensive amount of background info. I really appreciate it!

Have a nice sunday evening!

                        --- Eric
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry

signature.asc (853 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hi,

did I say "implementing the Iterator for OGRLineString wasn't that hard"?
Well, I guess it actually is.

bg::model::linestring<OGRPoint> delivers the correct results for any
bg::distance() call. However, when my OGRLineString iterator_facade is being
used, the wrong points are selected. In the example containing the
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),
using my own iterator_facade meant that bg::distance always calculated the
distance between the n-1th point on the linestring and the single point.

I.e., my iterator_facade is at fault. I don't know yet what's exactly wrong,
but I'll find it! :-)

Thanks for all the help so far!

                        --- Eric

On Sunday 11 January 2015 17:42:46, Eric MSP Veith <[hidden email]> wrote:

> Hi Adam,
>
> On Sunday 11 January 2015 03:47:01, Adam Wulkiewicz
>
> <[hidden email]> wrote:
> > [...]
> >
> > You could implement some convenient macro and then use it like this:
> >
> > DEFINE_DISTANCE(OGRPoint,OGRPoint)
> > DEFINE_DISTANCE(OGRPoint,OGRLinestring)
> > DEFINE_DISTANCE(OGRPoint,OGRBox)
>
> all right; good to know that there's a last-resort hackedy-hack possible.
>
> > Well, I see now that you've defined your own coordinate system tag. [...]
>
> Yes, that was because I wanted to ensure that none of the BG strategies was
> used, because I though the deviation comes from different formulae being
> used. That's, of course, neither a problem of BG nor OGR, because I assume
> that both libraries implement their corresponding formulae correctly --- I
> just needed consistency between the two.
>
> However, I fear that neither Boost nor OGR are to blame, but simply my very
> own code, because with your test code, I get the correct result.
>
> > What bothers me is why your results are slightly different than mine. Do
> > you get the same for the following program?
> >
> > #include <iostream>
> >
> > #include <boost/geometry.hpp>
> > #include <boost/geometry/geometries/geometries.hpp>
> > #include <boost/geometry/io/wkt/wkt.hpp>
> >
> > namespace bg = boost::geometry;
> > namespace bgi = boost::geometry::index;
> >
> > int main()
> > {
> >
> >      typedef bg::model::point<double, 2, bg::cs::cartesian> point;
> >      typedef bg::model::linestring<point> linestring;
> >      
> >      point pt;
> >      linestring ls, ls2;
> >      
> >      bg::read_wkt("LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0
> >
> > 4.0)", ls);
> >
> >      bg::read_wkt("POINT(15.0 15.0)", pt);
> >      bg::read_wkt("LINESTRING(15.0 15.0, 16.0 16.0)", ls2);
> >      
> >      std::cout << std::setprecision(24) << bg::distance(pt, ls) <<
> >
> > std::endl;
> >
> >      std::cout << std::setprecision(24) << bg::distance(ls, ls2) <<
> >
> > std::endl;
> > }
>
> This outputs:
>
> [eveith@basileia:~/tmp/boosttest]% ./bgtest
> 15.5563491861040450459086
> 15.5563491861040450459086
>
> Exactly what I was looking for. So I cut all the custom CS/strategy stuff I
> implemented over the last few days and went back to cs::cartesian. This is
> my current testcase:
>
> --->%---
>
> OGRGeometry *ls3 = nullptr, *p2 = nullptr;
> char wktLS[] = "LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0, 4.0 4.0)";
> char wktP[] = "POINT(15.0 15.0)";
> char *wktLSp = static_cast<char *>(wktLS);
> char *wktPp = static_cast<char *>(wktP);
> OGRGeometryFactory::createFromWkt(&wktLSp, sref, &ls3);
> OGRGeometryFactory::createFromWkt(&wktPp, sref, &p2);
>
> QCOMPARE(
>         bg::distance(
>                 *(dynamic_cast<OGRPoint *>(p2)),
>                 *(dynamic_cast<OGRLineString *>(ls3))),
>         ls3->Distance(p2));
>
> --->%---
>
> The result, however, is:
>
> ---%<---
>
> FAIL!  : OGRLineStringAdapterTest::testGeometry() Compared doubles are not
> the same (fuzzy compare)
>    Actual   (bg::distance( *(dynamic_cast<OGRPoint *>(p2)),
> *(dynamic_cast<OGRLineString *>(ls3)))): 16,9706
>    Expected (ls3->Distance(p2)): 15,5563
>
> --->%---
>
> Meh. Oh, and the distance between the two linestrings is 0.0, according to
> my code.
>
> > So I guess the answer is already above. First you should probably check
> > if you really need this workadound.
> > The right way would be to properly implement missing elements in
> > Boost.Geometry :)
>
> So, yes, it seems I've made a mistake somewhere in my adapter code, and all
> workarounds are unnecessary. The iterator itself seems to work, though,
> because I can iterate over all points on a given OGRLineString using
> range_begin(ls) and range_end(ls).  Hope I can find my bug.
>
> Thank you for the extensive amount of background info. I really appreciate
> it!
>
> Have a nice sunday evening!
>
> --- Eric

_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry

signature.asc (853 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Adam Wulkiewicz
Hi Eric,

Eric Msp Veith wrote:

> Hi,
>
> did I say "implementing the Iterator for OGRLineString wasn't that hard"?
> Well, I guess it actually is.
>
> bg::model::linestring<OGRPoint> delivers the correct results for any
> bg::distance() call. However, when my OGRLineString iterator_facade is being
> used, the wrong points are selected. In the example containing the
> 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),
> using my own iterator_facade meant that bg::distance always calculated the
> distance between the n-1th point on the linestring and the single point.
>
> I.e., my iterator_facade is at fault. I don't know yet what's exactly wrong,
> but I'll find it! :-)

Good luck!

> Thanks for all the help so far!

No problem.

Now when everything is clear and you decided to use cartesian CS. Note
that the distance between geographical points calculated as if they were
cartesian points will not be the "correct" one. By correctness I have in
mind being in line with the definition of a geodesic, the shortest path
between two points on the surface of the Earth. Depending on the points
configuration and actual position on the globe for a pair of geographic
coordinates treated as cartesian coordinates you will get the same or
greater distance than you should if you represented the points in
spherical or geographic CS.

For instance, in cartesian CS the result of distance(POINT(15 15),
POINT(4 4)) is 15.556349186104045, but in spherical (assuming that the
coordinates are degrees) 15.43701697622119 degrees (0.26942677292131906
radians). For the spherical Earth with radius 6371000 meters the
difference between those distances is around 13 kilometers. And for
geographic CS the distance will be different than in the above cases. Of
course this kind of error may be acceptable for you. I'm just pointing
out this aspect in case you find it important/interesting.

And AFAIU you must also deal with it when you're using GEOS or
ST_GeomFromText in PostGIS no matter what SRID you passed. However I'm
not entirely sure if this is true, feel free to proove me wrong.

Regards,
Adam
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith

Hi Adam,

 

thanks to your help, I've finally been able to integrate OGR and Boost.Geometry. Thank you very much for your patience and explanations. They also helped me alot in understanding the underlying concepts and connected knowledge.

 

I'd like to give something back and thus have updated the GitHub repository where I've stored the adapter code: <https://github.com/eveith/ogr-boost-adapter>

 

Perhaps that helps somebody else in the future!

 

Cheers,

Eric


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Mateusz Loskot
Administrator
2015-01-21 22:38 GMT+01:00 Eric MSP Veith <[hidden email]>:

> Hi Adam,
>
> thanks to your help, I've finally been able to integrate OGR and
> Boost.Geometry. Thank you very much for your patience and explanations. They
> also helped me alot in understanding the underlying concepts and connected
> knowledge.
>
> I'd like to give something back and thus have updated the GitHub repository
> where I've stored the adapter code:
> <https://github.com/eveith/ogr-boost-adapter>
>
> Perhaps that helps somebody else in the future!

Eric,

Sweet, thanks for sharing!

Best regards,
--
Mateusz  Loskot, http://mateusz.loskot.net
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
--
Mateusz Loskot
http://mateusz.loskot.net
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hello list,

earlier this year I adapted the OGRGeometry subclasses to the boost.Geometry
models. My adapter code is available at <https://github.com/eveith/ogr-boost-adapter>.

Everything was done on the basis of boost 1.56.0, where tests ran
successfully. I've now upgraded my Linux distribution, which also pulled boost
1.57.0. I recompiled everything, but much to my surprise, my adapter code
stopped working!

At first I thought the iterator code somehow had a bug lurking in it that
caused the failure, but I can successfully retrieve all points on an
OGRLineString without problems.

However, bg::distance() between two OGRLineStrings returns 0 instead of the
proper result. Is anybody aware of a change in bg::distance or Boost.Range
that might cause the failure? After having checked that the iterator works
forwards and backwards, I'm unsure where to begin with the debugging.

Here's the test code that I use. bg::distance(OGRLineString &, OGRLineString
&) always returns 0.0:

---%<---
void BoostOGRLineStringAdapterTest::testGeometryMultiLineString()
{
    typedef bg::model::linestring<OGRPoint> boostLinestring;
    boostLinestring bls1, bls2;

    OGRLineString *ls1 = new OGRLineString(),
            *ls2 = new OGRLineString(),
            *ls3 = new OGRLineString();
    auto distantPoint = new OGRPoint(15.0, 15.0);
    OGRSpatialReference *sref = new OGRSpatialReference();

    OGRErr rc = sref->importFromEPSG(4326);
    QVERIFY(OGRERR_NONE == rc);
    ls1->assignSpatialReference(sref);
    ls2->assignSpatialReference(sref);
    ls3->assignSpatialReference(sref);
    distantPoint->assignSpatialReference(sref);

    ls1->addPoint(0.0, 0.0);
    ls1->addPoint(1.0, 1.0);
    ls1->addPoint(2.0, 2.0);
    ls1->addPoint(3.0, 3.0);
    ls1->addPoint(4.0, 4.0);

    bls1.push_back(OGRPoint(0.0, 0.0));
    bls1.push_back(OGRPoint(1.0, 1.0));
    bls1.push_back(OGRPoint(2.0, 2.0));
    bls1.push_back(OGRPoint(3.0, 3.0));
    bls1.push_back(OGRPoint(4.0, 4.0));

    ls2->addPoint(17.0, 17.0);
    ls2->addPoint(21.0, 21.0);
    ls2->addPoint(33.0, 33.0);
    ls2->addPoint(76.0, 56.0);

    bls2.push_back(OGRPoint(17.0, 17.0));
    bls2.push_back(OGRPoint(21.0, 21.0));
    bls2.push_back(OGRPoint(33.0, 33.0));
    bls2.push_back(OGRPoint(76.0, 56.0));

    ls3->addPoint(42.0, 34.2);
    ls3->addPoint(72.0, 14.2);
    ls3->addPoint(67.0, 34.2);
    ls3->addPoint(82.0,  2.2);
    ls3->addPoint(5.0, 17.2);

    QCOMPARE(
            bg::crosses(*ls1, *distantPoint),
            ls1->Crosses(distantPoint));
    QCOMPARE(
            bg::intersects(*ls1, *distantPoint),
            ls1->Intersects(distantPoint));


    for (int i = 0; i != ls1->getNumPoints(); ++i) {
        auto p = new OGRPoint();
        ls1->getPoint(i, p);

        QCOMPARE(
                bg::distance(*p, *distantPoint),
                p->Distance(distantPoint));
    }

    QCOMPARE(
            bg::distance(*ls1, *distantPoint),
            ls1->Distance(distantPoint));
    QCOMPARE(
            bg::distance(*ls3, *distantPoint),
            ls3->Distance(distantPoint));
    QCOMPARE(
            bg::distance(*ls2, *distantPoint),
            ls2->Distance(distantPoint));
    QCOMPARE(
            bg::distance(bls1, bls2),
            ls1->Distance(ls2));
    QCOMPARE(
            bg::distance(bls1, bls2),
            bg::distance(*ls1, *ls2));
    QCOMPARE(
            bg::distance(*ls1, *ls2),
            ls1->Distance(ls2));


    delete sref;
}
--->%---

Thanks alot in advance for any hints!

                        --- Eric
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Menelaos Karavelas
Hello Eric.

On 21/05/2015 06:35 μμ, Eric MSP Veith wrote:

> Hello list,
>
> earlier this year I adapted the OGRGeometry subclasses to the boost.Geometry
> models. My adapter code is available at <https://github.com/eveith/ogr-boost-adapter>.
>
> Everything was done on the basis of boost 1.56.0, where tests ran
> successfully. I've now upgraded my Linux distribution, which also pulled boost
> 1.57.0. I recompiled everything, but much to my surprise, my adapter code
> stopped working!
>
> At first I thought the iterator code somehow had a bug lurking in it that
> caused the failure, but I can successfully retrieve all points on an
> OGRLineString without problems.

I cannot really tell what the problem is but there is one thing that I
think needs investigation:

Please make sure that you have correctly defined the specializations
required by Boost.Range. It seems that you are missing the
range_mutable_iterator specialization. See
http://www.boost.org/doc/libs/1_58_0/libs/range/doc/html/range/reference/extending.html 
for the details.

I do not know is this the root cause of your problem, but it seems to be
that you need to have this specialization anyway.

Another thing: would it be possible to also try with boost 1.58? It
would be helpful to know if the problem persists there.


> However, bg::distance() between two OGRLineStrings returns 0 instead of the
> proper result. Is anybody aware of a change in bg::distance or Boost.Range
> that might cause the failure? After having checked that the iterator works
> forwards and backwards, I'm unsure where to begin with the debugging.
>
> Here's the test code that I use. bg::distance(OGRLineString &, OGRLineString
> &) always returns 0.0:
>
> ---%<---
> void BoostOGRLineStringAdapterTest::testGeometryMultiLineString()
> {
>      typedef bg::model::linestring<OGRPoint> boostLinestring;
>      boostLinestring bls1, bls2;
>
>      OGRLineString *ls1 = new OGRLineString(),
>              *ls2 = new OGRLineString(),
>              *ls3 = new OGRLineString();
>      auto distantPoint = new OGRPoint(15.0, 15.0);
>      OGRSpatialReference *sref = new OGRSpatialReference();
>
>      OGRErr rc = sref->importFromEPSG(4326);
>      QVERIFY(OGRERR_NONE == rc);
>      ls1->assignSpatialReference(sref);
>      ls2->assignSpatialReference(sref);
>      ls3->assignSpatialReference(sref);
>      distantPoint->assignSpatialReference(sref);
>
>      ls1->addPoint(0.0, 0.0);
>      ls1->addPoint(1.0, 1.0);
>      ls1->addPoint(2.0, 2.0);
>      ls1->addPoint(3.0, 3.0);
>      ls1->addPoint(4.0, 4.0);
>
>      bls1.push_back(OGRPoint(0.0, 0.0));
>      bls1.push_back(OGRPoint(1.0, 1.0));
>      bls1.push_back(OGRPoint(2.0, 2.0));
>      bls1.push_back(OGRPoint(3.0, 3.0));
>      bls1.push_back(OGRPoint(4.0, 4.0));
>
>      ls2->addPoint(17.0, 17.0);
>      ls2->addPoint(21.0, 21.0);
>      ls2->addPoint(33.0, 33.0);
>      ls2->addPoint(76.0, 56.0);
>
>      bls2.push_back(OGRPoint(17.0, 17.0));
>      bls2.push_back(OGRPoint(21.0, 21.0));
>      bls2.push_back(OGRPoint(33.0, 33.0));
>      bls2.push_back(OGRPoint(76.0, 56.0));
>
>      ls3->addPoint(42.0, 34.2);
>      ls3->addPoint(72.0, 14.2);
>      ls3->addPoint(67.0, 34.2);
>      ls3->addPoint(82.0,  2.2);
>      ls3->addPoint(5.0, 17.2);
>
>      QCOMPARE(
>              bg::crosses(*ls1, *distantPoint),
>              ls1->Crosses(distantPoint));
>      QCOMPARE(
>              bg::intersects(*ls1, *distantPoint),
>              ls1->Intersects(distantPoint));
>
>
>      for (int i = 0; i != ls1->getNumPoints(); ++i) {
>          auto p = new OGRPoint();
>          ls1->getPoint(i, p);
>
>          QCOMPARE(
>                  bg::distance(*p, *distantPoint),
>                  p->Distance(distantPoint));
>      }
>
>      QCOMPARE(
>              bg::distance(*ls1, *distantPoint),
>              ls1->Distance(distantPoint));
>      QCOMPARE(
>              bg::distance(*ls3, *distantPoint),
>              ls3->Distance(distantPoint));
>      QCOMPARE(
>              bg::distance(*ls2, *distantPoint),
>              ls2->Distance(distantPoint));
>      QCOMPARE(
>              bg::distance(bls1, bls2),
>              ls1->Distance(ls2));
>      QCOMPARE(
>              bg::distance(bls1, bls2),
>              bg::distance(*ls1, *ls2));
>      QCOMPARE(
>              bg::distance(*ls1, *ls2),
>              ls1->Distance(ls2));
>

Which one(s) of the three tests above fail? All of them? Just the second?

Please let me know of your findings.

Best,

- m.


>      delete sref;
> }
> --->%---
>
> Thanks alot in advance for any hints!
>
> --- Eric
> _______________________________________________
> Geometry mailing list
> [hidden email]
> http://lists.boost.org/mailman/listinfo.cgi/geometry

_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hello Menelaos,

thanks for your reply!

On Friday 22 May 2015, 08:42:58, Menelaos Karavelas wrote:
> I cannot really tell what the problem is but there is one thing that I
> think needs investigation:
>
> Please make sure that you have correctly defined the specializations
> required by Boost.Range. It seems that you are missing the
> range_mutable_iterator specialization. See
> http://www.boost.org/doc/libs/1_58_0/libs/range/doc/html/range/reference/ext
> ending.html for the details.

Doesn't range_mutable_iterator mean that the return type of the iterator's
dereference operator is a modifiable reference? If so, I cannot do this due to
the OGRLineString's API.  :-/

Please correct me if I'm mistaken here; I'm by no means an expert in C++ STL-
conformant iterator design.

> Another thing: would it be possible to also try with boost 1.58? It
> would be helpful to know if the problem persists there.

Just upgraded to Boost 1.58.0. I used a different machine to make sure there
are no leftovers that interfer on the original machine. Same problem, sadly.

> >      QCOMPARE(
> >      
> >              bg::distance(bls1, bls2),
> >              bg::distance(*ls1, *ls2));
> >      
> >      QCOMPARE(
> >      
> >              bg::distance(*ls1, *ls2),
> >              ls1->Distance(ls2));
>
> Which one(s) of the three tests above fail? All of them? Just the second?

These two both fail. From that I conclude that (a) the OGRPoint adapter to
Boost.Geometry works, since I can successfully use bg::distance with my
`typedef bg::model::linestring<OGRPoint> boostLinestring` linestring. However,
the OGRLineString version uses my iterator code and fails. So the only bug
that can be found here is most probably in my own iterator code.

Thanks
        Eric
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hello again,

On Friday 22 May 2015 10:39:41, Eric MSP Veith <[hidden email]> wrote:

> > Please make sure that you have correctly defined the specializations
> > required by Boost.Range. It seems that you are missing the
> > range_mutable_iterator specialization. See
> > http://www.boost.org/doc/libs/1_58_0/libs/range/doc/html/range/reference/e
> > xt ending.html for the details.
>
> Doesn't range_mutable_iterator mean that the return type of the iterator's
> dereference operator is a modifiable reference? If so, I cannot do this due
> to the OGRLineString's API.  :-/
>
> Please correct me if I'm mistaken here; I'm by no means an expert in C++
> STL- conformant iterator design.
while I'm still not clear on the implications of  range_mutable_iterator, I
added the following specialization to my code:

namespace boost {
    template <>
    struct range_mutable_iterator<OGRLineString>
    {
        typedef Winzent::Simulation::boost::OGRLineStringIterator type;
    };
}

From what I can see, this will make the range_mutable_iterator concept usable
with my adapter. I checked that BOOST_FOREACH (...) { ... } works for an
OGRLineString; it successfully iterates over all points. However...

> > Another thing: would it be possible to also try with boost 1.58? It
> > would be helpful to know if the problem persists there.
>
> Just upgraded to Boost 1.58.0. I used a different machine to make sure there
> are no leftovers that interfer on the original machine. Same problem,
> sadly.
> > >      QCOMPARE(
> > >      
> > >              bg::distance(bls1, bls2),
> > >              bg::distance(*ls1, *ls2));
> > >      
> > >      QCOMPARE(
> > >      
> > >              bg::distance(*ls1, *ls2),
> > >              ls1->Distance(ls2));
> >
> > Which one(s) of the three tests above fail? All of them? Just the second?
>
> These two both fail. From that I conclude that (a) the OGRPoint adapter to
> Boost.Geometry works, since I can successfully use bg::distance with my
> `typedef bg::model::linestring<OGRPoint> boostLinestring` linestring.
> However, the OGRLineString version uses my iterator code and fails. So the
> only bug that can be found here is most probably in my own iterator code.
I'm still getting this error (copied from the second QCOMPARE, the first one
yields the same result, just with other parameters):

FAIL!  : BoostOGRLineStringAdapterTest::testGeometryMultiLineString() Compared
doubles are not the same (fuzzy compare)
   Actual   (bg::distance(*ls1, *ls2)): 0
   Expected (ls1->Distance(ls2))      : 18,3848

Any ideas on how I can start debugging...?

Thanks,
                Eric
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Menelaos Karavelas
Hi Eric.

On 22/05/2015 02:08 μμ, Eric MSP Veith wrote:
Hello again,

On Friday 22 May 2015 10:39:41, Eric MSP Veith [hidden email] wrote:
Please make sure that you have correctly defined the specializations
required by Boost.Range. It seems that you are missing the
range_mutable_iterator specialization. See
http://www.boost.org/doc/libs/1_58_0/libs/range/doc/html/range/reference/e
xt ending.html for the details.
Doesn't range_mutable_iterator mean that the return type of the iterator's
dereference operator is a modifiable reference? If so, I cannot do this due
to the OGRLineString's API.  :-/

Please correct me if I'm mistaken here; I'm by no means an expert in C++
STL- conformant iterator design.
while I'm still not clear on the implications of  range_mutable_iterator, I 
added the following specialization to my code:

namespace boost {
    template <>
    struct range_mutable_iterator<OGRLineString>
    {
        typedef Winzent::Simulation::boost::OGRLineStringIterator type;
    };
}

From what I can see, this will make the range_mutable_iterator concept usable 
with my adapter. I checked that BOOST_FOREACH (...) { ... } works for an 
OGRLineString; it successfully iterates over all points. However...

Another thing: would it be possible to also try with boost 1.58? It
would be helpful to know if the problem persists there.
Just upgraded to Boost 1.58.0. I used a different machine to make sure there
are no leftovers that interfer on the original machine. Same problem,
sadly.
     QCOMPARE(
     
             bg::distance(bls1, bls2),
             bg::distance(*ls1, *ls2));
     
     QCOMPARE(
     
             bg::distance(*ls1, *ls2),
             ls1->Distance(ls2));
Which one(s) of the three tests above fail? All of them? Just the second?
These two both fail. From that I conclude that (a) the OGRPoint adapter to
Boost.Geometry works, since I can successfully use bg::distance with my
`typedef bg::model::linestring<OGRPoint> boostLinestring` linestring.
However, the OGRLineString version uses my iterator code and fails. So the
only bug that can be found here is most probably in my own iterator code.
I'm still getting this error (copied from the second QCOMPARE, the first one 
yields the same result, just with other parameters):

FAIL!  : BoostOGRLineStringAdapterTest::testGeometryMultiLineString() Compared 
doubles are not the same (fuzzy compare)
   Actual   (bg::distance(*ls1, *ls2)): 0
   Expected (ls1->Distance(ls2))      : 18,3848

Any ideas on how I can start debugging...?

Could you please try the attached program with your geometries?
Basically, what I am asking is that you change the typedefs for point_type and linestring_type to indicate your geometries. Then give it a try.

I want to make sure that point and segment iterator for your linestrings work correctly. If they do then we can see what needs to be done next.

- m.

Thanks,
		Eric


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry

linestring_iterators.cpp (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hi Menelaos,

On Friday 22 May 2015 15:24:32, Menelaos Karavelas
<[hidden email]> wrote:
> Could you please try the attached program with your geometries?
> Basically, what I am asking is that you change the typedefs for
> point_type and linestring_type to indicate your geometries. Then give it
> a try.
>
> I want to make sure that point and segment iterator for your linestrings
> work correctly. If they do then we can see what needs to be done next.

I've changed the typedefs and added the required headers:


//...
#include <boost/geometry.hpp>

#include <gdal/ogr_geometry.h>

#include "boost/OGRPointAdapter.h"
#include "boost/OGRLineStringAdapter.h"
#include "boost/OGRPointCollectionIterator.h"


namespace bg = boost::geometry;

typedef OGRPoint point_type;
typedef OGRLineString linestring_type;

typedef bg::point_iterator<linestring_type const> point_iterator_type;
typedef bg::segment_iterator<linestring_type const> segment_iterator_type;


int main()
{ //...


But the code doesn't compile. I'm quoting only the first few lines:


---%<---
In file included from
/usr/include/boost/geometry/algorithms/detail/distance/iterator_selector.hpp:16:0,
                 from
/usr/include/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp:48,
                 from
/usr/include/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp:17,
                 from
/usr/include/boost/geometry/strategies/strategies.hpp:48,
                 from /usr/include/boost/geometry/geometry.hpp:50,
                 from /usr/include/boost/geometry.hpp:17,
                 from t.cpp:3:
/usr/include/boost/geometry/iterators/point_iterator.hpp: In instantiation of
‘boost::geometry::point_iterator<Geometry>::point_iterator(const
boost::geometry::point_iterator<G>&) [w
ith OtherGeometry = OGRLineString; Geometry = const OGRLineString]’:
t.cpp:29:62:   required from here  
/usr/include/boost/geometry/iterators/point_iterator.hpp:268:57: error: no
matching function for call to
‘boost::iterators::iterator_adaptor<boost::geometry::point_iterator<const OGR
LineString>, Winzent::Simulation::boost::OGRPointCollectionIter<const
OGRLineString, OGRPoint>, boost::iterators::use_default,
boost::iterators::use_default, boost::iterators::use_de
fault, boost::iterators::use_default>::iterator_adaptor(const
Winzent::Simulation::boost::OGRPointCollectionIter<OGRLineString, OGRPoint>&)’
         : point_iterator::iterator_adaptor_(other.base())
                                                         ^
/usr/include/boost/geometry/iterators/point_iterator.hpp:268:57: note:
candidates are:
In file included from /usr/include/boost/iterator/reverse_iterator.hpp:12:0,
                 from /usr/include/boost/range/reverse_iterator.hpp:21,
                 from /usr/include/boost/range/rbegin.hpp:19,
                 from /usr/include/boost/range/functions.hpp:23,
                 from /usr/include/boost/range/iterator_range_core.hpp:38,
                 from /usr/include/boost/lexical_cast.hpp:30,
                 from /usr/include/boost/math/constants/constants.hpp:18,
                 from /usr/include/boost/geometry/util/math.hpp:28,
                 from /usr/include/boost/geometry/core/radian_access.hpp:28,
                 from /usr/include/boost/geometry/geometry.hpp:43,
                 from /usr/include/boost/geometry.hpp:17,
                 from t.cpp:3:
/usr/include/boost/iterator/iterator_adaptor.hpp:265:16: note:
boost::iterators::iterator_adaptor<Derived, Base, Value, Traversal, Reference,
Difference>::iterator_adaptor(const Base
&) [with Derived = boost::geometry::point_iterator<const OGRLineString>; Base
= Winzent::Simulation::boost::OGRPointCollectionIter<const OGRLineString,
OGRPoint>; Value = boost::iter
ators::use_default; Traversal = boost::iterators::use_default; Reference =
boost::iterators::use_default; Difference = boost::iterators::use_default]
       explicit iterator_adaptor(Base const &iter)
                ^
/usr/include/boost/iterator/iterator_adaptor.hpp:265:16: note:   no known
conversion for argument 1 from ‘const
Winzent::Simulation::boost::OGRPointCollectionIter<OGRLineString, OGRPoint>’
to ‘const Winzent::Simulation::boost::OGRPointCollectionIter<const
OGRLineString, OGRPoint>&’
/usr/include/boost/iterator/iterator_adaptor.hpp:263:7: note:
boost::iterators::iterator_adaptor<Derived, Base, Value, Traversal, Reference,
Difference>::iterator_adaptor() [with Derived =
boost::geometry::point_iterator<const OGRLineString>; Base =
Winzent::Simulation::boost::OGRPointCollectionIter<const OGRLineString,
OGRPoint>; Value = boost::iterators::use_default; Traversal =
boost::iterators::use_default; Reference = boost::iterators::use_default;
Difference = boost::iterators::use_default]
       iterator_adaptor() {}
       ^
/usr/include/boost/iterator/iterator_adaptor.hpp:263:7: note:   candidate
expects 0 arguments, 1 provided
--->%---


My OGRPointCollectionIterator is both default and copy constructible:


---%<---
                OGRPointCollectionIter(): m_currentPointIndex(0)
                {
                }


                OGRPointCollectionIter(const OGRPointCollectionIter &other):
                        m_currentPointIndex(other.m_currentPointIndex),
                        m_collection(other.m_collection.get())
                {
                }
--->%---


                        --- Eric
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Menelaos Karavelas
Hi Eric.

On 22/05/2015 04:06 μμ, Eric MSP Veith wrote:
Hi Menelaos,

On Friday 22 May 2015 15:24:32, Menelaos Karavelas 
[hidden email] wrote:
Could you please try the attached program with your geometries?
Basically, what I am asking is that you change the typedefs for
point_type and linestring_type to indicate your geometries. Then give it
a try.

I want to make sure that point and segment iterator for your linestrings
work correctly. If they do then we can see what needs to be done next.
I've changed the typedefs and added the required headers:


//...
#include <boost/geometry.hpp>

#include <gdal/ogr_geometry.h>

#include "boost/OGRPointAdapter.h"
#include "boost/OGRLineStringAdapter.h"
#include "boost/OGRPointCollectionIterator.h"


namespace bg = boost::geometry;

typedef OGRPoint point_type;
typedef OGRLineString linestring_type;

typedef bg::point_iterator<linestring_type const> point_iterator_type;
typedef bg::segment_iterator<linestring_type const> segment_iterator_type;


int main()
{ //...


But the code doesn't compile. I'm quoting only the first few lines:


---%<---
In file included from 
/usr/include/boost/geometry/algorithms/detail/distance/iterator_selector.hpp:16:0,
                 from 
/usr/include/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp:48,
                 from 
/usr/include/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp:17,
                 from 
/usr/include/boost/geometry/strategies/strategies.hpp:48,
                 from /usr/include/boost/geometry/geometry.hpp:50,
                 from /usr/include/boost/geometry.hpp:17,
                 from t.cpp:3:
/usr/include/boost/geometry/iterators/point_iterator.hpp: In instantiation of 
‘boost::geometry::point_iterator<Geometry>::point_iterator(const 
boost::geometry::point_iterator<G>&) [w
ith OtherGeometry = OGRLineString; Geometry = const OGRLineString]’:
t.cpp:29:62:   required from here  
/usr/include/boost/geometry/iterators/point_iterator.hpp:268:57: error: no 
matching function for call to 
‘boost::iterators::iterator_adaptor<boost::geometry::point_iterator<const OGR
LineString>, Winzent::Simulation::boost::OGRPointCollectionIter<const 
OGRLineString, OGRPoint>, boost::iterators::use_default, 
boost::iterators::use_default, boost::iterators::use_de
fault, boost::iterators::use_default>::iterator_adaptor(const 
Winzent::Simulation::boost::OGRPointCollectionIter<OGRLineString, OGRPoint>&)’
         : point_iterator::iterator_adaptor_(other.base())
                                                         ^
/usr/include/boost/geometry/iterators/point_iterator.hpp:268:57: note: 
candidates are:
In file included from /usr/include/boost/iterator/reverse_iterator.hpp:12:0,
                 from /usr/include/boost/range/reverse_iterator.hpp:21,
                 from /usr/include/boost/range/rbegin.hpp:19,
                 from /usr/include/boost/range/functions.hpp:23,
                 from /usr/include/boost/range/iterator_range_core.hpp:38,
                 from /usr/include/boost/lexical_cast.hpp:30,
                 from /usr/include/boost/math/constants/constants.hpp:18,
                 from /usr/include/boost/geometry/util/math.hpp:28,
                 from /usr/include/boost/geometry/core/radian_access.hpp:28,
                 from /usr/include/boost/geometry/geometry.hpp:43,
                 from /usr/include/boost/geometry.hpp:17,
                 from t.cpp:3:
/usr/include/boost/iterator/iterator_adaptor.hpp:265:16: note: 
boost::iterators::iterator_adaptor<Derived, Base, Value, Traversal, Reference, 
Difference>::iterator_adaptor(const Base
&) [with Derived = boost::geometry::point_iterator<const OGRLineString>; Base 
= Winzent::Simulation::boost::OGRPointCollectionIter<const OGRLineString, 
OGRPoint>; Value = boost::iter
ators::use_default; Traversal = boost::iterators::use_default; Reference = 
boost::iterators::use_default; Difference = boost::iterators::use_default]
       explicit iterator_adaptor(Base const &iter)
                ^
/usr/include/boost/iterator/iterator_adaptor.hpp:265:16: note:   no known 
conversion for argument 1 from ‘const 
Winzent::Simulation::boost::OGRPointCollectionIter<OGRLineString, OGRPoint>’ 
to ‘const Winzent::Simulation::boost::OGRPointCollectionIter<const 
OGRLineString, OGRPoint>&’
/usr/include/boost/iterator/iterator_adaptor.hpp:263:7: note: 
boost::iterators::iterator_adaptor<Derived, Base, Value, Traversal, Reference, 
Difference>::iterator_adaptor() [with Derived = 
boost::geometry::point_iterator<const OGRLineString>; Base = 
Winzent::Simulation::boost::OGRPointCollectionIter<const OGRLineString, 
OGRPoint>; Value = boost::iterators::use_default; Traversal = 
boost::iterators::use_default; Reference = boost::iterators::use_default; 
Difference = boost::iterators::use_default]
       iterator_adaptor() {}
       ^
/usr/include/boost/iterator/iterator_adaptor.hpp:263:7: note:   candidate 
expects 0 arguments, 1 provided
--->%---


My OGRPointCollectionIterator is both default and copy constructible:

I think the question is whether your mutable iterator is convertible to your const iterator, or to pose it differently, whether your const iterator is constructible from your mutable iterator (which should be the case).

- m.



---%<---
                OGRPointCollectionIter(): m_currentPointIndex(0)
                {
                }


                OGRPointCollectionIter(const OGRPointCollectionIter &other):
                        m_currentPointIndex(other.m_currentPointIndex),
                        m_collection(other.m_collection.get())
                {
                }
--->%---


			--- Eric


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hello Menelaos,

On Friday 22 May 2015 17:33:35, Menelaos Karavelas
<[hidden email]> wrote:
> > My OGRPointCollectionIterator is both default and copy constructible:
> I think the question is whether your mutable iterator is convertible to
> your const iterator, or to pose it differently, whether your const
> iterator is constructible from your mutable iterator (which should be
> the case).

I'm still puzzled. I've checked my iterator code and updated some of it in
order to have it adhere to the Boost iterator_facade howto as closeley as
possible. Specifically, I made sure that `MyConstIterator iter =
boost::begin(someNonConstLineString);` works, which would cause the iterator
to be converted to the const iterator.

So I assume that it is not the iterator that is at fault.

Checking your example and investigating the Boost.Geometry headers, I see that
the bg::model::linestring<...> trait relies on several functions via
dispatching that are present in std::vector and other container types, but not
in OGRLineString. This includes, as seen from the compiler error I posted
previously, clear(), push_back(), and resize().

I'd now open up the boost::geometry::traits namespace and provide dispatch
structures for these operations along the lines of...


template <>
struct clear<OGRLineString>
{
    static inline void apply(
            typename rvalue_type<OGRLineString>::type range)
    {
        range.empty();
    }
};


Would that be the correct approach or merely a hack?


Thanks
Eric
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Menelaos Karavelas
Hi Eric.

On 26/05/2015 02:43 μμ, Eric MSP Veith wrote:
Hello Menelaos,

On Friday 22 May 2015 17:33:35, Menelaos Karavelas 
[hidden email] wrote:
My OGRPointCollectionIterator is both default and copy constructible:
I think the question is whether your mutable iterator is convertible to
your const iterator, or to pose it differently, whether your const
iterator is constructible from your mutable iterator (which should be
the case).
I'm still puzzled. I've checked my iterator code and updated some of it in 
order to have it adhere to the Boost iterator_facade howto as closeley as 
possible. Specifically, I made sure that `MyConstIterator iter = 
boost::begin(someNonConstLineString);` works, which would cause the iterator 
to be converted to the const iterator.

So I assume that it is not the iterator that is at fault.

Checking your example and investigating the Boost.Geometry headers, I see that 
the bg::model::linestring<...> trait relies on several functions via 
dispatching that are present in std::vector and other container types, but not 
in OGRLineString. This includes, as seen from the compiler error I posted 
previously, clear(), push_back(), and resize().

I'd now open up the boost::geometry::traits namespace and provide dispatch 
structures for these operations along the lines of...


template <>
struct clear<OGRLineString>
{
    static inline void apply(
            typename rvalue_type<OGRLineString>::type range)
    {
        range.empty();
    }
};


Would that be the correct approach or merely a hack?

Yes, this IS the correct way. You need to specialize various metafunctions in bg::traits namespace so that things work.
Please keep us posted about this.

- m.



Thanks
Eric


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Eric MSP Veith
Hello Menelaos,

On Tuesday 26 May 2015 14:47:20, Menelaos Karavelas
<[hidden email]> wrote:
> Yes, this IS the correct way. You need to specialize various
> metafunctions in bg::traits namespace so that things work.
> Please keep up posted about this.

ok, good to know. I've followed this path and provided template
specializations for clear, resize, and push_back. The test program you
supplied now compiles, but gives a rather surprising result:

geometry: LINESTRING(1 1,2 2,3 3,4 4,9 9)
points: (1, 1) (2, 2) (3, 3) (4, 4) (9, 9)
segments: ((2.0872e-317, 6.95257e-310), (6.91222e-310, 6.91222e-310))
((2.0872e-317, 6.95257e-310), (6.91222e-310, 6.91222e-310)) ((2.0872e-317,
6.95257e-310), (6.91222e-310, 6.91222e-310)) ((2.0872e-317, 6.95257e-310),
(6.91222e-310, 6.91222e-310))

The values of the last line change with each run, but never much, i.e., the
value left to the dot remains the same.

Do I need to provide a separate segment iterator...?

Thanks
Eric
_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Integrating OGR library with Boost.Geometry

Menelaos Karavelas
Hi Eric.

On 26/05/2015 03:00 μμ, Eric MSP Veith wrote:
Hello Menelaos,

On Tuesday 26 May 2015 14:47:20, Menelaos Karavelas 
[hidden email] wrote:
Yes, this IS the correct way. You need to specialize various
metafunctions in bg::traits namespace so that things work.
Please keep up posted about this.
ok, good to know. I've followed this path and provided template 
specializations for clear, resize, and push_back. The test program you 
supplied now compiles, but gives a rather surprising result:

geometry: LINESTRING(1 1,2 2,3 3,4 4,9 9)
points: (1, 1) (2, 2) (3, 3) (4, 4) (9, 9)
segments: ((2.0872e-317, 6.95257e-310), (6.91222e-310, 6.91222e-310)) 
((2.0872e-317, 6.95257e-310), (6.91222e-310, 6.91222e-310)) ((2.0872e-317, 
6.95257e-310), (6.91222e-310, 6.91222e-310)) ((2.0872e-317, 6.95257e-310), 
(6.91222e-310, 6.91222e-310))

The values of the last line change with each run, but never much, i.e., the 
value left to the dot remains the same.

My understanding is that something is left uninitialized, hence the strange values.

Do I need to provide a separate segment iterator...?

You should not need to. The implementation of the segment iterator is rather generic, but quite tricky, as it is not the typical kind of iterator (for example, dereferrencing returns a value rather than a reference).

What is your linestring's value type and reference type? In the implementation of the segment iterator it is assumed that, when dereferrencing an iterator on the points of the linestring, a reference (or const reference) is returned. If your linestring iterator returns point values then this could indeed be a problem.

- m.

Thanks
Eric


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry


_______________________________________________
Geometry mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/geometry
12