Line data Source code
1 : // SPDX-License-Identifier: MIT
2 : // Copyright 1999-2003, Daniel Morissette
3 : // Copyright (c) 1999-2001, Frank Warmerdam
4 : // Implementation translation between MIF CoordSys format, and
5 : // and OGRSpatialRef format.
6 :
7 : /*! @cond Doxygen_Suppress */
8 :
9 : #include "ogrmitabspatialref.h"
10 :
11 : #include "cpl_port.h"
12 :
13 : #include <algorithm>
14 : #include <cmath>
15 : #include <cstddef>
16 : #include <cstdio>
17 : #include <cstdlib>
18 : #include <cstring>
19 :
20 : #include "cpl_conv.h"
21 : #include "cpl_error.h"
22 : #include "cpl_string.h"
23 : #include "ogr_spatialref.h"
24 : #include "ogr_srs_api.h"
25 :
26 : typedef struct
27 : {
28 : int nDatumEPSGCode;
29 : int nMapInfoDatumID;
30 : const char *pszOGCDatumName;
31 : int nEllipsoid;
32 : double dfShiftX;
33 : double dfShiftY;
34 : double dfShiftZ;
35 : double dfDatumParm0; /* RotX */
36 : double dfDatumParm1; /* RotY */
37 : double dfDatumParm2; /* RotZ */
38 : double dfDatumParm3; /* Scale Factor */
39 : double dfDatumParm4; /* Prime Meridian */
40 : } MapInfoDatumInfo;
41 :
42 : typedef struct
43 : {
44 : int nMapInfoId;
45 : const char *pszMapinfoName;
46 : double dfA; /* semi major axis in meters */
47 : double dfInvFlattening; /* Inverse flattening */
48 : } MapInfoSpheroidInfo;
49 :
50 : /**********************************************************************
51 : * MapInfo Units string to numeric ID conversion
52 : **********************************************************************/
53 : typedef struct
54 : {
55 : int nUnitId;
56 : const char *pszAbbrev;
57 : } MapInfoUnitsInfo;
58 :
59 : static const MapInfoUnitsInfo gasUnitsList[] = {
60 : {0, "mi"}, {1, "km"}, {2, "in"}, {3, "ft"},
61 : {4, "yd"}, {5, "mm"}, {6, "cm"}, {7, "m"},
62 : {8, "survey ft"}, {8, "survey foot"}, // alternate
63 : {13, nullptr}, {9, "nmi"}, {30, "li"}, {31, "ch"},
64 : {32, "rd"}, {-1, nullptr}};
65 :
66 : /**********************************************************************
67 : * TABUnitIdToString()
68 : *
69 : * Return the MIF units name for specified units id.
70 : * Return "" if no match found.
71 : *
72 : * The returned string should not be freed by the caller.
73 : **********************************************************************/
74 81 : static const char *TABUnitIdToString(int nId)
75 : {
76 81 : const MapInfoUnitsInfo *psList = gasUnitsList;
77 :
78 674 : while (psList->nUnitId != -1)
79 : {
80 674 : if (psList->nUnitId == nId)
81 81 : return psList->pszAbbrev;
82 593 : psList++;
83 : }
84 :
85 0 : return "";
86 : }
87 :
88 : /**********************************************************************
89 : * TABUnitIdFromString()
90 : *
91 : * Return the units ID for specified MIF units name
92 : *
93 : * Returns -1 if no match found.
94 : **********************************************************************/
95 167 : static int TABUnitIdFromString(const char *pszName)
96 : {
97 167 : if (pszName == nullptr)
98 0 : return 13;
99 :
100 167 : const MapInfoUnitsInfo *psList = gasUnitsList;
101 :
102 1322 : while (psList->nUnitId != -1)
103 : {
104 1322 : if (psList->pszAbbrev != nullptr && EQUAL(psList->pszAbbrev, pszName))
105 167 : return psList->nUnitId;
106 1155 : psList++;
107 : }
108 :
109 0 : return -1;
110 : }
111 :
112 : /* -------------------------------------------------------------------- */
113 : /* This table was automatically generated by doing translations */
114 : /* between mif and tab for each datum, and extracting the */
115 : /* parameters from the tab file. The EPSG codes and OGC names */
116 : /* were added afterwards and may be incomplete or inaccurate. */
117 : /* -------------------------------------------------------------------- */
118 :
119 : extern const MapInfoDatumInfo asDatumInfoList[];
120 : extern const MapInfoSpheroidInfo asSpheroidInfoList[];
121 :
122 : /* EPSG code, MapInfo datum ID (or 9999), OGC Name, datum parameters... */
123 : const MapInfoDatumInfo asDatumInfoList[] = {
124 :
125 : {0, 104, "WGS_1984", 28, 0, 0, 0, 0, 0, 0, 0, 0},
126 : {6269, 74, "North_American_Datum_1983", 0, 0, 0, 0, 0, 0, 0, 0, 0},
127 :
128 : {0, 0, "", 29, 0, 0, 0, 0, 0, 0, 0, 0}, // Datum ignore
129 :
130 : {6201, 1, "Adindan", 6, -162, -12, 206, 0, 0, 0, 0, 0},
131 : {6205, 2, "Afgooye", 3, -43, -163, 45, 0, 0, 0, 0, 0},
132 : {6204, 3, "Ain_el_Abd_1970", 4, -150, -251, -2, 0, 0, 0, 0, 0},
133 : {0, 4, "Anna_1_Astro_1965", 2, -491, -22, 435, 0, 0, 0, 0, 0},
134 : {6209, 5, "Arc_1950", 15, -143, -90, -294, 0, 0, 0, 0, 0},
135 : {6210, 6, "Arc_1960", 6, -160, -8, -300, 0, 0, 0, 0, 0},
136 : {0, 7, "Ascension_Islands", 4, -207, 107, 52, 0, 0, 0, 0, 0},
137 : {0, 8, "Astro_Beacon_E", 4, 145, 75, -272, 0, 0, 0, 0, 0},
138 : {0, 9, "Astro_B4_Sorol_Atoll", 4, 114, -116, -333, 0, 0, 0, 0, 0},
139 : {0, 10, "Astro_Dos_71_4", 4, -320, 550, -494, 0, 0, 0, 0, 0},
140 : {0, 11, "Astronomic_Station_1952", 4, 124, -234, -25, 0, 0, 0, 0, 0},
141 : {6202, 12, "Australian_Geodetic_Datum_66", 2, -133, -48, 148, 0, 0, 0, 0,
142 : 0},
143 : {6203, 13, "Australian_Geodetic_Datum_84", 2, -134, -48, 149, 0, 0, 0, 0,
144 : 0},
145 : {0, 14, "Bellevue_Ign", 4, -127, -769, 472, 0, 0, 0, 0, 0},
146 : {6216, 15, "Bermuda_1957", 7, -73, 213, 296, 0, 0, 0, 0, 0},
147 : {6218, 16, "Bogota", 4, 307, 304, -318, 0, 0, 0, 0, 0},
148 : {6221, 17, "Campo_Inchauspe", 4, -148, 136, 90, 0, 0, 0, 0, 0},
149 : {0, 18, "Canton_Astro_1966", 4, 298, -304, -375, 0, 0, 0, 0, 0},
150 : {6222, 19, "Cape", 6, -136, -108, -292, 0, 0, 0, 0, 0},
151 : {6717, 20, "Cape_Canaveral", 7, -2, 150, 181, 0, 0, 0, 0, 0},
152 : {6223, 21, "Carthage", 6, -263, 6, 431, 0, 0, 0, 0, 0},
153 : {6672, 22, "Chatham_1971", 4, 175, -38, 113, 0, 0, 0, 0, 0},
154 : {6224, 23, "Chua", 4, -134, 229, -29, 0, 0, 0, 0, 0},
155 : {6225, 24, "Corrego_Alegre", 4, -206, 172, -6, 0, 0, 0, 0, 0},
156 : {6211, 25, "Batavia", 10, -377, 681, -50, 0, 0, 0, 0, 0},
157 : {0, 26, "Dos_1968", 4, 230, -199, -752, 0, 0, 0, 0, 0},
158 : {6719, 27, "Easter_Island_1967", 4, 211, 147, 111, 0, 0, 0, 0, 0},
159 : {6230, 28, "European_Datum_1950", 4, -87, -98, -121, 0, 0, 0, 0, 0},
160 : {6668, 29, "European_Datum_1979", 4, -86, -98, -119, 0, 0, 0, 0, 0},
161 : {6233, 30, "Gandajika_1970", 4, -133, -321, 50, 0, 0, 0, 0, 0},
162 : {6272, 31, "New_Zealand_GD49", 4, 84, -22, 209, 0, 0, 0, 0, 0},
163 : {6272, 31, "New_Zealand_Geodetic_Datum_1949", 4, 84, -22, 209, 0, 0, 0, 0,
164 : 0},
165 : {0, 32, "GRS_67", 21, 0, 0, 0, 0, 0, 0, 0, 0},
166 : {0, 33, "GRS_80", 0, 0, 0, 0, 0, 0, 0, 0, 0},
167 : {6171, 33, "Reseau_Geodesique_Francais_1993", 0, 0, 0, 0, 0, 0, 0, 0, 0},
168 : {6619, 33, "SWEREF99", 0, 0, 0, 0, 0, 0, 0, 0, 0},
169 : {6675, 34, "Guam_1963", 7, -100, -248, 259, 0, 0, 0, 0, 0},
170 : {0, 35, "Gux_1_Astro", 4, 252, -209, -751, 0, 0, 0, 0, 0},
171 : {6254, 36, "Hito_XVIII_1963", 4, 16, 196, 93, 0, 0, 0, 0, 0},
172 : {6658, 37, "Hjorsey_1955", 4, -73, 46, -86, 0, 0, 0, 0, 0},
173 : {6738, 38, "Hong_Kong_1963", 4, -156, -271, -189, 0, 0, 0, 0, 0},
174 : {6236, 39, "Hu_Tzu_Shan", 4, -634, -549, -201, 0, 0, 0, 0, 0},
175 : {0, 40, "Indian_Thailand_Vietnam", 11, 214, 836, 303, 0, 0, 0, 0, 0},
176 : {0, 41, "Indian_Bangladesh", 11, 289, 734, 257, 0, 0, 0, 0, 0},
177 : {6299, 42, "Ireland_1965", 13, 506, -122, 611, 0, 0, 0, 0, 0},
178 : {0, 43, "ISTS_073_Astro_1969", 4, 208, -435, -229, 0, 0, 0, 0, 0},
179 : {6725, 44, "Johnston_Island_1961", 4, 191, -77, -204, 0, 0, 0, 0, 0},
180 : {6244, 45, "Kandawala", 11, -97, 787, 86, 0, 0, 0, 0, 0},
181 : {0, 46, "Kerguyelen_Island", 4, 145, -187, 103, 0, 0, 0, 0, 0},
182 : {6245, 47, "Kertau", 17, -11, 851, 5, 0, 0, 0, 0, 0},
183 : {0, 48, "L_C_5_Astro", 7, 42, 124, 147, 0, 0, 0, 0, 0},
184 : {6251, 49, "Liberia_1964", 6, -90, 40, 88, 0, 0, 0, 0, 0},
185 : {0, 50, "Luzon_Phillippines", 7, -133, -77, -51, 0, 0, 0, 0, 0},
186 : {0, 51, "Luzon_Mindanao_Island", 7, -133, -79, -72, 0, 0, 0, 0, 0},
187 : {6256, 52, "Mahe_1971", 6, 41, -220, -134, 0, 0, 0, 0, 0},
188 : {0, 53, "Marco_Astro", 4, -289, -124, 60, 0, 0, 0, 0, 0},
189 : {6262, 54, "Massawa", 10, 639, 405, 60, 0, 0, 0, 0, 0},
190 : {6261, 55, "Merchich", 16, 31, 146, 47, 0, 0, 0, 0, 0},
191 : {0, 56, "Midway_Astro_1961", 4, 912, -58, 1227, 0, 0, 0, 0, 0},
192 : {6263, 57, "Minna", 6, -92, -93, 122, 0, 0, 0, 0, 0},
193 : {0, 58, "Nahrwan_Masirah_Island", 6, -247, -148, 369, 0, 0, 0, 0, 0},
194 : {0, 59, "Nahrwan_Un_Arab_Emirates", 6, -249, -156, 381, 0, 0, 0, 0, 0},
195 : {0, 60, "Nahrwan_Saudi_Arabia", 6, -231, -196, 482, 0, 0, 0, 0, 0},
196 : {6271, 61, "Naparima_1972", 4, -2, 374, 172, 0, 0, 0, 0, 0},
197 : {6267, 62, "NAD_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0},
198 : {6267, 62, "North_American_Datum_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0},
199 : {0, 63, "NAD_27_Alaska", 7, -5, 135, 172, 0, 0, 0, 0, 0},
200 : {0, 64, "NAD_27_Bahamas", 7, -4, 154, 178, 0, 0, 0, 0, 0},
201 : {0, 65, "NAD_27_San_Salvador", 7, 1, 140, 165, 0, 0, 0, 0, 0},
202 : {0, 66, "NAD_27_Canada", 7, -10, 158, 187, 0, 0, 0, 0, 0},
203 : {0, 67, "NAD_27_Canal_Zone", 7, 0, 125, 201, 0, 0, 0, 0, 0},
204 : {0, 68, "NAD_27_Caribbean", 7, -7, 152, 178, 0, 0, 0, 0, 0},
205 : {0, 69, "NAD_27_Central_America", 7, 0, 125, 194, 0, 0, 0, 0, 0},
206 : {0, 70, "NAD_27_Cuba", 7, -9, 152, 178, 0, 0, 0, 0, 0},
207 : {0, 71, "NAD_27_Greenland", 7, 11, 114, 195, 0, 0, 0, 0, 0},
208 : {0, 72, "NAD_27_Mexico", 7, -12, 130, 190, 0, 0, 0, 0, 0},
209 : {0, 73, "NAD_27_Michigan", 8, -8, 160, 176, 0, 0, 0, 0, 0},
210 : {0, 75, "Observatorio_1966", 4, -425, -169, 81, 0, 0, 0, 0, 0},
211 : {0, 76, "Old_Egyptian", 22, -130, 110, -13, 0, 0, 0, 0, 0},
212 : {6135, 77, "Old_Hawaiian", 7, 61, -285, -181, 0, 0, 0, 0, 0},
213 : {0, 78, "Oman", 6, -346, -1, 224, 0, 0, 0, 0, 0},
214 : {6277, 79, "OSGB_1936", 9, 375, -111, 431, 0, 0, 0, 0, 0},
215 : {0, 80, "Pico_De_Las_Nieves", 4, -307, -92, 127, 0, 0, 0, 0, 0},
216 : {6729, 81, "Pitcairn_Astro_1967", 4, 185, 165, 42, 0, 0, 0, 0, 0},
217 : {6248, 82, "Provisional_South_American", 4, -288, 175, -376, 0, 0, 0, 0, 0},
218 : {6139, 83, "Puerto_Rico", 7, 11, 72, -101, 0, 0, 0, 0, 0},
219 : {6614, 84, "Qatar_National", 4, -128, -283, 22, 0, 0, 0, 0, 0},
220 : {6287, 85, "Qornoq", 4, 164, 138, -189, 0, 0, 0, 0, 0},
221 : {6627, 86, "Reunion", 4, 94, -948, -1262, 0, 0, 0, 0, 0},
222 : {6265, 87, "Monte_Mario", 4, -225, -65, 9, 0, 0, 0, 0, 0},
223 : {0, 88, "Santo_Dos", 4, 170, 42, 84, 0, 0, 0, 0, 0},
224 : {0, 89, "Sao_Braz", 4, -203, 141, 53, 0, 0, 0, 0, 0},
225 : {6292, 90, "Sapper_Hill_1943", 4, -355, 16, 74, 0, 0, 0, 0, 0},
226 : {6293, 91, "Schwarzeck", 14, 616, 97, -251, 0, 0, 0, 0, 0},
227 : {6618, 92, "South_American_Datum_1969", 24, -57, 1, -41, 0, 0, 0, 0, 0},
228 : {0, 93, "South_Asia", 19, 7, -10, -26, 0, 0, 0, 0, 0},
229 : {0, 94, "Southeast_Base", 4, -499, -249, 314, 0, 0, 0, 0, 0},
230 : {0, 95, "Southwest_Base", 4, -104, 167, -38, 0, 0, 0, 0, 0},
231 : {6298, 96, "Timbalai_1948", 11, -689, 691, -46, 0, 0, 0, 0, 0},
232 : {6301, 97, "Tokyo", 10, -128, 481, 664, 0, 0, 0, 0, 0},
233 : {0, 98, "Tristan_Astro_1968", 4, -632, 438, -609, 0, 0, 0, 0, 0},
234 : {6731, 99, "Viti_Levu_1916", 6, 51, 391, -36, 0, 0, 0, 0, 0},
235 : {0, 100, "Wake_Entiwetok_1960", 23, 101, 52, -39, 0, 0, 0, 0, 0},
236 : {0, 101, "WGS_60", 26, 0, 0, 0, 0, 0, 0, 0, 0},
237 : {6760, 102, "WGS_66", 27, 0, 0, 0, 0, 0, 0, 0, 0},
238 : {6322, 103, "WGS_1972", 1, 0, 8, 10, 0, 0, 0, 0, 0},
239 : {6322, 103, "World_Geodetic_System_1972", 1, 0, 8, 10, 0, 0, 0, 0, 0},
240 : {6326, 104, "WGS_1984", 28, 0, 0, 0, 0, 0, 0, 0, 0},
241 : {6309, 105, "Yacare", 4, -155, 171, 37, 0, 0, 0, 0, 0},
242 : {6311, 106, "Zanderij", 4, -265, 120, -358, 0, 0, 0, 0, 0},
243 : {0, 107, "NTF", 30, -168, -60, 320, 0, 0, 0, 0, 0},
244 : {6231, 108, "European_Datum_1987", 4, -83, -96, -113, 0, 0, 0, 0, 0},
245 : {0, 109, "Netherlands_Bessel", 10, 593, 26, 478, 0, 0, 0, 0, 0},
246 : {0, 110, "Belgium_Hayford", 4, 81, 120, 129, 0, 0, 0, 0, 0},
247 : {0, 111, "NWGL_10", 1, -1, 15, 1, 0, 0, 0, 0, 0},
248 : {6124, 112, "Rikets_koordinatsystem_1990", 10, 498, -36, 568, 0, 0, 0, 0,
249 : 0},
250 : {0, 113, "Lisboa_DLX", 4, -303, -62, 105, 0, 0, 0, 0, 0},
251 : {0, 114, "Melrica_1973_D73", 4, -223, 110, 37, 0, 0, 0, 0, 0},
252 : {6258, 115, "European_Terrestrial_Reference_System_1989", 0, 0, 0, 0, 0, 0,
253 : 0, 0, 0},
254 : {6258, 115, "Euref_89", 0, 0, 0, 0, 0, 0, 0, 0, 0},
255 : {6180, 115, "Estonia_1997", 0, 0, 0, 0, 0, 0, 0, 0, 0},
256 : {6283, 116, "GDA94", 0, 0, 0, 0, 0, 0, 0, 0, 0},
257 : {6283, 116, "Geocentric_Datum_of_Australia_1994", 0, 0, 0, 0, 0, 0, 0, 0,
258 : 0},
259 : {6167, 117, "NZGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0},
260 : {6167, 117, "New_Zealand_Geodetic_Datum_2000", 0, 0, 0, 0, 0, 0, 0, 0, 0},
261 : {6169, 118, "America_Samoa", 7, -115, 118, 426, 0, 0, 0, 0, 0},
262 : {0, 119, "Antigua_Astro_1965", 6, -270, 13, 62, 0, 0, 0, 0, 0},
263 : {6713, 120, "Ayabelle_Lighthouse", 6, -79, -129, 145, 0, 0, 0, 0, 0},
264 : {6219, 121, "Bukit_Rimpah", 10, -384, 664, -48, 0, 0, 0, 0, 0},
265 : {0, 122, "Estonia_1937", 10, 374, 150, 588, 0, 0, 0, 0, 0},
266 : {6155, 123, "Dabola", 6, -83, 37, 124, 0, 0, 0, 0, 0},
267 : {6736, 124, "Deception_Island", 6, 260, 12, -147, 0, 0, 0, 0, 0},
268 : {0, 125, "Fort_Thomas_1955", 6, -7, 215, 225, 0, 0, 0, 0, 0},
269 : {0, 126, "Graciosa_base_1948", 4, -104, 167, -38, 0, 0, 0, 0, 0},
270 : {6255, 127, "Herat_North", 4, -333, -222, 114, 0, 0, 0, 0, 0},
271 : {0, 128, "Hermanns_Kogel", 10, 682, -203, 480, 0, 0, 0, 0, 0},
272 : {6240, 129, "Indian", 50, 283, 682, 231, 0, 0, 0, 0, 0},
273 : {6239, 130, "Indian_1954", 11, 217, 823, 299, 0, 0, 0, 0, 0},
274 : {6131, 131, "Indian_1960", 11, 198, 881, 317, 0, 0, 0, 0, 0},
275 : {6240, 132, "Indian_1975", 11, 210, 814, 289, 0, 0, 0, 0, 0},
276 : {6238, 133, "Indonesian_Datum_1974", 4, -24, -15, 5, 0, 0, 0, 0, 0},
277 : {0, 134, "ISTS061_Astro_1968", 4, -794, 119, -298, 0, 0, 0, 0, 0},
278 : {0, 135, "Kusaie_Astro_1951", 4, 647, 1777, -1124, 0, 0, 0, 0, 0},
279 : {6250, 136, "Leigon", 6, -130, 29, 364, 0, 0, 0, 0, 0},
280 : {0, 137, "Montserrat_Astro_1958", 6, 174, 359, 365, 0, 0, 0, 0, 0},
281 : {6266, 138, "Mporaloko", 6, -74, -130, 42, 0, 0, 0, 0, 0},
282 : {0, 139, "North_Sahara_1959", 6, -186, -93, 310, 0, 0, 0, 0, 0},
283 : {0, 140, "Observatorio_Met_1939", 4, -425, -169, 81, 0, 0, 0, 0, 0},
284 : {6620, 141, "Point_58", 6, -106, -129, 165, 0, 0, 0, 0, 0},
285 : {6282, 142, "Pointe_Noire", 6, -148, 51, -291, 0, 0, 0, 0, 0},
286 : {6615, 143, "Porto_Santo_1936", 4, -499, -249, 314, 0, 0, 0, 0, 0},
287 : {6616, 144, "Selvagem_Grande_1938", 4, -289, -124, 60, 0, 0, 0, 0, 0},
288 : {0, 145, "Sierra_Leone_1960", 6, -88, 4, 101, 0, 0, 0, 0, 0},
289 : {6156, 146, "S_JTSK_Ferro", 10, 589, 76, 480, 0, 0, 0, 0, 0},
290 : {6297, 147, "Tananarive_1925", 4, -189, -242, -91, 0, 0, 0, 0, 0},
291 : {6811, 148, "Voirol_1874", 6, -73, -247, 227, 0, 0, 0, 0, 0},
292 : {0, 149, "Virol_1960", 6, -123, -206, 219, 0, 0, 0, 0, 0},
293 : {6148, 150, "Hartebeesthoek94", 28, 0, 0, 0, 0, 0, 0, 0, 0},
294 : {6122, 151, "ATS77", 51, 0, 0, 0, 0, 0, 0, 0, 0},
295 : {6612, 152, "JGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0},
296 : {0, 153, "HGRS87", 0, -199.87, 74.79, 246.62, 0, 0, 0, 0, 0},
297 : {6214, 154, "Beijing 1954", 3, -31.4, 144.3, 81.2, 0, 0, 0, 0, 0},
298 : {6754, 155, "Libya (LGD 2006)", 4, 208.4058, 109.8777, 2.5764, 0, 0, 0, 0,
299 : 0},
300 : {6317, 156, "Dealul Piscului 1970", 3, 28, -121, -77, 0, 0, 0, 0, 0},
301 : {0, 157, "WGS_1984", 54, 0, 0, 0, 0, 0, 0, 0, 0}, // Google merc
302 : {6150, 158, "CH1903+ datum for Switzerland", 10, 674.374, 15.056, 405.346,
303 : 0, 0, 0, 0, 0},
304 : {0, 159, "Schwarzeck (updated) datum for Namibia", 14, 616.8, 103.3, -256.9,
305 : 0, 0, 0, 0, 0},
306 : {0, 161, "NOAA GCS_Sphere", 55, 0, 0, 0, 0, 0, 0, 0, 0},
307 : // Ellipsoid 40 got from https://docs.precisely.com/docs/sftw/mapinfo-pro/v2021/en-us/pdf/mapinfo-pro-v2021-user-guide.pdf
308 : // Ellipsoid 40 is "Everest (India 1956)", 6377301.243, 300.80174
309 : // but EPSG uses "Everest 1830 (RSO 1969)",6377295.664,300.8017
310 : {6751, 164, "Kertau (RSO)", 40, -11, 851, 5, 0, 0, 0, 0, 0},
311 : {0, 1000, "DHDN_Potsdam_Rauenberg", 10, 582, 105, 414, -1.04, -0.35, 3.08,
312 : 8.3, 0},
313 : {6284, 1001, "Pulkovo_1942", 3, 24, -123, -94, -0.02, 0.25, 0.13, 1.1, 0},
314 : {6807, 1002, "NTF_Paris_Meridian", 30, -168, -60, 320, 0, 0, 0, 0,
315 : 2.337229166667},
316 : {6149, 1003, "Switzerland_CH_1903", 10, 660.077, 13.551, 369.344, 0.804816,
317 : 0.577692, 0.952236, 5.66, 0},
318 : {6237, 1004, "Hungarian_Datum_1972", 21, -56, 75.77, 15.31, -0.37, -0.2,
319 : -0.21, -1.01, 0},
320 : {0, 1005, "Cape_7_Parameter", 28, -134.73, -110.92, -292.66, 0, 0, 0, 1, 0},
321 : {6203, 1006, "AGD84_7_Param_Aust", 2, -117.763, -51.51, 139.061, -0.292,
322 : -0.443, -0.277, -0.191, 0},
323 : {0, 1007, "AGD66_7_Param_ACT", 2, -129.193, -41.212, 130.73, -0.246, -0.374,
324 : -0.329, -2.955, 0},
325 : {0, 1008, "AGD66_7_Param_TAS", 2, -120.271, -64.543, 161.632, -0.2175,
326 : 0.0672, 0.1291, 2.4985, 0},
327 : {0, 1009, "AGD66_7_Param_VIC_NSW", 2, -119.353, -48.301, 139.484, -0.415,
328 : -0.26, -0.437, -0.613, 0},
329 : {6272, 1010, "NZGD_7_Param_49", 4, 59.47, -5.04, 187.44, -0.47, 0.1, -1.024,
330 : -4.5993, 0},
331 : {0, 1011, "Rikets_Tri_7_Param_1990", 10, 419.3836, 99.3335, 591.3451,
332 : -0.850389, -1.817277, 7.862238, -0.99496, 0},
333 : {0, 1012, "Russia_PZ90", 52, -1.08, -0.27, -0.9, 0, 0, -0.16, -0.12, 0},
334 : {0, 1013, "Russia_SK42", 52, 23.92, -141.27, -80.9, 0, -0.35, -0.82, -0.12,
335 : 0},
336 : {0, 1014, "Russia_SK95", 52, 24.82, -131.21, -82.66, 0, 0, -0.16, -0.12, 0},
337 : {6301, 1015, "Tokyo", 10, -146.414, 507.337, 680.507, 0, 0, 0, 0, 0},
338 : {6123, 1016, "Kartastokoordinaattijarjestelma_1966", 4, -96.062, -82.428,
339 : -121.754, -4.801, -0.345, 1.376, 1.496, 0},
340 : {6610, 1017, "Xian 1980", 53, 24, -123, -94, -0.02, -0.25, 0.13, 1.1, 0},
341 : {0, 1018, "Lithuanian Pulkovo 1942", 4, -40.59527, -18.54979, -69.33956,
342 : -2.508, -1.8319, 2.6114, -4.2991, 0},
343 : {6313, 1019, "Belgian 1972 7 Parameter", 4, -99.059, 53.322, -112.486,
344 : -0.419, 0.83, -1.885, 0.999999, 0},
345 : {6818, 1020, "S-JTSK with Ferro prime meridian", 10, 589, 76, 480, 0, 0, 0,
346 : 0, -17.666666666667},
347 : {1031, 1021, "Serbia datum MGI 1901", 10, 574.027, 170.175, 401.545,
348 : 4.88786, -0.66524, -13.24673, 6.88933, 0},
349 : {0, 1022, "North Sahara 7-parameter", 6, -38.7086, -128.8054, 118.8837,
350 : 0.83822, 7.38459, -1.57989, 3.9904, 0},
351 : {0, 1023, "Hungarian Projection System (EOV) - updated", 21, 52.684,
352 : -71.194, -13.975, 0.312, 0.1063, 0.3729, 1.0191, 0},
353 : {1052, 1024, "S-JTSK (Krovak) Coordinate system - updated", 10, 570.6934,
354 : 85.6936, 462.8393, -4.99825, -1.58663, -5.26114, 3.5430155, 0},
355 : {0, 1025, "JTSK03 (Slovak Republic)", 10, 485.014055, 169.473618,
356 : 483.842943, -7.78625453, -4.39770887, -4.10248899, 0, 0},
357 : {1168, 1028, "Geocentric Datum of Australia 2020", 0, -0.06155, 0.01087,
358 : 0.04019, 0.0394924, 0.0327221, 0.0328979, 0.009994, 0},
359 : // For some weird reason, MapInfo uses nEllipsoid=8 "Clarke 1866 (modified
360 : // for Michigan)" cf
361 : // https://docs.precisely.com/docs/sftw/mapinfo-pro/v2021.1/en-us/pdf/mapinfo-pro-v2021.1-release-notes.pdf
362 : // page 8 whereas EPSG uses the regular Clarke 1866 ellipsoid.
363 : {6683, 1031, "Philippine Reference System 1992", 8, -127.62, -67.24, -47.04,
364 : -3.068, 4.903, 1.578, -1.06, 0},
365 : {0, 9999, "Bosnia-Herzegovina", 10, 472.8677, 187.8769, 544.7084,
366 : -5.76198422, -5.3222842, 12.80666941, 1.54517287, 0},
367 : {6181, 9999, "Luxembourg 1930 / Gauss", 4, -192.986, 13.673, -39.309,
368 : 0.4099, 2.9332, -2.6881, 0.43, 0},
369 : {1168, 9999, "Geocentric Datum of Australia 2020", 0, -0.06155, 0.01087,
370 : 0.04019, 0.0394924, 0.0327221, 0.0328979, 0.009994, 0},
371 : {-1, -1, nullptr, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* This table was hand entered from Appendix I of the mapinfo 6 */
375 : /* manuals. */
376 : /* -------------------------------------------------------------------- */
377 :
378 : const MapInfoSpheroidInfo asSpheroidInfoList[] = {
379 : {9, "Airy 1930", 6377563.396, 299.3249646},
380 : {13, "Airy 1930 (modified for Ireland 1965", 6377340.189, 299.3249646},
381 : {51, "ATS77 (Average Terrestrial System 1977)", 6378135, 298.257},
382 : {2, "Australian", 6378160.0, 298.25},
383 : {10, "Bessel 1841", 6377397.155, 299.1528128},
384 : {35, "Bessel 1841 (modified for NGO 1948)", 6377492.0176, 299.15281},
385 : {14, "Bessel 1841 (modified for Schwarzeck)", 6377483.865, 299.1528128},
386 : {36, "Clarke 1858", 6378293.639, 294.26068},
387 : {7, "Clarke 1866", 6378206.4, 294.9786982},
388 : {8, "Clarke 1866 (modified for Michigan)", 6378450.047484481, 294.9786982},
389 : {6, "Clarke 1880", 6378249.145, 293.465},
390 : {15, "Clarke 1880 (modified for Arc 1950)", 6378249.145326, 293.4663076},
391 : {30, "Clarke 1880 (modified for IGN)", 6378249.2, 293.4660213},
392 : {37, "Clarke 1880 (modified for Jamaica)", 6378249.136, 293.46631},
393 : {16, "Clarke 1880 (modified for Merchich)", 6378249.2, 293.46598},
394 : {38, "Clarke 1880 (modified for Palestine)", 6378300.79, 293.46623},
395 : {39, "Everest (Brunei and East Malaysia)", 6377298.556, 300.8017},
396 : {11, "Everest (India 1830)", 6377276.345, 300.8017},
397 : {40, "Everest (India 1956)", 6377301.243, 300.80174},
398 : {50, "Everest (Pakistan)", 6377309.613, 300.8017},
399 : {17, "Everest (W. Malaysia and Singapore 1948)", 6377304.063, 300.8017},
400 : {48, "Everest (West Malaysia 1969)", 6377304.063, 300.8017},
401 : {18, "Fischer 1960", 6378166.0, 298.3},
402 : {19, "Fischer 1960 (modified for South Asia)", 6378155.0, 298.3},
403 : {20, "Fischer 1968", 6378150.0, 298.3},
404 : {21, "GRS 67", 6378160.0, 298.247167427},
405 : {0, "GRS 80", 6378137.0, 298.257222101},
406 : {56, "GSK2011", 6378136.5, 298.2564151},
407 : {5, "Hayford", 6378388.0, 297.0},
408 : {22, "Helmert 1906", 6378200.0, 298.3},
409 : {23, "Hough", 6378270.0, 297.0},
410 : {31, "IAG 75", 6378140.0, 298.257222},
411 : {41, "Indonesian", 6378160.0, 298.247},
412 : {4, "International 1924", 6378388.0, 297.0},
413 : {49, "Irish (WOFO)", 6377542.178, 299.325},
414 : {3, "Krassovsky", 6378245.0, 298.3},
415 : {32, "MERIT 83", 6378137.0, 298.257},
416 : {33, "New International 1967", 6378157.5, 298.25},
417 : {42, "NWL 9D", 6378145.0, 298.25},
418 : {43, "NWL 10D", 6378135.0, 298.26},
419 : {44, "OSU86F", 6378136.2, 298.25722},
420 : {45, "OSU91A", 6378136.3, 298.25722},
421 : {46, "Plessis 1817", 6376523.0, 308.64},
422 : {52, "PZ90", 6378136.0, 298.257839303},
423 : {57, "PZ90.11", 6378136.0, 298.25784},
424 : {24, "South American", 6378160.0, 298.25},
425 : {12, "Sphere", 6370997.0, 0.0},
426 : {47, "Struve 1860", 6378297.0, 294.73},
427 : {34, "Walbeck", 6376896.0, 302.78},
428 : {25, "War Office", 6378300.583, 296.0},
429 : {26, "WGS 60", 6378165.0, 298.3},
430 : {27, "WGS 66", 6378145.0, 298.25},
431 : {1, "WGS 72", 6378135.0, 298.26},
432 : {28, "WGS 84", 6378137.0, 298.257223563},
433 : {29, "WGS 84 (MAPINFO Datum 0)", 6378137.01, 298.257223563},
434 : {54, "WGS 84 (MAPINFO Datum 157)", 6378137.01, 298.257223563},
435 : {-1, nullptr, 0.0, 0.0}};
436 :
437 : /* For LCC, standard parallel 1 and 2 can be switched indifferently */
438 : /* So the MapInfo order and the EPSG order are not generally identical */
439 : /* which may cause recognition problems when reading in MapInfo */
440 : /* This table contains the parameters in the order expected by MapInfo */
441 : typedef struct
442 : {
443 : int nEPSGCode;
444 : int bReverseStdP;
445 : int nMapInfoDatumID;
446 : double dfCenterLong;
447 : double dfCenterLat;
448 : double dfStdP1;
449 : double dfStdP2;
450 : } MapInfoLCCSRS;
451 :
452 : static const MapInfoLCCSRS asMapInfoLCCSRSList[] = {
453 : {2154, 1, 33, 3, 46.5, 44, 49},
454 : {2154, 1, 33, 3, 46.5, 44, 49.00000000001},
455 : {2154, 1, 33, 3, 46.5, 44, 49.00000000002},
456 : {2225, 1, 74, -122, 39.3333333333, 40, 41.6666666667},
457 : {2226, 1, 74, -122, 37.6666666667, 38.3333333333, 39.8333333333},
458 : {2227, 1, 74, -120.5, 36.5, 37.0666666667, 38.4333333333},
459 : {2228, 1, 74, -119, 35.3333333333, 36, 37.25},
460 : {2229, 1, 74, -118, 33.5, 34.0333333333, 35.4666666667},
461 : {2230, 1, 74, -116.25, 32.1666666667, 32.7833333333, 33.8833333333},
462 : {2231, 1, 74, -105.5, 39.3333333333, 39.7166666667, 40.7833333333},
463 : {2232, 1, 74, -105.5, 37.8333333333, 38.45, 39.75},
464 : {2233, 1, 74, -105.5, 36.6666666667, 37.2333333333, 38.4333333333},
465 : {2234, 1, 74, -72.75, 40.8333333333, 41.2, 41.8666666667},
466 : {2238, 1, 74, -84.5, 29, 29.5833333333, 30.75},
467 : {2246, 0, 74, -84.25, 37.5, 37.9666666667, 38.9666666667},
468 : {2247, 1, 74, -85.75, 36.3333333333, 36.7333333333, 37.9333333333},
469 : {2248, 1, 74, -77, 37.6666666667, 38.3, 39.45},
470 : {2249, 1, 74, -71.5, 41, 41.7166666667, 42.6833333333},
471 : {2250, 1, 74, -70.5, 41, 41.2833333333, 41.4833333333},
472 : {2251, 1, 74, -87, 44.7833333333, 45.4833333333, 47.0833333333},
473 : {2252, 1, 74, -84.3666666667, 43.3166666667, 44.1833333333, 45.7},
474 : {2253, 1, 74, -84.3666666667, 41.5, 42.1, 43.6666666667},
475 : {2256, 1, 74, -109.5, 44.25, 45, 49},
476 : {2263, 1, 74, -74, 40.1666666667, 40.6666666667, 41.0333333333},
477 : {2264, 1, 74, -79, 33.75, 34.3333333333, 36.1666666667},
478 : {2265, 1, 74, -100.5, 47, 47.4333333333, 48.7333333333},
479 : {2266, 1, 74, -100.5, 45.6666666667, 46.1833333333, 47.4833333333},
480 : {2267, 1, 74, -98, 35, 35.5666666667, 36.7666666667},
481 : {2268, 1, 74, -98, 33.3333333333, 33.9333333333, 35.2333333333},
482 : {2269, 1, 74, -120.5, 43.6666666667, 44.3333333333, 46},
483 : {2270, 1, 74, -120.5, 41.6666666667, 42.3333333333, 44},
484 : {2271, 1, 74, -77.75, 40.1666666667, 40.8833333333, 41.95},
485 : {2272, 1, 74, -77.75, 39.3333333333, 39.9333333333, 40.9666666667},
486 : {2273, 1, 74, -81, 31.8333333333, 32.5, 34.8333333333},
487 : {2274, 1, 74, -86, 34.3333333333, 35.25, 36.4166666667},
488 : {2275, 1, 74, -101.5, 34, 34.65, 36.1833333333},
489 : {2276, 1, 74, -98.5, 31.6666666667, 32.1333333333, 33.9666666667},
490 : {2277, 1, 74, -100.3333333333, 29.6666666667, 30.1166666667, 31.8833333333},
491 : {2278, 1, 74, -99, 27.8333333333, 28.3833333333, 30.2833333333},
492 : {2279, 1, 74, -98.5, 25.6666666667, 26.1666666667, 27.8333333333},
493 : {2280, 1, 74, -111.5, 40.3333333333, 40.7166666667, 41.7833333333},
494 : {2281, 1, 74, -111.5, 38.3333333333, 39.0166666667, 40.65},
495 : {2282, 1, 74, -111.5, 36.6666666667, 37.2166666667, 38.35},
496 : {2283, 1, 74, -78.5, 37.6666666667, 38.0333333333, 39.2},
497 : {2284, 1, 74, -78.5, 36.3333333333, 36.7666666667, 37.9666666667},
498 : {2285, 1, 74, -120.8333333333, 47, 47.5, 48.7333333333},
499 : {2286, 1, 74, -120.5, 45.3333333333, 45.8333333333, 47.3333333333},
500 : {2287, 1, 74, -90, 45.1666666667, 45.5666666667, 46.7666666667},
501 : {2288, 1, 74, -90, 43.8333333333, 44.25, 45.5},
502 : {2289, 1, 74, -90, 42, 42.7333333333, 44.0666666667},
503 : {26740, 1, 63, -176, 51, 51.8333333333, 53.8333333333},
504 : {26741, 1, 62, -122, 39.3333333333, 40, 41.6666666667},
505 : {26742, 1, 62, -122, 37.6666666667, 38.3333333333, 39.8333333333},
506 : {26743, 1, 62, -120.5, 36.5, 37.0666666667, 38.4333333333},
507 : {26744, 1, 62, -119, 35.3333333333, 36, 37.25},
508 : {26745, 1, 62, -118, 33.5, 34.0333333333, 35.4666666667},
509 : {26746, 1, 62, -116.25, 32.1666666667, 32.7833333333, 33.8833333333},
510 : {26747, 1, 62, -118.3333333333, 34.1333333333, 33.8666666667,
511 : 34.4166666667},
512 : {26751, 1, 62, -92, 34.3333333333, 34.9333333333, 36.2333333333},
513 : {26752, 1, 62, -92, 32.6666666667, 33.3, 34.7666666667},
514 : {26753, 0, 62, -105.5, 39.3333333333, 39.7166666667, 40.7833333333},
515 : {26754, 1, 62, -105.5, 37.8333333333, 38.45, 39.75},
516 : {26755, 1, 62, -105.5, 36.6666666667, 37.2333333333, 38.4333333333},
517 : {26756, 1, 62, -72.75, 40.8333333333, 41.2, 41.8666666667},
518 : {26760, 1, 62, -84.5, 29, 29.5833333333, 30.75},
519 : {26775, 1, 62, -93.5, 41.5, 42.0666666667, 43.2666666667},
520 : {26776, 1, 62, -93.5, 40, 40.6166666667, 41.7833333333},
521 : {26777, 1, 62, -98, 38.3333333333, 38.7166666667, 39.7833333333},
522 : {26778, 0, 62, -98.5, 36.6666666667, 38.5666666667, 37.2666666667},
523 : {26779, 0, 62, -84.25, 37.5, 37.9666666667, 38.9666666667},
524 : {26780, 0, 62, -85.75, 36.3333333333, 36.7333333333, 37.9333333333},
525 : {26781, 0, 62, -92.5, 30.6666666667, 31.1666666667, 32.6666666667},
526 : {26785, 0, 62, -77, 37.8333333333, 38.3, 39.45},
527 : {26786, 0, 62, -71.5, 41, 41.7166666667, 42.6833333333},
528 : {26788, 0, 73, -87, 44.7833333333, 45.4833333333, 47.0833333333},
529 : {26789, 0, 73, -84.3333333333, 43.3166666667, 44.1833333333, 45.7},
530 : {26790, 0, 73, -84.3333333333, 41.5, 42.1, 43.6666666667},
531 : {26791, 0, 62, -93.1, 46.5, 47.0333333333, 48.6333333333},
532 : {26792, 0, 62, -94.25, 45, 45.6166666667, 47.05},
533 : {26793, 0, 62, -94, 43, 43.7833333333, 45.2166666667},
534 : {26940, 1, 74, -176, 51, 51.8333333333, 53.8333333333},
535 : {26941, 1, 74, -122, 39.3333333333, 40, 41.6666666667},
536 : {26942, 1, 74, -122, 37.6666666667, 38.3333333333, 39.8333333333},
537 : {26943, 1, 74, -120.5, 36.5, 37.0666666667, 38.4333333333},
538 : {26944, 1, 74, -119, 35.3333333333, 36, 37.25},
539 : {26945, 1, 74, -118, 33.5, 34.0333333333, 35.4666666667},
540 : {26946, 1, 74, -116.25, 32.1666666667, 32.7833333333, 33.8833333333},
541 : {26951, 1, 74, -92, 34.3333333333, 34.9333333333, 36.2333333333},
542 : {26952, 1, 74, -92, 32.6666666667, 33.3, 34.7666666667},
543 : {26953, 1, 74, -105.5, 39.3333333333, 39.7166666667, 40.7833333333},
544 : {26954, 1, 74, -105.5, 37.8333333333, 38.45, 39.75},
545 : {26955, 1, 74, -105.5, 36.6666666667, 37.2333333333, 38.4333333333},
546 : {26956, 1, 74, -72.75, 40.8333333333, 41.2, 41.8666666667},
547 : {26960, 1, 74, -84.5, 29, 29.5833333333, 30.75},
548 : {26975, 1, 74, -93.5, 41.5, 42.0666666667, 43.2666666667},
549 : {26976, 1, 74, -93.5, 40, 40.6166666667, 41.7833333333},
550 : {26977, 1, 74, -98, 38.3333333333, 38.7166666667, 39.7833333333},
551 : {26978, 0, 74, -98.5, 36.6666666667, 38.5666666667, 37.2666666667},
552 : {26980, 1, 74, -85.75, 36.3333333333, 36.7333333333, 37.9333333333},
553 : {26981, 1, 74, -92.5, 30.5, 31.1666666667, 32.6666666667},
554 : {26982, 1, 74, -91.3333333333, 28.5, 29.3, 30.7},
555 : {26985, 1, 74, -77, 37.6666666667, 38.3, 39.45},
556 : {26986, 1, 74, -71.5, 41, 41.7166666667, 42.6833333333},
557 : {26987, 1, 74, -70.5, 41, 41.2833333333, 41.4833333333},
558 : {26988, 1, 74, -87, 44.7833333333, 45.4833333333, 47.0833333333},
559 : {26989, 1, 74, -84.3666666667, 43.3166666667, 44.1833333333, 45.7},
560 : {26990, 1, 74, -84.3666666667, 41.5, 42.1, 43.6666666667},
561 : {26991, 1, 74, -93.1, 46.5, 47.0333333333, 48.6333333333},
562 : {26992, 1, 74, -94.25, 45, 45.6166666667, 47.05},
563 : {26993, 1, 74, -94, 43, 43.7833333333, 45.2166666667},
564 : {3111, 0, 116, 145, -37, -36, -38},
565 : {31370, 1, 1019, 4.3674866667, 90, 49.8333339000, 51.1666672333},
566 : {32001, 1, 62, -109.5, 47, 47.85, 48.7166666667},
567 : {32002, 1, 62, -109.5, 45.8333333333, 46.45, 47.8833333333},
568 : {32003, 1, 62, -109.5, 44, 44.8666666667, 46.4},
569 : {32005, 0, 62, -100, 41.3333333333, 41.85, 42.8166666667},
570 : {32006, 0, 62, -99.5, 39.6666666667, 40.2833333333, 41.7166666667},
571 : {32018, 1, 62, -74, 40.5, 40.6666666667, 41.0333333333},
572 : {32019, 0, 62, -79, 33.75, 34.3333333333, 36.1666666667},
573 : {32020, 0, 62, -100.5, 47, 47.4333333333, 48.7333333333},
574 : {32021, 0, 62, -100.5, 45.6666666667, 46.1833333333, 47.4833333333},
575 : {32022, 0, 62, -82.5, 39.6666666667, 40.4333333333, 41.7},
576 : {32023, 0, 62, -82.5, 38, 38.7333333333, 40.0333333333},
577 : {32024, 0, 62, -98, 35, 35.5666666667, 36.7666666667},
578 : {32025, 0, 62, -98, 33.3333333333, 33.9333333333, 35.2333333333},
579 : {32026, 0, 62, -120.5, 43.6666666667, 44.3333333333, 46},
580 : {32027, 0, 62, -120.5, 41.6666666667, 42.3333333333, 44},
581 : {32028, 0, 62, -77.75, 40.1666666667, 40.8833333333, 41.95},
582 : {32031, 0, 62, -81, 33, 33.7666666667, 34.9666666667},
583 : {32033, 0, 62, -81, 31.8333333333, 32.3333333333, 33.6666666667},
584 : {32034, 0, 62, -100, 43.8333333333, 44.4166666667, 45.6833333333},
585 : {32035, 0, 62, -100.3333333333, 42.3333333333, 42.8333333333, 44.4},
586 : {32036, 0, 62, -86, 34.6666666667, 35.25, 36.4166666667},
587 : {32037, 0, 62, -101.5, 34, 34.65, 36.1833333333},
588 : {32038, 0, 62, -97.5, 31.6666666667, 32.1333333333, 33.9666666667},
589 : {32039, 0, 62, -100.3333333333, 29.6666666667, 30.1166666667,
590 : 31.8833333333},
591 : {32040, 0, 62, -99, 27.8333333333, 28.3833333333, 30.2833333333},
592 : {32041, 0, 62, -98.5, 25.6666666667, 26.1666666667, 27.8333333333},
593 : {32042, 0, 62, -111.5, 40.3333333333, 40.7166666667, 41.7833333333},
594 : {32043, 0, 62, -111.5, 38.3333333333, 39.0166666667, 40.65},
595 : {32044, 0, 62, -111.5, 36.6666666667, 37.2166666667, 38.35},
596 : {32046, 0, 62, -78.5, 37.6666666667, 38.0333333333, 39.2},
597 : {32047, 0, 62, -78.5, 36.3333333333, 36.7666666667, 37.9666666667},
598 : {32048, 0, 62, -120.8333333333, 47, 47.5, 48.7333333333},
599 : {32049, 0, 62, -120.5, 45.3333333333, 45.8333333333, 47.3333333333},
600 : {32050, 0, 62, -79.5, 38.5, 39, 40.25},
601 : {32051, 0, 62, -81, 37, 37.4833333333, 38.8833333333},
602 : {32052, 0, 62, -90, 45.1666666667, 45.5666666667, 46.7666666667},
603 : {32053, 0, 62, -90, 43.8333333333, 44.25, 45.5},
604 : {32054, 0, 62, -90, 42, 42.7333333333, 44.0666666667},
605 : {32059, 0, 62, -66.4333333333, 18.4333333333, 18.0333333333, 18.4333333333},
606 : {32060, 0, 62, -66.4333333333, 18.4333333333, 18.0333333333, 18.4333333333},
607 : {32100, 1, 74, -109.5, 44.25, 45, 49},
608 : {32104, 1, 74, -100, 39.8333333333, 40, 43},
609 : {32118, 1, 74, -74, 40.1666666667, 40.6666666667, 41.0333333333},
610 : {32119, 1, 74, -79, 33.75, 34.3333333333, 36.1666666667},
611 : {32120, 1, 74, -100.5, 47, 47.4333333333, 48.7333333333},
612 : {32121, 1, 74, -100.5, 45.6666666667, 46.1833333333, 47.4833333333},
613 : {32122, 1, 74, -82.5, 39.6666666667, 40.4333333333, 41.7},
614 : {32123, 1, 74, -82.5, 38, 38.7333333333, 40.0333333333},
615 : {32124, 1, 74, -98, 35, 35.5666666667, 36.7666666667},
616 : {32125, 1, 74, -98, 33.3333333333, 33.9333333333, 35.2333333333},
617 : {32126, 1, 74, -120.5, 43.6666666667, 44.3333333333, 46},
618 : {32127, 1, 74, -120.5, 41.6666666667, 42.3333333333, 44},
619 : {32128, 1, 74, -77.75, 40.1666666667, 40.8833333333, 41.95},
620 : {32129, 1, 74, -77.75, 39.3333333333, 39.9333333333, 40.9666666667},
621 : {32133, 1, 74, -81, 31.8333333333, 32.5, 34.8333333333},
622 : {32134, 1, 74, -100, 43.8333333333, 44.4166666667, 45.6833333333},
623 : {32135, 1, 74, -100.3333333333, 42.3333333333, 42.8333333333, 44.4},
624 : {32136, 1, 74, -86, 34.3333333333, 35.25, 36.4166666667},
625 : {32137, 1, 74, -101.5, 34, 34.65, 36.1833333333},
626 : {32138, 1, 74, -98.5, 31.6666666667, 32.1333333333, 33.9666666667},
627 : {32139, 1, 74, -100.3333333333, 29.6666666667, 30.1166666667,
628 : 31.8833333333},
629 : {32140, 1, 74, -99, 27.8333333333, 28.3833333333, 30.2833333333},
630 : {32141, 1, 74, -98.5, 25.6666666667, 26.1666666667, 27.8333333333},
631 : {32142, 1, 74, -111.5, 40.3333333333, 40.7166666667, 41.7833333333},
632 : {32143, 1, 74, -111.5, 38.3333333333, 39.0166666667, 40.65},
633 : {32144, 1, 74, -111.5, 36.6666666667, 37.2166666667, 38.35},
634 : {32146, 1, 74, -78.5, 37.6666666667, 38.0333333333, 39.2},
635 : {32147, 1, 74, -78.5, 36.3333333333, 36.7666666667, 37.9666666667},
636 : {32148, 1, 74, -120.8333333333, 47, 47.5, 48.7333333333},
637 : {32149, 1, 74, -120.5, 45.3333333333, 45.8333333333, 47.3333333333},
638 : {32150, 1, 74, -79.5, 38.5, 39, 40.25},
639 : {32151, 1, 74, -81, 37, 37.4833333333, 38.8833333333},
640 : {32152, 1, 74, -90, 45.1666666667, 45.5666666667, 46.7666666667},
641 : {32153, 1, 74, -90, 43.8333333333, 44.25, 45.5},
642 : {32154, 1, 74, -90, 42, 42.7333333333, 44.0666666667},
643 : {32161, 1, 74, -66.4333333333, 17.8333333333, 18.0333333333, 18.4333333333},
644 : {3300, 1, 115, 24, 57.51755394, 58, 59.33333333},
645 : {3301, 1, 115, 24, 57.51755393056, 58, 59.33333333},
646 : {3797, 0, 66, -70, 44, 50, 46},
647 : {3798, 0, 74, -70, 44, 50, 46},
648 : {3799, 0, 74, -70, 44, 50, 46},
649 : {3942, 0, 33, 3, 42, 41.25, 42.75},
650 : {3943, 0, 33, 3, 43, 42.25, 43.75},
651 : {3944, 0, 33, 3, 44, 43.25, 44.75},
652 : {3945, 0, 33, 3, 45, 44.25, 45.75},
653 : {3946, 0, 33, 3, 46, 45.25, 46.75},
654 : {3947, 0, 33, 3, 47, 46.25, 47.75},
655 : {3948, 0, 33, 3, 48, 47.25, 48.75},
656 : {3949, 0, 33, 3, 49, 48.25, 49.75},
657 : {3950, 0, 33, 3, 50, 49.25, 50.75},
658 : {42101, 0, 104, -95, 0, 49, 77},
659 : {42103, 0, 104, -100, 0, 33, 45},
660 : {42304, 0, 74, -95, 49, 49, 77},
661 : {0, 0, 0, 110, 10, 25, 40},
662 : {0, 0, 0, 132.5, -10, -21.5, -33.5},
663 : {0, 0, 0, 25, 35, 40, 65},
664 : {0, 0, 0, 47.5, 25, 15, 35},
665 : {0, 0, 0, 95, 40, 20, 60},
666 : {0, 0, 1002, 0, 42.165, 41.5603877778, 42.76766333},
667 : {0, 0, 1002, 0, 42.165, 41.5603877778, 42.767663333},
668 : {0, 0, 1002, 0, 42.165, 41.560387778, 42.76766333},
669 : {0, 0, 1002, 0, 42.165, 41.560387778, 42.767663333},
670 : {0, 0, 1002, 0, 42.165, 41.56038778, 42.76766333},
671 : {0, 0, 1002, 0, 42.165, 41.560387840948, 42.76766346965},
672 : {0, 0, 1002, 0, 44.1, 43.199291275544, 44.996093814511},
673 : {0, 0, 1002, 0, 44.1, 43.1992913889, 44.99609389},
674 : {0, 0, 1002, 0, 44.1, 43.199291389, 44.99609389},
675 : {0, 0, 1002, 0, 44.1, 43.19929139, 44.99609389},
676 : {0, 0, 1002, 0, 46.8, 45.8989188889, 47.69601444},
677 : {0, 0, 1002, 0, 46.8, 45.898918889, 47.69601444},
678 : {0, 0, 1002, 0, 46.8, 45.89891889, 47.69601444},
679 : {0, 0, 1002, 0, 46.8, 45.898918964419, 47.696014502038},
680 : {0, 0, 1002, 0, 49.5, 48.5985227778, 50.39591167},
681 : {0, 0, 1002, 0, 49.5, 48.598522778, 50.39591167},
682 : {0, 0, 1002, 0, 49.5, 48.59852278, 50.39591167},
683 : {0, 0, 1002, 0, 49.5, 48.598522847174, 50.395911631678},
684 : {0, 0, 1005, 23, -23, -18, -32},
685 : {0, 0, 1022, 2.7, 36, 37.575, 34.425},
686 : {0, 0, 104, 13.33333333, 47.5, 46, 49},
687 : {0, 0, 104, 13.33333333, 48, 46, 49},
688 : {0, 0, 104, -19, 65, 64.25, 65.75},
689 : {0, 0, 104, 36.0, 25.0, 37.5, 40.5},
690 : {0, 0, 104, 36, 25, 37.5, 40.5},
691 : {0, 0, 104, 70, -50, -68.5, -74.5},
692 : {0, 0, 110, 4.367975, 90, 49.8333333333, 51.1666666667},
693 : {0, 0, 115, 10, 52, 35, 45},
694 : {0, 0, 116, 135, -24, -18, -36},
695 : {0, 0, 116, 135, -32, -28, -36},
696 : {0, 0, 12, 135, -24, -18, -36},
697 : {0, 0, 12, 145, -37, -36, -38},
698 : {0, 0, 13, 135, -24, -18, -36},
699 : {0, 0, 19, 23, -23, -18, -32},
700 : {0, 0, 28, 17, 29.77930555, 42, 56},
701 : {0, 0, 28, 19, 29.77930555, 42, 56},
702 : {0, 0, 28, 36.0, 25.0, 37.5, 40.5},
703 : {0, 0, 33, 13.5, 0, 52.6666666667, 55.3333333333},
704 : {0, 0, 33, 15, 0, 56.5, 60.5},
705 : {0, 0, 33, 15, 0, 58, 66},
706 : {0, 0, 33, 15, 0, 63.5, 67.5},
707 : {0, 0, 33, 15.5, 0, 56.6666666667, 59.3333333333},
708 : {0, 0, 33, 15.5, 0, 60.6666666667, 63.3333333333},
709 : {0, 0, 33, 16.5, 0, 60.6666666667, 63.3333333333},
710 : {0, 0, 33, 18.5, 0, 64.6666666667, 67.3333333333},
711 : {0, 0, 33, 19, 0, 64.6666666667, 67.3333333333},
712 : {0, 0, 55, -5.4, 22.5, 20.9075742561, 24.0921050540},
713 : {0, 0, 55, -5.4, 26.1, 24.5075340813, 27.6921073632},
714 : {0, 0, 55, -5.4, 29.7, 28.1063294800, 31.2932791054},
715 : {0, 0, 55, -5.4, 33.3, 31.72786641202, 34.8717272112},
716 : {0, 0, 62, -70.5, 41, 41.2833333333, 41.4833333333},
717 : {0, 0, 62, -77.75, 39.3333333333, 39.9333333333, 40.9666666667},
718 : {0, 0, 62, -91.3333333333, 25.6666666667, 26.1666666667, 27.8333333333},
719 : {0, 0, 62, -91.3333333333, 28.6666666667, 29.3, 30.67},
720 : {0, 0, 62, -96, 23, 20, 60},
721 : {0, 0, 62, -96, 23, 33, 45},
722 : {0, 0, 62, -96, 39, 33, 45},
723 : {0, 0, 66, -68.5, 44, 46, 60},
724 : {0, 0, 74, -100.3333333333, 42.3333333333, 42.8333333333, 44.4},
725 : {0, 0, 74, -100, 39.8333333333, 40, 43},
726 : {0, 0, 74, -100, 43.8333333333, 44.4166666667, 45.6833333333},
727 : {0, 0, 74, -109.5, 44.25, 45, 49},
728 : {0, 0, 74, -111.5, 36.6666666667, 37.2166666667, 38.35},
729 : {0, 0, 74, -111.5, 38.3333333333, 39.0166666667, 40.65},
730 : {0, 0, 74, -111.5, 40.3333333333, 40.7166666667, 41.7833333333},
731 : {0, 0, 74, -120.5, 41.6666666667, 42.3333333333, 44},
732 : {0, 0, 74, -120.5, 43.6666666667, 44.3333333333, 46},
733 : {0, 0, 74, -176, 51, 51.8333333333, 53.8333333333},
734 : {0, 0, 74, -66.4333333333, 17.8333333333, 18.0333333333, 18.4333333333},
735 : {0, 0, 74, -68.5, 44, 46, 60},
736 : {0, 0, 74, -79.5, 38.5, 39, 40.25},
737 : {0, 0, 74, -81, 31.8333333333, 32.5, 34.8333333333},
738 : {0, 0, 74, -81, 37, 37.4833333333, 38.8833333333},
739 : {0, 0, 74, -82.5, 38, 38.7333333333, 40.0333333333},
740 : {0, 0, 74, -82.5, 39.6666666667, 40.4333333333, 41.7},
741 : {0, 0, 74, -84.25, 37.5, 37.9666666667, 38.9666666667},
742 : {0, 0, 74, -84.3666666667, 41.5, 42.1, 43.6666666667},
743 : {0, 0, 74, -84.3666666667, 43.3166666667, 44.1833333333, 45.7},
744 : {0, 0, 74, -87, 44.7833333333, 45.4833333333, 47.0833333333},
745 : {0, 0, 74, -91.3333333333, 25.5, 26.1666666667, 27.8333333333},
746 : {0, 0, 74, -91.3333333333, 28.5, 29.3, 30.7},
747 : {0, 0, 74, -92, 32.6666666667, 33.3, 34.7666666667},
748 : {0, 0, 74, -92, 34.3333333333, 34.9333333333, 36.2333333333},
749 : {0, 0, 74, -92.5, 30.5, 31.1666666667, 32.6666666667},
750 : {0, 0, 74, -93.1, 46.5, 47.0333333333, 48.6333333333},
751 : {0, 0, 74, -93.5, 40, 40.6166666667, 41.7833333333},
752 : {0, 0, 74, -93.5, 41.5, 42.0666666667, 43.2666666667},
753 : {0, 0, 74, -94.25, 45, 45.6166666667, 47.05},
754 : {0, 0, 74, -94, 43, 43.7833333333, 45.2166666667},
755 : {0, 0, 74, -98, 38.3333333333, 38.7166666667, 39.7833333333},
756 : {0, 0, 74, -98.5, 36.6666666667, 38.5666666667, 37.2666666667},
757 : };
758 :
759 : /**********************************************************************
760 : * TABFile::GetSpatialRefFromTABProj()
761 : **********************************************************************/
762 :
763 11015 : static bool TAB_EQUAL(double a, double b)
764 : {
765 11015 : return std::fabs(a - b) < 1.0e-10;
766 : }
767 :
768 : OGRSpatialReference *
769 1442 : TABFileGetSpatialRefFromTABProj(const TABProjInfo &sTABProj)
770 : {
771 : /*-----------------------------------------------------------------
772 : * Get the units name, and translation factor.
773 : *----------------------------------------------------------------*/
774 1442 : const char *pszUnitsName = nullptr;
775 1442 : const char *pszUnitsConv = nullptr;
776 : /* double dfConv = 1.0; */
777 :
778 1442 : switch (sTABProj.nUnitsId)
779 : {
780 16 : case 0:
781 16 : pszUnitsName = "Mile";
782 16 : pszUnitsConv = "1609.344";
783 16 : break;
784 :
785 2 : case 1:
786 2 : pszUnitsName = "Kilometer";
787 2 : pszUnitsConv = "1000.0";
788 2 : break;
789 :
790 2 : case 2:
791 2 : pszUnitsName = "IINCH";
792 2 : pszUnitsConv = "0.0254";
793 2 : break;
794 :
795 4 : case 3:
796 4 : pszUnitsName = SRS_UL_FOOT;
797 4 : pszUnitsConv = SRS_UL_FOOT_CONV;
798 4 : break;
799 :
800 2 : case 4:
801 2 : pszUnitsName = "IYARD";
802 2 : pszUnitsConv = "0.9144";
803 2 : break;
804 :
805 2 : case 5:
806 2 : pszUnitsName = "Millimeter";
807 2 : pszUnitsConv = "0.001";
808 2 : break;
809 :
810 2 : case 6:
811 2 : pszUnitsName = "Centimeter";
812 2 : pszUnitsConv = "0.01";
813 2 : break;
814 :
815 1395 : case 7:
816 1395 : pszUnitsName = SRS_UL_METER;
817 1395 : pszUnitsConv = "1.0";
818 1395 : break;
819 :
820 8 : case 8:
821 8 : pszUnitsName = SRS_UL_US_FOOT;
822 8 : pszUnitsConv = SRS_UL_US_FOOT_CONV;
823 8 : break;
824 :
825 2 : case 9:
826 2 : pszUnitsName = SRS_UL_NAUTICAL_MILE;
827 2 : pszUnitsConv = SRS_UL_NAUTICAL_MILE_CONV;
828 2 : break;
829 :
830 2 : case 30:
831 2 : pszUnitsName = SRS_UL_LINK;
832 2 : pszUnitsConv = SRS_UL_LINK_CONV;
833 2 : break;
834 :
835 2 : case 31:
836 2 : pszUnitsName = SRS_UL_CHAIN;
837 2 : pszUnitsConv = SRS_UL_CHAIN_CONV;
838 2 : break;
839 :
840 2 : case 32:
841 2 : pszUnitsName = SRS_UL_ROD;
842 2 : pszUnitsConv = SRS_UL_ROD_CONV;
843 2 : break;
844 :
845 1 : default:
846 1 : pszUnitsName = SRS_UL_METER;
847 1 : pszUnitsConv = "1.0";
848 1 : break;
849 : }
850 :
851 : /* dfConv = CPLAtof(pszUnitsConv); */
852 :
853 : /*-----------------------------------------------------------------
854 : * Transform them into an OGRSpatialReference.
855 : *----------------------------------------------------------------*/
856 1442 : OGRSpatialReference *poSpatialRef = new OGRSpatialReference;
857 1442 : poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
858 :
859 : /*-----------------------------------------------------------------
860 : * Handle the PROJCS style projections, but add the datum later.
861 : *----------------------------------------------------------------*/
862 1442 : switch (sTABProj.nProjId)
863 : {
864 1259 : case 0:
865 1259 : poSpatialRef->SetLocalCS("Nonearth");
866 1259 : poSpatialRef->SetLinearUnits(pszUnitsName, CPLAtof(pszUnitsConv));
867 1259 : break;
868 :
869 : /*--------------------------------------------------------------
870 : * lat/long .. just add the GEOGCS later.
871 : *-------------------------------------------------------------*/
872 15 : case 1:
873 15 : break;
874 :
875 : /*--------------------------------------------------------------
876 : * Cylindrical Equal Area
877 : *-------------------------------------------------------------*/
878 2 : case 2:
879 2 : poSpatialRef->SetCEA(
880 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
881 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
882 2 : break;
883 :
884 : /*--------------------------------------------------------------
885 : * Lambert Conic Conformal
886 : *-------------------------------------------------------------*/
887 55 : case 3:
888 55 : poSpatialRef->SetLCC(
889 55 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
890 55 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
891 55 : sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
892 55 : break;
893 :
894 : /*--------------------------------------------------------------
895 : * Lambert Azimuthal Equal Area
896 : *-------------------------------------------------------------*/
897 2 : case 4:
898 : case 29:
899 2 : poSpatialRef->SetLAEA(sTABProj.adProjParams[1],
900 2 : sTABProj.adProjParams[0], 0.0, 0.0);
901 2 : break;
902 :
903 : /*--------------------------------------------------------------
904 : * Azimuthal Equidistant (Polar aspect only)
905 : *-------------------------------------------------------------*/
906 4 : case 5:
907 : case 28:
908 4 : poSpatialRef->SetAE(sTABProj.adProjParams[1],
909 4 : sTABProj.adProjParams[0], 0.0, 0.0);
910 4 : break;
911 :
912 : /*--------------------------------------------------------------
913 : * Equidistant Conic
914 : *-------------------------------------------------------------*/
915 2 : case 6:
916 2 : poSpatialRef->SetEC(
917 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
918 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
919 2 : sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
920 2 : break;
921 :
922 : /*--------------------------------------------------------------
923 : * Hotine Oblique Mercator
924 : *-------------------------------------------------------------*/
925 2 : case 7:
926 2 : poSpatialRef->SetHOM(
927 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
928 2 : sTABProj.adProjParams[2], 90.0, sTABProj.adProjParams[3],
929 2 : sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
930 2 : break;
931 :
932 : /*--------------------------------------------------------------
933 : * Hotine Oblique Mercator with Angle from Rectified to Skew Grid
934 : *-------------------------------------------------------------*/
935 5 : case 35:
936 5 : poSpatialRef->SetHOM(
937 5 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
938 5 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
939 5 : sTABProj.adProjParams[4], sTABProj.adProjParams[5],
940 5 : sTABProj.adProjParams[6]);
941 5 : break;
942 :
943 : /*--------------------------------------------------------------
944 : * Transverse Mercator
945 : *-------------------------------------------------------------*/
946 53 : case 8:
947 : case 34: // Extended Transverse Mercator
948 53 : poSpatialRef->SetTM(
949 53 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
950 53 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
951 53 : sTABProj.adProjParams[4]);
952 53 : break;
953 :
954 : /*----------------------------------------------------------------
955 : * Transverse Mercator,(modified for Danish System 34 Jylland-Fyn)
956 : *---------------------------------------------------------------*/
957 0 : case 21:
958 : // poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_21,
959 0 : poSpatialRef->SetTM(
960 0 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
961 0 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
962 0 : sTABProj.adProjParams[4]);
963 0 : break;
964 :
965 : /*--------------------------------------------------------------
966 : * Transverse Mercator,(modified for Danish System 34 Sjaelland)
967 : *-------------------------------------------------------------*/
968 0 : case 22:
969 : // poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_22,
970 0 : poSpatialRef->SetTM(
971 0 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
972 0 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
973 0 : sTABProj.adProjParams[4]);
974 0 : break;
975 :
976 : /*----------------------------------------------------------------
977 : * Transverse Mercator,(modified for Danish System 34/45 Bornholm)
978 : *---------------------------------------------------------------*/
979 0 : case 23:
980 : // poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_23,
981 0 : poSpatialRef->SetTM(
982 0 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
983 0 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
984 0 : sTABProj.adProjParams[4]);
985 0 : break;
986 :
987 : /*--------------------------------------------------------------
988 : * Transverse Mercator,(modified for Finnish KKJ)
989 : *-------------------------------------------------------------*/
990 3 : case 24:
991 : // poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_24,
992 3 : poSpatialRef->SetTM(
993 3 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
994 3 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
995 3 : sTABProj.adProjParams[4]);
996 3 : break;
997 :
998 : /*--------------------------------------------------------------
999 : * Albers Conic Equal Area
1000 : *-------------------------------------------------------------*/
1001 2 : case 9:
1002 2 : poSpatialRef->SetACEA(
1003 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
1004 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1005 2 : sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
1006 2 : break;
1007 :
1008 : /*--------------------------------------------------------------
1009 : * Mercator
1010 : *-------------------------------------------------------------*/
1011 4 : case 10:
1012 4 : poSpatialRef->SetMercator(0.0, sTABProj.adProjParams[0], 1.0, 0.0,
1013 : 0.0);
1014 4 : break;
1015 :
1016 : /*--------------------------------------------------------------
1017 : * Miller Cylindrical
1018 : *-------------------------------------------------------------*/
1019 2 : case 11:
1020 2 : poSpatialRef->SetMC(0.0, sTABProj.adProjParams[0], 0.0, 0.0);
1021 2 : break;
1022 :
1023 : /*--------------------------------------------------------------
1024 : * Robinson
1025 : *-------------------------------------------------------------*/
1026 2 : case 12:
1027 2 : poSpatialRef->SetRobinson(sTABProj.adProjParams[0], 0.0, 0.0);
1028 2 : break;
1029 :
1030 : /*--------------------------------------------------------------
1031 : * Mollweide
1032 : *-------------------------------------------------------------*/
1033 2 : case 13:
1034 2 : poSpatialRef->SetMollweide(sTABProj.adProjParams[0], 0.0, 0.0);
1035 2 : break;
1036 :
1037 : /*--------------------------------------------------------------
1038 : * Eckert IV
1039 : *-------------------------------------------------------------*/
1040 2 : case 14:
1041 2 : poSpatialRef->SetEckertIV(sTABProj.adProjParams[0], 0.0, 0.0);
1042 2 : break;
1043 :
1044 : /*--------------------------------------------------------------
1045 : * Eckert VI
1046 : *-------------------------------------------------------------*/
1047 2 : case 15:
1048 2 : poSpatialRef->SetEckertVI(sTABProj.adProjParams[0], 0.0, 0.0);
1049 2 : break;
1050 :
1051 : /*--------------------------------------------------------------
1052 : * Sinusoidal
1053 : *-------------------------------------------------------------*/
1054 2 : case 16:
1055 2 : poSpatialRef->SetSinusoidal(sTABProj.adProjParams[0], 0.0, 0.0);
1056 2 : break;
1057 :
1058 : /*--------------------------------------------------------------
1059 : * Gall Stereographic
1060 : *-------------------------------------------------------------*/
1061 2 : case 17:
1062 2 : poSpatialRef->SetGS(sTABProj.adProjParams[0], 0.0, 0.0);
1063 2 : break;
1064 :
1065 : /*--------------------------------------------------------------
1066 : * New Zealand Map Grid
1067 : *-------------------------------------------------------------*/
1068 2 : case 18:
1069 2 : poSpatialRef->SetNZMG(
1070 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1071 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
1072 2 : break;
1073 :
1074 : /*--------------------------------------------------------------
1075 : * Lambert Conic Conformal (Belgium)
1076 : *-------------------------------------------------------------*/
1077 2 : case 19:
1078 2 : poSpatialRef->SetLCCB(
1079 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
1080 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1081 2 : sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
1082 2 : break;
1083 :
1084 : /*--------------------------------------------------------------
1085 : * Stereographic
1086 : *-------------------------------------------------------------*/
1087 2 : case 20:
1088 2 : poSpatialRef->SetStereographic(
1089 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1090 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
1091 2 : sTABProj.adProjParams[4]);
1092 2 : break;
1093 :
1094 : /*--------------------------------------------------------------
1095 : * Swiss Oblique Mercator / Cylindrical
1096 : *-------------------------------------------------------------*/
1097 2 : case 25:
1098 2 : poSpatialRef->SetSOC(
1099 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1100 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
1101 2 : break;
1102 :
1103 : /*--------------------------------------------------------------
1104 : * Regional Mercator (regular mercator with a latitude).
1105 : *-------------------------------------------------------------*/
1106 2 : case 26:
1107 2 : poSpatialRef->SetMercator2SP(sTABProj.adProjParams[1], 0.0,
1108 2 : sTABProj.adProjParams[0], 0.0, 0.0);
1109 2 : break;
1110 :
1111 : /*--------------------------------------------------------------
1112 : * Polyconic
1113 : *-------------------------------------------------------------*/
1114 2 : case 27:
1115 2 : poSpatialRef->SetPolyconic(
1116 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1117 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
1118 2 : break;
1119 :
1120 : /*--------------------------------------------------------------
1121 : * Cassini/Soldner
1122 : *-------------------------------------------------------------*/
1123 2 : case 30:
1124 2 : poSpatialRef->SetCS(
1125 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1126 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
1127 2 : break;
1128 :
1129 : /*--------------------------------------------------------------
1130 : * Oblique Stereographic
1131 : *-------------------------------------------------------------*/
1132 2 : case 31:
1133 2 : poSpatialRef->SetOS(
1134 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1135 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3],
1136 2 : sTABProj.adProjParams[4]);
1137 2 : break;
1138 :
1139 : /*--------------------------------------------------------------
1140 : * Krovak
1141 : *-------------------------------------------------------------*/
1142 2 : case 32:
1143 2 : poSpatialRef->SetKrovak(
1144 2 : sTABProj.adProjParams[1], // dfCenterLat
1145 2 : sTABProj.adProjParams[0], // dfCenterLong
1146 2 : sTABProj.adProjParams[3], // dfAzimuth
1147 2 : sTABProj.adProjParams[2], // dfPseudoStdParallelLat
1148 : 1.0, // dfScale
1149 2 : sTABProj.adProjParams[4], // dfFalseEasting
1150 2 : sTABProj.adProjParams[5]); // dfFalseNorthing
1151 2 : break;
1152 :
1153 : /*--------------------------------------------------------------
1154 : * Equidistant Cylindrical / Equirectangular
1155 : *-------------------------------------------------------------*/
1156 2 : case 33:
1157 2 : poSpatialRef->SetEquirectangular(
1158 2 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1159 2 : sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
1160 2 : break;
1161 :
1162 0 : default:
1163 0 : poSpatialRef->SetProjection(CPLSPrintf(
1164 0 : "Unhandled MapInfo projection method %d", sTABProj.nProjId));
1165 0 : break;
1166 : }
1167 :
1168 : /*-----------------------------------------------------------------
1169 : * Local (nonearth) coordinate systems have no Geographic relationship
1170 : * so we just return from here.
1171 : *----------------------------------------------------------------*/
1172 1442 : if (sTABProj.nProjId == 0)
1173 1259 : return poSpatialRef;
1174 :
1175 : /*-----------------------------------------------------------------
1176 : * Set the datum. We are only given the X, Y and Z shift for
1177 : * the datum, so for now we just synthesize a name from this.
1178 : * It would be better if we could lookup a name based on the shift.
1179 : *
1180 : * Since we have already encountered files in which adDatumParams[] values
1181 : * were in the order of 1e-150 when they should have actually been zeros,
1182 : * we will use an epsilon in our scan instead of looking for equality.
1183 : *----------------------------------------------------------------*/
1184 183 : const MapInfoDatumInfo *psDatumInfo = nullptr;
1185 :
1186 9549 : for (int iDatumInfo = 0; asDatumInfoList[iDatumInfo].nMapInfoDatumID != -1;
1187 : iDatumInfo++)
1188 : {
1189 9544 : psDatumInfo = asDatumInfoList + iDatumInfo;
1190 :
1191 10220 : if (TAB_EQUAL(psDatumInfo->nEllipsoid, sTABProj.nEllipsoidId) &&
1192 676 : ((sTABProj.nDatumId > 0 &&
1193 663 : sTABProj.nDatumId == psDatumInfo->nMapInfoDatumID) ||
1194 512 : (sTABProj.nDatumId <= 0 &&
1195 14 : TAB_EQUAL(psDatumInfo->dfShiftX, sTABProj.dDatumShiftX) &&
1196 2 : TAB_EQUAL(psDatumInfo->dfShiftY, sTABProj.dDatumShiftY) &&
1197 2 : TAB_EQUAL(psDatumInfo->dfShiftZ, sTABProj.dDatumShiftZ) &&
1198 2 : TAB_EQUAL(psDatumInfo->dfDatumParm0, sTABProj.adDatumParams[0]) &&
1199 2 : TAB_EQUAL(psDatumInfo->dfDatumParm1, sTABProj.adDatumParams[1]) &&
1200 2 : TAB_EQUAL(psDatumInfo->dfDatumParm2, sTABProj.adDatumParams[2]) &&
1201 2 : TAB_EQUAL(psDatumInfo->dfDatumParm3, sTABProj.adDatumParams[3]) &&
1202 1 : TAB_EQUAL(psDatumInfo->dfDatumParm4, sTABProj.adDatumParams[4]))))
1203 178 : break;
1204 :
1205 9366 : psDatumInfo = nullptr;
1206 : }
1207 :
1208 183 : char szDatumName[200] = {};
1209 183 : if (psDatumInfo == nullptr)
1210 : {
1211 5 : if (sTABProj.adDatumParams[0] == 0.0 &&
1212 2 : sTABProj.adDatumParams[1] == 0.0 &&
1213 2 : sTABProj.adDatumParams[2] == 0.0 &&
1214 2 : sTABProj.adDatumParams[3] == 0.0 &&
1215 2 : sTABProj.adDatumParams[4] == 0.0)
1216 : {
1217 2 : snprintf(szDatumName, sizeof(szDatumName),
1218 2 : "MIF 999,%u,%.15g,%.15g,%.15g", sTABProj.nEllipsoidId,
1219 2 : sTABProj.dDatumShiftX, sTABProj.dDatumShiftY,
1220 2 : sTABProj.dDatumShiftZ);
1221 : }
1222 : else
1223 : {
1224 3 : snprintf(
1225 : szDatumName, sizeof(szDatumName),
1226 : "MIF 9999,%u,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g",
1227 3 : sTABProj.nEllipsoidId, sTABProj.dDatumShiftX,
1228 3 : sTABProj.dDatumShiftY, sTABProj.dDatumShiftZ,
1229 3 : sTABProj.adDatumParams[0], sTABProj.adDatumParams[1],
1230 3 : sTABProj.adDatumParams[2], sTABProj.adDatumParams[3],
1231 3 : sTABProj.adDatumParams[4]);
1232 : }
1233 : }
1234 178 : else if (strlen(psDatumInfo->pszOGCDatumName) > 0)
1235 : {
1236 177 : CPLStrlcpy(szDatumName, psDatumInfo->pszOGCDatumName,
1237 : sizeof(szDatumName));
1238 : }
1239 : else
1240 : {
1241 1 : snprintf(szDatumName, sizeof(szDatumName), "MIF %d",
1242 1 : psDatumInfo->nMapInfoDatumID);
1243 : }
1244 :
1245 : /*-----------------------------------------------------------------
1246 : * Set the spheroid.
1247 : *----------------------------------------------------------------*/
1248 183 : double dfSemiMajor = 0.0;
1249 183 : double dfInvFlattening = 0.0;
1250 183 : const char *pszSpheroidName = nullptr;
1251 :
1252 6689 : for (int i = 0; asSpheroidInfoList[i].nMapInfoId != -1; i++)
1253 : {
1254 6689 : if (asSpheroidInfoList[i].nMapInfoId == sTABProj.nEllipsoidId)
1255 : {
1256 183 : dfSemiMajor = asSpheroidInfoList[i].dfA;
1257 183 : dfInvFlattening = asSpheroidInfoList[i].dfInvFlattening;
1258 183 : pszSpheroidName = asSpheroidInfoList[i].pszMapinfoName;
1259 183 : break;
1260 : }
1261 : }
1262 :
1263 : // use WGS 84 if nothing is known.
1264 183 : if (pszSpheroidName == nullptr)
1265 : {
1266 0 : pszSpheroidName = "unknown";
1267 0 : dfSemiMajor = 6378137.0;
1268 0 : dfInvFlattening = 298.257223563;
1269 : }
1270 :
1271 : /*-----------------------------------------------------------------
1272 : * Set the prime meridian.
1273 : *----------------------------------------------------------------*/
1274 183 : double dfPMOffset = 0.0;
1275 183 : const char *pszPMName = "Greenwich";
1276 :
1277 183 : if (/*sTABProj.nDatumId == 9999 ||*/ sTABProj.adDatumParams[4] != 0.0)
1278 : {
1279 5 : dfPMOffset = sTABProj.adDatumParams[4];
1280 :
1281 5 : if (fabs(dfPMOffset - 2.337229166667) < 1e-10)
1282 3 : pszPMName = "Paris";
1283 : else
1284 2 : pszPMName = "non-Greenwich";
1285 : }
1286 :
1287 : /*-----------------------------------------------------------------
1288 : * Create a GEOGCS definition.
1289 : *----------------------------------------------------------------*/
1290 :
1291 183 : poSpatialRef->SetGeogCS("unnamed", szDatumName, pszSpheroidName,
1292 : dfSemiMajor, dfInvFlattening, pszPMName, dfPMOffset,
1293 : SRS_UA_DEGREE, CPLAtof(SRS_UA_DEGREE_CONV));
1294 :
1295 183 : if (psDatumInfo != nullptr)
1296 : {
1297 178 : if (CPLTestBool(
1298 : CPLGetConfigOption("MITAB_SET_TOWGS84_ON_KNOWN_DATUM", "NO")))
1299 : {
1300 0 : poSpatialRef->SetTOWGS84(
1301 0 : psDatumInfo->dfShiftX, psDatumInfo->dfShiftY,
1302 0 : psDatumInfo->dfShiftZ,
1303 0 : psDatumInfo->dfDatumParm0 == 0
1304 : ? 0
1305 0 : : -psDatumInfo->dfDatumParm0, /* avoids 0 to be transformed
1306 : into -0 */
1307 0 : psDatumInfo->dfDatumParm1 == 0 ? 0 : -psDatumInfo->dfDatumParm1,
1308 0 : psDatumInfo->dfDatumParm2 == 0 ? 0 : -psDatumInfo->dfDatumParm2,
1309 0 : psDatumInfo->dfDatumParm3);
1310 : }
1311 : }
1312 : else
1313 : {
1314 6 : poSpatialRef->SetTOWGS84(
1315 5 : sTABProj.dDatumShiftX, sTABProj.dDatumShiftY, sTABProj.dDatumShiftZ,
1316 5 : sTABProj.adDatumParams[0] == 0 ? 0 : -sTABProj.adDatumParams[0],
1317 5 : sTABProj.adDatumParams[1] == 0 ? 0 : -sTABProj.adDatumParams[1],
1318 3 : sTABProj.adDatumParams[2] == 0 ? 0 : -sTABProj.adDatumParams[2],
1319 5 : sTABProj.adDatumParams[3]);
1320 : }
1321 :
1322 : /*-----------------------------------------------------------------
1323 : * Special case for Google Mercator (datum=157, ellipse=54, gdal #4115)
1324 : *----------------------------------------------------------------*/
1325 183 : if (sTABProj.nProjId == 10 && sTABProj.nDatumId == 157 &&
1326 2 : sTABProj.nEllipsoidId == 54)
1327 : {
1328 2 : poSpatialRef->SetNode("PROJCS", "WGS 84 / Pseudo-Mercator");
1329 2 : poSpatialRef->SetExtension(
1330 : "PROJCS", "PROJ4",
1331 : "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 "
1332 : "+y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs");
1333 : }
1334 :
1335 : /*-----------------------------------------------------------------
1336 : * Special case for France Lambert-93
1337 : *----------------------------------------------------------------*/
1338 55 : if (sTABProj.nProjId == 3 && sTABProj.nDatumId == 33 &&
1339 86 : sTABProj.nEllipsoidId == 0 &&
1340 43 : TAB_EQUAL(poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0),
1341 238 : 3.0) &&
1342 43 : TAB_EQUAL(poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0),
1343 : 46.5))
1344 : {
1345 43 : poSpatialRef->SetNode("PROJCS", "RGF93 / Lambert-93");
1346 43 : poSpatialRef->SetNode("PROJCS|GEOGCS", "RGF93");
1347 43 : poSpatialRef->SetNode("PROJCS|GEOGCS|DATUM",
1348 : "Reseau_Geodesique_Francais_1993");
1349 : }
1350 :
1351 183 : if (sTABProj.nProjId == 3)
1352 : {
1353 : // If the LCC_2SP can be turned into a LCC_1SP that has the same
1354 : // latitude of origin, then it is a better candidate
1355 55 : OGRSpatialReference *poLCC1SP = poSpatialRef->convertToOtherProjection(
1356 : SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP);
1357 55 : if (poLCC1SP)
1358 : {
1359 55 : if (TAB_EQUAL(
1360 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,
1361 : 0.0),
1362 : poLCC1SP->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0)))
1363 : {
1364 3 : delete poSpatialRef;
1365 3 : poSpatialRef = poLCC1SP;
1366 : }
1367 : else
1368 : {
1369 52 : delete poLCC1SP;
1370 : }
1371 : }
1372 : }
1373 :
1374 : /* For LCC, standard parallel 1 and 2 can be switched indifferently */
1375 : /* So the MapInfo order and the EPSG order are not generally identical */
1376 : /* which may cause recognition problems when reading in MapInfo */
1377 183 : int nEPSGCandidateCode = 0;
1378 183 : if (sTABProj.nProjId == 3)
1379 : {
1380 55 : double dfCenterLong = sTABProj.adProjParams[0];
1381 55 : double dfCenterLat = sTABProj.adProjParams[1];
1382 55 : double dfStdP1 = sTABProj.adProjParams[2];
1383 55 : double dfStdP2 = sTABProj.adProjParams[3];
1384 :
1385 3116 : for (size_t i = 0;
1386 3116 : i < sizeof(asMapInfoLCCSRSList) / sizeof(asMapInfoLCCSRSList[0]);
1387 : i++)
1388 : {
1389 623 : if (sTABProj.nDatumId == asMapInfoLCCSRSList[i].nMapInfoDatumID &&
1390 3732 : TAB_EQUAL(dfCenterLong, asMapInfoLCCSRSList[i].dfCenterLong) &&
1391 152 : TAB_EQUAL(dfCenterLat, asMapInfoLCCSRSList[i].dfCenterLat))
1392 : {
1393 211 : if (TAB_EQUAL(dfStdP1, asMapInfoLCCSRSList[i].dfStdP1) &&
1394 99 : (TAB_EQUAL(dfStdP2, asMapInfoLCCSRSList[i].dfStdP2) ||
1395 : // EPSG:3301 "Estonian Coordinate System of 1997"
1396 : // MapInfo uses a less accurate value of StdP2 than EPSG
1397 4 : (TAB_EQUAL(asMapInfoLCCSRSList[i].dfStdP2, 59.33333333) &&
1398 2 : TAB_EQUAL(dfStdP2, 59.3333333333333))))
1399 : {
1400 97 : if (nEPSGCandidateCode)
1401 : {
1402 47 : poSpatialRef->SetAuthority("PROJCS", "EPSG",
1403 : nEPSGCandidateCode);
1404 47 : nEPSGCandidateCode = 0;
1405 47 : break;
1406 : }
1407 50 : if (asMapInfoLCCSRSList[i].bReverseStdP)
1408 : {
1409 49 : CPLDebug("MITAB",
1410 : "Switching standard parallel 1 and 2");
1411 49 : poSpatialRef->SetLCC(
1412 49 : sTABProj.adProjParams[3], sTABProj.adProjParams[2],
1413 49 : sTABProj.adProjParams[1], sTABProj.adProjParams[0],
1414 49 : sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
1415 : }
1416 50 : if (asMapInfoLCCSRSList[i].nEPSGCode > 0)
1417 49 : nEPSGCandidateCode = asMapInfoLCCSRSList[i].nEPSGCode;
1418 : else
1419 1 : break;
1420 : }
1421 : }
1422 : }
1423 : }
1424 :
1425 : /*-----------------------------------------------------------------
1426 : * Apply linear units. Do that only after all above manipulations of
1427 : * projection parameters.
1428 : *----------------------------------------------------------------*/
1429 351 : if (sTABProj.nProjId != 0 && sTABProj.nProjId != 1 &&
1430 168 : CPLAtof(pszUnitsConv) != 1)
1431 : {
1432 8 : poSpatialRef->SetTargetLinearUnits(nullptr, pszUnitsName,
1433 : CPLAtof(pszUnitsConv));
1434 : }
1435 :
1436 183 : if (nEPSGCandidateCode)
1437 : {
1438 4 : OGRSpatialReference oTmp;
1439 2 : oTmp.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1440 2 : if (oTmp.importFromEPSG(nEPSGCandidateCode) == OGRERR_NONE)
1441 : {
1442 2 : *poSpatialRef = std::move(oTmp);
1443 : }
1444 : }
1445 :
1446 : /*-----------------------------------------------------------------
1447 : * Special case for Philippine Reference System 1992, to override
1448 : * the MapInfo ellipsoid=8 "Clarke 1866 (modified for Michigan)"
1449 : * by the regular Clarke 1866 of EPSG
1450 : *----------------------------------------------------------------*/
1451 183 : if (sTABProj.nDatumId == 1031 && sTABProj.nEllipsoidId == 8)
1452 : {
1453 4 : OGRSpatialReference oSRS_EPSG_4683;
1454 2 : if (oSRS_EPSG_4683.importFromEPSG(4683) == OGRERR_NONE)
1455 2 : poSpatialRef->CopyGeogCSFrom(&oSRS_EPSG_4683);
1456 : }
1457 :
1458 : /*-----------------------------------------------------------------
1459 : * Special case for Kertau (RSO), to override
1460 : * the MapInfo ellipsoid=40 "Everest (India 1956)", 6377301.243, 300.80174
1461 : * with EPSG's "Everest 1830 (RSO 1969)",6377295.664,300.8017
1462 : *----------------------------------------------------------------*/
1463 183 : if (sTABProj.nDatumId == 164 && sTABProj.nEllipsoidId == 40)
1464 : {
1465 10 : OGRSpatialReference oSRS_EPSG_4751;
1466 5 : if (oSRS_EPSG_4751.importFromEPSG(4751) == OGRERR_NONE)
1467 5 : poSpatialRef->CopyGeogCSFrom(&oSRS_EPSG_4751);
1468 : }
1469 :
1470 183 : return poSpatialRef;
1471 : }
1472 :
1473 2 : static int MITABGetCustomDatum(const OGRSpatialReference *poSpatialRef,
1474 : TABProjInfo &sTABProj)
1475 : {
1476 2 : double adfTOWGS[7] = {0};
1477 2 : if (OGRERR_NONE != poSpatialRef->GetTOWGS84(
1478 : adfTOWGS, sizeof(adfTOWGS) / sizeof(adfTOWGS[0])))
1479 : {
1480 0 : return FALSE;
1481 : }
1482 2 : sTABProj.nDatumId = 9999;
1483 2 : sTABProj.dDatumShiftX = adfTOWGS[0];
1484 2 : sTABProj.dDatumShiftY = adfTOWGS[1];
1485 2 : sTABProj.dDatumShiftZ = adfTOWGS[2];
1486 2 : sTABProj.adDatumParams[0] = -adfTOWGS[3];
1487 2 : sTABProj.adDatumParams[1] = -adfTOWGS[4];
1488 2 : sTABProj.adDatumParams[2] = -adfTOWGS[5];
1489 2 : sTABProj.adDatumParams[3] = adfTOWGS[6];
1490 :
1491 2 : int nSpheroidId = -1;
1492 :
1493 2 : const char *pszWKTSpheroid = poSpatialRef->GetAttrValue("SPHEROID");
1494 104 : for (int i = 0; asSpheroidInfoList[i].nMapInfoId != -1; i++)
1495 : {
1496 103 : if (EQUAL(pszWKTSpheroid, asSpheroidInfoList[i].pszMapinfoName))
1497 : {
1498 1 : nSpheroidId = asSpheroidInfoList[i].nMapInfoId;
1499 1 : break;
1500 : }
1501 : }
1502 :
1503 2 : if (nSpheroidId == -1)
1504 : {
1505 1 : double adSemiMajor = poSpatialRef->GetSemiMajor();
1506 1 : double adInvFlattening = poSpatialRef->GetInvFlattening();
1507 :
1508 39 : for (int i = 0; asSpheroidInfoList[i].nMapInfoId != -1; i++)
1509 : {
1510 39 : if (CPLIsEqual(adSemiMajor, asSpheroidInfoList[i].dfA) &&
1511 1 : CPLIsEqual(adInvFlattening,
1512 : asSpheroidInfoList[i].dfInvFlattening))
1513 : {
1514 1 : nSpheroidId = asSpheroidInfoList[i].nMapInfoId;
1515 1 : break;
1516 : }
1517 : }
1518 : }
1519 2 : if (nSpheroidId == -1)
1520 : {
1521 0 : CPLDebug(
1522 : "MITAB",
1523 : "Cannot find MapInfo spheroid matching %s. Defaulting to WGS 84",
1524 : pszWKTSpheroid);
1525 0 : nSpheroidId = 28; /* WGS 84 */
1526 : }
1527 2 : sTABProj.nEllipsoidId = static_cast<GByte>(nSpheroidId);
1528 2 : return TRUE;
1529 : }
1530 :
1531 110 : int TABFileGetTABProjFromSpatialRef(const OGRSpatialReference *poSpatialRef,
1532 : TABProjInfo &sTABProj, int &nParamCount)
1533 : {
1534 : /*-----------------------------------------------------------------
1535 : * Initialize TABProjInfo
1536 : *----------------------------------------------------------------*/
1537 110 : sTABProj.nProjId = 0;
1538 110 : sTABProj.nEllipsoidId = 0; /* how will we set this? */
1539 110 : sTABProj.nUnitsId = 7;
1540 110 : sTABProj.adProjParams[0] = sTABProj.adProjParams[1] = 0.0;
1541 110 : sTABProj.adProjParams[2] = sTABProj.adProjParams[3] = 0.0;
1542 110 : sTABProj.adProjParams[4] = sTABProj.adProjParams[5] = 0.0;
1543 :
1544 110 : sTABProj.nDatumId = 0;
1545 110 : sTABProj.dDatumShiftX = 0.0;
1546 110 : sTABProj.dDatumShiftY = 0.0;
1547 110 : sTABProj.dDatumShiftZ = 0.0;
1548 110 : sTABProj.adDatumParams[0] = 0.0;
1549 110 : sTABProj.adDatumParams[1] = 0.0;
1550 110 : sTABProj.adDatumParams[2] = 0.0;
1551 110 : sTABProj.adDatumParams[3] = 0.0;
1552 110 : sTABProj.adDatumParams[4] = 0.0;
1553 :
1554 110 : sTABProj.nAffineFlag = 0;
1555 110 : sTABProj.nAffineUnits = 7;
1556 110 : sTABProj.dAffineParamA = 0.0;
1557 110 : sTABProj.dAffineParamB = 0.0;
1558 110 : sTABProj.dAffineParamC = 0.0;
1559 110 : sTABProj.dAffineParamD = 0.0;
1560 110 : sTABProj.dAffineParamE = 0.0;
1561 110 : sTABProj.dAffineParamF = 0.0;
1562 :
1563 : /*-----------------------------------------------------------------
1564 : * Get the linear units and conversion.
1565 : *----------------------------------------------------------------*/
1566 110 : const char *pszLinearUnits = nullptr;
1567 110 : double dfLinearConv = poSpatialRef->GetLinearUnits(&pszLinearUnits);
1568 110 : if (dfLinearConv == 0.0)
1569 0 : dfLinearConv = 1.0;
1570 :
1571 : // Get datum information
1572 110 : const char *pszWKTDatum = poSpatialRef->GetAttrValue("DATUM");
1573 :
1574 110 : const auto GetDatumCode = [](const OGRSpatialReference *poSRS)
1575 : {
1576 110 : const char *pszDatumAuthority = poSRS->GetAuthorityName("DATUM");
1577 110 : const char *pszDatumCode = poSRS->GetAuthorityCode("DATUM");
1578 110 : if (pszDatumCode && pszDatumAuthority &&
1579 54 : EQUAL(pszDatumAuthority, "EPSG"))
1580 : {
1581 54 : return atoi(pszDatumCode);
1582 : }
1583 56 : return -1;
1584 : };
1585 :
1586 110 : int nDatumEPSGCode = GetDatumCode(poSpatialRef);
1587 110 : if (nDatumEPSGCode < 0)
1588 : {
1589 : const auto GetDatumCodeFromCRSIndirect =
1590 104 : [&GetDatumCode](const OGRSpatialReference *poSRS,
1591 0 : const char *pszNode)
1592 : {
1593 104 : const char *pszAuthorityName = poSRS->GetAuthorityName(pszNode);
1594 104 : const char *pszAuthorityCode = poSRS->GetAuthorityCode(pszNode);
1595 104 : if (pszAuthorityName && pszAuthorityCode)
1596 : {
1597 0 : OGRSpatialReference oSRSTmp;
1598 0 : if (oSRSTmp.SetFromUserInput(CPLSPrintf(
1599 0 : "%s:%s", pszAuthorityName, pszAuthorityCode)) ==
1600 : OGRERR_NONE)
1601 : {
1602 0 : return GetDatumCode(&oSRSTmp);
1603 : }
1604 : }
1605 104 : return -1;
1606 56 : };
1607 :
1608 : // When the CRS is built from WKT2 CRS string, the DATUM code will
1609 : // typically be absent from the CRS string.
1610 : // Try to get the AUTHORITY:CODE from the CRS to instantiate
1611 : // a temporary CRS and get its DATUM code.
1612 56 : nDatumEPSGCode = GetDatumCodeFromCRSIndirect(poSpatialRef, nullptr);
1613 56 : if (nDatumEPSGCode < 0 && !poSpatialRef->IsGeographic())
1614 : {
1615 : // If there's no AUTHORITY:CODE on the CRS, then retry with its
1616 : // geographic CRS
1617 : nDatumEPSGCode =
1618 48 : GetDatumCodeFromCRSIndirect(poSpatialRef, "GEOGCS");
1619 : }
1620 : }
1621 :
1622 : /*-----------------------------------------------------------------
1623 : * Transform the projection and projection parameters.
1624 : *----------------------------------------------------------------*/
1625 110 : const char *pszProjection = poSpatialRef->GetAttrValue("PROJECTION");
1626 110 : double *params = sTABProj.adProjParams;
1627 110 : nParamCount = 0;
1628 :
1629 138 : if (pszProjection == nullptr &&
1630 28 : poSpatialRef->GetAttrNode("GEOGCS") == nullptr)
1631 : {
1632 : /* nonearth */
1633 17 : sTABProj.nProjId = 0;
1634 : }
1635 :
1636 93 : else if (pszProjection == nullptr)
1637 : {
1638 11 : sTABProj.nProjId = 1;
1639 : }
1640 :
1641 82 : else if (EQUAL(pszProjection, SRS_PT_ALBERS_CONIC_EQUAL_AREA))
1642 : {
1643 1 : sTABProj.nProjId = 9;
1644 1 : params[0] =
1645 1 : poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1646 2 : params[1] =
1647 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
1648 2 : params[2] =
1649 1 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
1650 2 : params[3] =
1651 1 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
1652 1 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1653 1 : params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1654 1 : nParamCount = 6;
1655 : }
1656 :
1657 81 : else if (EQUAL(pszProjection, SRS_PT_AZIMUTHAL_EQUIDISTANT))
1658 : {
1659 2 : sTABProj.nProjId = 5;
1660 2 : params[0] =
1661 2 : poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1662 4 : params[1] =
1663 2 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
1664 2 : params[2] = 90.0;
1665 2 : nParamCount = 3;
1666 :
1667 2 : if (std::abs((std::abs(params[1]) - 90)) > 0.001)
1668 1 : sTABProj.nProjId = 28;
1669 : }
1670 :
1671 79 : else if (EQUAL(pszProjection, SRS_PT_CYLINDRICAL_EQUAL_AREA))
1672 : {
1673 1 : sTABProj.nProjId = 2;
1674 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1675 2 : params[1] =
1676 1 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
1677 1 : nParamCount = 2;
1678 : }
1679 :
1680 78 : else if (EQUAL(pszProjection, SRS_PT_ECKERT_IV))
1681 : {
1682 1 : sTABProj.nProjId = 14;
1683 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1684 1 : nParamCount = 1;
1685 : }
1686 :
1687 77 : else if (EQUAL(pszProjection, SRS_PT_ECKERT_VI))
1688 : {
1689 1 : sTABProj.nProjId = 15;
1690 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1691 1 : nParamCount = 1;
1692 : }
1693 :
1694 76 : else if (EQUAL(pszProjection, SRS_PT_EQUIDISTANT_CONIC))
1695 : {
1696 1 : sTABProj.nProjId = 6;
1697 1 : params[0] =
1698 1 : poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1699 2 : params[1] =
1700 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
1701 2 : params[2] =
1702 1 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
1703 2 : params[3] =
1704 1 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
1705 1 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1706 1 : params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1707 1 : nParamCount = 6;
1708 : }
1709 :
1710 75 : else if (EQUAL(pszProjection, SRS_PT_GALL_STEREOGRAPHIC))
1711 : {
1712 1 : sTABProj.nProjId = 17;
1713 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1714 1 : nParamCount = 1;
1715 : }
1716 :
1717 74 : else if (EQUAL(pszProjection, SRS_PT_HOTINE_OBLIQUE_MERCATOR))
1718 : {
1719 3 : if (std::abs(poSpatialRef->GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,
1720 : 90.0) -
1721 3 : 90.0) < 1e-8)
1722 : {
1723 1 : sTABProj.nProjId = 7;
1724 1 : params[0] =
1725 1 : poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1726 2 : params[1] =
1727 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
1728 1 : params[2] = poSpatialRef->GetNormProjParm(SRS_PP_AZIMUTH, 0.0);
1729 1 : params[3] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1730 1 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1731 1 : params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1732 1 : nParamCount = 6;
1733 : }
1734 : else
1735 : {
1736 2 : sTABProj.nProjId = 35;
1737 2 : params[0] =
1738 2 : poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1739 4 : params[1] =
1740 2 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
1741 2 : params[2] = poSpatialRef->GetNormProjParm(SRS_PP_AZIMUTH, 0.0);
1742 4 : params[3] =
1743 2 : poSpatialRef->GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE, 0.0);
1744 2 : params[4] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1745 2 : params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1746 2 : params[6] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1747 2 : nParamCount = 7;
1748 : }
1749 : }
1750 :
1751 71 : else if (EQUAL(pszProjection, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA))
1752 : {
1753 1 : sTABProj.nProjId = 4;
1754 1 : params[0] =
1755 1 : poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1756 2 : params[1] =
1757 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
1758 1 : params[2] = 90.0;
1759 1 : nParamCount = 3;
1760 :
1761 1 : if (std::abs((std::abs(params[1]) - 90)) > 0.001)
1762 0 : sTABProj.nProjId = 29;
1763 : }
1764 :
1765 70 : else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP))
1766 : {
1767 28 : sTABProj.nProjId = 3;
1768 28 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1769 56 : params[1] =
1770 28 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1771 56 : params[2] =
1772 28 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
1773 56 : params[3] =
1774 28 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
1775 28 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1776 28 : params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1777 28 : nParamCount = 6;
1778 : }
1779 :
1780 42 : else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP))
1781 : {
1782 : OGRSpatialReference *poOtherSRS =
1783 1 : poSpatialRef->convertToOtherProjection(
1784 : SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP);
1785 1 : if (poOtherSRS)
1786 : {
1787 1 : sTABProj.nProjId = 3;
1788 1 : params[0] =
1789 1 : poOtherSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1790 2 : params[1] =
1791 1 : poOtherSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1792 2 : params[2] =
1793 1 : poOtherSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
1794 2 : params[3] =
1795 1 : poOtherSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
1796 1 : params[4] = poOtherSRS->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1797 1 : params[5] = poOtherSRS->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1798 1 : nParamCount = 6;
1799 1 : delete poOtherSRS;
1800 : }
1801 : }
1802 :
1803 41 : else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM))
1804 : {
1805 1 : sTABProj.nProjId = 19;
1806 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1807 2 : params[1] =
1808 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1809 2 : params[2] =
1810 1 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
1811 2 : params[3] =
1812 1 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
1813 1 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1814 1 : params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1815 1 : nParamCount = 6;
1816 : }
1817 :
1818 40 : else if (EQUAL(pszProjection, SRS_PT_MERCATOR_1SP))
1819 : {
1820 3 : sTABProj.nProjId = 10;
1821 3 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1822 6 : params[1] =
1823 3 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1824 3 : params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1825 3 : nParamCount = 1; // FIXME for MIF export ?
1826 :
1827 3 : if (params[1] != 0.0)
1828 : {
1829 0 : sTABProj.nProjId = 26;
1830 0 : nParamCount = 2; // FIXME for MIF export ?
1831 : }
1832 : }
1833 :
1834 37 : else if (EQUAL(pszProjection, SRS_PT_MERCATOR_2SP))
1835 : {
1836 1 : sTABProj.nProjId = 26;
1837 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1838 2 : params[1] =
1839 1 : poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
1840 1 : nParamCount = 2; // FIXME for MIF export ?
1841 : }
1842 :
1843 36 : else if (EQUAL(pszProjection, SRS_PT_MILLER_CYLINDRICAL))
1844 : {
1845 1 : sTABProj.nProjId = 11;
1846 1 : params[0] =
1847 1 : poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1848 1 : nParamCount = 1;
1849 : }
1850 :
1851 35 : else if (EQUAL(pszProjection, SRS_PT_MOLLWEIDE))
1852 : {
1853 1 : sTABProj.nProjId = 13;
1854 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1855 1 : nParamCount = 1;
1856 : }
1857 :
1858 34 : else if (EQUAL(pszProjection, SRS_PT_NEW_ZEALAND_MAP_GRID))
1859 : {
1860 1 : sTABProj.nProjId = 18;
1861 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1862 2 : params[1] =
1863 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1864 1 : params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1865 1 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1866 1 : nParamCount = 4;
1867 : }
1868 :
1869 33 : else if (EQUAL(pszProjection, SRS_PT_SWISS_OBLIQUE_CYLINDRICAL))
1870 : {
1871 0 : sTABProj.nProjId = 25;
1872 0 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1873 0 : params[1] =
1874 0 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1875 0 : params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1876 0 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1877 0 : nParamCount = 4;
1878 : }
1879 :
1880 : // Swiss Oblique expressed as Hotine Oblique Mercator Azimuth Center
1881 66 : else if (EQUAL(pszProjection,
1882 1 : SRS_PT_HOTINE_OBLIQUE_MERCATOR_AZIMUTH_CENTER) &&
1883 1 : std::abs(poSpatialRef->GetNormProjParm(SRS_PP_AZIMUTH, 90.0) -
1884 1 : 90.0) < 1e-8 &&
1885 1 : std::abs(poSpatialRef->GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,
1886 : 90.0) -
1887 34 : 90.0) < 1e-8 &&
1888 1 : std::abs(poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0) -
1889 : 1.0) < 1e-8)
1890 : {
1891 1 : sTABProj.nProjId = 25;
1892 1 : params[0] =
1893 1 : poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
1894 2 : params[1] =
1895 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
1896 1 : params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1897 1 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1898 1 : nParamCount = 4;
1899 : }
1900 :
1901 32 : else if (EQUAL(pszProjection, SRS_PT_ROBINSON))
1902 : {
1903 1 : sTABProj.nProjId = 12;
1904 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1905 1 : nParamCount = 1;
1906 : }
1907 :
1908 31 : else if (EQUAL(pszProjection, SRS_PT_SINUSOIDAL))
1909 : {
1910 1 : sTABProj.nProjId = 16;
1911 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1912 1 : nParamCount = 1;
1913 : }
1914 :
1915 30 : else if (EQUAL(pszProjection, SRS_PT_STEREOGRAPHIC))
1916 : {
1917 1 : sTABProj.nProjId = 20;
1918 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1919 2 : params[1] =
1920 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1921 1 : params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1922 1 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1923 1 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1924 1 : nParamCount = 5;
1925 : }
1926 :
1927 29 : else if (EQUAL(pszProjection, SRS_PT_OBLIQUE_STEREOGRAPHIC))
1928 : {
1929 1 : sTABProj.nProjId = 31;
1930 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1931 2 : params[1] =
1932 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1933 1 : params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1934 1 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1935 1 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1936 1 : nParamCount = 5;
1937 : }
1938 :
1939 28 : else if (EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR))
1940 : {
1941 24 : sTABProj.nProjId = 8;
1942 24 : if ((pszWKTDatum &&
1943 24 : EQUAL(pszWKTDatum, "Kartastokoordinaattijarjestelma_1966")) ||
1944 : nDatumEPSGCode == 6123)
1945 : {
1946 : // Special case for Finnish KKJ
1947 2 : sTABProj.nProjId = 24;
1948 : }
1949 24 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1950 48 : params[1] =
1951 24 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1952 24 : params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1953 24 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1954 24 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1955 24 : nParamCount = 5;
1956 : }
1957 :
1958 4 : else if (EQUAL(pszProjection,
1959 : SRS_PT_TRANSVERSE_MERCATOR_MI_21)) // Encom 2003
1960 : {
1961 0 : sTABProj.nProjId = 21;
1962 0 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1963 0 : params[1] =
1964 0 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1965 0 : params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1966 0 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1967 0 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1968 0 : nParamCount = 5;
1969 : }
1970 :
1971 4 : else if (EQUAL(pszProjection,
1972 : SRS_PT_TRANSVERSE_MERCATOR_MI_22)) // Encom 2003
1973 : {
1974 0 : sTABProj.nProjId = 22;
1975 0 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1976 0 : params[1] =
1977 0 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1978 0 : params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1979 0 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1980 0 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1981 0 : nParamCount = 5;
1982 : }
1983 :
1984 4 : else if (EQUAL(pszProjection,
1985 : SRS_PT_TRANSVERSE_MERCATOR_MI_23)) // Encom 2003
1986 : {
1987 0 : sTABProj.nProjId = 23;
1988 0 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
1989 0 : params[1] =
1990 0 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
1991 0 : params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1992 0 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
1993 0 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1994 0 : nParamCount = 5;
1995 : }
1996 :
1997 4 : else if (EQUAL(pszProjection,
1998 : SRS_PT_TRANSVERSE_MERCATOR_MI_24)) // Encom 2003
1999 : {
2000 0 : sTABProj.nProjId = 24;
2001 0 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
2002 0 : params[1] =
2003 0 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
2004 0 : params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
2005 0 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
2006 0 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
2007 0 : nParamCount = 5;
2008 : }
2009 :
2010 4 : else if (EQUAL(pszProjection, SRS_PT_CASSINI_SOLDNER))
2011 : {
2012 1 : sTABProj.nProjId = 30;
2013 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
2014 2 : params[1] =
2015 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
2016 1 : params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
2017 1 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
2018 1 : nParamCount = 4;
2019 : }
2020 :
2021 3 : else if (EQUAL(pszProjection, SRS_PT_POLYCONIC))
2022 : {
2023 1 : sTABProj.nProjId = 27;
2024 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
2025 2 : params[1] =
2026 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
2027 1 : params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
2028 1 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
2029 1 : nParamCount = 4;
2030 : }
2031 :
2032 2 : else if (EQUAL(pszProjection, SRS_PT_KROVAK))
2033 : {
2034 1 : sTABProj.nProjId = 32;
2035 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
2036 2 : params[1] =
2037 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
2038 2 : params[2] =
2039 1 : poSpatialRef->GetNormProjParm(SRS_PP_PSEUDO_STD_PARALLEL_1, 0.0);
2040 1 : params[3] = poSpatialRef->GetNormProjParm(SRS_PP_AZIMUTH, 0.0);
2041 1 : params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
2042 1 : params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
2043 1 : nParamCount = 6;
2044 : }
2045 :
2046 1 : else if (EQUAL(pszProjection, SRS_PT_EQUIRECTANGULAR))
2047 : {
2048 1 : sTABProj.nProjId = 33;
2049 1 : params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
2050 2 : params[1] =
2051 1 : poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
2052 1 : params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
2053 1 : params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
2054 1 : nParamCount = 4;
2055 : }
2056 :
2057 : else
2058 : {
2059 0 : CPLError(CE_Warning, CPLE_AppDefined,
2060 : "No translation from %s to MapInfo known", pszProjection);
2061 : }
2062 :
2063 : /* ==============================================================
2064 : * Translate Datum and Ellipsoid
2065 : * ============================================================== */
2066 110 : const MapInfoDatumInfo *psDatumInfo = nullptr;
2067 :
2068 : /*-----------------------------------------------------------------
2069 : * Default to WGS84 if we have no datum at all.
2070 : *----------------------------------------------------------------*/
2071 110 : if (pszWKTDatum == nullptr)
2072 : {
2073 17 : CPLDebug("MITAB",
2074 : "Cannot find MapInfo datum matching %d. Defaulting to WGS 84",
2075 : nDatumEPSGCode);
2076 17 : psDatumInfo = asDatumInfoList + 0; /* WGS 84 */
2077 : // From MIF export code. FIXME?
2078 : // if( nProjection == 1 )
2079 : // nProjection = 0;
2080 : }
2081 :
2082 : /*-----------------------------------------------------------------
2083 : * We know the MIF datum number, and need to look it up to
2084 : * translate into datum parameters.
2085 : *----------------------------------------------------------------*/
2086 93 : else if (STARTS_WITH_CI(pszWKTDatum, "MIF ") &&
2087 2 : atoi(pszWKTDatum + 4) != 999 && atoi(pszWKTDatum + 4) != 9999)
2088 : {
2089 0 : int nDatum = atoi(pszWKTDatum + 4);
2090 0 : for (int i = 0; asDatumInfoList[i].nMapInfoDatumID != -1; i++)
2091 : {
2092 0 : if (nDatum == asDatumInfoList[i].nMapInfoDatumID)
2093 : {
2094 0 : psDatumInfo = asDatumInfoList + i;
2095 0 : break;
2096 : }
2097 : }
2098 :
2099 0 : if (psDatumInfo == nullptr)
2100 : {
2101 0 : CPLDebug(
2102 : "MITAB",
2103 : "Cannot find MapInfo datum matching %s. Defaulting to WGS 84",
2104 : pszWKTDatum);
2105 0 : psDatumInfo = asDatumInfoList + 0; /* WGS 84 */
2106 0 : }
2107 : }
2108 :
2109 : /*-----------------------------------------------------------------
2110 : * We have the MIF datum parameters, and apply those directly.
2111 : *----------------------------------------------------------------*/
2112 93 : else if (STARTS_WITH_CI(pszWKTDatum, "MIF ") &&
2113 2 : (atoi(pszWKTDatum + 4) == 999 || atoi(pszWKTDatum + 4) == 9999))
2114 : {
2115 2 : sTABProj.nDatumId = static_cast<GInt16>(atoi(pszWKTDatum + 4));
2116 : char **papszFields =
2117 2 : CSLTokenizeStringComplex(pszWKTDatum + 4, ",", FALSE, TRUE);
2118 :
2119 2 : if (CSLCount(papszFields) >= 5)
2120 : {
2121 2 : sTABProj.nEllipsoidId = static_cast<GByte>(atoi(papszFields[1]));
2122 2 : sTABProj.dDatumShiftX = CPLAtof(papszFields[2]);
2123 2 : sTABProj.dDatumShiftY = CPLAtof(papszFields[3]);
2124 2 : sTABProj.dDatumShiftZ = CPLAtof(papszFields[4]);
2125 : }
2126 :
2127 2 : if (CSLCount(papszFields) >= 10)
2128 : {
2129 1 : sTABProj.adDatumParams[0] = CPLAtof(papszFields[5]);
2130 1 : sTABProj.adDatumParams[1] = CPLAtof(papszFields[6]);
2131 1 : sTABProj.adDatumParams[2] = CPLAtof(papszFields[7]);
2132 1 : sTABProj.adDatumParams[3] = CPLAtof(papszFields[8]);
2133 1 : sTABProj.adDatumParams[4] = CPLAtof(papszFields[9]);
2134 : }
2135 :
2136 2 : if (CSLCount(papszFields) < 5)
2137 : {
2138 0 : CPLDebug(
2139 : "MITAB",
2140 : "Cannot find MapInfo datum matching %s. Defaulting to WGS 84",
2141 : pszWKTDatum);
2142 0 : psDatumInfo = asDatumInfoList + 0; /* WGS 84 */
2143 : }
2144 :
2145 2 : CSLDestroy(papszFields);
2146 : }
2147 :
2148 : /*-----------------------------------------------------------------
2149 : * We have a "real" datum name, and possibly an EPSG code for the
2150 : * datum. Try to look it up (using EPSG code first) and get the
2151 : * parameters. If we don't find it with either just use WGS84.
2152 : *----------------------------------------------------------------*/
2153 : else
2154 : {
2155 3938 : for (int i = 0; asDatumInfoList[i].nMapInfoDatumID != -1; i++)
2156 : {
2157 3936 : if ((nDatumEPSGCode > 0 &&
2158 3199 : asDatumInfoList[i].nDatumEPSGCode == nDatumEPSGCode) ||
2159 3888 : EQUAL(pszWKTDatum, asDatumInfoList[i].pszOGCDatumName))
2160 : {
2161 89 : psDatumInfo = asDatumInfoList + i;
2162 89 : break;
2163 : }
2164 : }
2165 :
2166 93 : if (psDatumInfo == nullptr &&
2167 2 : !MITABGetCustomDatum(poSpatialRef, sTABProj))
2168 : {
2169 0 : CPLDebug("MITAB",
2170 : "Cannot find MapInfo datum matching %s,%d. Defaulting to "
2171 : "WGS 84",
2172 : pszWKTDatum, nDatumEPSGCode);
2173 0 : psDatumInfo = asDatumInfoList + 0; /* WGS 84 */
2174 : }
2175 : }
2176 :
2177 110 : if (psDatumInfo != nullptr)
2178 : {
2179 106 : sTABProj.nEllipsoidId = static_cast<GByte>(psDatumInfo->nEllipsoid);
2180 106 : sTABProj.nDatumId = static_cast<GInt16>(psDatumInfo->nMapInfoDatumID);
2181 106 : sTABProj.dDatumShiftX = psDatumInfo->dfShiftX;
2182 106 : sTABProj.dDatumShiftY = psDatumInfo->dfShiftY;
2183 106 : sTABProj.dDatumShiftZ = psDatumInfo->dfShiftZ;
2184 106 : sTABProj.adDatumParams[0] = psDatumInfo->dfDatumParm0;
2185 106 : sTABProj.adDatumParams[1] = psDatumInfo->dfDatumParm1;
2186 106 : sTABProj.adDatumParams[2] = psDatumInfo->dfDatumParm2;
2187 106 : sTABProj.adDatumParams[3] = psDatumInfo->dfDatumParm3;
2188 106 : sTABProj.adDatumParams[4] = psDatumInfo->dfDatumParm4;
2189 :
2190 : /* For LCC, standard parallel 1 and 2 can be switched indifferently */
2191 : /* So the MapInfo order and the EPSG order are not generally identical
2192 : */
2193 : /* which may cause recognition problems when reading in MapInfo */
2194 106 : if (sTABProj.nProjId == 3)
2195 : {
2196 29 : const double dfCenterLong = params[0];
2197 29 : const double dfCenterLat = params[1];
2198 29 : const double dfStdP1 = params[2];
2199 29 : const double dfStdP2 = params[3];
2200 :
2201 : // EPSG:3301 "Estonian Coordinate System of 1997"
2202 29 : if (std::fabs(dfCenterLong - 24) <= 1e-10 &&
2203 1 : std::fabs(dfCenterLat - 57.51755393056) <= 1e-10 &&
2204 : // MapInfo uses a less accurate value of StdP2 than EPSG
2205 1 : std::fabs(dfStdP1 - 59.33333333) <= 1e-8 &&
2206 1 : std::fabs(dfStdP2 - 58) <= 1e-8)
2207 : {
2208 1 : CPLDebug("MITAB", "Switching standard parallel 1 and 2");
2209 1 : std::swap(params[2], params[3]);
2210 : }
2211 : else
2212 : {
2213 1005 : for (size_t i = 0; i < sizeof(asMapInfoLCCSRSList) /
2214 : sizeof(asMapInfoLCCSRSList[0]);
2215 : i++)
2216 : {
2217 2004 : if (sTABProj.nDatumId ==
2218 192 : asMapInfoLCCSRSList[i].nMapInfoDatumID &&
2219 192 : TAB_EQUAL(dfCenterLong,
2220 1194 : asMapInfoLCCSRSList[i].dfCenterLong) &&
2221 43 : TAB_EQUAL(dfCenterLat,
2222 43 : asMapInfoLCCSRSList[i].dfCenterLat))
2223 : {
2224 62 : if (TAB_EQUAL(dfStdP1,
2225 31 : asMapInfoLCCSRSList[i].dfStdP1) &&
2226 0 : TAB_EQUAL(dfStdP2, asMapInfoLCCSRSList[i].dfStdP2))
2227 : {
2228 0 : break;
2229 : }
2230 62 : else if (TAB_EQUAL(dfStdP1,
2231 56 : asMapInfoLCCSRSList[i].dfStdP2) &&
2232 25 : TAB_EQUAL(dfStdP2,
2233 25 : asMapInfoLCCSRSList[i].dfStdP1))
2234 : {
2235 25 : CPLDebug("MITAB",
2236 : "Switching standard parallel 1 and 2");
2237 25 : std::swap(params[2], params[3]);
2238 25 : break;
2239 : }
2240 : }
2241 : }
2242 : }
2243 : }
2244 : }
2245 :
2246 : // Google Merc
2247 110 : const char *pszAuthorityName = nullptr;
2248 110 : const char *pszAuthorityCode = nullptr;
2249 110 : const char *pszExtension = nullptr;
2250 110 : if (((pszAuthorityName = poSpatialRef->GetAuthorityName(nullptr)) !=
2251 50 : nullptr &&
2252 50 : EQUAL(pszAuthorityName, "EPSG") &&
2253 50 : (pszAuthorityCode = poSpatialRef->GetAuthorityCode(nullptr)) !=
2254 50 : nullptr &&
2255 269 : atoi(pszAuthorityCode) == 3857) ||
2256 109 : ((pszExtension = poSpatialRef->GetExtension(nullptr, "PROJ4")) !=
2257 1 : nullptr &&
2258 1 : (EQUAL(pszExtension, "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 "
2259 : "+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m "
2260 1 : "+nadgrids=@null +wktext +no_defs") ||
2261 1 : EQUAL(pszExtension,
2262 : "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 "
2263 : "+y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs"))))
2264 : {
2265 2 : sTABProj.nDatumId = 157;
2266 2 : sTABProj.nEllipsoidId = 54;
2267 : }
2268 :
2269 : /*-----------------------------------------------------------------
2270 : * Translate the units
2271 : *----------------------------------------------------------------*/
2272 110 : if (sTABProj.nProjId == 1 || pszLinearUnits == nullptr)
2273 11 : sTABProj.nUnitsId = 13;
2274 99 : else if (dfLinearConv == 1000.0)
2275 1 : sTABProj.nUnitsId = 1;
2276 98 : else if (dfLinearConv == 0.0254 || EQUAL(pszLinearUnits, "Inch") ||
2277 97 : EQUAL(pszLinearUnits, "IINCH"))
2278 1 : sTABProj.nUnitsId = 2;
2279 97 : else if (fabs(dfLinearConv - CPLAtof(SRS_UL_FOOT_CONV)) <
2280 192 : 1e-15 * dfLinearConv ||
2281 95 : EQUAL(pszLinearUnits, SRS_UL_FOOT))
2282 2 : sTABProj.nUnitsId = 3;
2283 95 : else if (EQUAL(pszLinearUnits, "YARD") || EQUAL(pszLinearUnits, "IYARD") ||
2284 : dfLinearConv == 0.9144)
2285 1 : sTABProj.nUnitsId = 4;
2286 94 : else if (dfLinearConv == 0.001)
2287 1 : sTABProj.nUnitsId = 5;
2288 93 : else if (dfLinearConv == 0.01)
2289 1 : sTABProj.nUnitsId = 6;
2290 92 : else if (dfLinearConv == 1.0)
2291 83 : sTABProj.nUnitsId = 7;
2292 9 : else if (fabs(dfLinearConv - CPLAtof(SRS_UL_US_FOOT_CONV)) <
2293 14 : 1e-15 * dfLinearConv ||
2294 5 : EQUAL(pszLinearUnits, SRS_UL_US_FOOT))
2295 4 : sTABProj.nUnitsId = 8;
2296 5 : else if (dfLinearConv == 1852.0 ||
2297 4 : EQUAL(pszLinearUnits, SRS_UL_NAUTICAL_MILE))
2298 1 : sTABProj.nUnitsId = 9;
2299 4 : else if (EQUAL(pszLinearUnits, SRS_UL_LINK) ||
2300 3 : EQUAL(pszLinearUnits, "GUNTERLINK"))
2301 1 : sTABProj.nUnitsId = 30;
2302 3 : else if (EQUAL(pszLinearUnits, SRS_UL_CHAIN) ||
2303 2 : EQUAL(pszLinearUnits, "GUNTERCHAIN"))
2304 1 : sTABProj.nUnitsId = 31;
2305 2 : else if (EQUAL(pszLinearUnits, SRS_UL_ROD))
2306 1 : sTABProj.nUnitsId = 32;
2307 1 : else if (EQUAL(pszLinearUnits, "Mile") || EQUAL(pszLinearUnits, "IMILE"))
2308 1 : sTABProj.nUnitsId = 0;
2309 : else
2310 0 : sTABProj.nUnitsId = 7;
2311 :
2312 110 : return 0;
2313 : }
2314 :
2315 : extern const MapInfoDatumInfo asDatumInfoList[];
2316 : extern const MapInfoSpheroidInfo asSpheroidInfoList[];
2317 :
2318 : /************************************************************************/
2319 : /* MITABCoordSys2SpatialRef() */
2320 : /* */
2321 : /* Convert a MIF COORDSYS string into a new OGRSpatialReference */
2322 : /* object. */
2323 : /************************************************************************/
2324 :
2325 7021 : OGRSpatialReference *MITABCoordSys2SpatialRef(const char *pszCoordSys)
2326 :
2327 : {
2328 : TABProjInfo sTABProj;
2329 7021 : if (MITABCoordSys2TABProjInfo(pszCoordSys, &sTABProj) < 0)
2330 6858 : return nullptr;
2331 163 : OGRSpatialReference *poSR = TABFileGetSpatialRefFromTABProj(sTABProj);
2332 :
2333 : // Report on translation.
2334 163 : char *pszWKT = nullptr;
2335 :
2336 163 : poSR->exportToWkt(&pszWKT);
2337 163 : if (pszWKT != nullptr)
2338 : {
2339 163 : CPLDebug("MITAB", "This CoordSys value:\n%s\nwas translated to:\n%s",
2340 : pszCoordSys, pszWKT);
2341 163 : CPLFree(pszWKT);
2342 : }
2343 :
2344 163 : return poSR;
2345 : }
2346 :
2347 : /************************************************************************/
2348 : /* MITABSpatialRef2CoordSys() */
2349 : /* */
2350 : /* Converts a OGRSpatialReference object into a MIF COORDSYS */
2351 : /* string. */
2352 : /* */
2353 : /* The function returns a newly allocated string that should be */
2354 : /* CPLFree()'d by the caller. */
2355 : /************************************************************************/
2356 :
2357 81 : char *MITABSpatialRef2CoordSys(const OGRSpatialReference *poSR)
2358 :
2359 : {
2360 81 : if (poSR == nullptr)
2361 0 : return nullptr;
2362 :
2363 : TABProjInfo sTABProj;
2364 81 : int nParamCount = 0;
2365 81 : TABFileGetTABProjFromSpatialRef(poSR, sTABProj, nParamCount);
2366 :
2367 : // Do coordsys lookup.
2368 81 : double dXMin = 0.0;
2369 81 : double dYMin = 0.0;
2370 81 : double dXMax = 0.0;
2371 81 : double dYMax = 0.0;
2372 81 : bool bHasBounds = false;
2373 136 : if (sTABProj.nProjId > 1 &&
2374 55 : MITABLookupCoordSysBounds(&sTABProj, dXMin, dYMin, dXMax, dYMax, true))
2375 : {
2376 5 : bHasBounds = true;
2377 : }
2378 :
2379 : // Translate the units.
2380 81 : const char *pszMIFUnits = TABUnitIdToString(sTABProj.nUnitsId);
2381 :
2382 : // Build coordinate system definition.
2383 162 : CPLString osCoordSys;
2384 :
2385 81 : if (sTABProj.nProjId != 0)
2386 : {
2387 66 : osCoordSys.Printf("Earth Projection %d", sTABProj.nProjId);
2388 : }
2389 : else
2390 : {
2391 15 : osCoordSys.Printf("NonEarth Units");
2392 : }
2393 :
2394 : // Append Datum.
2395 81 : if (sTABProj.nProjId != 0)
2396 : {
2397 66 : osCoordSys += CPLSPrintf(", %d", sTABProj.nDatumId);
2398 :
2399 66 : if (sTABProj.nDatumId == 999 || sTABProj.nDatumId == 9999)
2400 : {
2401 : osCoordSys +=
2402 4 : CPLSPrintf(", %d, %.15g, %.15g, %.15g", sTABProj.nEllipsoidId,
2403 : sTABProj.dDatumShiftX, sTABProj.dDatumShiftY,
2404 4 : sTABProj.dDatumShiftZ);
2405 : }
2406 :
2407 66 : if (sTABProj.nDatumId == 9999)
2408 : {
2409 : osCoordSys +=
2410 : CPLSPrintf(", %.15g, %.15g, %.15g, %.15g, %.15g",
2411 : sTABProj.adDatumParams[0], sTABProj.adDatumParams[1],
2412 : sTABProj.adDatumParams[2], sTABProj.adDatumParams[3],
2413 3 : sTABProj.adDatumParams[4]);
2414 : }
2415 : }
2416 :
2417 : // Append units.
2418 81 : if (sTABProj.nProjId != 1 && pszMIFUnits != nullptr)
2419 : {
2420 70 : if (sTABProj.nProjId != 0)
2421 55 : osCoordSys += ",";
2422 :
2423 70 : osCoordSys += CPLSPrintf(" \"%s\"", pszMIFUnits);
2424 : }
2425 :
2426 : // Append Projection Params.
2427 321 : for (int iParam = 0; iParam < nParamCount; iParam++)
2428 240 : osCoordSys += CPLSPrintf(", %.15g", sTABProj.adProjParams[iParam]);
2429 :
2430 : // Append user bounds.
2431 81 : if (bHasBounds)
2432 : {
2433 5 : if (fabs(dXMin - floor(dXMin + 0.5)) < 1e-8 &&
2434 5 : fabs(dYMin - floor(dYMin + 0.5)) < 1e-8 &&
2435 5 : fabs(dXMax - floor(dXMax + 0.5)) < 1e-8 &&
2436 5 : fabs(dYMax - floor(dYMax + 0.5)) < 1e-8)
2437 : {
2438 5 : osCoordSys +=
2439 : CPLSPrintf(" Bounds (%d, %d) (%d, %d)", static_cast<int>(dXMin),
2440 : static_cast<int>(dYMin), static_cast<int>(dXMax),
2441 5 : static_cast<int>(dYMax));
2442 : }
2443 : else
2444 : {
2445 : osCoordSys += CPLSPrintf(" Bounds (%f, %f) (%f, %f)", dXMin, dYMin,
2446 0 : dXMax, dYMax);
2447 : }
2448 : }
2449 :
2450 : // Report on translation.
2451 81 : char *pszWKT = nullptr;
2452 :
2453 81 : poSR->exportToWkt(&pszWKT);
2454 81 : if (pszWKT != nullptr)
2455 : {
2456 81 : CPLDebug("MITAB", "This WKT Projection:\n%s\n\ntranslates to:\n%s",
2457 : pszWKT, osCoordSys.c_str());
2458 81 : CPLFree(pszWKT);
2459 : }
2460 :
2461 81 : return CPLStrdup(osCoordSys.c_str());
2462 : }
2463 :
2464 : /************************************************************************/
2465 : /* MITABExtractCoordSysBounds */
2466 : /* */
2467 : /* Return true if MIF coordsys string contains a BOUNDS parameter and */
2468 : /* Set x/y min/max values. */
2469 : /************************************************************************/
2470 :
2471 12 : bool MITABExtractCoordSysBounds(const char *pszCoordSys, double &dXMin,
2472 : double &dYMin, double &dXMax, double &dYMax)
2473 :
2474 : {
2475 12 : if (pszCoordSys == nullptr)
2476 0 : return false;
2477 :
2478 : char **papszFields =
2479 12 : CSLTokenizeStringComplex(pszCoordSys, " ,()", TRUE, FALSE);
2480 :
2481 12 : int iBounds = CSLFindString(papszFields, "Bounds");
2482 :
2483 12 : if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
2484 : {
2485 12 : dXMin = CPLAtof(papszFields[++iBounds]);
2486 12 : dYMin = CPLAtof(papszFields[++iBounds]);
2487 12 : dXMax = CPLAtof(papszFields[++iBounds]);
2488 12 : dYMax = CPLAtof(papszFields[++iBounds]);
2489 12 : CSLDestroy(papszFields);
2490 12 : return true;
2491 : }
2492 :
2493 0 : CSLDestroy(papszFields);
2494 0 : return false;
2495 : }
2496 :
2497 : /**********************************************************************
2498 : * MITABCoordSys2TABProjInfo()
2499 : *
2500 : * Convert a MIF COORDSYS string into a TABProjInfo structure.
2501 : *
2502 : * Returns 0 on success, -1 on error.
2503 : **********************************************************************/
2504 7039 : int MITABCoordSys2TABProjInfo(const char *pszCoordSys, TABProjInfo *psProj)
2505 :
2506 : {
2507 : // Set all fields to zero, equivalent of NonEarth Units "mi"
2508 7039 : memset(psProj, 0, sizeof(TABProjInfo));
2509 :
2510 7039 : if (pszCoordSys == nullptr)
2511 6858 : return -1;
2512 :
2513 : // Parse the passed string into words.
2514 215 : while (*pszCoordSys == ' ')
2515 34 : pszCoordSys++; // Eat leading spaces.
2516 181 : if (STARTS_WITH_CI(pszCoordSys, "CoordSys") && pszCoordSys[8] != '\0')
2517 33 : pszCoordSys += 9;
2518 :
2519 : char **papszFields =
2520 181 : CSLTokenizeStringComplex(pszCoordSys, " ,", TRUE, FALSE);
2521 :
2522 : // Clip off Bounds information.
2523 181 : int iBounds = CSLFindString(papszFields, "Bounds");
2524 :
2525 322 : while (iBounds != -1 && papszFields[iBounds] != nullptr)
2526 : {
2527 141 : CPLFree(papszFields[iBounds]);
2528 141 : papszFields[iBounds] = nullptr;
2529 141 : iBounds++;
2530 : }
2531 :
2532 : // Fetch the projection.
2533 181 : char **papszNextField = nullptr;
2534 :
2535 329 : if (CSLCount(papszFields) >= 3 && EQUAL(papszFields[0], "Earth") &&
2536 148 : EQUAL(papszFields[1], "Projection"))
2537 : {
2538 148 : int nProjId = atoi(papszFields[2]);
2539 148 : if (nProjId >= 3000)
2540 0 : nProjId -= 3000;
2541 148 : else if (nProjId >= 2000)
2542 0 : nProjId -= 2000;
2543 148 : else if (nProjId >= 1000)
2544 0 : nProjId -= 1000;
2545 :
2546 148 : psProj->nProjId = static_cast<GByte>(nProjId);
2547 148 : papszNextField = papszFields + 3;
2548 : }
2549 33 : else if (CSLCount(papszFields) >= 2 && EQUAL(papszFields[0], "NonEarth"))
2550 : {
2551 : // NonEarth Units "..." Bounds (x, y) (x, y)
2552 33 : psProj->nProjId = 0;
2553 33 : papszNextField = papszFields + 2;
2554 :
2555 33 : if (papszNextField[0] != nullptr && EQUAL(papszNextField[0], "Units"))
2556 0 : papszNextField++;
2557 : }
2558 : else
2559 : {
2560 : // Invalid projection string ???
2561 0 : if (CSLCount(papszFields) > 0)
2562 0 : CPLError(CE_Warning, CPLE_IllegalArg,
2563 : "Failed parsing CoordSys: '%s'", pszCoordSys);
2564 0 : CSLDestroy(papszFields);
2565 0 : return -1;
2566 : }
2567 :
2568 : // Fetch the datum information.
2569 181 : int nDatum = 0;
2570 :
2571 181 : if (psProj->nProjId != 0 && CSLCount(papszNextField) > 0)
2572 : {
2573 148 : nDatum = atoi(papszNextField[0]);
2574 148 : papszNextField++;
2575 : }
2576 :
2577 181 : if ((nDatum == 999 || nDatum == 9999) && CSLCount(papszNextField) >= 4)
2578 : {
2579 5 : psProj->nEllipsoidId = static_cast<GByte>(atoi(papszNextField[0]));
2580 5 : psProj->dDatumShiftX = CPLAtof(papszNextField[1]);
2581 5 : psProj->dDatumShiftY = CPLAtof(papszNextField[2]);
2582 5 : psProj->dDatumShiftZ = CPLAtof(papszNextField[3]);
2583 5 : papszNextField += 4;
2584 :
2585 5 : if (nDatum == 9999 && CSLCount(papszNextField) >= 5)
2586 : {
2587 3 : psProj->adDatumParams[0] = CPLAtof(papszNextField[0]);
2588 3 : psProj->adDatumParams[1] = CPLAtof(papszNextField[1]);
2589 3 : psProj->adDatumParams[2] = CPLAtof(papszNextField[2]);
2590 3 : psProj->adDatumParams[3] = CPLAtof(papszNextField[3]);
2591 3 : psProj->adDatumParams[4] = CPLAtof(papszNextField[4]);
2592 3 : papszNextField += 5;
2593 : }
2594 : }
2595 176 : else if (nDatum != 999 && nDatum != 9999)
2596 : {
2597 : // Find the datum, and collect its parameters if possible.
2598 176 : const MapInfoDatumInfo *psDatumInfo = nullptr;
2599 :
2600 176 : int iDatum = 0; // Used after for.
2601 5981 : for (; asDatumInfoList[iDatum].nMapInfoDatumID != -1; iDatum++)
2602 : {
2603 5981 : if (asDatumInfoList[iDatum].nMapInfoDatumID == nDatum)
2604 : {
2605 176 : psDatumInfo = asDatumInfoList + iDatum;
2606 176 : break;
2607 : }
2608 : }
2609 :
2610 176 : if (asDatumInfoList[iDatum].nMapInfoDatumID == -1)
2611 : {
2612 : // Use WGS84.
2613 0 : psDatumInfo = asDatumInfoList + 0;
2614 : }
2615 :
2616 176 : if (psDatumInfo != nullptr)
2617 : {
2618 176 : psProj->nEllipsoidId = static_cast<GByte>(psDatumInfo->nEllipsoid);
2619 176 : psProj->nDatumId =
2620 176 : static_cast<GInt16>(psDatumInfo->nMapInfoDatumID);
2621 176 : psProj->dDatumShiftX = psDatumInfo->dfShiftX;
2622 176 : psProj->dDatumShiftY = psDatumInfo->dfShiftY;
2623 176 : psProj->dDatumShiftZ = psDatumInfo->dfShiftZ;
2624 176 : psProj->adDatumParams[0] = psDatumInfo->dfDatumParm0;
2625 176 : psProj->adDatumParams[1] = psDatumInfo->dfDatumParm1;
2626 176 : psProj->adDatumParams[2] = psDatumInfo->dfDatumParm2;
2627 176 : psProj->adDatumParams[3] = psDatumInfo->dfDatumParm3;
2628 176 : psProj->adDatumParams[4] = psDatumInfo->dfDatumParm4;
2629 : }
2630 : }
2631 :
2632 : // Fetch the units string.
2633 181 : if (CSLCount(papszNextField) > 0)
2634 : {
2635 167 : if (isdigit(static_cast<unsigned char>(papszNextField[0][0])))
2636 : {
2637 0 : psProj->nUnitsId = static_cast<GByte>(atoi(papszNextField[0]));
2638 : }
2639 : else
2640 : {
2641 167 : psProj->nUnitsId =
2642 167 : static_cast<GByte>(TABUnitIdFromString(papszNextField[0]));
2643 : }
2644 167 : papszNextField++;
2645 : }
2646 :
2647 : // Finally the projection parameters.
2648 808 : for (int iParam = 0; iParam < 7 && CSLCount(papszNextField) > 0; iParam++)
2649 : {
2650 627 : psProj->adProjParams[iParam] = CPLAtof(papszNextField[0]);
2651 627 : papszNextField++;
2652 : }
2653 :
2654 181 : CSLDestroy(papszFields);
2655 :
2656 181 : return 0;
2657 : }
2658 :
2659 : /*! @endcond */
|