Coverage Report

Created: 2025-08-28 06:57

/src/gdal/ogr/ogrsf_frmts/generic/ogrlayer.cpp
Line
Count
Source (jump to first uncovered line)
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 <set>
28
29
/************************************************************************/
30
/*                              OGRLayer()                              */
31
/************************************************************************/
32
33
OGRLayer::OGRLayer()
34
0
    : m_poPrivate(new Private()), m_bFilterIsEnvelope(FALSE),
35
0
      m_poFilterGeom(nullptr),
36
0
      m_pPreparedFilterGeom(nullptr), m_sFilterEnvelope{},
37
0
      m_iGeomFieldFilter(0), m_poStyleTable(nullptr), m_poAttrQuery(nullptr),
38
0
      m_pszAttrQueryString(nullptr), m_poAttrIndex(nullptr), m_nRefCount(0),
39
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
int OGRLayer::Reference()
93
94
0
{
95
0
    return ++m_nRefCount;
96
0
}
97
98
/************************************************************************/
99
/*                          OGR_L_Reference()                           */
100
/************************************************************************/
101
102
int OGR_L_Reference(OGRLayerH hLayer)
103
104
0
{
105
0
    VALIDATE_POINTER1(hLayer, "OGR_L_Reference", 0);
106
107
0
    return OGRLayer::FromHandle(hLayer)->Reference();
108
0
}
109
110
/************************************************************************/
111
/*                            Dereference()                             */
112
/************************************************************************/
113
114
int OGRLayer::Dereference()
115
116
0
{
117
0
    return --m_nRefCount;
118
0
}
119
120
/************************************************************************/
121
/*                         OGR_L_Dereference()                          */
122
/************************************************************************/
123
124
int OGR_L_Dereference(OGRLayerH hLayer)
125
126
0
{
127
0
    VALIDATE_POINTER1(hLayer, "OGR_L_Dereference", 0);
128
129
0
    return OGRLayer::FromHandle(hLayer)->Dereference();
130
0
}
131
132
/************************************************************************/
133
/*                            GetRefCount()                             */
134
/************************************************************************/
135
136
int OGRLayer::GetRefCount() const
137
138
0
{
139
0
    return m_nRefCount;
140
0
}
141
142
/************************************************************************/
143
/*                         OGR_L_GetRefCount()                          */
144
/************************************************************************/
145
146
int OGR_L_GetRefCount(OGRLayerH hLayer)
147
148
0
{
149
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetRefCount", 0);
150
151
0
    return OGRLayer::FromHandle(hLayer)->GetRefCount();
152
0
}
153
154
/************************************************************************/
155
/*                         GetFeatureCount()                            */
156
/************************************************************************/
157
158
GIntBig OGRLayer::GetFeatureCount(int bForce)
159
160
0
{
161
0
    if (!bForce)
162
0
        return -1;
163
164
0
    GIntBig nFeatureCount = 0;
165
0
    for (auto &&poFeature : *this)
166
0
    {
167
0
        CPL_IGNORE_RET_VAL(poFeature.get());
168
0
        nFeatureCount++;
169
0
    }
170
0
    ResetReading();
171
172
0
    return nFeatureCount;
173
0
}
174
175
/************************************************************************/
176
/*                      OGR_L_GetFeatureCount()                         */
177
/************************************************************************/
178
179
GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
180
181
0
{
182
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
183
184
0
#ifdef OGRAPISPY_ENABLED
185
0
    if (bOGRAPISpyEnabled)
186
0
        OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
187
0
#endif
188
189
0
    return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
190
0
}
191
192
/************************************************************************/
193
/*                            GetExtent()                               */
194
/************************************************************************/
195
196
/**
197
 \brief Fetch the extent of this layer.
198
199
 Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
200
 and it would be expensive to establish the extent then OGRERR_FAILURE
201
 will be returned indicating that the extent isn't know.  If bForce is
202
 TRUE then some implementations will actually scan the entire layer once
203
 to compute the MBR of all the features in the layer.
204
205
 Depending on the drivers, the returned extent may or may not take the
206
 spatial filter into account.  So it is safer to call GetExtent() without
207
 setting a spatial filter.
208
209
 Layers without any geometry may return OGRERR_FAILURE just indicating that
210
 no meaningful extents could be collected.
211
212
 Note that some implementations of this method may alter the read cursor
213
 of the layer.
214
215
 This method is the same as the C function OGR_L_GetExtent().
216
217
 @param psExtent the structure in which the extent value will be returned.
218
 @param bForce Flag indicating whether the extent should be computed even
219
 if it is expensive.
220
221
 @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
222
*/
223
224
OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, bool bForce)
225
0
{
226
0
    return GetExtent(0, psExtent, bForce);
227
0
}
228
229
/**
230
 \brief Fetch the extent of this layer, on the specified geometry field.
231
232
 Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
233
 and it would be expensive to establish the extent then OGRERR_FAILURE
234
 will be returned indicating that the extent isn't know.  If bForce is
235
 TRUE then some implementations will actually scan the entire layer once
236
 to compute the MBR of all the features in the layer.
237
238
 Depending on the drivers, the returned extent may or may not take the
239
 spatial filter into account.  So it is safer to call GetExtent() without
240
 setting a spatial filter.
241
242
 Layers without any geometry may return OGRERR_FAILURE just indicating that
243
 no meaningful extents could be collected.
244
245
 Note that some implementations of this method may alter the read cursor
246
 of the layer.
247
248
 This method is the same as the C function OGR_L_GetExtentEx().
249
250
 @param iGeomField the index of the geometry field on which to compute the extent.
251
 @param psExtent the structure in which the extent value will be returned.
252
 @param bForce Flag indicating whether the extent should be computed even
253
 if it is expensive.
254
255
 @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
256
257
*/
258
259
OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
260
0
{
261
0
    psExtent->MinX = 0.0;
262
0
    psExtent->MaxX = 0.0;
263
0
    psExtent->MinY = 0.0;
264
0
    psExtent->MaxY = 0.0;
265
266
    /* -------------------------------------------------------------------- */
267
    /*      If this layer has a none geometry type, then we can             */
268
    /*      reasonably assume there are not extents available.              */
269
    /* -------------------------------------------------------------------- */
270
0
    if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
271
0
        GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
272
0
    {
273
0
        if (iGeomField != 0)
274
0
        {
275
0
            CPLError(CE_Failure, CPLE_AppDefined,
276
0
                     "Invalid geometry field index : %d", iGeomField);
277
0
        }
278
0
        return OGRERR_FAILURE;
279
0
    }
280
281
0
    return IGetExtent(iGeomField, psExtent, bForce);
282
0
}
283
284
/************************************************************************/
285
/*                            IGetExtent()                              */
286
/************************************************************************/
287
288
/**
289
 \brief Fetch the extent of this layer, on the specified geometry field.
290
291
 Virtual method implemented by drivers since 3.11. In previous versions,
292
 GetExtent() itself was the virtual method.
293
294
 Driver implementations, when wanting to call the base method, must take
295
 care of calling OGRLayer::IGetExtent() (and note the public method without
296
 the leading I).
297
298
 @param iGeomField 0-based index of the geometry field to consider.
299
 @param psExtent the computed extent of the layer.
300
 @param bForce if TRUE, the extent will be computed even if all the
301
        layer features have to be fetched.
302
 @return OGRERR_NONE on success or an error code in case of failure.
303
 @since GDAL 3.11
304
*/
305
306
OGRErr OGRLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
307
308
0
{
309
    /* -------------------------------------------------------------------- */
310
    /*      If not forced, we should avoid having to scan all the           */
311
    /*      features and just return a failure.                             */
312
    /* -------------------------------------------------------------------- */
313
0
    if (!bForce)
314
0
        return OGRERR_FAILURE;
315
316
    /* -------------------------------------------------------------------- */
317
    /*      OK, we hate to do this, but go ahead and read through all       */
318
    /*      the features to collect geometries and build extents.           */
319
    /* -------------------------------------------------------------------- */
320
0
    OGREnvelope oEnv;
321
0
    bool bExtentSet = false;
322
323
0
    for (auto &&poFeature : *this)
324
0
    {
325
0
        OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
326
0
        if (poGeom == nullptr || poGeom->IsEmpty())
327
0
        {
328
            /* Do nothing */
329
0
        }
330
0
        else if (!bExtentSet)
331
0
        {
332
0
            poGeom->getEnvelope(psExtent);
333
0
            if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
334
0
                  std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
335
0
            {
336
0
                bExtentSet = true;
337
0
            }
338
0
        }
339
0
        else
340
0
        {
341
0
            poGeom->getEnvelope(&oEnv);
342
0
            if (oEnv.MinX < psExtent->MinX)
343
0
                psExtent->MinX = oEnv.MinX;
344
0
            if (oEnv.MinY < psExtent->MinY)
345
0
                psExtent->MinY = oEnv.MinY;
346
0
            if (oEnv.MaxX > psExtent->MaxX)
347
0
                psExtent->MaxX = oEnv.MaxX;
348
0
            if (oEnv.MaxY > psExtent->MaxY)
349
0
                psExtent->MaxY = oEnv.MaxY;
350
0
        }
351
0
    }
352
0
    ResetReading();
353
354
0
    return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
355
0
}
356
357
/************************************************************************/
358
/*                          OGR_L_GetExtent()                           */
359
/************************************************************************/
360
361
/**
362
 \brief Fetch the extent of this layer.
363
364
 Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
365
 and it would be expensive to establish the extent then OGRERR_FAILURE
366
 will be returned indicating that the extent isn't know.  If bForce is
367
 TRUE then some implementations will actually scan the entire layer once
368
 to compute the MBR of all the features in the layer.
369
370
 Depending on the drivers, the returned extent may or may not take the
371
 spatial filter into account.  So it is safer to call OGR_L_GetExtent() without
372
 setting a spatial filter.
373
374
 Layers without any geometry may return OGRERR_FAILURE just indicating that
375
 no meaningful extents could be collected.
376
377
 Note that some implementations of this method may alter the read cursor
378
 of the layer.
379
380
 This function is the same as the C++ method OGRLayer::GetExtent().
381
382
 @param hLayer handle to the layer from which to get extent.
383
 @param psExtent the structure in which the extent value will be returned.
384
 @param bForce Flag indicating whether the extent should be computed even
385
 if it is expensive.
386
387
 @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
388
389
*/
390
391
OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
392
393
0
{
394
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
395
396
0
#ifdef OGRAPISPY_ENABLED
397
0
    if (bOGRAPISpyEnabled)
398
0
        OGRAPISpy_L_GetExtent(hLayer, bForce);
399
0
#endif
400
401
0
    return OGRLayer::FromHandle(hLayer)->GetExtent(0, psExtent,
402
0
                                                   bForce != FALSE);
403
0
}
404
405
/************************************************************************/
406
/*                         OGR_L_GetExtentEx()                          */
407
/************************************************************************/
408
409
/**
410
 \brief Fetch the extent of this layer, on the specified geometry field.
411
412
 Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
413
 and it would be expensive to establish the extent then OGRERR_FAILURE
414
 will be returned indicating that the extent isn't know.  If bForce is
415
 TRUE then some implementations will actually scan the entire layer once
416
 to compute the MBR of all the features in the layer.
417
418
 Depending on the drivers, the returned extent may or may not take the
419
 spatial filter into account.  So it is safer to call OGR_L_GetExtent() without
420
 setting a spatial filter.
421
422
 Layers without any geometry may return OGRERR_FAILURE just indicating that
423
 no meaningful extents could be collected.
424
425
 Note that some implementations of this method may alter the read cursor
426
 of the layer.
427
428
 This function is the same as the C++ method OGRLayer::GetExtent().
429
430
 @param hLayer handle to the layer from which to get extent.
431
 @param iGeomField the index of the geometry field on which to compute the extent.
432
 @param psExtent the structure in which the extent value will be returned.
433
 @param bForce Flag indicating whether the extent should be computed even
434
 if it is expensive.
435
436
 @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
437
438
*/
439
OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
440
                         OGREnvelope *psExtent, int bForce)
441
442
0
{
443
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
444
445
0
#ifdef OGRAPISPY_ENABLED
446
0
    if (bOGRAPISpyEnabled)
447
0
        OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
448
0
#endif
449
450
0
    return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
451
0
                                                   bForce != FALSE);
452
0
}
453
454
/************************************************************************/
455
/*                            GetExtent3D()                             */
456
/************************************************************************/
457
458
/**
459
 \brief Fetch the 3D extent of this layer, on the specified geometry field.
460
461
 Returns the 3D extent (MBR) of the data in the layer.  If bForce is FALSE,
462
 and it would be expensive to establish the extent then OGRERR_FAILURE
463
 will be returned indicating that the extent isn't know.  If bForce is
464
 TRUE then some implementations will actually scan the entire layer once
465
 to compute the MBR of all the features in the layer.
466
467
 (Contrarty to GetExtent() 2D), the returned extent will always take into
468
 account the attribute and spatial filters that may be installed.
469
470
 Layers without any geometry may return OGRERR_FAILURE just indicating that
471
 no meaningful extents could be collected.
472
473
 For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
474
 fields will be respectively set to +Infinity and -Infinity.
475
476
 Note that some implementations of this method may alter the read cursor
477
 of the layer.
478
479
 This function is the same as the C function OGR_L_GetExtent3D().
480
481
 @param iGeomField 0-based index of the geometry field to consider.
482
 @param psExtent3D the computed 3D extent of the layer.
483
 @param bForce if TRUE, the extent will be computed even if all the
484
        layer features have to be fetched.
485
 @return OGRERR_NONE on success or an error code in case of failure.
486
 @since GDAL 3.9
487
*/
488
489
OGRErr OGRLayer::GetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
490
                             bool bForce)
491
492
0
{
493
0
    psExtent3D->MinX = 0.0;
494
0
    psExtent3D->MaxX = 0.0;
495
0
    psExtent3D->MinY = 0.0;
496
0
    psExtent3D->MaxY = 0.0;
497
0
    psExtent3D->MinZ = std::numeric_limits<double>::infinity();
498
0
    psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
499
500
    /* -------------------------------------------------------------------- */
501
    /*      If this layer has a none geometry type, then we can             */
502
    /*      reasonably assume there are not extents available.              */
503
    /* -------------------------------------------------------------------- */
504
0
    if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
505
0
        GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
506
0
    {
507
0
        if (iGeomField != 0)
508
0
        {
509
0
            CPLError(CE_Failure, CPLE_AppDefined,
510
0
                     "Invalid geometry field index : %d", iGeomField);
511
0
        }
512
0
        return OGRERR_FAILURE;
513
0
    }
514
515
0
    return IGetExtent3D(iGeomField, psExtent3D, bForce);
516
0
}
517
518
/************************************************************************/
519
/*                           IGetExtent3D()                             */
520
/************************************************************************/
521
522
/**
523
 \brief Fetch the 3D extent of this layer, on the specified geometry field.
524
525
 See GetExtent3D() documentation.
526
527
 Virtual method implemented by drivers since 3.11. In previous versions,
528
 GetExtent3D() itself was the virtual method.
529
530
 Driver implementations, when wanting to call the base method, must take
531
 care of calling OGRLayer::IGetExtent3D() (and note the public method without
532
 the leading I).
533
534
 @param iGeomField 0-based index of the geometry field to consider.
535
 @param psExtent3D the computed 3D extent of the layer.
536
 @param bForce if TRUE, the extent will be computed even if all the
537
        layer features have to be fetched.
538
 @return OGRERR_NONE on success or an error code in case of failure.
539
 @since GDAL 3.11
540
*/
541
542
OGRErr OGRLayer::IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
543
                              bool bForce)
544
545
0
{
546
    /* -------------------------------------------------------------------- */
547
    /*      If not forced, we should avoid having to scan all the           */
548
    /*      features and just return a failure.                             */
549
    /* -------------------------------------------------------------------- */
550
0
    if (!bForce)
551
0
        return OGRERR_FAILURE;
552
553
    /* -------------------------------------------------------------------- */
554
    /*      OK, we hate to do this, but go ahead and read through all       */
555
    /*      the features to collect geometries and build extents.           */
556
    /* -------------------------------------------------------------------- */
557
0
    OGREnvelope3D oEnv;
558
0
    bool bExtentSet = false;
559
560
0
    for (auto &&poFeature : *this)
561
0
    {
562
0
        OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
563
0
        if (poGeom == nullptr || poGeom->IsEmpty())
564
0
        {
565
            /* Do nothing */
566
0
        }
567
0
        else if (!bExtentSet)
568
0
        {
569
0
            poGeom->getEnvelope(psExtent3D);
570
            // This is required because getEnvelope initializes Z to 0 for 2D geometries
571
0
            if (!poGeom->Is3D())
572
0
            {
573
0
                psExtent3D->MinZ = std::numeric_limits<double>::infinity();
574
0
                psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
575
0
            }
576
0
            bExtentSet = true;
577
0
        }
578
0
        else
579
0
        {
580
0
            poGeom->getEnvelope(&oEnv);
581
            // This is required because getEnvelope initializes Z to 0 for 2D geometries
582
0
            if (!poGeom->Is3D())
583
0
            {
584
0
                oEnv.MinZ = std::numeric_limits<double>::infinity();
585
0
                oEnv.MaxZ = -std::numeric_limits<double>::infinity();
586
0
            }
587
            // Merge handles infinity correctly
588
0
            psExtent3D->Merge(oEnv);
589
0
        }
590
0
    }
591
0
    ResetReading();
592
593
0
    return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
594
0
}
595
596
/************************************************************************/
597
/*                          OGR_L_GetExtent3D()                         */
598
/************************************************************************/
599
600
/**
601
 \brief Fetch the 3D extent of this layer, on the specified geometry field.
602
603
 Returns the 3D extent (MBR) of the data in the layer.  If bForce is FALSE,
604
 and it would be expensive to establish the extent then OGRERR_FAILURE
605
 will be returned indicating that the extent isn't know.  If bForce is
606
 TRUE then some implementations will actually scan the entire layer once
607
 to compute the MBR of all the features in the layer.
608
609
 (Contrarty to GetExtent() 2D), the returned extent will always take into
610
 account the attribute and spatial filters that may be installed.
611
612
 Layers without any geometry may return OGRERR_FAILURE just indicating that
613
 no meaningful extents could be collected.
614
615
 For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
616
 fields will be respectively set to +Infinity and -Infinity.
617
618
 Note that some implementations of this method may alter the read cursor
619
 of the layer.
620
621
 This function is the same as the C++ method OGRLayer::GetExtent3D().
622
623
 @param hLayer the layer to consider.
624
 @param iGeomField 0-based index of the geometry field to consider.
625
 @param psExtent3D the computed 3D extent of the layer.
626
 @param bForce if TRUE, the extent will be computed even if all the
627
        layer features have to be fetched.
628
 @return OGRERR_NONE on success or an error code in case of failure.
629
 @since GDAL 3.9
630
*/
631
632
OGRErr OGR_L_GetExtent3D(OGRLayerH hLayer, int iGeomField,
633
                         OGREnvelope3D *psExtent3D, int bForce)
634
635
0
{
636
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent3D", OGRERR_INVALID_HANDLE);
637
638
0
#ifdef OGRAPISPY_ENABLED
639
0
    if (bOGRAPISpyEnabled)
640
0
        OGRAPISpy_L_GetExtent3D(hLayer, iGeomField, bForce);
641
0
#endif
642
643
0
    return OGRLayer::FromHandle(hLayer)->GetExtent3D(iGeomField, psExtent3D,
644
0
                                                     bForce != FALSE);
645
0
}
646
647
/************************************************************************/
648
/*                         SetAttributeFilter()                         */
649
/************************************************************************/
650
651
OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
652
653
0
{
654
0
    CPLFree(m_pszAttrQueryString);
655
0
    m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
656
657
    /* -------------------------------------------------------------------- */
658
    /*      Are we just clearing any existing query?                        */
659
    /* -------------------------------------------------------------------- */
660
0
    if (pszQuery == nullptr || strlen(pszQuery) == 0)
661
0
    {
662
0
        if (m_poAttrQuery)
663
0
        {
664
0
            delete m_poAttrQuery;
665
0
            m_poAttrQuery = nullptr;
666
0
            ResetReading();
667
0
        }
668
0
        return OGRERR_NONE;
669
0
    }
670
671
    /* -------------------------------------------------------------------- */
672
    /*      Or are we installing a new query?                               */
673
    /* -------------------------------------------------------------------- */
674
0
    OGRErr eErr;
675
676
0
    if (!m_poAttrQuery)
677
0
        m_poAttrQuery = new OGRFeatureQuery();
678
679
0
    eErr = m_poAttrQuery->Compile(this, pszQuery);
680
0
    if (eErr != OGRERR_NONE)
681
0
    {
682
0
        delete m_poAttrQuery;
683
0
        m_poAttrQuery = nullptr;
684
0
    }
685
686
0
    ResetReading();
687
688
0
    return eErr;
689
0
}
690
691
/************************************************************************/
692
/*                        ContainGeomSpecialField()                     */
693
/************************************************************************/
694
695
static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
696
0
{
697
0
    if (expr->eNodeType == SNT_COLUMN)
698
0
    {
699
0
        if (expr->table_index == 0 && expr->field_index != -1)
700
0
        {
701
0
            int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
702
0
            return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
703
0
                   nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
704
0
                   nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
705
0
        }
706
0
    }
707
0
    else if (expr->eNodeType == SNT_OPERATION)
708
0
    {
709
0
        for (int i = 0; i < expr->nSubExprCount; i++)
710
0
        {
711
0
            if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
712
0
                return TRUE;
713
0
        }
714
0
    }
715
0
    return FALSE;
716
0
}
717
718
/************************************************************************/
719
/*                AttributeFilterEvaluationNeedsGeometry()              */
720
/************************************************************************/
721
722
//! @cond Doxygen_Suppress
723
int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
724
0
{
725
0
    if (!m_poAttrQuery)
726
0
        return FALSE;
727
728
0
    swq_expr_node *expr =
729
0
        static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
730
0
    int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
731
732
0
    return ContainGeomSpecialField(expr, nLayerFieldCount);
733
0
}
734
735
//! @endcond
736
737
/************************************************************************/
738
/*                      OGR_L_SetAttributeFilter()                      */
739
/************************************************************************/
740
741
OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
742
743
0
{
744
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
745
0
                      OGRERR_INVALID_HANDLE);
746
747
0
#ifdef OGRAPISPY_ENABLED
748
0
    if (bOGRAPISpyEnabled)
749
0
        OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
750
0
#endif
751
752
0
    return OGRLayer::FromHandle(hLayer)->SetAttributeFilter(pszQuery);
753
0
}
754
755
/************************************************************************/
756
/*                             GetFeature()                             */
757
/************************************************************************/
758
759
OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
760
761
0
{
762
    /* Save old attribute and spatial filters */
763
0
    char *pszOldFilter =
764
0
        m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
765
0
    OGRGeometry *poOldFilterGeom =
766
0
        (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
767
0
    int iOldGeomFieldFilter = m_iGeomFieldFilter;
768
    /* Unset filters */
769
0
    SetAttributeFilter(nullptr);
770
0
    SetSpatialFilter(0, nullptr);
771
772
0
    OGRFeatureUniquePtr poFeature;
773
0
    for (auto &&poFeatureIter : *this)
774
0
    {
775
0
        if (poFeatureIter->GetFID() == nFID)
776
0
        {
777
0
            poFeature.swap(poFeatureIter);
778
0
            break;
779
0
        }
780
0
    }
781
782
    /* Restore filters */
783
0
    SetAttributeFilter(pszOldFilter);
784
0
    CPLFree(pszOldFilter);
785
0
    SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
786
0
    delete poOldFilterGeom;
787
788
0
    return poFeature.release();
789
0
}
790
791
/************************************************************************/
792
/*                          OGR_L_GetFeature()                          */
793
/************************************************************************/
794
795
OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
796
797
0
{
798
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
799
800
0
#ifdef OGRAPISPY_ENABLED
801
0
    if (bOGRAPISpyEnabled)
802
0
        OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
803
0
#endif
804
805
0
    return OGRFeature::ToHandle(
806
0
        OGRLayer::FromHandle(hLayer)->GetFeature(nFeatureId));
807
0
}
808
809
/************************************************************************/
810
/*                           SetNextByIndex()                           */
811
/************************************************************************/
812
813
OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
814
815
0
{
816
0
    if (nIndex < 0)
817
0
        nIndex = GINTBIG_MAX;
818
819
0
    ResetReading();
820
821
0
    while (nIndex-- > 0)
822
0
    {
823
0
        auto poFeature = std::unique_ptr<OGRFeature>(GetNextFeature());
824
0
        if (poFeature == nullptr)
825
0
            return OGRERR_NON_EXISTING_FEATURE;
826
0
    }
827
828
0
    return OGRERR_NONE;
829
0
}
830
831
/************************************************************************/
832
/*                        OGR_L_SetNextByIndex()                        */
833
/************************************************************************/
834
835
OGRErr OGR_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
836
837
0
{
838
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE);
839
840
0
#ifdef OGRAPISPY_ENABLED
841
0
    if (bOGRAPISpyEnabled)
842
0
        OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
843
0
#endif
844
845
0
    return OGRLayer::FromHandle(hLayer)->SetNextByIndex(nIndex);
846
0
}
847
848
/************************************************************************/
849
/*                        OGR_L_GetNextFeature()                        */
850
/************************************************************************/
851
852
OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
853
854
0
{
855
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
856
857
0
#ifdef OGRAPISPY_ENABLED
858
0
    if (bOGRAPISpyEnabled)
859
0
        OGRAPISpy_L_GetNextFeature(hLayer);
860
0
#endif
861
862
0
    return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
863
0
}
864
865
/************************************************************************/
866
/*                       ConvertGeomsIfNecessary()                      */
867
/************************************************************************/
868
869
void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
870
0
{
871
0
    if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
872
0
    {
873
        // One time initialization
874
0
        m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
875
0
        m_poPrivate->m_bSupportsCurve =
876
0
            CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
877
0
        m_poPrivate->m_bSupportsM =
878
0
            CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
879
0
        if (CPLTestBool(
880
0
                CPLGetConfigOption("OGR_APPLY_GEOM_SET_PRECISION", "FALSE")))
881
0
        {
882
0
            const auto poFeatureDefn = GetLayerDefn();
883
0
            const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
884
0
            for (int i = 0; i < nGeomFieldCount; i++)
885
0
            {
886
0
                const double dfXYResolution = poFeatureDefn->GetGeomFieldDefn(i)
887
0
                                                  ->GetCoordinatePrecision()
888
0
                                                  .dfXYResolution;
889
0
                if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
890
0
                    OGRGeometryFactory::haveGEOS())
891
0
                {
892
0
                    m_poPrivate->m_bApplyGeomSetPrecision = true;
893
0
                    break;
894
0
                }
895
0
            }
896
0
        }
897
0
    }
898
899
0
    if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
900
0
        m_poPrivate->m_bApplyGeomSetPrecision)
901
0
    {
902
0
        const auto poFeatureDefn = GetLayerDefn();
903
0
        const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
904
0
        for (int i = 0; i < nGeomFieldCount; i++)
905
0
        {
906
0
            OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
907
0
            if (poGeom)
908
0
            {
909
0
                if (!m_poPrivate->m_bSupportsM &&
910
0
                    OGR_GT_HasM(poGeom->getGeometryType()))
911
0
                {
912
0
                    poGeom->setMeasured(FALSE);
913
0
                }
914
915
0
                if (!m_poPrivate->m_bSupportsCurve &&
916
0
                    OGR_GT_IsNonLinear(poGeom->getGeometryType()))
917
0
                {
918
0
                    OGRwkbGeometryType eTargetType =
919
0
                        OGR_GT_GetLinear(poGeom->getGeometryType());
920
0
                    poGeom = OGRGeometryFactory::forceTo(
921
0
                        poFeature->StealGeometry(i), eTargetType);
922
0
                    poFeature->SetGeomFieldDirectly(i, poGeom);
923
0
                    poGeom = poFeature->GetGeomFieldRef(i);
924
0
                }
925
926
0
                if (poGeom && m_poPrivate->m_bApplyGeomSetPrecision)
927
0
                {
928
0
                    const double dfXYResolution =
929
0
                        poFeatureDefn->GetGeomFieldDefn(i)
930
0
                            ->GetCoordinatePrecision()
931
0
                            .dfXYResolution;
932
0
                    if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
933
0
                        !poGeom->hasCurveGeometry())
934
0
                    {
935
0
                        auto poNewGeom = poGeom->SetPrecision(dfXYResolution,
936
0
                                                              /* nFlags = */ 0);
937
0
                        if (poNewGeom)
938
0
                        {
939
0
                            poFeature->SetGeomFieldDirectly(i, poNewGeom);
940
                            // If there was potential further processing...
941
                            // poGeom = poFeature->GetGeomFieldRef(i);
942
0
                        }
943
0
                    }
944
0
                }
945
0
            }
946
0
        }
