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