1 /******************************************************************************
2 * $Id: ogravcbinlayer.cpp 28383 2015-01-30 15:47:59Z rouault $
3 *
4 * Project: OGR
5 * Purpose: Implements OGRAVCBinLayer class.
6 * Author: Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "ogr_avc.h"
31 #include "ogr_api.h"
32 #include "cpl_conv.h"
33 #include "cpl_string.h"
34
35 CPL_CVSID("$Id: ogravcbinlayer.cpp 28383 2015-01-30 15:47:59Z rouault $");
36
37 /************************************************************************/
38 /* OGRAVCBinLayer() */
39 /************************************************************************/
40
OGRAVCBinLayer(OGRAVCBinDataSource * poDSIn,AVCE00Section * psSectionIn)41 OGRAVCBinLayer::OGRAVCBinLayer( OGRAVCBinDataSource *poDSIn,
42 AVCE00Section *psSectionIn )
43 : OGRAVCLayer( psSectionIn->eType, poDSIn )
44
45 {
46 psSection = psSectionIn;
47 hFile = NULL;
48 poArcLayer = NULL;
49 bNeedReset = FALSE;
50 nNextFID = 1;
51
52 hTable = NULL;
53 nTableBaseField = -1;
54 nTableAttrIndex = -1;
55
56 SetupFeatureDefinition( psSection->pszName );
57
58 szTableName[0] = '\0';
59 if( psSection->eType == AVCFilePAL )
60 sprintf( szTableName, "%s.PAT", poDS->GetCoverageName() );
61 else if( psSection->eType == AVCFileRPL )
62 sprintf( szTableName, "%s.PAT%s", poDS->GetCoverageName(),
63 psSectionIn->pszName );
64 else if( psSection->eType == AVCFileARC )
65 sprintf( szTableName, "%s.AAT", poDS->GetCoverageName() );
66 else if( psSection->eType == AVCFileLAB )
67 {
68 AVCE00ReadPtr psInfo = ((OGRAVCBinDataSource *) poDS)->GetInfo();
69
70 sprintf( szTableName, "%s.PAT", poDS->GetCoverageName() );
71
72 for( int iSection = 0; iSection < psInfo->numSections; iSection++ )
73 {
74 if( psInfo->pasSections[iSection].eType == AVCFilePAL )
75 nTableAttrIndex = poFeatureDefn->GetFieldIndex( "PolyId" );
76 }
77 }
78
79 CheckSetupTable();
80 }
81
82 /************************************************************************/
83 /* ~OGRAVCBinLayer() */
84 /************************************************************************/
85
~OGRAVCBinLayer()86 OGRAVCBinLayer::~OGRAVCBinLayer()
87
88 {
89 ResetReading();
90 }
91
92 /************************************************************************/
93 /* ResetReading() */
94 /************************************************************************/
95
ResetReading()96 void OGRAVCBinLayer::ResetReading()
97
98 {
99 if( hFile != NULL )
100 {
101 AVCBinReadClose( hFile );
102 hFile = NULL;
103 }
104
105 bNeedReset = FALSE;
106 nNextFID = 1;
107
108 if( hTable != NULL )
109 {
110 AVCBinReadClose( hTable );
111 hTable = NULL;
112 }
113 }
114
115 /************************************************************************/
116 /* GetFeature() */
117 /************************************************************************/
118
GetFeature(GIntBig nFID)119 OGRFeature *OGRAVCBinLayer::GetFeature( GIntBig nFID )
120
121 {
122 if( (GIntBig)(int)nFID != nFID )
123 return NULL;
124
125 /* -------------------------------------------------------------------- */
126 /* If we haven't started yet, open the file now. */
127 /* -------------------------------------------------------------------- */
128 if( hFile == NULL )
129 {
130 AVCE00ReadPtr psInfo = ((OGRAVCBinDataSource *) poDS)->GetInfo();
131
132 hFile = AVCBinReadOpen(psInfo->pszCoverPath,
133 psSection->pszFilename,
134 psInfo->eCoverType,
135 psSection->eType,
136 psInfo->psDBCSInfo);
137 }
138
139 /* -------------------------------------------------------------------- */
140 /* Read the raw feature - the -3 fid is a special flag */
141 /* indicating serial access. */
142 /* -------------------------------------------------------------------- */
143 void *pFeature;
144
145 if( nFID == -3 )
146 {
147 while( (pFeature = AVCBinReadNextObject( hFile )) != NULL
148 && !MatchesSpatialFilter( pFeature ) )
149 {
150 nNextFID++;
151 }
152 }
153 else
154 {
155 bNeedReset = TRUE;
156 pFeature = AVCBinReadObject( hFile, (int)nFID );
157 }
158
159 if( pFeature == NULL )
160 return NULL;
161
162 /* -------------------------------------------------------------------- */
163 /* Translate the feature. */
164 /* -------------------------------------------------------------------- */
165 OGRFeature *poFeature;
166
167 poFeature = TranslateFeature( pFeature );
168 if( poFeature == NULL )
169 return NULL;
170
171 /* -------------------------------------------------------------------- */
172 /* LAB's we have to assign the FID to directly, since it */
173 /* doesn't seem to be stored in the file structure. */
174 /* -------------------------------------------------------------------- */
175 if( psSection->eType == AVCFileLAB )
176 {
177 if( nFID == -3 )
178 poFeature->SetFID( nNextFID++ );
179 else
180 poFeature->SetFID( nFID );
181 }
182
183 /* -------------------------------------------------------------------- */
184 /* If this is a polygon layer, try to assemble the arcs to form */
185 /* the whole polygon geometry. */
186 /* -------------------------------------------------------------------- */
187 if( psSection->eType == AVCFilePAL
188 || psSection->eType == AVCFileRPL )
189 FormPolygonGeometry( poFeature, (AVCPal *) pFeature );
190
191 /* -------------------------------------------------------------------- */
192 /* If we have an attribute table, append the attributes now. */
193 /* -------------------------------------------------------------------- */
194 AppendTableFields( poFeature );
195
196 return poFeature;
197 }
198
199 /************************************************************************/
200 /* GetNextFeature() */
201 /************************************************************************/
202
GetNextFeature()203 OGRFeature *OGRAVCBinLayer::GetNextFeature()
204
205 {
206 if( bNeedReset )
207 ResetReading();
208
209 OGRFeature *poFeature = GetFeature( -3 );
210
211 // Skip universe polygon.
212 if( poFeature != NULL && poFeature->GetFID() == 1
213 && psSection->eType == AVCFilePAL )
214 {
215 OGRFeature::DestroyFeature( poFeature );
216 poFeature = GetFeature( -3 );
217 }
218
219 while( poFeature != NULL
220 && ((m_poAttrQuery != NULL
221 && !m_poAttrQuery->Evaluate( poFeature ) )
222 || !FilterGeometry( poFeature->GetGeometryRef() ) ) )
223 {
224 OGRFeature::DestroyFeature( poFeature );
225 poFeature = GetFeature( -3 );
226 }
227
228 if( poFeature == NULL )
229 ResetReading();
230
231 return poFeature;
232 }
233
234 /************************************************************************/
235 /* TestCapability() */
236 /************************************************************************/
237
TestCapability(const char * pszCap)238 int OGRAVCBinLayer::TestCapability( const char * pszCap )
239
240 {
241 if( eSectionType == AVCFileARC && EQUAL(pszCap,OLCRandomRead) )
242 return TRUE;
243 else
244 return OGRAVCLayer::TestCapability( pszCap );
245 }
246
247 /************************************************************************/
248 /* FormPolygonGeometry() */
249 /* */
250 /* Collect all the arcs forming edges to this polygon and form */
251 /* them into the appropriate OGR geometry on the target feature. */
252 /************************************************************************/
253
FormPolygonGeometry(OGRFeature * poFeature,AVCPal * psPAL)254 int OGRAVCBinLayer::FormPolygonGeometry( OGRFeature *poFeature,
255 AVCPal *psPAL )
256
257 {
258 /* -------------------------------------------------------------------- */
259 /* Try to find the corresponding ARC layer if not already */
260 /* recorded. */
261 /* -------------------------------------------------------------------- */
262 if( poArcLayer == NULL )
263 {
264 int i;
265
266 for( i = 0; i < poDS->GetLayerCount(); i++ )
267 {
268 OGRAVCBinLayer *poLayer = (OGRAVCBinLayer *) poDS->GetLayer(i);
269
270 if( poLayer->eSectionType == AVCFileARC )
271 poArcLayer = poLayer;
272 }
273
274 if( poArcLayer == NULL )
275 return FALSE;
276 }
277
278 /* -------------------------------------------------------------------- */
279 /* Read all the arcs related to this polygon, making a working */
280 /* copy of them since the one returned by AVC is temporary. */
281 /* -------------------------------------------------------------------- */
282 OGRGeometryCollection oArcs;
283 int iArc;
284
285 for( iArc = 0; iArc < psPAL->numArcs; iArc++ )
286 {
287 OGRFeature *poArc;
288
289 if( psPAL->pasArcs[iArc].nArcId == 0 )
290 continue;
291
292 // If the other side of the line is the same polygon then this
293 // arc is a "bridge" arc and can be discarded. If we don't discard
294 // it, then we should double it as bridge arcs seem to only appear
295 // once. But by discarding it we ensure a multi-ring polygon will be
296 // properly formed.
297 if( psPAL->pasArcs[iArc].nAdjPoly == psPAL->nPolyId )
298 continue;
299
300 poArc = poArcLayer->GetFeature( ABS(psPAL->pasArcs[iArc].nArcId) );
301
302 if( poArc == NULL )
303 return FALSE;
304
305 if( poArc->GetGeometryRef() == NULL )
306 return FALSE;
307
308 oArcs.addGeometry( poArc->GetGeometryRef() );
309 OGRFeature::DestroyFeature( poArc );
310 }
311
312 OGRErr eErr;
313 OGRPolygon *poPolygon;
314
315 poPolygon = (OGRPolygon *)
316 OGRBuildPolygonFromEdges( (OGRGeometryH) &oArcs, TRUE, FALSE,
317 0.0, &eErr );
318 if( poPolygon != NULL )
319 poFeature->SetGeometryDirectly( poPolygon );
320
321 return eErr == OGRERR_NONE;
322 }
323
324 /************************************************************************/
325 /* CheckSetupTable() */
326 /* */
327 /* Check if the named table exists, and if so, setup access to */
328 /* it (open it), and add it's fields to the feature class */
329 /* definition. */
330 /************************************************************************/
331
CheckSetupTable()332 int OGRAVCBinLayer::CheckSetupTable()
333
334 {
335 if( szTableName[0] == '\0' )
336 return FALSE;
337
338 /* -------------------------------------------------------------------- */
339 /* Scan for the indicated section. */
340 /* -------------------------------------------------------------------- */
341 AVCE00ReadPtr psInfo = ((OGRAVCBinDataSource *) poDS)->GetInfo();
342 int iSection;
343 AVCE00Section *psSection = NULL;
344 char szPaddedName[65];
345
346 sprintf( szPaddedName, "%s%32s", szTableName, " " );
347 szPaddedName[32] = '\0';
348
349 for( iSection = 0; iSection < psInfo->numSections; iSection++ )
350 {
351 if( EQUAL(szPaddedName,psInfo->pasSections[iSection].pszName)
352 && psInfo->pasSections[iSection].eType == AVCFileTABLE )
353 psSection = psInfo->pasSections + iSection;
354 }
355
356 if( psSection == NULL )
357 {
358 szTableName[0] = '\0';
359 return FALSE;
360 }
361
362 /* -------------------------------------------------------------------- */
363 /* Try opening the table. */
364 /* -------------------------------------------------------------------- */
365 hTable = AVCBinReadOpen( psInfo->pszInfoPath, szTableName,
366 psInfo->eCoverType, AVCFileTABLE,
367 psInfo->psDBCSInfo);
368
369 if( hTable == NULL )
370 {
371 szTableName[0] = '\0';
372 return FALSE;
373 }
374
375 /* -------------------------------------------------------------------- */
376 /* Setup attributes. */
377 /* -------------------------------------------------------------------- */
378 nTableBaseField = poFeatureDefn->GetFieldCount();
379
380 AppendTableDefinition( hTable->hdr.psTableDef );
381
382 /* -------------------------------------------------------------------- */
383 /* Close table so we don't have to many files open at once. */
384 /* -------------------------------------------------------------------- */
385 AVCBinReadClose( hTable );
386
387 hTable = NULL;
388
389 return TRUE;
390 }
391
392 /************************************************************************/
393 /* AppendTableFields() */
394 /************************************************************************/
395
AppendTableFields(OGRFeature * poFeature)396 int OGRAVCBinLayer::AppendTableFields( OGRFeature *poFeature )
397
398 {
399 AVCE00ReadPtr psInfo = ((OGRAVCBinDataSource *) poDS)->GetInfo();
400
401 if( szTableName[0] == '\0' )
402 return FALSE;
403
404 /* -------------------------------------------------------------------- */
405 /* Open the table if it is currently closed. */
406 /* -------------------------------------------------------------------- */
407 if( hTable == NULL )
408 {
409 hTable = AVCBinReadOpen( psInfo->pszInfoPath, szTableName,
410 psInfo->eCoverType, AVCFileTABLE,
411 psInfo->psDBCSInfo);
412 }
413
414 if( hTable == NULL )
415 return FALSE;
416
417 /* -------------------------------------------------------------------- */
418 /* Read the info record. */
419 /* */
420 /* We usually assume the FID of the feature is the key but in a */
421 /* polygon coverage we need to use the PolyId attribute of LAB */
422 /* features to lookup the related attributes. In this case */
423 /* nTableAttrIndex will already be setup to refer to the */
424 /* PolyId field. */
425 /* -------------------------------------------------------------------- */
426 int nRecordId;
427 void *hRecord;
428
429 if( nTableAttrIndex == -1 )
430 nRecordId = (int) poFeature->GetFID();
431 else
432 nRecordId = poFeature->GetFieldAsInteger( nTableAttrIndex );
433
434 hRecord = AVCBinReadObject( hTable, nRecordId );
435 if( hRecord == NULL )
436 return FALSE;
437
438 /* -------------------------------------------------------------------- */
439 /* Translate it. */
440 /* -------------------------------------------------------------------- */
441 return TranslateTableFields( poFeature, nTableBaseField,
442 hTable->hdr.psTableDef,
443 (AVCField *) hRecord );
444 }
445
446
447
448
449
450