Coverage Report

Created: 2026-09-26 08:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogr_srs_panorama.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  OGRSpatialReference translation to/from "Panorama" GIS
5
 *           georeferencing information (also know as GIS "Integration").
6
 * Author:   Andrey Kiselev, dron@ak4719.spb.edu
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2005, Andrey Kiselev <dron@ak4719.spb.edu>
10
 * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
11
 * Copyright (c) 2020-2022, Dmitry Baryshnikov <polimax@mail.ru>
12
 *
13
 * SPDX-License-Identifier: MIT
14
 ****************************************************************************/
15
16
#include "ogr_spatialref.h"
17
#include "cpl_conv.h"
18
#include "cpl_csv.h"
19
#include "ogr_p.h"
20
21
#include <cmath>
22
23
constexpr double TO_DEGREES = 180.0 / M_PI;
24
constexpr double TO_RADIANS = M_PI / 180.0;
25
constexpr int NONE_VAL = -1L;
26
27
// This function computes zone number from the central meridian parameter.
28
static int GetZoneNumberGK(double dfCenterLong)
29
418
{
30
418
    return static_cast<int>((dfCenterLong + 363.0) / 6.0 + 0.5) % 60;
31
418
}
32
33
static int GetZoneNumberUTM(double dfCenterLong)
34
8
{
35
8
    return static_cast<int>((dfCenterLong + 186.0) / 6.0);
36
8
}
37
38
static bool IsNone(long val)
39
1.80k
{
40
1.80k
    return val == -1L || val == 0L || val == 255L;
41
1.80k
}
42
43
/************************************************************************/
44
/*                     "Panorama" projection codes.                     */
45
/************************************************************************/
46
47
constexpr long PAN_PROJ_TM = 1L;       // Gauss-Kruger (Transverse Mercator)
48
constexpr long PAN_PROJ_LCC = 2L;      // Lambert Conformal Conic 2SP
49
constexpr long PAN_PROJ_STEREO = 5L;   // Stereographic
50
constexpr long PAN_PROJ_AE = 6L;       // Azimuthal Equidistant (Postel)
51
constexpr long PAN_PROJ_MERCAT = 8L;   // Mercator
52
constexpr long PAN_PROJ_POLYC = 10L;   // Polyconic
53
constexpr long PAN_PROJ_PS = 13L;      // Polar Stereographic
54
constexpr long PAN_PROJ_GNOMON = 15L;  // Gnomonic
55
constexpr long PAN_PROJ_UTM = 17L;     // Universal Transverse Mercator (UTM)
56
constexpr long PAN_PROJ_WAG1 = 18L;    // Wagner I (Kavraisky VI)
57
constexpr long PAN_PROJ_MOLL = 19L;    // Mollweide
58
constexpr long PAN_PROJ_EC = 20L;      // Equidistant Conic
59
constexpr long PAN_PROJ_LAEA = 24L;    // Lambert Azimuthal Equal Area
60
constexpr long PAN_PROJ_EQC = 27L;     // Equirectangular
61
constexpr long PAN_PROJ_CEA = 28L;     // Cylindrical Equal Area (Lambert)
62
constexpr long PAN_PROJ_IMWP = 29L;  // International Map of the World Polyconic
63
constexpr long PAN_PROJ_SPHERE = 33L;  // Sphere
64
constexpr long PAN_PROJ_MILLER = 34L;  // Miller
65
constexpr long PAN_PROJ_PSEUDO_MERCATOR =
66
    35L;  // Popular Visualisation Pseudo Mercator
