Coverage Report

Created: 2026-02-14 06:52

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