1 /******************************************************************************
2  *
3  * Project:  GDAL
4  * Purpose:  GDALPamDataset with internal storage for georeferencing, with
5  *           priority for PAM over internal georeferencing
6  * Author:   Even Rouault <even dot rouault at spatialys.com>
7  *
8  ******************************************************************************
9  * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com>
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 "gdalgeorefpamdataset.h"
31 
32 #include <cstring>
33 
34 #include "cpl_conv.h"
35 #include "cpl_error.h"
36 #include "gdal.h"
37 
38 //! @cond Doxygen_Suppress
39 /************************************************************************/
40 /*                       GDALGeorefPamDataset()                         */
41 /************************************************************************/
42 
43 GDALGeorefPamDataset::GDALGeorefPamDataset() :
44     bGeoTransformValid(false),
45     pszProjection(nullptr),
46     nGCPCount(0),
47     pasGCPList(nullptr),
48     m_papszRPC(nullptr),
49     m_bPixelIsPoint(false),
50     m_nGeoTransformGeorefSrcIndex(-1),
51     m_nGCPGeorefSrcIndex(-1),
52     m_nProjectionGeorefSrcIndex(-1),
53     m_nRPCGeorefSrcIndex(-1),
54     m_nPixelIsPointGeorefSrcIndex(-1),
55     m_bGotPAMGeorefSrcIndex(false),
56     m_nPAMGeorefSrcIndex(0),
57     m_bPAMLoaded(false),
58     m_papszMainMD(nullptr)
59 {
60     adfGeoTransform[0] = 0.0;
61     adfGeoTransform[1] = 1.0;
62     adfGeoTransform[2] = 0.0;
63     adfGeoTransform[3] = 0.0;
64     adfGeoTransform[4] = 0.0;
65     adfGeoTransform[5] = 1.0;
66 }
67 
68 /************************************************************************/
69 /*                       ~GDALGeorefPamDataset()                        */
70 /************************************************************************/
71 
72 GDALGeorefPamDataset::~GDALGeorefPamDataset()
73 {
74     CPLFree( pszProjection );
75 
76     if( nGCPCount > 0 )
77     {
78         GDALDeinitGCPs( nGCPCount, pasGCPList );
79         CPLFree( pasGCPList );
80     }
81     CSLDestroy(m_papszMainMD);
82     CSLDestroy(m_papszRPC);
83 }
84 
85 /************************************************************************/
86 /*                          GetMetadata()                               */
87 /************************************************************************/
88 
89 char      **GDALGeorefPamDataset::GetMetadata( const char * pszDomain )
90 {
91     if( pszDomain != nullptr && EQUAL(pszDomain, "RPC") )
92     {
93         const int nPAMIndex = GetPAMGeorefSrcIndex();
94         if( nPAMIndex >= 0 &&
95             ((m_papszRPC != nullptr && nPAMIndex < m_nRPCGeorefSrcIndex) ||
96             m_nRPCGeorefSrcIndex < 0 || m_papszRPC == nullptr))
97         {
98             char** papszMD = GDALPamDataset::GetMetadata(pszDomain);
99             if( papszMD )
100                 return papszMD;
101         }
102         return m_papszRPC;
103     }
104 
105     if( pszDomain == nullptr || EQUAL(pszDomain, "") )
106     {
107         if( m_papszMainMD )
108             return m_papszMainMD;
109         m_papszMainMD = CSLDuplicate(GDALPamDataset::GetMetadata(pszDomain));
110         const int nPAMIndex = GetPAMGeorefSrcIndex();
111         if( nPAMIndex >= 0 &&
112             ((m_bPixelIsPoint && nPAMIndex < m_nPixelIsPointGeorefSrcIndex) ||
113             m_nPixelIsPointGeorefSrcIndex < 0 || !m_bPixelIsPoint))
114         {
115             if( CSLFetchNameValue(m_papszMainMD, GDALMD_AREA_OR_POINT) != nullptr )
116                 return m_papszMainMD;
117         }
118         if( m_bPixelIsPoint )
119         {
120             m_papszMainMD = CSLSetNameValue(m_papszMainMD,
121                                             GDALMD_AREA_OR_POINT,
122                                             GDALMD_AOP_POINT);
123         }
124         else
125         {
126             m_papszMainMD = CSLSetNameValue(m_papszMainMD,
127                                             GDALMD_AREA_OR_POINT, nullptr);
128         }
129         return m_papszMainMD;
130     }
131 
132     return GDALPamDataset::GetMetadata(pszDomain);
133 }
134 
135 /************************************************************************/
136 /*                         GetMetadataItem()                            */
137 /************************************************************************/
138 
139 const char *GDALGeorefPamDataset::GetMetadataItem( const char * pszName,
140                                                    const char * pszDomain )
141 {
142     if( pszDomain == nullptr || EQUAL(pszDomain, "") || EQUAL(pszDomain, "RPC") )
143     {
144         return CSLFetchNameValue( GetMetadata(pszDomain), pszName );
145     }
146     return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
147 }
148 
149 /************************************************************************/
150 /*                           TryLoadXML()                              */
151 /************************************************************************/
152 
153 CPLErr GDALGeorefPamDataset::TryLoadXML(char **papszSiblingFiles)
154 {
155     m_bPAMLoaded = true;
156     CPLErr eErr = GDALPamDataset::TryLoadXML(papszSiblingFiles);
157     CSLDestroy(m_papszMainMD);
158     m_papszMainMD = nullptr;
159     return eErr;
160 }
161 
162 /************************************************************************/
163 /*                            SetMetadata()                             */
164 /************************************************************************/
165 
166 CPLErr GDALGeorefPamDataset::SetMetadata( char ** papszMetadata,
167                                            const char * pszDomain )
168 {
169     if( m_bPAMLoaded && (pszDomain == nullptr || EQUAL(pszDomain, "")) )
170     {
171         CSLDestroy(m_papszMainMD);
172         m_papszMainMD = CSLDuplicate(papszMetadata);
173     }
174     return GDALPamDataset::SetMetadata(papszMetadata, pszDomain);
175 }
176 
177 /************************************************************************/
178 /*                            SetMetadata()                             */
179 /************************************************************************/
180 
181 CPLErr GDALGeorefPamDataset::SetMetadataItem( const char * pszName,
182                                             const char * pszValue,
183                                             const char * pszDomain )
184 {
185     if( m_bPAMLoaded && (pszDomain == nullptr || EQUAL(pszDomain, "")) )
186     {
187         m_papszMainMD = CSLSetNameValue( GetMetadata(), pszName, pszValue );
188     }
189     return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
190 }
191 
192 /************************************************************************/
193 /*                            GetGCPCount()                             */
194 /*                                                                      */
195 /*      By default, we let PAM override the value stored                */
196 /*      inside our file, unless GDAL_GEOREF_SOURCES is defined.         */
197 /************************************************************************/
198 
199 int GDALGeorefPamDataset::GetGCPCount()
200 
201 {
202     const int nPAMIndex = GetPAMGeorefSrcIndex();
203     if( nPAMIndex >= 0 &&
204         ((nGCPCount != 0 && nPAMIndex < m_nGCPGeorefSrcIndex) ||
205          m_nGCPGeorefSrcIndex < 0 || nGCPCount == 0))
206     {
207         const int nPAMGCPCount = GDALPamDataset::GetGCPCount();
208         if( nPAMGCPCount )
209             return nPAMGCPCount;
210     }
211 
212     return nGCPCount;
213 }
214 
215 /************************************************************************/
216 /*                          GetGCPProjection()                          */
217 /*                                                                      */
218 /*      By default, we let PAM override the value stored                */
219 /*      inside our file, unless GDAL_GEOREF_SOURCES is defined.         */
220 /************************************************************************/
221 
222 const char *GDALGeorefPamDataset::_GetGCPProjection()
223 
224 {
225     const int nPAMIndex = GetPAMGeorefSrcIndex();
226     if( nPAMIndex >= 0 &&
227         ((pszProjection != nullptr && nPAMIndex < m_nProjectionGeorefSrcIndex) ||
228          m_nProjectionGeorefSrcIndex < 0 || pszProjection == nullptr) )
229     {
230         const char* pszPAMGCPProjection = GDALPamDataset::_GetGCPProjection();
231         if( pszPAMGCPProjection != nullptr && strlen(pszPAMGCPProjection) > 0 )
232             return pszPAMGCPProjection;
233     }
234 
235     if( pszProjection != nullptr )
236         return pszProjection;
237 
238     return "";
239 }
240 
241 /************************************************************************/
242 /*                               GetGCP()                               */
243 /*                                                                      */
244 /*      By default, we let PAM override the value stored                */
245 /*      inside our file, unless GDAL_GEOREF_SOURCES is defined.         */
246 /************************************************************************/
247 
248 const GDAL_GCP *GDALGeorefPamDataset::GetGCPs()
249 
250 {
251     const int nPAMIndex = GetPAMGeorefSrcIndex();
252     if( nPAMIndex >= 0 &&
253         ((nGCPCount != 0 && nPAMIndex < m_nGCPGeorefSrcIndex) ||
254          m_nGCPGeorefSrcIndex < 0 || nGCPCount == 0))
255     {
256         const GDAL_GCP* pasPAMGCPList = GDALPamDataset::GetGCPs();
257         if( pasPAMGCPList )
258             return pasPAMGCPList;
259     }
260 
261     return pasGCPList;
262 }
263 
264 /************************************************************************/
265 /*                          GetProjectionRef()                          */
266 /*                                                                      */
267 /*      By default, we let PAM override the value stored                */
268 /*      inside our file, unless GDAL_GEOREF_SOURCES is defined.         */
269 /************************************************************************/
270 
271 const char *GDALGeorefPamDataset::_GetProjectionRef()
272 
273 {
274     if( GetGCPCount() > 0 )
275         return "";
276 
277     const int nPAMIndex = GetPAMGeorefSrcIndex();
278     if( nPAMIndex >= 0 &&
279         ((pszProjection != nullptr && nPAMIndex < m_nProjectionGeorefSrcIndex) ||
280          m_nProjectionGeorefSrcIndex < 0 || pszProjection == nullptr) )
281     {
282         const char* pszPAMProjection = GDALPamDataset::_GetProjectionRef();
283         if( pszPAMProjection != nullptr && strlen(pszPAMProjection) > 0 )
284             return pszPAMProjection;
285     }
286 
287     if( pszProjection != nullptr )
288         return pszProjection;
289 
290     return "";
291 }
292 
293 /************************************************************************/
294 /*                          GetGeoTransform()                           */
295 /*                                                                      */
296 /*      By default, we let PAM override the value stored                */
297 /*      inside our file, unless GDAL_GEOREF_SOURCES is defined.         */
298 /************************************************************************/
299 
300 CPLErr GDALGeorefPamDataset::GetGeoTransform( double * padfTransform )
301 
302 {
303     const int nPAMIndex = GetPAMGeorefSrcIndex();
304     if( nPAMIndex >= 0 &&
305         ((bGeoTransformValid && nPAMIndex <= m_nGeoTransformGeorefSrcIndex) ||
306           m_nGeoTransformGeorefSrcIndex < 0 || !bGeoTransformValid) )
307     {
308         if( GDALPamDataset::GetGeoTransform( padfTransform ) == CE_None )
309         {
310             m_nGeoTransformGeorefSrcIndex = nPAMIndex;
311             return CE_None;
312         }
313     }
314 
315     if( bGeoTransformValid )
316     {
317         memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
318         return( CE_None );
319     }
320 
321     return CE_Failure;
322 }
323 
324 /************************************************************************/
325 /*                     GetPAMGeorefSrcIndex()                           */
326 /*                                                                      */
327 /*      Get priority index of PAM (the lower, the more prioritary)      */
328 /************************************************************************/
329 int GDALGeorefPamDataset::GetPAMGeorefSrcIndex()
330 {
331     if( !m_bGotPAMGeorefSrcIndex )
332     {
333         m_bGotPAMGeorefSrcIndex = true;
334         const char* pszGeorefSources = CSLFetchNameValueDef( papszOpenOptions,
335             "GEOREF_SOURCES",
336             CPLGetConfigOption("GDAL_GEOREF_SOURCES", "PAM,OTHER") );
337         char** papszTokens = CSLTokenizeString2(pszGeorefSources, ",", 0);
338         m_nPAMGeorefSrcIndex = CSLFindString(papszTokens, "PAM");
339         CSLDestroy(papszTokens);
340     }
341     return m_nPAMGeorefSrcIndex;
342 }
343 //! @endcond
344