Coverage Report

Created: 2025-06-13 06:29

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