Boost logo

Geometry :

Subject: [geometry] Moving projections from extensions
From: Adam Wulkiewicz (adam.wulkiewicz_at_[hidden])
Date: 2016-06-20 11:59:36


I'm planning to move the projections from extensions. I've looked at the
code I have some questions and a proposal of some minor changes to the
interface, to simplify it.

The first question is:
Should the user be able to use the projections directly or should he/she
always use the transform() function with a strategy?

Currently there are several ways of using a projection, e.g.:

// compile-time
bool ok = prj.forward(pt_ll,pt_xy);

     // or
bool ok prj->forward(pt_ll,pt_xy);

// also runtime




>projection("+proj=robin+ellps=WGS84+units=m"); transform(pt_ll,pt_xy,projection);

There are several problems with this API:
- it is complex
- the implementation details (factory) are exposed to the user
- the parameters are always stored as doubles
- the transform strategy and projections require points as template
- the transform strategy always use the runtime projection (factory,
dynamic polymorphism, etc.)
- only proj4 strings and EPSG codes can be used to define a projection,
there may be other ways like ESRI-flavored WKT
( or compile time
definition like bg::srs::spheroid
- EPSG codes are simply used to generate proj4 string and then this
string is parsed, I suspect that the EPSG could be used to directly fill
the projection parameters

So in general I propose to hide as much as we can and expose only
crucial parts of the API.
For run-time projections use PIMPL idiom and wrap the pointer inside.
Require only to define CalculationType for projection and use double as
In transform strategy take projection as template parameter and use
run-time projection as default.

// compile-time
projections::forward(pt_ll,pt_xy, prj);

// run-time
projections::projection<> prj("+proj=robin+ellps=WGS84+units=m");
projections::projection<> prj(epsg);
projections::forward(pt_ll,pt_xy, prj);

// also runtime


If the user shouldn't use the projections directly (only transform +
strategy) we could leave the parameters type (filled in the transform
strategy) as it is now and pass it into the projections instead of proj4
string or epsg code. Then we wouldn't be forced to implement
constructors for all inputs in every projection. But parameters should
also take the CalculationType and I don't see a reason to have init()
function (this also causes problems with multiple representations, see

projections::parameters<> par("+ellps=WGS84+units=m");
projections::parameters<> par(epsg);

projections::robin_spheroid<> prj(par);

Now, regarding the other kinds of projections definitions, both proj4 an
WKTs are strings so currently it wouldn't be possible to implement both
unless there was some other function like init_wkt(), but i think it's
not elegant. Instead I propose wrapping the parameters, like this:

parameters<> par= proj4("+ellps=WGS84+units=m");
parameters<> par = epsg(epsg_code);
parameters<> par = static_epsg<EPSG>();
parameters<> par = spheroid<>();
parameters<> par = wkt("..."); // maybe in the future

     // still the user should use:
project_transformer<>projection(spheroid<>()); // compile-time error
project_transformer<aea_ellipsoid<> >projection(spheroid<>()); // ok


This would make the code more clear too, and semantically separate
Boost.Geometry from the internal implementation being Proj4.

There are also other things I'd like to ask about, i.e.:

What do you think about getting rid of forward and inverse methods and
instead figuring it out from the input types? The projection would
always perform a forward projection if the cartesian geometry was the
second parameter and inverse projection if it was the first parameter.
I'd be similar to boost::lexical_cast which gets the direction from
template parameters. In such case the user would be forced to pass the
correct point/geometries types so this is limiting.

This could be implemented only in the transform strategy (so the
projections would still have forward() and inverse() functions), then
project_inverse_transformer wouldn't be needed.
Another way could be project_transformer automatically figuring out the
projection direction and explicit project_forward_transformer,
project_inverse_transformer strategies.

I'm also confused about the names of projections. AFAIU the ones marked
as xxx_ellipsoid map from ellipsoid of revolution or spheroid and the
ones marked as xxx_spheroid map from a sphere. There is also e.g.
cass_spheroid which AFAIU can work with ellipsoid of revolution. Are
these simple inaccuracies or am I missing something?

Currently the names are directly derived from Proj4 parameter names but
in WKT they're different (PROJECTION["Transverse_Mercator"]) so users
which doesn't know Proj4 could be confused.
What do you think about naming projections using full names, e.g.:

projections::aea_ellipsoid -> projections::albers_equal_area
projections::cass_spheroid -> projections::cassini
projections::tmerc_ellipsoid -> projections::transverse_mercator

This would again be more clear and general. And wouldn't be confusing if
we had tri-axial ellipsoid projections in the future.


Geometry list run by mateusz at