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 : std::vector<std::unique_ptr<OGRGeometry>> apoGeom(
111 3 : poNASFeature->GetGeometryCount());
112 :
113 3 : bool bErrored = false, bFiltered = false;
114 3 : CPLString osLastErrorMsg;
115 4 : for (int iGeom = 0; iGeom < poNASFeature->GetGeometryCount(); ++iGeom)
116 : {
117 1 : if (papsGeometry[iGeom])
118 : {
119 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
120 :
121 2 : apoGeom[iGeom].reset(OGRGeometry::FromHandle(
122 1 : OGR_G_CreateFromGMLTree(papsGeometry[iGeom])));
123 1 : CPLPopErrorHandler();
124 1 : if (apoGeom[iGeom] == nullptr)
125 0 : osLastErrorMsg = CPLGetLastErrorMsg();
126 1 : apoGeom[iGeom] =
127 2 : NASReader::ConvertGeometry(std::move(apoGeom[iGeom]));
128 2 : apoGeom[iGeom] = OGRGeometryFactory::forceTo(
129 2 : std::move(apoGeom[iGeom]), GetGeomType());
130 :
131 1 : if (apoGeom[iGeom] == nullptr)
132 0 : bErrored = true;
133 : }
134 :
135 1 : bFiltered = m_poFilterGeom != nullptr &&
136 0 : !FilterGeometry(apoGeom[iGeom].get());
137 1 : if (bErrored || bFiltered)
138 : {
139 : break;
140 : }
141 : }
142 :
143 3 : if (bErrored)
144 : {
145 :
146 0 : CPLString osGMLId;
147 0 : if (poFClass->GetPropertyIndex("gml_id") == 0)
148 : {
149 0 : const GMLProperty *psGMLProperty = poNASFeature->GetProperty(0);
150 0 : if (psGMLProperty && psGMLProperty->nSubProperties == 1)
151 : {
152 : osGMLId.Printf("(gml_id=%s) ",
153 0 : psGMLProperty->papszSubProperties[0]);
154 : }
155 : }
156 :
157 0 : delete poNASFeature;
158 0 : poNASFeature = nullptr;
159 :
160 0 : const bool bGoOn = CPLTestBool(
161 : CPLGetConfigOption("NAS_SKIP_CORRUPTED_FEATURES", "NO"));
162 0 : CPLError(bGoOn ? CE_Warning : CE_Failure, CPLE_AppDefined,
163 : "Geometry of feature %d %scannot be parsed: %s%s",
164 : iNextNASId, osGMLId.c_str(), osLastErrorMsg.c_str(),
165 : bGoOn ? ". Skipping to next feature."
166 : : ". You may set the NAS_SKIP_CORRUPTED_FEATURES "
167 : "configuration option to YES to skip to the next "
168 : "feature");
169 0 : if (bGoOn)
170 0 : continue;
171 :
172 0 : return nullptr;
173 : }
174 :
175 3 : if (bFiltered)
176 0 : continue;
177 :
178 : /* --------------------------------------------------------------------
179 : */
180 : /* Convert the whole feature into an OGRFeature. */
181 : /* --------------------------------------------------------------------
182 : */
183 3 : OGRFeature *poOGRFeature = new OGRFeature(GetLayerDefn());
184 :
185 3 : poOGRFeature->SetFID(iNextNASId);
186 :
187 45 : for (int iField = 0; iField < poFClass->GetPropertyCount(); iField++)
188 : {
189 : const GMLProperty *psGMLProperty =
190 42 : poNASFeature->GetProperty(iField);
191 42 : if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
192 8 : continue;
193 :
194 34 : switch (poFClass->GetProperty(iField)->GetType())
195 : {
196 1 : case GMLPT_Real:
197 : {
198 1 : poOGRFeature->SetField(
199 1 : iField, CPLAtof(psGMLProperty->papszSubProperties[0]));
200 : }
201 1 : break;
202 :
203 0 : case GMLPT_IntegerList:
204 : {
205 0 : int nCount = psGMLProperty->nSubProperties;
206 : int *panIntList =
207 0 : static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
208 :
209 0 : for (int i = 0; i < nCount; i++)
210 0 : panIntList[i] =
211 0 : atoi(psGMLProperty->papszSubProperties[i]);
212 :
213 0 : poOGRFeature->SetField(iField, nCount, panIntList);
214 0 : CPLFree(panIntList);
215 : }
216 0 : break;
217 :
218 0 : case GMLPT_RealList:
219 : {
220 0 : int nCount = psGMLProperty->nSubProperties;
221 : double *padfList = static_cast<double *>(
222 0 : CPLMalloc(sizeof(double) * nCount));
223 :
224 0 : for (int i = 0; i < nCount; i++)
225 0 : padfList[i] =
226 0 : CPLAtof(psGMLProperty->papszSubProperties[i]);
227 :
228 0 : poOGRFeature->SetField(iField, nCount, padfList);
229 0 : CPLFree(padfList);
230 : }
231 0 : break;
232 :
233 2 : case GMLPT_StringList:
234 : {
235 2 : poOGRFeature->SetField(iField,
236 2 : psGMLProperty->papszSubProperties);
237 : }
238 2 : break;
239 :
240 31 : default:
241 31 : poOGRFeature->SetField(
242 31 : iField, psGMLProperty->papszSubProperties[0]);
243 31 : break;
244 : }
245 : }
246 :
247 4 : for (int iGeom = 0; iGeom < poNASFeature->GetGeometryCount(); ++iGeom)
248 : {
249 1 : poOGRFeature->SetGeomField(iGeom, std::move(apoGeom[iGeom]));
250 : }
251 :
252 : /* --------------------------------------------------------------------
253 : */
254 : /* Test against the attribute query. */
255 : /* --------------------------------------------------------------------
256 : */
257 3 : if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
258 : {
259 0 : delete poOGRFeature;
260 0 : continue;
261 : }
262 :
263 : /* --------------------------------------------------------------------
264 : */
265 : /* Wow, we got our desired feature. Return it. */
266 : /* --------------------------------------------------------------------
267 : */
268 3 : delete poNASFeature;
269 :
270 3 : return poOGRFeature;
271 0 : }
272 : }
273 :
274 : /************************************************************************/
275 : /* GetFeatureCount() */
276 : /************************************************************************/
277 :
278 3 : GIntBig OGRNASLayer::GetFeatureCount(int bForce)
279 :
280 : {
281 3 : if (poFClass == nullptr)
282 0 : return 0;
283 :
284 3 : if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
285 0 : return OGRLayer::GetFeatureCount(bForce);
286 :
287 3 : return poFClass->GetFeatureCount();
288 : }
289 :
290 : /************************************************************************/
291 : /* IGetExtent() */
292 : /************************************************************************/
293 :
294 0 : OGRErr OGRNASLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
295 : bool bForce)
296 :
297 : {
298 0 : double dfXMin = 0.0;
299 0 : double dfXMax = 0.0;
300 0 : double dfYMin = 0.0;
301 0 : double dfYMax = 0.0;
302 :
303 0 : if (poFClass != nullptr &&
304 0 : poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax))
305 : {
306 0 : psExtent->MinX = dfXMin;
307 0 : psExtent->MaxX = dfXMax;
308 0 : psExtent->MinY = dfYMin;
309 0 : psExtent->MaxY = dfYMax;
310 :
311 0 : return OGRERR_NONE;
312 : }
313 :
314 0 : return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
315 : }
316 :
317 : /************************************************************************/
318 : /* TestCapability() */
319 : /************************************************************************/
320 :
321 0 : int OGRNASLayer::TestCapability(const char *pszCap) const
322 :
323 : {
324 0 : if (EQUAL(pszCap, OLCFastGetExtent))
325 : {
326 0 : if (poFClass == nullptr)
327 0 : return FALSE;
328 :
329 0 : double dfXMin = 0.0;
330 0 : double dfXMax = 0.0;
331 0 : double dfYMin = 0.0;
332 0 : double dfYMax = 0.0;
333 :
334 0 : return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
335 : }
336 :
337 0 : if (EQUAL(pszCap, OLCFastFeatureCount))
338 : {
339 0 : if (poFClass == nullptr || m_poFilterGeom != nullptr ||
340 0 : m_poAttrQuery != nullptr)
341 0 : return FALSE;
342 :
343 0 : return poFClass->GetFeatureCount() != -1;
344 : }
345 :
346 0 : if (EQUAL(pszCap, OLCStringsAsUTF8))
347 0 : return TRUE;
348 :
349 0 : return FALSE;
350 : }
|