boost::geometry seems to have support to convert from lat/lon to UTM. Unfortunately I couldn't find any example on how exactly to do that. Does someone have an example they are willing to share?
2 Answers
I just spent an embarrassing amount of time looking for this (multiple hours).
It seems like everything spherical (SRS) is just ... not documented at all. Perhaps there's something broken with the documentation generator.
Regardless, several tedious searches through test code further I stumbled on a working answer.
Here's examples
- Amsterdam (UTM 629144.77 Easting 5803996.66 Northing in zone 31U)
- Barcelona (UTM 430887.56 Easting, 4581837.85 Northing, zone 31T)
With even more stumbling I found the corresponding EPSG code on https://epsg.io/?q=UTM+31N:
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/srs/epsg.hpp>
#ifdef COLIRU
#include <boost/geometry/srs/projection.hpp>
#endif
namespace bg = boost::geometry;
namespace bm = bg::model::d2;
namespace srs = bg::srs;
using LongLat = bm::point_xy<double, bg::cs::geographic<bg::degree> >;
using UTM = bm::point_xy<double/*, srs::static_epsg<3043>*/>;
constexpr LongLat Amsterdam() { return { 4.897, 52.371}; }
constexpr LongLat Barcelona() { return { 2.1734, 41.3851 }; }
void report(LongLat src, auto const& prj) {
UTM r {};
prj.forward(src, r);
std::cout << std::fixed << bg::wkt(src) << " -> " << bg::wkt(r) << "\n";
}
int main() {
#ifndef COLIRU
// dynamic projection factory too heavy on Coliru
srs::projection<> zone31 = srs::proj4("+proj=utm +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5 +zone=31");
report(Amsterdam(), zone31);
report(Barcelona(), zone31);
#endif
srs::projection<srs::static_epsg<3043> > epsg3043;
report(Amsterdam(), epsg3043);
report(Barcelona(), epsg3043);
}
Prints
POINT(4.897000 52.371000) -> POINT(629144.771310 5803996.656944)
POINT(2.173400 41.385100) -> POINT(430887.564331 4581837.853239)
POINT(4.897000 52.371000) -> POINT(629144.771310 5803996.656944)
POINT(2.173400 41.385100) -> POINT(430887.564331 4581837.853239)
Disclaimer:
I'm not actually convinced that the UTM
point type I defined makes much sense. I think any point type that can receive 2 coordinates will do. At least the srs::...
as the coordinate system doesn't seem to do anything - bg::convert, bg::assign and friends don't magically know how to apply the projection anyways. I think the "doxygen_z_article09" link you included is just badly out of date/not how things were eventually implemented.

