Line data Source code
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 7 : OGRErr OSRImportFromERM(OGRSpatialReferenceH hSRS, const char *pszProj,
38 : const char *pszDatum, const char *pszUnits)
39 :
40 : {
41 7 : VALIDATE_POINTER1(hSRS, "OSRImportFromERM", OGRERR_FAILURE);
42 :
43 7 : return reinterpret_cast<OGRSpatialReference *>(hSRS)->importFromERM(
44 7 : pszProj, pszDatum, pszUnits);
45 : }
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 82 : OGRErr OGRSpatialReference::importFromERM(const char *pszProj,
66 : const char *pszDatum,
67 : const char *pszUnits)
68 :
69 : {
70 82 : Clear();
71 :
72 : /* -------------------------------------------------------------------- */
73 : /* do we have projection and datum? */
74 : /* -------------------------------------------------------------------- */
75 82 : if (EQUAL(pszProj, "RAW"))
76 45 : return OGRERR_NONE;
77 :
78 : /* -------------------------------------------------------------------- */
79 : /* Do we have an EPSG coordinate system? */
80 : /* -------------------------------------------------------------------- */
81 :
82 37 : if (STARTS_WITH_CI(pszProj, "EPSG:"))
83 3 : return importFromEPSG(atoi(pszProj + 5));
84 :
85 34 : if (STARTS_WITH_CI(pszDatum, "EPSG:"))
86 0 : return importFromEPSG(atoi(pszDatum + 5));
87 :
88 68 : CPLString osGEOGCS = lookupInDict("ecw_cs.wkt", pszDatum);
89 34 : if (osGEOGCS.empty())
90 2 : return OGRERR_UNSUPPORTED_SRS;
91 :
92 : /* -------------------------------------------------------------------- */
93 : /* Set projection if we have it. */
94 : /* -------------------------------------------------------------------- */
95 32 : if (!EQUAL(pszProj, "GEODETIC"))
96 : {
97 50 : CPLString osProjWKT = lookupInDict("ecw_cs.wkt", pszProj);
98 25 : if (osProjWKT.empty() || osProjWKT.back() != ']')
99 0 : return OGRERR_UNSUPPORTED_SRS;
100 :
101 25 : if (osProjWKT.find("LOCAL_CS[") == 0)
102 : {
103 0 : return importFromWkt(osProjWKT);
104 : }
105 :
106 : // Remove trailing ]
107 25 : osProjWKT.pop_back();
108 :
109 : // Remove any UNIT
110 25 : auto nPos = osProjWKT.find(",UNIT");
111 25 : if (nPos != std::string::npos)
112 : {
113 18 : osProjWKT.resize(nPos);
114 : }
115 :
116 : // Insert GEOGCS
117 25 : nPos = osProjWKT.find(",PROJECTION");
118 25 : if (nPos == std::string::npos)
119 0 : return OGRERR_UNSUPPORTED_SRS;
120 :
121 : osProjWKT =
122 25 : osProjWKT.substr(0, nPos) + ',' + osGEOGCS + osProjWKT.substr(nPos);
123 :
124 25 : if (EQUAL(pszUnits, "FEET"))
125 5 : osProjWKT += ",UNIT[\"Foot_US\",0.3048006096012192]]";
126 : else
127 20 : osProjWKT += ",UNIT[\"Metre\",1.0]]";
128 :
129 25 : return importFromWkt(osProjWKT);
130 : }
131 : else
132 : {
133 7 : return importFromWkt(osGEOGCS);
134 : }
135 : }
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 1 : OGRErr OSRExportToERM(OGRSpatialReferenceH hSRS, char *pszProj, char *pszDatum,
146 : char *pszUnits)
147 :
148 : {
149 1 : VALIDATE_POINTER1(hSRS, "OSRExportToERM", OGRERR_FAILURE);
150 :
151 1 : return reinterpret_cast<OGRSpatialReference *>(hSRS)->exportToERM(
152 1 : pszProj, pszDatum, pszUnits);
153 : }
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 52 : OGRErr OGRSpatialReference::exportToERM(char *pszProj, char *pszDatum,
171 : char *pszUnits)
172 :
173 : {
174 52 : const int BUFFER_SIZE = 32;
175 52 : strcpy(pszProj, "RAW");
176 52 : strcpy(pszDatum, "RAW");
177 52 : strcpy(pszUnits, "METERS");
178 :
179 52 : if (!IsProjected() && !IsGeographic())
180 0 : return OGRERR_UNSUPPORTED_SRS;
181 :
182 : /* -------------------------------------------------------------------- */
183 : /* Try to find the EPSG code. */
184 : /* -------------------------------------------------------------------- */
185 52 : int nEPSGCode = 0;
186 :
187 52 : if (IsProjected())
188 : {
189 6 : const char *pszAuthName = GetAuthorityName("PROJCS");
190 :
191 6 : if (pszAuthName != nullptr && EQUAL(pszAuthName, "epsg"))
192 : {
193 2 : nEPSGCode = atoi(GetAuthorityCode("PROJCS"));
194 : }
195 : }
196 46 : else if (IsGeographic())
197 : {
198 46 : const char *pszAuthName = GetAuthorityName("GEOGCS");
199 :
200 46 : if (pszAuthName != nullptr && EQUAL(pszAuthName, "epsg"))
201 : {
202 2 : nEPSGCode = atoi(GetAuthorityCode("GEOGCS"));
203 : }
204 : }
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Is our GEOGCS name already defined in ecw_cs.wkt? */
208 : /* -------------------------------------------------------------------- */
209 52 : const char *pszWKTDatum = GetAttrValue("DATUM");
210 :
211 104 : if (pszWKTDatum != nullptr &&
212 104 : !lookupInDict("ecw_cs.wkt", pszWKTDatum).empty())
213 : {
214 0 : strncpy(pszDatum, pszWKTDatum, BUFFER_SIZE);
215 0 : pszDatum[BUFFER_SIZE - 1] = '\0';
216 : }
217 :
218 : /* -------------------------------------------------------------------- */
219 : /* Is this a "well known" geographic coordinate system? */
220 : /* -------------------------------------------------------------------- */
221 52 : if (EQUAL(pszDatum, "RAW"))
222 : {
223 52 : int nEPSGGCSCode = GetEPSGGeogCS();
224 :
225 52 : if (nEPSGGCSCode == 4326)
226 4 : strcpy(pszDatum, "WGS84");
227 :
228 48 : else if (nEPSGGCSCode == 4322)
229 0 : strcpy(pszDatum, "WGS72DOD");
230 :
231 48 : else if (nEPSGGCSCode == 4267)
232 2 : strcpy(pszDatum, "NAD27");
233 :
234 46 : else if (nEPSGGCSCode == 4269)
235 0 : strcpy(pszDatum, "NAD83");
236 :
237 46 : else if (nEPSGGCSCode == 4277)
238 0 : strcpy(pszDatum, "OSGB36");
239 :
240 46 : else if (nEPSGGCSCode == 4278)
241 0 : strcpy(pszDatum, "OSGB78");
242 :
243 46 : else if (nEPSGGCSCode == 4201)
244 0 : strcpy(pszDatum, "ADINDAN");
245 :
246 46 : else if (nEPSGGCSCode == 4202)
247 0 : strcpy(pszDatum, "AGD66");
248 :
249 46 : else if (nEPSGGCSCode == 4203)
250 0 : strcpy(pszDatum, "AGD84");
251 :
252 46 : else if (nEPSGGCSCode == 4209)
253 0 : strcpy(pszDatum, "ARC1950");
254 :
255 46 : else if (nEPSGGCSCode == 4210)
256 0 : strcpy(pszDatum, "ARC1960");
257 :
258 46 : else if (nEPSGGCSCode == 4275)
259 0 : strcpy(pszDatum, "NTF");
260 :
261 46 : else if (nEPSGGCSCode == 4283)
262 0 : strcpy(pszDatum, "GDA94");
263 :
264 46 : else if (nEPSGGCSCode == 4284)
265 0 : strcpy(pszDatum, "PULKOVO");
266 :
267 46 : else if (nEPSGGCSCode == 7844)
268 1 : strcpy(pszDatum, "GDA2020");
269 : }
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Are we working with a geographic (geodetic) coordinate system? */
273 : /* -------------------------------------------------------------------- */
274 :
275 52 : if (IsGeographic())
276 : {
277 46 : if (EQUAL(pszDatum, "RAW"))
278 44 : return OGRERR_UNSUPPORTED_SRS;
279 : else
280 : {
281 2 : strcpy(pszProj, "GEODETIC");
282 2 : return OGRERR_NONE;
283 : }
284 : }
285 :
286 : /* -------------------------------------------------------------------- */
287 : /* Is this a UTM projection? */
288 : /* -------------------------------------------------------------------- */
289 6 : int bNorth = FALSE;
290 6 : int nZone = 0;
291 :
292 6 : nZone = GetUTMZone(&bNorth);
293 6 : if (nZone > 0)
294 : {
295 4 : if ((EQUAL(pszDatum, "GDA94") || EQUAL(pszDatum, "GDA2020")) &&
296 1 : !bNorth && nZone >= 48 && nZone <= 58)
297 : {
298 1 : snprintf(pszProj, BUFFER_SIZE, "MGA%02d", nZone);
299 : }
300 : else
301 : {
302 3 : if (bNorth)
303 3 : snprintf(pszProj, BUFFER_SIZE, "NUTM%02d", nZone);
304 : else
305 0 : snprintf(pszProj, BUFFER_SIZE, "SUTM%02d", nZone);
306 : }
307 : }
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* Is our PROJCS name already defined in ecw_cs.wkt? */
311 : /* -------------------------------------------------------------------- */
312 : else
313 : {
314 2 : const char *pszPROJCS = GetAttrValue("PROJCS");
315 :
316 4 : if (pszPROJCS != nullptr &&
317 4 : lookupInDict("ecw_cs.wkt", pszPROJCS).find("PROJCS") == 0)
318 : {
319 1 : strncpy(pszProj, pszPROJCS, BUFFER_SIZE);
320 1 : pszProj[BUFFER_SIZE - 1] = '\0';
321 : }
322 : }
323 :
324 : /* -------------------------------------------------------------------- */
325 : /* If we have not translated it yet, but we have an EPSG code */
326 : /* then use EPSG:n notation. */
327 : /* -------------------------------------------------------------------- */
328 6 : if ((EQUAL(pszDatum, "RAW") || EQUAL(pszProj, "RAW")) && nEPSGCode != 0)
329 : {
330 0 : snprintf(pszProj, BUFFER_SIZE, "EPSG:%d", nEPSGCode);
331 0 : snprintf(pszDatum, BUFFER_SIZE, "EPSG:%d", nEPSGCode);
332 : }
333 :
334 : /* -------------------------------------------------------------------- */
335 : /* Handle the units. */
336 : /* -------------------------------------------------------------------- */
337 6 : const double dfUnits = GetLinearUnits();
338 :
339 6 : if (fabs(dfUnits - 0.3048) < 0.0001)
340 1 : strcpy(pszUnits, "FEET");
341 : else
342 5 : strcpy(pszUnits, "METERS");
343 :
344 6 : if (EQUAL(pszProj, "RAW"))
345 1 : return OGRERR_UNSUPPORTED_SRS;
346 :
347 5 : return OGRERR_NONE;
348 : }
|