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