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