CARLA
Loading...
Searching...
No Matches
GeoReferenceParser.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8
9#include "carla/Logging.h"
10#include "carla/StringUtil.h"
14#include "carla/geom/Math.h"
15
17
18#include <string>
19#include <vector>
20#include <regex>
21#include <utility>
22#include <cctype>
23#include <stdexcept>
24
25namespace carla {
26namespace opendrive {
27namespace parser {
28
29 template <typename S>
30 static std::string ToLowerCase(S&& s) {
31 std::string r = s;
32 for (auto& c : r)
33 c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
34 return r;
35 }
36
37 static std::unordered_map<std::string, std::string> ParseProjectionParameters(const std::string &s){
38
39 // +key[=value]; value can be "quoted" or 'quoted' or an unquoted token (no spaces)
40 // This also captures bare flags like +south
41 std::unordered_map<std::string, std::string> geo_parameters_map;
42
43 static const std::regex re(R"(\+([A-Za-z0-9_]+)(?:=("[^"]*"|'[^']*'|[^ \t\r\n+]+))?)");
44 for (std::sregex_iterator it(s.begin(), s.end(), re), end; it != end; ++it) {
45 std::string key = (*it)[1].str();
46 std::string val = (*it)[2].str();
47 geo_parameters_map[key] = val;
48 }
49
50 return geo_parameters_map;
51 }
52
53 static std::unordered_map<std::string, double> ParseOffsetParameters(const pugi::xml_node &geo_offset){
54
55 std::unordered_map<std::string, double> geo_offset_result;
56
57 for (auto attr = geo_offset.first_attribute(); attr; attr = attr.next_attribute()){
58 std::string key = attr.name();
59 double value = attr.as_double();
60 geo_offset_result[key] = value;
61 }
62 return geo_offset_result;
63 }
64
65
66 template <typename M, typename S>
67 static bool TryGetParameter(std::string& out, M& parameters, S&& name)
68 {
69 auto i = parameters.find(std::forward<S>(name));
70 if (i == parameters.cend())
71 return false;
72 out = i->second;
73 return true;
74 }
75
76 template <typename M, typename S, typename O>
77 static
78 std::enable_if_t<std::is_floating_point<O>::value, bool>
79 TryGetParameter(O& out, M& parameters, S&& name)
80 {
81 auto i = parameters.find(std::forward<S>(name));
82 if (i == parameters.cend())
83 return false;
84 out = static_cast<O>(std::stod(i->second));
85 return true;
86 }
87
88 template <typename M, typename S, typename O>
89 static
90 std::enable_if_t<std::is_integral<O>::value && std::is_unsigned<O>::value, bool>
91 TryGetParameter(O& out, M& parameters, S&& name)
92 {
93 auto i = parameters.find(std::forward<S>(name));
94 if (i == parameters.cend())
95 return false;
96 out = static_cast<O>(std::stoull(i->second));
97 return true;
98 }
99
100 template <typename M, typename S, typename O>
101 static
102 std::enable_if_t<std::is_integral<O>::value && std::is_signed<O>::value, bool>
103 TryGetParameter(O& out, M& parameters, S&& name)
104 {
105 auto i = parameters.find(std::forward<S>(name));
106 if (i == parameters.cend())
107 return false;
108 out = static_cast<O>(std::stoll(i->second));
109 return true;
110 }
111
112 template <typename S, typename O>
113 static bool TryGetParameter(O& out,std::unordered_map<std::string, double>& parameters,S&& name)
114 {
115 auto i = parameters.find(std::forward<S>(name));
116 if (i == parameters.cend()){
117 return false;
118 }
119 out = static_cast<O>(i->second);
120 return true;
121 }
122
123
124 static geom::Ellipsoid CreateEllipsoid(std::unordered_map<std::string, std::string> parameters){
125
126 geom::Ellipsoid ellps;
127 std::string value;
128 bool initialized=false;
129 double x;
130
131 if (TryGetParameter(value, parameters, "ellps") || TryGetParameter(value, parameters, "datum")) {
132 value = ToLowerCase(value);
133 auto it = geom::custom_ellipsoids.find(value);
134 if (it != geom::custom_ellipsoids.end()) {
135 ellps.a = it->second.first;
136 ellps.f_inv = it->second.second;
137 initialized=true;
138 }
139 }
140
141 initialized |= TryGetParameter(ellps.a, parameters, "a");
142 // Specific semi-major axis
143 if (TryGetParameter(x, parameters, "b")) {
144 initialized = true;
145 ellps.fromb(x);
146 }
147 if (TryGetParameter(x, parameters, "f")) {
148 initialized = true;
149 ellps.fromf(x);
150 }
151 initialized |= TryGetParameter(ellps.f_inv, parameters, "rf");
152
153 if (!initialized) {
154 auto val = geom::custom_ellipsoids.find("wgs84");
155 ellps.a = val->second.first;
156 ellps.f_inv = val->second.second;
157 }
158
159 return ellps;
160 }
161
162 static boost::optional<geom::OffsetTransform> CreateOffsetTransform(std::unordered_map<std::string, double>& offset_parameters){
163
164 if(offset_parameters.empty()){
165 return boost::none;
166 }
167
168 double x = 0.0;
169 double y = 0.0;
170 double z = 0.0;
171 double hdg = 0.0;
172
173 TryGetParameter(x, offset_parameters, "x");
174 TryGetParameter(y, offset_parameters, "y");
175 TryGetParameter(z, offset_parameters, "z");
176 TryGetParameter(hdg, offset_parameters, "hdg");
177
178 return geom::OffsetTransform{x, y, z, hdg};
179 }
180
181 static geom::GeoProjection CreateTransverseMercatorProjection(
182 std::unordered_map<std::string, std::string> parameters,
183 std::string proj_string,
184 geom::Ellipsoid ellipsoid){
185
186 geom::TransverseMercatorParams p;
187 TryGetParameter(p.lat_0, parameters, "lat_0");
188 TryGetParameter(p.lon_0, parameters, "lon_0");
189 TryGetParameter(p.k, parameters, "k");
190 TryGetParameter(p.x_0, parameters, "x_0");
191 TryGetParameter(p.y_0, parameters, "y_0");
192 p.ellps = ellipsoid;
193 auto projection = geom::GeoProjection::Make(p);
194 projection.SetPROJString(proj_string);
195 return projection;
196 }
197
198 static geom::GeoProjection CreateUniversalTransverseMercatorProjection(
199 std::unordered_map<std::string, std::string> parameters,
200 std::string proj_string,
201 geom::Ellipsoid ellipsoid, boost::optional<carla::geom::OffsetTransform> offset){
202
203 geom::UniversalTransverseMercatorParams p;
204 if (!TryGetParameter(p.zone, parameters, "zone")) {
205 log_warning("Missing 'zone' parameter for UTM projection. Using default value " + std::to_string(p.zone));
206 }
207 p.north = (parameters.count("south") > 0) ? false : true;
208 p.ellps = ellipsoid;
209 p.offset = offset;
210 auto projection = geom::GeoProjection::Make(p);
211 projection.SetPROJString(proj_string);
212 return projection;
213 }
214
215 static geom::GeoProjection CreateWebMercatorProjection(
216 std::string proj_string,
217 geom::Ellipsoid ellipsoid){
218
219 // Parameters are fixed.
220 geom::WebMercatorParams p;
221 p.ellps = ellipsoid;
222 auto projection = geom::GeoProjection::Make(p);
223 projection.SetPROJString(proj_string);
224 return projection;
225 }
226
227 static geom::GeoProjection CreateLambertConformalConicProjection(
228 std::unordered_map<std::string, std::string> parameters,
229 std::string proj_string,
230 geom::Ellipsoid ellipsoid){
231
232 geom::LambertConformalConicParams p;
233 TryGetParameter(p.lon_0, parameters, "lon_0");
234 TryGetParameter(p.lat_0, parameters, "lat_0");
235 if (!TryGetParameter(p.lat_1, parameters, "lat_1"))
236 log_warning("Missing 'lat_1' parameter for LCC projection. Using default value " + std::to_string(p.lat_1));
237 if (!TryGetParameter(p.lat_2, parameters, "lat_2"))
238 log_warning("Missing 'lat_2' parameter for LCC projection. Using default value " + std::to_string(p.lat_2));
239 TryGetParameter(p.x_0, parameters, "x_0");
240 TryGetParameter(p.y_0, parameters, "y_0");
241 p.ellps = ellipsoid;
242 auto projection = geom::GeoProjection::Make(p);
243 projection.SetPROJString(proj_string);
244 return projection;
245 }
246
247 // TransverseMercator projection with default parameters.
248 static geom::GeoProjection CreateDefaultProjection(geom::Ellipsoid ellipsoid){
249 geom::TransverseMercatorParams p;
250
251 p.ellps = ellipsoid;
252 auto projection = geom::GeoProjection::Make(p);
253 return projection;
254 }
255
256 static geom::GeoLocation CreateTransverseMercatorGeoReference(std::unordered_map<std::string, std::string> parameters){
257 geom::GeoLocation result{0.0, 0.0, 0.0};
258 TryGetParameter(result.latitude, parameters, "lat_0");
259 TryGetParameter(result.longitude, parameters, "lon_0");
260 return result;
261 }
262
263 static geom::GeoLocation CreateUniversalTransverseMercatorGeoReference(std::unordered_map<std::string, std::string> parameters){
264 geom::GeoLocation result{0.0, 0.0, 0.0};
265 double zone = 0.0;
266 if (TryGetParameter(zone, parameters, "zone"))
267 result.longitude = 6.0 * zone - 183.0;
268 return result;
269 }
270
271 static geom::GeoLocation CreateWebMercatorGeoReference(){
272 geom::GeoLocation result{0.0, 0.0, 0.0};
273 return result;
274 }
275
276 static geom::GeoLocation CreateLambertConic2SPGeoReference(std::unordered_map<std::string, std::string> parameters){
277 geom::GeoLocation result{0.0, 0.0, 0.0};
278 TryGetParameter(result.latitude, parameters, "lat_0");
279 TryGetParameter(result.longitude, parameters, "lon_0");
280 return result;
281 }
282
283 static geom::GeoLocation CreateDefaultGeoReference(){
284 geom::GeoLocation result{0.0, 0.0, 0.0};
285 return result;
286 }
287
288 static auto ParseGeoProjectionAndReference(const std::string& proj_string, const pugi::xml_node &geo_offset){
289 auto parameters = ParseProjectionParameters(proj_string);
290 auto offset_parameters = ParseOffsetParameters(geo_offset);
291 auto ellipsoid = CreateEllipsoid(parameters);
292 auto offset_transform = CreateOffsetTransform(offset_parameters);
293
294 // Get the projection type
295 std::string proj;
296 if (!TryGetParameter(proj, parameters, "proj")) {
297 log_warning("cannot find the type of projection, using default transverse mercator");
298 return std::make_pair(
299 CreateDefaultProjection(ellipsoid),
300 CreateDefaultGeoReference());
301 }
302
303 // Parse the parameters
304 if (proj == "tmerc") {
305 return std::make_pair(
306 CreateTransverseMercatorProjection(parameters, proj_string, ellipsoid),
307 CreateTransverseMercatorGeoReference(parameters));
308 } else if (proj == "utm") {
309 return std::make_pair(
310 CreateUniversalTransverseMercatorProjection(parameters, proj_string, ellipsoid, offset_transform),
311 CreateUniversalTransverseMercatorGeoReference(parameters));
312 } else if (proj == "merc") {
313 return std::make_pair(
314 CreateWebMercatorProjection(proj_string, ellipsoid),
315 CreateWebMercatorGeoReference());
316 } else if (proj == "lcc") {
317 return std::make_pair(
318 CreateLambertConformalConicProjection(parameters, proj_string, ellipsoid),
319 CreateLambertConic2SPGeoReference(parameters));
320 } else {
321 log_debug("projection '" + proj + "' is not supported, using default transverse mercator.");
322 return std::make_pair(
323 CreateDefaultProjection(ellipsoid),
324 CreateDefaultGeoReference());
325 }
326 }
327
329 const pugi::xml_document &xml,
330 carla::road::MapBuilder &map_builder) {
331
332 auto georeference_string =
333 xml
334 .child("OpenDRIVE")
335 .child("header")
336 .child_value("geoReference");
337
338 auto georeference_offset_node =
339 xml
340 .child("OpenDRIVE")
341 .child("header")
342 .child("offset");
343
344 auto reference_and_projection = ParseGeoProjectionAndReference(
345 georeference_string, georeference_offset_node);
346 map_builder.SetGeoProjection(reference_and_projection.first);
347 map_builder.SetGeoReference(reference_and_projection.second);
348
349
350 }
351
352} // parser
353} // opendrive
354} // carla
float y
float x
float z
static void Parse(const pugi::xml_document &xml, carla::road::MapBuilder &map_builder)
void SetGeoProjection(const geom::GeoProjection &geo_projection)
Definition MapBuilder.h:394
void SetGeoReference(const geom::GeoLocation &geo_reference)
Definition MapBuilder.h:390
xml_node child(const char_t *name) const
Definition pugixml.cpp:5490
const char_t * child_value() const
Definition pugixml.cpp:5592
xml_attribute first_attribute() const
Definition pugixml.cpp:5612
static const std::unordered_map< std::string, std::pair< double, double > > custom_ellipsoids
This file contains definitions of common data structures used in traffic manager.
static void log_warning(Args &&... args)
Definition Logging.h:96
static void log_debug(Args &&... args)
Definition Logging.h:68
static GeoProjection Make(T &&args)