Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Read metadata from DigitalGlobe 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 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "reader_digital_globe.h"
16 :
17 : #include <ctime>
18 :
19 : #include "cpl_conv.h"
20 : #include "cpl_error.h"
21 : #include "cpl_minixml.h"
22 : #include "cpl_string.h"
23 : #include "cpl_time.h"
24 :
25 : #include "gdal_priv.h"
26 :
27 : /**
28 : * GDALMDReaderDigitalGlobe()
29 : */
30 5151 : GDALMDReaderDigitalGlobe::GDALMDReaderDigitalGlobe(const char *pszPath,
31 5151 : char **papszSiblingFiles)
32 : : GDALMDReaderBase(pszPath, papszSiblingFiles),
33 : m_osXMLSourceFilename(
34 : GDALFindAssociatedFile(pszPath, "XML", papszSiblingFiles, 0)),
35 : m_osIMDSourceFilename(
36 : GDALFindAssociatedFile(pszPath, "IMD", papszSiblingFiles, 0)),
37 : m_osRPBSourceFilename(
38 5151 : GDALFindAssociatedFile(pszPath, "RPB", papszSiblingFiles, 0))
39 : {
40 5151 : if (!m_osIMDSourceFilename.empty())
41 36 : CPLDebug("MDReaderDigitalGlobe", "IMD Filename: %s",
42 : m_osIMDSourceFilename.c_str());
43 5151 : if (!m_osRPBSourceFilename.empty())
44 10 : CPLDebug("MDReaderDigitalGlobe", "RPB Filename: %s",
45 : m_osRPBSourceFilename.c_str());
46 5151 : if (!m_osXMLSourceFilename.empty())
47 9 : CPLDebug("MDReaderDigitalGlobe", "XML Filename: %s",
48 : m_osXMLSourceFilename.c_str());
49 5151 : }
50 :
51 : /**
52 : * ~GDALMDReaderDigitalGlobe()
53 : */
54 10302 : GDALMDReaderDigitalGlobe::~GDALMDReaderDigitalGlobe()
55 : {
56 10302 : }
57 :
58 : /**
59 : * HasRequiredFiles()
60 : */
61 5151 : bool GDALMDReaderDigitalGlobe::HasRequiredFiles() const
62 : {
63 5151 : if (!m_osIMDSourceFilename.empty())
64 36 : return true;
65 5115 : if (!m_osRPBSourceFilename.empty())
66 0 : return true;
67 :
68 : // check <isd>
69 5124 : if (!m_osXMLSourceFilename.empty() &&
70 9 : GDALCheckFileHeader(m_osXMLSourceFilename, "<isd>"))
71 2 : return true;
72 :
73 5113 : return false;
74 : }
75 :
76 : /**
77 : * LoadMetadata()
78 : */
79 76 : void GDALMDReaderDigitalGlobe::LoadMetadata()
80 : {
81 76 : if (m_bIsMetadataLoad)
82 38 : return;
83 :
84 38 : if (!m_osIMDSourceFilename.empty())
85 : {
86 36 : m_papszIMDMD = GDALLoadIMDFile(m_osIMDSourceFilename);
87 : }
88 :
89 38 : if (!m_osRPBSourceFilename.empty())
90 : {
91 10 : m_papszRPCMD = GDALLoadRPBFile(m_osRPBSourceFilename);
92 : }
93 :
94 66 : if ((nullptr == m_papszIMDMD || nullptr == m_papszRPCMD) &&
95 28 : !m_osXMLSourceFilename.empty())
96 : {
97 2 : CPLXMLNode *psNode = CPLParseXMLFile(m_osXMLSourceFilename);
98 :
99 2 : if (psNode != nullptr)
100 : {
101 2 : CPLXMLNode *psisdNode = psNode->psNext;
102 2 : if (psisdNode != nullptr)
103 : {
104 2 : if (m_papszIMDMD == nullptr)
105 2 : m_papszIMDMD =
106 2 : LoadIMDXmlNode(CPLSearchXMLNode(psisdNode, "IMD"));
107 2 : if (m_papszRPCMD == nullptr)
108 2 : m_papszRPCMD =
109 2 : LoadRPBXmlNode(CPLSearchXMLNode(psisdNode, "RPB"));
110 : }
111 2 : CPLDestroyXMLNode(psNode);
112 : }
113 : }
114 :
115 38 : m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "DG");
116 :
117 38 : m_bIsMetadataLoad = true;
118 :
119 38 : if (nullptr == m_papszIMDMD)
120 : {
121 4 : return;
122 : }
123 : // extract imagery metadata
124 34 : const char *pszSatId = CSLFetchNameValue(m_papszIMDMD, "IMAGE.SATID");
125 34 : if (nullptr != pszSatId)
126 : {
127 2 : m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
128 4 : CPLStripQuotes(pszSatId));
129 : }
130 : else
131 : {
132 32 : pszSatId = CSLFetchNameValue(m_papszIMDMD, "IMAGE_1.SATID");
133 32 : if (nullptr != pszSatId)
134 : {
135 30 : m_papszIMAGERYMD = CSLAddNameValue(
136 60 : m_papszIMAGERYMD, MD_NAME_SATELLITE, CPLStripQuotes(pszSatId));
137 : }
138 : }
139 :
140 : const char *pszCloudCover =
141 34 : CSLFetchNameValue(m_papszIMDMD, "IMAGE.CLOUDCOVER");
142 34 : if (nullptr != pszCloudCover)
143 : {
144 2 : double fCC = CPLAtofM(pszCloudCover);
145 2 : if (fCC < 0)
146 : {
147 0 : m_papszIMAGERYMD = CSLAddNameValue(
148 : m_papszIMAGERYMD, MD_NAME_CLOUDCOVER, MD_CLOUDCOVER_NA);
149 : }
150 : else
151 : {
152 2 : m_papszIMAGERYMD =
153 2 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
154 2 : CPLSPrintf("%d", int(fCC * 100)));
155 : }
156 : }
157 : else
158 : {
159 32 : pszCloudCover = CSLFetchNameValue(m_papszIMDMD, "IMAGE_1.cloudCover");
160 32 : if (nullptr != pszCloudCover)
161 : {
162 30 : double fCC = CPLAtofM(pszCloudCover);
163 30 : if (fCC < 0)
164 : {
165 0 : m_papszIMAGERYMD = CSLAddNameValue(
166 : m_papszIMAGERYMD, MD_NAME_CLOUDCOVER, MD_CLOUDCOVER_NA);
167 : }
168 : else
169 : {
170 30 : m_papszIMAGERYMD =
171 30 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
172 30 : CPLSPrintf("%d", int(fCC * 100)));
173 : }
174 : }
175 : }
176 :
177 : const char *pszDateTime =
178 34 : CSLFetchNameValue(m_papszIMDMD, "IMAGE.FIRSTLINETIME");
179 34 : if (nullptr != pszDateTime)
180 : {
181 2 : GIntBig timeStart = GetAcquisitionTimeFromString(pszDateTime);
182 : char szMidDateTime[80];
183 : struct tm tmBuf;
184 2 : strftime(szMidDateTime, 80, MD_DATETIMEFORMAT,
185 2 : CPLUnixTimeToYMDHMS(timeStart, &tmBuf));
186 :
187 2 : m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
188 : MD_NAME_ACQDATETIME, szMidDateTime);
189 : }
190 : else
191 : {
192 32 : pszDateTime = CSLFetchNameValue(m_papszIMDMD, "IMAGE_1.firstLineTime");
193 32 : if (nullptr != pszDateTime)
194 : {
195 30 : GIntBig timeStart = GetAcquisitionTimeFromString(pszDateTime);
196 : char szMidDateTime[80];
197 : struct tm tmBuf;
198 30 : strftime(szMidDateTime, 80, MD_DATETIMEFORMAT,
199 30 : CPLUnixTimeToYMDHMS(timeStart, &tmBuf));
200 :
201 30 : m_papszIMAGERYMD = CSLAddNameValue(
202 : m_papszIMAGERYMD, MD_NAME_ACQDATETIME, szMidDateTime);
203 : }
204 : }
205 : }
206 :
207 : /**
208 : * GetMetadataFiles()
209 : */
210 38 : char **GDALMDReaderDigitalGlobe::GetMetadataFiles() const
211 : {
212 38 : char **papszFileList = nullptr;
213 38 : if (!m_osIMDSourceFilename.empty())
214 36 : papszFileList = CSLAddString(papszFileList, m_osIMDSourceFilename);
215 38 : if (!m_osRPBSourceFilename.empty())
216 10 : papszFileList = CSLAddString(papszFileList, m_osRPBSourceFilename);
217 38 : if (!m_osXMLSourceFilename.empty())
218 2 : papszFileList = CSLAddString(papszFileList, m_osXMLSourceFilename);
219 :
220 38 : return papszFileList;
221 : }
222 :
223 : /**
224 : * GDALLoadIMDXmlNode()
225 : */
226 2 : char **GDALMDReaderDigitalGlobe::LoadIMDXmlNode(CPLXMLNode *psNode)
227 : {
228 2 : if (nullptr == psNode)
229 0 : return nullptr;
230 2 : char **papszList = nullptr;
231 2 : return ReadXMLToList(psNode->psChild, papszList);
232 : }
233 :
234 : /**
235 : * GDALLoadRPBXmlNode()
236 : */
237 : static const char *const apszRPBMap[] = {RPC_ERR_BIAS,
238 : "image.errBias",
239 : RPC_ERR_RAND,
240 : "image.errRand",
241 : RPC_LINE_OFF,
242 : "image.lineOffset",
243 : RPC_SAMP_OFF,
244 : "image.sampOffset",
245 : RPC_LAT_OFF,
246 : "image.latOffset",
247 : RPC_LONG_OFF,
248 : "image.longOffset",
249 : RPC_HEIGHT_OFF,
250 : "image.heightOffset",
251 : RPC_LINE_SCALE,
252 : "image.lineScale",
253 : RPC_SAMP_SCALE,
254 : "image.sampScale",
255 : RPC_LAT_SCALE,
256 : "image.latScale",
257 : RPC_LONG_SCALE,
258 : "image.longScale",
259 : RPC_HEIGHT_SCALE,
260 : "image.heightScale",
261 : RPC_LINE_NUM_COEFF,
262 : "image.lineNumCoefList.lineNumCoef",
263 : RPC_LINE_DEN_COEFF,
264 : "image.lineDenCoefList.lineDenCoef",
265 : RPC_SAMP_NUM_COEFF,
266 : "image.sampNumCoefList.sampNumCoef",
267 : RPC_SAMP_DEN_COEFF,
268 : "image.sampDenCoefList.sampDenCoef",
269 : nullptr,
270 : nullptr};
271 :
272 2 : char **GDALMDReaderDigitalGlobe::LoadRPBXmlNode(CPLXMLNode *psNode)
273 : {
274 2 : if (nullptr == psNode)
275 1 : return nullptr;
276 1 : char **papszList = nullptr;
277 1 : papszList = ReadXMLToList(psNode->psChild, papszList);
278 :
279 1 : if (nullptr == papszList)
280 0 : return nullptr;
281 :
282 1 : char **papszRPB = nullptr;
283 17 : for (int i = 0; apszRPBMap[i] != nullptr; i += 2)
284 : {
285 : papszRPB =
286 16 : CSLAddNameValue(papszRPB, apszRPBMap[i],
287 16 : CSLFetchNameValue(papszList, apszRPBMap[i + 1]));
288 : }
289 :
290 1 : CSLDestroy(papszList);
291 :
292 1 : return papszRPB;
293 : }
|