0

I am currently using the GEOS library through OGR and data from a PostGIS database to work with geospatial data. I now found myself in the need to use some of the algorithms Boost.Geometry and Boost.Graph offers, so I've adopted the OGR classes to boost's iterator/range concept. However, the two libraries yield different results, and I am unsure why. From the compiler perspective everything works; however, a simple test case fails.

Step by step, here is what I did.

I define two linestrings and a point and assign WGS84 as projection, in PostGIS:

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)

Then I calculate the distance between the first and the second linestring and the distance between the first linestring and the point:

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

Using OGR/GEOS to do the same calculations in the client program yields the same results.

Now I compare those with the result of the boost adaption. I registered OGRPoint with the boost library with the following code:

BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(
    OGRPoint,
    qreal,
    boost::geometry::cs::cartesian,
    getX,
    getY,
    setX,
    setY)

The most important part is the fourth line, where the coordinate system is defined. Since all my coordinates are in WGS84 projection, I chose "cartesian" as the appropriate coordinate system.

And here is the relevant code from my unit test:

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

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

for (int i = 0; i != 5; ++i) {
    ls1.addPoint(static_cast<qreal>(i), static_cast<qreal>(i));
}

ls2.addPoint(15.0, 15.0);
ls2.addPoint(16.0, 16.0);

QCOMPARE(
        bg::crosses(ls1, distantPoint),
        ls1.Crosses(&distantPoint));
QCOMPARE(
        bg::intersects(ls1, distantPoint),
        ls1.Intersects(&distantPoint));
QCOMPARE(bg::distance(ls1, ls2), ls1.Distance(&ls2));
QCOMPARE(
        bg::distance(
            ls1,
            distantPoint),
        ls1.Distance(&distantPoint));

delete sref;

However, using boost's boost::geometry::distance yields totally different results: For the distance linestring to linestring, the result is 0, for point to linestring, 16.9706. Using one of the other strategies defined in the boost library also yields completely different results, such as 0.294082 for boost::geometry::cs::geographic.

What is the reason for this? What am I doing wrong?

0

As it turned out, the problem was not different algorithms calculating different distance results, but simply a problem in the C++ source code.

There is a related question on Stackoverflow (“How to register a Boost.Geometry distance strategy for OGRPoint and OGRLineString?”), as well as a thread on the Boost.Geometry mailing list I created. The root cause for my problem was a flaw in a C++ iterator that created a follow-up question (“How to create a well-behaved Iterator for a write-to-pointer API?”).

The working iterator/adapter code is in a GitHub project.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.