Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/generic/ogrlayer.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  The generic portions of the OGRSFLayer class.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999,  Les Technologies SoftMap Inc.
9
 * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "ogrsf_frmts.h"
15
#include "ogr_api.h"
16
#include "ogr_p.h"
17
#include "ogr_attrind.h"
18
#include "ogr_swq.h"
19
#include "ograpispy.h"
20
#include "ogr_wkb.h"
21
#include "ogrlayer_private.h"
22
23
#include "cpl_time.h"
24
#include <cassert>
25
#include <cmath>
26
#include <limits>
27
#include <memory>
28
#include <set>
29
30
/************************************************************************/
31
/*                              OGRLayer()                              */
32
/************************************************************************/
33
34
OGRLayer::OGRLayer()
35
0
    : m_poPrivate(new Private()), m_bFilterIsEnvelope(FALSE),
36
0
      m_poFilterGeom(nullptr),
37
0
      m_pPreparedFilterGeom(nullptr), m_sFilterEnvelope{},
38
0
      m_iGeomFieldFilter(0), m_poStyleTable(nullptr), m_poAttrQuery(nullptr),
39
0
      m_pszAttrQueryString(nullptr), m_poAttrIndex(nullptr), m_nRefCount(0),
40
0
      m_nFeaturesRead(0)
41
0
{
42
0
}
43
44
/************************************************************************/
45
/*                             ~OGRLayer()                              */
46
/************************************************************************/
47
48
OGRLayer::~OGRLayer()
49
50
0
{
51
0
    if (m_poStyleTable)
52
0
    {
53
0
        delete m_poStyleTable;
54
0
        m_poStyleTable = nullptr;
55
0
    }
56
57
0
    if (m_poAttrIndex != nullptr)
58
0
    {
59
0
        delete m_poAttrIndex;
60
0
        m_poAttrIndex = nullptr;
61
0
    }
62
63
0
    if (m_poAttrQuery != nullptr)
64
0
    {
65
0
        delete m_poAttrQuery;
66
0
        m_poAttrQuery = nullptr;
67
0
    }
68
69
0
    CPLFree(m_pszAttrQueryString);
70
71
0
    if (m_poFilterGeom)
72
0
    {
73
0
        delete m_poFilterGeom;
74
0
        m_poFilterGeom = nullptr;
75
0
    }
76
77
0
    if (m_pPreparedFilterGeom != nullptr)
78
0
    {
79
0
        OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
80
0
        m_pPreparedFilterGeom = nullptr;
81
0
    }
82
83
0
    if (m_poSharedArrowArrayStreamPrivateData != nullptr)
84
0
    {
85
0
        m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
86
0
    }
87
0
}
88
89
/************************************************************************/
90
/*                             Reference()                              */
91
/************************************************************************/
92
93
/**
94
\brief Increment layer reference count.
95
96
This method is the same as the C function OGR_L_Reference().
97
98
@return the reference count after incrementing.
99
*/
100
int OGRLayer::Reference()
101
102
0
{
103
0
    return ++m_nRefCount;
104
0
}
105
106
/************************************************************************/
107
/*                          OGR_L_Reference()                           */
108
/************************************************************************/
109
110
int OGR_L_Reference(OGRLayerH hLayer)
111
112
0
{
113
0
    VALIDATE_POINTER1(hLayer, "OGR_L_Reference", 0);
114
115
0
    return OGRLayer::FromHandle(hLayer)->Reference();
116
0
}
117
118
/************************************************************************/
119
/*                            Dereference()                             */
120
/************************************************************************/
121
122
/**
123
\brief Decrement layer reference count.
124
125
This method is the same as the C function OGR_L_Dereference().
126
127
@return the reference count after decrementing.
128
*/
129
130
int OGRLayer::Dereference()
131
132
0
{
133
0
    return --m_nRefCount;
134
0
}
135
136
/************************************************************************/
137
/*                         OGR_L_Dereference()                          */
138
/************************************************************************/
139
140
int OGR_L_Dereference(OGRLayerH hLayer)
141
142
0
{
143
0
    VALIDATE_POINTER1(hLayer, "OGR_L_Dereference", 0);
144
145
0
    return OGRLayer::FromHandle(hLayer)->Dereference();
146
0
}
147
148
/************************************************************************/
149
/*                            GetRefCount()                             */
150
/************************************************************************/
151
152
/**
153
\brief Fetch reference count.
154
155
This method is the same as the C function OGR_L_GetRefCount().
156
157
@return the current reference count for the layer object itself.
158
*/
159
160
int OGRLayer::GetRefCount() const
161
162
0
{
163
0
    return m_nRefCount;
164
0
}
165
166
/************************************************************************/
167
/*                         OGR_L_GetRefCount()                          */
168
/************************************************************************/
169
170
int OGR_L_GetRefCount(OGRLayerH hLayer)
171
172
0
{
173
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetRefCount", 0);
174
175
0
    return OGRLayer::FromHandle(hLayer)->GetRefCount();
176
0
}
177
178
/************************************************************************/
179
/*                         GetFeatureCount()                            */
180
/************************************************************************/
181
182
/**
183
 \brief Fetch the feature count in this layer.
184
185
 Returns the number of features in the layer.  For dynamic databases the
186
 count may not be exact.  If bForce is FALSE, and it would be expensive
187
 to establish the feature count a value of -1 may be returned indicating
188
 that the count isn't know.  If bForce is TRUE some implementations will
189
 actually scan the entire layer once to count objects.
190
191
 The returned count takes the spatial filter into account.
192
193
 Note that some implementations of this method may alter the read cursor
194
 of the layer.
195
196
 This method is the same as the C function OGR_L_GetFeatureCount().
197
198
199
 @param bForce Flag indicating whether the count should be computed even
200
 if it is expensive.
201
202
 @return feature count, -1 if count not known.
203
*/
204
205
GIntBig OGRLayer::GetFeatureCount(int bForce)
206
207
0
{
208
0
    if (!bForce)
209
0
        return -1;
210
211
0
    GIntBig nFeatureCount = 0;
212
0
    for (auto &&poFeature : *this)
213
0
    {
214
0
        CPL_IGNORE_RET_VAL(poFeature.get());
215
0
        nFeatureCount++;
216
0
    }
217
0
    ResetReading();
218
219
0
    return nFeatureCount;
220
0
}
221
222
/************************************************************************/
223
/*                      OGR_L_GetFeatureCount()                         */
224
/************************************************************************/
225
226
/**
227
 \brief Fetch the feature count in this layer.
228
229
 Returns the number of features in the layer.  For dynamic databases the
230
 count may not be exact.  If bForce is FALSE, and it would be expensive
231
 to establish the feature count a value of -1 may be returned indicating
232
 that the count isn't know.  If bForce is TRUE some implementations will
233
 actually scan the entire layer once to count objects.
234
235
 The returned count takes the spatial filter into account.
236
237
 Note that some implementations of this method may alter the read cursor
238
 of the layer.
239
240
 This function is the same as the CPP OGRLayer::GetFeatureCount().
241
242
243
 @param hLayer handle to the layer that owned the features.
244
 @param bForce Flag indicating whether the count should be computed even
245
 if it is expensive.
246
247
 @return feature count, -1 if count not known.
248
*/
249
250
GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
251
252
0
{
253
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
254
255
0
#ifdef OGRAPISPY_ENABLED
256
0
    if (bOGRAPISpyEnabled)
257
0
        OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
258
0
#endif
259
260
0
    return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
261
0
}
262
263
/************************************************************************/
264
/*                            GetExtent()                               */
265
/************************************************************************/
266
267
/**
268
 \brief Fetch the extent of this layer.
269
270
 Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
271
 and it would be expensive to establish the extent then OGRERR_FAILURE
272
 will be returned indicating that the extent isn't know.  If bForce is
273
 TRUE then some implementations will actually scan the entire layer once
274
 to compute the MBR of all the features in the layer.
275
276
 Depending on the drivers, the returned extent may or may not take the
277
 spatial filter into account.  So it is safer to call GetExtent() without
278
 setting a spatial filter.
279
280
 Layers without any geometry may return OGRERR_FAILURE just indicating that
281
 no meaningful extents could be collected.
282
283
 Note that some implementations of this method may alter the read cursor
284
 of the layer.
285
286
 This method is the same as the C function OGR_L_GetExtent().
287
288
 @param psExtent the structure in which the extent value will be returned.
289
 @param bForce Flag indicating whether the extent should be computed even
290
 if it is expensive.
291
292
 @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
293
*/
294
295
OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, bool bForce)
296
0
{
297
0
    return GetExtent(0, psExtent, bForce);
298
0
}
299
300
/**
301
 \brief Fetch the extent of this layer, on the specified geometry field.
302
303
 Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
304
 and it would be expensive to establish the extent then OGRERR_FAILURE
305
 will be returned indicating that the extent isn't know.  If bForce is
306
 TRUE then some implementations will actually scan the entire layer once
307
 to compute the MBR of all the features in the layer.
308
309
 Depending on the drivers, the returned extent may or may not take the
310
 spatial filter into account.  So it is safer to call GetExtent() without
311
 setting a spatial filter.
312
313
 Layers without any geometry may return OGRERR_FAILURE just indicating that
314
 no meaningful extents could be collected.
315
316
 Note that some implementations of this method may alter the read cursor
317
 of the layer.
318
319
 This method is the same as the C function OGR_L_GetExtentEx().
320
321
 @param iGeomField the index of the geometry field on which to compute the extent.
322
 @param psExtent the structure in which the extent value will be returned.
323
 @param bForce Flag indicating whether the extent should be computed even
324
 if it is expensive.
325
326
 @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
327
328
*/
329
330
OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
331
0
{
332
0
    psExtent->MinX = 0.0;
333
0
    psExtent->MaxX = 0.0;
334
0
    psExtent->MinY = 0.0;
335
0
    psExtent->MaxY = 0.0;
336
337
    /* -------------------------------------------------------------------- */
338
    /*      If this layer has a none geometry type, then we can             */
339
    /*      reasonably assume there are not extents available.              */
340
    /* -------------------------------------------------------------------- */
341
0
    if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
342
0
        GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
343
0
    {
344
0
        if (iGeomField != 0)
345
0
        {
346
0
            CPLError(CE_Failure, CPLE_AppDefined,
347
0
                     "Invalid geometry field index : %d", iGeomField);
348
0
        }
349
0
        return OGRERR_FAILURE;
350
0
    }
351
352
0
    return IGetExtent(iGeomField, psExtent, bForce);
353
0
}
354
355
/************************************************************************/
356
/*                            IGetExtent()                              */
357
/************************************************************************/
358
359
/**
360
 \brief Fetch the extent of this layer, on the specified geometry field.
361
362
 Virtual method implemented by drivers since 3.11. In previous versions,
363
 GetExtent() itself was the virtual method.
364
365
 Driver implementations, when wanting to call the base method, must take
366
 care of calling OGRLayer::IGetExtent() (and note the public method without
367
 the leading I).
368
369
 @param iGeomField 0-based index of the geometry field to consider.
370
 @param psExtent the computed extent of the layer.
371
 @param bForce if TRUE, the extent will be computed even if all the
372
        layer features have to be fetched.
373
 @return OGRERR_NONE on success or an error code in case of failure.
374
 @since GDAL 3.11
375
*/
376
377
OGRErr OGRLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
378
379
0
{
380
    /* -------------------------------------------------------------------- */
381
    /*      If not forced, we should avoid having to scan all the           */
382
    /*      features and just return a failure.                             */
383
    /* -------------------------------------------------------------------- */
384
0
    if (!bForce)
385
0
        return OGRERR_FAILURE;
386
387
    /* -------------------------------------------------------------------- */
388
    /*      OK, we hate to do this, but go ahead and read through all       */
389
    /*      the features to collect geometries and build extents.           */
390
    /* -------------------------------------------------------------------- */
391
0
    OGREnvelope oEnv;
392
0
    bool bExtentSet = false;
393
394
0
    for (auto &&poFeature : *this)
395
0
    {
396
0
        OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
397
0
        if (poGeom == nullptr || poGeom->IsEmpty())
398
0
        {
399
            /* Do nothing */
400
0
        }
401
0
        else if (!bExtentSet)
402
0
        {
403
0
            poGeom->getEnvelope(psExtent);
404
0
            if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
405
0
                  std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
406
0
            {
407
0
                bExtentSet = true;
408
0
            }
409
0
        }
410
0
        else
411
0
        {
412
0
            poGeom->getEnvelope(&oEnv);
413
0
            if (oEnv.MinX < psExtent->MinX)
414
0
                psExtent->MinX = oEnv.MinX;
415
0
            if (oEnv.MinY < psExtent->MinY)
416
0
                psExtent->MinY = oEnv.MinY;
417
0
            if (oEnv.MaxX > psExtent->MaxX)
418
0
                psExtent->MaxX = oEnv.MaxX;
419
0
            if (oEnv.MaxY > psExtent->MaxY)
420
0
                psExtent->MaxY = oEnv.MaxY;
421
0
        }
422
0
    }
423
0
    ResetReading();
424
425
0
    return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
426
0
}
427
428
/************************************************************************/
429
/*                          OGR_L_GetExtent()                           */
430
/************************************************************************/
431
432
/**
433
 \brief Fetch the extent of this layer.
434
435
 Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
436
 and it would be expensive to establish the extent then OGRERR_FAILURE
437
 will be returned indicating that the extent isn't know.  If bForce is
438
 TRUE then some implementations will actually scan the entire layer once
439
 to compute the MBR of all the features in the layer.
440
441
 Depending on the drivers, the returned extent may or may not take the
442
 spatial filter into account.  So it is safer to call OGR_L_GetExtent() without
443
 setting a spatial filter.
444
445
 Layers without any geometry may return OGRERR_FAILURE just indicating that
446
 no meaningful extents could be collected.
447
448
 Note that some implementations of this method may alter the read cursor
449
 of the layer.
450
451
 This function is the same as the C++ method OGRLayer::GetExtent().
452
453
 @param hLayer handle to the layer from which to get extent.
454
 @param psExtent the structure in which the extent value will be returned.
455
 @param bForce Flag indicating whether the extent should be computed even
456
 if it is expensive.
457
458
 @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
459
460
*/
461
462
OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
463
464
0
{
465
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
466
467
0
#ifdef OGRAPISPY_ENABLED
468
0
    if (bOGRAPISpyEnabled)
469
0
        OGRAPISpy_L_GetExtent(hLayer, bForce);
470
0
#endif
471
472
0
    return OGRLayer::FromHandle(hLayer)->GetExtent(0, psExtent,
473
0
                                                   bForce != FALSE);
474
0
}
475
476
/************************************************************************/
477
/*                         OGR_L_GetExtentEx()                          */
478
/************************************************************************/
479
480
/**
481
 \brief Fetch the extent of this layer, on the specified geometry field.
482
483
 Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
484
 and it would be expensive to establish the extent then OGRERR_FAILURE
485
 will be returned indicating that the extent isn't know.  If bForce is
486
 TRUE then some implementations will actually scan the entire layer once
487
 to compute the MBR of all the features in the layer.
488
489
 Depending on the drivers, the returned extent may or may not take the
490
 spatial filter into account.  So it is safer to call OGR_L_GetExtent() without
491
 setting a spatial filter.
492
493
 Layers without any geometry may return OGRERR_FAILURE just indicating that
494
 no meaningful extents could be collected.
495
496
 Note that some implementations of this method may alter the read cursor
497
 of the layer.
498
499
 This function is the same as the C++ method OGRLayer::GetExtent().
500
501
 @param hLayer handle to the layer from which to get extent.
502
 @param iGeomField the index of the geometry field on which to compute the extent.
503
 @param psExtent the structure in which the extent value will be returned.
504
 @param bForce Flag indicating whether the extent should be computed even
505
 if it is expensive.
506
507
 @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
508
509
*/
510
OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
511
                         OGREnvelope *psExtent, int bForce)
512
513
0
{
514
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
515
516
0
#ifdef OGRAPISPY_ENABLED
517
0
    if (bOGRAPISpyEnabled)
518
0
        OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
519
0
#endif
520
521
0
    return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
522
0
                                                   bForce != FALSE);
523
0
}
524
525
/************************************************************************/
526
/*                            GetExtent3D()                             */
527
/************************************************************************/
528
529
/**
530
 \brief Fetch the 3D extent of this layer, on the specified geometry field.
531
532
 Returns the 3D extent (MBR) of the data in the layer.  If bForce is FALSE,
533
 and it would be expensive to establish the extent then OGRERR_FAILURE
534
 will be returned indicating that the extent isn't know.  If bForce is
535
 TRUE then some implementations will actually scan the entire layer once
536
 to compute the MBR of all the features in the layer.
537
538
 (Contrarty to GetExtent() 2D), the returned extent will always take into
539
 account the attribute and spatial filters that may be installed.
540
541
 Layers without any geometry may return OGRERR_FAILURE just indicating that
542
 no meaningful extents could be collected.
543
544
 For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
545
 fields will be respectively set to +Infinity and -Infinity.
546
547
 Note that some implementations of this method may alter the read cursor
548
 of the layer.
549
550
 This function is the same as the C function OGR_L_GetExtent3D().
551
552
 @param iGeomField 0-based index of the geometry field to consider.
553
 @param psExtent3D the computed 3D extent of the layer.
554
 @param bForce if TRUE, the extent will be computed even if all the
555
        layer features have to be fetched.
556
 @return OGRERR_NONE on success or an error code in case of failure.
557
 @since GDAL 3.9
558
*/
559
560
OGRErr OGRLayer::GetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
561
                             bool bForce)
562
563
0
{
564
0
    psExtent3D->MinX = 0.0;
565
0
    psExtent3D->MaxX = 0.0;
566
0
    psExtent3D->MinY = 0.0;
567
0
    psExtent3D->MaxY = 0.0;
568
0
    psExtent3D->MinZ = std::numeric_limits<double>::infinity();
569
0
    psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
570
571
    /* -------------------------------------------------------------------- */
572
    /*      If this layer has a none geometry type, then we can             */
573
    /*      reasonably assume there are not extents available.              */
574
    /* -------------------------------------------------------------------- */
575
0
    if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
576
0
        GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
577
0
    {
578
0
        if (iGeomField != 0)
579
0
        {
580
0
            CPLError(CE_Failure, CPLE_AppDefined,
581
0
                     "Invalid geometry field index : %d", iGeomField);
582
0
        }
583
0
        return OGRERR_FAILURE;
584
0
    }
585
586
0
    return IGetExtent3D(iGeomField, psExtent3D, bForce);
587
0
}
588
589
/************************************************************************/
590
/*                           IGetExtent3D()                             */
591
/************************************************************************/
592
593
/**
594
 \brief Fetch the 3D extent of this layer, on the specified geometry field.
595
596
 See GetExtent3D() documentation.
597
598
 Virtual method implemented by drivers since 3.11. In previous versions,
599
 GetExtent3D() itself was the virtual method.
600
601
 Driver implementations, when wanting to call the base method, must take
602
 care of calling OGRLayer::IGetExtent3D() (and note the public method without
603
 the leading I).
604
605
 @param iGeomField 0-based index of the geometry field to consider.
606
 @param psExtent3D the computed 3D extent of the layer.
607
 @param bForce if TRUE, the extent will be computed even if all the
608
        layer features have to be fetched.
609
 @return OGRERR_NONE on success or an error code in case of failure.
610
 @since GDAL 3.11
611
*/
612
613
OGRErr OGRLayer::IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
614
                              bool bForce)
615
616
0
{
617
    /* -------------------------------------------------------------------- */
618
    /*      If not forced, we should avoid having to scan all the           */
619
    /*      features and just return a failure.                             */
620
    /* -------------------------------------------------------------------- */
621
0
    if (!bForce)
622
0
        return OGRERR_FAILURE;
623
624
    /* -------------------------------------------------------------------- */
625
    /*      OK, we hate to do this, but go ahead and read through all       */
626
    /*      the features to collect geometries and build extents.           */
627
    /* -------------------------------------------------------------------- */
628
0
    OGREnvelope3D oEnv;
629
0
    bool bExtentSet = false;
630
631
0
    for (auto &&poFeature : *this)
632
0
    {
633
0
        OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
634
0
        if (poGeom == nullptr || poGeom->IsEmpty())
635
0
        {
636
            /* Do nothing */
637
0
        }
638
0
        else if (!bExtentSet)
639
0
        {
640
0
            poGeom->getEnvelope(psExtent3D);
641
            // This is required because getEnvelope initializes Z to 0 for 2D geometries
642
0
            if (!poGeom->Is3D())
643
0
            {
644
0
                psExtent3D->MinZ = std::numeric_limits<double>::infinity();
645
0
                psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
646
0
            }
647
0
            bExtentSet = true;
648
0
        }
649
0
        else
650
0
        {
651
0
            poGeom->getEnvelope(&oEnv);
652
            // This is required because getEnvelope initializes Z to 0 for 2D geometries
653
0
            if (!poGeom->Is3D())
654
0
            {
655
0
                oEnv.MinZ = std::numeric_limits<double>::infinity();
656
0
                oEnv.MaxZ = -std::numeric_limits<double>::infinity();
657
0
            }
658
            // Merge handles infinity correctly
659
0
            psExtent3D->Merge(oEnv);
660
0
        }
661
0
    }
662
0
    ResetReading();
663
664
0
    return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
665
0
}
666
667
/************************************************************************/
668
/*                          OGR_L_GetExtent3D()                         */
669
/************************************************************************/
670
671
/**
672
 \brief Fetch the 3D extent of this layer, on the specified geometry field.
673
674
 Returns the 3D extent (MBR) of the data in the layer.  If bForce is FALSE,
675
 and it would be expensive to establish the extent then OGRERR_FAILURE
676
 will be returned indicating that the extent isn't know.  If bForce is
677
 TRUE then some implementations will actually scan the entire layer once
678
 to compute the MBR of all the features in the layer.
679
680
 (Contrarty to GetExtent() 2D), the returned extent will always take into
681
 account the attribute and spatial filters that may be installed.
682
683
 Layers without any geometry may return OGRERR_FAILURE just indicating that
684
 no meaningful extents could be collected.
685
686
 For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
687
 fields will be respectively set to +Infinity and -Infinity.
688
689
 Note that some implementations of this method may alter the read cursor
690
 of the layer.
691
692
 This function is the same as the C++ method OGRLayer::GetExtent3D().
693
694
 @param hLayer the layer to consider.
695
 @param iGeomField 0-based index of the geometry field to consider.
696
 @param psExtent3D the computed 3D extent of the layer.
697
 @param bForce if TRUE, the extent will be computed even if all the
698
        layer features have to be fetched.
699
 @return OGRERR_NONE on success or an error code in case of failure.
700
 @since GDAL 3.9
701
*/
702
703
OGRErr OGR_L_GetExtent3D(OGRLayerH hLayer, int iGeomField,
704
                         OGREnvelope3D *psExtent3D, int bForce)
705
706
0
{
707
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent3D", OGRERR_INVALID_HANDLE);
708
709
0
#ifdef OGRAPISPY_ENABLED
710
0
    if (bOGRAPISpyEnabled)
711
0
        OGRAPISpy_L_GetExtent3D(hLayer, iGeomField, bForce);
712
0
#endif
713
714
0
    return OGRLayer::FromHandle(hLayer)->GetExtent3D(iGeomField, psExtent3D,
715
0
                                                     bForce != FALSE);
716
0
}
717
718
/************************************************************************/
719
/*                         SetAttributeFilter()                         */
720
/************************************************************************/
721
722
/**
723
 \brief Set a new attribute query.
724
725
 This method sets the attribute query string to be used when
726
 fetching features via the GetNextFeature() method.  Only features for which
727
 the query evaluates as true will be returned.
728
729
 The query string should be in the format of an SQL WHERE clause.  For
730
 instance "population > 1000000 and population < 5000000" where population
731
 is an attribute in the layer. The query format is normally a SQL WHERE clause
732
 as described in the
733
 <a href="https://gdal.org/user/ogr_sql_dialect.html#where">"WHERE"</a> section
734
 of the OGR SQL dialect documentation.
735
 In some cases (RDBMS backed drivers, SQLite, GeoPackage) the native
736
 capabilities of the database may be used to to interpret the WHERE clause, in
737
 which case the capabilities will be broader than those of OGR SQL.
738
739
 Note that installing a query string will generally result in resetting
740
 the current reading position (ala ResetReading()).
741
742
 This method is the same as the C function OGR_L_SetAttributeFilter().
743
744
 @param pszQuery query in restricted SQL WHERE format, or NULL to clear the
745
 current query.
746
747
 @return OGRERR_NONE if successfully installed, or an error code if the
748
 query expression is in error, or some other failure occurs.
749
 */
750
751
OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
752
753
0
{
754
0
    CPLFree(m_pszAttrQueryString);
755
0
    m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
756
757
    /* -------------------------------------------------------------------- */
758
    /*      Are we just clearing any existing query?                        */
759
    /* -------------------------------------------------------------------- */
760
0
    if (pszQuery == nullptr || strlen(pszQuery) == 0)
761
0
    {
762
0
        if (m_poAttrQuery)
763
0
        {
764
0
            delete m_poAttrQuery;
765
0
            m_poAttrQuery = nullptr;
766
0
            ResetReading();
767
0
        }
768
0
        return OGRERR_NONE;
769
0
    }
770
771
    /* -------------------------------------------------------------------- */
772
    /*      Or are we installing a new query?                               */
773
    /* -------------------------------------------------------------------- */
774
0
    OGRErr eErr;
775
776
0
    if (!m_poAttrQuery)
777
0
        m_poAttrQuery = new OGRFeatureQuery();
778
779
0
    eErr = m_poAttrQuery->Compile(this, pszQuery);
780
0
    if (eErr != OGRERR_NONE)
781
0
    {
782
0
        delete m_poAttrQuery;
783
0
        m_poAttrQuery = nullptr;
784
0
    }
785
786
0
    ResetReading();
787
788
0
    return eErr;
789
0
}
790
791
/************************************************************************/
792
/*                        ContainGeomSpecialField()                     */
793
/************************************************************************/
794
795
static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
796
0
{
797
0
    if (expr->eNodeType == SNT_COLUMN)
798
0
    {
799
0
        if (expr->table_index == 0 && expr->field_index != -1)
800
0
        {
801
0
            int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
802
0
            return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
803
0
                   nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
804
0
                   nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
805
0
        }
806
0
    }
807
0
    else if (expr->eNodeType == SNT_OPERATION)
808
0
    {
809
0
        for (int i = 0; i < expr->nSubExprCount; i++)
810
0
        {
811
0
            if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
812
0
                return TRUE;
813
0
        }
814
0
    }
815
0
    return FALSE;
816
0
}
817
818
/************************************************************************/
819
/*                AttributeFilterEvaluationNeedsGeometry()              */
820
/************************************************************************/
821
822
//! @cond Doxygen_Suppress
823
int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
824
0
{
825
0
    if (!m_poAttrQuery)
826
0
        return FALSE;
827
828
0
    swq_expr_node *expr =
829
0
        static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
830
0
    int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
831
832
0
    return ContainGeomSpecialField(expr, nLayerFieldCount);
833
0
}
834
835
//! @endcond
836
837
/************************************************************************/
838
/*                      OGR_L_SetAttributeFilter()                      */
839
/************************************************************************/
840
841
/**
842
 \brief Set a new attribute query.
843
844
 This function sets the attribute query string to be used when
845
 fetching features via the OGR_L_GetNextFeature() function.
846
 Only features for which the query evaluates as true will be returned.
847
848
 The query string should be in the format of an SQL WHERE clause.  For
849
 instance "population > 1000000 and population < 5000000" where population
850
 is an attribute in the layer. The query format is normally a SQL WHERE clause
851
 as described in the
852
 <a href="https://gdal.org/user/ogr_sql_dialect.html#where">"WHERE"</a> section
853
 of the OGR SQL dialect documentation.
854
 In some cases (RDBMS backed drivers, SQLite, GeoPackage) the native
855
 capabilities of the database may be used to to interpret the WHERE clause, in
856
 which case the capabilities will be broader than those of OGR SQL.
857
858
 Note that installing a query string will generally result in resetting
859
 the current reading position (ala OGR_L_ResetReading()).
860
861
 This function is the same as the C++ method OGRLayer::SetAttributeFilter().
862
863
 @param hLayer handle to the layer on which attribute query will be executed.
864
 @param pszQuery query in restricted SQL WHERE format, or NULL to clear the
865
 current query.
866
867
 @return OGRERR_NONE if successfully installed, or an error code if the
868
 query expression is in error, or some other failure occurs.
869
 */
870
871
OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
872
873
0
{
874
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
875
0
                      OGRERR_INVALID_HANDLE);
876
877
0
#ifdef OGRAPISPY_ENABLED
878
0
    if (bOGRAPISpyEnabled)
879
0
        OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
880
0
#endif
881
882
0
    return OGRLayer::FromHandle(hLayer)->SetAttributeFilter(pszQuery);
883
0
}
884
885
/************************************************************************/
886
/*                             GetFeature()                             */
887
/************************************************************************/
888
889
/**
890
 \brief Fetch a feature by its identifier.
891
892
 This function will attempt to read the identified feature.  The nFID
893
 value cannot be OGRNullFID.  Success or failure of this operation is
894
 unaffected by the spatial or attribute filters (and specialized implementations
895
 in drivers should make sure that they do not take into account spatial or
896
 attribute filters).
897
898
 If this method returns a non-NULL feature, it is guaranteed that its
899
 feature id (OGRFeature::GetFID()) will be the same as nFID.
900
901
 Use OGRLayer::TestCapability(OLCRandomRead) to establish if this layer
902
 supports efficient random access reading via GetFeature(); however, the
903
 call should always work if the feature exists as a fallback implementation
904
 just scans all the features in the layer looking for the desired feature.
905
906
 Sequential reads (with GetNextFeature()) are generally considered interrupted
907
 by a GetFeature() call.
908
909
 The returned feature should be free with OGRFeature::DestroyFeature().
910
911
 This method is the same as the C function OGR_L_GetFeature().
912
913
 @param nFID the feature id of the feature to read.
914
915
 @return a feature now owned by the caller, or NULL on failure.
916
*/
917
918
OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
919
920
0
{
921
    /* Save old attribute and spatial filters */
922
0
    char *pszOldFilter =
923
0
        m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
924
0
    OGRGeometry *poOldFilterGeom =
925
0
        (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
926
0
    int iOldGeomFieldFilter = m_iGeomFieldFilter;
927
    /* Unset filters */
928
0
    SetAttributeFilter(nullptr);
929
0
    SetSpatialFilter(0, nullptr);
930
931
0
    OGRFeatureUniquePtr poFeature;
932
0
    for (auto &&poFeatureIter : *this)
933
0
    {
934
0
        if (poFeatureIter->GetFID() == nFID)
935
0
        {
936
0
            poFeature.swap(poFeatureIter);
937
0
            break;
938
0
        }
939
0
    }
940
941
    /* Restore filters */
942
0
    SetAttributeFilter(pszOldFilter);
943
0
    CPLFree(pszOldFilter);
944
0
    SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
945
0
    delete poOldFilterGeom;
946
947
0
    return poFeature.release();
948
0
}
949
950
/************************************************************************/
951
/*                          OGR_L_GetFeature()                          */
952
/************************************************************************/
953
954
/**
955
 \brief Fetch a feature by its identifier.
956
957
 This function will attempt to read the identified feature.  The nFID
958
 value cannot be OGRNullFID.  Success or failure of this operation is
959
 unaffected by the spatial or attribute filters (and specialized implementations
960
 in drivers should make sure that they do not take into account spatial or
961
 attribute filters).
962
963
 If this function returns a non-NULL feature, it is guaranteed that its
964
 feature id (OGR_F_GetFID()) will be the same as nFID.
965
966
 Use OGR_L_TestCapability(OLCRandomRead) to establish if this layer
967
 supports efficient random access reading via OGR_L_GetFeature(); however,
968
 the call should always work if the feature exists as a fallback
969
 implementation just scans all the features in the layer looking for the
970
 desired feature.
971
972
 Sequential reads (with OGR_L_GetNextFeature()) are generally considered interrupted by a
973
 OGR_L_GetFeature() call.
974
975
 The returned feature should be free with OGR_F_Destroy().
976
977
 This function is the same as the C++ method OGRLayer::GetFeature( ).
978
979
 @param hLayer handle to the layer that owned the feature.
980
 @param nFeatureId the feature id of the feature to read.
981
982
 @return a handle to a feature now owned by the caller, or NULL on failure.
983
*/
984
985
OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
986
987
0
{
988
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
989
990
0
#ifdef OGRAPISPY_ENABLED
991
0
    if (bOGRAPISpyEnabled)
992
0
        OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
993
0
#endif
994
995
0
    return OGRFeature::ToHandle(
996
0
        OGRLayer::FromHandle(hLayer)->GetFeature(nFeatureId));
997
0
}
998
999
/************************************************************************/
1000
/*                           SetNextByIndex()                           */
1001
/************************************************************************/
1002
1003
/**
1004
 \brief Move read cursor to the nIndex'th feature in the current resultset.
1005
1006
 This method allows positioning of a layer such that the GetNextFeature()
1007
 call will read the requested feature, where nIndex is an absolute index
1008
 into the current result set.   So, setting it to 3 would mean the next
1009
 feature read with GetNextFeature() would have been the 4th feature to have
1010
 been read if sequential reading took place from the beginning of the layer,
1011
 including accounting for spatial and attribute filters.
1012
1013
 Only in rare circumstances is SetNextByIndex() efficiently implemented.
1014
 In all other cases the default implementation which calls ResetReading()
1015
 and then calls GetNextFeature() nIndex times is used.  To determine if
1016
 fast seeking is available on the current layer use the TestCapability()
1017
 method with a value of OLCFastSetNextByIndex.
1018
1019
 Starting with GDAL 3.12, when implementations can detect that nIndex is
1020
 invalid (at the minimum all should detect negative indices), they should
1021
 return OGRERR_NON_EXISTING_FEATURE, and following calls to GetNextFeature()
1022
 should return nullptr, until ResetReading() or a valid call to
1023
 SetNextByIndex() is done.
1024
1025
 This method is the same as the C function OGR_L_SetNextByIndex().
1026
1027
 @param nIndex the index indicating how many steps into the result set
1028
 to seek.
1029
1030
 @return OGRERR_NONE on success or an error code.
1031
*/
1032
1033
OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
1034
1035
0
{
1036
0
    if (nIndex < 0)
1037
0
        nIndex = GINTBIG_MAX;
1038
1039
0
    ResetReading();
1040
1041
0
    while (nIndex-- > 0)
1042
0
    {
1043
0
        auto poFeature = std::unique_ptr<OGRFeature>(GetNextFeature());
1044
0
        if (poFeature == nullptr)
1045
0
            return OGRERR_NON_EXISTING_FEATURE;
1046
0
    }
1047
1048
0
    return OGRERR_NONE;
1049
0
}
1050
1051
/************************************************************************/
1052
/*                        OGR_L_SetNextByIndex()                        */
1053
/************************************************************************/
1054
1055
/**
1056
 \brief Move read cursor to the nIndex'th feature in the current resultset.
1057
1058
 This method allows positioning of a layer such that the GetNextFeature()
1059
 call will read the requested feature, where nIndex is an absolute index
1060
 into the current result set.   So, setting it to 3 would mean the next
1061
 feature read with GetNextFeature() would have been the 4th feature to have
1062
 been read if sequential reading took place from the beginning of the layer,
1063
 including accounting for spatial and attribute filters.
1064
1065
 Only in rare circumstances is SetNextByIndex() efficiently implemented.
1066
 In all other cases the default implementation which calls ResetReading()
1067
 and then calls GetNextFeature() nIndex times is used.  To determine if
1068
 fast seeking is available on the current layer use the TestCapability()
1069
 method with a value of OLCFastSetNextByIndex.
1070
1071
 Starting with GDAL 3.12, when implementations can detect that nIndex is
1072
 invalid (at the minimum all should detect negative indices), they should
1073
 return OGRERR_NON_EXISTING_FEATURE, and following calls to GetNextFeature()
1074
 should return nullptr, until ResetReading() or a valid call to
1075
 SetNextByIndex() is done.
1076
1077
 This method is the same as the C++ method OGRLayer::SetNextByIndex()
1078
1079
 @param hLayer handle to the layer
1080
 @param nIndex the index indicating how many steps into the result set
1081
 to seek.
1082
1083
 @return OGRERR_NONE on success or an error code.
1084
*/
1085
1086
OGRErr OGR_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
1087
1088
0
{
1089
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE);
1090
1091
0
#ifdef OGRAPISPY_ENABLED
1092
0
    if (bOGRAPISpyEnabled)
1093
0
        OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
1094
0
#endif
1095
1096
0
    return OGRLayer::FromHandle(hLayer)->SetNextByIndex(nIndex);
1097
0
}
1098
1099
/************************************************************************/
1100
/*                       OGRLayer::GetNextFeature()                     */
1101
/************************************************************************/
1102
1103
/**
1104
 \fn OGRFeature *OGRLayer::GetNextFeature();
1105
1106
 \brief Fetch the next available feature from this layer.
1107
1108
 The returned feature becomes the responsibility of the caller to
1109
 delete with OGRFeature::DestroyFeature(). It is critical that all
1110
 features associated with an OGRLayer (more specifically an
1111
 OGRFeatureDefn) be deleted before that layer/datasource is deleted.
1112
1113
 Only features matching the current spatial filter (set with
1114
 SetSpatialFilter()) will be returned.
1115
1116
 This method implements sequential access to the features of a layer.  The
1117
 ResetReading() method can be used to start at the beginning again.
1118
1119
 Starting with GDAL 3.6, it is possible to retrieve them by batches, with a
1120
 column-oriented memory layout, using the GetArrowStream() method.
1121
1122
 Features returned by GetNextFeature() may or may not be affected by
1123
 concurrent modifications depending on drivers. A guaranteed way of seeing
1124
 modifications in effect is to call ResetReading() on layers where
1125
 GetNextFeature() has been called, before reading again.  Structural changes
1126
 in layers (field addition, deletion, ...) when a read is in progress may or
1127
 may not be possible depending on drivers.  If a transaction is
1128
 committed/aborted, the current sequential reading may or may not be valid
1129
 after that operation and a call to ResetReading() might be needed.
1130
1131
 This method is the same as the C function OGR_L_GetNextFeature().
1132
1133
 @return a feature, or NULL if no more features are available.
1134
1135
*/
1136
1137
/************************************************************************/
1138
/*                        OGR_L_GetNextFeature()                        */
1139
/************************************************************************/
1140
1141
/**
1142
 \brief Fetch the next available feature from this layer.
1143
1144
 The returned feature becomes the responsibility of the caller to
1145
 delete with OGR_F_Destroy().  It is critical that all features
1146
 associated with an OGRLayer (more specifically an OGRFeatureDefn) be
1147
 deleted before that layer/datasource is deleted.
1148
1149
 Only features matching the current spatial filter (set with
1150
 SetSpatialFilter()) will be returned.
1151
1152
 This function implements sequential access to the features of a layer.
1153
 The OGR_L_ResetReading() function can be used to start at the beginning
1154
 again.
1155
1156
 Starting with GDAL 3.6, it is possible to retrieve them by batches, with a
1157
 column-oriented memory layout, using the OGR_L_GetArrowStream() function.
1158
1159
 Features returned by OGR_GetNextFeature() may or may not be affected by
1160
 concurrent modifications depending on drivers. A guaranteed way of seeing
1161
 modifications in effect is to call OGR_L_ResetReading() on layers where
1162
 OGR_GetNextFeature() has been called, before reading again.  Structural
1163
 changes in layers (field addition, deletion, ...) when a read is in progress
1164
 may or may not be possible depending on drivers.  If a transaction is
1165
 committed/aborted, the current sequential reading may or may not be valid
1166
 after that operation and a call to OGR_L_ResetReading() might be needed.
1167
1168
 This function is the same as the C++ method OGRLayer::GetNextFeature().
1169
1170
 @param hLayer handle to the layer from which feature are read.
1171
 @return a handle to a feature, or NULL if no more features are available.
1172
1173
*/
1174
1175
OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
1176
1177
0
{
1178
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
1179
1180
0
#ifdef OGRAPISPY_ENABLED
1181
0
    if (bOGRAPISpyEnabled)
1182
0
        OGRAPISpy_L_GetNextFeature(hLayer);
1183
0
#endif
1184
1185
0
    return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
1186
0
}
1187
1188
/************************************************************************/
1189
/*                       ConvertGeomsIfNecessary()                      */
1190
/************************************************************************/
1191
1192
void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
1193
0
{
1194
0
    if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
1195
0
    {
1196
        // One time initialization
1197
0
        m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
1198
0
        m_poPrivate->m_bSupportsCurve =
1199
0
            CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
1200
0
        m_poPrivate->m_bSupportsM =
1201
0
            CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
1202
0
        if (CPLTestBool(
1203
0
                CPLGetConfigOption("OGR_APPLY_GEOM_SET_PRECISION", "FALSE")))
1204
0
        {
1205
0
            const auto poFeatureDefn = GetLayerDefn();
1206
0
            const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
1207
0
            for (int i = 0; i < nGeomFieldCount; i++)
1208
0
            {
1209
0
                const double dfXYResolution = poFeatureDefn->GetGeomFieldDefn(i)
1210
0
                                                  ->GetCoordinatePrecision()
1211
0
                                                  .dfXYResolution;
1212
0
                if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
1213
0
                    OGRGeometryFactory::haveGEOS())
1214
0
                {
1215
0
                    m_poPrivate->m_bApplyGeomSetPrecision = true;
1216
0
                    break;
1217
0
                }
1218
0
            }
1219
0
        }
1220
0
    }