67
/************************************************************************/
68
/*                       "Panorama" datum codes.                        */
69
/************************************************************************/
70
71
constexpr long PAN_DATUM_PULKOVO42 = 1L;    // Pulkovo 1942
72
constexpr long PAN_DATUM_UTM = 2L;          // Universal Transverse Mercator
73
constexpr long PAN_DATUM_RECTANGULAR = 6L;  // WGS84
74
// constexpr long PAN_DATUM_WGS84 = 8L;        // WGS84
75
constexpr long PAN_DATUM_PULKOVO95 = 9L;  // Pulokovo 1995
76
constexpr long PAN_DATUM_GSK2011 = 10L;   // GSK 2011
77
78
/************************************************************************/
79
/*                     "Panorama" ellipsoid codes.                      */
80
/************************************************************************/
81
82
constexpr long PAN_ELLIPSOID_KRASSOVSKY = 1L;  // Krassovsky, 1940
83
// constexpr long PAN_ELLIPSOID_WGS72       = 2L;  // WGS, 1972
84
// constexpr long PAN_ELLIPSOID_INT1924     = 3L;  // International, 1924
85
// (Hayford, 1909) constexpr long PAN_ELLIPSOID_CLARCKE1880 = 4L;  // Clarke,
86
// 1880 constexpr long PAN_ELLIPSOID_CLARCKE1866 = 5L;  // Clarke, 1866
87
// (NAD1927) constexpr long PAN_ELLIPSOID_EVEREST1830 = 6L;  // Everest, 1830
88
// constexpr long PAN_ELLIPSOID_BESSEL1841  = 7L;  // Bessel, 1841
89
// constexpr long PAN_ELLIPSOID_AIRY1830    = 8L;  // Airy, 1830
90
constexpr long PAN_ELLIPSOID_WGS84 = 9L;          // WGS, 1984 (GPS)
91
constexpr long PAN_ELLIPSOID_WGS84_SPHERE = 45L;  // WGS, 1984 (Sphere)
92
constexpr long PAN_ELLIPSOID_GSK2011 = 46L;       // GSK 2011
93
constexpr long PAN_ELLIPSOID_PZ90 = 47L;          // PZ-90
94
95
/************************************************************************/
96
/*    Correspondence between "Panorama" datum and EPSG GeogCS codes.    */
97
/************************************************************************/
98
99
constexpr int aoDatums[] = {
100
    0,     // 0.  Undefined (also may be 255 or -1)
101
    4284,  // 1.  Pulkovo, 1942
102
    4326,  // 2.  WGS, 1984,
103
    4277,  // 3.  OSGB 1936 (British National Grid)
104
    0,     // 4.  Local spatial reference
105
    0,     // 5.  SK 63
106
    0,     // 6.  Rectangular conditional spatial reference
107
    0,     // 7.  Geodesic coordinates in radians
108
    0,     // 8.  Geodesic coordinates in degrees
109
    4200,  // 9.  Pulkovo, 1995
110
    7683   // 10. GSK 2011
111
};
112
113
constexpr int NUMBER_OF_DATUMS = static_cast<int>(CPL_ARRAYSIZE(aoDatums));
114
115
/************************************************************************/
116
/*     Correspondence between "Panorama" and EPSG ellipsoid codes.      */
117
/************************************************************************/
118
119
constexpr int aoPanoramaEllips[] = {
120
    0,     // 0. Undefined
121
    7024,  // 1. Krassovsky, 1940
122
    7043,  // 2. WGS, 1972
123
    7022,  // 3. International, 1924 (Hayford, 1909)
124
    7034,  // 4. Clarke, 1880
125
    7008,  // 5. Clarke, 1866 (NAD1927)
126
    7015,  // 6. Everest, 1830
127
    7004,  // 7. Bessel, 1841
128
    7001,  // 8. Airy, 1830
129
    7030,  // 9. WGS, 1984 (GPS)
130
    7054,  // 10. PZ-90.02 // http://epsg.io/7054-ellipsoid
131
    7019,  // 11. GRS, 1980 (NAD1983)
132
    0,     // 12. IERS 1996 (6378136.49 298.25645)
133
    7022,  // 13. International, 1924 (Hayford, 1909) XXX?
134
    7036,  // 14. South American, 1969
135
    7021,  // 15. Indonesian, 1974
136
    7020,  // 16. Helmert 1906
137
    0,     // 17. FIXME: Fisher 1960 - https://epsg.io/37002
138
    0,     // 18. FIXME: Fisher 1968 - https://epsg.io/37003
139
    0,     // 19. FIXME: Haff 1960 - (6378270.0 297.0)
140
    7042,  // 20. Everest, 1830
141
    7003,  // 21. Australian National, 1965
142
    1024,  // 22. CGCS2000 http://epsg.io/1024-ellipsoid
143
    7002,  // 23. Airy Modified 1849 http://epsg.io/7002-ellipsoid
144
    7005,  // 24. Bessel Modified
145
    7046,  // 25. Bessel Namibia
146
    7046,  // 26. Bessel Namibia (GLM)
147
    7013,  // 27. Clarke 1880 (Arc)
148
    7014,  // 28. Clarke 1880 (SGA 1922)
149
    7042,  // 29. Everest (1830 Definition)
150
    7018,  // 30. Everest 1830 Modified
151
    7056,  // 31. Everest 1830 (RSO 1969)
152
    7045,  // 32. Everest 1830 (1975 Definition)
153
    7025,  // 33. NWL 9D
154
    7027,  // 34. Plessis 1817
155
    7028,  // 35. Struve 1860
156
    7029,  // 36. War Office
157
    7031,  // 37. GEM 10C
158
    7032,  // 38. OSU86F
159
    7033,  // 39. OSU91A
160
    7036,  // 40. GRS 1967
161
    7041,  // 41. Average Terrestrial System 1977
162
    7049,  // 42. IAG 1975
163
    7050,  // 43. GRS 1967 Modified
164
    7051,  // 44. Danish 1876
165
    7048,  // 45. GRS 1980 Authalic Sphere
166
    1025,  // 46. GSK 2011
167
    7054   // 47. PZ-90
168
};
169
170
constexpr int NUMBER_OF_PANORAM_ELLIPSOIDS =
171
    static_cast<int>(CPL_ARRAYSIZE(aoPanoramaEllips));
172
173
/************************************************************************/
174
/*       Correspondence between "Panorama" and EPSG vertical CS.        */
175
/************************************************************************/
176
177
constexpr int aoVCS[] = {
178
    0,     //0, 255, -1 - Undefined
179
    8357,  //1 Baltic 1957 height
180
    5711,  //2 AHD height
181
    5195,  //3 Trieste height
182
    5710,  //4 Ostend height - zero normal
183
    5710,  //5 Ostend height - null point de shosse
184
    0,     //6 Channel height (GB)
185
    5732,  //7 Belfast height
186
    5731,  //8 Malin Head height
187
    0,     //9 Dublib bay height
188
    5716,  //10 Piraeus height
189
    5733,  //11 DNN height
190
    8089,  //12 ISH2004 height
191
    5782,  //13 Alicante height
192
    0,     //14 Canary islands
193
    5214,  //15 Genoa height
194
    5709,  //16 NAP height
195
    5776,  //17 NN54 height
196
    0,     //18 North Norway
197
    5780,  //19 Cascais height
198
    5717,  //20 N60 height
199
    5613,  //21 RH2000 height
200
    0,     //22 France, Marseilles height
201
    5775,  //23 Antalya height
202
    5702,  //24 NGVD29 height (ftUS)
203
    5705,  //25 Baltic 1977 height
204
    0,     //26 Pacific Ocean (Ohotsk sea level)
205
    5714   //27 MSL height
206
};
207
208
constexpr int NUMBER_OF_VERTICALCS = static_cast<int>(CPL_ARRAYSIZE(aoVCS));
209
210
/************************************************************************/
211
/*                       OSRImportFromPanorama()                        */
212
/************************************************************************/
213
214
/** Import coordinate system from "Panorama" GIS projection definition.
215
 *
216
 * See OGRSpatialReference::importFromPanorama()
217
 */
218
219
OGRErr OSRImportFromPanorama(OGRSpatialReferenceH hSRS, long iProjSys,
220
                             long iDatum, long iEllips, double *padfPrjParams)
