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