1221
1222
0
    if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
1223
0
        m_poPrivate->m_bApplyGeomSetPrecision)
1224
0
    {
1225
0
        const auto poFeatureDefn = GetLayerDefn();
1226
0
        const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
1227
0
        for (int i = 0; i < nGeomFieldCount; i++)
1228
0
        {
1229
0
            OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
1230
0
            if (poGeom)
1231
0
            {
1232
0
                if (!m_poPrivate->m_bSupportsM &&
1233
0
                    OGR_GT_HasM(poGeom->getGeometryType()))
1234
0
                {
1235
0
                    poGeom->setMeasured(FALSE);
1236
0
                }
1237
1238
0
                if (!m_poPrivate->m_bSupportsCurve &&
1239
0
                    OGR_GT_IsNonLinear(poGeom->getGeometryType()))
1240
0
                {
1241
0
                    OGRwkbGeometryType eTargetType =
1242
0
                        OGR_GT_GetLinear(poGeom->getGeometryType());
1243
0
                    poGeom = OGRGeometryFactory::forceTo(
1244
0
                        poFeature->StealGeometry(i), eTargetType);
1245
0
                    poFeature->SetGeomFieldDirectly(i, poGeom);
1246
0
                    poGeom = poFeature->GetGeomFieldRef(i);
1247
0
                }
1248
1249
0
                if (poGeom && m_poPrivate->m_bApplyGeomSetPrecision)
1250
0
                {
1251
0
                    const double dfXYResolution =
1252
0
                        poFeatureDefn->GetGeomFieldDefn(i)
1253
0
                            ->GetCoordinatePrecision()
1254
0
                            .dfXYResolution;
1255
0
                    if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
1256
0
                        !poGeom->hasCurveGeometry())
1257
0
                    {
1258
0
                        auto poNewGeom = poGeom->SetPrecision(dfXYResolution,
1259
0
                                                              /* nFlags = */ 0);
1260
0
                        if (poNewGeom)
1261
0
                        {
1262
0
                            poFeature->SetGeomFieldDirectly(i, poNewGeom);
1263
                            // If there was potential further processing...
1264
                            // poGeom = poFeature->GetGeomFieldRef(i);
1265
0
                        }
1266
0
                    }
1267
0
                }
1268
0
            }
1269
0
        }
1270
0
    }