221
222
0
{
223
0
    VALIDATE_POINTER1(hSRS, "OSRImportFromPanorama", OGRERR_FAILURE);
224
225
0
    return reinterpret_cast<OGRSpatialReference *>(hSRS)->importFromPanorama(
226
0
        iProjSys, iDatum, iEllips, padfPrjParams);
227
0
}
228
229
/************************************************************************/
230
/*                         importFromPanorama()                         */
231
/************************************************************************/
232
233
/**
234
 * Import coordinate system from "Panorama" GIS projection definition.
235
 *
236
 * This method will import projection definition in style, used by
237
 * "Panorama" GIS.
238
 *
239
 * This function is the equivalent of the C function OSRImportFromPanorama().
240
 *
241
 * @param iProjSys Input projection system code, used in GIS "Panorama".
242
 *
243
 * Supported Projections are:
244
 * <ul>
245
 * <li>1:  Gauss-Kruger (Transverse Mercator)</li>
246
 * <li>2:  Lambert Conformal Conic 2SP</li>
247
 * <li>5:  Stereographic</li>
248
 * <li>6:  Azimuthal Equidistant (Postel)</li>
249
 * <li>8:  Mercator</li>
250
 * <li>10: Polyconic</li>
251
 * <li>13: Polar Stereographic</li>
252
 * <li>15: Gnomonic</li>
253
 * <li>17: Universal Transverse Mercator (UTM)</li>
254
 * <li>18: Wagner I (Kavraisky VI)</li>
255
 * <li>19: Mollweide</li>
256
 * <li>20: Equidistant Conic</li>
257
 * <li>24: Lambert Azimuthal Equal Area</li>
258
 * <li>27: Equirectangular</li>
259
 * <li>28: Cylindrical Equal Area (Lambert)</li>
260
 * <li>29: International Map of the World Polyconic</li>
261
 * </ul>
262
 *
263
 * @param iDatum Input coordinate system.
264
 *
265
 * Supported Datums are:
266
 * <ul>
267
 * <li>1:  Pulkovo, 1942</li>
268
 * <li>2:  WGS, 1984</li>
269
 * <li>3:  OSGB 1936 (British National Grid)</li>
270
 * <li>9:  Pulkovo, 1995</li>
271
 * <li>10: GSK 2011</li>
272
 * </ul>
273
 *
274
 * @param iEllips Input spheroid.
275
 *
276
 * Supported Spheroids are:
277
 * <ul>
278
 * <li>1:  Krassovsky, 1940</li>
279
 * <li>2:  WGS, 1972</li>
280
 * <li>3:  International, 1924 (Hayford, 1909)</li>
281
 * <li>4:  Clarke, 1880</li>
282
 * <li>5:  Clarke, 1866 (NAD1927)</li>
283
 * <li>6:  Everest, 1830</li>
284
 * <li>7:  Bessel, 1841</li>
285
 * <li>8:  Airy, 1830</li>
286
 * <li>9:  WGS, 1984 (GPS)</li>
287
 * <li>10: PZ-90.02</li>
288
 * <li>11: GRS, 1980 (NAD1983)</li>
289
 * <li>12: IERS 1996 (6378136.49 298.25645)</li>
290
 * <li>13: International, 1924 (Hayford, 1909)</li>
291
 * <li>14: South American, 1969</li>
292
 * <li>15: Indonesian, 1974</li>
293
 * <li>16: Helmert 1906</li>
294
 * <li>17: Fisher 1960</li>
295
 * <li>18: Fisher 1968</li>
296
 * <li>19. Haff 1960 - (6378270.0 297.0)</li>
297
 * <li>20: Everest, 1830</li>
298
 * <li>21: Australian National, 1965</li>
299
 * <li>22: CGCS2000</li>
300
 * <li>23: Airy Modified 1849</li>
301
 * <li>24: Bessel Modified</li>
302
 * <li>25: Bessel Namibia</li>
303
 * <li>26: Bessel Namibia (GLM)</li>
304
 * <li>27: Clarke 1880 (Arc)</li>
305
 * <li>28: Clarke 1880 (SGA 1922)</li>
306
 * <li>29: Everest (1830 Definition)</li>
307
 * <li>30: Everest 1830 Modified</li>
308
 * <li>31: Everest 1830 (RSO 1969)</li>
309
 * <li>32: Everest 1830 (1975 Definition)</li>
310
 * <li>33: NWL 9D</li>
311
 * <li>34: Plessis 1817</li>
312
 * <li>35: Struve 1860</li>
313
 * <li>36: War Office</li>
314
 * <li>37: GEM 10C</li>
315
 * <li>38: OSU86F</li>
316
 * <li>39: OSU91A</li>
317
 * <li>40: GRS 1967</li>
318
 * <li>41: Average Terrestrial System 1977</li>
319
 * <li>42: IAG 1975</li>
320
 * <li>43: GRS 1967 Modified</li>
321
 * <li>44: Danish 1876</li>
322
 * <li>45: GRS 1980 Authalic Sphere</li>
323
 * <li>46: GSK 2011</li>
324
 * <li>47: PZ-90</li>
325
 * </ul>
326
 *
327
 * @param padfPrjParams Array of 8 coordinate system parameters:
328
 *
329
 * <ul>
330
 * <li>[0]  Latitude of the first standard parallel (radians)</li>
331
 * <li>[1]  Latitude of the second standard parallel (radians)</li>
332
 * <li>[2]  Latitude of center of projection (radians)</li>
333
 * <li>[3]  Longitude of center of projection (radians)</li>
334
 * <li>[4]  Scaling factor</li>
335
 * <li>[5]  False Easting</li>
336
 * <li>[6]  False Northing</li>
337
 * <li>[7]  Zone number</li>
338
 * </ul>
339
 *
340
 * @param bNorth If northern hemisphere true, else false. Defaults to true.
341
 *
342
 * Particular projection uses different parameters, unused ones may be set to
343
 * zero. If NULL supplied instead of array pointer default values will be used
344
 * (i.e., zeroes).
345
 *
346
 * @return OGRERR_NONE on success or an error code in case of failure.
347
 */
348
349
OGRErr OGRSpatialReference::importFromPanorama(long iProjSys, long iDatum,
350
                                               long iEllips,
351
                                               double *padfPrjParams,
352
                                               bool bNorth)
