Coverage Report

Created: 2025-12-31 06:48

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