1271
0
}
1272
1273
/************************************************************************/
1274
/*                             SetFeature()                             */
1275
/************************************************************************/
1276
1277
/**
1278
 \brief Rewrite/replace an existing feature.
1279
1280
 This method will write a feature to the layer, based on the feature id
1281
 within the OGRFeature.
1282
1283
 Use OGRLayer::TestCapability(OLCRandomWrite) to establish if this layer
1284
 supports random access writing via SetFeature().
1285
1286
 The way unset fields in the provided poFeature are processed is driver dependent:
1287
 <ul>
1288
 <li>
1289
 SQL based drivers which implement SetFeature() through SQL UPDATE will skip
1290
 unset fields, and thus the content of the existing feature will be preserved.
1291
 </li>
1292
 <li>
1293
 The shapefile driver will write a NULL value in the DBF file.
1294
 </li>
1295
 <li>
1296
 The GeoJSON driver will take into account unset fields to remove the corresponding
1297
 JSON member.
1298
 </li>
1299
 </ul>
1300
1301
 Drivers should specialize the ISetFeature() method.
1302
1303
 This method is the same as the C function OGR_L_SetFeature().
1304
1305
 To set a feature, but create it if it doesn't exist see OGRLayer::UpsertFeature().
1306
1307
 @param poFeature the feature to write.
1308
1309
 @return OGRERR_NONE if the operation works, otherwise an appropriate error
1310
 code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
1311
1312
 @see UpdateFeature(), CreateFeature(), UpsertFeature()
1313
*/
1314
1315
OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
1316
1317
0
{
1318
0
    ConvertGeomsIfNecessary(poFeature);
1319
0
    return ISetFeature(poFeature);
1320
0
}
1321
1322
/************************************************************************/
1323
/*                             ISetFeature()                            */
1324
/************************************************************************/
1325
1326
/**
1327
 \brief Rewrite/replace an existing feature.
1328
1329
 This method is implemented by drivers and not called directly. User code should
1330
 use SetFeature() instead.
1331
1332
 This method will write a feature to the layer, based on the feature id
1333
 within the OGRFeature.
1334
1335
 @param poFeature the feature to write.
1336
1337
 @return OGRERR_NONE if the operation works, otherwise an appropriate error
1338
 code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
1339
1340
 @see SetFeature()
1341
*/
1342
1343
OGRErr OGRLayer::ISetFeature(OGRFeature *poFeature)
1344
1345
0
{
1346
0
    (void)poFeature;
1347
0
    return OGRERR_UNSUPPORTED_OPERATION;
1348
0
}
1349
1350
/************************************************************************/
1351
/*                          OGR_L_SetFeature()                          */
1352
/************************************************************************/
1353
1354
/**
1355
 \brief Rewrite/replace an existing feature.
1356
1357
 This function will write a feature to the layer, based on the feature id
1358
 within the OGRFeature.
1359
1360
 Use OGR_L_TestCapability(OLCRandomWrite) to establish if this layer
1361
 supports random access writing via OGR_L_SetFeature().
1362
1363
 The way unset fields in the provided poFeature are processed is driver dependent:
1364
 <ul>
1365
 <li>
1366
 SQL based drivers which implement SetFeature() through SQL UPDATE will skip
1367
 unset fields, and thus the content of the existing feature will be preserved.
1368
 </li>
1369
 <li>
1370
 The shapefile driver will write a NULL value in the DBF file.
1371
 </li>
1372
 <li>
1373
 The GeoJSON driver will take into account unset fields to remove the corresponding
1374
 JSON member.
1375
 </li>
1376
 </ul>
1377
1378
 This function is the same as the C++ method OGRLayer::SetFeature().
1379
1380
 To set a feature, but create it if it doesn't exist see OGR_L_UpsertFeature().
1381
1382
 @param hLayer handle to the layer to write the feature.
1383
 @param hFeat the feature to write.
1384
1385
 @return OGRERR_NONE if the operation works, otherwise an appropriate error
1386
 code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
1387
1388
 @see OGR_L_UpdateFeature(), OGR_L_CreateFeature(), OGR_L_UpsertFeature()
1389
*/
1390
1391
OGRErr OGR_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1392
1393
0
{
1394
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
1395
0
    VALIDATE_POINTER1(hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
1396
1397
0
#ifdef OGRAPISPY_ENABLED
1398
0
    if (bOGRAPISpyEnabled)
1399
0
        OGRAPISpy_L_SetFeature(hLayer, hFeat);
1400
0
#endif
1401
1402
0
    return OGRLayer::FromHandle(hLayer)->SetFeature(
1403
0
        OGRFeature::FromHandle(hFeat));
1404
0
}
1405
1406
/************************************************************************/
1407
/*                           CreateFeature()                            */
1408
/************************************************************************/
1409
1410
/**
1411
 \brief Create and write a new feature within a layer.
1412
1413
 The passed feature is written to the layer as a new feature, rather than
1414
 overwriting an existing one.  If the feature has a feature id other than
1415
 OGRNullFID, then the native implementation may use that as the feature id
1416
 of the new feature, but not necessarily.  Upon successful return the
1417
 passed feature will have been updated with the new feature id.
1418
1419
 Drivers should specialize the ICreateFeature() method.
1420
1421
 This method is the same as the C function OGR_L_CreateFeature().
1422
1423
 To create a feature, but set it if it exists see OGRLayer::UpsertFeature().
1424
1425
 @param poFeature the feature to write to disk.
1426
1427
 @return OGRERR_NONE on success.
1428
1429
 @see SetFeature(), UpdateFeature(), UpsertFeature()
1430
*/
1431
1432
OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
1433
1434
0
{
1435
0
    ConvertGeomsIfNecessary(poFeature);
1436
0
    return ICreateFeature(poFeature);
1437
0
}
1438
1439
/************************************************************************/
1440
/*                           ICreateFeature()                            */
1441
/************************************************************************/
1442
1443
/**
1444
 \brief Create and write a new feature within a layer.
1445
1446
 This method is implemented by drivers  and not called directly. User code should
1447
 use CreateFeature() instead.
1448
1449
 The passed feature is written to the layer as a new feature, rather than
1450
 overwriting an existing one.  If the feature has a feature id other than
1451
 OGRNullFID, then the native implementation may use that as the feature id
1452
 of the new feature, but not necessarily.  Upon successful return the
1453
 passed feature will have been updated with the new feature id.
1454
1455
 @param poFeature the feature to write to disk.
1456
1457
 @return OGRERR_NONE on success.
1458
1459
 @see CreateFeature()
1460
*/
1461
1462
OGRErr OGRLayer::ICreateFeature(OGRFeature *poFeature)
1463
1464
0
{
1465
0
    (void)poFeature;
1466
0
    return OGRERR_UNSUPPORTED_OPERATION;
1467
0
}
1468
1469
/************************************************************************/
1470
/*                        OGR_L_CreateFeature()                         */
1471
/************************************************************************/
1472
1473
/**
1474
 \brief Create and write a new feature within a layer.
1475
1476
 The passed feature is written to the layer as a new feature, rather than
1477
 overwriting an existing one.  If the feature has a feature id other than
1478
 OGRNullFID, then the native implementation may use that as the feature id
1479
 of the new feature, but not necessarily.  Upon successful return the
1480
 passed feature will have been updated with the new feature id.
1481
1482
 This function is the same as the C++ method OGRLayer::CreateFeature().
1483
1484
 To create a feature, but set it if it exists see OGR_L_UpsertFeature().
1485
1486
 @param hLayer handle to the layer to write the feature to.
1487
 @param hFeat the handle of the feature to write to disk.
1488
1489
 @return OGRERR_NONE on success.
1490
1491
 @see OGR_L_SetFeature(), OGR_L_UpdateFeature(), OGR_L_UpsertFeature()
1492
*/
1493
1494
OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1495
1496
0
{
1497
0
    VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1498
0
    VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1499
1500
0
#ifdef OGRAPISPY_ENABLED
1501
0
    if (bOGRAPISpyEnabled)
1502
0
        OGRAPISpy_L_CreateFeature(hLayer, hFeat);
1503
0
#endif
1504
1505
0
    return OGRLayer::FromHandle(hLayer)->CreateFeature(
1506
0
        OGRFeature::FromHandle(hFeat));
1507
0
}
1508
1509
/************************************************************************/
1510
/*                           UpsertFeature()                           */
1511
/************************************************************************/
1512
1513
/**
1514
 \brief Rewrite/replace an existing feature or create a new feature within a layer.
1515
1516
 This function will write a feature to the layer, based on the feature id
1517
 within the OGRFeature.  If the feature id doesn't exist a new feature will be
1518
 written.  Otherwise, the existing feature will be rewritten.
1519
1520
 Use OGRLayer::TestCapability(OLCUpsertFeature) to establish if this layer
1521
 supports upsert writing.
1522
1523
 This method is the same as the C function OGR_L_UpsertFeature().
1524
1525
 @param poFeature the feature to write to disk.
1526
1527
 @return OGRERR_NONE on success.
1528
 @since GDAL 3.6.0
1529
1530
 @see SetFeature(), CreateFeature(), UpdateFeature()
1531
*/
1532
1533
OGRErr OGRLayer::UpsertFeature(OGRFeature *poFeature)
1534
1535
0
{
1536
0
    ConvertGeomsIfNecessary(poFeature);
1537
0
    return IUpsertFeature(poFeature);
1538
0
}
1539
1540
/************************************************************************/
1541
/*                           IUpsertFeature()                           */
1542
/************************************************************************/
1543
1544
/**
1545
 \brief Rewrite/replace an existing feature or create a new feature within a layer.
1546
1547
 This method is implemented by drivers and not called directly. User code should
1548
 use UpsertFeature() instead.
1549
1550
 This function will write a feature to the layer, based on the feature id
1551
 within the OGRFeature.  If the feature id doesn't exist a new feature will be
1552
 written.  Otherwise, the existing feature will be rewritten.
1553
1554
 @param poFeature the feature to write to disk.
1555
1556
 @return OGRERR_NONE on success.
1557
 @since GDAL 3.6.0
1558
1559
 @see UpsertFeature()
1560
*/
1561
1562
OGRErr OGRLayer::IUpsertFeature(OGRFeature *poFeature)
1563
0
{
1564
0
    (void)poFeature;
1565
0
    return OGRERR_UNSUPPORTED_OPERATION;
1566
0
}
1567
1568
/************************************************************************/
1569
/*                        OGR_L_UpsertFeature()                         */
1570
/************************************************************************/
1571
1572
/**
1573
 \brief Rewrite/replace an existing feature or create a new feature within a layer.
1574
1575
 This function will write a feature to the layer, based on the feature id
1576
 within the OGRFeature.  If the feature id doesn't exist a new feature will be
1577
 written.  Otherwise, the existing feature will be rewritten.
1578
1579
 Use OGR_L_TestCapability(OLCUpsertFeature) to establish if this layer
1580
 supports upsert writing.
1581
1582
 This function is the same as the C++ method OGRLayer::UpsertFeature().
1583
1584
 @param hLayer handle to the layer to write the feature to.
1585
 @param hFeat the handle of the feature to write to disk.
1586
1587
 @return OGRERR_NONE on success.
1588
 @since GDAL 3.6.0
1589
1590
 @see OGR_L_SetFeature(), OGR_L_CreateFeature(), OGR_L_UpdateFeature()
1591
*/
1592
1593
OGRErr OGR_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1594
1595
0
{
1596
0
    VALIDATE_POINTER1(hLayer, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
1597
0
    VALIDATE_POINTER1(hFeat, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
1598
1599
0
#ifdef OGRAPISPY_ENABLED
1600
0
    if (bOGRAPISpyEnabled)
1601
0
        OGRAPISpy_L_UpsertFeature(hLayer, hFeat);
1602
0
#endif
1603
1604
0
    return OGRLayer::FromHandle(hLayer)->UpsertFeature(
1605
0
        OGRFeature::FromHandle(hFeat));
1606
0
}
1607
1608
/************************************************************************/
1609
/*                           UpdateFeature()                            */
1610
/************************************************************************/
1611
1612
/**
1613
 \brief Update (part of) an existing feature.
1614
1615
 This method will update the specified attribute and geometry fields of a
1616
 feature to the layer, based on the feature id within the OGRFeature.
1617
1618
 Use OGRLayer::TestCapability(OLCRandomWrite) to establish if this layer
1619
 supports random access writing via UpdateFeature(). And to know if the
1620
 driver supports a dedicated/efficient UpdateFeature() method, test for the
1621
 OLCUpdateFeature capability.
1622
1623
 The way unset fields in the provided poFeature are processed is driver dependent:
1624
 <ul>
1625
 <li>
1626
 SQL based drivers which implement SetFeature() through SQL UPDATE will skip
1627
 unset fields, and thus the content of the existing feature will be preserved.
1628
 </li>
1629
 <li>
1630
 The shapefile driver will write a NULL value in the DBF file.
1631
 </li>
1632
 <li>
1633
 The GeoJSON driver will take into account unset fields to remove the corresponding
1634
 JSON member.
1635
 </li>
1636
 </ul>
1637
1638
 This method is the same as the C function OGR_L_UpdateFeature().
1639
1640
 To fully replace a feature, see OGRLayer::SetFeature().
1641
1642
 Note that after this call the content of hFeat might have changed, and will
1643
 *not* reflect the content you would get with GetFeature().
1644
 In particular for performance reasons, passed geometries might have been "stolen",
1645
 in particular for the default implementation of UpdateFeature() which relies
1646
 on GetFeature() + SetFeature().
1647
1648
 @param poFeature the feature to update.
1649
1650
 @param nUpdatedFieldsCount number of attribute fields to update. May be 0
1651
1652
 @param panUpdatedFieldsIdx array of nUpdatedFieldsCount values, each between
1653
                            0 and GetLayerDefn()->GetFieldCount() - 1, indicating
1654
                            which fields of poFeature must be updated in the
1655
                            layer.
1656
1657
 @param nUpdatedGeomFieldsCount number of geometry fields to update. May be 0
1658
1659
 @param panUpdatedGeomFieldsIdx array of nUpdatedGeomFieldsCount values, each between
1660
                                0 and GetLayerDefn()->GetGeomFieldCount() - 1, indicating
1661
                                which geometry fields of poFeature must be updated in the
1662
                                layer.
1663
1664
 @param bUpdateStyleString whether the feature style string in the layer should
1665
                           be updated with the one of poFeature.
1666
1667
 @return OGRERR_NONE if the operation works, otherwise an appropriate error
1668
 code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
1669
1670
 @since GDAL 3.7
1671
1672
 @see UpdateFeature(), CreateFeature(), UpsertFeature()
1673
*/
1674
1675
OGRErr OGRLayer::UpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
1676
                               const int *panUpdatedFieldsIdx,
1677
                               int nUpdatedGeomFieldsCount,
1678
                               const int *panUpdatedGeomFieldsIdx,
1679
                               bool bUpdateStyleString)
1680
1681
0
{
1682
0
    ConvertGeomsIfNecessary(poFeature);
1683
0
    const int nFieldCount = GetLayerDefn()->GetFieldCount();
1684
0
    for (int i = 0; i < nUpdatedFieldsCount; ++i)
1685
0
    {
1686
0
        if (panUpdatedFieldsIdx[i] < 0 || panUpdatedFieldsIdx[i] >= nFieldCount)
1687
0
        {
1688
0
            CPLError(CE_Failure, CPLE_AppDefined,
1689
0
                     "Invalid panUpdatedFieldsIdx[%d] = %d", i,
1690
0
                     panUpdatedFieldsIdx[i]);
1691
0
            return OGRERR_FAILURE;
1692
0
        }
1693
0
    }
1694
0
    const int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
1695
0
    for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
1696
0
    {
1697
0
        if (panUpdatedGeomFieldsIdx[i] < 0 ||
1698
0
            panUpdatedGeomFieldsIdx[i] >= nGeomFieldCount)
1699
0
        {
1700
0
            CPLError(CE_Failure, CPLE_AppDefined,
1701
0
                     "Invalid panUpdatedGeomFieldsIdx[%d] = %d", i,
1702
0
                     panUpdatedGeomFieldsIdx[i]);
1703
0
            return OGRERR_FAILURE;
1704
0
        }
1705
0
    }
1706
0
    return IUpdateFeature(poFeature, nUpdatedFieldsCount, panUpdatedFieldsIdx,
1707
0
                          nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx,
1708
0
                          bUpdateStyleString);
1709
0
}
1710
1711
/************************************************************************/
1712
/*                           IUpdateFeature()                           */
1713
/************************************************************************/
1714
1715
/**
1716
 \brief Update (part of) an existing feature.
1717
1718
 This method is implemented by drivers and not called directly. User code should
1719
 use UpdateFeature() instead.
1720
1721
 @param poFeature the feature to update.
1722
1723
 @param nUpdatedFieldsCount number of attribute fields to update. May be 0
1724
1725
 @param panUpdatedFieldsIdx array of nUpdatedFieldsCount values, each between
1726
                            0 and GetLayerDefn()->GetFieldCount() - 1, indicating
1727
                            which fields of poFeature must be updated in the
1728
                            layer.
1729
1730
 @param nUpdatedGeomFieldsCount number of geometry fields to update. May be 0
1731
1732
 @param panUpdatedGeomFieldsIdx array of nUpdatedGeomFieldsCount values, each between
1733
                                0 and GetLayerDefn()->GetGeomFieldCount() - 1, indicating
1734
                                which geometry fields of poFeature must be updated in the
1735
                                layer.
1736
1737
 @param bUpdateStyleString whether the feature style string in the layer should
1738
                           be updated with the one of poFeature.
1739
1740
 @return OGRERR_NONE if the operation works, otherwise an appropriate error
1741
 code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
1742
1743
 @since GDAL 3.7
1744
1745
 @see UpdateFeature()
1746
*/
1747
1748
OGRErr OGRLayer::IUpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
1749
                                const int *panUpdatedFieldsIdx,
1750
                                int nUpdatedGeomFieldsCount,
1751
                                const int *panUpdatedGeomFieldsIdx,
1752
                                bool bUpdateStyleString)
1753
0
{
1754
0
    if (!TestCapability(OLCRandomWrite))
1755
0
        return OGRERR_UNSUPPORTED_OPERATION;
1756
1757
0
    auto poFeatureExisting =
1758
0
        std::unique_ptr<OGRFeature>(GetFeature(poFeature->GetFID()));
1759
0
    if (!poFeatureExisting)
1760
0
        return OGRERR_NON_EXISTING_FEATURE;
1761
1762
0
    for (int i = 0; i < nUpdatedFieldsCount; ++i)
1763
0
    {
1764
0
        poFeatureExisting->SetField(
1765
0
            panUpdatedFieldsIdx[i],
1766
0
            poFeature->GetRawFieldRef(panUpdatedFieldsIdx[i]));
1767
0
    }
1768
0
    for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
1769
0
    {
1770
0
        poFeatureExisting->SetGeomFieldDirectly(
1771
0
            panUpdatedGeomFieldsIdx[i],
1772
0
            poFeature->StealGeometry(panUpdatedGeomFieldsIdx[i]));
1773
0
    }
1774
0
    if (bUpdateStyleString)
1775
0
    {
1776
0
        poFeatureExisting->SetStyleString(poFeature->GetStyleString());
1777
0
    }
1778
0
    return ISetFeature(poFeatureExisting.get());
1779
0
}
1780
1781
/************************************************************************/
1782
/*                        OGR_L_UpdateFeature()                         */
1783
/************************************************************************/
1784
1785
/**
1786
 \brief Update (part of) an existing feature.
1787
1788
 This function will update the specified attribute and geometry fields of a
1789
 feature to the layer, based on the feature id within the OGRFeature.
1790
1791
 Use OGR_L_TestCapability(OLCRandomWrite) to establish if this layer
1792
 supports random access writing via UpdateFeature(). And to know if the
1793
 driver supports a dedicated/efficient UpdateFeature() method, test for the
1794
 OLCUpdateFeature capability.
1795
1796
 The way unset fields in the provided poFeature are processed is driver dependent:
1797
 <ul>
1798
 <li>
1799
 SQL based drivers which implement SetFeature() through SQL UPDATE will skip
1800
 unset fields, and thus the content of the existing feature will be preserved.
1801
 </li>
1802
 <li>
1803
 The shapefile driver will write a NULL value in the DBF file.
1804
 </li>
1805
 <li>
1806
 The GeoJSON driver will take into account unset fields to remove the corresponding
1807
 JSON member.
1808
 </li>
1809
 </ul>
1810
1811
 This method is the same as the C++ method OGRLayer::UpdateFeature().
1812
1813
 To fully replace a feature, see OGR_L_SetFeature()
1814
1815
 Note that after this call the content of hFeat might have changed, and will
1816
 *not* reflect the content you would get with OGR_L_GetFeature().
1817
 In particular for performance reasons, passed geometries might have been "stolen",
1818
 in particular for the default implementation of UpdateFeature() which relies
1819
 on GetFeature() + SetFeature().
1820
1821
 @param hLayer handle to the layer to write the feature.
1822
1823
 @param hFeat the feature to update.
1824
1825
 @param nUpdatedFieldsCount number of attribute fields to update. May be 0
1826
1827
 @param panUpdatedFieldsIdx array of nUpdatedFieldsCount values, each between
1828
                            0 and GetLayerDefn()->GetFieldCount() - 1, indicating
1829
                            which fields of hFeat must be updated in the
1830
                            layer.
1831
1832
 @param nUpdatedGeomFieldsCount number of geometry fields to update. May be 0
1833
1834
 @param panUpdatedGeomFieldsIdx array of nUpdatedGeomFieldsCount values, each between
1835
                                0 and GetLayerDefn()->GetGeomFieldCount() - 1, indicating
1836
                                which geometry fields of hFeat must be updated in the
1837
                                layer.
1838
1839
 @param bUpdateStyleString whether the feature style string in the layer should
1840
                           be updated with the one of hFeat.
1841
1842
 @return OGRERR_NONE if the operation works, otherwise an appropriate error
1843
 code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
1844
1845
 @since GDAL 3.7
1846
1847
 @see OGR_L_UpdateFeature(), OGR_L_CreateFeature(), OGR_L_UpsertFeature()
1848
*/
1849
1850
OGRErr OGR_L_UpdateFeature(OGRLayerH hLayer, OGRFeatureH hFeat,
1851
                           int nUpdatedFieldsCount,
1852
                           const int *panUpdatedFieldsIdx,
1853
                           int nUpdatedGeomFieldsCount,
1854
                           const int *panUpdatedGeomFieldsIdx,
1855
                           bool bUpdateStyleString)
1856
1857
0
{
1858
0
    VALIDATE_POINTER1(hLayer, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
1859
0
    VALIDATE_POINTER1(hFeat, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
1860
1861
0
    return OGRLayer::FromHandle(hLayer)->UpdateFeature(
1862
0
        OGRFeature::FromHandle(hFeat), nUpdatedFieldsCount, panUpdatedFieldsIdx,
1863
0
        nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
1864
0
}
1865
1866
/************************************************************************/
1867
/*                            CreateField()                             */
1868
/************************************************************************/
1869
1870
/**
1871
\brief Create a new field on a layer.
1872
1873
You must use this to create new fields
1874
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
1875
to reflect the new field.  Applications should never modify the OGRFeatureDefn
1876
used by a layer directly.
1877
1878
This method should not be called while there are feature objects in existence that
1879
were obtained or created with the previous layer definition.
1880
1881
Not all drivers support this method. You can query a layer to check if it supports it
1882
with the OLCCreateField capability. Some drivers may only support this method while
1883
there are still no features in the layer. When it is supported, the existing features of the
1884
backing file/database should be updated accordingly.
1885
1886
Drivers may or may not support not-null constraints. If they support creating
1887
fields with not-null constraints, this is generally before creating any feature to the layer.
1888
1889
This function is the same as the C function OGR_L_CreateField().
1890
1891
@param poField field definition to write to disk.
1892
@param bApproxOK If TRUE, the field may be created in a slightly different
1893
form depending on the limitations of the format driver.
1894
1895
@return OGRERR_NONE on success.
1896
*/
1897
1898
OGRErr OGRLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
1899
1900
0
{
1901
0
    (void)poField;
1902
0
    (void)bApproxOK;
1903
1904
0
    CPLError(CE_Failure, CPLE_NotSupported,
1905
0
             "CreateField() not supported by this layer.\n");
1906
1907
0
    return OGRERR_UNSUPPORTED_OPERATION;
1908
0
}
1909
1910
/************************************************************************/
1911
/*                         OGR_L_CreateField()                          */
1912
/************************************************************************/
1913
1914
/**
1915
\brief Create a new field on a layer.
1916
1917
You must use this to create new fields
1918
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
1919
to reflect the new field.  Applications should never modify the OGRFeatureDefn
1920
used by a layer directly.
1921
1922
This function should not be called while there are feature objects in existence that
1923
were obtained or created with the previous layer definition.
1924
1925
Not all drivers support this function. You can query a layer to check if it supports it
1926
with the OLCCreateField capability. Some drivers may only support this method while
1927
there are still no features in the layer. When it is supported, the existing features of the
1928
backing file/database should be updated accordingly.
1929
1930
Drivers may or may not support not-null constraints. If they support creating
1931
fields with not-null constraints, this is generally before creating any feature to the layer.
1932
1933
 This function is the same as the C++ method OGRLayer::CreateField().
1934
1935
 @param hLayer handle to the layer to write the field definition.
1936
 @param hField handle of the field definition to write to disk.
1937
 @param bApproxOK If TRUE, the field may be created in a slightly different
1938
form depending on the limitations of the format driver.
1939
1940
 @return OGRERR_NONE on success.
1941
*/
1942
1943
OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
1944
1945
0
{
1946
0
    VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1947
0
    VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1948
1949
0
#ifdef OGRAPISPY_ENABLED
1950
0
    if (bOGRAPISpyEnabled)
1951
0
        OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
1952
0
#endif
1953
1954
0
    return OGRLayer::FromHandle(hLayer)->CreateField(
1955
0
        OGRFieldDefn::FromHandle(hField), bApproxOK);
1956
0
}
1957
1958
/************************************************************************/
1959
/*                            DeleteField()                             */
1960
/************************************************************************/
1961
1962
/**
1963
\brief Delete an existing field on a layer.
1964
1965
You must use this to delete existing fields
1966
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
1967
to reflect the deleted field.  Applications should never modify the OGRFeatureDefn
1968
used by a layer directly.
1969
1970
This method should not be called while there are feature objects in existence that
1971
were obtained or created with the previous layer definition.
1972
1973
If a OGRFieldDefn* object corresponding to the deleted field has been retrieved
1974
from the layer definition before the call to DeleteField(), it must no longer be
1975
used after the call to DeleteField(), which will have destroyed it.
1976
1977
Not all drivers support this method. You can query a layer to check if it supports it
1978
with the OLCDeleteField capability. Some drivers may only support this method while
1979
there are still no features in the layer. When it is supported, the existing features of the
1980
backing file/database should be updated accordingly.
1981
1982
This function is the same as the C function OGR_L_DeleteField().
1983
1984
@param iField index of the field to delete.
1985
1986
@return OGRERR_NONE on success.
1987
*/
1988
1989
OGRErr OGRLayer::DeleteField(int iField)
1990
1991
0
{
1992
0
    (void)iField;
1993
1994
0
    CPLError(CE_Failure, CPLE_NotSupported,
1995
0
             "DeleteField() not supported by this layer.\n");
1996
1997
0
    return OGRERR_UNSUPPORTED_OPERATION;
1998
0
}
1999
2000
/************************************************************************/
2001
/*                         OGR_L_DeleteField()                          */
2002
/************************************************************************/
2003
2004
/**
2005
\brief Delete an existing field on a layer.
2006
2007
You must use this to delete existing fields
2008
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
2009
to reflect the deleted field.  Applications should never modify the OGRFeatureDefn
2010
used by a layer directly.
2011
2012
This function should not be called while there are feature objects in existence that
2013
were obtained or created with the previous layer definition.
2014
2015
If a OGRFieldDefnH object corresponding to the deleted field has been retrieved
2016
from the layer definition before the call to DeleteField(), it must no longer be
2017
used after the call to DeleteField(), which will have destroyed it.
2018
2019
Not all drivers support this function. You can query a layer to check if it supports it
2020
with the OLCDeleteField capability. Some drivers may only support this method while
2021
there are still no features in the layer. When it is supported, the existing features of the
2022
backing file/database should be updated accordingly.
2023
2024
This function is the same as the C++ method OGRLayer::DeleteField().
2025
2026
@param hLayer handle to the layer.
2027
@param iField index of the field to delete.
2028
2029
@return OGRERR_NONE on success.
2030
*/
2031
2032
OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
2033
2034
0
{
2035
0
    VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
2036
2037
0
#ifdef OGRAPISPY_ENABLED
2038
0
    if (bOGRAPISpyEnabled)
2039
0
        OGRAPISpy_L_DeleteField(hLayer, iField);
2040
0
#endif
2041
2042
0
    return OGRLayer::FromHandle(hLayer)->DeleteField(iField);
2043
0
}
2044
2045
/************************************************************************/
2046
/*                           ReorderFields()                            */
2047
/************************************************************************/
2048
2049
/**
2050
\brief Reorder all the fields of a layer.
2051
2052
You must use this to reorder existing fields
2053
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
2054
to reflect the reordering of the fields.  Applications should never modify the OGRFeatureDefn
2055
used by a layer directly.
2056
2057
This method should not be called while there are feature objects in existence that
2058
were obtained or created with the previous layer definition.
2059
2060
panMap is such that,for each field definition at position i after reordering,
2061
its position before reordering was panMap[i].
2062
2063
For example, let suppose the fields were "0","1","2","3","4" initially.
2064
ReorderFields([0,2,3,1,4]) will reorder them as "0","2","3","1","4".
2065
2066
Not all drivers support this method. You can query a layer to check if it supports it
2067
with the OLCReorderFields capability. Some drivers may only support this method while
2068
there are still no features in the layer. When it is supported, the existing features of the
2069
backing file/database should be updated accordingly.
2070
2071
This function is the same as the C function OGR_L_ReorderFields().
2072
2073
@param panMap an array of GetLayerDefn()->OGRFeatureDefn::GetFieldCount() elements which
2074
is a permutation of [0, GetLayerDefn()->OGRFeatureDefn::GetFieldCount()-1].
2075
2076
@return OGRERR_NONE on success.
2077
*/
2078
2079
OGRErr OGRLayer::ReorderFields(int *panMap)
2080
2081
0
{
2082
0
    (void)panMap;
2083
2084
0
    CPLError(CE_Failure, CPLE_NotSupported,
2085
0
             "ReorderFields() not supported by this layer.\n");
2086
2087
0
    return OGRERR_UNSUPPORTED_OPERATION;
2088
0
}
2089
2090
/************************************************************************/
2091
/*                       OGR_L_ReorderFields()                          */
2092
/************************************************************************/
2093
2094
/**
2095
\brief Reorder all the fields of a layer.
2096
2097
You must use this to reorder existing fields
2098
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
2099
to reflect the reordering of the fields.  Applications should never modify the OGRFeatureDefn
2100
used by a layer directly.
2101
2102
This function should not be called while there are feature objects in existence that
2103
were obtained or created with the previous layer definition.
2104
2105
panMap is such that,for each field definition at position i after reordering,
2106
its position before reordering was panMap[i].
2107
2108
For example, let suppose the fields were "0","1","2","3","4" initially.
2109
ReorderFields([0,2,3,1,4]) will reorder them as "0","2","3","1","4".
2110
2111
Not all drivers support this function. You can query a layer to check if it supports it
2112
with the OLCReorderFields capability. Some drivers may only support this method while
2113
there are still no features in the layer. When it is supported, the existing features of the
2114
backing file/database should be updated accordingly.
2115
2116
This function is the same as the C++ method OGRLayer::ReorderFields().
2117
2118
@param hLayer handle to the layer.
2119
@param panMap an array of GetLayerDefn()->OGRFeatureDefn::GetFieldCount() elements which
2120
is a permutation of [0, GetLayerDefn()->OGRFeatureDefn::GetFieldCount()-1].
2121
2122
@return OGRERR_NONE on success.
2123
*/
2124
2125
OGRErr OGR_L_ReorderFields(OGRLayerH hLayer, int *panMap)
2126
2127
0
{
2128
0
    VALIDATE_POINTER1(hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE);
2129
2130
0
#ifdef OGRAPISPY_ENABLED
2131
0
    if (bOGRAPISpyEnabled)
2132
0
        OGRAPISpy_L_ReorderFields(hLayer, panMap);
2133
0
#endif
2134
2135
0
    return OGRLayer::FromHandle(hLayer)->ReorderFields(panMap);
2136
0
}
2137
2138
/************************************************************************/
2139
/*                            ReorderField()                            */
2140
/************************************************************************/
2141
2142
/**
2143
\brief Reorder an existing field on a layer.
2144
2145
This method is a convenience wrapper of ReorderFields() dedicated to move a single field.
2146
It is a non-virtual method, so drivers should implement ReorderFields() instead.
2147
2148
You must use this to reorder existing fields
2149
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
2150
to reflect the reordering of the fields.  Applications should never modify the OGRFeatureDefn
2151
used by a layer directly.
2152
2153
This method should not be called while there are feature objects in existence that
2154
were obtained or created with the previous layer definition.
2155
2156
The field definition that was at initial position iOldFieldPos will be moved at
2157
position iNewFieldPos, and elements between will be shuffled accordingly.
2158
2159
For example, let suppose the fields were "0","1","2","3","4" initially.
2160
ReorderField(1, 3) will reorder them as "0","2","3","1","4".
2161
2162
Not all drivers support this method. You can query a layer to check if it supports it
2163
with the OLCReorderFields capability. Some drivers may only support this method while
2164
there are still no features in the layer. When it is supported, the existing features of the
2165
backing file/database should be updated accordingly.
2166
2167
This function is the same as the C function OGR_L_ReorderField().
2168
2169
@param iOldFieldPos previous position of the field to move. Must be in the range [0,GetFieldCount()-1].
2170
@param iNewFieldPos new position of the field to move. Must be in the range [0,GetFieldCount()-1].
2171
2172
@return OGRERR_NONE on success.
2173
*/
2174
2175
OGRErr OGRLayer::ReorderField(int iOldFieldPos, int iNewFieldPos)
2176
2177
0
{
2178
0
    OGRErr eErr;
2179
2180
0
    int nFieldCount = GetLayerDefn()->GetFieldCount();
2181
2182
0
    if (iOldFieldPos < 0 || iOldFieldPos >= nFieldCount)
2183
0
    {
2184
0
        CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
2185
0
        return OGRERR_FAILURE;
2186
0
    }
2187
0
    if (iNewFieldPos < 0 || iNewFieldPos >= nFieldCount)
2188
0
    {
2189
0
        CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
2190
0
        return OGRERR_FAILURE;
2191
0
    }
2192
0
    if (iNewFieldPos == iOldFieldPos)
2193
0
        return OGRERR_NONE;
2194
2195
0
    int *panMap = static_cast<int *>(CPLMalloc(sizeof(int) * nFieldCount));
2196
0
    if (iOldFieldPos < iNewFieldPos)
2197
0
    {
2198
        /* "0","1","2","3","4" (1,3) -> "0","2","3","1","4" */
2199
0
        int i = 0;  // Used after for.
2200
0
        for (; i < iOldFieldPos; i++)
2201
0
            panMap[i] = i;
2202
0
        for (; i < iNewFieldPos; i++)
2203
0
            panMap[i] = i + 1;
2204
0
        panMap[iNewFieldPos] = iOldFieldPos;
2205
0
        for (i = iNewFieldPos + 1; i < nFieldCount; i++)
2206
0
            panMap[i] = i;
2207
0
    }
2208
0
    else
2209
0
    {
2210
        /* "0","1","2","3","4" (3,1) -> "0","3","1","2","4" */
2211
0
        for (int i = 0; i < iNewFieldPos; i++)
2212
0
            panMap[i] = i;
2213
0
        panMap[iNewFieldPos] = iOldFieldPos;
2214
0
        int i = iNewFieldPos + 1;  // Used after for.
2215
0
        for (; i <= iOldFieldPos; i++)
2216
0
            panMap[i] = i - 1;
2217
0
        for (; i < nFieldCount; i++)
2218
0
            panMap[i] = i;
2219
0
    }
2220
2221
0
    eErr = ReorderFields(panMap);
2222
2223
0
    CPLFree(panMap);
2224
2225
0
    return eErr;
2226
0
}
2227
2228
/************************************************************************/
2229
/*                        OGR_L_ReorderField()                          */
2230
/************************************************************************/
2231
2232
/**
2233
\brief Reorder an existing field on a layer.
2234
2235
This function is a convenience wrapper of OGR_L_ReorderFields() dedicated to move a single field.
2236
2237
You must use this to reorder existing fields
2238
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
2239
to reflect the reordering of the fields.  Applications should never modify the OGRFeatureDefn
2240
used by a layer directly.
2241
2242
This function should not be called while there are feature objects in existence that
2243
were obtained or created with the previous layer definition.
2244
2245
The field definition that was at initial position iOldFieldPos will be moved at
2246
position iNewFieldPos, and elements between will be shuffled accordingly.
2247
2248
For example, let suppose the fields were "0","1","2","3","4" initially.
2249
ReorderField(1, 3) will reorder them as "0","2","3","1","4".
2250
2251
Not all drivers support this function. You can query a layer to check if it supports it
2252
with the OLCReorderFields capability. Some drivers may only support this method while
2253
there are still no features in the layer. When it is supported, the existing features of the
2254
backing file/database should be updated accordingly.
2255
2256
This function is the same as the C++ method OGRLayer::ReorderField().
2257
2258
@param hLayer handle to the layer.
2259
@param iOldFieldPos previous position of the field to move. Must be in the range [0,GetFieldCount()-1].
2260
@param iNewFieldPos new position of the field to move. Must be in the range [0,GetFieldCount()-1].
2261
2262
@return OGRERR_NONE on success.
2263
*/
2264
2265
OGRErr OGR_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos)
2266
2267
0
{
2268
0
    VALIDATE_POINTER1(hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE);
2269
2270
0
#ifdef OGRAPISPY_ENABLED
2271
0
    if (bOGRAPISpyEnabled)
2272
0
        OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
2273
0
#endif
2274
2275
0
    return OGRLayer::FromHandle(hLayer)->ReorderField(iOldFieldPos,
2276
0
                                                      iNewFieldPos);
2277
0
}
2278
2279
/************************************************************************/
2280
/*                           AlterFieldDefn()                           */
2281
/************************************************************************/
2282
2283
/**
2284
\brief Alter the definition of an existing field on a layer.
2285
2286
You must use this to alter the definition of an existing field of a real layer.
2287
Internally the OGRFeatureDefn for the layer will be updated
2288
to reflect the altered field.  Applications should never modify the OGRFeatureDefn
2289
used by a layer directly.
2290
2291
This method should not be called while there are feature objects in existence that
2292
were obtained or created with the previous layer definition.
2293
2294
Not all drivers support this method. You can query a layer to check if it supports it
2295
with the OLCAlterFieldDefn capability. Some drivers may only support this method while
2296
there are still no features in the layer. When it is supported, the existing features of the
2297
backing file/database should be updated accordingly. Some drivers might also not support
2298
all update flags.
2299
2300
This function is the same as the C function OGR_L_AlterFieldDefn().
2301
2302
@param iField index of the field whose definition must be altered.
2303
@param poNewFieldDefn new field definition
2304
@param nFlagsIn combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG, ALTER_WIDTH_PRECISION_FLAG,
2305
ALTER_NULLABLE_FLAG and ALTER_DEFAULT_FLAG
2306
to indicate which of the name and/or type and/or width and precision fields and/or nullability from the new field
2307
definition must be taken into account.
2308
2309
@return OGRERR_NONE on success.
2310
*/
2311
2312
OGRErr OGRLayer::AlterFieldDefn(int iField, OGRFieldDefn *poNewFieldDefn,
2313
                                int nFlagsIn)
2314
2315
0
{
2316
0
    (void)iField;
2317
0
    (void)poNewFieldDefn;
2318
0
    (void)nFlagsIn;
2319
0
    CPLError(CE_Failure, CPLE_NotSupported,
2320
0
             "AlterFieldDefn() not supported by this layer.\n");
2321
2322
0
    return OGRERR_UNSUPPORTED_OPERATION;
2323
0
}
2324
2325
/************************************************************************/
2326
/*                        OGR_L_AlterFieldDefn()                        */
2327
/************************************************************************/
2328
2329
/**
2330
\brief Alter the definition of an existing field on a layer.
2331
2332
You must use this to alter the definition of an existing field of a real layer.
2333
Internally the OGRFeatureDefn for the layer will be updated
2334
to reflect the altered field.  Applications should never modify the OGRFeatureDefn
2335
used by a layer directly.
2336
2337
This function should not be called while there are feature objects in existence that
2338
were obtained or created with the previous layer definition.
2339
2340
Not all drivers support this function. You can query a layer to check if it supports it
2341
with the OLCAlterFieldDefn capability. Some drivers may only support this method while
2342
there are still no features in the layer. When it is supported, the existing features of the
2343
backing file/database should be updated accordingly. Some drivers might also not support
2344
all update flags.
2345
2346
This function is the same as the C++ method OGRLayer::AlterFieldDefn().
2347
2348
@param hLayer handle to the layer.
2349
@param iField index of the field whose definition must be altered.
2350
@param hNewFieldDefn new field definition
2351
@param nFlags combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG, ALTER_WIDTH_PRECISION_FLAG,
2352
ALTER_NULLABLE_FLAG and ALTER_DEFAULT_FLAG
2353
to indicate which of the name and/or type and/or width and precision fields and/or nullability from the new field
2354
definition must be taken into account.
2355
2356
@return OGRERR_NONE on success.
2357
*/
2358
2359
OGRErr OGR_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
2360
                            OGRFieldDefnH hNewFieldDefn, int nFlags)
2361
2362
0
{
2363
0
    VALIDATE_POINTER1(hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE);
2364
0
    VALIDATE_POINTER1(hNewFieldDefn, "OGR_L_AlterFieldDefn",
2365
0
                      OGRERR_INVALID_HANDLE);
2366
2367
0
#ifdef OGRAPISPY_ENABLED
2368
0
    if (bOGRAPISpyEnabled)
2369
0
        OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
2370
0
#endif
2371
2372
0
    return OGRLayer::FromHandle(hLayer)->AlterFieldDefn(
2373
0
        iField, OGRFieldDefn::FromHandle(hNewFieldDefn), nFlags);
2374
0
}
2375
2376
/************************************************************************/
2377
/*                        AlterGeomFieldDefn()                          */
2378
/************************************************************************/
2379
2380
/**
2381
\brief Alter the definition of an existing geometry field on a layer.
2382
2383
You must use this to alter the definition of an existing geometry field of a real layer.
2384
Internally the OGRFeatureDefn for the layer will be updated
2385
to reflect the altered field.  Applications should never modify the OGRFeatureDefn
2386
used by a layer directly.
2387
2388
Note that altering the SRS does *not* cause coordinate reprojection to occur:
2389
this is simply a modification of the layer metadata (correcting a wrong SRS
2390
definition). No modification to existing geometries will ever be performed,
2391
so this method cannot be used to e.g. promote single part geometries to their
2392
multipart equivalents.
2393
2394
This method should not be called while there are feature objects in existence that
2395
were obtained or created with the previous layer definition.
2396
2397
Not all drivers support this method. You can query a layer to check if it supports it
2398
with the OLCAlterGeomFieldDefn capability. Some drivers might not support
2399
all update flags. The GDAL_DMD_ALTER_GEOM_FIELD_DEFN_FLAGS driver metadata item
2400
can be queried to examine which flags may be supported by a driver.
2401
2402
This function is the same as the C function OGR_L_AlterGeomFieldDefn().
2403
2404
@param iGeomField index of the field whose definition must be altered.
2405
@param poNewGeomFieldDefn new field definition
2406
@param nFlagsIn combination of ALTER_GEOM_FIELD_DEFN_NAME_FLAG, ALTER_GEOM_FIELD_DEFN_TYPE_FLAG, ALTER_GEOM_FIELD_DEFN_NULLABLE_FLAG, ALTER_GEOM_FIELD_DEFN_SRS_FLAG, ALTER_GEOM_FIELD_DEFN_SRS_COORD_EPOCH_FLAG
2407
to indicate which of the name and/or type and/or nullability and/or SRS and/or coordinate epoch from the new field
2408
definition must be taken into account. Or ALTER_GEOM_FIELD_DEFN_ALL_FLAG to update all members.
2409
2410
@return OGRERR_NONE on success.
2411
2412
@since OGR 3.6.0
2413
*/
2414
2415
OGRErr OGRLayer::AlterGeomFieldDefn(int iGeomField,
2416
                                    const OGRGeomFieldDefn *poNewGeomFieldDefn,
2417
                                    int nFlagsIn)
2418
2419
0
{
2420
0
    (void)iGeomField;
2421
0
    (void)poNewGeomFieldDefn;
2422
0
    (void)nFlagsIn;
2423
2424
0
    CPLError(CE_Failure, CPLE_NotSupported,
2425
0
             "AlterGeomFieldDefn() not supported by this layer.\n");
2426
2427
0
    return OGRERR_UNSUPPORTED_OPERATION;
2428
0
}
2429
2430
/************************************************************************/
2431
/*                      OGR_L_AlterGeomFieldDefn()                      */
2432
/************************************************************************/
2433
2434
/**
2435
\brief Alter the definition of an existing geometry field on a layer.
2436
2437
You must use this to alter the definition of an existing geometry field of a real layer.
2438
Internally the OGRFeatureDefn for the layer will be updated
2439
to reflect the altered field.  Applications should never modify the OGRFeatureDefn
2440
used by a layer directly.
2441
2442
Note that altering the SRS does *not* cause coordinate reprojection to occur:
2443
this is simply a modification of the layer metadata (correcting a wrong SRS
2444
definition). No modification to existing geometries will ever be performed,
2445
so this method cannot be used to e.g. promote single part geometries to their
2446
multipart equivalents.
2447
2448
This function should not be called while there are feature objects in existence that
2449
were obtained or created with the previous layer definition.
2450
2451
Not all drivers support this function. You can query a layer to check if it supports it
2452
with the OLCAlterGeomFieldDefn capability. Some drivers might not support
2453
all update flags. The GDAL_DMD_ALTER_GEOM_FIELD_DEFN_FLAGS driver metadata item
2454
can be queried to examine which flags may be supported by a driver.
2455
2456
This function is the same as the C++ method OGRLayer::AlterFieldDefn().
2457
2458
@param hLayer handle to the layer.
2459
@param iGeomField index of the field whose definition must be altered.
2460
@param hNewGeomFieldDefn new field definition
2461
@param nFlags combination of ALTER_GEOM_FIELD_DEFN_NAME_FLAG, ALTER_GEOM_FIELD_DEFN_TYPE_FLAG, ALTER_GEOM_FIELD_DEFN_NULLABLE_FLAG, ALTER_GEOM_FIELD_DEFN_SRS_FLAG, ALTER_GEOM_FIELD_DEFN_SRS_COORD_EPOCH_FLAG
2462
to indicate which of the name and/or type and/or nullability and/or SRS and/or coordinate epoch from the new field
2463
definition must be taken into account. Or ALTER_GEOM_FIELD_DEFN_ALL_FLAG to update all members.
2464
2465
@return OGRERR_NONE on success.
2466
2467
@since OGR 3.6.0
2468
*/
2469
2470
OGRErr OGR_L_AlterGeomFieldDefn(OGRLayerH hLayer, int iGeomField,
2471
                                OGRGeomFieldDefnH hNewGeomFieldDefn, int nFlags)
2472
2473
0
{
2474
0
    VALIDATE_POINTER1(hLayer, "OGR_L_AlterGeomFieldDefn",
2475
0
                      OGRERR_INVALID_HANDLE);
2476
0
    VALIDATE_POINTER1(hNewGeomFieldDefn, "OGR_L_AlterGeomFieldDefn",
2477
0
                      OGRERR_INVALID_HANDLE);
2478
2479
0
    return OGRLayer::FromHandle(hLayer)->AlterGeomFieldDefn(
2480
0
        iGeomField,
2481
0
        const_cast<const OGRGeomFieldDefn *>(
2482
0
            OGRGeomFieldDefn::FromHandle(hNewGeomFieldDefn)),
2483
0
        nFlags);
2484
0
}
2485
2486
/************************************************************************/
2487
/*                         CreateGeomField()                            */
2488
/************************************************************************/
2489
2490
/**
2491
\brief Create a new geometry field on a layer.
2492
2493
You must use this to create new geometry fields
2494
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
2495
to reflect the new field.  Applications should never modify the OGRFeatureDefn
2496
used by a layer directly.
2497
2498
This method should not be called while there are feature objects in existence that
2499
were obtained or created with the previous layer definition.
2500
2501
Not all drivers support this method. You can query a layer to check if it supports it
2502
with the OLCCreateGeomField capability. Some drivers may only support this method while
2503
there are still no features in the layer. When it is supported, the existing features of the
2504
backing file/database should be updated accordingly.
2505
2506
Drivers may or may not support not-null constraints. If they support creating
2507
fields with not-null constraints, this is generally before creating any feature to the layer.
2508
2509
This function is the same as the C function OGR_L_CreateGeomField().
2510
2511
@param poField geometry field definition to write to disk.
2512
@param bApproxOK If TRUE, the field may be created in a slightly different
2513
form depending on the limitations of the format driver.
2514
2515
@return OGRERR_NONE on success.
2516
*/
2517
2518
OGRErr OGRLayer::CreateGeomField(const OGRGeomFieldDefn *poField, int bApproxOK)
2519
2520
0
{
2521
0
    (void)poField;
2522
0
    (void)bApproxOK;
2523
2524
0
    CPLError(CE_Failure, CPLE_NotSupported,
2525
0
             "CreateGeomField() not supported by this layer.\n");
2526
2527
0
    return OGRERR_UNSUPPORTED_OPERATION;
2528
0
}
2529
2530
/************************************************************************/
2531
/*                        OGR_L_CreateGeomField()                       */
2532
/************************************************************************/
2533
2534
/**
2535
\brief Create a new geometry field on a layer.
2536
2537
You must use this to create new geometry fields
2538
on a real layer. Internally the OGRFeatureDefn for the layer will be updated
2539
to reflect the new field.  Applications should never modify the OGRFeatureDefn
2540
used by a layer directly.
2541
2542
This function should not be called while there are feature objects in existence that
2543
were obtained or created with the previous layer definition.
2544
2545
Not all drivers support this function. You can query a layer to check if it supports it
2546
with the OLCCreateField capability. Some drivers may only support this method while
2547
there are still no features in the layer. When it is supported, the existing features of the
2548
backing file/database should be updated accordingly.
2549
2550
Drivers may or may not support not-null constraints. If they support creating
2551
fields with not-null constraints, this is generally before creating any feature to the layer.
2552
2553
 This function is the same as the C++ method OGRLayer::CreateField().
2554
2555
 @param hLayer handle to the layer to write the field definition.
2556
 @param hField handle of the geometry field definition to write to disk.
2557
 @param bApproxOK If TRUE, the field may be created in a slightly different
2558
form depending on the limitations of the format driver.
2559
2560
 @return OGRERR_NONE on success.
2561
*/
2562
2563
OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
2564
                             int bApproxOK)
2565
2566
0
{
2567
0
    VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
2568
0
    VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
2569
2570
0
#ifdef OGRAPISPY_ENABLED
2571
0
    if (bOGRAPISpyEnabled)
2572
0
        OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
2573
0
#endif
2574
2575
0
    return OGRLayer::FromHandle(hLayer)->CreateGeomField(
2576
0
        OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
2577
0
}
2578
2579
/************************************************************************/
2580
/*                          StartTransaction()                          */
2581
/************************************************************************/
2582
2583
/**
2584
 \brief For datasources which support transactions, StartTransaction creates a transaction.
2585
2586
 If starting the transaction fails, will return
2587
 OGRERR_FAILURE. Datasources which do not support transactions will
2588
 always return OGRERR_NONE.
2589
2590
 Use of this API is discouraged when the dataset offers
2591
 dataset level transaction with GDALDataset::StartTransaction(). The reason is
2592
 that most drivers can only offer transactions at dataset level, and not layer level.
2593
 Very few drivers really support transactions at layer scope.
2594
2595
 This function is the same as the C function OGR_L_StartTransaction().
2596
2597
 @return OGRERR_NONE on success.
2598
*/
2599
2600
OGRErr OGRLayer::StartTransaction()
2601
2602
0
{
2603
0
    return OGRERR_NONE;
2604
0
}
2605
2606
/************************************************************************/
2607
/*                       OGR_L_StartTransaction()                       */
2608
/************************************************************************/
2609
2610
/**
2611
 \brief For datasources which support transactions, StartTransaction creates a transaction.
2612
2613
 If starting the transaction fails, will return
2614
 OGRERR_FAILURE. Datasources which do not support transactions will
2615
 always return OGRERR_NONE.
2616
2617
 Use of this API is discouraged when the dataset offers
2618
 dataset level transaction with GDALDataset::StartTransaction(). The reason is
2619
 that most drivers can only offer transactions at dataset level, and not layer level.
2620
 Very few drivers really support transactions at layer scope.
2621
2622
 This function is the same as the C++ method OGRLayer::StartTransaction().
2623
2624
 @param hLayer handle to the layer
2625
2626
 @return OGRERR_NONE on success.
2627
2628
*/
2629
2630
OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
2631
2632
0
{
2633
0
    VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
2634
2635
0
#ifdef OGRAPISPY_ENABLED
2636
0
    if (bOGRAPISpyEnabled)
2637
0
        OGRAPISpy_L_StartTransaction(hLayer);
2638
0
#endif
2639
2640
0
    return OGRLayer::FromHandle(hLayer)->StartTransaction();
2641
0
}
2642
2643
/************************************************************************/
2644
/*                         CommitTransaction()                          */
2645
/************************************************************************/
2646
2647
/**
2648
 \brief For datasources which support transactions, CommitTransaction commits a transaction.
2649
2650
 If no transaction is active, or the commit fails, will return
2651
 OGRERR_FAILURE. Datasources which do not support transactions will
2652
 always return OGRERR_NONE.
2653
2654
 This function is the same as the C function OGR_L_CommitTransaction().
2655
2656
 @return OGRERR_NONE on success.
2657
*/
2658
2659
OGRErr OGRLayer::CommitTransaction()
2660
2661
0
{
2662
0
    return OGRERR_NONE;
2663
0
}
2664
2665
/************************************************************************/
2666
/*                       OGR_L_CommitTransaction()                      */
2667
/************************************************************************/
2668
2669
/**
2670
 \brief For datasources which support transactions, CommitTransaction commits a transaction.
2671
2672
 If no transaction is active, or the commit fails, will return
2673
 OGRERR_FAILURE. Datasources which do not support transactions will
2674
 always return OGRERR_NONE.
2675
2676
 This function is the same as the C function OGR_L_CommitTransaction().
2677
2678
 @return OGRERR_NONE on success.
2679
*/
2680
2681
OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
2682
2683
0
{
2684
0
    VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
2685
2686
0
#ifdef OGRAPISPY_ENABLED
2687
0
    if (bOGRAPISpyEnabled)
2688
0
        OGRAPISpy_L_CommitTransaction(hLayer);
2689
0
#endif
2690
2691
0
    return OGRLayer::FromHandle(hLayer)->CommitTransaction();
2692
0
}
2693
2694
/************************************************************************/
2695
/*                        RollbackTransaction()                         */
2696
/************************************************************************/
2697
2698
/**
2699
 \brief For datasources which support transactions, RollbackTransaction will roll back a datasource to its state before the start of the current transaction.
2700
 If no transaction is active, or the rollback fails, will return
2701
 OGRERR_FAILURE. Datasources which do not support transactions will
2702
 always return OGRERR_NONE.
2703
2704
 This function is the same as the C function OGR_L_RollbackTransaction().
2705
2706
2707
 OGRFeature* instances acquired or created between the StartTransaction() and RollbackTransaction() should
2708
 be destroyed before RollbackTransaction() if the field structure has been modified during the transaction.
2709
2710
 In particular, the following is invalid:
2711
2712
 \code
2713
 lyr->StartTransaction();
2714
 lyr->DeleteField(...);
2715
 f = new OGRFeature(lyr->GetLayerDefn());
2716
 lyr->RollbackTransaction();
2717
 // f is in a inconsistent state at this point, given its array of fields doesn't match
2718
 // the updated layer definition, and thus it cannot even be safely deleted !
2719
 \endcode
2720
2721
 Instead, the feature should be destroyed before the rollback:
2722
2723
 \code
2724
 lyr->StartTransaction();
2725
 lyr->DeleteField(...);
2726
 f = new OGRFeature(lyr->GetLayerDefn());
2727
 ...
2728
 delete f;
2729
 \endcode
2730
2731
 @return OGRERR_NONE on success.
2732
*/
2733
2734
OGRErr OGRLayer::RollbackTransaction()
2735
2736
0
{
2737
0
    return OGRERR_UNSUPPORTED_OPERATION;
2738
0
}
2739
2740
/************************************************************************/
2741
/*                     OGR_L_RollbackTransaction()                      */
2742
/************************************************************************/
2743
2744
/**
2745
 \brief For datasources which support transactions, RollbackTransaction will roll back a datasource to its state before the start of the current transaction.
2746
 If no transaction is active, or the rollback fails, will return
2747
 OGRERR_FAILURE. Datasources which do not support transactions will
2748
 always return OGRERR_NONE.
2749
2750
 This function is the same as the C++ method OGRLayer::RollbackTransaction().
2751
2752
 @param hLayer handle to the layer
2753
2754
 @return OGRERR_NONE on success.
2755
*/
2756
2757
OGRErr OGR_L_RollbackTransaction(OGRLayerH hLayer)
2758
2759
0
{
2760
0
    VALIDATE_POINTER1(hLayer, "OGR_L_RollbackTransaction",
2761
0
                      OGRERR_INVALID_HANDLE);
2762
2763
0
#ifdef OGRAPISPY_ENABLED
2764
0
    if (bOGRAPISpyEnabled)
2765
0
        OGRAPISpy_L_RollbackTransaction(hLayer);
2766
0
#endif
2767
2768
0
    return OGRLayer::FromHandle(hLayer)->RollbackTransaction();
2769
0
}
2770
2771
/************************************************************************/
2772
/*                        OGRLayer::GetLayerDefn()                      */
2773
/************************************************************************/
2774
2775
/**
2776
 \fn OGRFeatureDefn *OGRLayer::GetLayerDefn();
2777
2778
 \brief Fetch the schema information for this layer.
2779
2780
 The returned OGRFeatureDefn is owned by the OGRLayer, and should not be
2781
 modified or freed by the application.  It encapsulates the attribute schema
2782
 of the features of the layer.
2783
2784
 This method is the same as the C function OGR_L_GetLayerDefn().
2785
2786
 @return feature definition.
2787
*/
2788
2789
/**
2790
 \fn const OGRFeatureDefn *OGRLayer::GetLayerDefn() const;
2791
2792
 \brief Fetch the schema information for this layer.
2793
2794
 The returned OGRFeatureDefn is owned by the OGRLayer, and should not be
2795
 modified or freed by the application.  It encapsulates the attribute schema
2796
 of the features of the layer.
2797
2798
 Note that even if this method is const, there is no guarantee it can be
2799
 safely called by concurrent threads on the same GDALDataset object.
2800
2801
 This method is the same as the C function OGR_L_GetLayerDefn().
2802
2803
 @return feature definition.
2804
2805
 @since 3.12
2806
*/
2807
2808
/************************************************************************/
2809
/*                         OGR_L_GetLayerDefn()                         */
2810
/************************************************************************/
2811
2812
/**
2813
 \brief Fetch the schema information for this layer.
2814
2815
 The returned handle to the OGRFeatureDefn is owned by the OGRLayer,
2816
 and should not be modified or freed by the application.  It encapsulates
2817
 the attribute schema of the features of the layer.
2818
2819
 This function is the same as the C++ method OGRLayer::GetLayerDefn().
2820
2821
 @param hLayer handle to the layer to get the schema information.
2822
 @return a handle to the feature definition.
2823
2824
*/
2825
OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
2826
2827
0
{
2828
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
2829
2830
0
#ifdef OGRAPISPY_ENABLED
2831
0
    if (bOGRAPISpyEnabled)
2832
0
        OGRAPISpy_L_GetLayerDefn(hLayer);
2833
0
#endif
2834
2835
0
    return OGRFeatureDefn::ToHandle(
2836
0
        OGRLayer::FromHandle(hLayer)->GetLayerDefn());
2837
0
}
2838
2839
/************************************************************************/
2840
/*                         OGR_L_FindFieldIndex()                       */
2841
/************************************************************************/
2842
2843
/**
2844
 \brief Find the index of field in a layer.
2845
2846
 The returned number is the index of the field in the layers, or -1 if the
2847
 field doesn't exist.
2848
2849
 If bExactMatch is set to FALSE and the field doesn't exists in the given form
2850
 the driver might apply some changes to make it match, like those it might do
2851
 if the layer was created (eg. like LAUNDER in the OCI driver).
2852
2853
 This method is the same as the C++ method OGRLayer::FindFieldIndex().
2854
2855
 @return field index, or -1 if the field doesn't exist
2856
*/
2857
2858
int OGR_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
2859
                         int bExactMatch)
2860
2861
0
{
2862
0
    VALIDATE_POINTER1(hLayer, "OGR_L_FindFieldIndex", -1);
2863
2864
0
#ifdef OGRAPISPY_ENABLED
2865
0
    if (bOGRAPISpyEnabled)
2866
0
        OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
2867
0
#endif
2868
2869
0
    return OGRLayer::FromHandle(hLayer)->FindFieldIndex(pszFieldName,
2870
0
                                                        bExactMatch);
2871
0
}
2872
2873
/************************************************************************/
2874
/*                           FindFieldIndex()                           */
2875
/************************************************************************/
2876
2877
/**
2878
 \brief Find the index of field in the layer.
2879
2880
 The returned number is the index of the field in the layers, or -1 if the
2881
 field doesn't exist.
2882
2883
 If bExactMatch is set to FALSE and the field doesn't exists in the given form
2884
 the driver might apply some changes to make it match, like those it might do
2885
 if the layer was created (eg. like LAUNDER in the OCI driver).
2886
2887
 This method is the same as the C function OGR_L_FindFieldIndex().
2888
2889
 @return field index, or -1 if the field doesn't exist
2890
*/
2891
2892
int OGRLayer::FindFieldIndex(const char *pszFieldName,
2893
                             CPL_UNUSED int bExactMatch)
2894
0
{
2895
0
    return GetLayerDefn()->GetFieldIndex(pszFieldName);
2896
0
}
2897
2898
/************************************************************************/
2899
/*                           GetSpatialRef()                            */
2900
/************************************************************************/
2901
2902
/**
2903
 \brief Fetch the spatial reference system for this layer.
2904
2905
 The returned object is owned by the OGRLayer and should not be modified
2906
 or freed by the application.
2907
2908
 Note that even if this method is const (since GDAL 3.12), there is no guarantee
2909
 it can be safely called by concurrent threads on the same GDALDataset object.
2910
2911
 Several geometry fields can be associated to a
2912
 feature definition. Each geometry field can have its own spatial reference
2913
 system, which is returned by OGRGeomFieldDefn::GetSpatialRef().
2914
 OGRLayer::GetSpatialRef() is equivalent to
2915
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(0)->GetSpatialRef()
2916
2917
 This method is the same as the C function OGR_L_GetSpatialRef().
2918
2919
 @return spatial reference, or NULL if there isn't one.
2920
*/
2921
2922
const OGRSpatialReference *OGRLayer::GetSpatialRef() const
2923
0
{
2924
0
    const auto poLayerDefn = GetLayerDefn();
2925
0
    if (poLayerDefn->GetGeomFieldCount() > 0)
2926
0
        return const_cast<OGRSpatialReference *>(
2927
0
            poLayerDefn->GetGeomFieldDefn(0)->GetSpatialRef());
2928
0
    else
2929
0
        return nullptr;
2930
0
}
2931
2932
/************************************************************************/
2933
/*                        OGR_L_GetSpatialRef()                         */
2934
/************************************************************************/
2935
2936
/**
2937
 \brief Fetch the spatial reference system for this layer.
2938
2939
 The returned object is owned by the OGRLayer and should not be modified
2940
 or freed by the application.
2941
2942
 This function is the same as the C++ method OGRLayer::GetSpatialRef().
2943
2944
 @param hLayer handle to the layer to get the spatial reference from.
2945
 @return spatial reference, or NULL if there isn't one.
2946
*/
2947
2948
OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
2949
2950
0
{
2951
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
2952
2953
0
#ifdef OGRAPISPY_ENABLED
2954
0
    if (bOGRAPISpyEnabled)
2955
0
        OGRAPISpy_L_GetSpatialRef(hLayer);
2956
0
#endif
2957
2958
0
    return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2959
0
        OGRLayer::FromHandle(hLayer)->GetSpatialRef()));
