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