947
0
    }
948
0
}
949
950
/************************************************************************/
951
/*                             SetFeature()                             */
952
/************************************************************************/
953
954
OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
955
956
0
{
957
0
    ConvertGeomsIfNecessary(poFeature);
958
0
    return ISetFeature(poFeature);
959
0
}
960
961
/************************************************************************/
962
/*                             ISetFeature()                            */
963
/************************************************************************/
964
965
OGRErr OGRLayer::ISetFeature(OGRFeature *)
966
967
0
{
968
0
    return OGRERR_UNSUPPORTED_OPERATION;
969
0
}
970
971
/************************************************************************/
972
/*                          OGR_L_SetFeature()                          */
973
/************************************************************************/
974
975
OGRErr OGR_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
976
977
0
{
978
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
979
0
    VALIDATE_POINTER1(hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
980
981
0
#ifdef OGRAPISPY_ENABLED
982
0
    if (bOGRAPISpyEnabled)
983
0
        OGRAPISpy_L_SetFeature(hLayer, hFeat);
984
0
#endif
985
986
0
    return OGRLayer::FromHandle(hLayer)->SetFeature(
987
0
        OGRFeature::FromHandle(hFeat));
988
0
}
989
990
/************************************************************************/
991
/*                           CreateFeature()                            */
992
/************************************************************************/
993
994
OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
995
996
0
{
997
0
    ConvertGeomsIfNecessary(poFeature);
998
0
    return ICreateFeature(poFeature);
999
0
}
1000
1001
/************************************************************************/
1002
/*                           ICreateFeature()                            */
1003
/************************************************************************/
1004
1005
OGRErr OGRLayer::ICreateFeature(OGRFeature *)
1006
1007
0
{
1008
0
    return OGRERR_UNSUPPORTED_OPERATION;
1009
0
}
1010
1011
/************************************************************************/
1012
/*                        OGR_L_CreateFeature()                         */
1013
/************************************************************************/
1014
1015
OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1016
1017
0
{
1018
0
    VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1019
0
    VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1020
1021
0
#ifdef OGRAPISPY_ENABLED
1022
0
    if (bOGRAPISpyEnabled)
1023
0
        OGRAPISpy_L_CreateFeature(hLayer, hFeat);
1024
0
#endif
1025
1026
0
    return OGRLayer::FromHandle(hLayer)->CreateFeature(
1027
0
        OGRFeature::FromHandle(hFeat));
1028
0
}
1029
1030
/************************************************************************/
1031
/*                           UpsertFeature()                           */
1032
/************************************************************************/
1033
1034
OGRErr OGRLayer::UpsertFeature(OGRFeature *poFeature)
1035
1036
0
{
1037
0
    ConvertGeomsIfNecessary(poFeature);
1038
0
    return IUpsertFeature(poFeature);
1039
0
}
1040
1041
/************************************************************************/
1042
/*                           IUpsertFeature()                           */
1043
/************************************************************************/
1044
1045
OGRErr OGRLayer::IUpsertFeature(OGRFeature *)
1046
0
{
1047
0
    return OGRERR_UNSUPPORTED_OPERATION;
1048
0
}
1049
1050
/************************************************************************/
1051
/*                        OGR_L_UpsertFeature()                         */
1052
/************************************************************************/
1053
1054
OGRErr OGR_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1055
1056
0
{
1057
0
    VALIDATE_POINTER1(hLayer, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
1058
0
    VALIDATE_POINTER1(hFeat, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
1059
1060
0
#ifdef OGRAPISPY_ENABLED
1061
0
    if (bOGRAPISpyEnabled)
1062
0
        OGRAPISpy_L_UpsertFeature(hLayer, hFeat);
1063
0
#endif
1064
1065
0
    return OGRLayer::FromHandle(hLayer)->UpsertFeature(
1066
0
        OGRFeature::FromHandle(hFeat));
1067
0
}
1068
1069
/************************************************************************/
1070
/*                           UpdateFeature()                            */
1071
/************************************************************************/
1072
1073
OGRErr OGRLayer::UpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
1074
                               const int *panUpdatedFieldsIdx,
1075
                               int nUpdatedGeomFieldsCount,
1076
                               const int *panUpdatedGeomFieldsIdx,
1077
                               bool bUpdateStyleString)
1078
1079
0
{
1080
0
    ConvertGeomsIfNecessary(poFeature);
1081
0
    const int nFieldCount = GetLayerDefn()->GetFieldCount();
1082
0
    for (int i = 0; i < nUpdatedFieldsCount; ++i)
1083
0
    {
1084
0
        if (panUpdatedFieldsIdx[i] < 0 || panUpdatedFieldsIdx[i] >= nFieldCount)
1085
0
        {
1086
0
            CPLError(CE_Failure, CPLE_AppDefined,
1087
0
                     "Invalid panUpdatedFieldsIdx[%d] = %d", i,
1088
0
                     panUpdatedFieldsIdx[i]);
1089
0
            return OGRERR_FAILURE;
1090
0
        }
1091
0
    }
1092
0
    const int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
1093
0
    for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
1094
0
    {
1095
0
        if (panUpdatedGeomFieldsIdx[i] < 0 ||
1096
0
            panUpdatedGeomFieldsIdx[i] >= nGeomFieldCount)
1097
0
        {
1098
0
            CPLError(CE_Failure, CPLE_AppDefined,
1099
0
                     "Invalid panUpdatedGeomFieldsIdx[%d] = %d", i,
1100
0
                     panUpdatedGeomFieldsIdx[i]);
1101
0
            return OGRERR_FAILURE;
1102
0
        }
1103
0
    }
1104
0
    return IUpdateFeature(poFeature, nUpdatedFieldsCount, panUpdatedFieldsIdx,
1105
0
                          nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx,
1106
0
                          bUpdateStyleString);
1107
0
}
1108
1109
/************************************************************************/
1110
/*                           IUpdateFeature()                           */
1111
/************************************************************************/
1112
1113
OGRErr OGRLayer::IUpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
1114
                                const int *panUpdatedFieldsIdx,
1115
                                int nUpdatedGeomFieldsCount,
1116
                                const int *panUpdatedGeomFieldsIdx,
1117
                                bool bUpdateStyleString)
1118
0
{
1119
0
    if (!TestCapability(OLCRandomWrite))
1120
0
        return OGRERR_UNSUPPORTED_OPERATION;
1121
1122
0
    auto poFeatureExisting =
1123
0
        std::unique_ptr<OGRFeature>(GetFeature(poFeature->GetFID()));
1124
0
    if (!poFeatureExisting)
1125
0
        return OGRERR_NON_EXISTING_FEATURE;
1126
1127
0
    for (int i = 0; i < nUpdatedFieldsCount; ++i)
1128
0
    {
1129
0
        poFeatureExisting->SetField(
1130
0
            panUpdatedFieldsIdx[i],
1131
0
            poFeature->GetRawFieldRef(panUpdatedFieldsIdx[i]));
1132
0
    }
1133
0
    for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
1134
0
    {
1135
0
        poFeatureExisting->SetGeomFieldDirectly(
1136
0
            panUpdatedGeomFieldsIdx[i],
1137
0
            poFeature->StealGeometry(panUpdatedGeomFieldsIdx[i]));
1138
0
    }
1139
0
    if (bUpdateStyleString)
1140
0
    {
1141
0
        poFeatureExisting->SetStyleString(poFeature->GetStyleString());
1142
0
    }
1143
0
    return ISetFeature(poFeatureExisting.get());
1144
0
}
1145
1146
/************************************************************************/
1147
/*                        OGR_L_UpdateFeature()                         */
1148
/************************************************************************/
1149
1150
OGRErr OGR_L_UpdateFeature(OGRLayerH hLayer, OGRFeatureH hFeat,
1151
                           int nUpdatedFieldsCount,
1152
                           const int *panUpdatedFieldsIdx,
1153
                           int nUpdatedGeomFieldsCount,
1154
                           const int *panUpdatedGeomFieldsIdx,
1155
                           bool bUpdateStyleString)
1156
1157
0
{
1158
0
    VALIDATE_POINTER1(hLayer, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
1159
0
    VALIDATE_POINTER1(hFeat, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
1160
1161
0
    return OGRLayer::FromHandle(hLayer)->UpdateFeature(
1162
0
        OGRFeature::FromHandle(hFeat), nUpdatedFieldsCount, panUpdatedFieldsIdx,
1163
0
        nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
1164
0
}
1165
1166
/************************************************************************/
1167
/*                            CreateField()                             */
1168
/************************************************************************/
1169
1170
OGRErr OGRLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
1171
1172
0
{
1173
0
    (void)poField;
1174
0
    (void)bApproxOK;
1175
1176
0
    CPLError(CE_Failure, CPLE_NotSupported,
1177
0
             "CreateField() not supported by this layer.\n");
1178
1179
0
    return OGRERR_UNSUPPORTED_OPERATION;
1180
0
}
1181
1182
/************************************************************************/
1183
/*                         OGR_L_CreateField()                          */
1184
/************************************************************************/
1185
1186
OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
1187
1188
0
{
1189
0
    VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1190
0
    VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1191
1192
0
#ifdef OGRAPISPY_ENABLED
1193
0
    if (bOGRAPISpyEnabled)
1194
0
        OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
1195
0
#endif
1196
1197
0
    return OGRLayer::FromHandle(hLayer)->CreateField(
1198
0
        OGRFieldDefn::FromHandle(hField), bApproxOK);
1199
0
}
1200
1201
/************************************************************************/
1202
/*                            DeleteField()                             */
1203
/************************************************************************/
1204
1205
OGRErr OGRLayer::DeleteField(int iField)
1206
1207
0
{
1208
0
    (void)iField;
1209
1210
0
    CPLError(CE_Failure, CPLE_NotSupported,
1211
0
             "DeleteField() not supported by this layer.\n");
1212
1213
0
    return OGRERR_UNSUPPORTED_OPERATION;
1214
0
}
1215
1216
/************************************************************************/
1217
/*                         OGR_L_DeleteField()                          */
1218
/************************************************************************/
1219
1220
OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
1221
1222
0
{
1223
0
    VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
1224
1225
0
#ifdef OGRAPISPY_ENABLED
1226
0
    if (bOGRAPISpyEnabled)
1227
0
        OGRAPISpy_L_DeleteField(hLayer, iField);
1228
0
#endif
1229
1230
0
    return OGRLayer::FromHandle(hLayer)->DeleteField(iField);
1231
0
}
1232
1233
/************************************************************************/
1234
/*                           ReorderFields()                            */
1235
/************************************************************************/
1236
1237
OGRErr OGRLayer::ReorderFields(int *panMap)
1238
1239
0
{
1240
0
    (void)panMap;
1241
1242
0
    CPLError(CE_Failure, CPLE_NotSupported,
1243
0
             "ReorderFields() not supported by this layer.\n");
1244
1245
0
    return OGRERR_UNSUPPORTED_OPERATION;
1246
0
}
1247
1248
/************************************************************************/
1249
/*                       OGR_L_ReorderFields()                          */
1250
/************************************************************************/
1251
1252
OGRErr OGR_L_ReorderFields(OGRLayerH hLayer, int *panMap)
1253
1254
0
{
1255
0
    VALIDATE_POINTER1(hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE);
1256
1257
0
#ifdef OGRAPISPY_ENABLED
1258
0
    if (bOGRAPISpyEnabled)
1259
0
        OGRAPISpy_L_ReorderFields(hLayer, panMap);
1260
0
#endif
1261
1262
0
    return OGRLayer::FromHandle(hLayer)->ReorderFields(panMap);
1263
0
}
1264
1265
/************************************************************************/
1266
/*                            ReorderField()                            */
1267
/************************************************************************/
1268
1269
OGRErr OGRLayer::ReorderField(int iOldFieldPos, int iNewFieldPos)
1270
1271
0
{
1272
0
    OGRErr eErr;
1273
1274
0
    int nFieldCount = GetLayerDefn()->GetFieldCount();
1275
1276
0
    if (iOldFieldPos < 0 || iOldFieldPos >= nFieldCount)
1277
0
    {
1278
0
        CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
1279
0
        return OGRERR_FAILURE;
1280
0
    }
1281
0
    if (iNewFieldPos < 0 || iNewFieldPos >= nFieldCount)
1282
0
    {
1283
0
        CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
1284
0
        return OGRERR_FAILURE;
1285
0
    }
1286
0
    if (iNewFieldPos == iOldFieldPos)
1287
0
        return OGRERR_NONE;
1288
1289
0
    int *panMap = static_cast<int *>(CPLMalloc(sizeof(int) * nFieldCount));
1290
0
    if (iOldFieldPos < iNewFieldPos)
1291
0
    {
1292
        /* "0","1","2","3","4" (1,3) -> "0","2","3","1","4" */
1293
0
        int i = 0;  // Used after for.
1294
0
        for (; i < iOldFieldPos; i++)
1295
0
            panMap[i] = i;
1296
0
        for (; i < iNewFieldPos; i++)
1297
0
            panMap[i] = i + 1;
1298
0
        panMap[iNewFieldPos] = iOldFieldPos;
1299
0
        for (i = iNewFieldPos + 1; i < nFieldCount; i++)
1300
0
            panMap[i] = i;
1301
0
    }
1302
0
    else
1303
0
    {
1304
        /* "0","1","2","3","4" (3,1) -> "0","3","1","2","4" */
1305
0
        for (int i = 0; i < iNewFieldPos; i++)
1306
0
            panMap[i] = i;
1307
0
        panMap[iNewFieldPos] = iOldFieldPos;
1308
0
        int i = iNewFieldPos + 1;  // Used after for.
1309
0
        for (; i <= iOldFieldPos; i++)
1310
0
            panMap[i] = i - 1;
1311
0
        for (; i < nFieldCount; i++)
1312
0
            panMap[i] = i;
1313
0
    }
1314
1315
0
    eErr = ReorderFields(panMap);
1316
1317
0
    CPLFree(panMap);
1318
1319
0
    return eErr;
1320
0
}
1321
1322
/************************************************************************/
1323
/*                        OGR_L_ReorderField()                          */
1324
/************************************************************************/
1325
1326
OGRErr OGR_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos)
1327
1328
0
{
1329
0
    VALIDATE_POINTER1(hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE);
1330
1331
0
#ifdef OGRAPISPY_ENABLED
1332
0
    if (bOGRAPISpyEnabled)
1333
0
        OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
1334
0
#endif
1335
1336
0
    return OGRLayer::FromHandle(hLayer)->ReorderField(iOldFieldPos,
1337
0
                                                      iNewFieldPos);
1338
0
}
1339
1340
/************************************************************************/
1341
/*                           AlterFieldDefn()                           */
1342
/************************************************************************/
1343
1344
OGRErr OGRLayer::AlterFieldDefn(int /* iField*/,
1345
                                OGRFieldDefn * /*poNewFieldDefn*/,
1346
                                int /* nFlags */)
1347
1348
0
{
1349
0
    CPLError(CE_Failure, CPLE_NotSupported,
1350
0
             "AlterFieldDefn() not supported by this layer.\n");
1351
1352
0
    return OGRERR_UNSUPPORTED_OPERATION;
1353
0
}
1354
1355
/************************************************************************/
1356
/*                        OGR_L_AlterFieldDefn()                        */
1357
/************************************************************************/
1358
1359
OGRErr OGR_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
1360
                            OGRFieldDefnH hNewFieldDefn, int nFlags)
1361
1362
0
{
1363
0
    VALIDATE_POINTER1(hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE);
1364
0
    VALIDATE_POINTER1(hNewFieldDefn, "OGR_L_AlterFieldDefn",
1365
0
                      OGRERR_INVALID_HANDLE);
1366
1367
0
#ifdef OGRAPISPY_ENABLED
1368
0
    if (bOGRAPISpyEnabled)
1369
0
        OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
1370
0
#endif
1371
1372
0
    return OGRLayer::FromHandle(hLayer)->AlterFieldDefn(
1373
0
        iField, OGRFieldDefn::FromHandle(hNewFieldDefn), nFlags);
1374
0
}
1375
1376
/************************************************************************/
1377
/*                        AlterGeomFieldDefn()                          */
1378
/************************************************************************/
1379
1380
OGRErr
1381
OGRLayer::AlterGeomFieldDefn(int /* iGeomField*/,
1382
                             const OGRGeomFieldDefn * /*poNewGeomFieldDefn*/,
1383
                             int /* nFlags */)
1384
1385
0
{
1386
0
    CPLError(CE_Failure, CPLE_NotSupported,
1387
0
             "AlterGeomFieldDefn() not supported by this layer.\n");
1388
1389
0
    return OGRERR_UNSUPPORTED_OPERATION;
1390
0
}
1391
1392
/************************************************************************/
1393
/*                      OGR_L_AlterGeomFieldDefn()                      */
1394
/************************************************************************/
1395
1396
OGRErr OGR_L_AlterGeomFieldDefn(OGRLayerH hLayer, int iGeomField,
1397
                                OGRGeomFieldDefnH hNewGeomFieldDefn, int nFlags)
1398
1399
0
{
1400
0
    VALIDATE_POINTER1(hLayer, "OGR_L_AlterGeomFieldDefn",
1401
0
                      OGRERR_INVALID_HANDLE);
1402
0
    VALIDATE_POINTER1(hNewGeomFieldDefn, "OGR_L_AlterGeomFieldDefn",
1403
0
                      OGRERR_INVALID_HANDLE);
1404
1405
0
    return OGRLayer::FromHandle(hLayer)->AlterGeomFieldDefn(
1406
0
        iGeomField,
1407
0
        const_cast<const OGRGeomFieldDefn *>(
1408
0
            OGRGeomFieldDefn::FromHandle(hNewGeomFieldDefn)),
1409
0
        nFlags);
1410
0
}
1411
1412
/************************************************************************/
1413
/*                         CreateGeomField()                            */
1414
/************************************************************************/
1415
1416
OGRErr OGRLayer::CreateGeomField(const OGRGeomFieldDefn *poField, int bApproxOK)
1417
1418
0
{
1419
0
    (void)poField;
1420
0
    (void)bApproxOK;
1421
1422
0
    CPLError(CE_Failure, CPLE_NotSupported,
1423
0
             "CreateGeomField() not supported by this layer.\n");
1424
1425
0
    return OGRERR_UNSUPPORTED_OPERATION;
1426
0
}
1427
1428
/************************************************************************/
1429
/*                        OGR_L_CreateGeomField()                       */
1430
/************************************************************************/
1431
1432
OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
1433
                             int bApproxOK)
1434
1435
0
{
1436
0
    VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1437
0
    VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1438
1439
0
#ifdef OGRAPISPY_ENABLED
1440
0
    if (bOGRAPISpyEnabled)
1441
0
        OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
1442
0
#endif
1443
1444
0
    return OGRLayer::FromHandle(hLayer)->CreateGeomField(
1445
0
        OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
1446
0
}
1447
1448
/************************************************************************/
1449
/*                          StartTransaction()                          */
1450
/************************************************************************/
1451
1452
OGRErr OGRLayer::StartTransaction()
1453
1454
0
{
1455
0
    return OGRERR_NONE;
1456
0
}
1457
1458
/************************************************************************/
1459
/*                       OGR_L_StartTransaction()                       */
1460
/************************************************************************/
1461
1462
OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
1463
1464
0
{
1465
0
    VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
1466
1467
0
#ifdef OGRAPISPY_ENABLED
1468
0
    if (bOGRAPISpyEnabled)
1469
0
        OGRAPISpy_L_StartTransaction(hLayer);
1470
0
#endif
1471
1472
0
    return OGRLayer::FromHandle(hLayer)->StartTransaction();
1473
0
}
1474
1475
/************************************************************************/
1476
/*                         CommitTransaction()                          */
1477
/************************************************************************/
1478
1479
OGRErr OGRLayer::CommitTransaction()
1480
1481
0
{
1482
0
    return OGRERR_NONE;
1483
0
}
1484
1485
/************************************************************************/
1486
/*                       OGR_L_CommitTransaction()                      */
1487
/************************************************************************/
1488
1489
OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
1490
1491
0
{
1492
0
    VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
1493
1494
0
#ifdef OGRAPISPY_ENABLED
1495
0
    if (bOGRAPISpyEnabled)
1496
0
        OGRAPISpy_L_CommitTransaction(hLayer);
1497
0
#endif
1498
1499
0
    return OGRLayer::FromHandle(hLayer)->CommitTransaction();
1500
0
}
1501
1502
/************************************************************************/
1503
/*                        RollbackTransaction()                         */
1504
/************************************************************************/
1505
1506
OGRErr OGRLayer::RollbackTransaction()
1507
1508
0
{
1509
0
    return OGRERR_UNSUPPORTED_OPERATION;
1510
0
}
1511
1512
/************************************************************************/
1513
/*                     OGR_L_RollbackTransaction()                      */
1514
/************************************************************************/
1515
1516
OGRErr OGR_L_RollbackTransaction(OGRLayerH hLayer)
1517
1518
0
{
1519
0
    VALIDATE_POINTER1(hLayer, "OGR_L_RollbackTransaction",
1520
0
                      OGRERR_INVALID_HANDLE);
1521
1522
0
#ifdef OGRAPISPY_ENABLED
1523
0
    if (bOGRAPISpyEnabled)
1524
0
        OGRAPISpy_L_RollbackTransaction(hLayer);
1525
0
#endif
1526
1527
0
    return OGRLayer::FromHandle(hLayer)->RollbackTransaction();
1528
0
}
1529
1530
/************************************************************************/
1531
/*                         OGR_L_GetLayerDefn()                         */
1532
/************************************************************************/
1533
1534
OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
1535
1536
0
{
1537
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
1538
1539
0
#ifdef OGRAPISPY_ENABLED
1540
0
    if (bOGRAPISpyEnabled)
1541
0
        OGRAPISpy_L_GetLayerDefn(hLayer);
1542
0
#endif
1543
1544
0
    return OGRFeatureDefn::ToHandle(
1545
0
        OGRLayer::FromHandle(hLayer)->GetLayerDefn());
1546
0
}
1547
1548
/************************************************************************/
1549
/*                         OGR_L_FindFieldIndex()                       */
1550
/************************************************************************/
1551
1552
int OGR_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
1553
                         int bExactMatch)
1554
1555
0
{
1556
0
    VALIDATE_POINTER1(hLayer, "OGR_L_FindFieldIndex", -1);
1557
1558
0
#ifdef OGRAPISPY_ENABLED
1559
0
    if (bOGRAPISpyEnabled)
1560
0
        OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
1561
0
#endif
1562
1563
0
    return OGRLayer::FromHandle(hLayer)->FindFieldIndex(pszFieldName,
1564
0
                                                        bExactMatch);
1565
0
}
1566
1567
/************************************************************************/
1568
/*                           FindFieldIndex()                           */
1569
/************************************************************************/
1570
1571
int OGRLayer::FindFieldIndex(const char *pszFieldName,
1572
                             CPL_UNUSED int bExactMatch)
1573
0
{
1574
0
    return GetLayerDefn()->GetFieldIndex(pszFieldName);
1575
0
}
1576
1577
/************************************************************************/
1578
/*                           GetSpatialRef()                            */
1579
/************************************************************************/
1580
1581
OGRSpatialReference *OGRLayer::GetSpatialRef()
1582
0
{
1583
0
    if (GetLayerDefn()->GetGeomFieldCount() > 0)
1584
0
        return const_cast<OGRSpatialReference *>(
1585
0
            GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef());
1586
0
    else
1587
0
        return nullptr;
1588
0
}
1589
1590
/************************************************************************/
1591
/*                        OGR_L_GetSpatialRef()                         */
1592
/************************************************************************/
1593
1594
OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
1595
1596
0
{
1597
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
1598
1599
0
#ifdef OGRAPISPY_ENABLED
1600
0
    if (bOGRAPISpyEnabled)
1601
0
        OGRAPISpy_L_GetSpatialRef(hLayer);
1602
0
#endif
1603
1604
0
    return OGRSpatialReference::ToHandle(
1605
0
        OGRLayer::FromHandle(hLayer)->GetSpatialRef());
1606
0
}
1607
1608
/************************************************************************/
1609
/*                        OGR_L_TestCapability()                        */
1610
/************************************************************************/
1611
1612
int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
1613
1614
0
{
1615
0
    VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
1616
0
    VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
1617
1618
0
#ifdef OGRAPISPY_ENABLED
1619
0
    if (bOGRAPISpyEnabled)
1620
0
        OGRAPISpy_L_TestCapability(hLayer, pszCap);
1621
0
#endif
1622
1623
0
    return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
1624
0
}
1625
1626
/************************************************************************/
1627
/*                          GetSpatialFilter()                          */
1628
/************************************************************************/
1629
1630
OGRGeometry *OGRLayer::GetSpatialFilter()
1631
1632
0
{
1633
0
    return m_poFilterGeom;
1634
0
}
1635
1636
/************************************************************************/
1637
/*                       OGR_L_GetSpatialFilter()                       */
1638
/************************************************************************/
1639
1640
OGRGeometryH OGR_L_GetSpatialFilter(OGRLayerH hLayer)
1641
1642
0
{
1643
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialFilter", nullptr);
1644
1645
0
#ifdef OGRAPISPY_ENABLED
1646
0
    if (bOGRAPISpyEnabled)
1647
0
        OGRAPISpy_L_GetSpatialFilter(hLayer);
1648
0
#endif
1649
1650
0
    return OGRGeometry::ToHandle(
1651
0
        OGRLayer::FromHandle(hLayer)->GetSpatialFilter());
1652
0
}
1653
1654
/************************************************************************/
1655
/*             ValidateGeometryFieldIndexForSetSpatialFilter()          */
1656
/************************************************************************/
1657
1658
//! @cond Doxygen_Suppress
1659
bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
1660
    int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
1661
0
{
1662
0
    if (iGeomField == 0 && poGeomIn == nullptr &&
1663
0
        GetLayerDefn()->GetGeomFieldCount() == 0)
1664
0
    {
1665
        // Setting a null spatial filter on geometry field idx 0
1666
        // when there are no geometry field can't harm, and is accepted silently
1667
        // for backward compatibility with existing practice.
1668
0
    }
1669
0
    else if (iGeomField < 0 ||
1670
0
             iGeomField >= GetLayerDefn()->GetGeomFieldCount())
1671
0
    {
1672
0
        if (iGeomField == 0)
1673
0
        {
1674
0
            CPLError(
1675
0
                CE_Failure, CPLE_AppDefined,
1676
0
                bIsSelectLayer
1677
0
                    ? "Cannot set spatial filter: no geometry field selected."
1678
0
                    : "Cannot set spatial filter: no geometry field present in "
1679
0
                      "layer.");
1680
0
        }
1681
0
        else
1682
0
        {
1683
0
            CPLError(CE_Failure, CPLE_AppDefined,
1684
0
                     "Cannot set spatial filter on non-existing geometry field "
1685
0
                     "of index %d.",
1686
0
                     iGeomField);
1687
0
        }
1688
0
        return false;
1689
0
    }
1690
0
    return true;
1691
0
}
1692
1693
//! @endcond
1694
1695
/************************************************************************/
1696
/*                          SetSpatialFilter()                          */
1697
/************************************************************************/
1698
1699
/**
1700
 \brief Set a new spatial filter.
1701
1702
 This method set the geometry to be used as a spatial filter when
1703
 fetching features via the GetNextFeature() method.  Only features that
1704
 geometrically intersect the filter geometry will be returned.
1705
1706
 Currently this test is may be inaccurately implemented, but it is
1707
 guaranteed that all features whose envelope (as returned by
1708
 OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
1709
 will be returned.  This can result in more shapes being returned that
1710
 should strictly be the case.
1711
1712
 Starting with GDAL 2.3, features with null or empty geometries will never
1713
 be considered as matching a spatial filter.
1714
1715
 This method makes an internal copy of the passed geometry.  The
1716
 passed geometry remains the responsibility of the caller, and may
1717
 be safely destroyed.
1718
1719
 For the time being the passed filter geometry should be in the same
1720
 SRS as the layer (as returned by OGRLayer::GetSpatialRef()).  In the
1721
 future this may be generalized.
1722
1723
 This method is the same as the C function OGR_L_SetSpatialFilter().
1724
1725
 @param poFilter the geometry to use as a filtering region.  NULL may
1726
 be passed indicating that the current spatial filter should be cleared,
1727
 but no new one instituted.
1728
 */
1729
1730
OGRErr OGRLayer::SetSpatialFilter(const OGRGeometry *poFilter)
1731
1732
0
{
1733
0
    return SetSpatialFilter(0, poFilter);
1734
0
}
1735
1736
/**
1737
 \brief Set a new spatial filter.
1738
1739
 This method set the geometry to be used as a spatial filter when
1740
 fetching features via the GetNextFeature() method.  Only features that
1741
 geometrically intersect the filter geometry will be returned.
1742
1743
 Currently this test is may be inaccurately implemented, but it is
1744
 guaranteed that all features who's envelope (as returned by
1745
 OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
1746
 will be returned.  This can result in more shapes being returned that
1747
 should strictly be the case.
1748
1749
 This method makes an internal copy of the passed geometry.  The
1750
 passed geometry remains the responsibility of the caller, and may
1751
 be safely destroyed.
1752
1753
 For the time being the passed filter geometry should be in the same
1754
 SRS as the geometry field definition it corresponds to (as returned by
1755
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
1756
 future this may be generalized.
1757
1758
 Note that only the last spatial filter set is applied, even if several
1759
 successive calls are done with different iGeomField values.
1760
1761
 This method is the same as the C function OGR_L_SetSpatialFilterEx().
1762
1763
 @param iGeomField index of the geometry field on which the spatial filter
1764
 operates.
1765
 @param poFilter the geometry to use as a filtering region.  NULL may
1766
 be passed indicating that the current spatial filter should be cleared,
1767
 but no new one instituted.
1768
1769
 @since GDAL 1.11
1770
 */
1771
1772
OGRErr OGRLayer::SetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
1773
1774
0
{
1775
0
    if (iGeomField == 0)
1776
0
    {
1777
0
        if (poFilter &&
1778
0
            !ValidateGeometryFieldIndexForSetSpatialFilter(0, poFilter))
1779
0
        {
1780
0
            return OGRERR_FAILURE;
1781
0
        }
1782
0
    }
1783
0
    else
1784
0
    {
1785
0
        if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField,
1786
0
                                                           poFilter))
1787
0
        {
1788
0
            return OGRERR_FAILURE;
1789
0
        }
1790
0
    }