2960
0
}
2961
2962
/************************************************************************/
2963
/*                     OGRLayer::TestCapability()                       */
2964
/************************************************************************/
2965
2966
/**
2967
 \fn int OGRLayer::TestCapability( const char * pszCap ) const;
2968
2969
 \brief Test if this layer supported the named capability.
2970
2971
 The capability codes that can be tested are represented as strings, but
2972
 \#defined constants exists to ensure correct spelling.  Specific layer
2973
 types may implement class specific capabilities, but this can't generally
2974
 be discovered by the caller. <p>
2975
2976
<ul>
2977
2978
 <li> <b>OLCRandomRead</b> / "RandomRead": TRUE if the GetFeature() method
2979
is implemented in an optimized way for this layer, as opposed to the default
2980
implementation using ResetReading() and GetNextFeature() to find the requested
2981
feature id.<p>
2982
2983
 <li> <b>OLCSequentialWrite</b> / "SequentialWrite": TRUE if the
2984
CreateFeature() method works for this layer.  Note this means that this
2985
particular layer is writable.  The same OGRLayer class may return FALSE
2986
for other layer instances that are effectively read-only.<p>
2987
2988
 <li> <b>OLCRandomWrite</b> / "RandomWrite": TRUE if the SetFeature() method
2989
is operational on this layer.  Note this means that this
2990
particular layer is writable.  The same OGRLayer class may return FALSE
2991
for other layer instances that are effectively read-only.<p>
2992
2993
 <li> <b>OLCUpsertFeature</b> / "UpsertFeature": TRUE if the UpsertFeature()
2994
method is operational on this layer.  Note this means that this
2995
particular layer is writable.  The same OGRLayer class may return FALSE
2996
for other layer instances that are effectively read-only.<p>
2997
2998
 <li> <b>OLCFastSpatialFilter</b> / "FastSpatialFilter": TRUE if this layer
2999
implements spatial filtering efficiently.  Layers that effectively read all
3000
features, and test them with the OGRFeature intersection methods should
3001
return FALSE.  This can be used as a clue by the application whether it
3002
should build and maintain its own spatial index for features in this layer.<p>
3003
3004
 <li> <b>OLCFastFeatureCount</b> / "FastFeatureCount":
3005
TRUE if this layer can return a feature
3006
count (via GetFeatureCount()) efficiently. i.e. without counting
3007
the features.  In some cases this will return TRUE until a spatial filter is
3008
installed after which it will return FALSE.<p>
3009
3010
 <li> <b>OLCFastGetExtent</b> / "FastGetExtent":
3011
TRUE if this layer can return its data extent (via GetExtent())
3012
efficiently, i.e. without scanning all the features.  In some cases this
3013
will return TRUE until a spatial filter is installed after which it will
3014
return FALSE.<p>
3015
3016
 <li> <b>OLCFastSetNextByIndex</b> / "FastSetNextByIndex":
3017
TRUE if this layer can perform the SetNextByIndex() call efficiently, otherwise
3018
FALSE.<p>
3019
3020
 <li> <b>OLCCreateField</b> / "CreateField": TRUE if this layer can create
3021
new fields on the current layer using CreateField(), otherwise FALSE.<p>
3022
3023
 <li> <b>OLCCreateGeomField</b> / "CreateGeomField": (GDAL >= 1.11) TRUE if this layer can create
3024
new geometry fields on the current layer using CreateGeomField(), otherwise FALSE.<p>
3025
3026
 <li> <b>OLCDeleteField</b> / "DeleteField": TRUE if this layer can delete
3027
existing fields on the current layer using DeleteField(), otherwise FALSE.<p>
3028
3029
 <li> <b>OLCReorderFields</b> / "ReorderFields": TRUE if this layer can reorder
3030
existing fields on the current layer using ReorderField() or ReorderFields(), otherwise FALSE.<p>
3031
3032
 <li> <b>OLCAlterFieldDefn</b> / "AlterFieldDefn": TRUE if this layer can alter
3033
the definition of an existing field on the current layer using AlterFieldDefn(), otherwise FALSE.<p>
3034
3035
 <li> <b>OLCAlterGeomFieldDefn</b> / "AlterGeomFieldDefn": TRUE if this layer can alter
3036
the definition of an existing geometry field on the current layer using AlterGeomFieldDefn(), otherwise FALSE.<p>
3037
3038
 <li> <b>OLCDeleteFeature</b> / "DeleteFeature": TRUE if the DeleteFeature()
3039
method is supported on this layer, otherwise FALSE.<p>
3040
3041
 <li> <b>OLCStringsAsUTF8</b> / "StringsAsUTF8": TRUE if values of OFTString
3042
fields are assured to be in UTF-8 format.  If FALSE the encoding of fields
3043
is uncertain, though it might still be UTF-8.<p>
3044
3045
<li> <b>OLCTransactions</b> / "Transactions": TRUE if the StartTransaction(),
3046
CommitTransaction() and RollbackTransaction() methods work in a meaningful way,
3047
otherwise FALSE.<p>
3048
3049
<li> <b>OLCIgnoreFields</b> / "IgnoreFields": TRUE if fields, geometry and style
3050
will be omitted when fetching features as set by SetIgnoredFields() method.
3051
3052
<li> <b>OLCCurveGeometries</b> / "CurveGeometries": TRUE if this layer supports
3053
writing curve geometries or may return such geometries.
3054
3055
<p>
3056
3057
</ul>
3058
3059
 This method is the same as the C function OGR_L_TestCapability().
3060
3061
 @param pszCap the name of the capability to test.
3062
3063
 @return TRUE if the layer has the requested capability, or FALSE otherwise.
3064
OGRLayers will return FALSE for any unrecognized capabilities.<p>
3065
3066
*/
3067
3068
/************************************************************************/
3069
/*                        OGR_L_TestCapability()                        */
3070
/************************************************************************/
3071
3072
/**
3073
 \brief Test if this layer supported the named capability.
3074
3075
 The capability codes that can be tested are represented as strings, but
3076
 \#defined constants exists to ensure correct spelling.  Specific layer
3077
 types may implement class specific capabilities, but this can't generally
3078
 be discovered by the caller. <p>
3079
3080
<ul>
3081
3082
 <li> <b>OLCRandomRead</b> / "RandomRead": TRUE if the GetFeature() method
3083
is implemented in an optimized way for this layer, as opposed to the default
3084
implementation using ResetReading() and GetNextFeature() to find the requested
3085
feature id.<p>
3086
3087
 <li> <b>OLCSequentialWrite</b> / "SequentialWrite": TRUE if the
3088
CreateFeature() method works for this layer.  Note this means that this
3089
particular layer is writable.  The same OGRLayer class may return FALSE
3090
for other layer instances that are effectively read-only.<p>
3091
3092
 <li> <b>OLCRandomWrite</b> / "RandomWrite": TRUE if the SetFeature() method
3093
is operational on this layer.  Note this means that this
3094
particular layer is writable.  The same OGRLayer class may return FALSE
3095
for other layer instances that are effectively read-only.<p>
3096
3097
 <li> <b>OLCUpsertFeature</b> / "UpsertFeature": TRUE if the UpsertFeature()
3098
method is operational on this layer.  Note this means that this
3099
particular layer is writable.  The same OGRLayer class may return FALSE
3100
for other layer instances that are effectively read-only.<p>
3101
3102
 <li> <b>OLCFastSpatialFilter</b> / "FastSpatialFilter": TRUE if this layer
3103
implements spatial filtering efficiently.  Layers that effectively read all
3104
features, and test them with the OGRFeature intersection methods should
3105
return FALSE.  This can be used as a clue by the application whether it
3106
should build and maintain its own spatial index for features in this
3107
layer.<p>
3108
3109
 <li> <b>OLCFastFeatureCount</b> / "FastFeatureCount":
3110
TRUE if this layer can return a feature
3111
count (via OGR_L_GetFeatureCount()) efficiently, i.e. without counting
3112
the features.  In some cases this will return TRUE until a spatial filter is
3113
installed after which it will return FALSE.<p>
3114
3115
 <li> <b>OLCFastGetExtent</b> / "FastGetExtent":
3116
TRUE if this layer can return its data extent (via OGR_L_GetExtent())
3117
efficiently, i.e. without scanning all the features.  In some cases this
3118
will return TRUE until a spatial filter is installed after which it will
3119
return FALSE.<p>
3120
3121
 <li> <b>OLCFastSetNextByIndex</b> / "FastSetNextByIndex":
3122
TRUE if this layer can perform the SetNextByIndex() call efficiently, otherwise
3123
FALSE.<p>
3124
3125
 <li> <b>OLCCreateField</b> / "CreateField": TRUE if this layer can create
3126
new fields on the current layer using CreateField(), otherwise FALSE.<p>
3127
3128
 <li> <b>OLCCreateGeomField</b> / "CreateGeomField": (GDAL >= 1.11) TRUE if this layer can create
3129
new geometry fields on the current layer using CreateGeomField(), otherwise FALSE.<p>
3130
3131
 <li> <b>OLCDeleteField</b> / "DeleteField": TRUE if this layer can delete
3132
existing fields on the current layer using DeleteField(), otherwise FALSE.<p>
3133
3134
 <li> <b>OLCReorderFields</b> / "ReorderFields": TRUE if this layer can reorder
3135
existing fields on the current layer using ReorderField() or ReorderFields(), otherwise FALSE.<p>
3136
3137
 <li> <b>OLCAlterFieldDefn</b> / "AlterFieldDefn": TRUE if this layer can alter
3138
the definition of an existing field on the current layer using AlterFieldDefn(), otherwise FALSE.<p>
3139
3140
 <li> <b>OLCAlterGeomFieldDefn</b> / "AlterGeomFieldDefn": TRUE if this layer can alter
3141
the definition of an existing geometry field on the current layer using AlterGeomFieldDefn(), otherwise FALSE.<p>
3142
3143
 <li> <b>OLCDeleteFeature</b> / "DeleteFeature": TRUE if the DeleteFeature()
3144
method is supported on this layer, otherwise FALSE.<p>
3145
3146
 <li> <b>OLCStringsAsUTF8</b> / "StringsAsUTF8": TRUE if values of OFTString
3147
fields are assured to be in UTF-8 format.  If FALSE the encoding of fields
3148
is uncertain, though it might still be UTF-8.<p>
3149
3150
<li> <b>OLCTransactions</b> / "Transactions": TRUE if the StartTransaction(),
3151
CommitTransaction() and RollbackTransaction() methods work in a meaningful way,
3152
otherwise FALSE.<p>
3153
3154
<li> <b>OLCCurveGeometries</b> / "CurveGeometries": TRUE if this layer supports
3155
writing curve geometries or may return such geometries.
3156
3157
<p>
3158
3159
</ul>
3160
3161
 This function is the same as the C++ method OGRLayer::TestCapability().
3162
3163
 @param hLayer handle to the layer to get the capability from.
3164
 @param pszCap the name of the capability to test.
3165
3166
 @return TRUE if the layer has the requested capability, or FALSE otherwise.
3167
OGRLayers will return FALSE for any unrecognized capabilities.<p>
3168
3169
*/
3170
3171
int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
3172
3173
0
{
3174
0
    VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
3175
0
    VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
3176
3177
0
#ifdef OGRAPISPY_ENABLED
3178
0
    if (bOGRAPISpyEnabled)
3179
0
        OGRAPISpy_L_TestCapability(hLayer, pszCap);
3180
0
#endif
3181
3182
0
    return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
3183
0
}
3184
3185
/************************************************************************/
3186
/*                          GetSpatialFilter()                          */
3187
/************************************************************************/
3188
3189
/**
3190
 \brief This method returns the current spatial filter for this layer.
3191
3192
 The returned pointer is to an internally owned object, and should not
3193
 be altered or deleted by the caller.
3194
3195
 This method is the same as the C function OGR_L_GetSpatialFilter().
3196
3197
 @return spatial filter geometry.
3198
 */
3199
3200
OGRGeometry *OGRLayer::GetSpatialFilter()
3201
3202
0
{
3203
0
    return m_poFilterGeom;
3204
0
}
3205
3206
/************************************************************************/
3207
/*                       OGR_L_GetSpatialFilter()                       */
3208
/************************************************************************/
3209
3210
/**
3211
 \brief This function returns the current spatial filter for this layer.
3212
3213
 The returned pointer is to an internally owned object, and should not
3214
 be altered or deleted by the caller.
3215
3216
 This function is the same as the C++ method OGRLayer::GetSpatialFilter().
3217
3218
 @param hLayer handle to the layer to get the spatial filter from.
3219
 @return a handle to the spatial filter geometry.
3220
 */
3221
3222
OGRGeometryH OGR_L_GetSpatialFilter(OGRLayerH hLayer)
3223
3224
0
{
3225
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialFilter", nullptr);
3226
3227
0
#ifdef OGRAPISPY_ENABLED
3228
0
    if (bOGRAPISpyEnabled)
3229
0
        OGRAPISpy_L_GetSpatialFilter(hLayer);
3230
0
#endif
3231
3232
0
    return OGRGeometry::ToHandle(
3233
0
        OGRLayer::FromHandle(hLayer)->GetSpatialFilter());
3234
0
}
3235
3236
/************************************************************************/
3237
/*             ValidateGeometryFieldIndexForSetSpatialFilter()          */
3238
/************************************************************************/
3239
3240
//! @cond Doxygen_Suppress
3241
bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
3242
    int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
3243
0
{
3244
0
    if (iGeomField == 0 && poGeomIn == nullptr &&
3245
0
        GetLayerDefn()->GetGeomFieldCount() == 0)
3246
0
    {
3247
        // Setting a null spatial filter on geometry field idx 0
3248
        // when there are no geometry field can't harm, and is accepted silently
3249
        // for backward compatibility with existing practice.
3250
0
    }
3251
0
    else if (iGeomField < 0 ||
3252
0
             iGeomField >= GetLayerDefn()->GetGeomFieldCount())
3253
0
    {
3254
0
        if (iGeomField == 0)
3255
0
        {
3256
0
            CPLError(
3257
0
                CE_Failure, CPLE_AppDefined,
3258
0
                bIsSelectLayer
3259
0
                    ? "Cannot set spatial filter: no geometry field selected."
3260
0
                    : "Cannot set spatial filter: no geometry field present in "
3261
0
                      "layer.");
3262
0
        }
3263
0
        else
3264
0
        {
3265
0
            CPLError(CE_Failure, CPLE_AppDefined,
3266
0
                     "Cannot set spatial filter on non-existing geometry field "
3267
0
                     "of index %d.",
3268
0
                     iGeomField);
3269
0
        }
3270
0
        return false;
3271
0
    }
3272
0
    return true;
3273
0
}
3274
3275
//! @endcond
3276
3277
/************************************************************************/
3278
/*                          SetSpatialFilter()                          */
3279
/************************************************************************/
3280
3281
/**
3282
 \brief Set a new spatial filter.
3283
3284
 This method set the geometry to be used as a spatial filter when
3285
 fetching features via the GetNextFeature() method.  Only features that
3286
 geometrically intersect the filter geometry will be returned.
3287
3288
 Currently this test is may be inaccurately implemented, but it is
3289
 guaranteed that all features whose envelope (as returned by
3290
 OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
3291
 will be returned.  This can result in more shapes being returned that
3292
 should strictly be the case.
3293
3294
 Features with null or empty geometries will never
3295
 be considered as matching a spatial filter.
3296
3297
 This method makes an internal copy of the passed geometry.  The
3298
 passed geometry remains the responsibility of the caller, and may
3299
 be safely destroyed.
3300
3301
 For the time being the passed filter geometry should be in the same
3302
 SRS as the layer (as returned by OGRLayer::GetSpatialRef()).  In the
3303
 future this may be generalized.
3304
3305
 This method is the same as the C function OGR_L_SetSpatialFilter().
3306
3307
 @param poFilter the geometry to use as a filtering region.  NULL may
3308
 be passed indicating that the current spatial filter should be cleared,
3309
 but no new one instituted.
3310
 */
3311
3312
OGRErr OGRLayer::SetSpatialFilter(const OGRGeometry *poFilter)
3313
3314
0
{
3315
0
    return SetSpatialFilter(0, poFilter);
3316
0
}
3317
3318
/**
3319
 \brief Set a new spatial filter.
3320
3321
 This method set the geometry to be used as a spatial filter when
3322
 fetching features via the GetNextFeature() method.  Only features that
3323
 geometrically intersect the filter geometry will be returned.
3324
3325
 Currently this test is may be inaccurately implemented, but it is
3326
 guaranteed that all features who's envelope (as returned by
3327
 OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
3328
 will be returned.  This can result in more shapes being returned that
3329
 should strictly be the case.
3330
3331
 This method makes an internal copy of the passed geometry.  The
3332
 passed geometry remains the responsibility of the caller, and may
3333
 be safely destroyed.
3334
3335
 For the time being the passed filter geometry should be in the same
3336
 SRS as the geometry field definition it corresponds to (as returned by
3337
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
3338
 future this may be generalized.
3339
3340
 Note that only the last spatial filter set is applied, even if several
3341
 successive calls are done with different iGeomField values.
3342
3343
 This method is the same as the C function OGR_L_SetSpatialFilterEx().
3344
3345
 @param iGeomField index of the geometry field on which the spatial filter
3346
 operates.
3347
 @param poFilter the geometry to use as a filtering region.  NULL may
3348
 be passed indicating that the current spatial filter should be cleared,
3349
 but no new one instituted.
3350
 */
3351
3352
OGRErr OGRLayer::SetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
3353
3354
0
{
3355
0
    if (iGeomField == 0)
3356
0
    {
3357
0
        if (poFilter &&
3358
0
            !ValidateGeometryFieldIndexForSetSpatialFilter(0, poFilter))
3359
0
        {
3360
0
            return OGRERR_FAILURE;
3361
0
        }
3362
0
    }
3363
0
    else
3364
0
    {
3365
0
        if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField,
3366
0
                                                           poFilter))
3367
0
        {
3368
0
            return OGRERR_FAILURE;
3369
0
        }
3370
0
    }
3371
3372
0
    return ISetSpatialFilter(iGeomField, poFilter);
3373
0
}
3374
3375
/************************************************************************/
3376
/*                         ISetSpatialFilter()                          */
3377
/************************************************************************/
3378
3379
/**
3380
 \brief Set a new spatial filter.
3381
3382
 Virtual method implemented by drivers since 3.11. In previous versions,
3383
 SetSpatialFilter() / SetSpatialFilterRect() itself was the virtual method.
3384
3385
 Driver implementations, when wanting to call the base method, must take
3386
 care of calling OGRLayer::ISetSpatialFilter() (and note the public method without
3387
 the leading I).
3388
3389
 @param iGeomField index of the geometry field on which the spatial filter
3390
 operates.
3391
 @param poFilter the geometry to use as a filtering region.  NULL may
3392
 be passed indicating that the current spatial filter should be cleared,
3393
 but no new one instituted.
3394
3395
 @since GDAL 3.11
3396
 */
3397
3398
OGRErr OGRLayer::ISetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
3399
3400
0
{
3401
0
    m_iGeomFieldFilter = iGeomField;
3402
0
    if (InstallFilter(poFilter))
3403
0
        ResetReading();
3404
0
    return OGRERR_NONE;
3405
0
}
3406
3407
/************************************************************************/
3408
/*                       OGR_L_SetSpatialFilter()                       */
3409
/************************************************************************/
3410
3411
/**
3412
 \brief Set a new spatial filter.
3413
3414
 This function set the geometry to be used as a spatial filter when
3415
 fetching features via the OGR_L_GetNextFeature() function.  Only
3416
 features that geometrically intersect the filter geometry will be
3417
 returned.
3418
3419
 Currently this test is may be inaccurately implemented, but it is
3420
 guaranteed that all features whose envelope (as returned by
3421
 OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
3422
 will be returned.  This can result in more shapes being returned that
3423
 should strictly be the case.
3424
3425
 Features with null or empty geometries will never
3426
 be considered as matching a spatial filter.
3427
3428
 This function makes an internal copy of the passed geometry.  The
3429
 passed geometry remains the responsibility of the caller, and may
3430
 be safely destroyed.
3431
3432
 For the time being the passed filter geometry should be in the same
3433
 SRS as the layer (as returned by OGR_L_GetSpatialRef()).  In the
3434
 future this may be generalized.
3435
3436
 This function is the same as the C++ method OGRLayer::SetSpatialFilter.
3437
3438
 @param hLayer handle to the layer on which to set the spatial filter.
3439
 @param hGeom handle to the geometry to use as a filtering region.  NULL may
3440
 be passed indicating that the current spatial filter should be cleared,
3441
 but no new one instituted.
3442
3443
 */
3444
3445
void OGR_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
3446
3447
0
{
3448
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilter");
3449
3450
0
#ifdef OGRAPISPY_ENABLED
3451
0
    if (bOGRAPISpyEnabled)
3452
0
        OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
3453
0
#endif
3454
3455
0
    OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
3456
0
        OGRGeometry::FromHandle(hGeom));
3457
0
}
3458
3459
/************************************************************************/
3460
/*                      OGR_L_SetSpatialFilterEx()                      */
3461
/************************************************************************/
3462
3463
/**
3464
 \brief Set a new spatial filter.
3465
3466
 This function set the geometry to be used as a spatial filter when
3467
 fetching features via the OGR_L_GetNextFeature() function.  Only
3468
 features that geometrically intersect the filter geometry will be
3469
 returned.
3470
3471
 Currently this test is may be inaccurately implemented, but it is
3472
 guaranteed that all features who's envelope (as returned by
3473
 OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
3474
 will be returned.  This can result in more shapes being returned that
3475
 should strictly be the case.
3476
3477
 This function makes an internal copy of the passed geometry.  The
3478
 passed geometry remains the responsibility of the caller, and may
3479
 be safely destroyed.
3480
3481
 For the time being the passed filter geometry should be in the same
3482
 SRS as the geometry field definition it corresponds to (as returned by
3483
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
3484
 future this may be generalized.
3485
3486
 Note that only the last spatial filter set is applied, even if several
3487
 successive calls are done with different iGeomField values.
3488
3489
 This function is the same as the C++ method OGRLayer::SetSpatialFilter.
3490
3491
 @param hLayer handle to the layer on which to set the spatial filter.
3492
 @param iGeomField index of the geometry field on which the spatial filter
3493
 operates.
3494
 @param hGeom handle to the geometry to use as a filtering region.  NULL may
3495
 be passed indicating that the current spatial filter should be cleared,
3496
 but no new one instituted.
3497
3498
 */
3499
3500
void OGR_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
3501
                              OGRGeometryH hGeom)
3502
3503
0
{
3504
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterEx");
3505
3506
0
#ifdef OGRAPISPY_ENABLED
3507
0
    if (bOGRAPISpyEnabled)
3508
0
        OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
3509
0
#endif
3510
3511
0
    OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
3512
0
        iGeomField, OGRGeometry::FromHandle(hGeom));
3513
0
}
3514
3515
/************************************************************************/
3516
/*                        SetSpatialFilterRect()                        */
3517
/************************************************************************/
3518
3519
/**
3520
 \brief Set a new rectangular spatial filter.
3521
3522
 This method set rectangle to be used as a spatial filter when
3523
 fetching features via the GetNextFeature() method.  Only features that
3524
 geometrically intersect the given rectangle will be returned.
3525
3526
 The x/y values should be in the same coordinate system as the layer as
3527
 a whole (as returned by OGRLayer::GetSpatialRef()).   Internally this
3528
 method is normally implemented as creating a 5 vertex closed rectangular
3529
 polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
3530
 a convenience.
3531
3532
 The only way to clear a spatial filter set with this method is to
3533
 call OGRLayer::SetSpatialFilter(NULL).
3534
3535
 This method is the same as the C function OGR_L_SetSpatialFilterRect().
3536
3537
 @param dfMinX the minimum X coordinate for the rectangular region.
3538
 @param dfMinY the minimum Y coordinate for the rectangular region.
3539
 @param dfMaxX the maximum X coordinate for the rectangular region.
3540
 @param dfMaxY the maximum Y coordinate for the rectangular region.
3541
3542
 */
3543
3544
OGRErr OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY,
3545
                                      double dfMaxX, double dfMaxY)
3546
3547
0
{
3548
0
    return SetSpatialFilterRect(0, dfMinX, dfMinY, dfMaxX, dfMaxY);
3549
0
}
3550
3551
/**
3552
 \brief Set a new rectangular spatial filter.
3553
3554
 This method set rectangle to be used as a spatial filter when
3555
 fetching features via the GetNextFeature() method.  Only features that
3556
 geometrically intersect the given rectangle will be returned.
3557
3558
 The x/y values should be in the same coordinate system as as the geometry
3559
 field definition it corresponds to (as returned by
3560
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
3561
 method is normally implemented as creating a 5 vertex closed rectangular
3562
 polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
3563
 a convenience.
3564
3565
 The only way to clear a spatial filter set with this method is to
3566
 call OGRLayer::SetSpatialFilter(NULL).
3567
3568
 This method is the same as the C function OGR_L_SetSpatialFilterRectEx().
3569
3570
 @param iGeomField index of the geometry field on which the spatial filter
3571
 operates.
3572
 @param dfMinX the minimum X coordinate for the rectangular region.
3573
 @param dfMinY the minimum Y coordinate for the rectangular region.
3574
 @param dfMaxX the maximum X coordinate for the rectangular region.
3575
 @param dfMaxY the maximum Y coordinate for the rectangular region.
3576
 */
3577
3578
OGRErr OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
3579
                                      double dfMinY, double dfMaxX,
3580
                                      double dfMaxY)
3581
3582
0
{
3583
0
    auto poRing = std::make_unique<OGRLinearRing>();
3584
0
    OGRPolygon oPoly;
3585
3586
0
    poRing->addPoint(dfMinX, dfMinY);
3587
0
    poRing->addPoint(dfMinX, dfMaxY);
3588
0
    poRing->addPoint(dfMaxX, dfMaxY);
3589
0
    poRing->addPoint(dfMaxX, dfMinY);
3590
0
    poRing->addPoint(dfMinX, dfMinY);
3591
3592
0
    oPoly.addRing(std::move(poRing));
3593
3594
0
    return SetSpatialFilter(iGeomField, &oPoly);
3595
0
}
3596
3597
/************************************************************************/
3598
/*                     OGR_L_SetSpatialFilterRect()                     */
3599
/************************************************************************/
3600
3601
/**
3602
 \brief Set a new rectangular spatial filter.
3603
3604
 This method set rectangle to be used as a spatial filter when
3605
 fetching features via the OGR_L_GetNextFeature() method.  Only features that
3606
 geometrically intersect the given rectangle will be returned.
3607
3608
 The x/y values should be in the same coordinate system as the layer as
3609
 a whole (as returned by OGRLayer::GetSpatialRef()).   Internally this
3610
 method is normally implemented as creating a 5 vertex closed rectangular
3611
 polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
3612
 a convenience.
3613
3614
 The only way to clear a spatial filter set with this method is to
3615
 call OGRLayer::SetSpatialFilter(NULL).
3616
3617
 This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
3618
3619
 @param hLayer handle to the layer on which to set the spatial filter.
3620
 @param dfMinX the minimum X coordinate for the rectangular region.
3621
 @param dfMinY the minimum Y coordinate for the rectangular region.
3622
 @param dfMaxX the maximum X coordinate for the rectangular region.
3623
 @param dfMaxY the maximum Y coordinate for the rectangular region.
3624
3625
 */
3626
3627
void OGR_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX, double dfMinY,
3628
                                double dfMaxX, double dfMaxY)
3629
3630
0
{
3631
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRect");
3632
3633
0
#ifdef OGRAPISPY_ENABLED
3634
0
    if (bOGRAPISpyEnabled)
3635
0
        OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX,
3636
0
                                         dfMaxY);
3637
0
#endif
3638
3639
0
    OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX,
3640
0
                                                       dfMaxY);
3641
0
}
3642
3643
/************************************************************************/
3644
/*                    OGR_L_SetSpatialFilterRectEx()                    */
3645
/************************************************************************/
3646
3647
/**
3648
 \brief Set a new rectangular spatial filter.
3649
3650
 This method set rectangle to be used as a spatial filter when
3651
 fetching features via the OGR_L_GetNextFeature() method.  Only features that
3652
 geometrically intersect the given rectangle will be returned.
3653
3654
 The x/y values should be in the same coordinate system as as the geometry
3655
 field definition it corresponds to (as returned by
3656
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
3657
 method is normally implemented as creating a 5 vertex closed rectangular
3658
 polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
3659
 a convenience.
3660
3661
 The only way to clear a spatial filter set with this method is to
3662
 call OGRLayer::SetSpatialFilter(NULL).
3663
3664
 This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
3665
3666
 @param hLayer handle to the layer on which to set the spatial filter.
3667
 @param iGeomField index of the geometry field on which the spatial filter
3668
 operates.
3669
 @param dfMinX the minimum X coordinate for the rectangular region.
3670
 @param dfMinY the minimum Y coordinate for the rectangular region.
3671
 @param dfMaxX the maximum X coordinate for the rectangular region.
3672
 @param dfMaxY the maximum Y coordinate for the rectangular region.
3673
*/
3674
3675
void OGR_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
3676
                                  double dfMinX, double dfMinY, double dfMaxX,
3677
                                  double dfMaxY)
3678
3679
0
{
3680
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRectEx");
3681
3682
0
#ifdef OGRAPISPY_ENABLED
3683
0
    if (bOGRAPISpyEnabled)
3684
0
        OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY,
3685
0
                                           dfMaxX, dfMaxY);
3686
0
#endif
3687
3688
0
    OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(iGeomField, dfMinX,
3689
0
                                                       dfMinY, dfMaxX, dfMaxY);
3690
0
}
3691
3692
/************************************************************************/
3693
/*                           InstallFilter()                            */
3694
/*                                                                      */
3695
/*      This method is only intended to be used from within             */
3696
/*      drivers, normally from the SetSpatialFilter() method.           */
3697
/*      It installs a filter, and also tests it to see if it is         */
3698
/*      rectangular.  If so, it this is kept track of alongside the     */
3699
/*      filter geometry itself so we can do cheaper comparisons in      */
3700
/*      the FilterGeometry() call.                                      */
3701
/*                                                                      */
3702
/*      Returns TRUE if the newly installed filter differs in some      */
3703
/*      way from the current one.                                       */
3704
/************************************************************************/
3705
3706
//! @cond Doxygen_Suppress
3707
int OGRLayer::InstallFilter(const OGRGeometry *poFilter)
3708
3709
0
{
3710
0
    if (m_poFilterGeom == poFilter)
3711
0
        return FALSE;
3712
3713
    /* -------------------------------------------------------------------- */
3714
    /*      Replace the existing filter.                                    */
3715
    /* -------------------------------------------------------------------- */
3716
0
    if (m_poFilterGeom != nullptr)
3717
0
    {
3718
0
        delete m_poFilterGeom;
3719
0
        m_poFilterGeom = nullptr;
3720
0
    }
3721
3722
0
    if (m_pPreparedFilterGeom != nullptr)
3723
0
    {
3724
0
        OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
3725
0
        m_pPreparedFilterGeom = nullptr;
3726
0
    }
3727
3728
0
    if (poFilter != nullptr)
3729
0
        m_poFilterGeom = poFilter->clone();
3730
3731
0
    m_bFilterIsEnvelope = FALSE;
3732
3733
0
    if (m_poFilterGeom == nullptr)
3734
0
        return TRUE;
3735
3736
0
    m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
3737
3738
    /* Compile geometry filter as a prepared geometry */
3739
0
    m_pPreparedFilterGeom =
3740
0
        OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
3741
3742
0
    m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
3743
3744
0
    return TRUE;
3745
0
}
3746
3747
//! @endcond
3748
3749
/************************************************************************/
3750
/*                   DoesGeometryHavePointInEnvelope()                  */
3751
/************************************************************************/
3752
3753
static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
3754
                                            const OGREnvelope &sEnvelope)
3755
0
{
3756
0
    const OGRLineString *poLS = nullptr;
3757
3758
0
    switch (wkbFlatten(poGeometry->getGeometryType()))
3759
0
    {
3760
0
        case wkbPoint:
3761
0
        {
3762
0
            const auto poPoint = poGeometry->toPoint();
3763
0
            const double x = poPoint->getX();
3764
0
            const double y = poPoint->getY();
3765
0
            return (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
3766
0
                    x <= sEnvelope.MaxX && y <= sEnvelope.MaxY);
3767
0
        }
3768
3769
0
        case wkbLineString:
3770
0
            poLS = poGeometry->toLineString();
3771
0
            break;
3772
3773
0
        case wkbPolygon:
3774
0
        {
3775
0
            const OGRPolygon *poPoly = poGeometry->toPolygon();
3776
0
            poLS = poPoly->getExteriorRing();
3777
0
            break;
3778
0
        }
3779
3780
0
        case wkbMultiPoint:
3781
0
        case wkbMultiLineString:
3782
0
        case wkbMultiPolygon:
3783
0
        case wkbGeometryCollection:
3784
0
        {
3785
0
            for (const auto &poSubGeom : *(poGeometry->toGeometryCollection()))
3786
0
            {
3787
0
                if (DoesGeometryHavePointInEnvelope(poSubGeom, sEnvelope))
3788
0
                    return true;
3789
0
            }
3790
0
            return false;
3791
0
        }
3792
3793
0
        default:
3794
0
            return false;
3795
0
    }
3796
3797
0
    if (poLS != nullptr)
3798
0
    {
3799
0
        const int nNumPoints = poLS->getNumPoints();
3800
0
        for (int i = 0; i < nNumPoints; i++)
3801
0
        {
3802
0
            const double x = poLS->getX(i);
3803
0
            const double y = poLS->getY(i);
3804
0
            if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
3805
0
                x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
3806
0
            {
3807
0
                return true;
3808
0
            }
3809
0
        }
3810
0
    }
3811
3812
0
    return false;
3813
0
}
3814
3815
/************************************************************************/
3816
/*                           FilterGeometry()                           */
3817
/*                                                                      */
3818
/*      Compare the passed in geometry to the currently installed       */
3819
/*      filter.  Optimize for case where filter is just an              */
3820
/*      envelope.                                                       */
3821
/************************************************************************/
3822
3823
//! @cond Doxygen_Suppress
3824
int OGRLayer::FilterGeometry(const OGRGeometry *poGeometry)
3825
3826
0
{
3827
    /* -------------------------------------------------------------------- */
3828
    /*      In trivial cases of new filter or target geometry, we accept    */
3829
    /*      an intersection.  No geometry is taken to mean "the whole       */
3830
    /*      world".                                                         */
3831
    /* -------------------------------------------------------------------- */
3832
0
    if (m_poFilterGeom == nullptr)
3833
0
        return TRUE;
3834
3835
0
    if (poGeometry == nullptr || poGeometry->IsEmpty())
3836
0
        return FALSE;
3837
3838
    /* -------------------------------------------------------------------- */
3839
    /*      Compute the target geometry envelope, and if there is no        */
3840
    /*      intersection between the envelopes we are sure not to have      */
3841
    /*      any intersection.                                               */
3842
    /* -------------------------------------------------------------------- */
3843
0
    OGREnvelope sGeomEnv;
3844
3845
0
    poGeometry->getEnvelope(&sGeomEnv);
3846
3847
0
    if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
3848
0
        sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
3849
0
        m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
3850
0
        m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
3851
0
        return FALSE;
3852
3853
    /* -------------------------------------------------------------------- */
3854
    /*      If the filter geometry is its own envelope and if the           */
3855
    /*      envelope of the geometry is inside the filter geometry,         */
3856
    /*      the geometry itself is inside the filter geometry               */
3857
    /* -------------------------------------------------------------------- */
3858
0
    if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
3859
0
        sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
3860
0
        sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
3861
0
        sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
3862
0
    {
3863
0
        return TRUE;
3864
0
    }
3865
0
    else
3866
0
    {
3867
        // If the filter geometry is its own envelope and if the geometry has
3868
        // at least one point inside the filter geometry, the geometry itself
3869
        // intersects the filter geometry.
3870
0
        if (m_bFilterIsEnvelope)
3871
0
        {
3872
0
            if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
3873
0
                return true;
3874
0
        }
3875
3876
        /* --------------------------------------------------------------------
3877
         */
3878
        /*      Fallback to full intersect test (using GEOS) if we still */
3879
        /*      don't know for sure. */
3880
        /* --------------------------------------------------------------------
3881
         */
3882
0
        if (OGRGeometryFactory::haveGEOS())
3883
0
        {
3884
            // CPLDebug("OGRLayer", "GEOS intersection");
3885
0
            if (m_pPreparedFilterGeom != nullptr)
3886
0
                return OGRPreparedGeometryIntersects(
3887
0
                    m_pPreparedFilterGeom,
3888
0
                    OGRGeometry::ToHandle(
3889
0
                        const_cast<OGRGeometry *>(poGeometry)));
3890
0
            else
3891
0
                return m_poFilterGeom->Intersects(poGeometry);
3892
0
        }
3893
0
        else
3894
0
            return TRUE;
3895
0
    }
3896
0
}
3897
3898
/************************************************************************/
3899
/*                         FilterWKBGeometry()                          */
3900
/************************************************************************/
3901
3902
bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
3903
                                 bool bEnvelopeAlreadySet,
3904
                                 OGREnvelope &sEnvelope) const
3905
0
{
3906
0
    OGRPreparedGeometry *pPreparedFilterGeom = m_pPreparedFilterGeom;
3907
0
    bool bRet = FilterWKBGeometry(
3908
0
        pabyWKB, nWKBSize, bEnvelopeAlreadySet, sEnvelope, m_poFilterGeom,
3909
0
        m_bFilterIsEnvelope, m_sFilterEnvelope, pPreparedFilterGeom);
3910
0
    const_cast<OGRLayer *>(this)->m_pPreparedFilterGeom = pPreparedFilterGeom;
3911
0
    return bRet;
3912
0
}
3913
3914
/* static */
3915
bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
3916
                                 bool bEnvelopeAlreadySet,
3917
                                 OGREnvelope &sEnvelope,
3918
                                 const OGRGeometry *poFilterGeom,
3919
                                 bool bFilterIsEnvelope,
3920
                                 const OGREnvelope &sFilterEnvelope,
3921
                                 OGRPreparedGeometry *&pPreparedFilterGeom)
3922
0
{
3923
0
    if (!poFilterGeom)
3924
0
        return true;
3925
3926
0
    if ((bEnvelopeAlreadySet ||
3927
0
         OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
3928
0
        sFilterEnvelope.Intersects(sEnvelope))
3929
0
    {
3930
0
        if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
3931
0
        {
3932
0
            return true;
3933
0
        }
3934
0
        else
3935
0
        {
3936
0
            if (bFilterIsEnvelope &&
3937
0
                OGRWKBIntersectsPessimistic(pabyWKB, nWKBSize, sFilterEnvelope))
3938
0
            {
3939
0
                return true;
3940
0
            }
3941
0
            else if (OGRGeometryFactory::haveGEOS())
3942
0
            {
3943
0
                OGRGeometry *poGeom = nullptr;
3944
0
                int ret = FALSE;
3945
0
                if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
3946
0
                                                      nWKBSize) == OGRERR_NONE)
3947
0
                {
3948
0
                    if (!pPreparedFilterGeom)
3949
0
                    {
3950
0
                        pPreparedFilterGeom =
3951
0
                            OGRCreatePreparedGeometry(OGRGeometry::ToHandle(
3952
0
                                const_cast<OGRGeometry *>(poFilterGeom)));
3953
0
                    }
3954
0
                    if (pPreparedFilterGeom)
3955
0
                        ret = OGRPreparedGeometryIntersects(
3956
0
                            pPreparedFilterGeom,
3957
0
                            OGRGeometry::ToHandle(
3958
0
                                const_cast<OGRGeometry *>(poGeom)));
3959
0
                    else
3960
0
                        ret = poFilterGeom->Intersects(poGeom);
3961
0
                }
3962
0
                delete poGeom;
3963
0
                return CPL_TO_BOOL(ret);
3964
0
            }
3965
0
            else
3966
0
            {
3967
                // Assume intersection
3968
0
                return true;
3969
0
            }
3970
0
        }
3971
0
    }
3972
3973
0
    return false;
3974
0
}
3975
3976
/************************************************************************/
3977
/*                          PrepareStartTransaction()                   */
3978
/************************************************************************/
3979
3980
void OGRLayer::PrepareStartTransaction()
3981
0
{
3982
0
    m_apoFieldDefnChanges.clear();
3983
0
    m_apoGeomFieldDefnChanges.clear();
3984
0
}
3985
3986
/************************************************************************/
3987
/*                          FinishRollbackTransaction()                 */
3988
/************************************************************************/
3989
3990
void OGRLayer::FinishRollbackTransaction(const std::string &osSavepointName)
3991
0
{
3992
3993
    // Deleted fields can be safely removed from the storage after being restored.
3994
0
    std::vector<int> toBeRemoved;
3995
3996
0
    bool bSavepointFound = false;
3997
3998
    // Loop through all changed fields and reset them to their previous state.
3999
0
    for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
4000
0
         i--)
