Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OGR
4 : * Purpose: Implements OGRNASLayer class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2010-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 "cpl_conv.h"
31 : #include "cpl_port.h"
32 : #include "cpl_string.h"
33 : #include "ogr_nas.h"
34 :
35 : /************************************************************************/
36 : /* OGRNASLayer() */
37 : /************************************************************************/
38 :
39 3 : OGRNASLayer::OGRNASLayer(const char *pszName, OGRNASDataSource *poDSIn)
40 : : poFeatureDefn(new OGRFeatureDefn(
41 3 : pszName + (STARTS_WITH_CI(pszName, "ogr:") ? 4 : 0))),
42 : iNextNASId(0), poDS(poDSIn),
43 : // Readers should get the corresponding GMLFeatureClass and cache it.
44 6 : poFClass(poDS->GetReader()->GetClass(pszName))
45 : {
46 3 : SetDescription(poFeatureDefn->GetName());
47 3 : poFeatureDefn->Reference();
48 3 : poFeatureDefn->SetGeomType(wkbNone);
49 3 : }
50 :
51 : /************************************************************************/
52 : /* ~OGRNASLayer() */
53 : /************************************************************************/
54 :
55 6 : OGRNASLayer::~OGRNASLayer()
56 :
57 : {
58 3 : if (poFeatureDefn)
59 3 : poFeatureDefn->Release();
60 6 : }
61 :
62 : /************************************************************************/
63 : /* ResetReading() */
64 : /************************************************************************/
65 :
66 6 : void OGRNASLayer::ResetReading()
67 :
68 : {
69 6 : iNextNASId = 0;
70 6 : poDS->GetReader()->ResetReading();
71 6 : if (poFClass)
72 6 : poDS->GetReader()->SetFilteredClassName(poFClass->GetElementName());
73 6 : }
74 :
75 : /************************************************************************/
76 : /* GetNextFeature() */
77 : /************************************************************************/
78 :
79 3 : OGRFeature *OGRNASLayer::GetNextFeature()
80 :
81 : {
82 3 : GMLFeature *poNASFeature = nullptr;
83 :
84 3 : if (iNextNASId == 0)
85 3 : ResetReading();
86 :
87 : /* ==================================================================== */
88 : /* Loop till we find and translate a feature meeting all our */
89 : /* requirements. */
90 : /* ==================================================================== */
91 : while (true)
92 : {
93 : /* --------------------------------------------------------------------
94 : */
95 : /* Cleanup last feature, and get a new raw nas feature. */
96 : /* --------------------------------------------------------------------
97 : */
98 3 : delete poNASFeature;
99 3 : poNASFeature = poDS->GetReader()->NextFeature();
100 3 : if (poNASFeature == nullptr)
101 3 : return nullptr;
102 :
103 : /* --------------------------------------------------------------------
104 : */
105 : /* Is it of the proper feature class? */
106 : /* --------------------------------------------------------------------
107 : */
108 :
109 : // We count reading low level NAS features as a feature read for
110 : // work checking purposes, though at least we didn't necessary
111 : // have to turn it into an OGRFeature.
112 3 : m_nFeaturesRead++;
113 :
114 3 : if (poNASFeature->GetClass() != poFClass)
115 0 : continue;
116 :
117 3 : iNextNASId++;
118 :
119 : /* --------------------------------------------------------------------
120 : */
121 : /* Does it satisfy the spatial query, if there is one? */
122 : /* --------------------------------------------------------------------
123 : */
124 3 : const CPLXMLNode *const *papsGeometry = poNASFeature->GetGeometryList();
125 :
126 3 : std::vector<OGRGeometry *> poGeom(poNASFeature->GetGeometryCount());
127 :
128 3 : bool bErrored = false, bFiltered = false;
129 3 : CPLString osLastErrorMsg;
130 4 : for (int iGeom = 0; iGeom < poNASFeature->GetGeometryCount(); ++iGeom)
131 : {
132 1 : if (papsGeometry[iGeom] == nullptr)
133 : {
134 0 : poGeom[iGeom] = nullptr;
135 : }
136 : else
137 : {
138 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
139 :
140 2 : poGeom[iGeom] =
141 1 : (OGRGeometry *)OGR_G_CreateFromGMLTree(papsGeometry[iGeom]);
142 1 : CPLPopErrorHandler();
143 1 : if (poGeom[iGeom] == nullptr)
144 0 : osLastErrorMsg = CPLGetLastErrorMsg();
145 1 : poGeom[iGeom] = NASReader::ConvertGeometry(poGeom[iGeom]);
146 2 : poGeom[iGeom] =
147 1 : OGRGeometryFactory::forceTo(poGeom[iGeom], GetGeomType());
148 : // poGeom->dumpReadable( 0, "NAS: " );
149 :
150 1 : if (poGeom[iGeom] == nullptr)
151 0 : bErrored = true;
152 : }
153 :
154 1 : bFiltered =
155 1 : m_poFilterGeom != nullptr && !FilterGeometry(poGeom[iGeom]);
156 1 : if (bErrored || bFiltered)
157 : {
158 0 : while (iGeom > 0)
159 0 : delete poGeom[--iGeom];
160 0 : poGeom.clear();
161 :
162 0 : break;
163 : }
164 : }
165 :
166 3 : if (bErrored)
167 : {
168 :
169 0 : CPLString osGMLId;
170 0 : if (poFClass->GetPropertyIndex("gml_id") == 0)
171 : {
172 0 : const GMLProperty *psGMLProperty = poNASFeature->GetProperty(0);
173 0 : if (psGMLProperty && psGMLProperty->nSubProperties == 1)
174 : {
175 : osGMLId.Printf("(gml_id=%s) ",
176 0 : psGMLProperty->papszSubProperties[0]);
177 : }
178 : }
179 :
180 0 : delete poNASFeature;
181 0 : poNASFeature = nullptr;
182 :
183 0 : const bool bGoOn = CPLTestBool(
184 : CPLGetConfigOption("NAS_SKIP_CORRUPTED_FEATURES", "NO"));
185 0 : CPLError(bGoOn ? CE_Warning : CE_Failure, CPLE_AppDefined,
186 : "Geometry of feature %d %scannot be parsed: %s%s",
187 : iNextNASId, osGMLId.c_str(), osLastErrorMsg.c_str(),
188 : bGoOn ? ". Skipping to next feature."
189 : : ". You may set the NAS_SKIP_CORRUPTED_FEATURES "
190 : "configuration option to YES to skip to the next "
191 : "feature");
192 0 : if (bGoOn)
193 0 : continue;
194 :
195 0 : return nullptr;
196 : }
197 :
198 3 : if (bFiltered)
199 0 : continue;
200 :
201 : /* --------------------------------------------------------------------
202 : */
203 : /* Convert the whole feature into an OGRFeature. */
204 : /* --------------------------------------------------------------------
205 : */
206 3 : OGRFeature *poOGRFeature = new OGRFeature(GetLayerDefn());
207 :
208 3 : poOGRFeature->SetFID(iNextNASId);
209 :
210 45 : for (int iField = 0; iField < poFClass->GetPropertyCount(); iField++)
211 : {
212 : const GMLProperty *psGMLProperty =
213 42 : poNASFeature->GetProperty(iField);
214 42 : if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
215 8 : continue;
216 :
217 34 : switch (poFClass->GetProperty(iField)->GetType())
218 : {
219 1 : case GMLPT_Real:
220 : {
221 1 : poOGRFeature->SetField(
222 1 : iField, CPLAtof(psGMLProperty->papszSubProperties[0]));
223 : }
224 1 : break;
225 :
226 0 : case GMLPT_IntegerList:
227 : {
228 0 : int nCount = psGMLProperty->nSubProperties;
229 : int *panIntList =
230 0 : static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
231 :
232 0 : for (int i = 0; i < nCount; i++)
233 0 : panIntList[i] =
234 0 : atoi(psGMLProperty->papszSubProperties[i]);
235 :
236 0 : poOGRFeature->SetField(iField, nCount, panIntList);
237 0 : CPLFree(panIntList);
238 : }
239 0 : break;
240 :
241 0 : case GMLPT_RealList:
242 : {
243 0 : int nCount = psGMLProperty->nSubProperties;
244 : double *padfList = static_cast<double *>(
245 0 : CPLMalloc(sizeof(double) * nCount));
246 :
247 0 : for (int i = 0; i < nCount; i++)
248 0 : padfList[i] =
249 0 : CPLAtof(psGMLProperty->papszSubProperties[i]);
250 :
251 0 : poOGRFeature->SetField(iField, nCount, padfList);
252 0 : CPLFree(padfList);
253 : }
254 0 : break;
255 :
256 2 : case GMLPT_StringList:
257 : {
258 2 : poOGRFeature->SetField(iField,
259 2 : psGMLProperty->papszSubProperties);
260 : }
261 2 : break;
262 :
263 31 : default:
264 31 : poOGRFeature->SetField(
265 31 : iField, psGMLProperty->papszSubProperties[0]);
266 31 : break;
267 : }
268 : }
269 :
270 4 : for (int iGeom = 0; iGeom < poNASFeature->GetGeometryCount(); ++iGeom)
271 : {
272 1 : poOGRFeature->SetGeomFieldDirectly(iGeom, poGeom[iGeom]);
273 1 : poGeom[iGeom] = nullptr;
274 : }
275 3 : poGeom.clear();
276 :
277 : /* --------------------------------------------------------------------
278 : */
279 : /* Test against the attribute query. */
280 : /* --------------------------------------------------------------------
281 : */
282 3 : if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
283 : {
284 0 : delete poOGRFeature;
285 0 : continue;
286 : }
287 :
288 : /* --------------------------------------------------------------------
289 : */
290 : /* Wow, we got our desired feature. Return it. */
291 : /* --------------------------------------------------------------------
292 : */
293 3 : delete poNASFeature;
294 :
295 3 : return poOGRFeature;
296 0 : }
297 :
298 : return nullptr;
299 : }
300 :
301 : /************************************************************************/
302 : /* GetFeatureCount() */
303 : /************************************************************************/
304 :
305 3 : GIntBig OGRNASLayer::GetFeatureCount(int bForce)
306 :
307 : {
308 3 : if (poFClass == nullptr)
309 0 : return 0;
310 :
311 3 : if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
312 0 : return OGRLayer::GetFeatureCount(bForce);
313 :
314 3 : return poFClass->GetFeatureCount();
315 : }
316 :
317 : /************************************************************************/
318 : /* GetExtent() */
319 : /************************************************************************/
320 :
321 0 : OGRErr OGRNASLayer::GetExtent(OGREnvelope *psExtent, int bForce)
322 :
323 : {
324 0 : double dfXMin = 0.0;
325 0 : double dfXMax = 0.0;
326 0 : double dfYMin = 0.0;
327 0 : double dfYMax = 0.0;
328 :
329 0 : if (poFClass != nullptr &&
330 0 : poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax))
331 : {
332 0 : psExtent->MinX = dfXMin;
333 0 : psExtent->MaxX = dfXMax;
334 0 : psExtent->MinY = dfYMin;
335 0 : psExtent->MaxY = dfYMax;
336 :
337 0 : return OGRERR_NONE;
338 : }
339 :
340 0 : return OGRLayer::GetExtent(psExtent, bForce);
341 : }
342 :
343 : /************************************************************************/
344 : /* TestCapability() */
345 : /************************************************************************/
346 :
347 0 : int OGRNASLayer::TestCapability(const char *pszCap)
348 :
349 : {
350 0 : if (EQUAL(pszCap, OLCFastGetExtent))
351 : {
352 0 : if (poFClass == nullptr)
353 0 : return FALSE;
354 :
355 0 : double dfXMin = 0.0;
356 0 : double dfXMax = 0.0;
357 0 : double dfYMin = 0.0;
358 0 : double dfYMax = 0.0;
359 :
360 0 : return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
361 : }
362 :
363 0 : if (EQUAL(pszCap, OLCFastFeatureCount))
364 : {
365 0 : if (poFClass == nullptr || m_poFilterGeom != nullptr ||
366 0 : m_poAttrQuery != nullptr)
367 0 : return FALSE;
368 :
369 0 : return poFClass->GetFeatureCount() != -1;
370 : }
371 :
372 0 : if (EQUAL(pszCap, OLCStringsAsUTF8))
373 0 : return TRUE;
374 :
375 0 : return FALSE;
376 : }
|