Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Read metadata from Alos imagery.
5 : * Author: Alexander Lisovenko
6 : * Author: Dmitry Baryshnikov, polimax@mail.ru
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2014-2015 NextGIS <info@nextgis.ru>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "reader_alos.h"
31 :
32 : #include <cstdio>
33 : #include <cstdlib>
34 :
35 : #include <string>
36 :
37 : #include "cpl_conv.h"
38 : #include "cpl_error.h"
39 : #include "cpl_string.h"
40 : #include "cpl_time.h"
41 : #include "gdal_mdreader.h"
42 :
43 : /**
44 : * GDALMDReaderALOS()
45 : */
46 5023 : GDALMDReaderALOS::GDALMDReaderALOS(const char *pszPath,
47 5023 : char **papszSiblingFiles)
48 5023 : : GDALMDReaderBase(pszPath, papszSiblingFiles)
49 : {
50 10046 : CPLString osDirName = CPLGetDirname(pszPath);
51 10046 : CPLString osBaseName = CPLGetBasename(pszPath);
52 :
53 : CPLString osIMDSourceFilename =
54 10046 : CPLFormFilename(osDirName, "summary", ".txt");
55 5023 : if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
56 : {
57 1 : m_osIMDSourceFilename = std::move(osIMDSourceFilename);
58 : }
59 : else
60 : {
61 5022 : osIMDSourceFilename = CPLFormFilename(osDirName, "SUMMARY", ".TXT");
62 5022 : if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
63 : {
64 0 : m_osIMDSourceFilename = std::move(osIMDSourceFilename);
65 : }
66 : }
67 :
68 5023 : if (osBaseName.size() >= 6)
69 : {
70 : // check if this is separate band or whole image
71 : // test without 6 symbols
72 : CPLString osHDRFileName = CPLFormFilename(
73 6336 : osDirName, CPLSPrintf("HDR%s", osBaseName + 6), "txt");
74 3168 : if (CPLCheckForFile(&osHDRFileName[0], papszSiblingFiles))
75 : {
76 0 : m_osHDRSourceFilename = std::move(osHDRFileName);
77 : }
78 : else
79 : {
80 : osHDRFileName = CPLFormFilename(
81 3168 : osDirName, CPLSPrintf("HDR%s", osBaseName + 6), "TXT");
82 3168 : if (CPLCheckForFile(&osHDRFileName[0], papszSiblingFiles))
83 : {
84 0 : m_osHDRSourceFilename = std::move(osHDRFileName);
85 : }
86 : }
87 : }
88 :
89 : // test without 3 symbols
90 5023 : if (osBaseName.size() >= 3 && m_osHDRSourceFilename.empty())
91 : {
92 : CPLString osHDRFileName = CPLFormFilename(
93 10010 : osDirName, CPLSPrintf("HDR%s", osBaseName + 3), "txt");
94 5005 : if (CPLCheckForFile(&osHDRFileName[0], papszSiblingFiles))
95 : {
96 0 : m_osHDRSourceFilename = std::move(osHDRFileName);
97 : }
98 : else
99 : {
100 : osHDRFileName = CPLFormFilename(
101 5005 : osDirName, CPLSPrintf("HDR%s", osBaseName + 3), "TXT");
102 5005 : if (CPLCheckForFile(&osHDRFileName[0], papszSiblingFiles))
103 : {
104 0 : m_osHDRSourceFilename = std::move(osHDRFileName);
105 : }
106 : }
107 : }
108 :
109 : // test without 6 symbols
110 5023 : if (osBaseName.size() >= 6)
111 : {
112 : CPLString osRPCFileName = CPLFormFilename(
113 6336 : osDirName, CPLSPrintf("RPC%s", osBaseName + 6), "txt");
114 3168 : if (CPLCheckForFile(&osRPCFileName[0], papszSiblingFiles))
115 : {
116 0 : m_osRPBSourceFilename = std::move(osRPCFileName);
117 : }
118 : else
119 : {
120 : osRPCFileName = CPLFormFilename(
121 3168 : osDirName, CPLSPrintf("RPC%s", osBaseName + 6), "TXT");
122 3168 : if (CPLCheckForFile(&osRPCFileName[0], papszSiblingFiles))
123 : {
124 0 : m_osRPBSourceFilename = std::move(osRPCFileName);
125 : }
126 : }
127 : }
128 :
129 : // test without 3 symbols
130 5023 : if (osBaseName.size() >= 3 && m_osRPBSourceFilename.empty())
131 : {
132 : CPLString osRPCFileName = CPLFormFilename(
133 10010 : osDirName, CPLSPrintf("RPC%s", osBaseName + 3), "txt");
134 5005 : if (CPLCheckForFile(&osRPCFileName[0], papszSiblingFiles))
135 : {
136 1 : m_osRPBSourceFilename = std::move(osRPCFileName);
137 : }
138 : else
139 : {
140 : osRPCFileName = CPLFormFilename(
141 5004 : osDirName, CPLSPrintf("RPC%s", osBaseName + 3), "TXT");
142 5004 : if (CPLCheckForFile(&osRPCFileName[0], papszSiblingFiles))
143 : {
144 0 : m_osRPBSourceFilename = std::move(osRPCFileName);
145 : }
146 : }
147 : }
148 :
149 5023 : if (!m_osIMDSourceFilename.empty())
150 1 : CPLDebug("MDReaderALOS", "IMD Filename: %s",
151 : m_osIMDSourceFilename.c_str());
152 5023 : if (!m_osHDRSourceFilename.empty())
153 0 : CPLDebug("MDReaderALOS", "HDR Filename: %s",
154 : m_osHDRSourceFilename.c_str());
155 5023 : if (!m_osRPBSourceFilename.empty())
156 1 : CPLDebug("MDReaderALOS", "RPB Filename: %s",
157 : m_osRPBSourceFilename.c_str());
158 5023 : }
159 :
160 : /**
161 : * ~GDALMDReaderALOS()
162 : */
163 10046 : GDALMDReaderALOS::~GDALMDReaderALOS()
164 : {
165 10046 : }
166 :
167 : /**
168 : * HasRequiredFiles()
169 : */
170 5023 : bool GDALMDReaderALOS::HasRequiredFiles() const
171 : {
172 5023 : if (!m_osIMDSourceFilename.empty())
173 1 : return true;
174 :
175 5022 : if (!m_osHDRSourceFilename.empty() && !m_osRPBSourceFilename.empty())
176 0 : return true;
177 :
178 5022 : return false;
179 : }
180 :
181 : /**
182 : * GetMetadataFiles()
183 : */
184 1 : char **GDALMDReaderALOS::GetMetadataFiles() const
185 : {
186 1 : char **papszFileList = nullptr;
187 1 : if (!m_osIMDSourceFilename.empty())
188 1 : papszFileList = CSLAddString(papszFileList, m_osIMDSourceFilename);
189 1 : if (!m_osHDRSourceFilename.empty())
190 0 : papszFileList = CSLAddString(papszFileList, m_osHDRSourceFilename);
191 1 : if (!m_osRPBSourceFilename.empty())
192 1 : papszFileList = CSLAddString(papszFileList, m_osRPBSourceFilename);
193 :
194 1 : return papszFileList;
195 : }
196 :
197 : /**
198 : * LoadMetadata()
199 : */
200 2 : void GDALMDReaderALOS::LoadMetadata()
201 : {
202 2 : if (m_bIsMetadataLoad)
203 1 : return;
204 :
205 1 : if (!m_osIMDSourceFilename.empty())
206 : {
207 1 : m_papszIMDMD = CSLLoad(m_osIMDSourceFilename);
208 : }
209 :
210 1 : if (!m_osHDRSourceFilename.empty())
211 : {
212 0 : if (nullptr == m_papszIMDMD)
213 : {
214 0 : m_papszIMDMD = CSLLoad(m_osHDRSourceFilename);
215 : }
216 : else
217 : {
218 0 : char **papszHDR = CSLLoad(m_osHDRSourceFilename);
219 0 : m_papszIMDMD = CSLMerge(m_papszIMDMD, papszHDR);
220 0 : CSLDestroy(papszHDR);
221 : }
222 : }
223 :
224 1 : m_papszRPCMD = LoadRPCTxtFile();
225 :
226 1 : m_papszDEFAULTMD =
227 1 : CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "ALOS");
228 :
229 1 : m_bIsMetadataLoad = true;
230 :
231 1 : const char *pszSatId1 = CSLFetchNameValue(m_papszIMDMD, "Lbi_Satellite");
232 1 : const char *pszSatId2 = CSLFetchNameValue(m_papszIMDMD, "Lbi_Sensor");
233 1 : if (nullptr != pszSatId1 && nullptr != pszSatId2)
234 : {
235 2 : m_papszIMAGERYMD = CSLAddNameValue(
236 : m_papszIMAGERYMD, MD_NAME_SATELLITE,
237 2 : CPLSPrintf("%s %s", CPLStripQuotes(pszSatId1).c_str(),
238 2 : CPLStripQuotes(pszSatId2).c_str()));
239 : }
240 0 : else if (nullptr != pszSatId1 && nullptr == pszSatId2)
241 : {
242 0 : m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
243 0 : CPLStripQuotes(pszSatId1));
244 : }
245 0 : else if (nullptr == pszSatId1 && nullptr != pszSatId2)
246 : {
247 0 : m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
248 0 : CPLStripQuotes(pszSatId2));
249 : }
250 :
251 : const char *pszCloudCover =
252 1 : CSLFetchNameValue(m_papszIMDMD, "Img_CloudQuantityOfAllImage");
253 1 : if (nullptr != pszCloudCover)
254 : {
255 0 : int nCC = atoi(pszCloudCover);
256 0 : if (nCC >= 99)
257 : {
258 0 : m_papszIMAGERYMD = CSLAddNameValue(
259 : m_papszIMAGERYMD, MD_NAME_CLOUDCOVER, MD_CLOUDCOVER_NA);
260 : }
261 : else
262 : {
263 0 : m_papszIMAGERYMD =
264 0 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
265 : CPLSPrintf("%d", nCC * 10));
266 : }
267 : }
268 :
269 : const char *pszDate =
270 1 : CSLFetchNameValue(m_papszIMDMD, "Img_SceneCenterDateTime");
271 :
272 1 : if (nullptr != pszDate)
273 : {
274 : char buffer[80];
275 0 : GIntBig timeMid = GetAcquisitionTimeFromString(CPLStripQuotes(pszDate));
276 : struct tm tmBuf;
277 0 : strftime(buffer, 80, MD_DATETIMEFORMAT,
278 0 : CPLUnixTimeToYMDHMS(timeMid, &tmBuf));
279 0 : m_papszIMAGERYMD =
280 0 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_ACQDATETIME, buffer);
281 : }
282 : else
283 : {
284 1 : pszDate = CSLFetchNameValue(m_papszIMDMD, "Lbi_ObservationDate");
285 1 : if (nullptr != pszDate)
286 : {
287 1 : const char *pszTime = "00:00:00.000";
288 :
289 : char buffer[80];
290 2 : GIntBig timeMid = GetAcquisitionTimeFromString(
291 2 : CPLSPrintf("%s %s", CPLStripQuotes(pszDate).c_str(),
292 2 : CPLStripQuotes(pszTime).c_str()));
293 : struct tm tmBuf;
294 1 : strftime(buffer, 80, MD_DATETIMEFORMAT,
295 1 : CPLUnixTimeToYMDHMS(timeMid, &tmBuf));
296 1 : m_papszIMAGERYMD =
297 1 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_ACQDATETIME, buffer);
298 : }
299 : }
300 : }
301 :
302 : /**
303 : * LoadRPCTxtFile
304 : */
305 1 : char **GDALMDReaderALOS::LoadRPCTxtFile()
306 : {
307 1 : if (m_osRPBSourceFilename.empty())
308 0 : return nullptr;
309 :
310 2 : const CPLStringList aosLines(CSLLoad(m_osRPBSourceFilename));
311 1 : if (aosLines.empty())
312 0 : return nullptr;
313 :
314 1 : const char *pszFirstRow = aosLines[0];
315 2 : CPLStringList aosRPB;
316 1 : if (nullptr != pszFirstRow)
317 : {
318 : static const struct
319 : {
320 : const char *pszName;
321 : int nSize;
322 : } apsFieldDescriptors[] = {
323 : {RPC_LINE_OFF, 6}, {RPC_SAMP_OFF, 5}, {RPC_LAT_OFF, 8},
324 : {RPC_LONG_OFF, 9}, {RPC_HEIGHT_OFF, 5}, {RPC_LINE_SCALE, 6},
325 : {RPC_SAMP_SCALE, 5}, {RPC_LAT_SCALE, 8}, {RPC_LONG_SCALE, 9},
326 : {RPC_HEIGHT_SCALE, 5},
327 : };
328 :
329 1 : int nRequiredSize = 0;
330 11 : for (const auto &sFieldDescriptor : apsFieldDescriptors)
331 : {
332 10 : nRequiredSize += sFieldDescriptor.nSize;
333 : }
334 :
335 : static const char *const apszRPCTXT20ValItems[] = {
336 : RPC_LINE_NUM_COEFF, RPC_LINE_DEN_COEFF, RPC_SAMP_NUM_COEFF,
337 : RPC_SAMP_DEN_COEFF};
338 :
339 1 : constexpr int RPC_COEFF_COUNT1 = CPL_ARRAYSIZE(apszRPCTXT20ValItems);
340 1 : constexpr int RPC_COEFF_COUNT2 = 20;
341 1 : constexpr int RPC_COEFF_SIZE = 12;
342 1 : nRequiredSize += RPC_COEFF_COUNT1 * RPC_COEFF_COUNT2 * RPC_COEFF_SIZE;
343 1 : if (strlen(pszFirstRow) < static_cast<size_t>(nRequiredSize))
344 : {
345 0 : CPLError(CE_Failure, CPLE_AppDefined,
346 : "%s has only %d bytes wherea %d are required",
347 0 : m_osRPBSourceFilename.c_str(), int(strlen(pszFirstRow)),
348 : nRequiredSize);
349 0 : return nullptr;
350 : }
351 :
352 1 : int nOffset = 0;
353 1 : char buff[16] = {0};
354 11 : for (const auto &sFieldDescriptor : apsFieldDescriptors)
355 : {
356 10 : CPLAssert(sFieldDescriptor.nSize < int(sizeof(buff)));
357 10 : memcpy(buff, pszFirstRow + nOffset, sFieldDescriptor.nSize);
358 10 : buff[sFieldDescriptor.nSize] = 0;
359 10 : aosRPB.SetNameValue(sFieldDescriptor.pszName, buff);
360 10 : nOffset += sFieldDescriptor.nSize;
361 : }
362 :
363 5 : for (const char *pszItem : apszRPCTXT20ValItems)
364 : {
365 8 : std::string osValue;
366 84 : for (int j = 0; j < RPC_COEFF_COUNT2; j++)
367 : {
368 80 : memcpy(buff, pszFirstRow + nOffset, RPC_COEFF_SIZE);
369 80 : buff[RPC_COEFF_SIZE] = 0;
370 80 : nOffset += RPC_COEFF_SIZE;
371 :
372 80 : if (!osValue.empty())
373 76 : osValue += " ";
374 80 : osValue += buff;
375 : }
376 4 : aosRPB.SetNameValue(pszItem, osValue.c_str());
377 : }
378 : }
379 :
380 1 : return aosRPB.StealList();
381 : }
382 :
383 : /**
384 : * GetAcqisitionTimeFromString()
385 : */
386 1 : GIntBig GDALMDReaderALOS::GetAcquisitionTimeFromString(const char *pszDateTime)
387 : {
388 1 : if (nullptr == pszDateTime)
389 0 : return 0;
390 :
391 : int iYear;
392 : int iMonth;
393 : int iDay;
394 : int iHours;
395 : int iMin;
396 : int iSec;
397 :
398 1 : int r = sscanf(pszDateTime, "%4d%2d%2d %d:%d:%d.%*d", &iYear, &iMonth,
399 : &iDay, &iHours, &iMin, &iSec);
400 :
401 1 : if (r != 6)
402 0 : return 0;
403 :
404 : struct tm tmDateTime;
405 1 : tmDateTime.tm_sec = iSec;
406 1 : tmDateTime.tm_min = iMin;
407 1 : tmDateTime.tm_hour = iHours;
408 1 : tmDateTime.tm_mday = iDay;
409 1 : tmDateTime.tm_mon = iMonth - 1;
410 1 : tmDateTime.tm_year = iYear - 1900;
411 1 : tmDateTime.tm_isdst = -1;
412 :
413 1 : return CPLYMDHMSToUnixTime(&tmDateTime);
414 : }
|