4001
0
    {
4002
0
        auto &oFieldChange = m_apoFieldDefnChanges[i];
4003
4004
0
        if (!osSavepointName.empty())
4005
0
        {
4006
0
            if (oFieldChange.osSavepointName == osSavepointName)
4007
0
            {
4008
0
                bSavepointFound = true;
4009
0
            }
4010
0
            else if (bSavepointFound)
4011
0
            {
4012
0
                continue;
4013
0
            }
4014
0
        }
4015
4016
0
        CPLAssert(oFieldChange.poFieldDefn);
4017
0
        const char *pszName = oFieldChange.poFieldDefn->GetNameRef();
4018
0
        const int iField = oFieldChange.iField;
4019
0
        if (iField >= 0)
4020
0
        {
4021
0
            switch (oFieldChange.eChangeType)
4022
0
            {
4023
0
                case FieldChangeType::DELETE_FIELD:
4024
0
                {
4025
                    // Transfer ownership of the field to the layer
4026
0
                    whileUnsealing(GetLayerDefn())
4027
0
                        ->AddFieldDefn(std::move(oFieldChange.poFieldDefn));
4028
4029
                    // Now move the field to the right place
4030
                    // from the last position to its original position
4031
0
                    const int iFieldCount = GetLayerDefn()->GetFieldCount();
4032
0
                    CPLAssert(iFieldCount > 0);
4033
0
                    CPLAssert(iFieldCount > iField);
4034
0
                    std::vector<int> anOrder(iFieldCount);
4035
0
                    for (int j = 0; j < iField; j++)
4036
0
                    {
4037
0
                        anOrder[j] = j;
4038
0
                    }
4039
0
                    for (int j = iField + 1; j < iFieldCount; j++)
4040
0
                    {
4041
0
                        anOrder[j] = j - 1;
4042
0
                    }
4043
0
                    anOrder[iField] = iFieldCount - 1;
4044
0
                    if (OGRERR_NONE == whileUnsealing(GetLayerDefn())
4045
0
                                           ->ReorderFieldDefns(anOrder.data()))
4046
0
                    {
4047
0
                        toBeRemoved.push_back(i);
4048
0
                    }
4049
0
                    else
4050
0
                    {
4051
0
                        CPLError(CE_Failure, CPLE_AppDefined,
4052
0
                                 "Failed to restore deleted field %s", pszName);
4053
0
                    }
4054
0
                    break;
4055
0
                }
4056
0
                case FieldChangeType::ALTER_FIELD:
4057
0
                {
4058
0
                    OGRFieldDefn *poFieldDefn =
4059
0
                        GetLayerDefn()->GetFieldDefn(iField);
4060
0
                    if (poFieldDefn)
4061
0
                    {
4062
0
                        *poFieldDefn = *oFieldChange.poFieldDefn;
4063
0
                        toBeRemoved.push_back(i);
4064
0
                    }
4065
0
                    else
4066
0
                    {
4067
0
                        CPLError(CE_Failure, CPLE_AppDefined,
4068
0
                                 "Failed to restore altered field %s", pszName);
4069
0
                    }
4070
0
                    break;
4071
0
                }
4072
0
                case FieldChangeType::ADD_FIELD:
4073
0
                {
4074
0
                    std::unique_ptr<OGRFieldDefn> poFieldDef =
4075
0
                        GetLayerDefn()->StealFieldDefn(iField);
4076
0
                    if (poFieldDef)
4077
0
                    {
4078
0
                        oFieldChange.poFieldDefn = std::move(poFieldDef);
4079
0
                    }
4080
0
                    else
4081
0
                    {
4082
0
                        CPLError(CE_Failure, CPLE_AppDefined,
4083
0
                                 "Failed to delete added field %s", pszName);
4084
0
                    }
4085
0
                    break;
4086
0
                }
4087
0
            }
4088
0
        }
4089
0
        else
4090
0
        {
4091
0
            CPLError(CE_Failure, CPLE_AppDefined,
4092
0
                     "Failed to restore field %s (field not found at index %d)",
4093
0
                     pszName, iField);
4094
0
        }
4095
0
    }
4096
4097
    // Remove from the storage the deleted fields that have been restored
4098
0
    for (const auto &i : toBeRemoved)
4099
0
    {
4100
0
        m_apoFieldDefnChanges.erase(m_apoFieldDefnChanges.begin() + i);
4101
0
    }
4102
4103
    /**********************************************************************/
4104
    /* Reset geometry fields to their previous state.                    */
4105
    /**********************************************************************/
4106
4107
0
    bSavepointFound = false;
4108
4109
    // Loop through all changed geometry fields and reset them to their previous state.
4110
0
    for (int i = static_cast<int>(m_apoGeomFieldDefnChanges.size()) - 1; i >= 0;
4111
0
         i--)
4112
0
    {
4113
0
        auto &oGeomFieldChange = m_apoGeomFieldDefnChanges[i];
4114
4115
0
        if (!osSavepointName.empty())
4116
0
        {
4117
0
            if (oGeomFieldChange.osSavepointName == osSavepointName)
4118
0
            {
4119
0
                bSavepointFound = true;
4120
0
            }
4121
0
            else if (bSavepointFound)
4122
0
            {
4123
0
                continue;
4124
0
            }
4125
0
        }
4126
0
        const char *pszName = oGeomFieldChange.poFieldDefn->GetNameRef();
4127
0
        const int iGeomField = oGeomFieldChange.iField;
4128
0
        if (iGeomField >= 0)
4129
0
        {
4130
0
            switch (oGeomFieldChange.eChangeType)
4131
0
            {
4132
0
                case FieldChangeType::DELETE_FIELD:
4133
0
                case FieldChangeType::ALTER_FIELD:
4134
0
                {
4135
                    // Currently not handled by OGR for geometry fields
4136
0
                    break;
4137
0
                }
4138
0
                case FieldChangeType::ADD_FIELD:
4139
0
                {
4140
0
                    std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDef =
4141
0
                        GetLayerDefn()->StealGeomFieldDefn(
4142
0
                            oGeomFieldChange.iField);
4143
0
                    if (poGeomFieldDef)
4144
0
                    {
4145
0
                        oGeomFieldChange.poFieldDefn =
4146
0
                            std::move(poGeomFieldDef);
4147
0
                    }
4148
0
                    else
4149
0
                    {
4150
0
                        CPLError(CE_Failure, CPLE_AppDefined,
4151
0
                                 "Failed to delete added geometry field %s",
4152
0
                                 pszName);
4153
0
                    }
4154
0
                    break;
4155
0
                }
4156
0
            }
4157
0
        }
4158
0
        else
4159
0
        {
4160
0
            CPLError(CE_Failure, CPLE_AppDefined,
4161
0
                     "Failed to restore geometry field %s (field not found at "
4162
0
                     "index %d)",
4163
0
                     pszName, oGeomFieldChange.iField);
4164
0
        }
4165
0
    }
4166
0
}
4167
4168
//! @endcond
4169
4170
/************************************************************************/
4171
/*                    OGRLayer::ResetReading()                          */
4172
/************************************************************************/
4173
4174
/**
4175
 \fn void OGRLayer::ResetReading();
4176
4177
 \brief Reset feature reading to start on the first feature.
4178
4179
 This affects GetNextFeature() and GetArrowStream().
4180
4181
 This method is the same as the C function OGR_L_ResetReading().
4182
*/
4183
4184
/************************************************************************/
4185
/*                         OGR_L_ResetReading()                         */
4186
/************************************************************************/
4187
4188
/**
4189
 \brief Reset feature reading to start on the first feature.
4190
4191
 This affects GetNextFeature() and GetArrowStream().
4192
4193
 This function is the same as the C++ method OGRLayer::ResetReading().
4194
4195
 @param hLayer handle to the layer on which features are read.
4196
*/
4197
4198
void OGR_L_ResetReading(OGRLayerH hLayer)
4199
4200
0
{
4201
0
    VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
4202
4203
0
#ifdef OGRAPISPY_ENABLED
4204
0
    if (bOGRAPISpyEnabled)
4205
0
        OGRAPISpy_L_ResetReading(hLayer);
4206
0
#endif
4207
4208
0
    OGRLayer::FromHandle(hLayer)->ResetReading();
4209
0
}
4210
4211
/************************************************************************/
4212
/*                       InitializeIndexSupport()                       */
4213
/*                                                                      */
4214
/*      This is only intended to be called by driver layer              */
4215
/*      implementations but we don't make it protected so that the      */
4216
/*      datasources can do it too if that is more appropriate.          */
4217
/************************************************************************/
4218
4219
//! @cond Doxygen_Suppress
4220
OGRErr
4221
OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
4222
4223
0
{
4224
#ifdef HAVE_MITAB
4225
    OGRErr eErr;
4226
4227
    if (m_poAttrIndex != nullptr)
4228
        return OGRERR_NONE;
4229
4230
    m_poAttrIndex = OGRCreateDefaultLayerIndex();
4231
4232
    eErr = m_poAttrIndex->Initialize(pszFilename, this);
4233
    if (eErr != OGRERR_NONE)
4234
    {
4235
        delete m_poAttrIndex;
4236
        m_poAttrIndex = nullptr;
4237
    }
4238
4239
    return eErr;
4240
#else
4241
0
    return OGRERR_FAILURE;
4242
0
#endif
4243
0
}
4244
4245
//! @endcond
4246
4247
/************************************************************************/
4248
/*                             SyncToDisk()                             */
4249
/************************************************************************/
4250
4251
/**
4252
\brief Flush pending changes to disk.
4253
4254
This call is intended to force the layer to flush any pending writes to
4255
disk, and leave the disk file in a consistent state.  It would not normally
4256
have any effect on read-only datasources.
4257
4258
Some layers do not implement this method, and will still return
4259
OGRERR_NONE.  The default implementation just returns OGRERR_NONE.  An error
4260
is only returned if an error occurs while attempting to flush to disk.
4261
4262
In any event, you should always close any opened datasource with
4263
OGRDataSource::DestroyDataSource() that will ensure all data is correctly flushed.
4264
4265
This method is the same as the C function OGR_L_SyncToDisk().
4266
4267
@return OGRERR_NONE if no error occurs (even if nothing is done) or an
4268
error code.
4269
*/
4270
4271
OGRErr OGRLayer::SyncToDisk()
4272
4273
0
{
4274
0
    return OGRERR_NONE;
4275
0
}
4276
4277
/************************************************************************/
4278
/*                          OGR_L_SyncToDisk()                          */
4279
/************************************************************************/
4280
4281
/**
4282
\brief Flush pending changes to disk.
4283
4284
This call is intended to force the layer to flush any pending writes to
4285
disk, and leave the disk file in a consistent state.  It would not normally
4286
have any effect on read-only datasources.
4287
4288
Some layers do not implement this method, and will still return
4289
OGRERR_NONE.  The default implementation just returns OGRERR_NONE.  An error
4290
is only returned if an error occurs while attempting to flush to disk.
4291
4292
In any event, you should always close any opened datasource with
4293
OGR_DS_Destroy() that will ensure all data is correctly flushed.
4294
4295
This method is the same as the C++ method OGRLayer::SyncToDisk()
4296
4297
@param hLayer handle to the layer
4298
4299
@return OGRERR_NONE if no error occurs (even if nothing is done) or an
4300
error code.
4301
*/
4302
4303
OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
4304
4305
0
{
4306
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
4307
4308
0
#ifdef OGRAPISPY_ENABLED
4309
0
    if (bOGRAPISpyEnabled)
4310
0
        OGRAPISpy_L_SyncToDisk(hLayer);
4311
0
#endif
4312
4313
0
    return OGRLayer::FromHandle(hLayer)->SyncToDisk();
4314
0
}
4315
4316
/************************************************************************/
4317
/*                           DeleteFeature()                            */
4318
/************************************************************************/
4319
4320
/**
4321
 \brief Delete feature from layer.
4322
4323
 The feature with the indicated feature id is deleted from the layer if
4324
 supported by the driver.  Most drivers do not support feature deletion,
4325
 and will return OGRERR_UNSUPPORTED_OPERATION.  The TestCapability()
4326
 layer method may be called with OLCDeleteFeature to check if the driver
4327
 supports feature deletion.
4328
4329
 This method is the same as the C function OGR_L_DeleteFeature().
4330
4331
 @param nFID the feature id to be deleted from the layer
4332
4333
 @return OGRERR_NONE if the operation works, otherwise an appropriate error
4334
 code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
4335
4336
*/
4337
4338
OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
4339
0
{
4340
0
    return OGRERR_UNSUPPORTED_OPERATION;
4341
0
}
4342
4343
/************************************************************************/
4344
/*                        OGR_L_DeleteFeature()                         */
4345
/************************************************************************/
4346
4347
/**
4348
 \brief Delete feature from layer.
4349
4350
 The feature with the indicated feature id is deleted from the layer if
4351
 supported by the driver.  Most drivers do not support feature deletion,
4352
 and will return OGRERR_UNSUPPORTED_OPERATION.  The OGR_L_TestCapability()
4353
 function may be called with OLCDeleteFeature to check if the driver
4354
 supports feature deletion.
4355
4356
 This method is the same as the C++ method OGRLayer::DeleteFeature().
4357
4358
 @param hLayer handle to the layer
4359
 @param nFID the feature id to be deleted from the layer
4360
4361
 @return OGRERR_NONE if the operation works, otherwise an appropriate error
4362
 code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
4363
*/
4364
4365
OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
4366
4367
0
{
4368
0
    VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
4369
4370
0
#ifdef OGRAPISPY_ENABLED
4371
0
    if (bOGRAPISpyEnabled)
4372
0
        OGRAPISpy_L_DeleteFeature(hLayer, nFID);
4373
0
#endif
4374
4375
0
    return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
4376
0
}
4377
4378
/************************************************************************/
4379
/*                          GetFeaturesRead()                           */
4380
/************************************************************************/
4381
4382
//! @cond Doxygen_Suppress
4383
GIntBig OGRLayer::GetFeaturesRead()
4384
4385
0
{
4386
0
    return m_nFeaturesRead;
4387
0
}
4388
4389
//! @endcond
4390
4391
/************************************************************************/
4392
/*                       OGR_L_GetFeaturesRead()                        */
4393
/************************************************************************/
4394
4395
GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
4396
4397
0
{
4398
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
4399
4400
0
    return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
4401
0
}
4402
4403
/************************************************************************/
4404
/*                             GetFIDColumn                             */
4405
/************************************************************************/
4406
4407
/**
4408
 \brief This method returns the name of the underlying database column being used as the FID column, or "" if not supported.
4409
4410
 This method is the same as the C function OGR_L_GetFIDColumn().
4411
4412
 @return fid column name.
4413
*/
4414
4415
const char *OGRLayer::GetFIDColumn() const
4416
4417
0
{
4418
0
    return "";
4419
0
}
4420
4421
/************************************************************************/
4422
/*                         OGR_L_GetFIDColumn()                         */
4423
/************************************************************************/
4424
4425
/**
4426
 \brief This method returns the name of the underlying database column being used as the FID column, or "" if not supported.
4427
4428
 This method is the same as the C++ method OGRLayer::GetFIDColumn()
4429
4430
 @param hLayer handle to the layer
4431
 @return fid column name.
4432
*/
4433
4434
const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
4435
4436
0
{
4437
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
4438
4439
0
#ifdef OGRAPISPY_ENABLED
4440
0
    if (bOGRAPISpyEnabled)
4441
0
        OGRAPISpy_L_GetFIDColumn(hLayer);
4442
0
#endif
4443
4444
0
    return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
4445
0
}
4446
4447
/************************************************************************/
4448
/*                         GetGeometryColumn()                          */
4449
/************************************************************************/
4450
4451
/**
4452
 \brief This method returns the name of the underlying database column being used as the geometry column, or "" if not supported.
4453
4454
 For layers with multiple geometry fields, this method only returns the name
4455
 of the first geometry column. For other columns, use
4456
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetNameRef().
4457
4458
 This method is the same as the C function OGR_L_GetGeometryColumn().
4459
4460
 @return geometry column name.
4461
*/
4462
4463
const char *OGRLayer::GetGeometryColumn() const
4464
4465
0
{
4466
0
    const auto poLayerDefn = GetLayerDefn();
4467
0
    if (poLayerDefn->GetGeomFieldCount() > 0)
4468
0
        return poLayerDefn->GetGeomFieldDefn(0)->GetNameRef();
4469
0
    else
4470
0
        return "";
4471
0
}
4472
4473
/************************************************************************/
4474
/*                      OGR_L_GetGeometryColumn()                       */
4475
/************************************************************************/
4476
4477
/**
4478
 \brief This method returns the name of the underlying database column being used as the geometry column, or "" if not supported.
4479
4480
 For layers with multiple geometry fields, this method only returns the geometry
4481
 type of the first geometry column. For other columns, use
4482
 OGR_GFld_GetNameRef(OGR_FD_GetGeomFieldDefn(OGR_L_GetLayerDefn(hLayer), i)).
4483
4484
 This method is the same as the C++ method OGRLayer::GetGeometryColumn()
4485
4486
 @param hLayer handle to the layer
4487
 @return geometry column name.
4488
*/
4489
4490
const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
4491
4492
0
{
4493
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
4494
4495
0
#ifdef OGRAPISPY_ENABLED
4496
0
    if (bOGRAPISpyEnabled)
4497
0
        OGRAPISpy_L_GetGeometryColumn(hLayer);
4498
0
#endif
4499
4500
0
    return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
4501
0
}
4502
4503
/************************************************************************/
4504
/*                            GetStyleTable()                           */
4505
/************************************************************************/
4506
4507
/**
4508
 \brief Returns layer style table.
4509
4510
 This method is the same as the C function OGR_L_GetStyleTable().
4511
4512
 @return pointer to a style table which should not be modified or freed by the
4513
 caller.
4514
*/
4515
4516
OGRStyleTable *OGRLayer::GetStyleTable()
4517
0
{
4518
0
    return m_poStyleTable;
4519
0
}
4520
4521
/************************************************************************/
4522
/*                         SetStyleTableDirectly()                      */
4523
/************************************************************************/
4524
4525
/**
4526
 \brief Set layer style table.
4527
4528
 This method operate exactly as OGRLayer::SetStyleTable() except that it
4529
 assumes ownership of the passed table.
4530
4531
 This method is the same as the C function OGR_L_SetStyleTableDirectly().
4532
4533
 @param poStyleTable pointer to style table to set
4534
*/
4535
4536
void OGRLayer::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
4537
0
{
4538
0
    if (m_poStyleTable)
4539
0
        delete m_poStyleTable;
4540
0
    m_poStyleTable = poStyleTable;
4541
0
}
4542
4543
/************************************************************************/
4544
/*                            SetStyleTable()                           */
4545
/************************************************************************/
4546
4547
/**
4548
 \brief Set layer style table.
4549
4550
 This method operate exactly as OGRLayer::SetStyleTableDirectly() except
4551
 that it does not assume ownership of the passed table.
4552
4553
 This method is the same as the C function OGR_L_SetStyleTable().
4554
4555
 @param poStyleTable pointer to style table to set
4556
*/
4557
4558
void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
4559
0
{
4560
0
    if (m_poStyleTable)
4561
0
        delete m_poStyleTable;
4562
0
    if (poStyleTable)
4563
0
        m_poStyleTable = poStyleTable->Clone();
4564
0
}
4565
4566
/************************************************************************/
4567
/*                         OGR_L_GetStyleTable()                        */
4568
/************************************************************************/
4569
4570
OGRStyleTableH OGR_L_GetStyleTable(OGRLayerH hLayer)
4571
4572
0
{
4573
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetStyleTable", nullptr);
4574
4575
0
    return reinterpret_cast<OGRStyleTableH>(
4576
0
        OGRLayer::FromHandle(hLayer)->GetStyleTable());
4577
0
}
4578
4579
/************************************************************************/
4580
/*                         OGR_L_SetStyleTableDirectly()                */
4581
/************************************************************************/
4582
4583
void OGR_L_SetStyleTableDirectly(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
4584
4585
0
{
4586
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTableDirectly");
4587
4588
0
    OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
4589
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
4590
0
}
4591
4592
/************************************************************************/
4593
/*                         OGR_L_SetStyleTable()                        */
4594
/************************************************************************/
4595
4596
void OGR_L_SetStyleTable(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
4597
4598
0
{
4599
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTable");
4600
0
    VALIDATE_POINTER0(hStyleTable, "OGR_L_SetStyleTable");
4601
4602
0
    OGRLayer::FromHandle(hLayer)->SetStyleTable(
4603
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
4604
0
}
4605
4606
/************************************************************************/
4607
/*                               GetName()                              */
4608
/************************************************************************/
4609
4610
/**
4611
 \brief Return the layer name.
4612
4613
 This returns the same content as GetLayerDefn()->OGRFeatureDefn::GetName(), but for a
4614
 few drivers, calling GetName() directly can avoid lengthy layer
4615
 definition initialization.
4616
4617
 This method is the same as the C function OGR_L_GetName().
4618
4619
 If this method is derived in a driver, it must be done such that it
4620
 returns the same content as GetLayerDefn()->OGRFeatureDefn::GetName().
4621
4622
 @return the layer name (must not been freed)
4623
*/
4624
4625
const char *OGRLayer::GetName() const
4626
4627
0
{
4628
0
    return GetLayerDefn()->GetName();
4629
0
}
4630
4631
/************************************************************************/
4632
/*                           OGR_L_GetName()                            */
4633
/************************************************************************/
4634
4635
/**
4636
 \brief Return the layer name.
4637
4638
 This returns the same content as OGR_FD_GetName(OGR_L_GetLayerDefn(hLayer)),
4639
 but for a few drivers, calling OGR_L_GetName() directly can avoid lengthy
4640
 layer definition initialization.
4641
4642
 This function is the same as the C++ method OGRLayer::GetName().
4643
4644
 @param hLayer handle to the layer.
4645
 @return the layer name (must not been freed)
4646
*/
4647
4648
const char *OGR_L_GetName(OGRLayerH hLayer)
4649
4650
0
{
4651
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
4652
4653
0
#ifdef OGRAPISPY_ENABLED
4654
0
    if (bOGRAPISpyEnabled)
4655
0
        OGRAPISpy_L_GetName(hLayer);
4656
0
#endif
4657
4658
0
    return OGRLayer::FromHandle(hLayer)->GetName();
4659
0
}
4660
4661
/************************************************************************/
4662
/*                            GetGeomType()                             */
4663
/************************************************************************/
4664
4665
/**
4666
 \brief Return the layer geometry type.
4667
4668
 This returns the same result as GetLayerDefn()->OGRFeatureDefn::GetGeomType(), but for a
4669
 few drivers, calling GetGeomType() directly can avoid lengthy layer
4670
 definition initialization.
4671
4672
 Note that even if this method is const (since GDAL 3.12), there is no guarantee
4673
 it can be safely called by concurrent threads on the same GDALDataset object.
4674
4675
 For layers with multiple geometry fields, this method only returns the geometry
4676
 type of the first geometry column. For other columns, use
4677
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetType().
4678
 For layers without any geometry field, this method returns wkbNone.
4679
4680
 This method is the same as the C function OGR_L_GetGeomType().
4681
4682
 If this method is derived in a driver, it must be done such that it
4683
 returns the same content as GetLayerDefn()->OGRFeatureDefn::GetGeomType().
4684
4685
 @return the geometry type
4686
*/
4687
4688
OGRwkbGeometryType OGRLayer::GetGeomType() const
4689
0
{
4690
0
    const OGRFeatureDefn *poLayerDefn = GetLayerDefn();
4691
0
    if (poLayerDefn == nullptr)
4692
0
    {
4693
0
        CPLDebug("OGR", "GetLayerType() returns NULL !");
4694
0
        return wkbUnknown;
4695
0
    }
4696
0
    return poLayerDefn->GetGeomType();
4697
0
}
4698
4699
/************************************************************************/
4700
/*                         OGR_L_GetGeomType()                          */
4701
/************************************************************************/
4702
4703
/**
4704
 \brief Return the layer geometry type.
4705
4706
 This returns the same result as OGR_FD_GetGeomType(OGR_L_GetLayerDefn(hLayer)),
4707
 but for a few drivers, calling OGR_L_GetGeomType() directly can avoid lengthy
4708
 layer definition initialization.
4709
4710
 For layers with multiple geometry fields, this method only returns the geometry
4711
 type of the first geometry column. For other columns, use
4712
 OGR_GFld_GetType(OGR_FD_GetGeomFieldDefn(OGR_L_GetLayerDefn(hLayer), i)).
4713
 For layers without any geometry field, this method returns wkbNone.
4714
4715
 This function is the same as the C++ method OGRLayer::GetGeomType().
4716
4717
 @param hLayer handle to the layer.
4718
 @return the geometry type
4719
*/
4720
4721
OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
4722
4723
0
{
4724
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
4725
4726
0
#ifdef OGRAPISPY_ENABLED
4727
0
    if (bOGRAPISpyEnabled)
4728
0
        OGRAPISpy_L_GetGeomType(hLayer);
4729
0
#endif
4730
4731
0
    OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
4732
0
    if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
4733
0
    {
4734
0
        eType = OGR_GT_GetLinear(eType);
4735
0
    }
4736
0
    return eType;
4737
0
}
4738
4739
/************************************************************************/
4740
/*                          SetIgnoredFields()                          */
4741
/************************************************************************/
4742
4743
/**
4744
 \brief Set which fields can be omitted when retrieving features from the layer.
4745
4746
 If the driver supports this functionality (testable using OLCIgnoreFields capability), it will not fetch the specified fields
4747
 in subsequent calls to GetFeature() / GetNextFeature() and thus save some processing time and/or bandwidth.
4748
4749
 Besides field names of the layers, the following special fields can be passed: "OGR_GEOMETRY" to ignore geometry and
4750
 "OGR_STYLE" to ignore layer style.
4751
4752
 By default, no fields are ignored.
4753
4754
 Note that fields that are used in an attribute filter should generally not be set as
4755
 ignored fields, as most drivers (such as those relying on the OGR SQL engine)
4756
 will be unable to correctly evaluate the attribute filter.
4757
4758
 This method is the same as the C function OGR_L_SetIgnoredFields()
4759
4760
 @param papszFields an array of field names terminated by NULL item. If NULL is passed, the ignored list is cleared.
4761
 @return OGRERR_NONE if all field names have been resolved (even if the driver does not support this method)
4762
*/
4763
4764
OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
4765
0
{
4766
0
    OGRFeatureDefn *poDefn = GetLayerDefn();
4767
4768
    // first set everything as *not* ignored
4769
0
    for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
4770
0
    {
4771
0
        poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
4772
0
    }
4773
0
    for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
4774
0
    {
4775
0
        poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
4776
0
    }
4777
0
    poDefn->SetStyleIgnored(FALSE);
4778
4779
    // ignore some fields
4780
0
    for (const char *pszFieldName : cpl::Iterate(papszFields))
4781
0
    {
4782
        // check special fields
4783
0
        if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
4784
0
            poDefn->SetGeometryIgnored(TRUE);
4785
0
        else if (EQUAL(pszFieldName, "OGR_STYLE"))
4786
0
            poDefn->SetStyleIgnored(TRUE);
4787
0
        else
4788
0
        {
4789
            // check ordinary fields
4790
0
            int iField = poDefn->GetFieldIndex(pszFieldName);
4791
0
            if (iField == -1)
4792
0
            {
4793
                // check geometry field
4794
0
                iField = poDefn->GetGeomFieldIndex(pszFieldName);
4795
0
                if (iField == -1)
4796
0
                {
4797
0
                    return OGRERR_FAILURE;
4798
0
                }
4799
0
                else
4800
0
                    poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
4801
0
            }
4802
0
            else
4803
0
                poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
4804
0
        }
4805
0
    }
4806
4807
0
    return OGRERR_NONE;
4808
0
}
4809
4810
/************************************************************************/
4811
/*                       OGR_L_SetIgnoredFields()                       */
4812
/************************************************************************/
4813
4814
/**
4815
 \brief Set which fields can be omitted when retrieving features from the layer.
4816
4817
 If the driver supports this functionality (testable using OLCIgnoreFields capability), it will not fetch the specified fields
4818
 in subsequent calls to GetFeature() / GetNextFeature() and thus save some processing time and/or bandwidth.
4819
4820
 Besides field names of the layers, the following special fields can be passed: "OGR_GEOMETRY" to ignore geometry and
4821
 "OGR_STYLE" to ignore layer style.
4822
4823
 By default, no fields are ignored.
4824
4825
 Note that fields that are used in an attribute filter should generally not be set as
4826
 ignored fields, as most drivers (such as those relying on the OGR SQL engine)
4827
 will be unable to correctly evaluate the attribute filter.
4828
4829
 This method is the same as the C++ method OGRLayer::SetIgnoredFields()
4830
4831
 @param hLayer handle to the layer
4832
 @param papszFields an array of field names terminated by NULL item. If NULL is passed, the ignored list is cleared.
4833
 @return OGRERR_NONE if all field names have been resolved (even if the driver does not support this method)
4834
*/
4835
4836
OGRErr OGR_L_SetIgnoredFields(OGRLayerH hLayer, const char **papszFields)
4837
4838
0
{
4839
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE);
4840
4841
0
#ifdef OGRAPISPY_ENABLED
4842
0
    if (bOGRAPISpyEnabled)
4843
0
        OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
4844
0
#endif
4845
4846
0
    return OGRLayer::FromHandle(hLayer)->SetIgnoredFields(papszFields);
4847
0
}
4848
4849
/************************************************************************/
4850
/*                             Rename()                                 */
4851
/************************************************************************/
4852
4853
/** Rename layer.
4854
 *
4855
 * This operation is implemented only by layers that expose the OLCRename
4856
 * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
4857
 *
4858
 * This operation will fail if a layer with the new name already exists.
4859
 *
4860
 * On success, GetDescription() and GetLayerDefn()->GetName() will return
4861
 * pszNewName.
4862
 *
4863
 * Renaming the layer may interrupt current feature iteration.
4864
 *
4865
 * @param pszNewName New layer name. Must not be NULL.
4866
 * @return OGRERR_NONE in case of success
4867
 *
4868
 * @since GDAL 3.5
4869
 */
4870
OGRErr OGRLayer::Rename(CPL_UNUSED const char *pszNewName)
4871
0
{
4872
0
    CPLError(CE_Failure, CPLE_NotSupported,
4873
0
             "Rename() not supported by this layer.");
4874
4875
0
    return OGRERR_UNSUPPORTED_OPERATION;
4876
0
}
4877
4878
/************************************************************************/
4879
/*                           OGR_L_Rename()                             */
4880
/************************************************************************/
4881
4882
/** Rename layer.
4883
 *
4884
 * This operation is implemented only by layers that expose the OLCRename
4885
 * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
4886
 *
4887
 * This operation will fail if a layer with the new name already exists.
4888
 *
4889
 * On success, GetDescription() and GetLayerDefn()->GetName() will return
4890
 * pszNewName.
4891
 *
4892
 * Renaming the layer may interrupt current feature iteration.
4893
 *
4894
 * @param hLayer     Layer to rename.
4895
 * @param pszNewName New layer name. Must not be NULL.
4896
 * @return OGRERR_NONE in case of success
4897
 *
4898
 * @since GDAL 3.5
4899
 */
4900
OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
4901
4902
0
{
4903
0
    VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
4904
0
    VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
4905
4906
0
    return OGRLayer::FromHandle(hLayer)->Rename(pszNewName);
4907
0
}
4908
4909
/************************************************************************/
4910
/*         helper functions for layer overlay methods                   */
4911
/************************************************************************/
4912
4913
static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
4914
0
{
4915
0
    OGRErr ret = OGRERR_NONE;
4916
0
    OGRGeometry *g = pLayer->GetSpatialFilter();
4917
0
    *ppGeometry = g ? g->clone() : nullptr;
4918
0
    return ret;
4919
0
}
4920
4921
static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
4922
0
{
4923
0
    OGRErr ret = OGRERR_NONE;
4924
0
    int n = poDefn->GetFieldCount();
4925
0
    if (n > 0)
4926
0
    {
4927
0
        *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
4928
0
        if (!(*map))
4929
0
            return OGRERR_NOT_ENOUGH_MEMORY;
4930
0
        for (int i = 0; i < n; i++)
4931
0
            (*map)[i] = -1;
4932
0
    }
4933
0
    return ret;
4934
0
}
4935
4936
static OGRErr set_result_schema(OGRLayer *pLayerResult,
4937
                                OGRFeatureDefn *poDefnInput,
4938
                                OGRFeatureDefn *poDefnMethod, int *mapInput,
4939
                                int *mapMethod, bool combined,
4940
                                const char *const *papszOptions)
4941
0
{
4942
0
    if (!CPLTestBool(CSLFetchNameValueDef(papszOptions, "ADD_FIELDS", "YES")))
4943
0
        return OGRERR_NONE;
4944
4945
0
    OGRErr ret = OGRERR_NONE;
4946
0
    OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
4947
0
    const char *pszInputPrefix =
4948
0
        CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
4949
0
    const char *pszMethodPrefix =
4950
0
        CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
4951
0
    const bool bSkipFailures =
4952
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4953
0
    if (poDefnResult->GetFieldCount() > 0)
4954
0
    {
4955
        // the user has defined the schema of the output layer
4956
0
        if (mapInput)
4957
0
        {
4958
0
            for (int iField = 0; iField < poDefnInput->GetFieldCount();
4959
0
                 iField++)
4960
0
            {
4961
0
                CPLString osName(
4962
0
                    poDefnInput->GetFieldDefn(iField)->GetNameRef());
4963
0
                if (pszInputPrefix != nullptr)
4964
0
                    osName = pszInputPrefix + osName;
4965
0
                mapInput[iField] = poDefnResult->GetFieldIndex(osName);
4966
0
            }
4967
0
        }
4968
0
        if (!mapMethod)
4969
0
            return ret;
4970
        // cppcheck-suppress nullPointer
4971
0
        for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
4972
0
        {
4973
            // cppcheck-suppress nullPointer
4974
0
            CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
4975
0
            if (pszMethodPrefix != nullptr)
4976
0
                osName = pszMethodPrefix + osName;
4977
0
            mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
4978
0
        }
4979
0
    }
4980
0
    else
4981
0
    {
4982
        // use schema from the input layer or from input and method layers
4983
0
        const int nFieldsInput = poDefnInput->GetFieldCount();
4984
4985
        // If no prefix is specified and we have input+method layers, make
4986
        // sure we will generate unique field names
4987
0
        std::set<std::string> oSetInputFieldNames;
4988
0
        std::set<std::string> oSetMethodFieldNames;
4989
0
        if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
4990
0
            pszMethodPrefix == nullptr)
4991
0
        {
4992
0
            for (int iField = 0; iField < nFieldsInput; iField++)
4993
0
            {
4994
0
                oSetInputFieldNames.insert(
4995
0
                    poDefnInput->GetFieldDefn(iField)->GetNameRef());
4996
0
            }
4997
0
            const int nFieldsMethod = poDefnMethod->GetFieldCount();
4998
0
            for (int iField = 0; iField < nFieldsMethod; iField++)
4999
0
            {
5000
0
                oSetMethodFieldNames.insert(
5001
0
                    poDefnMethod->GetFieldDefn(iField)->GetNameRef());
5002
0
            }
5003
0
        }
5004
5005
0
        const bool bAddInputFields = CPLTestBool(
5006
0
            CSLFetchNameValueDef(papszOptions, "ADD_INPUT_FIELDS", "YES"));
5007
0
        if (bAddInputFields)
5008
0
        {
5009
0
            for (int iField = 0; iField < nFieldsInput; iField++)
5010
0
            {
5011
0
                OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
5012
0
                if (pszInputPrefix != nullptr)
5013
0
                    oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
5014
0
                                                  oFieldDefn.GetNameRef()));
5015
0
                else if (!oSetMethodFieldNames.empty() &&
5016
0
                         oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
5017
0
                             oSetMethodFieldNames.end())
5018
0
                {
5019
                    // Field of same name present in method layer
5020
0
                    oFieldDefn.SetName(
5021
0
                        CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
5022
0
                }
5023
0
                ret = pLayerResult->CreateField(&oFieldDefn);
5024
0
                if (ret != OGRERR_NONE)
5025
0
                {
5026
0
                    if (!bSkipFailures)
5027
0
                        return ret;
5028
0
                    else
5029
0
                    {
5030
0
                        CPLErrorReset();
5031
0
                        ret = OGRERR_NONE;
5032
0
                    }
5033
0
                }
5034
0
                if (mapInput)
5035
0
                    mapInput[iField] =
5036
0
                        pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
5037
0
            }
5038
0
        }
5039
5040
0
        if (!combined)
5041
0
            return ret;
5042
0
        if (!mapMethod)
5043
0
            return ret;
5044
0
        if (!poDefnMethod)
5045
0
            return ret;
5046
5047
0
        const bool bAddMethodFields = CPLTestBool(
5048
0
            CSLFetchNameValueDef(papszOptions, "ADD_METHOD_FIELDS", "YES"));
5049
0
        if (bAddMethodFields)
5050
0
        {
5051
0
            const int nFieldsMethod = poDefnMethod->GetFieldCount();
5052
0
            for (int iField = 0; iField < nFieldsMethod; iField++)
5053
0
            {
5054
0
                OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
5055
0
                if (pszMethodPrefix != nullptr)
5056
0
                    oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
5057
0
                                                  oFieldDefn.GetNameRef()));
5058
0
                else if (!oSetInputFieldNames.empty() &&
5059
0
                         oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
5060
0
                             oSetInputFieldNames.end())
5061
0
                {
5062
                    // Field of same name present in method layer
5063
0
                    oFieldDefn.SetName(
5064
0
                        CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
5065
0
                }
5066
0
                ret = pLayerResult->CreateField(&oFieldDefn);
5067
0
                if (ret != OGRERR_NONE)
5068
0
                {
5069
0
                    if (!bSkipFailures)
5070
0
                        return ret;
5071
0
                    else
5072
0
                    {
5073
0
                        CPLErrorReset();
5074
0
                        ret = OGRERR_NONE;
5075
0
                    }
5076
0
                }
5077
0
                mapMethod[iField] =
5078
0
                    pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
5079
0
            }
5080
0
        }
5081
0
    }
5082
0
    return ret;
5083
0
}
5084
5085
static OGRGeometry *set_filter_from(OGRLayer *pLayer,
5086
                                    OGRGeometry *pGeometryExistingFilter,
5087
                                    OGRFeature *pFeature)
