1 : /******************************************************************************
2 : * $Id: gmlutils.cpp 22954 2011-08-19 21:47:19Z 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 :
37 : /************************************************************************/
38 : /* GML_ExtractSrsNameFromGeometry() */
39 : /************************************************************************/
40 :
41 695 : const char* GML_ExtractSrsNameFromGeometry(const CPLXMLNode* const * papsGeometry,
42 : std::string& osWork,
43 : int bConsiderEPSGAsURN)
44 : {
45 695 : if (papsGeometry[0] != NULL && papsGeometry[1] == NULL)
46 : {
47 695 : const char* pszSRSName = CPLGetXMLValue((CPLXMLNode*)papsGeometry[0], "srsName", NULL);
48 695 : if (pszSRSName)
49 : {
50 403 : int nLen = strlen(pszSRSName);
51 :
52 403 : if (strncmp(pszSRSName, "EPSG:", 5) == 0 &&
53 : bConsiderEPSGAsURN)
54 : {
55 36 : osWork.reserve(22 + nLen-5);
56 36 : osWork.assign("urn:ogc:def:crs:EPSG::", 22);
57 36 : osWork.append(pszSRSName+5, nLen-5);
58 36 : return osWork.c_str();
59 : }
60 367 : else if (strncmp(pszSRSName, "http://www.opengis.net/gml/srs/epsg.xml#", 40) == 0)
61 : {
62 42 : osWork.reserve(5 + nLen-40 );
63 42 : osWork.assign("EPSG:", 5);
64 42 : osWork.append(pszSRSName+40, nLen-40);
65 42 : return osWork.c_str();
66 : }
67 : else
68 : {
69 325 : return pszSRSName;
70 : }
71 : }
72 : }
73 292 : return NULL;
74 : }
75 :
76 : /************************************************************************/
77 : /* GML_IsSRSLatLongOrder() */
78 : /************************************************************************/
79 :
80 193 : int GML_IsSRSLatLongOrder(const char* pszSRSName)
81 : {
82 193 : if (pszSRSName == NULL)
83 13 : return FALSE;
84 :
85 180 : if (strncmp(pszSRSName, "urn:", 4) == 0)
86 : {
87 68 : if (strstr(pszSRSName, ":4326") != NULL)
88 : {
89 : /* Shortcut ... */
90 56 : return TRUE;
91 : }
92 : else
93 : {
94 12 : OGRSpatialReference oSRS;
95 12 : if (oSRS.importFromURN(pszSRSName) == OGRERR_NONE)
96 : {
97 12 : if (oSRS.EPSGTreatsAsLatLong())
98 0 : return TRUE;
99 0 : }
100 : }
101 : }
102 124 : return FALSE;
103 : }
104 :
105 :
106 : /************************************************************************/
107 : /* GML_BuildOGRGeometryFromList_CreateCache() */
108 : /************************************************************************/
109 :
110 : class SRSCache
111 238 : {
112 : public:
113 : std::string osLastSRSName;
114 : int bAxisInvertLastSRSName;
115 : };
116 :
117 119 : void* GML_BuildOGRGeometryFromList_CreateCache()
118 : {
119 119 : return new SRSCache();
120 : }
121 :
122 : /************************************************************************/
123 : /* GML_BuildOGRGeometryFromList_DestroyCache() */
124 : /************************************************************************/
125 :
126 119 : void GML_BuildOGRGeometryFromList_DestroyCache(void* hCacheSRS)
127 : {
128 119 : delete (SRSCache*)hCacheSRS;
129 119 : }
130 :
131 : /************************************************************************/
132 : /* GML_BuildOGRGeometryFromList() */
133 : /************************************************************************/
134 :
135 519 : OGRGeometry* GML_BuildOGRGeometryFromList(const CPLXMLNode* const * papsGeometry,
136 : int bTryToMakeMultipolygons,
137 : int bInvertAxisOrderIfLatLong,
138 : const char* pszDefaultSRSName,
139 : int bConsiderEPSGAsURN,
140 : int bGetSecondaryGeometryOption,
141 : void* hCacheSRS)
142 : {
143 519 : OGRGeometry* poGeom = NULL;
144 : int i;
145 519 : OGRGeometryCollection* poCollection = NULL;
146 1030 : for(i=0;papsGeometry[i] != NULL;i++)
147 : {
148 : OGRGeometry* poSubGeom = GML2OGRGeometry_XMLNode( papsGeometry[i],
149 511 : bGetSecondaryGeometryOption );
150 511 : if (poSubGeom)
151 : {
152 511 : if (poGeom == NULL)
153 511 : poGeom = poSubGeom;
154 : else
155 : {
156 0 : if (poCollection == NULL)
157 : {
158 0 : if (bTryToMakeMultipolygons &&
159 0 : wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
160 0 : wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon)
161 : {
162 0 : OGRGeometryCollection* poGeomColl = new OGRMultiPolygon();
163 0 : poGeomColl->addGeometryDirectly(poGeom);
164 0 : poGeomColl->addGeometryDirectly(poSubGeom);
165 0 : poGeom = poGeomColl;
166 : }
167 0 : else if (bTryToMakeMultipolygons &&
168 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon &&
169 0 : wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon)
170 : {
171 0 : OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom;
172 0 : poGeomColl->addGeometryDirectly(poSubGeom);
173 : }
174 0 : else if (bTryToMakeMultipolygons &&
175 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon &&
176 0 : wkbFlatten(poSubGeom->getGeometryType()) == wkbMultiPolygon)
177 : {
178 0 : OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom;
179 0 : OGRGeometryCollection* poGeomColl2 = (OGRGeometryCollection* )poSubGeom;
180 0 : int nCount = poGeomColl2->getNumGeometries();
181 : int i;
182 0 : for(i=0;i<nCount;i++)
183 : {
184 0 : poGeomColl->addGeometry(poGeomColl2->getGeometryRef(i));
185 : }
186 0 : delete poSubGeom;
187 : }
188 0 : else if (bTryToMakeMultipolygons &&
189 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
190 : {
191 0 : delete poGeom;
192 0 : delete poSubGeom;
193 : return GML_BuildOGRGeometryFromList(papsGeometry, FALSE,
194 : bInvertAxisOrderIfLatLong,
195 : pszDefaultSRSName,
196 : bConsiderEPSGAsURN,
197 : bGetSecondaryGeometryOption,
198 0 : hCacheSRS);
199 : }
200 : else
201 : {
202 0 : poCollection = new OGRGeometryCollection();
203 0 : poCollection->addGeometryDirectly(poGeom);
204 0 : poGeom = poCollection;
205 : }
206 : }
207 0 : if (poCollection != NULL)
208 : {
209 0 : poCollection->addGeometryDirectly(poSubGeom);
210 : }
211 : }
212 : }
213 : }
214 :
215 519 : if ( poGeom != NULL && bInvertAxisOrderIfLatLong )
216 : {
217 490 : std::string osWork;
218 : const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork,
219 490 : bConsiderEPSGAsURN);
220 490 : const char* pszNameLookup = pszSRSName ? pszSRSName : pszDefaultSRSName;
221 490 : if (pszNameLookup != NULL)
222 : {
223 301 : SRSCache* poSRSCache = (SRSCache*)hCacheSRS;
224 : int bSwap;
225 301 : if (strcmp(poSRSCache->osLastSRSName.c_str(), pszNameLookup) == 0)
226 : {
227 254 : bSwap = poSRSCache->bAxisInvertLastSRSName;
228 : }
229 : else
230 : {
231 47 : bSwap = GML_IsSRSLatLongOrder(pszNameLookup);
232 47 : poSRSCache->osLastSRSName = pszNameLookup;
233 47 : poSRSCache->bAxisInvertLastSRSName= bSwap;
234 : }
235 301 : if (bSwap)
236 63 : poGeom->swapXY();
237 490 : }
238 : }
239 :
240 519 : return poGeom;
241 : }
242 :
243 : /************************************************************************/
244 : /* GML_GetSRSName() */
245 : /************************************************************************/
246 :
247 20 : char* GML_GetSRSName(const OGRSpatialReference* poSRS, int bLongSRS, int *pbCoordSwap)
248 : {
249 20 : *pbCoordSwap = FALSE;
250 20 : if (poSRS == NULL)
251 0 : return CPLStrdup("");
252 :
253 20 : const char* pszAuthName = NULL;
254 20 : const char* pszAuthCode = NULL;
255 20 : const char* pszTarget = NULL;
256 :
257 20 : if (poSRS->IsProjected())
258 11 : pszTarget = "PROJCS";
259 : else
260 9 : pszTarget = "GEOGCS";
261 :
262 : char szSrsName[50];
263 20 : szSrsName[0] = 0;
264 :
265 20 : pszAuthName = poSRS->GetAuthorityName( pszTarget );
266 20 : if( NULL != pszAuthName )
267 : {
268 9 : if( EQUAL( pszAuthName, "EPSG" ) )
269 : {
270 9 : pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
271 9 : if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
272 : {
273 9 : if (bLongSRS && !((OGRSpatialReference*)poSRS)->EPSGTreatsAsLatLong())
274 : {
275 9 : OGRSpatialReference oSRS;
276 9 : if (oSRS.importFromEPSGA(atoi(pszAuthCode)) == OGRERR_NONE)
277 : {
278 9 : if (oSRS.EPSGTreatsAsLatLong())
279 9 : *pbCoordSwap = TRUE;
280 9 : }
281 : }
282 :
283 9 : if (bLongSRS)
284 : {
285 : sprintf( szSrsName, " srsName=\"urn:ogc:def:crs:%s::%s\"",
286 9 : pszAuthName, pszAuthCode );
287 : }
288 : else
289 : {
290 : sprintf( szSrsName, " srsName=\"%s:%s\"",
291 0 : pszAuthName, pszAuthCode );
292 : }
293 : }
294 : }
295 : }
296 :
297 20 : return CPLStrdup(szSrsName);
298 : }
|