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