5088
0
{
5089
0
    OGRGeometry *geom = pFeature->GetGeometryRef();
5090
0
    if (!geom)
5091
0
        return nullptr;
5092
0
    if (pGeometryExistingFilter)
5093
0
    {
5094
0
        if (!geom->Intersects(pGeometryExistingFilter))
5095
0
            return nullptr;
5096
0
        OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
5097
0
        if (intersection)
5098
0
        {
5099
0
            pLayer->SetSpatialFilter(intersection);
5100
0
            delete intersection;
5101
0
        }
5102
0
        else
5103
0
            return nullptr;
5104
0
    }
5105
0
    else
5106
0
    {
5107
0
        pLayer->SetSpatialFilter(geom);
5108
0
    }
5109
0
    return geom;
5110
0
}
5111
5112
static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
5113
0
{
5114
0
    OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
5115
0
    if (eType == wkbPoint)
5116
0
        return OGRGeometryFactory::forceToMultiPoint(poGeom);
5117
0
    else if (eType == wkbPolygon)
5118
0
        return OGRGeometryFactory::forceToMultiPolygon(poGeom);
5119
0
    else if (eType == wkbLineString)
5120
0
        return OGRGeometryFactory::forceToMultiLineString(poGeom);
5121
0
    else
5122
0
        return poGeom;
5123
0
}
5124
5125
/************************************************************************/
5126
/*                          Intersection()                              */
5127
/************************************************************************/
5128
/**
5129
 * \brief Intersection of two layers.
5130
 *
5131
 * The result layer contains features whose geometries represent areas
5132
 * that are common between features in the input layer and in the
5133
 * method layer. The features in the result layer have attributes from
5134
 * both input and method layers. The schema of the result layer can be
5135
 * set by the user or, if it is empty, is initialized to contain all
5136
 * fields in the input and method layers.
5137
 *
5138
 * \note If the schema of the result is set by user and contains
5139
 * fields that have the same name as a field in input and in method
5140
 * layer, then the attribute in the result feature will get the value
5141
 * from the feature of the method layer.
5142
 *
5143
 * \note For best performance use the minimum amount of features in
5144
 * the method layer and copy it into a memory layer.
5145
 *
5146
 * \note This method relies on GEOS support. Do not use unless the
5147
 * GEOS support is compiled in.
5148
 *
5149
 * The recognized list of options is:
5150
 * <ul>
5151
 * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
5152
 *     feature could not be inserted or a GEOS call failed.
5153
 * </li>
5154
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5155
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5156
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5157
 * </li>
5158
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5159
 *     will be created from the fields of the input layer.
5160
 * </li>
5161
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5162
 *     will be created from the fields of the method layer.
5163
 * </li>
5164
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5165
 *     geometries to pretest intersection of features of method layer
5166
 *     with features of this layer.
5167
 * </li>
5168
 * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
5169
 *     containment of features of method layer within the features of
5170
 *     this layer. This will speed up the method significantly in some
5171
 *     cases. Requires that the prepared geometries are in effect.
5172
 * </li>
5173
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5174
 *     result features with lower dimension geometry that would
5175
 *     otherwise be added to the result layer. The default is YES, to add
5176
 *     features with lower dimension geometry, but only if the result layer
5177
 *     has an unknown geometry type.
5178
 * </li>
5179
 * </ul>
5180
 *
5181
 * This method is the same as the C function OGR_L_Intersection().
5182
 *
5183
 * @param pLayerMethod the method layer. Should not be NULL.
5184
 *
5185
 * @param pLayerResult the layer where the features resulting from the
5186
 * operation are inserted. Should not be NULL. See above the note
5187
 * about the schema.
5188
 *
5189
 * @param papszOptions NULL terminated list of options (may be NULL).
5190
 *
5191
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5192
 * reporting progress or NULL.
5193
 *
5194
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5195
 *
5196
 * @return an error code if there was an error or the execution was
5197
 * interrupted, OGRERR_NONE otherwise.
5198
 *
5199
 * @note The first geometry field is always used.
5200
 *
5201
 * @since OGR 1.10
5202
 */
5203
5204
OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5205
                              char **papszOptions, GDALProgressFunc pfnProgress,
5206
                              void *pProgressArg)
5207
0
{
5208
0
    OGRErr ret = OGRERR_NONE;
5209
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
5210
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
5211
0
    OGRFeatureDefn *poDefnResult = nullptr;
5212
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
5213
0
    int *mapInput = nullptr;
5214
0
    int *mapMethod = nullptr;
5215
0
    OGREnvelope sEnvelopeMethod;
5216
0
    GBool bEnvelopeSet;
5217
0
    double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5218
0
    double progress_counter = 0;
5219
0
    double progress_ticker = 0;
5220
0
    const bool bSkipFailures =
5221
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5222
0
    const bool bPromoteToMulti = CPLTestBool(
5223
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5224
0
    const bool bUsePreparedGeometries = CPLTestBool(
5225
0
        CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
5226
0
    const bool bPretestContainment = CPLTestBool(
5227
0
        CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
5228
0
    bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
5229
0
        papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
5230
5231
    // check for GEOS
5232
0
    if (!OGRGeometryFactory::haveGEOS())
5233
0
    {
5234
0
        CPLError(CE_Failure, CPLE_AppDefined,
5235
0
                 "OGRLayer::Intersection() requires GEOS support");
5236
0
        return OGRERR_UNSUPPORTED_OPERATION;
5237
0
    }
5238
5239
    // get resources
5240
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5241
0
    if (ret != OGRERR_NONE)
5242
0
        goto done;
5243
0
    ret = create_field_map(poDefnInput, &mapInput);
5244
0
    if (ret != OGRERR_NONE)
5245
0
        goto done;
5246
0
    ret = create_field_map(poDefnMethod, &mapMethod);
5247
0
    if (ret != OGRERR_NONE)
5248
0
        goto done;
5249
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
5250
0
                            mapMethod, true, papszOptions);
5251
0
    if (ret != OGRERR_NONE)
5252
0
        goto done;
5253
0
    poDefnResult = pLayerResult->GetLayerDefn();
5254
0
    bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
5255
0
    if (bKeepLowerDimGeom)
5256
0
    {
5257
        // require that the result layer is of geom type unknown
5258
0
        if (pLayerResult->GetGeomType() != wkbUnknown)
5259
0
        {
5260
0
            CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
5261
0
                            "since the result layer does not allow it.");
5262
0
            bKeepLowerDimGeom = false;
5263
0
        }
5264
0
    }
5265
5266
0
    for (auto &&x : this)
5267
0
    {
5268
5269
0
        if (pfnProgress)
5270
0
        {
5271
0
            double p = progress_counter / progress_max;
5272
0
            if (p > progress_ticker)
5273
0
            {
5274
0
                if (!pfnProgress(p, "", pProgressArg))
5275
0
                {
5276
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5277
0
                    ret = OGRERR_FAILURE;
5278
0
                    goto done;
5279
0
                }
5280
0
            }
5281
0
            progress_counter += 1.0;
5282
0
        }
5283
5284
        // is it worth to proceed?
5285
0
        if (bEnvelopeSet)
5286
0
        {
5287
0
            OGRGeometry *x_geom = x->GetGeometryRef();
5288
0
            if (x_geom)
5289
0
            {
5290
0
                OGREnvelope x_env;
5291
0
                x_geom->getEnvelope(&x_env);
5292
0
                if (x_env.MaxX < sEnvelopeMethod.MinX ||
5293
0
                    x_env.MaxY < sEnvelopeMethod.MinY ||
5294
0
                    sEnvelopeMethod.MaxX < x_env.MinX ||
5295
0
                    sEnvelopeMethod.MaxY < x_env.MinY)
5296
0
                {
5297
0
                    continue;
5298
0
                }
5299
0
            }
5300
0
            else
5301
0
            {
5302
0
                continue;
5303
0
            }
5304
0
        }
5305
5306
        // set up the filter for method layer
5307
0
        CPLErrorReset();
5308
0
        OGRGeometry *x_geom =
5309
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5310
0
        if (CPLGetLastErrorType() != CE_None)
5311
0
        {
5312
0
            if (!bSkipFailures)
5313
0
            {
5314
0
                ret = OGRERR_FAILURE;
5315
0
                goto done;
5316
0
            }
5317
0
            else
5318
0
            {
5319
0
                CPLErrorReset();
5320
0
                ret = OGRERR_NONE;
5321
0
            }
5322
0
        }
5323
0
        if (!x_geom)
5324
0
        {
5325
0
            continue;
5326
0
        }
5327
5328
0
        OGRPreparedGeometryUniquePtr x_prepared_geom;
5329
0
        if (bUsePreparedGeometries)
5330
0
        {
5331
0
            x_prepared_geom.reset(
5332
0
                OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
5333
0
            if (!x_prepared_geom)
5334
0
            {
5335
0
                goto done;
5336
0
            }
5337
0
        }
5338
5339
0
        for (auto &&y : pLayerMethod)
5340
0
        {
5341
0
            OGRGeometry *y_geom = y->GetGeometryRef();
5342
0
            if (!y_geom)
5343
0
                continue;
5344
0
            OGRGeometryUniquePtr z_geom;
5345
5346
0
            if (x_prepared_geom)
5347
0
            {
5348
0
                CPLErrorReset();
5349
0
                ret = OGRERR_NONE;
5350
0
                if (bPretestContainment &&
5351
0
                    OGRPreparedGeometryContains(x_prepared_geom.get(),
5352
0
                                                OGRGeometry::ToHandle(y_geom)))
5353
0
                {
5354
0
                    if (CPLGetLastErrorType() == CE_None)
5355
0
                        z_geom.reset(y_geom->clone());
5356
0
                }
5357
0
                else if (!(OGRPreparedGeometryIntersects(
5358
0
                             x_prepared_geom.get(),
5359
0
                             OGRGeometry::ToHandle(y_geom))))
5360
0
                {
5361
0
                    if (CPLGetLastErrorType() == CE_None)
5362
0
                    {
5363
0
                        continue;
5364
0
                    }
5365
0
                }
5366
0
                if (CPLGetLastErrorType() != CE_None)
5367
0
                {
5368
0
                    if (!bSkipFailures)
5369
0
                    {
5370
0
                        ret = OGRERR_FAILURE;
5371
0
                        goto done;
5372
0
                    }
5373
0
                    else
5374
0
                    {
5375
0
                        CPLErrorReset();
5376
0
                        ret = OGRERR_NONE;
5377
0
                        continue;
5378
0
                    }
5379
0
                }
5380
0
            }
5381
0
            if (!z_geom)
5382
0
            {
5383
0
                CPLErrorReset();
5384
0
                z_geom.reset(x_geom->Intersection(y_geom));
5385
0
                if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
5386
0
                {
5387
0
                    if (!bSkipFailures)
5388
0
                    {
5389
0
                        ret = OGRERR_FAILURE;
5390
0
                        goto done;
5391
0
                    }
5392
0
                    else
5393
0
                    {
5394
0
                        CPLErrorReset();
5395
0
                        ret = OGRERR_NONE;
5396
0
                        continue;
5397
0
                    }
5398
0
                }
5399
0
                if (z_geom->IsEmpty() ||
5400
0
                    (!bKeepLowerDimGeom &&
5401
0
                     (x_geom->getDimension() == y_geom->getDimension() &&
5402
0
                      z_geom->getDimension() < x_geom->getDimension())))
5403
0
                {
5404
0
                    continue;
5405
0
                }
5406
0
            }
5407
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5408
0
            z->SetFieldsFrom(x.get(), mapInput);
5409
0
            z->SetFieldsFrom(y.get(), mapMethod);
5410
0
            if (bPromoteToMulti)
5411
0
                z_geom.reset(promote_to_multi(z_geom.release()));
5412
0
            z->SetGeometryDirectly(z_geom.release());
5413
0
            ret = pLayerResult->CreateFeature(z.get());
5414
5415
0
            if (ret != OGRERR_NONE)
5416
0
            {
5417
0
                if (!bSkipFailures)
5418
0
                {
5419
0
                    goto done;
5420
0
                }
5421
0
                else
5422
0
                {
5423
0
                    CPLErrorReset();
5424
0
                    ret = OGRERR_NONE;
5425
0
                }
5426
0
            }
5427
0
        }
5428
0
    }
5429
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5430
0
    {
5431
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5432
0
        ret = OGRERR_FAILURE;
5433
0
        goto done;
5434
0
    }
5435
0
done:
5436
    // release resources
5437
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5438
0
    if (pGeometryMethodFilter)
5439
0
        delete pGeometryMethodFilter;
5440
0
    if (mapInput)
5441
0
        VSIFree(mapInput);
5442
0
    if (mapMethod)
5443
0
        VSIFree(mapMethod);
5444
0
    return ret;
5445
0
}
5446
5447
/************************************************************************/
5448
/*                       OGR_L_Intersection()                           */
5449
/************************************************************************/
5450
/**
5451
 * \brief Intersection of two layers.
5452
 *
5453
 * The result layer contains features whose geometries represent areas
5454
 * that are common between features in the input layer and in the
5455
 * method layer. The features in the result layer have attributes from
5456
 * both input and method layers. The schema of the result layer can be
5457
 * set by the user or, if it is empty, is initialized to contain all
5458
 * fields in the input and method layers.
5459
 *
5460
 * \note If the schema of the result is set by user and contains
5461
 * fields that have the same name as a field in input and in method
5462
 * layer, then the attribute in the result feature will get the value
5463
 * from the feature of the method layer.
5464
 *
5465
 * \note For best performance use the minimum amount of features in
5466
 * the method layer and copy it into a memory layer.
5467
 *
5468
 * \note This method relies on GEOS support. Do not use unless the
5469
 * GEOS support is compiled in.
5470
 *
5471
 * The recognized list of options is :
5472
 * <ul>
5473
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5474
 *     feature could not be inserted or a GEOS call failed.
5475
 * </li>
5476
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5477
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5478
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5479
 * </li>
5480
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5481
 *     will be created from the fields of the input layer.
5482
 * </li>
5483
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5484
 *     will be created from the fields of the method layer.
5485
 * </li>
5486
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5487
 *     geometries to pretest intersection of features of method layer
5488
 *     with features of this layer.
5489
 * </li>
5490
 * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
5491
 *     containment of features of method layer within the features of
5492
 *     this layer. This will speed up the method significantly in some
5493
 *     cases. Requires that the prepared geometries are in effect.
5494
 * </li>
5495
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5496
 *     result features with lower dimension geometry that would
5497
 *     otherwise be added to the result layer. The default is YES, to add
5498
 *     features with lower dimension geometry, but only if the result layer
5499
 *     has an unknown geometry type.
5500
 * </li>
5501
 * </ul>
5502
 *
5503
 * This function is the same as the C++ method OGRLayer::Intersection().
5504
 *
5505
 * @param pLayerInput the input layer. Should not be NULL.
5506
 *
5507
 * @param pLayerMethod the method layer. Should not be NULL.
5508
 *
5509
 * @param pLayerResult the layer where the features resulting from the
5510
 * operation are inserted. Should not be NULL. See above the note
5511
 * about the schema.
5512
 *
5513
 * @param papszOptions NULL terminated list of options (may be NULL).
5514
 *
5515
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5516
 * reporting progress or NULL.
5517
 *
5518
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5519
 *
5520
 * @return an error code if there was an error or the execution was
5521
 * interrupted, OGRERR_NONE otherwise.
5522
 *
5523
 * @note The first geometry field is always used.
5524
 *
5525
 * @since OGR 1.10
5526
 */
5527
5528
OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5529
                          OGRLayerH pLayerResult, char **papszOptions,
5530
                          GDALProgressFunc pfnProgress, void *pProgressArg)
5531
5532
0
{
5533
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
5534
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
5535
0
                      OGRERR_INVALID_HANDLE);
5536
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
5537
0
                      OGRERR_INVALID_HANDLE);
5538
5539
0
    return OGRLayer::FromHandle(pLayerInput)
5540
0
        ->Intersection(OGRLayer::FromHandle(pLayerMethod),
5541
0
                       OGRLayer::FromHandle(pLayerResult), papszOptions,
5542
0
                       pfnProgress, pProgressArg);
5543
0
}
5544
5545
/************************************************************************/
5546
/*                              Union()                                 */
5547
/************************************************************************/
5548
5549
/**
5550
 * \brief Union of two layers.
5551
 *
5552
 * The result layer contains features whose geometries represent areas
5553
 * that are either in the input layer, in the method layer, or in
5554
 * both. The features in the result layer have attributes from both
5555
 * input and method layers. For features which represent areas that
5556
 * are only in the input or in the method layer the respective
5557
 * attributes have undefined values. The schema of the result layer
5558
 * can be set by the user or, if it is empty, is initialized to
5559
 * contain all fields in the input and method layers.
5560
 *
5561
 * \note If the schema of the result is set by user and contains
5562
 * fields that have the same name as a field in input and in method
5563
 * layer, then the attribute in the result feature will get the value
5564
 * from the feature of the method layer (even if it is undefined).
5565
 *
5566
 * \note For best performance use the minimum amount of features in
5567
 * the method layer and copy it into a memory layer.
5568
 *
5569
 * \note This method relies on GEOS support. Do not use unless the
5570
 * GEOS support is compiled in.
5571
 *
5572
 * The recognized list of options is :
5573
 * <ul>
5574
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5575
 *     feature could not be inserted or a GEOS call failed.
5576
 * </li>
5577
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5578
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5579
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5580
 * </li>
5581
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5582
 *     will be created from the fields of the input layer.
5583
 * </li>
5584
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5585
 *     will be created from the fields of the method layer.
5586
 * </li>
5587
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5588
 *     geometries to pretest intersection of features of method layer
5589
 *     with features of this layer.
5590
 * </li>
5591
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5592
 *     result features with lower dimension geometry that would
5593
 *     otherwise be added to the result layer. The default is YES, to add
5594
 *     features with lower dimension geometry, but only if the result layer
5595
 *     has an unknown geometry type.
5596
 * </li>
5597
 * </ul>
5598
 *
5599
 * This method is the same as the C function OGR_L_Union().
5600
 *
5601
 * @param pLayerMethod the method layer. Should not be NULL.
5602
 *
5603
 * @param pLayerResult the layer where the features resulting from the
5604
 * operation are inserted. Should not be NULL. See above the note
5605
 * about the schema.
5606
 *
5607
 * @param papszOptions NULL terminated list of options (may be NULL).
5608
 *
5609
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5610
 * reporting progress or NULL.
5611
 *
5612
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5613
 *
5614
 * @return an error code if there was an error or the execution was
5615
 * interrupted, OGRERR_NONE otherwise.
5616
 *
5617
 * @note The first geometry field is always used.
5618
 *
5619
 * @since OGR 1.10
5620
 */
5621
5622
OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5623
                       char **papszOptions, GDALProgressFunc pfnProgress,
5624
                       void *pProgressArg)
5625
0
{
5626
0
    OGRErr ret = OGRERR_NONE;
5627
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
5628
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
5629
0
    OGRFeatureDefn *poDefnResult = nullptr;
5630
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
5631
0
    OGRGeometry *pGeometryInputFilter = nullptr;
5632
0
    int *mapInput = nullptr;
5633
0
    int *mapMethod = nullptr;
5634
0
    double progress_max =
5635
0
        static_cast<double>(GetFeatureCount(FALSE)) +
5636
0
        static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
5637
0
    double progress_counter = 0;
5638
0
    double progress_ticker = 0;
5639
0
    const bool bSkipFailures =
5640
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5641
0
    const bool bPromoteToMulti = CPLTestBool(
5642
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5643
0
    const bool bUsePreparedGeometries = CPLTestBool(
5644
0
        CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
5645
0
    bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
5646
0
        papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
5647
5648
    // check for GEOS
5649
0
    if (!OGRGeometryFactory::haveGEOS())
5650
0
    {
5651
0
        CPLError(CE_Failure, CPLE_AppDefined,
5652
0
                 "OGRLayer::Union() requires GEOS support");
5653
0
        return OGRERR_UNSUPPORTED_OPERATION;
5654
0
    }
5655
5656
    // get resources
5657
0
    ret = clone_spatial_filter(this, &pGeometryInputFilter);
5658
0
    if (ret != OGRERR_NONE)
5659
0
        goto done;
5660
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5661
0
    if (ret != OGRERR_NONE)
5662
0
        goto done;
5663
0
    ret = create_field_map(poDefnInput, &mapInput);
5664
0
    if (ret != OGRERR_NONE)
5665
0
        goto done;
5666
0
    ret = create_field_map(poDefnMethod, &mapMethod);
5667
0
    if (ret != OGRERR_NONE)
5668
0
        goto done;
5669
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
5670
0
                            mapMethod, true, papszOptions);
5671
0
    if (ret != OGRERR_NONE)
5672
0
        goto done;
5673
0
    poDefnResult = pLayerResult->GetLayerDefn();
5674
0
    if (bKeepLowerDimGeom)
5675
0
    {
5676
        // require that the result layer is of geom type unknown
5677
0
        if (pLayerResult->GetGeomType() != wkbUnknown)
5678
0
        {
5679
0
            CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
5680
0
                            "since the result layer does not allow it.");
5681
0
            bKeepLowerDimGeom = FALSE;
5682
0
        }
5683
0
    }
5684
5685
    // add features based on input layer
5686
0
    for (auto &&x : this)
5687
0
    {
5688
5689
0
        if (pfnProgress)
5690
0
        {
5691
0
            double p = progress_counter / progress_max;
5692
0
            if (p > progress_ticker)
5693
0
            {
5694
0
                if (!pfnProgress(p, "", pProgressArg))
5695
0
                {
5696
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5697
0
                    ret = OGRERR_FAILURE;
5698
0
                    goto done;
5699
0
                }
5700
0
            }
5701
0
            progress_counter += 1.0;
5702
0
        }
5703
5704
        // set up the filter on method layer
5705
0
        CPLErrorReset();
5706
0
        OGRGeometry *x_geom =
5707
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5708
0
        if (CPLGetLastErrorType() != CE_None)
5709
0
        {
5710
0
            if (!bSkipFailures)
5711
0
            {
5712
0
                ret = OGRERR_FAILURE;
5713
0
                goto done;
5714
0
            }
5715
0
            else
5716
0
            {
5717
0
                CPLErrorReset();
5718
0
                ret = OGRERR_NONE;
5719
0
            }
5720
0
        }
5721
0
        if (!x_geom)
5722
0
        {
5723
0
            continue;
5724
0
        }
5725
5726
0
        OGRPreparedGeometryUniquePtr x_prepared_geom;
5727
0
        if (bUsePreparedGeometries)
5728
0
        {
5729
0
            x_prepared_geom.reset(
5730
0
                OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
5731
0
            if (!x_prepared_geom)
5732
0
            {
5733
0
                goto done;
5734
0
            }
5735
0
        }
5736
5737
0
        OGRGeometryUniquePtr x_geom_diff(
5738
0
            x_geom
5739
0
                ->clone());  // this will be the geometry of the result feature
5740
0
        for (auto &&y : pLayerMethod)
5741
0
        {
5742
0
            OGRGeometry *y_geom = y->GetGeometryRef();
5743
0
            if (!y_geom)
5744
0
            {
5745
0
                continue;
5746
0
            }
5747
5748
0
            CPLErrorReset();
5749
0
            if (x_prepared_geom &&
5750
0
                !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
5751
0
                                                OGRGeometry::ToHandle(y_geom))))
5752
0
            {
5753
0
                if (CPLGetLastErrorType() == CE_None)
5754
0
                {
5755
0
                    continue;
5756
0
                }
5757
0
            }
5758
0
            if (CPLGetLastErrorType() != CE_None)
5759
0
            {
5760
0
                if (!bSkipFailures)
5761
0
                {
5762
0
                    ret = OGRERR_FAILURE;
5763
0
                    goto done;
5764
0
                }
5765
0
                else
5766
0
                {
5767
0
                    CPLErrorReset();
5768
0
                    ret = OGRERR_NONE;
5769
0
                }
5770
0
            }
5771
5772
0
            CPLErrorReset();
5773
0
            OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
5774
0
            if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
5775
0
            {
5776
0
                if (!bSkipFailures)
5777
0
                {
5778
0
                    ret = OGRERR_FAILURE;
5779
0
                    goto done;
5780
0
                }
5781
0
                else
5782
0
                {
5783
0
                    CPLErrorReset();
5784
0
                    ret = OGRERR_NONE;
5785
0
                    continue;
5786
0
                }
5787
0
            }
5788
0
            if (poIntersection->IsEmpty() ||
5789
0
                (!bKeepLowerDimGeom &&
5790
0
                 (x_geom->getDimension() == y_geom->getDimension() &&
5791
0
                  poIntersection->getDimension() < x_geom->getDimension())))
5792
0
            {
5793
                // ok
5794
0
            }
5795
0
            else
5796
0
            {
5797
0
                OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5798
0
                z->SetFieldsFrom(x.get(), mapInput);
5799
0
                z->SetFieldsFrom(y.get(), mapMethod);
5800
0
                if (bPromoteToMulti)
5801
0
                    poIntersection.reset(
5802
0
                        promote_to_multi(poIntersection.release()));
5803
0
                z->SetGeometryDirectly(poIntersection.release());
5804
5805
0
                if (x_geom_diff)
5806
0
                {
5807
0
                    CPLErrorReset();
5808
0
                    OGRGeometryUniquePtr x_geom_diff_new(
5809
0
                        x_geom_diff->Difference(y_geom));
5810
0
                    if (CPLGetLastErrorType() != CE_None ||
5811
0
                        x_geom_diff_new == nullptr)
5812
0
                    {
5813
0
                        if (!bSkipFailures)
5814
0
                        {
5815
0
                            ret = OGRERR_FAILURE;
5816
0
                            goto done;
5817
0
                        }
5818
0
                        else
5819
0
                        {
5820
0
                            CPLErrorReset();
5821
0
                        }
5822
0
                    }
5823
0
                    else
5824
0
                    {
5825
0
                        x_geom_diff.swap(x_geom_diff_new);
5826
0
                    }
5827
0
                }
5828
5829
0
                ret = pLayerResult->CreateFeature(z.get());
5830
0
                if (ret != OGRERR_NONE)
5831
0
                {
5832
0
                    if (!bSkipFailures)
5833
0
                    {
5834
0
                        goto done;
5835
0
                    }
5836
0
                    else
5837
0
                    {
5838
0
                        CPLErrorReset();
5839
0
                        ret = OGRERR_NONE;
5840
0
                    }
5841
0
                }
5842
0
            }
5843
0
        }
5844
0
        x_prepared_geom.reset();
5845
5846
0
        if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
5847
0
        {
5848
            // ok
5849
0
        }
5850
0
        else
5851
0
        {
5852
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5853
0
            z->SetFieldsFrom(x.get(), mapInput);
5854
0
            if (bPromoteToMulti)
5855
0
                x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
5856
0
            z->SetGeometryDirectly(x_geom_diff.release());
5857
0
            ret = pLayerResult->CreateFeature(z.get());
5858
0
            if (ret != OGRERR_NONE)
5859
0
            {
5860
0
                if (!bSkipFailures)
5861
0
                {
5862
0
                    goto done;
5863
0
                }
5864
0
                else
5865
0
                {
5866
0
                    CPLErrorReset();
5867
0
                    ret = OGRERR_NONE;
5868
0
                }
5869
0
            }
5870
0
        }
5871
0
    }
5872
5873
    // restore filter on method layer and add features based on it
5874
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5875
0
    for (auto &&x : pLayerMethod)
5876
0
    {
5877
5878
0
        if (pfnProgress)
5879
0
        {
5880
0
            double p = progress_counter / progress_max;
5881
0
            if (p > progress_ticker)
5882
0
            {
5883
0
                if (!pfnProgress(p, "", pProgressArg))
5884
0
                {
5885
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5886
0
                    ret = OGRERR_FAILURE;
5887
0
                    goto done;
5888
0
                }
5889
0
            }
5890
0
            progress_counter += 1.0;
5891
0
        }
5892
5893
        // set up the filter on input layer
5894
0
        CPLErrorReset();
5895
0
        OGRGeometry *x_geom =
5896
0
            set_filter_from(this, pGeometryInputFilter, x.get());
5897
0
        if (CPLGetLastErrorType() != CE_None)
5898
0
        {
5899
0
            if (!bSkipFailures)
5900
0
            {
5901
0
                ret = OGRERR_FAILURE;
5902
0
                goto done;
5903
0
            }
5904
0
            else
5905
0
            {
5906
0
                CPLErrorReset();
5907
0
                ret = OGRERR_NONE;
5908
0
            }
5909
0
        }
5910
0
        if (!x_geom)
5911
0
        {
5912
0
            continue;
5913
0
        }
5914
5915
0
        OGRGeometryUniquePtr x_geom_diff(
5916
0
            x_geom
5917
0
                ->clone());  // this will be the geometry of the result feature
5918
0
        for (auto &&y : this)
5919
0
        {
5920
0
            OGRGeometry *y_geom = y->GetGeometryRef();
5921
0
            if (!y_geom)
5922
0
            {
5923
0
                continue;
5924
0
            }
5925
5926
0
            if (x_geom_diff)
5927
0
            {
5928
0
                CPLErrorReset();
5929
0
                OGRGeometryUniquePtr x_geom_diff_new(
5930
0
                    x_geom_diff->Difference(y_geom));
5931
0
                if (CPLGetLastErrorType() != CE_None ||
5932
0
                    x_geom_diff_new == nullptr)
5933
0
                {
5934
0
                    if (!bSkipFailures)
5935
0
                    {
5936
0
                        ret = OGRERR_FAILURE;
5937
0
                        goto done;
5938
0
                    }
5939
0
                    else
5940
0
                    {
5941
0
                        CPLErrorReset();
5942
0
                        ret = OGRERR_NONE;
5943
0
                    }
5944
0
                }
5945
0
                else
5946
0
                {
5947
0
                    x_geom_diff.swap(x_geom_diff_new);
5948
0
                }
5949
0
            }
5950
0
        }
5951
5952
0
        if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
5953
0
        {
5954
            // ok
5955
0
        }
5956
0
        else
5957
0
        {
5958
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5959
0
            z->SetFieldsFrom(x.get(), mapMethod);
5960
0
            if (bPromoteToMulti)
5961
0
                x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
5962
0
            z->SetGeometryDirectly(x_geom_diff.release());
5963
0
            ret = pLayerResult->CreateFeature(z.get());
5964
0
            if (ret != OGRERR_NONE)
5965
0
            {
5966
0
                if (!bSkipFailures)
5967
0
                {
5968
0
                    goto done;
5969
0
                }
5970
0
                else
5971
0
                {
5972
0
                    CPLErrorReset();
5973
0
                    ret = OGRERR_NONE;
5974
0
                }
5975
0
            }
5976
0
        }
5977
0
    }
5978
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5979
0
    {
5980
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5981
0
        ret = OGRERR_FAILURE;
5982
0
        goto done;
5983
0
    }
5984
0
done:
5985
    // release resources
5986
0
    SetSpatialFilter(pGeometryInputFilter);
5987
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5988
0
    if (pGeometryMethodFilter)
5989
0
        delete pGeometryMethodFilter;
5990
0
    if (pGeometryInputFilter)
5991
0
        delete pGeometryInputFilter;
5992
0
    if (mapInput)
5993
0
        VSIFree(mapInput);
5994
0
    if (mapMethod)
5995
0
        VSIFree(mapMethod);
5996
0
    return ret;
5997
0
}
5998
5999
/************************************************************************/
6000
/*                           OGR_L_Union()                              */
6001
/************************************************************************/
6002
6003
/**
6004
 * \brief Union of two layers.
6005
 *
6006
 * The result layer contains features whose geometries represent areas
6007
 * that are in either in the input layer, in the method layer, or in
6008
 * both. The features in the result layer have attributes from both
6009
 * input and method layers. For features which represent areas that
6010
 * are only in the input or in the method layer the respective
6011
 * attributes have undefined values. The schema of the result layer
6012
 * can be set by the user or, if it is empty, is initialized to
6013
 * contain all fields in the input and method layers.
6014
 *
6015
 * \note If the schema of the result is set by user and contains
6016
 * fields that have the same name as a field in input and in method
6017
 * layer, then the attribute in the result feature will get the value
6018
 * from the feature of the method layer (even if it is undefined).
6019
 *
6020
 * \note For best performance use the minimum amount of features in
6021
 * the method layer and copy it into a memory layer.
6022
 *
6023
 * \note This method relies on GEOS support. Do not use unless the
6024
 * GEOS support is compiled in.
6025
 *
6026
 * The recognized list of options is :
6027
 * <ul>
6028
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6029
 *     feature could not be inserted or a GEOS call failed.
6030
 * </li>
6031
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
6032
 *     into MultiPolygons, LineStrings to MultiLineStrings or
6033
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
6034
 * </li>
6035
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6036
 *     will be created from the fields of the input layer.
6037
 * </li>
6038
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6039
 *     will be created from the fields of the method layer.
6040
 * </li>
6041
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
6042
 *     geometries to pretest intersection of features of method layer
6043
 *     with features of this layer.
6044
 * </li>
6045
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
6046
 *     result features with lower dimension geometry that would
6047
 *     otherwise be added to the result layer. The default is YES, to add
6048
 *     features with lower dimension geometry, but only if the result layer
6049
 *     has an unknown geometry type.
6050
 * </li>
6051
 * </ul>
6052
 *
6053
 * This function is the same as the C++ method OGRLayer::Union().
6054
 *
6055
 * @param pLayerInput the input layer. Should not be NULL.
6056
 *
6057
 * @param pLayerMethod the method layer. Should not be NULL.
6058
 *
6059
 * @param pLayerResult the layer where the features resulting from the
6060
 * operation are inserted. Should not be NULL. See above the note
6061
 * about the schema.
6062
 *
6063
 * @param papszOptions NULL terminated list of options (may be NULL).
6064
 *
6065
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
6066
 * reporting progress or NULL.
6067
 *
6068
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6069
 *
6070
 * @return an error code if there was an error or the execution was
6071
 * interrupted, OGRERR_NONE otherwise.
6072
 *
6073
 * @note The first geometry field is always used.
6074
 *
6075
 * @since OGR 1.10
6076
 */
6077
6078
OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
6079
                   OGRLayerH pLayerResult, char **papszOptions,
6080
                   GDALProgressFunc pfnProgress, void *pProgressArg)
6081
6082
0
{
6083
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
6084
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
6085
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
6086
6087
0
    return OGRLayer::FromHandle(pLayerInput)
6088
0
        ->Union(OGRLayer::FromHandle(pLayerMethod),
6089
0
                OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
6090
0
                pProgressArg);
6091
0
}
6092
6093
/************************************************************************/
6094
/*                          SymDifference()                             */
6095
/************************************************************************/
6096
6097
/**
6098
 * \brief Symmetrical difference of two layers.
6099
 *
6100
 * The result layer contains features whose geometries represent areas
6101
 * that are in either in the input layer or in the method layer but
6102
 * not in both. The features in the result layer have attributes from
6103
 * both input and method layers. For features which represent areas
6104
 * that are only in the input or in the method layer the respective
6105
 * attributes have undefined values. The schema of the result layer
6106
 * can be set by the user or, if it is empty, is initialized to
6107
 * contain all fields in the input and method layers.
6108
 *
6109
 * \note If the schema of the result is set by user and contains
6110
 * fields that have the same name as a field in input and in method
6111
 * layer, then the attribute in the result feature will get the value
6112
 * from the feature of the method layer (even if it is undefined).
6113
 *
6114
 * \note For best performance use the minimum amount of features in
6115
 * the method layer and copy it into a memory layer.
6116
 *
6117
 * \note This method relies on GEOS support. Do not use unless the
6118
 * GEOS support is compiled in.
6119
 *
6120
 * The recognized list of options is :
6121
 * <ul>
6122
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6123
 *     feature could not be inserted or a GEOS call failed.
6124
 * </li>
6125
 * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
6126
 *     into MultiPolygons, or LineStrings to MultiLineStrings.
6127
 * </li>
6128
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6129
 *     will be created from the fields of the input layer.
6130
 * </li>
6131
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6132
 *     will be created from the fields of the method layer.
6133
 * </li>
6134
 * </ul>
6135
 *
6136
 * This method is the same as the C function OGR_L_SymDifference().
6137
 *
6138
 * @param pLayerMethod the method layer. Should not be NULL.
6139
 *
6140
 * @param pLayerResult the layer where the features resulting from the
6141
 * operation are inserted. Should not be NULL. See above the note
6142
 * about the schema.
6143
 *
6144
 * @param papszOptions NULL terminated list of options (may be NULL).
6145
 *
6146
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
6147
 * reporting progress or NULL.
6148
 *
6149
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6150
 *
6151
 * @return an error code if there was an error or the execution was
6152
 * interrupted, OGRERR_NONE otherwise.
6153
 *
6154
 * @note The first geometry field is always used.
6155
 *
6156
 * @since OGR 1.10
6157
 */
6158
6159
OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
6160
                               char **papszOptions,
6161
                               GDALProgressFunc pfnProgress, void *pProgressArg)
