Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: SDTSReader
4 : * Purpose: Implements OGRSDTSLayer class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "ogr_sdts.h"
14 : #include "cpl_conv.h"
15 : #include "cpl_string.h"
16 :
17 : /************************************************************************/
18 : /* OGRSDTSLayer() */
19 : /* */
20 : /* Note that the OGRSDTSLayer assumes ownership of the passed */
21 : /* OGRFeatureDefn object. */
22 : /************************************************************************/
23 :
24 8 : OGRSDTSLayer::OGRSDTSLayer(SDTSTransfer *poTransferIn, int iLayerIn,
25 8 : OGRSDTSDataSource *poDSIn)
26 : : poFeatureDefn(nullptr), poTransfer(poTransferIn), iLayer(iLayerIn),
27 8 : poReader(poTransferIn->GetLayerIndexedReader(iLayerIn)), poDS(poDSIn)
28 : {
29 : /* -------------------------------------------------------------------- */
30 : /* Define the feature. */
31 : /* -------------------------------------------------------------------- */
32 8 : const int iCATDEntry = poTransfer->GetLayerCATDEntry(iLayer);
33 :
34 8 : poFeatureDefn =
35 8 : new OGRFeatureDefn(poTransfer->GetCATD()->GetEntryModule(iCATDEntry));
36 8 : SetDescription(poFeatureDefn->GetName());
37 8 : poFeatureDefn->Reference();
38 8 : poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poDS->GetSpatialRef());
39 :
40 16 : OGRFieldDefn oRecId("RCID", OFTInteger);
41 8 : poFeatureDefn->AddFieldDefn(&oRecId);
42 :
43 8 : if (poTransfer->GetLayerType(iLayer) == SLTPoint)
44 : {
45 3 : poFeatureDefn->SetGeomType(wkbPoint);
46 : }
47 5 : else if (poTransfer->GetLayerType(iLayer) == SLTLine)
48 : {
49 1 : poFeatureDefn->SetGeomType(wkbLineString);
50 :
51 1 : oRecId.SetName("SNID");
52 1 : poFeatureDefn->AddFieldDefn(&oRecId);
53 :
54 1 : oRecId.SetName("ENID");
55 1 : poFeatureDefn->AddFieldDefn(&oRecId);
56 : }
57 4 : else if (poTransfer->GetLayerType(iLayer) == SLTPoly)
58 : {
59 1 : poFeatureDefn->SetGeomType(wkbPolygon);
60 : }
61 3 : else if (poTransfer->GetLayerType(iLayer) == SLTAttr)
62 : {
63 3 : poFeatureDefn->SetGeomType(wkbNone);
64 : }
65 :
66 : /* -------------------------------------------------------------------- */
67 : /* Add schema from referenced attribute records. */
68 : /* -------------------------------------------------------------------- */
69 8 : char **papszATIDRefs = nullptr;
70 :
71 8 : if (poTransfer->GetLayerType(iLayer) != SLTAttr)
72 5 : papszATIDRefs = poReader->ScanModuleReferences();
73 : else
74 3 : papszATIDRefs = CSLAddString(
75 3 : papszATIDRefs, poTransfer->GetCATD()->GetEntryModule(iCATDEntry));
76 :
77 12 : for (int iTable = 0;
78 12 : papszATIDRefs != nullptr && papszATIDRefs[iTable] != nullptr; iTable++)
79 : {
80 : /* --------------------------------------------------------------------
81 : */
82 : /* Get the attribute table reader, and the associated user */
83 : /* attribute field. */
84 : /* --------------------------------------------------------------------
85 : */
86 4 : const int nLayerIdx = poTransfer->FindLayer(papszATIDRefs[iTable]);
87 4 : if (nLayerIdx < 0)
88 0 : continue;
89 0 : SDTSAttrReader *poAttrReader = dynamic_cast<SDTSAttrReader *>(
90 4 : poTransfer->GetLayerIndexedReader(nLayerIdx));
91 :
92 4 : if (poAttrReader == nullptr)
93 0 : continue;
94 :
95 : DDFFieldDefn *poFDefn =
96 4 : poAttrReader->GetModule()->FindFieldDefn("ATTP");
97 4 : if (poFDefn == nullptr)
98 0 : poFDefn = poAttrReader->GetModule()->FindFieldDefn("ATTS");
99 4 : if (poFDefn == nullptr)
100 0 : continue;
101 :
102 : /* --------------------------------------------------------------------
103 : */
104 : /* Process each user subfield on the attribute table into an */
105 : /* OGR field definition. */
106 : /* --------------------------------------------------------------------
107 : */
108 64 : for (int iSF = 0; iSF < poFDefn->GetSubfieldCount(); iSF++)
109 : {
110 60 : DDFSubfieldDefn *poSFDefn = poFDefn->GetSubfield(iSF);
111 60 : const int nWidth = poSFDefn->GetWidth();
112 :
113 : char *pszFieldName =
114 60 : poFeatureDefn->GetFieldIndex(poSFDefn->GetName()) != -1
115 60 : ? CPLStrdup(CPLSPrintf("%s_%s", papszATIDRefs[iTable],
116 : poSFDefn->GetName()))
117 60 : : CPLStrdup(poSFDefn->GetName());
118 :
119 60 : switch (poSFDefn->GetType())
120 : {
121 44 : case DDFString:
122 : {
123 88 : OGRFieldDefn oStrField(pszFieldName, OFTString);
124 :
125 44 : if (nWidth != 0)
126 44 : oStrField.SetWidth(nWidth);
127 :
128 44 : poFeatureDefn->AddFieldDefn(&oStrField);
129 : }
130 44 : break;
131 :
132 4 : case DDFInt:
133 : {
134 8 : OGRFieldDefn oIntField(pszFieldName, OFTInteger);
135 :
136 4 : if (nWidth != 0)
137 4 : oIntField.SetWidth(nWidth);
138 :
139 4 : poFeatureDefn->AddFieldDefn(&oIntField);
140 : }
141 4 : break;
142 :
143 12 : case DDFFloat:
144 : {
145 24 : OGRFieldDefn oRealField(pszFieldName, OFTReal);
146 :
147 : // We don't have a precision in DDF files, so we never even
148 : // use the width. Otherwise with a precision of zero the
149 : // result would look like an integer.
150 :
151 12 : poFeatureDefn->AddFieldDefn(&oRealField);
152 : }
153 12 : break;
154 :
155 0 : default:
156 0 : break;
157 : }
158 :
159 60 : CPLFree(pszFieldName);
160 : } /* next iSF (subfield) */
161 : } /* next iTable */
162 8 : CSLDestroy(papszATIDRefs);
163 8 : }
164 :
165 : /************************************************************************/
166 : /* ~OGRSDTSLayer() */
167 : /************************************************************************/
168 :
169 16 : OGRSDTSLayer::~OGRSDTSLayer()
170 :
171 : {
172 8 : if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr)
173 : {
174 16 : CPLDebug("SDTS", "%d features read on layer '%s'.",
175 8 : static_cast<int>(m_nFeaturesRead), poFeatureDefn->GetName());
176 : }
177 :
178 8 : if (poFeatureDefn)
179 8 : poFeatureDefn->Release();
180 16 : }
181 :
182 : /************************************************************************/
183 : /* ResetReading() */
184 : /************************************************************************/
185 :
186 16 : void OGRSDTSLayer::ResetReading()
187 :
188 : {
189 16 : poReader->Rewind();
190 16 : }
191 :
192 : /************************************************************************/
193 : /* AssignAttrRecordToFeature() */
194 : /************************************************************************/
195 :
196 195 : static void AssignAttrRecordToFeature(OGRFeature *poFeature,
197 : CPL_UNUSED SDTSTransfer *poTransfer,
198 : DDFField *poSR)
199 : {
200 : /* -------------------------------------------------------------------- */
201 : /* Process each subfield in the record. */
202 : /* -------------------------------------------------------------------- */
203 195 : DDFFieldDefn *poFDefn = poSR->GetFieldDefn();
204 :
205 3027 : for (int iSF = 0; iSF < poFDefn->GetSubfieldCount(); iSF++)
206 : {
207 2832 : DDFSubfieldDefn *poSFDefn = poFDefn->GetSubfield(iSF);
208 2832 : int nMaxBytes = 0;
209 2832 : const char *pachData = poSR->GetSubfieldData(poSFDefn, &nMaxBytes);
210 : /* --------------------------------------------------------------------
211 : */
212 : /* Identify this field on the feature. */
213 : /* --------------------------------------------------------------------
214 : */
215 2832 : const int iField = poFeature->GetFieldIndex(poSFDefn->GetName());
216 :
217 : /* --------------------------------------------------------------------
218 : */
219 : /* Handle each of the types. */
220 : /* --------------------------------------------------------------------
221 : */
222 2832 : switch (poSFDefn->GetType())
223 : {
224 2466 : case DDFString:
225 : {
226 : const char *pszValue =
227 2466 : poSFDefn->ExtractStringData(pachData, nMaxBytes, nullptr);
228 :
229 2466 : if (iField != -1)
230 2466 : poFeature->SetField(iField, pszValue);
231 2466 : break;
232 : }
233 24 : case DDFFloat:
234 : {
235 : double dfValue =
236 24 : poSFDefn->ExtractFloatData(pachData, nMaxBytes, nullptr);
237 :
238 24 : if (iField != -1)
239 24 : poFeature->SetField(iField, dfValue);
240 24 : break;
241 : }
242 342 : case DDFInt:
243 : {
244 : int nValue =
245 342 : poSFDefn->ExtractIntData(pachData, nMaxBytes, nullptr);
246 :
247 342 : if (iField != -1)
248 342 : poFeature->SetField(iField, nValue);
249 342 : break;
250 : }
251 0 : default:
252 0 : break;
253 : }
254 : } /* next subfield */
255 195 : }
256 :
257 : /************************************************************************/
258 : /* GetNextUnfilteredFeature() */
259 : /************************************************************************/
260 :
261 391 : OGRFeature *OGRSDTSLayer::GetNextUnfilteredFeature()
262 :
263 : {
264 : /* -------------------------------------------------------------------- */
265 : /* If not done before we need to assemble the geometry for a */
266 : /* polygon layer. */
267 : /* -------------------------------------------------------------------- */
268 391 : if (poTransfer->GetLayerType(iLayer) == SLTPoly)
269 : {
270 38 : ((SDTSPolygonReader *)poReader)->AssembleRings(poTransfer, iLayer);
271 : }
272 :
273 : /* -------------------------------------------------------------------- */
274 : /* Fetch the next sdts style feature object from the reader. */
275 : /* -------------------------------------------------------------------- */
276 391 : SDTSFeature *poSDTSFeature = poReader->GetNextFeature();
277 : // Retain now the IsIndexed state to determine if we must delete or
278 : // not poSDTSFeature when done with it, because later calls might cause
279 : // indexing.
280 391 : const bool bIsIndexed = CPL_TO_BOOL(poReader->IsIndexed());
281 :
282 391 : if (poSDTSFeature == nullptr)
283 8 : return nullptr;
284 :
285 : /* -------------------------------------------------------------------- */
286 : /* Create the OGR feature. */
287 : /* -------------------------------------------------------------------- */
288 383 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
289 :
290 383 : m_nFeaturesRead++;
291 :
292 383 : switch (poTransfer->GetLayerType(iLayer))
293 : {
294 : /* --------------------------------------------------------------------
295 : */
296 : /* Translate point feature specific information and geometry.
297 : */
298 : /* --------------------------------------------------------------------
299 : */
300 129 : case SLTPoint:
301 : {
302 129 : SDTSRawPoint *poPoint = (SDTSRawPoint *)poSDTSFeature;
303 :
304 129 : poFeature->SetGeometryDirectly(
305 129 : new OGRPoint(poPoint->dfX, poPoint->dfY, poPoint->dfZ));
306 : }
307 129 : break;
308 :
309 : /* --------------------------------------------------------------------
310 : */
311 : /* Translate line feature specific information and geometry. */
312 : /* --------------------------------------------------------------------
313 : */
314 28 : case SLTLine:
315 : {
316 28 : SDTSRawLine *poLine = (SDTSRawLine *)poSDTSFeature;
317 28 : OGRLineString *poOGRLine = new OGRLineString();
318 :
319 28 : poOGRLine->setPoints(poLine->nVertices, poLine->padfX,
320 28 : poLine->padfY, poLine->padfZ);
321 28 : poFeature->SetGeometryDirectly(poOGRLine);
322 28 : poFeature->SetField("SNID", (int)poLine->oStartNode.nRecord);
323 28 : poFeature->SetField("ENID", (int)poLine->oEndNode.nRecord);
324 : }
325 28 : break;
326 :
327 : /* --------------------------------------------------------------------
328 : */
329 : /* Translate polygon feature specific information and geometry.
330 : */
331 : /* --------------------------------------------------------------------
332 : */
333 37 : case SLTPoly:
334 : {
335 37 : SDTSRawPolygon *poPoly = (SDTSRawPolygon *)poSDTSFeature;
336 37 : OGRPolygon *poOGRPoly = new OGRPolygon();
337 :
338 58 : for (int iRing = 0; iRing < poPoly->nRings; iRing++)
339 : {
340 21 : OGRLinearRing *poRing = new OGRLinearRing();
341 21 : const int nVertices =
342 21 : iRing == poPoly->nRings - 1
343 21 : ? poPoly->nVertices - poPoly->panRingStart[iRing]
344 6 : : (poPoly->panRingStart[iRing + 1] -
345 6 : poPoly->panRingStart[iRing]);
346 :
347 21 : poRing->setPoints(nVertices,
348 21 : poPoly->padfX + poPoly->panRingStart[iRing],
349 21 : poPoly->padfY + poPoly->panRingStart[iRing],
350 21 : poPoly->padfZ + poPoly->panRingStart[iRing]);
351 :
352 21 : poOGRPoly->addRingDirectly(poRing);
353 : }
354 :
355 37 : poFeature->SetGeometryDirectly(poOGRPoly);
356 : }
357 37 : break;
358 :
359 189 : default:
360 189 : break;
361 : }
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Set attributes for any indicated attribute records. */
365 : /* -------------------------------------------------------------------- */
366 389 : for (int iAttrRecord = 0; iAttrRecord < poSDTSFeature->nAttributes;
367 : iAttrRecord++)
368 : {
369 : DDFField *poSR =
370 6 : poTransfer->GetAttr(poSDTSFeature->paoATID + iAttrRecord);
371 6 : if (poSR != nullptr)
372 6 : AssignAttrRecordToFeature(poFeature, poTransfer, poSR);
373 : }
374 :
375 : /* -------------------------------------------------------------------- */
376 : /* If this record is an attribute record, attach the local */
377 : /* attributes. */
378 : /* -------------------------------------------------------------------- */
379 383 : if (poTransfer->GetLayerType(iLayer) == SLTAttr)
380 : {
381 189 : AssignAttrRecordToFeature(poFeature, poTransfer,
382 : ((SDTSAttrRecord *)poSDTSFeature)->poATTR);
383 : }
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Translate the record id. */
387 : /* -------------------------------------------------------------------- */
388 383 : poFeature->SetFID(poSDTSFeature->oModId.nRecord);
389 383 : poFeature->SetField(0, (int)poSDTSFeature->oModId.nRecord);
390 383 : if (poFeature->GetGeometryRef() != nullptr)
391 388 : poFeature->GetGeometryRef()->assignSpatialReference(
392 194 : poDS->GetSpatialRef());
393 :
394 383 : if (!bIsIndexed)
395 346 : delete poSDTSFeature;
396 :
397 383 : return poFeature;
398 : }
399 :
400 : /************************************************************************/
401 : /* GetNextFeature() */
402 : /************************************************************************/
403 :
404 391 : OGRFeature *OGRSDTSLayer::GetNextFeature()
405 :
406 : {
407 391 : OGRFeature *poFeature = nullptr;
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Read features till we find one that satisfies our current */
411 : /* spatial criteria. */
412 : /* -------------------------------------------------------------------- */
413 : while (true)
414 : {
415 391 : poFeature = GetNextUnfilteredFeature();
416 391 : if (poFeature == nullptr)
417 8 : break;
418 :
419 766 : if ((m_poFilterGeom == nullptr ||
420 766 : FilterGeometry(poFeature->GetGeometryRef())) &&
421 383 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
422 383 : break;
423 :
424 0 : delete poFeature;
425 : }
426 :
427 391 : return poFeature;
428 : }
429 :
430 : /************************************************************************/
431 : /* TestCapability() */
432 : /************************************************************************/
433 :
434 0 : int OGRSDTSLayer::TestCapability(const char * /* pszCap */)
435 :
436 : {
437 0 : return FALSE;
438 : }
|