1 /******************************************************************************
2  *
3  * Project:  PROJ
4  * Purpose:  ISO19111:2019 implementation
5  * Author:   Even Rouault <even dot rouault at spatialys dot com>
6  *
7  ******************************************************************************
8  * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "parammappings.hpp"
30 #include "oputils.hpp"
31 #include "proj_constants.h"
32 
33 #include "proj/internal/internal.hpp"
34 
35 NS_PROJ_START
36 
37 using namespace internal;
38 
39 namespace operation {
40 
41 //! @cond Doxygen_Suppress
42 
43 const char *WKT1_LATITUDE_OF_ORIGIN = "latitude_of_origin";
44 const char *WKT1_CENTRAL_MERIDIAN = "central_meridian";
45 const char *WKT1_SCALE_FACTOR = "scale_factor";
46 const char *WKT1_FALSE_EASTING = "false_easting";
47 const char *WKT1_FALSE_NORTHING = "false_northing";
48 const char *WKT1_STANDARD_PARALLEL_1 = "standard_parallel_1";
49 const char *WKT1_STANDARD_PARALLEL_2 = "standard_parallel_2";
50 const char *WKT1_LATITUDE_OF_CENTER = "latitude_of_center";
51 const char *WKT1_LONGITUDE_OF_CENTER = "longitude_of_center";
52 const char *WKT1_AZIMUTH = "azimuth";
53 const char *WKT1_RECTIFIED_GRID_ANGLE = "rectified_grid_angle";
54 
55 static const char *lat_0 = "lat_0";
56 static const char *lat_1 = "lat_1";
57 static const char *lat_2 = "lat_2";
58 static const char *lat_ts = "lat_ts";
59 static const char *lon_0 = "lon_0";
60 static const char *lon_1 = "lon_1";
61 static const char *lon_2 = "lon_2";
62 static const char *lonc = "lonc";
63 static const char *alpha = "alpha";
64 static const char *gamma = "gamma";
65 static const char *k_0 = "k_0";
66 static const char *k = "k";
67 static const char *x_0 = "x_0";
68 static const char *y_0 = "y_0";
69 static const char *h = "h";
70 
71 // ---------------------------------------------------------------------------
72 
73 const ParamMapping paramLatitudeNatOrigin = {
74     EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
75     EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, WKT1_LATITUDE_OF_ORIGIN,
76     common::UnitOfMeasure::Type::ANGULAR, lat_0};
77 
78 static const ParamMapping paramLongitudeNatOrigin = {
79     EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN,
80     EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, WKT1_CENTRAL_MERIDIAN,
81     common::UnitOfMeasure::Type::ANGULAR, lon_0};
82 
83 static const ParamMapping paramScaleFactor = {
84     EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN,
85     EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, WKT1_SCALE_FACTOR,
86     common::UnitOfMeasure::Type::SCALE, k_0};
87 
88 static const ParamMapping paramScaleFactorK = {
89     EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN,
90     EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, WKT1_SCALE_FACTOR,
91     common::UnitOfMeasure::Type::SCALE, k};
92 
93 static const ParamMapping paramFalseEasting = {
94     EPSG_NAME_PARAMETER_FALSE_EASTING, EPSG_CODE_PARAMETER_FALSE_EASTING,
95     WKT1_FALSE_EASTING, common::UnitOfMeasure::Type::LINEAR, x_0};
96 
97 static const ParamMapping paramFalseNorthing = {
98     EPSG_NAME_PARAMETER_FALSE_NORTHING, EPSG_CODE_PARAMETER_FALSE_NORTHING,
99     WKT1_FALSE_NORTHING, common::UnitOfMeasure::Type::LINEAR, y_0};
100 
101 static const ParamMapping paramLatitudeFalseOrigin = {
102     EPSG_NAME_PARAMETER_LATITUDE_FALSE_ORIGIN,
103     EPSG_CODE_PARAMETER_LATITUDE_FALSE_ORIGIN, WKT1_LATITUDE_OF_ORIGIN,
104     common::UnitOfMeasure::Type::ANGULAR, lat_0};
105 
106 static const ParamMapping paramLongitudeFalseOrigin = {
107     EPSG_NAME_PARAMETER_LONGITUDE_FALSE_ORIGIN,
108     EPSG_CODE_PARAMETER_LONGITUDE_FALSE_ORIGIN, WKT1_CENTRAL_MERIDIAN,
109     common::UnitOfMeasure::Type::ANGULAR, lon_0};
110 
111 static const ParamMapping paramFalseEastingOrigin = {
112     EPSG_NAME_PARAMETER_EASTING_FALSE_ORIGIN,
113     EPSG_CODE_PARAMETER_EASTING_FALSE_ORIGIN, WKT1_FALSE_EASTING,
114     common::UnitOfMeasure::Type::LINEAR, x_0};
115 
116 static const ParamMapping paramFalseNorthingOrigin = {
117     EPSG_NAME_PARAMETER_NORTHING_FALSE_ORIGIN,
118     EPSG_CODE_PARAMETER_NORTHING_FALSE_ORIGIN, WKT1_FALSE_NORTHING,
119     common::UnitOfMeasure::Type::LINEAR, y_0};
120 
121 static const ParamMapping paramLatitude1stStdParallel = {
122     EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL,
123     EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL, WKT1_STANDARD_PARALLEL_1,
124     common::UnitOfMeasure::Type::ANGULAR, lat_1};
125 
126 static const ParamMapping paramLatitude2ndStdParallel = {
127     EPSG_NAME_PARAMETER_LATITUDE_2ND_STD_PARALLEL,
128     EPSG_CODE_PARAMETER_LATITUDE_2ND_STD_PARALLEL, WKT1_STANDARD_PARALLEL_2,
129     common::UnitOfMeasure::Type::ANGULAR, lat_2};
130 
131 static const ParamMapping *const paramsNatOriginScale[] = {
132     &paramLatitudeNatOrigin, &paramLongitudeNatOrigin, &paramScaleFactor,
133     &paramFalseEasting,      &paramFalseNorthing,      nullptr};
134 
135 static const ParamMapping *const paramsNatOriginScaleK[] = {
136     &paramLatitudeNatOrigin, &paramLongitudeNatOrigin, &paramScaleFactorK,
137     &paramFalseEasting,      &paramFalseNorthing,      nullptr};
138 
139 static const ParamMapping paramLatFirstPoint = {
140     "Latitude of 1st point", 0, "Latitude_Of_1st_Point",
141     common::UnitOfMeasure::Type::ANGULAR, lat_1};
142 static const ParamMapping paramLongFirstPoint = {
143     "Longitude of 1st point", 0, "Longitude_Of_1st_Point",
144     common::UnitOfMeasure::Type::ANGULAR, lon_1};
145 static const ParamMapping paramLatSecondPoint = {
146     "Latitude of 2nd point", 0, "Latitude_Of_2nd_Point",
147     common::UnitOfMeasure::Type::ANGULAR, lat_2};
148 static const ParamMapping paramLongSecondPoint = {
149     "Longitude of 2nd point", 0, "Longitude_Of_2nd_Point",
150     common::UnitOfMeasure::Type::ANGULAR, lon_2};
151 
152 static const ParamMapping *const paramsTPEQD[] = {&paramLatFirstPoint,
153                                                   &paramLongFirstPoint,
154                                                   &paramLatSecondPoint,
155                                                   &paramLongSecondPoint,
156                                                   &paramFalseEasting,
157                                                   &paramFalseNorthing,
158                                                   nullptr};
159 
160 static const ParamMapping *const paramsTMG[] = {
161     &paramLatitudeFalseOrigin, &paramLongitudeFalseOrigin,
162     &paramFalseEastingOrigin, &paramFalseNorthingOrigin, nullptr};
163 
164 static const ParamMapping paramLatFalseOriginLatOfCenter = {
165     EPSG_NAME_PARAMETER_LATITUDE_FALSE_ORIGIN,
166     EPSG_CODE_PARAMETER_LATITUDE_FALSE_ORIGIN, WKT1_LATITUDE_OF_CENTER,
167     common::UnitOfMeasure::Type::ANGULAR, lat_0};
168 
169 static const ParamMapping paramLongFalseOriginLongOfCenter = {
170     EPSG_NAME_PARAMETER_LONGITUDE_FALSE_ORIGIN,
171     EPSG_CODE_PARAMETER_LONGITUDE_FALSE_ORIGIN, WKT1_LONGITUDE_OF_CENTER,
172     common::UnitOfMeasure::Type::ANGULAR, lon_0};
173 
174 static const ParamMapping *const paramsAEA[] = {
175     &paramLatFalseOriginLatOfCenter,
176     &paramLongFalseOriginLongOfCenter,
177     &paramLatitude1stStdParallel,
178     &paramLatitude2ndStdParallel,
179     &paramFalseEastingOrigin,
180     &paramFalseNorthingOrigin,
181     nullptr};
182 
183 static const ParamMapping *const paramsLCC2SP[] = {
184     &paramLatitudeFalseOrigin,
185     &paramLongitudeFalseOrigin,
186     &paramLatitude1stStdParallel,
187     &paramLatitude2ndStdParallel,
188     &paramFalseEastingOrigin,
189     &paramFalseNorthingOrigin,
190     nullptr,
191 };
192 
193 static const ParamMapping paramEllipsoidScaleFactor = {
194     EPSG_NAME_PARAMETER_ELLIPSOID_SCALE_FACTOR,
195     EPSG_CODE_PARAMETER_ELLIPSOID_SCALE_FACTOR, nullptr,
196     common::UnitOfMeasure::Type::SCALE, k_0};
197 
198 static const ParamMapping *const paramsLCC2SPMichigan[] = {
199     &paramLatitudeFalseOrigin,    &paramLongitudeFalseOrigin,
200     &paramLatitude1stStdParallel, &paramLatitude2ndStdParallel,
201     &paramFalseEastingOrigin,     &paramFalseNorthingOrigin,
202     &paramEllipsoidScaleFactor,   nullptr,
203 };
204 
205 static const ParamMapping paramLatNatLatCenter = {
206     EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
207     EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, WKT1_LATITUDE_OF_CENTER,
208     common::UnitOfMeasure::Type::ANGULAR, lat_0};
209 
210 static const ParamMapping paramLonNatLonCenter = {
211     EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN,
212     EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, WKT1_LONGITUDE_OF_CENTER,
213     common::UnitOfMeasure::Type::ANGULAR, lon_0};
214 
215 static const ParamMapping *const paramsAEQD[]{
216     &paramLatNatLatCenter, &paramLonNatLonCenter, &paramFalseEasting,
217     &paramFalseNorthing, nullptr};
218 
219 static const ParamMapping *const paramsNatOrigin[] = {
220     &paramLatitudeNatOrigin, &paramLongitudeNatOrigin, &paramFalseEasting,
221     &paramFalseNorthing, nullptr};
222 
223 static const ParamMapping paramLatNatOriginLat1 = {
224     EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
225     EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, WKT1_STANDARD_PARALLEL_1,
226     common::UnitOfMeasure::Type::ANGULAR, lat_1};
227 
228 static const ParamMapping *const paramsBonne[] = {
229     &paramLatNatOriginLat1, &paramLongitudeNatOrigin, &paramFalseEasting,
230     &paramFalseNorthing, nullptr};
231 
232 static const ParamMapping paramLat1stParallelLatTs = {
233     EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL,
234     EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL, WKT1_STANDARD_PARALLEL_1,
235     common::UnitOfMeasure::Type::ANGULAR, lat_ts};
236 
237 static const ParamMapping *const paramsCEA[] = {
238     &paramLat1stParallelLatTs, &paramLongitudeNatOrigin, &paramFalseEasting,
239     &paramFalseNorthing, nullptr};
240 
241 static const ParamMapping *const paramsEQDC[] = {&paramLatNatLatCenter,
242                                                  &paramLonNatLonCenter,
243                                                  &paramLatitude1stStdParallel,
244                                                  &paramLatitude2ndStdParallel,
245                                                  &paramFalseEasting,
246                                                  &paramFalseNorthing,
247                                                  nullptr};
248 
249 static const ParamMapping *const paramsLonNatOrigin[] = {
250     &paramLongitudeNatOrigin, &paramFalseEasting, &paramFalseNorthing, nullptr};
251 
252 static const ParamMapping *const paramsEqc[] = {
253     &paramLat1stParallelLatTs,
254     &paramLatitudeNatOrigin, // extension of EPSG, but used by GDAL / PROJ
255     &paramLongitudeNatOrigin,  &paramFalseEasting,
256     &paramFalseNorthing,       nullptr};
257 
258 static const ParamMapping paramSatelliteHeight = {
259     "Satellite Height", 0, "satellite_height",
260     common::UnitOfMeasure::Type::LINEAR, h};
261 
262 static const ParamMapping *const paramsGeos[] = {
263     &paramLongitudeNatOrigin, &paramSatelliteHeight, &paramFalseEasting,
264     &paramFalseNorthing, nullptr};
265 
266 static const ParamMapping paramLatCentreLatCenter = {
267     EPSG_NAME_PARAMETER_LATITUDE_PROJECTION_CENTRE,
268     EPSG_CODE_PARAMETER_LATITUDE_PROJECTION_CENTRE, WKT1_LATITUDE_OF_CENTER,
269     common::UnitOfMeasure::Type::ANGULAR, lat_0};
270 
271 static const ParamMapping paramLonCentreLonCenterLonc = {
272     EPSG_NAME_PARAMETER_LONGITUDE_PROJECTION_CENTRE,
273     EPSG_CODE_PARAMETER_LONGITUDE_PROJECTION_CENTRE, WKT1_LONGITUDE_OF_CENTER,
274     common::UnitOfMeasure::Type::ANGULAR, lonc};
275 
276 static const ParamMapping paramAzimuth = {
277     EPSG_NAME_PARAMETER_AZIMUTH_INITIAL_LINE,
278     EPSG_CODE_PARAMETER_AZIMUTH_INITIAL_LINE, WKT1_AZIMUTH,
279     common::UnitOfMeasure::Type::ANGULAR, alpha};
280 
281 static const ParamMapping paramAngleToSkewGrid = {
282     EPSG_NAME_PARAMETER_ANGLE_RECTIFIED_TO_SKEW_GRID,
283     EPSG_CODE_PARAMETER_ANGLE_RECTIFIED_TO_SKEW_GRID, WKT1_RECTIFIED_GRID_ANGLE,
284     common::UnitOfMeasure::Type::ANGULAR, gamma};
285 static const ParamMapping paramScaleFactorInitialLine = {
286     EPSG_NAME_PARAMETER_SCALE_FACTOR_INITIAL_LINE,
287     EPSG_CODE_PARAMETER_SCALE_FACTOR_INITIAL_LINE, WKT1_SCALE_FACTOR,
288     common::UnitOfMeasure::Type::SCALE, k};
289 
290 static const ParamMapping *const paramsHomVariantA[] = {
291     &paramLatCentreLatCenter,
292     &paramLonCentreLonCenterLonc,
293     &paramAzimuth,
294     &paramAngleToSkewGrid,
295     &paramScaleFactorInitialLine,
296     &paramFalseEasting,
297     &paramFalseNorthing,
298     nullptr};
299 
300 static const ParamMapping paramFalseEastingProjectionCentre = {
301     EPSG_NAME_PARAMETER_EASTING_PROJECTION_CENTRE,
302     EPSG_CODE_PARAMETER_EASTING_PROJECTION_CENTRE, WKT1_FALSE_EASTING,
303     common::UnitOfMeasure::Type::LINEAR, x_0};
304 
305 static const ParamMapping paramFalseNorthingProjectionCentre = {
306     EPSG_NAME_PARAMETER_NORTHING_PROJECTION_CENTRE,
307     EPSG_CODE_PARAMETER_NORTHING_PROJECTION_CENTRE, WKT1_FALSE_NORTHING,
308     common::UnitOfMeasure::Type::LINEAR, y_0};
309 
310 static const ParamMapping *const paramsHomVariantB[] = {
311     &paramLatCentreLatCenter,
312     &paramLonCentreLonCenterLonc,
313     &paramAzimuth,
314     &paramAngleToSkewGrid,
315     &paramScaleFactorInitialLine,
316     &paramFalseEastingProjectionCentre,
317     &paramFalseNorthingProjectionCentre,
318     nullptr};
319 
320 static const ParamMapping paramLatPoint1 = {
321     "Latitude of 1st point", 0, "latitude_of_point_1",
322     common::UnitOfMeasure::Type::ANGULAR, lat_1};
323 
324 static const ParamMapping paramLonPoint1 = {
325     "Longitude of 1st point", 0, "longitude_of_point_1",
326     common::UnitOfMeasure::Type::ANGULAR, lon_1};
327 
328 static const ParamMapping paramLatPoint2 = {
329     "Latitude of 2nd point", 0, "latitude_of_point_2",
330     common::UnitOfMeasure::Type::ANGULAR, lat_2};
331 
332 static const ParamMapping paramLonPoint2 = {
333     "Longitude of 2nd point", 0, "longitude_of_point_2",
334     common::UnitOfMeasure::Type::ANGULAR, lon_2};
335 
336 static const ParamMapping *const paramsHomTwoPoint[] = {
337     &paramLatCentreLatCenter,
338     &paramLatPoint1,
339     &paramLonPoint1,
340     &paramLatPoint2,
341     &paramLonPoint2,
342     &paramScaleFactorInitialLine,
343     &paramFalseEastingProjectionCentre,
344     &paramFalseNorthingProjectionCentre,
345     nullptr};
346 
347 static const ParamMapping *const paramsIMWP[] = {
348     &paramLongitudeNatOrigin, &paramLatFirstPoint, &paramLatSecondPoint,
349     &paramFalseEasting,       &paramFalseNorthing, nullptr};
350 
351 static const ParamMapping paramLonCentreLonCenter = {
352     EPSG_NAME_PARAMETER_LONGITUDE_OF_ORIGIN,
353     EPSG_CODE_PARAMETER_LONGITUDE_OF_ORIGIN, WKT1_LONGITUDE_OF_CENTER,
354     common::UnitOfMeasure::Type::ANGULAR, lon_0};
355 
356 static const ParamMapping paramColatitudeConeAxis = {
357     EPSG_NAME_PARAMETER_COLATITUDE_CONE_AXIS,
358     EPSG_CODE_PARAMETER_COLATITUDE_CONE_AXIS, WKT1_AZIMUTH,
359     common::UnitOfMeasure::Type::ANGULAR,
360     "alpha"}; /* ignored by PROJ currently */
361 
362 static const ParamMapping paramLatitudePseudoStdParallel = {
363     EPSG_NAME_PARAMETER_LATITUDE_PSEUDO_STANDARD_PARALLEL,
364     EPSG_CODE_PARAMETER_LATITUDE_PSEUDO_STANDARD_PARALLEL,
365     "pseudo_standard_parallel_1", common::UnitOfMeasure::Type::ANGULAR,
366     nullptr}; /* ignored by PROJ currently */
367 
368 static const ParamMapping paramScaleFactorPseudoStdParallel = {
369     EPSG_NAME_PARAMETER_SCALE_FACTOR_PSEUDO_STANDARD_PARALLEL,
370     EPSG_CODE_PARAMETER_SCALE_FACTOR_PSEUDO_STANDARD_PARALLEL,
371     WKT1_SCALE_FACTOR, common::UnitOfMeasure::Type::SCALE,
372     k}; /* ignored by PROJ currently */
373 
374 static const ParamMapping *const krovakParameters[] = {
375     &paramLatCentreLatCenter,
376     &paramLonCentreLonCenter,
377     &paramColatitudeConeAxis,
378     &paramLatitudePseudoStdParallel,
379     &paramScaleFactorPseudoStdParallel,
380     &paramFalseEasting,
381     &paramFalseNorthing,
382     nullptr};
383 
384 static const ParamMapping *const paramsLaea[] = {
385     &paramLatNatLatCenter, &paramLonNatLonCenter, &paramFalseEasting,
386     &paramFalseNorthing, nullptr};
387 
388 static const ParamMapping *const paramsMiller[] = {
389     &paramLonNatLonCenter, &paramFalseEasting, &paramFalseNorthing, nullptr};
390 
391 static const ParamMapping paramLatMerc1SP = {
392     EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
393     EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
394     nullptr, // always set to zero, not to be exported in WKT1
395     common::UnitOfMeasure::Type::ANGULAR,
396     nullptr}; // always set to zero, not to be exported in PROJ strings
397 
398 static const ParamMapping *const paramsMerc1SP[] = {
399     &paramLatMerc1SP,   &paramLongitudeNatOrigin, &paramScaleFactorK,
400     &paramFalseEasting, &paramFalseNorthing,      nullptr};
401 
402 static const ParamMapping *const paramsMerc2SP[] = {
403     &paramLat1stParallelLatTs, &paramLongitudeNatOrigin, &paramFalseEasting,
404     &paramFalseNorthing, nullptr};
405 
406 static const ParamMapping *const paramsObliqueStereo[] = {
407     &paramLatitudeNatOrigin, &paramLongitudeNatOrigin, &paramScaleFactorK,
408     &paramFalseEasting,      &paramFalseNorthing,      nullptr};
409 
410 static const ParamMapping paramLatStdParallel = {
411     EPSG_NAME_PARAMETER_LATITUDE_STD_PARALLEL,
412     EPSG_CODE_PARAMETER_LATITUDE_STD_PARALLEL, WKT1_LATITUDE_OF_ORIGIN,
413     common::UnitOfMeasure::Type::ANGULAR, lat_ts};
414 
415 static const ParamMapping paramsLonOrigin = {
416     EPSG_NAME_PARAMETER_LONGITUDE_OF_ORIGIN,
417     EPSG_CODE_PARAMETER_LONGITUDE_OF_ORIGIN, WKT1_CENTRAL_MERIDIAN,
418     common::UnitOfMeasure::Type::ANGULAR, lon_0};
419 
420 static const ParamMapping *const paramsPolarStereo[] = {
421     &paramLatStdParallel, &paramsLonOrigin, &paramFalseEasting,
422     &paramFalseNorthing, nullptr};
423 
424 static const ParamMapping *const paramsLonNatOriginLongitudeCentre[] = {
425     &paramLonNatLonCenter, &paramFalseEasting, &paramFalseNorthing, nullptr};
426 
427 static const ParamMapping paramLatTrueScaleWag3 = {
428     "Latitude of true scale", 0, WKT1_LATITUDE_OF_ORIGIN,
429     common::UnitOfMeasure::Type::ANGULAR, lat_ts};
430 
431 static const ParamMapping *const paramsWag3[] = {
432     &paramLatTrueScaleWag3, &paramLongitudeNatOrigin, &paramFalseEasting,
433     &paramFalseNorthing, nullptr};
434 
435 static const ParamMapping paramPegLat = {
436     "Peg point latitude", 0, "peg_point_latitude",
437     common::UnitOfMeasure::Type::ANGULAR, "plat_0"};
438 
439 static const ParamMapping paramPegLon = {
440     "Peg point longitude", 0, "peg_point_longitude",
441     common::UnitOfMeasure::Type::ANGULAR, "plon_0"};
442 
443 static const ParamMapping paramPegHeading = {
444     "Peg point heading", 0, "peg_point_heading",
445     common::UnitOfMeasure::Type::ANGULAR, "phdg_0"};
446 
447 static const ParamMapping paramPegHeight = {
448     "Peg point height", 0, "peg_point_height",
449     common::UnitOfMeasure::Type::LINEAR, "h_0"};
450 
451 static const ParamMapping *const paramsSch[] = {
452     &paramPegLat, &paramPegLon, &paramPegHeading, &paramPegHeight, nullptr};
453 
454 static const ParamMapping *const paramsWink1[] = {
455     &paramLongitudeNatOrigin, &paramLat1stParallelLatTs, &paramFalseEasting,
456     &paramFalseNorthing, nullptr};
457 
458 static const ParamMapping *const paramsWink2[] = {
459     &paramLongitudeNatOrigin, &paramLatitude1stStdParallel, &paramFalseEasting,
460     &paramFalseNorthing, nullptr};
461 
462 static const ParamMapping paramLatLoxim = {
463     EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
464     EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, WKT1_LATITUDE_OF_ORIGIN,
465     common::UnitOfMeasure::Type::ANGULAR, lat_1};
466 
467 static const ParamMapping *const paramsLoxim[] = {
468     &paramLatLoxim, &paramLongitudeNatOrigin, &paramFalseEasting,
469     &paramFalseNorthing, nullptr};
470 
471 static const ParamMapping paramLonCentre = {
472     EPSG_NAME_PARAMETER_LONGITUDE_PROJECTION_CENTRE,
473     EPSG_CODE_PARAMETER_LONGITUDE_PROJECTION_CENTRE, WKT1_LONGITUDE_OF_CENTER,
474     common::UnitOfMeasure::Type::ANGULAR, lon_0};
475 
476 static const ParamMapping paramLabordeObliqueMercatorAzimuth = {
477     EPSG_NAME_PARAMETER_AZIMUTH_INITIAL_LINE,
478     EPSG_CODE_PARAMETER_AZIMUTH_INITIAL_LINE, WKT1_AZIMUTH,
479     common::UnitOfMeasure::Type::ANGULAR, "azi"};
480 
481 static const ParamMapping *const paramsLabordeObliqueMercator[] = {
482     &paramLatCentreLatCenter,
483     &paramLonCentre,
484     &paramLabordeObliqueMercatorAzimuth,
485     &paramScaleFactorInitialLine,
486     &paramFalseEasting,
487     &paramFalseNorthing,
488     nullptr};
489 
490 static const ParamMapping paramLatTopoOrigin = {
491     EPSG_NAME_PARAMETER_LATITUDE_TOPOGRAPHIC_ORIGIN,
492     EPSG_CODE_PARAMETER_LATITUDE_TOPOGRAPHIC_ORIGIN, nullptr,
493     common::UnitOfMeasure::Type::ANGULAR, lat_0};
494 
495 static const ParamMapping paramLonTopoOrigin = {
496     EPSG_NAME_PARAMETER_LONGITUDE_TOPOGRAPHIC_ORIGIN,
497     EPSG_CODE_PARAMETER_LONGITUDE_TOPOGRAPHIC_ORIGIN, nullptr,
498     common::UnitOfMeasure::Type::ANGULAR, lon_0};
499 
500 static const ParamMapping paramHeightTopoOrigin = {
501     EPSG_NAME_PARAMETER_ELLIPSOIDAL_HEIGHT_TOPOCENTRIC_ORIGIN,
502     EPSG_CODE_PARAMETER_ELLIPSOIDAL_HEIGHT_TOPOCENTRIC_ORIGIN, nullptr,
503     common::UnitOfMeasure::Type::LINEAR,
504     nullptr}; // unsupported by PROJ right now
505 
506 static const ParamMapping paramViewpointHeight = {
507     EPSG_NAME_PARAMETER_VIEWPOINT_HEIGHT, EPSG_CODE_PARAMETER_VIEWPOINT_HEIGHT,
508     nullptr, common::UnitOfMeasure::Type::LINEAR, "h"};
509 
510 static const ParamMapping *const paramsVerticalPerspective[] = {
511     &paramLatTopoOrigin,
512     &paramLonTopoOrigin,
513     &paramHeightTopoOrigin, // unsupported by PROJ right now
514     &paramViewpointHeight,
515     &paramFalseEasting,  // PROJ addition
516     &paramFalseNorthing, // PROJ addition
517     nullptr};
518 
519 static const ParamMapping paramProjectionPlaneOriginHeight = {
520     EPSG_NAME_PARAMETER_PROJECTION_PLANE_ORIGIN_HEIGHT,
521     EPSG_CODE_PARAMETER_PROJECTION_PLANE_ORIGIN_HEIGHT, nullptr,
522     common::UnitOfMeasure::Type::LINEAR, "h_0"};
523 
524 static const ParamMapping *const paramsColombiaUrban[] = {
525     &paramLatitudeNatOrigin,
526     &paramLongitudeNatOrigin,
527     &paramFalseEasting,
528     &paramFalseNorthing,
529     &paramProjectionPlaneOriginHeight,
530     nullptr};
531 
532 static const MethodMapping projectionMethodMappings[] = {
533     {EPSG_NAME_METHOD_TRANSVERSE_MERCATOR, EPSG_CODE_METHOD_TRANSVERSE_MERCATOR,
534      "Transverse_Mercator", "tmerc", nullptr, paramsNatOriginScaleK},
535 
536     {EPSG_NAME_METHOD_TRANSVERSE_MERCATOR_SOUTH_ORIENTATED,
537      EPSG_CODE_METHOD_TRANSVERSE_MERCATOR_SOUTH_ORIENTATED,
538      "Transverse_Mercator_South_Orientated", "tmerc", "axis=wsu",
539      paramsNatOriginScaleK},
540 
541     {PROJ_WKT2_NAME_METHOD_TWO_POINT_EQUIDISTANT, 0, "Two_Point_Equidistant",
542      "tpeqd", nullptr, paramsTPEQD},
543 
544     {EPSG_NAME_METHOD_TUNISIA_MAPPING_GRID,
545      EPSG_CODE_METHOD_TUNISIA_MAPPING_GRID, "Tunisia_Mapping_Grid", nullptr,
546      nullptr, // no proj equivalent
547      paramsTMG},
548 
549     {EPSG_NAME_METHOD_ALBERS_EQUAL_AREA, EPSG_CODE_METHOD_ALBERS_EQUAL_AREA,
550      "Albers_Conic_Equal_Area", "aea", nullptr, paramsAEA},
551 
552     {EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_1SP,
553      EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP,
554      "Lambert_Conformal_Conic_1SP", "lcc", nullptr,
__anonf1886f500102() 555      []() {
556          static const ParamMapping paramLatLCC1SP = {
557              EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
558              EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
559              WKT1_LATITUDE_OF_ORIGIN, common::UnitOfMeasure::Type::ANGULAR,
560              lat_1};
561 
562          static const ParamMapping *const x[] = {
563              &paramLatLCC1SP,    &paramLongitudeNatOrigin, &paramScaleFactor,
564              &paramFalseEasting, &paramFalseNorthing,      nullptr,
565          };
566          return x;
567      }()},
568 
569     {EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_2SP,
570      EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP,
571      "Lambert_Conformal_Conic_2SP", "lcc", nullptr, paramsLCC2SP},
572 
573     // Oracle WKT
574     {EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_2SP,
575      EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP, "Lambert Conformal Conic",
576      "lcc", nullptr, paramsLCC2SP},
577 
578     {EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_2SP_MICHIGAN,
579      EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP_MICHIGAN,
580      nullptr, // no mapping to WKT1_GDAL
581      "lcc", nullptr, paramsLCC2SPMichigan},
582 
583     {EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_2SP_BELGIUM,
584      EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP_BELGIUM,
585      "Lambert_Conformal_Conic_2SP_Belgium", "lcc",
586      nullptr, // FIXME: this is what is done in GDAL, but the formula of
587               // LCC 2SP
588      // Belgium in the EPSG 7.2 guidance is difference from the regular
589      // LCC 2SP
590      paramsLCC2SP},
591 
592     {EPSG_NAME_METHOD_MODIFIED_AZIMUTHAL_EQUIDISTANT,
593      EPSG_CODE_METHOD_MODIFIED_AZIMUTHAL_EQUIDISTANT, "Azimuthal_Equidistant",
594      "aeqd", nullptr, paramsAEQD},
595 
596     {EPSG_NAME_METHOD_GUAM_PROJECTION, EPSG_CODE_METHOD_GUAM_PROJECTION,
597      nullptr, // no mapping to GDAL WKT1
598      "aeqd", "guam", paramsNatOrigin},
599 
600     {EPSG_NAME_METHOD_BONNE, EPSG_CODE_METHOD_BONNE, "Bonne", "bonne", nullptr,
601      paramsBonne},
602 
603     {PROJ_WKT2_NAME_METHOD_COMPACT_MILLER, 0, "Compact_Miller", "comill",
604      nullptr, paramsLonNatOrigin},
605 
606     {EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL,
607      EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL,
608      "Cylindrical_Equal_Area", "cea", nullptr, paramsCEA},
609 
610     {EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA,
611      EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA, "Cylindrical_Equal_Area",
612      "cea", nullptr, paramsCEA},
613 
614     {EPSG_NAME_METHOD_CASSINI_SOLDNER, EPSG_CODE_METHOD_CASSINI_SOLDNER,
615      "Cassini_Soldner", "cass", nullptr, paramsNatOrigin},
616 
617     {PROJ_WKT2_NAME_METHOD_EQUIDISTANT_CONIC, 0, "Equidistant_Conic", "eqdc",
618      nullptr, paramsEQDC},
619 
620     {PROJ_WKT2_NAME_METHOD_ECKERT_I, 0, "Eckert_I", "eck1", nullptr,
621      paramsLonNatOrigin},
622 
623     {PROJ_WKT2_NAME_METHOD_ECKERT_II, 0, "Eckert_II", "eck2", nullptr,
624      paramsLonNatOrigin},
625 
626     {PROJ_WKT2_NAME_METHOD_ECKERT_III, 0, "Eckert_III", "eck3", nullptr,
627      paramsLonNatOrigin},
628 
629     {PROJ_WKT2_NAME_METHOD_ECKERT_IV, 0, "Eckert_IV", "eck4", nullptr,
630      paramsLonNatOrigin},
631 
632     {PROJ_WKT2_NAME_METHOD_ECKERT_V, 0, "Eckert_V", "eck5", nullptr,
633      paramsLonNatOrigin},
634 
635     {PROJ_WKT2_NAME_METHOD_ECKERT_VI, 0, "Eckert_VI", "eck6", nullptr,
636      paramsLonNatOrigin},
637 
638     {EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL,
639      EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL, "Equirectangular", "eqc",
640      nullptr, paramsEqc},
641 
642     {EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL_SPHERICAL,
643      EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL_SPHERICAL, "Equirectangular",
644      "eqc", nullptr, paramsEqc},
645 
646     {PROJ_WKT2_NAME_METHOD_FLAT_POLAR_QUARTIC, 0, "Flat_Polar_Quartic",
647      "mbtfpq", nullptr, paramsLonNatOrigin},
648 
649     {PROJ_WKT2_NAME_METHOD_GALL_STEREOGRAPHIC, 0, "Gall_Stereographic", "gall",
650      nullptr, paramsLonNatOrigin},
651 
652     {PROJ_WKT2_NAME_METHOD_GOODE_HOMOLOSINE, 0, "Goode_Homolosine", "goode",
653      nullptr, paramsLonNatOrigin},
654 
655     {PROJ_WKT2_NAME_METHOD_INTERRUPTED_GOODE_HOMOLOSINE, 0,
656      "Interrupted_Goode_Homolosine", "igh", nullptr, paramsLonNatOrigin},
657 
658     {PROJ_WKT2_NAME_METHOD_INTERRUPTED_GOODE_HOMOLOSINE_OCEAN, 0, nullptr,
659      "igh_o", nullptr, paramsLonNatOrigin},
660 
661     // No proper WKT1 representation fr sweep=x
662     {PROJ_WKT2_NAME_METHOD_GEOSTATIONARY_SATELLITE_SWEEP_X, 0, nullptr, "geos",
663      "sweep=x", paramsGeos},
664 
665     {PROJ_WKT2_NAME_METHOD_GEOSTATIONARY_SATELLITE_SWEEP_Y, 0,
666      "Geostationary_Satellite", "geos", nullptr, paramsGeos},
667 
668     {PROJ_WKT2_NAME_METHOD_GAUSS_SCHREIBER_TRANSVERSE_MERCATOR, 0,
669      "Gauss_Schreiber_Transverse_Mercator", "gstmerc", nullptr,
670      paramsNatOriginScale},
671 
672     {PROJ_WKT2_NAME_METHOD_GNOMONIC, 0, "Gnomonic", "gnom", nullptr,
673      paramsNatOrigin},
674 
675     {EPSG_NAME_METHOD_HOTINE_OBLIQUE_MERCATOR_VARIANT_A,
676      EPSG_CODE_METHOD_HOTINE_OBLIQUE_MERCATOR_VARIANT_A,
677      "Hotine_Oblique_Mercator", "omerc", "no_uoff", paramsHomVariantA},
678 
679     {EPSG_NAME_METHOD_HOTINE_OBLIQUE_MERCATOR_VARIANT_B,
680      EPSG_CODE_METHOD_HOTINE_OBLIQUE_MERCATOR_VARIANT_B,
681      "Hotine_Oblique_Mercator_Azimuth_Center", "omerc", nullptr,
682      paramsHomVariantB},
683 
684     {PROJ_WKT2_NAME_METHOD_HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN, 0,
685      "Hotine_Oblique_Mercator_Two_Point_Natural_Origin", "omerc", nullptr,
686      paramsHomTwoPoint},
687 
688     {PROJ_WKT2_NAME_INTERNATIONAL_MAP_WORLD_POLYCONIC, 0,
689      "International_Map_of_the_World_Polyconic", "imw_p", nullptr, paramsIMWP},
690 
691     {EPSG_NAME_METHOD_KROVAK_NORTH_ORIENTED,
692      EPSG_CODE_METHOD_KROVAK_NORTH_ORIENTED, "Krovak", "krovak", nullptr,
693      krovakParameters},
694 
695     {EPSG_NAME_METHOD_KROVAK, EPSG_CODE_METHOD_KROVAK, "Krovak", "krovak",
696      "axis=swu", krovakParameters},
697 
698     {EPSG_NAME_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA,
699      EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA,
700      "Lambert_Azimuthal_Equal_Area", "laea", nullptr, paramsLaea},
701 
702     {EPSG_NAME_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA_SPHERICAL,
703      EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA_SPHERICAL,
704      "Lambert_Azimuthal_Equal_Area", "laea", nullptr, paramsLaea},
705 
706     {PROJ_WKT2_NAME_METHOD_MILLER_CYLINDRICAL, 0, "Miller_Cylindrical", "mill",
707      "R_A", paramsMiller},
708 
709     {EPSG_NAME_METHOD_MERCATOR_VARIANT_A, EPSG_CODE_METHOD_MERCATOR_VARIANT_A,
710      "Mercator_1SP", "merc", nullptr, paramsMerc1SP},
711 
712     {EPSG_NAME_METHOD_MERCATOR_VARIANT_B, EPSG_CODE_METHOD_MERCATOR_VARIANT_B,
713      "Mercator_2SP", "merc", nullptr, paramsMerc2SP},
714 
715     {EPSG_NAME_METHOD_POPULAR_VISUALISATION_PSEUDO_MERCATOR,
716      EPSG_CODE_METHOD_POPULAR_VISUALISATION_PSEUDO_MERCATOR,
717      "Popular_Visualisation_Pseudo_Mercator", // particular case actually
718                                               // handled manually
719      "webmerc", nullptr, paramsNatOrigin},
720 
721     {PROJ_WKT2_NAME_METHOD_MOLLWEIDE, 0, "Mollweide", "moll", nullptr,
722      paramsLonNatOrigin},
723 
724     {PROJ_WKT2_NAME_METHOD_NATURAL_EARTH, 0, "Natural_Earth", "natearth",
725      nullptr, paramsLonNatOrigin},
726 
727     {PROJ_WKT2_NAME_METHOD_NATURAL_EARTH_II, 0, "Natural_Earth_II", "natearth2",
728      nullptr, paramsLonNatOrigin},
729 
730     {EPSG_NAME_METHOD_NZMG, EPSG_CODE_METHOD_NZMG, "New_Zealand_Map_Grid",
731      "nzmg", nullptr, paramsNatOrigin},
732 
733     {
734         EPSG_NAME_METHOD_OBLIQUE_STEREOGRAPHIC,
735         EPSG_CODE_METHOD_OBLIQUE_STEREOGRAPHIC, "Oblique_Stereographic",
736         "sterea", nullptr, paramsObliqueStereo,
737     },
738 
739     {EPSG_NAME_METHOD_ORTHOGRAPHIC, EPSG_CODE_METHOD_ORTHOGRAPHIC,
740      "Orthographic", "ortho", nullptr, paramsNatOrigin},
741 
742     {PROJ_WKT2_NAME_ORTHOGRAPHIC_SPHERICAL, 0, "Orthographic", "ortho", "f=0",
743      paramsNatOrigin},
744 
745     {PROJ_WKT2_NAME_METHOD_PATTERSON, 0, "Patterson", "patterson", nullptr,
746      paramsLonNatOrigin},
747 
748     {EPSG_NAME_METHOD_AMERICAN_POLYCONIC, EPSG_CODE_METHOD_AMERICAN_POLYCONIC,
749      "Polyconic", "poly", nullptr, paramsNatOrigin},
750 
751     {EPSG_NAME_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A,
752      EPSG_CODE_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A, "Polar_Stereographic",
753      "stere", nullptr, paramsObliqueStereo},
754 
755     {EPSG_NAME_METHOD_POLAR_STEREOGRAPHIC_VARIANT_B,
756      EPSG_CODE_METHOD_POLAR_STEREOGRAPHIC_VARIANT_B, "Polar_Stereographic",
757      "stere", nullptr, paramsPolarStereo},
758 
759     {PROJ_WKT2_NAME_METHOD_ROBINSON, 0, "Robinson", "robin", nullptr,
760      paramsLonNatOriginLongitudeCentre},
761 
762     {PROJ_WKT2_NAME_METHOD_SINUSOIDAL, 0, "Sinusoidal", "sinu", nullptr,
763      paramsLonNatOriginLongitudeCentre},
764 
765     {PROJ_WKT2_NAME_METHOD_STEREOGRAPHIC, 0, "Stereographic", "stere", nullptr,
766      paramsObliqueStereo},
767 
768     {PROJ_WKT2_NAME_METHOD_TIMES, 0, "Times", "times", nullptr,
769      paramsLonNatOrigin},
770 
771     {PROJ_WKT2_NAME_METHOD_VAN_DER_GRINTEN, 0, "VanDerGrinten", "vandg", "R_A",
772      paramsLonNatOrigin},
773 
774     {PROJ_WKT2_NAME_METHOD_WAGNER_I, 0, "Wagner_I", "wag1", nullptr,
775      paramsLonNatOrigin},
776 
777     {PROJ_WKT2_NAME_METHOD_WAGNER_II, 0, "Wagner_II", "wag2", nullptr,
778      paramsLonNatOrigin},
779 
780     {PROJ_WKT2_NAME_METHOD_WAGNER_III, 0, "Wagner_III", "wag3", nullptr,
781      paramsWag3},
782 
783     {PROJ_WKT2_NAME_METHOD_WAGNER_IV, 0, "Wagner_IV", "wag4", nullptr,
784      paramsLonNatOrigin},
785 
786     {PROJ_WKT2_NAME_METHOD_WAGNER_V, 0, "Wagner_V", "wag5", nullptr,
787      paramsLonNatOrigin},
788 
789     {PROJ_WKT2_NAME_METHOD_WAGNER_VI, 0, "Wagner_VI", "wag6", nullptr,
790      paramsLonNatOrigin},
791 
792     {PROJ_WKT2_NAME_METHOD_WAGNER_VII, 0, "Wagner_VII", "wag7", nullptr,
793      paramsLonNatOrigin},
794 
795     {PROJ_WKT2_NAME_METHOD_QUADRILATERALIZED_SPHERICAL_CUBE, 0,
796      "Quadrilateralized_Spherical_Cube", "qsc", nullptr, paramsNatOrigin},
797 
798     {PROJ_WKT2_NAME_METHOD_SPHERICAL_CROSS_TRACK_HEIGHT, 0,
799      "Spherical_Cross_Track_Height", "sch", nullptr, paramsSch},
800 
801     // The following methods have just the WKT <--> PROJ string mapping, but
802     // no setter. Similarly to GDAL
803 
804     {"Aitoff", 0, "Aitoff", "aitoff", nullptr, paramsLonNatOrigin},
805 
806     {"Winkel I", 0, "Winkel_I", "wink1", nullptr, paramsWink1},
807 
808     {"Winkel II", 0, "Winkel_II", "wink2", nullptr, paramsWink2},
809 
810     {"Winkel Tripel", 0, "Winkel_Tripel", "wintri", nullptr, paramsWink2},
811 
812     {"Craster Parabolic", 0, "Craster_Parabolic", "crast", nullptr,
813      paramsLonNatOrigin},
814 
815     {"Loximuthal", 0, "Loximuthal", "loxim", nullptr, paramsLoxim},
816 
817     {"Quartic Authalic", 0, "Quartic_Authalic", "qua_aut", nullptr,
818      paramsLonNatOrigin},
819 
820     {"Transverse Cylindrical Equal Area", 0,
821      "Transverse_Cylindrical_Equal_Area", "tcea", nullptr, paramsObliqueStereo},
822 
823     {EPSG_NAME_METHOD_EQUAL_EARTH, EPSG_CODE_METHOD_EQUAL_EARTH, nullptr,
824      "eqearth", nullptr, paramsLonNatOrigin},
825 
826     {EPSG_NAME_METHOD_LABORDE_OBLIQUE_MERCATOR,
827      EPSG_CODE_METHOD_LABORDE_OBLIQUE_MERCATOR, "Laborde_Oblique_Mercator",
828      "labrd", nullptr, paramsLabordeObliqueMercator},
829 
830     {EPSG_NAME_METHOD_VERTICAL_PERSPECTIVE,
831      EPSG_CODE_METHOD_VERTICAL_PERSPECTIVE, nullptr, "nsper", nullptr,
832      paramsVerticalPerspective},
833 
834     {EPSG_NAME_METHOD_COLOMBIA_URBAN, EPSG_CODE_METHOD_COLOMBIA_URBAN, nullptr,
835      "col_urban", nullptr, paramsColombiaUrban},
836 };
837 
getProjectionMethodMappings(size_t & nElts)838 const MethodMapping *getProjectionMethodMappings(size_t &nElts) {
839     nElts =
840         sizeof(projectionMethodMappings) / sizeof(projectionMethodMappings[0]);
841     return projectionMethodMappings;
842 }
843 
844 #define METHOD_NAME_CODE(method)                                               \
845     { EPSG_NAME_METHOD_##method, EPSG_CODE_METHOD_##method }
846 
847 const struct MethodNameCode methodNameCodes[] = {
848     // Projection methods
849     METHOD_NAME_CODE(TRANSVERSE_MERCATOR),
850     METHOD_NAME_CODE(TRANSVERSE_MERCATOR_SOUTH_ORIENTATED),
851     METHOD_NAME_CODE(LAMBERT_CONIC_CONFORMAL_1SP), METHOD_NAME_CODE(NZMG),
852     METHOD_NAME_CODE(TUNISIA_MAPPING_GRID), METHOD_NAME_CODE(ALBERS_EQUAL_AREA),
853     METHOD_NAME_CODE(LAMBERT_CONIC_CONFORMAL_2SP),
854     METHOD_NAME_CODE(LAMBERT_CONIC_CONFORMAL_2SP_BELGIUM),
855     METHOD_NAME_CODE(LAMBERT_CONIC_CONFORMAL_2SP_MICHIGAN),
856     METHOD_NAME_CODE(MODIFIED_AZIMUTHAL_EQUIDISTANT),
857     METHOD_NAME_CODE(GUAM_PROJECTION), METHOD_NAME_CODE(BONNE),
858     METHOD_NAME_CODE(LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL),
859     METHOD_NAME_CODE(LAMBERT_CYLINDRICAL_EQUAL_AREA),
860     METHOD_NAME_CODE(CASSINI_SOLDNER),
861     METHOD_NAME_CODE(EQUIDISTANT_CYLINDRICAL),
862     METHOD_NAME_CODE(EQUIDISTANT_CYLINDRICAL_SPHERICAL),
863     METHOD_NAME_CODE(HOTINE_OBLIQUE_MERCATOR_VARIANT_A),
864     METHOD_NAME_CODE(HOTINE_OBLIQUE_MERCATOR_VARIANT_B),
865     METHOD_NAME_CODE(KROVAK_NORTH_ORIENTED), METHOD_NAME_CODE(KROVAK),
866     METHOD_NAME_CODE(LAMBERT_AZIMUTHAL_EQUAL_AREA),
867     METHOD_NAME_CODE(POPULAR_VISUALISATION_PSEUDO_MERCATOR),
868     METHOD_NAME_CODE(MERCATOR_VARIANT_A), METHOD_NAME_CODE(MERCATOR_VARIANT_B),
869     METHOD_NAME_CODE(OBLIQUE_STEREOGRAPHIC),
870     METHOD_NAME_CODE(AMERICAN_POLYCONIC),
871     METHOD_NAME_CODE(POLAR_STEREOGRAPHIC_VARIANT_A),
872     METHOD_NAME_CODE(POLAR_STEREOGRAPHIC_VARIANT_B),
873     METHOD_NAME_CODE(EQUAL_EARTH), METHOD_NAME_CODE(LABORDE_OBLIQUE_MERCATOR),
874     METHOD_NAME_CODE(VERTICAL_PERSPECTIVE), METHOD_NAME_CODE(COLOMBIA_URBAN),
875     // Other conversions
876     METHOD_NAME_CODE(CHANGE_VERTICAL_UNIT),
877     METHOD_NAME_CODE(HEIGHT_DEPTH_REVERSAL),
878     METHOD_NAME_CODE(AXIS_ORDER_REVERSAL_2D),
879     METHOD_NAME_CODE(AXIS_ORDER_REVERSAL_3D),
880     METHOD_NAME_CODE(GEOGRAPHIC_GEOCENTRIC),
881     // Transformations
882     METHOD_NAME_CODE(LONGITUDE_ROTATION),
883     METHOD_NAME_CODE(AFFINE_PARAMETRIC_TRANSFORMATION),
884     METHOD_NAME_CODE(COORDINATE_FRAME_GEOCENTRIC),
885     METHOD_NAME_CODE(COORDINATE_FRAME_GEOGRAPHIC_2D),
886     METHOD_NAME_CODE(COORDINATE_FRAME_GEOGRAPHIC_3D),
887     METHOD_NAME_CODE(POSITION_VECTOR_GEOCENTRIC),
888     METHOD_NAME_CODE(POSITION_VECTOR_GEOGRAPHIC_2D),
889     METHOD_NAME_CODE(POSITION_VECTOR_GEOGRAPHIC_3D),
890     METHOD_NAME_CODE(GEOCENTRIC_TRANSLATION_GEOCENTRIC),
891     METHOD_NAME_CODE(GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D),
892     METHOD_NAME_CODE(GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D),
893     METHOD_NAME_CODE(TIME_DEPENDENT_COORDINATE_FRAME_GEOCENTRIC),
894     METHOD_NAME_CODE(TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D),
895     METHOD_NAME_CODE(TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D),
896     METHOD_NAME_CODE(TIME_DEPENDENT_POSITION_VECTOR_GEOCENTRIC),
897     METHOD_NAME_CODE(TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D),
898     METHOD_NAME_CODE(TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D),
899     METHOD_NAME_CODE(MOLODENSKY_BADEKAS_CF_GEOCENTRIC),
900     METHOD_NAME_CODE(MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D),
901     METHOD_NAME_CODE(MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_3D),
902     METHOD_NAME_CODE(MOLODENSKY_BADEKAS_PV_GEOCENTRIC),
903     METHOD_NAME_CODE(MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D),
904     METHOD_NAME_CODE(MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_3D),
905     METHOD_NAME_CODE(MOLODENSKY), METHOD_NAME_CODE(ABRIDGED_MOLODENSKY),
906     METHOD_NAME_CODE(GEOGRAPHIC2D_OFFSETS),
907     METHOD_NAME_CODE(GEOGRAPHIC2D_WITH_HEIGHT_OFFSETS),
908     METHOD_NAME_CODE(GEOGRAPHIC3D_OFFSETS), METHOD_NAME_CODE(VERTICAL_OFFSET),
909     METHOD_NAME_CODE(NTV2), METHOD_NAME_CODE(NTV1), METHOD_NAME_CODE(NADCON),
910     METHOD_NAME_CODE(VERTCON),
911     METHOD_NAME_CODE(GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN),
912 };
913 
getMethodNameCodes(size_t & nElts)914 const MethodNameCode *getMethodNameCodes(size_t &nElts) {
915     nElts = sizeof(methodNameCodes) / sizeof(methodNameCodes[0]);
916     return methodNameCodes;
917 }
918 
919 #define PARAM_NAME_CODE(method)                                                \
920     { EPSG_NAME_PARAMETER_##method, EPSG_CODE_PARAMETER_##method }
921 
922 const struct ParamNameCode paramNameCodes[] = {
923     // Parameters of projection methods
924     PARAM_NAME_CODE(COLATITUDE_CONE_AXIS),
925     PARAM_NAME_CODE(LATITUDE_OF_NATURAL_ORIGIN),
926     PARAM_NAME_CODE(LONGITUDE_OF_NATURAL_ORIGIN),
927     PARAM_NAME_CODE(SCALE_FACTOR_AT_NATURAL_ORIGIN),
928     PARAM_NAME_CODE(FALSE_EASTING), PARAM_NAME_CODE(FALSE_NORTHING),
929     PARAM_NAME_CODE(LATITUDE_PROJECTION_CENTRE),
930     PARAM_NAME_CODE(LONGITUDE_PROJECTION_CENTRE),
931     PARAM_NAME_CODE(AZIMUTH_INITIAL_LINE),
932     PARAM_NAME_CODE(ANGLE_RECTIFIED_TO_SKEW_GRID),
933     PARAM_NAME_CODE(SCALE_FACTOR_INITIAL_LINE),
934     PARAM_NAME_CODE(EASTING_PROJECTION_CENTRE),
935     PARAM_NAME_CODE(NORTHING_PROJECTION_CENTRE),
936     PARAM_NAME_CODE(LATITUDE_PSEUDO_STANDARD_PARALLEL),
937     PARAM_NAME_CODE(SCALE_FACTOR_PSEUDO_STANDARD_PARALLEL),
938     PARAM_NAME_CODE(LATITUDE_FALSE_ORIGIN),
939     PARAM_NAME_CODE(LONGITUDE_FALSE_ORIGIN),
940     PARAM_NAME_CODE(LATITUDE_1ST_STD_PARALLEL),
941     PARAM_NAME_CODE(LATITUDE_2ND_STD_PARALLEL),
942     PARAM_NAME_CODE(EASTING_FALSE_ORIGIN),
943     PARAM_NAME_CODE(NORTHING_FALSE_ORIGIN),
944     PARAM_NAME_CODE(LATITUDE_STD_PARALLEL),
945     PARAM_NAME_CODE(LONGITUDE_OF_ORIGIN),
946     PARAM_NAME_CODE(ELLIPSOID_SCALE_FACTOR),
947     PARAM_NAME_CODE(PROJECTION_PLANE_ORIGIN_HEIGHT),
948     // Parameters of transformations
949     PARAM_NAME_CODE(SEMI_MAJOR_AXIS_DIFFERENCE),
950     PARAM_NAME_CODE(FLATTENING_DIFFERENCE),
951     PARAM_NAME_CODE(LATITUDE_LONGITUDE_DIFFERENCE_FILE),
952     PARAM_NAME_CODE(GEOID_CORRECTION_FILENAME),
953     PARAM_NAME_CODE(VERTICAL_OFFSET_FILE),
954     PARAM_NAME_CODE(LATITUDE_DIFFERENCE_FILE),
955     PARAM_NAME_CODE(LONGITUDE_DIFFERENCE_FILE),
956     PARAM_NAME_CODE(UNIT_CONVERSION_SCALAR), PARAM_NAME_CODE(LATITUDE_OFFSET),
957     PARAM_NAME_CODE(LONGITUDE_OFFSET), PARAM_NAME_CODE(VERTICAL_OFFSET),
958     PARAM_NAME_CODE(GEOID_UNDULATION), PARAM_NAME_CODE(A0), PARAM_NAME_CODE(A1),
959     PARAM_NAME_CODE(A2), PARAM_NAME_CODE(B0), PARAM_NAME_CODE(B1),
960     PARAM_NAME_CODE(B2), PARAM_NAME_CODE(X_AXIS_TRANSLATION),
961     PARAM_NAME_CODE(Y_AXIS_TRANSLATION), PARAM_NAME_CODE(Z_AXIS_TRANSLATION),
962     PARAM_NAME_CODE(X_AXIS_ROTATION), PARAM_NAME_CODE(Y_AXIS_ROTATION),
963     PARAM_NAME_CODE(Z_AXIS_ROTATION), PARAM_NAME_CODE(SCALE_DIFFERENCE),
964     PARAM_NAME_CODE(RATE_X_AXIS_TRANSLATION),
965     PARAM_NAME_CODE(RATE_Y_AXIS_TRANSLATION),
966     PARAM_NAME_CODE(RATE_Z_AXIS_TRANSLATION),
967     PARAM_NAME_CODE(RATE_X_AXIS_ROTATION),
968     PARAM_NAME_CODE(RATE_Y_AXIS_ROTATION),
969     PARAM_NAME_CODE(RATE_Z_AXIS_ROTATION),
970     PARAM_NAME_CODE(RATE_SCALE_DIFFERENCE), PARAM_NAME_CODE(REFERENCE_EPOCH),
971     PARAM_NAME_CODE(TRANSFORMATION_REFERENCE_EPOCH),
972     PARAM_NAME_CODE(ORDINATE_1_EVAL_POINT),
973     PARAM_NAME_CODE(ORDINATE_2_EVAL_POINT),
974     PARAM_NAME_CODE(ORDINATE_3_EVAL_POINT),
975     PARAM_NAME_CODE(GEOCENTRIC_TRANSLATION_FILE),
976 };
977 
getParamNameCodes(size_t & nElts)978 const ParamNameCode *getParamNameCodes(size_t &nElts) {
979     nElts = sizeof(paramNameCodes) / sizeof(paramNameCodes[0]);
980     return paramNameCodes;
981 }
982 
983 static const ParamMapping paramUnitConversionScalar = {
984     EPSG_NAME_PARAMETER_UNIT_CONVERSION_SCALAR,
985     EPSG_CODE_PARAMETER_UNIT_CONVERSION_SCALAR, nullptr,
986     common::UnitOfMeasure::Type::SCALE, nullptr};
987 
988 static const ParamMapping *const paramsChangeVerticalUnit[] = {
989     &paramUnitConversionScalar, nullptr};
990 
991 static const ParamMapping paramLongitudeOffset = {
992     EPSG_NAME_PARAMETER_LONGITUDE_OFFSET, EPSG_CODE_PARAMETER_LONGITUDE_OFFSET,
993     nullptr, common::UnitOfMeasure::Type::ANGULAR, nullptr};
994 
995 static const ParamMapping *const paramsLongitudeRotation[] = {
996     &paramLongitudeOffset, nullptr};
997 
998 static const ParamMapping paramA0 = {
999     EPSG_NAME_PARAMETER_A0, EPSG_CODE_PARAMETER_A0, nullptr,
1000     common::UnitOfMeasure::Type::UNKNOWN, nullptr};
1001 
1002 static const ParamMapping paramA1 = {
1003     EPSG_NAME_PARAMETER_A1, EPSG_CODE_PARAMETER_A1, nullptr,
1004     common::UnitOfMeasure::Type::UNKNOWN, nullptr};
1005 
1006 static const ParamMapping paramA2 = {
1007     EPSG_NAME_PARAMETER_A2, EPSG_CODE_PARAMETER_A2, nullptr,
1008     common::UnitOfMeasure::Type::UNKNOWN, nullptr};
1009 
1010 static const ParamMapping paramB0 = {
1011     EPSG_NAME_PARAMETER_B0, EPSG_CODE_PARAMETER_B0, nullptr,
1012     common::UnitOfMeasure::Type::UNKNOWN, nullptr};
1013 
1014 static const ParamMapping paramB1 = {
1015     EPSG_NAME_PARAMETER_B1, EPSG_CODE_PARAMETER_B1, nullptr,
1016     common::UnitOfMeasure::Type::UNKNOWN, nullptr};
1017 
1018 static const ParamMapping paramB2 = {
1019     EPSG_NAME_PARAMETER_B2, EPSG_CODE_PARAMETER_B2, nullptr,
1020     common::UnitOfMeasure::Type::UNKNOWN, nullptr};
1021 
1022 static const ParamMapping *const paramsAffineParametricTransformation[] = {
1023     &paramA0, &paramA1, &paramA2, &paramB0, &paramB1, &paramB2, nullptr};
1024 
1025 static const ParamMapping paramXTranslation = {
1026     EPSG_NAME_PARAMETER_X_AXIS_TRANSLATION,
1027     EPSG_CODE_PARAMETER_X_AXIS_TRANSLATION, nullptr,
1028     common::UnitOfMeasure::Type::LINEAR, nullptr};
1029 
1030 static const ParamMapping paramYTranslation = {
1031     EPSG_NAME_PARAMETER_Y_AXIS_TRANSLATION,
1032     EPSG_CODE_PARAMETER_Y_AXIS_TRANSLATION, nullptr,
1033     common::UnitOfMeasure::Type::LINEAR, nullptr};
1034 
1035 static const ParamMapping paramZTranslation = {
1036     EPSG_NAME_PARAMETER_Z_AXIS_TRANSLATION,
1037     EPSG_CODE_PARAMETER_Z_AXIS_TRANSLATION, nullptr,
1038     common::UnitOfMeasure::Type::LINEAR, nullptr};
1039 
1040 static const ParamMapping paramXRotation = {
1041     EPSG_NAME_PARAMETER_X_AXIS_ROTATION, EPSG_CODE_PARAMETER_X_AXIS_ROTATION,
1042     nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr};
1043 
1044 static const ParamMapping paramYRotation = {
1045     EPSG_NAME_PARAMETER_Y_AXIS_ROTATION, EPSG_CODE_PARAMETER_Y_AXIS_ROTATION,
1046     nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr};
1047 
1048 static const ParamMapping paramZRotation = {
1049     EPSG_NAME_PARAMETER_Z_AXIS_ROTATION, EPSG_CODE_PARAMETER_Z_AXIS_ROTATION,
1050     nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr};
1051 
1052 static const ParamMapping paramScaleDifference = {
1053     EPSG_NAME_PARAMETER_SCALE_DIFFERENCE, EPSG_CODE_PARAMETER_SCALE_DIFFERENCE,
1054     nullptr, common::UnitOfMeasure::Type::SCALE, nullptr};
1055 
1056 static const ParamMapping *const paramsHelmert3[] = {
1057     &paramXTranslation, &paramYTranslation, &paramZTranslation, nullptr};
1058 
1059 static const ParamMapping *const paramsHelmert7[] = {
1060     &paramXTranslation,    &paramYTranslation,
1061     &paramZTranslation,    &paramXRotation,
1062     &paramYRotation,       &paramZRotation,
1063     &paramScaleDifference, nullptr};
1064 
1065 static const ParamMapping paramRateXTranslation = {
1066     EPSG_NAME_PARAMETER_RATE_X_AXIS_TRANSLATION,
1067     EPSG_CODE_PARAMETER_RATE_X_AXIS_TRANSLATION, nullptr,
1068     common::UnitOfMeasure::Type::LINEAR, nullptr};
1069 
1070 static const ParamMapping paramRateYTranslation = {
1071     EPSG_NAME_PARAMETER_RATE_Y_AXIS_TRANSLATION,
1072     EPSG_CODE_PARAMETER_RATE_Y_AXIS_TRANSLATION, nullptr,
1073     common::UnitOfMeasure::Type::LINEAR, nullptr};
1074 
1075 static const ParamMapping paramRateZTranslation = {
1076     EPSG_NAME_PARAMETER_RATE_Z_AXIS_TRANSLATION,
1077     EPSG_CODE_PARAMETER_RATE_Z_AXIS_TRANSLATION, nullptr,
1078     common::UnitOfMeasure::Type::LINEAR, nullptr};
1079 
1080 static const ParamMapping paramRateXRotation = {
1081     EPSG_NAME_PARAMETER_RATE_X_AXIS_ROTATION,
1082     EPSG_CODE_PARAMETER_RATE_X_AXIS_ROTATION, nullptr,
1083     common::UnitOfMeasure::Type::LINEAR, nullptr};
1084 
1085 static const ParamMapping paramRateYRotation = {
1086     EPSG_NAME_PARAMETER_RATE_Y_AXIS_ROTATION,
1087     EPSG_CODE_PARAMETER_RATE_Y_AXIS_ROTATION, nullptr,
1088     common::UnitOfMeasure::Type::LINEAR, nullptr};
1089 
1090 static const ParamMapping paramRateZRotation = {
1091     EPSG_NAME_PARAMETER_RATE_Z_AXIS_ROTATION,
1092     EPSG_CODE_PARAMETER_RATE_Z_AXIS_ROTATION, nullptr,
1093     common::UnitOfMeasure::Type::LINEAR, nullptr};
1094 
1095 static const ParamMapping paramRateScaleDifference = {
1096     EPSG_NAME_PARAMETER_RATE_SCALE_DIFFERENCE,
1097     EPSG_CODE_PARAMETER_RATE_SCALE_DIFFERENCE, nullptr,
1098     common::UnitOfMeasure::Type::SCALE, nullptr};
1099 
1100 static const ParamMapping paramReferenceEpoch = {
1101     EPSG_NAME_PARAMETER_REFERENCE_EPOCH, EPSG_CODE_PARAMETER_REFERENCE_EPOCH,
1102     nullptr, common::UnitOfMeasure::Type::TIME, nullptr};
1103 
1104 static const ParamMapping *const paramsHelmert15[] = {
1105     &paramXTranslation,     &paramYTranslation,
1106     &paramZTranslation,     &paramXRotation,
1107     &paramYRotation,        &paramZRotation,
1108     &paramScaleDifference,  &paramRateXTranslation,
1109     &paramRateYTranslation, &paramRateZTranslation,
1110     &paramRateXRotation,    &paramRateYRotation,
1111     &paramRateZRotation,    &paramRateScaleDifference,
1112     &paramReferenceEpoch,   nullptr};
1113 
1114 static const ParamMapping paramOrdinate1EvalPoint = {
1115     EPSG_NAME_PARAMETER_ORDINATE_1_EVAL_POINT,
1116     EPSG_CODE_PARAMETER_ORDINATE_1_EVAL_POINT, nullptr,
1117     common::UnitOfMeasure::Type::LINEAR, nullptr};
1118 
1119 static const ParamMapping paramOrdinate2EvalPoint = {
1120     EPSG_NAME_PARAMETER_ORDINATE_2_EVAL_POINT,
1121     EPSG_CODE_PARAMETER_ORDINATE_2_EVAL_POINT, nullptr,
1122     common::UnitOfMeasure::Type::LINEAR, nullptr};
1123 
1124 static const ParamMapping paramOrdinate3EvalPoint = {
1125     EPSG_NAME_PARAMETER_ORDINATE_3_EVAL_POINT,
1126     EPSG_CODE_PARAMETER_ORDINATE_3_EVAL_POINT, nullptr,
1127     common::UnitOfMeasure::Type::LINEAR, nullptr};
1128 
1129 static const ParamMapping *const paramsMolodenskyBadekas[] = {
1130     &paramXTranslation,
1131     &paramYTranslation,
1132     &paramZTranslation,
1133     &paramXRotation,
1134     &paramYRotation,
1135     &paramZRotation,
1136     &paramScaleDifference,
1137     &paramOrdinate1EvalPoint,
1138     &paramOrdinate2EvalPoint,
1139     &paramOrdinate3EvalPoint,
1140     nullptr};
1141 
1142 static const ParamMapping paramSemiMajorAxisDifference = {
1143     EPSG_NAME_PARAMETER_SEMI_MAJOR_AXIS_DIFFERENCE,
1144     EPSG_CODE_PARAMETER_SEMI_MAJOR_AXIS_DIFFERENCE, nullptr,
1145     common::UnitOfMeasure::Type::LINEAR, nullptr};
1146 
1147 static const ParamMapping paramFlatteningDifference = {
1148     EPSG_NAME_PARAMETER_FLATTENING_DIFFERENCE,
1149     EPSG_CODE_PARAMETER_FLATTENING_DIFFERENCE, nullptr,
1150     common::UnitOfMeasure::Type::NONE, nullptr};
1151 
1152 static const ParamMapping *const paramsMolodensky[] = {
1153     &paramXTranslation,         &paramYTranslation,
1154     &paramZTranslation,         &paramSemiMajorAxisDifference,
1155     &paramFlatteningDifference, nullptr};
1156 
1157 static const ParamMapping paramLatitudeOffset = {
1158     EPSG_NAME_PARAMETER_LATITUDE_OFFSET, EPSG_CODE_PARAMETER_LATITUDE_OFFSET,
1159     nullptr, common::UnitOfMeasure::Type::ANGULAR, nullptr};
1160 
1161 static const ParamMapping *const paramsGeographic2DOffsets[] = {
1162     &paramLatitudeOffset, &paramLongitudeOffset, nullptr};
1163 
1164 static const ParamMapping paramGeoidUndulation = {
1165     EPSG_NAME_PARAMETER_GEOID_UNDULATION, EPSG_CODE_PARAMETER_GEOID_UNDULATION,
1166     nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr};
1167 
1168 static const ParamMapping *const paramsGeographic2DWithHeightOffsets[] = {
1169     &paramLatitudeOffset, &paramLongitudeOffset, &paramGeoidUndulation,
1170     nullptr};
1171 
1172 static const ParamMapping paramVerticalOffset = {
1173     EPSG_NAME_PARAMETER_VERTICAL_OFFSET, EPSG_CODE_PARAMETER_VERTICAL_OFFSET,
1174     nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr};
1175 
1176 static const ParamMapping *const paramsGeographic3DOffsets[] = {
1177     &paramLatitudeOffset, &paramLongitudeOffset, &paramVerticalOffset, nullptr};
1178 
1179 static const ParamMapping *const paramsVerticalOffsets[] = {
1180     &paramVerticalOffset, nullptr};
1181 
1182 static const ParamMapping paramLatitudeLongitudeDifferenceFile = {
1183     EPSG_NAME_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE,
1184     EPSG_CODE_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE, nullptr,
1185     common::UnitOfMeasure::Type::NONE, nullptr};
1186 
1187 static const ParamMapping *const paramsNTV2[] = {
1188     &paramLatitudeLongitudeDifferenceFile, nullptr};
1189 
1190 static const ParamMapping paramGeocentricTranslationFile = {
1191     EPSG_NAME_PARAMETER_GEOCENTRIC_TRANSLATION_FILE,
1192     EPSG_CODE_PARAMETER_GEOCENTRIC_TRANSLATION_FILE, nullptr,
1193     common::UnitOfMeasure::Type::NONE, nullptr};
1194 
1195 static const ParamMapping
1196     *const paramsGeocentricTranslationGridInterpolationIGN[] = {
1197         &paramGeocentricTranslationFile, nullptr};
1198 
1199 static const ParamMapping paramLatitudeDifferenceFile = {
1200     EPSG_NAME_PARAMETER_LATITUDE_DIFFERENCE_FILE,
1201     EPSG_CODE_PARAMETER_LATITUDE_DIFFERENCE_FILE, nullptr,
1202     common::UnitOfMeasure::Type::NONE, nullptr};
1203 
1204 static const ParamMapping paramLongitudeDifferenceFile = {
1205     EPSG_NAME_PARAMETER_LONGITUDE_DIFFERENCE_FILE,
1206     EPSG_CODE_PARAMETER_LONGITUDE_DIFFERENCE_FILE, nullptr,
1207     common::UnitOfMeasure::Type::NONE, nullptr};
1208 
1209 static const ParamMapping *const paramsNADCON[] = {
1210     &paramLatitudeDifferenceFile, &paramLongitudeDifferenceFile, nullptr};
1211 
1212 static const ParamMapping paramVerticalOffsetFile = {
1213     EPSG_NAME_PARAMETER_VERTICAL_OFFSET_FILE,
1214     EPSG_CODE_PARAMETER_VERTICAL_OFFSET_FILE, nullptr,
1215     common::UnitOfMeasure::Type::NONE, nullptr};
1216 
1217 static const ParamMapping *const paramsVERTCON[] = {&paramVerticalOffsetFile,
1218                                                     nullptr};
1219 
1220 static const ParamMapping paramSouthPoleLatGRIB = {
1221     PROJ_WKT2_NAME_PARAMETER_SOUTH_POLE_LATITUDE_GRIB_CONVENTION, 0, nullptr,
1222     common::UnitOfMeasure::Type::ANGULAR, nullptr};
1223 
1224 static const ParamMapping paramSouthPoleLonGRIB = {
1225     PROJ_WKT2_NAME_PARAMETER_SOUTH_POLE_LONGITUDE_GRIB_CONVENTION, 0, nullptr,
1226     common::UnitOfMeasure::Type::ANGULAR, nullptr};
1227 
1228 static const ParamMapping paramAxisRotationGRIB = {
1229     PROJ_WKT2_NAME_PARAMETER_AXIS_ROTATION_GRIB_CONVENTION, 0, nullptr,
1230     common::UnitOfMeasure::Type::ANGULAR, nullptr};
1231 
1232 static const ParamMapping *const paramsPoleRotationGRIBConvention[] = {
1233     &paramSouthPoleLatGRIB, &paramSouthPoleLonGRIB, &paramAxisRotationGRIB,
1234     nullptr};
1235 
1236 static const MethodMapping otherMethodMappings[] = {
1237     {EPSG_NAME_METHOD_CHANGE_VERTICAL_UNIT,
1238      EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT, nullptr, nullptr, nullptr,
1239      paramsChangeVerticalUnit},
1240     {EPSG_NAME_METHOD_HEIGHT_DEPTH_REVERSAL,
1241      EPSG_CODE_METHOD_HEIGHT_DEPTH_REVERSAL, nullptr, nullptr, nullptr,
1242      paramsChangeVerticalUnit},
1243     {EPSG_NAME_METHOD_AXIS_ORDER_REVERSAL_2D,
1244      EPSG_CODE_METHOD_AXIS_ORDER_REVERSAL_2D, nullptr, nullptr, nullptr,
1245      nullptr},
1246     {EPSG_NAME_METHOD_AXIS_ORDER_REVERSAL_3D,
1247      EPSG_CODE_METHOD_AXIS_ORDER_REVERSAL_3D, nullptr, nullptr, nullptr,
1248      nullptr},
1249     {EPSG_NAME_METHOD_GEOGRAPHIC_GEOCENTRIC,
1250      EPSG_CODE_METHOD_GEOGRAPHIC_GEOCENTRIC, nullptr, nullptr, nullptr,
1251      nullptr},
1252     {EPSG_NAME_METHOD_LONGITUDE_ROTATION, EPSG_CODE_METHOD_LONGITUDE_ROTATION,
1253      nullptr, nullptr, nullptr, paramsLongitudeRotation},
1254     {EPSG_NAME_METHOD_AFFINE_PARAMETRIC_TRANSFORMATION,
1255      EPSG_CODE_METHOD_AFFINE_PARAMETRIC_TRANSFORMATION, nullptr, nullptr,
1256      nullptr, paramsAffineParametricTransformation},
1257 
1258     {PROJ_WKT2_NAME_METHOD_POLE_ROTATION_GRIB_CONVENTION, 0, nullptr, nullptr,
1259      nullptr, paramsPoleRotationGRIBConvention},
1260 
1261     {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_GEOCENTRIC,
1262      EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOCENTRIC, nullptr, nullptr,
1263      nullptr, paramsHelmert3},
1264     {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D,
1265      EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D, nullptr, nullptr,
1266      nullptr, paramsHelmert3},
1267     {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D,
1268      EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D, nullptr, nullptr,
1269      nullptr, paramsHelmert3},
1270 
1271     {EPSG_NAME_METHOD_COORDINATE_FRAME_GEOCENTRIC,
1272      EPSG_CODE_METHOD_COORDINATE_FRAME_GEOCENTRIC, nullptr, nullptr, nullptr,
1273      paramsHelmert7},
1274     {EPSG_NAME_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D,
1275      EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D, nullptr, nullptr, nullptr,
1276      paramsHelmert7},
1277     {EPSG_NAME_METHOD_COORDINATE_FRAME_GEOGRAPHIC_3D,
1278      EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_3D, nullptr, nullptr, nullptr,
1279      paramsHelmert7},
1280 
1281     {EPSG_NAME_METHOD_POSITION_VECTOR_GEOCENTRIC,
1282      EPSG_CODE_METHOD_POSITION_VECTOR_GEOCENTRIC, nullptr, nullptr, nullptr,
1283      paramsHelmert7},
1284     {EPSG_NAME_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D,
1285      EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D, nullptr, nullptr, nullptr,
1286      paramsHelmert7},
1287     {EPSG_NAME_METHOD_POSITION_VECTOR_GEOGRAPHIC_3D,
1288      EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_3D, nullptr, nullptr, nullptr,
1289      paramsHelmert7},
1290 
1291     {EPSG_NAME_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOCENTRIC,
1292      EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOCENTRIC, nullptr,
1293      nullptr, nullptr, paramsHelmert15},
1294     {EPSG_NAME_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D,
1295      EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D, nullptr,
1296      nullptr, nullptr, paramsHelmert15},
1297     {EPSG_NAME_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D,
1298      EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D, nullptr,
1299      nullptr, nullptr, paramsHelmert15},
1300 
1301     {EPSG_NAME_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOCENTRIC,
1302      EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOCENTRIC, nullptr,
1303      nullptr, nullptr, paramsHelmert15},
1304     {EPSG_NAME_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D,
1305      EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D, nullptr,
1306      nullptr, nullptr, paramsHelmert15},
1307     {EPSG_NAME_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D,
1308      EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D, nullptr,
1309      nullptr, nullptr, paramsHelmert15},
1310 
1311     {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOCENTRIC,
1312      EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOCENTRIC, nullptr, nullptr,
1313      nullptr, paramsMolodenskyBadekas},
1314     {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D,
1315      EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D, nullptr, nullptr,
1316      nullptr, paramsMolodenskyBadekas},
1317     {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_3D,
1318      EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_3D, nullptr, nullptr,
1319      nullptr, paramsMolodenskyBadekas},
1320 
1321     {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOCENTRIC,
1322      EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOCENTRIC, nullptr, nullptr,
1323      nullptr, paramsMolodenskyBadekas},
1324     {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D,
1325      EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D, nullptr, nullptr,
1326      nullptr, paramsMolodenskyBadekas},
1327     {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_3D,
1328      EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_3D, nullptr, nullptr,
1329      nullptr, paramsMolodenskyBadekas},
1330 
1331     {EPSG_NAME_METHOD_MOLODENSKY, EPSG_CODE_METHOD_MOLODENSKY, nullptr, nullptr,
1332      nullptr, paramsMolodensky},
1333 
1334     {EPSG_NAME_METHOD_ABRIDGED_MOLODENSKY, EPSG_CODE_METHOD_ABRIDGED_MOLODENSKY,
1335      nullptr, nullptr, nullptr, paramsMolodensky},
1336 
1337     {EPSG_NAME_METHOD_GEOGRAPHIC2D_OFFSETS,
1338      EPSG_CODE_METHOD_GEOGRAPHIC2D_OFFSETS, nullptr, nullptr, nullptr,
1339      paramsGeographic2DOffsets},
1340 
1341     {EPSG_NAME_METHOD_GEOGRAPHIC2D_WITH_HEIGHT_OFFSETS,
1342      EPSG_CODE_METHOD_GEOGRAPHIC2D_WITH_HEIGHT_OFFSETS, nullptr, nullptr,
1343      nullptr, paramsGeographic2DWithHeightOffsets},
1344 
1345     {EPSG_NAME_METHOD_GEOGRAPHIC3D_OFFSETS,
1346      EPSG_CODE_METHOD_GEOGRAPHIC3D_OFFSETS, nullptr, nullptr, nullptr,
1347      paramsGeographic3DOffsets},
1348 
1349     {EPSG_NAME_METHOD_VERTICAL_OFFSET, EPSG_CODE_METHOD_VERTICAL_OFFSET,
1350      nullptr, nullptr, nullptr, paramsVerticalOffsets},
1351 
1352     {EPSG_NAME_METHOD_NTV2, EPSG_CODE_METHOD_NTV2, nullptr, nullptr, nullptr,
1353      paramsNTV2},
1354 
1355     {EPSG_NAME_METHOD_NTV1, EPSG_CODE_METHOD_NTV1, nullptr, nullptr, nullptr,
1356      paramsNTV2},
1357 
1358     {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN,
1359      EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN, nullptr,
1360      nullptr, nullptr, paramsGeocentricTranslationGridInterpolationIGN},
1361 
1362     {EPSG_NAME_METHOD_NADCON, EPSG_CODE_METHOD_NADCON, nullptr, nullptr,
1363      nullptr, paramsNADCON},
1364 
1365     {EPSG_NAME_METHOD_VERTCON, EPSG_CODE_METHOD_VERTCON, nullptr, nullptr,
1366      nullptr, paramsVERTCON},
1367     {EPSG_NAME_METHOD_VERTCON_OLDNAME, EPSG_CODE_METHOD_VERTCON, nullptr,
1368      nullptr, nullptr, paramsVERTCON},
1369 };
1370 
getOtherMethodMappings(size_t & nElts)1371 const MethodMapping *getOtherMethodMappings(size_t &nElts) {
1372     nElts = sizeof(otherMethodMappings) / sizeof(otherMethodMappings[0]);
1373     return otherMethodMappings;
1374 }
1375 
1376 // ---------------------------------------------------------------------------
1377 
getMapping(int epsg_code)1378 PROJ_NO_INLINE const MethodMapping *getMapping(int epsg_code) noexcept {
1379     for (const auto &mapping : projectionMethodMappings) {
1380         if (mapping.epsg_code == epsg_code) {
1381             return &mapping;
1382         }
1383     }
1384     return nullptr;
1385 }
1386 
1387 // ---------------------------------------------------------------------------
1388 
getMapping(const OperationMethod * method)1389 const MethodMapping *getMapping(const OperationMethod *method) noexcept {
1390     const std::string &name(method->nameStr());
1391     const int epsg_code = method->getEPSGCode();
1392     for (const auto &mapping : projectionMethodMappings) {
1393         if ((epsg_code != 0 && mapping.epsg_code == epsg_code) ||
1394             metadata::Identifier::isEquivalentName(mapping.wkt2_name,
1395                                                    name.c_str())) {
1396             return &mapping;
1397         }
1398     }
1399     return nullptr;
1400 }
1401 
1402 // ---------------------------------------------------------------------------
1403 
getMappingFromWKT1(const std::string & wkt1_name)1404 const MethodMapping *getMappingFromWKT1(const std::string &wkt1_name) noexcept {
1405     // Unusual for a WKT1 projection name, but mentioned in OGC 12-063r5 C.4.2
1406     if (ci_starts_with(wkt1_name, "UTM zone")) {
1407         return getMapping(EPSG_CODE_METHOD_TRANSVERSE_MERCATOR);
1408     }
1409 
1410     for (const auto &mapping : projectionMethodMappings) {
1411         if (mapping.wkt1_name && metadata::Identifier::isEquivalentName(
1412                                      mapping.wkt1_name, wkt1_name.c_str())) {
1413             return &mapping;
1414         }
1415     }
1416     return nullptr;
1417 }
1418 // ---------------------------------------------------------------------------
1419 
getMapping(const char * wkt2_name)1420 const MethodMapping *getMapping(const char *wkt2_name) noexcept {
1421     for (const auto &mapping : projectionMethodMappings) {
1422         if (metadata::Identifier::isEquivalentName(mapping.wkt2_name,
1423                                                    wkt2_name)) {
1424             return &mapping;
1425         }
1426     }
1427     for (const auto &mapping : otherMethodMappings) {
1428         if (metadata::Identifier::isEquivalentName(mapping.wkt2_name,
1429                                                    wkt2_name)) {
1430             return &mapping;
1431         }
1432     }
1433     return nullptr;
1434 }
1435 
1436 // ---------------------------------------------------------------------------
1437 
1438 std::vector<const MethodMapping *>
getMappingsFromPROJName(const std::string & projName)1439 getMappingsFromPROJName(const std::string &projName) {
1440     std::vector<const MethodMapping *> res;
1441     for (const auto &mapping : projectionMethodMappings) {
1442         if (mapping.proj_name_main && projName == mapping.proj_name_main) {
1443             res.push_back(&mapping);
1444         }
1445     }
1446     return res;
1447 }
1448 
1449 // ---------------------------------------------------------------------------
1450 
getMapping(const MethodMapping * mapping,const OperationParameterNNPtr & param)1451 const ParamMapping *getMapping(const MethodMapping *mapping,
1452                                const OperationParameterNNPtr &param) {
1453     if (mapping->params == nullptr) {
1454         return nullptr;
1455     }
1456 
1457     // First try with id
1458     const int epsg_code = param->getEPSGCode();
1459     if (epsg_code) {
1460         for (int i = 0; mapping->params[i] != nullptr; ++i) {
1461             const auto *paramMapping = mapping->params[i];
1462             if (paramMapping->epsg_code == epsg_code) {
1463                 return paramMapping;
1464             }
1465         }
1466     }
1467 
1468     // then equivalent name
1469     const std::string &name = param->nameStr();
1470     for (int i = 0; mapping->params[i] != nullptr; ++i) {
1471         const auto *paramMapping = mapping->params[i];
1472         if (metadata::Identifier::isEquivalentName(paramMapping->wkt2_name,
1473                                                    name.c_str())) {
1474             return paramMapping;
1475         }
1476     }
1477 
1478     // and finally different name, but equivalent parameter
1479     for (int i = 0; mapping->params[i] != nullptr; ++i) {
1480         const auto *paramMapping = mapping->params[i];
1481         if (areEquivalentParameters(paramMapping->wkt2_name, name)) {
1482             return paramMapping;
1483         }
1484     }
1485 
1486     return nullptr;
1487 }
1488 
1489 // ---------------------------------------------------------------------------
1490 
getMappingFromWKT1(const MethodMapping * mapping,const std::string & wkt1_name)1491 const ParamMapping *getMappingFromWKT1(const MethodMapping *mapping,
1492                                        const std::string &wkt1_name) {
1493     for (int i = 0; mapping->params[i] != nullptr; ++i) {
1494         const auto *paramMapping = mapping->params[i];
1495         if (paramMapping->wkt1_name &&
1496             (metadata::Identifier::isEquivalentName(paramMapping->wkt1_name,
1497                                                     wkt1_name.c_str()) ||
1498              areEquivalentParameters(paramMapping->wkt1_name, wkt1_name))) {
1499             return paramMapping;
1500         }
1501     }
1502     return nullptr;
1503 }
1504 
1505 //! @endcond
1506 
1507 // ---------------------------------------------------------------------------
1508 
1509 } // namespace operation
1510 NS_PROJ_END
1511