LCOV - code coverage report
Current view: top level - gnm - gnmgenericnetwork.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 407 739 55.1 %
Date: 2024-11-21 22:18:42 Functions: 34 57 59.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL/OGR Geography Network support (Geographic Network Model)
       4             :  * Purpose:  GNM network class.
       5             :  * Authors:  Mikhail Gusev (gusevmihs at gmail dot com)
       6             :  *           Dmitry Baryshnikov, polimax@mail.ru
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2014, Mikhail Gusev
      10             :  * Copyright (c) 2014-2015, NextGIS <info@nextgis.com>
      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 "gnm_api.h"
      32             : #include "gnm_priv.h"
      33             : #include "ogrsf_frmts.h"
      34             : 
      35             : #include <set>
      36             : 
      37             : //! @cond Doxygen_Suppress
      38          16 : GNMGenericNetwork::GNMGenericNetwork()
      39             :     : GNMNetwork(), m_nVersion(0), m_nGID(0), m_nVirtualConnectionGID(-1),
      40             :       m_poMetadataLayer(nullptr), m_poGraphLayer(nullptr),
      41             :       m_poFeaturesLayer(nullptr), m_poLayerDriver(nullptr),
      42          16 :       m_bIsRulesChanged(false), m_bIsGraphLoaded(false)
      43             : {
      44          16 : }
      45             : 
      46          16 : GNMGenericNetwork::~GNMGenericNetwork()
      47             : {
      48          37 :     for (size_t i = 0; i < m_apoLayers.size(); i++)
      49          21 :         delete m_apoLayers[i];
      50          16 : }
      51             : 
      52          43 : int GNMGenericNetwork::GetLayerCount()
      53             : {
      54          43 :     return (int)m_apoLayers.size();
      55             : }
      56             : 
      57          37 : OGRLayer *GNMGenericNetwork::GetLayer(int nIndex)
      58             : {
      59          37 :     if (nIndex < 0 || nIndex >= (int)m_apoLayers.size())
      60           0 :         return nullptr;
      61          37 :     return m_apoLayers[nIndex];
      62             : }
      63             : 
      64           4 : OGRErr GNMGenericNetwork::DeleteLayer(int nIndex)
      65             : {
      66           4 :     if (nIndex < 0 || nIndex >= (int)m_apoLayers.size())
      67           0 :         return OGRERR_FAILURE;
      68             : 
      69           4 :     const char *pszLayerName = m_apoLayers[nIndex]->GetName();
      70             :     OGRFeature *poFeature;
      71             : 
      72           4 :     std::set<GNMGFID> anGFIDs;
      73           4 :     std::set<GNMGFID>::iterator it;
      74             :     // remove layer GFID's from Features layer
      75             : 
      76           4 :     m_poFeaturesLayer->ResetReading();
      77         194 :     while ((poFeature = m_poFeaturesLayer->GetNextFeature()) != nullptr)
      78             :     {
      79             :         const char *pFeatureClass =
      80         190 :             poFeature->GetFieldAsString(GNM_SYSFIELD_LAYERNAME);
      81             : 
      82         190 :         if (EQUAL(pFeatureClass, pszLayerName))
      83             :         {
      84         128 :             anGFIDs.insert(poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_GFID));
      85         128 :             CPL_IGNORE_RET_VAL(
      86         128 :                 m_poFeaturesLayer->DeleteFeature(poFeature->GetFID()));
      87             :         }
      88         190 :         OGRFeature::DestroyFeature(poFeature);
      89             :     }
      90             : 
      91             :     // remove GFID's from graph layer
      92             : 
      93           4 :     m_poGraphLayer->ResetReading();
      94          70 :     while ((poFeature = m_poGraphLayer->GetNextFeature()) != nullptr)
      95             :     {
      96          66 :         GNMGFID nGFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_SOURCE);
      97          66 :         it = anGFIDs.find(nGFID);
      98          66 :         if (it != anGFIDs.end())
      99             :         {
     100           0 :             CPL_IGNORE_RET_VAL(
     101           0 :                 m_poGraphLayer->DeleteFeature(poFeature->GetFID()));
     102           0 :             OGRFeature::DestroyFeature(poFeature);
     103          66 :             continue;
     104             :         }
     105             : 
     106          66 :         nGFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_TARGET);
     107          66 :         it = anGFIDs.find(nGFID);
     108          66 :         if (it != anGFIDs.end())
     109             :         {
     110           0 :             CPL_IGNORE_RET_VAL(
     111           0 :                 m_poGraphLayer->DeleteFeature(poFeature->GetFID()));
     112           0 :             OGRFeature::DestroyFeature(poFeature);
     113           0 :             continue;
     114             :         }
     115             : 
     116          66 :         nGFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_CONNECTOR);
     117          66 :         it = anGFIDs.find(nGFID);
     118          66 :         if (it != anGFIDs.end())
     119             :         {
     120          66 :             CPL_IGNORE_RET_VAL(
     121          66 :                 m_poGraphLayer->DeleteFeature(poFeature->GetFID()));
     122          66 :             OGRFeature::DestroyFeature(poFeature);
     123          66 :             continue;
     124             :         }
     125             : 
     126           0 :         OGRFeature::DestroyFeature(poFeature);
     127             :     }
     128             : 
     129             :     // remove connected rules
     130           8 :     for (size_t i = m_asRules.size(); i > 0; --i)
     131             :     {
     132           4 :         if (EQUAL(m_asRules[i - 1].GetSourceLayerName(), pszLayerName))
     133             :         {
     134           0 :             m_asRules.erase(m_asRules.begin() + i - 1);
     135           0 :             m_bIsRulesChanged = true;
     136             :         }
     137           4 :         else if (EQUAL(m_asRules[i - 1].GetTargetLayerName(), pszLayerName))
     138             :         {
     139           0 :             m_asRules.erase(m_asRules.begin() + i - 1);
     140           0 :             m_bIsRulesChanged = true;
     141             :         }
     142           4 :         else if (EQUAL(m_asRules[i - 1].GetConnectorLayerName(), pszLayerName))
     143             :         {
     144           0 :             m_asRules.erase(m_asRules.begin() + i - 1);
     145           0 :             m_bIsRulesChanged = true;
     146             :         }
     147             :     }
     148             : 
     149           4 :     delete m_apoLayers[nIndex];
     150             :     // remove from array
     151           4 :     m_apoLayers.erase(m_apoLayers.begin() + nIndex);
     152           4 :     return OGRERR_NONE;
     153             : }
     154             : 
     155           2 : CPLErr GNMGenericNetwork::Delete()
     156             : {
     157           2 :     CPLErr eResult = DeleteNetworkLayers();
     158           2 :     if (eResult != CE_None)
     159           0 :         return eResult;
     160           2 :     eResult = DeleteMetadataLayer();
     161           2 :     if (eResult != CE_None)
     162           0 :         return eResult;
     163           2 :     eResult = DeleteGraphLayer();
     164           2 :     if (eResult != CE_None)
     165           0 :         return eResult;
     166             : 
     167           2 :     return DeleteFeaturesLayer();
     168             : }
     169             : 
     170           4 : int GNMGenericNetwork::GetVersion() const
     171             : {
     172           4 :     return m_nVersion;
     173             : }
     174             : 
     175         128 : GIntBig GNMGenericNetwork::GetNewGlobalFID()
     176             : {
     177         128 :     return m_nGID++;
     178             : }
     179             : 
     180           5 : CPLString GNMGenericNetwork::GetAlgorithmName(GNMDirection eAlgorithm,
     181             :                                               bool bShortName)
     182             : {
     183           5 :     switch (eAlgorithm)
     184             :     {
     185           2 :         case GATDijkstraShortestPath:
     186           2 :             if (bShortName)
     187           2 :                 return CPLString("Dijkstra");
     188             :             else
     189           0 :                 return CPLString("Dijkstra shortest path");
     190           2 :         case GATKShortestPath:
     191           2 :             if (bShortName)
     192           2 :                 return CPLString("Yens");
     193             :             else
     194           0 :                 return CPLString("Yens shortest paths");
     195           1 :         case GATConnectedComponents:
     196           1 :             if (bShortName)
     197           1 :                 return CPLString("Connected");
     198             :             else
     199           0 :                 return CPLString("Connected components");
     200             :     }
     201             : 
     202           0 :     return CPLString("Invalid");
     203             : }
     204             : 
     205         128 : CPLErr GNMGenericNetwork::AddFeatureGlobalFID(GNMGFID nFID,
     206             :                                               const char *pszLayerName)
     207             : {
     208             :     OGRFeature *poFeature =
     209         128 :         OGRFeature::CreateFeature(m_poFeaturesLayer->GetLayerDefn());
     210         128 :     poFeature->SetField(GNM_SYSFIELD_GFID, nFID);
     211         128 :     poFeature->SetField(GNM_SYSFIELD_LAYERNAME, pszLayerName);
     212             : 
     213         128 :     if (m_poFeaturesLayer->CreateFeature(poFeature) != OGRERR_NONE)
     214             :     {
     215           0 :         OGRFeature::DestroyFeature(poFeature);
     216           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to create feature.");
     217           0 :         return CE_Failure;
     218             :     }
     219             : 
     220         128 :     OGRFeature::DestroyFeature(poFeature);
     221             : 
     222         128 :     return CE_None;
     223             : }
     224             : 
     225          66 : CPLErr GNMGenericNetwork::ConnectFeatures(GNMGFID nSrcGFID, GNMGFID nTgtGFID,
     226             :                                           GNMGFID nConGFID, double dfCost,
     227             :                                           double dfInvCost, GNMDirection eDir)
     228             : {
     229          66 :     if (!m_bIsGraphLoaded && LoadGraph() != CE_None)
     230             :     {
     231           0 :         return CE_Failure;
     232             :     }
     233             : 
     234          66 :     OGRFeature *poFeature = FindConnection(nSrcGFID, nTgtGFID, nConGFID);
     235          66 :     if (poFeature != nullptr)
     236             :     {
     237           0 :         OGRFeature::DestroyFeature(poFeature);
     238           0 :         CPLError(CE_Failure, CPLE_AppDefined, "The connection already created");
     239           0 :         return CE_Failure;
     240             :     }
     241             : 
     242          66 :     if (m_asRules.empty())
     243             :     {
     244           0 :         CPLError(CE_Failure, CPLE_AppDefined, "The connection forbidden");
     245           0 :         return CE_Failure;
     246             :     }
     247             :     else
     248             :     {
     249          66 :         CPLString soSrcLayerName = m_moFeatureFIDMap[nSrcGFID];
     250          66 :         CPLString soTgtLayerName = m_moFeatureFIDMap[nTgtGFID];
     251          66 :         CPLString soConnLayerName = m_moFeatureFIDMap[nConGFID];
     252         132 :         for (size_t i = 0; i < m_asRules.size(); ++i)
     253             :         {
     254         132 :             if (!m_asRules[i].CanConnect(soSrcLayerName, soTgtLayerName,
     255          66 :                                          soConnLayerName))
     256             :             {
     257           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     258             :                          "The connection forbidden");
     259           0 :                 return CE_Failure;
     260             :             }
     261             :         }
     262             :     }
     263             : 
     264             :     // we support both vertices and edge to be virtual
     265          66 :     if (nConGFID == -1)
     266           0 :         nConGFID = GetNewVirtualFID();
     267          66 :     if (nSrcGFID == -1)
     268           0 :         nSrcGFID = GetNewVirtualFID();
     269          66 :     if (nTgtGFID == -1)
     270           0 :         nTgtGFID = GetNewVirtualFID();
     271             : 
     272          66 :     poFeature = OGRFeature::CreateFeature(m_poGraphLayer->GetLayerDefn());
     273          66 :     poFeature->SetField(GNM_SYSFIELD_SOURCE, nSrcGFID);
     274          66 :     poFeature->SetField(GNM_SYSFIELD_TARGET, nTgtGFID);
     275          66 :     poFeature->SetField(GNM_SYSFIELD_CONNECTOR, nConGFID);
     276          66 :     poFeature->SetField(GNM_SYSFIELD_COST, dfCost);
     277          66 :     poFeature->SetField(GNM_SYSFIELD_INVCOST, dfInvCost);
     278          66 :     poFeature->SetField(GNM_SYSFIELD_DIRECTION, eDir);
     279          66 :     poFeature->SetField(GNM_SYSFIELD_BLOCKED, GNM_BLOCK_NONE);
     280             : 
     281          66 :     if (m_poGraphLayer->CreateFeature(poFeature) != OGRERR_NONE)
     282             :     {
     283           0 :         OGRFeature::DestroyFeature(poFeature);
     284           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to create feature.");
     285           0 :         return CE_Failure;
     286             :     }
     287             : 
     288          66 :     OGRFeature::DestroyFeature(poFeature);
     289             : 
     290             :     // update graph
     291             : 
     292          66 :     m_oGraph.AddEdge(nConGFID, nSrcGFID, nTgtGFID, eDir == GNM_EDGE_DIR_BOTH,
     293             :                      dfCost, dfInvCost);
     294             : 
     295          66 :     return CE_None;
     296             : }
     297             : 
     298           0 : CPLErr GNMGenericNetwork::DisconnectFeatures(GNMGFID nSrcGFID, GNMGFID nTgtGFID,
     299             :                                              GNMGFID nConGFID)
     300             : {
     301           0 :     if (!m_bIsGraphLoaded && LoadGraph() != CE_None)
     302             :     {
     303           0 :         return CE_Failure;
     304             :     }
     305             : 
     306           0 :     OGRFeature *poFeature = FindConnection(nSrcGFID, nTgtGFID, nConGFID);
     307           0 :     if (poFeature == nullptr)
     308             :     {
     309           0 :         CPLError(CE_Failure, CPLE_AppDefined, "The connection not exist");
     310           0 :         return CE_Failure;
     311             :     }
     312             : 
     313           0 :     if (m_poGraphLayer->DeleteFeature(poFeature->GetFID()) != OGRERR_NONE)
     314             :     {
     315           0 :         OGRFeature::DestroyFeature(poFeature);
     316           0 :         return CE_Failure;
     317             :     }
     318             : 
     319           0 :     OGRFeature::DestroyFeature(poFeature);
     320             : 
     321             :     // update graph
     322             : 
     323           0 :     m_oGraph.DeleteEdge(nConGFID);
     324             : 
     325           0 :     return CE_None;
     326             : }
     327             : 
     328           0 : CPLErr GNMGenericNetwork::DisconnectFeaturesWithId(GNMGFID nFID)
     329             : {
     330           0 :     if (!m_bIsGraphLoaded && LoadGraph() != CE_None)
     331             :     {
     332           0 :         return CE_Failure;
     333             :     }
     334             : 
     335           0 :     CPLString soFilter;
     336             :     soFilter.Printf("%s = " GNMGFIDFormat " or %s = " GNMGFIDFormat
     337             :                     " or %s = " GNMGFIDFormat,
     338             :                     GNM_SYSFIELD_SOURCE, nFID, GNM_SYSFIELD_TARGET, nFID,
     339           0 :                     GNM_SYSFIELD_CONNECTOR, nFID);
     340             : 
     341           0 :     CPLDebug("GNM", "Set attribute filter: %s", soFilter.c_str());
     342             : 
     343           0 :     m_poGraphLayer->SetAttributeFilter(soFilter);
     344           0 :     m_poGraphLayer->ResetReading();
     345             :     OGRFeature *poFeature;
     346           0 :     while ((poFeature = m_poGraphLayer->GetNextFeature()) != nullptr)
     347             :     {
     348           0 :         if (m_poGraphLayer->DeleteFeature(poFeature->GetFID()) != CE_None)
     349             :         {
     350           0 :             OGRFeature::DestroyFeature(poFeature);
     351           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     352             :                      "Failed to remove feature connection.");
     353           0 :             return CE_Failure;
     354             :         }
     355           0 :         OGRFeature::DestroyFeature(poFeature);
     356             :     }
     357             : 
     358           0 :     m_poGraphLayer->SetAttributeFilter(nullptr);
     359             : 
     360           0 :     m_oGraph.DeleteEdge(nFID);
     361           0 :     m_oGraph.DeleteVertex(nFID);
     362             : 
     363           0 :     return CE_None;
     364             : }
     365             : 
     366           0 : CPLErr GNMGenericNetwork::ReconnectFeatures(GNMGFID nSrcGFID, GNMGFID nTgtGFID,
     367             :                                             GNMGFID nConGFID, double dfCost,
     368             :                                             double dfInvCost, GNMDirection eDir)
     369             : {
     370           0 :     if (!m_bIsGraphLoaded && LoadGraph() != CE_None)
     371             :     {
     372           0 :         return CE_Failure;
     373             :     }
     374             : 
     375           0 :     OGRFeature *poFeature = FindConnection(nSrcGFID, nTgtGFID, nConGFID);
     376           0 :     if (poFeature == nullptr)
     377             :     {
     378           0 :         CPLError(CE_Failure, CPLE_AppDefined, "The connection not exist");
     379           0 :         return CE_Failure;
     380             :     }
     381             : 
     382           0 :     poFeature->SetField(GNM_SYSFIELD_COST, dfCost);
     383           0 :     poFeature->SetField(GNM_SYSFIELD_INVCOST, dfInvCost);
     384           0 :     poFeature->SetField(GNM_SYSFIELD_DIRECTION, eDir);
     385             : 
     386           0 :     if (m_poGraphLayer->SetFeature(poFeature) != OGRERR_NONE)
     387             :     {
     388           0 :         OGRFeature::DestroyFeature(poFeature);
     389           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to update feature.");
     390           0 :         return CE_Failure;
     391             :     }
     392             : 
     393           0 :     OGRFeature::DestroyFeature(poFeature);
     394             : 
     395             :     // update graph
     396             : 
     397           0 :     m_oGraph.ChangeEdge(nConGFID, dfCost, dfInvCost);
     398             : 
     399           0 :     return CE_None;
     400             : }
     401             : 
     402           0 : CPLErr GNMGenericNetwork::DisconnectAll()
     403             : {
     404           0 :     if (!m_bIsGraphLoaded && LoadGraph() != CE_None)
     405             :     {
     406           0 :         return CE_Failure;
     407             :     }
     408             :     // delete everything from m_pGraphLayer
     409             : 
     410             :     OGRFeature *poFeature;
     411           0 :     m_poGraphLayer->ResetReading();
     412           0 :     while ((poFeature = m_poGraphLayer->GetNextFeature()) != nullptr)
     413             :     {
     414           0 :         CPL_IGNORE_RET_VAL(m_poGraphLayer->DeleteFeature(poFeature->GetFID()));
     415           0 :         OGRFeature::DestroyFeature(poFeature);
     416             :     }
     417             : 
     418           0 :     m_oGraph.Clear();
     419             : 
     420           0 :     return CE_None;
     421             : }
     422             : 
     423         300 : OGRFeature *GNMGenericNetwork::GetFeatureByGlobalFID(GNMGFID nFID)
     424             : {
     425         600 :     CPLString soLayerName = m_moFeatureFIDMap[nFID];
     426         466 :     for (size_t i = 0; i < m_apoLayers.size(); ++i)
     427             :     {
     428         458 :         if (EQUAL(soLayerName, m_apoLayers[i]->GetName()))
     429         292 :             return m_apoLayers[i]->GetFeature(nFID);
     430             :     }
     431           8 :     return nullptr;
     432             : }
     433             : 
     434           2 : CPLErr GNMGenericNetwork::CreateRule(const char *pszRuleStr)
     435             : {
     436           2 :     CPLDebug("GNM", "Try to create rule '%s'", pszRuleStr);
     437           4 :     GNMRule oRule(pszRuleStr);
     438           2 :     if (!oRule.IsValid())
     439             :     {
     440           0 :         return CE_Failure;
     441             :     }
     442             : 
     443           2 :     if (!oRule.IsAcceptAny())
     444             :     {
     445           0 :         bool bSrcExist = false;
     446           0 :         bool bTgtExist = false;
     447           0 :         bool bConnExist = false;
     448             :         // check layers exist
     449           0 :         for (size_t i = 0; i < m_apoLayers.size(); ++i)
     450             :         {
     451           0 :             if (EQUAL(oRule.GetSourceLayerName(), m_apoLayers[i]->GetName()))
     452             :             {
     453           0 :                 bSrcExist = true;
     454             :             }
     455           0 :             else if (EQUAL(oRule.GetTargetLayerName(),
     456             :                            m_apoLayers[i]->GetName()))
     457             :             {
     458           0 :                 bTgtExist = true;
     459             :             }
     460           0 :             else if (EQUAL(oRule.GetConnectorLayerName(),
     461             :                            m_apoLayers[i]->GetName()))
     462             :             {
     463           0 :                 bConnExist = true;
     464             :             }
     465             :         }
     466             : 
     467           0 :         if (!bSrcExist || !bTgtExist)
     468             :         {
     469           0 :             CPLError(CE_Failure, CPLE_IllegalArg,
     470             :                      "Layers '%s' or '%s' not exist",
     471           0 :                      oRule.GetSourceLayerName().c_str(),
     472           0 :                      oRule.GetTargetLayerName().c_str());
     473           0 :             return CE_Failure;
     474             :         }
     475             : 
     476           0 :         if (!bConnExist && !oRule.GetConnectorLayerName().empty())
     477             :         {
     478           0 :             CPLError(CE_Failure, CPLE_IllegalArg,
     479             :                      "Connector layer '%s' not exist",
     480           0 :                      oRule.GetConnectorLayerName().c_str());
     481           0 :             return CE_Failure;
     482             :         }
     483             :     }
     484             : 
     485           2 :     m_asRules.push_back(oRule);
     486           2 :     m_bIsRulesChanged = true;
     487             : 
     488           2 :     return CE_None;
     489             : }
     490             : 
     491           2 : CPLErr GNMGenericNetwork::DeleteAllRules()
     492             : {
     493           4 :     CPLString soFilter;
     494           2 :     soFilter.Printf("%s LIKE '%s%%'", GNM_SYSFIELD_PARAMNAME, GNM_MD_RULE);
     495           2 :     m_poMetadataLayer->SetAttributeFilter(soFilter);
     496             : 
     497           2 :     m_poMetadataLayer->ResetReading();
     498             :     OGRFeature *poFeature;
     499           2 :     std::vector<GIntBig> aFIDs;
     500           2 :     while ((poFeature = m_poMetadataLayer->GetNextFeature()) != nullptr)
     501             :     {
     502           0 :         aFIDs.push_back(poFeature->GetFID());
     503           0 :         OGRFeature::DestroyFeature(poFeature);
     504             :     }
     505             : 
     506           2 :     m_poMetadataLayer->SetAttributeFilter(nullptr);
     507           2 :     for (size_t i = 0; i < aFIDs.size(); ++i)
     508             :     {
     509           0 :         CPL_IGNORE_RET_VAL(m_poMetadataLayer->DeleteFeature(aFIDs[i]));
     510             :     }
     511             : 
     512           4 :     return CE_None;
     513             : }
     514             : 
     515           0 : CPLErr GNMGenericNetwork::DeleteRule(const char *pszRuleStr)
     516             : {
     517           0 :     for (size_t i = 0; i < m_asRules.size(); ++i)
     518             :     {
     519           0 :         if (EQUAL(pszRuleStr, m_asRules[i]))
     520             :         {
     521           0 :             m_asRules.erase(m_asRules.begin() + i);
     522           0 :             m_bIsRulesChanged = true;
     523           0 :             return CE_None;
     524             :         }
     525             :     }
     526             : 
     527           0 :     return CE_Failure;
     528             : }
     529             : 
     530           1 : char **GNMGenericNetwork::GetRules() const
     531             : {
     532           1 :     char **papszRules = nullptr;
     533           2 :     for (size_t i = 0; i < m_asRules.size(); ++i)
     534             :     {
     535           1 :         papszRules = CSLAddString(papszRules, m_asRules[i]);
     536             :     }
     537           1 :     return papszRules;
     538             : }
     539             : 
     540           2 : CPLErr GNMGenericNetwork::ConnectPointsByLines(char **papszLayerList,
     541             :                                                double dfTolerance,
     542             :                                                double dfCost, double dfInvCost,
     543             :                                                GNMDirection eDir)
     544             : {
     545           2 :     if (CSLCount(papszLayerList) < 2)
     546             :     {
     547           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     548             :                  "Minimum 2 layers needed to connect");
     549           0 :         return CE_Failure;
     550             :     }
     551             : 
     552           4 :     std::vector<OGRLayer *> paLineLayers;
     553           4 :     std::vector<OGRLayer *> paPointLayers;
     554             :     int eType;
     555             :     int iLayer;
     556             :     OGRLayer *poLayer;
     557             : 
     558           6 :     for (iLayer = 0; papszLayerList[iLayer] != nullptr; ++iLayer)
     559             :     {
     560           4 :         poLayer = GetLayerByName(papszLayerList[iLayer]);
     561           4 :         if (nullptr == poLayer)
     562           0 :             continue;
     563             : 
     564           4 :         eType = wkbFlatten(poLayer->GetGeomType());
     565           4 :         if (eType == wkbLineString || eType == wkbMultiLineString)
     566             :         {
     567           2 :             paLineLayers.push_back(poLayer);
     568             :         }
     569           2 :         else if (eType == wkbPoint)
     570             :         {
     571           2 :             paPointLayers.push_back(poLayer);
     572             :         }
     573             :     }
     574             : 
     575           2 :     if (paLineLayers.empty() || paPointLayers.empty())
     576             :     {
     577           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     578             :                  "Need at least one line (or "
     579             :                  "multiline) layer and one point layer to connect");
     580           0 :         return CE_Failure;
     581             :     }
     582             : 
     583             :     // now walk through all lines and find nearest points for line start and end
     584             :     OGRFeature *poFeature;
     585           4 :     for (size_t i = 0; i < paLineLayers.size(); ++i)
     586             :     {
     587           2 :         poLayer = paLineLayers[i];
     588             : 
     589           2 :         poLayer->ResetReading();
     590          68 :         while ((poFeature = poLayer->GetNextFeature()) != nullptr)
     591             :         {
     592          66 :             const OGRGeometry *poGeom = poFeature->GetGeometryRef();
     593          66 :             if (nullptr != poGeom)
     594             :             {
     595          66 :                 eType = wkbFlatten(poGeom->getGeometryType());
     596          66 :                 if (eType == wkbLineString)
     597             :                 {
     598          66 :                     const OGRLineString *poLineString =
     599             :                         (const OGRLineString *)poGeom;
     600          66 :                     ConnectPointsByLine(poFeature->GetFID(), poLineString,
     601             :                                         paPointLayers, dfTolerance, dfCost,
     602          66 :                                         dfInvCost, eDir);
     603             :                 }
     604           0 :                 else if (eType == wkbMultiLineString)
     605             :                 {
     606           0 :                     const OGRMultiLineString *poMultiLineString =
     607             :                         (const OGRMultiLineString *)poGeom;
     608           0 :                     ConnectPointsByMultiline(
     609             :                         poFeature->GetFID(), poMultiLineString, paPointLayers,
     610           0 :                         dfTolerance, dfCost, dfInvCost, eDir);
     611             :                 }
     612             :             }
     613          66 :             OGRFeature::DestroyFeature(poFeature);
     614             :         }
     615             :     }
     616             : 
     617           2 :     return CE_None;
     618             : }
     619             : 
     620           0 : CPLErr GNMGenericNetwork::ChangeBlockState(GNMGFID nFID, bool bIsBlock)
     621             : {
     622           0 :     if (!m_bIsGraphLoaded && LoadGraph() != CE_None)
     623             :     {
     624           0 :         return CE_Failure;
     625             :     }
     626             : 
     627             :     // change block state in layer
     628           0 :     OGRLayer *poLayer = GetLayerByName(m_moFeatureFIDMap[nFID]);
     629           0 :     if (nullptr == poLayer)
     630             :     {
     631           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to get layer '%s'.",
     632           0 :                  m_moFeatureFIDMap[nFID].c_str());
     633           0 :         return CE_Failure;
     634             :     }
     635             : 
     636           0 :     OGRFeature *poFeature = poLayer->GetFeature(nFID);
     637           0 :     if (nullptr == poFeature)
     638             :     {
     639           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     640             :                  "Failed to get feature '" GNMGFIDFormat "'.", nFID);
     641           0 :         return CE_Failure;
     642             :     }
     643             : 
     644           0 :     if (bIsBlock)
     645             :     {
     646           0 :         poFeature->SetField(GNM_SYSFIELD_BLOCKED, GNM_BLOCK_ALL);
     647             :     }
     648             :     else
     649             :     {
     650           0 :         poFeature->SetField(GNM_SYSFIELD_BLOCKED, GNM_BLOCK_NONE);
     651             :     }
     652             : 
     653           0 :     if (poLayer->SetFeature(poFeature) != OGRERR_NONE)
     654             :     {
     655           0 :         OGRFeature::DestroyFeature(poFeature);
     656           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to update feature.");
     657           0 :         return CE_Failure;
     658             :     }
     659             : 
     660           0 :     OGRFeature::DestroyFeature(poFeature);
     661             : 
     662             :     GNMGFID nSrcFID, nTgtFID, nConFID;
     663             : 
     664             :     // change block state in graph layer
     665           0 :     m_poGraphLayer->ResetReading();
     666           0 :     while ((poFeature = m_poGraphLayer->GetNextFeature()) != nullptr)
     667             :     {
     668           0 :         nSrcFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_SOURCE);
     669           0 :         nTgtFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_TARGET);
     670           0 :         nConFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_CONNECTOR);
     671           0 :         int nBlockState = poFeature->GetFieldAsInteger(GNM_SYSFIELD_BLOCKED);
     672             : 
     673           0 :         if (bIsBlock)
     674             :         {
     675           0 :             if (nSrcFID == nFID)
     676           0 :                 nBlockState |= GNM_BLOCK_SRC;
     677           0 :             else if (nTgtFID == nFID)
     678           0 :                 nBlockState |= GNM_BLOCK_TGT;
     679           0 :             else if (nConFID == nFID)
     680           0 :                 nBlockState |= GNM_BLOCK_CONN;
     681             : 
     682           0 :             poFeature->SetField(GNM_SYSFIELD_BLOCKED, nBlockState);
     683             :         }
     684             :         else
     685             :         {
     686           0 :             if (nSrcFID == nFID)
     687           0 :                 nBlockState &= ~GNM_BLOCK_SRC;
     688           0 :             else if (nTgtFID == nFID)
     689           0 :                 nBlockState &= ~GNM_BLOCK_TGT;
     690           0 :             else if (nConFID == nFID)
     691           0 :                 nBlockState &= ~GNM_BLOCK_CONN;
     692             : 
     693           0 :             poFeature->SetField(GNM_SYSFIELD_BLOCKED, nBlockState);
     694             :         }
     695             : 
     696           0 :         if (m_poGraphLayer->SetFeature(poFeature) != OGRERR_NONE)
     697             :         {
     698           0 :             OGRFeature::DestroyFeature(poFeature);
     699           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to update feature.");
     700           0 :             return CE_Failure;
     701             :         }
     702             : 
     703           0 :         OGRFeature::DestroyFeature(poFeature);
     704             :     }
     705             : 
     706             :     // change block state in graph
     707           0 :     m_oGraph.ChangeBlockState(nFID, bIsBlock);
     708             : 
     709           0 :     return CE_None;
     710             : }
     711             : 
     712           0 : CPLErr GNMGenericNetwork::ChangeAllBlockState(bool bIsBlock)
     713             : {
     714           0 :     if (!m_bIsGraphLoaded && LoadGraph() != CE_None)
     715             :     {
     716           0 :         return CE_Failure;
     717             :     }
     718             : 
     719             :     OGRFeature *poFeature;
     720           0 :     m_poGraphLayer->ResetReading();
     721           0 :     while ((poFeature = m_poGraphLayer->GetNextFeature()) != nullptr)
     722             :     {
     723           0 :         if (bIsBlock)
     724             :         {
     725           0 :             poFeature->SetField(GNM_SYSFIELD_BLOCKED, GNM_BLOCK_ALL);
     726             :         }
     727             :         else
     728             :         {
     729           0 :             poFeature->SetField(GNM_SYSFIELD_BLOCKED, GNM_BLOCK_NONE);
     730             :         }
     731             : 
     732           0 :         if (m_poGraphLayer->SetFeature(poFeature) != OGRERR_NONE)
     733             :         {
     734           0 :             OGRFeature::DestroyFeature(poFeature);
     735           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to update feature.");
     736           0 :             return CE_Failure;
     737             :         }
     738             : 
     739           0 :         OGRFeature::DestroyFeature(poFeature);
     740             :     }
     741             : 
     742             :     // change all network layers
     743             : 
     744           0 :     for (size_t i = 0; i < m_apoLayers.size(); ++i)
     745             :     {
     746           0 :         OGRLayer *poLayer = m_apoLayers[i];
     747           0 :         if (nullptr == poLayer)
     748           0 :             continue;
     749           0 :         while ((poFeature = poLayer->GetNextFeature()) != nullptr)
     750             :         {
     751           0 :             if (bIsBlock)
     752             :             {
     753           0 :                 poFeature->SetField(GNM_SYSFIELD_BLOCKED, GNM_BLOCK_ALL);
     754             :             }
     755             :             else
     756             :             {
     757           0 :                 poFeature->SetField(GNM_SYSFIELD_BLOCKED, GNM_BLOCK_NONE);
     758             :             }
     759             : 
     760           0 :             if (poLayer->SetFeature(poFeature) != OGRERR_NONE)
     761             :             {
     762           0 :                 OGRFeature::DestroyFeature(poFeature);
     763           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     764             :                          "Failed to update feature.");
     765           0 :                 return CE_Failure;
     766             :             }
     767             : 
     768           0 :             OGRFeature::DestroyFeature(poFeature);
     769             :         }
     770             :     }
     771             : 
     772           0 :     m_oGraph.ChangeAllBlockState(bIsBlock);
     773             : 
     774           0 :     return CE_None;
     775             : }
     776             : 
     777           5 : OGRLayer *GNMGenericNetwork::GetPath(GNMGFID nStartFID, GNMGFID nEndFID,
     778             :                                      GNMGraphAlgorithmType eAlgorithm,
     779             :                                      char **papszOptions)
     780             : {
     781             : 
     782           5 :     if (!m_bIsGraphLoaded && LoadGraph() != CE_None)
     783             :     {
     784           0 :         return nullptr;
     785             :     }
     786             : 
     787             :     GDALDriver *poMEMDrv =
     788           5 :         OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
     789           5 :     if (poMEMDrv == nullptr)
     790             :     {
     791           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot load 'Memory' driver");
     792           0 :         return nullptr;
     793             :     }
     794             : 
     795             :     GDALDataset *poMEMDS =
     796           5 :         poMEMDrv->Create("dummy_name", 0, 0, 0, GDT_Unknown, nullptr);
     797           5 :     OGRSpatialReference oDstSpaRef(GetProjectionRef());
     798             :     OGRLayer *poMEMLayer =
     799           5 :         poMEMDS->CreateLayer(GetAlgorithmName(eAlgorithm, true), &oDstSpaRef,
     800             :                              wkbGeometryCollection, nullptr);
     801             : 
     802             :     OGRGNMWrappedResultLayer *poResLayer =
     803           5 :         new OGRGNMWrappedResultLayer(poMEMDS, poMEMLayer);
     804             : 
     805             :     const bool bReturnEdges =
     806           5 :         CPLFetchBool(papszOptions, GNM_MD_FETCHEDGES, true);
     807             :     const bool bReturnVertices =
     808           5 :         CPLFetchBool(papszOptions, GNM_MD_FETCHVERTEX, true);
     809             : 
     810           5 :     switch (eAlgorithm)
     811             :     {
     812           2 :         case GATDijkstraShortestPath:
     813             :         {
     814           4 :             GNMPATH path = m_oGraph.DijkstraShortestPath(nStartFID, nEndFID);
     815             : 
     816             :             // fill features in result layer
     817           2 :             FillResultLayer(poResLayer, path, 1, bReturnVertices, bReturnEdges);
     818             :         }
     819           2 :         break;
     820           2 :         case GATKShortestPath:
     821             :         {
     822             :             int nK =
     823           2 :                 atoi(CSLFetchNameValueDef(papszOptions, GNM_MD_NUM_PATHS, "1"));
     824             : 
     825           2 :             CPLDebug("GNM", "Search %d path(s)", nK);
     826             : 
     827             :             std::vector<GNMPATH> paths =
     828           4 :                 m_oGraph.KShortestPaths(nStartFID, nEndFID, nK);
     829             : 
     830             :             // fill features in result layer
     831           8 :             for (size_t i = 0; i < paths.size(); ++i)
     832             :             {
     833           6 :                 FillResultLayer(poResLayer, paths[i], static_cast<int>(i + 1),
     834           6 :                                 bReturnVertices, bReturnEdges);
     835             :             }
     836             :         }
     837           2 :         break;
     838           1 :         case GATConnectedComponents:
     839             :         {
     840           2 :             GNMVECTOR anEmitters;
     841           1 :             if (nullptr != papszOptions)
     842             :             {
     843             :                 char **papszEmitter =
     844           0 :                     CSLFetchNameValueMultiple(papszOptions, GNM_MD_EMITTER);
     845           0 :                 for (int i = 0; papszEmitter[i] != nullptr; ++i)
     846             :                 {
     847           0 :                     GNMGFID nEmitter = atol(papszEmitter[i]);
     848           0 :                     anEmitters.push_back(nEmitter);
     849             :                 }
     850           0 :                 CSLDestroy(papszEmitter);
     851             :             }
     852             : 
     853           1 :             if (nStartFID != -1)
     854             :             {
     855           1 :                 anEmitters.push_back(nStartFID);
     856             :             }
     857             : 
     858           1 :             if (nStartFID != -1)
     859             :             {
     860           1 :                 anEmitters.push_back(nEndFID);
     861             :             }
     862             : 
     863           2 :             GNMPATH path = m_oGraph.ConnectedComponents(anEmitters);
     864             : 
     865             :             // fill features in result layer
     866           1 :             FillResultLayer(poResLayer, path, 1, bReturnVertices, bReturnEdges);
     867             :         }
     868           1 :         break;
     869             :     }
     870             : 
     871           5 :     return poResLayer;
     872             : }
     873             : 
     874           0 : void GNMGenericNetwork::ConnectPointsByMultiline(
     875             :     GIntBig nFID, const OGRMultiLineString *poMultiLineString,
     876             :     const std::vector<OGRLayer *> &paPointLayers, double dfTolerance,
     877             :     double dfCost, double dfInvCost, GNMDirection eDir)
     878             : {
     879           0 :     VALIDATE_POINTER0(poMultiLineString,
     880             :                       "GNMGenericNetwork::ConnectPointsByMultiline");
     881           0 :     for (auto &&poLineString : poMultiLineString)
     882             :     {
     883           0 :         ConnectPointsByLine(nFID, poLineString, paPointLayers, dfTolerance,
     884           0 :                             dfCost, dfInvCost, eDir);
     885             :     }
     886             : }
     887             : 
     888          66 : void GNMGenericNetwork::ConnectPointsByLine(
     889             :     GIntBig nFID, const OGRLineString *poLineString,
     890             :     const std::vector<OGRLayer *> &paPointLayers, double dfTolerance,
     891             :     double dfCost, double dfInvCost, GNMDirection eDir)
     892             : {
     893          66 :     VALIDATE_POINTER0(poLineString, "GNMGenericNetwork::ConnectPointsByLine");
     894          66 :     OGRPoint oStartPoint, oEndPoint;
     895          66 :     poLineString->StartPoint(&oStartPoint);
     896          66 :     poLineString->EndPoint(&oEndPoint);
     897          66 :     double dfHalfTolerance = dfTolerance / 2;
     898             : 
     899             :     GNMGFID nSrcFID =
     900          66 :         FindNearestPoint(&oStartPoint, paPointLayers, dfHalfTolerance);
     901             :     GNMGFID nTgtFID =
     902          66 :         FindNearestPoint(&oEndPoint, paPointLayers, dfHalfTolerance);
     903             : 
     904          66 :     if (nSrcFID == -1 || nTgtFID == -1)
     905           0 :         return;
     906             : 
     907             :     // connect nSrcFID with nTgtFID via nFID
     908          66 :     ConnectFeatures(nSrcFID, nTgtFID, (GNMGFID)nFID, dfCost, dfInvCost, eDir);
     909             : }
     910             : 
     911         132 : GNMGFID GNMGenericNetwork::FindNearestPoint(
     912             :     const OGRPoint *poPoint, const std::vector<OGRLayer *> &paPointLayers,
     913             :     double dfTolerance)
     914             : {
     915         132 :     VALIDATE_POINTER1(poPoint, "GNMGenericNetwork::FindNearestPoint", -1);
     916         132 :     double dfMinX = poPoint->getX() - dfTolerance;
     917         132 :     double dfMinY = poPoint->getY() - dfTolerance;
     918         132 :     double dfMaxX = poPoint->getX() + dfTolerance;
     919         132 :     double dfMaxY = poPoint->getY() + dfTolerance;
     920             : 
     921             :     OGRFeature *poFeature;
     922             : 
     923         132 :     for (size_t i = 0; i < paPointLayers.size(); ++i)
     924             :     {
     925         132 :         OGRLayer *poLayer = paPointLayers[i];
     926             : 
     927         132 :         poLayer->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX, dfMaxY);
     928         132 :         poLayer->ResetReading();
     929         132 :         while ((poFeature = poLayer->GetNextFeature()) != nullptr)
     930             :         {
     931         132 :             GNMGFID nRetFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_GFID);
     932         132 :             OGRFeature::DestroyFeature(poFeature);
     933         132 :             return nRetFID;
     934             :         }
     935             :     }
     936             : 
     937           0 :     return -1;
     938             : }
     939             : 
     940          66 : OGRFeature *GNMGenericNetwork::FindConnection(GNMGFID nSrcFID, GNMGFID nTgtFID,
     941             :                                               GNMGFID nConFID)
     942             : {
     943             : 
     944          66 :     CPLString soFilter;
     945             :     soFilter.Printf("%s = " GNMGFIDFormat " and %s = " GNMGFIDFormat
     946             :                     " and %s = " GNMGFIDFormat,
     947             :                     GNM_SYSFIELD_SOURCE, nSrcFID, GNM_SYSFIELD_TARGET, nTgtFID,
     948          66 :                     GNM_SYSFIELD_CONNECTOR, nConFID);
     949             : 
     950          66 :     CPLDebug("GNM", "Set attribute filter: %s", soFilter.c_str());
     951             : 
     952          66 :     m_poGraphLayer->SetAttributeFilter(soFilter);
     953          66 :     m_poGraphLayer->ResetReading();
     954          66 :     OGRFeature *f = m_poGraphLayer->GetNextFeature();
     955          66 :     m_poGraphLayer->SetAttributeFilter(nullptr);
     956         132 :     return f;
     957             : }
     958             : 
     959          16 : bool GNMGenericNetwork::SaveRules()
     960             : {
     961          16 :     if (!m_bIsRulesChanged)
     962          14 :         return true;
     963             : 
     964           2 :     if (DeleteAllRules() != CE_None)
     965           0 :         return false;
     966             : 
     967           2 :     bool bOK = true;
     968             :     OGRFeature *poFeature;
     969           4 :     for (int i = 0; i < (int)m_asRules.size(); ++i)
     970             :     {
     971             :         poFeature =
     972           2 :             OGRFeature::CreateFeature(m_poMetadataLayer->GetLayerDefn());
     973           2 :         poFeature->SetField(GNM_SYSFIELD_PARAMNAME,
     974             :                             CPLSPrintf("%s%d", GNM_MD_RULE, i + 1));
     975           2 :         poFeature->SetField(GNM_SYSFIELD_PARAMVALUE, m_asRules[i]);
     976           2 :         if (m_poMetadataLayer->CreateFeature(poFeature) != OGRERR_NONE)
     977             :         {
     978           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Write rule '%s' failed",
     979           0 :                      m_asRules[i].c_str());
     980           0 :             bOK = false;
     981             :             // TODO: do we need interrupt here?
     982             :             // OGRFeature::DestroyFeature( poFeature );
     983             :             // return CE_Failure;
     984             :         }
     985           2 :         OGRFeature::DestroyFeature(poFeature);
     986             :     }
     987           2 :     return bOK;
     988             : }
     989             : 
     990           0 : GNMGFID GNMGenericNetwork::GetNewVirtualFID()
     991             : {
     992           0 :     return --m_nVirtualConnectionGID;
     993             : }
     994             : 
     995           9 : void GNMGenericNetwork::FillResultLayer(OGRGNMWrappedResultLayer *poResLayer,
     996             :                                         const GNMPATH &path, int nNoOfPath,
     997             :                                         bool bReturnVertices, bool bReturnEdges)
     998             : {
     999         159 :     for (size_t i = 0; i < path.size(); ++i)
    1000             :     {
    1001         150 :         if (bReturnVertices)
    1002             :         {
    1003         150 :             GNMGFID nGFID = path[i].first;
    1004             : 
    1005             :             // TODO: create feature for virtual vertex
    1006             :             // if(nGFID < -1) {...}
    1007             : 
    1008         300 :             CPLString soLayerName = m_moFeatureFIDMap[nGFID];
    1009         150 :             OGRFeature *poFeature = GetFeatureByGlobalFID(nGFID);
    1010         150 :             if (nullptr != poFeature)
    1011             :             {
    1012         150 :                 poResLayer->InsertFeature(poFeature, soLayerName, nNoOfPath,
    1013         150 :                                           false);
    1014             : 
    1015         150 :                 OGRFeature::DestroyFeature(poFeature);
    1016             :             }
    1017             :         }
    1018             : 
    1019         150 :         if (bReturnEdges)
    1020             :         {
    1021         150 :             GNMGFID nGFID = path[i].second;
    1022             : 
    1023             :             // TODO: create feature for virtual edge
    1024             :             // if(nGFID < -1) {...}
    1025             : 
    1026         300 :             CPLString soLayerName = m_moFeatureFIDMap[nGFID];
    1027         150 :             OGRFeature *poFeature = GetFeatureByGlobalFID(nGFID);
    1028         150 :             if (nullptr != poFeature)
    1029             :             {
    1030         142 :                 poResLayer->InsertFeature(poFeature, soLayerName, nNoOfPath,
    1031         142 :                                           true);
    1032         142 :                 OGRFeature::DestroyFeature(poFeature);
    1033             :             }
    1034             :         }
    1035             :     }
    1036           9 : }
    1037             : 
    1038           6 : CPLErr GNMGenericNetwork::CheckLayerDriver(const char *pszDefaultDriverName,
    1039             :                                            char **papszOptions)
    1040             : {
    1041           6 :     if (nullptr == m_poLayerDriver)
    1042             :     {
    1043           2 :         const char *pszDriverName = CSLFetchNameValueDef(
    1044             :             papszOptions, GNM_MD_FORMAT, pszDefaultDriverName);
    1045             : 
    1046           2 :         if (!CheckStorageDriverSupport(pszDriverName))
    1047             :         {
    1048           0 :             CPLError(CE_Failure, CPLE_IllegalArg,
    1049             :                      "%s driver not supported as network storage",
    1050             :                      pszDriverName);
    1051           0 :             return CE_Failure;
    1052             :         }
    1053             : 
    1054           2 :         m_poLayerDriver =
    1055           2 :             GetGDALDriverManager()->GetDriverByName(pszDriverName);
    1056           2 :         if (nullptr == m_poLayerDriver)
    1057             :         {
    1058           0 :             CPLError(CE_Failure, CPLE_IllegalArg, "%s driver not available",
    1059             :                      pszDriverName);
    1060           0 :             return CE_Failure;
    1061             :         }
    1062             :     }
    1063           6 :     return CE_None;
    1064             : }
    1065             : 
    1066           2 : CPLErr GNMGenericNetwork::CreateMetadataLayer(GDALDataset *const pDS,
    1067             :                                               int nVersion, size_t nFieldSize)
    1068             : {
    1069             :     OGRLayer *pMetadataLayer =
    1070           2 :         pDS->CreateLayer(GNM_SYSLAYER_META, nullptr, wkbNone, nullptr);
    1071           2 :     if (nullptr == pMetadataLayer)
    1072             :     {
    1073           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Creation of '%s' layer failed",
    1074             :                  GNM_SYSLAYER_META);
    1075           0 :         return CE_Failure;
    1076             :     }
    1077             : 
    1078           4 :     OGRFieldDefn oFieldKey(GNM_SYSFIELD_PARAMNAME, OFTString);
    1079           2 :     oFieldKey.SetWidth(static_cast<int>(nFieldSize));
    1080           4 :     OGRFieldDefn oFieldValue(GNM_SYSFIELD_PARAMVALUE, OFTString);
    1081           2 :     oFieldValue.SetWidth(static_cast<int>(nFieldSize));
    1082             : 
    1083           4 :     if (pMetadataLayer->CreateField(&oFieldKey) != OGRERR_NONE ||
    1084           2 :         pMetadataLayer->CreateField(&oFieldValue) != OGRERR_NONE)
    1085             :     {
    1086           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1087             :                  "Creation of layer '%s' fields failed", GNM_SYSLAYER_META);
    1088           0 :         return CE_Failure;
    1089             :     }
    1090             : 
    1091             :     OGRFeature *poFeature;
    1092             : 
    1093             :     // write name
    1094           2 :     poFeature = OGRFeature::CreateFeature(pMetadataLayer->GetLayerDefn());
    1095           2 :     poFeature->SetField(GNM_SYSFIELD_PARAMNAME, GNM_MD_NAME);
    1096           2 :     poFeature->SetField(GNM_SYSFIELD_PARAMVALUE, m_soName);
    1097           2 :     if (pMetadataLayer->CreateFeature(poFeature) != OGRERR_NONE)
    1098             :     {
    1099           0 :         OGRFeature::DestroyFeature(poFeature);
    1100           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Write GNM name failed");
    1101           0 :         return CE_Failure;
    1102             :     }
    1103           2 :     OGRFeature::DestroyFeature(poFeature);
    1104             : 
    1105             :     // write version
    1106           2 :     poFeature = OGRFeature::CreateFeature(pMetadataLayer->GetLayerDefn());
    1107           2 :     poFeature->SetField(GNM_SYSFIELD_PARAMNAME, GNM_MD_VERSION);
    1108           2 :     poFeature->SetField(GNM_SYSFIELD_PARAMVALUE, CPLSPrintf("%d", nVersion));
    1109           2 :     if (pMetadataLayer->CreateFeature(poFeature) != OGRERR_NONE)
    1110             :     {
    1111           0 :         OGRFeature::DestroyFeature(poFeature);
    1112           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Write GNM version failed");
    1113           0 :         return CE_Failure;
    1114             :     }
    1115           2 :     OGRFeature::DestroyFeature(poFeature);
    1116             : 
    1117             :     // write description
    1118           2 :     if (!sDescription.empty())
    1119             :     {
    1120           2 :         poFeature = OGRFeature::CreateFeature(pMetadataLayer->GetLayerDefn());
    1121           2 :         poFeature->SetField(GNM_SYSFIELD_PARAMNAME, GNM_MD_DESCR);
    1122           2 :         poFeature->SetField(GNM_SYSFIELD_PARAMVALUE, sDescription);
    1123           2 :         if (pMetadataLayer->CreateFeature(poFeature) != OGRERR_NONE)
    1124             :         {
    1125           0 :             OGRFeature::DestroyFeature(poFeature);
    1126           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1127             :                      "Write GNM description failed");
    1128           0 :             return CE_Failure;
    1129             :         }
    1130           2 :         OGRFeature::DestroyFeature(poFeature);
    1131             :     }
    1132             : 
    1133             :     // write srs if < 254 or create file
    1134           2 :     if (!m_oSRS.IsEmpty())
    1135             :     {
    1136           2 :         char *pszWKT = nullptr;
    1137           2 :         m_oSRS.exportToWkt(&pszWKT);
    1138           2 :         const std::string soSRS = pszWKT ? pszWKT : "";
    1139           2 :         CPLFree(pszWKT);
    1140           2 :         if (soSRS.size() >= nFieldSize)
    1141             :         {
    1142             :             // cppcheck-suppress knownConditionTrueFalse
    1143           2 :             if (StoreNetworkSrs() != CE_None)
    1144           0 :                 return CE_Failure;
    1145             :         }
    1146             :         else
    1147             :         {
    1148             :             poFeature =
    1149           0 :                 OGRFeature::CreateFeature(pMetadataLayer->GetLayerDefn());
    1150           0 :             poFeature->SetField(GNM_SYSFIELD_PARAMNAME, GNM_MD_SRS);
    1151           0 :             poFeature->SetField(GNM_SYSFIELD_PARAMVALUE, soSRS.c_str());
    1152           0 :             if (pMetadataLayer->CreateFeature(poFeature) != OGRERR_NONE)
    1153             :             {
    1154           0 :                 OGRFeature::DestroyFeature(poFeature);
    1155           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Write GNM SRS failed");
    1156           0 :                 return CE_Failure;
    1157             :             }
    1158           0 :             OGRFeature::DestroyFeature(poFeature);
    1159             :         }
    1160             :     }
    1161             : 
    1162           2 :     m_poMetadataLayer = pMetadataLayer;
    1163             : 
    1164           2 :     m_nVersion = nVersion;
    1165             : 
    1166             :     // create default rule
    1167           2 :     return CreateRule("ALLOW CONNECTS ANY");
    1168             : }
    1169             : 
    1170           0 : CPLErr GNMGenericNetwork::StoreNetworkSrs()
    1171             : {
    1172           0 :     return CE_Failure;
    1173             : }
    1174             : 
    1175           0 : CPLErr GNMGenericNetwork::LoadNetworkSrs()
    1176             : {
    1177           0 :     return CE_Failure;
    1178             : }
    1179             : 
    1180           2 : CPLErr GNMGenericNetwork::CreateGraphLayer(GDALDataset *const pDS)
    1181             : {
    1182           2 :     m_poGraphLayer =
    1183           2 :         pDS->CreateLayer(GNM_SYSLAYER_GRAPH, nullptr, wkbNone, nullptr);
    1184           2 :     if (nullptr == m_poGraphLayer)
    1185             :     {
    1186           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Creation of '%s' layer failed",
    1187             :                  GNM_SYSLAYER_GRAPH);
    1188           0 :         return CE_Failure;
    1189             :     }
    1190             : 
    1191           4 :     OGRFieldDefn oFieldSrc(GNM_SYSFIELD_SOURCE, GNMGFIDInt);
    1192           4 :     OGRFieldDefn oFieldDst(GNM_SYSFIELD_TARGET, GNMGFIDInt);
    1193           4 :     OGRFieldDefn oFieldConnector(GNM_SYSFIELD_CONNECTOR, GNMGFIDInt);
    1194           4 :     OGRFieldDefn oFieldCost(GNM_SYSFIELD_COST, OFTReal);
    1195           4 :     OGRFieldDefn oFieldInvCost(GNM_SYSFIELD_INVCOST, OFTReal);
    1196           4 :     OGRFieldDefn oFieldDir(GNM_SYSFIELD_DIRECTION, OFTInteger);
    1197           4 :     OGRFieldDefn oFieldBlock(GNM_SYSFIELD_BLOCKED, OFTInteger);
    1198             : 
    1199           2 :     if (m_poGraphLayer->CreateField(&oFieldSrc) != OGRERR_NONE ||
    1200           2 :         m_poGraphLayer->CreateField(&oFieldDst) != OGRERR_NONE ||
    1201           2 :         m_poGraphLayer->CreateField(&oFieldConnector) != OGRERR_NONE ||
    1202           2 :         m_poGraphLayer->CreateField(&oFieldCost) != OGRERR_NONE ||
    1203           2 :         m_poGraphLayer->CreateField(&oFieldInvCost) != OGRERR_NONE ||
    1204           6 :         m_poGraphLayer->CreateField(&oFieldDir) != OGRERR_NONE ||
    1205           2 :         m_poGraphLayer->CreateField(&oFieldBlock) != OGRERR_NONE)
    1206             :     {
    1207           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1208             :                  "Creation of layer '%s' fields failed", GNM_SYSLAYER_GRAPH);
    1209           0 :         return CE_Failure;
    1210             :     }
    1211             : 
    1212           2 :     return CE_None;
    1213             : }
    1214             : 
    1215           2 : CPLErr GNMGenericNetwork::CreateFeaturesLayer(GDALDataset *const pDS)
    1216             : {
    1217           2 :     m_poFeaturesLayer =
    1218           2 :         pDS->CreateLayer(GNM_SYSLAYER_FEATURES, nullptr, wkbNone, nullptr);
    1219           2 :     if (nullptr == m_poFeaturesLayer)
    1220             :     {
    1221           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Creation of '%s' layer failed",
    1222             :                  GNM_SYSLAYER_FEATURES);
    1223           0 :         return CE_Failure;
    1224             :     }
    1225             : 
    1226           4 :     OGRFieldDefn oFieldGID(GNM_SYSFIELD_GFID, GNMGFIDInt);
    1227           4 :     OGRFieldDefn oFieldLayerName(GNM_SYSFIELD_LAYERNAME, OFTString);
    1228           2 :     oFieldLayerName.SetWidth(254);
    1229             : 
    1230           4 :     if (m_poFeaturesLayer->CreateField(&oFieldGID) != OGRERR_NONE ||
    1231           2 :         m_poFeaturesLayer->CreateField(&oFieldLayerName) != OGRERR_NONE)
    1232             :     {
    1233           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1234             :                  "Creation of layer '%s' fields failed", GNM_SYSLAYER_FEATURES);
    1235           0 :         return CE_Failure;
    1236             :     }
    1237             : 
    1238           2 :     return CE_None;
    1239             : }
    1240             : 
    1241          14 : CPLErr GNMGenericNetwork::LoadMetadataLayer(GDALDataset *const pDS)
    1242             : {
    1243             :     // read version, description, SRS, classes, rules
    1244          14 :     m_poMetadataLayer = pDS->GetLayerByName(GNM_SYSLAYER_META);
    1245          14 :     if (nullptr == m_poMetadataLayer)
    1246             :     {
    1247           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Loading of '%s' layer failed",
    1248             :                  GNM_SYSLAYER_META);
    1249           0 :         return CE_Failure;
    1250             :     }
    1251             : 
    1252          28 :     std::map<int, GNMRule> moRules;
    1253          14 :     int nRulePrefixLen = static_cast<int>(CPLStrnlen(GNM_MD_RULE, 255));
    1254             :     OGRFeature *poFeature;
    1255          14 :     m_poMetadataLayer->ResetReading();
    1256          70 :     while ((poFeature = m_poMetadataLayer->GetNextFeature()) != nullptr)
    1257             :     {
    1258          56 :         const char *pKey = poFeature->GetFieldAsString(GNM_SYSFIELD_PARAMNAME);
    1259             :         const char *pValue =
    1260          56 :             poFeature->GetFieldAsString(GNM_SYSFIELD_PARAMVALUE);
    1261             : 
    1262          56 :         CPLDebug("GNM", "Load metadata. Key: %s, value %s", pKey, pValue);
    1263             : 
    1264          56 :         if (EQUAL(pKey, GNM_MD_NAME))
    1265             :         {
    1266          14 :             m_soName = pValue;
    1267             :         }
    1268          42 :         else if (EQUAL(pKey, GNM_MD_DESCR))
    1269             :         {
    1270          14 :             sDescription = pValue;
    1271             :         }
    1272          28 :         else if (EQUAL(pKey, GNM_MD_SRS))
    1273             :         {
    1274           0 :             m_oSRS.importFromWkt(pValue);
    1275             :         }
    1276          28 :         else if (EQUAL(pKey, GNM_MD_VERSION))
    1277             :         {
    1278          14 :             m_nVersion = atoi(pValue);
    1279             :         }
    1280          14 :         else if (EQUALN(pKey, GNM_MD_RULE, nRulePrefixLen))
    1281             :         {
    1282          14 :             moRules[atoi(pKey + nRulePrefixLen)] = GNMRule(pValue);
    1283             :         }
    1284             : 
    1285          56 :         OGRFeature::DestroyFeature(poFeature);
    1286             :     }
    1287             : 
    1288          28 :     for (std::map<int, GNMRule>::iterator it = moRules.begin();
    1289          42 :          it != moRules.end(); ++it)
    1290             :     {
    1291          14 :         if (it->second.IsValid())
    1292          14 :             m_asRules.push_back(it->second);
    1293             :     }
    1294             : 
    1295          14 :     if (!m_oSRS.IsEmpty())
    1296             :     {
    1297             :         // cppcheck-suppress knownConditionTrueFalse
    1298           0 :         if (LoadNetworkSrs() != CE_None)
    1299           0 :             return CE_Failure;
    1300             :     }
    1301             : 
    1302          14 :     return CE_None;
    1303             : }
    1304             : 
    1305          14 : CPLErr GNMGenericNetwork::LoadGraphLayer(GDALDataset *const pDS)
    1306             : {
    1307          14 :     m_poGraphLayer = pDS->GetLayerByName(GNM_SYSLAYER_GRAPH);
    1308          14 :     if (nullptr == m_poGraphLayer)
    1309             :     {
    1310           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Loading of '%s' layer failed",
    1311             :                  GNM_SYSLAYER_GRAPH);
    1312           0 :         return CE_Failure;
    1313             :     }
    1314             : 
    1315          14 :     return CE_None;
    1316             : }
    1317             : 
    1318           7 : CPLErr GNMGenericNetwork::LoadGraph()
    1319             : {
    1320           7 :     if (m_bIsGraphLoaded)
    1321           0 :         return CE_None;
    1322             : 
    1323           7 :     if (nullptr == m_poGraphLayer)
    1324             :     {
    1325           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Loading of graph data failed");
    1326           0 :         return CE_Failure;
    1327             :     }
    1328             : 
    1329             :     OGRFeature *poFeature;
    1330           7 :     m_poGraphLayer->ResetReading();
    1331             :     GNMGFID nSrcFID, nTgtFID, nConFID;
    1332             :     double dfCost, dfInvCost;
    1333         172 :     while ((poFeature = m_poGraphLayer->GetNextFeature()) != nullptr)
    1334             :     {
    1335         165 :         nSrcFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_SOURCE);
    1336         165 :         nTgtFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_TARGET);
    1337         165 :         nConFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_CONNECTOR);
    1338         165 :         dfCost = poFeature->GetFieldAsDouble(GNM_SYSFIELD_COST);
    1339         165 :         dfInvCost = poFeature->GetFieldAsDouble(GNM_SYSFIELD_INVCOST);
    1340             :         GNMDirection eDir =
    1341         165 :             poFeature->GetFieldAsInteger(GNM_SYSFIELD_DIRECTION);
    1342             : 
    1343         165 :         int nBlockState = poFeature->GetFieldAsInteger(GNM_SYSFIELD_BLOCKED);
    1344             : 
    1345         165 :         bool bIsBlock = GNM_BLOCK_NONE != nBlockState;
    1346             : 
    1347         165 :         m_oGraph.AddEdge(nConFID, nSrcFID, nTgtFID, eDir == GNM_EDGE_DIR_BOTH,
    1348             :                          dfCost, dfInvCost);
    1349             : 
    1350         165 :         if (bIsBlock)
    1351             :         {
    1352           0 :             if (nBlockState & GNM_BLOCK_SRC)
    1353           0 :                 m_oGraph.ChangeBlockState(nSrcFID, bIsBlock);
    1354           0 :             if (nBlockState & GNM_BLOCK_TGT)
    1355           0 :                 m_oGraph.ChangeBlockState(nTgtFID, bIsBlock);
    1356           0 :             if (nBlockState & GNM_BLOCK_CONN)
    1357           0 :                 m_oGraph.ChangeBlockState(nConFID, bIsBlock);
    1358             :         }
    1359             : 
    1360         165 :         if (nConFID < m_nVirtualConnectionGID)
    1361           0 :             m_nVirtualConnectionGID = nConFID;
    1362             : 
    1363         165 :         OGRFeature::DestroyFeature(poFeature);
    1364             :     }
    1365             : 
    1366           7 :     m_bIsGraphLoaded = true;
    1367           7 :     return CE_None;
    1368             : }
    1369             : 
    1370          14 : CPLErr GNMGenericNetwork::LoadFeaturesLayer(GDALDataset *const pDS)
    1371             : {
    1372          14 :     m_poFeaturesLayer = pDS->GetLayerByName(GNM_SYSLAYER_FEATURES);
    1373          14 :     if (nullptr == m_poFeaturesLayer)
    1374             :     {
    1375           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Loading of '%s' layer failed",
    1376             :                  GNM_SYSLAYER_FEATURES);
    1377           0 :         return CE_Failure;
    1378             :     }
    1379             : 
    1380             :     OGRFeature *poFeature;
    1381          14 :     m_poFeaturesLayer->ResetReading();
    1382         687 :     while ((poFeature = m_poFeaturesLayer->GetNextFeature()) != nullptr)
    1383             :     {
    1384         673 :         GNMGFID nFID = poFeature->GetFieldAsGNMGFID(GNM_SYSFIELD_GFID);
    1385             :         const char *pFeatureClass =
    1386         673 :             poFeature->GetFieldAsString(GNM_SYSFIELD_LAYERNAME);
    1387             : 
    1388         673 :         if (nFID >= m_nGID)
    1389         673 :             m_nGID = nFID + 1;
    1390             : 
    1391         673 :         m_moFeatureFIDMap[nFID] = pFeatureClass;
    1392             : 
    1393             :         // Load network layer. No error handling as we want to load whole
    1394             :         // network
    1395         673 :         LoadNetworkLayer(pFeatureClass);
    1396             : 
    1397         673 :         OGRFeature::DestroyFeature(poFeature);
    1398             :     }
    1399          14 :     return CE_None;
    1400             : }
    1401             : 
    1402           4 : int GNMGenericNetwork::TestCapability(const char *pszCap)
    1403             : 
    1404             : {
    1405           4 :     if (EQUAL(pszCap, ODsCCreateLayer))
    1406           4 :         return TRUE;
    1407           0 :     else if (EQUAL(pszCap, ODsCDeleteLayer))
    1408           0 :         return TRUE;
    1409             :     else
    1410           0 :         return FALSE;
    1411             : }
    1412             : 
    1413           4 : OGRLayer *GNMGenericNetwork::CopyLayer(OGRLayer *poSrcLayer,
    1414             :                                        const char *pszNewName,
    1415             :                                        char **papszOptions)
    1416             : {
    1417           8 :     CPLStringList aosOptions(CSLDuplicate(papszOptions));
    1418           4 :     aosOptions.SetNameValue("DST_SRSWKT", GetProjectionRef());
    1419           8 :     return GDALDataset::CopyLayer(poSrcLayer, pszNewName, aosOptions.List());
    1420             : }
    1421             : 
    1422           0 : int GNMGenericNetwork::CloseDependentDatasets()
    1423             : {
    1424           0 :     size_t nCount = m_apoLayers.size();
    1425           0 :     for (size_t i = 0; i < nCount; ++i)
    1426             :     {
    1427           0 :         delete m_apoLayers[i];
    1428             :     }
    1429           0 :     m_apoLayers.clear();
    1430             : 
    1431           0 :     GNMNetwork::CloseDependentDatasets();
    1432             : 
    1433           0 :     return nCount > 0 ? TRUE : FALSE;
    1434             : }
    1435             : 
    1436          16 : CPLErr GNMGenericNetwork::FlushCache(bool bAtClosing)
    1437             : {
    1438          16 :     CPLErr eErr = CE_None;
    1439          16 :     if (!SaveRules())
    1440           0 :         eErr = CE_Failure;
    1441             : 
    1442          16 :     if (GNMNetwork::FlushCache(bAtClosing) != CE_None)
    1443           0 :         eErr = CE_Failure;
    1444          16 :     return eErr;
    1445             : }
    1446             : 
    1447             : //--- C API --------------------------------------------------------------------
    1448             : 
    1449           0 : CPLErr CPL_STDCALL GNMConnectFeatures(GNMGenericNetworkH hNet, GNMGFID nSrcFID,
    1450             :                                       GNMGFID nTgtFID, GNMGFID nConFID,
    1451             :                                       double dfCost, double dfInvCost,
    1452             :                                       GNMDirection eDir)
    1453             : {
    1454           0 :     VALIDATE_POINTER1(hNet, "GNMConnectFeatures", CE_Failure);
    1455             : 
    1456             :     return ((GNMGenericNetwork *)hNet)
    1457           0 :         ->ConnectFeatures(nSrcFID, nTgtFID, nConFID, dfCost, dfInvCost, eDir);
    1458             : }
    1459             : 
    1460           0 : CPLErr CPL_STDCALL GNMDisconnectFeatures(GNMGenericNetworkH hNet,
    1461             :                                          GNMGFID nSrcFID, GNMGFID nTgtFID,
    1462             :                                          GNMGFID nConFID)
    1463             : {
    1464           0 :     VALIDATE_POINTER1(hNet, "GNMDisconnectFeatures", CE_Failure);
    1465             : 
    1466             :     return ((GNMGenericNetwork *)hNet)
    1467           0 :         ->DisconnectFeatures(nSrcFID, nTgtFID, nConFID);
    1468             : }
    1469             : 
    1470           0 : CPLErr CPL_STDCALL GNMDisconnectFeaturesWithId(GNMGenericNetworkH hNet,
    1471             :                                                GNMGFID nFID)
    1472             : {
    1473           0 :     VALIDATE_POINTER1(hNet, "GNMDisconnectFeaturesWithId", CE_Failure);
    1474             : 
    1475           0 :     return ((GNMGenericNetwork *)hNet)->DisconnectFeaturesWithId(nFID);
    1476             : }
    1477             : 
    1478           0 : CPLErr CPL_STDCALL GNMReconnectFeatures(GNMGenericNetworkH hNet,
    1479             :                                         GNMGFID nSrcFID, GNMGFID nTgtFID,
    1480             :                                         GNMGFID nConFID, double dfCost,
    1481             :                                         double dfInvCost, GNMDirection eDir)
    1482             : {
    1483           0 :     VALIDATE_POINTER1(hNet, "GNMReconnectFeatures", CE_Failure);
    1484             : 
    1485             :     return ((GNMGenericNetwork *)hNet)
    1486           0 :         ->ReconnectFeatures(nSrcFID, nTgtFID, nConFID, dfCost, dfInvCost, eDir);
    1487             : }
    1488             : 
    1489           0 : CPLErr CPL_STDCALL GNMCreateRule(GNMGenericNetworkH hNet,
    1490             :                                  const char *pszRuleStr)
    1491             : {
    1492           0 :     VALIDATE_POINTER1(hNet, "GNMCreateRule", CE_Failure);
    1493             : 
    1494           0 :     return ((GNMGenericNetwork *)hNet)->CreateRule(pszRuleStr);
    1495             : }
    1496             : 
    1497           0 : CPLErr CPL_STDCALL GNMDeleteAllRules(GNMGenericNetworkH hNet)
    1498             : {
    1499           0 :     VALIDATE_POINTER1(hNet, "GNMDeleteAllRules", CE_Failure);
    1500             : 
    1501           0 :     return ((GNMGenericNetwork *)hNet)->DeleteAllRules();
    1502             : }
    1503             : 
    1504           0 : CPLErr CPL_STDCALL GNMDeleteRule(GNMGenericNetworkH hNet,
    1505             :                                  const char *pszRuleStr)
    1506             : {
    1507           0 :     VALIDATE_POINTER1(hNet, "GNMDeleteRule", CE_Failure);
    1508             : 
    1509           0 :     return ((GNMGenericNetwork *)hNet)->DeleteRule(pszRuleStr);
    1510             : }
    1511             : 
    1512           0 : char **CPL_STDCALL GNMGetRules(GNMGenericNetworkH hNet)
    1513             : {
    1514           0 :     VALIDATE_POINTER1(hNet, "GNMDeleteRule", nullptr);
    1515             : 
    1516           0 :     return ((GNMGenericNetwork *)hNet)->GetRules();
    1517             : }
    1518             : 
    1519           1 : CPLErr CPL_STDCALL GNMConnectPointsByLines(GNMGenericNetworkH hNet,
    1520             :                                            char **papszLayerList,
    1521             :                                            double dfTolerance, double dfCost,
    1522             :                                            double dfInvCost, GNMDirection eDir)
    1523             : {
    1524           1 :     VALIDATE_POINTER1(hNet, "GNMConnectPointsByLines", CE_Failure);
    1525             : 
    1526             :     return ((GNMGenericNetwork *)hNet)
    1527           1 :         ->ConnectPointsByLines(papszLayerList, dfTolerance, dfCost, dfInvCost,
    1528           1 :                                eDir);
    1529             : }
    1530             : 
    1531           0 : CPLErr CPL_STDCALL GNMChangeBlockState(GNMGenericNetworkH hNet, GNMGFID nFID,
    1532             :                                        bool bIsBlock)
    1533             : {
    1534           0 :     VALIDATE_POINTER1(hNet, "GNMChangeBlockState", CE_Failure);
    1535             : 
    1536           0 :     return ((GNMGenericNetwork *)hNet)->ChangeBlockState(nFID, bIsBlock);
    1537             : }
    1538             : 
    1539           0 : CPLErr CPL_STDCALL GNMChangeAllBlockState(GNMGenericNetworkH hNet, int bIsBlock)
    1540             : {
    1541           0 :     VALIDATE_POINTER1(hNet, "GNMChangeAllBlockState", CE_Failure);
    1542             : 
    1543           0 :     return ((GNMGenericNetwork *)hNet)->ChangeAllBlockState(bIsBlock == TRUE);
    1544             : }
    1545             : 
    1546             : //! @endcond

Generated by: LCOV version 1.14