353
354
758
{
355
758
    Clear();
356
357
    /* -------------------------------------------------------------------- */
358
    /*      Use safe defaults if projection parameters are not supplied.    */
359
    /* -------------------------------------------------------------------- */
360
758
    double adfPrjParams[8] = {0.0};
361
758
    if (padfPrjParams != nullptr)
362
758
    {
363
758
        std::copy(padfPrjParams, padfPrjParams + 8, adfPrjParams);
364
758
    }
365
366
758
    CPLDebug("OSR_Panorama",
367
758
             "importFromPanorama: proj %ld, datum %ld, ellips %ld, params [%f, "
368
758
             "%f, %f, %f, %f, %f, %f, %f], north %d",
369
758
             iProjSys, iDatum, iEllips, adfPrjParams[0], adfPrjParams[1],
370
758
             adfPrjParams[2], adfPrjParams[3], adfPrjParams[4], adfPrjParams[5],
371
758
             adfPrjParams[6], adfPrjParams[7], bNorth);
372
373
    // Check some zonal projections
374
758
    if ((IsNone(iEllips) || iEllips == PAN_ELLIPSOID_KRASSOVSKY) &&
375
522
        (IsNone(iDatum) || iDatum == PAN_DATUM_PULKOVO42) &&
376
464
        iProjSys == PAN_PROJ_TM)  // Pulkovo 1942 / Gauss-Kruger
377
312
    {
378
312
        int nZone = adfPrjParams[7] == 0.0
379
312
                        ? GetZoneNumberGK(TO_DEGREES * adfPrjParams[3])
380
312
                        : static_cast<int>(adfPrjParams[7]);
381
382
312
        if (nZone > 1 && nZone < 33)
383
235
        {
384
235
            return importFromEPSG(28400 + nZone);
385
235
        }
386
312
    }
387
523
    if ((IsNone(iEllips) || iEllips == PAN_ELLIPSOID_KRASSOVSKY) &&
388
287
        iDatum == PAN_DATUM_PULKOVO95 &&
389
1
        iProjSys == PAN_PROJ_TM)  // Pulkovo 1995 / Gauss-Kruger
390
1
    {
391
1
        int nZone = adfPrjParams[7] == 0.0
392
1
                        ? GetZoneNumberGK(TO_DEGREES * adfPrjParams[3])
393
1
                        : static_cast<int>(adfPrjParams[7]);
394
395
1
        if (nZone > 3 && nZone < 33)
396
0
        {
397
0
            return importFromEPSG(20000 + nZone);
398
0
        }
399
1
    }
400
523
    if (iEllips == PAN_ELLIPSOID_WGS84 && iDatum == PAN_DATUM_UTM &&
401
0
        iProjSys == PAN_PROJ_UTM)  // WGS84 / UTM
402
0
    {
403
0
        const int nZone = adfPrjParams[7] == 0.0
404
0
                              ? GetZoneNumberUTM(TO_DEGREES * adfPrjParams[3])
405
0
                              : static_cast<int>(adfPrjParams[7]);
406
0
        int nEPSG;
407
0
        if (bNorth)
408
0
        {
409
0
            nEPSG = 32600 + nZone;
410
0
        }
411
0
        else
412
0
        {
413
0
            nEPSG = 32700 + nZone;
414
0
        }
415
0
        return importFromEPSG(nEPSG);
416
0
    }
417
418
    /* -------------------------------------------------------------------- */
419
    /*      Operate on the basis of the projection code.                    */
420
    /* -------------------------------------------------------------------- */
421
523
    switch (iProjSys)
422
523
    {
423
0
        case -1L:
424
2
        case 255L:
425
2
            break;
426
427
0
        case PAN_PROJ_SPHERE:
428
0
            if (iEllips == PAN_ELLIPSOID_WGS84)
429
0
            {
430
0
                return SetWellKnownGeogCS("EPSG:4326");
431
0
            }
432
0
            break;
433
434
8
        case PAN_PROJ_UTM:
435
8
        {
436
8
            const int nZone =
437
8
                adfPrjParams[7] == 0.0
438
8
                    ? GetZoneNumberUTM(TO_DEGREES * adfPrjParams[3])
439
8
                    : static_cast<int>(adfPrjParams[7]);
440
441
8
            SetUTM(nZone, bNorth);
442
8
        }
443
8
        break;
444
445
0
        case PAN_PROJ_WAG1:
446
0
            SetWagner(1, 0.0, adfPrjParams[5], adfPrjParams[6]);
447
0
            break;
448
449
0
        case PAN_PROJ_MERCAT:
450
0
            SetMercator(TO_DEGREES * adfPrjParams[0],
451
0
                        TO_DEGREES * adfPrjParams[3], adfPrjParams[4],
452
0
                        adfPrjParams[5], adfPrjParams[6]);
453
0
            break;
454
455
0
        case PAN_PROJ_PS:
456
0
            SetPS(TO_DEGREES * adfPrjParams[2], TO_DEGREES * adfPrjParams[3],
457
0
                  adfPrjParams[4], adfPrjParams[5], adfPrjParams[6]);
458
0
            break;
459
460
0
        case PAN_PROJ_POLYC:
461
0
            SetPolyconic(TO_DEGREES * adfPrjParams[2],
462
0
                         TO_DEGREES * adfPrjParams[3], adfPrjParams[5],
463
0
                         adfPrjParams[6]);
464
0
            break;
465
466
0
        case PAN_PROJ_EC:
467
0
            SetEC(TO_DEGREES * adfPrjParams[0], TO_DEGREES * adfPrjParams[1],
468
0
                  TO_DEGREES * adfPrjParams[2], TO_DEGREES * adfPrjParams[3],
469
0
                  adfPrjParams[5], adfPrjParams[6]);
470
0
            break;
471
472
0
        case PAN_PROJ_LCC:
473
0
            SetLCC(TO_DEGREES * adfPrjParams[0], TO_DEGREES * adfPrjParams[1],
474
0
                   TO_DEGREES * adfPrjParams[2], TO_DEGREES * adfPrjParams[3],
475
0
                   adfPrjParams[5], adfPrjParams[6]);
476
0
            break;
477
478
169
        case PAN_PROJ_TM:
479
169
        {
480
            // XXX: we need zone number to compute false easting
481
            // parameter, because usually it is not contained in the
482
            // "Panorama" projection definition.
483
            // FIXME: what to do with negative values?
484
169
            int nZone = 0;
485
169
            double dfCenterLong = 0.0;
486
487
169
            if (adfPrjParams[7] == 0.0)
488
125
            {
489
125
                dfCenterLong = TO_DEGREES * adfPrjParams[3];
490
125
                nZone = GetZoneNumberGK(dfCenterLong);
491
125
            }
492
44
            else
493
44
            {
494
44
                nZone = static_cast<int>(adfPrjParams[7]);
495
44
                dfCenterLong = 6.0 * nZone - 3.0;
496
44
            }
497
498
169
            adfPrjParams[5] = nZone * 1000000.0 + 500000.0;
499
169
            adfPrjParams[4] = 1.0;
500
169
            SetTM(TO_DEGREES * adfPrjParams[2], dfCenterLong, adfPrjParams[4],
501
169
                  adfPrjParams[5], adfPrjParams[6]);
502
169
        }
503
169
        break;
504
505
0
        case PAN_PROJ_STEREO:
506
0
            SetStereographic(TO_DEGREES * adfPrjParams[2],
507
0
                             TO_DEGREES * adfPrjParams[3], adfPrjParams[4],
508
0
                             adfPrjParams[5], adfPrjParams[6]);
509
0
            break;
510
511
244
        case PAN_PROJ_AE:
512
244
            SetAE(TO_DEGREES * adfPrjParams[0], TO_DEGREES * adfPrjParams[3],
513
244
                  adfPrjParams[5], adfPrjParams[6]);
514
244
            break;
515
516
0
        case PAN_PROJ_GNOMON:
517
0
            SetGnomonic(TO_DEGREES * adfPrjParams[2],
518
0
                        TO_DEGREES * adfPrjParams[3], adfPrjParams[5],
519
0
                        adfPrjParams[6]);
520
0
            break;
521
522
0
        case PAN_PROJ_MOLL:
523
0
            SetMollweide(TO_DEGREES * adfPrjParams[3], adfPrjParams[5],
524
0
                         adfPrjParams[6]);
525
0
            break;
526
527
0
        case PAN_PROJ_LAEA:
528
0
            SetLAEA(TO_DEGREES * adfPrjParams[0], TO_DEGREES * adfPrjParams[3],
529
0
                    adfPrjParams[5], adfPrjParams[6]);
530
0
            break;
531
532
0
        case PAN_PROJ_EQC:
533
0
            SetEquirectangular(TO_DEGREES * adfPrjParams[0],
534
0
                               TO_DEGREES * adfPrjParams[3], adfPrjParams[5],
535
0
                               adfPrjParams[6]);
536
0
            break;
537
538
0
        case PAN_PROJ_CEA:
539
0
            SetCEA(TO_DEGREES * adfPrjParams[0], TO_DEGREES * adfPrjParams[3],
540
0
                   adfPrjParams[5], adfPrjParams[6]);
541
0
            break;
542
543
0
        case PAN_PROJ_IMWP:
544
0
            SetIWMPolyconic(
545
0
                TO_DEGREES * adfPrjParams[0], TO_DEGREES * adfPrjParams[1],
546
0
                TO_DEGREES * adfPrjParams[3], adfPrjParams[5], adfPrjParams[6]);
547
0
            break;
548
549
1
        case PAN_PROJ_MILLER:
550
1
            SetMC(TO_DEGREES * adfPrjParams[5], TO_DEGREES * adfPrjParams[4],
551
1
                  adfPrjParams[6], adfPrjParams[7]);
552
1
            break;
553
554
24
        case PAN_PROJ_PSEUDO_MERCATOR:
555
24
        {
556
24
            int nEPSG = 0;
557
24
            if (iEllips == PAN_ELLIPSOID_WGS84_SPHERE)
558
0
            {
559
0
                nEPSG = 3857;
560
0
            }
561
24
            else if (iEllips == PAN_ELLIPSOID_WGS84)
562
0
            {
563
0
                nEPSG = 3395;
564
0
            }
565
24
            if (nEPSG > 0)
566
0
            {
567
0
                return importFromEPSG(nEPSG);
568
0
            }
569
24
        }
570
24
        break;
571
572
75
        default:
573
75
            CPLDebug("OSR_Panorama", "Unsupported projection: %ld", iProjSys);
574
75
            SetLocalCS(CPLString().Printf("\"Panorama\" projection number %ld",
575
75
                                          iProjSys));
576
75
            break;
577
523
    }
578
579
    /* -------------------------------------------------------------------- */
580
    /*      Try to translate the datum/spheroid.                            */
581
    /* -------------------------------------------------------------------- */
582
583
523
    if (!IsLocal())
584
448
    {
585
448
        if (iEllips == PAN_ELLIPSOID_GSK2011 || iDatum == PAN_DATUM_GSK2011)
586
0
        {
587
0
            OGRSpatialReference oGCS;
588
0
            oGCS.importFromEPSG(7683);
589
0
            CopyGeogCSFrom(&oGCS);
590
0
        }
591
448
        else if (iEllips == PAN_ELLIPSOID_PZ90)
592
0
        {
593
0
            OGRSpatialReference oGCS;
594
0
            oGCS.importFromEPSG(7679);
595
0
            CopyGeogCSFrom(&oGCS);
596
0
        }
597
448
        else if (iDatum == PAN_DATUM_PULKOVO95)
598
1
        {
599
1
            OGRSpatialReference oGCS;
600
1
            oGCS.importFromEPSG(4200);
601
1
            CopyGeogCSFrom(&oGCS);
602
1
        }
603
447
        else if (iDatum > 0 && iDatum < NUMBER_OF_DATUMS && aoDatums[iDatum])
604
11
        {
605
11
            OGRSpatialReference oGCS;
606
11
            oGCS.importFromEPSG(aoDatums[iDatum]);
607
11
            CopyGeogCSFrom(&oGCS);
608
11
        }
609
436
        else if (iEllips > 0 && iEllips < NUMBER_OF_PANORAM_ELLIPSOIDS &&
610
53
                 aoPanoramaEllips[iEllips])
611
36
        {
612
36
            char *pszName = nullptr;
613
36
            double dfSemiMajor = 0.0;
614
36
            double dfInvFlattening = 0.0;
615
616
36
            if (OSRGetEllipsoidInfo(aoPanoramaEllips[iEllips], &pszName,
617
36
                                    &dfSemiMajor,
618
36
                                    &dfInvFlattening) == OGRERR_NONE)
619
36
            {
620
36
                SetGeogCS(
621
36
                    CPLString().Printf(
622
36
                        "Unknown datum based upon the %s ellipsoid", pszName),
623
36
                    CPLString().Printf("Not specified (based on %s spheroid)",
624
36
                                       pszName),
625
36
                    pszName, dfSemiMajor, dfInvFlattening, nullptr, 0.0,
626
36
                    nullptr, 0.0);
627
36
                SetAuthority("SPHEROID", "EPSG", aoPanoramaEllips[iEllips]);
628
36
            }
629
0
            else
630
0
            {
631
0
                CPLError(CE_Warning, CPLE_AppDefined,
632
0
                         "Failed to lookup ellipsoid code %ld. "
633
0
                         "Falling back to use Pulkovo 42.",
634
0
                         iEllips);
635
0
                SetWellKnownGeogCS("EPSG:4284");
636
0
            }
637
638
36
            CPLFree(pszName);
639
36
        }
640
400
        else
641
400
        {
642
400
            CPLError(CE_Warning, CPLE_AppDefined,
643
400
                     "Wrong datum code %ld. Supported datums are 1 - %d "
644
400
                     "only.  Falling back to use Pulkovo 42.",
645
400
                     iDatum, NUMBER_OF_DATUMS - 1);
646
400
            SetWellKnownGeogCS("EPSG:4284");
647
400
        }
648
448
    }
649
650
    /* -------------------------------------------------------------------- */
651
    /*      Grid units translation                                          */
652
    /* -------------------------------------------------------------------- */
653
523
    if (IsLocal() || IsProjected())
654
493
    {
655
493
        SetLinearUnits(SRS_UL_METER, 1.0);
656
493
    }
657
658
523
    return OGRERR_NONE;
659
523
}
660
661
/**
662
 * Import vertical coordinate system from "Panorama" GIS projection definition.
663
 *
664
 * @param iVCS Input vertical coordinate system ID.
665
 *
666
 * Supported VCS are:
667
 * <ul>
668
 * <li>1:  Baltic 1977 height (EPSG:5705)</li>
669
 * <li>2:  AHD height (EPSG:5711)</li>
670
 * <li>4:  Ostend height (EPSG:5710)</li>
671
 * <li>5:  Ostend height (EPSG:5710)</li>
672
 * <li>7:  Belfast height (EPSG: 5732)</li>
673
 * <li>8:  Malin Head height (EPSG: 5731)</li>
674
 * <li>10: Piraeus height (EPSG:5716)</li>
675
 * <li>11: DNN height (EPSG:5733)</li>
676
 * <li>12: ISH2004 height (EPSG:8089)</li>
677
 * <li>13: Alicante height (EPSG:5782)</li>
678
 * <li>15: Genoa height (EPSG:5214)</li>
679
 * <li>16: NAP height (EPSG:5709)</li>
680
 * <li>17: NN54 height (EPSG:5776)</li>
681
 * <li>19: Cascais height (EPSG:5780)</li>
682
 * <li>20: N60 height (EPSG:5717)</li>
683
 * <li>21: RH2000 height (EPSG:5613)</li>
684
 * <li>23: Antalya height (EPSG:5775)</li>
685
 * <li>24: NGVD29 height (ftUS) (EPSG:5702)</li>
686
 * <li>25: Baltic 1977 height (EPSG:5705)</li>
687
 * <li>27: MSL height (EPSG:5714)</li>
688
 * </ul>
689
 */