6162
0
{
6163
0
    OGRErr ret = OGRERR_NONE;
6164
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
6165
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
6166
0
    OGRFeatureDefn *poDefnResult = nullptr;
6167
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
6168
0
    OGRGeometry *pGeometryInputFilter = nullptr;
6169
0
    int *mapInput = nullptr;
6170
0
    int *mapMethod = nullptr;
6171
0
    double progress_max =
6172
0
        static_cast<double>(GetFeatureCount(FALSE)) +
6173
0
        static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
6174
0
    double progress_counter = 0;
6175
0
    double progress_ticker = 0;
6176
0
    const bool bSkipFailures =
6177
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
6178
0
    const bool bPromoteToMulti = CPLTestBool(
6179
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
6180
6181
    // check for GEOS
6182
0
    if (!OGRGeometryFactory::haveGEOS())
6183
0
    {
6184
0
        CPLError(CE_Failure, CPLE_AppDefined,
6185
0
                 "OGRLayer::SymDifference() requires GEOS support");
6186
0
        return OGRERR_UNSUPPORTED_OPERATION;
6187
0
    }
6188
6189
    // get resources
6190
0
    ret = clone_spatial_filter(this, &pGeometryInputFilter);
6191
0
    if (ret != OGRERR_NONE)
6192
0
        goto done;
6193
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
6194
0
    if (ret != OGRERR_NONE)
6195
0
        goto done;
6196
0
    ret = create_field_map(poDefnInput, &mapInput);
6197
0
    if (ret != OGRERR_NONE)
6198
0
        goto done;
6199
0
    ret = create_field_map(poDefnMethod, &mapMethod);
6200
0
    if (ret != OGRERR_NONE)
6201
0
        goto done;
6202
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
6203
0
                            mapMethod, true, papszOptions);
6204
0
    if (ret != OGRERR_NONE)
6205
0
        goto done;
6206
0
    poDefnResult = pLayerResult->GetLayerDefn();
6207
6208
    // add features based on input layer
6209
0
    for (auto &&x : this)
6210
0
    {
6211
6212
0
        if (pfnProgress)
6213
0
        {
6214
0
            double p = progress_counter / progress_max;
6215
0
            if (p > progress_ticker)
6216
0
            {
6217
0
                if (!pfnProgress(p, "", pProgressArg))
6218
0
                {
6219
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6220
0
                    ret = OGRERR_FAILURE;
6221
0
                    goto done;
6222
0
                }
6223
0
            }
6224
0
            progress_counter += 1.0;
6225
0
        }
6226
6227
        // set up the filter on method layer
6228
0
        CPLErrorReset();
6229
0
        OGRGeometry *x_geom =
6230
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
6231
0
        if (CPLGetLastErrorType() != CE_None)
6232
0
        {
6233
0
            if (!bSkipFailures)
6234
0
            {
6235
0
                ret = OGRERR_FAILURE;
6236
0
                goto done;
6237
0
            }
6238
0
            else
6239
0
            {
6240
0
                CPLErrorReset();
6241
0
                ret = OGRERR_NONE;
6242
0
            }
6243
0
        }
6244
0
        if (!x_geom)
6245
0
        {
6246
0
            continue;
6247
0
        }
6248
6249
0
        OGRGeometryUniquePtr geom(
6250
0
            x_geom
6251
0
                ->clone());  // this will be the geometry of the result feature
6252
0
        for (auto &&y : pLayerMethod)
6253
0
        {
6254
0
            OGRGeometry *y_geom = y->GetGeometryRef();
6255
0
            if (!y_geom)
6256
0
            {
6257
0
                continue;
6258
0
            }
6259
0
            if (geom)
6260
0
            {
6261
0
                CPLErrorReset();
6262
0
                OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
6263
0
                if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
6264
0
                {
6265
0
                    if (!bSkipFailures)
6266
0
                    {
6267
0
                        ret = OGRERR_FAILURE;
6268
0
                        goto done;
6269
0
                    }
6270
0
                    else
6271
0
                    {
6272
0
                        CPLErrorReset();
6273
0
                        ret = OGRERR_NONE;
6274
0
                    }
6275
0
                }
6276
0
                else
6277
0
                {
6278
0
                    geom.swap(geom_new);
6279
0
                }
6280
0
            }
6281
0
            if (geom && geom->IsEmpty())
6282
0
                break;
6283
0
        }
6284
6285
0
        if (geom && !geom->IsEmpty())
6286
0
        {
6287
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6288
0
            z->SetFieldsFrom(x.get(), mapInput);
6289
0
            if (bPromoteToMulti)
6290
0
                geom.reset(promote_to_multi(geom.release()));
6291
0
            z->SetGeometryDirectly(geom.release());
6292
0
            ret = pLayerResult->CreateFeature(z.get());
6293
0
            if (ret != OGRERR_NONE)
6294
0
            {
6295
0
                if (!bSkipFailures)
6296
0
                {
6297
0
                    goto done;
6298
0
                }
6299
0
                else
6300
0
                {
6301
0
                    CPLErrorReset();
6302
0
                    ret = OGRERR_NONE;
6303
0
                }
6304
0
            }
6305
0
        }
6306
0
    }
6307
6308
    // restore filter on method layer and add features based on it
6309
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
6310
0
    for (auto &&x : pLayerMethod)
6311
0
    {
6312
6313
0
        if (pfnProgress)
6314
0
        {
6315
0
            double p = progress_counter / progress_max;
6316
0
            if (p > progress_ticker)
6317
0
            {
6318
0
                if (!pfnProgress(p, "", pProgressArg))
6319
0
                {
6320
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6321
0
                    ret = OGRERR_FAILURE;
6322
0
                    goto done;
6323
0
                }
6324
0
            }
6325
0
            progress_counter += 1.0;
6326
0
        }
6327
6328
        // set up the filter on input layer
6329
0
        CPLErrorReset();
6330
0
        OGRGeometry *x_geom =
6331
0
            set_filter_from(this, pGeometryInputFilter, x.get());
6332
0
        if (CPLGetLastErrorType() != CE_None)
6333
0
        {
6334
0
            if (!bSkipFailures)
6335
0
            {
6336
0
                ret = OGRERR_FAILURE;
6337
0
                goto done;
6338
0
            }
6339
0
            else
6340
0
            {
6341
0
                CPLErrorReset();
6342
0
                ret = OGRERR_NONE;
6343
0
            }
6344
0
        }
6345
0
        if (!x_geom)
6346
0
        {
6347
0
            continue;
6348
0
        }
6349
6350
0
        OGRGeometryUniquePtr geom(
6351
0
            x_geom
6352
0
                ->clone());  // this will be the geometry of the result feature
6353
0
        for (auto &&y : this)
6354
0
        {
6355
0
            OGRGeometry *y_geom = y->GetGeometryRef();
6356
0
            if (!y_geom)
6357
0
                continue;
6358
0
            if (geom)
6359
0
            {
6360
0
                CPLErrorReset();
6361
0
                OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
6362
0
                if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
6363
0
                {
6364
0
                    if (!bSkipFailures)
6365
0
                    {
6366
0
                        ret = OGRERR_FAILURE;
6367
0
                        goto done;
6368
0
                    }
6369
0
                    else
6370
0
                    {
6371
0
                        CPLErrorReset();
6372
0
                        ret = OGRERR_NONE;
6373
0
                    }
6374
0
                }
6375
0
                else
6376
0
                {
6377
0
                    geom.swap(geom_new);
6378
0
                }
6379
0
            }
6380
0
            if (geom == nullptr || geom->IsEmpty())
6381
0
                break;
6382
0
        }
6383
6384
0
        if (geom && !geom->IsEmpty())
6385
0
        {
6386
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6387
0
            z->SetFieldsFrom(x.get(), mapMethod);
6388
0
            if (bPromoteToMulti)
6389
0
                geom.reset(promote_to_multi(geom.release()));
6390
0
            z->SetGeometryDirectly(geom.release());
6391
0
            ret = pLayerResult->CreateFeature(z.get());
6392
0
            if (ret != OGRERR_NONE)
6393
0
            {
6394
0
                if (!bSkipFailures)
6395
0
                {
6396
0
                    goto done;
6397
0
                }
6398
0
                else
6399
0
                {
6400
0
                    CPLErrorReset();
6401
0
                    ret = OGRERR_NONE;
6402
0
                }
6403
0
            }
6404
0
        }
6405
0
    }
6406
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
6407
0
    {
6408
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6409
0
        ret = OGRERR_FAILURE;
6410
0
        goto done;
6411
0
    }
6412
0
done:
6413
    // release resources
6414
0
    SetSpatialFilter(pGeometryInputFilter);
6415
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
6416
0
    if (pGeometryMethodFilter)
6417
0
        delete pGeometryMethodFilter;
6418
0
    if (pGeometryInputFilter)
6419
0
        delete pGeometryInputFilter;
6420
0
    if (mapInput)
6421
0
        VSIFree(mapInput);
6422
0
    if (mapMethod)
6423
0
        VSIFree(mapMethod);
6424
0
    return ret;
6425
0
}
6426
6427
/************************************************************************/
6428
/*                        OGR_L_SymDifference()                         */
6429
/************************************************************************/
6430
6431
/**
6432
 * \brief Symmetrical difference of two layers.
6433
 *
6434
 * The result layer contains features whose geometries represent areas
6435
 * that are in either in the input layer or in the method layer but
6436
 * not in both. The features in the result layer have attributes from
6437
 * both input and method layers. For features which represent areas
6438
 * that are only in the input or in the method layer the respective
6439
 * attributes have undefined values. The schema of the result layer
6440
 * can be set by the user or, if it is empty, is initialized to
6441
 * contain all fields in the input and method layers.
6442
 *
6443
 * \note If the schema of the result is set by user and contains
6444
 * fields that have the same name as a field in input and in method
6445
 * layer, then the attribute in the result feature will get the value
6446
 * from the feature of the method layer (even if it is undefined).
6447
 *
6448
 * \note For best performance use the minimum amount of features in
6449
 * the method layer and copy it into a memory layer.
6450
 *
6451
 * \note This method relies on GEOS support. Do not use unless the
6452
 * GEOS support is compiled in.
6453
 *
6454
 * The recognized list of options is :
6455
 * <ul>
6456
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6457
 *     feature could not be inserted or a GEOS call failed.
6458
 * </li>
6459
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
6460
 *     into MultiPolygons, LineStrings to MultiLineStrings or
6461
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
6462
 * </li>
6463
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6464
 *     will be created from the fields of the input layer.
6465
 * </li>
6466
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6467
 *     will be created from the fields of the method layer.
6468
 * </li>
6469
 * </ul>
6470
 *
6471
 * This function is the same as the C++ method OGRLayer::SymDifference().
6472
 *
6473
 * @param pLayerInput the input layer. Should not be NULL.
6474
 *
6475
 * @param pLayerMethod the method layer. Should not be NULL.
6476
 *
6477
 * @param pLayerResult the layer where the features resulting from the
6478
 * operation are inserted. Should not be NULL. See above the note
6479
 * about the schema.
6480
 *
6481
 * @param papszOptions NULL terminated list of options (may be NULL).
6482
 *
6483
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
6484
 * reporting progress or NULL.
6485
 *
6486
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6487
 *
6488
 * @return an error code if there was an error or the execution was
6489
 * interrupted, OGRERR_NONE otherwise.
6490
 *
6491
 * @note The first geometry field is always used.
6492
 *
6493
 * @since OGR 1.10
6494
 */
6495
6496
OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
6497
                           OGRLayerH pLayerResult, char **papszOptions,
6498
                           GDALProgressFunc pfnProgress, void *pProgressArg)
6499
6500
0
{
6501
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
6502
0
                      OGRERR_INVALID_HANDLE);
6503
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
6504
0
                      OGRERR_INVALID_HANDLE);
6505
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
6506
0
                      OGRERR_INVALID_HANDLE);
6507
6508
0
    return OGRLayer::FromHandle(pLayerInput)
6509
0
        ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
6510
0
                        OGRLayer::FromHandle(pLayerResult), papszOptions,
6511
0
                        pfnProgress, pProgressArg);
6512
0
}
6513
6514
/************************************************************************/
6515
/*                            Identity()                                */
6516
/************************************************************************/
6517
6518
/**
6519
 * \brief Identify the features of this layer with the ones from the
6520
 * identity layer.
6521
 *
6522
 * The result layer contains features whose geometries represent areas
6523
 * that are in the input layer. The features in the result layer have
6524
 * attributes from both input and method layers. The schema of the
6525
 * result layer can be set by the user or, if it is empty, is
6526
 * initialized to contain all fields in input and method layers.
6527
 *
6528
 * \note If the schema of the result is set by user and contains
6529
 * fields that have the same name as a field in input and in method
6530
 * layer, then the attribute in the result feature will get the value
6531
 * from the feature of the method layer (even if it is undefined).
6532
 *
6533
 * \note For best performance use the minimum amount of features in
6534
 * the method layer and copy it into a memory layer.
6535
 *
6536
 * \note This method relies on GEOS support. Do not use unless the
6537
 * GEOS support is compiled in.
6538
 *
6539
 * The recognized list of options is :
6540
 * <ul>
6541
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6542
 *     feature could not be inserted or a GEOS call failed.
6543
 * </li>
6544
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
6545
 *     into MultiPolygons, LineStrings to MultiLineStrings or
6546
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
6547
 * </li>
6548
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6549
 *     will be created from the fields of the input layer.
6550
 * </li>
6551
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6552
 *     will be created from the fields of the method layer.
6553
 * </li>
6554
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
6555
 *     geometries to pretest intersection of features of method layer
6556
 *     with features of this layer.
6557
 * </li>
6558
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
6559
 *     result features with lower dimension geometry that would
6560
 *     otherwise be added to the result layer. The default is YES, to add
6561
 *     features with lower dimension geometry, but only if the result layer
6562
 *     has an unknown geometry type.
6563
 * </li>
6564
 * </ul>
6565
 *
6566
 * This method is the same as the C function OGR_L_Identity().
6567
 *
6568
 * @param pLayerMethod the method layer. Should not be NULL.
6569
 *
6570
 * @param pLayerResult the layer where the features resulting from the
6571
 * operation are inserted. Should not be NULL. See above the note
6572
 * about the schema.
6573
 *
6574
 * @param papszOptions NULL terminated list of options (may be NULL).
6575
 *
6576
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
6577
 * reporting progress or NULL.
6578
 *
6579
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6580
 *
6581
 * @return an error code if there was an error or the execution was
6582
 * interrupted, OGRERR_NONE otherwise.
6583
 *
6584
 * @note The first geometry field is always used.
6585
 *
6586
 * @since OGR 1.10
6587
 */
6588
6589
OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
6590
                          char **papszOptions, GDALProgressFunc pfnProgress,
6591
                          void *pProgressArg)
6592
0
{
6593
0
    OGRErr ret = OGRERR_NONE;
6594
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
6595
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
6596
0
    OGRFeatureDefn *poDefnResult = nullptr;
6597
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
6598
0
    int *mapInput = nullptr;
6599
0
    int *mapMethod = nullptr;
6600
0
    double progress_max = static_cast<double>(GetFeatureCount(FALSE));
6601
0
    double progress_counter = 0;
6602
0
    double progress_ticker = 0;
6603
0
    const bool bSkipFailures =
6604
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
6605
0
    const bool bPromoteToMulti = CPLTestBool(
6606
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
6607
0
    const bool bUsePreparedGeometries = CPLTestBool(
6608
0
        CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
6609
0
    bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
6610
0
        papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
6611
6612
    // check for GEOS
6613
0
    if (!OGRGeometryFactory::haveGEOS())
6614
0
    {
6615
0
        CPLError(CE_Failure, CPLE_AppDefined,
6616
0
                 "OGRLayer::Identity() requires GEOS support");
6617
0
        return OGRERR_UNSUPPORTED_OPERATION;
6618
0
    }
6619
0
    if (bKeepLowerDimGeom)
6620
0
    {
6621
        // require that the result layer is of geom type unknown
6622
0
        if (pLayerResult->GetGeomType() != wkbUnknown)
6623
0
        {
6624
0
            CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
6625
0
                            "since the result layer does not allow it.");
6626
0
            bKeepLowerDimGeom = FALSE;
6627
0
        }
6628
0
    }
6629
6630
    // get resources
6631
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
6632
0
    if (ret != OGRERR_NONE)
6633
0
        goto done;
6634
0
    ret = create_field_map(poDefnInput, &mapInput);
6635
0
    if (ret != OGRERR_NONE)
6636
0
        goto done;
6637
0
    ret = create_field_map(poDefnMethod, &mapMethod);
6638
0
    if (ret != OGRERR_NONE)
6639
0
        goto done;
6640
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
6641
0
                            mapMethod, true, papszOptions);
6642
0
    if (ret != OGRERR_NONE)
6643
0
        goto done;
6644
0
    poDefnResult = pLayerResult->GetLayerDefn();
6645
6646
    // split the features in input layer to the result layer
6647
0
    for (auto &&x : this)
6648
0
    {
6649
6650
0
        if (pfnProgress)
6651
0
        {
6652
0
            double p = progress_counter / progress_max;
6653
0
            if (p > progress_ticker)
6654
0
            {
6655
0
                if (!pfnProgress(p, "", pProgressArg))
6656
0
                {
6657
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6658
0
                    ret = OGRERR_FAILURE;
6659
0
                    goto done;
6660
0
                }
6661
0
            }
6662
0
            progress_counter += 1.0;
6663
0
        }
6664
6665
        // set up the filter on method layer
6666
0
        CPLErrorReset();
6667
0
        OGRGeometry *x_geom =
6668
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
6669
0
        if (CPLGetLastErrorType() != CE_None)
6670
0
        {
6671
0
            if (!bSkipFailures)
6672
0
            {
6673
0
                ret = OGRERR_FAILURE;
6674
0
                goto done;
6675
0
            }
6676
0
            else
6677
0
            {
6678
0
                CPLErrorReset();
6679
0
                ret = OGRERR_NONE;
6680
0
            }
6681
0
        }
6682
0
        if (!x_geom)
6683
0
        {
6684
0
            continue;
6685
0
        }
6686
6687
0
        OGRPreparedGeometryUniquePtr x_prepared_geom;
6688
0
        if (bUsePreparedGeometries)
6689
0
        {
6690
0
            x_prepared_geom.reset(
6691
0
                OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
6692
0
            if (!x_prepared_geom)
6693
0
            {
6694
0
                goto done;
6695
0
            }
6696
0
        }
6697
6698
0
        OGRGeometryUniquePtr x_geom_diff(
6699
0
            x_geom
6700
0
                ->clone());  // this will be the geometry of the result feature
6701
0
        for (auto &&y : pLayerMethod)
6702
0
        {
6703
0
            OGRGeometry *y_geom = y->GetGeometryRef();
6704
0
            if (!y_geom)
6705
0
                continue;
6706
6707
0
            CPLErrorReset();
6708
0
            if (x_prepared_geom &&
6709
0
                !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
6710
0
                                                OGRGeometry::ToHandle(y_geom))))
6711
0
            {
6712
0
                if (CPLGetLastErrorType() == CE_None)
6713
0
                {
6714
0
                    continue;
6715
0
                }
6716
0
            }
6717
0
            if (CPLGetLastErrorType() != CE_None)
6718
0
            {
6719
0
                if (!bSkipFailures)
6720
0
                {
6721
0
                    ret = OGRERR_FAILURE;
6722
0
                    goto done;
6723
0
                }
6724
0
                else
6725
0
                {
6726
0
                    CPLErrorReset();
6727
0
                    ret = OGRERR_NONE;
6728
0
                }
6729
0
            }
6730
6731
0
            CPLErrorReset();
6732
0
            OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
6733
0
            if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
6734
0
            {
6735
0
                if (!bSkipFailures)
6736
0
                {
6737
0
                    ret = OGRERR_FAILURE;
6738
0
                    goto done;
6739
0
                }
6740
0
                else
6741
0
                {
6742
0
                    CPLErrorReset();
6743
0
                    ret = OGRERR_NONE;
6744
0
                }
6745
0
            }
6746
0
            else if (poIntersection->IsEmpty() ||
6747
0
                     (!bKeepLowerDimGeom &&
6748
0
                      (x_geom->getDimension() == y_geom->getDimension() &&
6749
0
                       poIntersection->getDimension() <
6750
0
                           x_geom->getDimension())))
6751
0
            {
6752
                /* ok*/
6753
0
            }
6754
0
            else
6755
0
            {
6756
0
                OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6757
0
                z->SetFieldsFrom(x.get(), mapInput);
6758
0
                z->SetFieldsFrom(y.get(), mapMethod);
6759
0
                if (bPromoteToMulti)
6760
0
                    poIntersection.reset(
6761
0
                        promote_to_multi(poIntersection.release()));
6762
0
                z->SetGeometryDirectly(poIntersection.release());
6763
0
                if (x_geom_diff)
6764
0
                {
6765
0
                    CPLErrorReset();
6766
0
                    OGRGeometryUniquePtr x_geom_diff_new(
6767
0
                        x_geom_diff->Difference(y_geom));
6768
0
                    if (CPLGetLastErrorType() != CE_None ||
6769
0
                        x_geom_diff_new == nullptr)
6770
0
                    {
6771
0
                        if (!bSkipFailures)
6772
0
                        {
6773
0
                            ret = OGRERR_FAILURE;
6774
0
                            goto done;
6775
0
                        }
6776
0
                        else
6777
0
                        {
6778
0
                            CPLErrorReset();
6779
0
                        }
6780
0
                    }
6781
0
                    else
6782
0
                    {
6783
0
                        x_geom_diff.swap(x_geom_diff_new);
6784
0
                    }
6785
0
                }
6786
0
                ret = pLayerResult->CreateFeature(z.get());
6787
0
                if (ret != OGRERR_NONE)
6788
0
                {
6789
0
                    if (!bSkipFailures)
6790
0
                    {
6791
0
                        goto done;
6792
0
                    }
6793
0
                    else
6794
0
                    {
6795
0
                        CPLErrorReset();
6796
0
                        ret = OGRERR_NONE;
6797
0
                    }
6798
0
                }
6799
0
            }
6800
0
        }
6801
6802
0
        x_prepared_geom.reset();
6803
6804
0
        if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
6805
0
        {
6806
            /* ok */
6807
0
        }
6808
0
        else
6809
0
        {
6810
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6811
0
            z->SetFieldsFrom(x.get(), mapInput);
6812
0
            if (bPromoteToMulti)
6813
0
                x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
6814
0
            z->SetGeometryDirectly(x_geom_diff.release());
6815
0
            ret = pLayerResult->CreateFeature(z.get());
6816
0
            if (ret != OGRERR_NONE)
6817
0
            {
6818
0
                if (!bSkipFailures)
6819
0
                {
6820
0
                    goto done;
6821
0
                }
6822
0
                else
6823
0
                {
6824
0
                    CPLErrorReset();
6825
0
                    ret = OGRERR_NONE;
6826
0
                }
6827
0
            }
6828
0
        }
6829
0
    }
6830
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
6831
0
    {
6832
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6833
0
        ret = OGRERR_FAILURE;
6834
0
        goto done;
6835
0
    }
6836
0
done:
6837
    // release resources
6838
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
6839
0
    if (pGeometryMethodFilter)
6840
0
        delete pGeometryMethodFilter;
6841
0
    if (mapInput)
6842
0
        VSIFree(mapInput);
6843
0
    if (mapMethod)
6844
0
        VSIFree(mapMethod);
6845
0
    return ret;
6846
0
}
6847
6848
/************************************************************************/
6849
/*                         OGR_L_Identity()                             */
6850
/************************************************************************/
6851
6852
/**
6853
 * \brief Identify the features of this layer with the ones from the
6854
 * identity layer.
6855
 *
6856
 * The result layer contains features whose geometries represent areas
6857
 * that are in the input layer. The features in the result layer have
6858
 * attributes from both input and method layers. The schema of the
6859
 * result layer can be set by the user or, if it is empty, is
6860
 * initialized to contain all fields in input and method layers.
6861
 *
6862
 * \note If the schema of the result is set by user and contains
6863
 * fields that have the same name as a field in input and in method
6864
 * layer, then the attribute in the result feature will get the value
6865
 * from the feature of the method layer (even if it is undefined).
6866
 *
6867
 * \note For best performance use the minimum amount of features in
6868
 * the method layer and copy it into a memory layer.
6869
 *
6870
 * \note This method relies on GEOS support. Do not use unless the
6871
 * GEOS support is compiled in.
6872
 *
6873
 * The recognized list of options is :
6874
 * <ul>
6875
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6876
 *     feature could not be inserted or a GEOS call failed.
6877
 * </li>
6878
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
6879
 *     into MultiPolygons, LineStrings to MultiLineStrings or
6880
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
6881
 * </li>
6882
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6883
 *     will be created from the fields of the input layer.
6884
 * </li>
6885
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6886
 *     will be created from the fields of the method layer.
6887
 * </li>
6888
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
6889
 *     geometries to pretest intersection of features of method layer
6890
 *     with features of this layer.
6891
 * </li>
6892
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
6893
 *     result features with lower dimension geometry that would
6894
 *     otherwise be added to the result layer. The default is YES, to add
6895
 *     features with lower dimension geometry, but only if the result layer
6896
 *     has an unknown geometry type.
6897
 * </li>
6898
 * </ul>
6899
 *
6900
 * This function is the same as the C++ method OGRLayer::Identity().
6901
 *
6902
 * @param pLayerInput the input layer. Should not be NULL.
6903
 *
6904
 * @param pLayerMethod the method layer. Should not be NULL.
6905
 *
6906
 * @param pLayerResult the layer where the features resulting from the
6907
 * operation are inserted. Should not be NULL. See above the note
6908
 * about the schema.
6909
 *
6910
 * @param papszOptions NULL terminated list of options (may be NULL).
6911
 *
6912
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
6913
 * reporting progress or NULL.
6914
 *
6915
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6916
 *
6917
 * @return an error code if there was an error or the execution was
6918
 * interrupted, OGRERR_NONE otherwise.
6919
 *
6920
 * @note The first geometry field is always used.
6921
 *
6922
 * @since OGR 1.10
6923
 */
6924
6925
OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
6926
                      OGRLayerH pLayerResult, char **papszOptions,
6927
                      GDALProgressFunc pfnProgress, void *pProgressArg)
6928
6929
0
{
6930
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
6931
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
6932
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
6933
6934
0
    return OGRLayer::FromHandle(pLayerInput)
6935
0
        ->Identity(OGRLayer::FromHandle(pLayerMethod),
6936
0
                   OGRLayer::FromHandle(pLayerResult), papszOptions,
6937
0
                   pfnProgress, pProgressArg);
6938
0
}
6939
6940
/************************************************************************/
6941
/*                             Update()                                 */
6942
/************************************************************************/
6943
6944
/**
6945
 * \brief Update this layer with features from the update layer.
6946
 *
6947
 * The result layer contains features whose geometries represent areas
6948
 * that are either in the input layer or in the method layer. The
6949
 * features in the result layer have areas of the features of the
6950
 * method layer or those ares of the features of the input layer that
6951
 * are not covered by the method layer. The features of the result
6952
 * layer get their attributes from the input layer. The schema of the
6953
 * result layer can be set by the user or, if it is empty, is
6954
 * initialized to contain all fields in the input layer.
6955
 *
6956
 * \note If the schema of the result is set by user and contains
6957
 * fields that have the same name as a field in the method layer, then
6958
 * the attribute in the result feature the originates from the method
6959
 * layer will get the value from the feature of the method layer.
6960
 *
6961
 * \note For best performance use the minimum amount of features in
6962
 * the method layer and copy it into a memory layer.
6963
 *
6964
 * \note This method relies on GEOS support. Do not use unless the
6965
 * GEOS support is compiled in.
6966
 *
6967
 * The recognized list of options is :
6968
 * <ul>
6969
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6970
 *     feature could not be inserted or a GEOS call failed.
6971
 * </li>
6972
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
6973
 *     into MultiPolygons, LineStrings to MultiLineStrings or
6974
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
6975
 * </li>
6976
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6977
 *     will be created from the fields of the input layer.
6978
 * </li>
6979
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6980
 *     will be created from the fields of the method layer.
6981
 * </li>
6982
 * </ul>
6983
 *
6984
 * This method is the same as the C function OGR_L_Update().
6985
 *
6986
 * @param pLayerMethod the method layer. Should not be NULL.
6987
 *
6988
 * @param pLayerResult the layer where the features resulting from the
6989
 * operation are inserted. Should not be NULL. See above the note
6990
 * about the schema.
6991
 *
6992
 * @param papszOptions NULL terminated list of options (may be NULL).
6993
 *
6994
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
6995
 * reporting progress or NULL.
6996
 *
6997
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6998
 *
6999
 * @return an error code if there was an error or the execution was
7000
 * interrupted, OGRERR_NONE otherwise.
7001
 *
7002
 * @note The first geometry field is always used.
7003
 *
7004
 * @since OGR 1.10
7005
 */
7006
7007
OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
7008
                        char **papszOptions, GDALProgressFunc pfnProgress,
7009
                        void *pProgressArg)
7010
0
{
7011
0
    OGRErr ret = OGRERR_NONE;
7012
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
7013
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
7014
0
    OGRFeatureDefn *poDefnResult = nullptr;
7015
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
7016
0
    int *mapInput = nullptr;
7017
0
    int *mapMethod = nullptr;
7018
0
    double progress_max =
7019
0
        static_cast<double>(GetFeatureCount(FALSE)) +
7020
0
        static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
7021
0
    double progress_counter = 0;
7022
0
    double progress_ticker = 0;
7023
0
    const bool bSkipFailures =
7024
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
7025
0
    const bool bPromoteToMulti = CPLTestBool(
7026
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
7027
7028
    // check for GEOS
7029
0
    if (!OGRGeometryFactory::haveGEOS())
7030
0
    {
7031
0
        CPLError(CE_Failure, CPLE_AppDefined,
7032
0
                 "OGRLayer::Update() requires GEOS support");
7033
0
        return OGRERR_UNSUPPORTED_OPERATION;
7034
0
    }
7035
7036
    // get resources
7037
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
7038
0
    if (ret != OGRERR_NONE)
7039
0
        goto done;
7040
0
    ret = create_field_map(poDefnInput, &mapInput);
7041
0
    if (ret != OGRERR_NONE)
7042
0
        goto done;
7043
0
    ret = create_field_map(poDefnMethod, &mapMethod);
7044
0
    if (ret != OGRERR_NONE)
7045
0
        goto done;
7046
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
7047
0
                            mapMethod, false, papszOptions);
7048
0
    if (ret != OGRERR_NONE)
7049
0
        goto done;
7050
0
    poDefnResult = pLayerResult->GetLayerDefn();
7051
7052
    // add clipped features from the input layer
7053
0
    for (auto &&x : this)
7054
0
    {
7055
7056
0
        if (pfnProgress)
7057
0
        {
7058
0
            double p = progress_counter / progress_max;
7059
0
            if (p > progress_ticker)
7060
0
            {
7061
0
                if (!pfnProgress(p, "", pProgressArg))
7062
0
                {
7063
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7064
0
                    ret = OGRERR_FAILURE;
7065
0
                    goto done;
7066
0
                }
7067
0
            }
7068
0
            progress_counter += 1.0;
7069
0
        }
7070
7071
        // set up the filter on method layer
7072
0
        CPLErrorReset();
7073
0
        OGRGeometry *x_geom =
7074
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
7075
0
        if (CPLGetLastErrorType() != CE_None)
7076
0
        {
7077
0
            if (!bSkipFailures)
7078
0
            {
7079
0
                ret = OGRERR_FAILURE;
7080
0
                goto done;
7081
0
            }
7082
0
            else
7083
0
            {
7084
0
                CPLErrorReset();
7085
0
                ret = OGRERR_NONE;
7086
0
            }
7087
0
        }
7088
0
        if (!x_geom)
7089
0
        {
7090
0
            continue;
7091
0
        }
7092
7093
0
        OGRGeometryUniquePtr x_geom_diff(
7094
0
            x_geom->clone());  // this will be the geometry of a result feature
7095
0
        for (auto &&y : pLayerMethod)
7096
0
        {
7097
0
            OGRGeometry *y_geom = y->GetGeometryRef();
7098
0
            if (!y_geom)
7099
0
                continue;
7100
0
            if (x_geom_diff)
7101
0
            {
7102
0
                CPLErrorReset();
7103
0
                OGRGeometryUniquePtr x_geom_diff_new(
7104
0
                    x_geom_diff->Difference(y_geom));
7105
0
                if (CPLGetLastErrorType() != CE_None ||
7106
0
                    x_geom_diff_new == nullptr)
7107
0
                {
7108
0
                    if (!bSkipFailures)
7109
0
                    {
7110
0
                        ret = OGRERR_FAILURE;
7111
0
                        goto done;
7112
0
                    }
7113
0
                    else
7114
0
                    {
7115
0
                        CPLErrorReset();
7116
0
                        ret = OGRERR_NONE;
7117
0
                    }
7118
0
                }
7119
0
                else
7120
0
                {
7121
0
                    x_geom_diff.swap(x_geom_diff_new);
7122
0
                }
7123
0
            }
7124
0
        }
7125
7126
0
        if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
7127
0
        {
7128
            /* ok */
7129
0
        }
7130
0
        else
7131
0
        {
7132
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
7133
0
            z->SetFieldsFrom(x.get(), mapInput);
7134
0
            if (bPromoteToMulti)
7135
0
                x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
7136
0
            z->SetGeometryDirectly(x_geom_diff.release());
7137
0
            ret = pLayerResult->CreateFeature(z.get());
7138
0
            if (ret != OGRERR_NONE)
7139
0
            {
7140
0
                if (!bSkipFailures)
7141
0
                {
7142
0
                    goto done;
7143
0
                }
7144
0
                else
7145
0
                {
7146
0
                    CPLErrorReset();
7147
0
                    ret = OGRERR_NONE;
7148
0
                }
7149
0
            }
7150
0
        }
7151
0
    }
7152
7153
    // restore the original filter and add features from the update layer
7154
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7155
0
    for (auto &&y : pLayerMethod)
7156
0
    {
7157
7158
0
        if (pfnProgress)
7159
0
        {
7160
0
            double p = progress_counter / progress_max;
7161
0
            if (p > progress_ticker)
7162
0
            {
7163
0
                if (!pfnProgress(p, "", pProgressArg))
7164
0
                {
7165
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7166
0
                    ret = OGRERR_FAILURE;
7167
0
                    goto done;
7168
0
                }
7169
0
            }
7170
0
            progress_counter += 1.0;
7171
0
        }
7172
7173
0
        OGRGeometry *y_geom = y->StealGeometry();
7174
0
        if (!y_geom)
7175
0
            continue;
7176
0
        OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
7177
0
        if (mapMethod)
7178
0
            z->SetFieldsFrom(y.get(), mapMethod);
7179
0
        z->SetGeometryDirectly(y_geom);
7180
0
        ret = pLayerResult->CreateFeature(z.get());
7181
0
        if (ret != OGRERR_NONE)
7182
0
        {
7183
0
            if (!bSkipFailures)
7184
0
            {
7185
0
                goto done;
7186
0
            }
7187
0
            else
7188
0
            {
7189
0
                CPLErrorReset();
7190
0
                ret = OGRERR_NONE;
7191
0
            }
7192
0
        }
7193
0
    }
7194
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
7195
0
    {
7196
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7197
0
        ret = OGRERR_FAILURE;
7198
0
        goto done;
7199
0
    }
7200
0
done:
7201
    // release resources
7202
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7203
0
    if (pGeometryMethodFilter)
7204
0
        delete pGeometryMethodFilter;
7205
0
    if (mapInput)
7206
0
        VSIFree(mapInput);
7207
0
    if (mapMethod)
7208
0
        VSIFree(mapMethod);
7209
0
    return ret;
7210
0
}
7211
7212
/************************************************************************/
7213
/*                          OGR_L_Update()                              */
7214
/************************************************************************/
7215
7216
/**
7217
 * \brief Update this layer with features from the update layer.
7218
 *
7219
 * The result layer contains features whose geometries represent areas
7220
 * that are either in the input layer or in the method layer. The
7221
 * features in the result layer have areas of the features of the
7222
 * method layer or those ares of the features of the input layer that
7223
 * are not covered by the method layer. The features of the result
7224
 * layer get their attributes from the input layer. The schema of the
7225
 * result layer can be set by the user or, if it is empty, is
7226
 * initialized to contain all fields in the input layer.
7227
 *
7228
 * \note If the schema of the result is set by user and contains
7229
 * fields that have the same name as a field in the method layer, then
7230
 * the attribute in the result feature the originates from the method
7231
 * layer will get the value from the feature of the method layer.
7232
 *
7233
 * \note For best performance use the minimum amount of features in
7234
 * the method layer and copy it into a memory layer.
7235
 *
7236
 * \note This method relies on GEOS support. Do not use unless the
7237
 * GEOS support is compiled in.
7238
 *
7239
 * The recognized list of options is :
7240
 * <ul>
7241
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7242
 *     feature could not be inserted or a GEOS call failed.
7243
 * </li>
7244
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7245
 *     into MultiPolygons, LineStrings to MultiLineStrings or
7246
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
7247
 * </li>
7248
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7249
 *     will be created from the fields of the input layer.
7250
 * </li>
7251
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7252
 *     will be created from the fields of the method layer.
7253
 * </li>
7254
 * </ul>
7255
 *
7256
 * This function is the same as the C++ method OGRLayer::Update().
7257
 *
7258
 * @param pLayerInput the input layer. Should not be NULL.
7259
 *
7260
 * @param pLayerMethod the method layer. Should not be NULL.
7261
 *
7262
 * @param pLayerResult the layer where the features resulting from the
7263
 * operation are inserted. Should not be NULL. See above the note
7264
 * about the schema.
7265
 *
7266
 * @param papszOptions NULL terminated list of options (may be NULL).
7267
 *
7268
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
7269
 * reporting progress or NULL.
7270
 *
7271
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7272
 *
7273
 * @return an error code if there was an error or the execution was
7274
 * interrupted, OGRERR_NONE otherwise.
7275
 *
7276
 * @note The first geometry field is always used.
7277
 *
7278
 * @since OGR 1.10
7279
 */
7280
7281
OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
7282
                    OGRLayerH pLayerResult, char **papszOptions,
7283
                    GDALProgressFunc pfnProgress, void *pProgressArg)