1791
1792
0
    return ISetSpatialFilter(iGeomField, poFilter);
1793
0
}
1794
1795
/************************************************************************/
1796
/*                         ISetSpatialFilter()                          */
1797
/************************************************************************/
1798
1799
/**
1800
 \brief Set a new spatial filter.
1801
1802
 Virtual method implemented by drivers since 3.11. In previous versions,
1803
 SetSpatialFilter() / SetSpatialFilterRect() itself was the virtual method.
1804
1805
 Driver implementations, when wanting to call the base method, must take
1806
 care of calling OGRLayer::ISetSpatialFilter() (and note the public method without
1807
 the leading I).
1808
1809
 @param iGeomField index of the geometry field on which the spatial filter
1810
 operates.
1811
 @param poFilter the geometry to use as a filtering region.  NULL may
1812
 be passed indicating that the current spatial filter should be cleared,
1813
 but no new one instituted.
1814
1815
 @since GDAL 3.11
1816
 */
1817
1818
OGRErr OGRLayer::ISetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
1819
1820
0
{
1821
0
    m_iGeomFieldFilter = iGeomField;
1822
0
    if (InstallFilter(poFilter))
1823
0
        ResetReading();
1824
0
    return OGRERR_NONE;
1825
0
}
1826
1827
/************************************************************************/
1828
/*                       OGR_L_SetSpatialFilter()                       */
1829
/************************************************************************/
1830
1831
/**
1832
 \brief Set a new spatial filter.
1833
1834
 This function set the geometry to be used as a spatial filter when
1835
 fetching features via the OGR_L_GetNextFeature() function.  Only
1836
 features that geometrically intersect the filter geometry will be
1837
 returned.
1838
1839
 Currently this test is may be inaccurately implemented, but it is
1840
 guaranteed that all features whose envelope (as returned by
1841
 OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
1842
 will be returned.  This can result in more shapes being returned that
1843
 should strictly be the case.
1844
1845
 Starting with GDAL 2.3, features with null or empty geometries will never
1846
 be considered as matching a spatial filter.
1847
1848
 This function makes an internal copy of the passed geometry.  The
1849
 passed geometry remains the responsibility of the caller, and may
1850
 be safely destroyed.
1851
1852
 For the time being the passed filter geometry should be in the same
1853
 SRS as the layer (as returned by OGR_L_GetSpatialRef()).  In the
1854
 future this may be generalized.
1855
1856
 This function is the same as the C++ method OGRLayer::SetSpatialFilter.
1857
1858
 @param hLayer handle to the layer on which to set the spatial filter.
1859
 @param hGeom handle to the geometry to use as a filtering region.  NULL may
1860
 be passed indicating that the current spatial filter should be cleared,
1861
 but no new one instituted.
1862
1863
 */
1864
1865
void OGR_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
1866
1867
0
{
1868
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilter");
1869
1870
0
#ifdef OGRAPISPY_ENABLED
1871
0
    if (bOGRAPISpyEnabled)
1872
0
        OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
1873
0
#endif
1874
1875
0
    OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
1876
0
        OGRGeometry::FromHandle(hGeom));
1877
0
}
1878
1879
/************************************************************************/
1880
/*                      OGR_L_SetSpatialFilterEx()                      */
1881
/************************************************************************/
1882
1883
/**
1884
 \brief Set a new spatial filter.
1885
1886
 This function set the geometry to be used as a spatial filter when
1887
 fetching features via the OGR_L_GetNextFeature() function.  Only
1888
 features that geometrically intersect the filter geometry will be
1889
 returned.
1890
1891
 Currently this test is may be inaccurately implemented, but it is
1892
 guaranteed that all features who's envelope (as returned by
1893
 OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
1894
 will be returned.  This can result in more shapes being returned that
1895
 should strictly be the case.
1896
1897
 This function makes an internal copy of the passed geometry.  The
1898
 passed geometry remains the responsibility of the caller, and may
1899
 be safely destroyed.
1900
1901
 For the time being the passed filter geometry should be in the same
1902
 SRS as the geometry field definition it corresponds to (as returned by
1903
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
1904
 future this may be generalized.
1905
1906
 Note that only the last spatial filter set is applied, even if several
1907
 successive calls are done with different iGeomField values.
1908
1909
 This function is the same as the C++ method OGRLayer::SetSpatialFilter.
1910
1911
 @param hLayer handle to the layer on which to set the spatial filter.
1912
 @param iGeomField index of the geometry field on which the spatial filter
1913
 operates.
1914
 @param hGeom handle to the geometry to use as a filtering region.  NULL may
1915
 be passed indicating that the current spatial filter should be cleared,
1916
 but no new one instituted.
1917
1918
 @since GDAL 1.11
1919
1920
 */
1921
1922
void OGR_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
1923
                              OGRGeometryH hGeom)
1924
1925
0
{
1926
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterEx");
1927
1928
0
#ifdef OGRAPISPY_ENABLED
1929
0
    if (bOGRAPISpyEnabled)
1930
0
        OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
1931
0
#endif
1932
1933
0
    OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
1934
0
        iGeomField, OGRGeometry::FromHandle(hGeom));
1935
0
}
1936
1937
/************************************************************************/
1938
/*                        SetSpatialFilterRect()                        */
1939
/************************************************************************/
1940
1941
/**
1942
 \brief Set a new rectangular spatial filter.
1943
1944
 This method set rectangle to be used as a spatial filter when
1945
 fetching features via the GetNextFeature() method.  Only features that
1946
 geometrically intersect the given rectangle will be returned.
1947
1948
 The x/y values should be in the same coordinate system as the layer as
1949
 a whole (as returned by OGRLayer::GetSpatialRef()).   Internally this
1950
 method is normally implemented as creating a 5 vertex closed rectangular
1951
 polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
1952
 a convenience.
1953
1954
 The only way to clear a spatial filter set with this method is to
1955
 call OGRLayer::SetSpatialFilter(NULL).
1956
1957
 This method is the same as the C function OGR_L_SetSpatialFilterRect().
1958
1959
 @param dfMinX the minimum X coordinate for the rectangular region.
1960
 @param dfMinY the minimum Y coordinate for the rectangular region.
1961
 @param dfMaxX the maximum X coordinate for the rectangular region.
1962
 @param dfMaxY the maximum Y coordinate for the rectangular region.
1963
1964
 */
1965
1966
OGRErr OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY,
1967
                                      double dfMaxX, double dfMaxY)
1968
1969
0
{
1970
0
    return SetSpatialFilterRect(0, dfMinX, dfMinY, dfMaxX, dfMaxY);
1971
0
}
1972
1973
/**
1974
 \brief Set a new rectangular spatial filter.
1975
1976
 This method set rectangle to be used as a spatial filter when
1977
 fetching features via the GetNextFeature() method.  Only features that
1978
 geometrically intersect the given rectangle will be returned.
1979
1980
 The x/y values should be in the same coordinate system as as the geometry
1981
 field definition it corresponds to (as returned by
1982
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
1983
 method is normally implemented as creating a 5 vertex closed rectangular
1984
 polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
1985
 a convenience.
1986
1987
 The only way to clear a spatial filter set with this method is to
1988
 call OGRLayer::SetSpatialFilter(NULL).
1989
1990
 This method is the same as the C function OGR_L_SetSpatialFilterRectEx().
1991
1992
 @param iGeomField index of the geometry field on which the spatial filter
1993
 operates.
1994
 @param dfMinX the minimum X coordinate for the rectangular region.
1995
 @param dfMinY the minimum Y coordinate for the rectangular region.
1996
 @param dfMaxX the maximum X coordinate for the rectangular region.
1997
 @param dfMaxY the maximum Y coordinate for the rectangular region.
1998
1999
 @since GDAL 1.11
2000
 */
2001
2002
OGRErr OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
2003
                                      double dfMinY, double dfMaxX,
2004
                                      double dfMaxY)
2005
2006
0
{
2007
0
    auto poRing = std::make_unique<OGRLinearRing>();
2008
0
    OGRPolygon oPoly;
2009
2010
0
    poRing->addPoint(dfMinX, dfMinY);
2011
0
    poRing->addPoint(dfMinX, dfMaxY);
2012
0
    poRing->addPoint(dfMaxX, dfMaxY);
2013
0
    poRing->addPoint(dfMaxX, dfMinY);
2014
0
    poRing->addPoint(dfMinX, dfMinY);
2015
2016
0
    oPoly.addRing(std::move(poRing));
2017
2018
0
    return SetSpatialFilter(iGeomField, &oPoly);
2019
0
}
2020
2021
/************************************************************************/
2022
/*                     OGR_L_SetSpatialFilterRect()                     */
2023
/************************************************************************/
2024
2025
/**
2026
 \brief Set a new rectangular spatial filter.
2027
2028
 This method set rectangle to be used as a spatial filter when
2029
 fetching features via the OGR_L_GetNextFeature() method.  Only features that
2030
 geometrically intersect the given rectangle will be returned.
2031
2032
 The x/y values should be in the same coordinate system as the layer as
2033
 a whole (as returned by OGRLayer::GetSpatialRef()).   Internally this
2034
 method is normally implemented as creating a 5 vertex closed rectangular
2035
 polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
2036
 a convenience.
2037
2038
 The only way to clear a spatial filter set with this method is to
2039
 call OGRLayer::SetSpatialFilter(NULL).
2040
2041
 This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
2042
2043
 @param hLayer handle to the layer on which to set the spatial filter.
2044
 @param dfMinX the minimum X coordinate for the rectangular region.
2045
 @param dfMinY the minimum Y coordinate for the rectangular region.
2046
 @param dfMaxX the maximum X coordinate for the rectangular region.
2047
 @param dfMaxY the maximum Y coordinate for the rectangular region.
2048
2049
 */
2050
2051
void OGR_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX, double dfMinY,
2052
                                double dfMaxX, double dfMaxY)
2053
2054
0
{
2055
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRect");
2056
2057
0
#ifdef OGRAPISPY_ENABLED
2058
0
    if (bOGRAPISpyEnabled)
2059
0
        OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX,
2060
0
                                         dfMaxY);
2061
0
#endif
2062
2063
0
    OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX,
2064
0
                                                       dfMaxY);
2065
0
}
2066
2067
/************************************************************************/
2068
/*                    OGR_L_SetSpatialFilterRectEx()                    */
2069
/************************************************************************/
2070
2071
/**
2072
 \brief Set a new rectangular spatial filter.
2073
2074
 This method set rectangle to be used as a spatial filter when
2075
 fetching features via the OGR_L_GetNextFeature() method.  Only features that
2076
 geometrically intersect the given rectangle will be returned.
2077
2078
 The x/y values should be in the same coordinate system as as the geometry
2079
 field definition it corresponds to (as returned by
2080
 GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
2081
 method is normally implemented as creating a 5 vertex closed rectangular
2082
 polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
2083
 a convenience.
2084
2085
 The only way to clear a spatial filter set with this method is to
2086
 call OGRLayer::SetSpatialFilter(NULL).
2087
2088
 This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
2089
2090
 @param hLayer handle to the layer on which to set the spatial filter.
2091
 @param iGeomField index of the geometry field on which the spatial filter
2092
 operates.
2093
 @param dfMinX the minimum X coordinate for the rectangular region.
2094
 @param dfMinY the minimum Y coordinate for the rectangular region.
2095
 @param dfMaxX the maximum X coordinate for the rectangular region.
2096
 @param dfMaxY the maximum Y coordinate for the rectangular region.
2097
2098
 @since GDAL 1.11
2099
 */
2100
2101
void OGR_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
2102
                                  double dfMinX, double dfMinY, double dfMaxX,
2103
                                  double dfMaxY)
2104
2105
0
{
2106
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRectEx");
2107
2108
0
#ifdef OGRAPISPY_ENABLED
2109
0
    if (bOGRAPISpyEnabled)
2110
0
        OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY,
2111
0
                                           dfMaxX, dfMaxY);
2112
0
#endif
2113
2114
0
    OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(iGeomField, dfMinX,
2115
0
                                                       dfMinY, dfMaxX, dfMaxY);
2116
0
}
2117
2118
/************************************************************************/
2119
/*                           InstallFilter()                            */
2120
/*                                                                      */
2121
/*      This method is only intended to be used from within             */
2122
/*      drivers, normally from the SetSpatialFilter() method.           */
2123
/*      It installs a filter, and also tests it to see if it is         */
2124
/*      rectangular.  If so, it this is kept track of alongside the     */
2125
/*      filter geometry itself so we can do cheaper comparisons in      */
2126
/*      the FilterGeometry() call.                                      */
2127
/*                                                                      */
2128
/*      Returns TRUE if the newly installed filter differs in some      */
2129
/*      way from the current one.                                       */
2130
/************************************************************************/
2131
2132
//! @cond Doxygen_Suppress
2133
int OGRLayer::InstallFilter(const OGRGeometry *poFilter)
2134
2135
0
{
2136
0
    if (m_poFilterGeom == poFilter)
2137
0
        return FALSE;
2138
2139
    /* -------------------------------------------------------------------- */
2140
    /*      Replace the existing filter.                                    */
2141
    /* -------------------------------------------------------------------- */
2142
0
    if (m_poFilterGeom != nullptr)
2143
0
    {
2144
0
        delete m_poFilterGeom;
2145
0
        m_poFilterGeom = nullptr;
2146
0
    }
2147
2148
0
    if (m_pPreparedFilterGeom != nullptr)
2149
0
    {
2150
0
        OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
2151
0
        m_pPreparedFilterGeom = nullptr;
2152
0
    }
2153
2154
0
    if (poFilter != nullptr)
2155
0
        m_poFilterGeom = poFilter->clone();
2156
2157
0
    m_bFilterIsEnvelope = FALSE;
2158
2159
0
    if (m_poFilterGeom == nullptr)
2160
0
        return TRUE;
2161
2162
0
    m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
2163
2164
    /* Compile geometry filter as a prepared geometry */
2165
0
    m_pPreparedFilterGeom =
2166
0
        OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
2167
2168
0
    m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
2169
2170
0
    return TRUE;
2171
0
}
2172
2173
//! @endcond
2174
2175
/************************************************************************/
2176
/*                   DoesGeometryHavePointInEnvelope()                  */
2177
/************************************************************************/
2178
2179
static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
2180
                                            const OGREnvelope &sEnvelope)
2181
0
{
2182
0
    const OGRLineString *poLS = nullptr;
2183
2184
0
    switch (wkbFlatten(poGeometry->getGeometryType()))
2185
0
    {
2186
0
        case wkbPoint:
2187
0
        {
2188
0
            const auto poPoint = poGeometry->toPoint();
2189
0
            const double x = poPoint->getX();
2190
0
            const double y = poPoint->getY();
2191
0
            return (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
2192
0
                    x <= sEnvelope.MaxX && y <= sEnvelope.MaxY);
2193
0
        }
2194
2195
0
        case wkbLineString:
2196
0
            poLS = poGeometry->toLineString();
2197
0
            break;
2198
2199
0
        case wkbPolygon:
2200
0
        {
2201
0
            const OGRPolygon *poPoly = poGeometry->toPolygon();
2202
0
            poLS = poPoly->getExteriorRing();
2203
0
            break;
2204
0
        }
2205
2206
0
        case wkbMultiPoint:
2207
0
        case wkbMultiLineString:
2208
0
        case wkbMultiPolygon:
2209
0
        case wkbGeometryCollection:
2210
0
        {
2211
0
            for (const auto &poSubGeom : *(poGeometry->toGeometryCollection()))
2212
0
            {
2213
0
                if (DoesGeometryHavePointInEnvelope(poSubGeom, sEnvelope))
2214
0
                    return true;
2215
0
            }
2216
0
            return false;
2217
0
        }
2218
2219
0
        default:
2220
0
            return false;
2221
0
    }
2222
2223
0
    if (poLS != nullptr)
2224
0
    {
2225
0
        const int nNumPoints = poLS->getNumPoints();
2226
0
        for (int i = 0; i < nNumPoints; i++)
2227
0
        {
2228
0
            const double x = poLS->getX(i);
2229
0
            const double y = poLS->getY(i);
2230
0
            if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
2231
0
                x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
2232
0
            {
2233
0
                return true;
2234
0
            }
2235
0
        }
2236
0
    }
2237
2238
0
    return false;
2239
0
}
2240
2241
/************************************************************************/
2242
/*                           FilterGeometry()                           */
2243
/*                                                                      */
2244
/*      Compare the passed in geometry to the currently installed       */
2245
/*      filter.  Optimize for case where filter is just an              */
2246
/*      envelope.                                                       */
2247
/************************************************************************/
2248
2249
//! @cond Doxygen_Suppress
2250
int OGRLayer::FilterGeometry(const OGRGeometry *poGeometry)
2251
2252
0
{
2253
    /* -------------------------------------------------------------------- */
2254
    /*      In trivial cases of new filter or target geometry, we accept    */
2255
    /*      an intersection.  No geometry is taken to mean "the whole       */
2256
    /*      world".                                                         */
2257
    /* -------------------------------------------------------------------- */
2258
0
    if (m_poFilterGeom == nullptr)
2259
0
        return TRUE;
2260
2261
0
    if (poGeometry == nullptr || poGeometry->IsEmpty())
2262
0
        return FALSE;
2263
2264
    /* -------------------------------------------------------------------- */
2265
    /*      Compute the target geometry envelope, and if there is no        */
2266
    /*      intersection between the envelopes we are sure not to have      */
2267
    /*      any intersection.                                               */
2268
    /* -------------------------------------------------------------------- */
2269
0
    OGREnvelope sGeomEnv;
2270
2271
0
    poGeometry->getEnvelope(&sGeomEnv);
2272
2273
0
    if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
2274
0
        sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
2275
0
        m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
2276
0
        m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
2277
0
        return FALSE;
2278
2279
    /* -------------------------------------------------------------------- */
2280
    /*      If the filter geometry is its own envelope and if the           */
2281
    /*      envelope of the geometry is inside the filter geometry,         */
2282
    /*      the geometry itself is inside the filter geometry               */
2283
    /* -------------------------------------------------------------------- */
2284
0
    if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
2285
0
        sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
2286
0
        sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
2287
0
        sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
2288
0
    {
2289
0
        return TRUE;
2290
0
    }
2291
0
    else
2292
0
    {
2293
        // If the filter geometry is its own envelope and if the geometry has
2294
        // at least one point inside the filter geometry, the geometry itself
2295
        // intersects the filter geometry.
2296
0
        if (m_bFilterIsEnvelope)
2297
0
        {
2298
0
            if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
2299
0
                return true;
2300
0
        }
2301
2302
        /* --------------------------------------------------------------------
2303
         */
2304
        /*      Fallback to full intersect test (using GEOS) if we still */
2305
        /*      don't know for sure. */
2306
        /* --------------------------------------------------------------------
2307
         */
2308
0
        if (OGRGeometryFactory::haveGEOS())
2309
0
        {
2310
            // CPLDebug("OGRLayer", "GEOS intersection");
2311
0
            if (m_pPreparedFilterGeom != nullptr)
2312
0
                return OGRPreparedGeometryIntersects(
2313
0
                    m_pPreparedFilterGeom,
2314
0
                    OGRGeometry::ToHandle(
2315
0
                        const_cast<OGRGeometry *>(poGeometry)));
2316
0
            else
2317
0
                return m_poFilterGeom->Intersects(poGeometry);
2318
0
        }
2319
0
        else
2320
0
            return TRUE;
2321
0
    }
2322
0
}
2323
2324
/************************************************************************/
2325
/*                         FilterWKBGeometry()                          */
2326
/************************************************************************/
2327
2328
bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
2329
                                 bool bEnvelopeAlreadySet,
2330
                                 OGREnvelope &sEnvelope) const
2331
0
{
2332
0
    OGRPreparedGeometry *pPreparedFilterGeom = m_pPreparedFilterGeom;
2333
0
    bool bRet = FilterWKBGeometry(
2334
0
        pabyWKB, nWKBSize, bEnvelopeAlreadySet, sEnvelope, m_poFilterGeom,
2335
0
        m_bFilterIsEnvelope, m_sFilterEnvelope, pPreparedFilterGeom);
2336
0
    const_cast<OGRLayer *>(this)->m_pPreparedFilterGeom = pPreparedFilterGeom;
2337
0
    return bRet;
2338
0
}
2339
2340
/* static */
2341
bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
2342
                                 bool bEnvelopeAlreadySet,
2343
                                 OGREnvelope &sEnvelope,
2344
                                 const OGRGeometry *poFilterGeom,
2345
                                 bool bFilterIsEnvelope,
2346
                                 const OGREnvelope &sFilterEnvelope,
2347
                                 OGRPreparedGeometry *&pPreparedFilterGeom)
2348
0
{
2349
0
    if (!poFilterGeom)
2350
0
        return true;
2351
2352
0
    if ((bEnvelopeAlreadySet ||
2353
0
         OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
2354
0
        sFilterEnvelope.Intersects(sEnvelope))
2355
0
    {
2356
0
        if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
2357
0
        {
2358
0
            return true;
2359
0
        }
2360
0
        else
2361
0
        {
2362
0
            if (bFilterIsEnvelope &&
2363
0
                OGRWKBIntersectsPessimistic(pabyWKB, nWKBSize, sFilterEnvelope))
2364
0
            {
2365
0
                return true;
2366
0
            }
2367
0
            else if (OGRGeometryFactory::haveGEOS())
2368
0
            {
2369
0
                OGRGeometry *poGeom = nullptr;
2370
0
                int ret = FALSE;
2371
0
                if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
2372
0
                                                      nWKBSize) == OGRERR_NONE)
2373
0
                {
2374
0
                    if (!pPreparedFilterGeom)
2375
0
                    {
2376
0
                        pPreparedFilterGeom =
2377
0
                            OGRCreatePreparedGeometry(OGRGeometry::ToHandle(
2378
0
                                const_cast<OGRGeometry *>(poFilterGeom)));
2379
0
                    }
2380
0
                    if (pPreparedFilterGeom)
2381
0
                        ret = OGRPreparedGeometryIntersects(
2382
0
                            pPreparedFilterGeom,
2383
0
                            OGRGeometry::ToHandle(
2384
0
                                const_cast<OGRGeometry *>(poGeom)));
2385
0
                    else
2386
0
                        ret = poFilterGeom->Intersects(poGeom);
2387
0
                }
2388
0
                delete poGeom;
2389
0
                return CPL_TO_BOOL(ret);
2390
0
            }
2391
0
            else
2392
0
            {
2393
                // Assume intersection
2394
0
                return true;
2395
0
            }
2396
0
        }
2397
0
    }
2398
2399
0
    return false;
2400
0
}
2401
2402
/************************************************************************/
2403
/*                          PrepareStartTransaction()                   */
2404
/************************************************************************/
2405
2406
void OGRLayer::PrepareStartTransaction()
2407
0
{
2408
0
    m_apoFieldDefnChanges.clear();
2409
0
    m_apoGeomFieldDefnChanges.clear();
2410
0
}
2411
2412
/************************************************************************/
2413
/*                          FinishRollbackTransaction()                 */
2414
/************************************************************************/
2415
2416
void OGRLayer::FinishRollbackTransaction(const std::string &osSavepointName)
2417
0
{
2418
2419
    // Deleted fields can be safely removed from the storage after being restored.
2420
0
    std::vector<int> toBeRemoved;
2421
2422
0
    bool bSavepointFound = false;
2423
2424
    // Loop through all changed fields and reset them to their previous state.
2425
0
    for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
2426
0
         i--)
