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