690
OGRErr OGRSpatialReference::importVertCSFromPanorama(int iVCS)
691
0
{
692
0
    if (iVCS < 0 || iVCS >= NUMBER_OF_VERTICALCS)
693
0
    {
694
0
        return OGRERR_CORRUPT_DATA;
695
0
    }
696
697
0
    const int nEPSG = aoVCS[iVCS];
698
699
0
    if (nEPSG == 0)
700
0
    {
701
0
        CPLError(CE_Warning, CPLE_NotSupported,
702
0
                 "Vertical coordinate system (Panorama index %d) not supported",
703
0
                 iVCS);
704
0
        return OGRERR_UNSUPPORTED_SRS;
705
0
    }
706
707
0
    OGRSpatialReference sr;
708
0
    sr.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
709
0
    OGRErr eImportFromEPSGErr = sr.importFromEPSG(nEPSG);
710
0
    if (eImportFromEPSGErr != OGRERR_NONE)
711
0
    {
712
0
        CPLError(CE_Warning, CPLE_None,
713
0
                 "Vertical coordinate system (Panorama index %d, EPSG %d) "
714
0
                 "import from EPSG error",
715
0
                 iVCS, nEPSG);
716
0
        return OGRERR_UNSUPPORTED_SRS;
717
0
    }
718
719
0
    if (sr.IsVertical() != 1)
720
0
    {
721
0
        CPLError(CE_Warning, CPLE_None,
722
0
                 "Coordinate system (Panorama index %d, EPSG %d) "
723
0
                 "is not Vertical",
724
0
                 iVCS, nEPSG);
725
0
        return OGRERR_UNSUPPORTED_SRS;
726
0
    }
727
728
0
    OGRErr eSetVertCSErr =
729
0
        SetVertCS(sr.GetAttrValue("VERT_CS"), sr.GetAttrValue("VERT_DATUM"));
730
0
    if (eSetVertCSErr != OGRERR_NONE)
731
0
    {
732
0
        CPLError(CE_Warning, CPLE_None,
733
0
                 "Vertical coordinate system (Panorama index %d, EPSG %d) "
734
0
                 "set error",
735
0
                 iVCS, nEPSG);
736
0
        return eSetVertCSErr;
737
0
    }
738
0
    return OGRERR_NONE;
739
0
}
740
741
/**
742
 * Export vertical coordinate system to "Panorama" GIS projection definition.
743
 */