2427
0
    {
2428
0
        auto &oFieldChange = m_apoFieldDefnChanges[i];
2429
2430
0
        if (!osSavepointName.empty())
2431
0
        {
2432
0
            if (oFieldChange.osSavepointName == osSavepointName)
2433
0
            {
2434
0
                bSavepointFound = true;
2435
0
            }
2436
0
            else if (bSavepointFound)
2437
0
            {
2438
0
                continue;
2439
0
            }
2440
0
        }
2441
2442
0
        CPLAssert(oFieldChange.poFieldDefn);
2443
0
        const char *pszName = oFieldChange.poFieldDefn->GetNameRef();
2444
0
        const int iField = oFieldChange.iField;
2445
0
        if (iField >= 0)
2446
0
        {
2447
0
            switch (oFieldChange.eChangeType)
2448
0
            {
2449
0
                case FieldChangeType::DELETE_FIELD:
2450
0
                {
2451
                    // Transfer ownership of the field to the layer
2452
0
                    whileUnsealing(GetLayerDefn())
2453
0
                        ->AddFieldDefn(std::move(oFieldChange.poFieldDefn));
2454
2455
                    // Now move the field to the right place
2456
                    // from the last position to its original position
2457
0
                    const int iFieldCount = GetLayerDefn()->GetFieldCount();
2458
0
                    CPLAssert(iFieldCount > 0);
2459
0
                    CPLAssert(iFieldCount > iField);
2460
0
                    std::vector<int> anOrder(iFieldCount);
2461
0
                    for (int j = 0; j < iField; j++)
2462
0
                    {
2463
0
                        anOrder[j] = j;
2464
0
                    }
2465
0
                    for (int j = iField + 1; j < iFieldCount; j++)
2466
0
                    {
2467
0
                        anOrder[j] = j - 1;
2468
0
                    }
2469
0
                    anOrder[iField] = iFieldCount - 1;
2470
0
                    if (OGRERR_NONE == whileUnsealing(GetLayerDefn())
2471
0
                                           ->ReorderFieldDefns(anOrder.data()))
2472
0
                    {
2473
0
                        toBeRemoved.push_back(i);
2474
0
                    }
2475
0
                    else
2476
0
                    {
2477
0
                        CPLError(CE_Failure, CPLE_AppDefined,
2478
0
                                 "Failed to restore deleted field %s", pszName);
2479
0
                    }
2480
0
                    break;
2481
0
                }
2482
0
                case FieldChangeType::ALTER_FIELD:
2483
0
                {
2484
0
                    OGRFieldDefn *poFieldDefn =
2485
0
                        GetLayerDefn()->GetFieldDefn(iField);
2486
0
                    if (poFieldDefn)
2487
0
                    {
2488
0
                        *poFieldDefn = *oFieldChange.poFieldDefn;
2489
0
                        toBeRemoved.push_back(i);
2490
0
                    }
2491
0
                    else
2492
0
                    {
2493
0
                        CPLError(CE_Failure, CPLE_AppDefined,
2494
0
                                 "Failed to restore altered field %s", pszName);
2495
0
                    }
2496
0
                    break;
2497
0
                }
2498
0
                case FieldChangeType::ADD_FIELD:
2499
0
                {
2500
0
                    std::unique_ptr<OGRFieldDefn> poFieldDef =
2501
0
                        GetLayerDefn()->StealFieldDefn(iField);
2502
0
                    if (poFieldDef)
2503
0
                    {
2504
0
                        oFieldChange.poFieldDefn = std::move(poFieldDef);
2505
0
                    }
2506
0
                    else
2507
0
                    {
2508
0
                        CPLError(CE_Failure, CPLE_AppDefined,
2509
0
                                 "Failed to delete added field %s", pszName);
2510
0
                    }
2511
0
                    break;
2512
0
                }
2513
0
            }
2514
0
        }
2515
0
        else
2516
0
        {
2517
0
            CPLError(CE_Failure, CPLE_AppDefined,
2518
0
                     "Failed to restore field %s (field not found at index %d)",
2519
0
                     pszName, iField);
2520
0
        }
2521
0
    }
2522
2523
    // Remove from the storage the deleted fields that have been restored
2524
0
    for (const auto &i : toBeRemoved)
2525
0
    {
2526
0
        m_apoFieldDefnChanges.erase(m_apoFieldDefnChanges.begin() + i);
2527
0
    }
2528
2529
    /**********************************************************************/
2530
    /* Reset geometry fields to their previous state.                    */
2531
    /**********************************************************************/
2532
2533
0
    bSavepointFound = false;
2534
2535
    // Loop through all changed geometry fields and reset them to their previous state.
2536
0
    for (int i = static_cast<int>(m_apoGeomFieldDefnChanges.size()) - 1; i >= 0;
2537
0
         i--)
2538
0
    {
2539
0
        auto &oGeomFieldChange = m_apoGeomFieldDefnChanges[i];
2540
2541
0
        if (!osSavepointName.empty())
2542
0
        {
2543
0
            if (oGeomFieldChange.osSavepointName == osSavepointName)
2544
0
            {
2545
0
                bSavepointFound = true;
2546
0
            }
2547
0
            else if (bSavepointFound)
2548
0
            {
2549
0
                continue;
2550
0
            }
2551
0
        }
2552
0
        const char *pszName = oGeomFieldChange.poFieldDefn->GetNameRef();
2553
0
        const int iGeomField = oGeomFieldChange.iField;
2554
0
        if (iGeomField >= 0)
2555
0
        {
2556
0
            switch (oGeomFieldChange.eChangeType)
2557
0
            {
2558
0
                case FieldChangeType::DELETE_FIELD:
2559
0
                case FieldChangeType::ALTER_FIELD:
2560
0
                {
2561
                    // Currently not handled by OGR for geometry fields
2562
0
                    break;
2563
0
                }
2564
0
                case FieldChangeType::ADD_FIELD:
2565
0
                {
2566
0
                    std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDef =
2567
0
                        GetLayerDefn()->StealGeomFieldDefn(
2568
0
                            oGeomFieldChange.iField);
2569
0
                    if (poGeomFieldDef)
2570
0
                    {
2571
0
                        oGeomFieldChange.poFieldDefn =
2572
0
                            std::move(poGeomFieldDef);
2573
0
                    }
2574
0
                    else
2575
0
                    {
2576
0
                        CPLError(CE_Failure, CPLE_AppDefined,
2577
0
                                 "Failed to delete added geometry field %s",
2578
0
                                 pszName);
2579
0
                    }
2580
0
                    break;
2581
0
                }
2582
0
            }
2583
0
        }
2584
0
        else
2585
0
        {
2586
0
            CPLError(CE_Failure, CPLE_AppDefined,
2587
0
                     "Failed to restore geometry field %s (field not found at "
2588
0
                     "index %d)",
2589
0
                     pszName, oGeomFieldChange.iField);
2590
0
        }
2591
0
    }
2592
0
}
2593
2594
//! @endcond
2595
2596
/************************************************************************/
2597
/*                         OGR_L_ResetReading()                         */
2598
/************************************************************************/
2599
2600
void OGR_L_ResetReading(OGRLayerH hLayer)
2601
2602
0
{
2603
0
    VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
2604
2605
0
#ifdef OGRAPISPY_ENABLED
2606
0
    if (bOGRAPISpyEnabled)
2607
0
        OGRAPISpy_L_ResetReading(hLayer);
2608
0
#endif
2609
2610
0
    OGRLayer::FromHandle(hLayer)->ResetReading();
2611
0
}
2612
2613
/************************************************************************/
2614
/*                       InitializeIndexSupport()                       */
2615
/*                                                                      */
2616
/*      This is only intended to be called by driver layer              */
2617
/*      implementations but we don't make it protected so that the      */
2618
/*      datasources can do it too if that is more appropriate.          */
2619
/************************************************************************/
2620
2621
//! @cond Doxygen_Suppress
2622
OGRErr
2623
OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
2624
2625
0
{
2626
#ifdef HAVE_MITAB
2627
    OGRErr eErr;
2628
2629
    if (m_poAttrIndex != nullptr)
2630
        return OGRERR_NONE;
2631
2632
    m_poAttrIndex = OGRCreateDefaultLayerIndex();
2633
2634
    eErr = m_poAttrIndex->Initialize(pszFilename, this);
2635
    if (eErr != OGRERR_NONE)
2636
    {
2637
        delete m_poAttrIndex;
2638
        m_poAttrIndex = nullptr;
2639
    }
2640
2641
    return eErr;
2642
#else
2643
0
    return OGRERR_FAILURE;
2644
0
#endif
2645
0
}
2646
2647
//! @endcond
2648
2649
/************************************************************************/
2650
/*                             SyncToDisk()                             */
2651
/************************************************************************/
2652
2653
OGRErr OGRLayer::SyncToDisk()
2654
2655
0
{
2656
0
    return OGRERR_NONE;
2657
0
}
2658
2659
/************************************************************************/
2660
/*                          OGR_L_SyncToDisk()                          */
2661
/************************************************************************/
2662
2663
OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
2664
2665
0
{
2666
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
2667
2668
0
#ifdef OGRAPISPY_ENABLED
2669
0
    if (bOGRAPISpyEnabled)
2670
0
        OGRAPISpy_L_SyncToDisk(hLayer);
2671
0
#endif
2672
2673
0
    return OGRLayer::FromHandle(hLayer)->SyncToDisk();
2674
0
}
2675
2676
/************************************************************************/
2677
/*                           DeleteFeature()                            */
2678
/************************************************************************/
2679
2680
OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
2681
0
{
2682
0
    return OGRERR_UNSUPPORTED_OPERATION;
2683
0
}
2684
2685
/************************************************************************/
2686
/*                        OGR_L_DeleteFeature()                         */
2687
/************************************************************************/
2688
2689
OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
2690
2691
0
{
2692
0
    VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
2693
2694
0
#ifdef OGRAPISPY_ENABLED
2695
0
    if (bOGRAPISpyEnabled)
2696
0
        OGRAPISpy_L_DeleteFeature(hLayer, nFID);
2697
0
#endif
2698
2699
0
    return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
2700
0
}
2701
2702
/************************************************************************/
2703
/*                          GetFeaturesRead()                           */
2704
/************************************************************************/
2705
2706
//! @cond Doxygen_Suppress
2707
GIntBig OGRLayer::GetFeaturesRead()
2708
2709
0
{
2710
0
    return m_nFeaturesRead;
2711
0
}
2712
2713
//! @endcond
2714
2715
/************************************************************************/
2716
/*                       OGR_L_GetFeaturesRead()                        */
2717
/************************************************************************/
2718
2719
GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
2720
2721
0
{
2722
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
2723
2724
0
    return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
2725
0
}
2726
2727
/************************************************************************/
2728
/*                             GetFIDColumn                             */
2729
/************************************************************************/
2730
2731
const char *OGRLayer::GetFIDColumn()
2732
2733
0
{
2734
0
    return "";
2735
0
}
2736
2737
/************************************************************************/
2738
/*                         OGR_L_GetFIDColumn()                         */
2739
/************************************************************************/
2740
2741
const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
2742
2743
0
{
2744
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
2745
2746
0
#ifdef OGRAPISPY_ENABLED
2747
0
    if (bOGRAPISpyEnabled)
2748
0
        OGRAPISpy_L_GetFIDColumn(hLayer);
2749
0
#endif
2750
2751
0
    return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
2752
0
}
2753
2754
/************************************************************************/
2755
/*                         GetGeometryColumn()                          */
2756
/************************************************************************/
2757
2758
const char *OGRLayer::GetGeometryColumn()
2759
2760
0
{
2761
0
    if (GetLayerDefn()->GetGeomFieldCount() > 0)
2762
0
        return GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef();
2763
0
    else
2764
0
        return "";
2765
0
}
2766
2767
/************************************************************************/
2768
/*                      OGR_L_GetGeometryColumn()                       */
2769
/************************************************************************/
2770
2771
const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
2772
2773
0
{
2774
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
2775
2776
0
#ifdef OGRAPISPY_ENABLED
2777
0
    if (bOGRAPISpyEnabled)
2778
0
        OGRAPISpy_L_GetGeometryColumn(hLayer);
2779
0
#endif
2780
2781
0
    return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
2782
0
}
2783
2784
/************************************************************************/
2785
/*                            GetStyleTable()                           */
2786
/************************************************************************/
2787
2788
OGRStyleTable *OGRLayer::GetStyleTable()
2789
0
{
2790
0
    return m_poStyleTable;
2791
0
}
2792
2793
/************************************************************************/
2794
/*                         SetStyleTableDirectly()                      */
2795
/************************************************************************/
2796
2797
void OGRLayer::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
2798
0
{
2799
0
    if (m_poStyleTable)
2800
0
        delete m_poStyleTable;
2801
0
    m_poStyleTable = poStyleTable;
2802
0
}
2803
2804
/************************************************************************/
2805
/*                            SetStyleTable()                           */
2806
/************************************************************************/
2807
2808
void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
2809
0
{
2810
0
    if (m_poStyleTable)
2811
0
        delete m_poStyleTable;
2812
0
    if (poStyleTable)
2813
0
        m_poStyleTable = poStyleTable->Clone();
2814
0
}
2815
2816
/************************************************************************/
2817
/*                         OGR_L_GetStyleTable()                        */
2818
/************************************************************************/
2819
2820
OGRStyleTableH OGR_L_GetStyleTable(OGRLayerH hLayer)
2821
2822
0
{
2823
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetStyleTable", nullptr);
2824
2825
0
    return reinterpret_cast<OGRStyleTableH>(
2826
0
        OGRLayer::FromHandle(hLayer)->GetStyleTable());
2827
0
}
2828
2829
/************************************************************************/
2830
/*                         OGR_L_SetStyleTableDirectly()                */
2831
/************************************************************************/
2832
2833
void OGR_L_SetStyleTableDirectly(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
2834
2835
0
{
2836
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTableDirectly");
2837
2838
0
    OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
2839
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
2840
0
}
2841
2842
/************************************************************************/
2843
/*                         OGR_L_SetStyleTable()                        */
2844
/************************************************************************/
2845
2846
void OGR_L_SetStyleTable(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
2847
2848
0
{
2849
0
    VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTable");
2850
0
    VALIDATE_POINTER0(hStyleTable, "OGR_L_SetStyleTable");
2851
2852
0
    OGRLayer::FromHandle(hLayer)->SetStyleTable(
2853
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
2854
0
}
2855
2856
/************************************************************************/
2857
/*                               GetName()                              */
2858
/************************************************************************/
2859
2860
const char *OGRLayer::GetName()
2861
2862
0
{
2863
0
    return GetLayerDefn()->GetName();
2864
0
}
2865
2866
/************************************************************************/
2867
/*                           OGR_L_GetName()                            */
2868
/************************************************************************/
2869
2870
const char *OGR_L_GetName(OGRLayerH hLayer)
2871
2872
0
{
2873
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
2874
2875
0
#ifdef OGRAPISPY_ENABLED
2876
0
    if (bOGRAPISpyEnabled)
2877
0
        OGRAPISpy_L_GetName(hLayer);
2878
0
#endif
2879
2880
0
    return OGRLayer::FromHandle(hLayer)->GetName();
2881
0
}
2882
2883
/************************************************************************/
2884
/*                            GetGeomType()                             */
2885
/************************************************************************/
2886
2887
OGRwkbGeometryType OGRLayer::GetGeomType()
2888
0
{
2889
0
    OGRFeatureDefn *poLayerDefn = GetLayerDefn();
2890
0
    if (poLayerDefn == nullptr)
2891
0
    {
2892
0
        CPLDebug("OGR", "GetLayerType() returns NULL !");
2893
0
        return wkbUnknown;
2894
0
    }
2895
0
    return poLayerDefn->GetGeomType();
2896
0
}
2897
2898
/************************************************************************/
2899
/*                         OGR_L_GetGeomType()                          */
2900
/************************************************************************/
2901
2902
OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
2903
2904
0
{
2905
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
2906
2907
0
#ifdef OGRAPISPY_ENABLED
2908
0
    if (bOGRAPISpyEnabled)
2909
0
        OGRAPISpy_L_GetGeomType(hLayer);
2910
0
#endif
2911
2912
0
    OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
2913
0
    if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
2914
0
    {
2915
0
        eType = OGR_GT_GetLinear(eType);
2916
0
    }
2917
0
    return eType;
2918
0
}
2919
2920
/************************************************************************/
2921
/*                          SetIgnoredFields()                          */
2922
/************************************************************************/
2923
2924
OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
2925
0
{
2926
0
    OGRFeatureDefn *poDefn = GetLayerDefn();
2927
2928
    // first set everything as *not* ignored
2929
0
    for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
2930
0
    {
2931
0
        poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
2932
0
    }
2933
0
    for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
2934
0
    {
2935
0
        poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
2936
0
    }
2937
0
    poDefn->SetStyleIgnored(FALSE);
2938
2939
    // ignore some fields
2940
0
    for (const char *pszFieldName : cpl::Iterate(papszFields))
2941
0
    {
2942
        // check special fields
2943
0
        if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
2944
0
            poDefn->SetGeometryIgnored(TRUE);
2945
0
        else if (EQUAL(pszFieldName, "OGR_STYLE"))
2946
0
            poDefn->SetStyleIgnored(TRUE);
2947
0
        else
2948
0
        {
2949
            // check ordinary fields
2950
0
            int iField = poDefn->GetFieldIndex(pszFieldName);
2951
0
            if (iField == -1)
2952
0
            {
2953
                // check geometry field
2954
0
                iField = poDefn->GetGeomFieldIndex(pszFieldName);
2955
0
                if (iField == -1)
2956
0
                {
2957
0
                    return OGRERR_FAILURE;
2958
0
                }
2959
0
                else
2960
0
                    poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
2961
0
            }
2962
0
            else
2963
0
                poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
2964
0
        }
2965
0
    }
2966
2967
0
    return OGRERR_NONE;
2968
0
}
2969
2970
/************************************************************************/
2971
/*                       OGR_L_SetIgnoredFields()                       */
2972
/************************************************************************/
2973
2974
OGRErr OGR_L_SetIgnoredFields(OGRLayerH hLayer, const char **papszFields)
2975
2976
0
{
2977
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE);
2978
2979
0
#ifdef OGRAPISPY_ENABLED
2980
0
    if (bOGRAPISpyEnabled)
2981
0
        OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
2982
0
#endif
2983
2984
0
    return OGRLayer::FromHandle(hLayer)->SetIgnoredFields(papszFields);
2985
0
}
2986
2987
/************************************************************************/
2988
/*                             Rename()                                 */
2989
/************************************************************************/
2990
2991
/** Rename layer.
2992
 *
2993
 * This operation is implemented only by layers that expose the OLCRename
2994
 * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
2995
 *
2996
 * This operation will fail if a layer with the new name already exists.
2997
 *
2998
 * On success, GetDescription() and GetLayerDefn()->GetName() will return
2999
 * pszNewName.
3000
 *
3001
 * Renaming the layer may interrupt current feature iteration.
3002
 *
3003
 * @param pszNewName New layer name. Must not be NULL.
3004
 * @return OGRERR_NONE in case of success
3005
 *
3006
 * @since GDAL 3.5
3007
 */
3008
OGRErr OGRLayer::Rename(CPL_UNUSED const char *pszNewName)
3009
0
{
3010
0
    CPLError(CE_Failure, CPLE_NotSupported,
3011
0
             "Rename() not supported by this layer.");
3012
3013
0
    return OGRERR_UNSUPPORTED_OPERATION;
3014
0
}
3015
3016
/************************************************************************/
3017
/*                           OGR_L_Rename()                             */
3018
/************************************************************************/
3019
3020
/** Rename layer.
3021
 *
3022
 * This operation is implemented only by layers that expose the OLCRename
3023
 * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
3024
 *
3025
 * This operation will fail if a layer with the new name already exists.
3026
 *
3027
 * On success, GetDescription() and GetLayerDefn()->GetName() will return
3028
 * pszNewName.
3029
 *
3030
 * Renaming the layer may interrupt current feature iteration.
3031
 *
3032
 * @param hLayer     Layer to rename.
3033
 * @param pszNewName New layer name. Must not be NULL.
3034
 * @return OGRERR_NONE in case of success
3035
 *
3036
 * @since GDAL 3.5
3037
 */
3038
OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
3039
3040
0
{
3041
0
    VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
3042
0
    VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
3043
3044
0
    return OGRLayer::FromHandle(hLayer)->Rename(pszNewName);
3045
0
}
3046
3047
/************************************************************************/
3048
/*         helper functions for layer overlay methods                   */
3049
/************************************************************************/
3050
3051
static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
3052
0
{
3053
0
    OGRErr ret = OGRERR_NONE;
3054
0
    OGRGeometry *g = pLayer->GetSpatialFilter();
3055
0
    *ppGeometry = g ? g->clone() : nullptr;
3056
0
    return ret;
3057
0
}
3058
3059
static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
3060
0
{
3061
0
    OGRErr ret = OGRERR_NONE;
3062
0
    int n = poDefn->GetFieldCount();
3063
0
    if (n > 0)
3064
0
    {
3065
0
        *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
3066
0
        if (!(*map))
3067
0
            return OGRERR_NOT_ENOUGH_MEMORY;
3068
0
        for (int i = 0; i < n; i++)
3069
0
            (*map)[i] = -1;
3070
0
    }
3071
0
    return ret;
3072
0
}
3073
3074
static OGRErr set_result_schema(OGRLayer *pLayerResult,
3075
                                OGRFeatureDefn *poDefnInput,
3076
                                OGRFeatureDefn *poDefnMethod, int *mapInput,
3077
                                int *mapMethod, bool combined,
3078
                                const char *const *papszOptions)
3079
0
{
3080
0
    if (!CPLTestBool(CSLFetchNameValueDef(papszOptions, "ADD_FIELDS", "YES")))
3081
0
        return OGRERR_NONE;
3082
3083
0
    OGRErr ret = OGRERR_NONE;
3084
0
    OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
3085
0
    const char *pszInputPrefix =
3086
0
        CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
3087
0
    const char *pszMethodPrefix =
3088
0
        CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
3089
0
    const bool bSkipFailures =
3090
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3091
0
    if (poDefnResult->GetFieldCount() > 0)
3092
0
    {
3093
        // the user has defined the schema of the output layer
3094
0
        if (mapInput)
3095
0
        {
3096
0
            for (int iField = 0; iField < poDefnInput->GetFieldCount();
3097
0
                 iField++)
3098
0
            {
3099
0
                CPLString osName(
3100
0
                    poDefnInput->GetFieldDefn(iField)->GetNameRef());
3101
0
                if (pszInputPrefix != nullptr)
3102
0
                    osName = pszInputPrefix + osName;
3103
0
                mapInput[iField] = poDefnResult->GetFieldIndex(osName);
3104
0
            }
3105
0
        }
3106
0
        if (!mapMethod)
3107
0
            return ret;
3108
        // cppcheck-suppress nullPointer
3109
0
        for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
3110
0
        {
3111
            // cppcheck-suppress nullPointer
3112
0
            CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
3113
0
            if (pszMethodPrefix != nullptr)
3114
0
                osName = pszMethodPrefix + osName;
3115
0
            mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
3116
0
        }
3117
0
    }
3118
0
    else
3119
0
    {
3120
        // use schema from the input layer or from input and method layers
3121
0
        const int nFieldsInput = poDefnInput->GetFieldCount();
3122
3123
        // If no prefix is specified and we have input+method layers, make
3124
        // sure we will generate unique field names
3125
0
        std::set<std::string> oSetInputFieldNames;
3126
0
        std::set<std::string> oSetMethodFieldNames;
3127
0
        if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
3128
0
            pszMethodPrefix == nullptr)
3129
0
        {
3130
0
            for (int iField = 0; iField < nFieldsInput; iField++)
3131
0
            {
3132
0
                oSetInputFieldNames.insert(
3133
0
                    poDefnInput->GetFieldDefn(iField)->GetNameRef());
3134
0
            }
3135
0
            const int nFieldsMethod = poDefnMethod->GetFieldCount();
3136
0
            for (int iField = 0; iField < nFieldsMethod; iField++)
3137
0
            {
3138
0
                oSetMethodFieldNames.insert(
3139
0
                    poDefnMethod->GetFieldDefn(iField)->GetNameRef());
3140
0
            }
3141
0
        }
3142
3143
0
        const bool bAddInputFields = CPLTestBool(
3144
0
            CSLFetchNameValueDef(papszOptions, "ADD_INPUT_FIELDS", "YES"));
3145
0
        if (bAddInputFields)
3146
0
        {
3147
0
            for (int iField = 0; iField < nFieldsInput; iField++)
3148
0
            {
3149
0
                OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
3150
0
                if (pszInputPrefix != nullptr)
3151
0
                    oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
3152
0
                                                  oFieldDefn.GetNameRef()));
3153
0
                else if (!oSetMethodFieldNames.empty() &&
3154
0
                         oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
3155
0
                             oSetMethodFieldNames.end())
3156
0
                {
3157
                    // Field of same name present in method layer
3158
0
                    oFieldDefn.SetName(
3159
0
                        CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
3160
0
                }
3161
0
                ret = pLayerResult->CreateField(&oFieldDefn);
3162
0
                if (ret != OGRERR_NONE)
3163
0
                {
3164
0
                    if (!bSkipFailures)
3165
0
                        return ret;
3166
0
                    else
3167
0
                    {
3168
0
                        CPLErrorReset();
3169
0
                        ret = OGRERR_NONE;
3170
0
                    }
3171
0
                }
3172
0
                if (mapInput)
3173
0
                    mapInput[iField] =
3174
0
                        pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
3175
0
            }
3176
0
        }
3177
3178
0
        if (!combined)
3179
0
            return ret;
3180
0
        if (!mapMethod)
3181
0
            return ret;
3182
0
        if (!poDefnMethod)
3183
0
            return ret;
3184
3185
0
        const bool bAddMethodFields = CPLTestBool(
3186
0
            CSLFetchNameValueDef(papszOptions, "ADD_METHOD_FIELDS", "YES"));
3187
0
        if (bAddMethodFields)
3188
0
        {
3189
0
            const int nFieldsMethod = poDefnMethod->GetFieldCount();
3190
0
            for (int iField = 0; iField < nFieldsMethod; iField++)
3191
0
            {
3192
0
                OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
3193
0
                if (pszMethodPrefix != nullptr)
3194
0
                    oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
3195
0
                                                  oFieldDefn.GetNameRef()));
3196
0
                else if (!oSetInputFieldNames.empty() &&
3197
0
                         oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
3198
0
                             oSetInputFieldNames.end())
3199
0
                {
3200
                    // Field of same name present in method layer
3201
0
                    oFieldDefn.SetName(
3202
0
                        CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
3203
0
                }
3204
0
                ret = pLayerResult->CreateField(&oFieldDefn);
3205
0
                if (ret != OGRERR_NONE)
3206
0
                {
3207
0
                    if (!bSkipFailures)
3208
0
                        return ret;
3209
0
                    else
3210
0
                    {
3211
0
                        CPLErrorReset();
3212
0
                        ret = OGRERR_NONE;
3213
0
                    }
3214
0
                }
3215
0
                mapMethod[iField] =
3216
0
                    pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
3217
0
            }
3218
0
        }
3219
0
    }
3220
0
    return ret;
3221
0
}
3222
3223
static OGRGeometry *set_filter_from(OGRLayer *pLayer,
3224
                                    OGRGeometry *pGeometryExistingFilter,
3225
                                    OGRFeature *pFeature)
