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