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 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "cpl_port.h"
31 #include "ogr_srs_api.h"
32
33 #include <cmath>
34 #include <cstdio>
35 #include <cstdlib>
36 #include <cstring>
37
38 #include "cpl_conv.h"
39 #include "cpl_error.h"
40 #include "ogr_core.h"
41 #include "ogr_spatialref.h"
42
43 CPL_CVSID("$Id: ogr_srs_erm.cpp b1c9c12ad373e40b955162b45d704070d4ebf7b0 2019-06-19 16:50:15 +0200 Even Rouault $")
44
45 /************************************************************************/
46 /* OSRImportFromERM() */
47 /************************************************************************/
48
49 /**
50 * \brief Create OGR WKT from ERMapper projection definitions.
51 *
52 * This function is the same as OGRSpatialReference::importFromERM().
53 */
54
OSRImportFromERM(OGRSpatialReferenceH hSRS,const char * pszProj,const char * pszDatum,const char * pszUnits)55 OGRErr OSRImportFromERM( OGRSpatialReferenceH hSRS, const char *pszProj,
56 const char *pszDatum, const char *pszUnits )
57
58 {
59 VALIDATE_POINTER1( hSRS, "OSRImportFromERM", OGRERR_FAILURE );
60
61 return reinterpret_cast<OGRSpatialReference *>(hSRS)->
62 importFromERM(pszProj, pszDatum, pszUnits);
63 }
64
65 /************************************************************************/
66 /* importFromERM() */
67 /************************************************************************/
68
69 /**
70 * Create OGR WKT from ERMapper projection definitions.
71 *
72 * Generates an OGRSpatialReference definition from an ERMapper datum
73 * and projection name. Based on the ecw_cs.wkt dictionary file from
74 * gdal/data.
75 *
76 * @param pszProj the projection name, such as "NUTM11" or "GEOGRAPHIC".
77 * @param pszDatum the datum name, such as "NAD83".
78 * @param pszUnits the linear units "FEET" or "METERS".
79 *
80 * @return OGRERR_NONE on success or OGRERR_UNSUPPORTED_SRS if not found.
81 */
82
importFromERM(const char * pszProj,const char * pszDatum,const char * pszUnits)83 OGRErr OGRSpatialReference::importFromERM( const char *pszProj,
84 const char *pszDatum,
85 const char *pszUnits )
86
87 {
88 Clear();
89
90 /* -------------------------------------------------------------------- */
91 /* do we have projection and datum? */
92 /* -------------------------------------------------------------------- */
93 if( EQUAL(pszProj, "RAW") )
94 return OGRERR_NONE;
95
96 /* -------------------------------------------------------------------- */
97 /* Do we have an EPSG coordinate system? */
98 /* -------------------------------------------------------------------- */
99
100 if( STARTS_WITH_CI(pszProj, "EPSG:") )
101 return importFromEPSG( atoi(pszProj+5) );
102
103 if( STARTS_WITH_CI(pszDatum, "EPSG:") )
104 return importFromEPSG( atoi(pszDatum+5) );
105
106
107 CPLString osGEOGCS = lookupInDict( "ecw_cs.wkt", pszDatum );
108 if( osGEOGCS.empty() )
109 return OGRERR_UNSUPPORTED_SRS;
110
111 /* -------------------------------------------------------------------- */
112 /* Set projection if we have it. */
113 /* -------------------------------------------------------------------- */
114 if( !EQUAL(pszProj, "GEODETIC") )
115 {
116 CPLString osProjWKT = lookupInDict( "ecw_cs.wkt", pszProj );
117 if( osProjWKT.empty() || osProjWKT.back() != ']' )
118 return OGRERR_UNSUPPORTED_SRS;
119
120 if( osProjWKT.find("LOCAL_CS[") == 0 )
121 {
122 return importFromWkt(osProjWKT);
123 }
124
125 // Remove trailing ]
126 osProjWKT.resize(osProjWKT.size() - 1);
127
128 // Remove any UNIT
129 auto nPos = osProjWKT.find(",UNIT");
130 if( nPos != std::string::npos )
131 {
132 osProjWKT.resize(nPos);
133 }
134
135 // Insert GEOGCS
136 nPos = osProjWKT.find(",PROJECTION");
137 if( nPos == std::string::npos )
138 return OGRERR_UNSUPPORTED_SRS;
139
140 osProjWKT = osProjWKT.substr(0, nPos) + ',' + osGEOGCS + osProjWKT.substr(nPos);
141
142 if( EQUAL(pszUnits, "FEET") )
143 osProjWKT += ",UNIT[\"Foot_US\",0.3048006096012192]]";
144 else
145 osProjWKT += ",UNIT[\"Metre\",1.0]]";
146
147 return importFromWkt(osProjWKT);
148 }
149 else
150 {
151 return importFromWkt(osGEOGCS);
152 }
153 }
154
155 /************************************************************************/
156 /* OSRExportToERM() */
157 /************************************************************************/
158 /**
159 * \brief Convert coordinate system to ERMapper format.
160 *
161 * This function is the same as OGRSpatialReference::exportToERM().
162 */
OSRExportToERM(OGRSpatialReferenceH hSRS,char * pszProj,char * pszDatum,char * pszUnits)163 OGRErr OSRExportToERM( OGRSpatialReferenceH hSRS,
164 char *pszProj, char *pszDatum, char *pszUnits )
165
166 {
167 VALIDATE_POINTER1( hSRS, "OSRExportToERM", OGRERR_FAILURE );
168
169 return reinterpret_cast<OGRSpatialReference *>(hSRS)->
170 exportToERM(pszProj, pszDatum, pszUnits);
171 }
172
173 /************************************************************************/
174 /* exportToERM() */
175 /************************************************************************/
176
177 /**
178 * Convert coordinate system to ERMapper format.
179 *
180 * @param pszProj 32 character buffer to receive projection name.
181 * @param pszDatum 32 character buffer to receive datum name.
182 * @param pszUnits 32 character buffer to receive units name.
183 *
184 * @return OGRERR_NONE on success, OGRERR_SRS_UNSUPPORTED if not translation is
185 * found, or OGRERR_FAILURE on other failures.
186 */
187
exportToERM(char * pszProj,char * pszDatum,char * pszUnits)188 OGRErr OGRSpatialReference::exportToERM( char *pszProj, char *pszDatum,
189 char *pszUnits )
190
191 {
192 const int BUFFER_SIZE = 32;
193 strcpy( pszProj, "RAW" );
194 strcpy( pszDatum, "RAW" );
195 strcpy( pszUnits, "METERS" );
196
197 if( !IsProjected() && !IsGeographic() )
198 return OGRERR_UNSUPPORTED_SRS;
199
200 /* -------------------------------------------------------------------- */
201 /* Try to find the EPSG code. */
202 /* -------------------------------------------------------------------- */
203 int nEPSGCode = 0;
204
205 if( IsProjected() )
206 {
207 const char *pszAuthName = GetAuthorityName( "PROJCS" );
208
209 if( pszAuthName != nullptr && EQUAL(pszAuthName, "epsg") )
210 {
211 nEPSGCode = atoi(GetAuthorityCode( "PROJCS" ));
212 }
213 }
214 else if( IsGeographic() )
215 {
216 const char *pszAuthName = GetAuthorityName( "GEOGCS" );
217
218 if( pszAuthName != nullptr && EQUAL(pszAuthName, "epsg") )
219 {
220 nEPSGCode = atoi(GetAuthorityCode( "GEOGCS" ));
221 }
222 }
223
224 /* -------------------------------------------------------------------- */
225 /* Is our GEOGCS name already defined in ecw_cs.wkt? */
226 /* -------------------------------------------------------------------- */
227 const char *pszWKTDatum = GetAttrValue( "DATUM" );
228
229 if( pszWKTDatum != nullptr
230 && !lookupInDict( "ecw_cs.wkt", pszWKTDatum ).empty() )
231 {
232 strncpy( pszDatum, pszWKTDatum, BUFFER_SIZE );
233 pszDatum[BUFFER_SIZE-1] = '\0';
234 }
235
236 /* -------------------------------------------------------------------- */
237 /* Is this a "well known" geographic coordinate system? */
238 /* -------------------------------------------------------------------- */
239 if( EQUAL(pszDatum, "RAW") )
240 {
241 int nEPSGGCSCode = GetEPSGGeogCS();
242
243 if( nEPSGGCSCode == 4326 )
244 strcpy( pszDatum, "WGS84" );
245
246 else if( nEPSGGCSCode == 4322 )
247 strcpy( pszDatum, "WGS72DOD" );
248
249 else if( nEPSGGCSCode == 4267 )
250 strcpy( pszDatum, "NAD27" );
251
252 else if( nEPSGGCSCode == 4269 )
253 strcpy( pszDatum, "NAD83" );
254
255 else if( nEPSGGCSCode == 4277 )
256 strcpy( pszDatum, "OSGB36" );
257
258 else if( nEPSGGCSCode == 4278 )
259 strcpy( pszDatum, "OSGB78" );
260
261 else if( nEPSGGCSCode == 4201 )
262 strcpy( pszDatum, "ADINDAN" );
263
264 else if( nEPSGGCSCode == 4202 )
265 strcpy( pszDatum, "AGD66" );
266
267 else if( nEPSGGCSCode == 4203 )
268 strcpy( pszDatum, "AGD84" );
269
270 else if( nEPSGGCSCode == 4209 )
271 strcpy( pszDatum, "ARC1950" );
272
273 else if( nEPSGGCSCode == 4210 )
274 strcpy( pszDatum, "ARC1960" );
275
276 else if( nEPSGGCSCode == 4275 )
277 strcpy( pszDatum, "NTF" );
278
279 else if( nEPSGGCSCode == 4283 )
280 strcpy( pszDatum, "GDA94" );
281
282 else if( nEPSGGCSCode == 4284 )
283 strcpy( pszDatum, "PULKOVO" );
284 }
285
286 /* -------------------------------------------------------------------- */
287 /* Are we working with a geographic (geodetic) coordinate system? */
288 /* -------------------------------------------------------------------- */
289
290 if( IsGeographic() )
291 {
292 if( EQUAL(pszDatum, "RAW") )
293 return OGRERR_UNSUPPORTED_SRS;
294 else
295 {
296 strcpy( pszProj, "GEODETIC" );
297 return OGRERR_NONE;
298 }
299 }
300
301 /* -------------------------------------------------------------------- */
302 /* Is this a UTM projection? */
303 /* -------------------------------------------------------------------- */
304 int bNorth = FALSE;
305 int nZone = 0;
306
307 nZone = GetUTMZone( &bNorth );
308 if( nZone > 0 )
309 {
310 if( EQUAL(pszDatum, "GDA94") && !bNorth && nZone >= 48 && nZone <= 58)
311 {
312 snprintf( pszProj, BUFFER_SIZE, "MGA%02d", nZone );
313 }
314 else
315 {
316 if( bNorth )
317 snprintf( pszProj, BUFFER_SIZE, "NUTM%02d", nZone );
318 else
319 snprintf( pszProj, BUFFER_SIZE, "SUTM%02d", nZone );
320 }
321 }
322
323 /* -------------------------------------------------------------------- */
324 /* Is our PROJCS name already defined in ecw_cs.wkt? */
325 /* -------------------------------------------------------------------- */
326 else
327 {
328 const char *pszPROJCS = GetAttrValue( "PROJCS" );
329
330 if( pszPROJCS != nullptr
331 && lookupInDict( "ecw_cs.wkt", pszPROJCS ).find("PROJCS") == 0 )
332 {
333 strncpy( pszProj, pszPROJCS, BUFFER_SIZE );
334 pszProj[BUFFER_SIZE-1] = '\0';
335 }
336 }
337
338 /* -------------------------------------------------------------------- */
339 /* If we have not translated it yet, but we have an EPSG code */
340 /* then use EPSG:n notation. */
341 /* -------------------------------------------------------------------- */
342 if( (EQUAL(pszDatum, "RAW") || EQUAL(pszProj, "RAW")) && nEPSGCode != 0 )
343 {
344 snprintf( pszProj, BUFFER_SIZE, "EPSG:%d", nEPSGCode );
345 snprintf( pszDatum, BUFFER_SIZE, "EPSG:%d", nEPSGCode );
346 }
347
348 /* -------------------------------------------------------------------- */
349 /* Handle the units. */
350 /* -------------------------------------------------------------------- */
351 const double dfUnits = GetLinearUnits();
352
353 if( fabs(dfUnits-0.3048) < 0.0001 )
354 strcpy( pszUnits, "FEET" );
355 else
356 strcpy( pszUnits, "METERS" );
357
358 if( EQUAL(pszProj, "RAW") )
359 return OGRERR_UNSUPPORTED_SRS;
360
361 return OGRERR_NONE;
362 }
363