744
OGRErr OGRSpatialReference::exportVertCSToPanorama(int *piVert) const
745
0
{
746
0
    auto pszVertCSName = GetAttrValue("COMPD_CS|VERT_CS");
747
0
    if (pszVertCSName != nullptr)
748
0
    {
749
0
        auto pszValue = GetAuthorityCode("COMPD_CS|VERT_CS");
750
0
        if (pszValue != nullptr)
751
0
        {
752
0
            auto nEPSG = atoi(pszValue);
753
0
            if (nEPSG > 0)
754
0
            {
755
0
                for (int i = 0; i < NUMBER_OF_VERTICALCS; i++)
756
0
                {
757
0
                    if (aoVCS[i] == nEPSG)
758
0
                    {
759
0
                        *piVert = i;
760
0
                        return OGRERR_NONE;
761
0
                    }
762
0
                }
763
0
            }
764
0
        }
765
0
        else  // Try to get Panorama ID from pszVertCSName
766
0
        {
767
0
            for (int i = 0; i < NUMBER_OF_VERTICALCS; i++)
768
0
            {
769
0
                if (aoVCS[i] > 0)
770
0
                {
771
0
                    OGRSpatialReference oTmpSRS;
772
0
                    oTmpSRS.importFromEPSG(aoVCS[i]);
773
0
                    if (EQUAL(pszVertCSName, oTmpSRS.GetAttrValue("VERT_CS")))
774
0
                    {
775
776
0
                        *piVert = i;
777
0
                        return OGRERR_NONE;
778
0
                    }
779
0
                }
780
0
            }
781
0
        }
782
0
    }
783
0
    CPLDebug("OSR_Panorama",
784
0
             "Vertical coordinate system not supported by Panorama");
785
0
    return OGRERR_UNSUPPORTED_SRS;
786
0
}
787
788
/************************************************************************/
789
/*                        OSRExportToPanorama()                         */
790
/************************************************************************/
791
792
/** Export coordinate system in "Panorama" GIS projection definition.
793
 *
794
 * See OGRSpatialReference::exportToPanorama()
795
 */
796
797
OGRErr OSRExportToPanorama(OGRSpatialReferenceH hSRS, long *piProjSys,
798
                           long *piDatum, long *piEllips, long *piZone,
799
                           double *padfPrjParams)
