Hi,

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
    projections::parameters par = projections::init("+ellps=WGS84 +units=m");
    projections::robin_spheroid<point_ll, point_xy> prj(par);
    bool ok = prj.forward(pt_ll, pt_xy);

    //run-time
    projections::parameters par = projections::init("+proj=robin +ellps=WGS84 +units=m");
    // or
    projections::parameters par = projections::init(epsg);
    projections::factory<point_ll, point_xy> fac;
    boost::shared_ptr<projections::projection<point_ll, point_xy> > prj(fac.create_new(par));
    bool ok prj->forward(pt_ll, pt_xy);

    // also runtime
    projections::project_transformer
        <
            point_ll_deg,
            point_xy
        > 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 parameters
- 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 (https://www.nceas.ucsb.edu/scicomp/recipes/projections) 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 default.
In transform strategy take projection as template parameter and use run-time projection as default.

    // compile-time
    projections::robin_spheroid<> prj("+ellps=WGS84 +units=m");
    projections::robin_spheroid<> prj(srs::spheroid<>());
    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
    projections::project_transformer<> projection("+proj=robin +ellps=WGS84 +units=m");
    transform(pt_ll, pt_xy, projection);

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 below):

    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:

    using namespace projections;
    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(proj4("+proj=robin +ellps=WGS84 +units=m"));
    project_transformer<> projection(epsg(epsg_code));
    project_transformer<> projection(spheroid<>()); // compile-time error
   
project_transformer<aea_ellipsoid<> > projection(spheroid<>()); // ok
    transform(pt_ll, pt_xy, projection);

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.

Regards,
Adam