Coverage Report

Created: 2026-06-30 08:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogr_srs_erm.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implement ERMapper projection conversions.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "ogr_srs_api.h"
16
17
#include <cmath>
18
#include <cstdio>
19
#include <cstdlib>
20
#include <cstring>
21
22
#include "cpl_conv.h"
23
#include "cpl_error.h"
24
#include "ogr_core.h"
25
#include "ogr_spatialref.h"
26
27
/************************************************************************/
28
/*                          OSRImportFromERM()                          */
29
/************************************************************************/
30
31
/**
32
 * \brief Create OGR WKT from ERMapper projection definitions.
33
 *
34
 * This function is the same as OGRSpatialReference::importFromERM().
35
 */
36
37
OGRErr OSRImportFromERM(OGRSpatialReferenceH hSRS, const char *pszProj,
38
                        const char *pszDatum, const char *pszUnits)
39
40
0
{
41
0
    VALIDATE_POINTER1(hSRS, "OSRImportFromERM", OGRERR_FAILURE);
42
43
0
    return reinterpret_cast<OGRSpatialReference *>(hSRS)->importFromERM(
44
0
        pszProj, pszDatum, pszUnits);
45
0
}
46
47
/************************************************************************/
48
/*                           importFromERM()                            */
49
/************************************************************************/
50
51
/**
52
 * Create OGR WKT from ERMapper projection definitions.
53
 *
54
 * Generates an OGRSpatialReference definition from an ERMapper datum
55
 * and projection name.  Based on the ecw_cs.wkt dictionary file from
56
 * gdal/data.
57
 *
58
 * @param pszProj the projection name, such as "NUTM11" or "GEOGRAPHIC".
59
 * @param pszDatum the datum name, such as "NAD83".
60
 * @param pszUnits the linear units "FEET" or "METERS".
61
 *
62
 * @return OGRERR_NONE on success or OGRERR_UNSUPPORTED_SRS if not found.
63
 */
64
65
OGRErr OGRSpatialReference::importFromERM(const char *pszProj,
66
                                          const char *pszDatum,
67
                                          const char *pszUnits)
68
69
1
{
70
1
    Clear();
71
72
    /* -------------------------------------------------------------------- */
73
    /*      do we have projection and datum?                                */
74
    /* -------------------------------------------------------------------- */
75
1
    if (EQUAL(pszProj, "RAW"))
76
1
        return OGRERR_NONE;
77
78
    /* -------------------------------------------------------------------- */
79
    /*      Do we have an EPSG coordinate system?                           */
80
    /* -------------------------------------------------------------------- */
81
82
0
    if (STARTS_WITH_CI(pszProj, "EPSG:"))
83
0
        return importFromEPSG(atoi(pszProj + 5));
84
85
0
    if (STARTS_WITH_CI(pszDatum, "EPSG:"))
86
0
        return importFromEPSG(atoi(pszDatum + 5));
87
88
0
    CPLString osGEOGCS = lookupInDict("ecw_cs.wkt", pszDatum);
89
0
    if (osGEOGCS.empty())
90
0
        return OGRERR_UNSUPPORTED_SRS;
91
92
    /* -------------------------------------------------------------------- */
93
    /*      Set projection if we have it.                                   */
94
    /* -------------------------------------------------------------------- */
95
0
    if (!EQUAL(pszProj, "GEODETIC"))
96
0
    {
97
0
        CPLString osProjWKT = lookupInDict("ecw_cs.wkt", pszProj);
98
0
        if (osProjWKT.empty() || osProjWKT.back() != ']')
99
0
            return OGRERR_UNSUPPORTED_SRS;
100
101
0
        if (osProjWKT.find("LOCAL_CS[") == 0)
102
0
        {
103
0
            return importFromWkt(osProjWKT);
104
0
        }
105
106
        // Remove trailing ]
107
0
        osProjWKT.pop_back();
108
109
        // Remove any UNIT
110
0
        auto nPos = osProjWKT.find(",UNIT");
111
0
        if (nPos != std::string::npos)
112
0
        {
113
0
            osProjWKT.resize(nPos);
114
0
        }
115
116
        // Insert GEOGCS
117
0
        nPos = osProjWKT.find(",PROJECTION");
118
0
        if (nPos == std::string::npos)
119
0
            return OGRERR_UNSUPPORTED_SRS;
120
121
0
        osProjWKT =
122
0
            osProjWKT.substr(0, nPos) + ',' + osGEOGCS + osProjWKT.substr(nPos);
123
124
0
        if (EQUAL(pszUnits, "FEET"))
125
0
            osProjWKT += ",UNIT[\"Foot_US\",0.3048006096012192]]";
126
0
        else
127
0
            osProjWKT += ",UNIT[\"Metre\",1.0]]";
128
129
0
        return importFromWkt(osProjWKT);
130
0
    }
131
0
    else
132
0
    {
133
0
        return importFromWkt(osGEOGCS);
134
0
    }
135
0
}
136
137
/************************************************************************/
138
/*                           OSRExportToERM()                           */
139
/************************************************************************/
140
/**
141
 * \brief Convert coordinate system to ERMapper format.
142
 *
143
 * This function is the same as OGRSpatialReference::exportToERM().
144
 */
