1 : /******************************************************************************
2 : * $Id: gmlutils.cpp 25309 2012-12-15 12:14:44Z rouault $
3 : *
4 : * Project: GML Utils
5 : * Purpose: GML reader
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault
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 OR
22 : * 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 "gmlutils.h"
31 :
32 : #include "cpl_string.h"
33 : #include "ogr_api.h"
34 : #include "ogr_p.h"
35 : #include <string>
36 : #include <map>
37 :
38 : /************************************************************************/
39 : /* GML_ExtractSrsNameFromGeometry() */
40 : /************************************************************************/
41 :
42 1859 : const char* GML_ExtractSrsNameFromGeometry(const CPLXMLNode* const * papsGeometry,
43 : std::string& osWork,
44 : int bConsiderEPSGAsURN)
45 : {
46 1859 : if (papsGeometry[0] != NULL && papsGeometry[1] == NULL)
47 : {
48 1859 : const char* pszSRSName = CPLGetXMLValue((CPLXMLNode*)papsGeometry[0], "srsName", NULL);
49 1859 : if (pszSRSName)
50 : {
51 1194 : int nLen = strlen(pszSRSName);
52 :
53 1194 : if (strncmp(pszSRSName, "EPSG:", 5) == 0 &&
54 : bConsiderEPSGAsURN)
55 : {
56 36 : osWork.reserve(22 + nLen-5);
57 36 : osWork.assign("urn:ogc:def:crs:EPSG::", 22);
58 36 : osWork.append(pszSRSName+5, nLen-5);
59 36 : return osWork.c_str();
60 : }
61 1158 : else if (strncmp(pszSRSName, "http://www.opengis.net/gml/srs/epsg.xml#", 40) == 0)
62 : {
63 48 : osWork.reserve(5 + nLen-40 );
64 48 : osWork.assign("EPSG:", 5);
65 48 : osWork.append(pszSRSName+40, nLen-40);
66 48 : return osWork.c_str();
67 : }
68 : else
69 : {
70 1110 : return pszSRSName;
71 : }
72 : }
73 : }
74 665 : return NULL;
75 : }
76 :
77 : /************************************************************************/
78 : /* GML_IsSRSLatLongOrder() */
79 : /************************************************************************/
80 :
81 549 : int GML_IsSRSLatLongOrder(const char* pszSRSName)
82 : {
83 549 : if (pszSRSName == NULL)
84 13 : return FALSE;
85 :
86 536 : if (strncmp(pszSRSName, "urn:", 4) == 0)
87 : {
88 309 : if (strstr(pszSRSName, ":4326") != NULL)
89 : {
90 : /* Shortcut ... */
91 117 : return TRUE;
92 : }
93 : else
94 : {
95 192 : OGRSpatialReference oSRS;
96 192 : if (oSRS.importFromURN(pszSRSName) == OGRERR_NONE)
97 : {
98 192 : if (oSRS.EPSGTreatsAsLatLong())
99 157 : return TRUE;
100 0 : }
101 : }
102 : }
103 262 : return FALSE;
104 : }
105 :
106 :
107 : /************************************************************************/
108 : /* GML_BuildOGRGeometryFromList_CreateCache() */
109 : /************************************************************************/
110 :
111 : class SRSDesc
112 896 : {
113 : public:
114 : std::string osSRSName;
115 : int bAxisInvert;
116 : OGRSpatialReference* poSRS;
117 :
118 356 : SRSDesc() : bAxisInvert(FALSE), poSRS(NULL)
119 : {
120 356 : }
121 : };
122 :
123 : class SRSCache
124 : {
125 : std::map<std::string, SRSDesc> oMap;
126 : SRSDesc oLastDesc;
127 :
128 : public:
129 :
130 248 : SRSCache()
131 248 : {
132 248 : }
133 :
134 248 : ~SRSCache()
135 : {
136 248 : std::map<std::string, SRSDesc>::iterator oIter;
137 356 : for( oIter = oMap.begin(); oIter != oMap.end(); ++oIter )
138 : {
139 108 : if( oIter->second.poSRS != NULL )
140 108 : oIter->second.poSRS->Release();
141 : }
142 248 : }
143 :
144 1118 : SRSDesc& Get(const std::string& osSRSName)
145 : {
146 1118 : if( osSRSName == oLastDesc.osSRSName )
147 1010 : return oLastDesc;
148 :
149 108 : std::map<std::string, SRSDesc>::iterator oIter = oMap.find(osSRSName);
150 108 : if( oIter != oMap.end() )
151 : {
152 0 : oLastDesc = oIter->second;
153 0 : return oLastDesc;
154 : }
155 :
156 108 : oLastDesc.osSRSName = osSRSName;
157 108 : oLastDesc.bAxisInvert = GML_IsSRSLatLongOrder(osSRSName.c_str());
158 108 : oLastDesc.poSRS = new OGRSpatialReference();
159 108 : if( oLastDesc.poSRS->SetFromUserInput(osSRSName.c_str()) != OGRERR_NONE )
160 : {
161 0 : delete oLastDesc.poSRS;
162 0 : oLastDesc.poSRS = NULL;
163 : }
164 108 : oMap[osSRSName] = oLastDesc;
165 108 : return oLastDesc;
166 : }
167 : };
168 :
169 248 : void* GML_BuildOGRGeometryFromList_CreateCache()
170 : {
171 248 : return new SRSCache();
172 : }
173 :
174 : /************************************************************************/
175 : /* GML_BuildOGRGeometryFromList_DestroyCache() */
176 : /************************************************************************/
177 :
178 248 : void GML_BuildOGRGeometryFromList_DestroyCache(void* hCacheSRS)
179 : {
180 248 : delete (SRSCache*)hCacheSRS;
181 248 : }
182 :
183 : /************************************************************************/
184 : /* GML_BuildOGRGeometryFromList() */
185 : /************************************************************************/
186 :
187 1511 : OGRGeometry* GML_BuildOGRGeometryFromList(const CPLXMLNode* const * papsGeometry,
188 : int bTryToMakeMultipolygons,
189 : int bInvertAxisOrderIfLatLong,
190 : const char* pszDefaultSRSName,
191 : int bConsiderEPSGAsURN,
192 : int bGetSecondaryGeometryOption,
193 : void* hCacheSRS,
194 : int bFaceHoleNegative)
195 : {
196 1511 : OGRGeometry* poGeom = NULL;
197 : int i;
198 1511 : OGRGeometryCollection* poCollection = NULL;
199 3014 : for(i=0;papsGeometry[i] != NULL;i++)
200 : {
201 : OGRGeometry* poSubGeom = GML2OGRGeometry_XMLNode( papsGeometry[i],
202 : bGetSecondaryGeometryOption,
203 : 0, FALSE, TRUE,
204 1503 : bFaceHoleNegative );
205 1503 : if (poSubGeom)
206 : {
207 1503 : if (poGeom == NULL)
208 1503 : poGeom = poSubGeom;
209 : else
210 : {
211 0 : if (poCollection == NULL)
212 : {
213 0 : if (bTryToMakeMultipolygons &&
214 0 : wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
215 0 : wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon)
216 : {
217 0 : OGRGeometryCollection* poGeomColl = new OGRMultiPolygon();
218 0 : poGeomColl->addGeometryDirectly(poGeom);
219 0 : poGeomColl->addGeometryDirectly(poSubGeom);
220 0 : poGeom = poGeomColl;
221 : }
222 0 : else if (bTryToMakeMultipolygons &&
223 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon &&
224 0 : wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon)
225 : {
226 0 : OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom;
227 0 : poGeomColl->addGeometryDirectly(poSubGeom);
228 : }
229 0 : else if (bTryToMakeMultipolygons &&
230 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon &&
231 0 : wkbFlatten(poSubGeom->getGeometryType()) == wkbMultiPolygon)
232 : {
233 0 : OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom;
234 0 : OGRGeometryCollection* poGeomColl2 = (OGRGeometryCollection* )poSubGeom;
235 0 : int nCount = poGeomColl2->getNumGeometries();
236 : int i;
237 0 : for(i=0;i<nCount;i++)
238 : {
239 0 : poGeomColl->addGeometry(poGeomColl2->getGeometryRef(i));
240 : }
241 0 : delete poSubGeom;
242 : }
243 0 : else if (bTryToMakeMultipolygons &&
244 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
245 : {
246 0 : delete poGeom;
247 0 : delete poSubGeom;
248 : return GML_BuildOGRGeometryFromList(papsGeometry, FALSE,
249 : bInvertAxisOrderIfLatLong,
250 : pszDefaultSRSName,
251 : bConsiderEPSGAsURN,
252 : bGetSecondaryGeometryOption,
253 0 : hCacheSRS);
254 : }
255 : else
256 : {
257 0 : poCollection = new OGRGeometryCollection();
258 0 : poCollection->addGeometryDirectly(poGeom);
259 0 : poGeom = poCollection;
260 : }
261 : }
262 0 : if (poCollection != NULL)
263 : {
264 0 : poCollection->addGeometryDirectly(poSubGeom);
265 : }
266 : }
267 : }
268 : }
269 :
270 1511 : if( poGeom == NULL )
271 8 : return NULL;
272 :
273 1503 : std::string osWork;
274 : const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork,
275 1503 : bConsiderEPSGAsURN);
276 1503 : const char* pszNameLookup = pszSRSName;
277 1503 : if( pszNameLookup == NULL )
278 392 : pszNameLookup = pszDefaultSRSName;
279 :
280 1503 : if (pszNameLookup != NULL)
281 : {
282 1118 : SRSCache* poSRSCache = (SRSCache*)hCacheSRS;
283 1118 : SRSDesc& oSRSDesc = poSRSCache->Get(pszNameLookup);
284 1118 : poGeom->assignSpatialReference(oSRSDesc.poSRS);
285 1118 : if (oSRSDesc.bAxisInvert && bInvertAxisOrderIfLatLong)
286 85 : poGeom->swapXY();
287 : }
288 :
289 1503 : return poGeom;
290 : }
291 :
292 : /************************************************************************/
293 : /* GML_GetSRSName() */
294 : /************************************************************************/
295 :
296 62 : char* GML_GetSRSName(const OGRSpatialReference* poSRS, int bLongSRS, int *pbCoordSwap)
297 : {
298 62 : *pbCoordSwap = FALSE;
299 62 : if (poSRS == NULL)
300 0 : return CPLStrdup("");
301 :
302 62 : const char* pszAuthName = NULL;
303 62 : const char* pszAuthCode = NULL;
304 62 : const char* pszTarget = NULL;
305 :
306 62 : if (poSRS->IsProjected())
307 11 : pszTarget = "PROJCS";
308 : else
309 51 : pszTarget = "GEOGCS";
310 :
311 : char szSrsName[50];
312 62 : szSrsName[0] = 0;
313 :
314 62 : pszAuthName = poSRS->GetAuthorityName( pszTarget );
315 62 : if( NULL != pszAuthName )
316 : {
317 51 : if( EQUAL( pszAuthName, "EPSG" ) )
318 : {
319 51 : pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
320 51 : if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
321 : {
322 51 : if (bLongSRS && !((OGRSpatialReference*)poSRS)->EPSGTreatsAsLatLong())
323 : {
324 51 : OGRSpatialReference oSRS;
325 51 : if (oSRS.importFromEPSGA(atoi(pszAuthCode)) == OGRERR_NONE)
326 : {
327 51 : if (oSRS.EPSGTreatsAsLatLong())
328 51 : *pbCoordSwap = TRUE;
329 51 : }
330 : }
331 :
332 51 : if (bLongSRS)
333 : {
334 : sprintf( szSrsName, " srsName=\"urn:ogc:def:crs:%s::%s\"",
335 51 : pszAuthName, pszAuthCode );
336 : }
337 : else
338 : {
339 : sprintf( szSrsName, " srsName=\"%s:%s\"",
340 0 : pszAuthName, pszAuthCode );
341 : }
342 : }
343 : }
344 : }
345 :
346 62 : return CPLStrdup(szSrsName);
347 : }
|