3226
0
{
3227
0
    OGRGeometry *geom = pFeature->GetGeometryRef();
3228
0
    if (!geom)
3229
0
        return nullptr;
3230
0
    if (pGeometryExistingFilter)
3231
0
    {
3232
0
        if (!geom->Intersects(pGeometryExistingFilter))
3233
0
            return nullptr;
3234
0
        OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
3235
0
        if (intersection)
3236
0
        {
3237
0
            pLayer->SetSpatialFilter(intersection);
3238
0
            delete intersection;
3239
0
        }
3240
0
        else
3241
0
            return nullptr;
3242
0
    }
3243
0
    else
3244
0
    {
3245
0
        pLayer->SetSpatialFilter(geom);
3246
0
    }
3247
0
    return geom;
3248
0
}
3249
3250
static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
3251
0
{
3252
0
    OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
3253
0
    if (eType == wkbPoint)
3254
0
        return OGRGeometryFactory::forceToMultiPoint(poGeom);
3255
0
    else if (eType == wkbPolygon)
3256
0
        return OGRGeometryFactory::forceToMultiPolygon(poGeom);
3257
0
    else if (eType == wkbLineString)
3258
0
        return OGRGeometryFactory::forceToMultiLineString(poGeom);
3259
0
    else
3260
0
        return poGeom;
3261
0
}
3262
3263
/************************************************************************/
3264
/*                          Intersection()                              */
3265
/************************************************************************/
3266
/**
3267
 * \brief Intersection of two layers.
3268
 *
3269
 * The result layer contains features whose geometries represent areas
3270
 * that are common between features in the input layer and in the
3271
 * method layer. The features in the result layer have attributes from
3272
 * both input and method layers. The schema of the result layer can be
3273
 * set by the user or, if it is empty, is initialized to contain all
3274
 * fields in the input and method layers.
3275
 *
3276
 * \note If the schema of the result is set by user and contains
3277
 * fields that have the same name as a field in input and in method
3278
 * layer, then the attribute in the result feature will get the value
3279
 * from the feature of the method layer.
3280
 *
3281
 * \note For best performance use the minimum amount of features in
3282
 * the method layer and copy it into a memory layer.
3283
 *
3284
 * \note This method relies on GEOS support. Do not use unless the
3285
 * GEOS support is compiled in.
3286
 *
3287
 * The recognized list of options is:
3288
 * <ul>
3289
 * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
3290
 *     feature could not be inserted or a GEOS call failed.
3291
 * </li>
3292
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3293
 *     into MultiPolygons, LineStrings to MultiLineStrings or
3294
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
3295
 * </li>
3296
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3297
 *     will be created from the fields of the input layer.
3298
 * </li>
3299
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3300
 *     will be created from the fields of the method layer.
3301
 * </li>
3302
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3303
 *     geometries to pretest intersection of features of method layer
3304
 *     with features of this layer.
3305
 * </li>
3306
 * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
3307
 *     containment of features of method layer within the features of
3308
 *     this layer. This will speed up the method significantly in some
3309
 *     cases. Requires that the prepared geometries are in effect.
3310
 * </li>
3311
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3312
 *     result features with lower dimension geometry that would
3313
 *     otherwise be added to the result layer. The default is YES, to add
3314
 *     features with lower dimension geometry, but only if the result layer
3315
 *     has an unknown geometry type.
3316
 * </li>
3317
 * </ul>
3318
 *
3319
 * This method is the same as the C function OGR_L_Intersection().
3320
 *
3321
 * @param pLayerMethod the method layer. Should not be NULL.
3322
 *
3323
 * @param pLayerResult the layer where the features resulting from the
3324
 * operation are inserted. Should not be NULL. See above the note
3325
 * about the schema.
3326
 *
3327
 * @param papszOptions NULL terminated list of options (may be NULL).
3328
 *
3329
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
3330
 * reporting progress or NULL.
3331
 *
3332
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3333
 *
3334
 * @return an error code if there was an error or the execution was
3335
 * interrupted, OGRERR_NONE otherwise.
3336
 *
3337
 * @note The first geometry field is always used.
3338
 *
3339
 * @since OGR 1.10
3340
 */
3341
3342
OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
3343
                              char **papszOptions, GDALProgressFunc pfnProgress,
3344
                              void *pProgressArg)
3345
0
{
3346
0
    OGRErr ret = OGRERR_NONE;
3347
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
3348
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3349
0
    OGRFeatureDefn *poDefnResult = nullptr;
3350
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
3351
0
    int *mapInput = nullptr;
3352
0
    int *mapMethod = nullptr;
3353
0
    OGREnvelope sEnvelopeMethod;
3354
0
    GBool bEnvelopeSet;
3355
0
    double progress_max = static_cast<double>(GetFeatureCount(FALSE));
3356
0
    double progress_counter = 0;
3357
0
    double progress_ticker = 0;
3358
0
    const bool bSkipFailures =
3359
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3360
0
    const bool bPromoteToMulti = CPLTestBool(
3361
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3362
0
    const bool bUsePreparedGeometries = CPLTestBool(
3363
0
        CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
3364
0
    const bool bPretestContainment = CPLTestBool(
3365
0
        CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
3366
0
    bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
3367
0
        papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
3368
3369
    // check for GEOS
3370
0
    if (!OGRGeometryFactory::haveGEOS())
3371
0
    {
3372
0
        CPLError(CE_Failure, CPLE_AppDefined,
3373
0
                 "OGRLayer::Intersection() requires GEOS support");
3374
0
        return OGRERR_UNSUPPORTED_OPERATION;
3375
0
    }
3376
3377
    // get resources
3378
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3379
0
    if (ret != OGRERR_NONE)
3380
0
        goto done;
3381
0
    ret = create_field_map(poDefnInput, &mapInput);
3382
0
    if (ret != OGRERR_NONE)
3383
0
        goto done;
3384
0
    ret = create_field_map(poDefnMethod, &mapMethod);
3385
0
    if (ret != OGRERR_NONE)
3386
0
        goto done;
3387
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
3388
0
                            mapMethod, true, papszOptions);
3389
0
    if (ret != OGRERR_NONE)
3390
0
        goto done;
3391
0
    poDefnResult = pLayerResult->GetLayerDefn();
3392
0
    bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
3393
0
    if (bKeepLowerDimGeom)
3394
0
    {
3395
        // require that the result layer is of geom type unknown
3396
0
        if (pLayerResult->GetGeomType() != wkbUnknown)
3397
0
        {
3398
0
            CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
3399
0
                            "since the result layer does not allow it.");
3400
0
            bKeepLowerDimGeom = false;
3401
0
        }
3402
0
    }
3403
3404
0
    for (auto &&x : this)
3405
0
    {
3406
3407
0
        if (pfnProgress)
3408
0
        {
3409
0
            double p = progress_counter / progress_max;
3410
0
            if (p > progress_ticker)
3411
0
            {
3412
0
                if (!pfnProgress(p, "", pProgressArg))
3413
0
                {
3414
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3415
0
                    ret = OGRERR_FAILURE;
3416
0
                    goto done;
3417
0
                }
3418
0
            }
3419
0
            progress_counter += 1.0;
3420
0
        }
3421
3422
        // is it worth to proceed?
3423
0
        if (bEnvelopeSet)
3424
0
        {
3425
0
            OGRGeometry *x_geom = x->GetGeometryRef();
3426
0
            if (x_geom)
3427
0
            {
3428
0
                OGREnvelope x_env;
3429
0
                x_geom->getEnvelope(&x_env);
3430
0
                if (x_env.MaxX < sEnvelopeMethod.MinX ||
3431
0
                    x_env.MaxY < sEnvelopeMethod.MinY ||
3432
0
                    sEnvelopeMethod.MaxX < x_env.MinX ||
3433
0
                    sEnvelopeMethod.MaxY < x_env.MinY)
3434
0
                {
3435
0
                    continue;
3436
0
                }
3437
0
            }
3438
0
            else
3439
0
            {
3440
0
                continue;
3441
0
            }
3442
0
        }
3443
3444
        // set up the filter for method layer
3445
0
        CPLErrorReset();
3446
0
        OGRGeometry *x_geom =
3447
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3448
0
        if (CPLGetLastErrorType() != CE_None)
3449
0
        {
3450
0
            if (!bSkipFailures)
3451
0
            {
3452
0
                ret = OGRERR_FAILURE;
3453
0
                goto done;
3454
0
            }
3455
0
            else
3456
0
            {
3457
0
                CPLErrorReset();
3458
0
                ret = OGRERR_NONE;
3459
0
            }
3460
0
        }
3461
0
        if (!x_geom)
3462
0
        {
3463
0
            continue;
3464
0
        }
3465
3466
0
        OGRPreparedGeometryUniquePtr x_prepared_geom;
3467
0
        if (bUsePreparedGeometries)
3468
0
        {
3469
0
            x_prepared_geom.reset(
3470
0
                OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
3471
0
            if (!x_prepared_geom)
3472
0
            {
3473
0
                goto done;
3474
0
            }
3475
0
        }
3476
3477
0
        for (auto &&y : pLayerMethod)
3478
0
        {
3479
0
            OGRGeometry *y_geom = y->GetGeometryRef();
3480
0
            if (!y_geom)
3481
0
                continue;
3482
0
            OGRGeometryUniquePtr z_geom;
3483
3484
0
            if (x_prepared_geom)
3485
0
            {
3486
0
                CPLErrorReset();
3487
0
                ret = OGRERR_NONE;
3488
0
                if (bPretestContainment &&
3489
0
                    OGRPreparedGeometryContains(x_prepared_geom.get(),
3490
0
                                                OGRGeometry::ToHandle(y_geom)))
3491
0
                {
3492
0
                    if (CPLGetLastErrorType() == CE_None)
3493
0
                        z_geom.reset(y_geom->clone());
3494
0
                }
3495
0
                else if (!(OGRPreparedGeometryIntersects(
3496
0
                             x_prepared_geom.get(),
3497
0
                             OGRGeometry::ToHandle(y_geom))))
3498
0
                {
3499
0
                    if (CPLGetLastErrorType() == CE_None)
3500
0
                    {
3501
0
                        continue;
3502
0
                    }
3503
0
                }
3504
0
                if (CPLGetLastErrorType() != CE_None)
3505
0
                {
3506
0
                    if (!bSkipFailures)
3507
0
                    {
3508
0
                        ret = OGRERR_FAILURE;
3509
0
                        goto done;
3510
0
                    }
3511
0
                    else
3512
0
                    {
3513
0
                        CPLErrorReset();
3514
0
                        ret = OGRERR_NONE;
3515
0
                        continue;
3516
0
                    }
3517
0
                }
3518
0
            }
3519
0
            if (!z_geom)
3520
0
            {
3521
0
                CPLErrorReset();
3522
0
                z_geom.reset(x_geom->Intersection(y_geom));
3523
0
                if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
3524
0
                {
3525
0
                    if (!bSkipFailures)
3526
0
                    {
3527
0
                        ret = OGRERR_FAILURE;
3528
0
                        goto done;
3529
0
                    }
3530
0
                    else
3531
0
                    {
3532
0
                        CPLErrorReset();
3533
0
                        ret = OGRERR_NONE;
3534
0
                        continue;
3535
0
                    }
3536
0
                }
3537
0
                if (z_geom->IsEmpty() ||
3538
0
                    (!bKeepLowerDimGeom &&
3539
0
                     (x_geom->getDimension() == y_geom->getDimension() &&
3540
0
                      z_geom->getDimension() < x_geom->getDimension())))
3541
0
                {
3542
0
                    continue;
3543
0
                }
3544
0
            }
3545
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3546
0
            z->SetFieldsFrom(x.get(), mapInput);
3547
0
            z->SetFieldsFrom(y.get(), mapMethod);
3548
0
            if (bPromoteToMulti)
3549
0
                z_geom.reset(promote_to_multi(z_geom.release()));
3550
0
            z->SetGeometryDirectly(z_geom.release());
3551
0
            ret = pLayerResult->CreateFeature(z.get());
3552
3553
0
            if (ret != OGRERR_NONE)
3554
0
            {
3555
0
                if (!bSkipFailures)
3556
0
                {
3557
0
                    goto done;
3558
0
                }
3559
0
                else
3560
0
                {
3561
0
                    CPLErrorReset();
3562
0
                    ret = OGRERR_NONE;
3563
0
                }
3564
0
            }
3565
0
        }
3566
0
    }
3567
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
3568
0
    {
3569
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3570
0
        ret = OGRERR_FAILURE;
3571
0
        goto done;
3572
0
    }
3573
0
done:
3574
    // release resources
3575
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3576
0
    if (pGeometryMethodFilter)
3577
0
        delete pGeometryMethodFilter;
3578
0
    if (mapInput)
3579
0
        VSIFree(mapInput);
3580
0
    if (mapMethod)
3581
0
        VSIFree(mapMethod);
3582
0
    return ret;
3583
0
}
3584
3585
/************************************************************************/
3586
/*                       OGR_L_Intersection()                           */
3587
/************************************************************************/
3588
/**
3589
 * \brief Intersection of two layers.
3590
 *
3591
 * The result layer contains features whose geometries represent areas
3592
 * that are common between features in the input layer and in the
3593
 * method layer. The features in the result layer have attributes from
3594
 * both input and method layers. The schema of the result layer can be
3595
 * set by the user or, if it is empty, is initialized to contain all
3596
 * fields in the input and method layers.
3597
 *
3598
 * \note If the schema of the result is set by user and contains
3599
 * fields that have the same name as a field in input and in method
3600
 * layer, then the attribute in the result feature will get the value
3601
 * from the feature of the method layer.
3602
 *
3603
 * \note For best performance use the minimum amount of features in
3604
 * the method layer and copy it into a memory layer.
3605
 *
3606
 * \note This method relies on GEOS support. Do not use unless the
3607
 * GEOS support is compiled in.
3608
 *
3609
 * The recognized list of options is :
3610
 * <ul>
3611
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3612
 *     feature could not be inserted or a GEOS call failed.
3613
 * </li>
3614
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3615
 *     into MultiPolygons, LineStrings to MultiLineStrings or
3616
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
3617
 * </li>
3618
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3619
 *     will be created from the fields of the input layer.
3620
 * </li>
3621
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3622
 *     will be created from the fields of the method layer.
3623
 * </li>
3624
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3625
 *     geometries to pretest intersection of features of method layer
3626
 *     with features of this layer.
3627
 * </li>
3628
 * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
3629
 *     containment of features of method layer within the features of
3630
 *     this layer. This will speed up the method significantly in some
3631
 *     cases. Requires that the prepared geometries are in effect.
3632
 * </li>
3633
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3634
 *     result features with lower dimension geometry that would
3635
 *     otherwise be added to the result layer. The default is YES, to add
3636
 *     features with lower dimension geometry, but only if the result layer
3637
 *     has an unknown geometry type.
3638
 * </li>
3639
 * </ul>
3640
 *
3641
 * This function is the same as the C++ method OGRLayer::Intersection().
3642
 *
3643
 * @param pLayerInput the input layer. Should not be NULL.
3644
 *
3645
 * @param pLayerMethod the method layer. Should not be NULL.
3646
 *
3647
 * @param pLayerResult the layer where the features resulting from the
3648
 * operation are inserted. Should not be NULL. See above the note
3649
 * about the schema.
3650
 *
3651
 * @param papszOptions NULL terminated list of options (may be NULL).
3652
 *
3653
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
3654
 * reporting progress or NULL.
3655
 *
3656
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3657
 *
3658
 * @return an error code if there was an error or the execution was
3659
 * interrupted, OGRERR_NONE otherwise.
3660
 *
3661
 * @note The first geometry field is always used.
3662
 *
3663
 * @since OGR 1.10
3664
 */
3665
3666
OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
3667
                          OGRLayerH pLayerResult, char **papszOptions,
3668
                          GDALProgressFunc pfnProgress, void *pProgressArg)
3669
3670
0
{
3671
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
3672
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
3673
0
                      OGRERR_INVALID_HANDLE);
3674
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
3675
0
                      OGRERR_INVALID_HANDLE);
3676
3677
0
    return OGRLayer::FromHandle(pLayerInput)
3678
0
        ->Intersection(OGRLayer::FromHandle(pLayerMethod),
3679
0
                       OGRLayer::FromHandle(pLayerResult), papszOptions,
3680
0
                       pfnProgress, pProgressArg);
3681
0
}
3682
3683
/************************************************************************/
3684
/*                              Union()                                 */
3685
/************************************************************************/
3686
3687
/**
3688
 * \brief Union of two layers.
3689
 *
3690
 * The result layer contains features whose geometries represent areas
3691
 * that are either in the input layer, in the method layer, or in
3692
 * both. The features in the result layer have attributes from both
3693
 * input and method layers. For features which represent areas that
3694
 * are only in the input or in the method layer the respective
3695
 * attributes have undefined values. The schema of the result layer
3696
 * can be set by the user or, if it is empty, is initialized to
3697
 * contain all fields in the input and method layers.
3698
 *
3699
 * \note If the schema of the result is set by user and contains
3700
 * fields that have the same name as a field in input and in method
3701
 * layer, then the attribute in the result feature will get the value
3702
 * from the feature of the method layer (even if it is undefined).
3703
 *
3704
 * \note For best performance use the minimum amount of features in
3705
 * the method layer and copy it into a memory layer.
3706
 *
3707
 * \note This method relies on GEOS support. Do not use unless the
3708
 * GEOS support is compiled in.
3709
 *
3710
 * The recognized list of options is :
3711
 * <ul>
3712
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3713
 *     feature could not be inserted or a GEOS call failed.
3714
 * </li>
3715
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3716
 *     into MultiPolygons, LineStrings to MultiLineStrings or
3717
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
3718
 * </li>
3719
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3720
 *     will be created from the fields of the input layer.
3721
 * </li>
3722
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3723
 *     will be created from the fields of the method layer.
3724
 * </li>
3725
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3726
 *     geometries to pretest intersection of features of method layer
3727
 *     with features of this layer.
3728
 * </li>
3729
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3730
 *     result features with lower dimension geometry that would
3731
 *     otherwise be added to the result layer. The default is YES, to add
3732
 *     features with lower dimension geometry, but only if the result layer
3733
 *     has an unknown geometry type.
3734
 * </li>
3735
 * </ul>
3736
 *
3737
 * This method is the same as the C function OGR_L_Union().
3738
 *
3739
 * @param pLayerMethod the method layer. Should not be NULL.
3740
 *
3741
 * @param pLayerResult the layer where the features resulting from the
3742
 * operation are inserted. Should not be NULL. See above the note
3743
 * about the schema.
3744
 *
3745
 * @param papszOptions NULL terminated list of options (may be NULL).
3746
 *
3747
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
3748
 * reporting progress or NULL.
3749
 *
3750
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3751
 *
3752
 * @return an error code if there was an error or the execution was
3753
 * interrupted, OGRERR_NONE otherwise.
3754
 *
3755
 * @note The first geometry field is always used.
3756
 *
3757
 * @since OGR 1.10
3758
 */
3759
3760
OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
3761
                       char **papszOptions, GDALProgressFunc pfnProgress,
3762
                       void *pProgressArg)
3763
0
{
3764
0
    OGRErr ret = OGRERR_NONE;
3765
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
3766
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3767
0
    OGRFeatureDefn *poDefnResult = nullptr;
3768
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
3769
0
    OGRGeometry *pGeometryInputFilter = nullptr;
3770
0
    int *mapInput = nullptr;
3771
0
    int *mapMethod = nullptr;
3772
0
    double progress_max =
3773
0
        static_cast<double>(GetFeatureCount(FALSE)) +
3774
0
        static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
3775
0
    double progress_counter = 0;
3776
0
    double progress_ticker = 0;
3777
0
    const bool bSkipFailures =
3778
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3779
0
    const bool bPromoteToMulti = CPLTestBool(
3780
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3781
0
    const bool bUsePreparedGeometries = CPLTestBool(
3782
0
        CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
3783
0
    bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
3784
0
        papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
3785
3786
    // check for GEOS
3787
0
    if (!OGRGeometryFactory::haveGEOS())
3788
0
    {
3789
0
        CPLError(CE_Failure, CPLE_AppDefined,
3790
0
                 "OGRLayer::Union() requires GEOS support");
3791
0
        return OGRERR_UNSUPPORTED_OPERATION;
3792
0
    }
3793
3794
    // get resources
3795
0
    ret = clone_spatial_filter(this, &pGeometryInputFilter);
3796
0
    if (ret != OGRERR_NONE)
3797
0
        goto done;
3798
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3799
0
    if (ret != OGRERR_NONE)
3800
0
        goto done;
3801
0
    ret = create_field_map(poDefnInput, &mapInput);
3802
0
    if (ret != OGRERR_NONE)
3803
0
        goto done;
3804
0
    ret = create_field_map(poDefnMethod, &mapMethod);
3805
0
    if (ret != OGRERR_NONE)
3806
0
        goto done;
3807
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
3808
0
                            mapMethod, true, papszOptions);
3809
0
    if (ret != OGRERR_NONE)
3810
0
        goto done;
3811
0
    poDefnResult = pLayerResult->GetLayerDefn();
3812
0
    if (bKeepLowerDimGeom)
3813
0
    {
3814
        // require that the result layer is of geom type unknown
3815
0
        if (pLayerResult->GetGeomType() != wkbUnknown)
3816
0
        {
3817
0
            CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
3818
0
                            "since the result layer does not allow it.");
3819
0
            bKeepLowerDimGeom = FALSE;
3820
0
        }
3821
0
    }
3822
3823
    // add features based on input layer
3824
0
    for (auto &&x : this)
3825
0
    {
3826
3827
0
        if (pfnProgress)
3828
0
        {
3829
0
            double p = progress_counter / progress_max;
3830
0
            if (p > progress_ticker)
3831
0
            {
3832
0
                if (!pfnProgress(p, "", pProgressArg))
3833
0
                {
3834
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3835
0
                    ret = OGRERR_FAILURE;
3836
0
                    goto done;
3837
0
                }
3838
0
            }
3839
0
            progress_counter += 1.0;
3840
0
        }
3841
3842
        // set up the filter on method layer
3843
0
        CPLErrorReset();
3844
0
        OGRGeometry *x_geom =
3845
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3846
0
        if (CPLGetLastErrorType() != CE_None)
3847
0
        {
3848
0
            if (!bSkipFailures)
3849
0
            {
3850
0
                ret = OGRERR_FAILURE;
3851
0
                goto done;
3852
0
            }
3853
0
            else
3854
0
            {
3855
0
                CPLErrorReset();
3856
0
                ret = OGRERR_NONE;
3857
0
            }
3858
0
        }
3859
0
        if (!x_geom)
3860
0
        {
3861
0
            continue;
3862
0
        }
3863
3864
0
        OGRPreparedGeometryUniquePtr x_prepared_geom;
3865
0
        if (bUsePreparedGeometries)
3866
0
        {
3867
0
            x_prepared_geom.reset(
3868
0
                OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
3869
0
            if (!x_prepared_geom)
3870
0
            {
3871
0
                goto done;
3872
0
            }
3873
0
        }
3874
3875
0
        OGRGeometryUniquePtr x_geom_diff(
3876
0
            x_geom
3877
0
                ->clone());  // this will be the geometry of the result feature
3878
0
        for (auto &&y : pLayerMethod)
3879
0
        {
3880
0
            OGRGeometry *y_geom = y->GetGeometryRef();
3881
0
            if (!y_geom)
3882
0
            {
3883
0
                continue;
3884
0
            }
3885
3886
0
            CPLErrorReset();
3887
0
            if (x_prepared_geom &&
3888
0
                !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
3889
0
                                                OGRGeometry::ToHandle(y_geom))))
3890
0
            {
3891
0
                if (CPLGetLastErrorType() == CE_None)
3892
0
                {
3893
0
                    continue;
3894
0
                }
3895
0
            }
3896
0
            if (CPLGetLastErrorType() != CE_None)
3897
0
            {
3898
0
                if (!bSkipFailures)
3899
0
                {
3900
0
                    ret = OGRERR_FAILURE;
3901
0
                    goto done;
3902
0
                }
3903
0
                else
3904
0
                {
3905
0
                    CPLErrorReset();
3906
0
                    ret = OGRERR_NONE;
3907
0
                }
3908
0
            }
3909
3910
0
            CPLErrorReset();
3911
0
            OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
3912
0
            if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
3913
0
            {
3914
0
                if (!bSkipFailures)
3915
0
                {
3916
0
                    ret = OGRERR_FAILURE;
3917
0
                    goto done;
3918
0
                }
3919
0
                else
3920
0
                {
3921
0
                    CPLErrorReset();
3922
0
                    ret = OGRERR_NONE;
3923
0
                    continue;
3924
0
                }
3925
0
            }
3926
0
            if (poIntersection->IsEmpty() ||
3927
0
                (!bKeepLowerDimGeom &&
3928
0
                 (x_geom->getDimension() == y_geom->getDimension() &&
3929
0
                  poIntersection->getDimension() < x_geom->getDimension())))
3930
0
            {
3931
                // ok
3932
0
            }
3933
0
            else
3934
0
            {
3935
0
                OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3936
0
                z->SetFieldsFrom(x.get(), mapInput);
3937
0
                z->SetFieldsFrom(y.get(), mapMethod);
3938
0
                if (bPromoteToMulti)
3939
0
                    poIntersection.reset(
3940
0
                        promote_to_multi(poIntersection.release()));
3941
0
                z->SetGeometryDirectly(poIntersection.release());
3942
3943
0
                if (x_geom_diff)
3944
0
                {
3945
0
                    CPLErrorReset();
3946
0
                    OGRGeometryUniquePtr x_geom_diff_new(
3947
0
                        x_geom_diff->Difference(y_geom));
3948
0
                    if (CPLGetLastErrorType() != CE_None ||
3949
0
                        x_geom_diff_new == nullptr)
3950
0
                    {
3951
0
                        if (!bSkipFailures)
3952
0
                        {
3953
0
                            ret = OGRERR_FAILURE;
3954
0
                            goto done;
3955
0
                        }
3956
0
                        else
3957
0
                        {
3958
0
                            CPLErrorReset();
3959
0
                        }
3960
0
                    }
3961
0
                    else
3962
0
                    {
3963
0
                        x_geom_diff.swap(x_geom_diff_new);
3964
0
                    }
3965
0
                }
3966
3967
0
                ret = pLayerResult->CreateFeature(z.get());
3968
0
                if (ret != OGRERR_NONE)
3969
0
                {
3970
0
                    if (!bSkipFailures)
3971
0
                    {
3972
0
                        goto done;
3973
0
                    }
3974
0
                    else
3975
0
                    {
3976
0
                        CPLErrorReset();
3977
0
                        ret = OGRERR_NONE;
3978
0
                    }
3979
0
                }
3980
0
            }
3981
0
        }
3982
0
        x_prepared_geom.reset();
3983
3984
0
        if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
3985
0
        {
3986
            // ok
3987
0
        }
3988
0
        else
3989
0
        {
3990
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3991
0
            z->SetFieldsFrom(x.get(), mapInput);
3992
0
            if (bPromoteToMulti)
3993
0
                x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
3994
0
            z->SetGeometryDirectly(x_geom_diff.release());
3995
0
            ret = pLayerResult->CreateFeature(z.get());
3996
0
            if (ret != OGRERR_NONE)
3997
0
            {
3998
0
                if (!bSkipFailures)
3999
0
                {
4000
0
                    goto done;
4001
0
                }
4002
0
                else
4003
0
                {
4004
0
                    CPLErrorReset();
4005
0
                    ret = OGRERR_NONE;
4006
0
                }
4007
0
            }
4008
0
        }
4009
0
    }
4010
4011
    // restore filter on method layer and add features based on it
4012
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4013
0
    for (auto &&x : pLayerMethod)
4014
0
    {
4015
4016
0
        if (pfnProgress)
4017
0
        {
4018
0
            double p = progress_counter / progress_max;
4019
0
            if (p > progress_ticker)
4020
0
            {
4021
0
                if (!pfnProgress(p, "", pProgressArg))
4022
0
                {
4023
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4024
0
                    ret = OGRERR_FAILURE;
4025
0
                    goto done;
4026
0
                }
4027
0
            }
4028
0
            progress_counter += 1.0;
4029
0
        }
4030
4031
        // set up the filter on input layer
4032
0
        CPLErrorReset();
4033
0
        OGRGeometry *x_geom =
4034
0
            set_filter_from(this, pGeometryInputFilter, x.get());
4035
0
        if (CPLGetLastErrorType() != CE_None)
4036
0
        {
4037
0
            if (!bSkipFailures)
4038
0
            {
4039
0
                ret = OGRERR_FAILURE;
4040
0
                goto done;
4041
0
            }
4042
0
            else
4043
0
            {
4044
0
                CPLErrorReset();
4045
0
                ret = OGRERR_NONE;
4046
0
            }
4047
0
        }
4048
0
        if (!x_geom)
4049
0
        {
4050
0
            continue;
4051
0
        }
4052
4053
0
        OGRGeometryUniquePtr x_geom_diff(
4054
0
            x_geom
4055
0
                ->clone());  // this will be the geometry of the result feature
4056
0
        for (auto &&y : this)
4057
0
        {
4058
0
            OGRGeometry *y_geom = y->GetGeometryRef();
4059
0
            if (!y_geom)
4060
0
            {
4061
0
                continue;
4062
0
            }
4063
4064
0
            if (x_geom_diff)
4065
0
            {
4066
0
                CPLErrorReset();
4067
0
                OGRGeometryUniquePtr x_geom_diff_new(
4068
0
                    x_geom_diff->Difference(y_geom));
4069
0
                if (CPLGetLastErrorType() != CE_None ||
4070
0
                    x_geom_diff_new == nullptr)
4071
0
                {
4072
0
                    if (!bSkipFailures)
4073
0
                    {
4074
0
                        ret = OGRERR_FAILURE;
4075
0
                        goto done;
4076
0
                    }
4077
0
                    else
4078
0
                    {
4079
0
                        CPLErrorReset();
4080
0
                        ret = OGRERR_NONE;
4081
0
                    }
4082
0
                }
4083
0
                else
4084
0
                {
4085
0
                    x_geom_diff.swap(x_geom_diff_new);
4086
0
                }
4087
0
            }
4088
0
        }
4089
4090
0
        if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
4091
0
        {
4092
            // ok
4093
0
        }
4094
0
        else
4095
0
        {
4096
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4097
0
            z->SetFieldsFrom(x.get(), mapMethod);
4098
0
            if (bPromoteToMulti)
4099
0
                x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
4100
0
            z->SetGeometryDirectly(x_geom_diff.release());
4101
0
            ret = pLayerResult->CreateFeature(z.get());
4102
0
            if (ret != OGRERR_NONE)
4103
0
            {
4104
0
                if (!bSkipFailures)
4105
0
                {
4106
0
                    goto done;
4107
0
                }
4108
0
                else
4109
0
                {
4110
0
                    CPLErrorReset();
4111
0
                    ret = OGRERR_NONE;
4112
0
                }
4113
0
            }
4114
0
        }
4115
0
    }
