1 : /******************************************************************************
2 : * $Id: gmlutils.cpp 25727 2013-03-10 14:56:33Z 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 1309 : const char* GML_ExtractSrsNameFromGeometry(const CPLXMLNode* const * papsGeometry,
43 : std::string& osWork,
44 : int bConsiderEPSGAsURN)
45 : {
46 1309 : if (papsGeometry[0] != NULL && papsGeometry[1] == NULL)
47 : {
48 1309 : const char* pszSRSName = CPLGetXMLValue((CPLXMLNode*)papsGeometry[0], "srsName", NULL);
49 1309 : if (pszSRSName)
50 : {
51 642 : int nLen = strlen(pszSRSName);
52 :
53 642 : 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 606 : else if (strncmp(pszSRSName, "http://www.opengis.net/gml/srs/epsg.xml#", 40) == 0)
62 : {
63 139 : osWork.reserve(5 + nLen-40 );
64 139 : osWork.assign("EPSG:", 5);
65 139 : osWork.append(pszSRSName+40, nLen-40);
66 139 : return osWork.c_str();
67 : }
68 : else
69 : {
70 467 : return pszSRSName;
71 : }
72 : }
73 : }
74 667 : return NULL;
75 : }
76 :
77 : /************************************************************************/
78 : /* GML_IsSRSLatLongOrder() */
79 : /************************************************************************/
80 :
81 368 : int GML_IsSRSLatLongOrder(const char* pszSRSName)
82 : {
83 368 : if (pszSRSName == NULL)
84 13 : return FALSE;
85 :
86 355 : if (strncmp(pszSRSName, "urn:", 4) == 0)
87 : {
88 128 : if (strstr(pszSRSName, ":4326") != NULL)
89 : {
90 : /* Shortcut ... */
91 82 : return TRUE;
92 : }
93 : else
94 : {
95 46 : OGRSpatialReference oSRS;
96 46 : if (oSRS.importFromURN(pszSRSName) == OGRERR_NONE)
97 : {
98 46 : if (oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting())
99 4 : return TRUE;
100 0 : }
101 : }
102 : }
103 269 : return FALSE;
104 : }
105 :
106 :
107 : /************************************************************************/
108 : /* GML_BuildOGRGeometryFromList_CreateCache() */
109 : /************************************************************************/
110 :
111 : class SRSDesc
112 708 : {
113 : public:
114 : std::string osSRSName;
115 : int bAxisInvert;
116 : OGRSpatialReference* poSRS;
117 :
118 273 : SRSDesc() : bAxisInvert(FALSE), poSRS(NULL)
119 : {
120 273 : }
121 : };
122 :
123 : class SRSCache
124 : {
125 : std::map<std::string, SRSDesc> oMap;
126 : SRSDesc oLastDesc;
127 :
128 : public:
129 :
130 186 : SRSCache()
131 186 : {
132 186 : }
133 :
134 186 : ~SRSCache()
135 : {
136 186 : std::map<std::string, SRSDesc>::iterator oIter;
137 273 : for( oIter = oMap.begin(); oIter != oMap.end(); ++oIter )
138 : {
139 87 : if( oIter->second.poSRS != NULL )
140 87 : oIter->second.poSRS->Release();
141 : }
142 186 : }
143 :
144 566 : SRSDesc& Get(const std::string& osSRSName)
145 : {
146 566 : if( osSRSName == oLastDesc.osSRSName )
147 479 : return oLastDesc;
148 :
149 87 : std::map<std::string, SRSDesc>::iterator oIter = oMap.find(osSRSName);
150 87 : if( oIter != oMap.end() )
151 : {
152 0 : oLastDesc = oIter->second;
153 0 : return oLastDesc;
154 : }
155 :
156 87 : oLastDesc.osSRSName = osSRSName;
157 87 : oLastDesc.bAxisInvert = GML_IsSRSLatLongOrder(osSRSName.c_str());
158 87 : oLastDesc.poSRS = new OGRSpatialReference();
159 87 : if( oLastDesc.poSRS->SetFromUserInput(osSRSName.c_str()) != OGRERR_NONE )
160 : {
161 0 : delete oLastDesc.poSRS;
162 0 : oLastDesc.poSRS = NULL;
163 : }
164 87 : oMap[osSRSName] = oLastDesc;
165 87 : return oLastDesc;
166 : }
167 : };
168 :
169 186 : void* GML_BuildOGRGeometryFromList_CreateCache()
170 : {
171 186 : return new SRSCache();
172 : }
173 :
174 : /************************************************************************/
175 : /* GML_BuildOGRGeometryFromList_DestroyCache() */
176 : /************************************************************************/
177 :
178 186 : void GML_BuildOGRGeometryFromList_DestroyCache(void* hCacheSRS)
179 : {
180 186 : delete (SRSCache*)hCacheSRS;
181 186 : }
182 :
183 : /************************************************************************/
184 : /* GML_BuildOGRGeometryFromList() */
185 : /************************************************************************/
186 :
187 961 : 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 961 : OGRGeometry* poGeom = NULL;
197 : int i;
198 961 : OGRGeometryCollection* poCollection = NULL;
199 1914 : for(i=0;papsGeometry[i] != NULL;i++)
200 : {
201 : OGRGeometry* poSubGeom = GML2OGRGeometry_XMLNode( papsGeometry[i],
202 : bGetSecondaryGeometryOption,
203 : 0, FALSE, TRUE,
204 953 : bFaceHoleNegative );
205 953 : if (poSubGeom)
206 : {
207 953 : if (poGeom == NULL)
208 953 : 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 961 : if( poGeom == NULL )
271 8 : return NULL;
272 :
273 953 : std::string osWork;
274 : const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork,
275 953 : bConsiderEPSGAsURN);
276 953 : const char* pszNameLookup = pszSRSName;
277 953 : if( pszNameLookup == NULL )
278 394 : pszNameLookup = pszDefaultSRSName;
279 :
280 953 : if (pszNameLookup != NULL)
281 : {
282 566 : SRSCache* poSRSCache = (SRSCache*)hCacheSRS;
283 566 : SRSDesc& oSRSDesc = poSRSCache->Get(pszNameLookup);
284 566 : poGeom->assignSpatialReference(oSRSDesc.poSRS);
285 566 : if (oSRSDesc.bAxisInvert && bInvertAxisOrderIfLatLong)
286 63 : poGeom->swapXY();
287 : }
288 :
289 953 : return poGeom;
290 : }
291 :
292 : /************************************************************************/
293 : /* GML_GetSRSName() */
294 : /************************************************************************/
295 :
296 20 : char* GML_GetSRSName(const OGRSpatialReference* poSRS, int bLongSRS, int *pbCoordSwap)
297 : {
298 20 : *pbCoordSwap = FALSE;
299 20 : if (poSRS == NULL)
300 0 : return CPLStrdup("");
301 :
302 20 : const char* pszAuthName = NULL;
303 20 : const char* pszAuthCode = NULL;
304 20 : const char* pszTarget = NULL;
305 :
306 20 : if (poSRS->IsProjected())
307 11 : pszTarget = "PROJCS";
308 : else
309 9 : pszTarget = "GEOGCS";
310 :
311 : char szSrsName[50];
312 20 : szSrsName[0] = 0;
313 :
314 20 : pszAuthName = poSRS->GetAuthorityName( pszTarget );
315 20 : if( NULL != pszAuthName )
316 : {
317 9 : if( EQUAL( pszAuthName, "EPSG" ) )
318 : {
319 9 : pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
320 9 : if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
321 : {
322 9 : if (bLongSRS && !(((OGRSpatialReference*)poSRS)->EPSGTreatsAsLatLong() ||
323 : ((OGRSpatialReference*)poSRS)->EPSGTreatsAsNorthingEasting()))
324 : {
325 9 : OGRSpatialReference oSRS;
326 9 : if (oSRS.importFromEPSGA(atoi(pszAuthCode)) == OGRERR_NONE)
327 : {
328 9 : if (oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting())
329 9 : *pbCoordSwap = TRUE;
330 9 : }
331 : }
332 :
333 9 : if (bLongSRS)
334 : {
335 : sprintf( szSrsName, " srsName=\"urn:ogc:def:crs:%s::%s\"",
336 9 : pszAuthName, pszAuthCode );
337 : }
338 : else
339 : {
340 : sprintf( szSrsName, " srsName=\"%s:%s\"",
341 0 : pszAuthName, pszAuthCode );
342 : }
343 : }
344 : }
345 : }
346 :
347 20 : return CPLStrdup(szSrsName);
348 : }
|