800
801
0
{
802
0
    VALIDATE_POINTER1(hSRS, "OSRExportToPanorama", OGRERR_FAILURE);
803
0
    VALIDATE_POINTER1(piProjSys, "OSRExportToPanorama", OGRERR_FAILURE);
804
0
    VALIDATE_POINTER1(piDatum, "OSRExportToPanorama", OGRERR_FAILURE);
805
0
    VALIDATE_POINTER1(piEllips, "OSRExportToPanorama", OGRERR_FAILURE);
806
0
    VALIDATE_POINTER1(padfPrjParams, "OSRExportToPanorama", OGRERR_FAILURE);
807
808
0
    return reinterpret_cast<OGRSpatialReference *>(hSRS)->exportToPanorama(
809
0
        piProjSys, piDatum, piEllips, piZone, padfPrjParams);
810
0
}
811
812
/************************************************************************/
813
/*                          exportToPanorama()                          */
814
/************************************************************************/
815
816
/**
817
 * Export coordinate system in "Panorama" GIS projection definition.
818
 *
819
 * This method is the equivalent of the C function OSRExportToPanorama().
820
 *
821
 * @param piProjSys Pointer to variable, where the projection system code will
822
 * be returned.
823
 *
824
 * @param piDatum Pointer to variable, where the coordinate system code will
825
 * be returned.
826
 *
827
 * @param piEllips Pointer to variable, where the spheroid code will be
828
 * returned.
829
 *
830
 * @param piZone Pointer to variable, where the zone for UTM projection
831
 * system will be returned.
832
 *
833
 * @param padfPrjParams an existing 7 double buffer into which the
834
 * projection parameters will be placed. See importFromPanorama()
835
 * for the list of parameters.
836
 *
837
 * @return OGRERR_NONE on success or an error code on failure.
838
 */
839
840
OGRErr OGRSpatialReference::exportToPanorama(long *piProjSys, long *piDatum,
841
                                             long *piEllips, long *piZone,
842
                                             double *padfPrjParams) const
843
844
0
{
845
0
    CPLAssert(padfPrjParams);
846
847
0
    const char *pszProjection = GetAttrValue("PROJECTION");
848
0
    int nEPSG = 0;
849
0
    auto pszEPSG = GetAuthorityCode("PROJCS");
850
0
    if (pszEPSG == nullptr)
851
0
    {
852
0
        pszEPSG = GetAuthorityCode("GEOGCS");
853
0
    }
854
0
    if (pszEPSG != nullptr)
855
0
    {
856
0
        nEPSG = atoi(pszEPSG);
857
0
    }
858
859
    /* -------------------------------------------------------------------- */
860
    /*      Fill all projection parameters with zero.                       */
861
    /* -------------------------------------------------------------------- */
862
0
    *piDatum = 0L;
863
0
    *piEllips = 0L;
864
0
    *piZone = 0L;
865
0
    for (int i = 0; i < 7; i++)
866
0
        padfPrjParams[i] = 0.0;
867
868
    /* ==================================================================== */
869
    /*      Handle the projection definition.                               */
870
    /* ==================================================================== */
871
0
    if (IsLocal())
872
0
    {
873
0
        *piProjSys = NONE_VAL;
874
0
    }
875
0
    else if (IsGeographic() || IsGeocentric())
876
0
    {
877
0
        *piProjSys = PAN_PROJ_SPHERE;
878
0
    }
879
    // Check well known EPSG codes
880
0
    else if (nEPSG == 3857)
881
0
    {
882
0
        *piProjSys = PAN_PROJ_PSEUDO_MERCATOR;
883
0
        *piDatum = PAN_DATUM_RECTANGULAR;
884
0
        *piEllips = PAN_ELLIPSOID_WGS84_SPHERE;
885
0
        return OGRERR_NONE;
886
0
    }
887
0
    else if (pszProjection == nullptr)
888
0
    {
889
#ifdef DEBUG
890
        CPLDebug("OSR_Panorama",
891
                 "Empty projection definition, considered as Geographic");
892
#endif
893
0
        *piProjSys = NONE_VAL;
894
0
    }
895
0
    else if (EQUAL(pszProjection, SRS_PT_MERCATOR_1SP))
896
0
    {
897
0
        *piProjSys = PAN_PROJ_MERCAT;
898
0
        padfPrjParams[3] =
899
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
900
0
        padfPrjParams[0] =
901
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
902
0
        padfPrjParams[4] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0);
903
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
904
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
905
0
    }
906
0
    else if (EQUAL(pszProjection, SRS_PT_POLAR_STEREOGRAPHIC))
907
0
    {
908
0
        *piProjSys = PAN_PROJ_PS;
909
0
        padfPrjParams[3] =
910
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
911
0
        padfPrjParams[2] =
912
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
913
0
        padfPrjParams[4] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0);
914
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
915
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
916
0
    }
917
0
    else if (EQUAL(pszProjection, SRS_PT_POLYCONIC))
918
0
    {
919
0
        *piProjSys = PAN_PROJ_POLYC;
920
0
        padfPrjParams[3] =
921
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
922
0
        padfPrjParams[2] =
923
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
924
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
925
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
926
0
    }
927
0
    else if (EQUAL(pszProjection, SRS_PT_EQUIDISTANT_CONIC))
928
0
    {
929
0
        *piProjSys = PAN_PROJ_EC;
930
0
        padfPrjParams[0] =
931
0
            TO_RADIANS * GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
932
0
        padfPrjParams[1] =
933
0
            TO_RADIANS * GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
934
0
        padfPrjParams[3] =
935
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
936
0
        padfPrjParams[2] =
937
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
938
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
939
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
940
0
    }
941
0
    else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP))
942
0
    {
943
0
        *piProjSys = PAN_PROJ_LCC;
944
0
        padfPrjParams[0] =
945
0
            TO_RADIANS * GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
946
0
        padfPrjParams[1] =
947
0
            TO_RADIANS * GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
948
0
        padfPrjParams[3] =
949
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
950
0
        padfPrjParams[2] =
951
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
952
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
953
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
954
0
    }
955
0
    else if (EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR))
956
0
    {
957
0
        int bNorth = FALSE;
958
959
0
        *piZone = GetUTMZone(&bNorth);
960
961
0
        auto dfCenterLong = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
962
0
        padfPrjParams[3] = TO_RADIANS * dfCenterLong;
963
0
        padfPrjParams[2] =
964
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
965
0
        padfPrjParams[4] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0);
966
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
967
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
968
969
0
        if (*piZone != 0)
970
0
        {
971
0
            *piProjSys = PAN_PROJ_UTM;
972
0
            if (!bNorth)
973
0
                *piZone = -*piZone;
974
0
        }
975
0
        else
976
0
        {
977
0
            *piProjSys = PAN_PROJ_TM;
978
0
            auto nZone = GetZoneNumberGK(dfCenterLong);
979
0
            *piZone = nZone;
980
0
        }
981
0
    }
982
0
    else if (EQUAL(pszProjection, SRS_PT_WAGNER_I))
983
0
    {
984
0
        *piProjSys = PAN_PROJ_WAG1;
985
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
986
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
987
0
    }
988
0
    else if (EQUAL(pszProjection, SRS_PT_STEREOGRAPHIC))
