Coverage Report

Created: 2025-06-13 06:18

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