4116
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4117
0
    {
4118
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4119
0
        ret = OGRERR_FAILURE;
4120
0
        goto done;
4121
0
    }
4122
0
done:
4123
    // release resources
4124
0
    SetSpatialFilter(pGeometryInputFilter);
4125
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4126
0
    if (pGeometryMethodFilter)
4127
0
        delete pGeometryMethodFilter;
4128
0
    if (pGeometryInputFilter)
4129
0
        delete pGeometryInputFilter;
4130
0
    if (mapInput)
4131
0
        VSIFree(mapInput);
4132
0
    if (mapMethod)
4133
0
        VSIFree(mapMethod);
4134
0
    return ret;
4135
0
}
4136
4137
/************************************************************************/
4138
/*                           OGR_L_Union()                              */
4139
/************************************************************************/
4140
4141
/**
4142
 * \brief Union of two layers.
4143
 *
4144
 * The result layer contains features whose geometries represent areas
4145
 * that are in either in the input layer, in the method layer, or in
4146
 * both. The features in the result layer have attributes from both
4147
 * input and method layers. For features which represent areas that
4148
 * are only in the input or in the method layer the respective
4149
 * attributes have undefined values. The schema of the result layer
4150
 * can be set by the user or, if it is empty, is initialized to
4151
 * contain all fields in the input and method layers.
4152
 *
4153
 * \note If the schema of the result is set by user and contains
4154
 * fields that have the same name as a field in input and in method
4155
 * layer, then the attribute in the result feature will get the value
4156
 * from the feature of the method layer (even if it is undefined).
4157
 *
4158
 * \note For best performance use the minimum amount of features in
4159
 * the method layer and copy it into a memory layer.
4160
 *
4161
 * \note This method relies on GEOS support. Do not use unless the
4162
 * GEOS support is compiled in.
4163
 *
4164
 * The recognized list of options is :
4165
 * <ul>
4166
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4167
 *     feature could not be inserted or a GEOS call failed.
4168
 * </li>
4169
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4170
 *     into MultiPolygons, LineStrings to MultiLineStrings or
4171
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
4172
 * </li>
4173
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4174
 *     will be created from the fields of the input layer.
4175
 * </li>
4176
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4177
 *     will be created from the fields of the method layer.
4178
 * </li>
4179
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
4180
 *     geometries to pretest intersection of features of method layer
4181
 *     with features of this layer.
4182
 * </li>
4183
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
4184
 *     result features with lower dimension geometry that would
4185
 *     otherwise be added to the result layer. The default is YES, to add
4186
 *     features with lower dimension geometry, but only if the result layer
4187
 *     has an unknown geometry type.
4188
 * </li>
4189
 * </ul>
4190
 *
4191
 * This function is the same as the C++ method OGRLayer::Union().
4192
 *
4193
 * @param pLayerInput the input layer. Should not be NULL.
4194
 *
4195
 * @param pLayerMethod the method layer. Should not be NULL.
4196
 *
4197
 * @param pLayerResult the layer where the features resulting from the
4198
 * operation are inserted. Should not be NULL. See above the note
4199
 * about the schema.
4200
 *
4201
 * @param papszOptions NULL terminated list of options (may be NULL).
4202
 *
4203
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
4204
 * reporting progress or NULL.
4205
 *
4206
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4207
 *
4208
 * @return an error code if there was an error or the execution was
4209
 * interrupted, OGRERR_NONE otherwise.
4210
 *
4211
 * @note The first geometry field is always used.
4212
 *
4213
 * @since OGR 1.10
4214
 */
4215
4216
OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4217
                   OGRLayerH pLayerResult, char **papszOptions,
4218
                   GDALProgressFunc pfnProgress, void *pProgressArg)
4219
4220
0
{
4221
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4222
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4223
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4224
4225
0
    return OGRLayer::FromHandle(pLayerInput)
4226
0
        ->Union(OGRLayer::FromHandle(pLayerMethod),
4227
0
                OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
4228
0
                pProgressArg);
4229
0
}
4230
4231
/************************************************************************/
4232
/*                          SymDifference()                             */
4233
/************************************************************************/
4234
4235
/**
4236
 * \brief Symmetrical difference of two layers.
4237
 *
4238
 * The result layer contains features whose geometries represent areas
4239
 * that are in either in the input layer or in the method layer but
4240
 * not in both. The features in the result layer have attributes from
4241
 * both input and method layers. For features which represent areas
4242
 * that are only in the input or in the method layer the respective
4243
 * attributes have undefined values. The schema of the result layer
4244
 * can be set by the user or, if it is empty, is initialized to
4245
 * contain all fields in the input and method layers.
4246
 *
4247
 * \note If the schema of the result is set by user and contains
4248
 * fields that have the same name as a field in input and in method
4249
 * layer, then the attribute in the result feature will get the value
4250
 * from the feature of the method layer (even if it is undefined).
4251
 *
4252
 * \note For best performance use the minimum amount of features in
4253
 * the method layer and copy it into a memory layer.
4254
 *
4255
 * \note This method relies on GEOS support. Do not use unless the
4256
 * GEOS support is compiled in.
4257
 *
4258
 * The recognized list of options is :
4259
 * <ul>
4260
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4261
 *     feature could not be inserted or a GEOS call failed.
4262
 * </li>
4263
 * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
4264
 *     into MultiPolygons, or LineStrings to MultiLineStrings.
4265
 * </li>
4266
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4267
 *     will be created from the fields of the input layer.
4268
 * </li>
4269
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4270
 *     will be created from the fields of the method layer.
4271
 * </li>
4272
 * </ul>
4273
 *
4274
 * This method is the same as the C function OGR_L_SymDifference().
4275
 *
4276
 * @param pLayerMethod the method layer. Should not be NULL.
4277
 *
4278
 * @param pLayerResult the layer where the features resulting from the
4279
 * operation are inserted. Should not be NULL. See above the note
4280
 * about the schema.
4281
 *
4282
 * @param papszOptions NULL terminated list of options (may be NULL).
4283
 *
4284
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
4285
 * reporting progress or NULL.
4286
 *
4287
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4288
 *
4289
 * @return an error code if there was an error or the execution was
4290
 * interrupted, OGRERR_NONE otherwise.
4291
 *
4292
 * @note The first geometry field is always used.
4293
 *
4294
 * @since OGR 1.10
4295
 */
4296
4297
OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4298
                               char **papszOptions,
4299
                               GDALProgressFunc pfnProgress, void *pProgressArg)
4300
0
{
4301
0
    OGRErr ret = OGRERR_NONE;
4302
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
4303
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
4304
0
    OGRFeatureDefn *poDefnResult = nullptr;
4305
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
4306
0
    OGRGeometry *pGeometryInputFilter = nullptr;
4307
0
    int *mapInput = nullptr;
4308
0
    int *mapMethod = nullptr;
4309
0
    double progress_max =
4310
0
        static_cast<double>(GetFeatureCount(FALSE)) +
4311
0
        static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
4312
0
    double progress_counter = 0;
4313
0
    double progress_ticker = 0;
4314
0
    const bool bSkipFailures =
4315
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4316
0
    const bool bPromoteToMulti = CPLTestBool(
4317
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4318
4319
    // check for GEOS
4320
0
    if (!OGRGeometryFactory::haveGEOS())
4321
0
    {
4322
0
        CPLError(CE_Failure, CPLE_AppDefined,
4323
0
                 "OGRLayer::SymDifference() requires GEOS support");
4324
0
        return OGRERR_UNSUPPORTED_OPERATION;
4325
0
    }
4326
4327
    // get resources
4328
0
    ret = clone_spatial_filter(this, &pGeometryInputFilter);
4329
0
    if (ret != OGRERR_NONE)
4330
0
        goto done;
4331
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4332
0
    if (ret != OGRERR_NONE)
4333
0
        goto done;
4334
0
    ret = create_field_map(poDefnInput, &mapInput);
4335
0
    if (ret != OGRERR_NONE)
4336
0
        goto done;
4337
0
    ret = create_field_map(poDefnMethod, &mapMethod);
4338
0
    if (ret != OGRERR_NONE)
4339
0
        goto done;
4340
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
4341
0
                            mapMethod, true, papszOptions);
4342
0
    if (ret != OGRERR_NONE)
4343
0
        goto done;
4344
0
    poDefnResult = pLayerResult->GetLayerDefn();
4345
4346
    // add features based on input layer
4347
0
    for (auto &&x : this)
4348
0
    {
4349
4350
0
        if (pfnProgress)
4351
0
        {
4352
0
            double p = progress_counter / progress_max;
4353
0
            if (p > progress_ticker)
4354
0
            {
4355
0
                if (!pfnProgress(p, "", pProgressArg))
4356
0
                {
4357
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4358
0
                    ret = OGRERR_FAILURE;
4359
0
                    goto done;
4360
0
                }
4361
0
            }
4362
0
            progress_counter += 1.0;
4363
0
        }
4364
4365
        // set up the filter on method layer
4366
0
        CPLErrorReset();
4367
0
        OGRGeometry *x_geom =
4368
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4369
0
        if (CPLGetLastErrorType() != CE_None)
4370
0
        {
4371
0
            if (!bSkipFailures)
4372
0
            {
4373
0
                ret = OGRERR_FAILURE;
4374
0
                goto done;
4375
0
            }
4376
0
            else
4377
0
            {
4378
0
                CPLErrorReset();
4379
0
                ret = OGRERR_NONE;
4380
0
            }
4381
0
        }
4382
0
        if (!x_geom)
4383
0
        {
4384
0
            continue;
4385
0
        }
4386
4387
0
        OGRGeometryUniquePtr geom(
4388
0
            x_geom
4389
0
                ->clone());  // this will be the geometry of the result feature
4390
0
        for (auto &&y : pLayerMethod)
4391
0
        {
4392
0
            OGRGeometry *y_geom = y->GetGeometryRef();
4393
0
            if (!y_geom)
4394
0
            {
4395
0
                continue;
4396
0
            }
4397
0
            if (geom)
4398
0
            {
4399
0
                CPLErrorReset();
4400
0
                OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
4401
0
                if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
4402
0
                {
4403
0
                    if (!bSkipFailures)
4404
0
                    {
4405
0
                        ret = OGRERR_FAILURE;
4406
0
                        goto done;
4407
0
                    }
4408
0
                    else
4409
0
                    {
4410
0
                        CPLErrorReset();
4411
0
                        ret = OGRERR_NONE;
4412
0
                    }
4413
0
                }
4414
0
                else
4415
0
                {
4416
0
                    geom.swap(geom_new);
4417
0
                }
4418
0
            }
4419
0
            if (geom && geom->IsEmpty())
4420
0
                break;
4421
0
        }
4422
4423
0
        if (geom && !geom->IsEmpty())
4424
0
        {
4425
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4426
0
            z->SetFieldsFrom(x.get(), mapInput);
4427
0
            if (bPromoteToMulti)
4428
0
                geom.reset(promote_to_multi(geom.release()));
4429
0
            z->SetGeometryDirectly(geom.release());
4430
0
            ret = pLayerResult->CreateFeature(z.get());
4431
0
            if (ret != OGRERR_NONE)
4432
0
            {
4433
0
                if (!bSkipFailures)
4434
0
                {
4435
0
                    goto done;
4436
0
                }
4437
0
                else
4438
0
                {
4439
0
                    CPLErrorReset();
4440
0
                    ret = OGRERR_NONE;
4441
0
                }
4442
0
            }
4443
0
        }
4444
0
    }
4445
4446
    // restore filter on method layer and add features based on it
4447
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4448
0
    for (auto &&x : pLayerMethod)
4449
0
    {
4450
4451
0
        if (pfnProgress)
4452
0
        {
4453
0
            double p = progress_counter / progress_max;
4454
0
            if (p > progress_ticker)
4455
0
            {
4456
0
                if (!pfnProgress(p, "", pProgressArg))
4457
0
                {
4458
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4459
0
                    ret = OGRERR_FAILURE;
4460
0
                    goto done;
4461
0
                }
4462
0
            }
4463
0
            progress_counter += 1.0;
4464
0
        }
4465
4466
        // set up the filter on input layer
4467
0
        CPLErrorReset();
4468
0
        OGRGeometry *x_geom =
4469
0
            set_filter_from(this, pGeometryInputFilter, x.get());
4470
0
        if (CPLGetLastErrorType() != CE_None)
4471
0
        {
4472
0
            if (!bSkipFailures)
4473
0
            {
4474
0
                ret = OGRERR_FAILURE;
4475
0
                goto done;
4476
0
            }
4477
0
            else
4478
0
            {
4479
0
                CPLErrorReset();
4480
0
                ret = OGRERR_NONE;
4481
0
            }
4482
0
        }
4483
0
        if (!x_geom)
4484
0
        {
4485
0
            continue;
4486
0
        }
4487
4488
0
        OGRGeometryUniquePtr geom(
4489
0
            x_geom
4490
0
                ->clone());  // this will be the geometry of the result feature
4491
0
        for (auto &&y : this)
4492
0
        {
4493
0
            OGRGeometry *y_geom = y->GetGeometryRef();
4494
0
            if (!y_geom)
4495
0
                continue;
4496
0
            if (geom)
4497
0
            {
4498
0
                CPLErrorReset();
4499
0
                OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
4500
0
                if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
4501
0
                {
4502
0
                    if (!bSkipFailures)
4503
0
                    {
4504
0
                        ret = OGRERR_FAILURE;
4505
0
                        goto done;
4506
0
                    }
4507
0
                    else
4508
0
                    {
4509
0
                        CPLErrorReset();
4510
0
                        ret = OGRERR_NONE;
4511
0
                    }
4512
0
                }
4513
0
                else
4514
0
                {
4515
0
                    geom.swap(geom_new);
4516
0
                }
4517
0
            }
4518
0
            if (geom == nullptr || geom->IsEmpty())
4519
0
                break;
4520
0
        }
4521
4522
0
        if (geom && !geom->IsEmpty())
4523
0
        {
4524
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4525
0
            z->SetFieldsFrom(x.get(), mapMethod);
4526
0
            if (bPromoteToMulti)
4527
0
                geom.reset(promote_to_multi(geom.release()));
4528
0
            z->SetGeometryDirectly(geom.release());
4529
0
            ret = pLayerResult->CreateFeature(z.get());
4530
0
            if (ret != OGRERR_NONE)
4531
0
            {
4532
0
                if (!bSkipFailures)
4533
0
                {
4534
0
                    goto done;
4535
0
                }
4536
0
                else
4537
0
                {
4538
0
                    CPLErrorReset();
4539
0
                    ret = OGRERR_NONE;
4540
0
                }
4541
0
            }
4542
0
        }
4543
0
    }
4544
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4545
0
    {
4546
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4547
0
        ret = OGRERR_FAILURE;
4548
0
        goto done;
4549
0
    }
4550
0
done:
4551
    // release resources
4552
0
    SetSpatialFilter(pGeometryInputFilter);
4553
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4554
0
    if (pGeometryMethodFilter)
4555
0
        delete pGeometryMethodFilter;
4556
0
    if (pGeometryInputFilter)
4557
0
        delete pGeometryInputFilter;
4558
0
    if (mapInput)
4559
0
        VSIFree(mapInput);
4560
0
    if (mapMethod)
4561
0
        VSIFree(mapMethod);
4562
0
    return ret;
4563
0
}
4564
4565
/************************************************************************/
4566
/*                        OGR_L_SymDifference()                         */
4567
/************************************************************************/
4568
4569
/**
4570
 * \brief Symmetrical difference of two layers.
4571
 *
4572
 * The result layer contains features whose geometries represent areas
4573
 * that are in either in the input layer or in the method layer but
4574
 * not in both. The features in the result layer have attributes from
4575
 * both input and method layers. For features which represent areas
4576
 * that are only in the input or in the method layer the respective
4577
 * attributes have undefined values. The schema of the result layer
4578
 * can be set by the user or, if it is empty, is initialized to
4579
 * contain all fields in the input and method layers.
4580
 *
4581
 * \note If the schema of the result is set by user and contains
4582
 * fields that have the same name as a field in input and in method
4583
 * layer, then the attribute in the result feature will get the value
4584
 * from the feature of the method layer (even if it is undefined).
4585
 *
4586
 * \note For best performance use the minimum amount of features in
4587
 * the method layer and copy it into a memory layer.
4588
 *
4589
 * \note This method relies on GEOS support. Do not use unless the
4590
 * GEOS support is compiled in.
4591
 *
4592
 * The recognized list of options is :
4593
 * <ul>
4594
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4595
 *     feature could not be inserted or a GEOS call failed.
4596
 * </li>
4597
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4598
 *     into MultiPolygons, LineStrings to MultiLineStrings or
4599
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
4600
 * </li>
4601
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4602
 *     will be created from the fields of the input layer.
4603
 * </li>
4604
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4605
 *     will be created from the fields of the method layer.
4606
 * </li>
4607
 * </ul>
4608
 *
4609
 * This function is the same as the C++ method OGRLayer::SymDifference().
4610
 *
4611
 * @param pLayerInput the input layer. Should not be NULL.
4612
 *
4613
 * @param pLayerMethod the method layer. Should not be NULL.
4614
 *
4615
 * @param pLayerResult the layer where the features resulting from the
4616
 * operation are inserted. Should not be NULL. See above the note
4617
 * about the schema.
4618
 *
4619
 * @param papszOptions NULL terminated list of options (may be NULL).
4620
 *
4621
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
4622
 * reporting progress or NULL.
4623
 *
4624
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4625
 *
4626
 * @return an error code if there was an error or the execution was
4627
 * interrupted, OGRERR_NONE otherwise.
4628
 *
4629
 * @note The first geometry field is always used.
4630
 *
4631
 * @since OGR 1.10
4632
 */
4633
4634
OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4635
                           OGRLayerH pLayerResult, char **papszOptions,
4636
                           GDALProgressFunc pfnProgress, void *pProgressArg)
4637
4638
0
{
4639
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
4640
0
                      OGRERR_INVALID_HANDLE);
4641
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
4642
0
                      OGRERR_INVALID_HANDLE);
4643
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
4644
0
                      OGRERR_INVALID_HANDLE);
4645
4646
0
    return OGRLayer::FromHandle(pLayerInput)
4647
0
        ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
4648
0
                        OGRLayer::FromHandle(pLayerResult), papszOptions,
4649
0
                        pfnProgress, pProgressArg);
4650
0
}
4651
4652
/************************************************************************/
4653
/*                            Identity()                                */
4654
/************************************************************************/
4655
4656
/**
4657
 * \brief Identify the features of this layer with the ones from the
4658
 * identity layer.
4659
 *
4660
 * The result layer contains features whose geometries represent areas
4661
 * that are in the input layer. The features in the result layer have
4662
 * attributes from both input and method layers. The schema of the
4663
 * result layer can be set by the user or, if it is empty, is
4664
 * initialized to contain all fields in input and method layers.
4665
 *
4666
 * \note If the schema of the result is set by user and contains
4667
 * fields that have the same name as a field in input and in method
4668
 * layer, then the attribute in the result feature will get the value
4669
 * from the feature of the method layer (even if it is undefined).
4670
 *
4671
 * \note For best performance use the minimum amount of features in
4672
 * the method layer and copy it into a memory layer.
4673
 *
4674
 * \note This method relies on GEOS support. Do not use unless the
4675
 * GEOS support is compiled in.
4676
 *
4677
 * The recognized list of options is :
4678
 * <ul>
4679
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4680
 *     feature could not be inserted or a GEOS call failed.
4681
 * </li>
4682
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4683
 *     into MultiPolygons, LineStrings to MultiLineStrings or
4684
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
4685
 * </li>
4686
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4687
 *     will be created from the fields of the input layer.
4688
 * </li>
4689
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4690
 *     will be created from the fields of the method layer.
4691
 * </li>
4692
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
4693
 *     geometries to pretest intersection of features of method layer
4694
 *     with features of this layer.
4695
 * </li>
4696
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
4697
 *     result features with lower dimension geometry that would
4698
 *     otherwise be added to the result layer. The default is YES, to add
4699
 *     features with lower dimension geometry, but only if the result layer
4700
 *     has an unknown geometry type.
4701
 * </li>
4702
 * </ul>
4703
 *
4704
 * This method is the same as the C function OGR_L_Identity().
4705
 *
4706
 * @param pLayerMethod the method layer. Should not be NULL.
4707
 *
4708
 * @param pLayerResult the layer where the features resulting from the
4709
 * operation are inserted. Should not be NULL. See above the note
4710
 * about the schema.
4711
 *
4712
 * @param papszOptions NULL terminated list of options (may be NULL).
4713
 *
4714
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
4715
 * reporting progress or NULL.
4716
 *
4717
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4718
 *
4719
 * @return an error code if there was an error or the execution was
4720
 * interrupted, OGRERR_NONE otherwise.
4721
 *
4722
 * @note The first geometry field is always used.
4723
 *
4724
 * @since OGR 1.10
4725
 */
4726
4727
OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4728
                          char **papszOptions, GDALProgressFunc pfnProgress,
4729
                          void *pProgressArg)
4730
0
{
4731
0
    OGRErr ret = OGRERR_NONE;
4732
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
4733
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
4734
0
    OGRFeatureDefn *poDefnResult = nullptr;
4735
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
4736
0
    int *mapInput = nullptr;
4737
0
    int *mapMethod = nullptr;
4738
0
    double progress_max = static_cast<double>(GetFeatureCount(FALSE));
4739
0
    double progress_counter = 0;
4740
0
    double progress_ticker = 0;
4741
0
    const bool bSkipFailures =
4742
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4743
0
    const bool bPromoteToMulti = CPLTestBool(
4744
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4745
0
    const bool bUsePreparedGeometries = CPLTestBool(
4746
0
        CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
4747
0
    bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
4748
0
        papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
4749
4750
    // check for GEOS
4751
0
    if (!OGRGeometryFactory::haveGEOS())
4752
0
    {
4753
0
        CPLError(CE_Failure, CPLE_AppDefined,
4754
0
                 "OGRLayer::Identity() requires GEOS support");
4755
0
        return OGRERR_UNSUPPORTED_OPERATION;
4756
0
    }
4757
0
    if (bKeepLowerDimGeom)
4758
0
    {
4759
        // require that the result layer is of geom type unknown
4760
0
        if (pLayerResult->GetGeomType() != wkbUnknown)
4761
0
        {
4762
0
            CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
4763
0
                            "since the result layer does not allow it.");
4764
0
            bKeepLowerDimGeom = FALSE;
4765
0
        }
4766
0
    }
4767
4768
    // get resources
4769
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4770
0
    if (ret != OGRERR_NONE)
4771
0
        goto done;
4772
0
    ret = create_field_map(poDefnInput, &mapInput);
4773
0
    if (ret != OGRERR_NONE)
4774
0
        goto done;
4775
0
    ret = create_field_map(poDefnMethod, &mapMethod);
4776
0
    if (ret != OGRERR_NONE)
4777
0
        goto done;
4778
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
4779
0
                            mapMethod, true, papszOptions);
4780
0
    if (ret != OGRERR_NONE)
4781
0
        goto done;
4782
0
    poDefnResult = pLayerResult->GetLayerDefn();
4783
4784
    // split the features in input layer to the result layer
4785
0
    for (auto &&x : this)
4786
0
    {
4787
4788
0
        if (pfnProgress)
4789
0
        {
4790
0
            double p = progress_counter / progress_max;
4791
0
            if (p > progress_ticker)
4792
0
            {
4793
0
                if (!pfnProgress(p, "", pProgressArg))
4794
0
                {
4795
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4796
0
                    ret = OGRERR_FAILURE;
4797
0
                    goto done;
4798
0
                }
4799
0
            }
4800
0
            progress_counter += 1.0;
4801
0
        }
4802
4803
        // set up the filter on method layer
4804
0
        CPLErrorReset();
4805
0
        OGRGeometry *x_geom =
4806
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4807
0
        if (CPLGetLastErrorType() != CE_None)
4808
0
        {
4809
0
            if (!bSkipFailures)
4810
0
            {
4811
0
                ret = OGRERR_FAILURE;
4812
0
                goto done;
4813
0
            }
4814
0
            else
4815
0
            {
4816
0
                CPLErrorReset();
4817
0
                ret = OGRERR_NONE;
4818
0
            }
4819
0
        }
4820
0
        if (!x_geom)
4821
0
        {
4822
0
            continue;
4823
0
        }
4824
4825
0
        OGRPreparedGeometryUniquePtr x_prepared_geom;
4826
0
        if (bUsePreparedGeometries)
4827
0
        {
4828
0
            x_prepared_geom.reset(
4829
0
                OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
4830
0
            if (!x_prepared_geom)
4831
0
            {
4832
0
                goto done;
4833
0
            }
4834
0
        }
4835
4836
0
        OGRGeometryUniquePtr x_geom_diff(
4837
0
            x_geom
4838
0
                ->clone());  // this will be the geometry of the result feature
4839
0
        for (auto &&y : pLayerMethod)
4840
0
        {
4841
0
            OGRGeometry *y_geom = y->GetGeometryRef();
4842
0
            if (!y_geom)
4843
0
                continue;
4844
4845
0
            CPLErrorReset();
4846
0
            if (x_prepared_geom &&
4847
0
                !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
4848
0
                                                OGRGeometry::ToHandle(y_geom))))
4849
0
            {
4850
0
                if (CPLGetLastErrorType() == CE_None)
4851
0
                {
4852
0
                    continue;
4853
0
                }
4854
0
            }
4855
0
            if (CPLGetLastErrorType() != CE_None)
4856
0
            {
4857
0
                if (!bSkipFailures)
4858
0
                {
4859
0
                    ret = OGRERR_FAILURE;
4860
0
                    goto done;
4861
0
                }
4862
0
                else
4863
0
                {
4864
0
                    CPLErrorReset();
4865
0
                    ret = OGRERR_NONE;
4866
0
                }
4867
0
            }
4868
4869
0
            CPLErrorReset();
4870
0
            OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
4871
0
            if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
4872
0
            {
4873
0
                if (!bSkipFailures)
4874
0
                {
4875
0
                    ret = OGRERR_FAILURE;
4876
0
                    goto done;
4877
0
                }
4878
0
                else
4879
0
                {
4880
0
                    CPLErrorReset();
4881
0
                    ret = OGRERR_NONE;
4882
0
                }
4883
0
            }
4884
0
            else if (poIntersection->IsEmpty() ||
4885
0
                     (!bKeepLowerDimGeom &&
4886
0
                      (x_geom->getDimension() == y_geom->getDimension() &&
4887
0
                       poIntersection->getDimension() <
4888
0
                           x_geom->getDimension())))
4889
0
            {
4890
                /* ok*/
4891
0
            }
4892
0
            else
4893
0
            {
4894
0
                OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4895
0
                z->SetFieldsFrom(x.get(), mapInput);
4896
0
                z->SetFieldsFrom(y.get(), mapMethod);
4897
0
                if (bPromoteToMulti)
4898
0
                    poIntersection.reset(
4899
0
                        promote_to_multi(poIntersection.release()));
4900
0
                z->SetGeometryDirectly(poIntersection.release());
4901
0
                if (x_geom_diff)
4902
0
                {
4903
0
                    CPLErrorReset();
4904
0
                    OGRGeometryUniquePtr x_geom_diff_new(
4905
0
                        x_geom_diff->Difference(y_geom));
4906
0
                    if (CPLGetLastErrorType() != CE_None ||
4907
0
                        x_geom_diff_new == nullptr)
4908
0
                    {
4909
0
                        if (!bSkipFailures)
4910
0
                        {
4911
0
                            ret = OGRERR_FAILURE;
4912
0
                            goto done;
4913
0
                        }
4914
0
                        else
4915
0
                        {
4916
0
                            CPLErrorReset();
4917
0
                        }
4918
0
                    }
4919
0
                    else
4920
0
                    {
4921
0
                        x_geom_diff.swap(x_geom_diff_new);
4922
0
                    }
4923
0
                }
4924
0
                ret = pLayerResult->CreateFeature(z.get());
4925
0
                if (ret != OGRERR_NONE)
4926
0
                {
4927
0
                    if (!bSkipFailures)
4928
0
                    {
4929
0
                        goto done;
4930
0
                    }
4931
0
                    else
4932
0
                    {
4933
0
                        CPLErrorReset();
4934
0
                        ret = OGRERR_NONE;
4935
0
                    }
4936
0
                }
4937
0
            }
4938
0
        }
4939
4940
0
        x_prepared_geom.reset();
4941
4942
0
        if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
4943
0
        {
4944
            /* ok */
4945
0
        }
4946
0
        else
4947
0
        {
4948
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4949
0
            z->SetFieldsFrom(x.get(), mapInput);
4950
0
            if (bPromoteToMulti)
4951
0
                x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
4952
0
            z->SetGeometryDirectly(x_geom_diff.release());
4953
0
            ret = pLayerResult->CreateFeature(z.get());
4954
0
            if (ret != OGRERR_NONE)
4955
0
            {
4956
0
                if (!bSkipFailures)
4957
0
                {
4958
0
                    goto done;
4959
0
                }
4960
0
                else
4961
0
                {
4962
0
                    CPLErrorReset();
4963
0
                    ret = OGRERR_NONE;
4964
0
                }
4965
0
            }
4966
0
        }
4967
0
    }