989
0
    {
990
0
        *piProjSys = PAN_PROJ_STEREO;
991
0
        padfPrjParams[3] =
992
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
993
0
        padfPrjParams[2] =
994
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
995
0
        padfPrjParams[4] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0);
996
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
997
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
998
0
    }
999
0
    else if (EQUAL(pszProjection, SRS_PT_AZIMUTHAL_EQUIDISTANT))
1000
0
    {
1001
0
        *piProjSys = PAN_PROJ_AE;
1002
0
        padfPrjParams[3] =
1003
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1004
0
        padfPrjParams[0] =
1005
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
1006
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
1007
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1008
0
    }
1009
0
    else if (EQUAL(pszProjection, SRS_PT_GNOMONIC))
1010
0
    {
1011
0
        *piProjSys = PAN_PROJ_GNOMON;
1012
0
        padfPrjParams[3] =
1013
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1014
0
        padfPrjParams[2] =
1015
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1016
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
1017
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1018
0
    }
1019
0
    else if (EQUAL(pszProjection, SRS_PT_MOLLWEIDE))
1020
0
    {
1021
0
        *piProjSys = PAN_PROJ_MOLL;
1022
0
        padfPrjParams[3] =
1023
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1024
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
1025
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1026
0
    }
1027
0
    else if (EQUAL(pszProjection, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA))
1028
0
    {
1029
0
        *piProjSys = PAN_PROJ_LAEA;
1030
0
        padfPrjParams[3] =
1031
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1032
0
        padfPrjParams[0] =
1033
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1034
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
1035
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1036
0
    }
1037
0
    else if (EQUAL(pszProjection, SRS_PT_EQUIRECTANGULAR))
1038
0
    {
1039
0
        *piProjSys = PAN_PROJ_EQC;
1040
0
        padfPrjParams[3] =
1041
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1042
0
        padfPrjParams[0] =
1043
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1044
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
1045
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1046
0
    }
1047
0
    else if (EQUAL(pszProjection, SRS_PT_CYLINDRICAL_EQUAL_AREA))
1048
0
    {
1049
0
        *piProjSys = PAN_PROJ_CEA;
1050
0
        padfPrjParams[3] =
1051
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1052
0
        padfPrjParams[2] =
1053
0
            TO_RADIANS * GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
1054
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
1055
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1056
0
    }
1057
0
    else if (EQUAL(pszProjection, SRS_PT_IMW_POLYCONIC))
1058
0
    {
1059
0
        *piProjSys = PAN_PROJ_IMWP;
1060
0
        padfPrjParams[3] =
1061
0
            TO_RADIANS * GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1062
0
        padfPrjParams[0] =
1063
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_1ST_POINT, 0.0);
1064
0
        padfPrjParams[1] =
1065
0
            TO_RADIANS * GetNormProjParm(SRS_PP_LATITUDE_OF_2ND_POINT, 0.0);
1066
0
        padfPrjParams[5] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
1067
0
        padfPrjParams[6] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1068
0
    }
1069
    // Projection unsupported by "Panorama" GIS
1070
0
    else
1071
0
    {
1072
0
        CPLDebug("OSR_Panorama",
1073
0
                 "Projection \"%s\" unsupported by \"Panorama\" GIS. "
1074
0
                 "Geographic system will be used.",
1075
0
                 pszProjection);
1076
0
        *piProjSys = NONE_VAL;
1077
0
    }
1078
1079
    /* -------------------------------------------------------------------- */
1080
    /*      Translate the datum.                                            */
1081
    /* -------------------------------------------------------------------- */
1082
0
    const char *pszDatum = GetAttrValue("DATUM");
1083
1084
0
    if (pszDatum == nullptr)
1085
0
    {
1086
0
        *piDatum = NONE_VAL;
1087
0
        *piEllips = NONE_VAL;
1088
0
    }
1089
0
    else if (EQUAL(pszDatum, "Pulkovo_1942"))
1090
0
    {
1091
0
        *piDatum = PAN_DATUM_PULKOVO42;
1092
0
        *piEllips = PAN_ELLIPSOID_KRASSOVSKY;
1093
0
    }
1094
0
    else if (EQUAL(pszDatum, "Pulkovo_1995"))
1095
0
    {
1096
0
        *piDatum = PAN_DATUM_PULKOVO95;
1097
0
        *piEllips = PAN_ELLIPSOID_KRASSOVSKY;
1098
0
    }
1099
0
    else if (EQUAL(pszDatum, SRS_DN_WGS84))
1100
0
    {
1101
0
        *piDatum = PAN_DATUM_RECTANGULAR;  // PAN_DATUM_WGS84;
1102
0
        *piEllips = PAN_ELLIPSOID_WGS84;
1103
0
    }
1104
1105
    // If not found well known datum, translate ellipsoid.
1106
0
    else
1107
0
    {
1108
0
        const double dfSemiMajor = GetSemiMajor();
1109
0
        const double dfInvFlattening = GetInvFlattening();
1110
1111
#ifdef DEBUG
1112
        CPLDebug("OSR_Panorama",
1113
                 "Datum \"%s\" unsupported by \"Panorama\" GIS. "
1114
                 "Trying to translate an ellipsoid definition.",
1115
                 pszDatum);
1116
#endif
1117
1118
0
        int i = 0;  // Used after for.
1119
0
        for (; i < NUMBER_OF_PANORAM_ELLIPSOIDS; i++)
1120
0
        {
1121
0
            if (aoPanoramaEllips[i])
1122
0
            {
1123
0
                double dfSM = 0.0;
1124
0
                double dfIF = 1.0;
1125
1126
0
                if (OSRGetEllipsoidInfo(aoPanoramaEllips[i], nullptr, &dfSM,
1127
0
                                        &dfIF) == OGRERR_NONE &&
1128
0
                    std::abs(dfSemiMajor - dfSM) < 1e-10 * dfSemiMajor &&
1129
0
                    std::abs(dfInvFlattening - dfIF) < 1e-10 * dfInvFlattening)
1130
0
                {
1131
0
                    *piEllips = i;
1132
0
                    break;
1133
0
                }
1134
0
            }
1135
0
        }
1136
1137
0
        if (i == NUMBER_OF_PANORAM_ELLIPSOIDS)  // Didn't found matches.
1138
0
        {
1139
#ifdef DEBUG
1140
            CPLDebug("OSR_Panorama",
1141
                     R"(Ellipsoid "%s" unsupported by "Panorama" GIS.)",
1142
                     pszDatum);
1143
#endif
1144
0
            *piDatum = NONE_VAL;
1145
0
            *piEllips = NONE_VAL;
1146
0
        }
1147
0
    }
1148
1149
0
    return OGRERR_NONE;
1150
0
}