7284
7285
0
{
7286
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
7287
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
7288
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
7289
7290
0
    return OGRLayer::FromHandle(pLayerInput)
7291
0
        ->Update(OGRLayer::FromHandle(pLayerMethod),
7292
0
                 OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
7293
0
                 pProgressArg);
7294
0
}
7295
7296
/************************************************************************/
7297
/*                              Clip()                                  */
7298
/************************************************************************/
7299
7300
/**
7301
 * \brief Clip off areas that are not covered by the method layer.
7302
 *
7303
 * The result layer contains features whose geometries represent areas
7304
 * that are in the input layer and in the method layer. The features
7305
 * in the result layer have the (possibly clipped) areas of features
7306
 * in the input layer and the attributes from the same features. The
7307
 * schema of the result layer can be set by the user or, if it is
7308
 * empty, is initialized to contain all fields in the input layer.
7309
 *
7310
 * \note For best performance use the minimum amount of features in
7311
 * the method layer and copy it into a memory layer.
7312
 *
7313
 * \note This method relies on GEOS support. Do not use unless the
7314
 * GEOS support is compiled in.
7315
 *
7316
 * The recognized list of options is :
7317
 * <ul>
7318
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7319
 *     feature could not be inserted or a GEOS call failed.
7320
 * </li>
7321
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7322
 *     into MultiPolygons, LineStrings to MultiLineStrings or
7323
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
7324
 * </li>
7325
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7326
 *     will be created from the fields of the input layer.
7327
 * </li>
7328
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7329
 *     will be created from the fields of the method layer.
7330
 * </li>
7331
 * </ul>
7332
 *
7333
 * This method is the same as the C function OGR_L_Clip().
7334
 *
7335
 * @param pLayerMethod the method layer. Should not be NULL.
7336
 *
7337
 * @param pLayerResult the layer where the features resulting from the
7338
 * operation are inserted. Should not be NULL. See above the note
7339
 * about the schema.
7340
 *
7341
 * @param papszOptions NULL terminated list of options (may be NULL).
7342
 *
7343
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
7344
 * reporting progress or NULL.
7345
 *
7346
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7347
 *
7348
 * @return an error code if there was an error or the execution was
7349
 * interrupted, OGRERR_NONE otherwise.
7350
 *
7351
 * @note The first geometry field is always used.
7352
 *
7353
 * @since OGR 1.10
7354
 */
7355
7356
OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
7357
                      char **papszOptions, GDALProgressFunc pfnProgress,
7358
                      void *pProgressArg)
7359
0
{
7360
0
    OGRErr ret = OGRERR_NONE;
7361
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
7362
0
    OGRFeatureDefn *poDefnResult = nullptr;
7363
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
7364
0
    int *mapInput = nullptr;
7365
0
    double progress_max = static_cast<double>(GetFeatureCount(FALSE));
7366
0
    double progress_counter = 0;
7367
0
    double progress_ticker = 0;
7368
0
    const bool bSkipFailures =
7369
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
7370
0
    const bool bPromoteToMulti = CPLTestBool(
7371
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
7372
7373
    // check for GEOS
7374
0
    if (!OGRGeometryFactory::haveGEOS())
7375
0
    {
7376
0
        CPLError(CE_Failure, CPLE_AppDefined,
7377
0
                 "OGRLayer::Clip() requires GEOS support");
7378
0
        return OGRERR_UNSUPPORTED_OPERATION;
7379
0
    }
7380
7381
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
7382
0
    if (ret != OGRERR_NONE)
7383
0
        goto done;
7384
0
    ret = create_field_map(poDefnInput, &mapInput);
7385
0
    if (ret != OGRERR_NONE)
7386
0
        goto done;
7387
0
    ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
7388
0
                            nullptr, false, papszOptions);
7389
0
    if (ret != OGRERR_NONE)
7390
0
        goto done;
7391
7392
0
    poDefnResult = pLayerResult->GetLayerDefn();
7393
0
    for (auto &&x : this)
7394
0
    {
7395
7396
0
        if (pfnProgress)
7397
0
        {
7398
0
            double p = progress_counter / progress_max;
7399
0
            if (p > progress_ticker)
7400
0
            {
7401
0
                if (!pfnProgress(p, "", pProgressArg))
7402
0
                {
7403
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7404
0
                    ret = OGRERR_FAILURE;
7405
0
                    goto done;
7406
0
                }
7407
0
            }
7408
0
            progress_counter += 1.0;
7409
0
        }
7410
7411
        // set up the filter on method layer
7412
0
        CPLErrorReset();
7413
0
        OGRGeometry *x_geom =
7414
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
7415
0
        if (CPLGetLastErrorType() != CE_None)
7416
0
        {
7417
0
            if (!bSkipFailures)
7418
0
            {
7419
0
                ret = OGRERR_FAILURE;
7420
0
                goto done;
7421
0
            }
7422
0
            else
7423
0
            {
7424
0
                CPLErrorReset();
7425
0
                ret = OGRERR_NONE;
7426
0
            }
7427
0
        }
7428
0
        if (!x_geom)
7429
0
        {
7430
0
            continue;
7431
0
        }
7432
7433
0
        OGRGeometryUniquePtr
7434
0
            geom;  // this will be the geometry of the result feature
7435
        // incrementally add area from y to geom
7436
0
        for (auto &&y : pLayerMethod)
7437
0
        {
7438
0
            OGRGeometry *y_geom = y->GetGeometryRef();
7439
0
            if (!y_geom)
7440
0
                continue;
7441
0
            if (!geom)
7442
0
            {
7443
0
                geom.reset(y_geom->clone());
7444
0
            }
7445
0
            else
7446
0
            {
7447
0
                CPLErrorReset();
7448
0
                OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
7449
0
                if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
7450
0
                {
7451
0
                    if (!bSkipFailures)
7452
0
                    {
7453
0
                        ret = OGRERR_FAILURE;
7454
0
                        goto done;
7455
0
                    }
7456
0
                    else
7457
0
                    {
7458
0
                        CPLErrorReset();
7459
0
                        ret = OGRERR_NONE;
7460
0
                    }
7461
0
                }
7462
0
                else
7463
0
                {
7464
0
                    geom.swap(geom_new);
7465
0
                }
7466
0
            }
7467
0
        }
7468
7469
        // possibly add a new feature with area x intersection sum of y
7470
0
        if (geom)
7471
0
        {
7472
0
            CPLErrorReset();
7473
0
            OGRGeometryUniquePtr poIntersection(
7474
0
                x_geom->Intersection(geom.get()));
7475
0
            if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
7476
0
            {
7477
0
                if (!bSkipFailures)
7478
0
                {
7479
0
                    ret = OGRERR_FAILURE;
7480
0
                    goto done;
7481
0
                }
7482
0
                else
7483
0
                {
7484
0
                    CPLErrorReset();
7485
0
                    ret = OGRERR_NONE;
7486
0
                }
7487
0
            }
7488
0
            else if (!poIntersection->IsEmpty())
7489
0
            {
7490
0
                OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
7491
0
                z->SetFieldsFrom(x.get(), mapInput);
7492
0
                if (bPromoteToMulti)
7493
0
                    poIntersection.reset(
7494
0
                        promote_to_multi(poIntersection.release()));
7495
0
                z->SetGeometryDirectly(poIntersection.release());
7496
0
                ret = pLayerResult->CreateFeature(z.get());
7497
0
                if (ret != OGRERR_NONE)
7498
0
                {
7499
0
                    if (!bSkipFailures)
7500
0
                    {
7501
0
                        goto done;
7502
0
                    }
7503
0
                    else
7504
0
                    {
7505
0
                        CPLErrorReset();
7506
0
                        ret = OGRERR_NONE;
7507
0
                    }
7508
0
                }
7509
0
            }
7510
0
        }
7511
0
    }
7512
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
7513
0
    {
7514
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7515
0
        ret = OGRERR_FAILURE;
7516
0
        goto done;
7517
0
    }
7518
0
done:
7519
    // release resources
7520
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7521
0
    if (pGeometryMethodFilter)
7522
0
        delete pGeometryMethodFilter;
7523
0
    if (mapInput)
7524
0
        VSIFree(mapInput);
7525
0
    return ret;
7526
0
}
7527
7528
/************************************************************************/
7529
/*                           OGR_L_Clip()                               */
7530
/************************************************************************/
7531
7532
/**
7533
 * \brief Clip off areas that are not covered by the method layer.
7534
 *
7535
 * The result layer contains features whose geometries represent areas
7536
 * that are in the input layer and in the method layer. The features
7537
 * in the result layer have the (possibly clipped) areas of features
7538
 * in the input layer and the attributes from the same features. The
7539
 * schema of the result layer can be set by the user or, if it is
7540
 * empty, is initialized to contain all fields in the input layer.
7541
 *
7542
 * \note For best performance use the minimum amount of features in
7543
 * the method layer and copy it into a memory layer.
7544
 *
7545
 * \note This method relies on GEOS support. Do not use unless the
7546
 * GEOS support is compiled in.
7547
 *
7548
 * The recognized list of options is :
7549
 * <ul>
7550
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7551
 *     feature could not be inserted or a GEOS call failed.
7552
 * </li>
7553
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7554
 *     into MultiPolygons, LineStrings to MultiLineStrings or
7555
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
7556
 * </li>
7557
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7558
 *     will be created from the fields of the input layer.
7559
 * </li>
7560
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7561
 *     will be created from the fields of the method layer.
7562
 * </li>
7563
 * </ul>
7564
 *
7565
 * This function is the same as the C++ method OGRLayer::Clip().
7566
 *
7567
 * @param pLayerInput the input layer. Should not be NULL.
7568
 *
7569
 * @param pLayerMethod the method layer. Should not be NULL.
7570
 *
7571
 * @param pLayerResult the layer where the features resulting from the
7572
 * operation are inserted. Should not be NULL. See above the note
7573
 * about the schema.
7574
 *
7575
 * @param papszOptions NULL terminated list of options (may be NULL).
7576
 *
7577
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
7578
 * reporting progress or NULL.
7579
 *
7580
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7581
 *
7582
 * @return an error code if there was an error or the execution was
7583
 * interrupted, OGRERR_NONE otherwise.
7584
 *
7585
 * @note The first geometry field is always used.
7586
 *
7587
 * @since OGR 1.10
7588
 */
7589
7590
OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
7591
                  OGRLayerH pLayerResult, char **papszOptions,
7592
                  GDALProgressFunc pfnProgress, void *pProgressArg)
7593
7594
0
{
7595
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
7596
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
7597
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
7598
7599
0
    return OGRLayer::FromHandle(pLayerInput)
7600
0
        ->Clip(OGRLayer::FromHandle(pLayerMethod),
7601
0
               OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
7602
0
               pProgressArg);
7603
0
}
7604
7605
/************************************************************************/
7606
/*                              Erase()                                 */
7607
/************************************************************************/
7608
7609
/**
7610
 * \brief Remove areas that are covered by the method layer.
7611
 *
7612
 * The result layer contains features whose geometries represent areas
7613
 * that are in the input layer but not in the method layer. The
7614
 * features in the result layer have attributes from the input
7615
 * layer. The schema of the result layer can be set by the user or, if
7616
 * it is empty, is initialized to contain all fields in the input
7617
 * layer.
7618
 *
7619
 * \note For best performance use the minimum amount of features in
7620
 * the method layer and copy it into a memory layer.
7621
 *
7622
 * \note This method relies on GEOS support. Do not use unless the
7623
 * GEOS support is compiled in.
7624
 *
7625
 * The recognized list of options is :
7626
 * <ul>
7627
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7628
 *     feature could not be inserted or a GEOS call failed.
7629
 * </li>
7630
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7631
 *     into MultiPolygons, LineStrings to MultiLineStrings or
7632
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
7633
 * </li>
7634
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7635
 *     will be created from the fields of the input layer.
7636
 * </li>
7637
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7638
 *     will be created from the fields of the method layer.
7639
 * </li>
7640
 * </ul>
7641
 *
7642
 * This method is the same as the C function OGR_L_Erase().
7643
 *
7644
 * @param pLayerMethod the method layer. Should not be NULL.
7645
 *
7646
 * @param pLayerResult the layer where the features resulting from the
7647
 * operation are inserted. Should not be NULL. See above the note
7648
 * about the schema.
7649
 *
7650
 * @param papszOptions NULL terminated list of options (may be NULL).
7651
 *
7652
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
7653
 * reporting progress or NULL.
7654
 *
7655
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7656
 *
7657
 * @return an error code if there was an error or the execution was
7658
 * interrupted, OGRERR_NONE otherwise.
7659
 *
7660
 * @note The first geometry field is always used.
7661
 *
7662
 * @since OGR 1.10
7663
 */
7664
7665
OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
7666
                       char **papszOptions, GDALProgressFunc pfnProgress,
7667
                       void *pProgressArg)
7668
0
{
7669
0
    OGRErr ret = OGRERR_NONE;
7670
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
7671
0
    OGRFeatureDefn *poDefnResult = nullptr;
7672
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
7673
0
    int *mapInput = nullptr;
7674
0
    double progress_max = static_cast<double>(GetFeatureCount(FALSE));
7675
0
    double progress_counter = 0;
7676
0
    double progress_ticker = 0;
7677
0
    const bool bSkipFailures =
7678
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
7679
0
    const bool bPromoteToMulti = CPLTestBool(
7680
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
7681
7682
    // check for GEOS
7683
0
    if (!OGRGeometryFactory::haveGEOS())
7684
0
    {
7685
0
        CPLError(CE_Failure, CPLE_AppDefined,
7686
0
                 "OGRLayer::Erase() requires GEOS support");
7687
0
        return OGRERR_UNSUPPORTED_OPERATION;
7688
0
    }
7689
7690
    // get resources
7691
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
7692
0
    if (ret != OGRERR_NONE)
7693
0
        goto done;
7694
0
    ret = create_field_map(poDefnInput, &mapInput);
7695
0
    if (ret != OGRERR_NONE)
7696
0
        goto done;
7697
0
    ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
7698
0
                            nullptr, false, papszOptions);
7699
0
    if (ret != OGRERR_NONE)
7700
0
        goto done;
7701
0
    poDefnResult = pLayerResult->GetLayerDefn();
7702
7703
0
    for (auto &&x : this)
7704
0
    {
7705
7706
0
        if (pfnProgress)
7707
0
        {
7708
0
            double p = progress_counter / progress_max;
7709
0
            if (p > progress_ticker)
7710
0
            {
7711
0
                if (!pfnProgress(p, "", pProgressArg))
7712
0
                {
7713
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7714
0
                    ret = OGRERR_FAILURE;
7715
0
                    goto done;
7716
0
                }
7717
0
            }
7718
0
            progress_counter += 1.0;
7719
0
        }
7720
7721
        // set up the filter on the method layer
7722
0
        CPLErrorReset();
7723
0
        OGRGeometry *x_geom =
7724
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
7725
0
        if (CPLGetLastErrorType() != CE_None)
7726
0
        {
7727
0
            if (!bSkipFailures)
7728
0
            {
7729
0
                ret = OGRERR_FAILURE;
7730
0
                goto done;
7731
0
            }
7732
0
            else
7733
0
            {
7734
0
                CPLErrorReset();
7735
0
                ret = OGRERR_NONE;
7736
0
            }
7737
0
        }
7738
0
        if (!x_geom)
7739
0
        {
7740
0
            continue;
7741
0
        }
7742
7743
0
        OGRGeometryUniquePtr geom(
7744
0
            x_geom
7745
0
                ->clone());  // this will be the geometry of the result feature
7746
        // incrementally erase y from geom
7747
0
        for (auto &&y : pLayerMethod)
7748
0
        {
7749
0
            OGRGeometry *y_geom = y->GetGeometryRef();
7750
0
            if (!y_geom)
7751
0
                continue;
7752
0
            CPLErrorReset();
7753
0
            OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
7754
0
            if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
7755
0
            {
7756
0
                if (!bSkipFailures)
7757
0
                {
7758
0
                    ret = OGRERR_FAILURE;
7759
0
                    goto done;
7760
0
                }
7761
0
                else
7762
0
                {
7763
0
                    CPLErrorReset();
7764
0
                    ret = OGRERR_NONE;
7765
0
                }
7766
0
            }
7767
0
            else
7768
0
            {
7769
0
                geom.swap(geom_new);
7770
0
                if (geom->IsEmpty())
7771
0
                {
7772
0
                    break;
7773
0
                }
7774
0
            }
7775
0
        }
7776
7777
        // add a new feature if there is remaining area
7778
0
        if (!geom->IsEmpty())
7779
0
        {
7780
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
7781
0
            z->SetFieldsFrom(x.get(), mapInput);
7782
0
            if (bPromoteToMulti)
7783
0
                geom.reset(promote_to_multi(geom.release()));
7784
0
            z->SetGeometryDirectly(geom.release());
7785
0
            ret = pLayerResult->CreateFeature(z.get());
7786
0
            if (ret != OGRERR_NONE)
7787
0
            {
7788
0
                if (!bSkipFailures)
7789
0
                {
7790
0
                    goto done;
7791
0
                }
7792
0
                else
7793
0
                {
7794
0
                    CPLErrorReset();
7795
0
                    ret = OGRERR_NONE;
7796
0
                }
7797
0
            }
7798
0
        }
7799
0
    }
7800
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
7801
0
    {
7802
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7803
0
        ret = OGRERR_FAILURE;
7804
0
        goto done;
7805
0
    }
7806
0
done:
7807
    // release resources
7808
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7809
0
    if (pGeometryMethodFilter)
7810
0
        delete pGeometryMethodFilter;
7811
0
    if (mapInput)
7812
0
        VSIFree(mapInput);
7813
0
    return ret;
7814
0
}
7815
7816
/************************************************************************/
7817
/*                           OGR_L_Erase()                              */
7818
/************************************************************************/
7819
7820
/**
7821
 * \brief Remove areas that are covered by the method layer.
7822
 *
7823
 * The result layer contains features whose geometries represent areas
7824
 * that are in the input layer but not in the method layer. The
7825
 * features in the result layer have attributes from the input
7826
 * layer. The schema of the result layer can be set by the user or, if
7827
 * it is empty, is initialized to contain all fields in the input
7828
 * layer.
7829
 *
7830
 * \note For best performance use the minimum amount of features in
7831
 * the method layer and copy it into a memory layer.
7832
 *
7833
 * \note This method relies on GEOS support. Do not use unless the
7834
 * GEOS support is compiled in.
7835
 *
7836
 * The recognized list of options is :
7837
 * <ul>
7838
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7839
 *     feature could not be inserted or a GEOS call failed.
7840
 * </li>
7841
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7842
 *     into MultiPolygons, LineStrings to MultiLineStrings or
7843
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
7844
 * </li>
7845
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7846
 *     will be created from the fields of the input layer.
7847
 * </li>
7848
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7849
 *     will be created from the fields of the method layer.
7850
 * </li>
7851
 * </ul>
7852
 *
7853
 * This function is the same as the C++ method OGRLayer::Erase().
7854
 *
7855
 * @param pLayerInput the input layer. Should not be NULL.
7856
 *
7857
 * @param pLayerMethod the method layer. Should not be NULL.
7858
 *
7859
 * @param pLayerResult the layer where the features resulting from the
7860
 * operation are inserted. Should not be NULL. See above the note
7861
 * about the schema.
7862
 *
7863
 * @param papszOptions NULL terminated list of options (may be NULL).
7864
 *
7865
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
7866
 * reporting progress or NULL.
7867
 *
7868
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7869
 *
7870
 * @return an error code if there was an error or the execution was
7871
 * interrupted, OGRERR_NONE otherwise.
7872
 *
7873
 * @note The first geometry field is always used.
7874
 *
7875
 * @since OGR 1.10
7876
 */
7877
7878
OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
7879
                   OGRLayerH pLayerResult, char **papszOptions,
7880
                   GDALProgressFunc pfnProgress, void *pProgressArg)
7881
7882
0
{
7883
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
7884
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
7885
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
7886
7887
0
    return OGRLayer::FromHandle(pLayerInput)
7888
0
        ->Erase(OGRLayer::FromHandle(pLayerMethod),
7889
0
                OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
7890
0
                pProgressArg);
7891
0
}
7892
7893
/************************************************************************/
7894
/*                  OGRLayer::FeatureIterator::Private                  */
7895
/************************************************************************/
7896
7897
struct OGRLayer::FeatureIterator::Private
7898
{
7899
    CPL_DISALLOW_COPY_ASSIGN(Private)
7900
0
    Private() = default;
7901
7902
    OGRFeatureUniquePtr m_poFeature{};
7903
    OGRLayer *m_poLayer = nullptr;
7904
    bool m_bError = false;
7905
    bool m_bEOF = true;
7906
};
7907
7908
/************************************************************************/
7909
/*                OGRLayer::FeatureIterator::FeatureIterator()          */
7910
/************************************************************************/
7911
7912
OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
7913
0
    : m_poPrivate(new OGRLayer::FeatureIterator::Private())
7914
0
{
7915
0
    m_poPrivate->m_poLayer = poLayer;
7916
0
    if (bStart)
7917
0
    {
7918
0
        if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
7919
0
        {
7920
0
            CPLError(CE_Failure, CPLE_NotSupported,
7921
0
                     "Only one feature iterator can be "
7922
0
                     "active at a time");
7923
0
            m_poPrivate->m_bError = true;
7924
0
        }
7925
0
        else
7926
0
        {
7927
0
            m_poPrivate->m_poLayer->ResetReading();
7928
0
            m_poPrivate->m_poFeature.reset(
7929
0
                m_poPrivate->m_poLayer->GetNextFeature());
7930
0
            m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
7931
0
            m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
7932
0
        }
7933
0
    }
7934
0
}
7935
7936
/************************************************************************/
7937
/*               ~OGRLayer::FeatureIterator::FeatureIterator()          */
7938
/************************************************************************/
7939
7940
OGRLayer::FeatureIterator::~FeatureIterator()
7941
0
{
7942
0
    if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
7943
0
        m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
7944
0
}
7945
7946
/************************************************************************/
7947
/*                              operator*()                             */
7948
/************************************************************************/
7949
7950
OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
7951
0
{
7952
0
    return m_poPrivate->m_poFeature;
7953
0
}
7954
7955
/************************************************************************/
7956
/*                              operator++()                            */
7957
/************************************************************************/
7958
7959
OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
7960
0
{
7961
0
    m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
7962
0
    m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
7963
0
    return *this;
7964
0
}
7965
7966
/************************************************************************/
7967
/*                             operator!=()                             */
7968
/************************************************************************/
7969
7970
bool OGRLayer::FeatureIterator::operator!=(
7971
    const OGRLayer::FeatureIterator &it) const
7972
0
{
7973
0
    return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
7974
0
}
7975
7976
/************************************************************************/
7977
/*                                 begin()                              */
7978
/************************************************************************/
7979
7980
OGRLayer::FeatureIterator OGRLayer::begin()
7981
0
{
7982
0
    return {this, true};
7983
0
}
7984
7985
/************************************************************************/
7986
/*                                  end()                               */
7987
/************************************************************************/
7988
7989
OGRLayer::FeatureIterator OGRLayer::end()
7990
0
{
7991
0
    return {this, false};
7992
0
}
7993
7994
/************************************************************************/
7995
/*                     OGRLayer::GetGeometryTypes()                     */
7996
/************************************************************************/
7997
7998
/** \brief Get actual geometry types found in features.
7999
 *
8000
 * This method iterates over features to retrieve their geometry types. This
8001
 * is mostly useful for layers that report a wkbUnknown geometry type with
8002
 * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
8003
 *
8004
 * By default this method returns an array of nEntryCount entries with each
8005
 * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
8006
 * number of features (in OGRGeometryTypeCounter::nCount).
8007
 * Features without geometries are reported as eGeomType == wkbNone.
8008
 *
8009
 * The nFlagsGGT parameter can be a combination (with binary or operator) of the
8010
 * following hints:
8011
 * <ul>
8012
 * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
8013
 * matter, not the number of features per geometry type. Consequently the value
8014
 * of OGRGeometryTypeCounter::nCount should be ignored.</li>
8015
 * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
8016
 * iterating over features as soon as 2 different geometry types (not counting
8017
 * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
8018
 * should be ignored (zero might be systematically reported by some
8019
 * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
8020
 * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
8021
 * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
8022
 * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
8023
 * geometries.</li>
8024
 * </ul>
8025
 *
8026
 * If the layer has no features, a non-NULL returned array with nEntryCount == 0
8027
 * will be returned.
8028
 *
8029
 * Spatial and/or attribute filters will be taken into account.
8030
 *
8031
 * This method will error out on a layer without geometry fields
8032
 * (GetGeomType() == wkbNone).
8033
 *
8034
 * A cancellation callback may be provided. The progress percentage it is called
8035
 * with is not relevant. The callback should return TRUE if processing should go
8036
 * on, or FALSE if it should be interrupted.
8037
 *
8038
 * @param iGeomField Geometry field index.
8039
 * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
8040
 *                  OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
8041
 * @param[out] nEntryCountOut Number of entries in the returned array.
8042
 * @param pfnProgress Cancellation callback. May be NULL.
8043
 * @param pProgressData User data for the cancellation callback. May be NULL.
8044
 * @return an array of nEntryCount that must be freed with CPLFree(),
8045
 *         or NULL in case of error
8046
 * @since GDAL 3.6
8047
 */
8048
OGRGeometryTypeCounter *
8049
OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
8050
                           GDALProgressFunc pfnProgress, void *pProgressData)
8051
0
{
8052
0
    OGRFeatureDefn *poDefn = GetLayerDefn();
8053
0
    const int nGeomFieldCount = poDefn->GetGeomFieldCount();
8054
0
    if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
8055
0
    {
8056
0
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
8057
0
        nEntryCountOut = 0;
8058
0
        return nullptr;
8059
0
    }
8060
8061
    // Ignore all fields but the geometry one of interest
8062
0
    CPLStringList aosIgnoredFieldsRestore;
8063
0
    CPLStringList aosIgnoredFields;
8064
0
    const int nFieldCount = poDefn->GetFieldCount();
8065
0
    for (int iField = 0; iField < nFieldCount; iField++)
8066
0
    {
8067
0
        const auto poFieldDefn = poDefn->GetFieldDefn(iField);
8068
0
        const char *pszName = poFieldDefn->GetNameRef();
8069
0
        if (poFieldDefn->IsIgnored())
8070
0
            aosIgnoredFieldsRestore.AddString(pszName);
8071
0
        if (iField != iGeomField)
8072
0
            aosIgnoredFields.AddString(pszName);
8073
0
    }
8074
0
    for (int iField = 0; iField < nGeomFieldCount; iField++)
8075
0
    {
8076
0
        const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
8077
0
        const char *pszName = poFieldDefn->GetNameRef();
8078
0
        if (poFieldDefn->IsIgnored())
8079
0
            aosIgnoredFieldsRestore.AddString(pszName);
8080
0
        if (iField != iGeomField)
8081
0
            aosIgnoredFields.AddString(pszName);
8082
0
    }
8083
0
    if (poDefn->IsStyleIgnored())
8084
0
        aosIgnoredFieldsRestore.AddString("OGR_STYLE");
8085
0
    aosIgnoredFields.AddString("OGR_STYLE");
8086
0
    SetIgnoredFields(aosIgnoredFields.List());
8087
8088
    // Iterate over features
8089
0
    std::map<OGRwkbGeometryType, int64_t> oMapCount;
8090
0
    std::set<OGRwkbGeometryType> oSetNotNull;
8091
0
    const bool bGeomCollectionZTInZ =
8092
0
        (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
8093
0
    const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
8094
0
    if (pfnProgress == GDALDummyProgress)
8095
0
        pfnProgress = nullptr;
8096
0
    bool bInterrupted = false;
8097
0
    for (auto &&poFeature : *this)
8098
0
    {
8099
0
        const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
8100
0
        if (poGeom == nullptr)
8101
0
        {
8102
0
            ++oMapCount[wkbNone];
8103
0
        }
8104
0
        else
8105
0
        {
8106
0
            auto eGeomType = poGeom->getGeometryType();
8107
0
            if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
8108
0
            {
8109
0
                const auto poGC = poGeom->toGeometryCollection();
8110
0
                if (poGC->getNumGeometries() > 0)
8111
0
                {
8112
0
                    auto eSubGeomType =
8113
0
                        poGC->getGeometryRef(0)->getGeometryType();
8114
0
                    if (eSubGeomType == wkbTINZ)
8115
0
                        eGeomType = wkbTINZ;
8116
0
                }
8117
0
            }
8118
0
            ++oMapCount[eGeomType];
8119
0
            if (bStopIfMixed)
8120
0
            {
8121
0
                oSetNotNull.insert(eGeomType);
8122
0
                if (oSetNotNull.size() == 2)
8123
0
                    break;
8124
0
            }
8125
0
        }
8126
0
        if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
8127
0
        {
8128
0
            bInterrupted = true;
8129
0
            break;
8130
0
        }
8131
0
    }
8132
8133
    // Restore ignore fields state
8134
0
    SetIgnoredFields(aosIgnoredFieldsRestore.List());
8135
8136
0
    if (bInterrupted)
8137
0
    {
8138
0
        nEntryCountOut = 0;
8139
0
        return nullptr;
8140
0
    }
8141
8142
    // Format result
8143
0
    nEntryCountOut = static_cast<int>(oMapCount.size());
8144
0
    OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
8145
0
        CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
8146
0
    int i = 0;
8147
0
    for (const auto &oIter : oMapCount)
8148
0
    {
8149
0
        pasRet[i].eGeomType = oIter.first;
8150
0
        pasRet[i].nCount = oIter.second;
8151
0
        ++i;
8152
0
    }
8153
0
    return pasRet;
8154
0
}
8155
8156
/************************************************************************/
8157
/*                      OGR_L_GetGeometryTypes()                        */
8158
/************************************************************************/
8159
8160
/** \brief Get actual geometry types found in features.
8161
 *
8162
 * See OGRLayer::GetGeometryTypes() for details.
8163
 *
8164
 * @param hLayer Layer.
8165
 * @param iGeomField Geometry field index.
8166
 * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
8167
 *               OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
8168
 * @param[out] pnEntryCount Pointer to the number of entries in the returned
8169
 *                          array. Must not be NULL.
8170
 * @param pfnProgress Cancellation callback. May be NULL.
8171
 * @param pProgressData User data for the cancellation callback. May be NULL.
8172
 * @return an array of *pnEntryCount that must be freed with CPLFree(),
8173
 *         or NULL in case of error
8174
 * @since GDAL 3.6
8175
 */
8176
OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
8177
                                               int nFlags, int *pnEntryCount,
8178
                                               GDALProgressFunc pfnProgress,
8179
                                               void *pProgressData)
8180
0
{
8181
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
8182
0
    VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
8183
8184
0
    return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
8185
0
        iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
8186
0
}
8187
8188
/************************************************************************/
8189
/*                    OGRLayer::GetSupportedSRSList()                   */
8190
/************************************************************************/
8191
8192
/** \brief Get the list of SRS supported.
8193
 *
8194
 * The base implementation of this method will return an empty list. Some
8195
 * drivers (OAPIF, WFS) may return a non-empty list.
8196
 *
8197
 * One of the SRS returned may be passed to SetActiveSRS() to change the
8198
 * active SRS.
8199
 *
8200
 * @param iGeomField Geometry field index.
8201
 * @return list of supported SRS.
8202
 * @since GDAL 3.7
8203
 */
8204
const OGRLayer::GetSupportedSRSListRetType &
8205
OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
8206
0
{
8207
0
    static OGRLayer::GetSupportedSRSListRetType empty;
8208
0
    return empty;
8209
0
}
8210
8211
/************************************************************************/
8212
/*                    OGR_L_GetSupportedSRSList()                       */
8213
/************************************************************************/
8214
8215
/** \brief Get the list of SRS supported.
8216
 *
8217
 * The base implementation of this method will return an empty list. Some
8218
 * drivers (OAPIF, WFS) may return a non-empty list.
8219
 *
8220
 * One of the SRS returned may be passed to SetActiveSRS() to change the
8221
 * active SRS.
8222
 *
8223
 * @param hLayer Layer.
8224
 * @param iGeomField Geometry field index.
8225
 * @param[out] pnCount Number of values in returned array. Must not be null.
8226
 * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
8227
 * nullptr
8228
 * @since GDAL 3.7
8229
 */
8230
OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
8231
                                                int iGeomField, int *pnCount)
8232
0
{
8233
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
8234
0
    VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
8235
8236
0
    const auto &srsList =
8237
0
        OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
8238
0
    *pnCount = static_cast<int>(srsList.size());
8239
0
    if (srsList.empty())
8240
0
    {
8241
0
        return nullptr;
8242
0
    }
8243
0
    OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
8244
0
        CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
8245
0
    size_t i = 0;
8246
0
    for (const auto &poSRS : srsList)
8247
0
    {
8248
0
        poSRS->Reference();
8249
0
        pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
8250
0
        ++i;
8251
0
    }
8252
0
    pahRet[i] = nullptr;
8253
0
    return pahRet;
8254
0
}
8255
8256
/************************************************************************/
8257
/*                       OGRLayer::SetActiveSRS()                       */
8258
/************************************************************************/
8259
8260
/** \brief Change the active SRS.
8261
 *
8262
 * The passed SRS must be in the list returned by GetSupportedSRSList()
8263
 * (the actual pointer may be different, but should be tested as identical
8264
 * with OGRSpatialReference::IsSame()).
8265
 *
8266
 * Changing the active SRS affects:
8267
 * <ul>
8268
 * <li>the SRS in which geometries of returned features are expressed,</li>
8269
 * <li>the SRS in which geometries of passed features (CreateFeature(),
8270
 * SetFeature()) are expressed,</li>
8271
 * <li>the SRS returned by GetSpatialRef() and
8272
 * GetGeomFieldDefn()->GetSpatialRef(),</li>
8273
 * <li>the SRS used to interpret SetSpatialFilter() values.</li>
8274
 * </ul>
8275
 * This also resets feature reading and the spatial filter.
8276
 * Note however that this does not modify the storage SRS of the features of
8277
 * geometries. Said otherwise, this setting is volatile and has no persistent
8278
 * effects after dataset reopening.
8279
 *
8280
 * @param iGeomField Geometry field index.
8281
 * @param poSRS SRS to use
8282
 * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
8283
 *         the passed SRS is not in GetSupportedSRSList()
8284
 * @since GDAL 3.7
8285
 */
8286
OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
8287
                              CPL_UNUSED const OGRSpatialReference *poSRS)
8288
0
{
8289
0
    return OGRERR_FAILURE;
8290
0
}
8291
8292
/************************************************************************/
8293
/*                         OGR_L_SetActiveSRS()                         */
8294
/************************************************************************/
8295
8296
/** \brief Change the active SRS.
8297
 *
8298
 * The passed SRS must be in the list returned by GetSupportedSRSList()
8299
 * (the actual pointer may be different, but should be tested as identical
8300
 * with OGRSpatialReference::IsSame()).
8301
 *
8302
 * Changing the active SRS affects:
8303
 * <ul>
8304
 * <li>the SRS in which geometries of returned features are expressed,</li>
8305
 * <li>the SRS in which geometries of passed features (CreateFeature(),
8306
 * SetFeature()) are expressed,</li>
8307
 * <li>the SRS returned by GetSpatialRef() and
8308
 * GetGeomFieldDefn()->GetSpatialRef(),</li>
8309
 * <li>the SRS used to interpret SetSpatialFilter() values.</li>
8310
 * </ul>
8311
 * This also resets feature reading and the spatial filter.
8312
 * Note however that this does not modify the storage SRS of the features of
8313
 * geometries. Said otherwise, this setting is volatile and has no persistent
8314
 * effects after dataset reopening.
8315
 *
8316
 * @param hLayer Layer.
8317
 * @param iGeomField Geometry field index.
8318
 * @param hSRS SRS to use
8319
 * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
8320
 *         the passed SRS is not in GetSupportedSRSList().
8321
 * @since GDAL 3.7
8322
 */
8323
OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
8324
                          OGRSpatialReferenceH hSRS)
8325
0
{
8326
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
8327
0
    return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
8328
0
        iGeomField, OGRSpatialReference::FromHandle(hSRS));
8329
0
}
8330
8331
/************************************************************************/
8332
/*                             GetDataset()                             */
8333
/************************************************************************/
8334
8335
/** Return the dataset associated with this layer.
8336
 *
8337
 * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
8338
 * have CreateLayer() capability. It may not be implemented in read-only
8339
 * drivers or out-of-tree drivers.
8340
 *
8341
 * It is currently only used by the GetRecordBatchSchema()
8342
 * method to retrieve the field domain associated with a field, to fill the
8343
 * dictionary field of a struct ArrowSchema.
8344
 * It is also used by CreateFieldFromArrowSchema() to determine which field
8345
 * types and subtypes are supported by the layer, by inspecting the driver
8346
 * metadata, and potentially use fallback types when needed.
8347
 *
8348
 * This method is the same as the C function OGR_L_GetDataset().
8349
 *
8350
 * @return dataset, or nullptr when unknown.
8351
 * @since GDAL 3.6
8352
 */
8353
GDALDataset *OGRLayer::GetDataset()
8354
0
{
8355
0
    return nullptr;
8356
0
}
8357
8358
/************************************************************************/
8359
/*                          OGR_L_GetDataset()                          */
8360
/************************************************************************/
8361
8362
/** Return the dataset associated with this layer.
8363
 *
8364
 * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
8365
 * have CreateLayer() capability. It may not be implemented in read-only
8366
 * drivers or out-of-tree drivers.
8367
 *
8368
 * It is currently only used by the GetRecordBatchSchema()
8369
 * method to retrieve the field domain associated with a field, to fill the
8370
 * dictionary field of a struct ArrowSchema.
8371
 * It is also used by CreateFieldFromArrowSchema() to determine which field
8372
 * types and subtypes are supported by the layer, by inspecting the driver
8373
 * metadata, and potentially use fallback types when needed.
8374
 *
8375
 * This function is the same as the C++ method OGRLayer::GetDataset().
8376
 *
8377
 * @return dataset, or nullptr when unknown.
8378
 * @since GDAL 3.9
8379
 */
8380
GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
8381
0
{
8382
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
8383
0
    return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
8384
0
}