4968
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4969
0
    {
4970
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4971
0
        ret = OGRERR_FAILURE;
4972
0
        goto done;
4973
0
    }
4974
0
done:
4975
    // release resources
4976
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4977
0
    if (pGeometryMethodFilter)
4978
0
        delete pGeometryMethodFilter;
4979
0
    if (mapInput)
4980
0
        VSIFree(mapInput);
4981
0
    if (mapMethod)
4982
0
        VSIFree(mapMethod);
4983
0
    return ret;
4984
0
}
4985
4986
/************************************************************************/
4987
/*                         OGR_L_Identity()                             */
4988
/************************************************************************/
4989
4990
/**
4991
 * \brief Identify the features of this layer with the ones from the
4992
 * identity layer.
4993
 *
4994
 * The result layer contains features whose geometries represent areas
4995
 * that are in the input layer. The features in the result layer have
4996
 * attributes from both input and method layers. The schema of the
4997
 * result layer can be set by the user or, if it is empty, is
4998
 * initialized to contain all fields in input and method layers.
4999
 *
5000
 * \note If the schema of the result is set by user and contains
5001
 * fields that have the same name as a field in input and in method
5002
 * layer, then the attribute in the result feature will get the value
5003
 * from the feature of the method layer (even if it is undefined).
5004
 *
5005
 * \note For best performance use the minimum amount of features in
5006
 * the method layer and copy it into a memory layer.
5007
 *
5008
 * \note This method relies on GEOS support. Do not use unless the
5009
 * GEOS support is compiled in.
5010
 *
5011
 * The recognized list of options is :
5012
 * <ul>
5013
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5014
 *     feature could not be inserted or a GEOS call failed.
5015
 * </li>
5016
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5017
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5018
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5019
 * </li>
5020
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5021
 *     will be created from the fields of the input layer.
5022
 * </li>
5023
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5024
 *     will be created from the fields of the method layer.
5025
 * </li>
5026
 * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5027
 *     geometries to pretest intersection of features of method layer
5028
 *     with features of this layer.
5029
 * </li>
5030
 * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5031
 *     result features with lower dimension geometry that would
5032
 *     otherwise be added to the result layer. The default is YES, to add
5033
 *     features with lower dimension geometry, but only if the result layer
5034
 *     has an unknown geometry type.
5035
 * </li>
5036
 * </ul>
5037
 *
5038
 * This function is the same as the C++ method OGRLayer::Identity().
5039
 *
5040
 * @param pLayerInput the input layer. Should not be NULL.
5041
 *
5042
 * @param pLayerMethod the method layer. Should not be NULL.
5043
 *
5044
 * @param pLayerResult the layer where the features resulting from the
5045
 * operation are inserted. Should not be NULL. See above the note
5046
 * about the schema.
5047
 *
5048
 * @param papszOptions NULL terminated list of options (may be NULL).
5049
 *
5050
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5051
 * reporting progress or NULL.
5052
 *
5053
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5054
 *
5055
 * @return an error code if there was an error or the execution was
5056
 * interrupted, OGRERR_NONE otherwise.
5057
 *
5058
 * @note The first geometry field is always used.
5059
 *
5060
 * @since OGR 1.10
5061
 */
5062
5063
OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5064
                      OGRLayerH pLayerResult, char **papszOptions,
5065
                      GDALProgressFunc pfnProgress, void *pProgressArg)
5066
5067
0
{
5068
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5069
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5070
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5071
5072
0
    return OGRLayer::FromHandle(pLayerInput)
5073
0
        ->Identity(OGRLayer::FromHandle(pLayerMethod),
5074
0
                   OGRLayer::FromHandle(pLayerResult), papszOptions,
5075
0
                   pfnProgress, pProgressArg);
5076
0
}
5077
5078
/************************************************************************/
5079
/*                             Update()                                 */
5080
/************************************************************************/
5081
5082
/**
5083
 * \brief Update this layer with features from the update layer.
5084
 *
5085
 * The result layer contains features whose geometries represent areas
5086
 * that are either in the input layer or in the method layer. The
5087
 * features in the result layer have areas of the features of the
5088
 * method layer or those ares of the features of the input layer that
5089
 * are not covered by the method layer. The features of the result
5090
 * layer get their attributes from the input layer. The schema of the
5091
 * result layer can be set by the user or, if it is empty, is
5092
 * initialized to contain all fields in the input layer.
5093
 *
5094
 * \note If the schema of the result is set by user and contains
5095
 * fields that have the same name as a field in the method layer, then
5096
 * the attribute in the result feature the originates from the method
5097
 * layer will get the value from the feature of the method layer.
5098
 *
5099
 * \note For best performance use the minimum amount of features in
5100
 * the method layer and copy it into a memory layer.
5101
 *
5102
 * \note This method relies on GEOS support. Do not use unless the
5103
 * GEOS support is compiled in.
5104
 *
5105
 * The recognized list of options is :
5106
 * <ul>
5107
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5108
 *     feature could not be inserted or a GEOS call failed.
5109
 * </li>
5110
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5111
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5112
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5113
 * </li>
5114
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5115
 *     will be created from the fields of the input layer.
5116
 * </li>
5117
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5118
 *     will be created from the fields of the method layer.
5119
 * </li>
5120
 * </ul>
5121
 *
5122
 * This method is the same as the C function OGR_L_Update().
5123
 *
5124
 * @param pLayerMethod the method layer. Should not be NULL.
5125
 *
5126
 * @param pLayerResult the layer where the features resulting from the
5127
 * operation are inserted. Should not be NULL. See above the note
5128
 * about the schema.
5129
 *
5130
 * @param papszOptions NULL terminated list of options (may be NULL).
5131
 *
5132
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5133
 * reporting progress or NULL.
5134
 *
5135
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5136
 *
5137
 * @return an error code if there was an error or the execution was
5138
 * interrupted, OGRERR_NONE otherwise.
5139
 *
5140
 * @note The first geometry field is always used.
5141
 *
5142
 * @since OGR 1.10
5143
 */
5144
5145
OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5146
                        char **papszOptions, GDALProgressFunc pfnProgress,
5147
                        void *pProgressArg)
5148
0
{
5149
0
    OGRErr ret = OGRERR_NONE;
5150
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
5151
0
    OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
5152
0
    OGRFeatureDefn *poDefnResult = nullptr;
5153
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
5154
0
    int *mapInput = nullptr;
5155
0
    int *mapMethod = nullptr;
5156
0
    double progress_max =
5157
0
        static_cast<double>(GetFeatureCount(FALSE)) +
5158
0
        static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
5159
0
    double progress_counter = 0;
5160
0
    double progress_ticker = 0;
5161
0
    const bool bSkipFailures =
5162
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5163
0
    const bool bPromoteToMulti = CPLTestBool(
5164
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5165
5166
    // check for GEOS
5167
0
    if (!OGRGeometryFactory::haveGEOS())
5168
0
    {
5169
0
        CPLError(CE_Failure, CPLE_AppDefined,
5170
0
                 "OGRLayer::Update() requires GEOS support");
5171
0
        return OGRERR_UNSUPPORTED_OPERATION;
5172
0
    }
5173
5174
    // get resources
5175
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5176
0
    if (ret != OGRERR_NONE)
5177
0
        goto done;
5178
0
    ret = create_field_map(poDefnInput, &mapInput);
5179
0
    if (ret != OGRERR_NONE)
5180
0
        goto done;
5181
0
    ret = create_field_map(poDefnMethod, &mapMethod);
5182
0
    if (ret != OGRERR_NONE)
5183
0
        goto done;
5184
0
    ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
5185
0
                            mapMethod, false, papszOptions);
5186
0
    if (ret != OGRERR_NONE)
5187
0
        goto done;
5188
0
    poDefnResult = pLayerResult->GetLayerDefn();
5189
5190
    // add clipped features from the input layer
5191
0
    for (auto &&x : this)
5192
0
    {
5193
5194
0
        if (pfnProgress)
5195
0
        {
5196
0
            double p = progress_counter / progress_max;
5197
0
            if (p > progress_ticker)
5198
0
            {
5199
0
                if (!pfnProgress(p, "", pProgressArg))
5200
0
                {
5201
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5202
0
                    ret = OGRERR_FAILURE;
5203
0
                    goto done;
5204
0
                }
5205
0
            }
5206
0
            progress_counter += 1.0;
5207
0
        }
5208
5209
        // set up the filter on method layer
5210
0
        CPLErrorReset();
5211
0
        OGRGeometry *x_geom =
5212
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5213
0
        if (CPLGetLastErrorType() != CE_None)
5214
0
        {
5215
0
            if (!bSkipFailures)
5216
0
            {
5217
0
                ret = OGRERR_FAILURE;
5218
0
                goto done;
5219
0
            }
5220
0
            else
5221
0
            {
5222
0
                CPLErrorReset();
5223
0
                ret = OGRERR_NONE;
5224
0
            }
5225
0
        }
5226
0
        if (!x_geom)
5227
0
        {
5228
0
            continue;
5229
0
        }
5230
5231
0
        OGRGeometryUniquePtr x_geom_diff(
5232
0
            x_geom->clone());  // this will be the geometry of a result feature
5233
0
        for (auto &&y : pLayerMethod)
5234
0
        {
5235
0
            OGRGeometry *y_geom = y->GetGeometryRef();
5236
0
            if (!y_geom)
5237
0
                continue;
5238
0
            if (x_geom_diff)
5239
0
            {
5240
0
                CPLErrorReset();
5241
0
                OGRGeometryUniquePtr x_geom_diff_new(
5242
0
                    x_geom_diff->Difference(y_geom));
5243
0
                if (CPLGetLastErrorType() != CE_None ||
5244
0
                    x_geom_diff_new == nullptr)
5245
0
                {
5246
0
                    if (!bSkipFailures)
5247
0
                    {
5248
0
                        ret = OGRERR_FAILURE;
5249
0
                        goto done;
5250
0
                    }
5251
0
                    else
5252
0
                    {
5253
0
                        CPLErrorReset();
5254
0
                        ret = OGRERR_NONE;
5255
0
                    }
5256
0
                }
5257
0
                else
5258
0
                {
5259
0
                    x_geom_diff.swap(x_geom_diff_new);
5260
0
                }
5261
0
            }
5262
0
        }
5263
5264
0
        if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
5265
0
        {
5266
            /* ok */
5267
0
        }
5268
0
        else
5269
0
        {
5270
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5271
0
            z->SetFieldsFrom(x.get(), mapInput);
5272
0
            if (bPromoteToMulti)
5273
0
                x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
5274
0
            z->SetGeometryDirectly(x_geom_diff.release());
5275
0
            ret = pLayerResult->CreateFeature(z.get());
5276
0
            if (ret != OGRERR_NONE)
5277
0
            {
5278
0
                if (!bSkipFailures)
5279
0
                {
5280
0
                    goto done;
5281
0
                }
5282
0
                else
5283
0
                {
5284
0
                    CPLErrorReset();
5285
0
                    ret = OGRERR_NONE;
5286
0
                }
5287
0
            }
5288
0
        }
5289
0
    }
5290
5291
    // restore the original filter and add features from the update layer
5292
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5293
0
    for (auto &&y : pLayerMethod)
5294
0
    {
5295
5296
0
        if (pfnProgress)
5297
0
        {
5298
0
            double p = progress_counter / progress_max;
5299
0
            if (p > progress_ticker)
5300
0
            {
5301
0
                if (!pfnProgress(p, "", pProgressArg))
5302
0
                {
5303
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5304
0
                    ret = OGRERR_FAILURE;
5305
0
                    goto done;
5306
0
                }
5307
0
            }
5308
0
            progress_counter += 1.0;
5309
0
        }
5310
5311
0
        OGRGeometry *y_geom = y->StealGeometry();
5312
0
        if (!y_geom)
5313
0
            continue;
5314
0
        OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5315
0
        if (mapMethod)
5316
0
            z->SetFieldsFrom(y.get(), mapMethod);
5317
0
        z->SetGeometryDirectly(y_geom);
5318
0
        ret = pLayerResult->CreateFeature(z.get());
5319
0
        if (ret != OGRERR_NONE)
5320
0
        {
5321
0
            if (!bSkipFailures)
5322
0
            {
5323
0
                goto done;
5324
0
            }
5325
0
            else
5326
0
            {
5327
0
                CPLErrorReset();
5328
0
                ret = OGRERR_NONE;
5329
0
            }
5330
0
        }
5331
0
    }
5332
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5333
0
    {
5334
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5335
0
        ret = OGRERR_FAILURE;
5336
0
        goto done;
5337
0
    }
5338
0
done:
5339
    // release resources
5340
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5341
0
    if (pGeometryMethodFilter)
5342
0
        delete pGeometryMethodFilter;
5343
0
    if (mapInput)
5344
0
        VSIFree(mapInput);
5345
0
    if (mapMethod)
5346
0
        VSIFree(mapMethod);
5347
0
    return ret;
5348
0
}
5349
5350
/************************************************************************/
5351
/*                          OGR_L_Update()                              */
5352
/************************************************************************/
5353
5354
/**
5355
 * \brief Update this layer with features from the update layer.
5356
 *
5357
 * The result layer contains features whose geometries represent areas
5358
 * that are either in the input layer or in the method layer. The
5359
 * features in the result layer have areas of the features of the
5360
 * method layer or those ares of the features of the input layer that
5361
 * are not covered by the method layer. The features of the result
5362
 * layer get their attributes from the input layer. The schema of the
5363
 * result layer can be set by the user or, if it is empty, is
5364
 * initialized to contain all fields in the input layer.
5365
 *
5366
 * \note If the schema of the result is set by user and contains
5367
 * fields that have the same name as a field in the method layer, then
5368
 * the attribute in the result feature the originates from the method
5369
 * layer will get the value from the feature of the method layer.
5370
 *
5371
 * \note For best performance use the minimum amount of features in
5372
 * the method layer and copy it into a memory layer.
5373
 *
5374
 * \note This method relies on GEOS support. Do not use unless the
5375
 * GEOS support is compiled in.
5376
 *
5377
 * The recognized list of options is :
5378
 * <ul>
5379
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5380
 *     feature could not be inserted or a GEOS call failed.
5381
 * </li>
5382
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5383
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5384
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5385
 * </li>
5386
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5387
 *     will be created from the fields of the input layer.
5388
 * </li>
5389
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5390
 *     will be created from the fields of the method layer.
5391
 * </li>
5392
 * </ul>
5393
 *
5394
 * This function is the same as the C++ method OGRLayer::Update().
5395
 *
5396
 * @param pLayerInput the input layer. Should not be NULL.
5397
 *
5398
 * @param pLayerMethod the method layer. Should not be NULL.
5399
 *
5400
 * @param pLayerResult the layer where the features resulting from the
5401
 * operation are inserted. Should not be NULL. See above the note
5402
 * about the schema.
5403
 *
5404
 * @param papszOptions NULL terminated list of options (may be NULL).
5405
 *
5406
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5407
 * reporting progress or NULL.
5408
 *
5409
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5410
 *
5411
 * @return an error code if there was an error or the execution was
5412
 * interrupted, OGRERR_NONE otherwise.
5413
 *
5414
 * @note The first geometry field is always used.
5415
 *
5416
 * @since OGR 1.10
5417
 */
5418
5419
OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5420
                    OGRLayerH pLayerResult, char **papszOptions,
5421
                    GDALProgressFunc pfnProgress, void *pProgressArg)
5422
5423
0
{
5424
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5425
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5426
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5427
5428
0
    return OGRLayer::FromHandle(pLayerInput)
5429
0
        ->Update(OGRLayer::FromHandle(pLayerMethod),
5430
0
                 OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
5431
0
                 pProgressArg);
5432
0
}
5433
5434
/************************************************************************/
5435
/*                              Clip()                                  */
5436
/************************************************************************/
5437
5438
/**
5439
 * \brief Clip off areas that are not covered by the method layer.
5440
 *
5441
 * The result layer contains features whose geometries represent areas
5442
 * that are in the input layer and in the method layer. The features
5443
 * in the result layer have the (possibly clipped) areas of features
5444
 * in the input layer and the attributes from the same features. The
5445
 * schema of the result layer can be set by the user or, if it is
5446
 * empty, is initialized to contain all fields in the input layer.
5447
 *
5448
 * \note For best performance use the minimum amount of features in
5449
 * the method layer and copy it into a memory layer.
5450
 *
5451
 * \note This method relies on GEOS support. Do not use unless the
5452
 * GEOS support is compiled in.
5453
 *
5454
 * The recognized list of options is :
5455
 * <ul>
5456
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5457
 *     feature could not be inserted or a GEOS call failed.
5458
 * </li>
5459
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5460
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5461
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5462
 * </li>
5463
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5464
 *     will be created from the fields of the input layer.
5465
 * </li>
5466
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5467
 *     will be created from the fields of the method layer.
5468
 * </li>
5469
 * </ul>
5470
 *
5471
 * This method is the same as the C function OGR_L_Clip().
5472
 *
5473
 * @param pLayerMethod the method layer. Should not be NULL.
5474
 *
5475
 * @param pLayerResult the layer where the features resulting from the
5476
 * operation are inserted. Should not be NULL. See above the note
5477
 * about the schema.
5478
 *
5479
 * @param papszOptions NULL terminated list of options (may be NULL).
5480
 *
5481
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5482
 * reporting progress or NULL.
5483
 *
5484
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5485
 *
5486
 * @return an error code if there was an error or the execution was
5487
 * interrupted, OGRERR_NONE otherwise.
5488
 *
5489
 * @note The first geometry field is always used.
5490
 *
5491
 * @since OGR 1.10
5492
 */
5493
5494
OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5495
                      char **papszOptions, GDALProgressFunc pfnProgress,
5496
                      void *pProgressArg)
5497
0
{
5498
0
    OGRErr ret = OGRERR_NONE;
5499
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
5500
0
    OGRFeatureDefn *poDefnResult = nullptr;
5501
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
5502
0
    int *mapInput = nullptr;
5503
0
    double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5504
0
    double progress_counter = 0;
5505
0
    double progress_ticker = 0;
5506
0
    const bool bSkipFailures =
5507
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5508
0
    const bool bPromoteToMulti = CPLTestBool(
5509
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5510
5511
    // check for GEOS
5512
0
    if (!OGRGeometryFactory::haveGEOS())
5513
0
    {
5514
0
        CPLError(CE_Failure, CPLE_AppDefined,
5515
0
                 "OGRLayer::Clip() requires GEOS support");
5516
0
        return OGRERR_UNSUPPORTED_OPERATION;
5517
0
    }
5518
5519
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5520
0
    if (ret != OGRERR_NONE)
5521
0
        goto done;
5522
0
    ret = create_field_map(poDefnInput, &mapInput);
5523
0
    if (ret != OGRERR_NONE)
5524
0
        goto done;
5525
0
    ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
5526
0
                            nullptr, false, papszOptions);
5527
0
    if (ret != OGRERR_NONE)
5528
0
        goto done;
5529
5530
0
    poDefnResult = pLayerResult->GetLayerDefn();
5531
0
    for (auto &&x : this)
5532
0
    {
5533
5534
0
        if (pfnProgress)
5535
0
        {
5536
0
            double p = progress_counter / progress_max;
5537
0
            if (p > progress_ticker)
5538
0
            {
5539
0
                if (!pfnProgress(p, "", pProgressArg))
5540
0
                {
5541
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5542
0
                    ret = OGRERR_FAILURE;
5543
0
                    goto done;
5544
0
                }
5545
0
            }
5546
0
            progress_counter += 1.0;
5547
0
        }
5548
5549
        // set up the filter on method layer
5550
0
        CPLErrorReset();
5551
0
        OGRGeometry *x_geom =
5552
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5553
0
        if (CPLGetLastErrorType() != CE_None)
5554
0
        {
5555
0
            if (!bSkipFailures)
5556
0
            {
5557
0
                ret = OGRERR_FAILURE;
5558
0
                goto done;
5559
0
            }
5560
0
            else
5561
0
            {
5562
0
                CPLErrorReset();
5563
0
                ret = OGRERR_NONE;
5564
0
            }
5565
0
        }
5566
0
        if (!x_geom)
5567
0
        {
5568
0
            continue;
5569
0
        }
5570
5571
0
        OGRGeometryUniquePtr
5572
0
            geom;  // this will be the geometry of the result feature
5573
        // incrementally add area from y to geom
5574
0
        for (auto &&y : pLayerMethod)
5575
0
        {
5576
0
            OGRGeometry *y_geom = y->GetGeometryRef();
5577
0
            if (!y_geom)
5578
0
                continue;
5579
0
            if (!geom)
5580
0
            {
5581
0
                geom.reset(y_geom->clone());
5582
0
            }
5583
0
            else
5584
0
            {
5585
0
                CPLErrorReset();
5586
0
                OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
5587
0
                if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
5588
0
                {
5589
0
                    if (!bSkipFailures)
5590
0
                    {
5591
0
                        ret = OGRERR_FAILURE;
5592
0
                        goto done;
5593
0
                    }
5594
0
                    else
5595
0
                    {
5596
0
                        CPLErrorReset();
5597
0
                        ret = OGRERR_NONE;
5598
0
                    }
5599
0
                }
5600
0
                else
5601
0
                {
5602
0
                    geom.swap(geom_new);
5603
0
                }
5604
0
            }
5605
0
        }
5606
5607
        // possibly add a new feature with area x intersection sum of y
5608
0
        if (geom)
5609
0
        {
5610
0
            CPLErrorReset();
5611
0
            OGRGeometryUniquePtr poIntersection(
5612
0
                x_geom->Intersection(geom.get()));
5613
0
            if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
5614
0
            {
5615
0
                if (!bSkipFailures)
5616
0
                {
5617
0
                    ret = OGRERR_FAILURE;
5618
0
                    goto done;
5619
0
                }
5620
0
                else
5621
0
                {
5622
0
                    CPLErrorReset();
5623
0
                    ret = OGRERR_NONE;
5624
0
                }
5625
0
            }
5626
0
            else if (!poIntersection->IsEmpty())
5627
0
            {
5628
0
                OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5629
0
                z->SetFieldsFrom(x.get(), mapInput);
5630
0
                if (bPromoteToMulti)
5631
0
                    poIntersection.reset(
5632
0
                        promote_to_multi(poIntersection.release()));
5633
0
                z->SetGeometryDirectly(poIntersection.release());
5634
0
                ret = pLayerResult->CreateFeature(z.get());
5635
0
                if (ret != OGRERR_NONE)
5636
0
                {
5637
0
                    if (!bSkipFailures)
5638
0
                    {
5639
0
                        goto done;
5640
0
                    }
5641
0
                    else
5642
0
                    {
5643
0
                        CPLErrorReset();
5644
0
                        ret = OGRERR_NONE;
5645
0
                    }
5646
0
                }
5647
0
            }
5648
0
        }
5649
0
    }
5650
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5651
0
    {
5652
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5653
0
        ret = OGRERR_FAILURE;
5654
0
        goto done;
5655
0
    }
5656
0
done:
5657
    // release resources
5658
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5659
0
    if (pGeometryMethodFilter)
5660
0
        delete pGeometryMethodFilter;
5661
0
    if (mapInput)
5662
0
        VSIFree(mapInput);
5663
0
    return ret;
5664
0
}
5665
5666
/************************************************************************/
5667
/*                           OGR_L_Clip()                               */
5668
/************************************************************************/
5669
5670
/**
5671
 * \brief Clip off areas that are not covered by the method layer.
5672
 *
5673
 * The result layer contains features whose geometries represent areas
5674
 * that are in the input layer and in the method layer. The features
5675
 * in the result layer have the (possibly clipped) areas of features
5676
 * in the input layer and the attributes from the same features. The
5677
 * schema of the result layer can be set by the user or, if it is
5678
 * empty, is initialized to contain all fields in the input layer.
5679
 *
5680
 * \note For best performance use the minimum amount of features in
5681
 * the method layer and copy it into a memory layer.
5682
 *
5683
 * \note This method relies on GEOS support. Do not use unless the
5684
 * GEOS support is compiled in.
5685
 *
5686
 * The recognized list of options is :
5687
 * <ul>
5688
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5689
 *     feature could not be inserted or a GEOS call failed.
5690
 * </li>
5691
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5692
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5693
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5694
 * </li>
5695
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5696
 *     will be created from the fields of the input layer.
5697
 * </li>
5698
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5699
 *     will be created from the fields of the method layer.
5700
 * </li>
5701
 * </ul>
5702
 *
5703
 * This function is the same as the C++ method OGRLayer::Clip().
5704
 *
5705
 * @param pLayerInput the input layer. Should not be NULL.
5706
 *
5707
 * @param pLayerMethod the method layer. Should not be NULL.
5708
 *
5709
 * @param pLayerResult the layer where the features resulting from the
5710
 * operation are inserted. Should not be NULL. See above the note
5711
 * about the schema.
5712
 *
5713
 * @param papszOptions NULL terminated list of options (may be NULL).
5714
 *
5715
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5716
 * reporting progress or NULL.
5717
 *
5718
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5719
 *
5720
 * @return an error code if there was an error or the execution was
5721
 * interrupted, OGRERR_NONE otherwise.
5722
 *
5723
 * @note The first geometry field is always used.
5724
 *
5725
 * @since OGR 1.10
5726
 */
5727
5728
OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5729
                  OGRLayerH pLayerResult, char **papszOptions,
5730
                  GDALProgressFunc pfnProgress, void *pProgressArg)
