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