145
OGRErr OSRExportToERM(OGRSpatialReferenceH hSRS, char *pszProj, char *pszDatum,
146
                      char *pszUnits)
147
148
0
{
149
0
    VALIDATE_POINTER1(hSRS, "OSRExportToERM", OGRERR_FAILURE);
150
151
0
    return reinterpret_cast<OGRSpatialReference *>(hSRS)->exportToERM(
152
0
        pszProj, pszDatum, pszUnits);
153
0
}
154
155
/************************************************************************/
156
/*                            exportToERM()                             */
157
/************************************************************************/
158
159
/**
160
 * Convert coordinate system to ERMapper format.
161
 *
162
 * @param pszProj 32 character buffer to receive projection name.
163
 * @param pszDatum 32 character buffer to receive datum name.
164
 * @param pszUnits 32 character buffer to receive units name.
165
 *
166
 * @return OGRERR_NONE on success, OGRERR_SRS_UNSUPPORTED if not translation is
167
 * found, or OGRERR_FAILURE on other failures.
168
 */
169
170
OGRErr OGRSpatialReference::exportToERM(char *pszProj, char *pszDatum,
171
                                        char *pszUnits)
172
173
0
{
174
0
    const int BUFFER_SIZE = 32;
175
0
    strcpy(pszProj, "RAW");
176
0
    strcpy(pszDatum, "RAW");
177
0
    strcpy(pszUnits, "METERS");
178
179
0
    if (!IsProjected() && !IsGeographic())
180
0
        return OGRERR_UNSUPPORTED_SRS;
181
182
    /* -------------------------------------------------------------------- */
183
    /*      Try to find the EPSG code.                                      */
184
    /* -------------------------------------------------------------------- */
185
0
    int nEPSGCode = 0;
186
187
0
    if (IsProjected())
188
0
    {
189
0
        const char *pszAuthName = GetAuthorityName("PROJCS");
190
191
0
        if (pszAuthName != nullptr && EQUAL(pszAuthName, "epsg"))
192
0
        {
193
0
            nEPSGCode = atoi(GetAuthorityCode("PROJCS"));
194
0
        }
195
0
    }
196
0
    else if (IsGeographic())
197
0
    {
198
0
        const char *pszAuthName = GetAuthorityName("GEOGCS");
199
200
0
        if (pszAuthName != nullptr && EQUAL(pszAuthName, "epsg"))
201
0
        {
202
0
            nEPSGCode = atoi(GetAuthorityCode("GEOGCS"));
203
0
        }
204
0
    }
205
206
    /* -------------------------------------------------------------------- */
207
    /*      Is our GEOGCS name already defined in ecw_cs.wkt?               */
208
    /* -------------------------------------------------------------------- */
209
0
    const char *pszWKTDatum = GetAttrValue("DATUM");
210
211
0
    if (pszWKTDatum != nullptr &&
212
0
        !lookupInDict("ecw_cs.wkt", pszWKTDatum).empty())
213
0
    {
214
0
        strncpy(pszDatum, pszWKTDatum, BUFFER_SIZE);
215
0
        pszDatum[BUFFER_SIZE - 1] = '\0';
216
0
    }
217
218
    /* -------------------------------------------------------------------- */
219
    /*      Is this a "well known" geographic coordinate system?            */
220
    /* -------------------------------------------------------------------- */
221
0
    if (EQUAL(pszDatum, "RAW"))
222
0
    {
223
0
        int nEPSGGCSCode = GetEPSGGeogCS();
224
225
0
        if (nEPSGGCSCode == 4326)
226
0
            strcpy(pszDatum, "WGS84");
227
228
0
        else if (nEPSGGCSCode == 4322)
229
0
            strcpy(pszDatum, "WGS72DOD");
230
231
0
        else if (nEPSGGCSCode == 4267)
232
0
            strcpy(pszDatum, "NAD27");
233
234
0
        else if (nEPSGGCSCode == 4269)
235
0
            strcpy(pszDatum, "NAD83");
236
237
0
        else if (nEPSGGCSCode == 4277)
238
0
            strcpy(pszDatum, "OSGB36");
239
240
0
        else if (nEPSGGCSCode == 4278)
241
0
            strcpy(pszDatum, "OSGB78");
242
243
0
        else if (nEPSGGCSCode == 4201)
244
0
            strcpy(pszDatum, "ADINDAN");
245
246
0
        else if (nEPSGGCSCode == 4202)
247
0
            strcpy(pszDatum, "AGD66");
248
249
0
        else if (nEPSGGCSCode == 4203)
250
0
            strcpy(pszDatum, "AGD84");
251
252
0
        else if (nEPSGGCSCode == 4209)
253
0
            strcpy(pszDatum, "ARC1950");
254
255
0
        else if (nEPSGGCSCode == 4210)
256
0
            strcpy(pszDatum, "ARC1960");
257
258
0
        else if (nEPSGGCSCode == 4275)
259
0
            strcpy(pszDatum, "NTF");
260
261
0
        else if (nEPSGGCSCode == 4283)
262
0
            strcpy(pszDatum, "GDA94");
263
264
0
        else if (nEPSGGCSCode == 4284)
265
0
            strcpy(pszDatum, "PULKOVO");
266
267
0
        else if (nEPSGGCSCode == 7844)
268
0
            strcpy(pszDatum, "GDA2020");
269
0
    }
270
271
    /* -------------------------------------------------------------------- */
272
    /*      Are we working with a geographic (geodetic) coordinate system?  */
273
    /* -------------------------------------------------------------------- */
274
275
0
    if (IsGeographic())
276
0
    {
277
0
        if (EQUAL(pszDatum, "RAW"))
278
0
            return OGRERR_UNSUPPORTED_SRS;
279
0
        else
280
0
        {
281
0
            strcpy(pszProj, "GEODETIC");
282
0
            return OGRERR_NONE;
283
0
        }
284
0
    }
285
286
    /* -------------------------------------------------------------------- */
287
    /*      Is this a UTM projection?                                       */
288
    /* -------------------------------------------------------------------- */
289
0
    int bNorth = FALSE;
290
0
    int nZone = 0;
291
292
0
    nZone = GetUTMZone(&bNorth);
293
0
    if (nZone > 0)
294
0
    {
295
0
        if ((EQUAL(pszDatum, "GDA94") || EQUAL(pszDatum, "GDA2020")) &&
296
0
            !bNorth && nZone >= 48 && nZone <= 58)
297
0
        {
298
0
            snprintf(pszProj, BUFFER_SIZE, "MGA%02d", nZone);
299
0
        }
300
0
        else
301
0
        {
302
0
            if (bNorth)
303
0
                snprintf(pszProj, BUFFER_SIZE, "NUTM%02d", nZone);
304
0
            else
305
0
                snprintf(pszProj, BUFFER_SIZE, "SUTM%02d", nZone);
306
0
        }
307
0
    }
308
309
    /* -------------------------------------------------------------------- */
310
    /*      Is our PROJCS name already defined in ecw_cs.wkt?               */
311
    /* -------------------------------------------------------------------- */
312
0
    else
313
0
    {
314
0
        const char *pszPROJCS = GetAttrValue("PROJCS");
315
316
0
        if (pszPROJCS != nullptr &&
317
0
            lookupInDict("ecw_cs.wkt", pszPROJCS).find("PROJCS") == 0)
318
0
        {
319
0
            strncpy(pszProj, pszPROJCS, BUFFER_SIZE);
320
0
            pszProj[BUFFER_SIZE - 1] = '\0';
321
0
        }
322
0
    }
323
324
    /* -------------------------------------------------------------------- */
325
    /*      If we have not translated it yet, but we have an EPSG code      */
326
    /*      then use EPSG:n notation.                                       */
327
    /* -------------------------------------------------------------------- */
328
0
    if ((EQUAL(pszDatum, "RAW") || EQUAL(pszProj, "RAW")) && nEPSGCode != 0)
329
0
    {
330
0
        snprintf(pszProj, BUFFER_SIZE, "EPSG:%d", nEPSGCode);
331
0
        snprintf(pszDatum, BUFFER_SIZE, "EPSG:%d", nEPSGCode);
332
0
    }
333
334
    /* -------------------------------------------------------------------- */
335
    /*      Handle the units.                                               */
336
    /* -------------------------------------------------------------------- */
337
0
    const double dfUnits = GetLinearUnits();
338
339
0
    if (fabs(dfUnits - 0.3048) < 0.0001)
340
0
        strcpy(pszUnits, "FEET");
341
0
    else
342
0
        strcpy(pszUnits, "METERS");
343
344
0
    if (EQUAL(pszProj, "RAW"))
345
0
        return OGRERR_UNSUPPORTED_SRS;
346
347
0
    return OGRERR_NONE;
348
0
}