/src/gdal/ogr/ogr_srs_pci.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: OGRSpatialReference translation to/from PCI georeferencing |
5 | | * information. |
6 | | * Author: Andrey Kiselev, dron@ak4719.spb.edu |
7 | | * |
8 | | ****************************************************************************** |
9 | | * Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu> |
10 | | * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com> |
11 | | * |
12 | | * SPDX-License-Identifier: MIT |
13 | | ****************************************************************************/ |
14 | | |
15 | | #include "cpl_port.h" |
16 | | #include "ogr_srs_api.h" |
17 | | |
18 | | #include <cctype> |
19 | | #include <cstdio> |
20 | | #include <cstdlib> |
21 | | #include <cstring> |
22 | | |
23 | | #include "cpl_conv.h" |
24 | | #include "cpl_csv.h" |
25 | | #include "cpl_error.h" |
26 | | #include "cpl_string.h" |
27 | | #include "cpl_vsi.h" |
28 | | #include "ogr_core.h" |
29 | | #include "ogr_p.h" |
30 | | #include "ogr_spatialref.h" |
31 | | |
32 | | // PCI uses a 16-character string for coordinate system and datum/ellipsoid. |
33 | | constexpr int knProjSize = 16; |
34 | | |
35 | | struct PCIDatums |
36 | | { |
37 | | const char *pszPCIDatum; |
38 | | int nEPSGCode; |
39 | | }; |
40 | | |
41 | | static const PCIDatums asDatums[] = { |
42 | | {"D-01", 4267}, // NAD27 (USA, NADCON) |
43 | | {"D-03", 4267}, // NAD27 (Canada, NTv1) |
44 | | {"D-02", 4269}, // NAD83 (USA, NADCON) |
45 | | {"D-04", 4269}, // NAD83 (Canada, NTv1) |
46 | | {"D-25", 7844}, // GDA2020 (Australia) |
47 | | {"D000", 4326}, // WGS 1984 |
48 | | {"D001", 4322}, // WGS 1972 |
49 | | {"D008", 4296}, // Sudan |
50 | | {"D013", 4601}, // Antigua Island Astro 1943 |
51 | | {"D029", 4202}, // Australian Geodetic 1966 |
52 | | {"D030", 4203}, // Australian Geodetic 1984 |
53 | | {"D033", 4216}, // Bermuda 1957 |
54 | | {"D034", 4165}, // Bissau |
55 | | {"D036", 4219}, // Bukit Rimpah |
56 | | {"D038", 4221}, // Campo Inchauspe |
57 | | {"D040", 4222}, // Cape |
58 | | {"D042", 4223}, // Carthage |
59 | | {"D044", 4224}, // Chua Astro |
60 | | {"D045", 4225}, // Corrego Alegre |
61 | | {"D046", 4155}, // Dabola (Guinea) |
62 | | {"D066", 4272}, // Geodetic Datum 1949 (New Zealand) |
63 | | {"D071", 4255}, // Herat North (Afghanistan) |
64 | | {"D077", 4239}, // Indian 1954 (Thailand, Vietnam) |
65 | | {"D078", 4240}, // Indian 1975 (Thailand) |
66 | | {"D083", 4244}, // Kandawala (Sri Lanka) |
67 | | {"D085", 4245}, // Kertau 1948 (West Malaysia & Singapore) |
68 | | {"D088", 4250}, // Leigon (Ghana) |
69 | | {"D089", 4251}, // Liberia 1964 (Liberia) |
70 | | {"D092", 4256}, // Mahe 1971 (Mahe Island) |
71 | | {"D093", 4262}, // Massawa (Ethiopia (Eritrea)) |
72 | | {"D094", 4261}, // Merchich (Morocco) |
73 | | {"D098", |
74 | | 4604}, // Montserrat Island Astro 1958 (Montserrat (Leeward Islands)) |
75 | | {"D110", 4267}, // NAD27 / Alaska |
76 | | {"D139", 4282}, // Pointe Noire 1948 (Congo) |
77 | | {"D140", 4615}, // Porto Santo 1936 (Porto Santo, Madeira Islands) |
78 | | {"D151", 4139}, // Puerto Rico (Puerto Rico, Virgin Islands) |
79 | | {"D153", 4287}, // Qornoq (Greenland (South)) |
80 | | {"D158", 4292}, // Sapper Hill 1943 (East Falkland Island) |
81 | | {"D159", 4293}, // Schwarzeck (Namibia) |
82 | | {"D160", 4616}, // Selvagem Grande 1938 (Salvage Islands) |
83 | | {"D176", 4297}, // Tananarive Observatory 1925 (Madagascar) |
84 | | {"D177", 4298}, // Timbalai 1948 (Brunei, East Malaysia (Sabah, Sarawak)) |
85 | | {"D187", 4309}, // Yacare (Uruguay) |
86 | | {"D188", 4311}, // Zanderij (Suriname) |
87 | | {"D401", 4124}, // RT90 (Sweden) |
88 | | {"D501", 4312}, // MGI (Hermannskogel, Austria) |
89 | | {"D536", 4283}, // GDA94 (Australia) |
90 | | {nullptr, 0}}; |
91 | | |
92 | | static const PCIDatums asEllips[] = { |
93 | | {"E000", 7008}, // Clarke, 1866 (NAD1927) |
94 | | {"E001", 7034}, // Clarke, 1880 |
95 | | {"E002", 7004}, // Bessel, 1841 |
96 | | {"E004", 7022}, // International, 1924 (Hayford, 1909) |
97 | | {"E005", 7043}, // WGS, 1972 |
98 | | {"E006", 7042}, // Everest, 1830 |
99 | | {"E008", 7019}, // GRS, 1980 (NAD1983) |
100 | | {"E009", 7001}, // Airy, 1830 |
101 | | {"E010", 7018}, // Modified Everest |
102 | | {"E011", 7002}, // Modified Airy |
103 | | {"E012", 7030}, // WGS, 1984 (GPS) |
104 | | {"E014", 7003}, // Australian National, 1965 |
105 | | {"E015", 7024}, // Krassovsky, 1940 |
106 | | {"E016", 7053}, // Hough |
107 | | {"E019", 7052}, // normal sphere |
108 | | {"E333", 7046}, // Bessel 1841 (Japan By Law) |
109 | | {"E900", 7006}, // Bessel, 1841 (Namibia) |
110 | | {"E901", 7044}, // Everest, 1956 |
111 | | {"E902", 7056}, // Everest, 1969 |
112 | | {"E903", 7016}, // Everest (Sabah & Sarawak) |
113 | | {"E904", 7020}, // Helmert, 1906 |
114 | | {"E907", 7036}, // South American, 1969 |
115 | | {"E910", 7041}, // ATS77 |
116 | | {nullptr, 0}}; |
117 | | |
118 | | /************************************************************************/ |
119 | | /* OSRImportFromPCI() */ |
120 | | /************************************************************************/ |
121 | | |
122 | | /** |
123 | | * \brief Import coordinate system from PCI projection definition. |
124 | | * |
125 | | * This function is the same as OGRSpatialReference::importFromPCI(). |
126 | | */ |
127 | | |
128 | | OGRErr OSRImportFromPCI(OGRSpatialReferenceH hSRS, const char *pszProj, |
129 | | const char *pszUnits, double *padfPrjParams) |
130 | | |
131 | 0 | { |
132 | 0 | VALIDATE_POINTER1(hSRS, "OSRImportFromPCI", OGRERR_FAILURE); |
133 | | |
134 | 0 | return OGRSpatialReference::FromHandle(hSRS)->importFromPCI( |
135 | 0 | pszProj, pszUnits, padfPrjParams); |
136 | 0 | } |
137 | | |
138 | | /************************************************************************/ |
139 | | /* importFromPCI() */ |
140 | | /************************************************************************/ |
141 | | |
142 | | /** |
143 | | * \brief Import coordinate system from PCI projection definition. |
144 | | * |
145 | | * PCI software uses 16-character string to specify coordinate system |
146 | | * and datum/ellipsoid. You should supply at least this string to the |
147 | | * importFromPCI() function. |
148 | | * |
149 | | * This function is the equivalent of the C function OSRImportFromPCI(). |
150 | | * |
151 | | * @param pszProj NULL terminated string containing the definition. Looks |
152 | | * like "pppppppppppp Ennn" or "pppppppppppp Dnnn", where "pppppppppppp" is |
153 | | * a projection code, "Ennn" is an ellipsoid code, "Dnnn" a datum code. |
154 | | * |
155 | | * @param pszUnits Grid units code ("DEGREE" or "METRE"). If NULL "METRE" will |
156 | | * be used. |
157 | | * |
158 | | * @param padfPrjParams Array of 17 coordinate system parameters: |
159 | | * |
160 | | * [0] Spheroid semi major axis |
161 | | * [1] Spheroid semi minor axis |
162 | | * [2] Reference Longitude |
163 | | * [3] Reference Latitude |
164 | | * [4] First Standard Parallel |
165 | | * [5] Second Standard Parallel |
166 | | * [6] False Easting |
167 | | * [7] False Northing |
168 | | * [8] Scale Factor |
169 | | * [9] Height above sphere surface |
170 | | * [10] Longitude of 1st point on center line |
171 | | * [11] Latitude of 1st point on center line |
172 | | * [12] Longitude of 2nd point on center line |
173 | | * [13] Latitude of 2nd point on center line |
174 | | * [14] Azimuth east of north for center line |
175 | | * [15] Landsat satellite number |
176 | | * [16] Landsat path number |
177 | | * |
178 | | * Particular projection uses different parameters, unused ones may be set to |
179 | | * zero. If NULL is supplied instead of an array pointer, default values will be |
180 | | * used (i.e., zeroes). |
181 | | * |
182 | | * @return OGRERR_NONE on success or an error code in case of failure. |
183 | | */ |
184 | | |
185 | | OGRErr OGRSpatialReference::importFromPCI(const char *pszProj, |
186 | | const char *pszUnits, |
187 | | const double *padfPrjParams) |
188 | | |
189 | 5.21k | { |
190 | 5.21k | Clear(); |
191 | | |
192 | 5.21k | if (pszProj == nullptr || |
193 | 5.21k | CPLStrnlen(pszProj, knProjSize) < static_cast<size_t>(knProjSize)) |
194 | 13 | { |
195 | 13 | return OGRERR_CORRUPT_DATA; |
196 | 13 | } |
197 | | |
198 | 5.20k | CPLDebug("OSR_PCI", "Trying to import projection \"%s\"", pszProj); |
199 | | |
200 | | /* -------------------------------------------------------------------- */ |
201 | | /* Use safe defaults if projection parameters are not supplied. */ |
202 | | /* -------------------------------------------------------------------- */ |
203 | 5.20k | static const double adfZeroedPrjParams[17] = {0}; |
204 | 5.20k | if (padfPrjParams == nullptr) |
205 | 0 | { |
206 | 0 | padfPrjParams = adfZeroedPrjParams; |
207 | 0 | } |
208 | | |
209 | | /* -------------------------------------------------------------------- */ |
210 | | /* Extract and "normalize" the earthmodel to look like E001, */ |
211 | | /* D-02 or D109. */ |
212 | | /* -------------------------------------------------------------------- */ |
213 | 5.20k | char szEarthModel[5] = {}; |
214 | | |
215 | 5.20k | strcpy(szEarthModel, ""); |
216 | 5.20k | const char *pszEM = pszProj + strlen(pszProj) - 1; |
217 | 55.1k | while (pszEM != pszProj) |
218 | 55.1k | { |
219 | 55.1k | if (*pszEM == 'e' || *pszEM == 'E' || *pszEM == 'd' || *pszEM == 'D') |
220 | 5.20k | { |
221 | 5.20k | int nCode = atoi(pszEM + 1); |
222 | | |
223 | 5.20k | if (nCode >= -99 && nCode <= 999) |
224 | 5.20k | snprintf(szEarthModel, sizeof(szEarthModel), "%c%03d", |
225 | 5.20k | CPLToupper(static_cast<unsigned char>(*pszEM)), nCode); |
226 | | |
227 | 5.20k | break; |
228 | 5.20k | } |
229 | | |
230 | 49.9k | pszEM--; |
231 | 49.9k | } |
232 | | |
233 | 5.20k | const bool bIsNAD27 = EQUAL(pszEM, "E000") || EQUAL(pszEM, "D-01") || |
234 | 5.15k | EQUAL(pszEM, "D-03") || EQUAL(pszEM, "D-07") || |
235 | 5.15k | EQUAL(pszEM, "D-09") || EQUAL(pszEM, "D-11") || |
236 | 5.15k | EQUAL(pszEM, "D-13") || EQUAL(pszEM, "D-17"); |
237 | | |
238 | | /* -------------------------------------------------------------------- */ |
239 | | /* Operate on the basis of the projection name. */ |
240 | | /* -------------------------------------------------------------------- */ |
241 | 5.20k | if (STARTS_WITH_CI(pszProj, "LONG/LAT")) |
242 | 233 | { |
243 | | // TODO(schwehr): A NOP is okay? |
244 | 233 | } |
245 | 4.96k | else if (STARTS_WITH_CI(pszProj, "METER") || |
246 | 4.96k | STARTS_WITH_CI(pszProj, "METRE")) |
247 | 4.28k | { |
248 | 4.28k | SetLocalCS("METER"); |
249 | 4.28k | SetLinearUnits("METER", 1.0); |
250 | 4.28k | } |
251 | 678 | else if (STARTS_WITH_CI(pszProj, "FEET") || STARTS_WITH_CI(pszProj, "FOOT")) |
252 | 0 | { |
253 | 0 | SetLocalCS("FEET"); |
254 | 0 | SetLinearUnits("FEET", CPLAtof(SRS_UL_FOOT_CONV)); |
255 | 0 | } |
256 | 678 | else if (STARTS_WITH_CI(pszProj, "ACEA")) |
257 | 9 | { |
258 | 9 | SetACEA(padfPrjParams[4], padfPrjParams[5], padfPrjParams[3], |
259 | 9 | padfPrjParams[2], padfPrjParams[6], padfPrjParams[7]); |
260 | 9 | } |
261 | 669 | else if (STARTS_WITH_CI(pszProj, "AE")) |
262 | 0 | { |
263 | 0 | SetAE(padfPrjParams[3], padfPrjParams[2], padfPrjParams[6], |
264 | 0 | padfPrjParams[7]); |
265 | 0 | } |
266 | 669 | else if (STARTS_WITH_CI(pszProj, "CASS ")) |
267 | 0 | { |
268 | 0 | SetCS(padfPrjParams[3], padfPrjParams[2], padfPrjParams[6], |
269 | 0 | padfPrjParams[7]); |
270 | 0 | } |
271 | 669 | else if (STARTS_WITH_CI(pszProj, "EC")) |
272 | 0 | { |
273 | 0 | SetEC(padfPrjParams[4], padfPrjParams[5], padfPrjParams[3], |
274 | 0 | padfPrjParams[2], padfPrjParams[6], padfPrjParams[7]); |
275 | 0 | } |
276 | 669 | else if (STARTS_WITH_CI(pszProj, "ER")) |
277 | 0 | { |
278 | | // PCI and GCTP don't support natural origin lat. |
279 | 0 | SetEquirectangular2(0.0, padfPrjParams[2], padfPrjParams[3], |
280 | 0 | padfPrjParams[6], padfPrjParams[7]); |
281 | 0 | } |
282 | 669 | else if (STARTS_WITH_CI(pszProj, "GNO")) |
283 | 0 | { |
284 | 0 | SetGnomonic(padfPrjParams[3], padfPrjParams[2], padfPrjParams[6], |
285 | 0 | padfPrjParams[7]); |
286 | 0 | } |
287 | | // FIXME: GVNP --- General Vertical Near- Side Perspective skipped. |
288 | | // FIXME: GOOD -- Our Goode's is not the interrupted version from PCI. |
289 | 669 | else if (STARTS_WITH_CI(pszProj, "LAEA")) |
290 | 0 | { |
291 | 0 | SetLAEA(padfPrjParams[3], padfPrjParams[2], padfPrjParams[6], |
292 | 0 | padfPrjParams[7]); |
293 | 0 | } |
294 | 669 | else if (STARTS_WITH_CI(pszProj, "LCC ")) |
295 | 176 | { |
296 | 176 | SetLCC(padfPrjParams[4], padfPrjParams[5], padfPrjParams[3], |
297 | 176 | padfPrjParams[2], padfPrjParams[6], padfPrjParams[7]); |
298 | 176 | } |
299 | 493 | else if (STARTS_WITH_CI(pszProj, "LCC_1SP ")) |
300 | 9 | { |
301 | 9 | SetLCC1SP(padfPrjParams[3], padfPrjParams[2], padfPrjParams[8], |
302 | 9 | padfPrjParams[6], padfPrjParams[7]); |
303 | 9 | } |
304 | 484 | else if (STARTS_WITH_CI(pszProj, "MC")) |
305 | 0 | { |
306 | 0 | SetMC(padfPrjParams[3], padfPrjParams[2], padfPrjParams[6], |
307 | 0 | padfPrjParams[7]); |
308 | 0 | } |
309 | 484 | else if (STARTS_WITH_CI(pszProj, "MER")) |
310 | 0 | { |
311 | 0 | if (EQUAL(pszEM, "D894") && padfPrjParams[3] == 0 && |
312 | 0 | padfPrjParams[2] == 0 && padfPrjParams[8] == 1.0 && |
313 | 0 | padfPrjParams[6] == 0 && padfPrjParams[7] == 0) |
314 | 0 | { |
315 | | // Special case for Web Mercator |
316 | 0 | return importFromEPSG(3857); |
317 | 0 | } |
318 | 0 | SetMercator(padfPrjParams[3], padfPrjParams[2], |
319 | 0 | (padfPrjParams[8] != 0.0) ? padfPrjParams[8] : 1.0, |
320 | 0 | padfPrjParams[6], padfPrjParams[7]); |
321 | 0 | } |
322 | 484 | else if (STARTS_WITH_CI(pszProj, "OG")) |
323 | 0 | { |
324 | 0 | SetOrthographic(padfPrjParams[3], padfPrjParams[2], padfPrjParams[6], |
325 | 0 | padfPrjParams[7]); |
326 | 0 | } |
327 | 484 | else if (STARTS_WITH_CI(pszProj, "OM ")) |
328 | 53 | { |
329 | 53 | if (padfPrjParams[10] == 0.0 && padfPrjParams[11] == 0.0 && |
330 | 53 | padfPrjParams[12] == 0.0 && padfPrjParams[13] == 0.0) |
331 | 53 | { |
332 | 53 | SetHOM(padfPrjParams[3], padfPrjParams[2], padfPrjParams[14], |
333 | 53 | padfPrjParams[14], // Use azimuth for grid angle. |
334 | 53 | padfPrjParams[8], padfPrjParams[6], padfPrjParams[7]); |
335 | 53 | } |
336 | 0 | else |
337 | 0 | { |
338 | 0 | SetHOM2PNO(padfPrjParams[3], padfPrjParams[11], padfPrjParams[10], |
339 | 0 | padfPrjParams[13], padfPrjParams[12], padfPrjParams[8], |
340 | 0 | padfPrjParams[6], padfPrjParams[7]); |
341 | 0 | } |
342 | 53 | } |
343 | 431 | else if (STARTS_WITH_CI(pszProj, "PC")) |
344 | 0 | { |
345 | 0 | SetPolyconic(padfPrjParams[3], padfPrjParams[2], padfPrjParams[6], |
346 | 0 | padfPrjParams[7]); |
347 | 0 | } |
348 | 431 | else if (STARTS_WITH_CI(pszProj, "PS")) |
349 | 11 | { |
350 | 11 | SetPS(padfPrjParams[3], padfPrjParams[2], |
351 | 11 | (padfPrjParams[8] != 0.0) ? padfPrjParams[8] : 1.0, |
352 | 11 | padfPrjParams[6], padfPrjParams[7]); |
353 | 11 | } |
354 | 420 | else if (STARTS_WITH_CI(pszProj, "ROB")) |
355 | 0 | { |
356 | 0 | SetRobinson(padfPrjParams[2], padfPrjParams[6], padfPrjParams[7]); |
357 | 0 | } |
358 | | |
359 | 420 | else if (STARTS_WITH_CI(pszProj, "SGDO")) |
360 | 0 | { |
361 | 0 | SetOS(padfPrjParams[3], padfPrjParams[2], |
362 | 0 | (padfPrjParams[8] != 0.0) ? padfPrjParams[8] : 1.0, |
363 | 0 | padfPrjParams[6], padfPrjParams[7]); |
364 | 0 | } |
365 | 420 | else if (STARTS_WITH_CI(pszProj, "SG")) |
366 | 0 | { |
367 | 0 | SetStereographic(padfPrjParams[3], padfPrjParams[2], |
368 | 0 | (padfPrjParams[8] != 0.0) ? padfPrjParams[8] : 1.0, |
369 | 0 | padfPrjParams[6], padfPrjParams[7]); |
370 | 0 | } |
371 | 420 | else if (STARTS_WITH_CI(pszProj, "SIN")) |
372 | 0 | { |
373 | 0 | SetSinusoidal(padfPrjParams[2], padfPrjParams[6], padfPrjParams[7]); |
374 | 0 | } |
375 | | // FIXME: SOM --- Space Oblique Mercator skipped. |
376 | 420 | else if (STARTS_WITH_CI(pszProj, "SPCS")) |
377 | 0 | { |
378 | 0 | const int iZone = |
379 | 0 | static_cast<int>(CPLScanLong(const_cast<char *>(pszProj) + 5, 4)); |
380 | |
|
381 | 0 | SetStatePlane(iZone, !bIsNAD27); |
382 | 0 | SetLinearUnitsAndUpdateParameters(SRS_UL_METER, 1.0); |
383 | 0 | } |
384 | 420 | else if (STARTS_WITH_CI(pszProj, "SPIF")) |
385 | 0 | { |
386 | 0 | const int iZone = |
387 | 0 | static_cast<int>(CPLScanLong(const_cast<char *>(pszProj) + 5, 4)); |
388 | |
|
389 | 0 | SetStatePlane(iZone, !bIsNAD27); |
390 | 0 | SetLinearUnitsAndUpdateParameters(SRS_UL_FOOT, |
391 | 0 | CPLAtof(SRS_UL_FOOT_CONV)); |
392 | 0 | } |
393 | 420 | else if (STARTS_WITH_CI(pszProj, "SPAF")) |
394 | 0 | { |
395 | 0 | const int iZone = |
396 | 0 | static_cast<int>(CPLScanLong(const_cast<char *>(pszProj) + 5, 4)); |
397 | |
|
398 | 0 | SetStatePlane(iZone, !bIsNAD27); |
399 | 0 | SetLinearUnitsAndUpdateParameters(SRS_UL_US_FOOT, |
400 | 0 | CPLAtof(SRS_UL_US_FOOT_CONV)); |
401 | 0 | } |
402 | 420 | else if (STARTS_WITH_CI(pszProj, "TM")) |
403 | 123 | { |
404 | 123 | SetTM(padfPrjParams[3], padfPrjParams[2], |
405 | 123 | (padfPrjParams[8] != 0.0) ? padfPrjParams[8] : 1.0, |
406 | 123 | padfPrjParams[6], padfPrjParams[7]); |
407 | 123 | } |
408 | | |
409 | 297 | else if (STARTS_WITH_CI(pszProj, "UTM")) |
410 | 143 | { |
411 | 143 | bool bNorth = true; |
412 | | |
413 | 143 | int iZone = |
414 | 143 | static_cast<int>(CPLScanLong(const_cast<char *>(pszProj) + 4, 5)); |
415 | 143 | if (iZone < 0) |
416 | 3 | { |
417 | 3 | iZone = -iZone; |
418 | 3 | bNorth = false; |
419 | 3 | } |
420 | | |
421 | | // Check for a zone letter. PCI uses, accidentally, MGRS |
422 | | // type row lettering in its UTM projection. |
423 | 143 | char byZoneID = 0; |
424 | | |
425 | 143 | if (strlen(pszProj) > 10 && pszProj[10] != ' ') |
426 | 37 | byZoneID = pszProj[10]; |
427 | | |
428 | | // Determine if the MGRS zone falls above or below the equator. |
429 | 143 | if (byZoneID != 0) |
430 | 37 | { |
431 | 37 | CPLDebug("OSR_PCI", "Found MGRS zone in UTM projection string: %c", |
432 | 37 | byZoneID); |
433 | | |
434 | 37 | if (byZoneID >= 'N' && byZoneID <= 'X') |
435 | 36 | { |
436 | 36 | bNorth = true; |
437 | 36 | } |
438 | 1 | else if (byZoneID >= 'C' && byZoneID <= 'M') |
439 | 0 | { |
440 | 0 | bNorth = false; |
441 | 0 | } |
442 | 1 | else |
443 | 1 | { |
444 | | // Yikes. Most likely we got something that was not really |
445 | | // an MGRS zone code so we ignore it. |
446 | 1 | } |
447 | 37 | } |
448 | | |
449 | 143 | SetUTM(iZone, bNorth); |
450 | 143 | } |
451 | 154 | else if (STARTS_WITH_CI(pszProj, "VDG")) |
452 | 0 | { |
453 | 0 | SetVDG(padfPrjParams[2], padfPrjParams[6], padfPrjParams[7]); |
454 | 0 | } |
455 | 154 | else |
456 | 154 | { |
457 | 154 | CPLDebug("OSR_PCI", "Unsupported projection: %s", pszProj); |
458 | 154 | SetLocalCS(pszProj); |
459 | 154 | } |
460 | | |
461 | | /* ==================================================================== */ |
462 | | /* Translate the datum/spheroid. */ |
463 | | /* ==================================================================== */ |
464 | | |
465 | | /* -------------------------------------------------------------------- */ |
466 | | /* We have an earthmodel string, look it up in the datum list. */ |
467 | | /* -------------------------------------------------------------------- */ |
468 | 5.20k | if (strlen(szEarthModel) > 0 && |
469 | 5.20k | (GetRoot() == nullptr || IsProjected() || IsGeographic())) |
470 | 757 | { |
471 | 757 | const PCIDatums *pasDatum = asDatums; |
472 | | |
473 | | // Search for matching datum. |
474 | 35.5k | while (pasDatum->pszPCIDatum) |
475 | 34.8k | { |
476 | 34.8k | if (EQUALN(szEarthModel, pasDatum->pszPCIDatum, 4)) |
477 | 18 | { |
478 | 18 | OGRSpatialReference oGCS; |
479 | 18 | oGCS.importFromEPSG(pasDatum->nEPSGCode); |
480 | 18 | CopyGeogCSFrom(&oGCS); |
481 | 18 | break; |
482 | 18 | } |
483 | 34.8k | pasDatum++; |
484 | 34.8k | } |
485 | | |
486 | | /* -------------------------------------------------------------------- |
487 | | */ |
488 | | /* If we did not find a datum definition in our in-code EPSG */ |
489 | | /* lookup table, then try fetching from the pci_datum.txt */ |
490 | | /* file. */ |
491 | | /* -------------------------------------------------------------------- |
492 | | */ |
493 | 757 | char **papszDatumDefn = nullptr; |
494 | | |
495 | 757 | if (!pasDatum->pszPCIDatum && szEarthModel[0] == 'D') |
496 | 0 | { |
497 | 0 | const char *pszDatumCSV = CSVFilename("pci_datum.txt"); |
498 | 0 | VSILFILE *fp = pszDatumCSV ? VSIFOpenL(pszDatumCSV, "r") : nullptr; |
499 | |
|
500 | 0 | if (fp != nullptr) |
501 | 0 | { |
502 | 0 | char **papszLineItems = nullptr; |
503 | |
|
504 | 0 | while ((papszLineItems = CSVReadParseLineL(fp)) != nullptr) |
505 | 0 | { |
506 | 0 | if (CSLCount(papszLineItems) > 3 && |
507 | 0 | EQUALN(papszLineItems[0], szEarthModel, |
508 | 0 | sizeof(szEarthModel) - 1)) |
509 | 0 | { |
510 | 0 | papszDatumDefn = papszLineItems; |
511 | 0 | strncpy(szEarthModel, papszLineItems[2], |
512 | 0 | sizeof(szEarthModel) - 1); |
513 | 0 | break; |
514 | 0 | } |
515 | 0 | CSLDestroy(papszLineItems); |
516 | 0 | } |
517 | |
|
518 | 0 | VSIFCloseL(fp); |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | | /* -------------------------------------------------------------------- |
523 | | */ |
524 | | /* If not, look in the ellipsoid/EPSG matching list. */ |
525 | | /* -------------------------------------------------------------------- |
526 | | */ |
527 | 757 | if (!pasDatum->pszPCIDatum) // No matching; search for ellipsoids. |
528 | 739 | { |
529 | 739 | char *pszName = nullptr; |
530 | 739 | double dfSemiMajor = 0.0; |
531 | 739 | double dfInvFlattening = 0.0; |
532 | 739 | int nEPSGCode = 0; |
533 | | |
534 | 739 | pasDatum = asEllips; |
535 | | |
536 | 8.29k | while (pasDatum->pszPCIDatum) |
537 | 8.15k | { |
538 | 8.15k | if (EQUALN(szEarthModel, pasDatum->pszPCIDatum, 4)) |
539 | 594 | { |
540 | 594 | nEPSGCode = pasDatum->nEPSGCode; |
541 | 594 | CPL_IGNORE_RET_VAL( |
542 | 594 | OSRGetEllipsoidInfo(pasDatum->nEPSGCode, &pszName, |
543 | 594 | &dfSemiMajor, &dfInvFlattening)); |
544 | 594 | break; |
545 | 594 | } |
546 | 7.56k | pasDatum++; |
547 | 7.56k | } |
548 | | |
549 | | /* -------------------------------------------------------------------- |
550 | | */ |
551 | | /* If we don't find it in that list, do a lookup in the */ |
552 | | /* pci_ellips.txt file. */ |
553 | | /* -------------------------------------------------------------------- |
554 | | */ |
555 | 739 | if (!pasDatum->pszPCIDatum && szEarthModel[0] == 'E') |
556 | 145 | { |
557 | 145 | const char *pszCSV = CSVFilename("pci_ellips.txt"); |
558 | 145 | VSILFILE *fp = pszCSV ? VSIFOpenL(pszCSV, "r") : nullptr; |
559 | | |
560 | 145 | if (fp != nullptr) |
561 | 0 | { |
562 | 0 | char **papszLineItems = nullptr; |
563 | |
|
564 | 0 | while ((papszLineItems = CSVReadParseLineL(fp)) != nullptr) |
565 | 0 | { |
566 | 0 | if (CSLCount(papszLineItems) > 3 && |
567 | 0 | EQUALN(papszLineItems[0], szEarthModel, 4)) |
568 | 0 | { |
569 | 0 | dfSemiMajor = CPLAtof(papszLineItems[2]); |
570 | 0 | const double dfSemiMinor = |
571 | 0 | CPLAtof(papszLineItems[3]); |
572 | 0 | dfInvFlattening = |
573 | 0 | OSRCalcInvFlattening(dfSemiMajor, dfSemiMinor); |
574 | 0 | break; |
575 | 0 | } |
576 | 0 | CSLDestroy(papszLineItems); |
577 | 0 | } |
578 | 0 | CSLDestroy(papszLineItems); |
579 | |
|
580 | 0 | VSIFCloseL(fp); |
581 | 0 | } |
582 | 145 | } |
583 | | |
584 | | /* -------------------------------------------------------------------- |
585 | | */ |
586 | | /* Custom spheroid? */ |
587 | | /* -------------------------------------------------------------------- |
588 | | */ |
589 | 739 | if (dfSemiMajor == 0.0 && STARTS_WITH_CI(szEarthModel, "E999") && |
590 | 145 | padfPrjParams[0] != 0.0) |
591 | 76 | { |
592 | 76 | dfSemiMajor = padfPrjParams[0]; |
593 | 76 | double dfSemiMinor = padfPrjParams[1]; |
594 | 76 | dfInvFlattening = |
595 | 76 | OSRCalcInvFlattening(dfSemiMajor, dfSemiMinor); |
596 | 76 | } |
597 | | |
598 | | /* -------------------------------------------------------------------- |
599 | | */ |
600 | | /* If nothing else, fall back to WGS84 parameters. */ |
601 | | /* -------------------------------------------------------------------- |
602 | | */ |
603 | 739 | if (dfSemiMajor == 0.0) |
604 | 69 | { |
605 | 69 | dfSemiMajor = SRS_WGS84_SEMIMAJOR; |
606 | 69 | dfInvFlattening = SRS_WGS84_INVFLATTENING; |
607 | 69 | } |
608 | | |
609 | | /* -------------------------------------------------------------------- |
610 | | */ |
611 | | /* Now try to put this all together into a GEOGCS definition. |
612 | | */ |
613 | | /* -------------------------------------------------------------------- |
614 | | */ |
615 | | |
616 | 739 | CPLString osEllipseName; |
617 | 739 | if (pszName) |
618 | 594 | osEllipseName = pszName; |
619 | 145 | else |
620 | 145 | osEllipseName.Printf("Unknown - PCI %s", szEarthModel); |
621 | 739 | CPLFree(pszName); |
622 | | |
623 | 739 | CPLString osDatumName; |
624 | 739 | if (papszDatumDefn) |
625 | 0 | osDatumName = papszDatumDefn[1]; |
626 | 739 | else |
627 | 739 | osDatumName.Printf("Unknown - PCI %s", szEarthModel); |
628 | | |
629 | 739 | const CPLString osGCSName = osDatumName; |
630 | | |
631 | 739 | SetGeogCS(osGCSName, osDatumName, osEllipseName, dfSemiMajor, |
632 | 739 | dfInvFlattening); |
633 | | |
634 | | // Do we have an ellipsoid EPSG code? |
635 | 739 | if (nEPSGCode != 0) |
636 | 594 | SetAuthority("SPHEROID", "EPSG", nEPSGCode); |
637 | | |
638 | | // Do we have 7 datum shift parameters? |
639 | 739 | if (papszDatumDefn != nullptr && CSLCount(papszDatumDefn) >= 15 && |
640 | 0 | CPLAtof(papszDatumDefn[14]) != 0.0) |
641 | 0 | { |
642 | 0 | double dfScale = CPLAtof(papszDatumDefn[14]); |
643 | | |
644 | | // we want scale in parts per million off 1.0 |
645 | | // but pci uses a mix of forms. |
646 | 0 | if (dfScale >= 0.999 && dfScale <= 1.001) |
647 | 0 | dfScale = (dfScale - 1.0) * 1000000.0; |
648 | |
|
649 | 0 | SetTOWGS84( |
650 | 0 | CPLAtof(papszDatumDefn[3]), CPLAtof(papszDatumDefn[4]), |
651 | 0 | CPLAtof(papszDatumDefn[5]), CPLAtof(papszDatumDefn[11]), |
652 | 0 | CPLAtof(papszDatumDefn[12]), CPLAtof(papszDatumDefn[13]), |
653 | 0 | dfScale); |
654 | 0 | } |
655 | | |
656 | | // Do we have 7 datum shift parameters? |
657 | 739 | else if (papszDatumDefn != nullptr && |
658 | 0 | CSLCount(papszDatumDefn) == 11 && |
659 | 0 | (CPLAtof(papszDatumDefn[3]) != 0.0 || |
660 | 0 | CPLAtof(papszDatumDefn[4]) != 0.0 || |
661 | 0 | CPLAtof(papszDatumDefn[5]) != 0.0)) |
662 | 0 | { |
663 | 0 | SetTOWGS84(CPLAtof(papszDatumDefn[3]), |
664 | 0 | CPLAtof(papszDatumDefn[4]), |
665 | 0 | CPLAtof(papszDatumDefn[5])); |
666 | 0 | } |
667 | 739 | } |
668 | | |
669 | 757 | CSLDestroy(papszDatumDefn); |
670 | 757 | } |
671 | | |
672 | | /* -------------------------------------------------------------------- */ |
673 | | /* Grid units translation */ |
674 | | /* -------------------------------------------------------------------- */ |
675 | 5.20k | if ((IsLocal() || IsProjected()) && pszUnits) |
676 | 0 | { |
677 | 0 | if (EQUAL(pszUnits, "METRE")) |
678 | 0 | SetLinearUnits(SRS_UL_METER, 1.0); |
679 | 0 | else if (EQUAL(pszUnits, "DEGREE")) |
680 | 0 | SetAngularUnits(SRS_UA_DEGREE, CPLAtof(SRS_UA_DEGREE_CONV)); |
681 | 0 | else |
682 | 0 | SetLinearUnits(SRS_UL_METER, 1.0); |
683 | 0 | } |
684 | | |
685 | 5.20k | return OGRERR_NONE; |
686 | 5.20k | } |
687 | | |
688 | | /************************************************************************/ |
689 | | /* OSRExportToPCI() */ |
690 | | /************************************************************************/ |
691 | | /** |
692 | | * \brief Export coordinate system in PCI projection definition. |
693 | | * |
694 | | * This function is the same as OGRSpatialReference::exportToPCI(). |
695 | | */ |
696 | | OGRErr OSRExportToPCI(OGRSpatialReferenceH hSRS, char **ppszProj, |
697 | | char **ppszUnits, double **ppadfPrjParams) |
698 | | |
699 | 0 | { |
700 | 0 | VALIDATE_POINTER1(hSRS, "OSRExportToPCI", OGRERR_FAILURE); |
701 | | |
702 | 0 | *ppszProj = nullptr; |
703 | 0 | *ppszUnits = nullptr; |
704 | 0 | *ppadfPrjParams = nullptr; |
705 | |
|
706 | 0 | return OGRSpatialReference::FromHandle(hSRS)->exportToPCI( |
707 | 0 | ppszProj, ppszUnits, ppadfPrjParams); |
708 | 0 | } |
709 | | |
710 | | /************************************************************************/ |
711 | | /* exportToPCI() */ |
712 | | /************************************************************************/ |
713 | | |
714 | | /** |
715 | | * \brief Export coordinate system in PCI projection definition. |
716 | | * |
717 | | * Converts the loaded coordinate reference system into PCI projection |
718 | | * definition to the extent possible. The strings returned in ppszProj, |
719 | | * ppszUnits and ppadfPrjParams array should be deallocated by the caller |
720 | | * with CPLFree() when no longer needed. |
721 | | * |
722 | | * LOCAL_CS coordinate systems are not translatable. An empty string |
723 | | * will be returned along with OGRERR_NONE. |
724 | | * |
725 | | * This method is the equivalent of the C function OSRExportToPCI(). |
726 | | * |
727 | | * @param ppszProj pointer to which dynamically allocated PCI projection |
728 | | * definition will be assigned. |
729 | | * |
730 | | * @param ppszUnits pointer to which dynamically allocated units definition |
731 | | * will be assigned. |
732 | | * |
733 | | * @param ppadfPrjParams pointer to which dynamically allocated array of |
734 | | * 17 projection parameters will be assigned. See importFromPCI() for the list |
735 | | * of parameters. |
736 | | * |
737 | | * @return OGRERR_NONE on success or an error code on failure. |
738 | | */ |
739 | | |
740 | | OGRErr OGRSpatialReference::exportToPCI(char **ppszProj, char **ppszUnits, |
741 | | double **ppadfPrjParams) const |
742 | | |
743 | 356 | { |
744 | 356 | const char *pszProjection = GetAttrValue("PROJECTION"); |
745 | | |
746 | | /* -------------------------------------------------------------------- */ |
747 | | /* Fill all projection parameters with zero. */ |
748 | | /* -------------------------------------------------------------------- */ |
749 | 356 | *ppadfPrjParams = static_cast<double *>(CPLMalloc(17 * sizeof(double))); |
750 | 6.40k | for (int i = 0; i < 17; i++) |
751 | 6.05k | (*ppadfPrjParams)[i] = 0.0; |
752 | | |
753 | | /* -------------------------------------------------------------------- */ |
754 | | /* Get the prime meridian info. */ |
755 | | /* -------------------------------------------------------------------- */ |
756 | | #if 0 |
757 | | const OGR_SRSNode *poPRIMEM = GetAttrNode( "PRIMEM" ); |
758 | | double dfFromGreenwich = 0.0; |
759 | | |
760 | | if( poPRIMEM != NULL && poPRIMEM->GetChildCount() >= 2 |
761 | | && CPLAtof(poPRIMEM->GetChild(1)->GetValue()) != 0.0 ) |
762 | | { |
763 | | dfFromGreenwich = CPLAtof(poPRIMEM->GetChild(1)->GetValue()); |
764 | | } |
765 | | #endif |
766 | | |
767 | | /* ==================================================================== */ |
768 | | /* Handle the projection definition. */ |
769 | | /* ==================================================================== */ |
770 | 356 | char szProj[knProjSize + 1] = {}; |
771 | | |
772 | 356 | if (IsLocal()) |
773 | 0 | { |
774 | 0 | if (GetLinearUnits() > 0.30479999 && GetLinearUnits() < 0.3048010) |
775 | 0 | CPLPrintStringFill(szProj, "FEET", knProjSize); |
776 | 0 | else |
777 | 0 | CPLPrintStringFill(szProj, "METER", knProjSize); |
778 | 0 | } |
779 | 356 | else if (pszProjection == nullptr) |
780 | 95 | { |
781 | 95 | CPLPrintStringFill(szProj, "LONG/LAT", knProjSize); |
782 | 95 | } |
783 | 261 | else if (EQUAL(pszProjection, SRS_PT_ALBERS_CONIC_EQUAL_AREA)) |
784 | 3 | { |
785 | 3 | CPLPrintStringFill(szProj, "ACEA", knProjSize); |
786 | 3 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
787 | 3 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
788 | 3 | (*ppadfPrjParams)[4] = GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0); |
789 | 3 | (*ppadfPrjParams)[5] = GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0); |
790 | 3 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
791 | 3 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
792 | 3 | } |
793 | 258 | else if (EQUAL(pszProjection, SRS_PT_AZIMUTHAL_EQUIDISTANT)) |
794 | 0 | { |
795 | 0 | CPLPrintStringFill(szProj, "AE", knProjSize); |
796 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
797 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
798 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
799 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
800 | 0 | } |
801 | 258 | else if (EQUAL(pszProjection, SRS_PT_CASSINI_SOLDNER)) |
802 | 0 | { |
803 | 0 | CPLPrintStringFill(szProj, "CASS", knProjSize); |
804 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
805 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
806 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
807 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
808 | 0 | } |
809 | 258 | else if (EQUAL(pszProjection, SRS_PT_EQUIDISTANT_CONIC)) |
810 | 0 | { |
811 | 0 | CPLPrintStringFill(szProj, "EC", knProjSize); |
812 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0); |
813 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0); |
814 | 0 | (*ppadfPrjParams)[4] = GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0); |
815 | 0 | (*ppadfPrjParams)[5] = GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0); |
816 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
817 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
818 | 0 | } |
819 | 258 | else if (EQUAL(pszProjection, SRS_PT_EQUIRECTANGULAR)) |
820 | 0 | { |
821 | 0 | CPLPrintStringFill(szProj, "ER", knProjSize); |
822 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
823 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0); |
824 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
825 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
826 | 0 | } |
827 | 258 | else if (EQUAL(pszProjection, SRS_PT_GNOMONIC)) |
828 | 0 | { |
829 | 0 | CPLPrintStringFill(szProj, "GNO", knProjSize); |
830 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
831 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
832 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
833 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
834 | 0 | } |
835 | 258 | else if (EQUAL(pszProjection, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA)) |
836 | 0 | { |
837 | 0 | CPLPrintStringFill(szProj, "LAEA", knProjSize); |
838 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
839 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
840 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
841 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
842 | 0 | } |
843 | 258 | else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP)) |
844 | 70 | { |
845 | 70 | CPLPrintStringFill(szProj, "LCC", knProjSize); |
846 | 70 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
847 | 70 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
848 | 70 | (*ppadfPrjParams)[4] = GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0); |
849 | 70 | (*ppadfPrjParams)[5] = GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0); |
850 | 70 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
851 | 70 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
852 | 70 | } |
853 | 188 | else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP)) |
854 | 3 | { |
855 | 3 | CPLPrintStringFill(szProj, "LCC_1SP", knProjSize); |
856 | 3 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
857 | 3 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
858 | 3 | (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0); |
859 | 3 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
860 | 3 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
861 | 3 | } |
862 | 185 | else if (EQUAL(pszProjection, SRS_PT_MILLER_CYLINDRICAL)) |
863 | 0 | { |
864 | 0 | CPLPrintStringFill(szProj, "MC", knProjSize); |
865 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
866 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
867 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
868 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
869 | 0 | } |
870 | 185 | else if (EQUAL(pszProjection, SRS_PT_MERCATOR_1SP)) |
871 | 0 | { |
872 | 0 | CPLPrintStringFill(szProj, "MER", knProjSize); |
873 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
874 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
875 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
876 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
877 | 0 | (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0); |
878 | 0 | } |
879 | 185 | else if (EQUAL(pszProjection, SRS_PT_ORTHOGRAPHIC)) |
880 | 0 | { |
881 | 0 | CPLPrintStringFill(szProj, "OG", knProjSize); |
882 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
883 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
884 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
885 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
886 | 0 | } |
887 | 185 | else if (EQUAL(pszProjection, SRS_PT_HOTINE_OBLIQUE_MERCATOR)) |
888 | 21 | { |
889 | 21 | CPLPrintStringFill(szProj, "OM", knProjSize); |
890 | 21 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0); |
891 | 21 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0); |
892 | 21 | (*ppadfPrjParams)[14] = GetNormProjParm(SRS_PP_AZIMUTH, 0.0); |
893 | | // Note: Ignoring rectified_grid_angle which has no PCI analog. |
894 | 21 | (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 0.0); |
895 | 21 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
896 | 21 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
897 | 21 | } |
898 | 164 | else if (EQUAL(pszProjection, |
899 | 164 | SRS_PT_HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN)) |
900 | 0 | { |
901 | 0 | CPLPrintStringFill(szProj, "OM", knProjSize); |
902 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0); |
903 | 0 | (*ppadfPrjParams)[11] = |
904 | 0 | GetNormProjParm(SRS_PP_LATITUDE_OF_POINT_1, 0.0); |
905 | 0 | (*ppadfPrjParams)[10] = |
906 | 0 | GetNormProjParm(SRS_PP_LONGITUDE_OF_POINT_1, 0.0); |
907 | 0 | (*ppadfPrjParams)[13] = |
908 | 0 | GetNormProjParm(SRS_PP_LATITUDE_OF_POINT_2, 0.0); |
909 | 0 | (*ppadfPrjParams)[12] = |
910 | 0 | GetNormProjParm(SRS_PP_LONGITUDE_OF_POINT_2, 0.0); |
911 | 0 | (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 0.0); |
912 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
913 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
914 | 0 | } |
915 | 164 | else if (EQUAL(pszProjection, SRS_PT_POLYCONIC)) |
916 | 0 | { |
917 | 0 | CPLPrintStringFill(szProj, "PC", knProjSize); |
918 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
919 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
920 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
921 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
922 | 0 | } |
923 | 164 | else if (EQUAL(pszProjection, SRS_PT_POLAR_STEREOGRAPHIC)) |
924 | 5 | { |
925 | 5 | CPLPrintStringFill(szProj, "PS", knProjSize); |
926 | 5 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
927 | 5 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
928 | 5 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
929 | 5 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
930 | 5 | (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0); |
931 | 5 | } |
932 | 159 | else if (EQUAL(pszProjection, SRS_PT_ROBINSON)) |
933 | 0 | { |
934 | 0 | CPLPrintStringFill(szProj, "ROB", knProjSize); |
935 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
936 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
937 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
938 | 0 | } |
939 | 159 | else if (EQUAL(pszProjection, SRS_PT_OBLIQUE_STEREOGRAPHIC)) |
940 | 0 | { |
941 | 0 | CPLPrintStringFill(szProj, "SGDO", knProjSize); |
942 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
943 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
944 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
945 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
946 | 0 | (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0); |
947 | 0 | } |
948 | 159 | else if (EQUAL(pszProjection, SRS_PT_STEREOGRAPHIC)) |
949 | 0 | { |
950 | 0 | CPLPrintStringFill(szProj, "SG", knProjSize); |
951 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
952 | 0 | (*ppadfPrjParams)[3] = GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
953 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
954 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
955 | 0 | (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0); |
956 | 0 | } |
957 | 159 | else if (EQUAL(pszProjection, SRS_PT_SINUSOIDAL)) |
958 | 0 | { |
959 | 0 | CPLPrintStringFill(szProj, "SIN", knProjSize); |
960 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0); |
961 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
962 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
963 | 0 | } |
964 | 159 | else if (EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR)) |
965 | 97 | { |
966 | 97 | int bNorth = FALSE; |
967 | 97 | int nZone = GetUTMZone(&bNorth); |
968 | | |
969 | 97 | if (nZone != 0) |
970 | 52 | { |
971 | 52 | CPLPrintStringFill(szProj, "UTM", knProjSize); |
972 | 52 | if (bNorth) |
973 | 51 | CPLPrintInt32(szProj + 5, nZone, 4); |
974 | 1 | else |
975 | 1 | CPLPrintInt32(szProj + 5, -nZone, 4); |
976 | 52 | } |
977 | 45 | else |
978 | 45 | { |
979 | 45 | CPLPrintStringFill(szProj, "TM", knProjSize); |
980 | 45 | (*ppadfPrjParams)[2] = |
981 | 45 | GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
982 | 45 | (*ppadfPrjParams)[3] = |
983 | 45 | GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0); |
984 | 45 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
985 | 45 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
986 | 45 | (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0); |
987 | 45 | } |
988 | 97 | } |
989 | 62 | else if (EQUAL(pszProjection, SRS_PT_VANDERGRINTEN)) |
990 | 0 | { |
991 | 0 | CPLPrintStringFill(szProj, "VDG", knProjSize); |
992 | 0 | (*ppadfPrjParams)[2] = GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); |
993 | 0 | (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0); |
994 | 0 | (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0); |
995 | 0 | } |
996 | | // Projection unsupported by PCI. |
997 | 62 | else |
998 | 62 | { |
999 | 62 | CPLDebug("OSR_PCI", |
1000 | 62 | "Projection \"%s\" unsupported by PCI. " |
1001 | 62 | "PIXEL value will be used.", |
1002 | 62 | pszProjection); |
1003 | 62 | CPLPrintStringFill(szProj, "PIXEL", knProjSize); |
1004 | 62 | } |
1005 | | |
1006 | | /* ==================================================================== */ |
1007 | | /* Translate the earth model. */ |
1008 | | /* ==================================================================== */ |
1009 | | |
1010 | | /* -------------------------------------------------------------------- */ |
1011 | | /* Is this a well known datum? */ |
1012 | | /* -------------------------------------------------------------------- */ |
1013 | 356 | const char *pszDatum = GetAttrValue("DATUM"); |
1014 | 356 | char szEarthModel[5] = {}; |
1015 | | |
1016 | 356 | if (pszDatum == nullptr || strlen(pszDatum) == 0) |
1017 | 57 | { |
1018 | | // Do nothing. |
1019 | 57 | } |
1020 | 299 | else if (EQUAL(pszDatum, SRS_DN_NAD27)) |
1021 | 4 | { |
1022 | 4 | CPLPrintStringFill(szEarthModel, "D-01", 4); |
1023 | 4 | } |
1024 | 295 | else if (EQUAL(pszDatum, SRS_DN_NAD83)) |
1025 | 0 | { |
1026 | 0 | CPLPrintStringFill(szEarthModel, "D-02", 4); |
1027 | 0 | } |
1028 | 295 | else if (EQUAL(pszDatum, SRS_DN_WGS84)) |
1029 | 67 | { |
1030 | 67 | CPLPrintStringFill(szEarthModel, "D000", 4); |
1031 | 67 | if (pszProjection && EQUAL(pszProjection, SRS_PT_MERCATOR_1SP)) |
1032 | 0 | { |
1033 | | // Special case for Web Mercator |
1034 | 0 | const char *method_name = ""; |
1035 | 0 | GetWKT2ProjectionMethod(&method_name, nullptr, nullptr); |
1036 | 0 | if (EQUAL(method_name, "Popular Visualisation Pseudo Mercator")) |
1037 | 0 | { |
1038 | 0 | CPLPrintStringFill(szEarthModel, "D894", 4); |
1039 | 0 | } |
1040 | 0 | } |
1041 | 67 | } |
1042 | | |
1043 | | /* -------------------------------------------------------------------- */ |
1044 | | /* If not a very well known datum, try for an EPSG based */ |
1045 | | /* translation. */ |
1046 | | /* -------------------------------------------------------------------- */ |
1047 | 356 | if (szEarthModel[0] == '\0') |
1048 | 285 | { |
1049 | 285 | const char *pszAuthority = GetAuthorityName("GEOGCS"); |
1050 | | |
1051 | 285 | if (pszAuthority && EQUAL(pszAuthority, "EPSG")) |
1052 | 228 | { |
1053 | 228 | const int nGCS_EPSG = atoi(GetAuthorityCode("GEOGCS")); |
1054 | | |
1055 | 10.9k | for (int i = 0; asDatums[i].nEPSGCode != 0; i++) |
1056 | 10.7k | { |
1057 | 10.7k | if (asDatums[i].nEPSGCode == nGCS_EPSG) |
1058 | 1 | { |
1059 | 1 | snprintf(szEarthModel, sizeof(szEarthModel), "%s", |
1060 | 1 | asDatums[i].pszPCIDatum); |
1061 | 1 | break; |
1062 | 1 | } |
1063 | 10.7k | } |
1064 | 228 | } |
1065 | 285 | } |
1066 | | |
1067 | | /* -------------------------------------------------------------------- */ |
1068 | | /* If we haven't found something yet, try translating the */ |
1069 | | /* ellipsoid. */ |
1070 | | /* -------------------------------------------------------------------- */ |
1071 | 356 | const double dfSemiMajor = GetSemiMajor(); |
1072 | 356 | const double dfInvFlattening = GetInvFlattening(); |
1073 | 356 | if (szEarthModel[0] == '\0') |
1074 | 284 | { |
1075 | 284 | const PCIDatums *pasDatum = asEllips; |
1076 | | |
1077 | 3.50k | while (pasDatum->pszPCIDatum) |
1078 | 3.43k | { |
1079 | 3.43k | double dfSM = 0.0; |
1080 | 3.43k | double dfIF = 0.0; |
1081 | | |
1082 | 3.43k | if (OSRGetEllipsoidInfo(pasDatum->nEPSGCode, nullptr, &dfSM, |
1083 | 3.43k | &dfIF) == OGRERR_NONE && |
1084 | 3.43k | CPLIsEqual(dfSemiMajor, dfSM) && |
1085 | 272 | CPLIsEqual(dfInvFlattening, dfIF)) |
1086 | 215 | { |
1087 | 215 | CPLPrintStringFill(szEarthModel, pasDatum->pszPCIDatum, 4); |
1088 | 215 | break; |
1089 | 215 | } |
1090 | | |
1091 | 3.21k | pasDatum++; |
1092 | 3.21k | } |
1093 | 284 | } |
1094 | | |
1095 | | // Try to find in pci_ellips.txt. |
1096 | 356 | if (szEarthModel[0] == '\0') |
1097 | 69 | { |
1098 | 69 | const char *pszCSV = CSVFilename("pci_ellips.txt"); |
1099 | 69 | const double dfSemiMinor = |
1100 | 69 | OSRCalcSemiMinorFromInvFlattening(dfSemiMajor, dfInvFlattening); |
1101 | | |
1102 | 69 | VSILFILE *fp = pszCSV ? VSIFOpenL(pszCSV, "r") : nullptr; |
1103 | | |
1104 | 69 | if (fp != nullptr) |
1105 | 0 | { |
1106 | 0 | char **papszLineItems = nullptr; |
1107 | |
|
1108 | 0 | while ((papszLineItems = CSVReadParseLineL(fp)) != nullptr) |
1109 | 0 | { |
1110 | 0 | if (CSLCount(papszLineItems) >= 4 && |
1111 | 0 | CPLIsEqual(dfSemiMajor, CPLAtof(papszLineItems[2])) && |
1112 | 0 | CPLIsEqual(dfSemiMinor, CPLAtof(papszLineItems[3]))) |
1113 | 0 | { |
1114 | 0 | snprintf(szEarthModel, sizeof(szEarthModel), "%s", |
1115 | 0 | papszLineItems[0]); |
1116 | 0 | break; |
1117 | 0 | } |
1118 | | |
1119 | 0 | CSLDestroy(papszLineItems); |
1120 | 0 | } |
1121 | |
|
1122 | 0 | CSLDestroy(papszLineItems); |
1123 | 0 | VSIFCloseL(fp); |
1124 | 0 | } |
1125 | 69 | } |
1126 | | |
1127 | | // Custom ellipsoid parameters. |
1128 | 356 | if (szEarthModel[0] == '\0') |
1129 | 69 | { |
1130 | 69 | CPLPrintStringFill(szEarthModel, "E999", 4); |
1131 | 69 | (*ppadfPrjParams)[0] = dfSemiMajor; |
1132 | 69 | (*ppadfPrjParams)[1] = |
1133 | 69 | OSRCalcSemiMinorFromInvFlattening(dfSemiMajor, dfInvFlattening); |
1134 | 69 | } |
1135 | | |
1136 | | /* -------------------------------------------------------------------- */ |
1137 | | /* If we have a non-parameteric ellipsoid, scan the */ |
1138 | | /* pci_datum.txt for a match. */ |
1139 | | /* -------------------------------------------------------------------- */ |
1140 | 356 | if (szEarthModel[0] == 'E' && !EQUAL(szEarthModel, "E999") && |
1141 | 215 | pszDatum != nullptr) |
1142 | 158 | { |
1143 | 158 | const char *pszDatumCSV = CSVFilename("pci_datum.txt"); |
1144 | 158 | double adfTOWGS84[7] = {}; |
1145 | 158 | const bool bHaveTOWGS84 = GetTOWGS84(adfTOWGS84, 7) == OGRERR_NONE; |
1146 | | |
1147 | 158 | VSILFILE *fp = pszDatumCSV ? VSIFOpenL(pszDatumCSV, "r") : nullptr; |
1148 | | |
1149 | 158 | if (fp != nullptr) |
1150 | 0 | { |
1151 | 0 | char **papszLineItems = nullptr; |
1152 | |
|
1153 | 0 | while ((papszLineItems = CSVReadParseLineL(fp)) != nullptr) |
1154 | 0 | { |
1155 | | // Compare based on datum name. This is mostly for |
1156 | | // PCI round-tripping. We won't usually get exact matches |
1157 | | // from other sources. |
1158 | 0 | if (CSLCount(papszLineItems) > 3 && |
1159 | 0 | EQUAL(papszLineItems[1], pszDatum) && |
1160 | 0 | EQUAL(papszLineItems[2], szEarthModel)) |
1161 | 0 | { |
1162 | 0 | snprintf(szEarthModel, sizeof(szEarthModel), "%s", |
1163 | 0 | papszLineItems[0]); |
1164 | 0 | break; |
1165 | 0 | } |
1166 | | |
1167 | 0 | bool bTOWGS84Match = bHaveTOWGS84; |
1168 | |
|
1169 | 0 | if (CSLCount(papszLineItems) < 11) |
1170 | 0 | bTOWGS84Match = false; |
1171 | |
|
1172 | 0 | if (bTOWGS84Match && |
1173 | 0 | (!CPLIsEqual(adfTOWGS84[0], CPLAtof(papszLineItems[3])) || |
1174 | 0 | !CPLIsEqual(adfTOWGS84[1], CPLAtof(papszLineItems[4])) || |
1175 | 0 | !CPLIsEqual(adfTOWGS84[2], CPLAtof(papszLineItems[5])))) |
1176 | 0 | bTOWGS84Match = false; |
1177 | |
|
1178 | 0 | if (bTOWGS84Match && CSLCount(papszLineItems) >= 15 && |
1179 | 0 | (!CPLIsEqual(adfTOWGS84[3], CPLAtof(papszLineItems[11])) || |
1180 | 0 | !CPLIsEqual(adfTOWGS84[4], CPLAtof(papszLineItems[12])) || |
1181 | 0 | !CPLIsEqual(adfTOWGS84[5], CPLAtof(papszLineItems[13])))) |
1182 | 0 | bTOWGS84Match = false; |
1183 | |
|
1184 | 0 | if (bTOWGS84Match && CSLCount(papszLineItems) >= 15) |
1185 | 0 | { |
1186 | 0 | double dfScale = CPLAtof(papszLineItems[14]); |
1187 | | |
1188 | | // Convert to parts per million if is a 1 based scaling. |
1189 | 0 | if (dfScale >= 0.999 && dfScale <= 1.001) |
1190 | 0 | dfScale = (dfScale - 1.0) * 1000000.0; |
1191 | |
|
1192 | 0 | if (fabs(adfTOWGS84[6] - dfScale) > |
1193 | 0 | 1e-11 * fabs(adfTOWGS84[6])) |
1194 | 0 | bTOWGS84Match = false; |
1195 | 0 | } |
1196 | |
|
1197 | 0 | if (bTOWGS84Match && CSLCount(papszLineItems) < 15 && |
1198 | 0 | (!CPLIsEqual(adfTOWGS84[3], 0.0) || |
1199 | 0 | !CPLIsEqual(adfTOWGS84[4], 0.0) || |
1200 | 0 | !CPLIsEqual(adfTOWGS84[5], 0.0) || |
1201 | 0 | !CPLIsEqual(adfTOWGS84[6], 0.0))) |
1202 | 0 | bTOWGS84Match = false; |
1203 | |
|
1204 | 0 | if (bTOWGS84Match) |
1205 | 0 | { |
1206 | 0 | snprintf(szEarthModel, sizeof(szEarthModel), "%s", |
1207 | 0 | papszLineItems[0]); |
1208 | 0 | break; |
1209 | 0 | } |
1210 | | |
1211 | 0 | CSLDestroy(papszLineItems); |
1212 | 0 | } |
1213 | |
|
1214 | 0 | CSLDestroy(papszLineItems); |
1215 | 0 | VSIFCloseL(fp); |
1216 | 0 | } |
1217 | 158 | } |
1218 | | |
1219 | 356 | CPLPrintStringFill(szProj + 12, szEarthModel, 4); |
1220 | | |
1221 | 356 | CPLDebug("OSR_PCI", "Translated as '%s'", szProj); |
1222 | | |
1223 | | /* -------------------------------------------------------------------- */ |
1224 | | /* Translate the linear units. */ |
1225 | | /* -------------------------------------------------------------------- */ |
1226 | 356 | const char *pszUnits = |
1227 | 356 | STARTS_WITH_CI(szProj, "LONG/LAT") ? "DEGREE" : "METRE"; |
1228 | | |
1229 | | /* -------------------------------------------------------------------- */ |
1230 | | /* Report results. */ |
1231 | | /* -------------------------------------------------------------------- */ |
1232 | 356 | szProj[knProjSize] = '\0'; |
1233 | 356 | *ppszProj = CPLStrdup(szProj); |
1234 | | |
1235 | 356 | *ppszUnits = CPLStrdup(pszUnits); |
1236 | | |
1237 | 356 | return OGRERR_NONE; |
1238 | 356 | } |