/src/gdal/frmts/raw/ace2dataset.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: ACE2 Driver |
4 | | * Purpose: Implementation of ACE2 elevation format read support. |
5 | | * http://tethys.eaprs.cse.dmu.ac.uk/ACE2/shared/documentation |
6 | | * Author: Even Rouault, <even dot rouault at spatialys.com> |
7 | | * |
8 | | ****************************************************************************** |
9 | | * Copyright (c) 2011-2012, Even Rouault <even dot rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "gdal_frmts.h" |
15 | | #include "ogr_spatialref.h" |
16 | | #include "rawdataset.h" |
17 | | |
18 | | static const char *const apszCategorySource[] = { |
19 | | "Pure SRTM (above 60deg N pure GLOBE data, below 60S pure ACE [original] " |
20 | | "data)", |
21 | | "SRTM voids filled by interpolation and/or altimeter data", |
22 | | "SRTM data warped using the ERS-1 Geodetic Mission", |
23 | | "SRTM data warped using EnviSat & ERS-2 data", |
24 | | "Mean lake level data derived from Altimetry", |
25 | | "GLOBE/ACE data warped using combined altimetry (only above 60deg N)", |
26 | | "Pure altimetry data (derived from ERS-1 Geodetic Mission, ERS-2 and " |
27 | | "EnviSat data using Delaunay Triangulation", |
28 | | nullptr}; |
29 | | |
30 | | static const char *const apszCategoryQuality[] = { |
31 | | "Generic - use base datasets", |
32 | | "Accuracy of greater than +/- 16m", |
33 | | "Accuracy between +/- 16m - +/- 10m", |
34 | | "Accuracy between +/-10m - +/-5m", |
35 | | "Accuracy between +/-5m - +/-1m", |
36 | | "Accuracy between +/-1m", |
37 | | nullptr}; |
38 | | |
39 | | static const char *const apszCategoryConfidence[] = { |
40 | | "No confidence could be derived due to lack of data", |
41 | | "Heights generated by interpolation", |
42 | | "Low confidence", |
43 | | "Low confidence", |
44 | | "Low confidence", |
45 | | "Medium confidence", |
46 | | "Medium confidence", |
47 | | "Medium confidence", |
48 | | "Medium confidence", |
49 | | "Medium confidence", |
50 | | "Medium confidence", |
51 | | "Medium confidence", |
52 | | "Medium confidence", |
53 | | "High confidence", |
54 | | "High confidence", |
55 | | "High confidence", |
56 | | "High confidence", |
57 | | "Inland water confidence", |
58 | | "Inland water confidence", |
59 | | "Inland water confidence", |
60 | | "Inland water confidence", |
61 | | "Inland water confidence", |
62 | | nullptr}; |
63 | | |
64 | | /************************************************************************/ |
65 | | /* ==================================================================== */ |
66 | | /* ACE2Dataset */ |
67 | | /* ==================================================================== */ |
68 | | /************************************************************************/ |
69 | | |
70 | | class ACE2Dataset final : public GDALPamDataset |
71 | | { |
72 | | friend class ACE2RasterBand; |
73 | | |
74 | | OGRSpatialReference m_oSRS{}; |
75 | | GDALGeoTransform m_gt{}; |
76 | | |
77 | | public: |
78 | | ACE2Dataset(); |
79 | | |
80 | | const OGRSpatialReference *GetSpatialRef() const override |
81 | 0 | { |
82 | 0 | return &m_oSRS; |
83 | 0 | } |
84 | | |
85 | | CPLErr GetGeoTransform(GDALGeoTransform >) const override; |
86 | | |
87 | | static GDALDataset *Open(GDALOpenInfo *); |
88 | | static int Identify(GDALOpenInfo *); |
89 | | }; |
90 | | |
91 | | /************************************************************************/ |
92 | | /* ==================================================================== */ |
93 | | /* ACE2RasterBand */ |
94 | | /* ==================================================================== */ |
95 | | /************************************************************************/ |
96 | | |
97 | | class ACE2RasterBand final : public RawRasterBand |
98 | | { |
99 | | public: |
100 | | ACE2RasterBand(VSILFILE *fpRaw, GDALDataType eDataType, int nXSize, |
101 | | int nYSize); |
102 | | |
103 | | const char *GetUnitType() override; |
104 | | char **GetCategoryNames() override; |
105 | | }; |
106 | | |
107 | | /************************************************************************/ |
108 | | /* ==================================================================== */ |
109 | | /* ACE2Dataset */ |
110 | | /* ==================================================================== */ |
111 | | /************************************************************************/ |
112 | | |
113 | | /************************************************************************/ |
114 | | /* ACE2Dataset() */ |
115 | | /************************************************************************/ |
116 | | |
117 | | ACE2Dataset::ACE2Dataset() |
118 | 0 | { |
119 | 0 | m_oSRS.SetFromUserInput(SRS_WKT_WGS84_LAT_LONG); |
120 | 0 | m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
121 | 0 | } |
122 | | |
123 | | /************************************************************************/ |
124 | | /* GetGeoTransform() */ |
125 | | /************************************************************************/ |
126 | | |
127 | | CPLErr ACE2Dataset::GetGeoTransform(GDALGeoTransform >) const |
128 | | |
129 | 0 | { |
130 | 0 | gt = m_gt; |
131 | 0 | return CE_None; |
132 | 0 | } |
133 | | |
134 | | /************************************************************************/ |
135 | | /* ACE2RasterBand() */ |
136 | | /************************************************************************/ |
137 | | |
138 | | ACE2RasterBand::ACE2RasterBand(VSILFILE *fpRawIn, GDALDataType eDataTypeIn, |
139 | | int nXSize, int nYSize) |
140 | 0 | : RawRasterBand(fpRawIn, 0, GDALGetDataTypeSizeBytes(eDataTypeIn), |
141 | 0 | nXSize * GDALGetDataTypeSizeBytes(eDataTypeIn), eDataTypeIn, |
142 | 0 | CPL_IS_LSB, nXSize, nYSize, RawRasterBand::OwnFP::YES) |
143 | 0 | { |
144 | 0 | } |
145 | | |
146 | | /************************************************************************/ |
147 | | /* GetUnitType() */ |
148 | | /************************************************************************/ |
149 | | |
150 | | const char *ACE2RasterBand::GetUnitType() |
151 | 0 | { |
152 | 0 | if (eDataType == GDT_Float32) |
153 | 0 | return "m"; |
154 | | |
155 | 0 | return ""; |
156 | 0 | } |
157 | | |
158 | | /************************************************************************/ |
159 | | /* GetCategoryNames() */ |
160 | | /************************************************************************/ |
161 | | |
162 | | char **ACE2RasterBand::GetCategoryNames() |
163 | 0 | { |
164 | 0 | if (eDataType != GDT_Int16) |
165 | 0 | return nullptr; |
166 | | |
167 | 0 | const char *pszName = poDS->GetDescription(); |
168 | |
|
169 | 0 | if (strstr(pszName, "_SOURCE_")) |
170 | 0 | return const_cast<char **>(apszCategorySource); |
171 | 0 | if (strstr(pszName, "_QUALITY_")) |
172 | 0 | return const_cast<char **>(apszCategoryQuality); |
173 | 0 | if (strstr(pszName, "_CONF_")) |
174 | 0 | return const_cast<char **>(apszCategoryConfidence); |
175 | | |
176 | 0 | return nullptr; |
177 | 0 | } |
178 | | |
179 | | /************************************************************************/ |
180 | | /* Identify() */ |
181 | | /************************************************************************/ |
182 | | |
183 | | int ACE2Dataset::Identify(GDALOpenInfo *poOpenInfo) |
184 | | |
185 | 561k | { |
186 | 561k | if (!(poOpenInfo->IsExtensionEqualToCI("ACE2") || |
187 | 561k | strstr(poOpenInfo->pszFilename, ".ACE2.gz") || |
188 | 561k | strstr(poOpenInfo->pszFilename, ".ace2.gz"))) |
189 | 560k | return FALSE; |
190 | | |
191 | 941 | return TRUE; |
192 | 561k | } |
193 | | |
194 | | /************************************************************************/ |
195 | | /* Open() */ |
196 | | /************************************************************************/ |
197 | | |
198 | | GDALDataset *ACE2Dataset::Open(GDALOpenInfo *poOpenInfo) |
199 | | |
200 | 470 | { |
201 | 470 | if (!Identify(poOpenInfo)) |
202 | 0 | return nullptr; |
203 | | |
204 | 470 | const std::string osBasename = CPLGetBasenameSafe(poOpenInfo->pszFilename); |
205 | 470 | const char *pszBasename = osBasename.c_str(); |
206 | | |
207 | 470 | if (strlen(pszBasename) < 7) |
208 | 39 | return nullptr; |
209 | | |
210 | | /* Determine southwest coordinates from filename */ |
211 | | |
212 | | /* e.g. 30S120W_5M.ACE2 */ |
213 | 431 | char pszLatLonValueString[4] = {'\0'}; |
214 | 431 | memset(pszLatLonValueString, 0, 4); |
215 | | // cppcheck-suppress redundantCopy |
216 | 431 | strncpy(pszLatLonValueString, &pszBasename[0], 2); |
217 | 431 | int southWestLat = atoi(pszLatLonValueString); |
218 | 431 | memset(pszLatLonValueString, 0, 4); |
219 | | // cppcheck-suppress redundantCopy |
220 | 431 | strncpy(pszLatLonValueString, &pszBasename[3], 3); |
221 | 431 | int southWestLon = atoi(pszLatLonValueString); |
222 | | |
223 | 431 | if (pszBasename[2] == 'N' || pszBasename[2] == 'n') |
224 | 38 | /*southWestLat = southWestLat*/; |
225 | 393 | else if (pszBasename[2] == 'S' || pszBasename[2] == 's') |
226 | 24 | southWestLat = southWestLat * -1; |
227 | 369 | else |
228 | 369 | return nullptr; |
229 | | |
230 | 62 | if (pszBasename[6] == 'E' || pszBasename[6] == 'e') |
231 | 12 | /*southWestLon = southWestLon*/; |
232 | 50 | else if (pszBasename[6] == 'W' || pszBasename[6] == 'w') |
233 | 2 | southWestLon = southWestLon * -1; |
234 | 48 | else |
235 | 48 | return nullptr; |
236 | | |
237 | 14 | GDALDataType eDT = GDT_Unknown; |
238 | 14 | if (strstr(pszBasename, "_CONF_") || strstr(pszBasename, "_QUALITY_") || |
239 | 14 | strstr(pszBasename, "_SOURCE_")) |
240 | 0 | eDT = GDT_Int16; |
241 | 14 | else |
242 | 14 | eDT = GDT_Float32; |
243 | 14 | const int nWordSize = GDALGetDataTypeSizeBytes(eDT); |
244 | | |
245 | 14 | VSIStatBufL sStat; |
246 | 14 | if (strstr(pszBasename, "_5M")) |
247 | 0 | sStat.st_size = 180 * 180 * nWordSize; |
248 | 14 | else if (strstr(pszBasename, "_30S")) |
249 | 0 | sStat.st_size = 1800 * 1800 * nWordSize; |
250 | 14 | else if (strstr(pszBasename, "_9S")) |
251 | 0 | sStat.st_size = 6000 * 6000 * nWordSize; |
252 | 14 | else if (strstr(pszBasename, "_3S")) |
253 | 0 | sStat.st_size = 18000 * 18000 * nWordSize; |
254 | | /* Check file size otherwise */ |
255 | 14 | else if (VSIStatL(poOpenInfo->pszFilename, &sStat) != 0) |
256 | 11 | { |
257 | 11 | return nullptr; |
258 | 11 | } |
259 | | |
260 | 3 | int nXSize = 0; |
261 | 3 | int nYSize = 0; |
262 | | |
263 | 3 | double dfPixelSize = 0; |
264 | 3 | if (sStat.st_size == 180 * 180 * nWordSize) |
265 | 0 | { |
266 | | /* 5 minute */ |
267 | 0 | nXSize = 180; |
268 | 0 | nYSize = 180; |
269 | 0 | dfPixelSize = 5.0 / 60; |
270 | 0 | } |
271 | 3 | else if (sStat.st_size == 1800 * 1800 * nWordSize) |
272 | 0 | { |
273 | | /* 30 s */ |
274 | 0 | nXSize = 1800; |
275 | 0 | nYSize = 1800; |
276 | 0 | dfPixelSize = 30.0 / 3600; |
277 | 0 | } |
278 | 3 | else if (sStat.st_size == 6000 * 6000 * nWordSize) |
279 | 0 | { |
280 | | /* 9 s */ |
281 | 0 | nXSize = 6000; |
282 | 0 | nYSize = 6000; |
283 | 0 | dfPixelSize = 9.0 / 3600; |
284 | 0 | } |
285 | 3 | else if (sStat.st_size == 18000 * 18000 * nWordSize) |
286 | 0 | { |
287 | | /* 3 s */ |
288 | 0 | nXSize = 18000; |
289 | 0 | nYSize = 18000; |
290 | 0 | dfPixelSize = 3.0 / 3600; |
291 | 0 | } |
292 | 3 | else |
293 | 3 | return nullptr; |
294 | | |
295 | | /* -------------------------------------------------------------------- */ |
296 | | /* Open file. */ |
297 | | /* -------------------------------------------------------------------- */ |
298 | | |
299 | 0 | CPLString osFilename = poOpenInfo->pszFilename; |
300 | 0 | if ((strstr(poOpenInfo->pszFilename, ".ACE2.gz") || |
301 | 0 | strstr(poOpenInfo->pszFilename, ".ace2.gz")) && |
302 | 0 | !STARTS_WITH(poOpenInfo->pszFilename, "/vsigzip/")) |
303 | 0 | osFilename = "/vsigzip/" + osFilename; |
304 | |
|
305 | 0 | VSILFILE *fpImage = VSIFOpenL(osFilename, "rb+"); |
306 | 0 | if (fpImage == nullptr) |
307 | 0 | return nullptr; |
308 | | |
309 | | /* -------------------------------------------------------------------- */ |
310 | | /* Create the dataset. */ |
311 | | /* -------------------------------------------------------------------- */ |
312 | 0 | auto poDS = std::make_unique<ACE2Dataset>(); |
313 | |
|
314 | 0 | poDS->nRasterXSize = nXSize; |
315 | 0 | poDS->nRasterYSize = nYSize; |
316 | |
|
317 | 0 | poDS->m_gt[0] = southWestLon; |
318 | 0 | poDS->m_gt[1] = dfPixelSize; |
319 | 0 | poDS->m_gt[2] = 0.0; |
320 | 0 | poDS->m_gt[3] = southWestLat + nYSize * dfPixelSize; |
321 | 0 | poDS->m_gt[4] = 0.0; |
322 | 0 | poDS->m_gt[5] = -dfPixelSize; |
323 | | |
324 | | /* -------------------------------------------------------------------- */ |
325 | | /* Create band information objects */ |
326 | | /* -------------------------------------------------------------------- */ |
327 | 0 | auto poBand = |
328 | 0 | std::make_unique<ACE2RasterBand>(fpImage, eDT, nXSize, nYSize); |
329 | 0 | if (!poBand->IsValid()) |
330 | 0 | return nullptr; |
331 | 0 | poDS->SetBand(1, std::move(poBand)); |
332 | | |
333 | | /* -------------------------------------------------------------------- */ |
334 | | /* Initialize any PAM information. */ |
335 | | /* -------------------------------------------------------------------- */ |
336 | 0 | poDS->SetDescription(poOpenInfo->pszFilename); |
337 | 0 | poDS->TryLoadXML(); |
338 | | |
339 | | /* -------------------------------------------------------------------- */ |
340 | | /* Check for overviews. */ |
341 | | /* -------------------------------------------------------------------- */ |
342 | 0 | poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename); |
343 | |
|
344 | 0 | return poDS.release(); |
345 | 0 | } |
346 | | |
347 | | /************************************************************************/ |
348 | | /* GDALRegister_ACE2() */ |
349 | | /************************************************************************/ |
350 | | |
351 | | void GDALRegister_ACE2() |
352 | | |
353 | 22 | { |
354 | 22 | if (GDALGetDriverByName("ACE2") != nullptr) |
355 | 0 | return; |
356 | | |
357 | 22 | GDALDriver *poDriver = new GDALDriver(); |
358 | | |
359 | 22 | poDriver->SetDescription("ACE2"); |
360 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); |
361 | 22 | poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ACE2"); |
362 | 22 | poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/ace2.html"); |
363 | 22 | poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ACE2"); |
364 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); |
365 | | |
366 | 22 | poDriver->pfnOpen = ACE2Dataset::Open; |
367 | 22 | poDriver->pfnIdentify = ACE2Dataset::Identify; |
368 | | |
369 | 22 | GetGDALDriverManager()->RegisterDriver(poDriver); |
370 | 22 | } |