- 374,641
- 47
- 450
- 633
-
Who's being quoted in the `Disclaimer` section? Or, it's not a quote? – LuisTavares Feb 20 '21 at 11:33
-
1@LuisTavares I use markdown for expressiveness. Block quotes are just that. I use them for "asides" often. I appreciate that - apparently - this sometimes leads to minor confusion, so I will keep that in mind. However, just look at some of my answers, and you'll appreciate that many would suffer from decreased structural clarity if I were to avoid some typographical options for reasons of purity. – sehe Feb 20 '21 at 17:32
-
I'm the one who upvoted... both the answer and your comment. – LuisTavares Mar 10 '21 at 21:20
-
1@LuisTavares Cheers. I didn't think that - that was a full 4 weeks ago. Pretty sure someone else came by, and perhaps did find something wrong (or maybe it was just noise. Mouse slips happen, but not a lot in the low-traffic tags from a month ago :)) – sehe Mar 10 '21 at 22:23
-
I'm afraid that this answer is inappropriate. When doing projections in general, you must first define (or find out) the exact geodetic definition which is used by your lon/lat coordinate data. At least, parameters like geodetic reference system, datum, ellipsoid, etc. must be provided. Like you said in the "Disclaimer" section, your conversion won't make much sense in geodetic point of view. Check this video: https://www.youtube.com/watch?v=dA5zcnNJKDY – saki7 Mar 11 '21 at 17:46
-
@saki7 I did not say that in my comment. (I [added a word](https://stackoverflow.com/posts/66271415/revisions) to remove the ambiguity). This is stackoverflow, not https://gis.stackexchange.com/. We answer the _programming related_ questions. I did try to select an appropriate CRS (based on the UTM requirement) and [link to the site](https://epsg.io/3043) where I got that information from so people can select the relevant systems. Did I do miss anything? Also, even if the question lacks information to select the correct CRS, I feel this answer will help people find the missing steps. – sehe Mar 11 '21 at 20:11
-
@sehe Your code will most likely result in wrong values for real-world datasets because you haven't specified the parameters for lon/lat coordinates. A lon/lat coordinate value itself is not some absolute value that you can use for arbitrary projection. For instance, the coordinates of (4.897, 52.371) is only valid within the original geodetic system. Another system might have values like (4.7, 52.4) for exact same point. Your answer is inappropriate because it will produce wrong output. It isn't the matter of GIS relevance; your program does not fulfill the original question's purpose. – saki7 Mar 11 '21 at 21:03
-
You will get expected result if you use `boost::geometry::srs::transformation` class and specify both source and destination projection parameters :) – saki7 Mar 11 '21 at 21:13
-
@saki7 I think I'm just not following. I think I did specify, and I did cross-check the results with the linked site (note that there are 4 hyperlinks in the answer text). Perhaps you can contribute an answer, so we can in fact learn. I'm happy to upvote, bounty and delete mine. The unfortunate state of affairs seems to be that the BG documentation is simply lacking. And ,aybe/apparently that's not an issue since only geodetic pros use these parts. – sehe Mar 11 '21 at 21:27
-
@sehe No offense but OP has already posted a "modified version" of your answer - so I will not post my own answer. Doing so will essentially result in 3 copies of your code, which just contain slight differences between each other. Your code is like 80% correct, so I suggest you add further explanation for the wrong part. I've already described the rationale, and technical details are also available on the YouTube video I commented above. – saki7 Mar 11 '21 at 21:43
-
@saki7 can you please do the edit as I don't feel I will get your "rationale" correct. Speciically, do I just need to remove one example point? As in, was the chosen EPSG CRS only good for Amsterdam (31U) not Barcelona (31T)? Also, "You code is like 80% correct" already sounds wholly different from "your answer is just inappropriate", "gives the wrong output". can we get somewhere _together_? I **just don't know** how to "use boost::geometry::srs::transformation class and specify both source and destination projection parameters :)". I'm also happy if you point me to the documentation for it. – sehe Mar 12 '21 at 00:09
-
1For your reference, PDF of the video is available: https://archive.fosdem.org/2019/schedule/event/geo_spatialboostgeometry/attachments/slides/3306/export/events/attachments/geo_spatialboostgeometry/slides/3306/Boost_Geometry_SRS_Transformations.pdf / In general, you will likely to find the PDF format slides if you google the video session's title, especially for technical conferences. – saki7 Mar 12 '21 at 02:07
I have some minor modifications to the answer from @sehe to make it compile with VS 2019/C++14:
#include <boost/geometry.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <iostream>
#include <boost/geometry/srs/epsg.hpp>
#ifdef COLIRU
#include <boost/geometry/srs/projection.hpp>
#endif
namespace bg = boost::geometry;
namespace bm = bg::model::d2;
namespace srs = bg::srs;
using LongLat = bm::point_xy<double, bg::cs::geographic<bg::degree>>;
using UTM = bm::point_xy<double /*, srs::static_epsg<3043>*/>;
LongLat Barcelona{2.1734, 41.3851};
LongLat Amsterdam{4.897, 52.371};
template <typename T> void report(LongLat src, T const &prj) {
UTM r{};
prj.forward(src, r);
std::cout << std::fixed << bg::wkt(src) << " -> " << bg::wkt(r) << "\n";
}
int main() {
#ifndef COLIRU
// dynamic projection factory too heavy on Coliru
srs::projection<> zone31 = srs::proj4("+proj=utm +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5 +zone=31");
report(Amsterdam, zone31);
report(Barcelona, zone31);
#endif
srs::projection<srs::static_epsg<3043>> epsg3043;
report(Amsterdam, epsg3043);
report(Barcelona, epsg3043);
}

- 419
- 3
- 9