5731
5732
0
{
5733
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5734
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5735
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5736
5737
0
    return OGRLayer::FromHandle(pLayerInput)
5738
0
        ->Clip(OGRLayer::FromHandle(pLayerMethod),
5739
0
               OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
5740
0
               pProgressArg);
5741
0
}
5742
5743
/************************************************************************/
5744
/*                              Erase()                                 */
5745
/************************************************************************/
5746
5747
/**
5748
 * \brief Remove areas that are covered by the method layer.
5749
 *
5750
 * The result layer contains features whose geometries represent areas
5751
 * that are in the input layer but not in the method layer. The
5752
 * features in the result layer have attributes from the input
5753
 * layer. The schema of the result layer can be set by the user or, if
5754
 * it is empty, is initialized to contain all fields in the input
5755
 * layer.
5756
 *
5757
 * \note For best performance use the minimum amount of features in
5758
 * the method layer and copy it into a memory layer.
5759
 *
5760
 * \note This method relies on GEOS support. Do not use unless the
5761
 * GEOS support is compiled in.
5762
 *
5763
 * The recognized list of options is :
5764
 * <ul>
5765
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5766
 *     feature could not be inserted or a GEOS call failed.
5767
 * </li>
5768
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5769
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5770
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5771
 * </li>
5772
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5773
 *     will be created from the fields of the input layer.
5774
 * </li>
5775
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5776
 *     will be created from the fields of the method layer.
5777
 * </li>
5778
 * </ul>
5779
 *
5780
 * This method is the same as the C function OGR_L_Erase().
5781
 *
5782
 * @param pLayerMethod the method layer. Should not be NULL.
5783
 *
5784
 * @param pLayerResult the layer where the features resulting from the
5785
 * operation are inserted. Should not be NULL. See above the note
5786
 * about the schema.
5787
 *
5788
 * @param papszOptions NULL terminated list of options (may be NULL).
5789
 *
5790
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
5791
 * reporting progress or NULL.
5792
 *
5793
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5794
 *
5795
 * @return an error code if there was an error or the execution was
5796
 * interrupted, OGRERR_NONE otherwise.
5797
 *
5798
 * @note The first geometry field is always used.
5799
 *
5800
 * @since OGR 1.10
5801
 */
5802
5803
OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5804
                       char **papszOptions, GDALProgressFunc pfnProgress,
5805
                       void *pProgressArg)
5806
0
{
5807
0
    OGRErr ret = OGRERR_NONE;
5808
0
    OGRFeatureDefn *poDefnInput = GetLayerDefn();
5809
0
    OGRFeatureDefn *poDefnResult = nullptr;
5810
0
    OGRGeometry *pGeometryMethodFilter = nullptr;
5811
0
    int *mapInput = nullptr;
5812
0
    double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5813
0
    double progress_counter = 0;
5814
0
    double progress_ticker = 0;
5815
0
    const bool bSkipFailures =
5816
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5817
0
    const bool bPromoteToMulti = CPLTestBool(
5818
0
        CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5819
5820
    // check for GEOS
5821
0
    if (!OGRGeometryFactory::haveGEOS())
5822
0
    {
5823
0
        CPLError(CE_Failure, CPLE_AppDefined,
5824
0
                 "OGRLayer::Erase() requires GEOS support");
5825
0
        return OGRERR_UNSUPPORTED_OPERATION;
5826
0
    }
5827
5828
    // get resources
5829
0
    ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5830
0
    if (ret != OGRERR_NONE)
5831
0
        goto done;
5832
0
    ret = create_field_map(poDefnInput, &mapInput);
5833
0
    if (ret != OGRERR_NONE)
5834
0
        goto done;
5835
0
    ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
5836
0
                            nullptr, false, papszOptions);
5837
0
    if (ret != OGRERR_NONE)
5838
0
        goto done;
5839
0
    poDefnResult = pLayerResult->GetLayerDefn();
5840
5841
0
    for (auto &&x : this)
5842
0
    {
5843
5844
0
        if (pfnProgress)
5845
0
        {
5846
0
            double p = progress_counter / progress_max;
5847
0
            if (p > progress_ticker)
5848
0
            {
5849
0
                if (!pfnProgress(p, "", pProgressArg))
5850
0
                {
5851
0
                    CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5852
0
                    ret = OGRERR_FAILURE;
5853
0
                    goto done;
5854
0
                }
5855
0
            }
5856
0
            progress_counter += 1.0;
5857
0
        }
5858
5859
        // set up the filter on the method layer
5860
0
        CPLErrorReset();
5861
0
        OGRGeometry *x_geom =
5862
0
            set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5863
0
        if (CPLGetLastErrorType() != CE_None)
5864
0
        {
5865
0
            if (!bSkipFailures)
5866
0
            {
5867
0
                ret = OGRERR_FAILURE;
5868
0
                goto done;
5869
0
            }
5870
0
            else
5871
0
            {
5872
0
                CPLErrorReset();
5873
0
                ret = OGRERR_NONE;
5874
0
            }
5875
0
        }
5876
0
        if (!x_geom)
5877
0
        {
5878
0
            continue;
5879
0
        }
5880
5881
0
        OGRGeometryUniquePtr geom(
5882
0
            x_geom
5883
0
                ->clone());  // this will be the geometry of the result feature
5884
        // incrementally erase y from geom
5885
0
        for (auto &&y : pLayerMethod)
5886
0
        {
5887
0
            OGRGeometry *y_geom = y->GetGeometryRef();
5888
0
            if (!y_geom)
5889
0
                continue;
5890
0
            CPLErrorReset();
5891
0
            OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
5892
0
            if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
5893
0
            {
5894
0
                if (!bSkipFailures)
5895
0
                {
5896
0
                    ret = OGRERR_FAILURE;
5897
0
                    goto done;
5898
0
                }
5899
0
                else
5900
0
                {
5901
0
                    CPLErrorReset();
5902
0
                    ret = OGRERR_NONE;
5903
0
                }
5904
0
            }
5905
0
            else
5906
0
            {
5907
0
                geom.swap(geom_new);
5908
0
                if (geom->IsEmpty())
5909
0
                {
5910
0
                    break;
5911
0
                }
5912
0
            }
5913
0
        }
5914
5915
        // add a new feature if there is remaining area
5916
0
        if (!geom->IsEmpty())
5917
0
        {
5918
0
            OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5919
0
            z->SetFieldsFrom(x.get(), mapInput);
5920
0
            if (bPromoteToMulti)
5921
0
                geom.reset(promote_to_multi(geom.release()));
5922
0
            z->SetGeometryDirectly(geom.release());
5923
0
            ret = pLayerResult->CreateFeature(z.get());
5924
0
            if (ret != OGRERR_NONE)
5925
0
            {
5926
0
                if (!bSkipFailures)
5927
0
                {
5928
0
                    goto done;
5929
0
                }
5930
0
                else
5931
0
                {
5932
0
                    CPLErrorReset();
5933
0
                    ret = OGRERR_NONE;
5934
0
                }
5935
0
            }
5936
0
        }
5937
0
    }
5938
0
    if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5939
0
    {
5940
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5941
0
        ret = OGRERR_FAILURE;
5942
0
        goto done;
5943
0
    }
5944
0
done:
5945
    // release resources
5946
0
    pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5947
0
    if (pGeometryMethodFilter)
5948
0
        delete pGeometryMethodFilter;
5949
0
    if (mapInput)
5950
0
        VSIFree(mapInput);
5951
0
    return ret;
5952
0
}
5953
5954
/************************************************************************/
5955
/*                           OGR_L_Erase()                              */
5956
/************************************************************************/
5957
5958
/**
5959
 * \brief Remove areas that are covered by the method layer.
5960
 *
5961
 * The result layer contains features whose geometries represent areas
5962
 * that are in the input layer but not in the method layer. The
5963
 * features in the result layer have attributes from the input
5964
 * layer. The schema of the result layer can be set by the user or, if
5965
 * it is empty, is initialized to contain all fields in the input
5966
 * layer.
5967
 *
5968
 * \note For best performance use the minimum amount of features in
5969
 * the method layer and copy it into a memory layer.
5970
 *
5971
 * \note This method relies on GEOS support. Do not use unless the
5972
 * GEOS support is compiled in.
5973
 *
5974
 * The recognized list of options is :
5975
 * <ul>
5976
 * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5977
 *     feature could not be inserted or a GEOS call failed.
5978
 * </li>
5979
 * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5980
 *     into MultiPolygons, LineStrings to MultiLineStrings or
5981
 *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
5982
 * </li>
5983
 * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5984
 *     will be created from the fields of the input layer.
5985
 * </li>
5986
 * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5987
 *     will be created from the fields of the method layer.
5988
 * </li>
5989
 * </ul>
5990
 *
5991
 * This function is the same as the C++ method OGRLayer::Erase().
5992
 *
5993
 * @param pLayerInput the input layer. Should not be NULL.
5994
 *
5995
 * @param pLayerMethod the method layer. Should not be NULL.
5996
 *
5997
 * @param pLayerResult the layer where the features resulting from the
5998
 * operation are inserted. Should not be NULL. See above the note
5999
 * about the schema.
6000
 *
6001
 * @param papszOptions NULL terminated list of options (may be NULL).
6002
 *
6003
 * @param pfnProgress a GDALProgressFunc() compatible callback function for
6004
 * reporting progress or NULL.
6005
 *
6006
 * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6007
 *
6008
 * @return an error code if there was an error or the execution was
6009
 * interrupted, OGRERR_NONE otherwise.
6010
 *
6011
 * @note The first geometry field is always used.
6012
 *
6013
 * @since OGR 1.10
6014
 */
6015
6016
OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
6017
                   OGRLayerH pLayerResult, char **papszOptions,
6018
                   GDALProgressFunc pfnProgress, void *pProgressArg)
6019
6020
0
{
6021
0
    VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6022
0
    VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6023
0
    VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6024
6025
0
    return OGRLayer::FromHandle(pLayerInput)
6026
0
        ->Erase(OGRLayer::FromHandle(pLayerMethod),
6027
0
                OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
6028
0
                pProgressArg);
6029
0
}
6030
6031
/************************************************************************/
6032
/*                  OGRLayer::FeatureIterator::Private                  */
6033
/************************************************************************/
6034
6035
struct OGRLayer::FeatureIterator::Private
6036
{
6037
    CPL_DISALLOW_COPY_ASSIGN(Private)
6038
0
    Private() = default;
6039
6040
    OGRFeatureUniquePtr m_poFeature{};
6041
    OGRLayer *m_poLayer = nullptr;
6042
    bool m_bError = false;
6043
    bool m_bEOF = true;
6044
};
6045
6046
/************************************************************************/
6047
/*                OGRLayer::FeatureIterator::FeatureIterator()          */
6048
/************************************************************************/
6049
6050
OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
6051
0
    : m_poPrivate(new OGRLayer::FeatureIterator::Private())
6052
0
{
6053
0
    m_poPrivate->m_poLayer = poLayer;
6054
0
    if (bStart)
6055
0
    {
6056
0
        if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
6057
0
        {
6058
0
            CPLError(CE_Failure, CPLE_NotSupported,
6059
0
                     "Only one feature iterator can be "
6060
0
                     "active at a time");
6061
0
            m_poPrivate->m_bError = true;
6062
0
        }
6063
0
        else
6064
0
        {
6065
0
            m_poPrivate->m_poLayer->ResetReading();
6066
0
            m_poPrivate->m_poFeature.reset(
6067
0
                m_poPrivate->m_poLayer->GetNextFeature());
6068
0
            m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
6069
0
            m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
6070
0
        }
6071
0
    }
6072
0
}
6073
6074
/************************************************************************/
6075
/*               ~OGRLayer::FeatureIterator::FeatureIterator()          */
6076
/************************************************************************/
6077
6078
OGRLayer::FeatureIterator::~FeatureIterator()
6079
0
{
6080
0
    if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
6081
0
        m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
6082
0
}
6083
6084
/************************************************************************/
6085
/*                              operator*()                             */
6086
/************************************************************************/
6087
6088
OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
6089
0
{
6090
0
    return m_poPrivate->m_poFeature;
6091
0
}
6092
6093
/************************************************************************/
6094
/*                              operator++()                            */
6095
/************************************************************************/
6096
6097
OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
6098
0
{
6099
0
    m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
6100
0
    m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
6101
0
    return *this;
6102
0
}
6103
6104
/************************************************************************/
6105
/*                             operator!=()                             */
6106
/************************************************************************/
6107
6108
bool OGRLayer::FeatureIterator::operator!=(
6109
    const OGRLayer::FeatureIterator &it) const
6110
0
{
6111
0
    return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
6112
0
}
6113
6114
/************************************************************************/
6115
/*                                 begin()                              */
6116
/************************************************************************/
6117
6118
OGRLayer::FeatureIterator OGRLayer::begin()
6119
0
{
6120
0
    return {this, true};
6121
0
}
6122
6123
/************************************************************************/
6124
/*                                  end()                               */
6125
/************************************************************************/
6126
6127
OGRLayer::FeatureIterator OGRLayer::end()
6128
0
{
6129
0
    return {this, false};
6130
0
}
6131
6132
/************************************************************************/
6133
/*                     OGRLayer::GetGeometryTypes()                     */
6134
/************************************************************************/
6135
6136
/** \brief Get actual geometry types found in features.
6137
 *
6138
 * This method iterates over features to retrieve their geometry types. This
6139
 * is mostly useful for layers that report a wkbUnknown geometry type with
6140
 * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
6141
 *
6142
 * By default this method returns an array of nEntryCount entries with each
6143
 * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
6144
 * number of features (in OGRGeometryTypeCounter::nCount).
6145
 * Features without geometries are reported as eGeomType == wkbNone.
6146
 *
6147
 * The nFlagsGGT parameter can be a combination (with binary or operator) of the
6148
 * following hints:
6149
 * <ul>
6150
 * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
6151
 * matter, not the number of features per geometry type. Consequently the value
6152
 * of OGRGeometryTypeCounter::nCount should be ignored.</li>
6153
 * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
6154
 * iterating over features as soon as 2 different geometry types (not counting
6155
 * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
6156
 * should be ignored (zero might be systematically reported by some
6157
 * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
6158
 * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
6159
 * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
6160
 * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
6161
 * geometries.</li>
6162
 * </ul>
6163
 *
6164
 * If the layer has no features, a non-NULL returned array with nEntryCount == 0
6165
 * will be returned.
6166
 *
6167
 * Spatial and/or attribute filters will be taken into account.
6168
 *
6169
 * This method will error out on a layer without geometry fields
6170
 * (GetGeomType() == wkbNone).
6171
 *
6172
 * A cancellation callback may be provided. The progress percentage it is called
6173
 * with is not relevant. The callback should return TRUE if processing should go
6174
 * on, or FALSE if it should be interrupted.
6175
 *
6176
 * @param iGeomField Geometry field index.
6177
 * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
6178
 *                  OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
6179
 * @param[out] nEntryCountOut Number of entries in the returned array.
6180
 * @param pfnProgress Cancellation callback. May be NULL.
6181
 * @param pProgressData User data for the cancellation callback. May be NULL.
6182
 * @return an array of nEntryCount that must be freed with CPLFree(),
6183
 *         or NULL in case of error
6184
 * @since GDAL 3.6
6185
 */
6186
OGRGeometryTypeCounter *
6187
OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
6188
                           GDALProgressFunc pfnProgress, void *pProgressData)
6189
0
{
6190
0
    OGRFeatureDefn *poDefn = GetLayerDefn();
6191
0
    const int nGeomFieldCount = poDefn->GetGeomFieldCount();
6192
0
    if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
6193
0
    {
6194
0
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
6195
0
        nEntryCountOut = 0;
6196
0
        return nullptr;
6197
0
    }
6198
6199
    // Ignore all fields but the geometry one of interest
6200
0
    CPLStringList aosIgnoredFieldsRestore;
6201
0
    CPLStringList aosIgnoredFields;
6202
0
    const int nFieldCount = poDefn->GetFieldCount();
6203
0
    for (int iField = 0; iField < nFieldCount; iField++)
6204
0
    {
6205
0
        const auto poFieldDefn = poDefn->GetFieldDefn(iField);
6206
0
        const char *pszName = poFieldDefn->GetNameRef();
6207
0
        if (poFieldDefn->IsIgnored())
6208
0
            aosIgnoredFieldsRestore.AddString(pszName);
6209
0
        if (iField != iGeomField)
6210
0
            aosIgnoredFields.AddString(pszName);
6211
0
    }
6212
0
    for (int iField = 0; iField < nGeomFieldCount; iField++)
6213
0
    {
6214
0
        const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
6215
0
        const char *pszName = poFieldDefn->GetNameRef();
6216
0
        if (poFieldDefn->IsIgnored())
6217
0
            aosIgnoredFieldsRestore.AddString(pszName);
6218
0
        if (iField != iGeomField)
6219
0
            aosIgnoredFields.AddString(pszName);
6220
0
    }
6221
0
    if (poDefn->IsStyleIgnored())
6222
0
        aosIgnoredFieldsRestore.AddString("OGR_STYLE");
6223
0
    aosIgnoredFields.AddString("OGR_STYLE");
6224
0
    SetIgnoredFields(aosIgnoredFields.List());
6225
6226
    // Iterate over features
6227
0
    std::map<OGRwkbGeometryType, int64_t> oMapCount;
6228
0
    std::set<OGRwkbGeometryType> oSetNotNull;
6229
0
    const bool bGeomCollectionZTInZ =
6230
0
        (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
6231
0
    const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
6232
0
    if (pfnProgress == GDALDummyProgress)
6233
0
        pfnProgress = nullptr;
6234
0
    bool bInterrupted = false;
6235
0
    for (auto &&poFeature : *this)
6236
0
    {
6237
0
        const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
6238
0
        if (poGeom == nullptr)
6239
0
        {
6240
0
            ++oMapCount[wkbNone];
6241
0
        }
6242
0
        else
6243
0
        {
6244
0
            auto eGeomType = poGeom->getGeometryType();
6245
0
            if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
6246
0
            {
6247
0
                const auto poGC = poGeom->toGeometryCollection();
6248
0
                if (poGC->getNumGeometries() > 0)
6249
0
                {
6250
0
                    auto eSubGeomType =
6251
0
                        poGC->getGeometryRef(0)->getGeometryType();
6252
0
                    if (eSubGeomType == wkbTINZ)
6253
0
                        eGeomType = wkbTINZ;
6254
0
                }
6255
0
            }
6256
0
            ++oMapCount[eGeomType];
6257
0
            if (bStopIfMixed)
6258
0
            {
6259
0
                oSetNotNull.insert(eGeomType);
6260
0
                if (oSetNotNull.size() == 2)
6261
0
                    break;
6262
0
            }
6263
0
        }
6264
0
        if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
6265
0
        {
6266
0
            bInterrupted = true;
6267
0
            break;
6268
0
        }
6269
0
    }
6270
6271
    // Restore ignore fields state
6272
0
    SetIgnoredFields(aosIgnoredFieldsRestore.List());
6273
6274
0
    if (bInterrupted)
6275
0
    {
6276
0
        nEntryCountOut = 0;
6277
0
        return nullptr;
6278
0
    }
6279
6280
    // Format result
6281
0
    nEntryCountOut = static_cast<int>(oMapCount.size());
6282
0
    OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
6283
0
        CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
6284
0
    int i = 0;
6285
0
    for (const auto &oIter : oMapCount)
6286
0
    {
6287
0
        pasRet[i].eGeomType = oIter.first;
6288
0
        pasRet[i].nCount = oIter.second;
6289
0
        ++i;
6290
0
    }
6291
0
    return pasRet;
6292
0
}
6293
6294
/************************************************************************/
6295
/*                      OGR_L_GetGeometryTypes()                        */
6296
/************************************************************************/
6297
6298
/** \brief Get actual geometry types found in features.
6299
 *
6300
 * See OGRLayer::GetGeometryTypes() for details.
6301
 *
6302
 * @param hLayer Layer.
6303
 * @param iGeomField Geometry field index.
6304
 * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
6305
 *               OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
6306
 * @param[out] pnEntryCount Pointer to the number of entries in the returned
6307
 *                          array. Must not be NULL.
6308
 * @param pfnProgress Cancellation callback. May be NULL.
6309
 * @param pProgressData User data for the cancellation callback. May be NULL.
6310
 * @return an array of *pnEntryCount that must be freed with CPLFree(),
6311
 *         or NULL in case of error
6312
 * @since GDAL 3.6
6313
 */
6314
OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
6315
                                               int nFlags, int *pnEntryCount,
6316
                                               GDALProgressFunc pfnProgress,
6317
                                               void *pProgressData)
6318
0
{
6319
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
6320
0
    VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
6321
6322
0
    return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
6323
0
        iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
6324
0
}
6325
6326
/************************************************************************/
6327
/*                    OGRLayer::GetSupportedSRSList()                   */
6328
/************************************************************************/
6329
6330
/** \brief Get the list of SRS supported.
6331
 *
6332
 * The base implementation of this method will return an empty list. Some
6333
 * drivers (OAPIF, WFS) may return a non-empty list.
6334
 *
6335
 * One of the SRS returned may be passed to SetActiveSRS() to change the
6336
 * active SRS.
6337
 *
6338
 * @param iGeomField Geometry field index.
6339
 * @return list of supported SRS.
6340
 * @since GDAL 3.7
6341
 */
6342
const OGRLayer::GetSupportedSRSListRetType &
6343
OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
6344
0
{
6345
0
    static OGRLayer::GetSupportedSRSListRetType empty;
6346
0
    return empty;
6347
0
}
6348
6349
/************************************************************************/
6350
/*                    OGR_L_GetSupportedSRSList()                       */
6351
/************************************************************************/
6352
6353
/** \brief Get the list of SRS supported.
6354
 *
6355
 * The base implementation of this method will return an empty list. Some
6356
 * drivers (OAPIF, WFS) may return a non-empty list.
6357
 *
6358
 * One of the SRS returned may be passed to SetActiveSRS() to change the
6359
 * active SRS.
6360
 *
6361
 * @param hLayer Layer.
6362
 * @param iGeomField Geometry field index.
6363
 * @param[out] pnCount Number of values in returned array. Must not be null.
6364
 * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
6365
 * nullptr
6366
 * @since GDAL 3.7
6367
 */
6368
OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
6369
                                                int iGeomField, int *pnCount)
6370
0
{
6371
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
6372
0
    VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
6373
6374
0
    const auto &srsList =
6375
0
        OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
6376
0
    *pnCount = static_cast<int>(srsList.size());
6377
0
    if (srsList.empty())
6378
0
    {
6379
0
        return nullptr;
6380
0
    }
6381
0
    OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
6382
0
        CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
6383
0
    size_t i = 0;
6384
0
    for (const auto &poSRS : srsList)
6385
0
    {
6386
0
        poSRS->Reference();
6387
0
        pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
6388
0
        ++i;
6389
0
    }
6390
0
    pahRet[i] = nullptr;
6391
0
    return pahRet;
6392
0
}
6393
6394
/************************************************************************/
6395
/*                       OGRLayer::SetActiveSRS()                       */
6396
/************************************************************************/
6397
6398
/** \brief Change the active SRS.
6399
 *
6400
 * The passed SRS must be in the list returned by GetSupportedSRSList()
6401
 * (the actual pointer may be different, but should be tested as identical
6402
 * with OGRSpatialReference::IsSame()).
6403
 *
6404
 * Changing the active SRS affects:
6405
 * <ul>
6406
 * <li>the SRS in which geometries of returned features are expressed,</li>
6407
 * <li>the SRS in which geometries of passed features (CreateFeature(),
6408
 * SetFeature()) are expressed,</li>
6409
 * <li>the SRS returned by GetSpatialRef() and
6410
 * GetGeomFieldDefn()->GetSpatialRef(),</li>
6411
 * <li>the SRS used to interpret SetSpatialFilter() values.</li>
6412
 * </ul>
6413
 * This also resets feature reading and the spatial filter.
6414
 * Note however that this does not modify the storage SRS of the features of
6415
 * geometries. Said otherwise, this setting is volatile and has no persistent
6416
 * effects after dataset reopening.
6417
 *
6418
 * @param iGeomField Geometry field index.
6419
 * @param poSRS SRS to use
6420
 * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
6421
 *         the passed SRS is not in GetSupportedSRSList()
6422
 * @since GDAL 3.7
6423
 */
6424
OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
6425
                              CPL_UNUSED const OGRSpatialReference *poSRS)
6426
0
{
6427
0
    return OGRERR_FAILURE;
6428
0
}
6429
6430
/************************************************************************/
6431
/*                         OGR_L_SetActiveSRS()                         */
6432
/************************************************************************/
6433
6434
/** \brief Change the active SRS.
6435
 *
6436
 * The passed SRS must be in the list returned by GetSupportedSRSList()
6437
 * (the actual pointer may be different, but should be tested as identical
6438
 * with OGRSpatialReference::IsSame()).
6439
 *
6440
 * Changing the active SRS affects:
6441
 * <ul>
6442
 * <li>the SRS in which geometries of returned features are expressed,</li>
6443
 * <li>the SRS in which geometries of passed features (CreateFeature(),
6444
 * SetFeature()) are expressed,</li>
6445
 * <li>the SRS returned by GetSpatialRef() and
6446
 * GetGeomFieldDefn()->GetSpatialRef(),</li>
6447
 * <li>the SRS used to interpret SetSpatialFilter() values.</li>
6448
 * </ul>
6449
 * This also resets feature reading and the spatial filter.
6450
 * Note however that this does not modify the storage SRS of the features of
6451
 * geometries. Said otherwise, this setting is volatile and has no persistent
6452
 * effects after dataset reopening.
6453
 *
6454
 * @param hLayer Layer.
6455
 * @param iGeomField Geometry field index.
6456
 * @param hSRS SRS to use
6457
 * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
6458
 *         the passed SRS is not in GetSupportedSRSList().
6459
 * @since GDAL 3.7
6460
 */
6461
OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
6462
                          OGRSpatialReferenceH hSRS)
6463
0
{
6464
0
    VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
6465
0
    return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
6466
0
        iGeomField, OGRSpatialReference::FromHandle(hSRS));
6467
0
}
6468
6469
/************************************************************************/
6470
/*                             GetDataset()                             */
6471
/************************************************************************/
6472
6473
/** Return the dataset associated with this layer.
6474
 *
6475
 * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
6476
 * have CreateLayer() capability. It may not be implemented in read-only
6477
 * drivers or out-of-tree drivers.
6478
 *
6479
 * It is currently only used by the GetRecordBatchSchema()
6480
 * method to retrieve the field domain associated with a field, to fill the
6481
 * dictionary field of a struct ArrowSchema.
6482
 * It is also used by CreateFieldFromArrowSchema() to determine which field
6483
 * types and subtypes are supported by the layer, by inspecting the driver
6484
 * metadata, and potentially use fallback types when needed.
6485
 *
6486
 * This method is the same as the C function OGR_L_GetDataset().
6487
 *
6488
 * @return dataset, or nullptr when unknown.
6489
 * @since GDAL 3.6
6490
 */
6491
GDALDataset *OGRLayer::GetDataset()
6492
0
{
6493
0
    return nullptr;
6494
0
}
6495
6496
/************************************************************************/
6497
/*                          OGR_L_GetDataset()                          */
6498
/************************************************************************/
6499
6500
/** Return the dataset associated with this layer.
6501
 *
6502
 * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
6503
 * have CreateLayer() capability. It may not be implemented in read-only
6504
 * drivers or out-of-tree drivers.
6505
 *
6506
 * It is currently only used by the GetRecordBatchSchema()
6507
 * method to retrieve the field domain associated with a field, to fill the
6508
 * dictionary field of a struct ArrowSchema.
6509
 * It is also used by CreateFieldFromArrowSchema() to determine which field
6510
 * types and subtypes are supported by the layer, by inspecting the driver
6511
 * metadata, and potentially use fallback types when needed.
6512
 *
6513
 * This function is the same as the C++ method OGRLayer::GetDataset().
6514
 *
6515
 * @return dataset, or nullptr when unknown.
6516
 * @since GDAL 3.9
6517
 */
6518
GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
6519
0
{
6520
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
6521
0
    return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
6522
0
}