Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OGR
4 : * Purpose: Implements OGRAVCE00Layer class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : * James Flemer <jflemer@alum.rpi.edu>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
10 : * Copyright (c) 2006, James Flemer <jflemer@alum.rpi.edu>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "ogr_avc.h"
16 : #include "ogr_api.h"
17 : #include "cpl_conv.h"
18 : #include "cpl_string.h"
19 :
20 : #include <cstdlib>
21 :
22 : /************************************************************************/
23 : /* OGRAVCE00Layer() */
24 : /************************************************************************/
25 :
26 7 : OGRAVCE00Layer::OGRAVCE00Layer(OGRAVCDataSource *poDSIn,
27 7 : AVCE00Section *psSectionIn)
28 : : OGRAVCLayer(psSectionIn->eType, poDSIn), psSection(psSectionIn),
29 : psRead(nullptr), poArcLayer(nullptr), nFeatureCount(-1),
30 : bNeedReset(false), nNextFID(1), psTableSection(nullptr),
31 : psTableRead(nullptr), pszTableFilename(nullptr), nTablePos(0),
32 7 : nTableBaseField(0), nTableAttrIndex(-1)
33 : {
34 7 : SetupFeatureDefinition(psSection->pszName);
35 : /* psRead = AVCE00ReadOpenE00(psSection->pszFilename); */
36 :
37 : #if 0
38 : szTableName[0] = '\0';
39 : if( psSection->eType == AVCFilePAL )
40 : sprintf( szTableName, "%s.PAT", poDS->GetCoverageName() );
41 : else if( psSection->eType == AVCFileRPL )
42 : sprintf( szTableName, "%s.PAT%s", poDS->GetCoverageName(),
43 : psSectionIn->pszName );
44 : else if( psSection->eType == AVCFileARC )
45 : sprintf( szTableName, "%s.AAT", poDS->GetCoverageName() );
46 : else if( psSection->eType == AVCFileLAB )
47 : {
48 : AVCE00ReadPtr psInfo = ((OGRAVCE00DataSource *) poDS)->GetInfo();
49 :
50 : sprintf( szTableName, "%s.PAT", poDS->GetCoverageName() );
51 :
52 : for( int iSection = 0; iSection < psInfo->numSections; iSection++ )
53 : {
54 : if( psInfo->pasSections[iSection].eType == AVCFilePAL )
55 : nTableAttrIndex = poFeatureDefn->GetFieldIndex( "PolyId" );
56 : }
57 : }
58 :
59 : #endif
60 7 : }
61 :
62 : /************************************************************************/
63 : /* ~OGRAVCE00Layer() */
64 : /************************************************************************/
65 :
66 14 : OGRAVCE00Layer::~OGRAVCE00Layer()
67 :
68 : {
69 7 : if (psRead)
70 : {
71 4 : AVCE00ReadCloseE00(psRead);
72 4 : psRead = nullptr;
73 : }
74 :
75 7 : if (psTableRead)
76 : {
77 3 : AVCE00ReadCloseE00(psTableRead);
78 3 : psTableRead = nullptr;
79 : }
80 :
81 7 : if (pszTableFilename)
82 : {
83 3 : CPLFree(pszTableFilename);
84 3 : pszTableFilename = nullptr;
85 : }
86 14 : }
87 :
88 : /************************************************************************/
89 : /* ResetReading() */
90 : /************************************************************************/
91 :
92 3 : void OGRAVCE00Layer::ResetReading()
93 :
94 : {
95 3 : if (psRead)
96 : {
97 1 : AVCE00ReadGotoSectionE00(psRead, psSection, 0);
98 : }
99 :
100 3 : if (psTableRead)
101 : {
102 2 : AVCE00ReadGotoSectionE00(psTableRead, psTableSection, 0);
103 : }
104 :
105 3 : m_bEOF = false;
106 3 : bNeedReset = false;
107 3 : nNextFID = 1;
108 3 : }
109 :
110 : /************************************************************************/
111 : /* GetFeature() */
112 : /************************************************************************/
113 :
114 109 : OGRFeature *OGRAVCE00Layer::GetFeature(GIntBig nFID)
115 :
116 : {
117 109 : if (nFID < 0 && nFID != SERIAL_ACCESS_FID)
118 0 : return nullptr;
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* If we haven't started yet, open the file now. */
122 : /* -------------------------------------------------------------------- */
123 109 : if (psRead == nullptr)
124 : {
125 4 : psRead = AVCE00ReadOpenE00(psSection->pszFilename);
126 4 : if (psRead == nullptr)
127 0 : return nullptr;
128 : /* advance to the specified line number */
129 4 : if (AVCE00ReadGotoSectionE00(psRead, psSection, 0) != 0)
130 0 : return nullptr;
131 4 : nNextFID = 1;
132 : }
133 :
134 : /* -------------------------------------------------------------------- */
135 : /* Read the raw feature - the SERIAL_ACCESS_FID fid is a special flag
136 : */
137 : /* indicating serial access. */
138 : /* -------------------------------------------------------------------- */
139 109 : void *pFeature = nullptr;
140 :
141 109 : if (nFID == SERIAL_ACCESS_FID)
142 : {
143 95 : bLastWasSequential = true;
144 :
145 95 : while ((pFeature = AVCE00ReadNextObjectE00(psRead)) != nullptr &&
146 187 : psRead->hParseInfo->eFileType != AVCFileUnknown &&
147 92 : !MatchesSpatialFilter(pFeature))
148 : {
149 0 : nNextFID++;
150 : }
151 : }
152 : else
153 : {
154 14 : bNeedReset = true;
155 :
156 14 : if (nNextFID > nFID || bLastWasSequential)
157 : {
158 6 : bLastWasSequential = false;
159 : /* advance to the specified line number */
160 6 : if (AVCE00ReadGotoSectionE00(psRead, psSection, 0) != 0)
161 0 : return nullptr;
162 6 : nNextFID = 1;
163 : }
164 :
165 20 : do
166 : {
167 34 : pFeature = AVCE00ReadNextObjectE00(psRead);
168 34 : ++nNextFID;
169 34 : } while (nullptr != pFeature && nNextFID <= nFID);
170 : }
171 :
172 109 : if (pFeature == nullptr)
173 3 : return nullptr;
174 106 : if (eSectionType != psRead->hParseInfo->eFileType)
175 0 : return nullptr;
176 :
177 : /* -------------------------------------------------------------------- */
178 : /* Translate the feature. */
179 : /* -------------------------------------------------------------------- */
180 106 : OGRFeature *poFeature = TranslateFeature(pFeature);
181 106 : if (poFeature == nullptr)
182 0 : return nullptr;
183 :
184 : /* -------------------------------------------------------------------- */
185 : /* LAB's we have to assign the FID to directly, since it */
186 : /* doesn't seem to be stored in the file structure. */
187 : /* -------------------------------------------------------------------- */
188 106 : if (psSection->eType == AVCFileLAB)
189 : {
190 80 : if (nFID == SERIAL_ACCESS_FID)
191 80 : poFeature->SetFID(nNextFID++);
192 : else
193 0 : poFeature->SetFID(nFID);
194 : }
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* If this is a polygon layer, try to assemble the arcs to form */
198 : /* the whole polygon geometry. */
199 : /* -------------------------------------------------------------------- */
200 106 : if (psSection->eType == AVCFilePAL || psSection->eType == AVCFileRPL)
201 : {
202 4 : FormPolygonGeometry(poFeature, static_cast<AVCPal *>(pFeature));
203 : }
204 :
205 : /* -------------------------------------------------------------------- */
206 : /* If we have an attribute table, append the attributes now. */
207 : /* -------------------------------------------------------------------- */
208 106 : AppendTableFields(poFeature);
209 :
210 106 : return poFeature;
211 : }
212 :
213 : /************************************************************************/
214 : /* GetNextFeature() */
215 : /************************************************************************/
216 :
217 94 : OGRFeature *OGRAVCE00Layer::GetNextFeature()
218 :
219 : {
220 94 : if (m_bEOF)
221 0 : return nullptr;
222 :
223 94 : if (bNeedReset)
224 0 : ResetReading();
225 :
226 94 : OGRFeature *poFeature = GetFeature(SERIAL_ACCESS_FID);
227 :
228 : // Skip universe polygon.
229 98 : if (poFeature != nullptr && poFeature->GetFID() == 1 &&
230 4 : psSection->eType == AVCFilePAL)
231 : {
232 1 : OGRFeature::DestroyFeature(poFeature);
233 1 : poFeature = GetFeature(SERIAL_ACCESS_FID);
234 : }
235 :
236 185 : while (poFeature != nullptr &&
237 91 : ((m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poFeature)) ||
238 91 : !FilterGeometry(poFeature->GetGeometryRef())))
239 : {
240 0 : OGRFeature::DestroyFeature(poFeature);
241 0 : poFeature = GetFeature(SERIAL_ACCESS_FID);
242 : }
243 :
244 94 : if (poFeature == nullptr)
245 3 : m_bEOF = true;
246 :
247 94 : return poFeature;
248 : }
249 :
250 : /************************************************************************/
251 : /* TestCapability() */
252 : /************************************************************************/
253 :
254 : #if 0
255 : int OGRAVCE00Layer::TestCapability( const char * pszCap )
256 :
257 : {
258 : if( eSectionType == AVCFileARC && EQUAL(pszCap,OLCRandomRead) )
259 : return TRUE;
260 :
261 : return OGRAVCLayer::TestCapability( pszCap );
262 : }
263 : #endif
264 :
265 : /************************************************************************/
266 : /* FormPolygonGeometry() */
267 : /* */
268 : /* Collect all the arcs forming edges to this polygon and form */
269 : /* them into the appropriate OGR geometry on the target feature. */
270 : /************************************************************************/
271 :
272 4 : bool OGRAVCE00Layer::FormPolygonGeometry(OGRFeature *poFeature, AVCPal *psPAL)
273 : {
274 : /* -------------------------------------------------------------------- */
275 : /* Try to find the corresponding ARC layer if not already */
276 : /* recorded. */
277 : /* -------------------------------------------------------------------- */
278 4 : if (poArcLayer == nullptr)
279 : {
280 5 : for (int i = 0; i < poDS->GetLayerCount(); i++)
281 : {
282 : OGRAVCE00Layer *poLayer =
283 4 : static_cast<OGRAVCE00Layer *>(poDS->GetLayer(i));
284 :
285 4 : if (poLayer->eSectionType == AVCFileARC)
286 1 : poArcLayer = poLayer;
287 : }
288 :
289 1 : if (poArcLayer == nullptr)
290 0 : return false;
291 : }
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Read all the arcs related to this polygon, making a working */
295 : /* copy of them since the one returned by AVC is temporary. */
296 : /* -------------------------------------------------------------------- */
297 8 : OGRGeometryCollection oArcs;
298 :
299 19 : for (int iArc = 0; iArc < psPAL->numArcs; iArc++)
300 : {
301 15 : if (psPAL->pasArcs[iArc].nArcId == 0 ||
302 14 : psPAL->pasArcs[iArc].nArcId == INT_MIN)
303 : {
304 1 : continue;
305 : }
306 :
307 : // If the other side of the line is the same polygon then this
308 : // arc is a "bridge" arc and can be discarded. If we don't discard
309 : // it, then we should double it as bridge arcs seem to only appear
310 : // once. But by discarding it we ensure a multi-ring polygon will be
311 : // properly formed.
312 14 : if (psPAL->pasArcs[iArc].nAdjPoly == psPAL->nPolyId)
313 0 : continue;
314 :
315 : auto poArc = std::unique_ptr<OGRFeature>(
316 14 : poArcLayer->GetFeature(std::abs(psPAL->pasArcs[iArc].nArcId)));
317 :
318 14 : if (poArc == nullptr)
319 0 : return false;
320 :
321 14 : if (poArc->GetGeometryRef() == nullptr)
322 0 : return false;
323 :
324 14 : oArcs.addGeometryDirectly(poArc->StealGeometry());
325 : }
326 :
327 : OGRErr eErr;
328 4 : OGRGeometry *poPolygon = OGRGeometry::FromHandle(OGRBuildPolygonFromEdges(
329 : OGRGeometry::ToHandle(&oArcs), TRUE, FALSE, 0.0, &eErr));
330 4 : if (poPolygon != nullptr)
331 : {
332 4 : poPolygon->assignSpatialReference(GetSpatialRef());
333 4 : poFeature->SetGeometryDirectly(poPolygon);
334 : }
335 :
336 4 : return eErr == OGRERR_NONE;
337 : }
338 :
339 : /************************************************************************/
340 : /* CheckSetupTable() */
341 : /* */
342 : /* Check if the named table exists, and if so, setup access to */
343 : /* it (open it), and add its fields to the feature class */
344 : /* definition. */
345 : /************************************************************************/
346 :
347 31 : bool OGRAVCE00Layer::CheckSetupTable(AVCE00Section *psTblSectionIn)
348 : {
349 31 : if (psTableRead)
350 5 : return false;
351 :
352 26 : const char *pszTableType = nullptr;
353 26 : switch (eSectionType)
354 : {
355 9 : case AVCFileARC:
356 9 : pszTableType = ".AAT";
357 9 : break;
358 :
359 12 : case AVCFilePAL:
360 : case AVCFileLAB:
361 12 : pszTableType = ".PAT";
362 12 : break;
363 :
364 5 : default:
365 5 : break;
366 : }
367 :
368 : /* -------------------------------------------------------------------- */
369 : /* Is the table type found anywhere in the section pszName? Do */
370 : /* a case insensitive check. */
371 : /* -------------------------------------------------------------------- */
372 26 : if (pszTableType == nullptr)
373 5 : return false;
374 :
375 21 : int iCheckOff = 0;
376 618 : for (; psTblSectionIn->pszName[iCheckOff] != '\0'; iCheckOff++)
377 : {
378 600 : if (EQUALN(psTblSectionIn->pszName + iCheckOff, pszTableType,
379 : strlen(pszTableType)))
380 3 : break;
381 : }
382 :
383 21 : if (psTblSectionIn->pszName[iCheckOff] == '\0')
384 18 : return false;
385 :
386 3 : psTableSection = psTblSectionIn;
387 :
388 : /* -------------------------------------------------------------------- */
389 : /* Try opening the table. */
390 : /* -------------------------------------------------------------------- */
391 3 : psTableRead = AVCE00ReadOpenE00(psTblSectionIn->pszFilename);
392 3 : if (psTableRead == nullptr)
393 0 : return false;
394 :
395 : /* advance to the specified line number */
396 3 : if (AVCE00ReadGotoSectionE00(psTableRead, psTableSection, 0) != 0)
397 : {
398 0 : AVCE00ReadCloseE00(psTableRead);
399 0 : psTableRead = nullptr;
400 0 : return false;
401 : }
402 :
403 3 : AVCE00ReadNextObjectE00(psTableRead);
404 3 : bNeedReset = true;
405 :
406 3 : CPLFree(pszTableFilename);
407 3 : pszTableFilename = CPLStrdup(psTblSectionIn->pszFilename);
408 3 : nTableBaseField = poFeatureDefn->GetFieldCount();
409 :
410 3 : if (eSectionType == AVCFileLAB)
411 : {
412 : AVCE00ReadE00Ptr psInfo =
413 2 : static_cast<OGRAVCE00DataSource *>(poDS)->GetInfo();
414 16 : for (int iSection = 0; iSection < psInfo->numSections; iSection++)
415 : {
416 14 : if (psInfo->pasSections[iSection].eType == AVCFilePAL)
417 1 : nTableAttrIndex = poFeatureDefn->GetFieldIndex("PolyId");
418 : }
419 : }
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Setup attributes. */
423 : /* -------------------------------------------------------------------- */
424 3 : if (psTableRead->hParseInfo->hdr.psTableDef == nullptr)
425 : {
426 0 : AVCE00ReadCloseE00(psTableRead);
427 0 : psTableRead = nullptr;
428 0 : return false;
429 : }
430 :
431 3 : AppendTableDefinition(psTableRead->hParseInfo->hdr.psTableDef);
432 :
433 : /* -------------------------------------------------------------------- */
434 : /* Close table so we don't have to many files open at once. */
435 : /* -------------------------------------------------------------------- */
436 : /* AVCE00ReadCloseE00( psTableRead ); */
437 :
438 3 : return true;
439 : }
440 :
441 : /************************************************************************/
442 : /* AppendTableFields() */
443 : /************************************************************************/
444 :
445 106 : bool OGRAVCE00Layer::AppendTableFields(OGRFeature *poFeature)
446 :
447 : {
448 106 : if (psTableRead == nullptr)
449 22 : return false;
450 : #ifdef deadcode
451 : /* -------------------------------------------------------------------- */
452 : /* Open the table if it is currently closed. */
453 : /* -------------------------------------------------------------------- */
454 : if (psTableRead == nullptr)
455 : {
456 : psTableRead = AVCE00ReadOpenE00(pszTableFilename);
457 : if (psTableRead == nullptr)
458 : return false;
459 :
460 : /* Advance to the specified line number */
461 : if (AVCE00ReadGotoSectionE00(psTableRead, psTableSection, 0) != 0)
462 : {
463 : AVCE00ReadCloseE00(psTableRead);
464 : psTableRead = nullptr;
465 : return false;
466 : }
467 : nTablePos = 0;
468 : }
469 : #endif
470 : /* -------------------------------------------------------------------- */
471 : /* Read the info record. */
472 : /* */
473 : /* We usually assume the FID of the feature is the key but in a */
474 : /* polygon coverage we need to use the PolyId attribute of LAB */
475 : /* features to lookup the related attributes. In this case */
476 : /* nTableAttrIndex will already be setup to refer to the */
477 : /* PolyId field. */
478 : /* -------------------------------------------------------------------- */
479 84 : const int nRecordId = nTableAttrIndex == -1
480 84 : ? static_cast<int>(poFeature->GetFID())
481 0 : : poFeature->GetFieldAsInteger(nTableAttrIndex);
482 :
483 84 : if (nRecordId <= nTablePos)
484 : {
485 0 : if (AVCE00ReadGotoSectionE00(psTableRead, psTableSection, 0) != 0)
486 0 : return false;
487 0 : nTablePos = 0;
488 : }
489 :
490 84 : void *hRecord = nullptr;
491 0 : do
492 : {
493 84 : hRecord = AVCE00ReadNextObjectE00(psTableRead);
494 84 : ++nTablePos;
495 84 : } while (nullptr != hRecord && nTablePos < nRecordId);
496 :
497 84 : if (hRecord == nullptr)
498 0 : return false;
499 84 : if (psTableRead->hParseInfo->hdr.psTableDef == nullptr)
500 0 : return false;
501 :
502 : /* -------------------------------------------------------------------- */
503 : /* Translate it. */
504 : /* -------------------------------------------------------------------- */
505 168 : return TranslateTableFields(poFeature, nTableBaseField,
506 84 : psTableRead->hParseInfo->hdr.psTableDef,
507 84 : static_cast<AVCField *>(hRecord));
508 : }
509 :
510 2 : GIntBig OGRAVCE00Layer::GetFeatureCount(int bForce)
511 : {
512 2 : if (m_poAttrQuery != nullptr || m_poFilterGeom != nullptr)
513 0 : return OGRAVCLayer::GetFeatureCount(bForce);
514 :
515 2 : if (bForce && nFeatureCount < 0)
516 : {
517 2 : if (psSection->nFeatureCount < 0)
518 : {
519 0 : nFeatureCount = (int)OGRLayer::GetFeatureCount(bForce);
520 : }
521 : else
522 : {
523 2 : nFeatureCount = psSection->nFeatureCount;
524 2 : if (psSection->eType == AVCFilePAL)
525 1 : --nFeatureCount;
526 : }
527 : }
528 2 : return nFeatureCount;
529 : }
|