LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/avc - ogravcbinlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 131 155 84.5 %
Date: 2024-11-21 22:18:42 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OGR
       4             :  * Purpose:  Implements OGRAVCBinLayer class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_avc.h"
      14             : #include "ogr_api.h"
      15             : #include "cpl_conv.h"
      16             : #include "cpl_string.h"
      17             : 
      18             : #include <climits>
      19             : #include <cstdlib>
      20             : 
      21             : /************************************************************************/
      22             : /*                           OGRAVCBinLayer()                           */
      23             : /************************************************************************/
      24             : 
      25           7 : OGRAVCBinLayer::OGRAVCBinLayer(OGRAVCBinDataSource *poDSIn,
      26           7 :                                AVCE00Section *psSectionIn)
      27             :     : OGRAVCLayer(psSectionIn->eType, poDSIn), m_psSection(psSectionIn),
      28             :       hFile(nullptr), poArcLayer(nullptr), bNeedReset(false), hTable(nullptr),
      29           7 :       nTableBaseField(-1), nTableAttrIndex(-1), nNextFID(1)
      30             : {
      31           7 :     SetupFeatureDefinition(m_psSection->pszName);
      32             : 
      33           7 :     szTableName[0] = '\0';
      34           7 :     if (m_psSection->eType == AVCFilePAL)
      35           1 :         snprintf(szTableName, sizeof(szTableName), "%s.PAT",
      36           1 :                  poDS->GetCoverageName());
      37           6 :     else if (m_psSection->eType == AVCFileRPL)
      38           0 :         snprintf(szTableName, sizeof(szTableName), "%s.PAT%s",
      39           0 :                  poDS->GetCoverageName(), m_psSection->pszName);
      40           6 :     else if (m_psSection->eType == AVCFileARC)
      41           2 :         snprintf(szTableName, sizeof(szTableName), "%s.AAT",
      42           2 :                  poDS->GetCoverageName());
      43           4 :     else if (m_psSection->eType == AVCFileLAB)
      44             :     {
      45             :         AVCE00ReadPtr psInfo =
      46           3 :             static_cast<OGRAVCBinDataSource *>(poDS)->GetInfo();
      47             : 
      48           6 :         snprintf(szTableName, sizeof(szTableName), "%s.PAT",
      49           3 :                  poDS->GetCoverageName());
      50             : 
      51          41 :         for (int iSection = 0; iSection < psInfo->numSections; iSection++)
      52             :         {
      53          38 :             if (psInfo->pasSections[iSection].eType == AVCFilePAL)
      54           1 :                 nTableAttrIndex = poFeatureDefn->GetFieldIndex("PolyId");
      55             :         }
      56             :     }
      57             : 
      58           7 :     CheckSetupTable();
      59           7 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                          ~OGRAVCBinLayer()                           */
      63             : /************************************************************************/
      64             : 
      65          14 : OGRAVCBinLayer::~OGRAVCBinLayer()
      66             : 
      67             : {
      68           7 :     OGRAVCBinLayer::ResetReading();
      69          14 : }
      70             : 
      71             : /************************************************************************/
      72             : /*                            ResetReading()                            */
      73             : /************************************************************************/
      74             : 
      75          14 : void OGRAVCBinLayer::ResetReading()
      76             : 
      77             : {
      78          14 :     if (hFile != nullptr)
      79             :     {
      80           7 :         AVCBinReadClose(hFile);
      81           7 :         hFile = nullptr;
      82             :     }
      83             : 
      84          14 :     bNeedReset = false;
      85          14 :     nNextFID = 1;
      86          14 :     m_bEOF = false;
      87             : 
      88          14 :     if (hTable != nullptr)
      89             :     {
      90           4 :         AVCBinReadClose(hTable);
      91           4 :         hTable = nullptr;
      92             :     }
      93          14 : }
      94             : 
      95             : /************************************************************************/
      96             : /*                             GetFeature()                             */
      97             : /************************************************************************/
      98             : 
      99         209 : OGRFeature *OGRAVCBinLayer::GetFeature(GIntBig nFID)
     100             : 
     101             : {
     102         209 :     if (!CPL_INT64_FITS_ON_INT32(nFID))
     103           0 :         return nullptr;
     104             : 
     105             :     /* -------------------------------------------------------------------- */
     106             :     /*      If we haven't started yet, open the file now.                   */
     107             :     /* -------------------------------------------------------------------- */
     108         209 :     if (hFile == nullptr)
     109             :     {
     110             :         AVCE00ReadPtr psInfo =
     111           7 :             static_cast<OGRAVCBinDataSource *>(poDS)->GetInfo();
     112             : 
     113          14 :         hFile = AVCBinReadOpen(psInfo->pszCoverPath, m_psSection->pszFilename,
     114           7 :                                psInfo->eCoverType, m_psSection->eType,
     115             :                                psInfo->psDBCSInfo);
     116           7 :         if (hFile == nullptr)
     117           0 :             return nullptr;
     118             :     }
     119             : 
     120             :     /* -------------------------------------------------------------------- */
     121             :     /*      Read the raw feature - the SERIAL_ACCESS_FID fid is a special flag
     122             :      */
     123             :     /*      indicating serial access.                                       */
     124             :     /* -------------------------------------------------------------------- */
     125         209 :     void *pFeature = nullptr;
     126             : 
     127         209 :     if (nFID == SERIAL_ACCESS_FID)
     128             :     {
     129         357 :         while ((pFeature = AVCBinReadNextObject(hFile)) != nullptr &&
     130         176 :                !MatchesSpatialFilter(pFeature))
     131             :         {
     132           0 :             nNextFID++;
     133             :         }
     134             :     }
     135             :     else
     136             :     {
     137          28 :         bNeedReset = true;
     138          28 :         pFeature = AVCBinReadObject(hFile, (int)nFID);
     139             :     }
     140             : 
     141         209 :     if (pFeature == nullptr)
     142           5 :         return nullptr;
     143             : 
     144             :     /* -------------------------------------------------------------------- */
     145             :     /*      Translate the feature.                                          */
     146             :     /* -------------------------------------------------------------------- */
     147         204 :     OGRFeature *poFeature = TranslateFeature(pFeature);
     148         204 :     if (poFeature == nullptr)
     149           0 :         return nullptr;
     150             : 
     151             :     /* -------------------------------------------------------------------- */
     152             :     /*      LAB's we have to assign the FID to directly, since it           */
     153             :     /*      doesn't seem to be stored in the file structure.                */
     154             :     /* -------------------------------------------------------------------- */
     155         204 :     if (m_psSection->eType == AVCFileLAB)
     156             :     {
     157         160 :         if (nFID == SERIAL_ACCESS_FID)
     158         160 :             poFeature->SetFID(nNextFID++);
     159             :         else
     160           0 :             poFeature->SetFID(nFID);
     161             :     }
     162             : 
     163             :     /* -------------------------------------------------------------------- */
     164             :     /*      If this is a polygon layer, try to assemble the arcs to form    */
     165             :     /*      the whole polygon geometry.                                     */
     166             :     /* -------------------------------------------------------------------- */
     167         204 :     if (m_psSection->eType == AVCFilePAL || m_psSection->eType == AVCFileRPL)
     168           8 :         FormPolygonGeometry(poFeature, (AVCPal *)pFeature);
     169             : 
     170             :     /* -------------------------------------------------------------------- */
     171             :     /*      If we have an attribute table, append the attributes now.       */
     172             :     /* -------------------------------------------------------------------- */
     173         204 :     AppendTableFields(poFeature);
     174             : 
     175         204 :     return poFeature;
     176             : }
     177             : 
     178             : /************************************************************************/
     179             : /*                           GetNextFeature()                           */
     180             : /************************************************************************/
     181             : 
     182         179 : OGRFeature *OGRAVCBinLayer::GetNextFeature()
     183             : 
     184             : {
     185         179 :     if (m_bEOF)
     186           0 :         return nullptr;
     187             : 
     188         179 :     if (bNeedReset)
     189           0 :         ResetReading();
     190             : 
     191         179 :     OGRFeature *poFeature = GetFeature(SERIAL_ACCESS_FID);
     192             : 
     193             :     // Skip universe polygon.
     194         185 :     if (poFeature != nullptr && poFeature->GetFID() == 1 &&
     195           6 :         m_psSection->eType == AVCFilePAL)
     196             :     {
     197           2 :         OGRFeature::DestroyFeature(poFeature);
     198           2 :         poFeature = GetFeature(SERIAL_ACCESS_FID);
     199             :     }
     200             : 
     201         353 :     while (poFeature != nullptr &&
     202         174 :            ((m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poFeature)) ||
     203         174 :             !FilterGeometry(poFeature->GetGeometryRef())))
     204             :     {
     205           0 :         OGRFeature::DestroyFeature(poFeature);
     206           0 :         poFeature = GetFeature(SERIAL_ACCESS_FID);
     207             :     }
     208             : 
     209         179 :     if (poFeature == nullptr)
     210           5 :         m_bEOF = true;
     211             : 
     212         179 :     return poFeature;
     213             : }
     214             : 
     215             : /************************************************************************/
     216             : /*                           TestCapability()                           */
     217             : /************************************************************************/
     218             : 
     219           0 : int OGRAVCBinLayer::TestCapability(const char *pszCap)
     220             : 
     221             : {
     222           0 :     if (eSectionType == AVCFileARC && EQUAL(pszCap, OLCRandomRead))
     223           0 :         return TRUE;
     224             : 
     225           0 :     return OGRAVCLayer::TestCapability(pszCap);
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                        FormPolygonGeometry()                         */
     230             : /*                                                                      */
     231             : /*      Collect all the arcs forming edges to this polygon and form     */
     232             : /*      them into the appropriate OGR geometry on the target feature.   */
     233             : /************************************************************************/
     234             : 
     235           8 : bool OGRAVCBinLayer::FormPolygonGeometry(OGRFeature *poFeature, AVCPal *psPAL)
     236             : 
     237             : {
     238             :     /* -------------------------------------------------------------------- */
     239             :     /*      Try to find the corresponding ARC layer if not already          */
     240             :     /*      recorded.                                                       */
     241             :     /* -------------------------------------------------------------------- */
     242           8 :     if (poArcLayer == nullptr)
     243             :     {
     244           5 :         for (int i = 0; i < poDS->GetLayerCount(); i++)
     245             :         {
     246             :             OGRAVCBinLayer *poLayer =
     247           4 :                 static_cast<OGRAVCBinLayer *>(poDS->GetLayer(i));
     248             : 
     249           4 :             if (poLayer->eSectionType == AVCFileARC)
     250           1 :                 poArcLayer = poLayer;
     251             :         }
     252             : 
     253           1 :         if (poArcLayer == nullptr)
     254           0 :             return false;
     255             :     }
     256             : 
     257             :     /* -------------------------------------------------------------------- */
     258             :     /*      Read all the arcs related to this polygon, making a working     */
     259             :     /*      copy of them since the one returned by AVC is temporary.        */
     260             :     /* -------------------------------------------------------------------- */
     261          16 :     OGRGeometryCollection oArcs;
     262             : 
     263          38 :     for (int iArc = 0; iArc < psPAL->numArcs; iArc++)
     264             :     {
     265          30 :         if (psPAL->pasArcs[iArc].nArcId == 0 ||
     266          28 :             psPAL->pasArcs[iArc].nArcId == INT_MIN)
     267             :         {
     268           2 :             continue;
     269             :         }
     270             : 
     271             :         // If the other side of the line is the same polygon then this
     272             :         // arc is a "bridge" arc and can be discarded.  If we don't discard
     273             :         // it, then we should double it as bridge arcs seem to only appear
     274             :         // once.  But by discarding it we ensure a multi-ring polygon will be
     275             :         // properly formed.
     276          28 :         if (psPAL->pasArcs[iArc].nAdjPoly == psPAL->nPolyId)
     277           0 :             continue;
     278             : 
     279             :         OGRFeature *poArc =
     280          28 :             poArcLayer->GetFeature(std::abs(psPAL->pasArcs[iArc].nArcId));
     281             : 
     282          28 :         if (poArc == nullptr)
     283           0 :             return false;
     284             : 
     285          28 :         if (poArc->GetGeometryRef() == nullptr)
     286           0 :             return false;
     287             : 
     288          28 :         oArcs.addGeometry(poArc->GetGeometryRef());
     289          28 :         OGRFeature::DestroyFeature(poArc);
     290             :     }
     291             : 
     292             :     OGRErr eErr;
     293           8 :     OGRGeometry *poPolygon = OGRGeometry::FromHandle(OGRBuildPolygonFromEdges(
     294             :         (OGRGeometryH)&oArcs, TRUE, FALSE, 0.0, &eErr));
     295           8 :     if (poPolygon != nullptr)
     296             :     {
     297           8 :         poPolygon->assignSpatialReference(GetSpatialRef());
     298           8 :         poFeature->SetGeometryDirectly(poPolygon);
     299             :     }
     300             : 
     301           8 :     return eErr == OGRERR_NONE;
     302             : }
     303             : 
     304             : /************************************************************************/
     305             : /*                          CheckSetupTable()                           */
     306             : /*                                                                      */
     307             : /*      Check if the named table exists, and if so, setup access to     */
     308             : /*      it (open it), and add its fields to the feature class           */
     309             : /*      definition.                                                     */
     310             : /************************************************************************/
     311             : 
     312           7 : bool OGRAVCBinLayer::CheckSetupTable()
     313             : 
     314             : {
     315           7 :     if (szTableName[0] == '\0')
     316           1 :         return false;
     317             : 
     318             :     /* -------------------------------------------------------------------- */
     319             :     /*      Scan for the indicated section.                                 */
     320             :     /* -------------------------------------------------------------------- */
     321           6 :     AVCE00ReadPtr psInfo = static_cast<OGRAVCBinDataSource *>(poDS)->GetInfo();
     322             : 
     323           6 :     AVCE00Section *l_psSection = nullptr;
     324          86 :     for (int iSection = 0; iSection < psInfo->numSections; iSection++)
     325             :     {
     326         160 :         if (EQUAL(szTableName,
     327         163 :                   CPLString(psInfo->pasSections[iSection].pszName).Trim()) &&
     328           3 :             psInfo->pasSections[iSection].eType == AVCFileTABLE)
     329           3 :             l_psSection = psInfo->pasSections + iSection;
     330             :     }
     331             : 
     332           6 :     if (l_psSection == nullptr)
     333             :     {
     334           3 :         szTableName[0] = '\0';
     335           3 :         return false;
     336             :     }
     337             : 
     338             :     /* -------------------------------------------------------------------- */
     339             :     /*      Try opening the table.                                          */
     340             :     /* -------------------------------------------------------------------- */
     341           3 :     hTable =
     342           3 :         AVCBinReadOpen(psInfo->pszInfoPath, szTableName, psInfo->eCoverType,
     343             :                        AVCFileTABLE, psInfo->psDBCSInfo);
     344             : 
     345           3 :     if (hTable == nullptr)
     346             :     {
     347           0 :         szTableName[0] = '\0';
     348           0 :         return false;
     349             :     }
     350             : 
     351             :     /* -------------------------------------------------------------------- */
     352             :     /*      Setup attributes.                                               */
     353             :     /* -------------------------------------------------------------------- */
     354           3 :     nTableBaseField = poFeatureDefn->GetFieldCount();
     355             : 
     356           3 :     AppendTableDefinition(hTable->hdr.psTableDef);
     357             : 
     358             :     /* -------------------------------------------------------------------- */
     359             :     /*      Close table so we don't have to many files open at once.        */
     360             :     /* -------------------------------------------------------------------- */
     361           3 :     AVCBinReadClose(hTable);
     362             : 
     363           3 :     hTable = nullptr;
     364             : 
     365           3 :     return true;
     366             : }
     367             : 
     368             : /************************************************************************/
     369             : /*                         AppendTableFields()                          */
     370             : /************************************************************************/
     371             : 
     372         204 : bool OGRAVCBinLayer::AppendTableFields(OGRFeature *poFeature)
     373             : 
     374             : {
     375         204 :     AVCE00ReadPtr psInfo = static_cast<OGRAVCBinDataSource *>(poDS)->GetInfo();
     376             : 
     377         204 :     if (szTableName[0] == '\0')
     378          36 :         return false;
     379             : 
     380             :     /* -------------------------------------------------------------------- */
     381             :     /*      Open the table if it is currently closed.                       */
     382             :     /* -------------------------------------------------------------------- */
     383         168 :     if (hTable == nullptr)
     384             :     {
     385           4 :         hTable =
     386           4 :             AVCBinReadOpen(psInfo->pszInfoPath, szTableName, psInfo->eCoverType,
     387             :                            AVCFileTABLE, psInfo->psDBCSInfo);
     388             :     }
     389             : 
     390         168 :     if (hTable == nullptr)
     391           0 :         return false;
     392             : 
     393             :     /* -------------------------------------------------------------------- */
     394             :     /*      Read the info record.                                           */
     395             :     /*                                                                      */
     396             :     /*      We usually assume the FID of the feature is the key but in a    */
     397             :     /*      polygon coverage we need to use the PolyId attribute of LAB     */
     398             :     /*      features to lookup the related attributes.  In this case        */
     399             :     /*      nTableAttrIndex will already be setup to refer to the           */
     400             :     /*      PolyId field.                                                   */
     401             :     /* -------------------------------------------------------------------- */
     402         168 :     const int nRecordId = nTableAttrIndex == -1
     403         168 :                               ? static_cast<int>(poFeature->GetFID())
     404           0 :                               : poFeature->GetFieldAsInteger(nTableAttrIndex);
     405             : 
     406         168 :     void *hRecord = AVCBinReadObject(hTable, nRecordId);
     407         168 :     if (hRecord == nullptr)
     408           0 :         return false;
     409             : 
     410             :     /* -------------------------------------------------------------------- */
     411             :     /*      Translate it.                                                   */
     412             :     /* -------------------------------------------------------------------- */
     413         336 :     return TranslateTableFields(poFeature, nTableBaseField,
     414         168 :                                 hTable->hdr.psTableDef, (AVCField *)hRecord);
     415             : }

Generated by: LCOV version 1.14