Line data Source code
1 : /*****************************************************************************
2 : *
3 : * Project: Idrisi Raster Image File Driver
4 : * Purpose: Read/write Idrisi Raster Image Format RST
5 : * Author: Ivan Lucena, [lucena_ivan at hotmail.com]
6 : *
7 : * Revised by Hongmei Zhu, February, 2013
8 : * honzhu@clarku.edu
9 : * Clark Labs/Clark University
10 : *
11 : ******************************************************************************
12 : * Copyright( c ) 2006, Ivan Lucena
13 : * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
14 : *
15 : * Permission is hereby granted, free of charge, to any person obtaining a
16 : * copy of this software and associated documentation files( the "Software" ),
17 : * to deal in the Software without restriction, including without limitation
18 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 : * and/or sell copies of the Software, and to permit persons to whom the
20 : * Software is furnished to do so, subject to the following conditions:
21 : *
22 : * The above copyright notice and this permission notice shall be included
23 : * in all copies or substantial portions of the Software.
24 : *
25 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 : * DEALINGS IN THE SOFTWARE.
32 : ****************************************************************************/
33 :
34 : #include "cpl_conv.h"
35 : #include "cpl_string.h"
36 : #include "cpl_csv.h"
37 : #include "gdal_frmts.h"
38 : #include "gdal_pam.h"
39 : #include "gdal_alg.h"
40 : #include "gdal_priv.h"
41 : #include "gdal_rat.h"
42 : #include "ogr_spatialref.h"
43 : #include "idrisi.h"
44 :
45 : #include "proj_experimental.h"
46 : #include "ogr_proj_p.h"
47 :
48 : #include <cmath>
49 :
50 : #ifdef _WIN32
51 : #define PATHDELIM '\\'
52 : #else
53 : #define PATHDELIM '/'
54 : #endif
55 :
56 : //----- Safe numeric conversion, NULL as zero
57 : #define atoi_nz(s) (s == nullptr ? (int)0 : atoi(s))
58 : #define CPLAtof_nz(s) (s == nullptr ? (double)0.0 : CPLAtof(s))
59 :
60 : //----- file extensions:
61 : static const char *const extRST = "rst";
62 : static const char *const extRDC = "rdc";
63 : static const char *const extSMP = "smp";
64 : static const char *const extREF = "ref";
65 : // static const char * const extRSTu = "RST";
66 : static const char *const extRDCu = "RDC";
67 : static const char *const extSMPu = "SMP";
68 : static const char *const extREFu = "REF";
69 :
70 : //----- field names on rdc file:
71 : static const char *const rdcFILE_FORMAT = "file format ";
72 : static const char *const rdcFILE_TITLE = "file title ";
73 : static const char *const rdcDATA_TYPE = "data type ";
74 : static const char *const rdcFILE_TYPE = "file type ";
75 : static const char *const rdcCOLUMNS = "columns ";
76 : static const char *const rdcROWS = "rows ";
77 : static const char *const rdcREF_SYSTEM = "ref. system ";
78 : static const char *const rdcREF_UNITS = "ref. units ";
79 : static const char *const rdcUNIT_DIST = "unit dist. ";
80 : static const char *const rdcMIN_X = "min. X ";
81 : static const char *const rdcMAX_X = "max. X ";
82 : static const char *const rdcMIN_Y = "min. Y ";
83 : static const char *const rdcMAX_Y = "max. Y ";
84 : static const char *const rdcPOSN_ERROR = "pos'n error ";
85 : static const char *const rdcRESOLUTION = "resolution ";
86 : static const char *const rdcMIN_VALUE = "min. value ";
87 : static const char *const rdcMAX_VALUE = "max. value ";
88 : static const char *const rdcDISPLAY_MIN = "display min ";
89 : static const char *const rdcDISPLAY_MAX = "display max ";
90 : static const char *const rdcVALUE_UNITS = "value units ";
91 : static const char *const rdcVALUE_ERROR = "value error ";
92 : static const char *const rdcFLAG_VALUE = "flag value ";
93 : static const char *const rdcFLAG_DEFN = "flag def'n ";
94 : static const char *const rdcFLAG_DEFN2 = "flag def`n ";
95 : static const char *const rdcLEGEND_CATS = "legend cats ";
96 : static const char *const rdcLINEAGES = "lineage ";
97 : static const char *const rdcCOMMENTS = "comment ";
98 : static const char *const rdcCODE_N = "code %6d ";
99 :
100 : //----- ".ref" file field names:
101 : static const char *const refREF_SYSTEM = "ref. system ";
102 : static const char *const refREF_SYSTEM2 = "ref.system ";
103 : static const char *const refPROJECTION = "projection ";
104 : static const char *const refDATUM = "datum ";
105 : static const char *const refDELTA_WGS84 = "delta WGS84 ";
106 : static const char *const refELLIPSOID = "ellipsoid ";
107 : static const char *const refMAJOR_SAX = "major s-ax ";
108 : static const char *const refMINOR_SAX = "minor s-ax ";
109 : static const char *const refORIGIN_LONG = "origin long ";
110 : static const char *const refORIGIN_LAT = "origin lat ";
111 : static const char *const refORIGIN_X = "origin X ";
112 : static const char *const refORIGIN_Y = "origin Y ";
113 : static const char *const refSCALE_FAC = "scale fac ";
114 : static const char *const refUNITS = "units ";
115 : static const char *const refPARAMETERS = "parameters ";
116 : static const char *const refSTANDL_1 = "stand ln 1 ";
117 : static const char *const refSTANDL_2 = "stand ln 2 ";
118 :
119 : //----- standard values:
120 : static const char *const rstVERSION = "Idrisi Raster A.1";
121 : static const char *const rstBYTE = "byte";
122 : static const char *const rstINTEGER = "integer";
123 : static const char *const rstREAL = "real";
124 : static const char *const rstRGB24 = "rgb24";
125 : static const char *const rstDEGREE = "deg";
126 : static const char *const rstMETER = "m";
127 : static const char *const rstLATLONG = "latlong";
128 : static const char *const rstLATLONG2 = "lat/long";
129 : static const char *const rstPLANE = "plane";
130 : static const char *const rstUTM = "utm-%d%c";
131 : static const char *const rstSPC = "spc%2d%2s%d";
132 :
133 : //----- palette file( .smp ) header size:
134 : constexpr int smpHEADERSIZE = 18;
135 :
136 : //----- check if file exists:
137 : bool FileExists(const char *pszPath);
138 :
139 : //----- Reference Table
140 : struct ReferenceTab
141 : {
142 : int nCode;
143 : const char *pszName;
144 : };
145 :
146 : //----- USA State's reference table to USGS PCS Code
147 : constexpr ReferenceTab aoUSStateTable[] = {
148 : {101, "al"}, {201, "az"}, {301, "ar"}, {401, "ca"}, {501, "co"},
149 : {600, "ct"}, {700, "de"}, {901, "fl"}, {1001, "ga"}, {1101, "id"},
150 : {1201, "il"}, {1301, "in"}, {1401, "ia"}, {1501, "ks"}, {1601, "ky"},
151 : {1701, "la"}, {1801, "me"}, {1900, "md"}, {2001, "ma"}, {2111, "mi"},
152 : {2201, "mn"}, {2301, "ms"}, {2401, "mo"}, {2500, "mt"}, {2600, "ne"},
153 : {2701, "nv"}, {2800, "nh"}, {2900, "nj"}, {3001, "nm"}, {3101, "ny"},
154 : {3200, "nc"}, {3301, "nd"}, {3401, "oh"}, {3501, "ok"}, {3601, "or"},
155 : {3701, "pa"}, {3800, "ri"}, {3900, "sc"}, {4001, "sd"}, {4100, "tn"},
156 : {4201, "tx"}, {4301, "ut"}, {4400, "vt"}, {4501, "va"}, {4601, "wa"},
157 : {4701, "wv"}, {4801, "wv"}, {4901, "wy"}, {5001, "ak"}, {5101, "hi"},
158 : {5200, "pr"}};
159 :
160 : //---- The origin table for USA State Plane Systems
161 : struct OriginTab83
162 : {
163 : double longitude;
164 : double latitude;
165 : const char *spcs;
166 : };
167 :
168 : constexpr int ORIGIN_COUNT = 148;
169 :
170 : //---- USA State plane coordinate system in IDRISI
171 : static const OriginTab83 SPCS83Origin[] = {
172 : {85.83, 30.50, "SPC83AL1"}, {87.50, 30.00, "SPC83AL2"},
173 : {176.00, 51.00, "SPC83AK0"}, {142.00, 54.00, "SPC83AK2"},
174 : {146.00, 54.00, "SPC83AK3"}, {150.00, 54.00, "SPC83AK4"},
175 : {154.00, 54.00, "SPC83AK5"}, {158.00, 54.00, "SPC83AK6"},
176 : {162.00, 54.00, "SPC83AK7"}, {166.00, 54.00, "SPC83AK8"},
177 : {170.00, 54.00, "SPC83AK9"}, {110.17, 31.00, "SPC83AZ1"},
178 : {111.92, 31.00, "SPC83AZ2"}, {113.75, 31.00, "SPC83AZ3"},
179 : {92.00, 34.33, "SPC83AR1"}, {92.00, 32.67, "SPC83AR2"},
180 : {122.00, 39.33, "SPC83CA1"}, {122.00, 37.67, "SPC83CA2"},
181 : {120.50, 36.50, "SPC83CA3"}, {119.00, 35.33, "SPC83CA4"},
182 : {118.00, 33.50, "SPC83CA5"}, {116.25, 32.17, "SPC83CA6"},
183 : {105.50, 39.33, "SPC83CO1"}, {105.50, 37.83, "SPC83CO2"},
184 : {105.50, 36.67, "SPC83CO3"}, {72.75, 40.83, "SPC83CT1"},
185 : {75.42, 38.00, "SPC83DE1"}, {81.00, 24.33, "SPC83FL1"},
186 : {82.00, 24.33, "SPC83FL2"}, {84.50, 29.00, "SPC83FL3"},
187 : {82.17, 30.00, "SPC83GA1"}, {84.17, 30.00, "SPC83GA2"},
188 : {155.50, 18.83, "SPC83HI1"}, {156.67, 20.33, "SPC83HI2"},
189 : {158.00, 21.17, "SPC83HI3"}, {159.50, 21.83, "SPC83HI4"},
190 : {160.17, 21.67, "SPC83HI5"}, {112.17, 41.67, "SPC83ID1"},
191 : {114.00, 41.67, "SPC83ID2"}, {115.75, 41.67, "SPC83ID3"},
192 : {88.33, 36.67, "SPC83IL1"}, {90.17, 36.67, "SPC83IL1"},
193 : {85.67, 37.50, "SPC83IN1"}, {87.08, 37.50, "SPC83IN2"},
194 : {93.50, 41.50, "SPC83IA1"}, {93.50, 40.00, "SPC83IA1"},
195 : {98.00, 38.33, "SPC83KS1"}, {98.50, 36.67, "SPC83KS2"},
196 : {84.25, 37.50, "SPC83KY1"}, {85.75, 36.33, "SPC83KY2"},
197 : {92.50, 30.50, "SPC83LA1"}, {91.33, 28.50, "SPC83LA2"},
198 : {91.33, 25.50, "SPC83LA3"}, {92.50, 30.67, "SPC27LA1"}, // NAD27 system
199 : {91.33, 28.67, "SPC27LA2"}, {91.33, 25.67, "SPC27LA3"}, //
200 : {68.50, 43.67, "SPC83ME1"}, {68.50, 43.83, "SPC27ME1"}, // NAD27
201 : {70.17, 42.83, "SPC83ME2"}, {77.00, 37.67, "SPC83MD1"}, //
202 : {77.00, 37.83, "SPC27MD1"}, // NAD27
203 : {71.50, 41.00, "SPC83MA1"}, {70.50, 41.00, "SPC83MA2"},
204 : {87.00, 44.78, "SPC83MI1"}, {84.37, 43.32, "SPC83MI2"},
205 : {84.37, 41.50, "SPC83MI3"}, {84.33, 43.32, "SPC27MI2"}, // NAD27 L
206 : {84.33, 41.50, "SPC27MI3"}, // NAD27 L
207 : {83.67, 41.50, "SPC27MI4"}, // NAD27 TM
208 : {85.75, 41.50, "SPC27MI5"}, // NAD27 TM
209 : {88.75, 41.50, "SPC27MI6"}, // NAD27 TM
210 : {93.10, 46.50, "SPC83MN1"}, {94.25, 45.00, "SPC83MN2"},
211 : {94.00, 43.00, "SPC83MN3"}, {88.83, 29.50, "SPC83MS1"},
212 : {90.33, 29.50, "SPC83MS2"}, {88.83, 29.67, "SPC83MS1"}, // NAD27
213 : {90.33, 30.50, "SPC83MS2"}, //
214 : {90.50, 35.83, "SPC83MO1"}, {92.50, 35.83, "SPC83MO2"},
215 : {94.50, 36.17, "SPC83MO3"}, {109.50, 44.25, "SPC83MT1"},
216 : {109.50, 47.00, "SPC27MT1"}, // NAD27
217 : {109.50, 45.83, "SPC27MT2"}, {109.50, 44.00, "SPC27MT3"}, //
218 : {100.00, 39.83, "SPC83NE1"}, {115.58, 34.75, "SPC83NV1"},
219 : {116.67, 34.75, "SPC83NV2"}, {118.58, 34.75, "SPC83NV3"},
220 : {71.67, 42.50, "SPC83NH1"}, {74.50, 38.83, "SPC83NJ1"},
221 : {74.67, 38.83, "SPC27NJ1"}, // NAD27
222 : {104.33, 31.00, "SPC83NM1"}, {106.25, 31.00, "SPC83NM2"},
223 : {107.83, 31.00, "SPC83NM3"}, {74.50, 38.83, "SPC83NY1"},
224 : {76.58, 40.00, "SPC83NY2"}, {78.58, 40.00, "SPC83NY3"},
225 : {74.00, 40.17, "SPC83NY4"}, {74.33, 40.00, "SPC27NY1"}, // NAD27
226 : {74.00, 40.50, "SPC27NY4"}, //
227 : {79.00, 33.75, "SPC83NC1"}, {100.50, 47.00, "SPC83ND1"},
228 : {100.50, 45.67, "SPC83ND2"}, {82.50, 39.67, "SPC83OH1"},
229 : {82.50, 38.00, "SPC83OH2"}, {98.00, 35.00, "SPC83OK1"},
230 : {98.00, 33.33, "SPC83OK2"}, {120.50, 43.67, "SPC83OR1"},
231 : {120.50, 41.67, "SPC83OR2"}, {77.75, 40.17, "SPC83PA1"},
232 : {77.75, 39.33, "SPC83PA2"}, {71.50, 41.08, "SPC83RI1"},
233 : {81.00, 31.83, "SPC83SC1"}, {81.00, 33.00, "SPC27SC1"}, // NAD27
234 : {81.00, 31.83, "SPC27SC2"}, // NAD27
235 : {100.00, 43.83, "SPC83SD1"}, {100.33, 42.33, "SPC83SD2"},
236 : {86.00, 34.33, "SPC83TN1"}, {86.00, 34.67, "SPC27TN1"}, // NAD27
237 : {101.50, 34.00, "SPC83TX1"}, //
238 : {98.50, 31.67, "SPC83TX2"}, {100.33, 29.67, "SPC83TX3"},
239 : {99.00, 27.83, "SPC83TX4"}, {98.50, 25.67, "SPC83TX5"},
240 : {97.50, 31.67, "SPC27TX2"}, // NAD27
241 : {111.50, 40.33, "SPC83UT1"}, {111.50, 38.33, "SPC83UT2"},
242 : {111.50, 36.67, "SPC83UT3"}, {72.50, 42.50, "SPC83VT1"},
243 : {78.50, 37.67, "SPC83VA1"}, {78.50, 36.33, "SPC83VA2"},
244 : {120.83, 47.00, "SPC83WA1"}, {120.50, 45.33, "SPC83WA2"},
245 : {79.50, 38.50, "SPC83WV1"}, {81.00, 37.00, "SPC83WV2"},
246 : {90.00, 45.17, "SPC83WI1"}, {90.00, 43.83, "SPC83WI2"},
247 : {90.00, 42.00, "SPC83WI3"}, {105.17, 40.50, "SPC83WY1"},
248 : {107.33, 40.50, "SPC83WY2"}, {108.75, 40.50, "SPC83WY3"},
249 : {110.08, 40.50, "SPC83WY4"}, {105.17, 40.67, "SPC27WY1"}, // NAD27
250 : {105.33, 40.67, "SPC27WY2"}, {108.75, 40.67, "SPC27WY3"},
251 : {110.08, 40.67, "SPC27WY4"}, //
252 : {66.43, 17.83, "SPC83PR1"}};
253 :
254 : // Get IDRISI State Plane name by origin
255 : char *GetSpcs(double dfLon, double dfLat);
256 :
257 : // change NAD from 83 to 27
258 : void NAD83to27(char *pszOutRef, char *pszInRef);
259 :
260 : #define US_STATE_COUNT (sizeof(aoUSStateTable) / sizeof(ReferenceTab))
261 :
262 : //----- Get the Code of a US State
263 : int GetStateCode(const char *pszState);
264 :
265 : //----- Get the state name of a Code
266 : const char *GetStateName(int nCode);
267 :
268 : //----- Conversion Table definition
269 : struct ConversionTab
270 : {
271 : const char *pszName;
272 : int nDefaultI;
273 : int nDefaultG;
274 : double dfConv;
275 : };
276 :
277 : //----- Linear Unit Conversion Table
278 : static const ConversionTab aoLinearUnitsConv[] = {
279 : {"m", /* 0 */ 0, 1, 1.0},
280 : {SRS_UL_METER, /* 1 */ 0, 1, 1.0},
281 : {"meters", /* 2 */ 0, 1, 1.0},
282 : {"metre", /* 3 */ 0, 1, 1.0},
283 :
284 : {"ft", /* 4 */ 4, 5, 0.3048},
285 : {SRS_UL_FOOT, /* 5 */ 4, 5, 0.3048},
286 : {"feet", /* 6 */ 4, 5, 0.3048},
287 : {"foot_us", /* 7 */ 4, 5, 0.3048006},
288 : {"u.s. foot", /* 8 */ 4, 5, 0.3048006},
289 :
290 : {"mi", /* 9 */ 9, 10, 1612.9},
291 : {"mile", /* 10 */ 9, 10, 1612.9},
292 : {"miles", /* 11 */ 9, 10, 1612.9},
293 :
294 : {"km", /* 12 */ 12, 13, 1000.0},
295 : {"kilometers", /* 13 */ 12, 13, 1000.0},
296 : {"kilometer", /* 14 */ 12, 13, 1000.0},
297 : {"kilometre", /* 15 */ 12, 13, 1000.0},
298 :
299 : {"deg", /* 16 */ 16, 17, 0.0},
300 : {SRS_UA_DEGREE, /* 17 */ 16, 17, 0.0},
301 : {"degrees", /* 18 */ 16, 17, 0.0},
302 :
303 : {"rad", /* 19 */ 19, 20, 0.0},
304 : {SRS_UA_RADIAN, /* 20 */ 19, 20, 0.0},
305 : {"radians", /* 21 */ 19, 20, 0.0}};
306 : #define LINEAR_UNITS_COUNT (sizeof(aoLinearUnitsConv) / sizeof(ConversionTab))
307 :
308 : //----- Get the index of a given linear unit
309 : static int GetUnitIndex(const char *pszUnitName);
310 :
311 : //----- Get the default name
312 : static char *GetUnitDefault(const char *pszUnitName,
313 : const char *pszToMeter = nullptr);
314 :
315 : //----- Get the "to meter"
316 : static int GetToMeterIndex(const char *pszToMeter);
317 :
318 : //----- CSLSaveCRLF
319 : static int SaveAsCRLF(char **papszStrList, const char *pszFname);
320 :
321 : /************************************************************************/
322 : /* myCSLFetchNameValue() */
323 : /************************************************************************/
324 :
325 1192 : static const char *myCSLFetchNameValue(char **papszStrList, const char *pszName)
326 : {
327 1192 : if (papszStrList == nullptr || pszName == nullptr)
328 4 : return nullptr;
329 :
330 1188 : size_t nLen = strlen(pszName);
331 4541 : while (nLen > 0 && pszName[nLen - 1] == ' ')
332 3353 : nLen--;
333 20461 : while (*papszStrList != nullptr)
334 : {
335 20449 : if (EQUALN(*papszStrList, pszName, nLen))
336 : {
337 : size_t i;
338 4451 : for (i = nLen; (*papszStrList)[i] == ' '; ++i)
339 : {
340 : }
341 1176 : if ((*papszStrList)[i] == '=' || (*papszStrList)[i] == ':')
342 : {
343 1176 : return (*papszStrList) + i + 1;
344 : }
345 : }
346 19273 : ++papszStrList;
347 : }
348 12 : return nullptr;
349 : }
350 :
351 : /************************************************************************/
352 : /* myCSLSetNameValueSeparator() */
353 : /************************************************************************/
354 :
355 86 : static void myCSLSetNameValueSeparator(char **papszList,
356 : const char *pszSeparator)
357 : {
358 86 : const int nLines = CSLCount(papszList);
359 :
360 1926 : for (int iLine = 0; iLine < nLines; ++iLine)
361 : {
362 1840 : char *pszSep = strchr(papszList[iLine], '=');
363 1840 : if (pszSep == nullptr)
364 1164 : pszSep = strchr(papszList[iLine], ':');
365 1840 : if (pszSep == nullptr)
366 0 : continue;
367 1840 : *pszSep = '\0';
368 1840 : const char *pszKey = papszList[iLine];
369 1840 : const char *pszValue = pszSep + 1;
370 2626 : while (*pszValue == ' ')
371 786 : pszValue++;
372 :
373 3680 : char *pszNewLine = static_cast<char *>(CPLMalloc(
374 1840 : strlen(pszValue) + strlen(pszKey) + strlen(pszSeparator) + 1));
375 1840 : strcpy(pszNewLine, pszKey);
376 1840 : strcat(pszNewLine, pszSeparator);
377 1840 : strcat(pszNewLine, pszValue);
378 1840 : CPLFree(papszList[iLine]);
379 1840 : papszList[iLine] = pszNewLine;
380 : }
381 86 : }
382 :
383 : //----- Classes pre-definition:
384 : class IdrisiRasterBand;
385 :
386 : // ----------------------------------------------------------------------------
387 : // Idrisi GDALDataset
388 : // ----------------------------------------------------------------------------
389 :
390 : class IdrisiDataset final : public GDALPamDataset
391 : {
392 : friend class IdrisiRasterBand;
393 :
394 : private:
395 : VSILFILE *fp;
396 :
397 : char *pszFilename;
398 : char *pszDocFilename;
399 : char **papszRDC;
400 : double adfGeoTransform[6];
401 :
402 : mutable OGRSpatialReference m_oSRS{};
403 : char **papszCategories;
404 : char *pszUnitType;
405 : // Move GeoReference2Wkt() into header file.
406 : CPLErr Wkt2GeoReference(const OGRSpatialReference &oSRS,
407 : char **pszRefSystem, char **pszRefUnit);
408 :
409 : protected:
410 : GDALColorTable *poColorTable;
411 :
412 : public:
413 : IdrisiDataset();
414 : virtual ~IdrisiDataset();
415 :
416 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
417 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
418 : int nBands, GDALDataType eType,
419 : char **papszOptions);
420 : static GDALDataset *CreateCopy(const char *pszFilename,
421 : GDALDataset *poSrcDS, int bStrict,
422 : char **papszOptions,
423 : GDALProgressFunc pfnProgress,
424 : void *pProgressData);
425 : virtual char **GetFileList(void) override;
426 : virtual CPLErr GetGeoTransform(double *padfTransform) override;
427 : virtual CPLErr SetGeoTransform(double *padfTransform) override;
428 :
429 : const OGRSpatialReference *GetSpatialRef() const override;
430 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
431 : };
432 :
433 : // ----------------------------------------------------------------------------
434 : // Idrisi GDALPamRasterBand
435 : // ----------------------------------------------------------------------------
436 :
437 : class IdrisiRasterBand final : public GDALPamRasterBand
438 : {
439 : friend class IdrisiDataset;
440 :
441 : GDALRasterAttributeTable *poDefaultRAT;
442 :
443 : private:
444 : int nRecordSize;
445 : GByte *pabyScanLine;
446 :
447 : public:
448 : IdrisiRasterBand(IdrisiDataset *poDS, int nBand, GDALDataType eDataType);
449 : virtual ~IdrisiRasterBand();
450 :
451 : virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
452 : virtual double GetMinimum(int *pbSuccess = nullptr) override;
453 : virtual double GetMaximum(int *pbSuccess = nullptr) override;
454 : virtual CPLErr IReadBlock(int nBlockXOff, int nBlockYOff,
455 : void *pImage) override;
456 : virtual CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff,
457 : void *pImage) override;
458 : virtual GDALColorTable *GetColorTable() override;
459 : virtual GDALColorInterp GetColorInterpretation() override;
460 : virtual char **GetCategoryNames() override;
461 : virtual const char *GetUnitType() override;
462 :
463 : virtual CPLErr SetCategoryNames(char **papszCategoryNames) override;
464 : virtual CPLErr SetNoDataValue(double dfNoDataValue) override;
465 : virtual CPLErr SetColorTable(GDALColorTable *poColorTable) override;
466 : virtual CPLErr SetUnitType(const char *pszUnitType) override;
467 : virtual CPLErr SetStatistics(double dfMin, double dfMax, double dfMean,
468 : double dfStdDev) override;
469 : CPLErr SetMinMax(double dfMin, double dfMax);
470 : virtual GDALRasterAttributeTable *GetDefaultRAT() override;
471 : virtual CPLErr SetDefaultRAT(const GDALRasterAttributeTable *) override;
472 :
473 : float fMaximum;
474 : float fMinimum;
475 : bool bFirstVal;
476 : };
477 :
478 : // ------------------------------------------------------------------------ //
479 : // Implementation of IdrisiDataset //
480 : // ------------------------------------------------------------------------ //
481 :
482 : /************************************************************************/
483 : /* IdrisiDataset() */
484 : /************************************************************************/
485 :
486 36 : IdrisiDataset::IdrisiDataset()
487 : : fp(nullptr), pszFilename(nullptr), pszDocFilename(nullptr),
488 : papszRDC(nullptr), papszCategories(nullptr), pszUnitType(nullptr),
489 36 : poColorTable(new GDALColorTable())
490 : {
491 36 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
492 36 : adfGeoTransform[0] = 0.0;
493 36 : adfGeoTransform[1] = 1.0;
494 36 : adfGeoTransform[2] = 0.0;
495 36 : adfGeoTransform[3] = 0.0;
496 36 : adfGeoTransform[4] = 0.0;
497 36 : adfGeoTransform[5] = 1.0;
498 36 : }
499 :
500 : /************************************************************************/
501 : /* ~IdrisiDataset() */
502 : /************************************************************************/
503 :
504 72 : IdrisiDataset::~IdrisiDataset()
505 : {
506 36 : FlushCache(true);
507 :
508 36 : if (papszRDC != nullptr && eAccess == GA_Update)
509 : {
510 : // int bSuccessMin = FALSE;
511 : // int bSuccessMax = FALSE;
512 :
513 20 : double dfMin = 0.0;
514 20 : double dfMax = 0.0;
515 20 : double dfMean = 0.0;
516 20 : double dfStdDev = 0.0;
517 :
518 40 : for (int i = 0; i < nBands; i++)
519 : {
520 20 : IdrisiRasterBand *poBand = (IdrisiRasterBand *)GetRasterBand(i + 1);
521 20 : poBand->ComputeStatistics(false, &dfMin, &dfMax, &dfMean, &dfStdDev,
522 20 : nullptr, nullptr);
523 : /*
524 : dfMin = poBand->GetMinimum( &bSuccessMin );
525 : dfMax = poBand->GetMaximum( &bSuccessMax );
526 :
527 : if( ! ( bSuccessMin && bSuccessMax ) )
528 : {
529 : poBand->GetStatistics( false, true, &dfMin, &dfMax, NULL, NULL );
530 : }
531 : */
532 20 : poBand->SetMinMax(dfMin, dfMax);
533 : }
534 :
535 20 : myCSLSetNameValueSeparator(papszRDC, ": ");
536 20 : SaveAsCRLF(papszRDC, pszDocFilename);
537 : }
538 36 : CSLDestroy(papszRDC);
539 :
540 36 : if (poColorTable)
541 : {
542 36 : delete poColorTable;
543 : }
544 36 : CPLFree(pszFilename);
545 36 : CPLFree(pszDocFilename);
546 36 : CSLDestroy(papszCategories);
547 36 : CPLFree(pszUnitType);
548 :
549 36 : if (fp != nullptr)
550 36 : VSIFCloseL(fp);
551 72 : }
552 :
553 : /************************************************************************/
554 : /* Open() */
555 : /************************************************************************/
556 :
557 30417 : GDALDataset *IdrisiDataset::Open(GDALOpenInfo *poOpenInfo)
558 : {
559 34602 : if ((poOpenInfo->fpL == nullptr) ||
560 4185 : (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), extRST) ==
561 : FALSE)) // modified
562 30376 : return nullptr;
563 :
564 : // --------------------------------------------------------------------
565 : // Check the documentation file .rdc
566 : // --------------------------------------------------------------------
567 :
568 : const char *pszLDocFilename =
569 41 : CPLResetExtension(poOpenInfo->pszFilename, extRDC);
570 :
571 40 : if (!FileExists(pszLDocFilename))
572 : {
573 0 : pszLDocFilename = CPLResetExtension(poOpenInfo->pszFilename, extRDCu);
574 :
575 0 : if (!FileExists(pszLDocFilename))
576 : {
577 0 : return nullptr;
578 : }
579 : }
580 :
581 40 : char **papszLRDC = CSLLoad(pszLDocFilename);
582 :
583 40 : myCSLSetNameValueSeparator(papszLRDC, ":");
584 :
585 40 : const char *pszVersion = myCSLFetchNameValue(papszLRDC, rdcFILE_FORMAT);
586 :
587 40 : if (pszVersion == nullptr || !EQUAL(pszVersion, rstVERSION))
588 : {
589 4 : CSLDestroy(papszLRDC);
590 4 : return nullptr;
591 : }
592 :
593 : // --------------------------------------------------------------------
594 : // Create a corresponding GDALDataset
595 : // --------------------------------------------------------------------
596 :
597 36 : IdrisiDataset *poDS = new IdrisiDataset();
598 36 : poDS->eAccess = poOpenInfo->eAccess;
599 36 : poDS->pszFilename = CPLStrdup(poOpenInfo->pszFilename);
600 :
601 36 : if (poOpenInfo->eAccess == GA_ReadOnly)
602 : {
603 16 : poDS->fp = VSIFOpenL(poDS->pszFilename, "rb");
604 : }
605 : else
606 : {
607 20 : poDS->fp = VSIFOpenL(poDS->pszFilename, "r+b");
608 : }
609 :
610 36 : if (poDS->fp == nullptr)
611 : {
612 0 : CSLDestroy(papszLRDC);
613 0 : delete poDS;
614 0 : return nullptr;
615 : }
616 :
617 36 : poDS->pszDocFilename = CPLStrdup(pszLDocFilename);
618 36 : poDS->papszRDC = CSLDuplicate(papszLRDC);
619 36 : CSLDestroy(papszLRDC);
620 :
621 : // --------------------------------------------------------------------
622 : // Load information from rdc
623 : // --------------------------------------------------------------------
624 :
625 36 : poDS->nRasterXSize =
626 36 : atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcCOLUMNS));
627 36 : poDS->nRasterYSize = atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcROWS));
628 36 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
629 : {
630 6 : delete poDS;
631 6 : return nullptr;
632 : }
633 :
634 : // --------------------------------------------------------------------
635 : // Create band information
636 : // --------------------------------------------------------------------
637 :
638 30 : const char *pszDataType = myCSLFetchNameValue(poDS->papszRDC, rdcDATA_TYPE);
639 30 : if (pszDataType == nullptr)
640 : {
641 0 : delete poDS;
642 0 : return nullptr;
643 : }
644 :
645 30 : if (EQUAL(pszDataType, rstBYTE))
646 : {
647 5 : poDS->nBands = 1;
648 5 : poDS->SetBand(1, new IdrisiRasterBand(poDS, 1, GDT_Byte));
649 : }
650 25 : else if (EQUAL(pszDataType, rstINTEGER))
651 : {
652 9 : poDS->nBands = 1;
653 9 : poDS->SetBand(1, new IdrisiRasterBand(poDS, 1, GDT_Int16));
654 : }
655 16 : else if (EQUAL(pszDataType, rstREAL))
656 : {
657 10 : poDS->nBands = 1;
658 10 : poDS->SetBand(1, new IdrisiRasterBand(poDS, 1, GDT_Float32));
659 : }
660 6 : else if (EQUAL(pszDataType, rstRGB24))
661 : {
662 6 : poDS->nBands = 3;
663 6 : poDS->SetBand(1, new IdrisiRasterBand(poDS, 1, GDT_Byte));
664 6 : poDS->SetBand(2, new IdrisiRasterBand(poDS, 2, GDT_Byte));
665 6 : poDS->SetBand(3, new IdrisiRasterBand(poDS, 3, GDT_Byte));
666 : }
667 : else
668 : {
669 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unknown data type : %s",
670 : pszDataType);
671 0 : delete poDS;
672 0 : return nullptr;
673 : }
674 :
675 72 : for (int i = 0; i < poDS->nBands; i++)
676 : {
677 42 : IdrisiRasterBand *band = (IdrisiRasterBand *)poDS->GetRasterBand(i + 1);
678 42 : if (band->pabyScanLine == nullptr)
679 : {
680 0 : delete poDS;
681 0 : return nullptr;
682 : }
683 : }
684 :
685 : // --------------------------------------------------------------------
686 : // Load the transformation matrix
687 : // --------------------------------------------------------------------
688 :
689 30 : const char *pszMinX = myCSLFetchNameValue(poDS->papszRDC, rdcMIN_X);
690 30 : const char *pszMaxX = myCSLFetchNameValue(poDS->papszRDC, rdcMAX_X);
691 30 : const char *pszMinY = myCSLFetchNameValue(poDS->papszRDC, rdcMIN_Y);
692 30 : const char *pszMaxY = myCSLFetchNameValue(poDS->papszRDC, rdcMAX_Y);
693 30 : const char *pszUnit = myCSLFetchNameValue(poDS->papszRDC, rdcUNIT_DIST);
694 :
695 30 : if (pszMinX != nullptr && strlen(pszMinX) > 0 && pszMaxX != nullptr &&
696 30 : strlen(pszMaxX) > 0 && pszMinY != nullptr && strlen(pszMinY) > 0 &&
697 30 : pszMaxY != nullptr && strlen(pszMaxY) > 0 && pszUnit != nullptr &&
698 30 : strlen(pszUnit) > 0)
699 : {
700 : double dfMinX, dfMaxX, dfMinY, dfMaxY, dfUnit, dfXPixSz, dfYPixSz;
701 :
702 30 : dfMinX = CPLAtof_nz(pszMinX);
703 30 : dfMaxX = CPLAtof_nz(pszMaxX);
704 30 : dfMinY = CPLAtof_nz(pszMinY);
705 30 : dfMaxY = CPLAtof_nz(pszMaxY);
706 30 : dfUnit = CPLAtof_nz(pszUnit);
707 :
708 30 : dfMinX = dfMinX * dfUnit;
709 30 : dfMaxX = dfMaxX * dfUnit;
710 30 : dfMinY = dfMinY * dfUnit;
711 30 : dfMaxY = dfMaxY * dfUnit;
712 :
713 30 : dfYPixSz = (dfMinY - dfMaxY) / poDS->nRasterYSize;
714 30 : dfXPixSz = (dfMaxX - dfMinX) / poDS->nRasterXSize;
715 :
716 30 : poDS->adfGeoTransform[0] = dfMinX;
717 30 : poDS->adfGeoTransform[1] = dfXPixSz;
718 30 : poDS->adfGeoTransform[2] = 0.0;
719 30 : poDS->adfGeoTransform[3] = dfMaxY;
720 30 : poDS->adfGeoTransform[4] = 0.0;
721 30 : poDS->adfGeoTransform[5] = dfYPixSz;
722 : }
723 :
724 : // --------------------------------------------------------------------
725 : // Set Color Table in the presence of a smp file
726 : // --------------------------------------------------------------------
727 :
728 30 : if (poDS->nBands != 3)
729 : {
730 : const char *pszSMPFilename =
731 24 : CPLResetExtension(poDS->pszFilename, extSMP);
732 24 : VSILFILE *fpSMP = VSIFOpenL(pszSMPFilename, "rb");
733 24 : if (fpSMP != nullptr)
734 : {
735 : int dfMaxValue =
736 0 : atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcMAX_VALUE));
737 : int nCatCount =
738 0 : atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcLEGEND_CATS));
739 0 : if (nCatCount == 0)
740 0 : dfMaxValue = 255;
741 0 : VSIFSeekL(fpSMP, smpHEADERSIZE, SEEK_SET);
742 : GDALColorEntry oEntry;
743 : unsigned char aucRGB[3];
744 0 : int i = 0;
745 0 : while ((VSIFReadL(&aucRGB, sizeof(aucRGB), 1, fpSMP)) &&
746 : (i <= dfMaxValue))
747 : {
748 0 : oEntry.c1 = (short)aucRGB[0];
749 0 : oEntry.c2 = (short)aucRGB[1];
750 0 : oEntry.c3 = (short)aucRGB[2];
751 0 : oEntry.c4 = (short)255;
752 0 : poDS->poColorTable->SetColorEntry(i, &oEntry);
753 0 : i++;
754 : }
755 0 : VSIFCloseL(fpSMP);
756 : }
757 : }
758 :
759 : // --------------------------------------------------------------------
760 : // Check for Unit Type
761 : // --------------------------------------------------------------------
762 :
763 : const char *pszValueUnit =
764 30 : myCSLFetchNameValue(poDS->papszRDC, rdcVALUE_UNITS);
765 :
766 30 : if (pszValueUnit == nullptr)
767 0 : poDS->pszUnitType = CPLStrdup("unspecified");
768 : else
769 : {
770 30 : if (STARTS_WITH_CI(pszValueUnit, "meter"))
771 : {
772 0 : poDS->pszUnitType = CPLStrdup("m");
773 : }
774 30 : else if (STARTS_WITH_CI(pszValueUnit, "feet"))
775 : {
776 0 : poDS->pszUnitType = CPLStrdup("ft");
777 : }
778 : else
779 30 : poDS->pszUnitType = CPLStrdup(pszValueUnit);
780 : }
781 :
782 : // --------------------------------------------------------------------
783 : // Check for category names.
784 : // --------------------------------------------------------------------
785 :
786 : int nCatCount =
787 30 : atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcLEGEND_CATS));
788 :
789 30 : if (nCatCount > 0)
790 : {
791 : // ----------------------------------------------------------------
792 : // Sequentialize categories names, from 0 to the last "code n"
793 : // ----------------------------------------------------------------
794 :
795 0 : int nLine = -1;
796 0 : for (int i = 0; (i < CSLCount(poDS->papszRDC)) && (nLine == -1); i++)
797 0 : if (EQUALN(poDS->papszRDC[i], rdcLEGEND_CATS, 11))
798 0 : nLine = i; // get the line where legend cats is
799 :
800 0 : if (nLine > 0)
801 : {
802 0 : int nCode = 0;
803 0 : int nCount = 0;
804 0 : sscanf(poDS->papszRDC[++nLine], rdcCODE_N,
805 : &nCode); // assign legend cats to nCode
806 0 : for (int i = 0; (i < 255) && (nCount < nCatCount); i++)
807 : {
808 0 : if (i == nCode)
809 : {
810 0 : poDS->papszCategories = CSLAddString(
811 : poDS->papszCategories,
812 0 : CPLParseNameValue(poDS->papszRDC[nLine], nullptr));
813 0 : nCount++;
814 0 : if (nCount < nCatCount)
815 0 : sscanf(poDS->papszRDC[++nLine], rdcCODE_N, &nCode);
816 : }
817 : else
818 0 : poDS->papszCategories =
819 0 : CSLAddString(poDS->papszCategories, "");
820 : }
821 : }
822 : }
823 :
824 : /* -------------------------------------------------------------------- */
825 : /* Automatic Generated Color Table */
826 : /* -------------------------------------------------------------------- */
827 :
828 30 : if (poDS->papszCategories != nullptr &&
829 0 : (poDS->poColorTable->GetColorEntryCount() == 0))
830 : {
831 0 : int nEntryCount = CSLCount(poDS->papszCategories);
832 :
833 : GDALColorEntry sFromColor;
834 0 : sFromColor.c1 = (short)(255);
835 0 : sFromColor.c2 = (short)(0);
836 0 : sFromColor.c3 = (short)(0);
837 0 : sFromColor.c4 = (short)(255);
838 :
839 : GDALColorEntry sToColor;
840 0 : sToColor.c1 = (short)(0);
841 0 : sToColor.c2 = (short)(0);
842 0 : sToColor.c3 = (short)(255);
843 0 : sToColor.c4 = (short)(255);
844 :
845 0 : poDS->poColorTable->CreateColorRamp(0, &sFromColor, (nEntryCount - 1),
846 : &sToColor);
847 : }
848 :
849 : /* -------------------------------------------------------------------- */
850 : /* Initialize any PAM information. */
851 : /* -------------------------------------------------------------------- */
852 :
853 30 : poDS->SetDescription(poOpenInfo->pszFilename);
854 30 : poDS->TryLoadXML();
855 :
856 : /* -------------------------------------------------------------------- */
857 : /* Check for external overviews. */
858 : /* -------------------------------------------------------------------- */
859 :
860 30 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
861 :
862 30 : return poDS;
863 : }
864 :
865 : /************************************************************************/
866 : /* Create() */
867 : /************************************************************************/
868 :
869 50 : GDALDataset *IdrisiDataset::Create(const char *pszFilename, int nXSize,
870 : int nYSize, int nBandsIn, GDALDataType eType,
871 : char ** /* papszOptions */)
872 : {
873 : // --------------------------------------------------------------------
874 : // Check input options
875 : // --------------------------------------------------------------------
876 :
877 50 : if (nBandsIn != 1 && nBandsIn != 3)
878 : {
879 4 : CPLError(CE_Failure, CPLE_AppDefined,
880 : "Attempt to create IDRISI dataset with an illegal number of "
881 : "bands(%d)."
882 : " Try again by selecting a specific band if possible. \n",
883 : nBandsIn);
884 4 : return nullptr;
885 : }
886 :
887 46 : if (nBandsIn == 3 && eType != GDT_Byte)
888 : {
889 13 : CPLError(
890 : CE_Failure, CPLE_AppDefined,
891 : "Attempt to create IDRISI dataset with an unsupported combination "
892 : "of the number of bands(%d) and data type(%s). \n",
893 : nBandsIn, GDALGetDataTypeName(eType));
894 13 : return nullptr;
895 : }
896 :
897 : // ----------------------------------------------------------------
898 : // Create the header file with minimum information
899 : // ----------------------------------------------------------------
900 :
901 33 : const char *pszLDataType = nullptr;
902 :
903 33 : switch (eType)
904 : {
905 17 : case GDT_Byte:
906 17 : if (nBandsIn == 1)
907 14 : pszLDataType = rstBYTE;
908 : else
909 3 : pszLDataType = rstRGB24;
910 17 : break;
911 2 : case GDT_Int16:
912 2 : pszLDataType = rstINTEGER;
913 2 : break;
914 3 : case GDT_Float32:
915 3 : pszLDataType = rstREAL;
916 3 : break;
917 : //--- process compatible data types
918 1 : case (GDT_UInt16):
919 1 : pszLDataType = rstINTEGER;
920 1 : CPLError(CE_Warning, CPLE_AppDefined,
921 : "This process requires a conversion from %s to signed "
922 : "16-bit %s, "
923 : "which may cause data loss.\n",
924 : GDALGetDataTypeName(eType), rstINTEGER);
925 1 : break;
926 1 : case GDT_UInt32:
927 1 : pszLDataType = rstINTEGER;
928 1 : CPLError(CE_Warning, CPLE_AppDefined,
929 : "This process requires a conversion from %s to signed "
930 : "16-bit %s, "
931 : "which may cause data loss.\n",
932 : GDALGetDataTypeName(eType), rstINTEGER);
933 1 : break;
934 1 : case GDT_Int32:
935 1 : pszLDataType = rstINTEGER;
936 1 : CPLError(CE_Warning, CPLE_AppDefined,
937 : "This process requires a conversion from %s to signed "
938 : "16-bit %s, "
939 : "which may cause data loss.\n",
940 : GDALGetDataTypeName(eType), rstINTEGER);
941 1 : break;
942 1 : case GDT_Float64:
943 1 : pszLDataType = rstREAL;
944 1 : CPLError(CE_Warning, CPLE_AppDefined,
945 : "This process requires a conversion from %s to float "
946 : "32-bit %s, "
947 : "which may cause data loss.\n",
948 : GDALGetDataTypeName(eType), rstREAL);
949 1 : break;
950 7 : default:
951 7 : CPLError(CE_Failure, CPLE_AppDefined,
952 : "Attempt to create IDRISI dataset with an illegal "
953 : "data type(%s).\n",
954 : GDALGetDataTypeName(eType));
955 7 : return nullptr;
956 : };
957 :
958 26 : char **papszLRDC = nullptr;
959 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFILE_FORMAT, rstVERSION);
960 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFILE_TITLE, "");
961 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcDATA_TYPE, pszLDataType);
962 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFILE_TYPE, "binary");
963 : papszLRDC =
964 26 : CSLAddNameValue(papszLRDC, rdcCOLUMNS, CPLSPrintf("%d", nXSize));
965 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcROWS, CPLSPrintf("%d", nYSize));
966 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcREF_SYSTEM, "plane");
967 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcREF_UNITS, "m");
968 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcUNIT_DIST, "1");
969 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMIN_X, "0");
970 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMAX_X, CPLSPrintf("%d", nXSize));
971 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMIN_Y, "0");
972 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMAX_Y, CPLSPrintf("%d", nYSize));
973 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcPOSN_ERROR, "unspecified");
974 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcRESOLUTION, "1.0");
975 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMIN_VALUE, "0");
976 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMAX_VALUE, "0");
977 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcDISPLAY_MIN, "0");
978 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcDISPLAY_MAX, "0");
979 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcVALUE_UNITS, "unspecified");
980 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcVALUE_ERROR, "unspecified");
981 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFLAG_VALUE, "none");
982 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFLAG_DEFN, "none");
983 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcLEGEND_CATS, "0");
984 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcLINEAGES, "");
985 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcCOMMENTS, "");
986 :
987 26 : const char *pszLDocFilename = CPLResetExtension(pszFilename, extRDC);
988 :
989 26 : myCSLSetNameValueSeparator(papszLRDC, ": ");
990 26 : SaveAsCRLF(papszLRDC, pszLDocFilename);
991 26 : CSLDestroy(papszLRDC);
992 :
993 : // ----------------------------------------------------------------
994 : // Create an empty data file
995 : // ----------------------------------------------------------------
996 :
997 26 : VSILFILE *fp = VSIFOpenL(pszFilename, "wb+");
998 :
999 26 : if (fp == nullptr)
1000 : {
1001 2 : CPLError(CE_Failure, CPLE_OpenFailed,
1002 : "Attempt to create file %s' failed.\n", pszFilename);
1003 2 : return nullptr;
1004 : }
1005 :
1006 36 : const int nTargetDTSize = EQUAL(pszLDataType, rstBYTE) ? 1
1007 19 : : EQUAL(pszLDataType, rstINTEGER) ? 2
1008 7 : : EQUAL(pszLDataType, rstRGB24) ? 3
1009 : : 4;
1010 24 : VSIFTruncateL(fp,
1011 24 : static_cast<vsi_l_offset>(nXSize) * nYSize * nTargetDTSize);
1012 24 : VSIFCloseL(fp);
1013 :
1014 24 : return (IdrisiDataset *)GDALOpen(pszFilename, GA_Update);
1015 : }
1016 :
1017 : /************************************************************************/
1018 : /* CreateCopy() */
1019 : /************************************************************************/
1020 :
1021 29 : GDALDataset *IdrisiDataset::CreateCopy(const char *pszFilename,
1022 : GDALDataset *poSrcDS, int bStrict,
1023 : char **papszOptions,
1024 : GDALProgressFunc pfnProgress,
1025 : void *pProgressData)
1026 : {
1027 29 : if (!pfnProgress(0.0, nullptr, pProgressData))
1028 0 : return nullptr;
1029 :
1030 : // ------------------------------------------------------------------------
1031 : // Check number of bands
1032 : // ------------------------------------------------------------------------
1033 29 : if (!(poSrcDS->GetRasterCount() == 1) && !(poSrcDS->GetRasterCount() == 3))
1034 : {
1035 4 : CPLError(CE_Failure, CPLE_AppDefined,
1036 : "Attempt to create IDRISI dataset with an illegal number of "
1037 : "bands(%d)."
1038 : " Try again by selecting a specific band if possible.\n",
1039 : poSrcDS->GetRasterCount());
1040 4 : return nullptr;
1041 : }
1042 27 : if ((poSrcDS->GetRasterCount() == 3) &&
1043 2 : ((poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte) ||
1044 2 : (poSrcDS->GetRasterBand(2)->GetRasterDataType() != GDT_Byte) ||
1045 2 : (poSrcDS->GetRasterBand(3)->GetRasterDataType() != GDT_Byte)))
1046 : {
1047 0 : CPLError(
1048 : CE_Failure, CPLE_AppDefined,
1049 : "Attempt to create IDRISI dataset with an unsupported "
1050 : "data type when there are three bands. Only BYTE allowed.\n"
1051 : "Try again by selecting a specific band to convert if possible.\n");
1052 0 : return nullptr;
1053 : }
1054 :
1055 : // ------------------------------------------------------------------------
1056 : // Check Data types
1057 : // ------------------------------------------------------------------------
1058 :
1059 46 : for (int i = 1; i <= poSrcDS->GetRasterCount(); i++)
1060 : {
1061 29 : GDALDataType eType = poSrcDS->GetRasterBand(i)->GetRasterDataType();
1062 :
1063 29 : if (bStrict)
1064 : {
1065 25 : if (eType != GDT_Byte && eType != GDT_Int16 && eType != GDT_Float32)
1066 : {
1067 8 : CPLError(CE_Failure, CPLE_AppDefined,
1068 : "Attempt to create IDRISI dataset in strict mode "
1069 : "with an illegal data type(%s).\n",
1070 : GDALGetDataTypeName(eType));
1071 8 : return nullptr;
1072 : }
1073 : }
1074 : else
1075 : {
1076 4 : if (eType != GDT_Byte && eType != GDT_Int16 &&
1077 0 : eType != GDT_UInt16 && eType != GDT_UInt32 &&
1078 0 : eType != GDT_Int32 && eType != GDT_Float32 &&
1079 : eType != GDT_Float64)
1080 : {
1081 0 : CPLError(CE_Failure, CPLE_AppDefined,
1082 : "Attempt to create IDRISI dataset with an illegal "
1083 : "data type(%s).\n",
1084 : GDALGetDataTypeName(eType));
1085 0 : return nullptr;
1086 : }
1087 : }
1088 : }
1089 :
1090 : // --------------------------------------------------------------------
1091 : // Define data type
1092 : // --------------------------------------------------------------------
1093 :
1094 17 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(1);
1095 17 : GDALDataType eType = poBand->GetRasterDataType();
1096 :
1097 17 : int bSuccessMin = FALSE;
1098 17 : int bSuccessMax = FALSE;
1099 :
1100 17 : double dfMin = poBand->GetMinimum(&bSuccessMin);
1101 17 : double dfMax = poBand->GetMaximum(&bSuccessMax);
1102 :
1103 17 : if (!(bSuccessMin && bSuccessMax))
1104 : {
1105 6 : poBand->GetStatistics(false, true, &dfMin, &dfMax, nullptr, nullptr);
1106 : }
1107 :
1108 17 : if (!((eType == GDT_Byte) || (eType == GDT_Int16) ||
1109 : (eType == GDT_Float32)))
1110 : {
1111 0 : if (eType == GDT_Float64)
1112 : {
1113 0 : eType = GDT_Float32;
1114 : }
1115 : else
1116 : {
1117 0 : if ((dfMin < (double)SHRT_MIN) || (dfMax > (double)SHRT_MAX))
1118 : {
1119 0 : eType = GDT_Float32;
1120 : }
1121 : else
1122 : {
1123 0 : eType = GDT_Int16;
1124 : }
1125 : }
1126 : }
1127 :
1128 : // --------------------------------------------------------------------
1129 : // Create the dataset
1130 : // --------------------------------------------------------------------
1131 :
1132 17 : IdrisiDataset *poDS = (IdrisiDataset *)IdrisiDataset::Create(
1133 : pszFilename, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
1134 : poSrcDS->GetRasterCount(), eType, papszOptions);
1135 :
1136 17 : if (poDS == nullptr)
1137 12 : return nullptr;
1138 :
1139 : // --------------------------------------------------------------------
1140 : // Copy information to the dataset
1141 : // --------------------------------------------------------------------
1142 :
1143 : double adfGeoTransform[6];
1144 5 : if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None)
1145 : {
1146 5 : poDS->SetGeoTransform(adfGeoTransform);
1147 : }
1148 :
1149 5 : if (!EQUAL(poSrcDS->GetProjectionRef(), ""))
1150 : {
1151 5 : poDS->SetProjection(poSrcDS->GetProjectionRef());
1152 : }
1153 :
1154 : // --------------------------------------------------------------------
1155 : // Copy information to the raster band(s)
1156 : // --------------------------------------------------------------------
1157 :
1158 14 : for (int i = 1; i <= poDS->nBands; i++)
1159 : {
1160 9 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(i);
1161 : IdrisiRasterBand *poDstBand =
1162 9 : (IdrisiRasterBand *)poDS->GetRasterBand(i);
1163 :
1164 9 : if (poDS->nBands == 1)
1165 : {
1166 3 : poDstBand->SetUnitType(poSrcBand->GetUnitType());
1167 3 : poDstBand->SetColorTable(poSrcBand->GetColorTable());
1168 3 : poDstBand->SetCategoryNames(poSrcBand->GetCategoryNames());
1169 :
1170 3 : const GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
1171 :
1172 3 : if (poRAT != nullptr)
1173 : {
1174 0 : poDstBand->SetDefaultRAT(poRAT);
1175 : }
1176 : }
1177 :
1178 9 : dfMin = poSrcBand->GetMinimum(nullptr);
1179 9 : dfMax = poSrcBand->GetMaximum(nullptr);
1180 9 : poDstBand->SetMinMax(dfMin, dfMax);
1181 : int bHasNoDataValue;
1182 9 : double dfNoDataValue = poSrcBand->GetNoDataValue(&bHasNoDataValue);
1183 9 : if (bHasNoDataValue)
1184 0 : poDstBand->SetNoDataValue(dfNoDataValue);
1185 : }
1186 :
1187 : // --------------------------------------------------------------------
1188 : // Copy image data
1189 : // --------------------------------------------------------------------
1190 :
1191 5 : if (GDALDatasetCopyWholeRaster((GDALDatasetH)poSrcDS, (GDALDatasetH)poDS,
1192 : nullptr, pfnProgress,
1193 5 : pProgressData) != CE_None)
1194 : {
1195 0 : delete poDS;
1196 0 : return nullptr;
1197 : }
1198 :
1199 : // --------------------------------------------------------------------
1200 : // Finalize
1201 : // --------------------------------------------------------------------
1202 :
1203 5 : poDS->FlushCache(false);
1204 :
1205 5 : return poDS;
1206 : }
1207 :
1208 : /************************************************************************/
1209 : /* GetFileList() */
1210 : /************************************************************************/
1211 :
1212 4 : char **IdrisiDataset::GetFileList()
1213 : {
1214 4 : char **papszFileList = GDALPamDataset::GetFileList();
1215 :
1216 : // --------------------------------------------------------------------
1217 : // Symbol table file
1218 : // --------------------------------------------------------------------
1219 :
1220 4 : const char *pszAssociated = CPLResetExtension(pszFilename, extSMP);
1221 :
1222 4 : if (FileExists(pszAssociated))
1223 : {
1224 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1225 : }
1226 : else
1227 : {
1228 4 : pszAssociated = CPLResetExtension(pszFilename, extSMPu);
1229 :
1230 4 : if (FileExists(pszAssociated))
1231 : {
1232 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1233 : }
1234 : }
1235 :
1236 : // --------------------------------------------------------------------
1237 : // Documentation file
1238 : // --------------------------------------------------------------------
1239 :
1240 4 : pszAssociated = CPLResetExtension(pszFilename, extRDC);
1241 :
1242 4 : if (FileExists(pszAssociated))
1243 : {
1244 4 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1245 : }
1246 : else
1247 : {
1248 0 : pszAssociated = CPLResetExtension(pszFilename, extRDCu);
1249 :
1250 0 : if (FileExists(pszAssociated))
1251 : {
1252 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1253 : }
1254 : }
1255 :
1256 : // --------------------------------------------------------------------
1257 : // Reference file
1258 : // --------------------------------------------------------------------
1259 :
1260 4 : pszAssociated = CPLResetExtension(pszFilename, extREF);
1261 :
1262 4 : if (FileExists(pszAssociated))
1263 : {
1264 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1265 : }
1266 : else
1267 : {
1268 4 : pszAssociated = CPLResetExtension(pszFilename, extREFu);
1269 :
1270 4 : if (FileExists(pszAssociated))
1271 : {
1272 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1273 : }
1274 : }
1275 :
1276 4 : return papszFileList;
1277 : }
1278 :
1279 : /************************************************************************/
1280 : /* GetGeoTransform() */
1281 : /************************************************************************/
1282 :
1283 9 : CPLErr IdrisiDataset::GetGeoTransform(double *padfTransform)
1284 : {
1285 9 : if (GDALPamDataset::GetGeoTransform(padfTransform) != CE_None)
1286 : {
1287 9 : memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
1288 : /*
1289 : if( adfGeoTransform[0] == 0.0
1290 : && adfGeoTransform[1] == 1.0
1291 : && adfGeoTransform[2] == 0.0
1292 : && adfGeoTransform[3] == 0.0
1293 : && adfGeoTransform[4] == 0.0
1294 : && adfGeoTransform[5] == 1.0 )
1295 : return CE_Failure;
1296 : */
1297 : }
1298 :
1299 9 : return CE_None;
1300 : }
1301 :
1302 : /************************************************************************/
1303 : /* SetGeoTransform() */
1304 : /************************************************************************/
1305 :
1306 13 : CPLErr IdrisiDataset::SetGeoTransform(double *padfTransform)
1307 : {
1308 13 : if (padfTransform[2] != 0.0 || padfTransform[4] != 0.0)
1309 : {
1310 0 : CPLError(CE_Failure, CPLE_AppDefined,
1311 : "Attempt to set rotated geotransform on Idrisi Raster file.\n"
1312 : "Idrisi Raster does not support rotation.\n");
1313 0 : return CE_Failure;
1314 : }
1315 :
1316 : // --------------------------------------------------------------------
1317 : // Update the .rdc file
1318 : // --------------------------------------------------------------------
1319 :
1320 13 : double dfXPixSz = padfTransform[1];
1321 13 : double dfYPixSz = padfTransform[5];
1322 13 : double dfMinX = padfTransform[0];
1323 13 : double dfMaxX = (dfXPixSz * nRasterXSize) + dfMinX;
1324 :
1325 : double dfMinY, dfMaxY;
1326 13 : if (dfYPixSz < 0)
1327 : {
1328 13 : dfMaxY = padfTransform[3];
1329 13 : dfMinY = (dfYPixSz * nRasterYSize) + padfTransform[3];
1330 : }
1331 : else
1332 : {
1333 0 : dfMaxY = (dfYPixSz * nRasterYSize) + padfTransform[3];
1334 0 : dfMinY = padfTransform[3];
1335 : }
1336 :
1337 13 : papszRDC = CSLSetNameValue(papszRDC, rdcMIN_X, CPLSPrintf("%.7f", dfMinX));
1338 13 : papszRDC = CSLSetNameValue(papszRDC, rdcMAX_X, CPLSPrintf("%.7f", dfMaxX));
1339 13 : papszRDC = CSLSetNameValue(papszRDC, rdcMIN_Y, CPLSPrintf("%.7f", dfMinY));
1340 13 : papszRDC = CSLSetNameValue(papszRDC, rdcMAX_Y, CPLSPrintf("%.7f", dfMaxY));
1341 13 : papszRDC = CSLSetNameValue(papszRDC, rdcRESOLUTION,
1342 : CPLSPrintf("%.7f", fabs(dfYPixSz)));
1343 :
1344 : // --------------------------------------------------------------------
1345 : // Update the Dataset attribute
1346 : // --------------------------------------------------------------------
1347 :
1348 13 : memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6);
1349 :
1350 13 : return CE_None;
1351 : }
1352 :
1353 : /************************************************************************/
1354 : /* GetSpatialRef() */
1355 : /************************************************************************/
1356 :
1357 1 : const OGRSpatialReference *IdrisiDataset::GetSpatialRef() const
1358 : {
1359 1 : const auto poSRS = GDALPamDataset::GetSpatialRef();
1360 1 : if (poSRS)
1361 0 : return poSRS;
1362 :
1363 1 : if (m_oSRS.IsEmpty())
1364 : {
1365 1 : const char *pszRefSystem = myCSLFetchNameValue(papszRDC, rdcREF_SYSTEM);
1366 1 : const char *pszRefUnit = myCSLFetchNameValue(papszRDC, rdcREF_UNITS);
1367 1 : if (pszRefSystem != nullptr && pszRefUnit != nullptr)
1368 1 : IdrisiGeoReference2Wkt(pszFilename, pszRefSystem, pszRefUnit,
1369 1 : m_oSRS);
1370 : }
1371 1 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
1372 : }
1373 :
1374 : /************************************************************************/
1375 : /* SetProjection() */
1376 : /************************************************************************/
1377 :
1378 13 : CPLErr IdrisiDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
1379 : {
1380 13 : m_oSRS.Clear();
1381 13 : if (poSRS)
1382 13 : m_oSRS = *poSRS;
1383 :
1384 13 : char *pszRefSystem = nullptr;
1385 13 : char *pszRefUnit = nullptr;
1386 :
1387 13 : CPLErr eResult = Wkt2GeoReference(m_oSRS, &pszRefSystem, &pszRefUnit);
1388 :
1389 13 : papszRDC = CSLSetNameValue(papszRDC, rdcREF_SYSTEM, pszRefSystem);
1390 13 : papszRDC = CSLSetNameValue(papszRDC, rdcREF_UNITS, pszRefUnit);
1391 :
1392 13 : CPLFree(pszRefSystem);
1393 13 : CPLFree(pszRefUnit);
1394 :
1395 13 : return eResult;
1396 : }
1397 :
1398 : /************************************************************************/
1399 : /* IdrisiRasterBand() */
1400 : /************************************************************************/
1401 :
1402 42 : IdrisiRasterBand::IdrisiRasterBand(IdrisiDataset *poDSIn, int nBandIn,
1403 42 : GDALDataType eDataTypeIn)
1404 : : poDefaultRAT(nullptr),
1405 126 : nRecordSize(poDSIn->GetRasterXSize() * poDSIn->nBands *
1406 42 : GDALGetDataTypeSizeBytes(eDataTypeIn)),
1407 42 : pabyScanLine(static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
1408 : poDSIn->GetRasterXSize(), GDALGetDataTypeSizeBytes(eDataTypeIn),
1409 : poDSIn->nBands))),
1410 84 : fMaximum(0.0), fMinimum(0.0), bFirstVal(true)
1411 : {
1412 42 : poDS = poDSIn;
1413 42 : nBand = nBandIn;
1414 42 : eDataType = eDataTypeIn;
1415 42 : nBlockYSize = 1;
1416 42 : nBlockXSize = poDS->GetRasterXSize();
1417 42 : }
1418 :
1419 : /************************************************************************/
1420 : /* ~IdrisiRasterBand() */
1421 : /************************************************************************/
1422 :
1423 84 : IdrisiRasterBand::~IdrisiRasterBand()
1424 : {
1425 42 : CPLFree(pabyScanLine);
1426 :
1427 42 : if (poDefaultRAT)
1428 : {
1429 0 : delete poDefaultRAT;
1430 : }
1431 84 : }
1432 :
1433 : /************************************************************************/
1434 : /* IReadBlock() */
1435 : /************************************************************************/
1436 :
1437 1392 : CPLErr IdrisiRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
1438 : void *pImage)
1439 : {
1440 1392 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1441 :
1442 1392 : if (VSIFSeekL(poGDS->fp, vsi_l_offset(nRecordSize) * nBlockYOff, SEEK_SET) <
1443 : 0)
1444 : {
1445 0 : CPLError(CE_Failure, CPLE_FileIO,
1446 : "Can't seek(%s) block with X offset %d and Y offset %d.\n%s",
1447 : poGDS->pszFilename, nBlockXOff, nBlockYOff,
1448 0 : VSIStrerror(errno));
1449 0 : return CE_Failure;
1450 : }
1451 :
1452 1392 : if ((int)VSIFReadL(pabyScanLine, 1, nRecordSize, poGDS->fp) < nRecordSize)
1453 : {
1454 0 : CPLError(CE_Failure, CPLE_FileIO,
1455 : "Can't read(%s) block with X offset %d and Y offset %d.\n%s",
1456 : poGDS->pszFilename, nBlockXOff, nBlockYOff,
1457 0 : VSIStrerror(errno));
1458 0 : return CE_Failure;
1459 : }
1460 :
1461 1392 : if (poGDS->nBands == 3)
1462 : {
1463 43380 : for (int i = 0, j = (3 - nBand); i < nBlockXSize; i++, j += 3)
1464 : {
1465 42800 : ((GByte *)pImage)[i] = pabyScanLine[j];
1466 : }
1467 : }
1468 : else
1469 : {
1470 812 : memcpy(pImage, pabyScanLine, nRecordSize);
1471 : }
1472 :
1473 : #ifdef CPL_MSB
1474 : if (eDataType == GDT_Float32)
1475 : GDALSwapWords(pImage, 4, nBlockXSize * nBlockYSize, 4);
1476 : #endif
1477 :
1478 1392 : return CE_None;
1479 : }
1480 :
1481 : /************************************************************************/
1482 : /* IWriteBlock() */
1483 : /************************************************************************/
1484 :
1485 230 : CPLErr IdrisiRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
1486 : void *pImage)
1487 : {
1488 230 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1489 :
1490 : #ifdef CPL_MSB
1491 : // Swap in input buffer if needed.
1492 : if (eDataType == GDT_Float32)
1493 : GDALSwapWords(pImage, 4, nBlockXSize * nBlockYSize, 4);
1494 : #endif
1495 :
1496 230 : if (poGDS->nBands == 1)
1497 : {
1498 50 : memcpy(pabyScanLine, pImage, nRecordSize);
1499 : }
1500 : else
1501 : {
1502 180 : if (nBand > 1)
1503 : {
1504 120 : VSIFSeekL(poGDS->fp, vsi_l_offset(nRecordSize) * nBlockYOff,
1505 : SEEK_SET);
1506 120 : VSIFReadL(pabyScanLine, 1, nRecordSize, poGDS->fp);
1507 : }
1508 : int i, j;
1509 7980 : for (i = 0, j = (3 - nBand); i < nBlockXSize; i++, j += 3)
1510 : {
1511 7800 : pabyScanLine[j] = ((GByte *)pImage)[i];
1512 : }
1513 : }
1514 :
1515 : #ifdef CPL_MSB
1516 : // Swap input buffer back to original form.
1517 : if (eDataType == GDT_Float32)
1518 : GDALSwapWords(pImage, 4, nBlockXSize * nBlockYSize, 4);
1519 : #endif
1520 :
1521 230 : VSIFSeekL(poGDS->fp, vsi_l_offset(nRecordSize) * nBlockYOff, SEEK_SET);
1522 :
1523 230 : if ((int)VSIFWriteL(pabyScanLine, 1, nRecordSize, poGDS->fp) < nRecordSize)
1524 : {
1525 0 : CPLError(CE_Failure, CPLE_FileIO,
1526 : "Can't write(%s) block with X offset %d and Y offset %d.\n%s",
1527 : poGDS->pszFilename, nBlockXOff, nBlockYOff,
1528 0 : VSIStrerror(errno));
1529 0 : return CE_Failure;
1530 : }
1531 :
1532 230 : int bHasNoDataValue = FALSE;
1533 230 : float fNoDataValue = (float)GetNoDataValue(&bHasNoDataValue);
1534 :
1535 : // --------------------------------------------------------------------
1536 : // Search for the minimum and maximum values
1537 : // --------------------------------------------------------------------
1538 :
1539 230 : if (eDataType == GDT_Float32)
1540 : {
1541 530 : for (int i = 0; i < nBlockXSize; i++)
1542 : {
1543 500 : float fVal = ((float *)pabyScanLine)[i]; // this is fine
1544 500 : if (!bHasNoDataValue || fVal != fNoDataValue)
1545 : {
1546 500 : if (bFirstVal)
1547 : {
1548 2 : fMinimum = fVal;
1549 2 : fMaximum = fVal;
1550 2 : bFirstVal = false;
1551 : }
1552 : else
1553 : {
1554 498 : if (fVal < fMinimum)
1555 3 : fMinimum = fVal;
1556 498 : if (fVal > fMaximum)
1557 9 : fMaximum = fVal;
1558 : }
1559 : }
1560 : }
1561 : }
1562 200 : else if (eDataType == GDT_Int16)
1563 : {
1564 110 : for (int i = 0; i < nBlockXSize; i++)
1565 : {
1566 100 : float fVal = (float)((GInt16 *)pabyScanLine)[i];
1567 100 : if (!bHasNoDataValue || fVal != fNoDataValue)
1568 : {
1569 100 : if (bFirstVal)
1570 : {
1571 1 : fMinimum = fVal;
1572 1 : fMaximum = fVal;
1573 1 : bFirstVal = false;
1574 : }
1575 : else
1576 : {
1577 99 : if (fVal < fMinimum)
1578 0 : fMinimum = fVal;
1579 99 : if (fVal > fMaximum)
1580 0 : fMaximum = fVal;
1581 : }
1582 : }
1583 : }
1584 : }
1585 190 : else if (poGDS->nBands == 1)
1586 : {
1587 110 : for (int i = 0; i < nBlockXSize; i++)
1588 : {
1589 100 : float fVal = (float)((GByte *)pabyScanLine)[i];
1590 100 : if (!bHasNoDataValue || fVal != fNoDataValue)
1591 : {
1592 100 : if (bFirstVal)
1593 : {
1594 1 : fMinimum = fVal;
1595 1 : fMaximum = fVal;
1596 1 : bFirstVal = false;
1597 : }
1598 : else
1599 : {
1600 99 : if (fVal < fMinimum)
1601 0 : fMinimum =
1602 : fVal; // I don't change this part, keep it as it is
1603 99 : if (fVal > fMaximum)
1604 0 : fMaximum = fVal;
1605 : }
1606 : }
1607 : }
1608 : }
1609 : else
1610 : {
1611 7980 : for (int i = 0, j = (3 - nBand); i < nBlockXSize; i++, j += 3)
1612 : {
1613 7800 : float fVal = (float)((GByte *)pabyScanLine)[j];
1614 7800 : if (!bHasNoDataValue || fVal != fNoDataValue)
1615 : {
1616 7800 : if (bFirstVal)
1617 : {
1618 6 : fMinimum = fVal;
1619 6 : fMaximum = fVal;
1620 6 : bFirstVal = false;
1621 : }
1622 : else
1623 : {
1624 7794 : if (fVal < fMinimum)
1625 0 : fMinimum = fVal;
1626 7794 : if (fVal > fMaximum)
1627 28 : fMaximum = fVal;
1628 : }
1629 : }
1630 : }
1631 : }
1632 :
1633 230 : return CE_None;
1634 : }
1635 :
1636 : /************************************************************************/
1637 : /* GetMinimum() */
1638 : /************************************************************************/
1639 :
1640 0 : double IdrisiRasterBand::GetMinimum(int *pbSuccess)
1641 : {
1642 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1643 :
1644 0 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcMIN_VALUE) == nullptr)
1645 0 : return GDALPamRasterBand::GetMinimum(pbSuccess);
1646 :
1647 : double adfMinValue[3];
1648 0 : CPLsscanf(myCSLFetchNameValue(poGDS->papszRDC, rdcMIN_VALUE), "%lf %lf %lf",
1649 : &adfMinValue[0], &adfMinValue[1], &adfMinValue[2]);
1650 :
1651 0 : if (pbSuccess)
1652 : {
1653 0 : *pbSuccess = true;
1654 : }
1655 :
1656 0 : return adfMinValue[this->nBand - 1];
1657 : }
1658 :
1659 : /************************************************************************/
1660 : /* GetMaximum() */
1661 : /************************************************************************/
1662 :
1663 0 : double IdrisiRasterBand::GetMaximum(int *pbSuccess)
1664 : {
1665 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1666 :
1667 0 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcMAX_VALUE) == nullptr)
1668 0 : return GDALPamRasterBand::GetMaximum(pbSuccess);
1669 :
1670 : double adfMaxValue[3];
1671 0 : CPLsscanf(myCSLFetchNameValue(poGDS->papszRDC, rdcMAX_VALUE), "%lf %lf %lf",
1672 : &adfMaxValue[0], &adfMaxValue[1], &adfMaxValue[2]);
1673 :
1674 0 : if (pbSuccess)
1675 : {
1676 0 : *pbSuccess = true;
1677 : }
1678 :
1679 0 : return adfMaxValue[this->nBand - 1];
1680 : }
1681 :
1682 : /************************************************************************/
1683 : /* GetNoDataValue() */
1684 : /************************************************************************/
1685 :
1686 276 : double IdrisiRasterBand::GetNoDataValue(int *pbSuccess)
1687 : {
1688 276 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1689 :
1690 276 : const char *pszFlagDefn = nullptr;
1691 :
1692 276 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_DEFN) != nullptr)
1693 276 : pszFlagDefn = myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_DEFN);
1694 0 : else if (myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_DEFN2) != nullptr)
1695 0 : pszFlagDefn = myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_DEFN2);
1696 :
1697 : // ------------------------------------------------------------------------
1698 : // If Flag_Def is not "none", Flag_Value means "background"
1699 : // or "missing data"
1700 : // ------------------------------------------------------------------------
1701 :
1702 : double dfNoData;
1703 276 : if (pszFlagDefn != nullptr && !EQUAL(pszFlagDefn, "none"))
1704 : {
1705 0 : dfNoData =
1706 0 : CPLAtof_nz(myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_VALUE));
1707 0 : if (pbSuccess)
1708 0 : *pbSuccess = TRUE;
1709 : }
1710 : else
1711 : {
1712 276 : dfNoData = -9999.0; /* this value should be ignored */
1713 276 : if (pbSuccess)
1714 276 : *pbSuccess = FALSE;
1715 : }
1716 :
1717 276 : return dfNoData;
1718 : }
1719 :
1720 : /************************************************************************/
1721 : /* SetNoDataValue() */
1722 : /************************************************************************/
1723 :
1724 0 : CPLErr IdrisiRasterBand::SetNoDataValue(double dfNoDataValue)
1725 : {
1726 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1727 :
1728 0 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcFLAG_VALUE,
1729 : CPLSPrintf("%.7g", dfNoDataValue));
1730 0 : poGDS->papszRDC =
1731 0 : CSLSetNameValue(poGDS->papszRDC, rdcFLAG_DEFN, "missing data");
1732 :
1733 0 : return CE_None;
1734 : }
1735 :
1736 : /************************************************************************/
1737 : /* GetColorInterpretation() */
1738 : /************************************************************************/
1739 :
1740 0 : GDALColorInterp IdrisiRasterBand::GetColorInterpretation()
1741 : {
1742 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1743 :
1744 0 : if (poGDS->nBands == 3)
1745 : {
1746 0 : switch (nBand)
1747 : {
1748 0 : case 1:
1749 0 : return GCI_BlueBand;
1750 0 : case 2:
1751 0 : return GCI_GreenBand;
1752 0 : case 3:
1753 0 : return GCI_RedBand;
1754 : }
1755 : }
1756 0 : else if (poGDS->poColorTable->GetColorEntryCount() > 0)
1757 : {
1758 0 : return GCI_PaletteIndex;
1759 : }
1760 0 : return GCI_GrayIndex;
1761 : }
1762 :
1763 : /************************************************************************/
1764 : /* GetCategoryNames() */
1765 : /************************************************************************/
1766 :
1767 0 : char **IdrisiRasterBand::GetCategoryNames()
1768 : {
1769 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1770 :
1771 0 : return poGDS->papszCategories;
1772 : }
1773 :
1774 : /************************************************************************/
1775 : /* SetCategoryNames() */
1776 : /************************************************************************/
1777 :
1778 3 : CPLErr IdrisiRasterBand::SetCategoryNames(char **papszCategoryNames)
1779 : {
1780 3 : const int nCatCount = CSLCount(papszCategoryNames);
1781 :
1782 3 : if (nCatCount == 0)
1783 3 : return CE_None;
1784 :
1785 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1786 :
1787 0 : CSLDestroy(poGDS->papszCategories);
1788 0 : poGDS->papszCategories = CSLDuplicate(papszCategoryNames);
1789 :
1790 : // ------------------------------------------------------
1791 : // Search for the "Legend cats : N" line
1792 : // ------------------------------------------------------
1793 :
1794 0 : int nLine = -1;
1795 0 : for (int i = 0; (i < CSLCount(poGDS->papszRDC)) && (nLine == -1); i++)
1796 0 : if (EQUALN(poGDS->papszRDC[i], rdcLEGEND_CATS, 12))
1797 0 : nLine = i;
1798 :
1799 0 : if (nLine < 0)
1800 0 : return CE_None;
1801 :
1802 0 : int nCount = atoi_nz(myCSLFetchNameValue(poGDS->papszRDC, rdcLEGEND_CATS));
1803 :
1804 : // ------------------------------------------------------
1805 : // Delete old instance of the category names
1806 : // ------------------------------------------------------
1807 :
1808 0 : if (nCount > 0)
1809 0 : poGDS->papszRDC =
1810 0 : CSLRemoveStrings(poGDS->papszRDC, nLine + 1, nCount, nullptr);
1811 :
1812 0 : nCount = 0;
1813 :
1814 0 : for (int i = 0; i < nCatCount; i++)
1815 : {
1816 0 : if ((strlen(papszCategoryNames[i]) > 0))
1817 : {
1818 0 : poGDS->papszRDC =
1819 0 : CSLInsertString(poGDS->papszRDC, (nLine + nCount + 1),
1820 : CPLSPrintf("%s:%s", CPLSPrintf(rdcCODE_N, i),
1821 0 : papszCategoryNames[i]));
1822 0 : nCount++;
1823 : }
1824 : }
1825 :
1826 0 : poGDS->papszRDC =
1827 0 : CSLSetNameValue(poGDS->papszRDC, rdcLEGEND_CATS,
1828 : CPLSPrintf("%d", nCount)); // this is fine
1829 :
1830 0 : return CE_None;
1831 : }
1832 :
1833 : /************************************************************************/
1834 : /* GetColorTable() */
1835 : /************************************************************************/
1836 :
1837 0 : GDALColorTable *IdrisiRasterBand::GetColorTable()
1838 : {
1839 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1840 :
1841 0 : if (poGDS->poColorTable->GetColorEntryCount() == 0)
1842 : {
1843 0 : return nullptr;
1844 : }
1845 :
1846 0 : return poGDS->poColorTable;
1847 : }
1848 :
1849 : /************************************************************************/
1850 : /* SetColorTable() */
1851 : /************************************************************************/
1852 :
1853 3 : CPLErr IdrisiRasterBand::SetColorTable(GDALColorTable *poColorTable)
1854 : {
1855 3 : if (poColorTable == nullptr)
1856 : {
1857 3 : return CE_None;
1858 : }
1859 :
1860 0 : if (poColorTable->GetColorEntryCount() == 0)
1861 : {
1862 0 : return CE_None;
1863 : }
1864 :
1865 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1866 :
1867 0 : delete poGDS->poColorTable;
1868 :
1869 0 : poGDS->poColorTable = poColorTable->Clone();
1870 :
1871 0 : const char *pszSMPFilename = CPLResetExtension(poGDS->pszFilename, extSMP);
1872 0 : VSILFILE *fpSMP = VSIFOpenL(pszSMPFilename, "w");
1873 :
1874 0 : if (fpSMP != nullptr)
1875 : {
1876 0 : VSIFWriteL("[Idrisi]", 8, 1, fpSMP);
1877 0 : GByte nPlatform = 1;
1878 0 : VSIFWriteL(&nPlatform, 1, 1, fpSMP);
1879 0 : GByte nVersion = 11;
1880 0 : VSIFWriteL(&nVersion, 1, 1, fpSMP);
1881 0 : GByte nDepth = 8;
1882 0 : VSIFWriteL(&nDepth, 1, 1, fpSMP);
1883 0 : GByte nHeadSz = 18;
1884 0 : VSIFWriteL(&nHeadSz, 1, 1, fpSMP);
1885 0 : GUInt16 nCount = 255;
1886 0 : VSIFWriteL(&nCount, 2, 1, fpSMP);
1887 0 : GUInt16 nMix = 0;
1888 0 : VSIFWriteL(&nMix, 2, 1, fpSMP);
1889 0 : GUInt16 nMax = 255;
1890 0 : VSIFWriteL(&nMax, 2, 1, fpSMP);
1891 :
1892 : GDALColorEntry oEntry;
1893 : GByte aucRGB[3];
1894 :
1895 0 : for (int i = 0; i < poColorTable->GetColorEntryCount(); i++)
1896 : {
1897 0 : poColorTable->GetColorEntryAsRGB(i, &oEntry);
1898 0 : aucRGB[0] = (GByte)oEntry.c1;
1899 0 : aucRGB[1] = (GByte)oEntry.c2;
1900 0 : aucRGB[2] = (GByte)oEntry.c3;
1901 0 : VSIFWriteL(&aucRGB, 3, 1, fpSMP);
1902 : }
1903 : /* smp files always have 256 occurrences. */
1904 0 : for (int i = poColorTable->GetColorEntryCount(); i <= 255; i++)
1905 : {
1906 0 : poColorTable->GetColorEntryAsRGB(i, &oEntry);
1907 0 : aucRGB[0] = (GByte)0;
1908 0 : aucRGB[1] = (GByte)0;
1909 0 : aucRGB[2] = (GByte)0;
1910 0 : VSIFWriteL(&aucRGB, 3, 1, fpSMP);
1911 : }
1912 0 : VSIFCloseL(fpSMP);
1913 : }
1914 :
1915 0 : return CE_None;
1916 : }
1917 :
1918 : /************************************************************************/
1919 : /* GetUnitType() */
1920 : /************************************************************************/
1921 :
1922 0 : const char *IdrisiRasterBand::GetUnitType()
1923 : {
1924 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1925 :
1926 0 : return poGDS->pszUnitType;
1927 : }
1928 :
1929 : /************************************************************************/
1930 : /* SetUnitType() */
1931 : /************************************************************************/
1932 :
1933 3 : CPLErr IdrisiRasterBand::SetUnitType(const char *pszUnitType)
1934 : {
1935 3 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1936 :
1937 3 : if (strlen(pszUnitType) == 0)
1938 : {
1939 3 : poGDS->papszRDC =
1940 3 : CSLSetNameValue(poGDS->papszRDC, rdcVALUE_UNITS, "unspecified");
1941 : }
1942 : else
1943 : {
1944 0 : poGDS->papszRDC =
1945 0 : CSLSetNameValue(poGDS->papszRDC, rdcVALUE_UNITS, pszUnitType);
1946 : }
1947 :
1948 3 : return CE_None;
1949 : }
1950 :
1951 : /************************************************************************/
1952 : /* SetMinMax() */
1953 : /************************************************************************/
1954 :
1955 49 : CPLErr IdrisiRasterBand::SetMinMax(double dfMin, double dfMax)
1956 : {
1957 49 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1958 :
1959 49 : fMinimum = (float)dfMin;
1960 49 : fMaximum = (float)dfMax;
1961 :
1962 49 : double adfMin[3] = {0.0, 0.0, 0.0};
1963 49 : double adfMax[3] = {0.0, 0.0, 0.0};
1964 :
1965 49 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcMIN_VALUE) != nullptr)
1966 49 : CPLsscanf(myCSLFetchNameValue(poGDS->papszRDC, rdcMIN_VALUE),
1967 : "%lf %lf %lf", &adfMin[0], &adfMin[1], &adfMin[2]);
1968 49 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcMAX_VALUE) != nullptr)
1969 49 : CPLsscanf(myCSLFetchNameValue(poGDS->papszRDC, rdcMAX_VALUE),
1970 : "%lf %lf %lf", &adfMax[0], &adfMax[1], &adfMax[2]);
1971 :
1972 49 : adfMin[nBand - 1] = dfMin;
1973 49 : adfMax[nBand - 1] = dfMax;
1974 :
1975 49 : if (poGDS->nBands == 3)
1976 : {
1977 24 : poGDS->papszRDC = CSLSetNameValue(
1978 : poGDS->papszRDC, rdcMIN_VALUE,
1979 : CPLSPrintf("%.8g %.8g %.8g", adfMin[0], adfMin[1], adfMin[2]));
1980 24 : poGDS->papszRDC = CSLSetNameValue(
1981 : poGDS->papszRDC, rdcMAX_VALUE,
1982 : CPLSPrintf("%.8g %.8g %.8g", adfMax[0], adfMax[1], adfMax[2]));
1983 24 : poGDS->papszRDC = CSLSetNameValue(
1984 : poGDS->papszRDC, rdcDISPLAY_MIN,
1985 : CPLSPrintf("%.8g %.8g %.8g", adfMin[0], adfMin[1], adfMin[2]));
1986 24 : poGDS->papszRDC = CSLSetNameValue(
1987 : poGDS->papszRDC, rdcDISPLAY_MAX,
1988 : CPLSPrintf("%.8g %.8g %.8g", adfMax[0], adfMax[1], adfMax[2]));
1989 : }
1990 : else
1991 : {
1992 25 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcMIN_VALUE,
1993 : CPLSPrintf("%.8g", adfMin[0]));
1994 25 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcMAX_VALUE,
1995 : CPLSPrintf("%.8g", adfMax[0]));
1996 25 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcDISPLAY_MIN,
1997 : CPLSPrintf("%.8g", adfMin[0]));
1998 25 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcDISPLAY_MAX,
1999 : CPLSPrintf("%.8g", adfMax[0]));
2000 : }
2001 :
2002 49 : return CE_None;
2003 : }
2004 :
2005 : /************************************************************************/
2006 : /* SetStatistics() */
2007 : /************************************************************************/
2008 :
2009 20 : CPLErr IdrisiRasterBand::SetStatistics(double dfMin, double dfMax,
2010 : double dfMean, double dfStdDev)
2011 : {
2012 20 : SetMinMax(dfMin, dfMax);
2013 :
2014 20 : return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
2015 : }
2016 :
2017 : /************************************************************************/
2018 : /* SetDefaultRAT() */
2019 : /************************************************************************/
2020 :
2021 0 : CPLErr IdrisiRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
2022 : {
2023 0 : if (!poRAT)
2024 : {
2025 0 : return CE_Failure;
2026 : }
2027 :
2028 : // ----------------------------------------------------------
2029 : // Get field indices
2030 : // ----------------------------------------------------------
2031 :
2032 0 : int iValue = -1;
2033 0 : int iRed = poRAT->GetColOfUsage(GFU_Red);
2034 0 : int iGreen = poRAT->GetColOfUsage(GFU_Green);
2035 0 : int iBlue = poRAT->GetColOfUsage(GFU_Blue);
2036 :
2037 0 : GDALColorTable *poCT = nullptr;
2038 0 : char **papszNames = nullptr;
2039 :
2040 0 : int nFact = 1;
2041 :
2042 : // ----------------------------------------------------------
2043 : // Seek for "Value" field index (AGIS standards field name)
2044 : // ----------------------------------------------------------
2045 :
2046 0 : if (GetColorTable() == nullptr ||
2047 0 : GetColorTable()->GetColorEntryCount() == 0)
2048 : {
2049 0 : for (int i = 0; i < poRAT->GetColumnCount(); i++)
2050 : {
2051 0 : if (STARTS_WITH_CI(poRAT->GetNameOfCol(i), "Value"))
2052 : {
2053 0 : iValue = i;
2054 0 : break;
2055 : }
2056 : }
2057 :
2058 0 : if (iRed != -1 && iGreen != -1 && iBlue != -1)
2059 : {
2060 0 : poCT = new GDALColorTable();
2061 0 : nFact = poRAT->GetTypeOfCol(iRed) == GFT_Real ? 255 : 1;
2062 : }
2063 : }
2064 :
2065 : // ----------------------------------------------------------
2066 : // Seek for Name field index
2067 : // ----------------------------------------------------------
2068 :
2069 0 : int iName = -1;
2070 0 : if (CSLCount(GetCategoryNames()) == 0)
2071 : {
2072 0 : iName = poRAT->GetColOfUsage(GFU_Name);
2073 0 : if (iName == -1)
2074 : {
2075 0 : for (int i = 0; i < poRAT->GetColumnCount(); i++)
2076 : {
2077 0 : if (STARTS_WITH_CI(poRAT->GetNameOfCol(i), "Class_Name"))
2078 : {
2079 0 : iName = i;
2080 0 : break;
2081 : }
2082 0 : else if (STARTS_WITH_CI(poRAT->GetNameOfCol(i), "Categor"))
2083 : {
2084 0 : iName = i;
2085 0 : break;
2086 : }
2087 0 : else if (STARTS_WITH_CI(poRAT->GetNameOfCol(i), "Name"))
2088 : {
2089 0 : iName = i;
2090 0 : break;
2091 : }
2092 : }
2093 : }
2094 :
2095 : /* if still can't find it use the first String column */
2096 :
2097 0 : if (iName == -1)
2098 : {
2099 0 : for (int i = 0; i < poRAT->GetColumnCount(); i++)
2100 : {
2101 0 : if (poRAT->GetTypeOfCol(i) == GFT_String)
2102 : {
2103 0 : iName = i;
2104 0 : break;
2105 : }
2106 : }
2107 : }
2108 :
2109 : // ----------------------------------------------------------
2110 : // Incomplete Attribute Table;
2111 : // ----------------------------------------------------------
2112 :
2113 0 : if (iName == -1)
2114 : {
2115 0 : iName = iValue;
2116 : }
2117 : }
2118 :
2119 : // ----------------------------------------------------------
2120 : // Load values
2121 : // ----------------------------------------------------------
2122 :
2123 : GDALColorEntry sColor;
2124 0 : int iEntry = 0;
2125 0 : int iOut = 0;
2126 0 : int nEntryCount = poRAT->GetRowCount();
2127 0 : int nValue = 0;
2128 :
2129 0 : if (iValue != -1)
2130 : {
2131 0 : nValue = poRAT->GetValueAsInt(iEntry, iValue);
2132 : }
2133 :
2134 0 : for (iOut = 0; iOut < 65535 && (iEntry < nEntryCount); iOut++)
2135 : {
2136 0 : if (iOut == nValue)
2137 : {
2138 0 : if (poCT)
2139 : {
2140 0 : const double dRed = poRAT->GetValueAsDouble(iEntry, iRed);
2141 0 : const double dGreen = poRAT->GetValueAsDouble(iEntry, iGreen);
2142 0 : const double dBlue = poRAT->GetValueAsDouble(iEntry, iBlue);
2143 0 : sColor.c1 = (short)(dRed * nFact);
2144 0 : sColor.c2 = (short)(dGreen * nFact);
2145 0 : sColor.c3 = (short)(dBlue * nFact);
2146 0 : sColor.c4 = (short)(255 / nFact);
2147 0 : poCT->SetColorEntry(iEntry, &sColor);
2148 : }
2149 :
2150 0 : if (iName != -1)
2151 : {
2152 0 : papszNames = CSLAddString(
2153 0 : papszNames, poRAT->GetValueAsString(iEntry, iName));
2154 : }
2155 :
2156 : /* Advance on the table */
2157 :
2158 0 : if ((++iEntry) < nEntryCount)
2159 : {
2160 0 : if (iValue != -1)
2161 0 : nValue = poRAT->GetValueAsInt(iEntry, iValue);
2162 : else
2163 0 : nValue = iEntry;
2164 : }
2165 : }
2166 0 : else if (iOut < nValue)
2167 : {
2168 0 : if (poCT)
2169 : {
2170 0 : sColor.c1 = (short)0;
2171 0 : sColor.c2 = (short)0;
2172 0 : sColor.c3 = (short)0;
2173 0 : sColor.c4 = (short)255;
2174 0 : poCT->SetColorEntry(iEntry, &sColor);
2175 : }
2176 :
2177 0 : if (iName != -1)
2178 0 : papszNames = CSLAddString(papszNames, "");
2179 : }
2180 : }
2181 :
2182 : // ----------------------------------------------------------
2183 : // Set Color Table
2184 : // ----------------------------------------------------------
2185 :
2186 0 : if (poCT)
2187 : {
2188 0 : SetColorTable(poCT);
2189 0 : delete poCT;
2190 : }
2191 :
2192 : // ----------------------------------------------------------
2193 : // Update Category Names
2194 : // ----------------------------------------------------------
2195 :
2196 0 : if (papszNames)
2197 : {
2198 0 : SetCategoryNames(papszNames);
2199 0 : CSLDestroy(papszNames);
2200 : }
2201 :
2202 : // ----------------------------------------------------------
2203 : // Update Attribute Table
2204 : // ----------------------------------------------------------
2205 :
2206 0 : if (poDefaultRAT)
2207 : {
2208 0 : delete poDefaultRAT;
2209 : }
2210 :
2211 0 : poDefaultRAT = poRAT->Clone();
2212 :
2213 0 : return CE_None;
2214 : }
2215 :
2216 : /************************************************************************/
2217 : /* GetDefaultRAT() */
2218 : /************************************************************************/
2219 :
2220 0 : GDALRasterAttributeTable *IdrisiRasterBand::GetDefaultRAT()
2221 : {
2222 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
2223 :
2224 0 : if (poGDS->papszCategories == nullptr)
2225 : {
2226 0 : return nullptr;
2227 : }
2228 :
2229 0 : bool bHasColorTable = poGDS->poColorTable->GetColorEntryCount() > 0;
2230 :
2231 : // ----------------------------------------------------------
2232 : // Create the bands Attribute Table
2233 : // ----------------------------------------------------------
2234 :
2235 0 : if (poDefaultRAT)
2236 : {
2237 0 : delete poDefaultRAT;
2238 : }
2239 :
2240 0 : poDefaultRAT = new GDALDefaultRasterAttributeTable();
2241 :
2242 : // ----------------------------------------------------------
2243 : // Create (Value, Red, Green, Blue, Alpha, Class_Name) fields
2244 : // ----------------------------------------------------------
2245 :
2246 0 : poDefaultRAT->CreateColumn("Value", GFT_Integer, GFU_Generic);
2247 0 : poDefaultRAT->CreateColumn("Value_1", GFT_Integer, GFU_MinMax);
2248 :
2249 0 : if (bHasColorTable)
2250 : {
2251 0 : poDefaultRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
2252 0 : poDefaultRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
2253 0 : poDefaultRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
2254 0 : poDefaultRAT->CreateColumn("Alpha", GFT_Integer, GFU_Alpha);
2255 : }
2256 0 : poDefaultRAT->CreateColumn("Class_name", GFT_String, GFU_Name);
2257 :
2258 : // ----------------------------------------------------------
2259 : // Loop through the Category Names.
2260 : // ----------------------------------------------------------
2261 :
2262 : GDALColorEntry sEntry;
2263 0 : int iName = poDefaultRAT->GetColOfUsage(GFU_Name);
2264 0 : int nEntryCount = CSLCount(poGDS->papszCategories);
2265 0 : int iRows = 0;
2266 :
2267 0 : for (int iEntry = 0; iEntry < nEntryCount; iEntry++)
2268 : {
2269 0 : if (EQUAL(poGDS->papszCategories[iEntry], ""))
2270 : {
2271 0 : continue; // Eliminate the empty ones
2272 : }
2273 0 : poDefaultRAT->SetRowCount(poDefaultRAT->GetRowCount() + 1);
2274 0 : poDefaultRAT->SetValue(iRows, 0, iEntry);
2275 0 : poDefaultRAT->SetValue(iRows, 1, iEntry);
2276 0 : if (bHasColorTable)
2277 : {
2278 0 : poGDS->poColorTable->GetColorEntryAsRGB(iEntry, &sEntry);
2279 0 : poDefaultRAT->SetValue(iRows, 2, sEntry.c1);
2280 0 : poDefaultRAT->SetValue(iRows, 3, sEntry.c2);
2281 0 : poDefaultRAT->SetValue(iRows, 4, sEntry.c3);
2282 0 : poDefaultRAT->SetValue(iRows, 5, sEntry.c4);
2283 : }
2284 0 : poDefaultRAT->SetValue(iRows, iName, poGDS->papszCategories[iEntry]);
2285 0 : iRows++;
2286 : }
2287 :
2288 0 : return poDefaultRAT;
2289 : }
2290 :
2291 : /************************************************************************/
2292 : /* IdrisiGeoReference2Wkt() */
2293 : /************************************************************************/
2294 :
2295 : /***
2296 : * Converts Idrisi geographic reference information to OpenGIS WKT.
2297 : *
2298 : * The Idrisi metadata file contain two fields that describe the
2299 : * geographic reference, RefSystem and RefUnit.
2300 : *
2301 : * RefSystem can contains the world "plane" or the name of a georeference
2302 : * file <refsystem>.ref that details the geographic reference
2303 : * system( coordinate system and projection parameters ). RefUnits
2304 : * indicates the unit of the image bounds.
2305 : *
2306 : * The georeference files are generally located in the product installation
2307 : * folder $IDRISIDIR\Georef, but they are first looked for in the same
2308 : * folder as the data file.
2309 : *
2310 : * If a Reference system names can be recognized by a name convention
2311 : * it will be interpreted without the need to read the georeference file.
2312 : * That includes "latlong" and all the UTM and State Plane zones.
2313 : *
2314 : * RefSystem "latlong" means that the data is not project and the coordinate
2315 : * system is WGS84. RefSystem "plane" means that the there is no coordinate
2316 : * system but the it is possible to calculate areas and distance by looking
2317 : * at the RefUnits.
2318 : *
2319 : * If the environment variable IDRISIDIR is not set and the georeference file
2320 : * need to be read then the projection string will result as unknown.
2321 : ***/
2322 :
2323 4 : CPLErr IdrisiGeoReference2Wkt(const char *pszFilename, const char *pszRefSystem,
2324 : const char *pszRefUnits,
2325 : OGRSpatialReference &oSRS)
2326 : {
2327 : // ---------------------------------------------------------
2328 : // Plane
2329 : // ---------------------------------------------------------
2330 :
2331 4 : if (EQUAL(pszRefSystem, rstPLANE))
2332 : {
2333 0 : oSRS.SetLocalCS("Plane");
2334 0 : int nUnit = GetUnitIndex(pszRefUnits);
2335 0 : if (nUnit > -1)
2336 : {
2337 0 : int nDeft = aoLinearUnitsConv[nUnit].nDefaultG;
2338 0 : oSRS.SetLinearUnits(aoLinearUnitsConv[nDeft].pszName,
2339 0 : aoLinearUnitsConv[nDeft].dfConv);
2340 : }
2341 0 : return CE_None;
2342 : }
2343 :
2344 : // ---------------------------------------------------------
2345 : // Latlong
2346 : // ---------------------------------------------------------
2347 :
2348 4 : if (EQUAL(pszRefSystem, rstLATLONG) || EQUAL(pszRefSystem, rstLATLONG2))
2349 : {
2350 1 : oSRS.SetWellKnownGeogCS("WGS84");
2351 1 : return CE_None;
2352 : }
2353 :
2354 : // ---------------------------------------------------------
2355 : // Prepare for scanning in lower case
2356 : // ---------------------------------------------------------
2357 :
2358 3 : char *pszRefSystemLower = CPLStrdup(pszRefSystem);
2359 3 : CPLStrlwr(pszRefSystemLower);
2360 :
2361 : // ---------------------------------------------------------
2362 : // UTM naming convention( ex.: utm-30n )
2363 : // ---------------------------------------------------------
2364 :
2365 3 : if (EQUALN(pszRefSystem, rstUTM, 3))
2366 : {
2367 : int nZone;
2368 : char cNorth;
2369 3 : sscanf(pszRefSystemLower, rstUTM, &nZone, &cNorth);
2370 3 : oSRS.SetWellKnownGeogCS("WGS84");
2371 3 : oSRS.SetUTM(nZone, (cNorth == 'n'));
2372 3 : CPLFree(pszRefSystemLower);
2373 3 : return CE_None;
2374 : }
2375 :
2376 : // ---------------------------------------------------------
2377 : // State Plane naming convention( ex.: spc83ma1 )
2378 : // ---------------------------------------------------------
2379 :
2380 0 : if (EQUALN(pszRefSystem, rstSPC, 3))
2381 : {
2382 : int nNAD;
2383 : int nZone;
2384 : char szState[3];
2385 0 : sscanf(pszRefSystemLower, rstSPC, &nNAD, szState, &nZone);
2386 0 : int nSPCode = GetStateCode(szState);
2387 0 : if (nSPCode != -1)
2388 : {
2389 0 : nZone = (nZone == 1 ? nSPCode : nSPCode + nZone - 1);
2390 :
2391 0 : if (oSRS.SetStatePlane(nZone, (nNAD == 83)) != OGRERR_FAILURE)
2392 : {
2393 0 : CPLFree(pszRefSystemLower);
2394 0 : return CE_None;
2395 : }
2396 :
2397 : // ----------------------------------------------------------
2398 : // If SetStatePlane fails, set GeoCS as NAD Datum and let it
2399 : // try to read the projection info from georeference file( * )
2400 : // ----------------------------------------------------------
2401 :
2402 0 : oSRS.SetWellKnownGeogCS(CPLSPrintf("NAD%d", nNAD));
2403 : }
2404 : }
2405 :
2406 0 : CPLFree(pszRefSystemLower);
2407 0 : pszRefSystemLower = nullptr;
2408 :
2409 : // ------------------------------------------------------------------
2410 : // Search for georeference file <RefSystem>.ref
2411 : // ------------------------------------------------------------------
2412 :
2413 0 : const char *pszFName = CPLSPrintf("%s%c%s.ref", CPLGetDirname(pszFilename),
2414 : PATHDELIM, pszRefSystem);
2415 :
2416 0 : if (!FileExists(pszFName))
2417 : {
2418 : // ------------------------------------------------------------------
2419 : // Look at $IDRISIDIR\Georef\<RefSystem>.ref
2420 : // ------------------------------------------------------------------
2421 :
2422 0 : const char *pszIdrisiDir = CPLGetConfigOption("IDRISIDIR", nullptr);
2423 :
2424 0 : if ((pszIdrisiDir) != nullptr)
2425 : {
2426 0 : pszFName = CPLSPrintf("%s%cgeoref%c%s.ref", pszIdrisiDir, PATHDELIM,
2427 : PATHDELIM, pszRefSystem);
2428 : }
2429 : }
2430 :
2431 : // ------------------------------------------------------------------
2432 : // Cannot find georeference file
2433 : // ------------------------------------------------------------------
2434 :
2435 0 : if (!FileExists(pszFName))
2436 : {
2437 0 : CPLDebug("RST", "Cannot find Idrisi georeference file %s",
2438 : pszRefSystem);
2439 :
2440 0 : if (oSRS.IsGeographic() == FALSE) /* see State Plane remarks( * ) */
2441 : {
2442 0 : oSRS.SetLocalCS("Unknown");
2443 0 : int nUnit = GetUnitIndex(pszRefUnits);
2444 0 : if (nUnit > -1)
2445 : {
2446 0 : int nDeft = aoLinearUnitsConv[nUnit].nDefaultG;
2447 0 : oSRS.SetLinearUnits(aoLinearUnitsConv[nDeft].pszName,
2448 0 : aoLinearUnitsConv[nDeft].dfConv);
2449 : }
2450 : }
2451 0 : return CE_Failure;
2452 : }
2453 :
2454 : // ------------------------------------------------------------------
2455 : // Read values from georeference file
2456 : // ------------------------------------------------------------------
2457 :
2458 0 : char **papszRef = CSLLoad(pszFName);
2459 0 : myCSLSetNameValueSeparator(papszRef, ":");
2460 :
2461 0 : char *pszGeorefName = nullptr;
2462 :
2463 0 : const char *pszREF_SYSTEM = myCSLFetchNameValue(papszRef, refREF_SYSTEM);
2464 0 : if (pszREF_SYSTEM != nullptr && EQUAL(pszREF_SYSTEM, "") == FALSE)
2465 : {
2466 0 : pszGeorefName = CPLStrdup(pszREF_SYSTEM);
2467 : }
2468 : else
2469 : {
2470 : pszGeorefName =
2471 0 : CPLStrdup(myCSLFetchNameValue(papszRef, refREF_SYSTEM2));
2472 : }
2473 0 : char *pszProjName = CPLStrdup(myCSLFetchNameValue(papszRef, refPROJECTION));
2474 0 : char *pszDatum = CPLStrdup(myCSLFetchNameValue(papszRef, refDATUM));
2475 0 : char *pszEllipsoid = CPLStrdup(myCSLFetchNameValue(papszRef, refELLIPSOID));
2476 : const double dfCenterLat =
2477 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refORIGIN_LAT));
2478 : const double dfCenterLong =
2479 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refORIGIN_LONG));
2480 : const double dfSemiMajor =
2481 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refMAJOR_SAX));
2482 : const double dfSemiMinor =
2483 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refMINOR_SAX));
2484 : const double dfFalseEasting =
2485 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refORIGIN_X));
2486 : const double dfFalseNorthing =
2487 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refORIGIN_Y));
2488 : const double dfStdP1 =
2489 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refSTANDL_1));
2490 : const double dfStdP2 =
2491 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refSTANDL_2));
2492 : double dfScale;
2493 0 : double adfToWGS84[3] = {0.0, 0.0, 0.0};
2494 :
2495 0 : const char *pszToWGS84 = myCSLFetchNameValue(papszRef, refDELTA_WGS84);
2496 0 : if (pszToWGS84)
2497 0 : CPLsscanf(pszToWGS84, "%lf %lf %lf", &adfToWGS84[0], &adfToWGS84[1],
2498 : &adfToWGS84[2]);
2499 :
2500 0 : const char *pszSCALE_FAC = myCSLFetchNameValue(papszRef, refSCALE_FAC);
2501 0 : if (pszSCALE_FAC == nullptr || EQUAL(pszSCALE_FAC, "na"))
2502 0 : dfScale = 1.0;
2503 : else
2504 0 : dfScale = CPLAtof_nz(pszSCALE_FAC);
2505 :
2506 0 : CSLDestroy(papszRef);
2507 :
2508 : // ----------------------------------------------------------------------
2509 : // Set the Geographic Coordinate System
2510 : // ----------------------------------------------------------------------
2511 :
2512 0 : if (oSRS.IsGeographic() == FALSE) /* see State Plane remarks(*) */
2513 : {
2514 0 : int nEPSG = 0;
2515 :
2516 : // ----------------------------------------------------------------------
2517 : // Is it a WGS84 equivalent?
2518 : // ----------------------------------------------------------------------
2519 :
2520 0 : if ((STARTS_WITH_CI(pszEllipsoid, "WGS")) &&
2521 0 : (strstr(pszEllipsoid, "84")) && (STARTS_WITH_CI(pszDatum, "WGS")) &&
2522 0 : (strstr(pszDatum, "84")) && (adfToWGS84[0] == 0.0) &&
2523 0 : (adfToWGS84[1] == 0.0) && (adfToWGS84[2] == 0.0))
2524 : {
2525 0 : nEPSG = 4326;
2526 : }
2527 :
2528 : // ----------------------------------------------------------------------
2529 : // Match GCS's DATUM_NAME by using 'ApproxString' over Datum
2530 : // ----------------------------------------------------------------------
2531 :
2532 0 : if (nEPSG == 0)
2533 : {
2534 0 : const PJ_TYPE nObjType = PJ_TYPE_GEODETIC_REFERENCE_FRAME;
2535 : auto datumList =
2536 0 : proj_create_from_name(OSRGetProjTLSContext(), "EPSG", pszDatum,
2537 : &nObjType, 1, true, 1, nullptr);
2538 0 : if (datumList && proj_list_get_count(datumList) == 1)
2539 : {
2540 : auto datum =
2541 0 : proj_list_get(OSRGetProjTLSContext(), datumList, 0);
2542 0 : if (datum)
2543 : {
2544 0 : const char *datumCode = proj_get_id_code(datum, 0);
2545 0 : if (datumCode)
2546 : {
2547 0 : auto crsList = proj_query_geodetic_crs_from_datum(
2548 : OSRGetProjTLSContext(), "EPSG", "EPSG", datumCode,
2549 : "geographic 2D");
2550 0 : if (crsList && proj_list_get_count(crsList) != 0)
2551 : {
2552 0 : auto crs = proj_list_get(OSRGetProjTLSContext(),
2553 : crsList, 0);
2554 0 : if (crs)
2555 : {
2556 0 : const char *crsCode = proj_get_id_code(crs, 0);
2557 0 : if (crsCode)
2558 : {
2559 0 : nEPSG = atoi(crsCode);
2560 : }
2561 0 : proj_destroy(crs);
2562 : }
2563 : }
2564 0 : proj_list_destroy(crsList);
2565 : }
2566 0 : proj_destroy(datum);
2567 : }
2568 : }
2569 0 : proj_list_destroy(datumList);
2570 : }
2571 :
2572 : // ----------------------------------------------------------------------
2573 : // Match GCS's COORD_REF_SYS_NAME by using 'ApproxString' over Datum
2574 : // ----------------------------------------------------------------------
2575 :
2576 0 : if (nEPSG == 0)
2577 : {
2578 0 : const PJ_TYPE nObjType = PJ_TYPE_GEOGRAPHIC_2D_CRS;
2579 : auto crsList =
2580 0 : proj_create_from_name(OSRGetProjTLSContext(), "EPSG", pszDatum,
2581 : &nObjType, 1, true, 1, nullptr);
2582 0 : if (crsList && proj_list_get_count(crsList) != 0)
2583 : {
2584 0 : auto crs = proj_list_get(OSRGetProjTLSContext(), crsList, 0);
2585 0 : if (crs)
2586 : {
2587 0 : const char *crsCode = proj_get_id_code(crs, 0);
2588 0 : if (crsCode)
2589 : {
2590 0 : nEPSG = atoi(crsCode);
2591 : }
2592 0 : proj_destroy(crs);
2593 : }
2594 : }
2595 0 : proj_list_destroy(crsList);
2596 : }
2597 :
2598 0 : if (nEPSG != 0)
2599 : {
2600 0 : oSRS.importFromEPSG(nEPSG);
2601 : }
2602 : else
2603 : {
2604 : // --------------------------------------------------
2605 : // Create GeogCS based on the georeference file info
2606 : // --------------------------------------------------
2607 :
2608 0 : oSRS.SetGeogCS(pszRefSystem, pszDatum, pszEllipsoid, dfSemiMajor,
2609 : (dfSemiMinor == dfSemiMajor)
2610 : ? 0.0
2611 0 : : (-1.0 / (dfSemiMinor / dfSemiMajor - 1.0)));
2612 : }
2613 :
2614 : // ----------------------------------------------------------------------
2615 : // Note: That will override EPSG info:
2616 : // ----------------------------------------------------------------------
2617 :
2618 0 : oSRS.SetTOWGS84(adfToWGS84[0], adfToWGS84[1], adfToWGS84[2]);
2619 : }
2620 :
2621 : // ----------------------------------------------------------------------
2622 : // If the georeference file tells that it is a non project system:
2623 : // ----------------------------------------------------------------------
2624 :
2625 0 : if (EQUAL(pszProjName, "none"))
2626 : {
2627 0 : CPLFree(pszGeorefName);
2628 0 : CPLFree(pszProjName);
2629 0 : CPLFree(pszDatum);
2630 0 : CPLFree(pszEllipsoid);
2631 :
2632 0 : return CE_None;
2633 : }
2634 :
2635 : // ----------------------------------------------------------------------
2636 : // Create Projection information based on georeference file info
2637 : // ----------------------------------------------------------------------
2638 :
2639 : // Idrisi user's Manual, Supported Projection:
2640 : //
2641 : // Mercator
2642 : // Transverse Mercator
2643 : // Gauss-Kruger
2644 : // Lambert Conformal Conic
2645 : // Plate Carree
2646 : // Hammer Aitoff
2647 : // Lambert North Polar Azimuthal Equal Area
2648 : // Lambert South Polar Azimuthal Equal Area
2649 : // Lambert Transverse Azimuthal Equal Area
2650 : // Lambert Oblique Polar Azimuthal Equal Area
2651 : // North Polar Stereographic
2652 : // South Polar Stereographic
2653 : // Transverse Stereographic
2654 : // Oblique Stereographic
2655 : // Albers Equal Area Conic
2656 : // Sinusoidal
2657 : // Cylindrical Equal Area
2658 :
2659 0 : if (EQUAL(pszProjName, "Mercator"))
2660 : {
2661 0 : oSRS.SetMercator(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2662 : dfFalseNorthing);
2663 : }
2664 0 : else if (EQUAL(pszProjName, "Transverse Mercator"))
2665 : {
2666 0 : oSRS.SetTM(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2667 : dfFalseNorthing);
2668 : }
2669 0 : else if (EQUAL(pszProjName, "Gauss-Kruger"))
2670 : {
2671 0 : oSRS.SetTM(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2672 : dfFalseNorthing);
2673 : }
2674 0 : else if (EQUAL(pszProjName, "Lambert Conformal Conic"))
2675 : {
2676 0 : oSRS.SetLCC(dfStdP1, dfStdP2, dfCenterLat, dfCenterLong, dfFalseEasting,
2677 : dfFalseNorthing);
2678 : }
2679 0 : else if (EQUAL(pszProjName, "Plate Carr"
2680 : "\xE9"
2681 : "e")) /* 'eacute' in ISO-8859-1 */
2682 : {
2683 0 : oSRS.SetEquirectangular(dfCenterLat, dfCenterLong, dfFalseEasting,
2684 : dfFalseNorthing);
2685 : }
2686 0 : else if (EQUAL(pszProjName, "Hammer Aitoff"))
2687 : {
2688 0 : oSRS.SetProjection(pszProjName);
2689 0 : oSRS.SetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, dfCenterLat);
2690 0 : oSRS.SetProjParm(SRS_PP_CENTRAL_MERIDIAN, dfCenterLong);
2691 0 : oSRS.SetProjParm(SRS_PP_FALSE_EASTING, dfFalseEasting);
2692 0 : oSRS.SetProjParm(SRS_PP_FALSE_NORTHING, dfFalseNorthing);
2693 : }
2694 0 : else if (EQUAL(pszProjName, "Lambert North Polar Azimuthal Equal Area") ||
2695 0 : EQUAL(pszProjName, "Lambert South Polar Azimuthal Equal Area") ||
2696 0 : EQUAL(pszProjName, "Lambert Transverse Azimuthal Equal Area") ||
2697 0 : EQUAL(pszProjName, "Lambert Oblique Polar Azimuthal Equal Area"))
2698 : {
2699 0 : oSRS.SetLAEA(dfCenterLat, dfCenterLong, dfFalseEasting,
2700 : dfFalseNorthing);
2701 : }
2702 0 : else if (EQUAL(pszProjName, "North Polar Stereographic") ||
2703 0 : EQUAL(pszProjName, "South Polar Stereographic"))
2704 : {
2705 0 : oSRS.SetPS(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2706 : dfFalseNorthing);
2707 : }
2708 0 : else if (EQUAL(pszProjName, "Transverse Stereographic"))
2709 : {
2710 0 : oSRS.SetStereographic(dfCenterLat, dfCenterLong, dfScale,
2711 : dfFalseEasting, dfFalseNorthing);
2712 : }
2713 0 : else if (EQUAL(pszProjName, "Oblique Stereographic"))
2714 : {
2715 0 : oSRS.SetOS(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2716 : dfFalseNorthing);
2717 : }
2718 0 : else if (EQUAL(pszProjName, "Alber's Equal Area Conic") ||
2719 0 : EQUAL(pszProjName, "Albers Equal Area Conic"))
2720 : {
2721 0 : oSRS.SetACEA(dfStdP1, dfStdP2, dfCenterLat, dfCenterLong,
2722 : dfFalseEasting, dfFalseNorthing);
2723 : }
2724 0 : else if (EQUAL(pszProjName, "Sinusoidal"))
2725 : {
2726 0 : oSRS.SetSinusoidal(dfCenterLong, dfFalseEasting, dfFalseNorthing);
2727 : }
2728 0 : else if (EQUAL(pszProjName, "CylindricalEA") ||
2729 0 : EQUAL(pszProjName, "Cylindrical Equal Area"))
2730 : {
2731 0 : oSRS.SetCEA(dfStdP1, dfCenterLong, dfFalseEasting, dfFalseNorthing);
2732 : }
2733 : else
2734 : {
2735 0 : CPLError(
2736 : CE_Warning, CPLE_NotSupported,
2737 : "Projection not listed on Idrisi User's Manual( v.15.0/2005 ).\n\t"
2738 : "[\"%s\" in georeference file \"%s\"]",
2739 : pszProjName, pszFName);
2740 0 : oSRS.Clear();
2741 :
2742 0 : CPLFree(pszGeorefName);
2743 0 : CPLFree(pszProjName);
2744 0 : CPLFree(pszDatum);
2745 0 : CPLFree(pszEllipsoid);
2746 :
2747 0 : return CE_Warning;
2748 : }
2749 :
2750 : // ----------------------------------------------------------------------
2751 : // Set the Linear Units
2752 : // ----------------------------------------------------------------------
2753 :
2754 0 : int nUnit = GetUnitIndex(pszRefUnits);
2755 0 : if (nUnit > -1)
2756 : {
2757 0 : int nDeft = aoLinearUnitsConv[nUnit].nDefaultG;
2758 0 : oSRS.SetLinearUnits(aoLinearUnitsConv[nDeft].pszName,
2759 0 : aoLinearUnitsConv[nDeft].dfConv);
2760 : }
2761 : else
2762 : {
2763 0 : oSRS.SetLinearUnits("unknown", 1.0);
2764 : }
2765 :
2766 : // ----------------------------------------------------------------------
2767 : // Name ProjCS with the name on the georeference file
2768 : // ----------------------------------------------------------------------
2769 :
2770 0 : oSRS.SetProjCS(pszGeorefName);
2771 :
2772 0 : CPLFree(pszGeorefName);
2773 0 : CPLFree(pszProjName);
2774 0 : CPLFree(pszDatum);
2775 0 : CPLFree(pszEllipsoid);
2776 :
2777 0 : return CE_None;
2778 : }
2779 :
2780 : /************************************************************************/
2781 : /* Wkt2GeoReference() */
2782 : /************************************************************************/
2783 :
2784 : /***
2785 : * Converts OpenGIS WKT to Idrisi geographic reference information.
2786 : *
2787 : * That function will fill up the two parameters RefSystem and RefUnit
2788 : * that goes into the Idrisi metadata. But it could also create
2789 : * a accompanying georeference file to the output if necessary.
2790 : *
2791 : * First it will try to identify the ProjString as Local, WGS84 or
2792 : * one of the Idrisi name convention reference systems
2793 : * otherwise, if the projection system is supported by Idrisi,
2794 : * it will create a accompanying georeference files.
2795 : ***/
2796 :
2797 13 : CPLErr IdrisiDataset::Wkt2GeoReference(const OGRSpatialReference &oSRS,
2798 : char **pszRefSystem, char **pszRefUnit)
2799 : {
2800 : // -----------------------------------------------------
2801 : // Plane with default "Meters"
2802 : // -----------------------------------------------------
2803 :
2804 13 : if (oSRS.IsEmpty())
2805 : {
2806 0 : *pszRefSystem = CPLStrdup(rstPLANE);
2807 0 : *pszRefUnit = CPLStrdup(rstMETER);
2808 0 : return CE_None;
2809 : }
2810 :
2811 : // -----------------------------------------------------
2812 : // Local => Plane + Linear Unit
2813 : // -----------------------------------------------------
2814 :
2815 13 : if (oSRS.IsLocal())
2816 : {
2817 0 : *pszRefSystem = CPLStrdup(rstPLANE);
2818 0 : *pszRefUnit = GetUnitDefault(oSRS.GetAttrValue("UNIT"),
2819 : CPLSPrintf("%f", oSRS.GetLinearUnits()));
2820 0 : return CE_None;
2821 : }
2822 :
2823 : // -----------------------------------------------------
2824 : // Test to identify WGS84 => Latlong + Angular Unit
2825 : // -----------------------------------------------------
2826 :
2827 13 : if (oSRS.IsGeographic())
2828 : {
2829 13 : char *pszSpheroid = CPLStrdup(oSRS.GetAttrValue("SPHEROID"));
2830 13 : char *pszAuthName = CPLStrdup(oSRS.GetAuthorityName("GEOGCS"));
2831 13 : char *pszDatum = CPLStrdup(oSRS.GetAttrValue("DATUM"));
2832 13 : int nGCSCode = -1;
2833 13 : if (EQUAL(pszAuthName, "EPSG"))
2834 : {
2835 1 : nGCSCode = atoi(oSRS.GetAuthorityCode("GEOGCS"));
2836 : }
2837 13 : if ((nGCSCode == 4326) ||
2838 12 : ((STARTS_WITH_CI(pszSpheroid, "WGS")) &&
2839 12 : (strstr(pszSpheroid, "84")) && (STARTS_WITH_CI(pszDatum, "WGS")) &&
2840 12 : (strstr(pszDatum, "84"))))
2841 : {
2842 13 : *pszRefSystem = CPLStrdup(rstLATLONG);
2843 13 : *pszRefUnit = CPLStrdup(rstDEGREE);
2844 :
2845 13 : CPLFree(pszSpheroid);
2846 13 : CPLFree(pszAuthName);
2847 13 : CPLFree(pszDatum);
2848 :
2849 13 : return CE_None;
2850 : }
2851 :
2852 0 : CPLFree(pszSpheroid);
2853 0 : CPLFree(pszAuthName);
2854 0 : CPLFree(pszDatum);
2855 : }
2856 :
2857 : // -----------------------------------------------------
2858 : // Prepare to match some projections
2859 : // -----------------------------------------------------
2860 :
2861 0 : const char *pszProjName = oSRS.GetAttrValue("PROJECTION");
2862 :
2863 0 : if (pszProjName == nullptr)
2864 : {
2865 0 : pszProjName = "";
2866 : }
2867 :
2868 : // -----------------------------------------------------
2869 : // Check for UTM zones
2870 : // -----------------------------------------------------
2871 :
2872 0 : if (EQUAL(pszProjName, SRS_PT_TRANSVERSE_MERCATOR))
2873 : {
2874 0 : int nZone = oSRS.GetUTMZone();
2875 :
2876 0 : if ((nZone != 0) && (EQUAL(oSRS.GetAttrValue("DATUM"), SRS_DN_WGS84)))
2877 : {
2878 0 : double dfNorth = oSRS.GetProjParm(SRS_PP_FALSE_NORTHING);
2879 0 : *pszRefSystem = CPLStrdup(
2880 : CPLSPrintf(rstUTM, nZone, (dfNorth == 0.0 ? 'n' : 's')));
2881 0 : *pszRefUnit = CPLStrdup(rstMETER);
2882 0 : return CE_None;
2883 : }
2884 : }
2885 :
2886 : // -----------------------------------------------------
2887 : // Check for State Plane
2888 : // -----------------------------------------------------
2889 :
2890 0 : if (EQUAL(pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP) ||
2891 0 : EQUAL(pszProjName, SRS_PT_TRANSVERSE_MERCATOR))
2892 : {
2893 0 : CPLString osPCSCode;
2894 0 : const char *pszID = oSRS.GetAuthorityCode("PROJCS");
2895 0 : if (pszID != nullptr && strlen(pszID) > 0)
2896 : {
2897 : const char *pszPCSCode =
2898 0 : CSVGetField(CSVFilename("stateplane.csv"), "EPSG_PCS_CODE",
2899 : pszID, CC_Integer, "ID");
2900 0 : osPCSCode = (pszPCSCode) ? pszPCSCode : "";
2901 0 : if (!osPCSCode.empty())
2902 : {
2903 0 : int nZone = osPCSCode.back() - '0';
2904 0 : int nSPCode = atoi(osPCSCode);
2905 :
2906 0 : if (nZone == 0)
2907 0 : nZone = 1;
2908 : else
2909 0 : nSPCode = nSPCode - nZone + 1;
2910 :
2911 0 : int nNADYear = 83;
2912 0 : if (nSPCode > 10000)
2913 : {
2914 0 : nNADYear = 27;
2915 0 : nSPCode -= 10000;
2916 : }
2917 0 : char *pszState = CPLStrdup(GetStateName(nSPCode));
2918 0 : if (!EQUAL(pszState, ""))
2919 : {
2920 0 : *pszRefSystem = CPLStrdup(
2921 : CPLSPrintf(rstSPC, nNADYear, pszState, nZone));
2922 0 : *pszRefUnit =
2923 0 : GetUnitDefault(oSRS.GetAttrValue("UNIT"),
2924 : CPLSPrintf("%f", oSRS.GetLinearUnits()));
2925 0 : CPLFree(pszState);
2926 0 : return CE_None;
2927 : }
2928 0 : CPLFree(pszState);
2929 : }
2930 : } //
2931 :
2932 : // if EPSG code is missing, go to following steps to work with origin
2933 :
2934 0 : const char *pszNAD83 = "83";
2935 0 : const char *pszNAD27 = "27";
2936 0 : bool bIsOldNAD = false;
2937 :
2938 0 : const char *pszDatumValue = oSRS.GetAttrValue("DATUM", 0);
2939 0 : if ((strstr(pszDatumValue, pszNAD83) == nullptr) &&
2940 0 : (strstr(pszDatumValue, pszNAD27) != nullptr))
2941 : // strcpy(pszNAD, "27");
2942 0 : bIsOldNAD = true;
2943 :
2944 0 : if ((oSRS.FindProjParm("central_meridian", nullptr) != -1) &&
2945 0 : (oSRS.FindProjParm("latitude_of_origin", nullptr) != -1))
2946 : {
2947 0 : double dfLon = oSRS.GetProjParm("central_meridian");
2948 0 : double dfLat = oSRS.GetProjParm("latitude_of_origin");
2949 0 : dfLon = (int)(fabs(dfLon) * 100 + 0.5) / 100.0;
2950 0 : dfLat = (int)(fabs(dfLat) * 100 + 0.5) / 100.0;
2951 0 : *pszRefSystem = CPLStrdup(GetSpcs(dfLon, dfLat));
2952 : }
2953 :
2954 0 : if (*pszRefSystem != nullptr)
2955 : {
2956 : // Convert 83 TO 27
2957 0 : if (bIsOldNAD)
2958 : {
2959 : char pszOutRefSystem[9];
2960 0 : NAD83to27(pszOutRefSystem, *pszRefSystem);
2961 0 : *pszRefSystem = CPLStrdup(pszOutRefSystem);
2962 : }
2963 0 : *pszRefUnit =
2964 0 : GetUnitDefault(oSRS.GetAttrValue("UNIT"),
2965 : CPLSPrintf("%f", oSRS.GetLinearUnits()));
2966 0 : return CE_None;
2967 : }
2968 : }
2969 :
2970 0 : const char *pszProjectionOut = nullptr;
2971 :
2972 0 : if (oSRS.IsProjected())
2973 : {
2974 : // ---------------------------------------------------------
2975 : // Check for supported projections
2976 : // ---------------------------------------------------------
2977 :
2978 0 : if (EQUAL(pszProjName, SRS_PT_MERCATOR_1SP))
2979 : {
2980 0 : pszProjectionOut = "Mercator";
2981 : }
2982 0 : else if (EQUAL(pszProjName, SRS_PT_TRANSVERSE_MERCATOR))
2983 : {
2984 0 : pszProjectionOut = "Transverse Mercator";
2985 : }
2986 0 : else if (EQUAL(pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP))
2987 : {
2988 0 : pszProjectionOut = "Lambert Conformal Conic";
2989 : }
2990 0 : else if (EQUAL(pszProjName, SRS_PT_EQUIRECTANGULAR))
2991 : {
2992 0 : pszProjectionOut = "Plate Carr"
2993 : "\xE9"
2994 : "e"; /* 'eacute' in ISO-8859-1 */
2995 : }
2996 0 : else if (EQUAL(pszProjName, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA))
2997 : {
2998 : double dfCenterLat =
2999 0 : oSRS.GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0, nullptr);
3000 0 : if (dfCenterLat == 0.0)
3001 0 : pszProjectionOut = "Lambert Transverse Azimuthal Equal Area";
3002 0 : else if (fabs(dfCenterLat) == 90.0)
3003 0 : pszProjectionOut = "Lambert Oblique Polar Azimuthal Equal Area";
3004 0 : else if (dfCenterLat > 0.0)
3005 0 : pszProjectionOut = "Lambert North Oblique Azimuthal Equal Area";
3006 : else
3007 0 : pszProjectionOut = "Lambert South Oblique Azimuthal Equal Area";
3008 : }
3009 0 : else if (EQUAL(pszProjName, SRS_PT_POLAR_STEREOGRAPHIC))
3010 : {
3011 0 : if (oSRS.GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0, nullptr) > 0)
3012 0 : pszProjectionOut = "North Polar Stereographic";
3013 : else
3014 0 : pszProjectionOut = "South Polar Stereographic";
3015 : }
3016 0 : else if (EQUAL(pszProjName, SRS_PT_STEREOGRAPHIC))
3017 : {
3018 0 : pszProjectionOut = "Transverse Stereographic";
3019 : }
3020 0 : else if (EQUAL(pszProjName, SRS_PT_OBLIQUE_STEREOGRAPHIC))
3021 : {
3022 0 : pszProjectionOut = "Oblique Stereographic";
3023 : }
3024 0 : else if (EQUAL(pszProjName, SRS_PT_SINUSOIDAL))
3025 : {
3026 0 : pszProjectionOut = "Sinusoidal";
3027 : }
3028 0 : else if (EQUAL(pszProjName, SRS_PT_ALBERS_CONIC_EQUAL_AREA))
3029 : {
3030 0 : pszProjectionOut = "Alber's Equal Area Conic";
3031 : }
3032 0 : else if (EQUAL(pszProjName, SRS_PT_CYLINDRICAL_EQUAL_AREA))
3033 : {
3034 0 : pszProjectionOut = "Cylindrical Equal Area";
3035 : }
3036 :
3037 : // ---------------------------------------------------------
3038 : // Failure, Projection system not supported
3039 : // ---------------------------------------------------------
3040 :
3041 0 : if (pszProjectionOut == nullptr)
3042 : {
3043 0 : CPLDebug("RST", "Not supported by RST driver: PROJECTION[\"%s\"]",
3044 : pszProjName);
3045 :
3046 0 : *pszRefSystem = CPLStrdup(rstPLANE);
3047 0 : *pszRefUnit = CPLStrdup(rstMETER);
3048 0 : return CE_Failure;
3049 : }
3050 : }
3051 : else
3052 : {
3053 0 : pszProjectionOut = "none";
3054 : }
3055 :
3056 : // ---------------------------------------------------------
3057 : // Prepare to write ref file
3058 : // ---------------------------------------------------------
3059 :
3060 0 : char *pszGeorefName = CPLStrdup("Unknown");
3061 0 : char *pszDatum = CPLStrdup(oSRS.GetAttrValue("DATUM"));
3062 0 : char *pszEllipsoid = CPLStrdup(oSRS.GetAttrValue("SPHEROID"));
3063 0 : double dfSemiMajor = oSRS.GetSemiMajor();
3064 0 : double dfSemiMinor = oSRS.GetSemiMinor();
3065 : double adfToWGS84[3];
3066 0 : oSRS.GetTOWGS84(adfToWGS84, 3);
3067 :
3068 0 : double dfCenterLat = 0.0;
3069 0 : double dfCenterLong = 0.0;
3070 0 : double dfFalseNorthing = 0.0;
3071 0 : double dfFalseEasting = 0.0;
3072 0 : double dfScale = 1.0;
3073 0 : int nParameters = 0;
3074 0 : double dfStdP1 = 0.0;
3075 0 : double dfStdP2 = 0.0;
3076 0 : char *pszAngularUnit = CPLStrdup(oSRS.GetAttrValue("GEOGCS|UNIT"));
3077 0 : char *pszLinearUnit = nullptr;
3078 :
3079 0 : if (oSRS.IsProjected())
3080 : {
3081 0 : CPLFree(pszGeorefName);
3082 0 : pszGeorefName = CPLStrdup(oSRS.GetAttrValue("PROJCS"));
3083 0 : dfCenterLat = oSRS.GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0, nullptr);
3084 0 : dfCenterLong = oSRS.GetProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0, nullptr);
3085 0 : dfFalseNorthing = oSRS.GetProjParm(SRS_PP_FALSE_NORTHING, 0.0, nullptr);
3086 0 : dfFalseEasting = oSRS.GetProjParm(SRS_PP_FALSE_EASTING, 0.0, nullptr);
3087 0 : dfScale = oSRS.GetProjParm(SRS_PP_SCALE_FACTOR, 0.0, nullptr);
3088 0 : dfStdP1 = oSRS.GetProjParm(SRS_PP_STANDARD_PARALLEL_1, -0.1, nullptr);
3089 0 : if (EQUAL(pszProjectionOut, "Cylindrical Equal Area"))
3090 : {
3091 0 : dfStdP2 = -dfStdP1;
3092 0 : dfScale = 1.0;
3093 : }
3094 : else
3095 : {
3096 : dfStdP2 =
3097 0 : oSRS.GetProjParm(SRS_PP_STANDARD_PARALLEL_2, -0.1, nullptr);
3098 : }
3099 0 : if (dfStdP1 != -0.1)
3100 : {
3101 0 : nParameters = 1;
3102 0 : if (dfStdP2 != -0.1)
3103 0 : nParameters = 2;
3104 : }
3105 0 : pszLinearUnit = GetUnitDefault(oSRS.GetAttrValue("PROJCS|UNIT"),
3106 : CPLSPrintf("%f", oSRS.GetLinearUnits()));
3107 : }
3108 : else
3109 : {
3110 0 : pszLinearUnit = GetUnitDefault(pszAngularUnit);
3111 : }
3112 :
3113 : // ---------------------------------------------------------
3114 : // Create a companion georeference file for this dataset
3115 : // ---------------------------------------------------------
3116 :
3117 0 : char **papszRef = nullptr;
3118 0 : papszRef = CSLAddNameValue(papszRef, refREF_SYSTEM, pszGeorefName);
3119 0 : papszRef = CSLAddNameValue(papszRef, refPROJECTION, pszProjectionOut);
3120 0 : papszRef = CSLAddNameValue(papszRef, refDATUM, pszDatum);
3121 0 : papszRef = CSLAddNameValue(papszRef, refDELTA_WGS84,
3122 : CPLSPrintf("%.3g %.3g %.3g", adfToWGS84[0],
3123 : adfToWGS84[1], adfToWGS84[2]));
3124 0 : papszRef = CSLAddNameValue(papszRef, refELLIPSOID, pszEllipsoid);
3125 0 : papszRef = CSLAddNameValue(papszRef, refMAJOR_SAX,
3126 : CPLSPrintf("%.3f", dfSemiMajor));
3127 0 : papszRef = CSLAddNameValue(papszRef, refMINOR_SAX,
3128 : CPLSPrintf("%.3f", dfSemiMinor));
3129 0 : papszRef = CSLAddNameValue(papszRef, refORIGIN_LONG,
3130 : CPLSPrintf("%.9g", dfCenterLong));
3131 0 : papszRef = CSLAddNameValue(papszRef, refORIGIN_LAT,
3132 : CPLSPrintf("%.9g", dfCenterLat));
3133 0 : papszRef = CSLAddNameValue(papszRef, refORIGIN_X,
3134 : CPLSPrintf("%.9g", dfFalseEasting));
3135 0 : papszRef = CSLAddNameValue(papszRef, refORIGIN_Y,
3136 : CPLSPrintf("%.9g", dfFalseNorthing));
3137 : papszRef =
3138 0 : CSLAddNameValue(papszRef, refSCALE_FAC, CPLSPrintf("%.9g", dfScale));
3139 0 : papszRef = CSLAddNameValue(papszRef, refUNITS, pszLinearUnit);
3140 0 : papszRef = CSLAddNameValue(papszRef, refPARAMETERS,
3141 : CPLSPrintf("%1d", nParameters));
3142 0 : if (nParameters > 0)
3143 : papszRef =
3144 0 : CSLAddNameValue(papszRef, refSTANDL_1, CPLSPrintf("%.9g", dfStdP1));
3145 0 : if (nParameters > 1)
3146 : papszRef =
3147 0 : CSLAddNameValue(papszRef, refSTANDL_2, CPLSPrintf("%.9g", dfStdP2));
3148 0 : myCSLSetNameValueSeparator(papszRef, ": ");
3149 0 : SaveAsCRLF(papszRef, CPLResetExtension(pszFilename, extREF));
3150 0 : CSLDestroy(papszRef);
3151 :
3152 0 : *pszRefSystem = CPLStrdup(CPLGetBasename(pszFilename));
3153 0 : *pszRefUnit = CPLStrdup(pszLinearUnit);
3154 :
3155 0 : CPLFree(pszGeorefName);
3156 0 : CPLFree(pszDatum);
3157 0 : CPLFree(pszEllipsoid);
3158 0 : CPLFree(pszLinearUnit);
3159 0 : CPLFree(pszAngularUnit);
3160 :
3161 0 : return CE_None;
3162 : }
3163 :
3164 : /************************************************************************/
3165 : /* FileExists() */
3166 : /************************************************************************/
3167 :
3168 60 : bool FileExists(const char *pszPath)
3169 : {
3170 : VSIStatBufL sStat;
3171 :
3172 60 : return VSIStatL(pszPath, &sStat) == 0;
3173 : }
3174 :
3175 : /************************************************************************/
3176 : /* GetStateCode() */
3177 : /************************************************************************/
3178 :
3179 0 : int GetStateCode(const char *pszState)
3180 : {
3181 0 : for (unsigned int i = 0; i < US_STATE_COUNT; i++)
3182 : {
3183 0 : if (EQUAL(pszState, aoUSStateTable[i].pszName))
3184 : {
3185 0 : return aoUSStateTable[i].nCode;
3186 : }
3187 : }
3188 0 : return -1;
3189 : }
3190 :
3191 : /************************************************************************/
3192 : /* GetStateName() */
3193 : /************************************************************************/
3194 :
3195 0 : const char *GetStateName(int nCode)
3196 : {
3197 0 : for (unsigned int i = 0; i < US_STATE_COUNT; i++)
3198 : {
3199 0 : if (nCode == aoUSStateTable[i].nCode)
3200 : {
3201 0 : return aoUSStateTable[i].pszName;
3202 : }
3203 : }
3204 0 : return nullptr;
3205 : }
3206 :
3207 : /************************************************************************/
3208 : /* GetSpcs() */
3209 : /************************************************************************/
3210 :
3211 0 : char *GetSpcs(double dfLon, double dfLat)
3212 : {
3213 0 : for (int i = 0; i < ORIGIN_COUNT; i++)
3214 : {
3215 0 : if ((dfLon == SPCS83Origin[i].longitude) &&
3216 0 : (dfLat == SPCS83Origin[i].latitude))
3217 : {
3218 0 : return (char *)SPCS83Origin[i].spcs;
3219 : }
3220 : }
3221 0 : return nullptr;
3222 : }
3223 :
3224 : /************************************************************************/
3225 : /* NAD83to27() */
3226 : /************************************************************************/
3227 0 : void NAD83to27(char *pszOutRef, char *pszInRef)
3228 : {
3229 0 : char *pOutput = pszOutRef;
3230 0 : char *pInput = pszInRef;
3231 0 : strncpy(pOutput, pInput, 3);
3232 :
3233 0 : pOutput = pOutput + 3;
3234 0 : pInput = pInput + 3;
3235 :
3236 0 : memcpy(pOutput, "27", 2);
3237 0 : pOutput = pOutput + 2;
3238 0 : pInput = pInput + 2;
3239 0 : strcpy(pOutput, pInput);
3240 0 : }
3241 :
3242 : /************************************************************************/
3243 : /* GetUnitIndex() */
3244 : /************************************************************************/
3245 :
3246 0 : int GetUnitIndex(const char *pszUnitName)
3247 : {
3248 0 : for (int i = 0; i < (int)LINEAR_UNITS_COUNT; i++)
3249 : {
3250 0 : if (EQUAL(pszUnitName, aoLinearUnitsConv[i].pszName))
3251 : {
3252 0 : return i;
3253 : }
3254 : }
3255 0 : return -1;
3256 : }
3257 :
3258 : /************************************************************************/
3259 : /* GetToMeterIndex() */
3260 : /************************************************************************/
3261 :
3262 0 : int GetToMeterIndex(const char *pszToMeter)
3263 : {
3264 0 : const double dfToMeter = CPLAtof_nz(pszToMeter);
3265 :
3266 0 : if (dfToMeter != 0.0)
3267 : {
3268 0 : for (int i = 0; i < (int)LINEAR_UNITS_COUNT; i++)
3269 : {
3270 0 : if (std::abs(aoLinearUnitsConv[i].dfConv - dfToMeter) < 0.00001)
3271 : {
3272 0 : return i;
3273 : }
3274 : }
3275 : }
3276 :
3277 0 : return -1;
3278 : }
3279 :
3280 : /************************************************************************/
3281 : /* GetUnitDefault() */
3282 : /************************************************************************/
3283 :
3284 0 : char *GetUnitDefault(const char *pszUnitName, const char *pszToMeter)
3285 : {
3286 0 : int nIndex = GetUnitIndex(pszUnitName);
3287 :
3288 0 : if (nIndex == -1 && pszToMeter != nullptr)
3289 : {
3290 0 : nIndex = GetToMeterIndex(pszToMeter);
3291 : }
3292 :
3293 0 : if (nIndex == -1)
3294 : {
3295 0 : return CPLStrdup("Unknown");
3296 : }
3297 :
3298 0 : return CPLStrdup(
3299 0 : aoLinearUnitsConv[aoLinearUnitsConv[nIndex].nDefaultI].pszName);
3300 : }
3301 :
3302 : /************************************************************************/
3303 : /* CSLSaveCRLF() */
3304 : /************************************************************************/
3305 :
3306 : /***
3307 : * Write a stringlist to a CR + LF terminated text file.
3308 : *
3309 : * Returns the number of lines written, or 0 if the file could not
3310 : * be written.
3311 : */
3312 :
3313 46 : int SaveAsCRLF(char **papszStrList, const char *pszFname)
3314 : {
3315 46 : VSILFILE *fp = VSIFOpenL(pszFname, "wt");
3316 46 : int nLines = 0;
3317 :
3318 46 : if (papszStrList)
3319 : {
3320 46 : if (fp != nullptr)
3321 : {
3322 800 : while (*papszStrList != nullptr)
3323 : {
3324 766 : if (VSIFPrintfL(fp, "%s\r\n", *papszStrList) < 1)
3325 : {
3326 10 : CPLError(CE_Failure, CPLE_FileIO,
3327 : "CSLSaveCRLF(\"%s\") failed: unable to write to "
3328 : "output file.",
3329 : pszFname);
3330 10 : break;
3331 : }
3332 :
3333 756 : nLines++;
3334 756 : papszStrList++;
3335 : }
3336 :
3337 44 : VSIFCloseL(fp);
3338 : }
3339 : else
3340 : {
3341 2 : CPLError(CE_Failure, CPLE_OpenFailed,
3342 : "CSLSaveCRLF(\"%s\") failed: unable to open output file.",
3343 : pszFname);
3344 : }
3345 : }
3346 :
3347 46 : return nLines;
3348 : }
3349 :
3350 : /************************************************************************/
3351 : /* GDALRegister_IDRISI() */
3352 : /************************************************************************/
3353 :
3354 1520 : void GDALRegister_IDRISI()
3355 : {
3356 1520 : if (GDALGetDriverByName("RST") != nullptr)
3357 301 : return;
3358 :
3359 1219 : GDALDriver *poDriver = new GDALDriver();
3360 :
3361 1219 : poDriver->SetDescription("RST");
3362 1219 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
3363 1219 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, rstVERSION);
3364 1219 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/Idrisi.html");
3365 1219 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, extRST);
3366 1219 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte Int16 Float32");
3367 :
3368 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
3369 :
3370 1219 : poDriver->pfnOpen = IdrisiDataset::Open;
3371 1219 : poDriver->pfnCreate = IdrisiDataset::Create;
3372 1219 : poDriver->pfnCreateCopy = IdrisiDataset::CreateCopy;
3373 :
3374 1219 : GetGDALDriverManager()->RegisterDriver(poDriver);
3375 : }
|